Skip to content

feat(form): add media field with Upload and AEM Assets - #800

Draft
holtvogt wants to merge 24 commits into
adobe:mainfrom
holtvogt:feat-sc-asset-picker
Draft

holtvogt wants to merge 24 commits into
adobe:mainfrom
holtvogt:feat-sc-asset-picker

Conversation

@holtvogt

@holtvogt holtvogt commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #799 and the release of adobe/da-sc-sdk#18. Until the SDK is released and the bundle is rebuilt, this PR stays a draft.

What

Adds a media field to the Structured Content editor. Schema properties with "x-semantic-type": "media" render as a file field instead of a text input. Authors can upload a file, pick one from AEM Assets, replace it, or remove it after a confirmation. The document stores a single URL string.

{ "type": "string", "title": "Portrait", "x-semantic-type": "media" }

Upload follows Canvas and accepts SVG, PNG, JPEG and GIF. AEM Assets appears only when the site config has aem.repositoryId. It opens Adobe's hosted Asset Selector in a dialog and loads its code only when chosen. Images show a preview with a file type badge, and other files show their name. Rejected files, failed uploads and cancel all keep the previous value and show errors inline.

Saving passes the schema to the SDK, so media fields are written as images in the DA source. EDS then ingests them into the media bus on preview, as it does for images in Canvas. Published content serves ./media_<hash> paths that visitors can load, where before it kept the stored DA content or AEM publish URL.

Note

The SDK bundle in nx/deps/da-sc-sdk is built from the unreleased SDK change. It will be rebuilt with npm run build:da-sc-sdk after the SDK release and the version bump. The da-sc service also needs the new SDK to return media bus paths in queried JSON.

Why

Structured content often references images and documents, and authors should not have to paste URLs by hand. The field reuses what DA already offers. Upload uses the shared nx2 media upload policy, and AEM Assets uses the shared module from #799, so stored URLs match what Canvas inserts. Writing them as images makes delivery match Canvas too.

Not included

  • No upload of PDF, MP4 or other non-image files. AEM Assets covers them for now.
  • No Smart Crop step. Smart Crop sites store the original URL.
  • No alt text prefill from AEM metadata. Alt text stays a separate schema field.
  • Not yet checked live are Dynamic Media URLs and images in nested objects.

Comment thread nx/blocks/form/fields/asset.js Outdated
Comment thread nx/blocks/form/fields/button.js Outdated
@@ -0,0 +1,78 @@
import { loadIms, handleSignIn } from '../../../../nx2/utils/ims.js';

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.

Id this something specific to Structured Content, or can we used a shared library that /canvas and /form can use?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This already uses the shared library in nx2/utils/aem-assets, which Canvas and the classic editor also use. Here, each consumer owns its dialog. This file only keeps the form-specific parts. Those are the IMS sign-in, a dialog mounted on the page itself so the hosted selector's styles and popovers work, the schema type check and the field's result shape

Comment thread nx/blocks/form/views/editor.js Outdated
holtvogt and others added 9 commits October 5, 2026 16:14
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Require confirmation before clearing an image field. Keep the asset
file untouched, remove the obsolete Undo toast, and restore focus
after Cancel or Remove.

Align the Replace button hover surface with its rounded shape.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Render string fields with the media semantic type as an image field.
The stored URL stays unchanged.

Offer Upload on every site and AEM Assets only when the site config
names a repository and the host provides a picker. Log into the DA
preview and content origins so private images preview.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Open Adobe's hosted AEM Assets selector from the image field when the
site configures aem.repositoryId. The shared resolver turns the pick
into the same URL canvas inserts, and errors keep the previous value.
The selector code loads only when the user picks AEM Assets.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add the media semantic type from da-sc-sdk#18 to the bundled SDK so
image fields render. The bundle is hand-patched and does not match
the 0.5.0 dependency yet. Rebuild it with npm run build:da-sc-sdk
after the SDK release and the version bump.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The preview area painted a decorative gradient that flashed while an
uploaded image loaded and showed through transparent pixels. Use a
neutral surface, reveal the image once it has loaded, and draw the
canvas transparency checkerboard behind it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@holtvogt
holtvogt force-pushed the feat-sc-asset-picker branch 2 times, most recently from b8c67bc to 078821a Compare October 5, 2026 14:31
holtvogt and others added 6 commits October 5, 2026 16:41
Move ensureLivePreviewLogin from the loc glaas connector into
nx/utils/utils.js so other blocks can reuse it. Logins are cached per
org, repo and ref so concurrent callers share one cookie exchange. A
failed or rejected login is no longer cached, so the next request
retries. The ref defaults to main and the login function can be
injected for tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Export the mimetype helper so consumers resolve an asset's type the
same way the URL builders do. It prefers mimetype over dc:format and
keeps the original case. Document it in the README and cover it with
tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add one place for the image upload rules that Canvas uses, so the
form and later Canvas can share them. It covers the supported image
types and the size limit, which is 4.5 MB on hlx6 sites and 20 MB on
legacy ones. The hlx6 check only runs for larger files and falls back
to the legacy limit when the site cannot be resolved. It also builds
the document-scoped media path and runs the upload. A failed upload
returns an error object with its status.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Media fields now accept any file type. A schema's contentMediaType,
such as application/pdf or video/*, limits what a field allows, and
only images get a preview. AEM Assets can supply any allowed type.
Upload follows Canvas and still accepts only SVG, PNG, JPEG and GIF.

The field receives file sources from the form instead of a single
callback. Errors come back as results and show in the field instead
of being thrown. The field uses the shared nx2 menu and dialog, and
Upload reuses the shared nx2 media upload policy. A slow preview
login no longer delays the sources.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Built from the unreleased da-sc-sdk change. Rebuild after the SDK
release and version bump.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@holtvogt holtvogt changed the title feat(form): add image field with Upload and AEM Assets feat(form): add media field with Upload and AEM Assets Oct 6, 2026
@holtvogt
holtvogt requested a review from kozmaadrian October 6, 2026 13:07
holtvogt and others added 4 commits October 7, 2026 09:32
The form is nx2-based, but its preview login used the nx IMS stack,
which needs an imsClientId the form never sets. The login failed
silently, no preview cookie was set, and media previews of sites
that require sign-in returned 401.

Add a memoized preview login to nx2 utils and use it in the form.
Move the glaas connector back to its own login, as on main.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Files that are not images left the preview area blank, and images
that failed to load did the same. Show the file extension as a badge
in the preview and lay the image over it once it has loaded, so a
failed image falls back to the badge without extra state.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Long media file names were cut off at the end, which hid the file
type. Truncate the name before its extension instead, and keep the
full name in the tooltip.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
holtvogt and others added 3 commits October 8, 2026 15:38
Rebuild the da-sc-sdk bundle from the SDK branch so convertJsonToHtml
can write media fields as images and convertHtmlToJson reads them back.
Without a schema the output is unchanged. Temporary until the SDK
release, like the earlier bundle commits.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Image fields were saved as text, so preview and publish kept the
stored URL. Uploads stayed on DA content URLs that return 401 for
visitors. Pass the schema when saving so the SDK writes image fields
as images, which EDS ingests into the media bus like classic images.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants