Skip to content

Issue 36702 asset picker - #36944

Merged
nicobytes merged 61 commits into
mainfrom
issue-36702-asset-picker
Aug 19, 2026
Merged

Issue 36702 asset picker#36944
nicobytes merged 61 commits into
mainfrom
issue-36702-asset-picker

Conversation

@nicobytes

@nicobytes nicobytes commented Aug 7, 2026

Copy link
Copy Markdown
Member

This pull request introduces a set of improvements and refactorings to the folder tree utilities and related data-access APIs, aimed at enhancing code reuse, maintainability, and consistency across the Content Drive and Host Folder Field features. The changes include moving folder tree logic into shared utilities, updating service providers, and aligning data models.

Core refactoring and utility extraction:

  • Introduced new shared utilities folder-tree.utils.ts and folder-tree-load.utils.ts in @dotcms/data-access, centralizing the logic for building, loading, and paginating folder trees. This includes new functions such as generateAllParentPaths, createTreeNode, and buildTreeFolderNodes, as well as utilities for paginated loading and "Load more" node handling. [1] [2]

API and provider updates:

  • Updated DotContentDriveService to use Angular's providedIn: 'root' for global availability, and removed it from route-level providers. This ensures the service can be used from dialogs and other contexts without explicit injection in every route. [1] [2]

Imports and dependency cleanup:

  • Updated imports in various portlet files to use the new shared utilities from @dotcms/data-access instead of local utility definitions, and cleaned up duplicate or outdated imports for components such as DotFolderListViewComponent. [1] [2] [3] [4]

Data model alignment:

  • Extended the TreeNodeContentData model to include additional metadata fields (inode, defaultBaseType, fromTable) for improved folder selection and upload behavior in the Content Drive and AssetPicker.

Constants and type re-exports:

  • Refactored and re-exported shared folder tree page size constants from the new utilities, ensuring consistent pagination limits across features, and deprecated local type definitions in favor of those from @dotcms/data-access. [1] [2] [3] [4]

These changes improve code maintainability, reduce duplication, and ensure that folder tree behaviors remain consistent across all consuming features.

This PR fixes: #36702

AssetPicker series — all seven sub-issues are resolved in this PR:

Fixes #36831 — AssetPicker 1/7: Migrate DotFolderListView to @dotcms/ui
Fixes #36832 — AssetPicker 2/7: Lift folder-tree helpers and harden drive data-access
Fixes #36833 — AssetPicker 3/7: Decouple Content Drive toolbar chrome for AssetPicker reuse
Fixes #36834 — AssetPicker 4/7: Headless browse store (no URL) for AssetPicker
Fixes #36835 — AssetPicker 5/7: Build DotAssetPicker shell in @dotcms/ui
Fixes #36836 — AssetPicker 6/7: File/Image entry configs, silent mime, CT limits, global last path
Fixes #36837 — AssetPicker 7/7: Wire AssetPicker into Edit Content File/Image fields

This PR fixes: #36702

- Extracted DotFolderListView component and related models/constants/mocks into the new `@dotcms/ui` library.
- Updated imports in the Content Drive shell to reference the new location.
- Introduced `selectionMode` input to support both single and multiple selection.
- Re-exported necessary symbols from `@dotcms/ui` in the Content Drive UI for compatibility.
- Added tests for the new component and selection mode functionality.

This migration aims to share the folder/asset list component between Content Drive and future AssetPicker implementations, enhancing code reuse and maintainability.
Copilot AI lite review requested due to automatic review settings August 7, 2026 14:45
@github-actions github-actions Bot added the Area : Frontend PR changes Angular/TypeScript frontend code label Aug 7, 2026
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nicobytes's task in 2m 41s —— View job


Review — rechecked at 5480e964 (current HEAD)

Both approvals landed at feb2a044/852bf9ca. Since then two commits were pushed (157ef01b bundle budget, 5480e964 dot-toast). I re-verified every open finding against the code at this HEAD and reviewed the new commits.

New Issues

None. The new dot-toast component (5480e964) is sound: [innerHtml] runs through Angular's default DomSanitizer, so backend-supplied error text stays XSS-safe, and both consumers (dot-asset-picker.component.ts:96, dot-content-drive-shell.component.ts:125) still provide MessageService after ToastModule dropped out. Wiring checks out.

Existing

  • 🟠 High: core-web/libs/ui/src/lib/components/dot-asset-picker/store/features/with-asset-folder-tree.feature.ts:216publish() still does findNodeByKey(folders, selectedKey) ?? null. searchFoldersInBrowsingSite (line 179) returns { folders: allRoots } with the highlighted node deliberately left outside the published search tree, and the loadFolders tap correctly leaves selectedNode alone. But the next mutateNode → publish (expand / "Load more" after a search) can't find the key and nulls it → $targetFolder becomes undefined#uploadByBaseType falls back to the site root. Silent upload misplacement. Author flagged this as awaiting a decision between "keep previous node on miss" (their preferred, and mine) vs "clear path". Fix this →
  • 🟠 High: core-web/libs/portlets/dot-content-drive/portlet/src/lib/utils/tree-folder.utils.spec.ts:1 — still 37 lines, imports only ALL_FOLDER from @dotcms/ui. tree-folder.utils.ts is byte-identical to main and still consumed by store/features/sidebar/withSidebar.ts and utils/functions.ts, so generateAllParentPaths / createTreeNode / buildTreeFolderNodes (≈33 tests) are now live-but-uncovered. Author acknowledged this is the largest real gap and plans to restore it.
  • 🟡 Medium: core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.ts:313this.$selection() !== undefined (was ??). With the selectionMode="single" this PR adds, null is the natural "nothing selected" value, and !== undefined treats it as "controlled and empty", giving a permanently empty table. Latent (both in-repo consumers pass arrays / are uncontrolled) but a trap for the new mode. One-line revert to ??.
  • 🟡 Medium: core-web/libs/portlets/dot-content-drive/ui/src/lib/shared/models.ts:14 + dot-content-drive-shell.component.ts:1126DotContentDriveUploadFiles is now an alias of DotUploadFiles (optional, TreeNodeData targetFolder), while getMoveMetadata still reads event.targetFolder.hostname unguarded and isn't narrowed on LOAD_MORE_NODE_TYPE the way onRequestUpload is. strict: false hides the lost compile-time guarantee. Author is leaving the direction (narrow vs Content-Drive-specific alias) to the maintainers.
  • 🟡 Medium: core-web/apps/dotcms-block-editor/project.json (157ef01b) — initial bundle budget raised (4→4.5 MB error) rather than lazy-loading the picker. As the author notes, EditorModalService's static reference to DotAssetPickerComponent now pulls the picker subtree into the initial chunk of every @dotcms/new-block-editor consumer, dotcms-ui included. A dynamic import() in openAssetPicker would keep the original budget. Deliberate tradeoff, flagged for a maintainer call.

Resolved

  • SiteSearchAPIImpl.javagit diff origin/main is empty; the DotDataException passthrough is restored, byte-identical to main.
  • dot-workflow-push-publish.component.html:95 — back to 'Change' (capital), matching main.
  • dot-asset-picker.component.ts legacy-host providers — DotHttpErrorManagerService removed from the store features (errors now surface via MessageService); legacy-host spec un-skipped.
  • ui/src/index.ts picker wiring — File/Image "Select Existing" now opens DotAssetPickerComponent; Story Block + WYSIWYG wired to the same picker.
  • confirm() error handler — toasts + keeps dialog open on hydration failure.
  • dot-asset-picker.store.ts setSearch — clears path and re-selects root node.
  • with-asset-folder-tree.feature.ts — browsing site re-added to roots when a folder-name search drops it; tap uses conditional spread so an absent selectedNode no longer wipes the highlight.

Net: no new bugs in the two post-approval commits. The two 🟠 items are genuine and both were explicitly deferred by the author pending a maintainer decision rather than overlooked — worth confirming that decision before merge.
· issue-36702-asset-picker

Copilot AI 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.

Pull request overview

This PR refactors the existing Folder List View used by Content Drive into a reusable presentational component in @dotcms/ui, adding a single-selection mode intended for the upcoming AssetPicker (while preserving current Content Drive behavior via the default multiple selection mode).

Changes:

  • Moved Folder List View domain-agnostic types/constants into @dotcms/ui and re-exported them from the Content Drive UI package for compatibility.
  • Added selectionMode: 'single' | 'multiple' support to the table (checkboxes in multiple mode, radios in single mode) and normalized emitted selections to an array.
  • Updated Content Drive shell imports and updated/extended unit tests accordingly.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
