From 8a16893082c27ca4fc8232432d620467e4c1ece6 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 3 Jan 2025 20:29:34 +0800 Subject: [PATCH] feat(ui): new WorkflowElements using antd --- ui/index.html | 2 +- ui/src/App.tsx | 5 +- ui/src/components/{core => }/DrawerForm.tsx | 0 ui/src/components/{core => }/ModalForm.tsx | 0 .../components/{core => }/MultipleInput.tsx | 0 ui/src/components/{core => }/Version.tsx | 0 ui/src/components/access/AccessEditForm.tsx | 2 +- .../AccessProviderSelect.tsx | 0 .../provider/DeployProviderPicker.tsx | 75 ++++++ .../provider/DeployProviderSelect.tsx | 51 ++++ ui/src/components/workflow/AddNode.tsx | 65 ----- ui/src/components/workflow/BranchNode.tsx | 69 ------ ui/src/components/workflow/ConditionNode.tsx | 50 ---- .../components/workflow/DeployPanelBody.tsx | 48 ---- .../workflow/DropdownMenuItemIcon.tsx | 30 --- ui/src/components/workflow/Node.tsx | 147 ------------ ui/src/components/workflow/NodeRender.tsx | 24 +- ui/src/components/workflow/PanelBody.tsx | 15 +- .../components/workflow/WorkflowElement.tsx | 158 ++++++++++++ .../components/workflow/WorkflowElements.tsx | 41 ++++ .../{run => }/WorkflowRunDetailDrawer.tsx | 0 .../workflow/{run => }/WorkflowRuns.tsx | 0 ui/src/components/workflow/node/AddNode.tsx | 72 ++++++ .../workflow/node/ApplyNodeForm.tsx | 16 +- .../components/workflow/node/BranchNode.tsx | 63 +++++ .../workflow/node/ConditionNode.tsx | 78 ++++++ .../workflow/node/DeployNodeForm.tsx | 224 +++++++++--------- .../workflow/{End.tsx => node/EndNode.tsx} | 10 +- .../workflow/node/NotifyNodeForm.tsx | 8 +- .../workflow/node/StartNodeForm.tsx | 16 +- ui/src/components/workflow/types.ts | 10 +- ui/src/domain/settings.ts | 12 +- ui/src/domain/workflow.ts | 103 +------- ui/src/global.css | 32 +-- ui/src/i18n/locales/en/nls.workflow.json | 7 +- .../i18n/locales/en/nls.workflow.nodes.json | 7 + ui/src/i18n/locales/zh/nls.workflow.json | 9 +- .../i18n/locales/zh/nls.workflow.nodes.json | 7 + ui/src/pages/AuthLayout.tsx | 2 +- ui/src/pages/ConsoleLayout.tsx | 4 +- ui/src/pages/workflows/WorkflowDetail.tsx | 119 +++++----- ui/src/stores/workflow/index.ts | 10 +- ui/tailwind.config.js | 24 -- 43 files changed, 805 insertions(+), 810 deletions(-) rename ui/src/components/{core => }/DrawerForm.tsx (100%) rename ui/src/components/{core => }/ModalForm.tsx (100%) rename ui/src/components/{core => }/MultipleInput.tsx (100%) rename ui/src/components/{core => }/Version.tsx (100%) rename ui/src/components/{access => provider}/AccessProviderSelect.tsx (100%) create mode 100644 ui/src/components/provider/DeployProviderPicker.tsx create mode 100644 ui/src/components/provider/DeployProviderSelect.tsx delete mode 100644 ui/src/components/workflow/AddNode.tsx delete mode 100644 ui/src/components/workflow/BranchNode.tsx delete mode 100644 ui/src/components/workflow/ConditionNode.tsx delete mode 100644 ui/src/components/workflow/DeployPanelBody.tsx delete mode 100644 ui/src/components/workflow/DropdownMenuItemIcon.tsx delete mode 100644 ui/src/components/workflow/Node.tsx create mode 100644 ui/src/components/workflow/WorkflowElement.tsx create mode 100644 ui/src/components/workflow/WorkflowElements.tsx rename ui/src/components/workflow/{run => }/WorkflowRunDetailDrawer.tsx (100%) rename ui/src/components/workflow/{run => }/WorkflowRuns.tsx (100%) create mode 100644 ui/src/components/workflow/node/AddNode.tsx create mode 100644 ui/src/components/workflow/node/BranchNode.tsx create mode 100644 ui/src/components/workflow/node/ConditionNode.tsx rename ui/src/components/workflow/{End.tsx => node/EndNode.tsx} (50%) diff --git a/ui/index.html b/ui/index.html index 4a71aab8..fe1c7f6b 100644 --- a/ui/index.html +++ b/ui/index.html @@ -6,7 +6,7 @@ Certimate - Your Trusted SSL Automation Partner - +
diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 1a355b3b..65f98577 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -54,8 +54,9 @@ const RootApp = () => { theme={{ ...antdTheme, token: { - colorPrimary: "hsl(24.6 95% 53.1%)", - colorLink: "hsl(24.6 95% 53.1%)", + /* @see tailwind.config.js */ + colorPrimary: browserTheme === "dark" ? "hsl(20.5 90.2% 48.2%)" : "hsl(24.6 95% 53.1%)", + colorLink: browserTheme === "dark" ? "hsl(20.5 90.2% 48.2%)" : "hsl(24.6 95% 53.1%)", }, }} > diff --git a/ui/src/components/core/DrawerForm.tsx b/ui/src/components/DrawerForm.tsx similarity index 100% rename from ui/src/components/core/DrawerForm.tsx rename to ui/src/components/DrawerForm.tsx diff --git a/ui/src/components/core/ModalForm.tsx b/ui/src/components/ModalForm.tsx similarity index 100% rename from ui/src/components/core/ModalForm.tsx rename to ui/src/components/ModalForm.tsx diff --git a/ui/src/components/core/MultipleInput.tsx b/ui/src/components/MultipleInput.tsx similarity index 100% rename from ui/src/components/core/MultipleInput.tsx rename to ui/src/components/MultipleInput.tsx diff --git a/ui/src/components/core/Version.tsx b/ui/src/components/Version.tsx similarity index 100% rename from ui/src/components/core/Version.tsx rename to ui/src/components/Version.tsx diff --git a/ui/src/components/access/AccessEditForm.tsx b/ui/src/components/access/AccessEditForm.tsx index a4eb78ca..521e7467 100644 --- a/ui/src/components/access/AccessEditForm.tsx +++ b/ui/src/components/access/AccessEditForm.tsx @@ -5,6 +5,7 @@ import { Form, type FormInstance, Input } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; +import AccessProviderSelect from "@/components/provider/AccessProviderSelect"; import { type AccessModel } from "@/domain/access"; import { ACCESS_PROVIDERS } from "@/domain/provider"; import { useAntdForm } from "@/hooks"; @@ -28,7 +29,6 @@ import AccessEditFormSSHConfig from "./AccessEditFormSSHConfig"; import AccessEditFormTencentCloudConfig from "./AccessEditFormTencentCloudConfig"; import AccessEditFormVolcEngineConfig from "./AccessEditFormVolcEngineConfig"; import AccessEditFormWebhookConfig from "./AccessEditFormWebhookConfig"; -import AccessProviderSelect from "./AccessProviderSelect"; type AccessEditFormFieldValues = Partial>; type AccessEditFormPresets = "add" | "edit"; diff --git a/ui/src/components/access/AccessProviderSelect.tsx b/ui/src/components/provider/AccessProviderSelect.tsx similarity index 100% rename from ui/src/components/access/AccessProviderSelect.tsx rename to ui/src/components/provider/AccessProviderSelect.tsx diff --git a/ui/src/components/provider/DeployProviderPicker.tsx b/ui/src/components/provider/DeployProviderPicker.tsx new file mode 100644 index 00000000..d259dccb --- /dev/null +++ b/ui/src/components/provider/DeployProviderPicker.tsx @@ -0,0 +1,75 @@ +import { memo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useDebounceEffect } from "ahooks"; +import { Avatar, Card, Col, Empty, Flex, Input, Row, Typography } from "antd"; + +import Show from "@/components/Show"; +import { deployProvidersMap } from "@/domain/provider"; + +export type DeployProviderPickerProps = { + className?: string; + style?: React.CSSProperties; + onSelect?: (value: string) => void; +}; + +const DeployProviderPicker = ({ className, style, onSelect }: DeployProviderPickerProps) => { + const { t } = useTranslation(); + + const allProviders = Array.from(deployProvidersMap.values()); + const [providers, setProviders] = useState(allProviders); + const [keyword, setKeyword] = useState(); + useDebounceEffect( + () => { + if (keyword) { + setProviders( + allProviders.filter((provider) => { + const value = keyword.toLowerCase(); + return provider.type.toLowerCase().includes(value) || provider.name.toLowerCase().includes(value); + }) + ); + } else { + setProviders(allProviders); + } + }, + [keyword], + { wait: 300 } + ); + + const handleProviderTypeSelect = (value: string) => { + onSelect?.(value); + }; + + return ( +
+ setKeyword(e.target.value.trim())} /> + +
+ 0} fallback={}> + + {providers.map((provider, index) => { + return ( + + { + handleProviderTypeSelect(provider.type); + }} + > + + + {t(provider.name)} + + + + ); + })} + + +
+
+ ); +}; + +export default memo(DeployProviderPicker); diff --git a/ui/src/components/provider/DeployProviderSelect.tsx b/ui/src/components/provider/DeployProviderSelect.tsx new file mode 100644 index 00000000..ae7cbf9b --- /dev/null +++ b/ui/src/components/provider/DeployProviderSelect.tsx @@ -0,0 +1,51 @@ +import { memo } from "react"; +import { useTranslation } from "react-i18next"; +import { Avatar, Select, type SelectProps, Space, Typography } from "antd"; + +import { deployProvidersMap } from "@/domain/provider"; + +export type DeployProviderSelectProps = Omit< + SelectProps, + "filterOption" | "filterSort" | "labelRender" | "options" | "optionFilterProp" | "optionLabelProp" | "optionRender" +>; + +const DeployProviderSelect = (props: DeployProviderSelectProps) => { + const { t } = useTranslation(); + + const options = Array.from(deployProvidersMap.values()).map((item) => ({ + key: item.type, + value: item.type, + label: t(item.name), + })); + + const renderOption = (key: string) => { + const provider = deployProvidersMap.get(key); + return ( + + + + {t(provider?.name ?? "")} + + + ); + }; + + return ( + { - const type = String(option?.value ?? ""); - const target = deployProvidersMap.get(type); - const filter = (v?: string) => v?.toLowerCase()?.includes(searchValue.toLowerCase()) ?? false; - return filter(type) || filter(t(target?.name ?? "")); - }} - onSelect={handleProviderTypeSelect} - > - {Array.from(deployProvidersMap.values()).map((item) => { - return ( - - - - - {t(item.name)} - - - - ); - })} - - - - - - - { - if (defaultProivderType) { - return deployProvidersMap.get(defaultProivderType)?.provider === record.configType; - } - - const provider = accessProvidersMap.get(record.configType); - return ACCESS_USAGES.ALL === provider?.usage || ACCESS_USAGES.APPLY === provider?.usage; - }} + }> + + - - } - > - { + return { + label: item.name, + options: item.output?.map((output) => { + return { + label: `${item.name} - ${output.label}`, + value: `${item.id}#${output.name}`, + }; + }), + }; + })} + placeholder={t("workflow_node.deploy.form.certificate.placeholder")} + /> + - - - + + + {t("workflow_node.deploy.form.params_config.label")} + + + + {formFieldsComponent} + + + + + ); }; diff --git a/ui/src/components/workflow/End.tsx b/ui/src/components/workflow/node/EndNode.tsx similarity index 50% rename from ui/src/components/workflow/End.tsx rename to ui/src/components/workflow/node/EndNode.tsx index 072674d6..3843c562 100644 --- a/ui/src/components/workflow/End.tsx +++ b/ui/src/components/workflow/node/EndNode.tsx @@ -1,13 +1,17 @@ import { useTranslation } from "react-i18next"; +import { Typography } from "antd"; -const End = () => { +const EndNode = () => { const { t } = useTranslation(); + return (
-
{t("workflow_node.end.label")}
+
+ {t("workflow_node.end.label")} +
); }; -export default End; +export default EndNode; diff --git a/ui/src/components/workflow/node/NotifyNodeForm.tsx b/ui/src/components/workflow/node/NotifyNodeForm.tsx index 23a4fd59..5c523b58 100644 --- a/ui/src/components/workflow/node/NotifyNodeForm.tsx +++ b/ui/src/components/workflow/node/NotifyNodeForm.tsx @@ -15,7 +15,7 @@ import { useWorkflowStore } from "@/stores/workflow"; import { usePanel } from "../PanelProvider"; export type NotifyNodeFormProps = { - data: WorkflowNode; + node: WorkflowNode; }; const initFormModel = () => { @@ -25,7 +25,7 @@ const initFormModel = () => { }; }; -const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => { +const NotifyNodeForm = ({ node }: NotifyNodeFormProps) => { const { t } = useTranslation(); const { @@ -57,11 +57,11 @@ const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => { formPending, formProps, } = useAntdForm>({ - initialValues: data?.config ?? initFormModel(), + initialValues: node?.config ?? initFormModel(), onSubmit: async (values) => { await formInst.validateFields(); await updateNode( - produce(data, (draft) => { + produce(node, (draft) => { draft.config = { ...values }; draft.validated = true; }) diff --git a/ui/src/components/workflow/node/StartNodeForm.tsx b/ui/src/components/workflow/node/StartNodeForm.tsx index bffe9e45..9611e91d 100644 --- a/ui/src/components/workflow/node/StartNodeForm.tsx +++ b/ui/src/components/workflow/node/StartNodeForm.tsx @@ -14,7 +14,7 @@ import { getNextCronExecutions, validCronExpression } from "@/utils/cron"; import { usePanel } from "../PanelProvider"; export type StartNodeFormProps = { - data: WorkflowNode; + node: WorkflowNode; }; const initFormModel = () => { @@ -24,7 +24,7 @@ const initFormModel = () => { }; }; -const StartNodeForm = ({ data }: StartNodeFormProps) => { +const StartNodeForm = ({ node }: StartNodeFormProps) => { const { t } = useTranslation(); const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"])); @@ -54,11 +54,11 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => { formPending, formProps, } = useAntdForm>({ - initialValues: data?.config ?? initFormModel(), + initialValues: node?.config ?? initFormModel(), onSubmit: async (values) => { await formInst.validateFields(); await updateNode( - produce(data, (draft) => { + produce(node, (draft) => { draft.config = { ...values }; draft.validated = true; }) @@ -67,12 +67,12 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => { }, }); - const [triggerType, setTriggerType] = useState(data?.config?.executionMethod); + const [triggerType, setTriggerType] = useState(node?.config?.executionMethod); const [triggerCronLastExecutions, setTriggerCronExecutions] = useState([]); useEffect(() => { - setTriggerType(data?.config?.executionMethod); - setTriggerCronExecutions(getNextCronExecutions(data?.config?.crontab as string, 5)); - }, [data?.config?.executionMethod, data?.config?.crontab]); + setTriggerType(node?.config?.executionMethod); + setTriggerCronExecutions(getNextCronExecutions(node?.config?.crontab as string, 5)); + }, [node?.config?.executionMethod, node?.config?.crontab]); const handleTriggerTypeChange = (value: string) => { setTriggerType(value); diff --git a/ui/src/components/workflow/types.ts b/ui/src/components/workflow/types.ts index 094505e8..36ffc38f 100644 --- a/ui/src/components/workflow/types.ts +++ b/ui/src/components/workflow/types.ts @@ -1,11 +1,17 @@ import { type WorkflowBranchNode, type WorkflowNode } from "@/domain/workflow"; +/** + * @deprecated + */ export type NodeProps = { - data: WorkflowNode | WorkflowBranchNode; + node: WorkflowNode | WorkflowBranchNode; branchId?: string; branchIndex?: number; }; +/** + * @deprecated + */ export type BrandNodeProps = { - data: WorkflowBranchNode; + node: WorkflowBranchNode; }; diff --git a/ui/src/domain/settings.ts b/ui/src/domain/settings.ts index b2412a7d..a20822c8 100644 --- a/ui/src/domain/settings.ts +++ b/ui/src/domain/settings.ts @@ -1,12 +1,8 @@ -export const SETTINGS_NAME_EMAILS = "emails" as const; -export const SETTINGS_NAME_NOTIFYTEMPLATES = "notifyTemplates" as const; -export const SETTINGS_NAME_NOTIFYCHANNELS = "notifyChannels" as const; -export const SETTINGS_NAME_SSLPROVIDER = "sslProvider" as const; export const SETTINGS_NAMES = Object.freeze({ - EMAILS: SETTINGS_NAME_EMAILS, - NOTIFY_TEMPLATES: SETTINGS_NAME_NOTIFYTEMPLATES, - NOTIFY_CHANNELS: SETTINGS_NAME_NOTIFYCHANNELS, - SSL_PROVIDER: SETTINGS_NAME_SSLPROVIDER, + EMAILS: "emails", + NOTIFY_TEMPLATES: "notifyTemplates", + NOTIFY_CHANNELS: "notifyChannels", + SSL_PROVIDER: "sslProvider", } as const); export type SettingsNames = (typeof SETTINGS_NAMES)[keyof typeof SETTINGS_NAMES]; diff --git a/ui/src/domain/workflow.ts b/ui/src/domain/workflow.ts index 1633b60d..195934b5 100644 --- a/ui/src/domain/workflow.ts +++ b/ui/src/domain/workflow.ts @@ -28,7 +28,7 @@ export enum WorkflowNodeType { Custom = "custom", } -const workflowNodeTypeDefaultNames: Map = new Map([ +export const workflowNodeTypeDefaultNames: Map = new Map([ [WorkflowNodeType.Start, i18n.t("workflow_node.start.label")], [WorkflowNodeType.End, i18n.t("workflow_node.end.label")], [WorkflowNodeType.Branch, i18n.t("workflow_node.branch.label")], @@ -39,7 +39,7 @@ const workflowNodeTypeDefaultNames: Map = new Map([ [WorkflowNodeType.Custom, i18n.t("workflow_node.custom.title")], ]); -const workflowNodeTypeDefaultInputs: Map = new Map([ +export const workflowNodeTypeDefaultInputs: Map = new Map([ [WorkflowNodeType.Apply, []], [ WorkflowNodeType.Deploy, @@ -48,14 +48,14 @@ const workflowNodeTypeDefaultInputs: Map = n name: "certificate", type: "certificate", required: true, - label: i18n.t("workflow.common.certificate.label"), + label: "证书", }, ], ], [WorkflowNodeType.Notify, []], ]); -const workflowNodeTypeDefaultOutputs: Map = new Map([ +export const workflowNodeTypeDefaultOutputs: Map = new Map([ [ WorkflowNodeType.Apply, [ @@ -63,7 +63,7 @@ const workflowNodeTypeDefaultOutputs: Map = name: "certificate", type: "certificate", required: true, - label: i18n.t("workflow.common.certificate.label"), + label: "证书", }, ], ], @@ -148,10 +148,9 @@ export const initWorkflow = (options: InitWorkflowOptions = {}): WorkflowModel = type NewNodeOptions = { branchIndex?: number; - providerType?: string; }; -export const newNode = (nodeType: WorkflowNodeType, options: NewNodeOptions): WorkflowNode | WorkflowBranchNode => { +export const newNode = (nodeType: WorkflowNodeType, options: NewNodeOptions = {}): WorkflowNode | WorkflowBranchNode => { const nodeTypeName = workflowNodeTypeDefaultNames.get(nodeType) || ""; const nodeName = options.branchIndex != null ? `${nodeTypeName} ${options.branchIndex + 1}` : nodeTypeName; @@ -165,9 +164,7 @@ export const newNode = (nodeType: WorkflowNodeType, options: NewNodeOptions): Wo case WorkflowNodeType.Apply: case WorkflowNodeType.Deploy: { - node.config = { - providerType: options.providerType, - }; + node.config = {}; node.input = workflowNodeTypeDefaultInputs.get(nodeType); node.output = workflowNodeTypeDefaultOutputs.get(nodeType); } @@ -389,89 +386,3 @@ export const getExecuteMethod = (node: WorkflowNode): { type: string; crontab: s }; } }; - -/** - * @deprecated - */ -type WorkflowNodeDropdwonItem = { - type: WorkflowNodeType; - providerType?: string; - name: string; - icon: WorkflowNodeDropdwonItemIcon; - leaf?: boolean; - children?: WorkflowNodeDropdwonItem[]; -}; - -/** - * @deprecated - */ -export enum WorkflowNodeDropdwonItemIconType { - Icon, - Provider, -} - -/** - * @deprecated - */ -export type WorkflowNodeDropdwonItemIcon = { - type: WorkflowNodeDropdwonItemIconType; - name: string; -}; - -/** - * @deprecated - */ -const workflowNodeDropdownDeployList: WorkflowNodeDropdwonItem[] = Array.from(deployProvidersMap.values()).map((item) => { - return { - type: WorkflowNodeType.Apply, - providerType: item.type, - name: i18n.t(item.name), - leaf: true, - icon: { - type: WorkflowNodeDropdwonItemIconType.Provider, - name: item.icon, - }, - }; -}); - -/** - * @deprecated - */ -export const workflowNodeDropdownList: WorkflowNodeDropdwonItem[] = [ - { - type: WorkflowNodeType.Apply, - name: workflowNodeTypeDefaultNames.get(WorkflowNodeType.Apply) ?? "", - icon: { - type: WorkflowNodeDropdwonItemIconType.Icon, - name: "ApplyNodeIcon", - }, - leaf: true, - }, - { - type: WorkflowNodeType.Deploy, - name: workflowNodeTypeDefaultNames.get(WorkflowNodeType.Deploy) ?? "", - icon: { - type: WorkflowNodeDropdwonItemIconType.Icon, - name: "DeployNodeIcon", - }, - children: workflowNodeDropdownDeployList, - }, - { - type: WorkflowNodeType.Branch, - name: workflowNodeTypeDefaultNames.get(WorkflowNodeType.Branch) ?? "", - leaf: true, - icon: { - type: WorkflowNodeDropdwonItemIconType.Icon, - name: "BranchNodeIcon", - }, - }, - { - type: WorkflowNodeType.Notify, - name: workflowNodeTypeDefaultNames.get(WorkflowNodeType.Notify) ?? "", - leaf: true, - icon: { - type: WorkflowNodeDropdwonItemIconType.Icon, - name: "NotifyNodeIcon", - }, - }, -]; diff --git a/ui/src/global.css b/ui/src/global.css index 4f5ac844..2a7ef589 100644 --- a/ui/src/global.css +++ b/ui/src/global.css @@ -5,41 +5,13 @@ @layer base { :root { --background: 0 0% 100%; - --foreground: 20 14.3% 4.1%; - --popover: 0 0% 100%; - --popover-foreground: 20 14.3% 4.1%; + --foreground: 0, 0%, 8%; --primary: 24.6 95% 53.1%; - --primary-foreground: 60 9.1% 97.8%; - --secondary: 60 4.8% 95.9%; - --secondary-foreground: 24 9.8% 10%; - --muted: 60 4.8% 95.9%; - --muted-foreground: 25 5.3% 44.7%; - --accent: 60 4.8% 95.9%; - --accent-foreground: 24 9.8% 10%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 60 9.1% 97.8%; - --border: 20 5.9% 90%; - --input: 20 5.9% 90%; - --ring: 24.6 95% 53.1%; } .dark { - --background: 20 14.3% 4.1%; + --background: 0, 0%, 8%; --foreground: 60 9.1% 97.8%; - --popover: 20 14.3% 4.1%; - --popover-foreground: 60 9.1% 97.8%; --primary: 20.5 90.2% 48.2%; - --primary-foreground: 60 9.1% 97.8%; - --secondary: 12 6.5% 15.1%; - --secondary-foreground: 60 9.1% 97.8%; - --muted: 12 6.5% 15.1%; - --muted-foreground: 24 5.4% 63.9%; - --accent: 12 6.5% 15.1%; - --accent-foreground: 60 9.1% 97.8%; - --destructive: 0 72.2% 50.6%; - --destructive-foreground: 60 9.1% 97.8%; - --border: 12 6.5% 15.1%; - --input: 12 6.5% 15.1%; - --ring: 20.5 90.2% 48.2%; } } diff --git a/ui/src/i18n/locales/en/nls.workflow.json b/ui/src/i18n/locales/en/nls.workflow.json index 1b1aec8e..971a8a45 100644 --- a/ui/src/i18n/locales/en/nls.workflow.json +++ b/ui/src/i18n/locales/en/nls.workflow.json @@ -44,10 +44,5 @@ "workflow.detail.orchestration.action.release.failed.uncompleted": "Please complete the orchestration first", "workflow.detail.orchestration.action.run": "Run", "workflow.detail.orchestration.action.run.confirm": "There are unreleased changes, are you sure to run this workflow based on the latest released version?", - "workflow.detail.runs.tab": "History runs", - - "workflow.common.certificate.label": "Certificate", - "workflow.node.setting.label": "Setting Node", - "workflow.node.delete.label": "Delete Node", - "workflow.node.addBranch.label": "Add Branch" + "workflow.detail.runs.tab": "History runs" } diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 25ae5a79..f382addb 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -1,4 +1,10 @@ { + "workflow_node.action.configure_node": "Configure", + "workflow_node.action.add_node": "Add node", + "workflow_node.action.delete_node": "Delete node", + "workflow_node.action.add_branch": "Add branch", + "workflow_node.action.delete_branch": "Delete branch", + "workflow_node.start.label": "Start", "workflow_node.start.form.trigger.label": "Trigger", "workflow_node.start.form.trigger.placeholder": "Please select trigger", @@ -41,6 +47,7 @@ "workflow_node.apply.form.disable_follow_cname.tooltip": "It determines whether to disable CNAME following during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.
Learn more.", "workflow_node.deploy.label": "Deployment", + "workflow_node.deploy.search.provider_type.placeholder": "Search deploy target ...", "workflow_node.deploy.form.provider_type.label": "Deploy target", "workflow_node.deploy.form.provider_type.placeholder": "Please select deploy target", "workflow_node.deploy.form.provider_access.label": "Host provider authorization", diff --git a/ui/src/i18n/locales/zh/nls.workflow.json b/ui/src/i18n/locales/zh/nls.workflow.json index 831876b2..4fd90003 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.json +++ b/ui/src/i18n/locales/zh/nls.workflow.json @@ -41,13 +41,8 @@ "workflow.detail.orchestration.action.discard.confirm": "确定要撤销更改并回退到最近一次发布的版本吗?", "workflow.detail.orchestration.action.release": "发布更改", "workflow.detail.orchestration.action.release.confirm": "确定要发布更改吗?", - "workflow.detail.orchestration.action.release.failed.uncompleted": "流程编排未完成,请检查是否有节点未设置", + "workflow.detail.orchestration.action.release.failed.uncompleted": "流程编排未完成,请检查是否有节点未配置", "workflow.detail.orchestration.action.run": "执行", "workflow.detail.orchestration.action.run.confirm": "此工作流存在未发布的更改,将以最近一次发布的版本为准,确定要继续执行吗?", - "workflow.detail.runs.tab": "执行历史", - - "workflow.common.certificate.label": "证书", - "workflow.node.setting.label": "设置节点", - "workflow.node.delete.label": "删除节点", - "workflow.node.addBranch.label": "添加分支" + "workflow.detail.runs.tab": "执行历史" } diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index bdb419a2..7fdd58c2 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -1,4 +1,10 @@ { + "workflow_node.action.configure_node": "配置节点", + "workflow_node.branch.add_node": "添加节点", + "workflow_node.action.delete_node": "删除节点", + "workflow_node.action.add_branch": "添加分支", + "workflow_node.action.delete_branch": "删除分支", + "workflow_node.start.label": "开始", "workflow_node.start.form.trigger.label": "触发方式", "workflow_node.start.form.trigger.placeholder": "请选择触发方式", @@ -41,6 +47,7 @@ "workflow_node.apply.form.disable_follow_cname.tooltip": "在 ACME DNS-01 认证时是否禁止 CNAME 跟随。如果你不了解该选项的用途,保持默认即可。
点此了解更多。", "workflow_node.deploy.label": "部署", + "workflow_node.deploy.search.provider_type.placeholder": "搜索部署目标……", "workflow_node.deploy.form.provider_type.label": "部署目标", "workflow_node.deploy.form.provider_type.placeholder": "请选择部署目标", "workflow_node.deploy.form.provider_access.label": "主机提供商授权", diff --git a/ui/src/pages/AuthLayout.tsx b/ui/src/pages/AuthLayout.tsx index 10f84c38..ef1b55fe 100644 --- a/ui/src/pages/AuthLayout.tsx +++ b/ui/src/pages/AuthLayout.tsx @@ -1,6 +1,6 @@ import { Navigate, Outlet } from "react-router-dom"; -import Version from "@/components/core/Version"; +import Version from "@/components/Version"; import { getPocketBase } from "@/repository/pocketbase"; const AuthLayout = () => { diff --git a/ui/src/pages/ConsoleLayout.tsx b/ui/src/pages/ConsoleLayout.tsx index d4dff7a2..7363f54e 100644 --- a/ui/src/pages/ConsoleLayout.tsx +++ b/ui/src/pages/ConsoleLayout.tsx @@ -15,7 +15,7 @@ import { } from "@ant-design/icons"; import { Button, type ButtonProps, Drawer, Dropdown, Layout, Menu, type MenuProps, Tooltip, theme } from "antd"; -import Version from "@/components/core/Version"; +import Version from "@/components/Version"; import { useBrowserTheme } from "@/hooks"; import { getPocketBase } from "@/repository/pocketbase"; @@ -66,7 +66,7 @@ const ConsoleLayout = () => {
-
+
} onFinish={handleBaseInfoFormFinish} />, + extra={ + initialized + ? [ + {t("common.button.edit")}} + onFinish={handleBaseInfoFormFinish} + />, - , + , - , - onClick: () => { - handleDeleteClick(); - }, - }, - ], - }} - trigger={["click"]} - > - - , - ]} + , + onClick: () => { + handleDeleteClick(); + }, + }, + ], + }} + trigger={["click"]} + > + + , + ] + : [] + } > {workflow.description} {
- +
-
- {workflowNodes} +
+
- diff --git a/ui/src/stores/workflow/index.ts b/ui/src/stores/workflow/index.ts index 57b22188..369347c1 100644 --- a/ui/src/stores/workflow/index.ts +++ b/ui/src/stores/workflow/index.ts @@ -25,8 +25,9 @@ export type WorkflowState = { getWorkflowOuptutBeforeId: (id: string, type: string) => WorkflowNode[]; switchEnable(): void; save(): void; - init(id: string): void; setBaseInfo: (name: string, description: string) => void; + init(id: string): void; + destroy(): void; }; export const useWorkflowStore = create((set, get) => ({ @@ -214,4 +215,11 @@ export const useWorkflowStore = create((set, get) => ({ getWorkflowOuptutBeforeId: (id: string, type: string) => { return getWorkflowOutputBeforeId(get().workflow.draft as WorkflowNode, id, type); }, + + destroy: () => { + set({ + workflow: {} as WorkflowModel, + initialized: false, + }); + }, })); diff --git a/ui/tailwind.config.js b/ui/tailwind.config.js index 52dce060..8e4d86f0 100644 --- a/ui/tailwind.config.js +++ b/ui/tailwind.config.js @@ -14,34 +14,10 @@ module.exports = { }, extend: { colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", background: "hsl(var(--background))", foreground: "hsl(var(--foreground))", primary: { DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", }, }, },