Skip to content

36733 unify folder p tree into a shared dotcmsui component - #36848

Merged
nicobytes merged 23 commits into
mainfrom
36733-unify-folder-p-tree-into-a-shared-dotcmsui-component
Aug 5, 2026
Merged

36733 unify folder p tree into a shared dotcmsui component#36848
nicobytes merged 23 commits into
mainfrom
36733-unify-folder-p-tree-into-a-shared-dotcmsui-component

Conversation

@nicobytes

@nicobytes nicobytes commented Jul 31, 2026

Copy link
Copy Markdown
Member

This pull request refactors the folder tree display components in both the edit-content host folder field and the content drive sidebar to use the new DotFolderTreeComponent wrapper instead of the raw PrimeNG p-tree. It unifies the tree node data model to support a new "load-more" sentinel node type, updates related tests, and simplifies the handling of selected nodes and labels.

Component Refactoring and API Unification

  • Replaced all usages of p-tree with the new DotFolderTreeComponent in host-folder-field.component.html and dot-tree-folder.component.html, updating inputs and outputs to match the new API. This includes switching from [value]/[selection] to [folders]/[selectedNode], and updating event handlers and templates accordingly. [1] [2] [3]
  • Updated component and test imports to use DotFolderTreeComponent and new pipes, removing unused PrimeNG modules and pipes. [1] [2] [3] [4]

Tree Node Data Model Enhancements

  • Extended the TreeNodeData type to include a load-more node type, with optional nextPage and remaining properties for pagination support. Updated all relevant code to use this new type and ensure "load-more" nodes are correctly constructed. [1] [2] [3] [4]

Selected Node Handling

  • Changed the selected node input from an array to a single node object in both the sidebar and host folder field, updating tests and internal logic to match. [1] [2] [3] [4]

Load More Node Handling

  • Updated the "load more" node handling to use the new unified node type, changed the event signature for loading more items to accept an optional event, and ensured all "load more" buttons and test IDs are passed through the new component. [1] [2] [3]

Test and Utility Updates

  • Adjusted tests and utility functions to match the new node type, selected node handling, and component structure. This includes updating test expectations for selected nodes and "load more" nodes, and removing obsolete tree styling. [1] [2] [3] [4] [5]

These changes modernize and standardize the folder tree UI components, improve maintainability, and add support for paginated folder loading.

This PR fixes: #36733

This PR fixes: #36733

- Extracts a reusable dot-folder-tree component so host-folder-field,
  dot-tree-folder, and dot-sidebar consume one shared implementation
  instead of duplicating p-tree config, load-more button, and toggler
  templates.
- Adds a folder-name pipe as the successor to dot-truncate-path, kept
  as a thin deprecated alias for backward compatibility.
- Simplifies selectedNode handling to a single TreeNode instead of an
  array-transform workaround for PrimeNG's selection API.
Introduces a presentational folder-tree component in @dotcms/ui to
consolidate the p-tree chrome (togglers, load-more, node labels)
shared across Content Drive, Browser Selector, and Host Folder Field,
so each consumer can own its data/UX without duplicating tree markup.

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

Refactors the admin UI folder-tree implementations to use a shared, presentational DotFolderTreeComponent in @dotcms/ui, unifying selection handling and introducing a consistent “load-more” sentinel node model across consumers (Content Drive, Browser Selector sidebar, and Host Folder Field).

Changes:

  • Added DotFolderTreeComponent (standalone) that owns the PrimeNG p-tree shell, templates (default/load-more/toggler), selection normalization, and test IDs.
  • Migrated Browser Selector sidebar, Content Drive tree wrapper, and Host Folder Field overlay tree to consume the shared component and the unified node model (including type: 'load-more').
  • Consolidated path-label behavior by promoting FolderNamePipe and deprecating DotTruncatePathPipe as an alias, with corresponding test updates.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
core-web/libs/ui/src/lib/pipes/dot-truncate-path/dot-truncate-path.spec.ts Adds coverage for empty-path behavior in the deprecated alias pipe.
core-web/libs/ui/src/lib/pipes/dot-truncate-path/dot-truncate-path.pipe.ts Deprecates the pipe in favor of FolderNamePipe while keeping compatibility for existing call sites.
core-web/libs/ui/src/lib/pipes/dot-folder-name/dot-folder-name.pipe.ts Clarifies pipe intent/docs for extracting the final path segment.
core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.ts Introduces the shared folder-tree shell component and its unified API (folders/selection/load-more/toggler behavior).
core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.html Implements shared templates for default nodes, load-more button, and custom toggler icons.
core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.scss Centralizes tree toggler mode styling (chevron vs first-only folder icon).
core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.spec.ts Adds Jest/Spectator coverage for selection normalization, outputs, load-more behavior, and default labeling.
core-web/libs/ui/src/lib/components/dot-browser-selector/components/dot-sidebar/dot-sidebar.component.ts Switches Browser Selector sidebar to the shared tree and simplifies selection state management.
core-web/libs/ui/src/lib/components/dot-browser-selector/components/dot-sidebar/dot-sidebar.component.html Replaces inline p-tree usage with <dot-folder-tree> and wires events/inputs.
core-web/libs/ui/src/index.ts Exports the new shared DotFolderTreeComponent from @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/lib/dot-tree-folder/dot-tree-folder.component.ts Refactors Content Drive tree wrapper to delegate the tree shell to DotFolderTreeComponent while keeping drag/drop and “All folders” behavior.
core-web/libs/portlets/dot-content-drive/ui/src/lib/dot-tree-folder/dot-tree-folder.component.html Replaces Content Drive’s inline p-tree with <dot-folder-tree> and projects the label template for Content Drive–specific markup.
core-web/libs/portlets/dot-content-drive/ui/src/lib/dot-tree-folder/dot-tree-folder.component.scss Removes tree-specific toggler styling now owned by the shared component.
core-web/libs/portlets/dot-content-drive/ui/src/lib/dot-tree-folder/dot-tree-folder.component.spec.ts Updates tests for the wrapper’s new selected-node shape and wrapper-based rendering.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/utils/functions.ts Ensures load-more sentinel nodes also set the PrimeNG TreeNode.type for template matching.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/utils/functions.spec.ts Updates expectations to include the type: 'load-more' field for sentinel nodes.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/components/dot-content-drive-sidebar/dot-content-drive-sidebar.component.spec.ts Aligns sidebar tests with the new single-node selection input.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-host-folder-field/store/host-folder-field.store.ts Updates load-more node creation to include unified data payload for the new shared tree.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-host-folder-field/components/host-folder-field/host-folder-field.component.ts Migrates Host Folder Field overlay tree to the shared component and adjusts scroll-to-selection logic.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-host-folder-field/components/host-folder-field/host-folder-field.component.html Replaces inline p-tree with <dot-folder-tree>, projects label template, and wires load-more via the shared output.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-host-folder-field/components/host-folder-field/host-folder-field.component.spec.ts Updates stubs/expectations to match the wrapper component API and scroll helper access.
core-web/libs/dotcms-models/src/lib/dot-browser-selector.model.ts Extends the shared tree node data model to include load-more with pagination metadata.

Comment thread core-web/libs/ui/src/lib/pipes/dot-truncate-path/dot-truncate-path.pipe.ts Outdated
@github-actions github-actions Bot added the Area : Frontend PR changes Angular/TypeScript frontend code label Jul 31, 2026
- Updated the `createFolders` function to return an array of `CreatedFolder` objects instead of void, enhancing the API's usability.
- Modified the `createFolders` type definition in the fixture to reflect the new return type.
- Added export for `ContentDrivePage` in the index file to improve component accessibility.
- Introduced a new `ContentDrive` constant in the portlets utility for better navigation within the application.
@claude

claude Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nicobytes's task in 13m 22s —— View job


