diff --git a/frontend/desktop/public/locales/en/common.json b/frontend/desktop/public/locales/en/common.json index 35ebe0c1266..5fe9581fb20 100644 --- a/frontend/desktop/public/locales/en/common.json +++ b/frontend/desktop/public/locales/en/common.json @@ -116,5 +116,6 @@ "Click on any shadow to skip": "Click on any shadow to skip", "Start your Sealos journey": "Start your Sealos journey", "gift amount": "Reward {{amount}} balance.", - "Recharge Amount": "Recharge Amount" + "Recharge Amount": "Recharge Amount", + "Doc": "Doc" } diff --git a/frontend/desktop/public/locales/zh/common.json b/frontend/desktop/public/locales/zh/common.json index 5c2bd7082a8..666549c0703 100644 --- a/frontend/desktop/public/locales/zh/common.json +++ b/frontend/desktop/public/locales/zh/common.json @@ -109,5 +109,6 @@ "start immediately": "立即开始", "Click on any shadow to skip": "点击任意阴影跳过", "Start your Sealos journey": "开始您的 Sealos 之旅", - "gift amount": "赠送 {{amount}} 余额." -} \ No newline at end of file + "gift amount": "赠送 {{amount}} 余额.", + "Doc": "文档" +} diff --git a/frontend/desktop/src/components/account/index.tsx b/frontend/desktop/src/components/account/index.tsx index 3f0962bf627..56532e0696c 100644 --- a/frontend/desktop/src/components/account/index.tsx +++ b/frontend/desktop/src/components/account/index.tsx @@ -100,7 +100,7 @@ const NsMenu = () => { w="250px" background="linear-gradient(270deg, #F1F1F1 0%, #EEE 43.75%, #ECECEC 100%)" > - + - + + {wnapp.menuData?.helpDocs && ( + { + typeof wnapp.menuData?.helpDocs === 'string' && + window.open(wnapp.menuData?.helpDocs); + }} + > + {t('Doc')} + + )} new Promise((resolve, reject) => { dns.resolveCname(customDomain, (err, address) => { + console.log(err, address); if (err) return reject(err); if (address[0] !== publicDomain) 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 0d0021b15e7..161035887ee 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/components/Form.tsx @@ -974,16 +974,18 @@ const Form = ({ return ( {env.key} - - - {valText} - - + + + + {valText} + + + ); })} diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx index 5581c00dc14..400b9c3d194 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/index.tsx @@ -21,7 +21,7 @@ import { json2Service } from '@/utils/deployYaml2Json'; import { serviceSideProps } from '@/utils/i18n'; -import { getErrText, patchYamlList, patchYamlListV1 } from '@/utils/tools'; +import { getErrText, patchYamlList } from '@/utils/tools'; import { Box, Flex } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; @@ -158,10 +158,9 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) => if (appName) { const patch = patchYamlList({ formOldYamlList: formOldYamls.current.map((item) => item.value), - crYamlList: crOldYamls.current, - newYamlList: yamls + newYamlList: yamls, + crYamlList: crOldYamls.current }); - await putApp({ patch, appName, diff --git a/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts b/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts index 2df50b284ca..5cd1a61f051 100644 --- a/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts +++ b/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts @@ -1,18 +1,17 @@ -import yaml from 'js-yaml'; -import type { AppEditType, DeployKindsType } from '@/types/app'; -import { strToBase64, str2Num, pathFormat, pathToNameFormat } from '@/utils/tools'; -import { SEALOS_DOMAIN, INGRESS_SECRET } from '@/store/static'; import { - maxReplicasKey, - minReplicasKey, appDeployKey, - publicDomainKey, + deployPVCResizeKey, gpuNodeSelectorKey, gpuResourceKey, - deployPVCResizeKey + maxReplicasKey, + minReplicasKey, + publicDomainKey } from '@/constants/app'; +import { INGRESS_SECRET, SEALOS_DOMAIN } from '@/store/static'; +import type { AppEditType } from '@/types/app'; +import { pathFormat, pathToNameFormat, str2Num, strToBase64 } from '@/utils/tools'; import dayjs from 'dayjs'; -import jsonpatch, { Operation } from 'fast-json-patch'; +import yaml from 'js-yaml'; export const json2DeployCr = (data: AppEditType, type: 'deployment' | 'statefulset') => { const totalStorage = data.storeList.reduce((acc, item) => acc + item.value, 0); diff --git a/frontend/providers/applaunchpad/src/utils/tools.ts b/frontend/providers/applaunchpad/src/utils/tools.ts index 88fff9bb043..4c7dd3d567d 100644 --- a/frontend/providers/applaunchpad/src/utils/tools.ts +++ b/frontend/providers/applaunchpad/src/utils/tools.ts @@ -233,13 +233,13 @@ export const patchYamlList = ({ newYamlList: string[]; crYamlList: DeployKindsType[]; }) => { - console.log(formOldYamlList, newYamlList, crYamlList, '======='); - const oldFormJsonList = formOldYamlList .map((item) => yaml.loadAll(item)) .flat() as DeployKindsType[]; const newFormJsonList = newYamlList.map((item) => yaml.loadAll(item)).flat() as DeployKindsType[]; + console.log(oldFormJsonList, newFormJsonList, crYamlList, '===patchYamlList==='); + const actions: AppPatchPropsType = []; // find delete @@ -298,7 +298,21 @@ export const patchYamlList = ({ } /* generate new json */ - const patchResYamlJson = jsonpatch.applyPatch(crOldYamlJson, patchRes, true).newDocument; + const _patchRes: jsonpatch.Operation[] = patchRes.map((item) => { + let jsonPatchError = jsonpatch.validate([item], crOldYamlJson); + if ( + jsonPatchError?.operation && + jsonPatchError?.name === 'OPERATION_PATH_UNRESOLVABLE' + ) { + return { + ...jsonPatchError.operation, + op: 'add' + }; + } else { + return item; + } + }); + const patchResYamlJson = jsonpatch.applyPatch(crOldYamlJson, _patchRes, true).newDocument; // delete invalid field // @ts-ignore @@ -314,8 +328,7 @@ export const patchYamlList = ({ return patchResYamlJson; } catch (error) { - console.log(error); - + console.log('ACTIONS JSON ERROR\n', error); return newYamlJson; } })(); @@ -344,73 +357,18 @@ export const patchYamlList = ({ } } - actions.push({ - type: 'patch', - kind: newYamlJson.kind as `${YamlKindEnum}`, - value: actionsJson as any - }); - } else { - actions.push({ - type: 'create', - kind: newYamlJson.kind as `${YamlKindEnum}`, - value: yaml.dump(newYamlJson) - }); - } - }); - console.log(actions, 'actions'); - return actions; -}; - -export const patchYamlListV1 = ({ - newYamlList, - oldYamlList -}: { - newYamlList: string[]; - oldYamlList: DeployKindsType[]; -}) => { - const newFormJsonList = newYamlList.map((item) => yaml.loadAll(item)).flat() as DeployKindsType[]; - console.log('new:', newFormJsonList, '\n old', oldYamlList); - - const actions: AppPatchPropsType = []; - - // find delete - oldYamlList.forEach((oldYamlJson) => { - const item = newFormJsonList.find( - (item) => item.kind === oldYamlJson.kind && item.metadata?.name === oldYamlJson.metadata?.name - ); - if (!item && oldYamlJson.metadata?.name) { - actions.push({ - type: 'delete', - kind: oldYamlJson.kind as `${YamlKindEnum}`, - name: oldYamlJson.metadata?.name - }); - } - }); - - // find create and patch - newFormJsonList.forEach((newYamlJson) => { - const oldFormJson = oldYamlList.find( - (item) => - item.kind === newYamlJson.kind && item?.metadata?.name === newYamlJson?.metadata?.name - ); - - if (oldFormJson) { - // adapt service ports - if (newYamlJson.kind === YamlKindEnum.Service) { - // @ts-ignore - const ports = newYamlJson?.spec.ports || []; - - // @ts-ignore - if (ports.length > 1 && !ports[0]?.name) { - // @ts-ignore - newYamlJson.spec.ports[0].name = 'adaptport'; - } - } + console.log( + 'patch result===', + oldFormJson.metadata?.name, + oldFormJson.kind, + patchRes, + actionsJson + ); actions.push({ type: 'patch', kind: newYamlJson.kind as `${YamlKindEnum}`, - value: newYamlJson as any + value: actionsJson as any }); } else { actions.push({ diff --git a/frontend/providers/dbprovider/src/pages/api/platform/resourcePrice.ts b/frontend/providers/dbprovider/src/pages/api/platform/resourcePrice.ts index 44fbf07598d..7988ef87433 100644 --- a/frontend/providers/dbprovider/src/pages/api/platform/resourcePrice.ts +++ b/frontend/providers/dbprovider/src/pages/api/platform/resourcePrice.ts @@ -8,6 +8,7 @@ export type Response = { cpu: number; memory: number; storage: number; + nodeports: number; }; type ResourceType = | 'cpu' @@ -18,7 +19,8 @@ type ResourceType = | 'mongodb' | 'minio' | 'infra-memory' - | 'infra-disk'; + | 'infra-disk' + | 'services.nodeports'; type PriceCrdType = { apiVersion: 'account.sealos.io/v1'; kind: 'PriceQuery'; @@ -72,7 +74,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const data = { cpu: countSourcePrice(priceResponse, 'cpu'), memory: countSourcePrice(priceResponse, 'memory'), - storage: countSourcePrice(priceResponse, 'storage') + storage: countSourcePrice(priceResponse, 'storage'), + nodeports: countSourcePrice(priceResponse, 'services.nodeports') }; jsonRes(res, { diff --git a/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx b/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx index 345ad320ead..dbac6e0e802 100644 --- a/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx +++ b/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx @@ -9,6 +9,7 @@ import MyIcon from '@/components/Icon'; import { DBStatusEnum, DBTypeEnum, DBTypeSecretMap, defaultDBDetail } from '@/constants/db'; import { useToast } from '@/hooks/useToast'; import useEnvStore from '@/store/env'; +import { SOURCE_PRICE } from '@/store/static'; import type { DBDetailType } from '@/types/db'; import { json2NetworkService } from '@/utils/json2Yaml'; import { printMemory, useCopyData } from '@/utils/tools'; @@ -395,21 +396,9 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => { {t('Billing Standards')}
- 0.5 + {SOURCE_PRICE.nodeports} / {t('Hour')}
- {/*
window.open('https://forum.laf.run/d/1092')} - > - - 免费方案 -
*/} diff --git a/frontend/providers/dbprovider/src/store/static.ts b/frontend/providers/dbprovider/src/store/static.ts index daffd2bf0ea..c4415c27fc3 100644 --- a/frontend/providers/dbprovider/src/store/static.ts +++ b/frontend/providers/dbprovider/src/store/static.ts @@ -6,7 +6,8 @@ import type { Response as resourcePriceResponse } from '@/pages/api/platform/res export let SOURCE_PRICE: resourcePriceResponse = { cpu: 0.067, memory: 0.033792, - storage: 0.002048 + storage: 0.002048, + nodeports: 0.5 }; export let INSTALL_ACCOUNT = false; diff --git a/frontend/providers/template/src/pages/api/getKindTemplate.ts b/frontend/providers/template/src/pages/api/getKindTemplate.ts deleted file mode 100644 index 93d6a783113..00000000000 --- a/frontend/providers/template/src/pages/api/getKindTemplate.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { authSession } from '@/services/backend/auth'; -import { getK8s } from '@/services/backend/kubernetes'; -import { jsonRes } from '@/services/backend/response'; -import { ApiResp } from '@/services/kubernet'; -import { TemplateType } from '@/types/app'; -import fs from 'fs'; -import yaml from 'js-yaml'; -import type { NextApiRequest, NextApiResponse } from 'next'; -import path from 'path'; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - const { templateName } = req.query as { templateName: string }; - let user_namespace = ''; - - try { - const { namespace } = await getK8s({ - kubeconfig: await authSession(req.headers) - }); - user_namespace = namespace; - } catch (error) { - console.log(error, 'errpr-'); - } - - const originalPath = process.cwd(); - const targetPath = path.resolve(originalPath, 'FastDeployTemplates', 'template'); - const yamlString = fs.readFileSync(`${targetPath}/${templateName}.yaml`, 'utf-8'); - const yamlData = yaml.loadAll(yamlString); - const templateYaml: TemplateType = yamlData.find( - (item: any) => item.kind === 'Template' - ) as TemplateType; - - jsonRes(res, { - code: 200, - data: templateYaml - }); - } catch (err: any) { - console.log(err); - jsonRes(res, { - code: 500, - error: err - }); - } -} diff --git a/frontend/providers/template/src/pages/api/getTemplateSource.ts b/frontend/providers/template/src/pages/api/getTemplateSource.ts index 0ef0cf3a1e2..29be8f0535e 100644 --- a/frontend/providers/template/src/pages/api/getTemplateSource.ts +++ b/frontend/providers/template/src/pages/api/getTemplateSource.ts @@ -13,6 +13,7 @@ import { replaceRawWithCDN } from './listTemplate'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { const { templateName } = req.query as { templateName: string }; + let user_namespace = ''; try { @@ -72,8 +73,12 @@ export async function GetTemplateByName({ const originalPath = process.cwd(); const targetPath = path.resolve(originalPath, 'FastDeployTemplates', 'template'); - - const yamlString = fs.readFileSync(`${targetPath}/${templateName}.yaml`, 'utf-8'); + // Query by file name in template details + const jsonPath = path.resolve(originalPath, 'fast_deploy_template.json'); + const jsonData: TemplateType[] = JSON.parse(fs.readFileSync(jsonPath, 'utf8')); + const _tempalte = jsonData.find((item) => item.metadata.name === templateName); + const _tempalteName = _tempalte ? _tempalte.spec.fileName : `${templateName}.yaml`; + const yamlString = fs.readFileSync(`${targetPath}/${_tempalteName}`, 'utf-8'); const yamlData = yaml.loadAll(yamlString); const templateYaml: TemplateType = yamlData.find( diff --git a/frontend/providers/template/src/pages/api/updateRepo.ts b/frontend/providers/template/src/pages/api/updateRepo.ts index bb5a1ee069d..bb0cd1e9452 100644 --- a/frontend/providers/template/src/pages/api/updateRepo.ts +++ b/frontend/providers/template/src/pages/api/updateRepo.ts @@ -1,5 +1,6 @@ import { jsonRes } from '@/services/backend/response'; import { ApiResp } from '@/services/kubernet'; +import { TemplateType } from '@/types/app'; import { exec } from 'child_process'; import fs from 'fs'; import JSYAML from 'js-yaml'; @@ -65,9 +66,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< fileList.forEach((item: any) => { try { if (!item) return; + const fileName = path.basename(item); const content = fs.readFileSync(item, 'utf-8'); - const yamlTemplate: any = JSYAML.loadAll(content)[0]; + const yamlTemplate = JSYAML.loadAll(content)[0] as TemplateType; if (!!yamlTemplate) { + yamlTemplate.spec['fileName'] = fileName; jsonObjArr.push(yamlTemplate); } } catch (error) { diff --git a/frontend/providers/template/src/pages/deploy/components/Form.tsx b/frontend/providers/template/src/pages/deploy/components/Form.tsx index e57d60e0bd4..60b27634707 100644 --- a/frontend/providers/template/src/pages/deploy/components/Form.tsx +++ b/frontend/providers/template/src/pages/deploy/components/Form.tsx @@ -62,8 +62,7 @@ const Form = ({ w="200px" className="template-dynamic-label" color={'#333'} - userSelect={'none'} - > + userSelect={'none'}> {item?.label} {item?.required && ( @@ -79,7 +78,7 @@ const Form = ({ autoFocus={true} placeholder={item?.description} {...register(item?.key, { - required: item?.required + required: item?.required ? `${item.label} is required` : '' })} />
@@ -93,16 +92,14 @@ const Form = ({ alignItems="center" h={'160px'} w={'100%'} - flexDirection="column" - > + flexDirection="column"> + alignItems={'center'}> diff --git a/frontend/providers/template/src/pages/deploy/index.tsx b/frontend/providers/template/src/pages/deploy/index.tsx index 0af72834bd6..73bada34609 100644 --- a/frontend/providers/template/src/pages/deploy/index.tsx +++ b/frontend/providers/template/src/pages/deploy/index.tsx @@ -162,8 +162,8 @@ export default function EditApp({ appName }: { appName?: string }) { setIsLoading(false); }; - const submitError = () => { - formHook.getValues(); + const submitError = async () => { + await formHook.trigger(); toast({ title: deepSearch(formHook.formState.errors), status: 'error', diff --git a/frontend/providers/template/src/pages/develop/index.tsx b/frontend/providers/template/src/pages/develop/index.tsx index 4c2cd28a5ea..b0abfc84176 100644 --- a/frontend/providers/template/src/pages/develop/index.tsx +++ b/frontend/providers/template/src/pages/develop/index.tsx @@ -56,7 +56,7 @@ export default function Develop() { const onYamlChange = debounce((state: EditorState) => { const value = state.doc.toString(); parseTemplate(value); - }, 1000); + }, 500); const getYamlSource = (str: string): TemplateSourceType => { const yamlData = JsYaml.loadAll(str); diff --git a/frontend/providers/template/src/types/app.ts b/frontend/providers/template/src/types/app.ts index d601482f8a8..f765353db6f 100644 --- a/frontend/providers/template/src/types/app.ts +++ b/frontend/providers/template/src/types/app.ts @@ -7,6 +7,8 @@ export type TemplateType = { spec: { gitRepo: string; // new templateType: 'inline'; // new + fileName: string; // new + template_type?: string; author: string; title: string;