Skip to content

A Dashboard the UI cannot reach can make a saved query permanently undeletable #431

Description

@BorisTyshkevich

Summary

Once a workspace holds a Dashboard the UI cannot reach, a saved query that
Dashboard references can become permanently undeletable, with a diagnostic
the user has no way to act on.

How to reach it

  1. File → Import workspace… with a portable bundle containing two or more
    Dashboards. Since Introduce StoredWorkspaceV3 with a dashboard collection and no UI change #424 every bundled Dashboard is imported (in file order),
    so workspace.dashboards now has more than one entry.
  2. Only dashboards[0] — the compatibility Dashboard — is reachable in the UI;
    there is no selector, tree, or route parameter for the others yet.
  3. Suppose dashboards[1] has a tile referencing saved query p1, and
    dashboards[0] does not.
  4. Delete p1 from the ★ Queries list.

deleteSaved (src/state.ts) correctly carries the whole Dashboard collection
into its candidate, whole-workspace validation
(validateDashboardCollectionSemantics) correctly rejects the candidate with
dashboard-tile-query-missing at dashboards[1].tiles[0].queryId, and
src/ui/saved-history.ts toasts "Couldn't delete: Tile references unknown
saved query …"
.

Nothing is corrupted — the atomicity contract holds exactly as specified. The
problem is that no UI can reach dashboards[1] to remove that tile, so the
delete can never succeed. The same dead-end applies to any commit that would
dangle a hidden reference, e.g. changing a query's dashboard.role in the Spec
editor.

Why it is new

Before #424 the workspace held zero or one Dashboard, so the rejecting
Dashboard was always the visible one and the user could always repair it by
unstarring the query or deleting the tile. #424's storage change is what makes
an unreachable Dashboard possible, and the owner-approved import-all decision
is what makes one reachable in practice.

Why it is deferred, not fixed here

#424 is explicitly scoped as "storage, validation, repository, migration, and
internal API foundation only", with "Dashboard selector, tabs, dropdown, or
navigation UI" and "creating, deleting, duplicating, renaming, or reordering
Dashboards in the UI" as stated non-goals. The fix needs a surface that can
address a non-compatibility Dashboard, which is exactly what #425 (selection
state) and #426 (Dashboard tree) introduce, and #429 (panel/filter delete
actions) makes repairable.

Suggested resolution

Fold into the #430 programme rather than fixing standalone. Once #425/#426
land, either:

  • let the delete diagnostic name the offending Dashboard and offer to navigate
    to it (the diagnostic already carries resource = the Dashboard id and an
    indexed dashboards[i] path), or
  • offer the existing remove-affected-tiles repair from
    src/dashboard/application/saved-query-mutation.ts across the whole
    collection — note that planner is written for exactly this and still has no
    production caller.

Until then the exposure is limited to workspaces created by importing a
multi-Dashboard bundle; nothing the app itself authors can produce one.

Reference

  • src/state.tsdeleteSaved / candidateFrom
  • src/workspace/stored-workspace.tsvalidateStoredWorkspaceDocument
  • src/ui/saved-history.ts — the failure toast
  • src/dashboard/application/saved-query-mutation.ts — the unused repair planner

Found during the #424 review; filed rather than folded into that PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions