Skip to content

[FEAT] Persist dashboard column visibility across reloads #3822

@Ashkaan

Description

@Ashkaan

Summary

Column visibility toggles in the dashboard reset on every page reload and on navigation away from the table. Hiding columns on Events, Workers, Workflows, Scheduled Runs, Recurring, Filters, Rate Limits, or Workflow Runs only sticks for the current mount of that page.

Repro

  1. Open /events (or any other table page).
  2. Click the column-toggle menu, hide one or more columns.
  3. Hard reload, or navigate away and back.
  4. All columns are visible again.

Reproduced on a self-hosted instance running ghcr.io/hatchet-dev/hatchet/hatchet-dashboard:latest. Same code path applies to Hatchet Cloud since it ships the same React app.

Root cause

Every table page wires columnVisibility to plain useState, never to a persistence layer. Confirmed by code search across frontend/app/src/pages/main/v1/:

File Line
events/index.tsx 59
workers/index.tsx 45
scheduled-runs/index.tsx 63
workflows/index.tsx 19
filters/index.tsx 41
recurring/index.tsx 28
rate-limits/index.tsx 24
workflow-runs-v1/hooks/runs-provider.tsx 97

DataTable itself (frontend/app/src/components/v1/molecules/data-table/data-table.tsx) is correctly designed as a controlled component: it accepts columnVisibility and setColumnVisibility as props. The persistence responsibility sits with the parent, and no parent provides a persistent setter.

Suggested fix

The repo already has frontend/app/src/hooks/use-local-storage-state.tsx, which:

  • reads the initial value from window.localStorage,
  • writes on every set,
  • syncs across tabs via the native storage event plus a custom hatchet:local-storage event for same-tab listeners,
  • falls back gracefully on JSON parse / quota errors.

It is already used for sidebar collapse (use-sidebar.tsx), the refetch interval (refetch-interval-context.tsx), and the side panel (nav/side-panel.tsx).

Swapping useState<VisibilityState>(default) for useLocalStorageState<VisibilityState>(\"hatchet:columns:<page>\", default) at each of the 8 sites above should be enough. Each page would need a stable key, e.g. hatchet:columns:events, hatchet:columns:workers, etc.

Why it matters

Anyone who customizes their table view has to redo it every time they reload or change pages. The hook to fix it is in-tree, the change is mechanical, and no schema or backend work is involved. Happy to send a PR if the team is open to that approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions