Skip to content

fix(sdk): stop leaking UVE edit-mode data-dot-* attributes into live pages (#36095)#36288

Open
zJaaal wants to merge 2 commits into
mainfrom
issue-36095-sdk-strip-data-dot-live-mode
Open

fix(sdk): stop leaking UVE edit-mode data-dot-* attributes into live pages (#36095)#36288
zJaaal wants to merge 2 commits into
mainfrom
issue-36095-sdk-strip-data-dot-live-mode

Conversation

@zJaaal

@zJaaal zJaaal commented Jun 23, 2026

Copy link
Copy Markdown
Member

Proposed Changes

Fixes #36095 — the dotCMS SDKs (React, Angular, JS) shared rendering logic that always emitted the full set of UVE editor metadata onto container and contentlet wrappers, so data-dot-* attributes leaked into live / production output. This bloats public markup and exposes internal identifiers.

Behavior by mode

Edit (UVE) Live + Analytics active Live, no Analytics
Contentlet full editor set + data-dot-object only data-dot-identifier/inode/title/type/basetype + dotcms-contentlet class class only — zero data-dot-*
Container full editor set clean clean

The Analytics carve-out follows Arcadio's heads-up: impression/click tracking needs the content's identifying attributes (and the dotcms-contentlet class) in live mode. Gating is driven by window.__dotAnalyticsActive__, and the SDKs observe the dotcms:analytics:ready event so attributes appear regardless of analytics initialization order. No new customer configuration required.

Implementation

  • @dotcms/uve (shared): getAnalyticsContentletAttributes() (minimal set), isDotAnalyticsActive(), and ANALYTICS_ACTIVE_WINDOW_KEY / ANALYTICS_READY_EVENT constants — kept in sync with @dotcms/analytics.
  • @dotcms/react: Contentlet/Container gate attributes by mode; new useIsAnalyticsActive hook reacts to the ready event.
  • @dotcms/angular: contentlet/container use reactive host bindings; DotCMSStore exposes $isAnalyticsActive derived from the ready event via fromEvent + toSignal (no NgZone juggling; safe on the SDK's min Angular >=17).
  • @dotcms/types: DotAnalyticsContentletAttributes.

Angular

Screen.Recording.2026-06-23.at.1.copy.mp4

NextJS

Screen.Recording.2026-06-23.at.1.mp4

Testing

  • Regression tests across sdk-uve, sdk-react, sdk-angular covering all three modes (edit / live-no-analytics / live-with-analytics) — nx run-many -t test lint green for all four projects.
  • Manually verified the rendered live DOM in the Next.js and Angular example apps (against a local build): no data-dot-* in live mode; the minimal content attributes reappear when analytics activates; full set returns in UVE edit mode.

🤖 Generated with Claude Code

…pages (#36095)

The React, Angular and JS SDKs share rendering logic that always emitted
the full set of UVE editor metadata (data-dot-object, data-dot-identifier,
data-dot-container, data-dot-uuid, etc.) on container and contentlet
wrappers, even when a page is served in live mode. This bloats the public
markup and leaks internal identifiers.

Live mode now strips this metadata:
- Container wrappers emit no data-dot-* attributes outside edit mode.
- Contentlet wrappers emit nothing by default; only when DotCMS Analytics
  is active do they keep the minimal set it needs to identify content
  (data-dot-identifier/inode/title/type/basetype) plus the dotcms-contentlet
  class, per Arcadio's heads-up. The dotcms:analytics:ready event is observed
  so attributes appear regardless of analytics init order.
- Edit mode (UVE) is unchanged and still emits the full attribute set.

Shared helpers (getAnalyticsContentletAttributes, isDotAnalyticsActive) and
constants live in @dotcms/uve so all SDKs stay in sync. Adds regression tests
across uve, react and angular.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries labels Jun 23, 2026
@claude

claude Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @zJaaal's task in 1m 2s —— View job


Rollback Safety Analysis

  • Read rollback-unsafe categories reference
  • Get full PR diff
  • Analyze diff against all unsafe categories
  • Apply appropriate label

Verdict: ✅ Safe to Rollback

All 17 changed files are frontend TypeScript/TSX source files within core-web/libs/sdk/. The changes are purely:

  • Logic changes in Angular/React SDK components (attribute gating by mode)
  • New utility functions (getAnalyticsContentletAttributes, isDotAnalyticsActive) in dom.utils.ts
  • New constants (ANALYTICS_ACTIVE_WINDOW_KEY, ANALYTICS_READY_EVENT) in constants.ts
  • New type (DotAnalyticsContentletAttributes) in types/internal.ts
  • New hook (useIsAnalyticsActive) and updated tests

Categories checked and dismissed:

Category Verdict Reason
C-1 Structural Data Model ✅ Safe No database changes
C-2 ES Mapping ✅ Safe No Elasticsearch code
C-3 JSON Model Version ✅ Safe No contentlet_as_json / CURRENT_MODEL_VERSION changes
C-4 DROP TABLE/COLUMN ✅ Safe No SQL or runonce tasks
H-1 Data Migration ✅ Safe No data transformations
H-2 RENAME TABLE/COLUMN ✅ Safe No SQL renames
H-3 PK Restructuring ✅ Safe No constraint changes
H-4 New ContentType Field ✅ Safe No new field types
H-5 Storage Provider ✅ Safe No binary storage changes
H-6 DROP PROCEDURE/FUNCTION ✅ Safe No stored procedures
H-7 NOT NULL Column ✅ Safe No schema changes
H-8 VTL Viewtool Contract ✅ Safe No Java viewtool changes
M-1 Column Type Change ✅ Safe No SQL
M-2 Push Publishing Bundle ✅ Safe No bundle XML changes
M-3 REST/GraphQL Contract ✅ Safe No REST endpoint changes
M-4 OSGi Interface ✅ Safe No Java/OSGi changes

Rolling back to N-1 simply restores the previous SDK behavior (always-emitting data-dot-* attributes). No database, index, or storage state is modified by this PR.

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🤖 Bedrock Review — deepseek.v3.2

[🟠 High] core-web/libs/sdk/angular/src/lib/components/dotcms-layout-body/components/contentlet/contentlet.component.ts:96 — The getContainerAttribute() method is called in the host binding ('[attr.data-dot-container]': '$isDevMode() ? getContainerAttribute() : null'), but getContainerAttribute is not a signal or observable. This could cause change detection issues because Angular may not re-evaluate the binding when containerData changes. Use a computed signal instead.

[🟡 Medium] core-web/libs/sdk/angular/src/lib/components/dotcms-layout-body/components/contentlet/contentlet.component.ts:79 — The $dotAttributes computed signal returns {} as DotContentletAttributes when !contentlet. However, DotContentletAttributes expects specific required keys (e.g., 'data-dot-identifier'). Returning an empty object cast to this type could lead to runtime errors if something expects those keys. Return a properly typed empty object or adjust the type.

[🟡 Medium] core-web/libs/sdk/angular/src/lib/store/dotcms.store.ts:50 — The $isAnalyticsActive signal uses toSignal with fromEvent. If window is undefined (server-side), it defaults to signal(false). However, the fromEvent import and toSignal are still evaluated on the server, which could cause issues. Ensure the fromEvent import is side-effect safe or use a conditional import pattern.

[🟡 Medium] core-web/libs/sdk/react/src/lib/next/components/Contentlet/Contentlet.tsx:70 — In the dotAttributes memo, when isDevMode is true, the spread includes getDotContentletAttributes(...) and adds 'data-dot-object': 'contentlet'. However, getDotContentletAttributes already returns an object with 'data-dot-object': 'contentlet' (as seen in the Angular implementation). This could cause a duplicate key or override. Verify that getDotContentletAttributes does not already include data-dot-object; if it does, remove the explicit addition to avoid conflicts.

[🟡 Medium] core-web/libs/sdk/react/src/lib/next/components/Container/ContainerFallbacks.tsx:48EmptyContainer now accepts Partial<DotContainerAttributes> instead of DotContainerAttributes. This is a breaking change for any external caller passing the full type. Ensure no existing callers are affected (likely internal only, but review).

[🟡 Medium] core-web/libs/sdk/uve/src/lib/dom/dom.utils.ts:325isDotAnalyticsActive() checks for a window flag ANALYTICS_ACTIVE_WINDOW_KEY. The comment says it's duplicated from @dotcms/analytics. If the constant value changes in the analytics package, this will break. Consider importing the constant from a shared package or adding a synchronization test.

[🟡 Medium] core-web/libs/sdk/uve/src/lib/dom/dom.spec.ts:394 — The test for getAnalyticsContentletAttributes expects 'data-dot-basetype': 'test-base', but the implementation uses contentlet?.baseType (capital 'T'). The mock contentlet uses baseType: 'test-base' (lowercase 't'). This could cause a test failure if the property name doesn't match. Verify the property name in DotCMSBasicContentlet is baseType (capital 'T').

[🟡 Medium] core-web/libs/sdk/angular/src/lib/components/dotcms-layout-body/components/container/container.component.spec.ts:48 — The test uses as unknown as to cast the injected store. This bypasses type safety. Consider using a proper mock type or adjusting the provider to avoid casting.

[🟡 Medium] core-web/libs/sdk/angular/src/lib/components/dotcms-layout-body/components/contentlet/contentlet.component.spec.ts:49 — The test helper hostAttr uses as string | null casting. This is fine, but ensure it doesn't hide actual null returns from getAttribute (which can return null). It's acceptable.

[🟡 Medium] core-web/libs/sdk/react/src/lib/next/__test__/hook/useIsAnalyticsActive.test.tsx:47 — The test spies on window.removeEventListener but doesn't mock it globally. If other tests modify removeEventListener, this could cause interference. Use a jest spy on the specific instance or clean up properly.


Run: #28049574607 · tokens: in: 14198 · out: 1013 · total: 15211

@zJaaal zJaaal requested review from KevinDavilaDotCMS and oidacra and removed request for KevinDavilaDotCMS June 23, 2026 18:55
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 Area : SDK PR changes SDK libraries

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

SDK: UVE edit-mode data-dot-* attributes leak into live pages

1 participant