github.com/pluralsh/plural-cli@v0.9.5/pkg/ui/web/src/routes/installer/helpers.tsx (about) 1 import { ApolloClient } from '@apollo/client' 2 3 import { 4 AppsIcon, 5 InstallIcon, 6 WizardInstaller, 7 WizardPicker, 8 WizardStepConfig, 9 } from '@pluralsh/design-system' 10 11 import { 12 Datatype, 13 GetRecipeDocument, 14 ListRecipesDocument, 15 Provider, 16 Recipe, 17 RecipeSection, 18 RootQueryType, 19 } from '../../graphql/generated/graphql' 20 import { Binding, ClientBindingFactory } from '../../services/wails' 21 22 import { Application } from './Application' 23 24 const toPickerItems = (applications: Array<any>, provider: Provider, forcedApps: any): Array<WizardStepConfig> => applications?.map(app => ({ 25 key: app.id, 26 label: app.name, 27 imageUrl: app.icon, 28 node: <Application 29 key={app.id} 30 provider={provider} 31 />, 32 isRequired: Object.keys(forcedApps).includes(app.name), 33 tooltip: forcedApps[app.name], 34 })) || [] 35 36 const toDefaultSteps = (applications: any, provider: Provider, forcedApps: any): Array<WizardStepConfig> => [{ 37 key: 'apps', 38 label: 'Apps', 39 Icon: AppsIcon, 40 node: <WizardPicker items={toPickerItems(applications, provider, forcedApps)} />, 41 isDefault: true, 42 }, 43 { 44 key: 'placeholder', 45 isPlaceholder: true, 46 }, 47 { 48 key: 'install', 49 label: 'Install', 50 Icon: InstallIcon, 51 node: <WizardInstaller />, 52 isDefault: true, 53 }] 54 55 const toDependencySteps = (applications: {section: RecipeSection, dependencyOf: Set<string>}[], provider: Provider): Array<WizardStepConfig> => [...applications.map(app => ({ 56 key: app.section.repository!.id, 57 label: app.section.repository!.name, 58 imageUrl: app.section.repository!.icon!, 59 node: <Application 60 key={app.section.repository!.id} 61 provider={provider} 62 />, 63 isDependency: true, 64 dependencyOf: app.dependencyOf, 65 }))] 66 67 const buildSteps = async ( 68 client: ApolloClient<unknown>, 69 provider: Provider, 70 selectedApplications: Array<WizardStepConfig>, 71 installedApplications: Set<string> 72 ) => { 73 const dependencyMap = new Map<string, {section: RecipeSection, dependencyOf: Set<string>}>() 74 75 for (const app of selectedApplications) { 76 const { data: { recipes } = {} } = await client.query<Pick<RootQueryType, 'recipes'>>({ 77 query: ListRecipesDocument, 78 variables: { repositoryId: app.key }, 79 }) 80 81 const { node: recipeBase } = recipes?.edges?.find(edge => edge!.node!.provider === provider) || { node: undefined } 82 83 if (!recipeBase) continue 84 85 const { data: recipe } = await client.query<{recipe: Recipe}>({ 86 query: GetRecipeDocument, 87 variables: { id: recipeBase?.id }, 88 }) 89 90 const sections = recipe.recipe.recipeSections! 91 .filter(section => section!.repository!.name !== app.label) 92 .filter(section => !installedApplications.has(section!.repository!.name)) 93 94 sections.forEach(section => { 95 if (selectedApplications.find(app => app.key === section!.repository!.id)) return 96 97 if (!dependencyMap.has(section!.repository!.name)) { 98 dependencyMap.set(section!.repository!.name, { section: section!, dependencyOf: new Set([app.label!]) }) 99 100 return 101 } 102 103 const dep = dependencyMap.get(section!.repository!.name)! 104 const dependencyOf: Array<string> = [...Array.from(dep.dependencyOf.values()), app.label!] 105 106 dependencyMap.set(section!.repository!.name, { section: section!, dependencyOf: new Set<string>(dependencyOf) }) 107 }) 108 } 109 110 return toDependencySteps(Array.from(dependencyMap.values()), provider) 111 } 112 113 const install = async (client: ApolloClient<unknown>, apps: Array<WizardStepConfig<any>>) => { 114 const toAPIContext = context => ({ ...Object.keys(context || {}).reduce((acc, key) => ({ ...acc, [key]: context[key].value }), {}) }) 115 const toDataTypeValues = (context, datatype) => Object.keys(context || {}).reduce((acc: Array<any>, key) => (context[key].type === datatype ? [...acc, context[key].value] : [...acc]), []) 116 const install = ClientBindingFactory<void>(Binding.Install) 117 const domains = apps.reduce((acc: Array<any>, app) => [...acc, ...toDataTypeValues(app.data?.context || {}, Datatype.Domain)], []) 118 const buckets = apps.reduce((acc: Array<any>, app) => [...acc, ...toDataTypeValues(app.data?.context || {}, Datatype.Bucket)], []) 119 120 // Filter out some form validation fields from context 121 apps = apps.map(app => ({ ...app, data: { ...app.data, context: toAPIContext(app.data.context ?? {}) } })) 122 123 return install(apps.map(app => ({ ...app, dependencyOf: Array.from(app.dependencyOf ?? []) })), domains, buckets) 124 } 125 126 export { 127 toDependencySteps, toDefaultSteps, buildSteps, toPickerItems, install, 128 }