diff --git a/frontend/providers/template/src/api/delete.ts b/frontend/providers/template/src/api/delete.ts index 81668d1b7cb..b4418ef0533 100644 --- a/frontend/providers/template/src/api/delete.ts +++ b/frontend/providers/template/src/api/delete.ts @@ -19,6 +19,9 @@ export const delDBByName = (instanceName: string) => export const delInstanceByName = (instanceName: string) => DELETE('/api/instance/deleteByName', { instanceName }); +export const delJobByName = (instanceName: string) => + DELETE('/api/resource/delJob', { instanceName }); + export const deleteResourceByKind = (instanceName: string, kind: ResourceKindType) => { switch (kind) { case 'CronJob': @@ -33,6 +36,8 @@ export const deleteResourceByKind = (instanceName: string, kind: ResourceKindTyp return delDBByName(instanceName); case 'Instance': return delInstanceByName(instanceName); + case 'Job': + return delJobByName(instanceName); default: throw new Error(`Unsupported kind: ${kind}`); } diff --git a/frontend/providers/template/src/api/platform.ts b/frontend/providers/template/src/api/platform.ts index c892adf7d4e..111298c5358 100644 --- a/frontend/providers/template/src/api/platform.ts +++ b/frontend/providers/template/src/api/platform.ts @@ -1,3 +1,6 @@ +import { EnvResponse } from '@/pages/api/platform/getEnv'; import { GET } from '@/services/request'; export const updateRepo = () => GET('/api/updateRepo'); + +export const getPlatformEnv = () => GET('/api/platform/getEnv'); diff --git a/frontend/providers/template/src/pages/api/platform/getEnv.ts b/frontend/providers/template/src/pages/api/platform/getEnv.ts index da61ab6ab63..7f3fa5b3008 100644 --- a/frontend/providers/template/src/pages/api/platform/getEnv.ts +++ b/frontend/providers/template/src/pages/api/platform/getEnv.ts @@ -4,6 +4,13 @@ import { jsonRes } from '@/services/backend/response'; import { ApiResp } from '@/services/kubernet'; import type { NextApiRequest, NextApiResponse } from 'next'; +export type EnvResponse = { + SEALOS_CLOUD_DOMAIN: string; + SEALOS_CERT_SECRET_NAME: string; + TEMPLATE_REPO_URL: string; + SEALOS_NAMESPACE: string; +}; + export default async function handler(req: NextApiRequest, res: NextApiResponse) { let user_namespace = ''; @@ -16,7 +23,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< console.log(error, 'errpr-'); } - jsonRes(res, { + jsonRes(res, { data: { SEALOS_CLOUD_DOMAIN: process.env.SEALOS_CLOUD_DOMAIN || 'cloud.sealos.io', SEALOS_CERT_SECRET_NAME: process.env.SEALOS_CERT_SECRET_NAME || 'wildcard-cert', diff --git a/frontend/providers/template/src/pages/api/resource/delJob.ts b/frontend/providers/template/src/pages/api/resource/delJob.ts new file mode 100644 index 00000000000..8429d117824 --- /dev/null +++ b/frontend/providers/template/src/pages/api/resource/delJob.ts @@ -0,0 +1,28 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { ApiResp } from '@/services/kubernet'; +import { authSession } from '@/services/backend/auth'; +import { getK8s } from '@/services/backend/kubernetes'; +import { jsonRes } from '@/services/backend/response'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { instanceName } = req.query as { instanceName: string }; + if (!instanceName) { + throw new Error('Job name is empty'); + } + + const { namespace, k8sBatch } = await getK8s({ + kubeconfig: await authSession(req.headers) + }); + + // 删除 Job + const result = await k8sBatch.deleteNamespacedJob(instanceName, namespace); + + jsonRes(res, { data: result }); + } catch (err: any) { + jsonRes(res, { + code: 500, + error: err + }); + } +} diff --git a/frontend/providers/template/src/pages/deploy/components/Header.tsx b/frontend/providers/template/src/pages/deploy/components/Header.tsx index 07d875dbd5f..639c371d7fc 100644 --- a/frontend/providers/template/src/pages/deploy/components/Header.tsx +++ b/frontend/providers/template/src/pages/deploy/components/Header.tsx @@ -4,7 +4,6 @@ import type { YamlItemType } from '@/types/index'; import { downLoadBold } from '@/utils/tools'; import { Box, Button, Flex, Image, Text } from '@chakra-ui/react'; import dayjs from 'dayjs'; -import JSZip from 'jszip'; import { useTranslation } from 'next-i18next'; import { MouseEvent, useCallback } from 'react'; diff --git a/frontend/providers/template/src/pages/deploy/index.tsx b/frontend/providers/template/src/pages/deploy/index.tsx index 395a5113e68..5f5c4f30d38 100644 --- a/frontend/providers/template/src/pages/deploy/index.tsx +++ b/frontend/providers/template/src/pages/deploy/index.tsx @@ -1,20 +1,20 @@ import { getTemplateSource, postDeployApp } from '@/api/app'; +import { getPlatformEnv } from '@/api/platform'; import { editModeMap } from '@/constants/editApp'; import { useConfirm } from '@/hooks/useConfirm'; import { useLoading } from '@/hooks/useLoading'; import { useToast } from '@/hooks/useToast'; -import { GET } from '@/services/request'; import { useCachedStore } from '@/store/cached'; import { useGlobalStore } from '@/store/global'; import type { QueryType, YamlItemType } from '@/types'; -import { TemplateInstanceType, TemplateSourceType } from '@/types/app'; +import { TemplateSourceType } from '@/types/app'; import { serviceSideProps } from '@/utils/i18n'; import { generateYamlList, parseTemplateString } from '@/utils/json-yaml'; -import { deepSearch } from '@/utils/tools'; +import { deepSearch, useCopyData } from '@/utils/tools'; import { Box, Flex, Icon, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; import JSYAML from 'js-yaml'; -import { cloneDeep, isEmpty, mapValues, reduce } from 'lodash'; +import { mapValues, reduce } from 'lodash'; import debounce from 'lodash/debounce'; import { useTranslation } from 'next-i18next'; import dynamic from 'next/dynamic'; @@ -22,20 +22,20 @@ import { useRouter } from 'next/router'; import { useEffect, useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; import Form from './components/Form'; -import Yaml from './components/Yaml'; import ReadMe from './components/ReadMe'; const ErrorModal = dynamic(() => import('./components/ErrorModal')); const Header = dynamic(() => import('./components/Header'), { ssr: false }); -export default function EditApp({ appName, tabType }: { appName?: string; tabType: string }) { +export default function EditApp({ appName }: { appName?: string }) { const { t, i18n } = useTranslation(); const { toast } = useToast(); const router = useRouter(); + const { copyData } = useCopyData(); const { templateName } = router.query as QueryType; const { Loading, setIsLoading } = useLoading(); const [forceUpdate, setForceUpdate] = useState(false); - const { title, applyBtnText, applyMessage, applySuccess, applyError } = editModeMap(!!appName); + const { title, applyBtnText, applyMessage, applySuccess, applyError } = editModeMap(false); const [templateSource, setTemplateSource] = useState(); const [yamlList, setYamlList] = useState([]); const [errorMessage, setErrorMessage] = useState(''); @@ -47,7 +47,7 @@ export default function EditApp({ appName, tabType }: { appName?: string; tabTyp [templateSource] ); - const { data: platformEnvs } = useQuery(['getPlatformEnvs'], () => GET('/api/platform/getEnv'), { + const { data: platformEnvs } = useQuery(['getPlatformEnvs'], getPlatformEnv, { staleTime: 5 * 60 * 1000 }); @@ -134,7 +134,7 @@ export default function EditApp({ appName, tabType }: { appName?: string; tabTyp setIsLoading(false); setCached(JSON.stringify({ ...formHook.getValues(), cachedKey: templateName })); const _name = encodeURIComponent(`?templateName=${templateName}&sealos_inside=true`); - const _domain = platformEnvs.SEALOS_CLOUD_DOMAIN; + const _domain = platformEnvs?.SEALOS_CLOUD_DOMAIN; const href = `https://${_domain}/?openapp=system-fastdeploy${_name}`; return window.open(href, '_self'); } @@ -149,14 +149,12 @@ export default function EditApp({ appName, tabType }: { appName?: string; tabTyp deleteCached(); - openConfirm2(() => { - router.push({ - pathname: '/instance', - query: { - instanceName: detailName - } - }); - })(); + router.push({ + pathname: '/instance', + query: { + instanceName: detailName + } + }); } catch (error) { setErrorMessage(JSON.stringify(error)); } @@ -231,6 +229,11 @@ export default function EditApp({ appName, tabType }: { appName?: string; tabTyp } ); + const copyTemplateLink = () => { + const str = `https://${platformEnvs?.SEALOS_CLOUD_DOMAIN}/?openapp=system-fastdeploy%3FtemplateName%3D${appName}`; + copyData(str); + }; + useEffect(() => { setInsideCloud(!(window.top === window)); @@ -297,6 +300,7 @@ export default function EditApp({ appName, tabType }: { appName?: string; tabTyp / {data?.templateYaml?.metadata?.name} @@ -312,7 +316,7 @@ export default function EditApp({ appName, tabType }: { appName?: string; tabTyp backgroundColor={'rgba(255, 255, 255, 0.90)'}>
GET('/api/platform/getEnv')); + const { data: platformEnvs } = useQuery(['getPlatformEnvs'], getPlatformEnv) as { + data: EnvResponse; + }; const onYamlChange = (value: string) => { setYamlValue(value); diff --git a/frontend/providers/template/src/pages/index.tsx b/frontend/providers/template/src/pages/index.tsx index 2e214e5f98e..ab826c6ff42 100644 --- a/frontend/providers/template/src/pages/index.tsx +++ b/frontend/providers/template/src/pages/index.tsx @@ -16,7 +16,6 @@ export default function AppList() { const { searchValue } = useSearchStore(); const { setInsideCloud, insideCloud } = useCachedStore(); - const { data: PlatformEnvs } = useQuery(['getPlatForm'], () => GET('/api/platform/getEnv')); const { data: FastDeployTemplates } = useQuery(['listTemplte'], () => GET('/api/listTemplate'), { refetchInterval: 5 * 60 * 1000, staleTime: 5 * 60 * 1000 @@ -42,7 +41,6 @@ export default function AppList() { router.push({ pathname: '/deploy', query: { - type: 'form', templateName: name } }); @@ -75,15 +73,13 @@ export default function AppList() { borderRadius={'12px'} background={'linear-gradient(180deg, #FFF 0%, rgba(255, 255, 255, 0.70) 100%)'} py={'36px'} - px="42px" - > + px="42px"> + minW={'765px'}> {filterData && filterData?.map((item: TemplateType) => { return ( @@ -103,8 +99,7 @@ export default function AppList() { borderRadius={'8px'} backgroundColor={'#fff'} boxShadow={'0px 2px 4px 0px rgba(187, 196, 206, 0.25)'} - border={'1px solid #EAEBF0'} - > + border={'1px solid #EAEBF0'}> + border={' 1px solid rgba(255, 255, 255, 0.50)'}> @@ -129,8 +123,7 @@ export default function AppList() { h={'28px'} borderRadius={'4px'} border={'1px solid #DEE0E2'} - backgroundColor={'#F4F6F8'} - > + backgroundColor={'#F4F6F8'}> Deploy @@ -146,8 +139,7 @@ export default function AppList() { mt={'8px'} fontSize={'12px'} color={'5A646E'} - fontWeight={400} - > + fontWeight={400}> {item?.spec?.description} @@ -163,8 +155,7 @@ export default function AppList() { fill="#5A646E" _hover={{ fill: '#0884DD' - }} - > + }}> diff --git a/frontend/providers/template/src/pages/instance/components/appList.tsx b/frontend/providers/template/src/pages/instance/components/appList.tsx index 9fa8d208b35..a6f41bbcf17 100644 --- a/frontend/providers/template/src/pages/instance/components/appList.tsx +++ b/frontend/providers/template/src/pages/instance/components/appList.tsx @@ -8,14 +8,12 @@ import { printMemory } from '@/utils/tools'; import { Box, Button, Flex, Icon, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; -import { useRouter } from 'next/router'; import { useCallback, useMemo } from 'react'; import { sealosApp } from 'sealos-desktop-sdk/app'; export default function AppList({ instanceName }: { instanceName: string }) { const { t } = useTranslation(); - const router = useRouter(); - const { resource, appendResource } = useResourceStore(); + const { appendResource } = useResourceStore(); const { data, isLoading } = useQuery( ['getAppLaunchpadByName', instanceName], @@ -32,14 +30,14 @@ export default function AppList({ instanceName }: { instanceName: string }) { } ); - const handleToDetailPage = useCallback(() => { + const handleToDetailPage = useCallback((name: string) => { sealosApp.runEvents('openDesktopApp', { appKey: 'system-applaunchpad', pathname: '/app/detail', - query: { name: instanceName }, + query: { name: name }, messageData: {} }); - }, [instanceName]); + }, []); const columns = useMemo< { @@ -114,8 +112,7 @@ export default function AppList({ instanceName }: { instanceName: string }) { variant={'base'} leftIcon={} px={3} - onClick={handleToDetailPage} - > + onClick={() => handleToDetailPage(item.name)}> {t('Details')} @@ -144,16 +141,14 @@ export default function AppList({ instanceName }: { instanceName: string }) { justifyContent={'center'} alignItems={'center'} background={'white'} - p="32px" - > + p="32px"> + alignItems={'center'}> diff --git a/frontend/providers/template/src/pages/instance/components/cronjobList.tsx b/frontend/providers/template/src/pages/instance/components/cronjobList.tsx index f7432b23bf8..724b5edd786 100644 --- a/frontend/providers/template/src/pages/instance/components/cronjobList.tsx +++ b/frontend/providers/template/src/pages/instance/components/cronjobList.tsx @@ -30,14 +30,14 @@ export default function CronJobList({ instanceName }: { instanceName: string }) } } ); - const handleToDetailPage = useCallback(() => { + const handleToDetailPage = useCallback((name: string) => { sealosApp.runEvents('openDesktopApp', { appKey: 'system-cronjob', pathname: '/job/detail', - query: { name: instanceName }, + query: { name: name }, messageData: {} }); - }, [instanceName]); + }, []); const columns = useMemo< { @@ -100,8 +100,7 @@ export default function CronJobList({ instanceName }: { instanceName: string }) variant={'base'} leftIcon={} px={3} - onClick={handleToDetailPage} - > + onClick={() => handleToDetailPage(item.name)}> {t('Details')} @@ -130,16 +129,14 @@ export default function CronJobList({ instanceName }: { instanceName: string }) justifyContent={'center'} alignItems={'center'} background={'white'} - p="32px" - > + p="32px"> + alignItems={'center'}> diff --git a/frontend/providers/template/src/pages/instance/components/dbList.tsx b/frontend/providers/template/src/pages/instance/components/dbList.tsx index 8ea2ce2f8c4..afd3a766da9 100644 --- a/frontend/providers/template/src/pages/instance/components/dbList.tsx +++ b/frontend/providers/template/src/pages/instance/components/dbList.tsx @@ -1,20 +1,18 @@ import { getDBListByName } from '@/api/instance'; -import StatusTag from '@/components/StatusTag'; import MyIcon from '@/components/Icon'; +import StatusTag from '@/components/StatusTag'; import MyTable from '@/components/Table'; +import { useResourceStore } from '@/store/resource'; import { DBListItemType } from '@/types/db'; +import { printMemory } from '@/utils/tools'; import { Box, Button, Flex, Icon, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; -import { useRouter } from 'next/router'; -import { useCallback, useMemo } from 'react'; -import { printMemory } from '@/utils/tools'; -import { useResourceStore } from '@/store/resource'; +import { useMemo } from 'react'; import { sealosApp } from 'sealos-desktop-sdk/app'; export default function AppList({ instanceName }: { instanceName: string }) { const { t } = useTranslation(); - const router = useRouter(); const { appendResource } = useResourceStore(); const { data } = useQuery( @@ -31,14 +29,14 @@ export default function AppList({ instanceName }: { instanceName: string }) { } ); - const handleToDetailPage = useCallback(() => { + const handleToDetailPage = (name: string) => { sealosApp.runEvents('openDesktopApp', { appKey: 'system-dbprovider', pathname: '/db/detail', - query: { name: instanceName }, + query: { name: name }, messageData: {} }); - }, [instanceName]); + }; const columns = useMemo< { @@ -100,15 +98,14 @@ export default function AppList({ instanceName }: { instanceName: string }) { variant={'base'} leftIcon={} px={3} - onClick={handleToDetailPage} - > + onClick={() => handleToDetailPage(item.name)}> {t('Details')} ) } ], - [handleToDetailPage, t] + [t] ); return ( @@ -132,16 +129,14 @@ export default function AppList({ instanceName }: { instanceName: string }) { justifyContent={'center'} alignItems={'center'} background={'white'} - p="32px" - > + p="32px"> + alignItems={'center'}> diff --git a/frontend/providers/template/src/pages/instance/components/delDodal.tsx b/frontend/providers/template/src/pages/instance/components/delDodal.tsx index c0c130d1bef..669832cf99e 100644 --- a/frontend/providers/template/src/pages/instance/components/delDodal.tsx +++ b/frontend/providers/template/src/pages/instance/components/delDodal.tsx @@ -49,7 +49,7 @@ const DelModal = ({ console.error(error); } setLoading(false); - }, [name, toast, t, onSuccess, onClose]); + }, [resource, toast, t, onSuccess, onClose]); return ( @@ -86,8 +86,7 @@ const DelModal = ({ variant={'solid'} isDisabled={inputValue !== name} isLoading={loading} - onClick={handleDelApp} - > + onClick={handleDelApp}> {t('Confirm deletion')} diff --git a/frontend/providers/template/src/pages/instance/components/otherList.tsx b/frontend/providers/template/src/pages/instance/components/otherList.tsx index 191b351e505..14b1a230521 100644 --- a/frontend/providers/template/src/pages/instance/components/otherList.tsx +++ b/frontend/providers/template/src/pages/instance/components/otherList.tsx @@ -19,7 +19,7 @@ export default function OtherList({ instanceName }: { instanceName: string }) { onSuccess(data) { appendResource( data.map((item) => { - return { id: item.id, name: item.name, kind: item.kind || 'other' }; + return { id: item.id, name: item.name, kind: item.kind }; }) ); } @@ -81,16 +81,14 @@ export default function OtherList({ instanceName }: { instanceName: string }) { justifyContent={'center'} alignItems={'center'} background={'white'} - p="32px" - > + p="32px"> + alignItems={'center'}> diff --git a/frontend/providers/template/src/pages/instance/index.tsx b/frontend/providers/template/src/pages/instance/index.tsx index 042b55fb3aa..2e429aba6a9 100644 --- a/frontend/providers/template/src/pages/instance/index.tsx +++ b/frontend/providers/template/src/pages/instance/index.tsx @@ -1,18 +1,16 @@ -import { getInstanceByName } from '@/api/instance'; +import { useResourceStore } from '@/store/resource'; import { serviceSideProps } from '@/utils/i18n'; -import { Box, Flex, Icon, Text } from '@chakra-ui/react'; -import { useQuery } from '@tanstack/react-query'; +import { Box, Flex } from '@chakra-ui/react'; +import { useEffect } from 'react'; import AppList from './components/appList'; -import Header from './components/header'; -import DBList from './components/dbList'; import CronJobList from './components/cronjobList'; +import DBList from './components/dbList'; +import Header from './components/header'; import OtherList from './components/otherList'; -import { useResourceStore } from '@/store/resource'; -import { useEffect } from 'react'; export default function MyApp({ instanceName }: { instanceName: string }) { const { resource, setInstanceName } = useResourceStore(); - console.log(resource); + console.log(resource, 'resource'); useEffect(() => { setInstanceName(instanceName); diff --git a/frontend/providers/template/src/services/backend/response.ts b/frontend/providers/template/src/services/backend/response.ts index 20355c0509a..dd675391fd6 100644 --- a/frontend/providers/template/src/services/backend/response.ts +++ b/frontend/providers/template/src/services/backend/response.ts @@ -1,12 +1,12 @@ import { NextApiResponse } from 'next'; import { ERROR_TEXT, ERROR_RESPONSE } from '../error'; -export const jsonRes = ( +export const jsonRes = ( res: NextApiResponse, props?: { code?: number; message?: string; - data?: any; + data?: T; error?: any; } ) => {