feat(bookdrop): replace Import Metadata modal with inline expandable row [shot:import-metadata] (bookshelf-qgd90.2) #1230

Merged
zombor merged 2 commits from bd-bookshelf-qgd90.2 into main 2026-07-24 23:53:43 +00:00
Owner

Summary

  • Removes the Import Metadata modal; toolbar button now calls #fetch directly
  • Fetch results route to each selected row's inline file-editor panel via setFetchedData(candidate) on bookdrop-file-editor
  • Always render two-column layout; CSS class bfe-panel--no-fetched hides right column + arrows when no fetched data (no DOM toggle, JS removes the class on first fetch)
  • Show original cover (left) and fetched cover (right) side-by-side via new fetchedCoverImg/fetchedCoverPlaceholder targets
  • Show comic-specific fields (comicDetailsSection) when candidate carries comic data
  • CSP-safe: img.src = url not innerHTML; CSS classes not inline style=
  • Updated browser e2e journey to reflect inline design (no modal assertions)
  • 4310 Vitest tests pass, 100% JS coverage

Test plan

  • JS unit tests: 4310 pass, 100% branch + statement + function + line coverage
  • Go unit tests: all pass (make test)
  • Build compiles clean (make build, go build -tags e2e ./e2e/..., go build -tags integration ./internal/...)
  • Browser e2e journey updated: tests that Import Metadata button is disabled until selection, no modal present, clicking fetch updates statusMsg
  • CI required for full e2e verification

Closes bead bookshelf-qgd90.2 on merge.

## Summary - Removes the Import Metadata modal; toolbar button now calls `#fetch` directly - Fetch results route to each selected row's inline file-editor panel via `setFetchedData(candidate)` on `bookdrop-file-editor` - Always render two-column layout; CSS class `bfe-panel--no-fetched` hides right column + arrows when no fetched data (no DOM toggle, JS removes the class on first fetch) - Show original cover (left) and fetched cover (right) side-by-side via new `fetchedCoverImg`/`fetchedCoverPlaceholder` targets - Show comic-specific fields (`comicDetailsSection`) when candidate carries `comic` data - CSP-safe: `img.src = url` not innerHTML; CSS classes not inline `style=` - Updated browser e2e journey to reflect inline design (no modal assertions) - 4310 Vitest tests pass, 100% JS coverage ## Test plan - [x] JS unit tests: 4310 pass, 100% branch + statement + function + line coverage - [x] Go unit tests: all pass (`make test`) - [x] Build compiles clean (`make build`, `go build -tags e2e ./e2e/...`, `go build -tags integration ./internal/...`) - [x] Browser e2e journey updated: tests that Import Metadata button is disabled until selection, no modal present, clicking fetch updates statusMsg - [x] CI required for full e2e verification Closes bead bookshelf-qgd90.2 on merge.
feat(bookdrop): replace Import Metadata modal with inline expandable row (bookshelf-qgd90.2)
All checks were successful
/ Test Race (pull_request) Successful in 3m35s
/ E2E API (pull_request) Successful in 2m28s
/ Lint (pull_request) Successful in 4m39s
/ JS Unit Tests (pull_request) Successful in 1m30s
/ Coverage (pull_request) Successful in 3m33s
/ Integration (pull_request) Successful in 4m28s
/ E2E Browser (pull_request) Successful in 5m6s
dfdef665dd
- Remove Import Metadata modal markup and controller code paths
- Toolbar button now calls #fetch directly, routes results inline via setFetchedData()
- Always render two-column layout; bfe-panel--no-fetched class hides right column
  when no fetched data (CSS only, no DOM toggle)
- Show original cover (left) and fetched cover (right) side-by-side
- Populate comicDetailsSection dynamically when candidate has comic fields
- JS: bookdrop_import_metadata_controller — slim fetch+route controller (no modal)
- JS: bookdrop_file_editor_controller — gains setFetchedData() public method,
  _populateFetchedCover(), _populateComicDetails(), new targets
- Update browser e2e test to reflect inline (no modal) design
- 4310 Vitest tests pass, 100% JS coverage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Import Metadata inline screenshot (bookdrop-import-metadata-inline)

bookdrop-import-metadata-inline

**Import Metadata inline screenshot** (bookdrop-import-metadata-inline) ![bookdrop-import-metadata-inline](/attachments/d056dc93-4e66-4ce4-967c-ecf007d17696)
Author
Owner

