import { useState, useEffect, memo } from 'react'; import { api } from '../../api/client'; import type { Agent } from '../../types'; import { HelpTip } from '../HelpTip'; interface Props { agent: Agent; onUpdated?: (agent: Agent) => void; requestDeleteConfirm?: (req: { count: number; agentName?: string }) => Promise; } function CrucibleAgentMeta({ agent, onUpdated, requestDeleteConfirm }: Props) { const [notesDraft, setNotesDraft] = useState(agent.notes || ''); const [tagsDraft, setTagsDraft] = useState((agent.tags || []).join(', ')); const [saving, setSaving] = useState(false); const [msg, setMsg] = useState(''); useEffect(() => { setNotesDraft(agent.notes || ''); setTagsDraft((agent.tags || []).join(', ')); setMsg(''); }, [agent.id, agent.notes, agent.tags]); const save = async () => { setSaving(true); setMsg(''); const tags = tagsDraft.split(',').map((t) => t.trim()).filter(Boolean); try { const res = await api.updateAgentMeta(agent.id, notesDraft, tags); onUpdated?.(res.agent); setMsg('Saved'); setTimeout(() => setMsg(''), 2000); } catch (err) { setMsg(err instanceof Error ? err.message : 'Save failed'); } finally { setSaving(false); } }; const deleteFromRoster = async () => { const confirmed = requestDeleteConfirm ? await requestDeleteConfirm({ count: 1, agentName: agent.name }) : window.confirm( 'Remove from fleet — does not uninstall agent on host. Remove this machine from the registry?', ); if (!confirmed) return; try { await api.deleteAgent(agent.id); } catch (err) { alert(err instanceof Error ? err.message : 'Delete failed'); } }; const uninstallAndDelete = async () => { const label = agent.status === 'online' ? `Uninstall the miner from "${agent.name}" and remove it from the roster?` : `"${agent.name}" is offline — it cannot be remotely uninstalled. Remove from roster only?`; if (!window.confirm(label)) return; if (agent.status === 'online') { try { await api.sendAgentCommand(agent.id, 'uninstall', {}); } catch { // Non-fatal — proceed to delete the record regardless } } try { await api.deleteAgent(agent.id); } catch (err) { alert(err instanceof Error ? err.message : 'Delete failed'); } }; return (
NOTES & TAGS

Labels like "Living room PC" or "Rack B" — stored on the server, shown on node cards.

{(agent.tags?.length ?? 0) > 0 && (
{agent.tags!.map((t) => ( {t} ))}
)}