Reuse copyright/license metadata + "Add this info to all images" in C&L dialog#7983
Reuse copyright/license metadata + "Add this info to all images" in C&L dialog#7983hatton wants to merge 10 commits into
Conversation
|
| Filename | Overview |
|---|---|
| src/BloomBrowserUI/bookEdit/copyrightAndLicense/CopyrightAndLicenseDialog.tsx | Adds the metadata chooser, apply-to-all workflow, and state handling for websocket completion. |
| src/BloomBrowserUI/bookEdit/copyrightAndLicense/MetadataChooser.tsx | Adds progressive gathering and rendering of reusable metadata packages. |
| src/BloomBrowserUI/bookEdit/copyrightAndLicense/metadataReuseUtils.ts | Adds shared helpers for package identity and license shorthand display. |
| src/BloomExe/web/controllers/CopyrightAndLicenseApi.cs | Adds read-only metadata endpoints and apply-to-all handling for image metadata saves. |
| src/BloomExe/web/controllers/ImageApi.cs | Adds a reusable helper for listing creditable image files in book order. |
Reviews (8): Last reviewed commit: "Reset stale push "Done" when a reuse sho..." | Re-trigger Greptile
There was a problem hiding this comment.
Pull request overview
This PR enhances the Copyright & License dialog workflow for image metadata editing by adding (1) a progressive “reuse metadata” chooser sourced from other images in the book (and the book’s own C&L), and (2) an in-dialog “Add this info to all images in this book” push action with spinner + websocket-driven completion. It also adjusts how the dialog is launched so saving metadata (which reloads the page iframe) no longer tears the dialog down.
Changes:
- Added backend support for progressively discovering creditable images in a book and reading per-image metadata.
- Added React UI for metadata “Shortcuts” reuse, plus a push-to-all-images button with spinner/done states driven by a websocket event.
- Launched the dialog via the workspace (top window) bundle rather than the page iframe to prevent teardown on iframe reload.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/BloomExe/web/controllers/ImageApi.cs | Adds a static helper to list creditable (non-placeholder/branding/license) images used in a book. |
| src/BloomExe/web/controllers/CopyrightAndLicenseApi.cs | Adds read-only endpoints for image list + per-image metadata; adds apply-to-all handling and websocket completion signaling. |
| src/BloomExe/Edit/EditingView.cs | Normalizes image filenames from HTML src (decode + strip query) before loading metadata; removes old yes/no “copy to all?” prompt. |
| src/BloomExe/Edit/EditingModel.cs | Adds websocket context/event constants and a helper to notify the dialog that push-to-all finished. |
| src/BloomBrowserUI/bookEdit/toolbox/canvas/canvasControlRegistry.ts | Launches C&L dialog via workspace bundle exports (top window) instead of iframe import. |
| src/BloomBrowserUI/bookEdit/js/bloomImages.ts | Same workspace-root dialog launch adjustment for metadata button on images. |
| src/BloomBrowserUI/bookEdit/copyrightAndLicense/metadataReuseUtils.ts | Adds shared helpers for stable metadata-package identity + license shorthand. |
| src/BloomBrowserUI/bookEdit/copyrightAndLicense/MetadataChooser.tsx | New progressive metadata reuse chooser UI (dedupe, pin current match, render localized summaries). |
| src/BloomBrowserUI/bookEdit/copyrightAndLicense/CopyrightAndLicenseDialog.tsx | Adds chooser + push-to-all UI/state management and websocket subscription for completion. |
| DistFiles/localization/en/BloomMediumPriority.xlf | Adds new localization IDs for chooser header/labels and push-to-all/progress text. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
JohnThomson
left a comment
There was a problem hiding this comment.
A few very minor points. A slightly larger issue: in my current card about the image chooser, we are dropping the idea of locking credits for images from collections like AOR. But would we still want to prevent "copy to all images" from applying to them? Also wondering whether we want to invite users to copy the AOR credits to new images...should we filter them out?
@JohnThomson reviewed 11 files and all commit messages, and made 4 comments.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on hatton).
src/BloomBrowserUI/bookEdit/copyrightAndLicense/CopyrightAndLicenseDialog.tsx line 420 at r3 (raw file):
enabled={canSave && pushState !== "working"} /> <DialogCancelButton onClick_DEPRECATED={closeDialog} />
What are the implications of canceling while a copy-to-all-images is in-progress?
src/BloomBrowserUI/bookEdit/copyrightAndLicense/MetadataChooser.tsx line 65 at r3 (raw file):
// scroll). With four or more, we measure the first three rows and cap to exactly that // height, so the fourth option starts the scrollbar. Measuring (rather than a fixed pixel // height) keeps this correct across fonts and translations, where row heights vary.
In some contexts we have purposely shown a half-item, to make it obvious there are more.
src/BloomExe/web/controllers/ImageApi.cs line 107 at r3 (raw file):
{ var doNotPaste = new HashSet<string>( GetImageFilesToNotPasteCreditsFor().Select(BookStorage.GetNormalizedPathForOS)
What does this have to do with pasting credits? We are listing them in a dialog; I'm not aware of any way to paste credits.
|
@ MetadataChooser.tsx line 65 (half-item) — Good point. Changed the ImageApi.cs line 107 ( Still working on your other two points (cancel-during-copy-to-all |
hatton
left a comment
There was a problem hiding this comment.
This is based on code before yours, didn't take on that change of behavior.
@hatton partially reviewed 10 files and made 4 comments.
Reviewable status: 9 of 11 files reviewed, 4 unresolved discussions (waiting on JohnThomson).
src/BloomBrowserUI/bookEdit/copyrightAndLicense/CopyrightAndLicenseDialog.tsx line 420 at r3 (raw file):
Previously, JohnThomson (John Thomson) wrote…
What are the implications of canceling while a copy-to-all-images is in-progress?
Well one hopes it would stop.
src/BloomBrowserUI/bookEdit/copyrightAndLicense/MetadataChooser.tsx line 65 at r3 (raw file):
Previously, JohnThomson (John Thomson) wrote…
In some contexts we have purposely shown a half-item, to make it obvious there are more.
Done.
src/BloomExe/web/controllers/ImageApi.cs line 107 at r3 (raw file):
Previously, JohnThomson (John Thomson) wrote…
What does this have to do with pasting credits? We are listing them in a dialog; I'm not aware of any way to paste credits.
Yeah that's vestigial. I'll get rid of it.
…&L dialog Reworks the Copyright & License dialog for images: - Adds a "Shortcuts" reuse chooser that gathers copyright/license metadata from the other images in the book (plus the book's own copyright/license) so the user can apply an existing set with one click instead of retyping. Gathering is progressive (one image at a time) and stops when the dialog closes. The set matching the image's current metadata is shown checked and pinned to the top of the list. - Replaces the old WinForms yes/no "copy to all images?" MessageBox with an in-dialog "Add this info to all images in this book" button. The dialog stays open and shows a "Working…" spinner, then a "done" confirmation driven by a websocket event when the copy actually finishes. - Launches the dialog via the workspace (top window) bundle rather than the page iframe, so saving the metadata (which reloads the page iframe) no longer tears the dialog down. - BL-16446: reduces the image fileName (which may carry a query string and/or URL encoding from the html src attribute) to the on-disk file name before loading, so PalasoImage no longer wrongly reports the image as corrupt. Backend: new read-only endpoints to list the book's creditable image file names and to read a single image's metadata, plus a static ImageApi.GetCreditableImageFileNamesInBook helper. The reuse chooser is only offered when editing image metadata, not for the book's own copyright/license. Robustness: the image-metadata POST handler now notifies the dialog that an "add to all images" request has finished on every path (via a finally and the wrong-state branch), so the "Working…" spinner can never hang when the copy doesn't actually run (save failed, non-normal image, or an error). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vy5zgbKXxtYoMeaUxWBhA8
…els) The gather useEffect ran once on mount and baked localized labels into each package's summary/secondaryLabel. But useL10n returns the English fallback synchronously and the localized string only on a later render, so those display strings were stuck in English (non-CC license shorthands and the "Copyright and license from this book" label). Store only raw data in each package (plus an isFromThisBook flag) and compute the summary and the book label at render time, where the labels are always the current, localized ones. The gather effect no longer captures any label. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vy5zgbKXxtYoMeaUxWBhA8
When the Copyright & License dialog is launched from the Palaso image toolbox, the POST handler early-returns before reaching the SaveThen block that calls NotifyCopyrightPushedToAllImages(). The "Add this info to all images" button is still visible in that case, so clicking it left the dialog spinner stuck on "Working…" forever. Now fire the notification in the toolbox early-return path to clear the spinner. Also disable the OK button while a push is in flight (so the dialog can't unmount before the "pushedToAllImages" event arrives) and add a clarifying comment about path traversal in HandleImageMetadataForFile. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
handlePushToAllImages relied entirely on the "pushedToAllImages" websocket event to leave the "working" state. If the POST itself failed before reaching the C# server, no event would arrive and the spinner would hang indefinitely. Add an errorCallback that resets pushState to "idle". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mages helper - CopyrightAndLicenseDialog: editing a field while a push-to-all is still "working" no longer resets pushState to "idle". Resetting mid-operation would hide the spinner and re-enable the button for redundant clicks. We keep the spinner until the websocket completion event arrives. - Add a focused unit test for ImageApi.GetCreditableImageFileNamesInBook locking down ordering (first occurrence) and filtering of license and placeholder images. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show half-row peek in reuse chooser to signal scrolling Per review: when there are four or more reuse options, measure three full rows plus half of the fourth (rather than capping exactly at three) so a peek of the fourth row makes it obvious the list scrolls. This matches the convention used elsewhere in Bloom of showing a half-item to indicate more. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
Rename doNotPaste->nonCreditable in image-credit filtering Per review: the "paste" terminology was misleading—this list has nothing to do with pasting credits; it is the set of images we never generate/show credits for (license, placeholder, branding). Rename GetImageFilesToNotPasteCreditsFor->GetImageFilesToNotCreditFor and the local doNotPaste->nonCreditableImages, and fix the comment accordingly. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
Drop stale "unless unlocked" wording from C&L launcher comment We are not implementing the idea of locking credits for images from collections like AOR, so the launcher comment no longer describes a real code path. Replace the "read-only / cannot be changed unless unlocked" wording with an accurate description of what the GET actually does: return the image data (show the dialog), return nothing, or fail with a message we surface (e.g. embedded-data images cannot be edited). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
29cbe43 to
0392501
Compare
|
@ Concretely:
I also rebased the branch onto current master (where the locking idea is gone) Force-pushed the rebased branch (tip 0392501). |
Addresses PR review (greptile P1): if the user clicks "Add this info to all images" and then edits the copyright/license while the push is still running, markEditedSincePush keeps pushState at "working" (so the spinner stays and the button cannot be re-clicked). But the completion websocket event then flipped the UI to "done" unconditionally, claiming the current, edited values had been applied to all images when only the earlier values were. Tie completion to the submitted values: remember the package key of the values pushed, and when "pushedToAllImages" arrives, show "done" only if the dialog's current values still match that key; otherwise drop back to "idle" so the button is offered again for the new, un-pushed values. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Picking a metadata reuse shortcut runs applyMetadataPackage(), which changed the copyright/license fields without clearing a prior "pushed to all images" confirmation. A user could click "Add this info to all images", wait for "Done", then pick a different shortcut and still see "Done" for values that were never applied to all images. Route the shortcut path through the same markEditedSincePush() helper the manual-edit handlers use, so it re-offers the button (and leaves an in-flight push's spinner alone). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hatton
left a comment
There was a problem hiding this comment.
@hatton made 1 comment.
Reviewable status: 3 of 11 files reviewed, 3 unresolved discussions (waiting on JohnThomson).
src/BloomBrowserUI/bookEdit/copyrightAndLicense/CopyrightAndLicenseDialog.tsx line 420 at r3 (raw file):
Previously, hatton (John Hatton) wrote…
Well one hopes it would stop.
Canceling mid-copy is safe — the copy was already initiated server-side and completes; closing the dialog only stops showing progress. No abort, no partial state.
What this does
Adds tools to the Copyright & License dialog for reusing metadata from other images (pull), and causing all other images to get the same metadata as the current image (push).
The reuse chooser is offered only when editing image metadata, not for the book's own copyright/license.
Backend
New read-only endpoints to list the book's creditable image file names and to read a single image's metadata, plus a static
ImageApi.GetCreditableImageFileNamesInBookhelper.🤖 Generated with Claude Code
Devin review
This change is