diff --git a/core-web/CLAUDE.md b/core-web/CLAUDE.md index 415c27f6ba2a..4a2b1105b544 100644 --- a/core-web/CLAUDE.md +++ b/core-web/CLAUDE.md @@ -83,20 +83,10 @@ spectator.setInput('prop', value); // ALWAYS use setInput ### Form Markup -Always wrap form fields with this structure for consistent styling: - -```html -
-
- - -
-
- - -
-
-``` +See [Form Fields](docs/frontend/STYLING_STANDARDS.md#form-fields) for the current field-layout, +typography, and hint-handling rules — do not hand-roll a form wrapper from memory or copy an +existing form without checking it first. Different areas of the app (e.g. `edit-content`) have +diverged in the past; the doc is the tie-breaker. ## Portlet Development diff --git a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.html b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.html index 17cd78c4f37e..5ac6ee850115 100644 --- a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.html +++ b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.html @@ -1,5 +1,5 @@
- + {{ 'apps.ai.additional-properties.label' | dm }} @@ -10,20 +10,31 @@ + + [ariaLabel]="'apps.ai.additional-properties.remove.aria-label' | dm" + [attr.data-testid]="'remove-property-' + i" + (onClick)="removeProperty(i)"> + + + +
} @@ -32,8 +43,12 @@ + data-testid="add-property" + (onClick)="addProperty()"> + + + + diff --git a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.spec.ts b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.spec.ts new file mode 100644 index 000000000000..b7d76b44c674 --- /dev/null +++ b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-additional-properties/dot-ai-additional-properties.component.spec.ts @@ -0,0 +1,119 @@ +import { byTestId, createComponentFactory, Spectator } from '@openng/spectator/jest'; + +import { FormArray, FormControl, FormGroup } from '@angular/forms'; + +import { DotMessageService } from '@dotcms/data-access'; +import { MockDotMessageService } from '@dotcms/utils-testing'; + +import { + DotAiAdditionalPropertiesComponent, + DotAiAdditionalPropertyGroup +} from './dot-ai-additional-properties.component'; + +describe('DotAiAdditionalPropertiesComponent', () => { + let spectator: Spectator; + let properties: FormArray; + + const createComponent = createComponentFactory({ + component: DotAiAdditionalPropertiesComponent, + providers: [{ provide: DotMessageService, useValue: new MockDotMessageService({}) }] + }); + + function propertyRow(key: string, value: string): DotAiAdditionalPropertyGroup { + return new FormGroup({ + key: new FormControl(key, { nonNullable: true }), + value: new FormControl(value, { nonNullable: true }) + }); + } + + /** + * Rows have to exist before the first render. The component is OnPush and `properties` is a + * signal holding the FormArray, so pushing into that array from outside mutates it without + * changing the signal and without marking the component dirty. In the app the rows arrive the + * same way — hydrated into the array by the parent card before it renders. + */ + function setup(rows: DotAiAdditionalPropertyGroup[] = []): void { + properties = new FormArray(rows); + spectator = createComponent({ props: { properties } }); + } + + /** p-button renders its own ` - } - - - - - @if (visibleFields().length > 0) { -
- @for (field of visibleFields(); track field.name) { - - } +
+ +
+ + {{ 'apps.ai.provider.label' | dm }} + +
+ @for (provider of orderedProviders(); track provider.provider) { + + } +
- } - - -
- @if (advancedFields().length > 0) { -
- @for (field of advancedFields(); track field.name) { + + @if (visibleFields().length > 0) { +
+
+ @for (field of visibleFields(); track field.name) { }
- } - -
- +
+ } -
- + + +
+ @if (advancedFields().length > 0) { +
+
+ @for (field of advancedFields(); track field.name) { + + } +
+
+ } + +
+
- @if (testResult(); as result) { - - - {{ result.message | dm }} - - } +
+ + + @if (testResult(); as result) { + + + {{ result.success ? 'check_circle' : 'error' }} + + {{ result.message | dm }} + + } +
}
diff --git a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-capability-card/dot-ai-capability-card.component.spec.ts b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-capability-card/dot-ai-capability-card.component.spec.ts index 2e29d6e38c31..fdbcfa7ff144 100644 --- a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-capability-card/dot-ai-capability-card.component.spec.ts +++ b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-capability-card/dot-ai-capability-card.component.spec.ts @@ -23,7 +23,7 @@ describe('DotAiCapabilityCardComponent', () => { sectionKey: 'chat', title: 'apps.ai.capability.chat.title', description: 'apps.ai.capability.chat.description', - icon: 'pi pi-comments' + icon: 'forum' }; const openAiProvider: DotAiProviderMetadata = { diff --git a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-dynamic-field/dot-ai-dynamic-field.component.html b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-dynamic-field/dot-ai-dynamic-field.component.html index b203d9e29bd0..4b3f78bcbd32 100644 --- a/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-dynamic-field/dot-ai-dynamic-field.component.html +++ b/core-web/apps/dotcms-ui/src/app/portlets/dot-apps/components/dot-ai-config-detail/components/dot-ai-dynamic-field/dot-ai-dynamic-field.component.html @@ -1,6 +1,6 @@ -
-