@@ -440,7 +544,25 @@ function Cluster() {
to: n,
alive: n.status === 'online',
}));
- const sel = selected || NODES[0];
+
+ const addNode = () => {
+ alert('To add a worker node:\n\n1. Install Docker + docker-compose on the target machine\n2. Copy /opt/wild-dragon to that machine\n3. Set NODE_ROLE=worker in the .env file\n4. Run: docker compose up -d\n\nThe node will register with this cluster automatically.');
+ };
+
+ const drainNode = (node) => {
+ alert('Drain is not yet automated.\n\nTo drain ' + node.id + ':\n1. Stop new jobs from routing to this node\n2. Wait for in-progress jobs to complete\n3. Then remove the node safely');
+ };
+
+ const removeNode = (node) => {
+ if (!window.confirm('Remove node ' + node.id + ' from the cluster?\nThis does not stop the machine — it only removes it from cluster membership.')) return;
+ window.ZAMPP_API.fetch('/cluster/nodes/' + encodeURIComponent(node.id), { method: 'DELETE' })
+ .then(() => refresh())
+ .catch(e => alert('Remove failed: ' + e.message));
+ };
+
+ const nodeLogsHint = (node) => {
+ alert('To view logs for ' + node.id + ' (' + node.ip + '):\n\nSSH to ' + node.ip + ' and run:\ndocker compose -f /opt/wild-dragon/docker-compose.yml logs -f');
+ };
return (
@@ -449,8 +571,8 @@ function Cluster() {
{NODES.filter(n => n.status === "online").length} of {NODES.length} nodes online