From 52ee3863ae18222ed7dcce9c36030c5cf15a2ab4 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 3 Jan 2025 21:31:17 +0800 Subject: [PATCH] feat(ui): enhance WorkflowNew --- ui/src/components/DrawerForm.tsx | 16 +++- ui/src/components/ModalForm.tsx | 16 +++- ui/src/i18n/locales/en/nls.workflow.json | 9 +- ui/src/i18n/locales/zh/nls.workflow.json | 5 ++ ui/src/pages/workflows/WorkflowNew.tsx | 108 ++++++++++++++++++----- 5 files changed, 120 insertions(+), 34 deletions(-) diff --git a/ui/src/components/DrawerForm.tsx b/ui/src/components/DrawerForm.tsx index 49529060..1e4bb958 100644 --- a/ui/src/components/DrawerForm.tsx +++ b/ui/src/components/DrawerForm.tsx @@ -56,12 +56,20 @@ const DrawerForm = = NonNullable>({ } = useAntdForm({ form, onSubmit: async (values) => { - const ret = await onFinish?.(values); - if (ret != null && !ret) return false; - return true; + try { + const ret = await onFinish?.(values); + if (ret != null && !ret) return false; + return true; + } catch { + return false; + } }, }); - const mergedFormProps = { ...formProps, ...props }; + const mergedFormProps = { + preserve: drawerProps?.destroyOnClose ? false : undefined, + ...formProps, + ...props, + }; const handleOkClick = async () => { const ret = await submit(); diff --git a/ui/src/components/ModalForm.tsx b/ui/src/components/ModalForm.tsx index 5acd0ed1..2962a278 100644 --- a/ui/src/components/ModalForm.tsx +++ b/ui/src/components/ModalForm.tsx @@ -67,12 +67,20 @@ const ModalForm = = NonNullable>({ } = useAntdForm({ form, onSubmit: async (values) => { - const ret = await onFinish?.(values); - if (ret != null && !ret) return false; - return true; + try { + const ret = await onFinish?.(values); + if (ret != null && !ret) return false; + return true; + } catch { + return false; + } }, }); - const mergedFormProps = { ...formProps, ...props }; + const mergedFormProps = { + preserve: modalProps?.destroyOnClose ? false : undefined, + ...formProps, + ...props, + }; const handleOkClick = async () => { const ret = await submit(); diff --git a/ui/src/i18n/locales/en/nls.workflow.json b/ui/src/i18n/locales/en/nls.workflow.json index 971a8a45..a54e92cc 100644 --- a/ui/src/i18n/locales/en/nls.workflow.json +++ b/ui/src/i18n/locales/en/nls.workflow.json @@ -30,12 +30,17 @@ "workflow.new.templates.template.standard.description": "A standard operating procedure that includes application, deployment, and notification steps.", "workflow.new.templates.template.blank.title": "Blank template", "workflow.new.templates.template.blank.description": "Customize all the contents of the workflow from the beginning.", + "workflow.new.modal.title": "Create workflow", + "workflow.new.modal.form.name.label": "Name", + "workflow.new.modal.form.name.placeholder": "Please enter workflow name", + "workflow.new.modal.form.description.label": "Description", + "workflow.new.modal.form.description.placeholder": "Please enter workflow description", "workflow.detail.baseinfo.modal.title": "Workflow base information", "workflow.detail.baseinfo.form.name.label": "Name", - "workflow.detail.baseinfo.form.name.placeholder": "Please enter name", + "workflow.detail.baseinfo.form.name.placeholder": "Please enter workflow name", "workflow.detail.baseinfo.form.description.label": "Description", - "workflow.detail.baseinfo.form.description.placeholder": "Please enter description", + "workflow.detail.baseinfo.form.description.placeholder": "Please enter workflow description", "workflow.detail.orchestration.tab": "Orchestration", "workflow.detail.orchestration.action.discard": "Discard changes", "workflow.detail.orchestration.action.discard.confirm": "Are you sure to discard your changes?", diff --git a/ui/src/i18n/locales/zh/nls.workflow.json b/ui/src/i18n/locales/zh/nls.workflow.json index 4fd90003..cd360c31 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.json +++ b/ui/src/i18n/locales/zh/nls.workflow.json @@ -30,6 +30,11 @@ "workflow.new.templates.template.standard.description": "一个包含申请 + 部署 + 通知步骤的标准工作流程。", "workflow.new.templates.template.blank.title": "空白模板", "workflow.new.templates.template.blank.description": "从零开始自定义工作流的任务内容。", + "workflow.new.modal.title": "新建工作流", + "workflow.new.modal.form.name.label": "名称", + "workflow.new.modal.form.name.placeholder": "请输入工作流名称", + "workflow.new.modal.form.description.label": "描述", + "workflow.new.modal.form.description.placeholder": "请输入工作流描述", "workflow.detail.baseinfo.modal.title": "编辑基本信息", "workflow.detail.baseinfo.form.name.label": "名称", diff --git a/ui/src/pages/workflows/WorkflowNew.tsx b/ui/src/pages/workflows/WorkflowNew.tsx index 1d2553c2..623fac68 100644 --- a/ui/src/pages/workflows/WorkflowNew.tsx +++ b/ui/src/pages/workflows/WorkflowNew.tsx @@ -2,10 +2,13 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { PageHeader } from "@ant-design/pro-components"; -import { Card, Col, Row, Spin, Typography, notification } from "antd"; -import { sleep } from "radash"; +import { Card, Col, Form, Input, Row, Spin, Typography, notification } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; +import ModalForm from "@/components/ModalForm"; import { type WorkflowModel, initWorkflow } from "@/domain/workflow"; +import { useAntdForm } from "@/hooks"; import { save as saveWorkflow } from "@/repository/workflow"; import { getErrMsg } from "@/utils/error"; @@ -29,39 +32,74 @@ const WorkflowNew = () => { }; const [templateSelectKey, setTemplateSelectKey] = useState(); - const handleTemplateSelect = async (key: TemplateKeys) => { - if (templateSelectKey) return; + const formSchema = z.object({ + name: z + .string({ message: t("workflow.new.modal.form.name.placeholder") }) + .min(1, t("workflow.new.modal.form.name.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + description: z + .string({ message: t("workflow.new.modal.form.description.placeholder") }) + .max(256, t("common.errmsg.string_max", { max: 256 })) + .trim() + .nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + const { + form: formInst, + formPending, + formProps, + ...formApi + } = useAntdForm>({ + onSubmit: async (values) => { + try { + let workflow: WorkflowModel; - setTemplateSelectKey(key); + switch (templateSelectKey) { + case TEMPLATE_KEY_BLANK: + workflow = initWorkflow(); + break; - try { - let workflow: WorkflowModel; + case TEMPLATE_KEY_STANDARD: + workflow = initWorkflow({ template: "standard" }); + break; - switch (key) { - case TEMPLATE_KEY_BLANK: - workflow = initWorkflow(); - break; + default: + throw "Invalid state: `templateSelectKey`"; + } - case TEMPLATE_KEY_STANDARD: - workflow = initWorkflow({ template: "standard" }); - break; + workflow.name = values.name?.trim() ?? workflow.name; + workflow.description = values.description?.trim() ?? workflow.description; + workflow = await saveWorkflow(workflow); + navigate(`/workflows/${workflow.id}`, { replace: true }); + } catch (err) { + console.error(err); + notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); - default: - throw "Invalid args: `key`"; + return false; } + }, + }); + const [formModalOpen, setFormModalOpen] = useState(false); - workflow = await saveWorkflow(workflow); - await sleep(500); + const handleTemplateClick = (key: TemplateKeys) => { + setTemplateSelectKey(key); + setFormModalOpen(true); + }; - await navigate(`/workflows/${workflow.id}`, { replace: true }); - } catch (err) { - console.error(err); - notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); + const handleModalOpenChange = (open: boolean) => { + setFormModalOpen(open); + if (!open) { setTemplateSelectKey(undefined); + formInst.resetFields(); } }; + const handleModalFormFinish = () => { + return formApi.submit(); + }; + return (
{NotificationContextHolder} @@ -84,7 +122,7 @@ const WorkflowNew = () => { className="size-full" cover={} hoverable - onClick={() => handleTemplateSelect(TEMPLATE_KEY_STANDARD)} + onClick={() => handleTemplateClick(TEMPLATE_KEY_STANDARD)} >
{ className="size-full" cover={} hoverable - onClick={() => handleTemplateSelect(TEMPLATE_KEY_BLANK)} + onClick={() => handleTemplateClick(TEMPLATE_KEY_BLANK)} >
{
+ + + + setTimeout(() => ref?.focus({ cursor: "end" }), 0)} placeholder={t("workflow.new.modal.form.name.placeholder")} /> + + + + + +
);