Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
187 commits
Select commit Hold shift + click to select a range
214200c
Refactor dot-usage-shell component for improved UI and structure
fmontes Dec 24, 2025
f3201ce
Update dot-usage-shell component for improved skeleton loading and st…
fmontes Dec 24, 2025
81bd166
Enhance dot-usage-shell component with last updated timestamp
fmontes Dec 24, 2025
66503e6
Refactor dot-usage component tests to use structured metrics format
fmontes Dec 24, 2025
879ce37
Refactor dot-usage service and shell component tests to utilize new H…
fmontes Dec 24, 2025
67e26d1
Add dot-usage service and tests for usage summary functionality
fmontes Dec 24, 2025
317f1ad
Enhance DotUsageShellComponent tests to improve error handling and lo…
fmontes Dec 24, 2025
daa6ae1
Add informational message to DotUsageShellComponent for analytics upd…
fmontes Dec 24, 2025
625dde3
Enhance DotUsageShellComponent with accessibility improvements and er…
fmontes Dec 24, 2025
c90d04b
add layout tree
fmontes Dec 24, 2025
1c31dfb
Implement zoom and pan functionality in EditEmaEditor component
fmontes Dec 25, 2025
162a545
Refactor EditEmaEditor component to improve message handling and ifra…
fmontes Dec 25, 2025
4453853
Refactor EditEmaEditor component: rename zoom and pan method, update …
fmontes Dec 25, 2025
8615a44
Refactor EditEmaEditor component: rename zoom and pan method, update …
fmontes Dec 26, 2025
7fce1e8
Refactor DotUveBridgeService: streamline imports and simplify sendMes…
fmontes Dec 26, 2025
a5d3e22
Enhance EmaPageDropzone component: add zoomLevel input and adjust pos…
fmontes Dec 26, 2025
33fbe2b
Update DotUvePaletteComponent: change icon in tab header and remove u…
fmontes Dec 26, 2025
dfb4695
Refactor DotUvePaletteComponent: improve container label retrieval an…
fmontes Dec 26, 2025
25cb615
Enhance DotUvePaletteComponent: add contentlet nodes to layout tree s…
fmontes Dec 26, 2025
7f5076c
Update DotUvePaletteComponent: enhance tree display with overflow han…
fmontes Dec 26, 2025
d9f9ad9
DotUveDragDropService: clean up
fmontes Dec 26, 2025
b8c3ded
Refactor DotUveActionsHandlerService: streamline imports and remove u…
fmontes Dec 26, 2025
6f3469c
Enhance DotUvePaletteComponent and EditEmaEditor: add node selection …
fmontes Dec 26, 2025
db80e44
Adjust scroll position calculation in EditEmaEditor to account for zo…
fmontes Dec 26, 2025
7a4dd9b
Enhance DotUvePaletteComponent: implement drag-and-drop functionality…
fmontes Dec 26, 2025
9336d55
Integrate DotPageLayoutService into DotUvePaletteComponent and withSa…
fmontes Dec 26, 2025
bfeae75
Update _tree.scss and DotUvePaletteComponent: adjust tree node margin…
fmontes Dec 26, 2025
5b86cfd
Enhance EditEmaEditor: implement dynamic contentlet form generation w…
fmontes Dec 27, 2025
6a0b2fc
Enhance EditEmaEditor: add hidden inode field to form, implement load…
fmontes Dec 27, 2025
a70a80e
Refactor DotUvePaletteComponent: replace tree structure with DotRowRe…
fmontes Dec 28, 2025
11b3f7b
Enhance DotRowReorderComponent: implement expandable row functionalit…
fmontes Dec 28, 2025
06031dc
Update withSave function: add logic to re-fetch page content after sa…
fmontes Dec 28, 2025
34166dc
Enhance DotRowReorderComponent: implement column drag-and-drop functi…
fmontes Dec 28, 2025
9a05ac9
Enhance DotRowReorderComponent: add edit row dialog functionality, al…
fmontes Dec 28, 2025
01e5b4c
Enhance DotRowReorderComponent: add functionality to edit column styl…
fmontes Dec 28, 2025
a2787aa
Enhance DotRowReorderComponent: add column drag/sort animations to im…
fmontes Dec 28, 2025
22fdb67
Enhance EditEmaEditor: add cancel functionality to reset selected con…
fmontes Dec 28, 2025
0ebaca4
Refactor DotEmaShellComponent and update routing: streamline service …
fmontes Dec 28, 2025
def181c
Update styles in EditEmaEditor and TemplateBuilder: adjust grid colum…
fmontes Dec 28, 2025
de10f91
clean up state management
fmontes Dec 28, 2025
a9c1beb
Enhance EditEmaEditor and Zoom Controls: Introduce a sticky toolbar w…
fmontes Dec 28, 2025
caaed75
Implement UVE Refactor: Introduce a new service architecture by extra…
fmontes Dec 28, 2025
08968fd
Refactor updateRows method: Move from withSave.ts to withLayout.ts fo…
fmontes Dec 28, 2025
b5879c2
Enhance UVE Refactor Handoff: Add sections for palette UI visual grou…
fmontes Dec 28, 2025
07f3169
Address responsive preview issues caused by zoom implementation: docu…
fmontes Dec 28, 2025
ca0acce
Refactor DotUveContentletToolsComponent: Implement hover and selected…
fmontes Dec 30, 2025
5f38afe
Implement palette toggle functionality in EditEmaEditor: Add button t…
fmontes Dec 30, 2025
325fab0
Add right sidebar toggle functionality in EditEmaEditor: Introduce a …
fmontes Dec 30, 2025
c2c1edf
Update right sidebar toggle in EditEmaEditor: Replace icon with SVG i…
fmontes Dec 30, 2025
c39211a
Implement URL copy functionality in EditEmaEditor: Add a button to co…
fmontes Dec 30, 2025
b52fad0
Enhance UVE Refactor Handoff: Implement dual overlay system for conte…
fmontes Dec 30, 2025
d2ffc36
Add draggable attribute to toolbar icons in EditEmaEditor: Update lef…
fmontes Dec 30, 2025
b8f0e8c
Refactor right sidebar visibility in EditEmaEditor: Update sidebar re…
fmontes Dec 30, 2025
18a1658
Refactor spacing variables in SCSS files: Remove unused spacing varia…
fmontes Dec 30, 2025
674277d
Remove unused padding from editor content preview in SCSS file: Strea…
fmontes Dec 30, 2025
7fab8f9
Refactor height calculation in DotUveIframeComponent: Implement a mor…
fmontes Dec 30, 2025
38cddee
fix(edit-ema): replace unreliable iframe height calculation with post…
fmontes Dec 30, 2025
a2f76a1
refactor(edit-ema): enhance iframe styling and remove unused contentl…
fmontes Dec 31, 2025
83b052e
feat(edit-ema): integrate right sidebar state management into uveStore
fmontes Dec 31, 2025
4216d09
refactor(edit-ema): clean up event listener for iframe height reporting
fmontes Dec 31, 2025
88c8c54
fix(UVE_REFACTOR_HANDOFF): resolve responsive preview issues caused b…
fmontes Dec 31, 2025
b42aefe
move handoff doc
fmontes Dec 31, 2025
30d1a1a
chore(UVE_REFACTOR_HANDOFF): update production readiness plan with cr…
fmontes Dec 31, 2025
0a88295
fix(edit-ema): prevent accidental global content edits with copy cont…
fmontes Dec 31, 2025
4d42524
refactor(edit-ema): extract contentlet saving logic into a separate m…
fmontes Dec 31, 2025
b4e7aaf
refactor(edit-ema): extract toolbar presentational components for con…
fmontes Jan 2, 2026
3febd49
refactor(edit-ema): convert palette components to container/presentat…
fmontes Jan 3, 2026
de47a4a
feat(edit-ema): extract DotUveContentletQuickEditComponent as prese…
fmontes Jan 3, 2026
4b5a797
refactor(edit-ema): enhance component structure and documentation in …
fmontes Jan 3, 2026
d4a3f92
feat(edit-ema): enhance DotEmaShellComponent with local state managem…
fmontes Jan 3, 2026
da62e92
feat(edit-ema): implement local computed properties in EditEmaEditor …
fmontes Jan 3, 2026
5d030ce
refactor(edit-ema): restructure UVE store with nested UI state (Phase…
fmontes Jan 3, 2026
98283fd
refactor(edit-ema): group UI panel preferences under editor.panels
fmontes Jan 3, 2026
a4f15b6
refactor(uve-store): Phase 4 - Remove cross-feature dependencies
fmontes Jan 4, 2026
b966239
refactor(edit-ema): implement nested editor and toolbar state in UVE …
fmontes Jan 4, 2026
ac83562
refactor(edit-ema): remove pageAPIResponse and normalize UVE store state
fmontes Jan 4, 2026
037cfb3
refactor(edit-ema): reorganize UVE store state with logical groupings…
fmontes Jan 4, 2026
a7e121b
refactor(edit-ema): eliminate impossible states in UVE store with sta…
fmontes Jan 4, 2026
a75be72
refactor(edit-ema): flatten UVE store feature composition and elimina…
fmontes Jan 4, 2026
bffcb94
refactor(edit-ema): implement factory parameter pattern and improve n…
fmontes Jan 4, 2026
1aeb698
refactor(edit-ema): consolidate lock logic to eliminate duplicate com…
fmontes Jan 4, 2026
9b69fa1
refactor(uve-store): Phase 4 - eliminate cross-feature dependencies w…
fmontes Jan 4, 2026
cccfb39
refactor(uve-store): Phase 5.1 - move to shared contract, eliminate …
fmontes Jan 4, 2026
85a4a44
refactor(edit-ema): rename withToolbar to withView for semantic clarity
fmontes Jan 4, 2026
a5380de
test(edit-ema): fix test suite after toolbar→view store refactoring
fmontes Jan 4, 2026
a42adcd
test(dot-uve): update tests to reflect new state structure and add Do…
fmontes Jan 4, 2026
f3e74f0
test(dot-toggle-lock-button): enhance unit tests for lock button beha…
fmontes Jan 4, 2026
0a33529
feat(uve): address known issues with feature flags and quick editor f…
fmontes Jan 4, 2026
17c64a4
test(edit-ema): enhance unit tests for EditEmaEditorComponent with ne…
fmontes Jan 4, 2026
ff32fd7
refactor(edit-ema): replace DotUveZoomService with UVEStore for zoom …
fmontes Jan 5, 2026
c6acbb5
refactor(edit-ema): update page lock logic to incorporate feature fla…
fmontes Jan 5, 2026
3028987
refactor(edit-ema): streamline page context and lock handling logic
fmontes Jan 5, 2026
1b3957b
refactor(edit-ema): update tab mapping for UVE palette component
fmontes Jan 5, 2026
e1340e7
test(dot-uve-contentlet-quick-edit): enhance unit tests for form rend…
fmontes Jan 5, 2026
c8e8e39
test(dot-uve-contentlet-tools): enhance unit tests for contentlet sel…
fmontes Jan 5, 2026
96725c7
test(dot-uve-iframe): add unit tests for DotUveIframeComponent
fmontes Jan 5, 2026
83accea
test(dot-row-reorder): add unit tests for DotRowReorderComponent
fmontes Jan 5, 2026
98e24aa
test(dot-uve-toolbar): enhance unit tests for DotUveToolbarComponent
fmontes Jan 5, 2026
8fb48a6
test(dot-uve-toolbar): update unit tests for DotUveToolbarComponent
fmontes Jan 5, 2026
eab050b
test(dot-ema-shell): enhance unit tests for DotEmaShellComponent
fmontes Jan 5, 2026
f877bc9
Merge branch 'main' into uve-experiment
fmontes Jan 5, 2026
120ad98
clean up / update the handoff doc
fmontes Jan 6, 2026
4ca723b
fix(edit-ema): use uveStore.$zoomLevel() instead of zoomService
fmontes Jan 7, 2026
dfda414
fix type
fmontes Jan 7, 2026
83bb219
Merge branch 'main' into uve-experiment
fmontes Jan 15, 2026
97f1dab
refactor(style-editor): Update activeContentlet access and enhance st…
fmontes Jan 16, 2026
4b8b4a1
fix(tests): Add missing imports in dot-row-reorder and dot-uve-zoom-c…
fmontes Jan 16, 2026
1549df1
Merge branch 'main' into uve-experiment
fmontes Jan 22, 2026
c7e7c73
Merge branch 'main' into uve-experiment
fmontes Jan 26, 2026
5621ab2
Merge branch 'main' into uve-experiment
fmontes Feb 2, 2026
45ae31c
refactor: Replace selectedContentlet with activeContentlet in UVE editor
fmontes Feb 2, 2026
d547651
test
fmontes Feb 2, 2026
b307709
refactor: Remove console.log statements from DotUvePalette and DotUve…
fmontes Feb 2, 2026
e958624
Debugging about issue when change active contentlet
KevinDavilaDotCMS Feb 2, 2026
b1de67d
fix merge conflicts
fmontes Feb 3, 2026
681a0c9
refactor: Update access to activeContentlet in UVE editor components
fmontes Feb 3, 2026
b8e09c6
refactor: Enhance right sidebar functionality in EditEmaEditor
fmontes Feb 3, 2026
d4cd68d
fix
fmontes Feb 4, 2026
6aceef7
Merge branch 'main' into uve-experiment
fmontes Feb 4, 2026
31c39af
refactor(UVE): Remove layout from state and update handling in store
fmontes Feb 4, 2026
48a77a2
Merge branch 'main' into uve-experiment
fmontes Feb 13, 2026
88ba359
refactor: eliminate UVE store state duplication and improve type comp…
fmontes Feb 13, 2026
4e59a90
refactor: flatten view state in UVEStore
fmontes Feb 13, 2026
ace98e1
refactor(uve): consolidate feature duplication
fmontes Feb 13, 2026
3d683b3
style(uve): fix import spacing in withEditor
fmontes Feb 13, 2026
312f481
style(uve): fix remaining import grouping in withEditor
fmontes Feb 13, 2026
42680e5
style(uve): add spacing between import groups in withEditor
fmontes Feb 13, 2026
0333f2e
refactor(uve): streamline withPageContext and withEditor features
fmontes Feb 13, 2026
752f81e
refactor(uve): delete withUVEToolbar dead code
fmontes Feb 13, 2026
34c9c53
refactor(uve): Phase 6.2 - consolidate lock concerns into withWorkflow
fmontes Feb 13, 2026
44186e0
fix(uve): resolve circular dependency and missing canLock property
fmontes Feb 13, 2026
cc84c8e
refactor(uve): Phase 6.3 - merge withPageContext into withClient
fmontes Feb 13, 2026
81a2a06
refactor(uve): Phase 6.4 - Rename withClient to withPage
fmontes Feb 13, 2026
a446643
clean up
fmontes Feb 13, 2026
7ba69b1
refactor(uve): Phase 1 - Create withUve feature and migrate to domain…
fmontes Feb 13, 2026
6245e76
fix(uve): Phase 1 cleanup - Fix linting errors
fmontes Feb 13, 2026
e10a5e3
feat(uve): Phase 2 - Add reusable withHistory composition for undo/redo
fmontes Feb 13, 2026
41a214f
docs(uve): Add explanation comment for any type in withHistory selector
fmontes Feb 13, 2026
0d01e3d
refactor(uve): Phase 3 - merge withViewZoom into withView
fmontes Feb 13, 2026
cd1fd41
refactor(uve): Phase 4 - create withPageApi (merge withLoad + withSave)
fmontes Feb 13, 2026
bb463b9
refactor(uve): Phase 4 cleanup - add TODO for page accessor dependencies
fmontes Feb 13, 2026
3a6078e
refactor(uve): Phase 5 - improve withEditor and withWorkflow document…
fmontes Feb 13, 2026
c142924
refactor(uve): Phase 6 - verify and document feature composition order
fmontes Feb 13, 2026
26996f4
refactor(uve): Phase 7 - Update component tests with new naming
fmontes Feb 13, 2026
4e2ce3a
docs(uve): Phase 8 - Add store architecture documentation
fmontes Feb 13, 2026
2602fae
refactor(uve): unify page access
fmontes Feb 13, 2026
61ce107
refactor(uve): rename unified accessor to pageAsset
fmontes Feb 14, 2026
5a3d1b6
refactor(uve): simplify lock flow and remove legacy lock accessors
fmontes Feb 14, 2026
9842bd6
fix(security): resolve Angular XSS vulnerability and address code review
fmontes Feb 16, 2026
b616def
refactor(uve): remove Phase references from code comments
fmontes Feb 16, 2026
c63953e
fix this commit
fmontes Feb 18, 2026
9886ce0
Merge branch 'main' into uve-experiment
rjvelazco Feb 25, 2026
1bf3e43
Merge branch 'uve-experiment' of https://github.com/dotCMS/core into …
rjvelazco Feb 25, 2026
633016a
Merge branch 'main' into uve-experiment
rjvelazco Feb 25, 2026
e162ded
fix: double scroll on template builder
rjvelazco Feb 26, 2026
5f3e834
fix: test v1
rjvelazco Feb 26, 2026
e569d90
Merge branch 'main' into uve-experiment
rjvelazco Feb 26, 2026
b2e5cda
fix: test v2
rjvelazco Feb 26, 2026
de8b441
fix: test v3
rjvelazco Feb 26, 2026
4c1e655
fix: test v4
rjvelazco Feb 26, 2026
19c8c96
fix: test v5
rjvelazco Feb 26, 2026
9520b9e
Merge branch 'main' into uve-experiment
rjvelazco Feb 26, 2026
8bf28c8
fix: test v6
rjvelazco Feb 27, 2026
76e29ca
fix: linter
rjvelazco Feb 27, 2026
96bd864
feedback v1
rjvelazco Feb 27, 2026
bc7ca0c
feedback v2: Remove viewZoomGestureStartZoom logic
rjvelazco Feb 27, 2026
df144a1
feedback v3: Remove viewZoomIsActive logic
rjvelazco Feb 27, 2026
3fb65a9
feedback v4
rjvelazco Feb 27, 2026
be26d53
feedback v5
rjvelazco Feb 27, 2026
9bc87f4
Merge branch 'main' into uve-experiment manually
rjvelazco Mar 2, 2026
56bb532
fix: merge issues
rjvelazco Mar 2, 2026
60a2ab1
feat: add iframe height reporter script and update iframe component
rjvelazco Mar 2, 2026
62c194c
refactor: update tab panel value from STYLE_EDITOR to LAYERS in dot-u…
rjvelazco Mar 2, 2026
af08393
Merge branch 'main' into uve-experiment
rjvelazco Mar 2, 2026
dec3b12
Merge branch 'uve-experiment' of https://github.com/dotCMS/core into …
rjvelazco Mar 2, 2026
2b065e5
feedback v6
rjvelazco Mar 3, 2026
6a77adf
feedback v6
rjvelazco Mar 3, 2026
aea273c
feedback v7
rjvelazco Mar 3, 2026
25199cb
feedback v8
rjvelazco Mar 3, 2026
f2b9993
feedback v9
rjvelazco Mar 3, 2026
f731060
feedback v10
rjvelazco Mar 3, 2026
850a806
feedback v11
rjvelazco Mar 3, 2026
9b32703
Merge branch 'main' into uve-experiment
rjvelazco Mar 3, 2026
e924bed
fix: non-clickable buttons on contentlet tools
rjvelazco Mar 4, 2026
19f8ab1
refactor: update dot-uve-contentlet-quick-edit component for improved…
rjvelazco Mar 4, 2026
4544a7d
Fixed style editor form overflow and trigger
KevinDavilaDotCMS Mar 4, 2026
a19d47d
Renamed library from edit-ema to dot-uve
KevinDavilaDotCMS Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
808 changes: 808 additions & 0 deletions core-web/UVE_REFACTOR_HANDOFF.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions core-web/apps/dotcms-ui/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
},
{
"glob": "**/*",
"input": "./libs/portlets/edit-ema/portlet/src/lib/assets",
"output": "./assets/edit-ema"
"input": "./libs/portlets/dot-uve/portlet/src/lib/assets",
"output": "./assets/dot-uve"
},
{
"glob": "**/*",
Expand All @@ -61,8 +61,8 @@
},
{
"glob": "**/*",
"input": "./libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/assets",
"output": "./assets/edit-uve-toolbar"
"input": "./libs/portlets/dot-uve/portlet/src/lib/dot-uve-editor/components/dot-uve-toolbar/assets",
"output": "./assets/dot-uve-toolbar"
}
],
"styles": [
Expand Down
2 changes: 1 addition & 1 deletion core-web/apps/dotcms-ui/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const PORTLETS_ANGULAR: Route[] = [
return inject(EmaAppConfigurationService).get(route.queryParams.url);
}
},
loadChildren: () => import('@dotcms/portlets/dot-ema').then((m) => m.dotEmaRoutes)
loadChildren: () => import('@dotcms/portlets/dot-uve').then((m) => m.dotUveRoutes)
},
{
canActivate: [editContentGuard],
Expand Down
2 changes: 1 addition & 1 deletion core-web/apps/dotcms-ui/src/app/components.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DotContentCompareComponent } from '@dotcms/portlets/dot-ema/ui';
import { DotContentCompareComponent } from '@dotcms/portlets/dot-uve/ui';
import { DotIconComponent } from '@dotcms/ui';