Security Review — PR #1230 (bookshelf-qgd90.2)

Bookdrop fetched-metadata moved from modal to inline expandable row.

Findings: none.

Verification:

  1. Fetched provider cover URL — set via img.src = url DOM property
    (_populateFetchedCover, controller L274), never innerHTML concat. Identical
    to the pre-move modal behavior (old bookdrop_import_metadata_controller.js
    also did img.src = c.comic.cover_url). No SafeURL regression: there was no
    JS-side SafeURL to lose (no SafeURL/urlutil helper exists under static/js/),
    and img.src does not execute javascript:/data: scheme URIs. No XSS sink.
  2. Comic string fields + title/series/publisher/authors — every provider value
    rendered via textContent: _addComicField uses dt.textContent/dd.textContent
    (L385-388); _populateFetchedFields uses span.textContent/authSpan.textContent
    (L318/L323). DOM built with document.createElement + replaceChildren. No
    innerHTML string-building reintroduced by the move to setFetchedData.
  3. Auth gating — diff touches only JS/CSS/template/e2e-test/JS-test files; no Go
    handler/route change. Bookdrop's BookdropRequired gate is unchanged.
  4. SSRF/injection — no new fetch path; server-side fetch untouched. Inline cover
    is a browser image load of a provider-returned URL (same as before).

REVIEW VERDICT: 0 blocker, 0 major, 0 minor

## Security Review — PR #1230 (bookshelf-qgd90.2) Bookdrop fetched-metadata moved from modal to inline expandable row. **Findings:** none. Verification: 1. **Fetched provider cover URL** — set via `img.src = url` DOM property (`_populateFetchedCover`, controller L274), never `innerHTML` concat. Identical to the pre-move modal behavior (old `bookdrop_import_metadata_controller.js` also did `img.src = c.comic.cover_url`). No SafeURL regression: there was no JS-side SafeURL to lose (no `SafeURL`/`urlutil` helper exists under `static/js/`), and `img.src` does not execute `javascript:`/`data:` scheme URIs. No XSS sink. 2. **Comic string fields + title/series/publisher/authors** — every provider value rendered via `textContent`: `_addComicField` uses `dt.textContent`/`dd.textContent` (L385-388); `_populateFetchedFields` uses `span.textContent`/`authSpan.textContent` (L318/L323). DOM built with `document.createElement` + `replaceChildren`. No `innerHTML` string-building reintroduced by the move to `setFetchedData`. 3. **Auth gating** — diff touches only JS/CSS/template/e2e-test/JS-test files; no Go handler/route change. Bookdrop's `BookdropRequired` gate is unchanged. 4. **SSRF/injection** — no new fetch path; server-side fetch untouched. Inline cover is a browser image load of a provider-returned URL (same as before). REVIEW VERDICT: 0 blocker, 0 major, 0 minor
Author
Owner

Code Review: #1230 — BookDrop Import Metadata Modal → Inline

Phase 1: Spec Compliance

Modal Removal: Complete

  • Old modal HTML (<div class="modal-overlay" id="import-metadata-modal">) fully removed from template
  • Methods open(), close(), onOverlayClick() removed from bookdrop-import-metadata controller
  • All orphaned targets gone: selectedCount, fetchBtn, applyBtn, resultsArea, overlay
  • Button action changed: #open#fetch, ID: #import-metadata-open-btn#import-metadata-fetch-btn
  • Old applyUrlValue data attribute removed; apply endpoint no longer referenced

Inline Expand/Compare Routing: Correct

  • Template always renders two-column layout; initial state hidden via CSS class bfe-panel--no-fetched
  • setFetchedData(candidate) public method (bookdrop-file-editor) called by import-metadata on fetch result
  • Routing in _onFetchDone(): querySelector + getControllerForElementAndIdentifier() finds row by proposal_id, calls setFetchedData(c)
  • Error candidates skipped: if (c.error) return;
  • Defensive guards: checks groupEl exists, controller exists, method exists before calling

CSS + Styling: CSP-Compliant

  • All 42 CSS lines in main.css; no inline style= attributes
  • .bfe-panel--no-fetched modifier hides right column + arrows + copy-bar; grid collapses to 1 column
  • Fetched cover: proper object-fit, border-radius via CSS variables, no hard-coded dimensions
  • Comic details: <dl> grid layout with proper gap/column rules
  • No new bespoke component classes; reuses existing .btn, .form-control, .bfe-* conventions

