From 2cd5a1c630766ea3ce5766ca86b9212375230626 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Tue, 23 Dec 2025 22:44:19 +0800 Subject: [PATCH] feat(ui): save and continue button in drawer forms --- ui/src/components/access/AccessEditDrawer.tsx | 67 ++++++++++----- .../certificate/CertificateDetail.tsx | 4 +- .../workflow/designer/forms/_shared.tsx | 81 +++++++++++++------ ui/src/i18n/locales/en/nls.access.json | 2 +- ui/src/i18n/locales/en/nls.common.json | 1 + ui/src/i18n/locales/zh/nls.access.json | 2 +- ui/src/i18n/locales/zh/nls.common.json | 1 + 7 files changed, 108 insertions(+), 50 deletions(-) diff --git a/ui/src/components/access/AccessEditDrawer.tsx b/ui/src/components/access/AccessEditDrawer.tsx index a90174f5..12989472 100644 --- a/ui/src/components/access/AccessEditDrawer.tsx +++ b/ui/src/components/access/AccessEditDrawer.tsx @@ -1,8 +1,8 @@ import { startTransition, useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; -import { IconX } from "@tabler/icons-react"; +import { IconChevronDown, IconX } from "@tabler/icons-react"; import { useControllableValue, useGetState } from "ahooks"; -import { App, Button, Drawer, Flex, Form } from "antd"; +import { App, Button, Drawer, Dropdown, Flex, Form, Space } from "antd"; import { notifyTest } from "@/api/notify"; import AccessProviderPicker from "@/components/provider/AccessProviderPicker"; @@ -55,19 +55,7 @@ const AccessEditDrawer = ({ afterSubmit, mode, data, loading, trigger, usage, .. const [formPending, setFormPending] = useState(false); const [formChanged, setFormChanged] = useState(false); - const fieldProvider = Form.useWatch("provider", { form: formInst, preserve: true }); - - const [isTesting, setIsTesting] = useState(false); - - const handleProviderPick = (value: string) => { - formInst.setFieldValue("provider", value); - }; - - const handleFormChange = () => { - setFormChanged(true); - }; - - const handleOkClick = async () => { + const submitForm = async () => { let formValues: AccessModel; setFormPending(true); @@ -108,7 +96,6 @@ const AccessEditDrawer = ({ afterSubmit, mode, data, loading, trigger, usage, .. } afterSubmit?.(formValues); - setOpen(false); } catch (err) { notification.error({ title: t("common.text.request_error"), description: getErrMsg(err) }); @@ -118,6 +105,27 @@ const AccessEditDrawer = ({ afterSubmit, mode, data, loading, trigger, usage, .. } }; + const fieldProvider = Form.useWatch("provider", { form: formInst, preserve: true }); + + const [isTesting, setIsTesting] = useState(false); + + const handleProviderPick = (value: string) => { + formInst.setFieldValue("provider", value); + }; + + const handleFormChange = () => { + setFormChanged(true); + }; + + const handleOkClick = async () => { + await submitForm(); + setOpen(false); + }; + + const handleOkAndContinueClick = async () => { + await submitForm(); + }; + const handleCancelClick = () => { if (formPending) return; @@ -157,7 +165,7 @@ const AccessEditDrawer = ({ afterSubmit, mode, data, loading, trigger, usage, .. fieldProvider ? ( {usage === "notification" ? ( - ) : ( @@ -167,9 +175,28 @@ const AccessEditDrawer = ({ afterSubmit, mode, data, loading, trigger, usage, .. - + + + + + diff --git a/ui/src/components/workflow/designer/forms/_shared.tsx b/ui/src/components/workflow/designer/forms/_shared.tsx index 2cdfdc9f..069865ee 100644 --- a/ui/src/components/workflow/designer/forms/_shared.tsx +++ b/ui/src/components/workflow/designer/forms/_shared.tsx @@ -1,9 +1,9 @@ import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { type FlowNodeEntity, useClientContext, useRefresh } from "@flowgram.ai/fixed-layout-editor"; -import { IconEye, IconEyeOff, IconX } from "@tabler/icons-react"; +import { IconChevronDown, IconEye, IconEyeOff, IconX } from "@tabler/icons-react"; import { useControllableValue } from "ahooks"; -import { Anchor, type AnchorProps, App, Button, Drawer, Flex, type FormInstance, Tooltip, Typography } from "antd"; +import { Anchor, type AnchorProps, App, Button, Drawer, Dropdown, Flex, type FormInstance, Space, Tooltip, Typography } from "antd"; import { isEqual } from "radash"; import Show from "@/components/Show"; @@ -43,6 +43,31 @@ export const NodeConfigDrawer = ({ children, afterClose, anchor, footer = true, const [formPending, setFormPending] = useState(false); + const submitForm = async () => { + let formValues: Record; + + setFormPending(true); + try { + formValues = await formInst.validateFields(); + } catch (err) { + message.warning(t("common.errmsg.form_invalid")); + + setFormPending(false); + throw err; + } + + try { + node.form!.setValueIn("config", formValues); + node.form!.validate(); + } catch (err) { + notification.error({ title: t("common.text.request_error"), description: getErrMsg(err) }); + + throw err; + } finally { + setFormPending(false); + } + }; + const nodeRegistry = node?.getNodeRegistry(); const NodeIcon = nodeRegistry?.meta?.icon; const renderNodeIcon = () => @@ -80,30 +105,17 @@ export const NodeConfigDrawer = ({ children, afterClose, anchor, footer = true, return; } - let formValues: Record; - - setFormPending(true); - try { - formValues = await formInst.validateFields(); - } catch (err) { - message.warning(t("common.errmsg.form_invalid")); - - setFormPending(false); - throw err; - } - - try { - node.form!.setValueIn("config", formValues); - node.form!.validate(); + await submitForm(); + setOpen(false); + }; + const handleOkAndContinueClick = async () => { + if (node == null) { setOpen(false); - } catch (err) { - notification.error({ title: t("common.text.request_error"), description: getErrMsg(err) }); - - throw err; - } finally { - setFormPending(false); + return; } + + await submitForm(); }; const handleCancelClick = () => { @@ -170,9 +182,26 @@ export const NodeConfigDrawer = ({ children, afterClose, anchor, footer = true, footer ? ( - + + + +