github.com/argoproj/argo-cd/v2@v2.10.9/ui/src/app/applications/components/application-sync-options/application-sync-options.tsx (about)

     1  import {Checkbox, Select, Tooltip} from 'argo-ui';
     2  import * as classNames from 'classnames';
     3  import * as React from 'react';
     4  import * as ReactForm from 'react-form';
     5  
     6  import './application-sync-options.scss';
     7  
     8  export const REPLACE_WARNING = `The resources will be synced using 'kubectl replace/create' command that is a potentially destructive action and might cause resources recreation.`;
     9  export const FORCE_WARNING = `The resources will be synced using '--force' that is a potentially destructive action and will immediately remove resources from the API and bypasses graceful deletion. Immediate deletion of some resources may result in inconsistency or data loss.`;
    10  export const PRUNE_ALL_WARNING = `The resources will be synced using '--prune', and all resources are marked to be pruned. Only continue if you want to delete all of the Application's resources.`;
    11  
    12  export interface ApplicationSyncOptionProps {
    13      options: string[];
    14      onChanged: (updatedOptions: string[]) => any;
    15      id?: string;
    16  }
    17  
    18  function selectOption(name: string, label: string, defaultVal: string, values: string[], props: ApplicationSyncOptionProps) {
    19      const options = [...(props.options || [])];
    20      const prefix = `${name}=`;
    21      const index = options.findIndex(item => item.startsWith(prefix));
    22      const val = index < 0 ? defaultVal : options[index].substr(prefix.length);
    23  
    24      return (
    25          <div className='application-sync-options__select'>
    26              <label>{label}:</label>
    27              <Select
    28                  value={val}
    29                  options={values}
    30                  onChange={opt => {
    31                      const newValue = `${name}=${opt.value}`;
    32                      if (index < 0) {
    33                          props.onChanged(options.concat(newValue));
    34                      } else {
    35                          options[index] = newValue;
    36                          props.onChanged(options);
    37                      }
    38                  }}
    39              />
    40          </div>
    41      );
    42  }
    43  
    44  function booleanOption(name: string, label: string, defaultVal: boolean, props: ApplicationSyncOptionProps, invert: boolean, warning: string = null) {
    45      const options = [...(props.options || [])];
    46      const prefix = `${name}=`;
    47      const index = options.findIndex(item => item.startsWith(prefix));
    48      const checked = index < 0 ? defaultVal : options[index].substring(prefix.length) === (invert ? 'false' : 'true');
    49      return (
    50          <React.Fragment>
    51              <Checkbox
    52                  id={`sync-option-${name}-${props.id}`}
    53                  checked={checked}
    54                  onChange={(val: boolean) => {
    55                      if (index < 0) {
    56                          props.onChanged(options.concat(`${name}=${invert ? !val : val}`));
    57                      } else {
    58                          options.splice(index, 1);
    59                          props.onChanged(options);
    60                      }
    61                  }}
    62              />
    63              <label htmlFor={`sync-option-${name}-${props.id}`}>{label}</label>{' '}
    64              {warning && (
    65                  <>
    66                      <Tooltip content={warning}>
    67                          <i className='fa fa-exclamation-triangle' />
    68                      </Tooltip>
    69                      {checked && <div className='application-sync-options__warning'>{warning}</div>}
    70                  </>
    71              )}
    72          </React.Fragment>
    73      );
    74  }
    75  
    76  enum ManualSyncFlags {
    77      Prune = 'Prune',
    78      DryRun = 'Dry Run',
    79      ApplyOnly = 'Apply Only',
    80      Force = 'Force'
    81  }
    82  
    83  export interface SyncFlags {
    84      Prune: boolean;
    85      DryRun: boolean;
    86      ApplyOnly: boolean;
    87      Force: boolean;
    88  }
    89  
    90  const syncOptions: Array<(props: ApplicationSyncOptionProps) => React.ReactNode> = [
    91      props => booleanOption('Validate', 'Skip Schema Validation', false, props, true),
    92      props => booleanOption('CreateNamespace', 'Auto-Create Namespace', false, props, false),
    93      props => booleanOption('PruneLast', 'Prune Last', false, props, false),
    94      props => booleanOption('ApplyOutOfSyncOnly', 'Apply Out of Sync Only', false, props, false),
    95      props => booleanOption('RespectIgnoreDifferences', 'Respect Ignore Differences', false, props, false),
    96      props => booleanOption('ServerSideApply', 'Server-Side Apply', false, props, false),
    97      props => selectOption('PrunePropagationPolicy', 'Prune Propagation Policy', 'foreground', ['foreground', 'background', 'orphan'], props)
    98  ];
    99  
   100  const optionStyle = {marginTop: '0.5em'};
   101  
   102  export const ApplicationSyncOptions = (props: ApplicationSyncOptionProps) => (
   103      <div className='row application-sync-options'>
   104          {syncOptions.map((render, i) => (
   105              <div
   106                  key={i}
   107                  style={optionStyle}
   108                  className={classNames('small-12', {
   109                      'large-6': i < syncOptions.length - 1
   110                  })}>
   111                  {render(props)}
   112              </div>
   113          ))}
   114          <div className='small-12' style={optionStyle}>
   115              {booleanOption('Replace', 'Replace', false, props, false, REPLACE_WARNING)}
   116          </div>
   117      </div>
   118  );
   119  
   120  export const ApplicationManualSyncFlags = ReactForm.FormField((props: {fieldApi: ReactForm.FieldApi; id?: string}) => {
   121      const {
   122          fieldApi: {getValue, setValue, setTouched}
   123      } = props;
   124      const val = getValue() || false;
   125      return (
   126          <div style={optionStyle}>
   127              {Object.keys(ManualSyncFlags).map(flag => (
   128                  <React.Fragment key={flag}>
   129                      <Checkbox
   130                          id={`sync-option-${flag}-${props.id}`}
   131                          checked={val[flag]}
   132                          onChange={(newVal: boolean) => {
   133                              setTouched(true);
   134                              const update = {...val};
   135                              update[flag] = newVal;
   136                              setValue(update);
   137                          }}
   138                      />
   139                      <label htmlFor={`sync-option-${flag}-${props.id}`}>{ManualSyncFlags[flag as keyof typeof ManualSyncFlags]}</label>{' '}
   140                  </React.Fragment>
   141              ))}
   142          </div>
   143      );
   144  });
   145  
   146  export const ApplicationSyncOptionsField = ReactForm.FormField((props: {fieldApi: ReactForm.FieldApi}) => {
   147      const {
   148          fieldApi: {getValue, setValue, setTouched}
   149      } = props;
   150      const val = getValue() || [];
   151      return (
   152          <div className='argo-field' style={{borderBottom: '0'}}>
   153              <ApplicationSyncOptions
   154                  options={val}
   155                  onChanged={opts => {
   156                      setTouched(true);
   157                      setValue(opts);
   158                  }}
   159              />
   160          </div>
   161      );
   162  });