Code Review

Reviewed the diff against origin/main, focused on the load-more pagination logic added to the two stores and the shared DotFolderTreeComponent. The prior in-PR cleanup items (dead DOT_FOLDER_TREE_LOAD_MORE_TYPE, treeToggler, .folder-all, untracked, null-safe pipe, TreeNodeSelectEvent typing) are all resolved. One new bug in the browser store, plus a couple of smaller items.

New Issues

  • 🟠 High: core-web/libs/ui/src/lib/components/dot-browser-selector/store/browser.store.ts:368-371,429-432Load-more error path leaves a permanently stuck spinner. loadMore sets node.loading = true then immediately patchState(store, refreshFolders(store)), which structuredClones folders().data into a brand-new tree. That detaches the captured node from the tree PrimeNG is actually rendering. On the success path this is fine because the sentinel is rebuilt (stripLoadMore + withLoadMore), but on the error path the handler does node.loading = false on the now-stale reference and then refreshFolders(store) re-clones the current store tree — where the sentinel still has loading: true. Result: if the paginated request fails, the "Load more" button stays disabled with a spinner spinning forever, and the user cannot retry without reloading. The loadChildren method above doesn't hit this because it does not clone before the request, so its node stays live. Fix: after an error, clear loading on the live tree node (e.g. re-find the sentinel by key in folders().data and set loading = false before cloning), or don't pre-clone / thread the sentinel's key through. Neither loadMore error path is covered by tests (browser.store.test.ts:606-726 only asserts the success cases). Fix this →

Existing (follow-ups explicitly deferred, noting for completeness)

  • 🟡 Medium: core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.ts:81,92 — shared @dotcms/ui component still defaults $loadMoreLabelKey to '' and $showLoadMorePlusIcon to false — actually consumer-neutral now (good), but note the Content Drive wrapper (dot-tree-folder.component.html:14) passes loadMoreLabelKey="dot.file.field.host.folder.action.load.more", borrowing the Host Folder key rather than its own content-drive.tree.load-more. Behaviorally identical text today, but LOAD_MORE_LABEL_KEY in dot-content-drive/ui/src/lib/shared/constants.ts:20 is now dead. Deferred per the review thread; flagging so it's tracked.

  • 🟡 Medium: core-web/libs/portlets/dot-content-drive/ui/src/lib/dot-tree-folder/dot-tree-folder.component.html — the Content Drive tree no longer renders the (remaining) count next to "Load more" (the old inline template had @if (node.data.remaining) { ({{ node.data.remaining }}) }). The shared component supports it via [showLoadMoreRemaining], but the wrapper doesn't set it, so the count is silently dropped. If that was intentional, ignore; otherwise pass [showLoadMoreRemaining]="true".

Resolved

  • dot-folder-tree.component.html:45WONTWON'T typo fixed
  • dot-folder-name.pipe.ts:15 — pipe is now null/undefined-safe; guards the .split() the Copilot suppressed comments warned about
  • dot-truncate-path.pipe.ts — deleted; no longer instantiates a second pipe
  • dot-folder-tree.component.ts:109 / dot-sidebar.component.ts:123onNodeSelect / handleNodeSelect now typed TreeNodeSelectEvent
  • dot-sidebar.component.ts:104 — stale-selection clear uses signalMethod (untracked reads), no infinite-loop risk
  • dot-browser-selector.model.ts:17-41TreeNodeData is now a proper discriminated union (TreeNodeContentData | TreeNodeLoadMoreData) with type guards, addressing the earlier widening concern

Nothing here is data-corrupting or a security issue. The High item is error-path-only but leaves the UI unrecoverable, so worth fixing before merge.

· 36733-unify-folder-p-tree-into-a-shared-dotcmsui-component

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 30 out of 30 changed files in this pull request and generated no new comments.

Suppressed comments (8)

core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.ts:113

  • PrimeNG's (onNodeSelect) emits a select event, not an expand event. Typing this output as TreeNodeSelectEvent avoids confusing API consumers and matches other tree consumers in the codebase.
    onNodeSelect = output<TreeNodeExpandEvent>();

core-web/libs/ui/src/lib/components/dot-browser-selector/components/dot-sidebar/dot-sidebar.component.ts:63

  • onNodeSelect should be typed as TreeNodeSelectEvent (selection), not TreeNodeExpandEvent (expansion). This helps downstream consumers and matches the JSDoc intent.
    onNodeSelect = output<TreeNodeExpandEvent>();

core-web/libs/ui/src/lib/components/dot-browser-selector/components/dot-sidebar/dot-sidebar.component.ts:103

  • handleNodeSelect receives the selection event from dot-folder-tree / PrimeNG (onNodeSelect), so its parameter type should be TreeNodeSelectEvent rather than TreeNodeExpandEvent.
    handleNodeSelect(event: TreeNodeExpandEvent): void {
        this.#userSelected.set(event.node);
        this.onNodeSelect.emit(event);
    }

core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.html:22

  • TreeNode.label is optional in PrimeNG, and FolderNamePipe calls .split() on its input. If any node has an undefined/null label, this will throw at runtime. Guard the pipe input in the template to ensure a string is always passed.
            <span data-testid="tree-node-label" class="font-normal">
                {{ node.label | folderName }}
            </span>

core-web/libs/edit-content/src/lib/fields/dot-edit-content-host-folder-field/components/host-folder-field/host-folder-field.component.html:281

  • This template now uses folderName on node.label, but PrimeNG TreeNode.label can be undefined. Guarding with node.label ?? '' prevents runtime errors from .split() in the pipe if a node ever lacks a label.
                                <span
                                    class="block w-full min-w-0 truncate"
                                    [class.font-semibold]="isSearching"
                                    [class.leading-normal]="isSearching">
                                    {{ node.label | folderName }}
                                </span>

core-web/libs/ui/src/lib/pipes/dot-truncate-path/dot-truncate-path.pipe.ts:22

  • Even as a deprecated alias, dotTruncatePath can still be invoked from templates with null/undefined values. Guard the input so it never throws when delegating to FolderNamePipe.
    private readonly folderNamePipe = new FolderNamePipe();

    transform(value: string): string {
        return this.folderNamePipe.transform(value);
    }

core-web/libs/ui/src/lib/components/dot-folder-tree/dot-folder-tree.component.ts:17

  • DotFolderTreeComponent.onNodeSelect is currently typed as TreeNodeExpandEvent, but PrimeNG emits TreeNodeSelectEvent for selection. Importing the correct event type makes the wrapper API clearer and aligns with existing patterns (e.g. Content Drive sidebar uses TreeNodeSelectEvent).

This issue also appears on line 113 of the same file.

import type { TreeNodeCollapseEvent, TreeNodeExpandEvent } from 'primeng/types/tree';

core-web/libs/ui/src/lib/components/dot-browser-selector/components/dot-sidebar/dot-sidebar.component.ts:13

  • For consistency with other tree consumers (and to get access to TreeNodeSelectEvent), import PrimeNG tree event types from primeng/types/tree instead of primeng/tree.

This issue also appears in the following locations of the same file:

  • line 63
  • line 100
import type { TreeNodeExpandEvent } from 'primeng/tree';

@zJaaal

zJaaal commented Aug 3, 2026

Copy link
Copy Markdown
Member

Reviewed the refactor end to end. The core mechanic is correct and I verified it rather than assuming: PrimeNG resolves the load-more template via getTemplateForNode() (primeng-tree.mjs:1590 returns _templateMap[node.type], and with no match the node silently degrades to a plain {{ node.label }}), so adding type: 'load-more' to the builders is exactly what makes the shared pTemplate="load-more" fire. I checked that functions.ts:388 and host-folder-field.store.ts:56 are the only two sentinel construction sites. The selectedNode array-transform removal is also safe: in PrimeNG v21 the Tree host folds styleClass into the same class binding your [class] writes to, so the sidebar markup change is behaviorally equivalent.

