Skip to content

feat(uve): auto-create page language version on language switch (#36348)#36358

Draft
zJaaal wants to merge 3 commits into
mainfrom
issue-36348-spike-uve-auto-create-language-version
Draft

feat(uve): auto-create page language version on language switch (#36348)#36358
zJaaal wants to merge 3 commits into
mainfrom
issue-36348-spike-uve-auto-create-language-version

Conversation

@zJaaal

@zJaaal zJaaal commented Jun 29, 2026

Copy link
Copy Markdown
Member

Proposed Changes

Draft / spike (#36348). Prototype that replaces the "Create new language version?" confirmation dialog + legacy edit-contentlet iframe with a programmatic auto-create on language switch. Opened as a draft to demonstrate the behavior and inform the decision — see the trade-offs and the open detail-page gap below before considering this for merge.

What changed

  • On switching to an untranslated language, the editor now:
    1. Fetches the page's actual content type (DotContentTypeService.getContentType) and builds the new-version payload from its real field definitions (no hard-coded field allow/deny list).
    2. Copies each defined field's value from the source page, preserves identifier (new language version of the same content), overrides languageId, and sets indexPolicy=WAIT_FOR.
    3. Fires a workflow NEW action via DotWorkflowActionsFireService.newContentlet(...).
    4. Shows a success toast — "A new page version was created in {language}" — then re-renders via uveStore.pageLoad({ language_id }).
  • Both triggers route through the same path: the toolbar onLanguageSelected and the editor $translatePageEffect (deep-link / direct-load guard).
  • Removed the now-unused confirmation-dialog createNewTranslation in both the toolbar and the editor.

Files

  • edit-ema-editor.component.tstranslatePage#autoCreateTranslation (content-type fetch + fire + toast + reload) and #buildTranslationData.
  • dot-uve-toolbar.component.ts — emit translatePage directly instead of prompting; removed createNewTranslation.
  • Language.properties — new key editpage.language-change-missing-lang-populate.success.

Spike findings

  1. Feasible for normal pages. The workflow NEW action with the same identifier + new languageId creates the language version, and pageLoad re-renders it.
  2. It removes two things users rely on: the opt-in / Cancel (language switch becomes a silent write), and the edit-at-creation moment (no form to set per-language SEO/meta). The toast restores awareness but not the edit step.
  3. URL-content-map (detail) pages are broken end-to-end — pre-existing, not caused by this change. Tracked in UVE language switch on detail pages checks/translates the page, not the urlContentMap content #36355. This PR does not handle detail pages: detection still uses the page's languages (not the content's), and the action translates the page, not the urlContentMap content.

Recommendation

Keep the confirmation dialog as a guardrail rather than removing the friction product-wide for a single customer; the complaint is a UX/education issue (creating the version already works). If we do reduce friction, prefer an informative, cancellable pre-filled dialog over a silent write. Prioritize #36355 as the higher-impact bug. Capture the decision in an ADR.

Testing

  • Switch a normal page to an untranslated language → version is created, toast shows, editor re-renders in the new language.
  • Verify the fire payload matches what the backend expects for a same-identifier translation (core unknown from the spike).
  • Note: two existing specs assert the old dialog path (dialog.translatePage / confirm-then-emit) and will fail until updated — intentionally left for the spike branch.

Related: spike #36348 · original #35647 · detail-page defect #36355

🤖 Generated with Claude Code

zJaaal and others added 2 commits June 29, 2026 12:28
The Upload-button flow silently dropped the file in Chrome: onFileChange read
input.files (a live FileList) but reset input.value='' BEFORE the guard, which
empties that same live FileList, so files.length was 0 and the upload no-oped.
Consume the files (capture the File into FormData via resolveFilesUpload) before
resetting the input. Adds a regression test (verified red on the old ordering,
green on the fix) that models the live-FileList behavior jsdom doesn't reproduce.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the confirmation dialog + legacy edit-contentlet iframe with a
programmatic flow: on switching to an untranslated language, fetch the
page's content type, build the new-version payload from its actual field
definitions, fire a workflow NEW action to create the version in the
target language, show a success toast, and reload via pageLoad.

Both triggers (toolbar onLanguageSelected and the editor
$translatePageEffect) route through the same path.

Spike #36348. Does NOT handle URL-content-map detail pages — see #36355.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🤖 dotBot Review (Bedrock)

Reviewed 3 file(s); 2 candidate(s) → 2 confirmed, 0 uncertain (unverified, kept for review).

Confirmed findings

  • 🟠 High core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/components/dot-uve-toolbar/dot-uve-toolbar.component.ts:303 — Missing error handling after translatePage emission leaves language selector in inconsistent state
    The code emits translatePage but doesn't handle errors or reset the language selector on failure. When autoCreateTranslation fails (caught in editor component's error handler), the toolbar's language selector remains set to the new language while the page stays in original language. The removed dialog's rejection callback previously handled this reset, but current implementation lacks equivalent safety.
  • 🟠 High core-web/libs/portlets/edit-ema/portlet/src/lib/edit-ema-editor/edit-ema-editor.component.ts:1770 — Array field values corrupted during translation
    The code uses typeof value === 'object' which includes arrays, then spreads them as objects via Object.keys().forEach(), converting arrays to {0:...,1:...} objects. This corrupts multi-select/tag fields that require array values.

us.deepseek.r1-v1:0 · Run: #28396001519 · tokens: in: 18266 · out: 3423 · total: 21689 · calls: 7 · est. ~$0.043

@claude

claude Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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


Rollback Safety Analysis

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

Verdict: ✅ Safe To Rollback

After analyzing the full diff against all rollback-unsafe categories in docs/core/ROLLBACK_UNSAFE_CATEGORIES.md, none of the unsafe categories apply to this PR.

Analysis

The changes in this PR are entirely frontend/UI in scope:

File Change Rollback Risk?
dot-uve-toolbar.component.ts Removed confirmation dialog; emit translatePage directly No — UI behavior change only
edit-ema-editor.component.ts Replaced dialog-based createNewTranslation with programmatic #autoCreateTranslation using existing workflow API No — calls existing backend endpoints; no schema changes
Language.properties Added one new i18n key (editpage.language-change-missing-lang-populate.success) No — additive, N-1 simply won't display this key

Categories checked and cleared:

  • C-1 Structural Data Model Change — No DB schema changes of any kind
  • C-2 ES Mapping Change — No Elasticsearch mapping modifications
  • C-3 JSON Serialization Version Bump — No CURRENT_MODEL_VERSION or contentlet_as_json changes
  • C-4 DROP TABLE/COLUMN — No DDL statements
  • H-1 One-Way Data Migration — No data transformation tasks
  • H-2 RENAME TABLE/COLUMN — No renames
  • H-3 PK Restructuring — No constraint changes
  • H-4 New Field Type — No new FieldTypeAPI registrations
  • H-5 Storage Provider Change — No storage configuration changes
  • H-6 DROP PROCEDURE/FUNCTION — No stored procedure changes
  • H-7 NOT NULL Without Default — No DDL
  • H-8 VTL Viewtool Contract Change — No viewtool modifications
  • M-1 through M-4 — No REST contract changes, no push publishing bundle format changes, no OSGi interface changes

The PR invokes the existing DotWorkflowActionsFireService.newContentlet and DotContentTypeService.getContentType REST endpoints — no new backend endpoints are introduced or modified. Rolling back this PR simply restores the confirmation dialog UX; no data written by N would be unreadable by N-1.

The label AI: Safe To Rollback has been applied to this PR.

@github-actions github-actions Bot added the Area : Frontend PR changes Angular/TypeScript frontend code label Jun 29, 2026

if (!languageHasTranslation) {
// Show confirmation dialog to create a new translation
// Emit to the shell, which creates the language version and reloads.

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.

🟠 [High] Automatic language version creation removes user consent mechanism

The removal of the confirmation dialog (createNewTranslation) enables silent content creation on language switch. The code now directly calls translatePage without user confirmation, as shown by the removed dialog service call and conditional workflow. This violates user expectations for destructive actions by removing cancellation capability.

const data: Record<string, string> = {};

(contentType.fields ?? []).forEach((field) => {
const key = field.variable;

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.

🟠 [High] String conversion of all field values corrupts non-string data types

The code uses String() to convert all field values when building translation data, which will improperly serialize non-string types (numbers, booleans, dates) into string representations. This violates content type field definitions and will corrupt data integrity for non-string fields in translated pages.

const source = page as unknown as Record<string, unknown>;
const data: Record<string, string> = {};

(contentType.fields ?? []).forEach((field) => {

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.

🟠 [High] Skipping object-type fields creates incomplete translations

The code explicitly skips fields with fieldType === 'object' when building translation data (line 1759), resulting in missing data for all object-type fields during language version creation. This includes valid JSON field data that should be preserved across translations.

// Show confirmation dialog to create a new translation
// Emit to the shell, which creates the language version and reloads.
const page = this.#store.pageAsset()?.page;
if (page) {

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.

🟠 [High] Missing error handling after translatePage emission leaves language selector in inconsistent state

The code emits translatePage but doesn't handle errors or reset the language selector on failure. When autoCreateTranslation fails (caught in editor component's error handler), the toolbar's language selector remains set to the new language while the page stays in original language. The removed dialog's rejection callback previously handled this reset, but current implementation lacks equivalent safety.


// Only copy primitive field values that exist on the source page.
if (value === null || value === undefined || typeof value === 'object') {
return;

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.

🟠 [High] Array field values corrupted during translation

The code uses typeof value === 'object' which includes arrays, then spreads them as objects via Object.keys().forEach(), converting arrays to {0:...,1:...} objects. This corrupts multi-select/tag fields that require array values.

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.

Spike: prototype auto-creating a page language version on language switch in UVE

1 participant