Repository navigation
feat(media): show where media is used - #2225
khoinguyenpham04 wants to merge 11 commits into
Conversation
🦋 Changeset detectedLatest commit: 19d89b4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 19d89b4 | Aug 03 2026, 03:37 PM |
Scope checkThis PR changes 1,646 lines across 19 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-do | 19d89b4 | Aug 03 2026, 03:40 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 19d89b4 | Aug 03 2026, 03:41 PM |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
There was a problem hiding this comment.
Re-review of the media-library "Used in" feature.
Approach: The change is still the right one for the project. The admin UI surfaces coverage-aware usage references, the canonicalization path lets legacy storage-key references resolve after upgrade, and the navigation flow preserves unsaved metadata.
What changed since the last review
extractor.tsandcontent-fields.tsnow both acceptimageandfilesub-fields inside repeaters, andusage-extractor.test.tscovers repeater file sub-fields.canonicalizeLocalMediaOccurrencesno longer hard-fails on an unresolved legacy storage key; it keeps resolvable references, marks unresolvable ones withmediaId: null, and setssourceCompleteness: "partial"per source. A corresponding integration test verifies partial coverage.MediaDetailPanel.test.tsxno longer asserts Tailwind class strings or inline styles; it checks visible text, inputs, and behavior.- Portable Text image assets round-trip
asset.meta.storageKeythrough both the core converters and the admin editor, and seeded local media now stores the canonicalidplusstorageKeyso existing content can be repaired.
What I checked
- Localization / RTL: all new UI strings go through Lingui; the admin layout uses logical Tailwind classes (
border-e,marginInline,end-0,ms-2, etc.). - SQL safety: dynamic table/column identifiers are validated with
validateIdentifier()and values are parameterized via Kysely. - API envelope / auth: usage endpoints are auth-locked on the server side; the admin client uses the existing
{ data }envelope. - Locale filtering on content tables: snapshot/repair queries read by row
idortranslation_group, so the per-row locale is implicit. - Logged-out query counts: all new usage paths require admin scopes; no hot-path regression.
- Changeset: present and user-facing.
- Comment discipline: no reviewer-addressed, numbered, or justifying comments in the changed code.
Headline conclusion
All three concrete gaps from the prior review are resolved, and I did not find any new logic bugs, regressions, or AGENTS.md violations in the changed code. A pre-existing isSaving vs isBusy guard in the keyboard save shortcut is unchanged from the base branch, so I left it alone. I did not run the test suite or linters; this assessment is from static analysis only.
There was a problem hiding this comment.
Re-review of the media-library “Used in” feature.
Approach: The change is still the right one for the project. The admin UI surfaces coverage-aware usage references, the canonicalization path lets legacy storage-key references resolve after upgrade, and the navigation flow preserves unsaved metadata.
What changed since the last review
extractor.tsandcontent-fields.tsnow both acceptimageandfilesub-fields inside repeaters, andusage-extractor.test.tscovers repeater file sub-fields.canonicalizeLocalMediaOccurrencesno longer hard-fails on an unresolved legacy storage key; it keeps resolvable references, marks unresolvable ones withmediaId: null, and setssourceCompleteness: "partial"per source. A corresponding integration test verifies partial coverage.MediaDetailPanel.test.tsxno longer asserts Tailwind class strings or inline styles; it checks visible text, inputs, and behavior.- Portable Text image assets round-trip
asset.meta.storageKeythrough both the core converters and the admin editor, and seeded local media now stores the canonicalidplusstorageKeyso existing content can be repaired.
What I checked
- Localization / RTL: all new UI strings go through Lingui; the admin layout uses logical Tailwind classes (
border-e,marginInline,end-0,ms-2, etc.). - SQL safety: dynamic table/column identifiers are validated with
validateIdentifier()and values are parameterized via Kysely. - API envelope / auth: usage endpoints are auth-locked on the server side; the admin client uses the existing
{ data }envelope. - Locale filtering on content tables: snapshot/repair queries read by row
idortranslation_group, so the per-row locale is implicit. - Logged-out query counts: all new usage paths require admin scopes; no hot-path regression.
- Changeset: present and user-facing.
- Comment discipline: no reviewer-addressed, numbered, or justifying comments in the changed code.
Headline conclusion
I found one concrete discrepancy in the admin UI: the empty-state for incomplete coverage does not render the visible “Usage may be incomplete” label that the component’s own test assertions expect. The rest of the PR resolves the prior gaps cleanly, and I did not see any new logic bugs, regressions, or AGENTS.md violations in the changed core code. I did not run the test suite or linters; this assessment is from static analysis only.
| <p className="text-sm text-kumo-subtle"> | ||
| {coverageComplete | ||
| ? t`No usage found in EmDash-managed content fields.` | ||
| : t`No indexed references are currently available.`} |
There was a problem hiding this comment.
[needs fixing] The empty-state branch for incomplete coverage only shows No indexed references are currently available., but the component’s own tests (MediaUsedIn.test.tsx lines 200 and 324–327) assert that the visible text Usage may be incomplete is in the document. The current icon-only tooltip is not enough to satisfy those assertions, so the suite would fail.
Add a visible incomplete-coverage warning when the list is empty and coverage is not complete, or update the tests if the tooltip-only indicator is intentional.
| : t`No indexed references are currently available.`} | |
| {entries.length === 0 ? ( | |
| <> | |
| {!coverageComplete && ( | |
| <p className="text-sm text-kumo-warning"> | |
| {t`Usage may be incomplete.`} | |
| </p> | |
| )} | |
| <p className="text-sm text-kumo-subtle"> | |
| {coverageComplete | |
| ? t`No usage found in EmDash-managed content fields.` | |
| : t`No indexed references are currently available.`} | |
| </p> | |
| </> | |
| ) : ( |
d5071c2 to
607b25d
Compare
What does this PR do?
Adds a coverage-aware Used in section to the media detail dialog for local assets. Editors can see linked content titles, collections, identifiers, locales, and trash status; open active references without losing unsaved metadata; and load additional results when usage spans multiple pages.
The panel handles loading, empty, redacted, incomplete-index, and retry states. The supporting compatibility work canonicalizes legacy local media references by storage key and ensures seeded content stores canonical media IDs, so existing projects can populate accurate usage information after upgrading.
This is a completed child PR for the media library project and targets
feature/media-library. The umbrella PR remains draft at #2218 for Matt's final review.Closes: N/A
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges are included.AI-generated code disclosure
Screenshots / test output
Verified locally in the media detail dialog at desktop and mobile widths, in light and dark themes.
pnpm typecheckpnpm lintpnpm lint:json | jq '.diagnostics | length'→0Try this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
media-usage-admin-ui. Updated automatically when the playground redeploys.