Skip to content

Fix screen workspace review findings - #388

Merged
gbyo merged 1 commit into
mainfrom
gibby/coderabbit-findings-386
Jul 31, 2026
Merged

gbyo merged 1 commit into
mainfrom
gibby/coderabbit-findings-386

Conversation

@gbyo

@gbyo gbyo commented Jul 31, 2026 •

Copy link
Copy Markdown
Owner

Addresses the CodeRabbit findings on #386 and the two PRs before it.

Dashboard

  • Unknown ?tab= values. ScreenDetailWithPreviewPage passed anything it did not recognize straight through while ScreenDetailPage clamped it to Overview, so ?tab=bogus rendered the Overview panel without the preview layout or LivePreviewPanel. Both now call one exported normalizeScreenDetailTab, which also removes the duplicated legacy-tab list.
  • Android-only fields never showed. Players report android-tv or fire-tv and the server stores those strings unchanged, so platform === "android" hid the install-permission, Managed Kiosk, Power Assist, and device fields on every current Android player. New src/playerPlatform.ts holds one family predicate, used by all five gates and by SettingsOperations in place of its local copy. The Platform row now reports the string the device actually sent alongside the Android version.
  • Empty Maintenance workspace. A Viewer or Editor could select Maintenance and, with no command history, get a blank pane. It now renders a loading state, or says that an Owner or Administrator can send commands.
  • Unnamed progress bar. The release cache <progress> had no accessible name; the visible size text does not label a native control. It now carries an aria-label with the release and both sizes.

Server

  • Brand Bug logo could publish before it was downloadable. The worker sets player_compatible = TRUE while the asset is still processing, so resolveImageVariant could hand a Player a logo it cannot yet fetch. It now requires processing_status = 'ready'. The integration path covers the new state: a processing logo falls back to the mark's text and is not projected as an asset.
  • Migration 00077 validated under ACCESS EXCLUSIVE. ADD CONSTRAINT scanned player_releases inside Goose's transaction, holding the lock against cache-progress and release writes until commit. The constraint is now installed NOT VALID, and 00082 validates it in its own transaction under SHARE UPDATE EXCLUSIVE. Databases that already applied the original hold a valid constraint, so VALIDATE CONSTRAINT is a no-op there — confirmed against a database already at the old 00077.

Manifest schema

  • minLength: 1 accepted whitespace-only Brand Bug text that the server trims and rejects; the text-only branch now requires a non-space character. v12-v14 $ref into v11, so the one change covers them.
  • The README said a configured logo appears in assets; an unavailable logo drops the reference and falls back to text. Reworded to match runtime behavior.

Verification

  • npx tsc --noEmit, prettier --check, and the dashboard suite (321 tests in the touched areas, 584 overall) pass.
  • The two new dashboard tests were confirmed to fail against the pre-fix code, so they are real guards.
  • gofmt, go vet ./..., go build ./cmd/tilecast, and go test ./... with TEST_DATABASE_URL set all pass on this branch.

One thing to watch

The new migration is numbered 00082 because 00078-00081 are taken by other work not yet on main. If those land after this PR, renumber accordingly — Goose rejects out-of-order migrations on an existing database.

Summary by CodeRabbit

  • New Features

    • Screen details now handle legacy and invalid tabs more consistently.
    • Android-compatible screens display their reported Android version.
    • Viewers can see maintenance activity, including loading, empty, and recent command states.
    • Cache progress indicators now provide clearer accessibility information.
  • Bug Fixes

    • Unavailable or still-processing brand logos now fall back to text or are omitted when appropriate.
    • Brand configuration validation now rejects whitespace-only text.
  • Documentation

    • Documented logo fallback behavior for brand configurations.

CodeRabbit findings from #386 and the two PRs before it.

Screen detail tabs: ScreenDetailWithPreviewPage passed an unrecognized
?tab= value through unchanged while ScreenDetailPage clamped it to
Overview, so ?tab=bogus rendered the Overview panel without its preview
layout. Both now share normalizeScreenDetailTab.

