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 };