Skip to content

fix(edit-content): refine relationship field UI to match Content Drive#36377

Open
oidacra wants to merge 6 commits into
mainfrom
issue-36155-relationship-field-ui-refinements
Open

fix(edit-content): refine relationship field UI to match Content Drive#36377
oidacra wants to merge 6 commits into
mainfrom
issue-36155-relationship-field-ui-refinements

Conversation

@oidacra

@oidacra oidacra commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

Refines the Relationship field UI in the new Edit Contentlet so it aligns with the Content Drive look-and-feel and with the rest of the form fields. Frontend-only (plus one i18n string change); no backend or API contract changes.

CleanShot 2026-07-02 at 10 21 05@2x

Changes

  • Locales column: renamed the "Languages" column to "Locales" and each value now renders as a chip (p-tag with whitespace-nowrap) instead of plain text.
  • Status chips: the field already uses the shared dot-contentlet-status-badge (same STATUS_SEVERITY colors as Content Drive — verified, no color change needed). The Status column header is now left-aligned to the leading edge of its chips.
  • Hint placement: the field hint/error now renders outside the card via dot-card-field-footer, matching every other field wrapper; removed from the table's summary template.
  • Empty state: new message "No related content yet. Relate content or click the + button." where "Relate content" is an inline link that opens the same flow as the + button. The link (and its suffix) are hidden when the field is read-only.
  • showFields: the table scrolls horizontally so extra showFields columns are not clipped or collapsed.

Acceptance Criteria

  • Status chips use the same colors per status as Content Drive
  • Status column header aligned to the leading edge of its chips
  • "Languages" column renamed to "Locales"
  • Each locale value renders as a chip/tag (not plain text)
  • Field hint rendered outside the card, consistent with other fields
  • No hint text inside the card/table container
  • Empty state shows the new message with a clickable "Relate content" link
  • The link opens the same relate-content flow as the + button
  • The link is hidden when the field is read-only
  • With extra showFields columns there is no clipping; the table scrolls horizontally
  • Chips/tags still render correctly with extra columns
  • Existing behavior (add/remove related, label, validation, CVA contract) unaffected

Test plan

  • pnpm nx lint edit-content — passes (no new errors)
  • pnpm nx test edit-content — passes (102 suites, 1877 tests)
  • New spec for the inner dot-relationship-field component covering: Locales header, locale chip rendering, status header alignment, empty-state message + link click + read-only hiding, horizontal scroll, and the CVA contract.
  • Added footer-hint coverage to the wrapper spec (hint renders in the footer, not inside the table).

Changed files

  • .../dot-relationship-field/dot-relationship-field.component.{html,ts,scss}
  • .../dot-relationship-field/dot-relationship-field.component.spec.ts (new)
  • .../dot-edit-content-relationship-field.component.{html,ts,spec.ts}
  • dotCMS/src/main/webapp/WEB-INF/messages/Language.properties

This PR fixes: #36155

Align the Relationship field in the new Edit Contentlet with the Content
Drive look-and-feel and the rest of the form fields:

- Rename the "Languages" column to "Locales" and render each value as a
  chip (p-tag) instead of plain text