Android gates: players report "android-tv" or "fire-tv" and the server
stores those strings unchanged, so platform === "android" hid every
Android-only field and control on every current Android player. One
predicate in playerPlatform.ts now covers the family, replacing the
local copy in SettingsOperations.

Maintenance workspace: a Viewer or Editor selecting Maintenance with no
command history saw an empty pane with no explanation. It now says who
can send commands.

Release cache progress: the native progress element had no accessible
name; the visible size text does not label it.

Brand Bug logo: the worker marks a variant player-compatible while the
asset is still processing, so resolveImageVariant could publish a logo
the Player cannot download yet. It now requires processing_status
'ready', covered by the integration path. The manifest schema also
accepted whitespace-only text that the server trims and rejects, and the
README overstated when a configured logo reaches assets.

Migration 00077 installed its CHECK while holding ACCESS EXCLUSIVE over
player_releases; it is now NOT VALID there and validated in 00082, which
is a no-op on databases that already applied the original.
@github-actions github-actions Bot added documentation Improvements or additions to documentation go Pull requests that update go code studio Typescript dashboard/web server server Docker server javascript Pull requests that update javascript code labels Jul 31, 2026
@coderabbitai

coderabbitai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The dashboard centralizes tab and platform handling, expands maintenance states, and adds tests. Database migrations defer and then validate a download-progress constraint. Manifest generation now excludes processing assets and supports documented text fallback behavior.

Changes

Dashboard screen management

Layer / File(s) Summary
Screen-detail tab normalization
apps/dashboard/src/pages/ScreensPage.tsx, apps/dashboard/src/pages/ScreenDetailWithPreviewPage.tsx, apps/dashboard/src/pages/ScreenDetailActivityTab.test.tsx
Shared tab normalization handles canonical, legacy, missing, and invalid tab values. Tests cover invalid-tab fallback.
Platform-aware screen UI
apps/dashboard/src/playerPlatform.ts, apps/dashboard/src/pages/ScreensPage.tsx, apps/dashboard/src/settings/SettingsOperations.tsx, apps/dashboard/src/pages/ScreenDetailActivityTab.test.tsx
Shared platform helpers support Android-compatible device details, platform filtering, device version display, and accessible cache progress labels.
Maintenance operation states
apps/dashboard/src/pages/ScreensPage.tsx, apps/dashboard/src/pages/ScreenDetailActivityTab.test.tsx
Viewer maintenance views now show loading feedback, an empty state, or recent command history.

Database constraint validation

Layer / File(s) Summary
Deferred download-progress validation
apps/server/internal/database/migrations/00077_player_release_download_progress.sql, apps/server/internal/database/migrations/00082_validate_player_release_download_progress.sql
Migration 00077 installs the byte constraint as NOT VALID. Migration 00082 validates the constraint and uses a no-op down migration.

Manifest asset fallback

Layer / File(s) Summary
Unavailable brand asset handling
apps/server/internal/playlists/service.go, apps/server/internal/playlists/plugin_assets_integration_test.go, packages/manifest-schema/schema-v11.json, packages/manifest-schema/README.md
Manifest generation excludes processing assets. Integration coverage verifies text-only output. The schema rejects whitespace-only fallback text, and the README documents unavailable-logo behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies that the pull request fixes review findings in the screen workspace.
Description check ✅ Passed The description covers the changes, verification results, migration impact, and documentation updates, despite not using the exact template headings or checkboxes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gibby/coderabbit-findings-386

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies"


Comment @coderabbitai help to get the list of available commands.

@gbyo
gbyo merged commit 5088e20 into main Jul 31, 2026
11 of 12 checks passed
@gbyo
gbyo deleted the gibby/coderabbit-findings-386 branch July 31, 2026 17:45

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/server/internal/playlists/plugin_assets_integration_test.go (1)

