Skip to content

Refactor(UVE): Real-Time Canvas#34173

Open
fmontes wants to merge 229 commits intomainfrom
uve-experiment
Open

Refactor(UVE): Real-Time Canvas#34173
fmontes wants to merge 229 commits intomainfrom
uve-experiment

Conversation

@fmontes
Copy link
Member

@fmontes fmontes commented Dec 26, 2025

Scope

This summary is based on the branch artifacts available locally in this workspace (not live GitHub PR metadata, which is not accessible from this environment). The changes are centered on UVE store state refactoring in edit-ema.

What Changed

The branch refactors the UVE store architecture from a duplicated state model to a single-source-of-truth model.

1. New computed-signal access layer (withPageAsset)

A new store feature was introduced to expose page asset data through computed signals:

  • $page(), $site(), $containers(), $template(), $layout()
  • $viewAs(), $vanityUrl(), $urlContentMap(), $numberContents()
  • $clientResponse()

This centralizes derived state access and reduces direct dependence on internal response structure.

2. State/API renaming for cleaner semantics

Several store properties and methods were renamed to remove GraphQL-specific wording and better describe intent:

  • graphqlRequest -> requestMetadata
  • graphqlResponse -> pageAssetResponse
  • legacyGraphqlResponse -> legacyResponseFormat
  • setGraphqlResponse() -> setPageAssetResponse()
  • setGraphqlResponseOptimistic() -> setPageAssetResponseOptimistic()
  • rollbackGraphqlResponse() -> rollbackPageAssetResponse()
  • $graphqlWithParams -> $requestWithParams
  • $customGraphqlResponse -> $clientResponse

3. Duplication removed from load/save flows

withLoad and withSave were simplified by removing repeated manual extraction/sync of pageAsset sub-properties.

Instead of repeatedly patching multiple top-level fields, flows now rely on updating pageAssetResponse once and reading via computed signals.

4. Consumer updates

Related consumers were updated to use the new API naming and signals, including:

  • Store features (withLayout, etc.)
  • Services (for example, action handling)
  • Components (for example, editor/style-editor integrations)
  • Tests across affected store/features/components

Why This Matters

Architectural improvements

  • Moves from multiple duplicated state fields to one authoritative source.
  • Removes manual synchronization points that could drift out of sync.
  • Makes API naming implementation-agnostic and easier to maintain.
  • Improves type-safety and readability via explicit computed accessors.

Engineering impact

  • Lower maintenance overhead when pageAsset shape changes.
  • Fewer fragile updates across load/save/consumer code paths.
  • Simpler mocking in tests (less setup of duplicated top-level state).

Reported Quantified Outcomes

From branch docs/changelog:

  • Manual sync points eliminated.
  • Duplicate extraction code removed from load/save paths.
  • 10 computed signals added for page-asset-derived data.
  • Store-related test suite reported as passing (with unrelated failures noted in other areas).

Backward Compatibility and Migration

Current compatibility

The branch indicates no immediate breaking changes for consumers because existing patterns are still tolerated during transition.

Recommended direction

Adopt computed-signal usage in new/updated code:

  • Prefer store.$page() over store.page()
  • Prefer store.$site() over store.site()
  • Continue migrating remaining direct property reads progressively

Future cleanup (planned)

Branch docs mention a later cleanup phase to fully remove deprecated direct-property access patterns once migration is complete.

Risk / Attention Points

  • Broad usage of legacy access patterns means migration should remain incremental.
  • Any consumer still directly tied to old names/patterns is a potential regression point if cleanup phase lands.
  • End-to-end validation of editor workflows should continue through migration phases (loading, saving, style editing, rollback flows).

Quick Takeaway

PR #34173 is primarily an internal architecture refactor that modernizes UVE store state handling: one source of truth, cleaner API names, computed signal access, and reduced duplication in critical load/save paths. It is aimed at maintainability, consistency, and safer future evolution rather than introducing large user-facing behavior changes.

Videos

video-general-walkthrough.mov
content-editing.mov
uve-bookmark.mov
new-animation.mov

