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