164-170: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the text fallback explicitly.

This test checks that the plugin remains and both image identifiers are removed. It does not check that Text remains available. Add an assertion for the expected non-whitespace fallback text.

As per coding guidelines, protocol changes require unit tests and a complete PostgreSQL integration path.

Proposed assertion
-	if !ok || config.ImageAssetID != nil || config.ImageVariantID != nil {
+	if !ok || config.ImageAssetID != nil || config.ImageVariantID != nil || config.Text != "Presented by Example" {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/internal/playlists/plugin_assets_integration_test.go` around
lines 164 - 170, Extend the fallback assertions in the plugin asset integration
test after the ManifestBrandBugConfig type check to verify that config.Text
contains the expected non-whitespace fallback text, while preserving the
existing plugin-count and image-identifier checks.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/dashboard/src/pages/ScreensPage.tsx`:
- Around line 3395-3421: Update the command-history conditional rendering in the
operations section to check commands.isError before the empty-list condition,
and render an error notice when api.screenCommands fails. Preserve the existing
loading, empty-history, and command-list states for successful requests.

In `@packages/manifest-schema/schema-v11.json`:
- Around line 126-129: Revert the change in schema-v11.json so the released v11
validation behavior remains unchanged, including acceptance of whitespace-only
text under the prior rule. Enforce the non-whitespace fallback in server output
instead, or introduce a new schema version only with an explicit Player rollout
contract.

---

Nitpick comments:
In `@apps/server/internal/playlists/plugin_assets_integration_test.go`:
- Around line 164-170: Extend the fallback assertions in the plugin asset
integration test after the ManifestBrandBugConfig type check to verify that
config.Text contains the expected non-whitespace fallback text, while preserving
the existing plugin-count and image-identifier checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 72532bb5-e4f2-4cf6-97e6-b92986e6afce

📥 Commits

Reviewing files that changed from the base of the PR and between 06f30f2 and 1d85ee2.

📒 Files selected for processing (11)
  • apps/dashboard/src/pages/ScreenDetailActivityTab.test.tsx
  • apps/dashboard/src/pages/ScreenDetailWithPreviewPage.tsx
  • apps/dashboard/src/pages/ScreensPage.tsx
  • apps/dashboard/src/playerPlatform.ts
  • apps/dashboard/src/settings/SettingsOperations.tsx
  • apps/server/internal/database/migrations/00077_player_release_download_progress.sql
  • apps/server/internal/database/migrations/00082_validate_player_release_download_progress.sql
  • apps/server/internal/playlists/plugin_assets_integration_test.go
  • apps/server/internal/playlists/service.go
  • packages/manifest-schema/README.md
  • packages/manifest-schema/schema-v11.json

Comment on lines +3395 to +3421
!canManageScreens(auth.status?.user) && (
<section className="operations">
<h3>Recent operations</h3>
<div className="command-history">
{commands.data?.items?.map((c) => (
<div key={c.id}>
<strong>
{c.type?.replaceAll("_", " ") ?? "Unknown command"}
</strong>
<span>
{c.state} · {new Date(c.createdAt).toLocaleString()}
</span>
<small>
{c.resultCode?.replaceAll("_", " ") ?? "No result yet"}
</small>
</div>
))}
</div>
{commands.isLoading ? (
<div className="table-loading">Loading operations…</div>
) : (commands.data?.items?.length ?? 0) === 0 ? (
<p>
No maintenance commands have been sent to this screen. An Owner
or Administrator can send them.
</p>
) : (
<div className="command-history">
{commands.data?.items?.map((c) => (
<div key={c.id}>
<strong>
{c.type?.replaceAll("_", " ") ?? "Unknown command"}
</strong>
<span>
{c.state} · {new Date(c.createdAt).toLocaleString()}
</span>
<small>
{c.resultCode?.replaceAll("_", " ") ?? "No result yet"}
</small>
</div>
))}
</div>
)}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Show a command-history error state.

If api.screenCommands fails, this branch evaluates the missing item list as empty. The page then states that no maintenance commands exist when the history could not be loaded.

Check commands.isError before the empty-list condition and render an error notice.

Proposed fix
             {commands.isLoading ? (
               <div className="table-loading">Loading operations…</div>
+            ) : commands.isError ? (
+              <div className="notice notice--error" role="alert">
+                Recent operations could not be loaded. {commands.error.message}
+              </div>
             ) : (commands.data?.items?.length ?? 0) === 0 ? (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
!canManageScreens(auth.status?.user) && (
<section className="operations">
<h3>Recent operations</h3>
<div className="command-history">
{commands.data?.items?.map((c) => (
<div key={c.id}>
<strong>
{c.type?.replaceAll("_", " ") ?? "Unknown command"}
</strong>
<span>
{c.state} · {new Date(c.createdAt).toLocaleString()}
</span>
<small>
{c.resultCode?.replaceAll("_", " ") ?? "No result yet"}
</small>
</div>
))}
</div>
{commands.isLoading ? (
<div className="table-loading">Loading operations…</div>
) : (commands.data?.items?.length ?? 0) === 0 ? (
<p>
No maintenance commands have been sent to this screen. An Owner
or Administrator can send them.
</p>
) : (
<div className="command-history">
{commands.data?.items?.map((c) => (
<div key={c.id}>
<strong>
{c.type?.replaceAll("_", " ") ?? "Unknown command"}
</strong>
<span>
{c.state} · {new Date(c.createdAt).toLocaleString()}
</span>
<small>
{c.resultCode?.replaceAll("_", " ") ?? "No result yet"}
</small>
</div>
))}
</div>
)}
!canManageScreens(auth.status?.user) && (
<section className="operations">
<h3>Recent operations</h3>
{commands.isLoading ? (
<div className="table-loading">Loading operations…</div>
) : commands.isError ? (
<div className="notice notice--error" role="alert">
Recent operations could not be loaded. {commands.error.message}
</div>
) : (commands.data?.items?.length ?? 0) === 0 ? (
<p>
No maintenance commands have been sent to this screen. An Owner
or Administrator can send them.
</p>
) : (
<div className="command-history">
{commands.data?.items?.map((c) => (
<div key={c.id}>
<strong>
{c.type?.replaceAll("_", " ") ?? "Unknown command"}
</strong>
<span>
{c.state} · {new Date(c.createdAt).toLocaleString()}
</span>
<small>
{c.resultCode?.replaceAll("_", " ") ?? "No result yet"}
</small>
</div>
))}
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/dashboard/src/pages/ScreensPage.tsx` around lines 3395 - 3421, Update
the command-history conditional rendering in the operations section to check
commands.isError before the empty-list condition, and render an error notice
when api.screenCommands fails. Preserve the existing loading, empty-history, and
command-list states for successful requests.

Comment on lines +126 to +129
{
"required": ["text"],
"properties": { "text": { "pattern": "\\S" } }
}

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep the released v11 schema immutable.

The manifest README states that released versions are not reinterpreted. This change makes a previously valid v11 payload invalid: text: " " with no imageAssetId passed the previous minLength: 1 rule but fails pattern: "\\S".

Keep schema-v11.json unchanged. Enforce the non-whitespace fallback in server output, or add a new schema version with an explicit Player rollout contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/manifest-schema/schema-v11.json` around lines 126 - 129, Revert the
change in schema-v11.json so the released v11 validation behavior remains
unchanged, including acceptance of whitespace-only text under the prior rule.
Enforce the non-whitespace fallback in server output instead, or introduce a new
schema version only with an explicit Player rollout contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation go Pull requests that update go code javascript Pull requests that update javascript code server Docker server studio Typescript dashboard/web server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant