From 9139a45699d73f3b6e9d30e81ec9e48cb34d5eca Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 5 Sep 2025 09:06:09 +0800 Subject: [PATCH] feat(ui): enhance providers select --- ui/src/components/MultipleSplitValueInput.tsx | 2 +- ui/src/components/access/AccessEditDrawer.tsx | 1 + ui/src/components/access/AccessForm.tsx | 2 +- .../provider/AccessProviderPicker.tsx | 127 +++++++------- .../provider/DeploymentProviderPicker.tsx | 38 ++-- .../provider/DeploymentProviderSelect.tsx | 58 ++++--- .../provider/NotificationProviderPicker.tsx | 36 ++-- .../provider/NotificationProviderSelect.tsx | 58 ++++--- ui/src/components/provider/_shared.ts | 162 +++++++++++------- .../designer/forms/BizApplyNodeConfigForm.tsx | 66 +++++-- .../forms/BizDeployNodeConfigForm.tsx | 77 +++++---- .../forms/BizMonitorNodeConfigForm.tsx | 2 +- .../forms/BizNotifyNodeConfigForm.tsx | 11 +- .../forms/BizUploadNodeConfigForm.tsx | 2 +- .../forms/BranchBlockNodeConfigForm.tsx | 2 +- .../designer/forms/DelayNodeConfigForm.tsx | 2 +- .../designer/forms/StartNodeConfigForm.tsx | 2 +- ui/src/domain/workflow.ts | 1 - ui/src/hooks/useAntdForm.ts | 2 +- ui/src/i18n/locales/en/nls.provider.json | 4 +- ui/src/i18n/locales/zh/nls.provider.json | 4 +- ui/src/pages/accesses/AccessNew.tsx | 1 + 22 files changed, 385 insertions(+), 275 deletions(-) diff --git a/ui/src/components/MultipleSplitValueInput.tsx b/ui/src/components/MultipleSplitValueInput.tsx index d161c8474..e09082e2c 100644 --- a/ui/src/components/MultipleSplitValueInput.tsx +++ b/ui/src/components/MultipleSplitValueInput.tsx @@ -56,7 +56,7 @@ const MultipleSplitValueInput = ({ name: "componentMultipleSplitValueInput_" + nanoid(), initialValues: { value: value?.split(delimiter) }, onSubmit: (values) => { - const temp = values.value ?? []; + const temp = (values.value ?? []) as string[]; if (splitOptions.trimSpace) { temp.map((e) => e.trim()); } diff --git a/ui/src/components/access/AccessEditDrawer.tsx b/ui/src/components/access/AccessEditDrawer.tsx index 29c02c12f..df5a2c26d 100644 --- a/ui/src/components/access/AccessEditDrawer.tsx +++ b/ui/src/components/access/AccessEditDrawer.tsx @@ -146,6 +146,7 @@ const AccessEditDrawer = ({ afterClose, afterSubmit, mode, data, loading, trigge gap="large" placeholder={t("access.form.provider.search.placeholder")} showOptionTags={usage == null || (usage === "dns-hosting" ? { [ACCESS_USAGES.DNS]: true, [ACCESS_USAGES.HOSTING]: true } : false)} + showSearch onFilter={providerFilter} onSelect={handleProviderPick} /> diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 742782a87..976434ae7 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -112,7 +112,7 @@ const AccessForm = ({ className, style, disabled, initialValues, mode, usage, .. reserve: z.string().nullish(), }); const formRule = createSchemaFieldRule(formSchema); - const { form: formInst, formProps } = useAntdForm({ + const { form: formInst, formProps } = useAntdForm>({ form: props.form, name: "accessForm", initialValues: initialValues, diff --git a/ui/src/components/provider/AccessProviderPicker.tsx b/ui/src/components/provider/AccessProviderPicker.tsx index 3b7f1c5aa..6620c43c1 100644 --- a/ui/src/components/provider/AccessProviderPicker.tsx +++ b/ui/src/components/provider/AccessProviderPicker.tsx @@ -7,7 +7,7 @@ import Show from "@/components/Show"; import { ACCESS_USAGES, type AccessProvider, type AccessUsageType, accessProvidersMap } from "@/domain/provider"; import { mergeCls } from "@/utils/css"; -import { type SharedPickerProps, usePickerWrapperCols } from "./_shared"; +import { type SharedPickerProps, usePickerDataSource, usePickerWrapperCols } from "./_shared"; export interface AccessProviderPickerProps extends SharedPickerProps { showOptionTags?: boolean | { [key in AccessUsageType]?: boolean }; @@ -20,7 +20,7 @@ const AccessProviderPicker = ({ gap = "middle", placeholder, showOptionTags, - showSearch = true, + showSearch = false, onFilter, onSelect, }: AccessProviderPickerProps) => { @@ -52,24 +52,62 @@ const AccessProviderPicker = ({ } }); - const providers = useMemo(() => { - return Array.from(accessProvidersMap.values()) - .filter((provider) => { - if (onFilter) { - return onFilter(provider.type, provider); - } + const dataSources = usePickerDataSource({ + dataSource: Array.from(accessProvidersMap.values()), + filters: [onFilter!], + keyword: keyword, + }); - return true; - }) - .filter((provider) => { - if (keyword) { - const value = keyword.toLowerCase(); - return provider.type.toLowerCase().includes(value) || t(provider.name).toLowerCase().includes(value); - } + const renderOption = (provider: AccessProvider) => { + return ( +
+ { + if (provider.builtin) { + return; + } - return true; - }); - }, [onFilter, keyword]); + handleProviderTypeSelect(provider.type); + }} + > +
+
+ } shape="square" size={32} /> +
+
+
+ + {t(provider.name) || "\u00A0"} + +
+ +
+ + {t("access.props.provider.builtin")} + + + {t("access.props.provider.usage.dns")} + + + {t("access.props.provider.usage.hosting")} + + + {t("access.props.provider.usage.ca")} + + + {t("access.props.provider.usage.notification")} + +
+
+
+
+
+
+ ); + }; const handleProviderTypeSelect = (value: string) => { onSelect?.(value); @@ -83,7 +121,7 @@ const AccessProviderPicker = ({ - 0} fallback={}> + 0} fallback={}>
- {providers.map((provider) => { - return ( -
- { - if (provider.builtin) { - return; - } - - handleProviderTypeSelect(provider.type); - }} - > -
-
- } shape="square" size={32} /> -
-
-
- - {t(provider.name) || "\u00A0"} - -
- -
- - {t("access.props.provider.builtin")} - - - {t("access.props.provider.usage.dns")} - - - {t("access.props.provider.usage.hosting")} - - - {t("access.props.provider.usage.ca")} - - - {t("access.props.provider.usage.notification")} - -
-
-
-
-
-
- ); - })} + {dataSources.filtered.map((provider) => renderOption(provider))}
diff --git a/ui/src/components/provider/DeploymentProviderPicker.tsx b/ui/src/components/provider/DeploymentProviderPicker.tsx index 193bb6da0..61e4b98d7 100644 --- a/ui/src/components/provider/DeploymentProviderPicker.tsx +++ b/ui/src/components/provider/DeploymentProviderPicker.tsx @@ -10,7 +10,7 @@ import { mergeCls } from "@/utils/css"; import { type SharedPickerProps, usePickerDataSource, usePickerWrapperCols } from "./_shared"; export interface DeploymentProviderPickerProps extends SharedPickerProps { - showAvailable?: boolean; + showAvailability?: boolean; } const DeploymentProviderPicker = ({ @@ -19,8 +19,8 @@ const DeploymentProviderPicker = ({ autoFocus, gap = "middle", placeholder, - showAvailable = true, - showSearch = true, + showAvailability = false, + showSearch = false, onFilter, onSelect, }: DeploymentProviderPickerProps) => { @@ -41,7 +41,8 @@ const DeploymentProviderPicker = ({ const dataSources = usePickerDataSource({ dataSource: Array.from(deploymentProvidersMap.values()), filters: [ - (provider) => { + onFilter!, + (_, provider) => { if (category && category !== DEPLOYMENT_CATEGORIES.ALL) { return provider.category === category; } @@ -50,28 +51,29 @@ const DeploymentProviderPicker = ({ }, ], keyword: keyword, - onFilter: onFilter, deps: [category], }); - const renderOption = (provider: DeploymentProvider) => { + const renderOption = (provider: DeploymentProvider, transparent: boolean = false) => { return (
{ handleProviderTypeSelect(provider.type); }} > -
- } shape="square" size={28} /> -
-
- - {t(provider.name) || "\u00A0"} - +
+
+ } shape="square" size={28} /> +
+
+ + {t(provider.name) || "\u00A0"} + +
@@ -129,13 +131,13 @@ const DeploymentProviderPicker = ({ [`gap-${+gap || "2"}`]: typeof gap === "number", })} > - {(showAvailable ? dataSources.available : dataSources.filtered).map((provider) => renderOption(provider))} + {(showAvailability ? dataSources.available : dataSources.filtered).map((provider) => renderOption(provider))}
- 0}> + 0}> - {t("provider.text.unavailable_options")} + {t("provider.text.unavailable_divider")} @@ -147,7 +149,7 @@ const DeploymentProviderPicker = ({ [`gap-${+gap || "2"}`]: typeof gap === "number", })} > - {dataSources.unavailable.map((provider) => renderOption(provider))} + {dataSources.unavailable.map((provider) => renderOption(provider, true))}
diff --git a/ui/src/components/provider/DeploymentProviderSelect.tsx b/ui/src/components/provider/DeploymentProviderSelect.tsx index cd6f5b6d5..285e0e690 100644 --- a/ui/src/components/provider/DeploymentProviderSelect.tsx +++ b/ui/src/components/provider/DeploymentProviderSelect.tsx @@ -1,34 +1,31 @@ -import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Avatar, Select, Typography, theme } from "antd"; import { type DeploymentProvider, deploymentProvidersMap } from "@/domain/provider"; -import { type SharedSelectProps } from "./_shared"; +import { type SharedSelectProps, useSelectDataSource } from "./_shared"; -export interface DeploymentProviderSelectProps extends SharedSelectProps {} +export interface DeploymentProviderSelectProps extends SharedSelectProps { + showAvailability?: boolean; +} -const DeploymentProviderSelect = ({ onFilter, ...props }: DeploymentProviderSelectProps) => { +const DeploymentProviderSelect = ({ showAvailability = false, onFilter, ...props }: DeploymentProviderSelectProps) => { const { t } = useTranslation(); const { token: themeToken } = theme.useToken(); - const options = useMemo>(() => { - return Array.from(deploymentProvidersMap.values()) - .filter((provider) => { - if (onFilter) { - return onFilter(provider.type, provider); - } - - return true; - }) - .map((provider) => ({ - key: provider.type, - value: provider.type, - label: t(provider.name), - data: provider, - })); - }, [onFilter]); + const dataSources = useSelectDataSource({ + dataSource: Array.from(deploymentProvidersMap.values()), + filters: [onFilter!], + }); + const dataSource2Options = (providers: DeploymentProvider[]): Array<{ key: string; value: string; label: string; data: DeploymentProvider }> => { + return providers.map((provider) => ({ + key: provider.type, + value: provider.type, + label: t(provider.name), + data: provider, + })); + }; const renderOption = (key: string) => { const provider = deploymentProvidersMap.get(key); @@ -45,9 +42,11 @@ const DeploymentProviderSelect = ({ onFilter, ...props }: DeploymentProviderSele {...props} filterOption={(inputValue, option) => { if (!option) return false; + if (!option.label) return false; + if (!option.value) return false; const value = inputValue.toLowerCase(); - return option.value.toLowerCase().includes(value) || option.label.toLowerCase().includes(value); + return String(option.value).toLowerCase().includes(value) || String(option.label).toLowerCase().includes(value); }} labelRender={({ value }) => { if (value != null) { @@ -56,10 +55,23 @@ const DeploymentProviderSelect = ({ onFilter, ...props }: DeploymentProviderSele return {props.placeholder}; }} - options={options} + options={ + showAvailability + ? [ + { + label: t("provider.text.available_group"), + options: dataSource2Options(dataSources.available), + }, + { + label: t("provider.text.unavailable_group"), + options: dataSource2Options(dataSources.unavailable), + }, + ] + : dataSource2Options(dataSources.filtered) + } optionFilterProp={void 0} optionLabelProp={void 0} - optionRender={(option) => renderOption(option.data.value)} + optionRender={(option) => renderOption(option.data.value as string)} /> ); }; diff --git a/ui/src/components/provider/NotificationProviderPicker.tsx b/ui/src/components/provider/NotificationProviderPicker.tsx index 2a6bdc45e..7a46c3885 100644 --- a/ui/src/components/provider/NotificationProviderPicker.tsx +++ b/ui/src/components/provider/NotificationProviderPicker.tsx @@ -10,7 +10,7 @@ import { mergeCls } from "@/utils/css"; import { type SharedPickerProps, usePickerDataSource, usePickerWrapperCols } from "./_shared"; export interface NotificationProviderPickerProps extends SharedPickerProps { - showAvailable?: boolean; + showAvailability?: boolean; } const NotificationProviderPicker = ({ @@ -19,8 +19,8 @@ const NotificationProviderPicker = ({ autoFocus, gap = "middle", placeholder, - showAvailable = true, - showSearch = true, + showAvailability = false, + showSearch = false, onFilter, onSelect, }: NotificationProviderPickerProps) => { @@ -38,28 +38,30 @@ const NotificationProviderPicker = ({ const dataSources = usePickerDataSource({ dataSource: Array.from(notificationProvidersMap.values()), + filters: [onFilter!], keyword: keyword, - onFilter: onFilter, }); - const renderOption = (provider: NotificationProvider) => { + const renderOption = (provider: NotificationProvider, transparent: boolean = false) => { return (
{ handleProviderTypeSelect(provider.type); }} > -
- } shape="square" size={28} /> -
-
- - {t(provider.name) || "\u00A0"} - +
+
+ } shape="square" size={28} /> +
+
+ + {t(provider.name) || "\u00A0"} + +
@@ -89,13 +91,13 @@ const NotificationProviderPicker = ({ [`gap-${+gap || "2"}`]: typeof gap === "number", })} > - {(showAvailable ? dataSources.available : dataSources.filtered).map((provider) => renderOption(provider))} + {(showAvailability ? dataSources.available : dataSources.filtered).map((provider) => renderOption(provider))}
- 0}> + 0}> - {t("provider.text.unavailable_options")} + {t("provider.text.unavailable_divider")} @@ -107,7 +109,7 @@ const NotificationProviderPicker = ({ [`gap-${+gap || "2"}`]: typeof gap === "number", })} > - {dataSources.unavailable.map((provider) => renderOption(provider))} + {dataSources.unavailable.map((provider) => renderOption(provider, true))}
diff --git a/ui/src/components/provider/NotificationProviderSelect.tsx b/ui/src/components/provider/NotificationProviderSelect.tsx index f7f86ad16..ee65f35f3 100644 --- a/ui/src/components/provider/NotificationProviderSelect.tsx +++ b/ui/src/components/provider/NotificationProviderSelect.tsx @@ -1,34 +1,31 @@ -import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Avatar, Select, Typography, theme } from "antd"; import { type NotificationProvider, notificationProvidersMap } from "@/domain/provider"; -import { type SharedSelectProps } from "./_shared"; +import { type SharedSelectProps, useSelectDataSource } from "./_shared"; -export interface NotificationProviderSelectProps extends SharedSelectProps {} +export interface NotificationProviderSelectProps extends SharedSelectProps { + showAvailability?: boolean; +} -const NotificationProviderSelect = ({ onFilter, ...props }: NotificationProviderSelectProps) => { +const NotificationProviderSelect = ({ showAvailability = false, onFilter, ...props }: NotificationProviderSelectProps) => { const { t } = useTranslation(); const { token: themeToken } = theme.useToken(); - const options = useMemo>(() => { - return Array.from(notificationProvidersMap.values()) - .filter((provider) => { - if (onFilter) { - return onFilter(provider.type, provider); - } - - return true; - }) - .map((provider) => ({ - key: provider.type, - value: provider.type, - label: t(provider.name), - data: provider, - })); - }, [onFilter]); + const dataSources = useSelectDataSource({ + dataSource: Array.from(notificationProvidersMap.values()), + filters: [onFilter!], + }); + const dataSource2Options = (providers: NotificationProvider[]): Array<{ key: string; value: string; label: string; data: NotificationProvider }> => { + return providers.map((provider) => ({ + key: provider.type, + value: provider.type, + label: t(provider.name), + data: provider, + })); + }; const renderOption = (key: string) => { const provider = notificationProvidersMap.get(key); @@ -45,9 +42,11 @@ const NotificationProviderSelect = ({ onFilter, ...props }: NotificationProvider {...props} filterOption={(inputValue, option) => { if (!option) return false; + if (!option.label) return false; + if (!option.value) return false; const value = inputValue.toLowerCase(); - return option.value.toLowerCase().includes(value) || option.label.toLowerCase().includes(value); + return String(option.value).toLowerCase().includes(value) || String(option.label).toLowerCase().includes(value); }} labelRender={({ value }) => { if (value != null) { @@ -56,10 +55,23 @@ const NotificationProviderSelect = ({ onFilter, ...props }: NotificationProvider return {props.placeholder}; }} - options={options} + options={ + showAvailability + ? [ + { + label: t("provider.text.available_group"), + options: dataSource2Options(dataSources.available), + }, + { + label: t("provider.text.unavailable_group"), + options: dataSource2Options(dataSources.unavailable), + }, + ] + : dataSource2Options(dataSources.filtered) + } optionFilterProp={void 0} optionLabelProp={void 0} - optionRender={(option) => renderOption(option.data.value)} + optionRender={(option) => renderOption(option.data.value as string)} /> ); }; diff --git a/ui/src/components/provider/_shared.ts b/ui/src/components/provider/_shared.ts index ff345c880..9f47e4c44 100644 --- a/ui/src/components/provider/_shared.ts +++ b/ui/src/components/provider/_shared.ts @@ -16,81 +16,30 @@ export interface SharedSelectProps onFilter?: (value: string, option: T) => boolean; } -export interface SharedPickerProps { - className?: string; - style?: React.CSSProperties; - autoFocus?: boolean; - gap?: number | "small" | "middle" | "large"; - placeholder?: string; - showSearch?: boolean; - onFilter?: (value: string, option: T) => boolean; - onSelect?: (value: string) => void; -} - -export const usePickerWrapperCols = (width: number) => { - const wrapperElRef = useRef(null); - const wrapperSize = useSize(wrapperElRef); - - const cols = useMemo(() => { - if (!wrapperSize) { - return 1; - } - - const cols = Math.floor(wrapperSize.width / width); - return Math.min(9, Math.max(1, cols)); - }, [wrapperSize, width]); - - return { - wrapperElRef, - cols, - }; -}; - -export const usePickerDataSource = ({ +export const useSelectDataSource = ({ dataSource, filters, - keyword, - onFilter, deps, }: { dataSource: T[]; - filters?: Array<(option: T) => boolean>; - keyword?: string; - onFilter?: (value: string, option: T) => boolean; + filters?: Array<(value: string, option: T) => boolean>; deps?: React.DependencyList; }) => { - const { t } = useTranslation(); - const { accesses, fetchAccesses } = useAccessesStore(useZustandShallowSelector(["accesses", "fetchAccesses"])); useMount(() => fetchAccesses(false)); const filteredDataSource = useMemo(() => { - return dataSource - .filter((provider) => { - if (onFilter) { - return onFilter(provider.type, provider); + return dataSource.filter((provider) => { + if (filters) { + for (const filter of filters) { + if (!filter) continue; + if (!filter(provider.type, provider)) return false; } + } - return true; - }) - .filter((provider) => { - if (filters) { - for (const filter of filters) { - if (!filter(provider)) return false; - } - } - - return true; - }) - .filter((provider) => { - if (keyword) { - const value = keyword.toLowerCase(); - return provider.type.toLowerCase().includes(value) || t(provider.name).toLowerCase().includes(value); - } - - return true; - }); - }, [dataSource, filters, keyword, onFilter, ...(deps ?? [])]); + return true; + }); + }, [dataSource, filters, ...(deps ?? [])]); const availableDataSource = useMemo(() => { return filteredDataSource.filter((provider) => { @@ -107,7 +56,94 @@ export const usePickerDataSource = ({ }, [filteredDataSource, availableDataSource, ...(deps ?? [])]); return { - all: dataSource, + raw: dataSource, + filtered: filteredDataSource, + available: availableDataSource, + unavailable: unavailableDataSource, + }; +}; + +export interface SharedPickerProps { + className?: string; + style?: React.CSSProperties; + autoFocus?: boolean; + gap?: number | "small" | "middle" | "large"; + placeholder?: string; + showSearch?: boolean; + onFilter?: (value: string, option: T) => boolean; + onSelect?: (value: string) => void; +} + +export const usePickerWrapperCols = (width: number) => { + const wrapperElRef = useRef(null); + const wrapperSize = useSize(wrapperElRef); + + const columns = useMemo(() => { + const wWidth = wrapperSize?.width ?? document.body.clientWidth - 256; + const wCols = Math.floor(wWidth / width); + return Math.min(9, Math.max(1, wCols)); + }, [wrapperSize, width]); + + return { + wrapperElRef, + cols: columns, + }; +}; + +export const usePickerDataSource = ({ + dataSource, + filters, + keyword, + deps, +}: { + dataSource: T[]; + filters?: Array<(value: string, option: T) => boolean>; + keyword?: string; + deps?: React.DependencyList; +}) => { + const { t } = useTranslation(); + + const { accesses, fetchAccesses } = useAccessesStore(useZustandShallowSelector(["accesses", "fetchAccesses"])); + useMount(() => fetchAccesses(false)); + + const filteredDataSource = useMemo(() => { + return dataSource + .filter((provider) => { + if (filters) { + for (const filter of filters) { + if (!filter) continue; + if (!filter(provider.type, provider)) return false; + } + } + + return true; + }) + .filter((provider) => { + if (keyword) { + const value = keyword.toLowerCase(); + return provider.type.toLowerCase().includes(value) || t(provider.name).toLowerCase().includes(value); + } + + return true; + }); + }, [dataSource, filters, keyword, ...(deps ?? [])]); + + const availableDataSource = useMemo(() => { + return filteredDataSource.filter((provider) => { + return accesses.some((access) => { + if ("builtin" in provider && provider.builtin) return true; + if ("provider" in provider) return access.provider === provider.provider; + return access.provider === provider.type; + }); + }); + }, [accesses, filteredDataSource, ...(deps ?? [])]); + + const unavailableDataSource = useMemo(() => { + return filteredDataSource.filter((item) => !availableDataSource.includes(item)); + }, [filteredDataSource, availableDataSource, ...(deps ?? [])]); + + return { + raw: dataSource, filtered: filteredDataSource, available: availableDataSource, unavailable: unavailableDataSource, diff --git a/ui/src/components/workflow/designer/forms/BizApplyNodeConfigForm.tsx b/ui/src/components/workflow/designer/forms/BizApplyNodeConfigForm.tsx index 423d96f64..888bf7635 100644 --- a/ui/src/components/workflow/designer/forms/BizApplyNodeConfigForm.tsx +++ b/ui/src/components/workflow/designer/forms/BizApplyNodeConfigForm.tsx @@ -4,7 +4,22 @@ import { Link } from "react-router"; import { type FlowNodeEntity, getNodeForm } from "@flowgram.ai/fixed-layout-editor"; import { IconChevronRight, IconCircleMinus, IconPlus } from "@tabler/icons-react"; import { useControllableValue, useMount } from "ahooks"; -import { type AnchorProps, AutoComplete, Button, Divider, Flex, Form, type FormInstance, Input, InputNumber, Select, Space, Switch, Typography } from "antd"; +import { + type AnchorProps, + AutoComplete, + Button, + Divider, + Flex, + Form, + type FormInstance, + Input, + InputNumber, + Radio, + Select, + Space, + Switch, + Typography, +} from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -31,6 +46,9 @@ import { NodeType } from "../nodes/typings"; const MULTIPLE_INPUT_SEPARATOR = ";"; +const CHALLENGE_TYPE_DNS01 = "dns-01"; +const CHALLENGE_TYPE_HTTP01 = "http-01"; + export interface BizApplyNodeConfigFormProps { form: FormInstance; node: FlowNodeEntity; @@ -51,12 +69,13 @@ const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps) const formSchema = getSchema({ i18n }); const formRule = createSchemaFieldRule(formSchema); - const { form: formInst, formProps } = useAntdForm({ + const { form: formInst, formProps } = useAntdForm>({ form: props.form, name: "workflowNodeBizApplyConfigForm", initialValues: initialValues ?? getInitialValues(), }); + const fieldChallengeType = Form.useWatch("challengeType", { form: formInst, preserve: true }); const fieldProvider = Form.useWatch("provider", { form: formInst, preserve: true }); const fieldProviderAccessId = Form.useWatch("providerAccessId", { form: formInst, preserve: true }); const fieldCAProvider = Form.useWatch("caProvider", { form: formInst, preserve: true }); @@ -112,6 +131,29 @@ const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps) } }, [fieldCAProvider]); + const handleChallengeTypeChange = (value: string) => { + switch (value) { + case CHALLENGE_TYPE_DNS01: + { + formInst.setFieldValue("provider", void 0); + formInst.setFieldValue("providerAccessId", void 0); + formInst.setFieldValue("providerConfig", void 0); + } + break; + + case CHALLENGE_TYPE_HTTP01: + { + formInst.setFieldValue("provider", void 0); + formInst.setFieldValue("providerAccessId", void 0); + formInst.setFieldValue("providerConfig", void 0); + formInst.setFieldValue("dnsPropagationWait", void 0); + formInst.setFieldValue("dnsPropagationTimeout", void 0); + formInst.setFieldValue("dnsTTL", void 0); + } + break; + } + }; + const handleProviderSelect = (value: string) => { if (fieldProvider === value) return; @@ -136,7 +178,7 @@ const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps) const handleCAProviderSelect = (value?: string | undefined) => { // 切换 CA 提供商时联动授权信息 - if (value === "") { + if (value == null || value === "") { setTimeout(() => { formInst.setFieldValue("caProvider", void 0); formInst.setFieldValue("caProviderAccessId", void 0); @@ -173,14 +215,11 @@ const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps) - +
+ +
+ + + {t("workflow_node.deploy.form_anchor.deployment.title")} + + + - -