core-web/libs/ui/src/lib/components/dot-folder-list-view/models.ts Introduces shared column typing and selectionMode model for the Folder List View.
core-web/libs/ui/src/lib/components/dot-folder-list-view/constants.ts Defines header column config and drag MIME type local to the component folder.
core-web/libs/ui/src/lib/components/dot-folder-list-view/mocks.ts Moves test mocks alongside the component.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.ts Adds selectionMode input, normalizes selection output, and updates internal imports to local UI sources.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.html Switches checkbox vs radio rendering based on selectionMode and updates selection binding.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.scss Fixes relative SCSS imports to match the libs layout.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.spec.ts Updates tests for the new selection model and adds coverage for single-selection behavior.
core-web/libs/ui/src/index.ts Exposes Folder List View component + related models/constants from @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/lib/shared/models.ts Removes Folder List View column typing now owned by @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/lib/shared/constants.ts Removes list-view constants now owned by @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/index.ts Re-exports the Folder List View API surface from @dotcms/ui for Content Drive consumers.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.ts Updates imports to use @dotcms/ui for the presentational list component/types.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.spec.ts Aligns test imports with the updated component export location.

- Introduced new utility functions for managing folder hierarchies, including `getFolderHierarchyByPath` and `getFolderNodesByPath`, to improve folder navigation and loading in the content drive.
- Added `folder-tree-load.utils.ts` and `folder-tree.utils.ts` files to encapsulate the new logic.
- Implemented comprehensive unit tests for the new utilities to ensure functionality and reliability.
- Updated existing services to utilize the new utilities, enhancing code organization and maintainability.

These changes aim to streamline folder management and improve the user experience in the content drive interface.
Extracts the content-type, language, and search filter components (plus the
chip-filter/list-item primitives and upload button) out of the content-drive
portlet into @dotcms/ui so they can be shared with the AssetPicker. Store-
specific logic stays behind thin adapter components in the portlet.
- serve target lacked a dependsOn, so dotcms-webcomponents could be
  stale or missing when dotcms-ui starts serving
- webcomponents build target was missing outputs, preventing Nx from
  caching/detecting its build artifacts correctly
- Introduces DotAssetPickerStore in @dotcms/ui to power the upcoming
  AssetPicker dialog with a search request builder mirroring Content
  Drive's, but with no router/URL coupling so it can run inside a
  dialog over Edit Contentlet without corrupting host navigation.
- Relocates ALL_FOLDER/SYSTEM_HOST_ID out of the Content Drive UI
  library into shared dot-folder-tree constants so both Content
  Drive and the new picker consume a single source.
@nicobytes
nicobytes requested a lite review from Copilot August 7, 2026 17:55

Copilot AI 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.

Pull request overview

Copilot reviewed 76 out of 78 changed files in this pull request and generated no new comments.

Suppressed comments (1)

core-web/libs/ui/src/lib/components/dot-asset-picker/store/features/with-asset-folder-tree.feature.ts:97

  • loadFolders sets foldersStatus to ERROR in catchError, but then the subscribe block unconditionally patches it back to LOADED (because catchError returns an empty array). This masks folder-tree failures and makes the UI indistinguishable from a successful empty tree.

The AssetPicker (browse/pick a single asset) now composes the dropzone, upload-type selector, and folder sidebar/toolbar that Content Drive already had, so both features share one implementation instead of duplicating upload flow logic.

- Move `dot-content-drive-dropzone` and the upload-type-selector dialog out of the Content Drive portlet into `@dotcms/ui` as `DotUploadDropzoneComponent` and `DotUploadTypeSelectorComponent`, decoupled from `DotContentDriveStore` (folder/drag-state now passed via inputs/outputs)
- Add `DotAssetPickerComponent` with sidebar/toolbar subcomponents, wiring the shared dropzone, upload selector, and folder tree to a new `DotAssetPickerStore`
- Update Content Drive shell to consume the relocated shared components and derive drag/target-folder state locally
Adds a global last-used-path store, a config builder that translates
Edit Content field type (File/Image) into picker filters, and
server-side base-type narrowing for the content type filter so
restricted hosts don't page through mostly-discarded results.
- Add #assetPickerPending guard so a slow site lookup can't be
  raced by a second click before #dialogRef is set, and release it
  on every close (success, cancel, or lookup error) so the picker
  can reopen afterward.
- Rethrow DotDataException as-is in SiteSearchAPIImpl.defaultIndexName
  instead of re-wrapping it, preserving the original exception type.
Reproduces the NullInjectorError the picker still throws in the
binary-field custom-element host, which bootstraps with no Router and
none of the app-shell providers.

