fix(dashboard): preserve spawn-form input across approval_added/resolved re-renders

renderApprovals() called root.replaceChildren() on every
approval_added / approval_resolved SSE event, wiping the spawn
form's name input if the operator had started typing a new agent
name.

Save the current input value before the wipe and restore it into
the freshly-built input element. The form itself is still rebuilt
(no keyed-cache needed here — approval cards have no user inputs),
so all other behaviour is unchanged.
This commit is contained in:
iris 2026-06-05 12:35:22 +02:00
commit 221de2204d

View file

@ -2092,21 +2092,29 @@ window.marked = marked;
// no-op elsewhere — `approval_added` / `approval_resolved` SSE
// events route through here on every page that loads the bundle.
if (!root) return;
// Save spawn form input + focus state before the DOM wipe so a live
// approval_added/resolved event doesn't erase a partially-typed name
// or steal focus from the operator.
const savedSpawnName = root.querySelector('.spawnform input[name="name"]')?.value ?? '';
const spawnHadFocus = document.activeElement === root.querySelector('.spawnform input[name="name"]');
root.replaceChildren();
// Spawn request form: submitting it queues a Spawn approval that
// lands in this same list, so the form belongs here rather than on
// the containers list (the agent doesn't exist yet).
const spawnNameInput = el('input', {
name: 'name',
placeholder: 'new agent name (≤9 chars)',
maxlength: '9', required: '', autocomplete: 'off',
});
if (savedSpawnName) spawnNameInput.value = savedSpawnName;
if (spawnHadFocus) spawnNameInput.focus();
const spawn = el('form', {
method: 'POST', action: '/request-spawn',
class: 'spawnform', 'data-async': '', 'data-no-refresh': '',
});
spawn.append(
el('input', {
name: 'name',
placeholder: 'new agent name (≤9 chars)',
maxlength: '9', required: '', autocomplete: 'off',
}),
spawnNameInput,
el('button', { type: 'submit', class: 'btn btn-spawn' }, '◆ R3QU3ST SP4WN'),
);
root.append(spawn);