fix(frontend): reload the list on dismissal, and never re-offer a workspace that exists

Closing a landed import with the X left the home list stale: only
`finish()` reloaded it, so a workspace that now holds a project kept
showing its placeholder rows. A run that started wrote items whether it
finished, was abandoned or failed partway, so any dismissal after one
reloads.

Creation reported failure for a failed *list refresh* too, and handed
the form back — where a retry picks the next free id and creates a
second workspace. Once `createWorkspace` returns, nothing may report
failure: the refresh is logged if it fails, and the hand-over proceeds,
since the workspace is real either way.

The disabled-link tooltip also claimed the settings could not be read
during the ordinary load, before anything had failed.

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:39:05 +02:00
co-authored by Claude Opus 5
parent 58c9073656
commit 5988e50b12
2 changed files with 27 additions and 10 deletions
@@ -79,6 +79,11 @@
sendUserToast('Import stopped. What it already added stays; reopen the project to finish.')
}
}
// A run that started wrote items, whether it finished, was abandoned midway or failed
// 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?.()
finishing = false
onClose()
}
@@ -118,8 +118,10 @@
creating = true
const workspaceName = name.trim()
const started = Date.now()
let id: string | undefined
try {
const id = await freeWorkspaceId(idSeed(workspaceName))
id = await freeWorkspaceId(idSeed(workspaceName))
if (!id) {
sendUserToast(
'No workspace ID could be derived from that name. Pick one in advanced settings.',
@@ -136,19 +138,29 @@
username: automateUsername ? undefined : suggestedUsername
}
})
usersWorkspaceStore.set(await WorkspaceService.listUserWorkspaces())
switchWorkspace(id)
const left = WORKSPACE_HANDOVER_MS - (Date.now() - started)
if (left > 0) await new Promise((resolve) => setTimeout(resolve, left))
// Left up rather than cleared: the navigation it hands over to loads the workspace
// layout for the first time, and dropping back to the form under it would show the
// button again for as long as that takes.
onCreated()
} catch (error) {
console.error('Could not create the workspace:', error)
sendUserToast('Could not create the workspace: ' + (error?.body || error?.message), true)
creating = false
return
}
// The workspace exists from here on, so nothing below may report failure or hand the
// form back: a retry would pick the next free id and create a second one. A refresh
// that fails is worth a log and nothing more — the list reloads on the next page load,
// and the workspace this hands over to is real either way.
try {
usersWorkspaceStore.set(await WorkspaceService.listUserWorkspaces())
} catch (error) {
console.error('Created the workspace but could not refresh the list:', error)
}
switchWorkspace(id)
const left = WORKSPACE_HANDOVER_MS - (Date.now() - started)
if (left > 0) await new Promise((resolve) => setTimeout(resolve, left))
// Left up rather than cleared: the navigation it hands over to loads the workspace
// layout for the first time, and dropping back to the form under it would show the
// button again for as long as that takes.
onCreated()
}
</script>
@@ -197,7 +209,7 @@
<button
class="text-xs text-secondary hover:text-emphasis disabled:opacity-50 disabled:hover:text-secondary"
disabled={!policyLoaded}
title={policyLoaded ? undefined : "This instance's settings could not be read"}
title={policyFailed ? "This instance's settings could not be read" : undefined}
onclick={() => (advanced = true)}
>
Advanced settings