b27ab75 added DotContentTypeService and DotHttpErrorManagerService to
the picker's own providers. That closes the first half only:
DotContentTypeService just needs HttpClient, but
DotHttpErrorManagerService transitively pulls in DotAlertConfirmService,
DotRouterService (-> Router) and DotEventsSocket. The chain cannot be
closed with component-level providers, since provideRouter returns
EnvironmentProviders and cannot go in a component's providers array.

Skipped on purpose: the failure is the open finding, not a flaky test.
Un-skip it when the store stops depending on DotHttpErrorManagerService
and reports errors through the MessageService toast the picker already
owns for upload and confirm failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot removed the Area : Backend PR changes Java/Maven backend code label Aug 17, 2026
@nicobytes

Copy link
Copy Markdown
Member Author

Review feedback status — rechecked at e21bd64756

Went through every Critical/High finding from @zJaaal, @adrianjm-dotCMS, Copilot and the claude[bot] pass. Below is what changed since the last review, verified against the code at this HEAD rather than from the commit messages.

✅ Addressed

🟠 SiteSearchAPIImpl — merge dropped main's DotDataException passthrough (dfeca53acc)
Restored the } catch (DotDataException e) { throw e; } in defaultIndexName(). The file is now byte-identical to origin/main, so merging this PR no longer reverts the #36983 fix, and it is consistent again with isDefaultIndex() / getAggregations().

🟠 Async dialog open can stack two pickers (dfeca53acc)
Added an #assetPickerPending flag in dot-file-field.component.ts. Notes on the shape of the fix:

  • #dialogRef could not serve as the guard: it is shared with the other three dialogs this component opens and is never reset on close, so checking it would have blocked the picker permanently after any of them ran.
  • The flag is released on error, when no site resolves, and on every dialog close. That last one required dropping the filter(file => !!file) from the onClose subscription — with the filter in place, cancelling never released the guard and the button would have died for the rest of the session.
  • Three tests added in dot-edit-content-file-field.component.spec.ts: double click while the site lookup is in flight, re-open after close, and retry after a failed lookup.

The same race existed on the two callers added later in this PR (EditorModalService for the Story Block, DotWysiwygPluginService for the WYSIWYG field); both already guard with an equivalent pending flag, so all three entry points are consistent now.

⚠️ Partially addressed — please re-read this one

🔴 Missing providers / picker cannot construct in the legacy Dojo binary-field host

b27ab7557b adds DotHttpErrorManagerService and DotContentTypeService to the picker's providers, as suggested. That is necessary but not sufficient, so this finding should stay open.

I added a regression spec that constructs DotAssetPickerComponent with only the provider set the custom-element host actually has (dot-asset-picker.component.legacy-host.spec.ts, ec5aaccfca). It still fails:

NG0201: No provider found for `DotAlertConfirmService`

DotContentTypeService is satisfied — it only needs HttpClient. DotHttpErrorManagerService is not; it transitively pulls in:

DotHttpErrorManagerService
  ├── DotAlertConfirmService   → ConfirmationService          ← fails here now
  ├── DotMessageDisplayService → DotRouterService → Router, DotEventsSocket
  └── DotRouterService         → Router

apps/dotcms-binary-field-builder bootstraps without a Router — which is the same reason GlobalStore was deliberately kept out of DotFileFieldComponent. The chain therefore cannot be closed with component-level plumbing at all: provideRouter returns EnvironmentProviders and cannot go in a component's providers array.

The fix that actually closes it is to drop the DotHttpErrorManagerService dependency from the picker's store features (6 call sites across with-asset-browse / with-asset-folder-tree) and report errors through the MessageService toast the picker already owns — it does exactly that for upload and confirm failures today. The spec is committed skipped, with the chain documented, to be un-skipped as part of that change.

❌ Still open

Finding Verified at this HEAD
🟠 publish() nulls the tree highlight after a sidebar search, retargeting uploads to the site root with-asset-folder-tree.feature.ts:222 unchanged — still findNodeByKey(folders, selectedKey) ?? null
🟠 tree-folder.utils.spec.ts gutted on unchanged production code still 37 lines vs 681 on main, and still does not import tree-folder.utils
🟡 "Select Existing File" gives no feedback when getCurrentSite() fails still a silent return; only the new guard flag was added there
🟡 $selection() !== undefined vs ?? dot-folder-list-view.component.ts:313 unchanged
🟡 i18n 'change' resolves to lowercase change dot-workflow-push-publish.component.html:95 unchanged

One thing worth a separate look