- Replaced the usage header with a PrimeNG toolbar for better action handling.
- Enhanced loading state with a more structured skeleton layout for site metrics, system configuration, and user activity.
- Updated error handling to use PrimeNG card components for a cleaner presentation.
- Refactored dashboard content layout to utilize flexbox for better responsiveness.
- Adjusted SCSS styles to align with new component structure and improve overall styling consistency.

This update enhances the user experience and maintains a modern design approach.
…yling

- Adjusted skeleton component heights for better visual consistency.
- Added margin utility class to paragraph elements within skeleton templates.
- Enhanced SCSS styles for skeleton display and h3 elements to improve layout and readability.

These changes aim to refine the user interface and enhance the loading experience in the dot-usage-shell component.
- Introduced DotUsageService to fetch usage summary metrics from the backend API.
- Implemented error handling for various HTTP status codes.
- Added unit tests for DotUsageService to validate summary retrieval and error handling.
- Updated dot-usage-shell component to manage loading and error states using signals.
- Refactored component tests to utilize the new service structure.

These changes enhance the functionality and reliability of the dot-usage feature, ensuring accurate data retrieval and user-friendly error messages.
…itioning calculations for zoom functionality
…nused expanded property from node definitions
…d enhance data structure for container information
…nused service injections for improved code clarity
…handling to scroll to corresponding elements in the editor, improving user navigation experience.
…om levels, enhancing the accuracy of element positioning in the editor.
… for tree nodes, allowing users to reorder rows within the layout. Add event handling for node selection and drop validation to improve user interaction and layout management.
…ve function: implement updateRows method for saving reordered layout rows, enhancing layout management and state handling in the editor.
…s and paddings for improved layout, and modify row label to use styleClass for better representation.
…ith validation, integrate form submission handling, and update layout for improved user interaction. Adjust styles for right sidebar and contentlet tools to support new features.
…ing state during submission, and update submit button behavior for improved user experience.
…order component for improved row management, enhancing drag-and-drop functionality and simplifying layout handling.
const site = this.#store.pageAsset()?.site;

