mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-17 09:59:51 +00:00
feat(ui): enhance WorkflowNew
This commit is contained in:
parent
5ce5a08e41
commit
52ee3863ae
@ -56,12 +56,20 @@ const DrawerForm = <T extends NonNullable<unknown> = NonNullable<unknown>>({
|
|||||||
} = useAntdForm({
|
} = useAntdForm({
|
||||||
form,
|
form,
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
|
try {
|
||||||
const ret = await onFinish?.(values);
|
const ret = await onFinish?.(values);
|
||||||
if (ret != null && !ret) return false;
|
if (ret != null && !ret) return false;
|
||||||
return true;
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const mergedFormProps = { ...formProps, ...props };
|
const mergedFormProps = {
|
||||||
|
preserve: drawerProps?.destroyOnClose ? false : undefined,
|
||||||
|
...formProps,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
|
||||||
const handleOkClick = async () => {
|
const handleOkClick = async () => {
|
||||||
const ret = await submit();
|
const ret = await submit();
|
||||||
|
@ -67,12 +67,20 @@ const ModalForm = <T extends NonNullable<unknown> = NonNullable<unknown>>({
|
|||||||
} = useAntdForm({
|
} = useAntdForm({
|
||||||
form,
|
form,
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
|
try {
|
||||||
const ret = await onFinish?.(values);
|
const ret = await onFinish?.(values);
|
||||||
if (ret != null && !ret) return false;
|
if (ret != null && !ret) return false;
|
||||||
return true;
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const mergedFormProps = { ...formProps, ...props };
|
const mergedFormProps = {
|
||||||
|
preserve: modalProps?.destroyOnClose ? false : undefined,
|
||||||
|
...formProps,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
|
||||||
const handleOkClick = async () => {
|
const handleOkClick = async () => {
|
||||||
const ret = await submit();
|
const ret = await submit();
|
||||||
|
@ -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.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.title": "Blank template",
|
||||||
"workflow.new.templates.template.blank.description": "Customize all the contents of the workflow from the beginning.",
|
"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.modal.title": "Workflow base information",
|
||||||
"workflow.detail.baseinfo.form.name.label": "Name",
|
"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.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.tab": "Orchestration",
|
||||||
"workflow.detail.orchestration.action.discard": "Discard changes",
|
"workflow.detail.orchestration.action.discard": "Discard changes",
|
||||||
"workflow.detail.orchestration.action.discard.confirm": "Are you sure to discard your changes?",
|
"workflow.detail.orchestration.action.discard.confirm": "Are you sure to discard your changes?",
|
||||||
|
@ -30,6 +30,11 @@
|
|||||||
"workflow.new.templates.template.standard.description": "一个包含申请 + 部署 + 通知步骤的标准工作流程。",
|
"workflow.new.templates.template.standard.description": "一个包含申请 + 部署 + 通知步骤的标准工作流程。",
|
||||||
"workflow.new.templates.template.blank.title": "空白模板",
|
"workflow.new.templates.template.blank.title": "空白模板",
|
||||||
"workflow.new.templates.template.blank.description": "从零开始自定义工作流的任务内容。",
|
"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.modal.title": "编辑基本信息",
|
||||||
"workflow.detail.baseinfo.form.name.label": "名称",
|
"workflow.detail.baseinfo.form.name.label": "名称",
|
||||||
|
@ -2,10 +2,13 @@ import { useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { PageHeader } from "@ant-design/pro-components";
|
import { PageHeader } from "@ant-design/pro-components";
|
||||||
import { Card, Col, Row, Spin, Typography, notification } from "antd";
|
import { Card, Col, Form, Input, Row, Spin, Typography, notification } from "antd";
|
||||||
import { sleep } from "radash";
|
import { createSchemaFieldRule } from "antd-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import ModalForm from "@/components/ModalForm";
|
||||||
import { type WorkflowModel, initWorkflow } from "@/domain/workflow";
|
import { type WorkflowModel, initWorkflow } from "@/domain/workflow";
|
||||||
|
import { useAntdForm } from "@/hooks";
|
||||||
import { save as saveWorkflow } from "@/repository/workflow";
|
import { save as saveWorkflow } from "@/repository/workflow";
|
||||||
import { getErrMsg } from "@/utils/error";
|
import { getErrMsg } from "@/utils/error";
|
||||||
|
|
||||||
@ -29,15 +32,30 @@ const WorkflowNew = () => {
|
|||||||
};
|
};
|
||||||
const [templateSelectKey, setTemplateSelectKey] = useState<TemplateKeys>();
|
const [templateSelectKey, setTemplateSelectKey] = useState<TemplateKeys>();
|
||||||
|
|
||||||
const handleTemplateSelect = async (key: TemplateKeys) => {
|
const formSchema = z.object({
|
||||||
if (templateSelectKey) return;
|
name: z
|
||||||
|
.string({ message: t("workflow.new.modal.form.name.placeholder") })
|
||||||
setTemplateSelectKey(key);
|
.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<z.infer<typeof formSchema>>({
|
||||||
|
onSubmit: async (values) => {
|
||||||
try {
|
try {
|
||||||
let workflow: WorkflowModel;
|
let workflow: WorkflowModel;
|
||||||
|
|
||||||
switch (key) {
|
switch (templateSelectKey) {
|
||||||
case TEMPLATE_KEY_BLANK:
|
case TEMPLATE_KEY_BLANK:
|
||||||
workflow = initWorkflow();
|
workflow = initWorkflow();
|
||||||
break;
|
break;
|
||||||
@ -47,19 +65,39 @@ const WorkflowNew = () => {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw "Invalid args: `key`";
|
throw "Invalid state: `templateSelectKey`";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workflow.name = values.name?.trim() ?? workflow.name;
|
||||||
|
workflow.description = values.description?.trim() ?? workflow.description;
|
||||||
workflow = await saveWorkflow(workflow);
|
workflow = await saveWorkflow(workflow);
|
||||||
await sleep(500);
|
navigate(`/workflows/${workflow.id}`, { replace: true });
|
||||||
|
|
||||||
await navigate(`/workflows/${workflow.id}`, { replace: true });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
||||||
|
|
||||||
setTemplateSelectKey(undefined);
|
return false;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const [formModalOpen, setFormModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleTemplateClick = (key: TemplateKeys) => {
|
||||||
|
setTemplateSelectKey(key);
|
||||||
|
setFormModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleModalOpenChange = (open: boolean) => {
|
||||||
|
setFormModalOpen(open);
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
setTemplateSelectKey(undefined);
|
||||||
|
formInst.resetFields();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleModalFormFinish = () => {
|
||||||
|
return formApi.submit();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -84,7 +122,7 @@ const WorkflowNew = () => {
|
|||||||
className="size-full"
|
className="size-full"
|
||||||
cover={<img className="min-h-[120px] object-contain" src="/imgs/workflow/tpl-standard.png" />}
|
cover={<img className="min-h-[120px] object-contain" src="/imgs/workflow/tpl-standard.png" />}
|
||||||
hoverable
|
hoverable
|
||||||
onClick={() => handleTemplateSelect(TEMPLATE_KEY_STANDARD)}
|
onClick={() => handleTemplateClick(TEMPLATE_KEY_STANDARD)}
|
||||||
>
|
>
|
||||||
<div className="flex w-full items-center gap-4">
|
<div className="flex w-full items-center gap-4">
|
||||||
<Card.Meta
|
<Card.Meta
|
||||||
@ -101,7 +139,7 @@ const WorkflowNew = () => {
|
|||||||
className="size-full"
|
className="size-full"
|
||||||
cover={<img className="min-h-[120px] object-contain" src="/imgs/workflow/tpl-blank.png" />}
|
cover={<img className="min-h-[120px] object-contain" src="/imgs/workflow/tpl-blank.png" />}
|
||||||
hoverable
|
hoverable
|
||||||
onClick={() => handleTemplateSelect(TEMPLATE_KEY_BLANK)}
|
onClick={() => handleTemplateClick(TEMPLATE_KEY_BLANK)}
|
||||||
>
|
>
|
||||||
<div className="flex w-full items-center gap-4">
|
<div className="flex w-full items-center gap-4">
|
||||||
<Card.Meta
|
<Card.Meta
|
||||||
@ -115,6 +153,28 @@ const WorkflowNew = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ModalForm
|
||||||
|
disabled={formPending}
|
||||||
|
layout="vertical"
|
||||||
|
form={formInst}
|
||||||
|
modalProps={{ destroyOnClose: true }}
|
||||||
|
okText={t("common.button.submit")}
|
||||||
|
open={formModalOpen}
|
||||||
|
title={t(`workflow.new.modal.title`)}
|
||||||
|
width={480}
|
||||||
|
onFinish={handleModalFormFinish}
|
||||||
|
onOpenChange={handleModalOpenChange}
|
||||||
|
{...formProps}
|
||||||
|
>
|
||||||
|
<Form.Item name="name" label={t("workflow.new.modal.form.name.label")} rules={[formRule]}>
|
||||||
|
<Input ref={(ref) => setTimeout(() => ref?.focus({ cursor: "end" }), 0)} placeholder={t("workflow.new.modal.form.name.placeholder")} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="description" label={t("workflow.new.modal.form.description.label")} rules={[formRule]}>
|
||||||
|
<Input placeholder={t("workflow.new.modal.form.description.placeholder")} />
|
||||||
|
</Form.Item>
|
||||||
|
</ModalForm>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user