Nothing below blocks. A few small cleanups worth doing in this PR, then some follow-up material.

Worth fixing here (all deletions / one-liners)

Dead symbols introduced by this PR:

  • DOT_FOLDER_TREE_LOAD_MORE_TYPE (dot-folder-tree.component.ts:22): zero references. It is also a third copy of 'load-more' next to host-folder-field.store.ts:45 and content-drive constants.ts:16, so either make it the single source of truth or drop it.
  • ContentDrivePage.treeToggler (contentDrive.page.ts:11,20): assigned, never read, since toggleTree() builds its own locators.
  • The createFolders return-value change (requests/folders.ts:13-21,44 plus the fixture signature): I grepped all 9 call sites and every one discards the result. This is the one I would most like removed or actually used, because as written it implies callers depend on the entity shape when none do.

Misleading comments in new test helpers (contentDrive.page.ts:107, helpers/content-drive-tree.ts:15): both say the p-tree host "may not expose treeTestId". It does. [attr.data-testid] binds to the host element, and PrimeNG only host-binds class and attr.data-p. A wrong comment in a helper costs more later than it costs to fix now. Relatedly, the helpers still select on .p-tree-node-content / .p-tree-node-toggle-button / .p-tree-node-selected, which is the coupling the new treeTestId / loadMoreTestId plumbing exists to avoid.

Plus the two one-liners the bots already raised: the dead .folder-all block in the new scss, and wrapping the #userSelected read in untracked() in the sidebar effect.

Follow-up, not this PR

TreeNodeData (dot-browser-selector.model.ts:31) is widened rather than modeled. With type as a 3-way union and nextPage / remaining optional, every folder and site node now type-checks for pagination fields it can never have, and load-more sentinels have to carry meaningless path: '' / hostname: '' to satisfy required fields (host-folder-field.store.ts:59-63). A discriminated union would let the compiler enforce it:

type TreeNodeData =
    | { type: 'site' | 'folder'; path: string; hostname: string; id: string }
    | { type: 'load-more'; id: string; nextPage?: number; remaining?: number };

That change also covers the related smell that type now lives on both the node and its data payload, with node.type driving PrimeNG template selection and node.data.type driving consumer logic (dot-content-drive-sidebar.component.ts:157,211). Set one without the other and you get an untranslated, unclickable load-more row, which no current test would catch. Low risk today given a single builder per consumer, but worth locking down before more consumers adopt the shared component.

Two smaller follow-ups in the same bucket: the shared component defaults $loadMoreLabelKey to a host-folder-field i18n key and $showLoadMorePlusIcon to true (dot-folder-tree.component.ts:59-73), which bakes one consumer's opinions into @dotcms/ui; and content-drive.fixture.ts copy-pastes adminPage / testSuffix / getDefaultSite / getCurrentSite verbatim from host-folder.fixture.ts:59-84, which becomes three copies at the next portlet.


Review written by Claude (Claude Code), posted from @zJaaal's account.

@nicobytes

Copy link
Copy Markdown
Member Author

Addressed the in-PR cleanup items from the reviews:

  • onNodeSelect / handleNodeSelect now use TreeNodeSelectEvent
  • Sidebar effect reads #userSelected via untracked()
  • FolderNamePipe / deprecated DotTruncatePathPipe null-safe; alias no longer constructs another pipe
  • Removed unused DOT_FOLDER_TREE_LOAD_MORE_TYPE, .folder-all CSS, ContentDrivePage.treeToggler, and the unused createFolders return value
  • Fixed the WON'T typo and corrected the misleading treeTestId helper comments

Leaving the follow-ups (discriminated TreeNodeData, consumer-neutral defaults, fixture dedupe) for a separate issue as suggested.

