🐛 fix: Simplify initialValues assignment and update node submission logic in NodesPage
This commit is contained in:
parent
8700cf6a91
commit
05d6c8947c
@ -74,6 +74,20 @@ export default function NodeForm(props: {
|
||||
const Scheme = useMemo(() => buildSchema(t), [t]);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const [autoFilledFields, setAutoFilledFields] = useState<Set<string>>(new Set());
|
||||
|
||||
const addAutoFilledField = (fieldName: string) => {
|
||||
setAutoFilledFields((prev) => new Set(prev).add(fieldName));
|
||||
};
|
||||
|
||||
const removeAutoFilledField = (fieldName: string) => {
|
||||
setAutoFilledFields((prev) => {
|
||||
const newSet = new Set(prev);
|
||||
newSet.delete(fieldName);
|
||||
return newSet;
|
||||
});
|
||||
};
|
||||
|
||||
const form = useForm<NodeFormValues>({
|
||||
resolver: zodResolver(Scheme),
|
||||
defaultValues: {
|
||||
@ -112,12 +126,14 @@ export default function NodeForm(props: {
|
||||
const currentServer = useMemo(() => servers?.find((s) => s.id === serverId), [servers, serverId]);
|
||||
|
||||
const availableProtocols = useMemo(() => {
|
||||
return (currentServer?.protocols || [])
|
||||
if (!currentServer?.protocols) return [];
|
||||
|
||||
return (currentServer.protocols as Array<{ type: ProtocolName; port?: number }>)
|
||||
.filter((p) => p.type)
|
||||
.map((p) => ({
|
||||
protocol: (p as any).type as ProtocolName,
|
||||
port: (p as any).port as number | undefined,
|
||||
}))
|
||||
.filter((p) => !!p.protocol);
|
||||
protocol: p.type,
|
||||
port: p.port,
|
||||
}));
|
||||
}, [currentServer]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -139,60 +155,96 @@ export default function NodeForm(props: {
|
||||
const id = nextId ?? undefined;
|
||||
form.setValue('server_id', id);
|
||||
|
||||
const sel = servers.find((s) => s.id === id);
|
||||
const dirty = form.formState.dirtyFields as Record<string, any>;
|
||||
if (!id) {
|
||||
setAutoFilledFields(new Set());
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedServer = servers.find((s) => s.id === id);
|
||||
if (!selectedServer) return;
|
||||
|
||||
const currentValues = form.getValues();
|
||||
const fieldsToFill: string[] = [];
|
||||
|
||||
if (!dirty.name) {
|
||||
form.setValue('name', (sel?.name as string) || '', { shouldDirty: false });
|
||||
if (!currentValues.name || autoFilledFields.has('name')) {
|
||||
form.setValue('name', selectedServer.name as string, { shouldDirty: false });
|
||||
fieldsToFill.push('name');
|
||||
}
|
||||
|
||||
if (
|
||||
!dirty.address &&
|
||||
(!currentValues.address || currentValues.address === (sel?.address as string))
|
||||
) {
|
||||
form.setValue('address', (sel?.address as string) || '', { shouldDirty: false });
|
||||
if (!currentValues.address || autoFilledFields.has('address')) {
|
||||
form.setValue('address', selectedServer.address as string, { shouldDirty: false });
|
||||
fieldsToFill.push('address');
|
||||
}
|
||||
|
||||
const allowed = (sel?.protocols || [])
|
||||
.map((p) => (p as any).type as ProtocolName)
|
||||
.filter(Boolean);
|
||||
const protocols =
|
||||
(selectedServer.protocols as Array<{ type: ProtocolName; port?: number }>) || [];
|
||||
const firstProtocol = protocols[0];
|
||||
|
||||
const currentProtocol = form.getValues('protocol') as ProtocolName;
|
||||
if (firstProtocol && (!currentValues.protocol || autoFilledFields.has('protocol'))) {
|
||||
form.setValue('protocol', firstProtocol.type, { shouldDirty: false });
|
||||
fieldsToFill.push('protocol');
|
||||
|
||||
if (!allowed.includes(currentProtocol)) {
|
||||
const firstProtocol = allowed[0] || '';
|
||||
form.setValue('protocol', firstProtocol as any);
|
||||
|
||||
if (firstProtocol) {
|
||||
handleProtocolChange(firstProtocol);
|
||||
if (!currentValues.port || currentValues.port === 0 || autoFilledFields.has('port')) {
|
||||
const port = firstProtocol.port || 0;
|
||||
form.setValue('port', port, { shouldDirty: false });
|
||||
fieldsToFill.push('port');
|
||||
}
|
||||
}
|
||||
|
||||
setAutoFilledFields(new Set(fieldsToFill));
|
||||
}
|
||||
|
||||
const handleManualFieldChange = (fieldName: keyof NodeFormValues, value: any) => {
|
||||
form.setValue(fieldName, value);
|
||||
removeAutoFilledField(fieldName);
|
||||
};
|
||||
|
||||
function handleProtocolChange(nextProto?: ProtocolName | null) {
|
||||
const p = (nextProto || '') as ProtocolName | '';
|
||||
form.setValue('protocol', p);
|
||||
if (!p || !currentServer) return;
|
||||
const protocol = (nextProto || '') as ProtocolName | '';
|
||||
form.setValue('protocol', protocol);
|
||||
|
||||
const dirty = form.formState.dirtyFields as Record<string, any>;
|
||||
const currentValues = form.getValues();
|
||||
|
||||
if (!dirty.port) {
|
||||
const hit = (currentServer.protocols as any[]).find((x) => (x as any).type === p);
|
||||
const port = (hit as any)?.port as number | undefined;
|
||||
const newPort = typeof port === 'number' && port > 0 ? port : 0;
|
||||
|
||||
if (!currentValues.port || currentValues.port === 0 || currentValues.port === newPort) {
|
||||
form.setValue('port', newPort, { shouldDirty: false });
|
||||
if (!protocol || !currentServer) {
|
||||
removeAutoFilledField('protocol');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentValues = form.getValues();
|
||||
const isPortAutoFilled = autoFilledFields.has('port');
|
||||
|
||||
removeAutoFilledField('protocol');
|
||||
|
||||
if (!currentValues.port || currentValues.port === 0 || isPortAutoFilled) {
|
||||
const protocolData = (
|
||||
currentServer.protocols as Array<{ type: ProtocolName; port?: number }>
|
||||
)?.find((p) => p.type === protocol);
|
||||
|
||||
if (protocolData) {
|
||||
const port = protocolData.port || 0;
|
||||
form.setValue('port', port, { shouldDirty: false });
|
||||
addAutoFilledField('port');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit(values: NodeFormValues) {
|
||||
const result = await onSubmit(values);
|
||||
if (result) {
|
||||
setOpen(false);
|
||||
setAutoFilledFields(new Set());
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button onClick={() => form.reset()}>{trigger}</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
form.reset();
|
||||
setAutoFilledFields(new Set());
|
||||
}}
|
||||
>
|
||||
{trigger}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
|
||||
<SheetContent className='w-[560px] max-w-full'>
|
||||
@ -253,7 +305,7 @@ export default function NodeForm(props: {
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
onValueChange={(v) => form.setValue(field.name, v as string)}
|
||||
onValueChange={(v) => handleManualFieldChange('name', v as string)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@ -270,7 +322,7 @@ export default function NodeForm(props: {
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
onValueChange={(v) => form.setValue(field.name, v as string)}
|
||||
onValueChange={(v) => handleManualFieldChange('address', v as string)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@ -291,7 +343,7 @@ export default function NodeForm(props: {
|
||||
min={1}
|
||||
max={65535}
|
||||
placeholder='1-65535'
|
||||
onValueChange={(v) => form.setValue(field.name, Number(v))}
|
||||
onValueChange={(v) => handleManualFieldChange('port', Number(v))}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@ -327,7 +379,7 @@ export default function NodeForm(props: {
|
||||
</Button>
|
||||
<Button
|
||||
disabled={loading}
|
||||
onClick={form.handleSubmit(onSubmit, (errors) => {
|
||||
onClick={form.handleSubmit(handleSubmit, (errors) => {
|
||||
const key = Object.keys(errors)[0] as keyof typeof errors;
|
||||
if (key) toast.error(String(errors[key]?.message));
|
||||
return false;
|
||||
|
||||
@ -152,26 +152,13 @@ export default function NodesPage() {
|
||||
trigger={t('edit')}
|
||||
title={t('drawerEditTitle')}
|
||||
loading={loading}
|
||||
initialValues={{
|
||||
name: row.name,
|
||||
server_id: row.server_id,
|
||||
protocol: row.protocol as any,
|
||||
address: row.address as any,
|
||||
port: row.port as any,
|
||||
tags: (row.tags as any) || [],
|
||||
}}
|
||||
initialValues={row}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const body: API.UpdateNodeRequest = {
|
||||
id: row.id,
|
||||
name: values.name,
|
||||
server_id: Number(values.server_id!),
|
||||
protocol: values.protocol,
|
||||
address: values.address,
|
||||
port: Number(values.port!),
|
||||
tags: values.tags || [],
|
||||
enabled: row.enabled,
|
||||
...row,
|
||||
...values,
|
||||
} as any;
|
||||
await updateNode(body);
|
||||
toast.success(t('updated'));
|
||||
@ -201,16 +188,11 @@ export default function NodesPage() {
|
||||
key='copy'
|
||||
variant='outline'
|
||||
onClick={async () => {
|
||||
const { id, enabled, created_at, updated_at, ...rest } = row as any;
|
||||
const { id, enabled, created_at, updated_at, sort, ...rest } = row as any;
|
||||
await createNode({
|
||||
name: rest.name,
|
||||
server_id: rest.server_id,
|
||||
protocol: rest.protocol,
|
||||
address: rest.address,
|
||||
port: rest.port,
|
||||
tags: rest.tags || [],
|
||||
...rest,
|
||||
enabled: false,
|
||||
} as any);
|
||||
});
|
||||
toast.success(t('copied'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user