return createFavoritePagesURL({
languageId: Number(params?.language_id),
Copy link
Contributor

Choose a reason for hiding this comment

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

fallback to 1 or 0 because Number(undefined) is NaN

Copy link
Contributor

Choose a reason for hiding this comment

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

Or throw an error I think that safer

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we move it to the component decorator and use tailwind

@zJaaal
Copy link
Contributor

zJaaal commented Mar 10, 2026

🤖 Claude review — Tailwind-first: `dot-uve-contentlet-quick-edit`

`dot-uve-contentlet-quick-edit.component.scss` → can be deleted entirely

The whole file is:
```scss
:host {
display: flex;
flex-direction: column;
height: 100%;
}
```
All three rules have Tailwind equivalents. Move to the component decorator's `host` property and drop the file:
```typescript
@component({
selector: 'dot-uve-contentlet-quick-edit',
host: { class: 'flex flex-col h-full' },
templateUrl: '...'
// no styleUrl
})
```


`dot-uve-contentlet-quick-edit.component.html` — PrimeFlex classes & inline style

Three PrimeFlex classes that need replacing:

  • Lines 38 & 67: `flex-column` → `flex-col`
  • Line 92: `justify-content-end` → `justify-end`

Also line 30, the textarea has a `[style]` binding for static values — these can be Tailwind instead:
```html

[style]="{ height: '9.375rem', lineHeight: '1.5' }"

class="h-[9.375rem] leading-normal"
```

@zJaaal
Copy link
Contributor

zJaaal commented Mar 10, 2026

🤖 Claude review — Tailwind-first: `dot-uve-iframe`

`dot-uve-iframe.component.scss` → can be deleted entirely

Current content:
```scss
:host {
display: block;
position: relative;
}

iframe {
border: none;
display: block;
width: 100%;
height: auto;
min-height: 1px;
}
```

Move `:host` to the component `host` property, move iframe styles to the template, delete the file:

```typescript
@component({
selector: 'dot-uve-iframe',
host: { class: 'block relative' },
templateUrl: '...'
// no styleUrl
})
```

```html

<iframe class="block w-full h-auto border-none min-h-px" [style.pointer-events]="pointerEvents()" [style.opacity]="opacity()" ...> \`\`\`

`dot-uve-iframe.component.html` — `[ngStyle]` → individual `[style.X]` bindings

The `[ngStyle]` binding on the iframe (flagged in the earlier Angular patterns comment, resolved here) has a straightforward replacement. `pointerEvents` and `opacity` are dynamic so they can't be static Tailwind classes, but they don't need `NgStyle` either:

```html

[ngStyle]="{ pointerEvents: pointerEvents, opacity: opacity }"

[style.pointer-events]="pointerEvents()"
[style.opacity]="opacity()"
```

Don't forget to remove `NgStyle` from the component's `imports` array once this is done.

@zJaaal
Copy link
Contributor

zJaaal commented Mar 10, 2026

🤖 Claude review — Tailwind-first: `dot-uve-zoom-controls`

`dot-uve-zoom-controls.component.scss` → potentially deletable — worth checking

Current `:host` block:
```scss
:host {
display: flex;
align-items: center;
background-color: $color-palette-gray-200;
border-radius: 1000px;
padding: 0 $spacing-1;
gap: $spacing-0;
}
```

The layout rules are straightforward Tailwind. For the design token ones (`$color-palette-gray-200`, `$spacing-1`, `$spacing-0`) — the design system tokens likely have matching values configured in Tailwind (e.g. `bg-gray-200`, `gap-2`, `px-2`). Worth checking `tailwind.config.js` to confirm — if they match, the `:host` block becomes:

```typescript
host: { class: 'flex items-center bg-gray-200 rounded-full gap-2 px-2' }
```

Same story for the `div` rule — `$color-palette-gray-800` likely maps to a Tailwind color token. If it does, the whole `.scss` file can be deleted:

```html

{{ viewZoomLabel() }}
\`\`\`

If the Tailwind config confirms those mappings, delete the file entirely and move everything to the template + `host` property.

@zJaaal
Copy link
Contributor

zJaaal commented Mar 10, 2026

🤖 Claude review — Tailwind-first: `dot-uve-contentlet-tools`

`dot-uve-contentlet-tools.component.scss` — can't be deleted but needs cleanup

The `.bounds` block with container queries, hover pseudo-classes, and `pointer-events` overrides has to stay in SCSS. But a couple of things can be cleaned up:

  1. `:host { display: block; }` → move to the decorator `host` property and remove from SCSS:
    ```typescript
    host: { class: 'block' }
    ```

  2. `.drag-image` block is dead code — the drag image element was moved to `edit-ema-editor.component.html` (line 274–278 as `#customDragImage`). The `.drag-image` rule in this file no longer has any element to target. Delete the whole block.

  3. `top: 0px` / `bottom: 0px` (inside `.bounds`) — zero values shouldn't have a unit. Change to `top: 0` / `bottom: 0`.

@zJaaal
Copy link
Contributor

zJaaal commented Mar 10, 2026

🤖 Claude review — Tailwind-first: `edit-ema-editor`

This is the big one. The file has animations, container queries, `::ng-deep` PrimeNG overrides, and pseudo-elements that need to stay in SCSS. But a large portion can go.


`:host` block → move to the decorator `host` property

```scss
// ❌ in SCSS
:host {
display: grid;
grid-template-rows: min-content 1fr min-content;
height: 100%;
grid-template-columns: min-content 1fr min-content;
}
```
```typescript
// ✅ in @component
host: {
class: 'grid h-full grid-rows-[min-content_1fr_min-content] grid-cols-[min-content_1fr_min-content]'
}
```


Bare element/component selectors → move to the template

These bare tag selectors are fragile and won't pierce child component encapsulation anyway. Move grid placement directly to the elements:

```scss
// ❌ remove these from SCSS
dot-uve-toolbar { grid-column: 1 / 4; }
dot-ema-page-dropzone { position: absolute; inset: 0; }
dot-ema-device-display { grid-column: 1 / 2; }
dot-results-seo-tool { grid-column: 1 / -1; }
```

```html

<dot-uve-toolbar class="col-[1/4]" ...>
<dot-ema-page-dropzone class="absolute inset-0" ...>
<dot-ema-device-display class="col-[1/2]" ...>
<dot-results-seo-tool class="col-[1/-1]" ...>
```

Same for `.editor-content`, `.canvas-row`, `.canvas-outer`, `.canvas-inner` — all pure layout, all replaceable with Tailwind on their elements. For rules that use design tokens (`$spacing-`, `$color-palette-`), check `tailwind.config.js` — if those tokens are mapped there (they likely are), the Tailwind classes exist and the SCSS rule can be deleted too.


`::ng-deep` inside `.edit-panel-wrapper` is not scoped to `:host` (resolved from earlier Styles comment)

Around lines 100–110 the `::ng-deep` is nested inside `.edit-panel-wrapper` without `:host`, leaking PrimeNG overrides globally. It needs to be:
```scss
:host ::ng-deep {
.edit-panel-wrapper .p-tabpanels { ... }
.edit-panel-wrapper p-tabs { ... }
}
```


Dead code to delete (resolved from earlier Styles comment)

  • `.toggle-palette-placeholder` — not used in the template anymore, delete the block.
  • Line 184: `filter: progid:DXImageTransform.Microsoft.gradient(...)` — IE9 vendor hack, remove it.

`edit-ema-editor.component.html` — PrimeFlex classes (resolved from earlier Styles comment)

  • Line 238: `flex-column justify-content-center align-items-center` → `flex-col justify-center items-center`
  • Line 201 (`p-tabs styleClass`): `flex-column` → `flex-col`

`edit-ema-editor.component.html` — `[ngStyle]` on `p-progressBar`

The four static values on `p-progressBar` don't need `[ngStyle]`:
```html

<p-progressBar [ngStyle]="{ position: 'absolute', top: '0', left: '0', width: '100%' }" [style]="{ height: '6px' }">

<p-progressBar class="absolute top-0 left-0 w-full" [style]="{ height: '6px' }">
```


`edit-ema-editor.component.html` — inline `style` on drag image div

Lines 274–278, the `#customDragImage` div has a static `style` attribute:
```html

style="top: -1000px; left: -1000px; width: fit-content"

class="top-[-1000px] left-[-1000px] w-fit"
```

Also `border-round-lg` and `z-1` on the same element look like PrimeFlex leftovers — replace with `rounded-lg` and `z-[1]`.

rjvelazco and others added 6 commits March 11, 2026 11:57
…test payloads

- Migrate @output() onNodeSelect to output() signal API in dot-uve-palette
- Inject DotMessageService in dot-ema-shell, add $lockedByDisplay computed
  signal, and update template to use i18n fallback for unknown locked-by user
- Add uve.shell.page.locked.unknown.user=Unknown key to Language.properties
- Simplify field.options?.length in dot-uve-contentlet-quick-edit
- Migrate 3x <button pButton> to <p-button> in dot-uve-zoom-controls template
- Update dot-uve-iframe spec to call signal inputs as functions (src() etc.)
- Fix edit-ema-editor spec triggerEventHandler to pass content map directly
  instead of wrapped in { payload }

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ys and fix test providers

- Replace hardcoded tooltip strings in dot-uve-palette with i18n keys
  (uve.palette.tab.content.types, uve.palette.widgets.title,
  uve.palette.favorites.title, uve.palette.tab.layers)
- Add DotMessagePipe to dot-uve-palette imports; update template to pipe
  tooltipKey through `dm` (DotMessagePipe)
- Add uve.palette.tab.content.types and uve.palette.tab.layers entries
  to Language.properties
- Replace MockProvider(..., 'useValue') from ng-mocks with plain
  { provide, useValue } objects in edit-ema-layout spec
- Remove commented-out dead code from withEditor.ts

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
zJaaal and others added 3 commits March 12, 2026 15:37
…ignal

- Replace [ngStyle] with direct [style.*] bindings in dot-uve-iframe
- Remove NgStyle import from dot-uve-iframe component
- Migrate dot-row-reorder tests to data-testid selectors and DOM-event patterns;
  remove eslint-disable comment and private method access
- Document [attr.inert] pattern in quick-edit template
- Simplify $pageURL computed to derive from $pageURLS()[0] (live URL, no hardcoded host)
- Move $pageURLS/$pageURL tests from toolbar spec (wrong file) to editor spec
- Remove stale commented-out $pageURLS block from toolbar spec

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Backend PR changes Java/Maven backend code Area : Documentation PR changes documentation files Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

UVE: Real-Time Canvas

5 participants