diff --git a/src/components/ClusterNodesComponent.tsx b/src/components/ClusterNodesComponent.tsx index 59a9133..a24a1ea 100644 --- a/src/components/ClusterNodesComponent.tsx +++ b/src/components/ClusterNodesComponent.tsx @@ -175,7 +175,7 @@ export function ClusterNodesComponent() { }; const handleAddSubmit = async (data: NodeFormData) => { - await addNode({ + const nodeData = { hostname: data.hostname, role: data.role, disk: data.disk, @@ -183,7 +183,19 @@ export function ClusterNodesComponent() { interface: data.interface, schematic_id: data.schematicId, maintenance: data.maintenance, - }); + }; + + // Add node configuration (if this fails, error is shown and drawer stays open) + await addNode(nodeData); + + // Apply configuration immediately for new nodes + try { + await applyNode(data.hostname); + } catch (applyError) { + // Apply failed but node is added - user can use Apply button on card + console.error('Failed to apply node configuration:', applyError); + } + closeDrawer(); setAddNodeIp(''); }; diff --git a/src/components/nodes/NodeForm.tsx b/src/components/nodes/NodeForm.tsx index 9518e88..351b6da 100644 --- a/src/components/nodes/NodeForm.tsx +++ b/src/components/nodes/NodeForm.tsx @@ -171,7 +171,8 @@ export function NodeForm({ const newValues = getInitialValues(initialValues, detection, nodes, hostnamePrefix); reset(newValues); } - }, [initialValues, detection, nodes, hostnamePrefix, reset]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [initialValues, detection, nodes, hostnamePrefix]); // Set default role based on existing control plane nodes useEffect(() => { @@ -185,14 +186,16 @@ export function NodeForm({ setValue('role', defaultRole); } } - }, [nodes, initialValues?.role, setValue, watch]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [nodes, initialValues?.role]); // Pre-populate schematic ID from cluster config if available useEffect(() => { if (!schematicId && instanceConfig?.cluster?.nodes?.talos?.schematicId) { setValue('schematicId', instanceConfig.cluster.nodes.talos.schematicId); } - }, [instanceConfig, schematicId, setValue]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [instanceConfig, schematicId]); // Auto-generate hostname when role changes (only for NEW nodes without initial hostname) useEffect(() => { @@ -291,7 +294,8 @@ export function NodeForm({ } } } - }, [role, nodes, hostnamePrefix, setValue, watch, isExistingNode]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [role, nodes, hostnamePrefix, isExistingNode]); // Auto-calculate target IP for control plane nodes useEffect(() => { @@ -367,7 +371,8 @@ export function NodeForm({ } } } - }, [role, instanceConfig, nodes, setValue, watch, initialValues?.targetIp, detection?.ip]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [role, instanceConfig, nodes, initialValues?.targetIp, detection?.ip]); // Build disk options from both detection and initial values const diskOptions = (() => {