fix(frontend): reload after the abandoned run stops, not when it is asked to

`abandon()` stops the run at the next phase boundary; the request already
sent still lands. Reloading the list at that moment could read it before
that write committed, leaving the caller stale again — the thing the
reload was added to fix. It now waits for `running` to clear, which is
immediate for the common case of dismissing a finished import, with a
cap so a run that never settles still ends in a reload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
This commit is contained in:
Guilhem Lemouel
2026-09-07 14:50:51 +02:00
co-authored by Claude Opus 5
parent 5988e50b12
commit 1d9eed3103
@@ -83,11 +83,25 @@
// partway — so the list behind this dialog is stale either way, and only `finish()`
// was reloading it. Closing a landed import with the X left an emptied-out home
// showing its placeholder rows over a workspace that now holds a project.
if (!finishing && execution) onImported?.()
if (!finishing && execution) void reloadWhenSettled(execution, onImported)
finishing = false
onClose()
}
/**
* Reloads the caller's list once the run is no longer writing. Immediate for a run that
* has finished, which is the common dismissal — but `abandon()` only stops the *next*
* phase, and the request already sent still lands, so a reload issued at that moment can
* read the list before that write commits and leave it stale again. The cap is there so a
* run that never settles still ends in a reload rather than in nothing.
*/
async function reloadWhenSettled(run: ImportExecution, reload: (() => void) | undefined) {
for (let i = 0; i < 60 && run.running; i++) {
await new Promise((resolve) => setTimeout(resolve, 250))
}
reload?.()
}
// The wizard route asks step 1 which workspace to import into and step 2 which one it
// is. Opened from inside a workspace both answers are already given, so the dialog
// starts at the import itself and the plan is fixed rather than URL-driven.