Skip to content

feat(edit-content): edit VTL files in a Monaco side panel - #37966

Open
fmontes wants to merge 5 commits into
issue-37965-side-panel-helpersfrom
issue-37965-ease-edit-code
Open

fmontes wants to merge 5 commits into
issue-37965-side-panel-helpersfrom
issue-37965-ease-edit-code

Conversation

@fmontes

@fmontes fmontes commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Proposed Changes

  • Content Drive: "Edit Source" in a .vtl file's row menu (right-click or ⋮) opens its source in Monaco, in a side panel.
  • Page editor: choosing a file from a contentlet's VTL menu opens it in the same panel instead of Edit Content.
  • One rule for both, checked before opening: toSourceEditorRequest (edit-content/src/lib/utils/source-editor.util.ts) opens a file when the panel handles its type and the user can lock it. The server's canLock answer means edit permission and no one else's lock, the two things a save needs. Anything else goes where it went before: Content Drive doesn't offer the entry, and the page editor opens Edit Content.
  • The panel (DotSourceEditorSidePanelComponent, in @dotcms/edit-content) opens on the code, using the shared Velocity grammar (refactor(ui): one Velocity grammar for every Monaco editor (#37965) #37969) and the shared side-panel behaviour (refactor(edit-content): share side-panel behaviour across panels (#37965) #37970). Save (button or Cmd/Ctrl + S) writes a new working version without publishing, then closes the panel. Closing with unsaved changes asks first, and a failed save keeps the panel open with the edits.
  • Page editor hover actions, reordered and relabelled (the toolbar and its collapsed menu): Edit (was Quick Edit), Styles (was Edit Styles), Full Editor (was Edit), Code (was Edit VTL), then Remove.
  • Save by identifier: DotWorkflowActionsFireService.saveContentletByIdentifier(data, language) fires the default Save action for a given identifier and language, the Save twin of publishContentletByIdentifier.

Checklist

  • Tests
  • Translations
  • Security Implications Contemplated (add notes if applicable)

Additional Info

  • Third of three stacked PRs for Ease edit code #37965, based on refactor(edit-content): share side-panel behaviour across panels (#37965) #37970.
  • Scope: starts with .vtl. Each other code file type (css, js, html, json…) is one entry in SOURCE_EDITOR_LANGUAGES.
  • Security: no new endpoints. Loading uses GET /api/v1/content/{inode} and the version's own file URL; saving stages a temp file (POST /api/v1/temp) and fires the default Save action, so the server enforces permissions and locks.
  • Known gap: a save overwrites a newer version someone else saved after the file was opened, as the other dotCMS editors do. Tracked in Edit Source: warn before overwriting a file changed since it was opened #37968.
  • Escape: Escape inside the editor stays with Monaco, as in any IDE; Escape elsewhere in the panel closes it.
  • Manual check on a local instance: in Content Drive, opened a .vtl, edited it and saved with Cmd + S (a new unpublished working version, file name kept, and the panel closed); the unsaved-changes prompt and Discard worked. In the page editor, opened banner.vtl from the Banner's VTL menu, with the lock check made before opening.

Fixes #37965

🤖 Generated with Claude Code

@github-actions github-actions Bot mentioned this pull request Oct 9, 2026
3 tasks
@github-actions github-actions Bot added the Area : Frontend PR changes Angular/TypeScript frontend code label Oct 9, 2026
@claude

claude Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @fmontes's task in 3m 43s —— View job


Code Review

Reviewed the diff against origin/issue-37965-side-panel-helpers. The feature is well-structured and unusually well-tested; toSourceEditorRequest as the single open/permission rule shared by both openers is a clean design. A few things worth looking at, none blocking.

New Issues

  • 🟡 Medium: dot-content-drive-shell.component.ts (source editor wiring) — The Edit Source panel is not wired into the browser-Back / route-away guard, unlike the Edit Content panel. The source panel has no URL param, so the #location.subscribe handler returns early at if (!location) return; ($panelLocation() is null for it), and #activePanel() only returns $legacyPanel() ?? $sidePanel() — never the source panel. canLeaveRoute() guards only in-flight uploads. Net effect: with unsaved source edits, pressing browser Back (or any route navigation) tears the panel down without the unsaved-changes prompt, silently losing edits. The panel's own close paths (X, Cancel, Escape, mask) do prompt correctly — it's only history/route navigation that bypasses it. The same applies in UVE, where $sourceEditorPanel is a plain signal and UVE's canDeactivate force-saves the page, not the source editor. If deep-linking is intentionally out of scope, consider at least routing Back through requestClose(). Fix this →

  • 🟡 Medium: dot-source-editor.service.ts:88-92 — save() reads tempFiles[0].id with no check that the temp upload returned a file. If POST /api/v1/temp resolves with an empty tempFiles array, this throws a TypeError (not an HttpErrorResponse), so the panel's #reportServerError falls through to console.error with no user-facing message — the author sees the Save button re-enable and nothing else. Low likelihood (the endpoint normally returns the file or errors), but worth a guard that surfaces a real error. Fix this →

  • 🟡 Medium: dot-source-editor-side-panel.component.ts:122-127 — $editorOptions is a computed that flips readOnly on every $status change, and the whole options object is re-passed to <ngx-monaco-editor [options]>. Assumption: @materia-ui/ngx-monaco-editor re-initializes the editor when the options reference changes (couldn't verify — node_modules isn't installed here). What to verify: that toggling readOnly via $editorOptions during save doesn't dispose/recreate the Monaco model. If it does, a failed save (LOADED→SAVING→LOADED) recreates the editor twice; [ngModel] preserves the text but cursor position, scroll, and undo history reset, and onEditorInit re-fires focus(). On a successful save the panel closes, so no visible impact there. If the lib does recreate, prefer setting readOnly imperatively on the editor instance over driving it through the options object.

Notes (non-blocking, not counted as findings)

  • data-testId (capital I) on the component tags in both dot-content-drive-shell.component.html and edit-ema-editor.component.html vs the repo convention data-testid. The component's own drawer pt.root already uses lowercase data-testid, so there end up being two differently-cased attributes.

The reorder/relabel of the UVE contentlet-tools menu correctly drops the old vtlSubmenu?.length optional-chain for vtlSubmenu.length — safe, since vtlMenuItems() is typed MenuItem[] and returns [] rather than undefined. The handleEditVTL forkJoin + nested canLock catchError(() => of(null)) fallback chain is correct.
· issue-37965-ease-edit-code

Content Drive offers Edit Source on a .vtl File Asset's row menu, and the page editor opens a contentlet's VTL file in the same panel instead of Edit Content. Both decide with toSourceEditorRequest: a file type the panel handles, and a lock the user can take (edit permission and no one else's lock); anything else goes where it went before.

The panel lives in @dotcms/edit-content, uses the shared side-panel chrome and Velocity grammar, saves a new working version through the default Save action (button or Cmd/Ctrl + S), and keeps the edits when a save fails. DotWorkflowActionsFireService gains saveContentletByIdentifier.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fmontes
fmontes force-pushed the issue-37965-ease-edit-code branch from 0af26c3 to e352630 Compare October 9, 2026 16:59
@fmontes
fmontes changed the base branch from main to issue-37965-side-panel-helpers October 9, 2026 16:59
@fmontes
fmontes added this pull request to stack #37971 October 9, 2026 16:59
fmontes and others added 4 commits October 9, 2026 11:24
Save (button or Cmd/Ctrl + S) now saves and closes the drawer. A failed save still keeps the panel open with the edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
)

The hover toolbar and its collapsed menu now read Edit (was Quick Edit), Styles (was Edit Styles), Full Edit (was Edit), Edit Code (was Edit VTL), then Remove. Edit Code moves from first to after Full Edit, in both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

Ease edit code

1 participant