github.com/pluralsh/plural-cli@v0.9.5/pkg/ui/web/src/routes/installer/Application.tsx (about)

     1  import { useQuery } from '@apollo/client'
     2  import { Chip, WizardStep, useActive } from '@pluralsh/design-system'
     3  import { Div, Span } from 'honorable'
     4  import {
     5    ReactElement,
     6    useContext,
     7    useEffect,
     8    useMemo,
     9    useState,
    10  } from 'react'
    11  
    12  import Loader from '../../components/loader/Loader'
    13  import { WailsContext } from '../../context/wails'
    14  import {
    15    GetRecipeDocument,
    16    ListRecipesDocument,
    17    Recipe,
    18    RecipeEdge,
    19  } from '../../graphql/generated/graphql'
    20  
    21  import { Configuration } from './Configuration'
    22  
    23  interface StepData {
    24    id: string | undefined,
    25    context: Record<string, unknown>
    26    oidc: boolean
    27    skipped?: boolean,
    28  }
    29  
    30  const toConfig = config => (config ? Object.keys(config)
    31    .map(key => ({ [key]: { value: config[key], valid: true } }))
    32    .reduce((acc, entry) => ({ ...acc, ...entry }), {}) : undefined)
    33  
    34  export function Application({ provider, ...props }: any): ReactElement {
    35    const { active, setData } = useActive<StepData>()
    36    const { context: { configuration } } = useContext(WailsContext)
    37    const [context, setContext] = useState<Record<string, unknown>>(active.data?.context || {})
    38    const [valid, setValid] = useState(true)
    39    const [oidc, setOIDC] = useState(active.data?.oidc ?? true)
    40    const { data: { recipes: { edges: recipeEdges } = { edges: undefined } } = {} } = useQuery(ListRecipesDocument, {
    41      variables: { repositoryId: active.key },
    42    })
    43  
    44    const { node: recipeBase } = recipeEdges?.find((recipe: RecipeEdge) => recipe!.node!.provider === provider) || { node: undefined }
    45    const { data: recipe } = useQuery<{recipe: Recipe}>(GetRecipeDocument, {
    46      variables: { id: recipeBase?.id },
    47      skip: !recipeBase,
    48    })
    49  
    50    const recipeContext = useMemo(() => toConfig(configuration?.[active.label!]), [active.label, configuration])
    51    const mergedContext = useMemo<Record<string, unknown>>(() => ({ ...recipeContext, ...context }), [recipeContext, context])
    52    const stepData = useMemo(() => ({
    53      ...active.data, ...{ id: recipe?.recipe.id }, ...{ context: mergedContext }, ...{ oidc },
    54    }), [active.data, recipe?.recipe.id, mergedContext, oidc])
    55  
    56    useEffect(() => {
    57      const valid = Object.values<any>(context).every(({ valid }) => valid)
    58  
    59      setValid(valid)
    60    }, [context, setValid])
    61  
    62    // Update step data on change
    63    useEffect(() => setData(stepData), [stepData, setData])
    64  
    65    if (!recipe) {
    66      return (
    67        <WizardStep {...props}>
    68          <Loader />
    69        </WizardStep>
    70      )
    71    }
    72  
    73    if (recipe.recipe?.restricted) {
    74      return (
    75        <WizardStep
    76          valid={false}
    77          {...props}
    78        >
    79          <Div
    80            marginTop="xxsmall"
    81            marginBottom="medium"
    82            display="flex"
    83            gap="medium"
    84            flexDirection="column"
    85          >
    86            <Span
    87              color="text-xlight"
    88              overline
    89            >Cannot install app
    90            </Span>
    91            <Span
    92              color="text-light"
    93              body2
    94            >This application has been marked restricted because it requires configuration, like ssh keys, that are only able to be securely configured locally.
    95            </Span>
    96          </Div>
    97        </WizardStep>
    98      )
    99    }
   100  
   101    return (
   102      <WizardStep
   103        valid={valid}
   104        data={stepData}
   105        {...props}
   106      >
   107        <Div
   108          marginBottom="medium"
   109          display="flex"
   110          lineHeight="24px"
   111          alignItems="center"
   112          height="24px"
   113        >
   114          <Span
   115            overline
   116            color="text-xlight"
   117          >
   118            configure {active.label}
   119          </Span>
   120          {active.isDependency && (
   121            <Chip
   122              size="small"
   123              hue="lighter"
   124              marginLeft="xsmall"
   125            >Dependency
   126            </Chip>
   127          )}
   128        </Div>
   129        <Configuration
   130          recipe={recipe.recipe}
   131          context={mergedContext}
   132          setContext={setContext}
   133          oidc={oidc}
   134          setOIDC={setOIDC}
   135        />
   136      </WizardStep>
   137    )
   138  }