Skip to content

[BUG] Surface Vault list and mutation failures in VaultPane #181

Description

@vutuanlinh2k2

Context

VaultPane is the shared Vault browser/editor used by GTM. Read failures already have a dedicated error state, retry action, and component coverage. Its tree-listing and mutation handlers also settle their loading flags with try/finally, but list, save, create, and delete failures are not caught or presented.

Problem

Network, authorization, storage, or validation failures are not rendered as actionable UI states:

  • A rejected listTree() leaves the initial tree empty or a previously loaded tree stale, and the discarded promise can produce an unhandled rejection.
  • A rejected writeFile() correctly leaves the draft dirty, but gives the user no explanation or retry feedback and can produce an unhandled rejection.
  • Rejected createFile() and deleteFile() calls leave their dialogs open and loading flags settle, but no failure reason is shown and the discarded promises can produce unhandled rejections.
  • If create/delete succeeds but the follow-up tree refresh fails, the mutation has happened while the pane can show stale or inconsistent tree, dialog, or selection state.
  • React error boundaries do not catch errors thrown from asynchronous event handlers.

Expected Behavior

Every Vault operation has a visible success/failure outcome, preserves recoverable editor state, and offers an appropriate retry without remounting the pane.

Actual Behavior

Read failures are already surfaced and retryable. Rejected list/save/create/delete operations and post-mutation refresh failures are not surfaced by VaultPane. Existing component tests cover the happy paths and the read rejection path, but not the remaining rejection paths.

Proposed Scope

  • Add explicit tree and mutation error state to VaultPane.
  • Render list failures distinctly from an empty Vault, with a retry action.
  • Preserve the current draft and dirty state when a save fails, while displaying the failure reason and allowing retry/dismiss.
  • Keep create/delete dialogs, input, and selection deterministic when the mutation itself rejects.
  • Handle a failed follow-up refresh after a successful create/delete as a partial-success state and allow the tree to be reconciled.
  • Catch every operation promise at the pane boundary so failures do not escape as unhandled rejections.
  • If products need telemetry or host-level presentation, expose an optional typed operation-error callback that identifies the operation and relevant path without coupling the pane to a product toast system.

Acceptance Criteria

  • A failed initial tree listing renders an error state and retry action rather than an empty Vault.
  • A failed refresh does not silently replace a previously loaded tree with an empty state; the failure is visible and retryable.
  • Failed saves preserve the draft and dirty state, display the reason, and allow retry/dismiss.
  • Failed creates preserve the dialog input; failed deletes preserve the selected file; both display the reason and allow retry/dismiss.
  • A successful create/delete followed by a failed tree refresh is surfaced as a partial-success state and can reconcile the tree without remounting the pane.
  • Loading/saving/creating/deleting indicators continue to settle after every rejection.
  • No rejected Vault operation produces an unhandled promise rejection.
  • Component tests cover list, save, create, delete, and post-mutation refresh rejection paths; the existing read rejection test remains green.
  • Existing happy-path, dirty-draft, read-retry, and controlled-selection behavior remains unchanged.

Notes

Primary seams:

  • src/vault/VaultPane.tsx
  • tests/vault/vault-pane.test.ts

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Completed ✅

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions