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