Two of the findings above (SiteSearchAPIImpl, and the 'Change''change' i18n key) are both merge-resolution damage from the same commit (5624a082d4), not intentional changes — main has 'Change' on that line. Since two independent regressions came in through one automated conflict resolution, a manual pass over the backend and CI files in git diff origin/main before merge seems worthwhile; I was not able to complete that sweep myself.

Carrying these across from the Content Drive copy. Each one records a
bug that was already fixed once, so losing them makes it cheap to
reintroduce:

- $columns anchors extras to where "type" sits in the CANONICAL order,
  not its rendered index. Keying off the rendered index appended the
  extras when Type was hidden, putting every extra cell one heading
  early.
- the item-title `title` attribute is what keeps truncated text
  reachable on hover.
- the contentType cell truncates so a long variable name cannot grow
  the row past its neighbours.
- the locked-by-others icon is coloured rather than a different glyph
  on purpose.

The title rationale is reworded rather than copied verbatim: that column
is no longer a fixed width on this branch, it absorbs the leftover, so
the clipping now comes from the cell's `minmax(0,1fr)` track.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nicobytes's task in 1m 15s —— View job


I'll analyze this and get back to you.

nicobytes and others added 2 commits August 17, 2026 14:52
Wiring the Story Block to DotAssetPickerComponent means EditorModalService
now holds a static reference to it, so the picker and its subtree (folder
list table, folder tree, splitter, content-type filter, Content Drive
store) land in the initial chunk. It replaced DotBrowserSelectorComponent,
which was considerably lighter, pushing this app to 4.08 MB against a
4.00 MB hard limit.

Warning 3.5mb -> 4.25mb, error 4mb -> 4.5mb.

Note this is a budget raise, not an optimization: every consumer of
@dotcms/new-block-editor now ships the picker in its initial bundle. The
alternative is loading the picker through a dynamic import() in
openAssetPicker so its subtree moves to a lazy chunk, which would keep the
original budget. Left as a follow-up rather than folded in here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The picker threw NullInjectorError and rendered blank when opened from a
File/Image field in the legacy content editor, a regression against
DotBrowserSelectorComponent, which used root-provided services only.

Providing the missing services on the component (b27ab75) only moved
the failure one link along. DotHttpErrorManagerService transitively needs

    DotHttpErrorManagerService
      +-- DotAlertConfirmService   -> ConfirmationService
      +-- DotMessageDisplayService -> DotRouterService -> Router, DotEventsSocket
      +-- DotRouterService         -> Router

and dotcms-binary-field-builder bootstraps with no Router at all -- the
same reason GlobalStore was kept out of DotFileFieldComponent. It cannot
be closed by plumbing either: provideRouter returns EnvironmentProviders
and cannot go in a component's providers.

So drop the dependency instead. The store now records failures as
`requestError` state (6 call sites across with-asset-browse and
with-asset-folder-tree) and the picker component toasts them through the
MessageService it already owns for upload and confirm failures. That also
puts it back in line with the repo rule that a store holds data, not UI.

DotContentTypeService stays in providers -- it only needs HttpClient.

The legacy-host spec added in ec5aacc is un-skipped and passing. Its
provider set now mirrors app.module.ts exactly rather than a subset, so
it fails on anything router-bound being reintroduced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nicobytes

Copy link
Copy Markdown
Member Author

Two changes pushed that reviewers should know about (852bf9ca12, 157ef01ba6)

1. The 🔴 provider finding is now genuinely closed

Details in the thread. Short version: DotHttpErrorManagerService is out of the picker's store features — the store records failures as state, the component toasts them — and the legacy-Dojo-host spec is un-skipped and passing. My earlier "please keep this open" comment no longer applies.

2. I raised a bundle budget, which nobody asked for

nx run dotcms-block-editor:build:production was failing:

✘ [ERROR] bundle initial exceeded maximum budget. Budget 4.00 MB was not met by 80.43 kB with a total of 4.08 MB.

apps/dotcms-block-editor/project.json is byte-identical to main, so the budget was not moved — the bundle grew. Cause is this PR: wiring the Story Block to the picker means EditorModalService holds a static reference to DotAssetPickerComponent (dialogService.open needs the class), so the picker and its subtree — folder-list table, folder tree, splitter, content-type filter, Content Drive store — land in the initial chunk. It replaced DotBrowserSelectorComponent, which was considerably lighter.

I raised warning 3.5mb → 4.25mb and error 4mb → 4.5mb to unblock the build.

Flagging it because it is a budget raise, not an optimization, and it is not confined to the demo app: every consumer of @dotcms/new-block-editor now ships the picker in its initial bundle, dotcms-ui included.

