fix(assets): restore custom fields on the asset overview for BASE and SELF_SERVICE - #2824
Conversation
… SELF_SERVICE The overview loader skips `getActiveCustomFields` for users without `asset: update` (a perf optimization from #2486), but the page built its ENTIRE custom-fields list from those definitions. BASE holds `asset: [read]` and SELF_SERVICE holds `asset: [read, custody]`, so both received an empty array and saw no custom fields at all — even on assets with values set. Live since 2026-05-07. Invisible to CI (an empty array typechecks and passes every test) and to anyone who could have caught it, since ADMIN and OWNER short-circuit to allow-all in `hasPermission`. The stored values already carry their own definition via `getAssetOverviewFields`, so no extra query is needed and the optimization stays intact. The new `buildAssetOverviewCustomFields` helper seeds the list from the asset's values and only tops it up with editable definitions for the "Not set" placeholder rows. This also fixes a second bug of the same class affecting every role including owners: an uncategorized asset is offered only uncategorized definitions, so a value left behind by a category-scoped field rendered nowhere. Those rows are now visible but read-only — the action rejects writes for out-of-scope definitions with a 400, so offering an editor there would dead-end. Admins and owners keep inline editing on every row that had it before. Adds two rules: one for the loader-gating bug class, one requiring the GitHub `fix` label on fix PRs.
🩺 React Doctor — webappFindings on the files changed by this PR:
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
WalkthroughThe PR adds a reusable custom-field builder, preserves stored fields for view-only users, applies field-level editability in the asset overview, adds regression tests, and documents rules for permission-gated display data and bug-fix PR labels. ChangesAsset custom-field display
Bug-fix PR labeling
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
The bug
BASE and SELF_SERVICE users see no custom fields at all on an asset's overview page, even when values are set. Reported by a customer.
Root cause
The overview loader skips three "editor-only" queries for users who can't update the asset — a perf optimization from #2486, live since 2026-05-07:
Categories and locations genuinely are editor-only (dropdown sources). But the component built the entire custom-fields list from
allCustomFieldDefs:BASE holds
asset: [read], SELF_SERVICE holdsasset: [read, custody]— neither hasupdate, so the array is empty and the whole card disappears.The surrounding code shows this was never intended: it already had a "hide Not set rows from view-only users" branch and a card condition keyed on
some(storedValue)— logic that could never fire.Why nobody caught it for three months: an empty array typechecks and passes every test, and ADMIN/OWNER short-circuit to allow-all in
hasPermission, so no one who could have noticed ever saw it.The fix
Stored values already carry their own definition via
getAssetOverviewFields(id,name,type,options, …), so no extra query is needed and the perf optimization stays intact. New pure helperbuildAssetOverviewCustomFieldsseeds the list from the asset's own values and only tops up with editable definitions for the "Not set" placeholder rows.Second bug fixed along the way
Affects every role, including owners: an uncategorized asset is offered only uncategorized definitions, so a value left behind by a category-scoped field rendered nowhere. Those rows are now visible but read-only — the action rejects writes for out-of-scope definitions with a 400 (
getActiveCustomFieldsForAsset→if (!fieldDef) throw 400), so offering an editor there would dead-end.No change for admins/owners
Both validators short-circuit those roles, so
canEditAssetistrue,allCustomFieldDefsis actually fetched, every definition in it getsisEditable: true, andcanEditFieldistrue. Every row that had a pencil still has one. The only non-editable rows are ones that previously didn't render at all.Blast radius checked
canEditAssetuses on the page (category, location, description, tags, value, total value, asset model, placements) render their display path for view-only users — only pencils and editors are gated._layout+that gates data on a permission.assets.$assetIdAPI fetch custom fields ungated — unaffected.lastScanis deliberately withheld from these roles (scan: read— scanner name, email, GPS). Intentional privacy gate, left as-is.Testing
app/utils/custom-fields.test.ts, written failing first — all 6 failed before the fix, 15/15 pass afterpnpm webapp:validate: 4349 passed, lint + typecheck clean (the twoactivity[.csv]suites are the known 10s hookTimeout flake; both pass at--hookTimeout=30000)Also included
Two
.claude/rules/entries:permission-gated-loader-data-must-not-gate-display.md— the bug class: gating a loader fetch is safe only if nothing displayed derives from itlabel-fix-prs-on-github.md— fix PRs get thefixlabel at creation timeSummary by CodeRabbit
New Features
Bug Fixes
Documentation
fixlabel to bug-fix pull requests.