diff --git a/frontend/providers/applaunchpad/public/locales/en/common.json b/frontend/providers/applaunchpad/public/locales/en/common.json index 57396db55da..8cb013d4582 100644 --- a/frontend/providers/applaunchpad/public/locales/en/common.json +++ b/frontend/providers/applaunchpad/public/locales/en/common.json @@ -159,5 +159,7 @@ "common": { "Used": "Used", "Surplus": "Surplus" - } + }, + "Store At Least One": "Store At Least One", + "Network port conflict": "Network port conflict" } diff --git a/frontend/providers/applaunchpad/public/locales/zh/common.json b/frontend/providers/applaunchpad/public/locales/zh/common.json index f8415242cc4..0f1c1dfd0e7 100644 --- a/frontend/providers/applaunchpad/public/locales/zh/common.json +++ b/frontend/providers/applaunchpad/public/locales/zh/common.json @@ -202,5 +202,6 @@ }, "user": { "Insufficient account balance": "账号余额不足~" - } + }, + "Store At Least One": "存储最少保留一个" } diff --git a/frontend/providers/applaunchpad/src/components/Icon/icons/detail.svg b/frontend/providers/applaunchpad/src/components/Icon/icons/detail.svg index 951e9eb6cbb..e4c6fa97280 100644 --- a/frontend/providers/applaunchpad/src/components/Icon/icons/detail.svg +++ b/frontend/providers/applaunchpad/src/components/Icon/icons/detail.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/frontend/providers/applaunchpad/src/components/Icon/icons/log.svg b/frontend/providers/applaunchpad/src/components/Icon/icons/log.svg index 9140c6fb531..364239937be 100644 --- a/frontend/providers/applaunchpad/src/components/Icon/icons/log.svg +++ b/frontend/providers/applaunchpad/src/components/Icon/icons/log.svg @@ -1,6 +1,4 @@ - - - - \ No newline at end of file + + + + diff --git a/frontend/providers/applaunchpad/src/components/Icon/icons/restart.svg b/frontend/providers/applaunchpad/src/components/Icon/icons/restart.svg index de42eb25696..69676a80067 100644 --- a/frontend/providers/applaunchpad/src/components/Icon/icons/restart.svg +++ b/frontend/providers/applaunchpad/src/components/Icon/icons/restart.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/frontend/providers/applaunchpad/src/components/Icon/icons/terminal.svg b/frontend/providers/applaunchpad/src/components/Icon/icons/terminal.svg index db9147be96f..8df6de88aa3 100644 --- a/frontend/providers/applaunchpad/src/components/Icon/icons/terminal.svg +++ b/frontend/providers/applaunchpad/src/components/Icon/icons/terminal.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/Header.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/Header.tsx index bf8945ecabb..a8b0c247b63 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/Header.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/Header.tsx @@ -117,7 +117,7 @@ const Header = ({ flex={1} h={'40px'} borderColor={'myGray.200'} - leftIcon={} + leftIcon={} variant={'base'} bg={'white'} onClick={() => setShowSlider(true)} @@ -180,7 +180,7 @@ const Header = ({ borderColor={'myGray.200'} variant={'base'} bg={'white'} - leftIcon={} + leftIcon={} onClick={openRestartConfirm(handleRestartApp)} isLoading={loading} > diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/PodDetailModal.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/PodDetailModal.tsx index eb501692a62..488a8ebf8a0 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/PodDetailModal.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/PodDetailModal.tsx @@ -99,7 +99,7 @@ const Logs = ({ ); }, []); - const { isLoading } = useQuery(['init'], () => getPodEvents(pod.podName), { + const { isLoading } = useQuery(['initPodEvents'], () => getPodEvents(pod.podName), { refetchInterval: 3000, onSuccess(res) { setEvents(res); diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/Pods.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/Pods.tsx index b2014c9ff1d..1e321823a61 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/Pods.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/Pods.tsx @@ -10,7 +10,9 @@ import { Td, TableContainer, Flex, - MenuButton + MenuButton, + Tooltip, + Center } from '@chakra-ui/react'; import { sealosApp } from 'sealos-desktop-sdk/app'; import { restartPodByName } from '@/api/app'; @@ -135,70 +137,68 @@ const Pods = ({ title: 'Operation', key: 'control', render: (item: PodDetailType, i: number) => ( - - - - - - } - menuList={[ - { - child: ( - <> - - {t('Terminal')} - - ), - onClick: () => { - const defaultCommand = `kubectl exec -it ${item.podName} -c ${appName} -- sh -c "clear; (bash || ash || sh)"`; - sealosApp.runEvents('openDesktopApp', { - appKey: 'system-terminal', - query: { - defaultCommand - }, - messageData: { type: 'new terminal', command: defaultCommand } - }); - } - }, - { - child: ( - <> - - {t('Details')} - - ), - onClick: () => setDetailPodIndex(i) - }, - { - child: ( - <> - - {t('Restart')} - - ), - onClick: openConfirmRestart(() => handleRestartPod(item.podName)) - } - ]} - /> + + +
setLogsPodIndex(i)} + > + +
+
+ +
{ + const defaultCommand = `kubectl exec -it ${item.podName} -c ${appName} -- sh -c "clear; (bash || ash || sh)"`; + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-terminal', + query: { + defaultCommand + }, + messageData: { type: 'new terminal', command: defaultCommand } + }); + }} + > + +
+
+ +
setDetailPodIndex(i)} + > + +
+
+ +
handleRestartPod(item.podName))} + > + +
+
) } 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 5744b3eae61..d405aafc1d8 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx @@ -56,6 +56,7 @@ import { obj2Query } from '@/api/tools'; import { throttle } from 'lodash'; import { ProtocolList, noGpuSliderKey } from '@/constants/app'; import { sliderNumber2MarkList } from '@/utils/adapt'; +import { useToast } from '@/hooks/useToast'; const labelWidth = 120; @@ -79,6 +80,7 @@ const Form = ({ const { formSliderListConfig } = useGlobalStore(); const { userSourcePrice } = useUserStore(); const router = useRouter(); + const { toast } = useToast(); const { name } = router.query as QueryType; const theme = useTheme(); const isEdit = useMemo(() => !!name, [name]); @@ -1101,7 +1103,16 @@ const Form = ({ className={styles.deleteIcon} ml={3} cursor={'pointer'} - onClick={() => removeStoreList(index)} + onClick={() => { + if (storeList.length === 1) { + toast({ + title: t('Store At Least One'), + status: 'error' + }); + } else { + removeStoreList(index); + } + }} > diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx index 48ec6e20f03..5e2c15f634a 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx @@ -26,14 +26,18 @@ import Form from './components/Form'; import Yaml from './components/Yaml'; import dynamic from 'next/dynamic'; import { serviceSideProps } from '@/utils/i18n'; -import { getErrText, patchYamlList } from '@/utils/tools'; +import { getErrText, patchYamlListV1, patchYamlList } from '@/utils/tools'; import { useTranslation } from 'next-i18next'; import { noGpuSliderKey } from '@/constants/app'; import { useUserStore } from '@/store/user'; const ErrorModal = dynamic(() => import('./components/ErrorModal')); -export const formData2Yamls = (data: AppEditType) => [ +export const formData2Yamls = ( + data: AppEditType, + handleType: 'edit' | 'create' = 'create', + crYamlList?: DeployKindsType[] +) => [ { filename: 'service.yaml', value: json2Service(data) @@ -41,11 +45,11 @@ export const formData2Yamls = (data: AppEditType) => [ !!data.storeList?.length ? { filename: 'statefulSet.yaml', - value: json2DeployCr(data, 'statefulset') + value: json2DeployCr(data, 'statefulset', handleType, crYamlList) } : { filename: 'deployment.yaml', - value: json2DeployCr(data, 'deployment') + value: json2DeployCr(data, 'deployment', handleType, crYamlList) }, ...(data.configMapList.length > 0 ? [ @@ -83,7 +87,7 @@ export const formData2Yamls = (data: AppEditType) => [ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => { const { t } = useTranslation(); - const formOldYamls = useRef([]); + const crOldYamls = useRef([]); const oldAppEditData = useRef(); @@ -150,12 +154,10 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => const yamls = yamlList.map((item) => item.value); if (appName) { - const patch = patchYamlList({ - formOldYamlList: formOldYamls.current.map((item) => item.value), - crYamlList: crOldYamls.current, + const patch = patchYamlListV1({ + oldYamlList: crOldYamls.current, newYamlList: yamls }); - console.log(patch); await putApp({ patch, @@ -213,7 +215,7 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => }, [formHook.formState.errors, t, toast]); useQuery( - ['init'], + ['initLaunchpadApp'], () => { if (!appName) { const defaultApp = { @@ -242,7 +244,7 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => onSuccess(res) { if (!res) return; oldAppEditData.current = res; - formOldYamls.current = formData2Yamls(res); + crOldYamls.current = res.crYamlList; setDefaultStorePathList(res.storeList.map((item) => item.path)); @@ -265,10 +267,16 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => useEffect(() => { if (tabType === 'yaml') { try { - setYamlList(formData2Yamls(realTimeForm.current)); + setYamlList( + formData2Yamls( + realTimeForm.current, + appName !== '' ? 'edit' : 'create', + crOldYamls.current + ) + ); } catch (error) {} } - }, [router.query.name, tabType]); + }, [appName, router.query.name, tabType]); return ( <> @@ -286,7 +294,11 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => applyBtnText={applyBtnText} applyCb={() => formHook.handleSubmit((data) => { - const parseYamls = formData2Yamls(data); + const parseYamls = formData2Yamls( + data, + appName !== '' ? 'edit' : 'create', + crOldYamls.current + ); setYamlList(parseYamls); // balance check if (balance <= 0) { diff --git a/frontend/providers/applaunchpad/src/pages/apps/components/appList.tsx b/frontend/providers/applaunchpad/src/pages/apps/components/appList.tsx index bf9abf08969..42e84e27f30 100644 --- a/frontend/providers/applaunchpad/src/pages/apps/components/appList.tsx +++ b/frontend/providers/applaunchpad/src/pages/apps/components/appList.tsx @@ -195,7 +195,7 @@ const AppList = ({