From 21e0b3628310daaaa3a2028d7577d450705a19d7 Mon Sep 17 00:00:00 2001 From: Alex Lee <3076438032@qq.com> Date: Mon, 13 Jan 2025 15:21:34 +0800 Subject: [PATCH] fix: devbox list big counts bug (#5341) * fix: adjust prettier * fix: bug --- frontend/providers/devbox/.prettierrc.js | 20 +++ frontend/providers/devbox/.prettierrc.json | 18 -- .../(home)/components/DevboxList.tsx | 157 ++++++++-------- .../devbox/components/AdvancedTable.tsx | 76 ++++++++ frontend/providers/devbox/stores/devbox.ts | 167 +++++++++--------- 5 files changed, 264 insertions(+), 174 deletions(-) create mode 100644 frontend/providers/devbox/.prettierrc.js delete mode 100644 frontend/providers/devbox/.prettierrc.json create mode 100644 frontend/providers/devbox/components/AdvancedTable.tsx diff --git a/frontend/providers/devbox/.prettierrc.js b/frontend/providers/devbox/.prettierrc.js new file mode 100644 index 00000000000..b48f2c3caef --- /dev/null +++ b/frontend/providers/devbox/.prettierrc.js @@ -0,0 +1,20 @@ +module.exports = { + printWidth: 100, + tabWidth: 2, + useTabs: false, + semi: true, + singleQuote: true, + quoteProps: 'as-needed', + jsxSingleQuote: false, + trailingComma: 'none', + bracketSpacing: true, + jsxBracketSameLine: false, + arrowParens: 'always', + rangeStart: 0, + rangeEnd: Infinity, + requirePragma: false, + insertPragma: false, + proseWrap: 'preserve', + htmlWhitespaceSensitivity: 'css', + endOfLine: 'lf' +} diff --git a/frontend/providers/devbox/.prettierrc.json b/frontend/providers/devbox/.prettierrc.json deleted file mode 100644 index c3bc434d271..00000000000 --- a/frontend/providers/devbox/.prettierrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "printWidth": 100, - "tabWidth": 2, - "useTabs": false, - "semi": false, - "singleQuote": true, - "quoteProps": "as-needed", - "trailingComma": "none", - "bracketSpacing": true, - "jsxBracketSameLine": true, - "bracketSameLine": true, - "arrowParens": "always", - "requirePragma": false, - "insertPragma": false, - "proseWrap": "preserve", - "htmlWhitespaceSensitivity": "ignore", - "endOfLine": "auto" -} diff --git a/frontend/providers/devbox/app/[lang]/(platform)/(home)/components/DevboxList.tsx b/frontend/providers/devbox/app/[lang]/(platform)/(home)/components/DevboxList.tsx index 0264056cc81..7c0ff942e5b 100644 --- a/frontend/providers/devbox/app/[lang]/(platform)/(home)/components/DevboxList.tsx +++ b/frontend/providers/devbox/app/[lang]/(platform)/(home)/components/DevboxList.tsx @@ -1,113 +1,117 @@ -import { Box, Button, Flex, Image, MenuButton, Text } from '@chakra-ui/react' -import { MyTable, SealosMenu, useMessage } from '@sealos/ui' -import { useTranslations } from 'next-intl' -import dynamic from 'next/dynamic' -import { useCallback, useState } from 'react' -import { sealosApp } from 'sealos-desktop-sdk/app' +import { Box, Button, Flex, Image, MenuButton, Text } from '@chakra-ui/react'; +import { SealosMenu, useMessage } from '@sealos/ui'; +import { useTranslations } from 'next-intl'; +import dynamic from 'next/dynamic'; +import { useCallback, useState } from 'react'; +import { sealosApp } from 'sealos-desktop-sdk/app'; -import { pauseDevbox, restartDevbox, startDevbox } from '@/api/devbox' -import { useRouter } from '@/i18n' -import { useGlobalStore } from '@/stores/global' -import { DevboxListItemTypeV2 } from '@/types/devbox' +import { pauseDevbox, restartDevbox, startDevbox } from '@/api/devbox'; +import { useRouter } from '@/i18n'; +import { useGlobalStore } from '@/stores/global'; +import { DevboxListItemTypeV2 } from '@/types/devbox'; -import DevboxStatusTag from '@/components/DevboxStatusTag' -import MyIcon from '@/components/Icon' -import IDEButton from '@/components/IDEButton' -import ReleaseModal from '@/components/modals/releaseModal' -import PodLineChart from '@/components/PodLineChart' +import DevboxStatusTag from '@/components/DevboxStatusTag'; +import MyIcon from '@/components/Icon'; +import IDEButton from '@/components/IDEButton'; +import ReleaseModal from '@/components/modals/releaseModal'; +import PodLineChart from '@/components/PodLineChart'; +import { AdvancedTable } from '@/components/AdvancedTable'; -const DelModal = dynamic(() => import('@/components/modals/DelModal')) +const DelModal = dynamic(() => import('@/components/modals/DelModal')); const DevboxList = ({ devboxList = [], refetchDevboxList }: { - devboxList: DevboxListItemTypeV2[] - refetchDevboxList: () => void + devboxList: DevboxListItemTypeV2[]; + refetchDevboxList: () => void; }) => { - const router = useRouter() - const t = useTranslations() - const { message: toast } = useMessage() + const router = useRouter(); + const t = useTranslations(); + const { message: toast } = useMessage(); + const duplicatedDevboxList = Array(20) + .fill(0) + .flatMap(() => [...devboxList]); // TODO: Unified Loading Behavior - const { setLoading } = useGlobalStore() + const { setLoading } = useGlobalStore(); - const [onOpenRelease, setOnOpenRelease] = useState(false) - const [delDevbox, setDelDevbox] = useState(null) + const [onOpenRelease, setOnOpenRelease] = useState(false); + const [delDevbox, setDelDevbox] = useState(null); const [currentDevboxListItem, setCurrentDevboxListItem] = useState( null - ) + ); const handleOpenRelease = (devbox: DevboxListItemTypeV2) => { - setCurrentDevboxListItem(devbox) - setOnOpenRelease(true) - } + setCurrentDevboxListItem(devbox); + setOnOpenRelease(true); + }; const handlePauseDevbox = useCallback( async (devbox: DevboxListItemTypeV2) => { try { - setLoading(true) - await pauseDevbox({ devboxName: devbox.name }) + setLoading(true); + await pauseDevbox({ devboxName: devbox.name }); toast({ title: t('pause_success'), status: 'success' - }) + }); } catch (error: any) { toast({ title: typeof error === 'string' ? error : error.message || t('pause_error'), status: 'error' - }) - console.error(error) + }); + console.error(error); } - refetchDevboxList() - setLoading(false) + refetchDevboxList(); + setLoading(false); }, [refetchDevboxList, setLoading, t, toast] - ) + ); const handleRestartDevbox = useCallback( async (devbox: DevboxListItemTypeV2) => { try { - setLoading(true) - await restartDevbox({ devboxName: devbox.name }) + setLoading(true); + await restartDevbox({ devboxName: devbox.name }); toast({ title: t('restart_success'), status: 'success' - }) + }); } catch (error: any) { toast({ title: typeof error === 'string' ? error : error.message || t('restart_error'), status: 'error' - }) - console.error(error, '==') + }); + console.error(error, '=='); } - refetchDevboxList() - setLoading(false) + refetchDevboxList(); + setLoading(false); }, [refetchDevboxList, setLoading, t, toast] - ) + ); const handleStartDevbox = useCallback( async (devbox: DevboxListItemTypeV2) => { try { - setLoading(true) - await startDevbox({ devboxName: devbox.name }) + setLoading(true); + await startDevbox({ devboxName: devbox.name }); toast({ title: t('start_success'), status: 'success' - }) + }); } catch (error: any) { toast({ title: typeof error === 'string' ? error : error.message || t('start_error'), status: 'error' - }) - console.error(error, '==') + }); + console.error(error, '=='); } - refetchDevboxList() - setLoading(false) + refetchDevboxList(); + setLoading(false); }, [refetchDevboxList, setLoading, t, toast] - ) + ); const handleGoToTerminal = useCallback( async (devbox: DevboxListItemTypeV2) => { - const defaultCommand = `kubectl exec -it $(kubectl get po -l app.kubernetes.io/name=${devbox.name} -oname) -- sh -c "clear; (bash || ash || sh)"` + const defaultCommand = `kubectl exec -it $(kubectl get po -l app.kubernetes.io/name=${devbox.name} -oname) -- sh -c "clear; (bash || ash || sh)"`; try { sealosApp.runEvents('openDesktopApp', { appKey: 'system-terminal', @@ -115,22 +119,22 @@ const DevboxList = ({ defaultCommand }, messageData: { type: 'new terminal', command: defaultCommand } - }) + }); } catch (error: any) { toast({ title: typeof error === 'string' ? error : error.message || t('jump_terminal_error'), status: 'error' - }) - console.error(error) + }); + console.error(error); } }, [t, toast] - ) + ); const columns: { - title: string - dataIndex?: keyof DevboxListItemTypeV2 - key: string - render?: (item: DevboxListItemTypeV2) => JSX.Element + title: string; + dataIndex?: keyof DevboxListItemTypeV2; + key: string; + render?: (item: DevboxListItemTypeV2) => JSX.Element; }[] = [ { title: t('name'), @@ -148,7 +152,7 @@ const DevboxList = ({ {item.name} - ) + ); } }, { @@ -161,7 +165,7 @@ const DevboxList = ({ dataIndex: 'createTime', key: 'createTime', render: (item) => { - return {item.createTime} + return {item.createTime}; } }, { @@ -179,7 +183,8 @@ const DevboxList = ({ right={'4px'} bottom={'0px'} pointerEvents={'none'} - textShadow="1px 1px 0 #FFF, -1px -1px 0 #FFF, 1px -1px 0 #FFF, -1px 1px 0 #FFF"> + textShadow="1px 1px 0 #FFF, -1px -1px 0 #FFF, 1px -1px 0 #FFF, -1px 1px 0 #FFF" + > {item?.usedCpu?.yData[item?.usedCpu?.yData?.length - 1]}% @@ -201,7 +206,8 @@ const DevboxList = ({ right={'4px'} bottom={'0px'} pointerEvents={'none'} - textShadow="1px 1px 0 #FFF, -1px -1px 0 #FFF, 1px -1px 0 #FFF, -1px 1px 0 #FFF"> + textShadow="1px 1px 0 #FFF, -1px -1px 0 #FFF, 1px -1px 0 #FFF, -1px 1px 0 #FFF" + > {item?.usedMemory?.yData[item?.usedMemory?.yData?.length - 1]}% @@ -232,8 +238,9 @@ const DevboxList = ({ minW={'unset'} // leftIcon={} onClick={() => { - router.push(`/devbox/detail/${item.name}`) - }}> + router.push(`/devbox/detail/${item.name}`); + }} + > {/* {t('detail')} */} @@ -337,10 +344,10 @@ const DevboxList = ({ ) } - ] + ]; return ( <> - + {!!delDevbox && ( { - router.push(`/devbox/detail/${currentDevboxListItem?.name}`) + router.push(`/devbox/detail/${currentDevboxListItem?.name}`); }} onClose={() => { - setOnOpenRelease(false) - setCurrentDevboxListItem(null) + setOnOpenRelease(false); + setCurrentDevboxListItem(null); }} devbox={currentDevboxListItem} /> )} - ) -} + ); +}; -export default DevboxList +export default DevboxList; diff --git a/frontend/providers/devbox/components/AdvancedTable.tsx b/frontend/providers/devbox/components/AdvancedTable.tsx new file mode 100644 index 00000000000..401d677a628 --- /dev/null +++ b/frontend/providers/devbox/components/AdvancedTable.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { Box, BoxProps, Grid, Flex } from '@chakra-ui/react'; + +interface Props extends BoxProps { + columns: { + title: string; + dataIndex?: string; + key: string; + render?: (item: any) => JSX.Element; + }[]; + data: any[]; + itemClass?: string; +} + +export const AdvancedTable = ({ columns, data, itemClass = '' }: Props) => { + return ( + <> + + {columns.map((item, i) => ( + + {item.title} + + ))} + + {data.map((item: any, index1) => ( + + {columns.map((col, index2) => ( + + {col.render ? col.render(item) : col.dataIndex ? `${item[col.dataIndex]}` : ''} + + ))} + + ))} + + ); +}; diff --git a/frontend/providers/devbox/stores/devbox.ts b/frontend/providers/devbox/stores/devbox.ts index 6618dbb04b8..30690a18bb9 100644 --- a/frontend/providers/devbox/stores/devbox.ts +++ b/frontend/providers/devbox/stores/devbox.ts @@ -1,6 +1,6 @@ -import { create } from 'zustand' -import { devtools } from 'zustand/middleware' -import { immer } from 'zustand/middleware/immer' +import { create } from 'zustand'; +import { devtools } from 'zustand/middleware'; +import { immer } from 'zustand/middleware/immer'; import { getDevboxByName, @@ -9,40 +9,44 @@ import { getDevboxVersionList, getMyDevboxList, getSSHConnectionInfo -} from '@/api/devbox' -import { devboxStatusMap, PodStatusEnum } from '@/constants/devbox' +} from '@/api/devbox'; +import { devboxStatusMap, PodStatusEnum } from '@/constants/devbox'; import type { DevboxDetailType, DevboxDetailTypeV2, DevboxListItemTypeV2, DevboxVersionListItemType -} from '@/types/devbox' +} from '@/types/devbox'; type State = { - devboxList: DevboxListItemTypeV2[] - requestCache: Map> - setDevboxList: () => Promise - loadAvgMonitorData: (devboxName: string) => Promise - devboxVersionList: DevboxVersionListItemType[] + devboxList: DevboxListItemTypeV2[]; + requestCache: Map>; + setDevboxList: () => Promise; + loadAvgMonitorData: (devboxName: string) => Promise; + devboxVersionList: DevboxVersionListItemType[]; startedTemplate?: { - uid: string, - iconId: string | null, - name: string, - } - setStartedTemplate: (template: { - uid: string, - iconId: string | null, - name: string, - } | undefined) => void, + uid: string; + iconId: string | null; + name: string; + }; + setStartedTemplate: ( + template: + | { + uid: string; + iconId: string | null; + name: string; + } + | undefined + ) => void; setDevboxVersionList: ( devboxName: string, devboxUid: string - ) => Promise - devboxDetail?: DevboxDetailTypeV2 - setDevboxDetail: (devboxName: string, sealosDomain: string) => Promise - intervalLoadPods: (devboxName: string, updateDetail: boolean) => Promise - loadDetailMonitorData: (devboxName: string) => Promise -} + ) => Promise; + devboxDetail?: DevboxDetailTypeV2; + setDevboxDetail: (devboxName: string, sealosDomain: string) => Promise; + intervalLoadPods: (devboxName: string, updateDetail: boolean) => Promise; + loadDetailMonitorData: (devboxName: string) => Promise; +}; export const useDevboxStore = create()( devtools( @@ -50,15 +54,15 @@ export const useDevboxStore = create()( devboxList: [], requestCache: new Map(), setDevboxList: async () => { - const res = await getMyDevboxList() + const res = await getMyDevboxList(); set((state) => { - state.devboxList = res - }) - return res + state.devboxList = res; + }); + return res; }, loadAvgMonitorData: async (devboxName) => { - const pods = await getDevboxPodsByDevboxName(devboxName) - const queryName = pods.length > 0 ? pods[0].podName : devboxName + const pods = await getDevboxPodsByDevboxName(devboxName); + const queryName = pods.length > 0 ? pods[0].podName : devboxName; const [averageCpuData, averageMemoryData] = await Promise.all([ getDevboxMonitorData({ @@ -71,7 +75,7 @@ export const useDevboxStore = create()( queryName: queryName, step: '2m' }) - ]) + ]); set((state) => { state.devboxList = state.devboxList.map((item) => ({ ...item, @@ -81,69 +85,70 @@ export const useDevboxStore = create()( item.name === devboxName && averageMemoryData[0] ? averageMemoryData[0] : item.usedMemory - })) - }) + })); + }); }, devboxVersionList: [], setDevboxVersionList: async (devboxName, devboxUid) => { - const res = await getDevboxVersionList(devboxName, devboxUid) + const res = await getDevboxVersionList(devboxName, devboxUid); set((state) => { - state.devboxVersionList = res - }) - return res + state.devboxVersionList = res; + }); + return res; }, setStartedTemplate(templateRepository) { set((state) => { - if(!templateRepository) state.startedTemplate = undefined - else state.startedTemplate = { - uid: templateRepository.uid, - iconId: templateRepository.iconId, - name: templateRepository.name - } - }) + if (!templateRepository) state.startedTemplate = undefined; + else + state.startedTemplate = { + uid: templateRepository.uid, + iconId: templateRepository.iconId, + name: templateRepository.name + }; + }); }, startedTemplate: undefined, devboxDetail: undefined, setDevboxDetail: async (devboxName: string, sealosDomain: string) => { - const detail = await getDevboxByName(devboxName) + const detail = await getDevboxByName(devboxName); if (detail.status.value !== 'Running') { set((state) => { - state.devboxDetail = detail - }) - return detail + state.devboxDetail = detail; + }); + return detail; } - const pods = await getDevboxPodsByDevboxName(devboxName) + const pods = await getDevboxPodsByDevboxName(devboxName); const { base64PrivateKey, userName } = await getSSHConnectionInfo({ devboxName: detail.name - }) + }); - const sshPrivateKey = Buffer.from(base64PrivateKey, 'base64').toString('utf-8') + const sshPrivateKey = Buffer.from(base64PrivateKey, 'base64').toString('utf-8'); const sshConfig = { sshUser: userName, sshDomain: sealosDomain, sshPort: detail.sshPort, sshPrivateKey - } + }; // add sshConfig - detail.sshConfig = sshConfig as DevboxDetailType['sshConfig'] + detail.sshConfig = sshConfig as DevboxDetailType['sshConfig']; // add upTime by Pod - detail.upTime = pods[0].upTime + detail.upTime = pods[0].upTime; set((state) => { - state.devboxDetail = detail - }) + state.devboxDetail = detail; + }); - return detail + return detail; }, intervalLoadPods: async (devboxName, updateDetail) => { - if (!devboxName) return Promise.reject('devbox name is empty') + if (!devboxName) return Promise.reject('devbox name is empty'); - const pods = await getDevboxPodsByDevboxName(devboxName) + const pods = await getDevboxPodsByDevboxName(devboxName); // TODO: change Running to podStatusMap.running // TODO: check status enum and backend status enum @@ -151,24 +156,24 @@ export const useDevboxStore = create()( pods.length === 0 ? devboxStatusMap.Stopped : pods.filter((pod) => pod.status.value === PodStatusEnum.running).length > 0 - ? devboxStatusMap.Running - : devboxStatusMap.Pending + ? devboxStatusMap.Running + : devboxStatusMap.Pending; set((state) => { if (state?.devboxDetail?.name === devboxName && updateDetail) { - state.devboxDetail.status = devboxStatus + state.devboxDetail.status = devboxStatus; } state.devboxList = state.devboxList.map((item) => ({ ...item, status: item.name === devboxName ? devboxStatus : item.status - })) - }) - return 'success' + })); + }); + return 'success'; }, loadDetailMonitorData: async (devboxName) => { - const pods = await getDevboxPodsByDevboxName(devboxName) + const pods = await getDevboxPodsByDevboxName(devboxName); - const queryName = pods.length > 0 ? pods[0].podName : devboxName + const queryName = pods.length > 0 ? pods[0].podName : devboxName; const [averageCpuData, averageMemoryData] = await Promise.all([ getDevboxMonitorData({ @@ -181,28 +186,28 @@ export const useDevboxStore = create()( queryName: queryName, step: '2m' }) - ]) + ]); set((state) => { if (state?.devboxDetail?.name === devboxName && state.devboxDetail?.isPause !== true) { state.devboxDetail.usedCpu = averageCpuData[0] ? averageCpuData[0] : { - xData: new Array(30).fill(0), - yData: new Array(30).fill('0'), - name: '' - } + xData: new Array(30).fill(0), + yData: new Array(30).fill('0'), + name: '' + }; state.devboxDetail.usedMemory = averageMemoryData[0] ? averageMemoryData[0] : { - xData: new Array(30).fill(0), - yData: new Array(30).fill('0'), - name: '' - } + xData: new Array(30).fill(0), + yData: new Array(30).fill('0'), + name: '' + }; } - }) - return 'success' + }); + return 'success'; } })) ) -) +);