diff --git a/.gitattributes b/.gitattributes index ceb414770..128e843f5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 \ No newline at end of file +frontend/src/test/__snapshots__/** text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 40c7306ca..6fef50ece 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/frontend/src/pages/nodes/NodeFormModal.tsx b/frontend/src/pages/nodes/NodeFormModal.tsx index a6906a52e..6d5f58d9a 100644 --- a/frontend/src/pages/nodes/NodeFormModal.tsx +++ b/frontend/src/pages/nodes/NodeFormModal.tsx @@ -85,6 +85,8 @@ export default function NodeFormModal({ ...(node as unknown as Partial), 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'; diff --git a/frontend/src/schemas/node.ts b/frontend/src/schemas/node.ts index ec161b05a..2379ddebf 100644 --- a/frontend/src/schemas/node.ts +++ b/frontend/src/schemas/node.ts @@ -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;