feat(image-editor): wire Save and focal-point persistence for the new image editor#36350
Open
oidacra wants to merge 19 commits into
Open
feat(image-editor): wire Save and focal-point persistence for the new image editor#36350oidacra wants to merge 19 commits into
oidacra wants to merge 19 commits into
Conversation
Add a withSave feature (save events + saveEditedImage GET) that builds the contentAsset filter URL with _imageToolSaveFile=true, closes the dialog with the returned temp file on success and surfaces the error on failure. Fold the focal point into the save chain (epsilon-compared against the seeded baseline), seed it on open from ImageEditorOpenParams, widen isDirty to detect a focal move, and add a footer Save button that shows a loading spinner while busy or saving.
…p in binary field
onEditImage reads the asset's stored focal point ({field}MetaData.focalPoint) and
passes it to the launcher so the marker re-seeds on reopen. Guard the null metadata
that image-tool temp files return so the field renders instead of crashing.
…lPoint on read The _imageToolSaveFile save block created the temp from the empty file, so it came back with metadata:null/image:false; re-wrap it after copying the rendered bytes so it carries real metadata (mirrors TempFileAPI.createTempFile). Expose focalPoint on DefaultTransformStrategy.addBinaries (mirrors BinaryViewStrategy) so the editor can re-seed the marker on reopen.
920d5d6 to
dedc5f4
Compare
Open
5 tasks
Contributor
|
Claude finished @oidacra's task in 2m 20s —— View job Rollback Safety Analysis
Result: ✅ Safe To RollbackAfter analyzing the PR diff against all rollback-unsafe categories, no unsafe patterns were found. Categories checked
Summary of backend changes
|
Contributor
🤖 dotBot Review (Bedrock)Reviewed 39 file(s); 12 candidate(s) → 6 confirmed, 0 uncertain (unverified, kept for review).
Confirmed findings
us.deepseek.r1-v1:0 · Run: #28475231277 · tokens: in: 219357 · out: 66747 · total: 286104 · calls: 66 · est. ~$0.657 |
…ata on open onEditImage called getFileMetadata(this.contentlet), but the raw @input contentlet carries no fieldVariable, so it could not resolve {field}MetaData and returned {} — dropping the stored focalPoint. Pass fieldVariable explicitly (as the preview does) so the editor seeds the saved focal point instead of resetting to centre.
- Make the focal target dot red (var(--p-red-500)) instead of the UI primary blue so it reads as a focal marker and contrasts against arbitrary image content. - Observe the stage (the image's offsetParent) in addition to the image: toggling full-screen re-centres the image without changing its own size, which a ResizeObserver on the image alone never reports, leaving imageRect.x/y stale and the focal/crop overlays mispositioned on the full-screen -> windowed transition.
- DefaultTransformStrategy: log (debug) when reading the focal point custom-meta fails instead of silently swallowing it in the Try. - binary-field-utils.spec: split the focal-point sentinel test so the (0,0) case and the malformed/single-value case are asserted separately (the latter hits the NaN branch, not the (0,0) sentinel). - onEditImage: document why focalPoint is read via a narrow cast (it is exposed at runtime but not declared on the shared DotFileMetadata model).
adrianjm-dotCMS
approved these changes
Jun 30, 2026
…Content Removing FEATURE_FLAG_NEW_IMAGE_EDITOR made the new Edit Content always open the new Angular image editor, so the binary-field E2E that waited for the legacy Dojo iframe (legacy-image-editor-iframe) timed out. Assert the new editor's dialog (image-editor-root) instead. The legacy-editor describe block (legacy Edit Content, CONTENT_EDITOR2_ENABLED=false) is unchanged and still asserts the Dojo editor.
…' test The calendar-field 'now' TIME default test compared getDate() day-of-month values directly (Math.abs(actualDay - expectedDay) <= 2). Across a month boundary the timezone-shifted UTC formValue rolls to the next month, so e.g. Jun 30 vs Jul 1 reads as |30 - 1| = 29 and fails — deterministically on month-end days (today is Jun 30). Compare the whole-day distance between the two dates instead, which is correct across month boundaries. Unrelated to the image-editor work; surfaced on this PR's CI run.
|
Tick the box to add this pull request to the merge queue (same as
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wires the new Angular image editor's Save to the temp-file flow and completes
focal-point persistence for the new Edit Content.
On Save, the editor GETs the contentAsset filter URL it already builds for preview, with
binaryFieldId=<fieldVar>&_imageToolSaveFile=trueappended; the servlet stages the filteredrender as a
DotCMSTempFile, the dialog closes returning it, and the field stages it (previewrefreshes; the temp id is sent as the field value on check-in — the source binary is never
overwritten). A focal point is folded into the same request (
/filter/FocalPoint/fp/x,y+overwrite=true) and committed viacopyMetadata; the editor seeds the marker from the asset'sstored focal on open and treats a focal-only change as dirty.
Closes #36067.
What changed
Image editor (
libs/image-editor) — newwithSavefeature +saveRequested/saveSucceeded/saveFailedevents +
saveEditedImageGET;buildSaveUrlreuses the preview filter chain, appends the saveflags, and folds in the focal point (epsilon-compared against the seeded baseline — recenter-to-clear
and untouched-seed both handled); the dialog closes with the temp on success and stays open + surfaces
the error on failure; focal seeded on open from
ImageEditorOpenParams.focalPoint;isDirtywidened todetect a focal move (epsilon-tolerant); footer Save button (+ i18n) shows a loading spinner while the
editor is busy applying a filter or saving.
Binary field (
libs/edit-content) —onEditImagereads the asset's stored focal(
{field}MetaData.focalPoint, viaparseFocalPoint) and passes it to the launcher so the markerre-seeds on reopen; null-metadata guards (
handleTempFile,getFileMetadata) so the image-tool temp(
metadata: null) renders instead of crashing.Backend —
BinaryExporterServletre-wraps the temp after copying the rendered bytes so it carriesreal metadata (
image/mimeType/dimensions) — it was returningmetadata:null/image:false/mimeType:unknown,which left the field showing a file icon — mirroring
TempFileAPI.createTempFile;DefaultTransformStrategy.addBinariesexposesfocalPointon the content REST read path (mirrorsBinaryViewStrategy) so the editor can re-seed.Acceptance criteria
binaryFieldId+_imageToolSaveFile=trueand GETs itbinaryFieldIdis the dynamic field variablefocalPointexposed on the content read pathTest plan
Unit:
buildSaveUrl(filters, focal seed-vs-centre, recenter-to-clear, epsilon),withSave(statustransitions + the built Save URL), footer Save (click, loading spinner on busy/saving), dialog
close-on-success / no-close-on-failure, focal seeding,
isDirty(epsilon),parseFocalPoint,null-metadata guards,
DefaultTransformStrategyfocalPoint — 334 (image-editor) + 1980 (edit-content)passing, lint clean, backend compiles.
Manual (local,
FEATURE_FLAG_NEW_IMAGE_EDITOR=true): open the editor on a Binary field → apply a filter /move the focal point → Save → the dialog closes; after Publish the field shows the edited image;
reopen the editor → the focal marker is restored.
Notes
diff includes its commits — rebase onto
mainonce [IMAGE EDITOR] Build DotImageEditorComponent modal shell and image-editor signalStore #36063 lands.setPreviewFileconsumption and theEnterprise availability gate. The committed-thumbnail "shows the old image until Publish" behaviour is the
expected publish lifecycle (the field renders the committed binary), not a bug.