ReviewOS

stacks/ts-cloud

dashboard: robustness gaps — double-submit, swallowed errors, missing empty states

#127
Closed glennmichael123 opened this 2 months ago ·
2 months ago

A pass over the dashboard pages surfaced consistent robustness gaps.

No in-flight lock (double-submit)

server/database.stx (createDb:29, createUser:36, backupDb:51), server/sites.stx (addSite:23, saveEdit:62), server/ssh-keys.stx (addKey:25, removeKey:33), server/firewall.stx (allowPort:33, removePort:44), server/team.stx (invite:49, revoke:61), and every runOp() in the 13 partial pages — the shared bar's Run button is never disabled while a request is in flight.

Errors swallowed

  • .catch(() => ({})) discards the server's real error message, so it surfaces as a generic "Could not save.": server/team.stx:53,64, server/firewall.stx:39,47, server/ssh-keys.stx:28,36.
  • No try/catch around await res.json() in server/database.stx:32,41,54 — a 502 returning HTML rejects and the panel stays on "Creating database…" forever.
  • Silent catch {} on pollers: index.stx:132 (10s), server/logs.stx:28 and serverless/logs.stx:25 (8s). The logs pages are the worst case — the poll dies and the user keeps reading stale logs with no indication. index.stx:129 already has a live/snapshot pill worth copying.

Success messages destroyed

server/sites.stx:30,54,74 call location.reload() immediately after setting "Added…/Removed…/Updated…", wiping it. (Also a state-management smell — re-fetch and .set() the signal instead.)

Confirm bar rendered far from its trigger

server/services.stx:76, server/deployments.stx:111, and especially server/sites.stx:183 render the bar after the entire list. Clicking "Remove" on site 1 of 6 scrolls nothing into view and appears to do nothing. Move focus to the input and scroll it into view, or render inline per row.

Missing empty states

server/services.stx:52, serverless/queues.stx:84, serverless/deployments.stx:58, serverless/scheduler.stx:69, serverless/functions.stx:91, serverless/assets.stx:80, serverless/metrics.stx:59, serverless/cost.stx:123, serverless/firewall.stx:41, index.stx:213,243. Good examples: server/workers.stx:69, server/backups.stx:85.

Dead state

serverless/queues.stx:16 — const rows = state(initialQueues) is never read; the table renders the server-side queues, so a purge never updates the visible counts.

8 days ago

Roadmap relationship: tracked by #133 under master roadmap #132.

8 days ago

Implemented across cbc4c25, 7c8b2de, eeab6b8, and baa8e51 on main.

Coverage:

  • every shared operation confirmation has one in-flight lock; database, site, SSH-key, firewall, and team invitation mutations are guarded too
  • shared response parsing preserves API errors and extracts bounded text from HTML/proxy failures instead of swallowing them
  • database create/user/backup calls recover cleanly from network and non-JSON responses
  • overview and both log pollers use the lifecycle-owned stx interval composable and expose live/stale state while retaining the last good snapshot
  • site add/edit/remove update a reactive site list from mutation response data, preserving success output without location.reload()
  • confirmation focus/scroll follows the trigger through useOpConfirm
  • explicit empty states now cover services, sites, workers, queues, deployments, scheduler, functions, assets, metrics, cost, and firewall rules
  • the queue table now renders and refreshes from its rows signal instead of dead state

Verification: focused utility tests pass and all 46 UI routes build successfully.

Sign in to comment on this issue.