- Introduced a new `base.fixture.ts` to centralize shared Playwright fixtures for admin pages and API helpers.
- Updated `content-drive.fixture.ts`, `host-folder.fixture.ts`, and `relationship.fixture.ts` to extend from the new base fixture, simplifying their structure and improving maintainability.
- Modified the `createFolders` function to return void, aligning with the updated API design.
- Enhanced the `getDefaultSite` function to throw an error if no default site is found, improving error handling.
- Updated various components and tests to utilize the new `dotFolderName` pipe for consistent folder name formatting.
- Removed deprecated `dot-truncate-path` pipe references across the codebase.
- Improved the handling of load-more nodes in the folder tree structure, ensuring consistent behavior across components.
- Introduced a new helper function `isKnownFilterKey` to improve readability and maintainability.
- Updated the filter decoding process to utilize the typed known-key map, enhancing type safety and clarity in the assignment of decoded values.
- Simplified the handling of unknown filter keys by retaining existing functionality while improving code structure.
…ents

Co-authored-by: nicobytes <7611944+nicobytes@users.noreply.github.com>
- Updated the test for handling filters with null or undefined values to cast the filter object correctly, ensuring type safety.
- Enhanced the path assertion in the folder nodes test to safely access the path property, preventing potential runtime errors.
- Added a guard clause in the test for `getFolderNodesByPath` to ensure `data` is present and valid before accessing its properties, preventing potential runtime errors.
- Updated assertions to directly reference the `data` object for clarity and safety in the test outcomes.
- Added a new constant, FOLDER_TREE_HIERARCHY_PAGE_SIZE, to manage pagination for deep-link and initial hierarchy fetches, ensuring that folders beyond the interactive page of 40 are accessible.
- Updated utility functions and tests to utilize the new page size, enhancing the folder hierarchy retrieval process and maintaining consistency with existing pagination behavior.
- Adjusted related tests to reflect the new hierarchy page size and ensure proper functionality in folder searches.
- Reformatted conditional assignments in `dot-content-drive-dialog-content-type-selector`, `dot-content-drive-toolbar`, and `dot-content-drive-shell` components for better clarity and consistency.
- Updated import statements in `browser.store.ts` to follow a cleaner multi-line format, enhancing maintainability.
…ent-type-selector tests

- Modified the `selectedNode` mock to return an object with a `type` property set to 'folder', ensuring consistency with the expected data structure in tests.
- Enhanced the `onRequestUpload` method in `dot-content-drive-shell` to handle cases where `targetFolder` may be null or undefined, improving robustness against potential runtime errors.
@alwaysmeticulous

Copy link
Copy Markdown

🤖 No test run has been triggered as your Meticulous project has been deactivated (since you haven't viewed any test results in a while). Click here to reactivate.

Last updated for commit 8ca5cc0. This comment will update as new commits are pushed.

@mergify

mergify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

…tent-drive components

- Replaced folder icons from 'pi-folder-open' and 'pi-folder' to 'pi-globe' for consistency across various components and tests.
- Removed the `showFolderIconOnFirstOnly` property from the `dot-tree-folder` component and its related tests, simplifying the component's API.
- Adjusted related tests and mock data to reflect the new icon usage and ensure proper functionality.
- Introduced the `dot-users` portlet, including user creation and listing components.
- Implemented routing for the users section in the application.
- Added ESLint and Jest configurations specific to the new portlet.
- Enhanced the user list with search and filter functionalities, utilizing PrimeNG components for UI consistency.
- Created tests for the user list and filter components to ensure functionality and reliability.
…spec.ts

- Updated the `ALL_FOLDER` mock to include a PrimeNG folder icon (`icon: 'pi pi-folder'`).
- Added a new test case to verify the presence of the folder icon in the mock data.
@nicobytes
nicobytes added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit 8c72574 Aug 5, 2026
51 checks passed
@nicobytes
nicobytes deleted the 36733-unify-folder-p-tree-into-a-shared-dotcmsui-component branch August 5, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Unify folder p-tree into a shared @dotcms/ui component

4 participants