Skip to content

feat(media): show where media is used - #2225

Closed
khoinguyenpham04 wants to merge 11 commits into
mainfrom
media-usage-admin-ui
Closed

khoinguyenpham04 wants to merge 11 commits into
mainfrom
media-usage-admin-ui

Conversation

@khoinguyenpham04

@khoinguyenpham04 khoinguyenpham04 commented Jul 24, 2026 •

Copy link
Copy Markdown
Collaborator

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

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). No messages.po changes are included.
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion — N/A; this project was directly approved in Matt's maintainer handoff and is tracked by umbrella PR feat(admin): media library project #2218.

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: OpenAI Codex (GPT-5)

Screenshots / test output

Verified locally in the media detail dialog at desktop and mobile widths, in light and dark themes.

  • pnpm typecheck
  • pnpm lint
  • Admin focused suite: 62 tests passed
  • Core focused suite: 69 tests passed
  • Final Used in component suite: 17 tests passed
  • pnpm lint:json | jq '.diagnostics | length' → 0

Try 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.

@changeset-bot

changeset-bot Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19d89b4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
@emdash-cms/admin Patch
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/plugin-mcp-smoke Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

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

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 19d89b4 Aug 03 2026, 03:37 PM

@github-actions

Copy link
Copy Markdown
Contributor

Scope check

This 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.

@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Jul 24, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-do 19d89b4 Aug 03 2026, 03:40 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 19d89b4 Aug 03 2026, 03:41 PM

emdashbot[bot]

This comment was marked as outdated.

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond overlap and removed review/needs-review No maintainer or bot review yet labels Jul 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

@github-actions github-actions Bot added review/needs-rereview New commits since the last review and removed review/awaiting-author Reviewed; waiting on the author to respond labels Jul 24, 2026
@khoinguyenpham04 khoinguyenpham04 added the bot:review Trigger an emdashbot code review on this PR label Jul 24, 2026
emdashbot[bot]

This comment was marked as outdated.

@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Jul 24, 2026
@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-rereview New commits since the last review labels Jul 24, 2026
@github-actions github-actions Bot added review/needs-rereview New commits since the last review and removed review/awaiting-author Reviewed; waiting on the author to respond labels Aug 2, 2026
@khoinguyenpham04 khoinguyenpham04 added the bot:review Trigger an emdashbot code review on this PR label Aug 2, 2026

@emdashbot emdashbot 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.

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.ts and content-fields.ts now both accept image and file sub-fields inside repeaters, and usage-extractor.test.ts covers repeater file sub-fields.
  • canonicalizeLocalMediaOccurrences no longer hard-fails on an unresolved legacy storage key; it keeps resolvable references, marks unresolvable ones with mediaId: null, and sets sourceCompleteness: "partial" per source. A corresponding integration test verifies partial coverage.
  • MediaDetailPanel.test.tsx no longer asserts Tailwind class strings or inline styles; it checks visible text, inputs, and behavior.
  • Portable Text image assets round-trip asset.meta.storageKey through both the core converters and the admin editor, and seeded local media now stores the canonical id plus storageKey so 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 id or translation_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.

@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Aug 2, 2026
@github-actions github-actions Bot added review/approved Approved; no new commits since and removed review/needs-rereview New commits since the last review labels Aug 2, 2026
@github-actions github-actions Bot added review/needs-rereview New commits since the last review and removed review/approved Approved; no new commits since labels Aug 3, 2026
@khoinguyenpham04 khoinguyenpham04 added the bot:review Trigger an emdashbot code review on this PR label Aug 3, 2026

@emdashbot emdashbot 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.

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.ts and content-fields.ts now both accept image and file sub-fields inside repeaters, and usage-extractor.test.ts covers repeater file sub-fields.
  • canonicalizeLocalMediaOccurrences no longer hard-fails on an unresolved legacy storage key; it keeps resolvable references, marks unresolvable ones with mediaId: null, and sets sourceCompleteness: "partial" per source. A corresponding integration test verifies partial coverage.
  • MediaDetailPanel.test.tsx no longer asserts Tailwind class strings or inline styles; it checks visible text, inputs, and behavior.
  • Portable Text image assets round-trip asset.meta.storageKey through both the core converters and the admin editor, and seeded local media now stores the canonical id plus storageKey so 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 id or translation_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.`}

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.

[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.

Suggested change
: 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>
</>
) : (

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant