From fad81885c0f18b5e60e82bb829b60e64c0cd36e3 Mon Sep 17 00:00:00 2001 From: jingyang <72259332+zjy365@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:35:12 +0800 Subject: [PATCH] feat: launchpad implement URL query to form data conversion (#5081) * feat: launchpad implement URL query to form data conversion * add appName * update * fix dockerfile --- frontend/Dockerfile | 2 +- .../applaunchpad/src/constants/editApp.ts | 2 +- .../providers/applaunchpad/src/mock/apps.ts | 24 ++++++++- .../providers/applaunchpad/src/pages/_app.tsx | 8 +-- .../src/pages/app/edit/components/Form.tsx | 23 +++++++-- .../applaunchpad/src/pages/app/edit/index.tsx | 50 +++++++++++++++---- .../providers/applaunchpad/src/types/app.d.ts | 5 +- 7 files changed, 93 insertions(+), 21 deletions(-) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 3fd2cfa279e..3d4809f1f90 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -FROM node:20.4.0-alpine As base +FROM node:20.4.0-alpine AS base ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" WORKDIR /app diff --git a/frontend/providers/applaunchpad/src/constants/editApp.ts b/frontend/providers/applaunchpad/src/constants/editApp.ts index c0ef9fa66bb..171cae03527 100644 --- a/frontend/providers/applaunchpad/src/constants/editApp.ts +++ b/frontend/providers/applaunchpad/src/constants/editApp.ts @@ -30,7 +30,7 @@ export const defaultEditVal: AppEditType = { cmdParam: '', replicas: 1, cpu: 100, - memory: 64, + memory: 128, networks: [ { networkName: '', diff --git a/frontend/providers/applaunchpad/src/mock/apps.ts b/frontend/providers/applaunchpad/src/mock/apps.ts index 34d9e06e7de..66b02e00f69 100644 --- a/frontend/providers/applaunchpad/src/mock/apps.ts +++ b/frontend/providers/applaunchpad/src/mock/apps.ts @@ -1,4 +1,4 @@ -import { AppListItemType, AppDetailType, PodDetailType } from '@/types/app'; +import { AppListItemType, AppDetailType, PodDetailType, AppEditSyncedFields } from '@/types/app'; import { appStatusMap, podStatusMap } from '@/constants/app'; import { customAlphabet } from 'nanoid'; const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 12); @@ -295,3 +295,25 @@ export const MOCK_APP_DETAIL: AppDetailType = { sourceType: 'app_store' } }; + +export const MockAppEditSyncedFields: AppEditSyncedFields = { + imageName: 'nginx', + appName: 'hello-world-test', + replicas: 1, + cpu: 4000, + memory: 64, + networks: [ + { + networkName: 'network-atyjahgvtzqm', + portName: 'vsjrpjzjptex', + port: 80, + protocol: 'HTTP', + openPublicDomain: true, + publicDomain: 'tkywzlpibxdl', + customDomain: '', + domain: 'gzg.sealos.run' + } + ], + cmdParam: 'sleep 10', + runCMD: '/bin/bash -c' +}; diff --git a/frontend/providers/applaunchpad/src/pages/_app.tsx b/frontend/providers/applaunchpad/src/pages/_app.tsx index 4cbc0b9d9e8..662af6ca5ed 100644 --- a/frontend/providers/applaunchpad/src/pages/_app.tsx +++ b/frontend/providers/applaunchpad/src/pages/_app.tsx @@ -137,7 +137,7 @@ const App = ({ Component, pageProps }: AppProps) => { e: MessageEvent<{ type?: string; name?: string; - formData?: AppEditSyncedFields; + formData?: string; }> ) => { const whitelist = [`https://${SEALOS_DOMAIN}`]; @@ -154,10 +154,12 @@ const App = ({ Component, pageProps }: AppProps) => { name: name } }); - } else if (formData?.imageName) { + } else if (formData) { router.push({ pathname: '/app/edit', - query: formData + query: { + formData: formData + } }); } } diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx index 030e75b25a9..ecf65c89678 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx @@ -267,25 +267,42 @@ const Form = ({ inventory: countGpuInventory(selected.type) }; }, [userSourcePrice?.gpu, countGpuInventory, getValues, refresh]); + // cpu, memory have different sliderValue const countSliderList = useCallback(() => { const gpuType = getValues('gpu.type'); const key = gpuType && formSliderListConfig[gpuType] ? gpuType : defaultSliderKey; + const cpu = getValues('cpu'); + const memory = getValues('memory'); + + const cpuList = formSliderListConfig[key].cpu; + const memoryList = formSliderListConfig[key].memory; + + const sortedCpuList = + cpu !== undefined ? [...new Set([...cpuList, cpu])].sort((a, b) => a - b) : cpuList; + + const sortedMemoryList = + memory !== undefined + ? [...new Set([...memoryList, memory])].sort((a, b) => a - b) + : memoryList; + return { cpu: sliderNumber2MarkList({ - val: formSliderListConfig[key].cpu, + val: sortedCpuList, type: 'cpu', gpuAmount: getValues('gpu.amount') }), memory: sliderNumber2MarkList({ - val: formSliderListConfig[key].memory, + val: sortedMemoryList, type: 'memory', gpuAmount: getValues('gpu.amount') }) }; }, [formSliderListConfig, getValues]); - const SliderList = useMemo(() => countSliderList(), [countSliderList, refresh]); + + // eslint-disable-next-line react-hooks/exhaustive-deps + const SliderList = useMemo(() => countSliderList(), [already]); return ( <> diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx index 8a38c8a63f4..b18cbc7cc5b 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx @@ -32,6 +32,9 @@ import Form from './components/Form'; import Header from './components/Header'; import Yaml from './components/Yaml'; import { useMessage } from '@sealos/ui'; +import { customAlphabet } from 'nanoid'; + +const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 12); const ErrorModal = dynamic(() => import('./components/ErrorModal')); @@ -210,6 +213,7 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => isGuided ] ); + const submitError = useCallback(() => { // deep search message const deepSearch = (obj: any): string => { @@ -289,19 +293,43 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => }, [router.query.name, tabType]); useEffect(() => { - const query = router.query; - const updates: Partial = { - imageName: query.imageName as string, - replicas: query.replicas ? Number(query.replicas) : undefined, - cpu: query.cpu ? Number(query.cpu) : undefined, - memory: query.memory ? Number(query.memory) : undefined - }; + try { + const query = router.query as { formData?: string }; + if (!query.formData) return; + const parsedData: Partial = JSON.parse( + decodeURIComponent(query.formData) + ); + + const basicFields: (keyof AppEditSyncedFields)[] = [ + 'imageName', + 'replicas', + 'cpu', + 'memory', + 'cmdParam', + 'runCMD', + 'appName' + ]; - Object.entries(updates).forEach(([key, value]) => { - if (value !== undefined) { - formHook.setValue(key as keyof AppEditSyncedFields, value); + basicFields.forEach((field) => { + if (parsedData[field] !== undefined) { + formHook.setValue(field, parsedData[field] as any); + } + }); + + if (Array.isArray(parsedData.networks)) { + const completeNetworks = parsedData.networks.map((network) => ({ + networkName: network.networkName || `network-${nanoid()}`, + portName: network.portName || nanoid(), + port: network.port || 80, + protocol: network.protocol || 'HTTP', + openPublicDomain: network.openPublicDomain || false, + publicDomain: network.publicDomain || nanoid(), + customDomain: network.customDomain || '', + domain: network.domain || 'gzg.sealos.run' + })); + formHook.setValue('networks', completeNetworks); } - }); + } catch (error) {} }, []); return ( diff --git a/frontend/providers/applaunchpad/src/types/app.d.ts b/frontend/providers/applaunchpad/src/types/app.d.ts index 5b1cca0a953..952ea06bcb9 100644 --- a/frontend/providers/applaunchpad/src/types/app.d.ts +++ b/frontend/providers/applaunchpad/src/types/app.d.ts @@ -109,7 +109,10 @@ export interface AppEditType { }[]; } -export type AppEditSyncedFields = Pick; +export type AppEditSyncedFields = Pick< + AppEditType, + 'imageName' | 'replicas' | 'cpu' | 'memory' | 'networks' | 'cmdParam' | 'runCMD' | 'appName' +>; export type TAppSourceType = 'app_store' | 'sealaf';