- Reuse the shared status badge (already Content Drive's colors) and
  left-align the Status column header with its chips
- Move the field hint/error outside the card via dot-card-field-footer,
  consistent with the other field wrappers
- Rewrite the empty state with an inline "Relate content" link that opens
  the same flow as the + button; hidden when the field is read-only
- Enable horizontal scrolling so extra showFields columns are not clipped

Adds a spec for the inner dot-relationship-field component and footer-hint
coverage on the wrapper spec.

Closes #36155
@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @oidacra's task in 3m 1s —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🤖 dotBot Review (Bedrock)

Reviewed 11 file(s); 5 candidate(s) → 4 confirmed, 0 uncertain (unverified, kept for review).

Confirmed findings

  • 🟠 High core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/components/dot-relationship-field/dot-relationship-field.component.html:3 — Missing validation feedback in relationship field
    The HTML template for dot-relationship-field.component.html removed the previous hint/error display (likely in a template) but does not implement the dot-card-field-footer component in the card-footer slot. This breaks validation message display as described in the PR's 'Hint placement' changes. The dot-card-field component (line 2) has a card-footer slot that should contain dot-card-field-footer to show hints/errors, but no footer template exists in the current implementation.
  • 🟠 High core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/components/dot-relationship-field/dot-relationship-field.component.spec.ts:145 — Incorrect status header alignment assertion in test
    The test asserts that the status header has 'text-right!' class (right-aligned), but PR description states the status header should be left-aligned to match chips. This creates a false-positive test that validates against the intended UI change. The test should check for left-alignment instead.
  • 🟠 High core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.html:21 — Missing error message for non-required validation failures
    The error message block in dot-edit-content-relationship-field.component.html line 21 uses *ngIf="fieldHasError && isRequired", meaning only required validation errors display messages. Non-required validations (e.g. format, custom rules) will trigger fieldHasError=true but not show error messages, breaking validation feedback for these cases.
  • 🟡 Medium core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/components/dot-relationship-field/dot-relationship-field.component.scss:14 — Deprecated ::ng-deep usage
    The SCSS file uses ::ng-deep which is deprecated. While necessary for styling third-party components, its usage should be noted for future migration. Found in the added code: :host ::ng-deep .p-datatable .p-datatable-thead > tr > th.

us.deepseek.r1-v1:0 · Run: #28606379361 · tokens: in: 56047 · out: 11489 · total: 67536 · calls: 20 · est. ~$0.138

[isRequired]="isRequired" />
</dot-card-field-content>
<dot-card-field-footer>
@if (fieldHasError) {

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] Error message only shows required validation

The error message conditional *ngIf="control?.errors?.required" only displays when the 'required' error is present. Other validation errors (e.g., invalid format, custom validators) will not trigger the error message, leaving users unaware of other issues. Should check for any error with *ngIf="control?.errors" to surface all validation failures.

…ayout

- Do not mark the relationship control as touched on the initial value
  sync, so a required empty field no longer shows its validation error
  on first render (touched now fires only on user-driven changes)
- Constrain the Locales column to a fixed width so it no longer stretches
- Right-align the Status column header and chips

Refs #36155
<dot-card-field-footer>
@if (fieldHasError) {
<div class="error-message">
@if (isRequired) {

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 non-required validation error handling

The validation message only displays for 'required' errors (line 23 condition). Other validation errors (e.g., invalid relationships) will trigger the error state but not show a message, violating validation feedback expectations. The *ngIf should check for any error presence rather than specific error types.

…mplate

Address code-review findings:
- Keep the p-table summary template always registered; make only the
  pagination content conditional (avoids dynamic template create/destroy)
- Add data-testid to the Locales and Status column headers; query tests
  via byTestId and assert alignment with jest-dom toHaveClass
- Use createFakeLanguage instead of a hand-built DotLanguage mock
- Make the CVA contract test behavioral (setDisabledState flips state)
- Cover the footer error branch (required + invalid → error, hint hidden)
- Tailwind v4: focus-visible:outline-none → outline-hidden

Refs #36155
});
});

describe('Status column header alignment', () => {

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] Incorrect Tailwind class in status header alignment test

The test checks for 'text-right!' class which is invalid Tailwind syntax. The correct class for right-aligned text with important modifier is '!text-right'. This test would fail if the component properly uses '!text-right', leading to false negatives in test results.

// error as soon as the form renders.
if (this.#hasSyncedInitialValue) {
this.onTouched();
} else {

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] Incorrect touched state on programmatic value changes

The control is marked as touched on any value change after initial sync via this.control.markAsTouched(), including programmatic updates. This causes validation errors to appear prematurely when values are changed by code rather than user interaction, violating Angular's form control state semantics.

[hasError]="fieldHasError"
[isRequired]="isRequired" />
</dot-card-field-content>
<dot-card-field-footer>

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 non-required error messages in relationship field

The error message block in dot-edit-content-relationship-field.component.html line 20 only displays when isRequired is true. This misses validation errors from other sources (e.g., custom validators), leaving users unaware of non-required validation failures. The condition should check fieldHasError generally, not just required state.

@oidacra oidacra marked this pull request as ready for review July 2, 2026 14:48
@oidacra oidacra self-assigned this Jul 2, 2026
…rename

The default language column header was renamed from "Language" to "Locales";
update the E2E header assertion and comment to match.

Refs #36155
<th scope="col" class="w-32 max-w-32 min-w-32 text-right!">
<th
scope="col"
class="w-32 max-w-32 min-w-32 text-right!"

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] Status column header misaligned due to text-right! class

