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

     1  import { ApolloError, useApolloClient, useQuery } from '@apollo/client'
     2  import {
     3    GraphQLToast,
     4    Wizard,
     5    WizardNavigation,
     6    WizardStepConfig,
     7    WizardStepper,
     8  } from '@pluralsh/design-system'
     9  import React, {
    10    useCallback,
    11    useContext,
    12    useEffect,
    13    useMemo,
    14    useState,
    15  } from 'react'
    16  import { useNavigate } from 'react-router-dom'
    17  import styled from 'styled-components'
    18  
    19  import Loader from '../../components/loader/Loader'
    20  import { WailsContext } from '../../context/wails'
    21  import { ListRepositoriesDocument, ListRepositoriesQueryVariables, RootQueryType } from '../../graphql/generated/graphql'
    22  import { Routes } from '../routes'
    23  
    24  import { buildSteps, install, toDefaultSteps } from './helpers'
    25  import { InstallerContext } from './context'
    26  
    27  const FILTERED_APPS = ['bootstrap', 'ingress-nginx', 'postgres']
    28  const FORCED_APPS = {
    29    console: 'The Plural Console will allow you to monitor, upgrade, and deploy applications easily from one centralized place.',
    30  }
    31  
    32  const Installer = styled(InstallerUnstyled)(() => ({
    33    height: '100%',
    34  }))
    35  
    36  function InstallerUnstyled({ ...props }): React.ReactElement {
    37    const navigate = useNavigate()
    38    const client = useApolloClient()
    39    const { project: { provider } } = useContext(WailsContext)
    40  
    41    const [stepsLoading, setStepsLoading] = useState(false)
    42    const [steps, setSteps] = useState<Array<WizardStepConfig>>()
    43    const [error, setError] = useState<ApolloError | undefined>()
    44    const [defaultSteps, setDefaultSteps] = useState<Array<WizardStepConfig>>([])
    45    const [domains, setDomains] = useState<Record<string, string>>({})
    46  
    47    const { data: connection } = useQuery<Pick<RootQueryType, 'repositories'>, ListRepositoriesQueryVariables>(ListRepositoriesDocument, {
    48      variables: {
    49        installed: false,
    50        provider,
    51      },
    52      fetchPolicy: 'network-only',
    53    })
    54  
    55    const { data: installed } = useQuery<Pick<RootQueryType, 'repositories'>, ListRepositoriesQueryVariables>(ListRepositoriesDocument, {
    56      variables: {
    57        installed: true,
    58        provider,
    59      },
    60      fetchPolicy: 'network-only',
    61    })
    62  
    63    const context = useMemo(() => ({ domains, setDomains }), [domains])
    64  
    65    const applications = useMemo(() => connection
    66      ?.repositories
    67      ?.edges
    68      ?.map(repo => repo!.node)
    69      .filter(app => ((!app?.private ?? true)) && !FILTERED_APPS.includes(app!.name)), [connection?.repositories?.edges])
    70  
    71    const installedApplications = useMemo(() => installed
    72      ?.repositories
    73      ?.edges
    74      ?.map(repo => repo!.node) ?? [], [installed])
    75  
    76    const onInstall = useCallback((payload: Array<WizardStepConfig>) => {
    77      setStepsLoading(true)
    78  
    79      install(client, payload)
    80        .then(() => navigate(Routes.Next))
    81        .catch(err => setError(err))
    82        .finally(() => setStepsLoading(false))
    83    }, [client, navigate])
    84  
    85    const onSelect = useCallback((selectedApplications: Array<WizardStepConfig>) => {
    86      const build = async () => {
    87        const steps = await buildSteps(
    88          client,
    89          provider!,
    90          selectedApplications,
    91          new Set<string>(installedApplications.map(repository => repository!.name)),
    92        )
    93  
    94        setSteps(steps)
    95      }
    96  
    97      setStepsLoading(true)
    98      build().finally(() => setStepsLoading(false))
    99    }, [client, installedApplications, provider])
   100  
   101    useEffect(() => setDefaultSteps(toDefaultSteps(applications, provider!, { ...FORCED_APPS })), [applications?.length, provider])
   102  
   103    if (!applications || defaultSteps.length === 0) {
   104      return <Loader />
   105    }
   106  
   107    return (
   108      <div {...props}>
   109        <InstallerContext.Provider value={context}>
   110          <Wizard
   111            onSelect={onSelect}
   112            defaultSteps={defaultSteps}
   113            dependencySteps={steps}
   114            limit={5}
   115            loading={stepsLoading}
   116          >
   117            {{
   118              stepper: <WizardStepper />,
   119              navigation: <WizardNavigation onInstall={onInstall} />,
   120            }}
   121          </Wizard>
   122  
   123          {error && (
   124            <GraphQLToast
   125              error={{ graphQLErrors: error.graphQLErrors ? [...error.graphQLErrors] : [{ message: error as any }] }}
   126              header="Error"
   127              onClose={() => setError(undefined)}
   128              margin="medium"
   129              closeTimeout={20000}
   130            />
   131          )}
   132        </InstallerContext.Provider>
   133      </div>
   134    )
   135  }
   136  
   137  export default Installer