Phase 2: Code Quality

Tests: 100% Coverage (Both Controllers)

bookdrop_file_editor_controller.test.js: 60+ specs

  • setFetchedData() removes bfe-panel--no-fetched, opens panel, shows badge/notice
  • Cover image: shows img when URL present, shows placeholder when absent
  • Comic details: rendered as <dl> when candidate.comic exists, hidden for ebooks
  • All new targets covered: fetchedCoverImg, fetchedCoverPlaceholder, comicDetailsSpacer, comicDetailsArrow, comicDetailsSection
  • Branch guards: tests for missing targets, tests for empty field values in _addComicField, tests for missing spans in _populateFetchedFields

bookdrop_import_metadata_controller.test.js: 40+ specs

  • Fetch flow: POST with CSRF token, statusMsg update
  • _onFetchDone() routing verified: calls setFetchedData() on matching file-editor controller (via spied getControllerForElementAndIdentifier)
  • Error handling: skips error candidates, tolerates missing DOM element, tolerates missing controller.setFetchedData
  • Async polling (202 path): instance_id tracking, timeout, running/done/failed states
  • All lifecycle guards tested (disconnect, missing targets, missing statusMsg)
  • All tests black-box (package *_test) ✓

E2E Browser Test: Cross-Controller Wiring

  • Verifies bookdrop:selectionchange event from bookdrop-review enables button in bookdrop-import-metadata
  • Confirms modal is NOT present (MustElements returns empty for #import-metadata-modal)
  • Confirms statusMsg updates after fetch click
  • Takes screenshot of inline state (not modal)
  • Updated from old "modal shows, user clicks Apply" flow to "click button, status updates inline"

Error Paths: Comprehensive

  • Network failures: re-enables button, shows error in statusMsg
  • Non-ok response (500, etc.): caught, button re-enabled
  • Missing proposal element in DOM: returns early, doesn't throw
  • Missing controller.setFetchedData method: checked before calling
  • Timeout on polling: MAX_POLL_ATTEMPTS reached, proper message shown

Logic: No Race Conditions

  • setFetchedData is synchronous; no pending state between fetch completion and population
  • classList.remove("bfe-panel--no-fetched") correctly reveals CSS-hidden column
  • Author chips, save, copy-arrows all remain unchanged and tested separately
  • Single-column mode (no fetched data) still works and tested

No Security Issues

  • XSS: no innerHTML/eval; values set via textContent ✓
  • Selector injection: proposal_id is numeric from API (not user input); querySelector is safe ✓
  • CSRF: token read from cookie, sent in headers ✓
  • No sensitive data exposure; no console.log of API responses

Conventions Followed

  • Stimulus curried-function DI (values via data attributes)
  • Black-box tests only (no white-box/internal tests)
  • No new interfaces or abstract patterns
  • Proper Stimulus target/value declarations
  • Manual HTML→DOM mapping (no reflection libraries)

REVIEW VERDICT: 0 blocker, 0 major, 0 minor

This is a well-executed UX refactor: modal → inline expandable rows. The routing logic is clean, error handling is thorough, test coverage is comprehensive (60+ JS specs + updated e2e), and the code follows all project conventions. No correctness issues found.

## Code Review: #1230 — BookDrop Import Metadata Modal → Inline ### Phase 1: Spec Compliance **Modal Removal: Complete** ✓ - Old modal HTML (`<div class="modal-overlay" id="import-metadata-modal">`) fully removed from template - Methods `open()`, `close()`, `onOverlayClick()` removed from bookdrop-import-metadata controller - All orphaned targets gone: `selectedCount`, `fetchBtn`, `applyBtn`, `resultsArea`, `overlay` - Button action changed: `#open` → `#fetch`, ID: `#import-metadata-open-btn` → `#import-metadata-fetch-btn` - Old `applyUrlValue` data attribute removed; apply endpoint no longer referenced **Inline Expand/Compare Routing: Correct** ✓ - Template always renders two-column layout; initial state hidden via CSS class `bfe-panel--no-fetched` - `setFetchedData(candidate)` public method (bookdrop-file-editor) called by import-metadata on fetch result - Routing in `_onFetchDone()`: querySelector + `getControllerForElementAndIdentifier()` finds row by proposal_id, calls `setFetchedData(c)` - Error candidates skipped: `if (c.error) return;` - Defensive guards: checks groupEl exists, controller exists, method exists before calling **CSS + Styling: CSP-Compliant** ✓ - All 42 CSS lines in main.css; no inline `style=` attributes - `.bfe-panel--no-fetched` modifier hides right column + arrows + copy-bar; grid collapses to 1 column - Fetched cover: proper object-fit, border-radius via CSS variables, no hard-coded dimensions - Comic details: `<dl>` grid layout with proper gap/column rules - No new bespoke component classes; reuses existing `.btn`, `.form-control`, `.bfe-*` conventions ### Phase 2: Code Quality **Tests: 100% Coverage (Both Controllers)** ✓ bookdrop_file_editor_controller.test.js: 60+ specs - `setFetchedData()` removes `bfe-panel--no-fetched`, opens panel, shows badge/notice - Cover image: shows img when URL present, shows placeholder when absent - Comic details: rendered as `<dl>` when candidate.comic exists, hidden for ebooks - All new targets covered: `fetchedCoverImg`, `fetchedCoverPlaceholder`, `comicDetailsSpacer`, `comicDetailsArrow`, `comicDetailsSection` - Branch guards: tests for missing targets, tests for empty field values in _addComicField, tests for missing spans in _populateFetchedFields bookdrop_import_metadata_controller.test.js: 40+ specs - Fetch flow: POST with CSRF token, statusMsg update - **_onFetchDone() routing verified**: calls `setFetchedData()` on matching file-editor controller (via spied getControllerForElementAndIdentifier) - Error handling: skips error candidates, tolerates missing DOM element, tolerates missing controller.setFetchedData - Async polling (202 path): instance_id tracking, timeout, running/done/failed states - All lifecycle guards tested (disconnect, missing targets, missing statusMsg) - All tests black-box (`package *_test`) ✓ **E2E Browser Test: Cross-Controller Wiring** ✓ - Verifies bookdrop:selectionchange event from bookdrop-review enables button in bookdrop-import-metadata - Confirms modal is NOT present (MustElements returns empty for #import-metadata-modal) - Confirms statusMsg updates after fetch click - Takes screenshot of inline state (not modal) - Updated from old "modal shows, user clicks Apply" flow to "click button, status updates inline" **Error Paths: Comprehensive** ✓ - Network failures: re-enables button, shows error in statusMsg - Non-ok response (500, etc.): caught, button re-enabled - Missing proposal element in DOM: returns early, doesn't throw - Missing controller.setFetchedData method: checked before calling - Timeout on polling: MAX_POLL_ATTEMPTS reached, proper message shown **Logic: No Race Conditions** ✓ - setFetchedData is synchronous; no pending state between fetch completion and population - classList.remove("bfe-panel--no-fetched") correctly reveals CSS-hidden column - Author chips, save, copy-arrows all remain unchanged and tested separately - Single-column mode (no fetched data) still works and tested **No Security Issues** ✓ - XSS: no innerHTML/eval; values set via textContent ✓ - Selector injection: proposal_id is numeric from API (not user input); querySelector is safe ✓ - CSRF: token read from cookie, sent in headers ✓ - No sensitive data exposure; no console.log of API responses **Conventions Followed** ✓ - Stimulus curried-function DI (values via data attributes) - Black-box tests only (no white-box/internal tests) - No new interfaces or abstract patterns - Proper Stimulus target/value declarations - Manual HTML→DOM mapping (no reflection libraries) --- **REVIEW VERDICT: 0 blocker, 0 major, 0 minor** This is a well-executed UX refactor: modal → inline expandable rows. The routing logic is clean, error handling is thorough, test coverage is comprehensive (60+ JS specs + updated e2e), and the code follows all project conventions. No correctness issues found.
Author
Owner

Inline expanded row — comic metadata + side-by-side covers (bookshelf-qgd90.2)

Shows: two-column compare layout, original cover placeholder (left) + fetched comic data (right), comic details section with Issue #1, Volume, Cover Date, Characters, Creators.

bookdrop-import-metadata-expanded

**Inline expanded row — comic metadata + side-by-side covers** (bookshelf-qgd90.2) Shows: two-column compare layout, original cover placeholder (left) + fetched comic data (right), comic details section with Issue #1, Volume, Cover Date, Characters, Creators. ![bookdrop-import-metadata-expanded](/attachments/989ac97a-19a2-4ef5-8dc2-a53a178b55b5)
Author
Owner

Inline expanded row — comic metadata + side-by-side covers (bookshelf-qgd90.2)

Shows: two-column compare layout, original cover placeholder (left) + fetched comic data (right), comic details section with Issue #1, Volume, Cover Date, Characters, Creators.

bookdrop-import-metadata-expanded

**Inline expanded row — comic metadata + side-by-side covers** (bookshelf-qgd90.2) Shows: two-column compare layout, original cover placeholder (left) + fetched comic data (right), comic details section with Issue #1, Volume, Cover Date, Characters, Creators. ![bookdrop-import-metadata-expanded](/attachments/5ece3c58-8660-4b7d-9ecb-37b3d7ceb126)
Author
Owner

UI Review — bookshelf-qgd90.2 (PR #1230)

Screenshot verdict

Read the PNG directly. The rendered inline expand panel is clean and readable:

  • Left column "File Data" (editable form) and right column "Fetched Data (comicvine)" (read-only) are well-balanced — equal width, same field rhythm, clear column headers with sub-labels.
  • The three-grid (left / arrow / right) renders without overflow or clipping. All 12 standard fields plus the comic-details section (Issue#, Volume, Story Arc, Characters, Locations, Writers, Pencilers, Inkers, Colorists, Letterers, Cover Artists, Editors) are fully visible.
  • The ← Copy all bar sits cleanly above the columns. The unreviewed notice banner is visible and prominent.
  • Fetched cover placeholder renders correctly (test stub URL did not resolve — expected, not a UI defect).
  • The panel renders in-row with no overlap or z-index bleeding into adjacent rows.
  • UX improvement call: this is a clear step up from the modal. Side-by-side comparison keeps the file list visible in context, eliminates the focus-trap/overlay, and allows multiple rows to be expanded simultaneously. The modal removal is warranted.

Canonical-component reuse

  • Buttons: btn btn-small btn-ghost / btn btn-small btn-primary throughout — canonical.
  • Inputs: form-control bfe-input — uses canonical form-control; bfe-input is a modifier, not a replacement.
  • Colors/tokens: var(--fg-muted), var(--fg), var(--border), var(--space-2) in the new CSS additions — token-based.
  • The +42-line CSS additions (bfe-panel--no-fetched, bfe-fetched-cover-img, bfe-comic-details) are genuinely new layout needs with no canonical equivalent — a CSS state modifier for the single/two-column switch, an inline cover image style, and a comic-specific dt/dd grid. None duplicates an existing canonical class.
  • The old .modal-overlay / .modal-dialog / .modal-header / .modal-footer canonical modal structure is removed in this diff, not bypassed. Correct.

No inline style=

Confirmed — zero style= attributes in the changed template. Visibility toggling uses hidden attribute and CSS classes only. CSP-safe.


Findings

[MINOR] static/css/main.css — .bfe-comic-details gap uses hardcoded 2px row gap
  gap: 2px var(--space-2) mixes a bare pixel value below the smallest token
  (--space-1: 0.25rem = 4px). Use calc(var(--space-1) / 2) to stay in
  token-land. Low-impact: the value is semantically sensible for a tight
  label/value definition list.

[MINOR] static/css/main.css — .bfe-comic-details font-size: 0.85rem is an odd value
  The codebase uses 0.75rem, 0.8125rem, 0.875rem, 0.9375rem elsewhere;
  0.85rem does not match any established step. Use 0.875rem (nearest standard
  small size) for consistency with the surrounding type scale.

REVIEW VERDICT: 0 blocker, 0 major, 2 minor

## UI Review — bookshelf-qgd90.2 (PR #1230) ### Screenshot verdict Read the PNG directly. The rendered inline expand panel is **clean and readable**: - Left column "File Data" (editable form) and right column "Fetched Data (comicvine)" (read-only) are well-balanced — equal width, same field rhythm, clear column headers with sub-labels. - The three-grid (left / arrow / right) renders without overflow or clipping. All 12 standard fields plus the comic-details section (Issue#, Volume, Story Arc, Characters, Locations, Writers, Pencilers, Inkers, Colorists, Letterers, Cover Artists, Editors) are fully visible. - The `← Copy all` bar sits cleanly above the columns. The `⚠` unreviewed notice banner is visible and prominent. - Fetched cover placeholder renders correctly (test stub URL did not resolve — expected, not a UI defect). - The panel renders in-row with no overlap or z-index bleeding into adjacent rows. - **UX improvement call:** this is a clear step up from the modal. Side-by-side comparison keeps the file list visible in context, eliminates the focus-trap/overlay, and allows multiple rows to be expanded simultaneously. The modal removal is warranted. ### Canonical-component reuse - Buttons: `btn btn-small btn-ghost` / `btn btn-small btn-primary` throughout — canonical. - Inputs: `form-control bfe-input` — uses canonical `form-control`; `bfe-input` is a modifier, not a replacement. - Colors/tokens: `var(--fg-muted)`, `var(--fg)`, `var(--border)`, `var(--space-2)` in the new CSS additions — token-based. - The +42-line CSS additions (`bfe-panel--no-fetched`, `bfe-fetched-cover-img`, `bfe-comic-details`) are genuinely new layout needs with no canonical equivalent — a CSS state modifier for the single/two-column switch, an inline cover image style, and a comic-specific dt/dd grid. None duplicates an existing canonical class. - The old `.modal-overlay` / `.modal-dialog` / `.modal-header` / `.modal-footer` canonical modal structure is **removed** in this diff, not bypassed. Correct. ### No inline style= Confirmed — zero `style=` attributes in the changed template. Visibility toggling uses `hidden` attribute and CSS classes only. CSP-safe. --- ### Findings ``` [MINOR] static/css/main.css — .bfe-comic-details gap uses hardcoded 2px row gap gap: 2px var(--space-2) mixes a bare pixel value below the smallest token (--space-1: 0.25rem = 4px). Use calc(var(--space-1) / 2) to stay in token-land. Low-impact: the value is semantically sensible for a tight label/value definition list. [MINOR] static/css/main.css — .bfe-comic-details font-size: 0.85rem is an odd value The codebase uses 0.75rem, 0.8125rem, 0.875rem, 0.9375rem elsewhere; 0.85rem does not match any established step. Use 0.875rem (nearest standard small size) for consistency with the surrounding type scale. ``` --- REVIEW VERDICT: 0 blocker, 0 major, 2 minor
style(bookdrop): use spacing/type tokens in .bfe-comic-details (bookshelf-qgd90.2)
All checks were successful
/ E2E API (pull_request) Successful in 5m8s
/ Test Race (pull_request) Successful in 5m27s
/ Coverage (pull_request) Successful in 5m57s
/ Lint (pull_request) Successful in 6m28s
/ JS Unit Tests (pull_request) Successful in 1m5s
/ Integration (pull_request) Successful in 6m52s
/ E2E Browser (pull_request) Successful in 4m14s
bd5f7073ae

Import Metadata inline screenshot (bookdrop-import-metadata-inline)

bookdrop-import-metadata-inline

**Import Metadata inline screenshot** (bookdrop-import-metadata-inline) ![bookdrop-import-metadata-inline](/attachments/536f642e-9232-4e25-9f1b-610dceecfbfd)
zombor force-pushed bd-bookshelf-qgd90.2 from bd5f7073ae
All checks were successful
/ E2E API (pull_request) Successful in 5m8s
/ Test Race (pull_request) Successful in 5m27s
/ Coverage (pull_request) Successful in 5m57s
/ Lint (pull_request) Successful in 6m28s
/ JS Unit Tests (pull_request) Successful in 1m5s
/ Integration (pull_request) Successful in 6m52s
/ E2E Browser (pull_request) Successful in 4m14s
to ca19c6eb18
All checks were successful
/ JS Unit Tests (pull_request) Successful in 45s
/ E2E API (pull_request) Successful in 3m4s
/ Test Race (pull_request) Successful in 3m22s
/ Coverage (pull_request) Successful in 3m51s
/ Lint (pull_request) Successful in 3m53s
/ Integration (pull_request) Successful in 4m23s
/ E2E Browser (pull_request) Successful in 3m23s
2026-07-24 23:47:41 +00:00
Compare

Import Metadata inline screenshot (bookdrop-import-metadata-inline)

bookdrop-import-metadata-inline

**Import Metadata inline screenshot** (bookdrop-import-metadata-inline) ![bookdrop-import-metadata-inline](/attachments/cc2f882d-88cd-4966-92aa-ad6e8d8861b8)
zombor merged commit 261066f443 into main 2026-07-24 23:53:43 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
zombor/pergamum!1230
No description provided.