The alternative is loading the picker through a dynamic import() in openAssetPicker, moving its subtree to a lazy chunk and keeping the original budget. The picker only ever opens on user action, so lazy is semantically right. I did not do it because I could not verify it is sufficient on its own — @dotcms/ui is already pulled in statically for DotAIImagePromptComponent, though esbuild tree-shakes per symbol so the picker's subtree should still move.

Two caveats on my own diagnosis, so nobody takes it as measured fact:

  • I did not confirm whether this build passes on main. I attributed the growth by reasoning about the dependency graph, not by an A/B measurement — my attempt to measure it by stubbing the import did not come out clean and I reverted it rather than leave the tree dirty.
  • I did not measure the picker's exact contribution.

Happy to do the lazy-import route instead if you would rather not carry the raise.

Both sides independently moved dot-chip-filter and dot-filter-list-item
from dot-content-drive/ui into @dotcms/ui, so git saw add/add on five
files with no common ancestor and conflicted them whole. Resolved by
reconciling, not by picking a side -- the previous automated merge on
this branch (5624a08) picked sides and silently reverted two fixes.

What main brought that had to survive:

- emptyLabel on dot-chip-filter. Its only consumer is main's new
  Experiments portlet, so resolving these with "ours" would have dropped
  the input and broken that portlet's build.
- LISTBOX_OPTION_HEIGHT in the theme. Main solved the same problem this
  branch solved by measuring: it fixes every listbox option to Lara's
  0.625rem/1rem and exports the resulting 40.6 so virtual scrollers stop
  re-measuring it. That is why main dropped py-3 from dot-filter-list-item.

So instead of the planned "move the padding into CHIP_FILTER_LISTBOX_PT",
this adopts main's approach:

- dot-filter-list-item keeps main's version, without py-3.
- CHIP_FILTER_LISTBOX_PT drops its --p-listbox-option-padding: 0 1rem
  override, which would otherwise fight the theme and make every virtual
  scroller's row height disagree with what is rendered. Its remaining
  declarations now duplicate the theme; left in place rather than widening
  a merge commit into a refactor.
- dot-content-type-filter takes LISTBOX_OPTION_HEIGHT instead of its own
  hardcoded 40.6, carrying main's improvement to where the logic now lives.

The portlet's content-type and language filters stay as this branch's thin
store adapters over the shared @dotcms/ui components -- verified main added
no behaviour to them beyond dropping the same PT usage.

Also reverts 'change' -> 'Change' in dot-workflow-push-publish: leftover
damage from 5624a08, the same merge that dropped the SiteSearchAPIImpl
passthrough. change=change is lowercase, so the timezone toggle rendered
"change" next to "Hide".

Verified: ui 1343, content-drive 1147, edit-content 2243, new-block-editor
87, users 30, publishing-queue 255 -- all passing. Lint clean across the
six affected projects. dotcms-block-editor production build passes.
git diff origin/main outside core-web is Language.properties only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The upload success toast showed literal `<b>` tags: the picker used a bare
`<p-toast />`, whose default PrimeNG template renders `summary`/`detail` as
escaped text, while `content-drive.add-dotasset-success-detail` bolds the file
name and base type.

Content Drive already solved this with an inline `#message` template, so rather
than copy it — twelve lines of PrimeNG-internal class names and
`data-pc-section` attributes, duplicated — extract it as `dot-toast` in
`libs/ui` and use it in both places. Net -14 lines.

The extracted version modernizes what it moves: `pTemplate="message"` becomes
PrimeNG 21's `#message`, `innerHtml="{{ }}"` becomes `[innerHtml]`, and the
summary/detail wrappers become `div`s to match PrimeNG's own template. The
`MessageService` stays with the consumer, so each outlet keeps its own message
stream — the picker's dialog and the portlet shell do not share one.

`ToastModule` and `DotSeverityIconComponent` drop out of both hosts, and
`PICKER_REAL_IMPORTS` in the picker spec is updated so the list keeps matching
what the component actually composes.

Specs cover the regression directly (markup renders as elements, not text) and
pin the sanitization that makes `[innerHtml]` safe for backend error text.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nicobytes
nicobytes added this pull request to the merge queue Aug 19, 2026
Merged via the queue into main with commit 2275b1b Aug 19, 2026
47 checks passed
@nicobytes
nicobytes deleted the issue-36702-asset-picker branch August 19, 2026 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

5 participants