Skip to content

refactor(ui): redesign the shared key/value field across its three consumers (#37191) - #37284

Draft
adrianjm-dotCMS wants to merge 1 commit into
mainfrom
issue-37191-key-value-field-redesign
Draft

refactor(ui): redesign the shared key/value field across its three consumers (#37191)#37284
adrianjm-dotCMS wants to merge 1 commit into
mainfrom
issue-37191-key-value-field-redesign

Conversation

@adrianjm-dotCMS

Copy link
Copy Markdown
Member

Fixes #37191

Proposed Changes

Reworks the one shared Key/Value editor in libs/ui to the new design and rolls it out to all three
of its consumers — the Edit Content field, the Content Type Field Variables tab, and the
Apps custom-properties panel — so they finally look and behave the same.

Built from stock PrimeNG 21. No new component enters the workspace; the net component count for
this feature is zero.

What changed for the user

  • Values render as plain text at rest and become an input when activated — Enter commits, Escape restores.
  • Row actions (drag handle, remove) are revealed on hover instead of competing for attention on every row.
  • Hidden values move from a toggle switch in its own column to an eye inside the value field. It is a button in both states, so hiding a value is reversible — previously it was a one-way trip.
  • The hidden indicator is never hover-gated: which values are secret has to be readable at a glance.
  • Empty state gains an icon and reuses the existing copy, which already matched the design.
  • Reordering is offered in all three consumers rather than only one.

Three findings worth a reviewer's attention

  • The missing table styling was a selector problem, not a CSS one. PrimeNG themes its table with direct-child combinators (.p-datatable-tbody > tr > td). The row components used element selectors with display: contents, so the component element sat between the tbody and the tr and no table style from the theme ever applied — no borders, no header band. They now attach by attribute selector (tr[dotKeyValueTableRow]), making the host the tr itself.
  • onRowReorder must not re-apply the move. PrimeNG's onRowDrop already calls reorderArray on the array bound to [value]. Recomputing from dragIndex/dropIndex applies it twice. The handler only re-publishes the array with a fresh reference so the signal notifies.
  • Hover-hidden actions use opacity-0, never display:none or an @if. Those remove the control from the tab order and strand keyboard and touch users with no visible symptom for anyone on a mouse. A test asserts the mechanism, not merely that the icon is invisible.

Removed along the way

  • DotKeyValueUtil — 87 lines nothing imported.
  • A stale [autoFocus] binding in the Apps template, plus the spec stub that made it look real. It compiled only because strictTemplates is off in that app.
  • A duplicated copy of the row template that the tests were asserting against instead of the real one.
  • The dragAndDrop input, once reordering became universal and it had nothing left to gate.
  • Both SCSS files — styling is Tailwind against PrimeNG theme tokens, so no colour is hardcoded.

Checklist

  • Tests
  • Translations — none needed; the design's copy already existed as keyValue.value_no_rows.label
  • Security Implications Contemplated — value masking is a UI concern only, not a security boundary. It keeps a secret off a shoulder-surfer's screen; the underlying value is transmitted exactly as before. Stated in the spec so nobody mistakes it for protection.

Additional Info

Tests: 61 in libs/ui (from 31), 24 in edit-content, 70 in dotcms-ui, plus Playwright smokes for each consumer. Lint and build clean.

Not yet run: the Playwright specs have a clean typecheck but have not been executed, and the manual keyboard-only pass is still pending. Flagging it rather than implying green.

Scope: frontend only. Order persistence for Field Variables and Apps was scoped out of this issue — it would mean database, REST and encrypted-storage work.

spec.md, data-model.md and contracts/ are included as the reviewed contract; the Spec-Kit process artifacts are gitignored by design.

Screenshots

Original Updated
** original screenshot ** ** updated screenshot **

🤖 Generated with Claude Code

…nsumers (#37191)

Rework the one shared Key/Value editor in `libs/ui` to the new design and roll it
out to all three of its consumers: the Edit Content field, the Content Type Field
Variables tab, and the Apps custom-properties panel.

The redesign is assembled from stock PrimeNG 21 — no new component enters the
workspace, and the net component count for the feature is zero.

What changed for the user:

- Values render as plain text at rest and become an input when activated; Enter
  commits, Escape restores.
- Row actions (drag handle, remove) are revealed on hover instead of competing for
  attention on every row.
- Hidden values move from a toggle switch in its own column to an eye inside the
  value field. It is a button in both states, so hiding a value is reversible.
- The hidden indicator is never hover-gated: which values are secret has to be
  readable at a glance.
- Empty state gains an icon and reuses the existing `keyValue.value_no_rows.label`
  copy, which already matched the design.
- Reordering is offered in all three consumers rather than only one.

Implementation notes worth knowing:

- The row components attach by attribute selector (`tr[dotKeyValueTableRow]`), so
  their host IS the `tr`. PrimeNG themes its table with direct-child combinators
  (`.p-datatable-tbody > tr > td`), and an element wrapper between the tbody and
  the tr silently defeats every table style the theme provides. This is why the
  previous markup rendered with no borders or header band.
- `onRowReorder` must not re-apply the move: PrimeNG's `onRowDrop` already calls
  `reorderArray` on the array bound to `[value]`. The handler only re-publishes it
  with a fresh reference so the signal notifies.
- Hover-hidden actions use `opacity-0`, never `display:none` or an `@if` — those
  remove the control from the tab order and strand keyboard and touch users. A
  test asserts the mechanism, not merely that the icon is invisible.

Also removed along the way: `DotKeyValueUtil` (87 lines nothing imported), a stale
`[autoFocus]` binding in the Apps template together with the spec stub that made it
look real, a duplicated copy of the row template that tests were asserting against
instead of the real one, the now-unused `dragAndDrop` input, and both SCSS files.

Icons follow the repo standard (Material Symbols); PrimeIcons are gone from this
component's authored markup. No new i18n key was needed.

Tests: 61 in `libs/ui` (from 31), 24 in `edit-content`, 70 in `dotcms-ui`, plus
Playwright smokes for each consumer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Claude finished @adrianjm-dotCMS's task in 1m 35s —— View job


SDK Compatibility Analysis

  • Read docs/core/SDK_BREAKING_CHANGE_CATEGORIES.md
  • Get full PR diff (ecefa983f5a9222c86d7917a7293321c2e648a89^..ecefa983f5a9222c86d7917a7293321c2e648a89, matches the 24 files / +2114 -1014 in this PR)
  • Check diff against every SDK breaking-change category

Result: No SDK breaking changes detected.

This PR is scoped entirely to the shared Key/Value editor in core-web/libs/ui and its three admin-UI consumers:

  • apps/dotcms-ui (Apps custom-properties panel, Content Type Field Variables tab)
  • libs/edit-content (Edit Content key-value field)
  • e2e/spec test files under dotcms-ui-e2e, edit-content, and dotcms-ui
  • specs/37191-key-value-field-redesign/* (Spec-Kit artifacts, markdown only)

None of the changed files touch any SDK-relevant surface:

  • No GraphQL schema/query changes (page-api.ts, buildPageQuery/buildQuery, graphql.page/graphql.content) — not present in the diff.
  • No REST response shape changes to /api/v1/nav, /api/v1/content, or /api/v1/page/*.
  • No UVE/editor postMessage protocol changes (__DOTCMS_UVE_EVENT__, DotCMSUVEAction, events.ts) — not present in the diff.
  • No changes to SdkVersionWebInterceptor, X-DotCMS-Version/X-DotCMS-Min-SDK headers, or compareVersions()/sdk-compatibility.ts.

A grep across the full non-test diff for graphql, postMessage, __DOTCMS_UVE_EVENT__, DotCMSUVEAction, the version headers, and the REST paths above returned no matches — confirming this is a pure admin-UI (dotcms-ui) refactor with no wire-format impact.

No comment or label added per the SDK-compatibility check instructions (no breaking change found).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Refactor shared Key/Value field to new design across edit content, field variables, and apps portlet

1 participant