github.com/argoproj/argo-cd/v3@v3.2.1/ui/src/app/applications/components/application-retry-options/application-retry-options.tsx (about)

     1  /* eslint-disable no-prototype-builtins */
     2  import * as React from 'react';
     3  import {FormApi, NestedForm, Text, Form} from 'react-form';
     4  import {Checkbox, FormField} from 'argo-ui';
     5  import {omit} from 'lodash-es';
     6  import {NumberField} from '../../../shared/components';
     7  import * as models from '../../../shared/models';
     8  
     9  import './application-retry-options.scss';
    10  
    11  // eslint-disable-next-line no-useless-escape
    12  const durationRegex = /^([\d\.]+[HMS])+$/i;
    13  const durationRegexError = 'Should be 1h10m10s/10h10m/10m/10s';
    14  
    15  const onlyPositiveValidation = {
    16      min: '1',
    17      step: '1'
    18  };
    19  
    20  function buildFormItem(label: string, propertyPath: string, component: React.ComponentType, formApi: FormApi, componentProps?: Record<string, any>) {
    21      return <FormField formApi={formApi} label={label} field={propertyPath} component={component} componentProps={componentProps} />;
    22  }
    23  
    24  const retryOptions: Array<(formApi: FormApi) => React.ReactNode> = [
    25      formApi => buildFormItem('Limit', 'limit', NumberField, formApi, onlyPositiveValidation),
    26      formApi => buildFormItem('Duration', 'backoff.duration', Text, formApi),
    27      formApi => buildFormItem('Max Duration', 'backoff.maxDuration', Text, formApi),
    28      formApi => buildFormItem('Factor', 'backoff.factor', NumberField, formApi, onlyPositiveValidation)
    29  ];
    30  
    31  const defaultInitialValues = {
    32      limit: 2,
    33      backoff: {
    34          duration: '5s',
    35          maxDuration: '3m0s',
    36          factor: 2
    37      }
    38  };
    39  
    40  export const ApplicationRetryForm = ({initValues, field = 'retryStrategy'}: {initValues?: models.RetryStrategy; field: string}) => {
    41      return (
    42          <NestedForm field={field}>
    43              <Form
    44                  defaultValues={{
    45                      ...defaultInitialValues,
    46                      ...initValues
    47                  }}
    48                  validateError={values => {
    49                      const backoff = values.backoff || {};
    50  
    51                      if (!values) {
    52                          return {};
    53                      }
    54  
    55                      return {
    56                          'limit': !values.limit && values.hasOwnProperty('limit') && 'Limit is required',
    57  
    58                          'backoff.duration':
    59                              backoff.hasOwnProperty('duration') && ((!backoff.duration && 'Duration is required') || (!durationRegex.test(backoff.duration) && durationRegexError)),
    60  
    61                          'backoff.maxDuration':
    62                              backoff.hasOwnProperty('maxDuration') &&
    63                              ((!backoff.maxDuration && 'Max Duration is required') || (!durationRegex.test(backoff.maxDuration) && durationRegexError)),
    64  
    65                          'backoff.factor': backoff.hasOwnProperty('factor') && !backoff.factor && 'Factor is required'
    66                      };
    67                  }}>
    68                  {nestedFormApi => {
    69                      return (
    70                          <div className='row application-retry-options-list'>
    71                              {retryOptions.map((render, i) => (
    72                                  <div className='columns small-6 application-retry-options-list__item' key={i}>
    73                                      {render(nestedFormApi)}
    74                                  </div>
    75                              ))}
    76                          </div>
    77                      );
    78                  }}
    79              </Form>
    80          </NestedForm>
    81      );
    82  };
    83  
    84  export const ApplicationRetryOptions = ({
    85      formApi,
    86      initValues,
    87      field = 'retryStrategy',
    88      retry,
    89      setRetry,
    90      id
    91  }: {
    92      formApi: FormApi;
    93      field?: string;
    94      initValues?: models.RetryStrategy;
    95      retry?: boolean;
    96      setRetry?: (value: boolean) => any;
    97      id?: string;
    98  }) => {
    99      const [retryInternal, setRetryInternal] = React.useState(!!initValues);
   100  
   101      const toggleRetry = (value: boolean) => {
   102          if (!value) {
   103              const formState = formApi.getFormState();
   104              const values = formState.values;
   105              const errors = formState.errors;
   106  
   107              const newValues = omit(values, field);
   108              const newErrors = omit(errors, field);
   109  
   110              formApi.setFormState({
   111                  ...formState,
   112                  values: newValues,
   113                  errors: newErrors
   114              });
   115          }
   116          if (setRetry != null) {
   117              setRetry(value);
   118          } else {
   119              setRetryInternal(value);
   120          }
   121      };
   122      const isChecked = setRetry != null ? retry : retryInternal;
   123      return (
   124          <div className='application-retry-options'>
   125              <Checkbox id={`retry-${id}`} checked={isChecked} onChange={val => toggleRetry(val)} />
   126              <label htmlFor={`retry-${id}`}>Retry</label>
   127              {isChecked && <ApplicationRetryForm initValues={initValues} field={field} />}
   128          </div>
   129      );
   130  };