You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(frontend): shared EmptyState and PageHeader components - #4014
A UI audit found page-level states and panel headers hand-rolled separately on each page. This adds two small shared components and moves the clear duplicates onto them.
EmptyState (src/components/EmptyState.vue): props title, description?, icon? (component), iconClass?; slot #action. Renders an h2 (same level as before), icon is aria-hidden.
Replaces 24 identical not-found / preview-disabled blocks on app, bundle, channel and device pages.
The existing AppPageNotFound (mounted through AppPageFrame) now uses EmptyState, and the 8 pages that inlined a copy of it now render <AppPageNotFound />.
PageHeader (src/components/PageHeader.vue): props title, description?; slots #badges (next to the title), default (under the description), #actions (right side). Renders an h2 (same level as before).
Used by OrgNativeBuildStatsPanel, DeliveryLatencyPanel, OrgNotificationStatsPanel (dashboard tabs) and NativeReleaseStatsPanel (observe → native).
Visual change: only the empty state changes slightly. The description now wraps at max-w-md and is centered, as the preview-disabled variant already was, and the descriptions use one colour (text-slate-600, where AppPageNotFound used -500). PageHeader output looks the same as before.
src/pages/settings/** and the settings layout are not touched, to avoid conflicts with #4005.
Visual changes
Before (left/top) vs after (right/bottom), rendered from the real markup and component with src/styles/style.css.
In-card list empty states with mixed heading levels (h3/h4/p) and sizes: BuildTable#empty, OrgNativeBuildStatsPanel no-builds, bundle dependencies "no native dependencies", observe.compatibility empty, observe.errors no insights, observe.native no data, WebhookDeliveryLog no deliveries, UnpaidState, dashboard.vue "no apps yet" overlay. Covering these needs either a heading-level choice or picking one level, which is a separate decision.
Card headers on bundle dependencies/manifest (h3) and the notifications page (h1 + badge + refresh): same layout as PageHeader, but a different heading level.
ReleaseLivePanel header (uses xl: breakpoints, title hidden when dense).
BundleInstallStatsPanel non-dense mode (header and stat grid) can't be reached in prod: its only mount (LiveReleaseDashboard) passes dense. It could be deleted in its own PR.
Test plan
bun run lint: only warnings, both pre-existing on main (AppOnboardingSetupChecklist.vue)
bun run typecheck (pre-commit)
bun run test:unit: 461 files / 5193 tests pass
data-testid selectors and the "App not found" heading role used by Playwright are unchanged
Replace 24 hand-rolled not-found / preview-disabled blocks on app,
bundle, channel and device pages with one EmptyState component.
App-not-found pages reuse the existing AppPageNotFound, now built on
EmptyState.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dashboard and observe panels each hand-rolled the same title,
description, badges and actions row. Move it into PageHeader.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.
Walkthrough
The change adds reusable EmptyState and PageHeader components. App pages use the shared empty state for missing resources and disabled previews. Dashboard panels use the shared header for titles, descriptions, badges, and controls.
Changes: Empty-state views
Layer / File(s)
Summary
Shared empty-state component and app fallback src/components/EmptyState.vue, src/components.d.ts, src/components/dashboard/AppPageNotFound.vue
Adds EmptyState with optional description and icon props and an action slot. AppPageNotFound uses it while retaining its translated content and navigation.
Replaces inline missing-app and missing-resource layouts with AppPageNotFound or EmptyState. Existing text, icons, actions, navigation targets, and route conditions are retained as described.
Dashboard header component and integration src/components/PageHeader.vue, src/components.d.ts, src/components/dashboard/*StatsPanel.vue
Adds PageHeader with title and description props and default, badges, and actions slots. Four dashboard panels use it for their existing header content and controls.
The shared components consolidate existing empty states and panel headers without an identified behavioral regression. The change is mergeable subject to normal build and test checks.
Pre-merge checks: 5
Check name
Status
Explanation
Title check
The title clearly identifies the main change: shared frontend EmptyState and PageHeader components.
Description check
The description includes a clear summary, visual-change screenshots, implementation scope, follow-ups, and test results. It does not include the template’s separate Checklist section or detailed manua…
Docstring Coverage
No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Description check
Explanation
The description includes a clear summary, visual-change screenshots, implementation scope, follow-ups, and test results. It does not include the template’s separate Checklist section or detailed manual reproduction steps, but it is mostly complete and relevant.
Full details: Docstring Coverage
Explanation
No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 1 files. (27 skipped: 27 unsupported.)
Finishing Touches
Generate docstrings
Commit to this branch
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Warning
Some tools did not complete. Review the errors below.
ESLint
If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
src/components/EmptyState.vue
Parsing error: Unexpected token {
src/components/PageHeader.vue
Parsing error: Unexpected token description
src/components/dashboard/DeliveryLatencyPanel.vue
Parsing error: Unexpected token {
23 others
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A UI audit found page-level states and panel headers hand-rolled separately on each page. This adds two small shared components and moves the clear duplicates onto them.
EmptyState(src/components/EmptyState.vue): propstitle,description?,icon?(component),iconClass?; slot#action. Renders anh2(same level as before), icon isaria-hidden.AppPageNotFound(mounted throughAppPageFrame) now usesEmptyState, and the 8 pages that inlined a copy of it now render<AppPageNotFound />.PageHeader(src/components/PageHeader.vue): propstitle,description?; slots#badges(next to the title), default (under the description),#actions(right side). Renders anh2(same level as before).OrgNativeBuildStatsPanel,DeliveryLatencyPanel,OrgNotificationStatsPanel(dashboard tabs) andNativeReleaseStatsPanel(observe → native).Visual change: only the empty state changes slightly. The description now wraps at
max-w-mdand is centered, as the preview-disabled variant already was, and the descriptions use one colour (text-slate-600, whereAppPageNotFoundused-500). PageHeader output looks the same as before.src/pages/settings/**and the settings layout are not touched, to avoid conflicts with #4005.Visual changes
Before (left/top) vs after (right/bottom), rendered from the real markup and component with
src/styles/style.css.EmptyState: channel not found (light / dark)
PageHeader: dashboard Notifications tab (light / dark)
Follow-ups (not in this PR)
BuildTable#empty,OrgNativeBuildStatsPanelno-builds, bundle dependencies "no native dependencies",observe.compatibilityempty,observe.errorsno insights,observe.nativeno data,WebhookDeliveryLogno deliveries,UnpaidState,dashboard.vue"no apps yet" overlay. Covering these needs either a heading-level choice or picking one level, which is a separate decision.h3) and thenotificationspage (h1+ badge + refresh): same layout as PageHeader, but a different heading level.ReleaseLivePanelheader (usesxl:breakpoints, title hidden when dense).settings/organization/AuditLogs.vueno-org state: skipped because of feat(settings): profile menu, danger zones and DaisyUI buttons #4005.BundleInstallStatsPanelnon-dense mode (header and stat grid) can't be reached in prod: its only mount (LiveReleaseDashboard) passesdense. It could be deleted in its own PR.Test plan
bun run lint: only warnings, both pre-existing on main (AppOnboardingSetupChecklist.vue)bun run typecheck(pre-commit)bun run test:unit: 461 files / 5193 tests passdata-testidselectors and the "App not found" heading role used by Playwright are unchanged🤖 Generated with Claude Code
Summary by CodeRabbit