The Status column header uses 'text-right!' class which forces right alignment, contradicting the requirement to left-align it with the chips. The PR's AC specifies left alignment, and the class should be 'text-left' or removed if default aligns left.

describe('Status column header alignment', () => {
beforeEach(() => setup());

it('should right-align the status header so it lines up with the chips', () => {

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] Invalid Tailwind class in status header alignment test

The test checks for 'text-right!' class, but Tailwind's important modifier uses '!text-right'. This test would fail as the actual class is correctly applied with '!text-right'.

[hasError]="fieldHasError"
[isRequired]="isRequired" />
</dot-card-field-content>
<dot-card-field-footer>

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 validation error messages for non-required errors

The error message block in dot-edit-content-relationship-field.component.html line 20 only checks for 'required' errors using *ngIf="control?.errors?.['required']". This means other validation errors (e.g. custom validators, format errors) will not display their messages to users, leaving them without critical feedback when non-required validations fail. The PR's stated goal of maintaining existing validation behavior is violated as error visibility is reduced.

…t severity

Covers the issue #36155 suggested E2E: after relating content, the Locales
cell renders a p-tag chip (not plain text) and the Status cell renders a
status chip with the correct PrimeNG severity class (Published -> p-tag-success).
Adds localeTag()/statusTag() locators to the relationship-field helper.

Refs #36155
beforeEach(() => setup());

it('should render the Locales header using the table language key', () => {
const localeHeader = spectator.query(byTestId('relationship-locale-header'));

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] Test uses outdated i18n key for Locales column

The test at line 129 references 'dot.file.relationship.field.table.language' which no longer exists in Language.properties. The column was renamed to 'Locales' in the UI but the test wasn't updated to use the new i18n key, causing test failures.

describe('Status column header alignment', () => {
beforeEach(() => setup());

it('should right-align the status header so it lines up with the chips', () => {

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] Status header alignment test expects right-aligned style conflicting with PR's left-alignment requirement

The test at line 146 checks for 'right' text alignment on the Status header column (expect(headerStyles.textAlign).toBe('right')), which directly contradicts the PR's stated requirement to left-align the Status column header. This creates a false-positive test that would pass even if the implementation regressed to right-alignment.

@@ -17,4 +17,21 @@
[hasError]="fieldHasError"
[isRequired]="isRequired" />

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] Error message only handles required validation

The error message template only displays messages for 'required' errors (line 18), leaving other validation errors with empty messages. The [showError] binding correctly triggers visibility on any invalid state, but users see an empty message box for non-required errors.

…s test

The chips spec configures the relationship as ONE_TO_MANY, which renders
multi-select checkboxes in the select-existing-content dialog. The test was
calling selectSingleItem() (radio button), so the p-tableradiobutton locator
never resolved and the test hit the 60s timeout ("Target closed"). Switch to
selectItem() (checkbox), matching every other ONE_TO_MANY test in the suite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATxLthJvmM9tBfKUTCRBwA
@@ -3,10 +3,6 @@
@let data = store.paginatedData();

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 validation feedback in relationship field

The HTML template for dot-relationship-field.component.html removed the previous hint/error display (likely in a

template) but does not implement the dot-card-field-footer component in the card-footer slot. This breaks validation message display as described in the PR's 'Hint placement' changes. The dot-card-field component (line 2) has a card-footer slot that should contain dot-card-field-footer to show hints/errors, but no footer template exists in the current implementation.


describe('Status column header alignment', () => {
beforeEach(() => setup());

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] Incorrect status header alignment assertion in test

The test asserts that the status header has 'text-right!' class (right-aligned), but PR description states the status header should be left-aligned to match chips. This creates a false-positive test that validates against the intended UI change. The test should check for left-alignment instead.

[isRequired]="isRequired" />
</dot-card-field-content>
<dot-card-field-footer>
@if (fieldHasError) {

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 message for non-required validation failures

The error message block in dot-edit-content-relationship-field.component.html line 21 uses *ngIf="fieldHasError && isRequired", meaning only required validation errors display messages. Non-required validations (e.g. format, custom rules) will trigger fieldHasError=true but not show error messages, breaking validation feedback for these cases.

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.

Relationship field UI refinements: Content Drive chip colors, Locales tag column, hint & empty-state, showFields

2 participants