github.com/pluralsh/plural-cli@v0.9.5/pkg/ui/web/src/routes/installer/Configuration.tsx (about) 1 import { 2 Dispatch, 3 ReactElement, 4 SetStateAction, 5 useCallback, 6 useEffect, 7 useMemo, 8 } from 'react' 9 import { Flex, Span, Switch } from 'honorable' 10 import { useActive, useNavigation } from '@pluralsh/design-system' 11 12 import { 13 Datatype, 14 Maybe, 15 Operation as OperationType, 16 Recipe, 17 RecipeConfiguration, 18 } from '../../graphql/generated/graphql' 19 20 import { ConfigurationItem } from './ConfigurationItem' 21 22 const available = (config, context) => { 23 if (!config.condition) return true 24 25 const { condition } = config 26 27 switch (condition.operation) { 28 case OperationType.Not: 29 return !(context[condition.field]?.value) 30 case OperationType.Prefix: 31 return context[condition.field]?.value?.startsWith(condition.value) ?? false 32 case OperationType.Eq: 33 return context[condition.field]?.value 34 } 35 36 return true 37 } 38 39 interface ConfigurationProps { 40 recipe: Recipe, 41 context: Record<string, any> 42 setContext: Dispatch<SetStateAction<Record<string, any>>> 43 oidc?: boolean 44 setOIDC: Dispatch<boolean> 45 } 46 47 export function Configuration({ 48 recipe, context, setContext, oidc, setOIDC, 49 }: ConfigurationProps): ReactElement { 50 const { 51 active, completed, setCompleted, setData, 52 } = useActive<Record<string, unknown>>() 53 const { onNext } = useNavigation() 54 const sections = recipe.recipeSections 55 const configurations = sections!.filter(section => section!.repository!.name === active.label).map(section => section!.configuration).flat().filter(c => !!c) 56 const setValue = useCallback(( 57 fieldName, value, valid = true, type = Datatype.String 58 ) => setContext(context => ({ ...context, ...{ [fieldName]: { value, valid, type } } })), [setContext]) 59 const hiddenConfigurations = useMemo(() => configurations.filter(conf => !available(conf, context)), [configurations, context]) 60 61 useEffect(() => { 62 hiddenConfigurations.forEach(conf => { 63 setContext(context => ({ ...context, ...{ [conf!.name!]: { value: context[conf!.name!]?.value, valid: true, type: Datatype.String } } })) 64 }) 65 // eslint-disable-next-line react-hooks/exhaustive-deps 66 }, [hiddenConfigurations.length, setContext]) 67 68 useEffect(() => { 69 if (configurations.length === 0 && !completed && active.data?.id) setCompleted(true) 70 }, [configurations.length, completed, active.data?.id, setCompleted]) 71 72 useEffect(() => { 73 if (configurations.length === 0 && !active.data?.skipped && completed) { 74 setData({ ...active.data, ...{ skipped: true } }) 75 onNext() 76 } 77 }, [active.data, completed, configurations.length, onNext, setData]) 78 79 return ( 80 <Flex 81 gap="large" 82 direction="column" 83 marginRight="xsmall" 84 > 85 {configurations.filter(conf => available(conf, context)).map((conf?: Maybe<RecipeConfiguration>) => ( 86 <ConfigurationItem 87 key={`${recipe.name}-${conf!.name}`} 88 config={conf} 89 ctx={context} 90 setValue={setValue} 91 /> 92 ))} 93 {configurations?.length === 0 && ( 94 <Span 95 color="text-light" 96 body2 97 >Nothing needs doing here! You can continue. 98 </Span> 99 )} 100 {recipe.oidcEnabled && ( 101 <div> 102 <Switch 103 checked={oidc} 104 onChange={({ target: { checked } }) => setOIDC(checked)} 105 >Enable OIDC 106 </Switch> 107 </div> 108 )} 109 </Flex> 110 ) 111 }