import { AppComponent } from './app.component';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
PermissionsType,
UserPermissions
} from '@dotcms/dotcms-models';
import { DotFavoritePageComponent } from '@dotcms/portlets/dot-ema/ui';
import { DotFavoritePageComponent } from '@dotcms/portlets/dot-uve/ui';
import { generateDotFavoritePageUrl } from '@dotcms/utils';

import { DotCreatePageDialogComponent } from '../dot-create-page-dialog/dot-create-page-dialog.component';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
PermissionsType,
UserPermissions
} from '@dotcms/dotcms-models';
import { DotFavoritePageComponent } from '@dotcms/portlets/dot-ema/ui';
import { DotFavoritePageComponent } from '@dotcms/portlets/dot-uve/ui';
import { GlobalStore } from '@dotcms/store';
import { generateDotFavoritePageUrl } from '@dotcms/utils';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { RouterOutlet } from '@angular/router';

import { DotContentCompareDialogComponent } from '@dotcms/portlets/dot-ema/ui';
import { DotContentCompareDialogComponent } from '@dotcms/portlets/dot-uve/ui';

import { DotCustomEventHandlerService } from '../../../api/services/dot-custom-event-handler/dot-custom-event-handler.service';
import { DotAlertConfirmComponent } from '../_common/dot-alert-confirm/dot-alert-confirm';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const enterprisePorlets: DotUnlicensedPortletData[] = [
},
{
icon: 'list',
titleKey: 'com.dotcms.repackage.javax.app.title.edit-ema',
titleKey: 'com.dotcms.repackage.javax.app.title.dot-uve',
url: '/forms'
},
{
Expand All @@ -67,8 +67,8 @@ const enterprisePorlets: DotUnlicensedPortletData[] = [
},
{
icon: 'file-edit',
titleKey: 'com.dotcms.repackage.javax.portlet.title.edit-ema',
url: '/edit-ema'
titleKey: 'com.dotcms.repackage.javax.portlet.title.dot-uve',
url: '/dot-uve'
},
{
icon: 'bolt',
Expand Down
2 changes: 1 addition & 1 deletion core-web/libs/dot-rules/src/lib/services/api/rule/Rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ export class RuleService {
query = hash.substr(hash.indexOf('?') + 1);

return ApiRoot.parseQueryParam(query, 'realmId');
} else if (hash.includes('edit-page') || hash.includes('edit-ema')) {
} else if (hash.includes('edit-page') || hash.includes('dot-uve')) {
return hash.split('/').pop().split('?')[0];
}

Expand Down
1 change: 1 addition & 0 deletions core-web/libs/dotcms-models/src/lib/dot-current-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface DotCurrentUser {
roleId: string;
surname: string;
userId: string;
loginAs: boolean;
}

export interface DotPermissionsType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@
.p-tree-container {
.p-treenode {
padding: 0;
margin: 0;
margin: 2px 0;
outline: 0;

.p-treenode-content {
border-radius: common.$border-radius-xs;
transition: none;
padding: spacing.$spacing-0 spacing.$spacing-1;
padding: 0 $spacing-0;

.p-tree-toggler {
margin-right: spacing.$spacing-1;
width: spacing.$spacing-5;
height: spacing.$spacing-5;
color: colors.$black;
margin-right: $spacing-0;
width: $spacing-5;
height: $spacing-5;
color: $black;
border: 0 none;
background: transparent;
border-radius: 50%;
Expand Down
3 changes: 0 additions & 3 deletions core-web/libs/dotcms-scss/shared/_spacing.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,3 @@ $spacing-8: 4rem; // 64px
$spacing-9: 4.5rem; // 72px
$spacing-10: 7rem; // 112px
$spacing-11: 11rem; // 176px

// New Spacing Variables
$spacing-width-m: 0.875rem; // 14px
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

import { ButtonModule } from 'primeng/button';

import { DotContentCompareComponent } from '@dotcms/portlets/dot-ema/ui';
import { DotContentCompareComponent } from '@dotcms/portlets/dot-uve/ui';
import { DotMessagePipe } from '@dotcms/ui';

import { DotEditContentStore } from '../../store/edit-content.store';
Expand Down
252 changes: 252 additions & 0 deletions core-web/libs/portlets/dot-uve/portlet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
# Edit EMA Portlet

Universal Visual Editor (UVE) portlet for dotCMS - enables in-context editing of pages with drag-and-drop content management.

## Architecture

This portlet follows a **Container/Presentational Component Pattern** to maintain clear separation of concerns:

- **Smart Containers**: Inject `UVEStore`, manage state, pass data down via `@Input`
- **Presentational Components**: No store injection, receive all data via `@Input`, emit events via `@Output`

### Component Tree

```
DotUveShellComponent (Smart Container) [UVEStore]
├─ DotUveNavigationBarComponent (Smart Container) [UVEStore]
│ └─ Receives navigation data via @Input + reads from UVEStore
├─ Route → DotUveEditorComponent (Smart Container) [UVEStore]
├─ DotUveToolbarComponent (Smart Container) [UVEStore]
│ ├─ DotToggleLockButtonComponent (Presentational) [NO STORE]
│ │ └─ @Input: toggleLockOptions | @Output: toggleLockClick
│ ├─ DotUveInfoDisplayComponent (Presentational) [NO STORE]
│ │ └─ @Input: options | @Output: actionClicked
│ ├─ DotUveDeviceSelectorComponent (Presentational) [NO STORE]
│ │ └─ @Input: state, devices | @Output: stateChange
│ ├─ DotUveLanguageSelectorComponent (Presentational) [NO STORE]
│ │ └─ @Input: contentLanguageId, pageLanguageId | @Output: change
│ └─ ... (most toolbar children are presentational)
├─ DotUvePaletteComponent (Smart Container) [UVEStore]
│ ├─ Uses local signalState for tab management (not global store)
│ └─ DotUvePaletteListComponent (Smart Container) [DotPaletteListStore + GlobalStore]
│ └─ @Input: listType, languageId, pagePath, variantId
│ └─ Uses feature store for palette-specific state management
├─ DotUveContentletQuickEditComponent (Presentational) [NO STORE]
│ └─ @Input: data (ContentletEditData), loading | @Output: submit, cancel
│ └─ Dynamic form generation based on field types
├─ DotUvePageDropzoneComponent (Presentational) [NO STORE]
│ └─ @Input: containers, dragItem, zoomLevel
│ └─ Pure canvas for drag-and-drop operations
└─ DotUveLockOverlayComponent (Smart Container) [UVEStore]
└─ Reads toggle lock state directly from UVEStore
```

## Key Patterns

### Local vs Global State

**Local Component State** (use `signalState()`):
- UI-specific state (tab selection, form validation, etc.)
- State that doesn't need cross-component coordination
- Example: `DotUvePaletteComponent` tab management

**Global Store State** (use `UVEStore`):
- Shared feature state (page data, contentlet selection, etc.)
- Cross-component coordination required
- Example: `activeContentlet`, `pageAPIResponse`

**Feature Store State** (use component-specific store):
- Domain-specific state for a feature (palette list data, search params, pagination)
- Encapsulated within a feature boundary
- Example: `DotPaletteListStore` for palette list management

### Container Component Pattern (with UVEStore)

```typescript
// Smart Container (reads from global store, manages state)
@Component({ selector: 'dot-uve-palette' })
export class DotUvePaletteComponent {
protected readonly uveStore = inject(UVEStore);

// Read from global store
readonly $languageId = computed(() => this.uveStore.$languageId());
readonly $pagePath = computed(() => this.uveStore.$pageURI());

// Local UI state
readonly #localState = signalState({ currentTab: 0 });
}
```

### Container Component Pattern (with Feature Store)

```typescript
// Smart Container with feature store
@Component({ selector: 'dot-uve-palette-list' })
export class DotUvePaletteListComponent {
readonly #paletteListStore = inject(DotPaletteListStore);
readonly #globalStore = inject(GlobalStore);

// Inputs from parent (for initialization)
$type = input.required<DotUVEPaletteListTypes>({ alias: 'listType' });
$languageId = input.required<number>({ alias: 'languageId' });

// Read from feature store
protected readonly $contenttypes = this.#paletteListStore.contenttypes;
protected readonly $pagination = this.#paletteListStore.pagination;
}
```

### Presentational Component Pattern

```typescript
// Presentational (receives props, emits events, NO store injection)
@Component({ selector: 'dot-uve-contentlet-quick-edit' })
export class DotUveContentletQuickEditComponent {
// NO store injection!

// Inputs (data down from parent container)
data = input.required<ContentletEditData>({ alias: 'data' });
loading = input<boolean>(false, { alias: 'loading' });

// Outputs (events up to parent container)
submit = output<Record<string, unknown>>();
cancel = output<void>();
}
```

## Benefits

### Testability
- **Presentational components**: Easier to test (no mock store needed, pure input/output testing)
- **Container components**: Clear boundaries (test store interactions separately)
- **Feature stores**: Isolated testing of domain logic separate from UI

### Reusability
- **Presentational components**: Can be reused in different contexts without store coupling
- **Feature stores**: Domain logic can be shared across multiple components
- **Clear interfaces**: Well-defined @Input/@Output contracts

### Maintainability
- **Clear separation of concerns**: Smart containers vs presentational components vs feature stores
- **Localized changes**:
- Global store changes affect only global state consumers
- Feature store changes affect only feature-specific components
- Presentational component changes are isolated
- **Easier refactoring**: Components can be converted between patterns as needs evolve

## State Management Architecture

### UVEStore State Structure

The UVEStore uses a **nested state structure** to clearly separate concerns:

```typescript
interface UVEState {
// ============ DOMAIN STATE (Source of Truth) ============
languages: DotLanguage[];
isEnterprise: boolean;
currentUser?: CurrentUser;
experiment?: DotExperiment;
pageAPIResponse?: DotCMSPageAsset;

// ============ UI STATE (Transient) ============
// Nested editor state
editor: {
// Functional editor state
dragItem: EmaDragItem | null;
bounds: Container[];
state: EDITOR_STATE;
activeContentlet: ContentletPayload | null;
contentArea: ContentletArea | null;

// UI panel preferences (user-configurable)
panels: {
palette: { open: boolean };
rightSidebar: { open: boolean };
};

// Editor-specific data
ogTags: any | null;
styleSchemas: StyleEditorFormSchema[];
};

// Nested toolbar state
toolbar: {
device: DotDeviceListItem | null;
orientation: Orientation | null;
socialMedia: string | null;
isEditState: boolean;
isPreviewModeActive: boolean;
ogTagsResults: SeoMetaTagsResult[] | null;
};
}
```

### Accessing Nested State in Components

**Container components** access nested state directly:

```typescript
// Access editor functional state
const dragItem = this.uveStore.editor().dragItem;
const editorState = this.uveStore.editor().state;

// Access panel preferences
const isPaletteOpen = this.uveStore.editor().panels.palette.open;
const isSidebarOpen = this.uveStore.editor().panels.rightSidebar.open;

// Access toolbar state
const device = this.uveStore.toolbar().device;
const socialMedia = this.uveStore.toolbar().socialMedia;
```

**Updating nested state** requires spreading the parent object:

```typescript
// Update panel state
setPaletteOpen(open: boolean) {
const editor = store.editor();
patchState(store, {
editor: {
...editor,
panels: {
...editor.panels,
palette: { open }
}
}
});
}
```

### Benefits of Nested State

- **Clear Grouping**: Related state is grouped together (editor.panels groups all panel preferences)
- **Easier to Reason About**: The structure mirrors the UI hierarchy
- **Better Type Safety**: TypeScript can catch errors at deeper levels
- **Reduced Prop Drilling**: Components get logical state chunks instead of individual properties

## Running Tests

Run unit tests for this portlet:
```bash
nx test portlets-dot-uve-portlet
```

Run specific test file:
```bash
nx test portlets-dot-uve-portlet --testFile=path/to/test.spec.ts
```

## Development

This library uses:
- **Angular 19+** with standalone components
- **NgRx Signals** for state management
- **Modern Angular syntax**: `@if`, `@for`, `input()`, `output()`
- **PrimeNG** for UI components
- **Jest + Spectator** for testing
Loading
Loading