mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-18 10:17:36 +07:00
fix(nodes): "Invalid input" when saving a node with inbound sync mode "all"
NodeFormSchema required inboundTags, but the inboundTags Form.Item is only mounted when inboundSyncMode is "selected" - antd onFinish omits unmounted fields, so saving with the default "all" mode failed schema validation with Zod generic "Invalid input" (regression from #5178; same class as the earlier pinnedCertSha256 fix). Also tolerate null inboundTags (Go nil slice) for nodes saved before #5178, both in the form schema and NodeRecordSchema, and normalize edit-mode values.
This commit is contained in:
7
.gitattributes
vendored
7
.gitattributes
vendored
@ -1,11 +1,6 @@
|
||||
# Shell scripts must stay LF so the Docker build works when the repo is
|
||||
# checked out on Windows (CRLF breaks the script shebang -> exit 127).
|
||||
*.sh text eol=lf
|
||||
DockerInit.sh text eol=lf
|
||||
DockerEntrypoint.sh text eol=lf
|
||||
|
||||
# Generated files (regenerated from Go) must stay LF so a Windows regen
|
||||
# with core.autocrlf=true doesn't show phantom CRLF-only "modified" diffs.
|
||||
frontend/src/generated/** text eol=lf
|
||||
frontend/public/openapi.json text eol=lf
|
||||
frontend\src\test\__snapshots__\** text eol=lf
|
||||
frontend/src/test/__snapshots__/** text eol=lf
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -36,6 +36,7 @@ Thumbs.db
|
||||
x-ui.db
|
||||
x-ui.db-shm
|
||||
x-ui.db-wal
|
||||
system_metrics.gob
|
||||
*.dump
|
||||
|
||||
# Ignore Docker specific files
|
||||
|
||||
@ -85,6 +85,8 @@ export default function NodeFormModal({
|
||||
...(node as unknown as Partial<NodeFormValues>),
|
||||
id: node.id,
|
||||
scheme: (node.scheme as 'http' | 'https') || base.scheme,
|
||||
inboundSyncMode: (node.inboundSyncMode as 'all' | 'selected') || base.inboundSyncMode,
|
||||
inboundTags: node.inboundTags ?? [],
|
||||
}
|
||||
: base;
|
||||
if (next.scheme === 'http') next.tlsVerifyMode = 'skip';
|
||||
|
||||
@ -32,7 +32,8 @@ export const NodeRecordSchema = z.object({
|
||||
tlsVerifyMode: z.enum(['verify', 'skip', 'pin']).optional(),
|
||||
pinnedCertSha256: z.string().optional(),
|
||||
inboundSyncMode: z.enum(['all', 'selected']).optional(),
|
||||
inboundTags: z.array(z.string()).optional(),
|
||||
// Backend serializes a nil []string as null for nodes saved before #5178.
|
||||
inboundTags: z.array(z.string()).nullish(),
|
||||
// Multi-hop node tree (#4983): a node's stable GUID, its parent's GUID, and
|
||||
// whether it's a read-only transitive sub-node surfaced from a downstream node.
|
||||
guid: z.string().optional(),
|
||||
@ -65,8 +66,10 @@ export const NodeFormSchema = z.object({
|
||||
allowPrivateAddress: z.boolean(),
|
||||
tlsVerifyMode: z.enum(['verify', 'skip', 'pin']),
|
||||
pinnedCertSha256: z.string().optional().default(''),
|
||||
inboundSyncMode: z.enum(['all', 'selected']),
|
||||
inboundTags: z.array(z.string()),
|
||||
inboundSyncMode: z.enum(['all', 'selected']).optional().default('all'),
|
||||
// Unmounted when sync mode is "all" (absent from antd onFinish values) and
|
||||
// serialized as null by the backend for a nil slice — tolerate both.
|
||||
inboundTags: z.array(z.string()).nullish().transform((tags) => tags ?? []),
|
||||
});
|
||||
|
||||
export type NodeRecord = z.infer<typeof NodeRecordSchema>;
|
||||
|
||||
Reference in New Issue
Block a user