Skip to content

feat(dashboards): Add UI to view dashboard revisions#113441

Merged
skaasten merged 10 commits intomasterfrom
shaunkaasten/dain-1545-ui-to-view-dashboard-revisions
Apr 21, 2026
Merged

feat(dashboards): Add UI to view dashboard revisions#113441
skaasten merged 10 commits intomasterfrom
shaunkaasten/dain-1545-ui-to-view-dashboard-revisions

Conversation

@skaasten
Copy link
Copy Markdown
Contributor

Adds a clock icon button to the dashboard controls toolbar that opens a modal listing the revision history for the current dashboard. Each row shows the revision title, who created it, and a relative timestamp.

The button is gated behind the dashboards-revisions feature flag and hidden for prebuilt and default-overview dashboards (which have no stored revisions). The revisions endpoint is not called until the modal is opened — no eager fetch on page load.

Refs DAIN-1545

@linear-code
Copy link
Copy Markdown

linear-code Bot commented Apr 20, 2026

@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Apr 20, 2026
@skaasten skaasten marked this pull request as ready for review April 20, 2026 16:17
@skaasten skaasten requested a review from a team as a code owner April 20, 2026 16:17
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ce551f2. Configure here.

Comment thread static/app/views/dashboards/dashboardRevisions.tsx Outdated
Comment thread static/app/views/dashboards/dashboardRevisions.tsx Outdated
Comment thread static/app/views/dashboards/dashboardRevisions.tsx
{
staleTime: 30_000,
enabled,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we actually restore the revision, or create a new one, it would be a good idea to invalidate the cache for the next request to this endpoint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, added invalidation on edits to the dashboard, which would make a new revision. I'll do the same when we allow restore.

Comment on lines +354 to +361
export function makeDashboardRevisionsQueryKey(orgSlug: string, dashboardId: string) {
return [
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/$dashboardId/revisions/', {
path: {organizationIdOrSlug: orgSlug, dashboardId},
}),
] as const;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this into the file with the hook as it's directly related to that and only used there

enabled = true,
}: UseDashboardRevisionsOptions) {
const organization = useOrganization();
return useApiQuery<DashboardRevision[]>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think thew new pattern is to use useQuery + apiOptions and not useApiQuery

);
}

function RevisionList({revisions}: {revisions: DashboardRevision[]}) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of using the <Table> component here we have a <SimpleTable> core component that i think would be better to use. Not sure if the table is going to stick around or continue to be formatted like this but I still think it's good practice to use the design system!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you - it looks much nicer with that change!

skaasten and others added 8 commits April 21, 2026 09:47
Adds a clock icon button to the dashboard controls toolbar (gated behind
the dashboards-revisions feature flag) that opens a modal listing all
revisions for the current dashboard. Each row shows the revision title,
who created it, and a relative timestamp via TimeSince.

The revisions endpoint is only called when the modal is opened, not on
page load.

Refs DAIN-1545
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers: feature flag gate, prebuilt/default-overview exclusions, lazy
API fetching (endpoint not called until modal opens), revision list
rendering, createdBy fallbacks, and the empty state.

Also moves the feature flag check inside the component for testability,
removing the Feature wrapper from controls.tsx.

Refs DAIN-1545
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Show an error state (Alert danger) when the revisions API request fails
  instead of silently falling through to the empty state
- Move typography (font-weight, font-size, color) out of the Th styled
  component into Text primitives, keeping styled components layout-only
- Remove unused orgSlug prop from DashboardRevisionsModal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a muted grey tag to revisions created as a pre-restore snapshot.
The source type is narrowed to 'edit' | 'pre-restore' to match the
updated backend value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch useDashboardRevisions to useQuery + apiOptions (new preferred pattern)
- Move DashboardRevision type and query options factory to the hook file
  since they are only used there; export for future cache invalidation
- Replace custom styled table with SimpleTable core component

Co-Authored-By: Claude Sonnet 4 <noreply@example.com>
Remove the exported makeDashboardRevisionsQueryOptions helper since nothing
uses it yet — knip flagged it as an unused export. The query options can be
exported when a restore action needs to invalidate the cache.

Co-Authored-By: Claude Sonnet 4 <noreply@example.com>
After any successful updateDashboard call, invalidate the revisions query
so the next modal open reflects the newly created revision immediately
rather than serving stale cached data.

Co-Authored-By: Claude Sonnet 4 <noreply@example.com>
@skaasten skaasten force-pushed the shaunkaasten/dain-1545-ui-to-view-dashboard-revisions branch from ce1de0c to 716350a Compare April 21, 2026 13:53
Copy link
Copy Markdown
Member

@nikkikapadia nikkikapadia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm 😌

Copy link
Copy Markdown
Contributor

@DominikB2014 DominikB2014 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just one suggestion on the flag conditional!

</Tooltip>
)}
{renderEditButton(hasFeature)}
<DashboardRevisionsButton dashboard={dashboard} />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think it's cleaner to conditionally render the button here if the feature is available. In general i think feature checks should happen as early as possible for a few reasons

  1. minimizes risk, less of your featured code is ran
  2. consistent with the codebase (the line below checks hasFeature to render a tooltip)
  3. Easier to read, you don't have to jump into the DashboardRevisionsButton component to understand it's conditionally rendered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree - I'll update it thanks!

Gate the DashboardRevisionsButton behind a <Feature> component in
controls.tsx. Validity checks (default-overview, prebuilt dashboards)
stay inside the component with corresponding tests.

Co-Authored-By: Claude Sonnet 4 <noreply@example.com>
…s absent

Co-Authored-By: Claude Sonnet 4 <noreply@example.com>
@skaasten skaasten merged commit 48b6c48 into master Apr 21, 2026
65 checks passed
@skaasten skaasten deleted the shaunkaasten/dain-1545-ui-to-view-dashboard-revisions branch April 21, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants