Merge pull request #1440 from certimate-go/feat/form-input-trim

feat: form input trim
This commit is contained in:
Yoan.liu
2026-08-27 20:28:06 +08:00
committed by GitHub
9 changed files with 130 additions and 11 deletions

View File

@@ -56,12 +56,12 @@ const MultipleSplitValueInput = ({
name: "componentMultipleSplitValueInput_" + nanoid(),
initialValues: { value: value?.split(delimiter) },
onSubmit: (values) => {
const temp = (values.value ?? []) as string[];
let temp = (values.value ?? []) as string[];
if (splitOptions.trimSpace) {
temp.map((e) => e.trim());
temp = temp.map((e) => e.trim());
}
if (splitOptions.removeEmpty) {
temp.filter((e) => !!e);
temp = temp.filter((e) => !!e);
}
setValue(temp.join(delimiter));

View File

@@ -12,6 +12,7 @@ import { ACCESS_USAGES } from "@/domain/provider";
import { useTriggerElement, useZustandShallowSelector } from "@/hooks";
import { useAccessesStore } from "@/stores/access";
import { unwrapErrMsg } from "@/utils/error";
import { applyTrimmedFormValues } from "@/utils/form";
import AccessForm, { type AccessFormModes, type AccessFormProps, type AccessFormUsages } from "./AccessForm";
@@ -60,6 +61,7 @@ const AccessEditDrawer = ({ afterSubmit, mode, data, loading, trigger, usage, ..
setFormPending(true);
try {
applyTrimmedFormValues(formInst);
formValues = await formInst.validateFields();
formValues.reserve = usage === "ca" ? "ca" : usage === "notification" ? "notif" : void 0;
} catch (err) {

View File

@@ -8,6 +8,7 @@ import { saveAs } from "file-saver";
import { download as downloadCertificate } from "@/api/certificates";
import { CERTIFICATE_FORMATS, type CertificateFormatType, type CertificateModel } from "@/domain/certificate";
import { useAntdForm, useTriggerElement } from "@/hooks";
import { applyTrimmedFormValues } from "@/utils/form";
export interface CertificateDownloadModalProps {
className?: string;
@@ -153,10 +154,11 @@ const CertificateDownloadModal = ({ afterClose, data, trigger, ...props }: Certi
};
const handleDownloadClick = async (format: CertificateFormatType) => {
await formInst.validateFields();
applyTrimmedFormValues(formInst);
const formValues = await formInst.validateFields();
try {
const res = await downloadCertificate(data.id, format, formInst.getFieldsValue());
const res = await downloadCertificate(data.id, format, formValues);
const bstr = atob(res.data.zipBytes);
const u8arr = Uint8Array.from(bstr, (ch) => ch.charCodeAt(0));
const blob = new Blob([u8arr], { type: "application/zip" });

View File

@@ -8,6 +8,7 @@ import { z } from "zod";
import CodeTextInput from "@/components/CodeTextInput";
import { WORKFLOW_NODE_TYPES, type WorkflowGraph, type WorkflowNode, type WorkflowNodeType } from "@/domain/workflow";
import { useAntdForm } from "@/hooks";
import { applyTrimmedFormValues } from "@/utils/form";
export type WorkflowGraphImportInputBoxFormats = "json" | "yaml";
@@ -220,6 +221,7 @@ const WorkflowGraphImportInputBox = forwardRef<WorkflowGraphImportInputBoxInstan
useImperativeHandle(ref, () => {
return {
validate: async () => {
applyTrimmedFormValues(formInst);
const formValues = await formInst.validateFields();
return deserialize(formValues.content, formValues.format);
},

View File

@@ -15,6 +15,7 @@ import {
type ExprValueType,
} from "@/domain/workflow";
import { useAntdFormName } from "@/hooks";
import { applyTrimmedFormValues } from "@/utils/form";
import { useNodeFormContext } from "./_context";
import { getAllPreviousNodes } from "../_util";
@@ -261,6 +262,7 @@ const BranchBlockNodeConfigExprInputBox = forwardRef<BranchBlockNodeConfigExprIn
useImperativeHandle(ref, () => {
return {
validate: async () => {
applyTrimmedFormValues(formInst);
const formValues = await formInst.validateFields();
return formValuesToExpr(formValues);
},

View File

@@ -8,6 +8,7 @@ import { isEqual } from "radash";
import Show from "@/components/Show";
import { unwrapErrMsg } from "@/utils/error";
import { applyTrimmedFormValues } from "@/utils/form";
import { type NodeRegistry } from "../nodes/typings";
@@ -48,6 +49,7 @@ export const NodeConfigDrawer = ({ children, afterClose, anchor, footer = true,
setFormPending(true);
try {
applyTrimmedFormValues(formInst);
formValues = await formInst.validateFields();
} catch (err) {
message.warning(t("common.errmsg.form_invalid"));

View File

@@ -1,7 +1,9 @@
import { useState } from "react";
import { useMemo, useState } from "react";
import { useDeepCompareEffect } from "ahooks";
import { Form, type FormInstance, type FormProps } from "antd";
import { applyTrimmedFormValues, trimFormValues } from "@/utils/form";
import useAntdFormName from "./useAntdFormName";
export interface UseAntdFormOptions<T extends NonNullable<unknown> = any> {
@@ -64,11 +66,24 @@ const useAntdForm = <T extends NonNullable<unknown> = any>({ form, initialValues
};
}, [formInst, initialValues]);
const onFinish = (values: T) => {
const wrappedFormInst = useMemo(() => {
const originalSubmit = formInst.submit;
return {
...formInst,
submit: () => {
applyTrimmedFormValues(formInst);
return originalSubmit();
},
};
}, [formInst]);
const doFinish = () => {
if (formPending) return Promise.reject(new Error("Form is pending"));
setFormPending(true);
const values = trimFormValues(formInst.getFieldsValue(true));
return new Promise((resolve, reject) => {
formInst
.validateFields()
@@ -93,18 +108,19 @@ const useAntdForm = <T extends NonNullable<unknown> = any>({ form, initialValues
};
const formProps: FormProps = {
form: formInst,
form: wrappedFormInst,
initialValues: formInitialValues,
name: formName,
onFinish,
onFinish: doFinish,
};
return {
form: formInst,
form: wrappedFormInst,
formProps: formProps,
formPending: formPending,
submit: () => {
return onFinish(formInst.getFieldsValue(true));
applyTrimmedFormValues(formInst);
return doFinish();
},
};
};

View File

@@ -12,6 +12,7 @@ import { ACCESS_USAGES } from "@/domain/provider";
import { useZustandShallowSelector } from "@/hooks";
import { useAccessesStore } from "@/stores/access";
import { unwrapErrMsg } from "@/utils/error";
import { applyTrimmedFormValues } from "@/utils/form";
const AccessNew = () => {
const navigate = useNavigate();
@@ -47,6 +48,7 @@ const AccessNew = () => {
setFormPending(true);
try {
applyTrimmedFormValues(formInst);
formValues = await formInst.validateFields();
formValues.reserve = providerUsage === "ca" ? "ca" : providerUsage === "notification" ? "notif" : void 0;
} catch (err) {

91
ui/src/utils/form.ts Normal file
View File

@@ -0,0 +1,91 @@
import type { FormInstance } from "antd";
export const TRIM_EXEMPT_FIELD_NAMES = new Set([
"accesskey",
"accesskeyid",
"accesskeypassword",
"accesskeysecret",
"accesstoken",
"accesstokenid",
"apiaccesstoken",
"apikey",
"apikeysecret",
"apipassword",
"apisecret",
"apitoken",
"apitokenforzone",
"apitokensecret",
"appkey",
"applicationkey",
"applicationsecret",
"applicationtoken",
"authpassword",
"bottoken",
"clientsecret",
"clienttoken",
"confirmpassword",
"consumerkey",
"credentials",
"eabhmackey",
"httptoken",
"jkskeypass",
"jksstorepass",
"key",
"keypassphrase",
"mtlsprivatekey",
"newpassword",
"oldpassword",
"password",
"personalaccesstoken",
"pfxpassword",
"privatekey",
"privatekeypassphrase",
"secret",
"secretaccesskey",
"secretapikey",
"secretid",
"secretkey",
"serviceaccountkey",
"token",
"totpsecret",
"tsiggsspassword",
"tsigkey",
"tsigsecret",
]);
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
if (typeof value !== "object" || value === null) {
return false;
}
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null;
};
const trimValue = (value: unknown, key?: string): unknown => {
if (typeof value === "string") {
return key != null && TRIM_EXEMPT_FIELD_NAMES.has(key.toLowerCase()) ? value : value.trim();
}
if (Array.isArray(value)) {
return value.map((item) => trimValue(item));
}
if (isPlainObject(value)) {
const obj: Record<string, unknown> = {};
Object.keys(value).forEach((k) => {
obj[k] = trimValue(value[k], k);
});
return obj;
}
return value;
};
export const trimFormValues = <T>(values: T): T => {
return trimValue(values) as T;
};
export const applyTrimmedFormValues = (formInst: FormInstance): void => {
formInst.setFieldsValue(trimFormValues(formInst.getFieldsValue(true)));
};