diff --git a/core-web/apps/dotcms-ui/.storybook/main.js b/core-web/apps/dotcms-ui/.storybook/main.js index 8d8ae7d46183..c1ff1d7aa361 100644 --- a/core-web/apps/dotcms-ui/.storybook/main.js +++ b/core-web/apps/dotcms-ui/.storybook/main.js @@ -13,7 +13,8 @@ module.exports = { '../../../libs/template-builder/**/*.stories.@(js|jsx|ts|tsx|mdx)', '../../../libs/block-editor/**/*.stories.@(js|jsx|ts|tsx|mdx)', '../../../libs/contenttype-fields/**/*.stories.@(js|jsx|ts|tsx|mdx)', - '../../../libs/ui/**/*.stories.@(js|jsx|ts|tsx|mdx)' + '../../../libs/ui/**/*.stories.@(js|jsx|ts|tsx|mdx)', + '../../../libs/portlets/**/*.stories.@(js|jsx|ts|tsx|mdx)' ], addons: ['storybook-design-token', '@storybook/addon-essentials', ...rootMain.addons], features: { diff --git a/core-web/apps/dotcms-ui/.storybook/tsconfig.json b/core-web/apps/dotcms-ui/.storybook/tsconfig.json index 65c1db876c17..e3ced7fe28e7 100644 --- a/core-web/apps/dotcms-ui/.storybook/tsconfig.json +++ b/core-web/apps/dotcms-ui/.storybook/tsconfig.json @@ -9,6 +9,7 @@ "../../../**/template-builder/**/src/lib/**/*.stories.ts", "../../../**/block-editor/**/src/lib/**/*.stories.ts", "../../../**/contenttype-fields/**/src/lib/**/*.stories.ts", - "../../../**/ui/**/src/lib/**/*.stories.ts" + "../../../**/ui/**/src/lib/**/*.stories.ts", + "../../../**/portlets/**/src/lib/**/*.stories.ts" ] } diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.html b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.html index 4f8b65dddb93..d1e29eaee30e 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.html +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.html @@ -3,20 +3,17 @@ [(visible)]="vm.status.isOpen" (onHide)="closeSidebar()" dotSidebar - dotSize="{{ sidebarSizes.LG }}" - > + dotSize="{{ sidebarSizes.LG }}"> + dotTitle="{{ 'experiments.configure.goals.sidebar.header' | dm }}" />
+ novalidate>
@@ -24,22 +21,19 @@ [icon]="goals.BOUNCE_RATE.icon" [value]="goalsTypes.BOUNCE_RATE" detail="{{ goals.BOUNCE_RATE.description | dm }}" - title="{{ goals.BOUNCE_RATE.label | dm }}" - /> + title="{{ goals.BOUNCE_RATE.label | dm }}" /> + title="{{ goals.EXIT_RATE.label | dm }}" /> + title="{{ goals.REACH_PAGE.label | dm }}"> @@ -49,8 +43,7 @@ [icon]="goals.URL_PARAMETER.icon" [value]="goalsTypes.URL_PARAMETER" detail="{{ goals.URL_PARAMETER.description | dm }}" - title="{{ goals.URL_PARAMETER.label | dm }}" - > + title="{{ goals.URL_PARAMETER.label | dm }}"> @@ -66,16 +59,15 @@ [maxlength]="this.maxNameLength + 1" [placeholder]="'experiments.goal.reach_page.form.name.placeholder' | dm" data-testId="goal-name-input" + dotTrimInput formControlName="name" name="name" pInputText required - type="text" - /> + type="text" /> + [field]="goalNameControl">
@@ -92,7 +84,6 @@ data-testId="add-goal-button" label="{{ 'experiments.configure.goals.sidebar.header.button.apply.label' | dm }}" pButton - type="submit" - > + type="submit"> diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.ts b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.ts index 45c493150b59..2d61c745e64b 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.ts +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-goal-select/dot-experiments-configuration-goal-select.component.ts @@ -23,7 +23,7 @@ import { MAX_INPUT_DESCRIPTIVE_LENGTH, StepStatus } from '@dotcms/dotcms-models'; -import { DotAutofocusDirective, DotMessagePipe } from '@dotcms/ui'; +import { DotAutofocusDirective, DotMessagePipe, DotTrimInputDirective } from '@dotcms/ui'; import { DotDropdownDirective } from '@portlets/shared/directives/dot-dropdown.directive'; import { DotSidebarDirective, @@ -59,7 +59,8 @@ import { DotExperimentsConfigurationStore } from '../../store/dot-experiments-co DropdownModule, DotExperimentsGoalConfigurationReachPageComponent, DotExperimentsGoalConfigurationUrlParameterComponentComponent, - DotExperimentsGoalsComingSoonComponent + DotExperimentsGoalsComingSoonComponent, + DotTrimInputDirective ], templateUrl: './dot-experiments-configuration-goal-select.component.html', styleUrls: ['./dot-experiments-configuration-goal-select.component.scss'], diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-variants-add/dot-experiments-configuration-variants-add.component.html b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-variants-add/dot-experiments-configuration-variants-add.component.html index e00566d4dcbc..15b60bbd0394 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-variants-add/dot-experiments-configuration-variants-add.component.html +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-configuration/components/dot-experiments-configuration-variants-add/dot-experiments-configuration-variants-add.component.html @@ -2,8 +2,7 @@ + dotTitle="{{ 'experiments.configure.variants.add' | dm }}">
+ novalidate>
+ type="text" /> + [field]="form.controls.name">
@@ -49,7 +46,6 @@ form="new-variant-form" label="{{ 'experiments.action.add' | dm }}" pButton - type="submit" - > + type="submit"> diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.html b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.html index 618659589ed8..db47a41399e2 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.html +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.html @@ -2,8 +2,7 @@ + dotTitle="{{ 'experiments.create.form.sidebar.header' | dm }}">
+ novalidate>
@@ -48,12 +45,10 @@ name="description" pInputTextarea placeholder="{{ 'experiments.create.form.description.placeholder' | dm }}" - rows="6" - > + rows="6"> + [field]="form.controls.description">
@@ -68,7 +63,6 @@ form="new-experiment-form" label="{{ 'experiments.action.add' | dm }}" pButton - type="submit" - > + type="submit"> diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.ts b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.ts index 97d682acfbaf..a9e99cf07f54 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.ts +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/dot-experiments-list/components/dot-experiments-create/dot-experiments-create.component.ts @@ -11,7 +11,12 @@ import { SidebarModule } from 'primeng/sidebar'; import { DotFieldValidationMessageModule } from '@components/_common/dot-field-validation-message/dot-file-validation-message.module'; import { DotExperiment, MAX_INPUT_TITLE_LENGTH } from '@dotcms/dotcms-models'; -import { DotAutofocusDirective, DotFieldRequiredDirective, DotMessagePipe } from '@dotcms/ui'; +import { + DotAutofocusDirective, + DotFieldRequiredDirective, + DotMessagePipe, + DotTrimInputDirective +} from '@dotcms/ui'; import { DotSidebarDirective } from '@portlets/shared/directives/dot-sidebar.directive'; import { DotSidebarHeaderComponent } from '@shared/dot-sidebar-header/dot-sidebar-header.component'; import { DotValidators } from '@shared/validators/dotValidators'; @@ -44,7 +49,8 @@ interface CreateForm { InputTextModule, SidebarModule, ButtonModule, - DotFieldRequiredDirective + DotFieldRequiredDirective, + DotTrimInputDirective ], templateUrl: './dot-experiments-create.component.html', styleUrls: ['./dot-experiments-create.component.scss'], diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.html b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.html index cc3279f3897b..d883d995b734 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.html +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.html @@ -10,8 +10,7 @@ [class]="inplaceSizes[inputSize].button" data-testId="text-input-button" icon="pi pi-pencil" - pButton - > + pButton>
@@ -31,17 +30,16 @@ (keydown.escape)="deactivateInplace()" data-testId="inplace-input" dotAutofocus + dotTrimInput formControlName="text" - pInputText - /> + pInputText /> + data-testId="variant-inplace-button"> + type="button"> diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.scss b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.scss index bdb70727b9e5..4c9437e14dff 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.scss +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.scss @@ -17,16 +17,14 @@ } &::ng-deep { - .p-disabled, - .p-component { - width: 100%; - + .p-disabled { &:disabled { opacity: 0.8; } } p-inplace .p-inplace { + width: 100%; .p-inplace-display { padding: 0; white-space: pre-wrap; diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.spec.ts b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.spec.ts index 854853bb829c..80d1c36c45ff 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.spec.ts +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.spec.ts @@ -21,7 +21,7 @@ const LONG_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed condimentum eros sit amet malesuada mattis. Morbi ac congue lectus, ut vestibulum velit. Ut sed ornare metus. Proin a orci lacus. Aenean odio lacus, fringilla eu ipsum non, pellentesque sagittis purus. Integer non.'; const NEW_EXPERIMENT_DESCRIPTION = 'new experiment description'; -describe('DotExperimentsExperimentSummaryComponent', () => { +describe('DotExperimentsInlineEditTextComponent', () => { let spectator: Spectator; const createComponent = createComponentFactory({ component: DotExperimentsInlineEditTextComponent, @@ -176,6 +176,17 @@ describe('DotExperimentsExperimentSummaryComponent', () => { expect(deactivate).toHaveBeenCalled(); }); + it('should deactivate the textControl if isLoading input has `currentValue = true` ', () => { + spectator.dispatchMouseEvent(byTestId('text-input'), 'click'); + + const input = spectator.query(byTestId('inplace-input')) as HTMLInputElement; + + expect(input.disabled).toBe(false); + + spectator.setInput('isLoading', true); + expect(input.disabled).toBe(true); + }); + it('should show `dot-field-validation-message` message error by default', () => { spectator.setInput('text', SHORT_TEXT); spectator.setInput('required', true); diff --git a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.ts b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.ts index 0510fa508091..a55eac57f558 100644 --- a/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.ts +++ b/core-web/libs/portlets/dot-experiments/portlet/src/lib/shared/ui/dot-experiments-inline-edit-text/dot-experiments-inline-edit-text.component.ts @@ -23,7 +23,7 @@ import { InputTextModule } from 'primeng/inputtext'; import { DotFieldValidationMessageModule } from '@components/_common/dot-field-validation-message/dot-file-validation-message.module'; import { MAX_INPUT_DESCRIPTIVE_LENGTH } from '@dotcms/dotcms-models'; -import { DotAutofocusDirective, DotMessagePipe } from '@dotcms/ui'; +import { DotAutofocusDirective, DotMessagePipe, DotTrimInputDirective } from '@dotcms/ui'; import { DotValidators } from '@shared/validators/dotValidators'; type InplaceInputSize = 'small' | 'large'; @@ -50,7 +50,8 @@ const InplaceInputSizeMapPrimeNg: Record; + +const Template: Story = ( + args: DotExperimentsInlineEditTextComponent +) => ({ + props: { ...args, textChanged: action('textChanged') } +}); + +export const Default = Template.bind({}); diff --git a/core-web/libs/ui/src/index.ts b/core-web/libs/ui/src/index.ts index 603a72dbadc4..af0778d59de8 100644 --- a/core-web/libs/ui/src/index.ts +++ b/core-web/libs/ui/src/index.ts @@ -12,3 +12,4 @@ export * from './lib/components/dot-empty-container/dot-empty-container.componen export * from './lib/dot-tab-buttons/dot-tab-buttons.component'; export * from './lib/dot-remove-confirm-popup/dot-remove-confirm-popup.directive'; export * from './lib/directives/dot-autofocus/dot-autofocus.directive'; +export * from './lib/directives/dot-trim-input/dot-trim-input.directive'; diff --git a/core-web/libs/ui/src/lib/directives/dot-trim-input/dot-trim-input.directive.spec.ts b/core-web/libs/ui/src/lib/directives/dot-trim-input/dot-trim-input.directive.spec.ts new file mode 100644 index 000000000000..0466ac448ce0 --- /dev/null +++ b/core-web/libs/ui/src/lib/directives/dot-trim-input/dot-trim-input.directive.spec.ts @@ -0,0 +1,43 @@ +import { byTestId, createComponentFactory, Spectator } from '@ngneat/spectator'; + +import { Component } from '@angular/core'; +import { FormsModule, NgControl } from '@angular/forms'; + +import { DotTrimInputDirective } from '@dotcms/ui'; + +const STRING_WITH_SPACES = ' Test Value '; + +@Component({ + template: `` +}) +export class DotTrimInputHostMockComponent { + name = STRING_WITH_SPACES; +} + +describe('DotTrimInputDirective', () => { + let spectator: Spectator; + const createComponent = createComponentFactory({ + component: DotTrimInputHostMockComponent, + imports: [FormsModule, DotTrimInputDirective], + providers: [NgControl] + }); + + beforeEach(() => { + spectator = createComponent(); + }); + + it('should trim the input value on blur', async () => { + const input = spectator.query(byTestId('input-to-trim')) as HTMLInputElement; + const expectedValue = STRING_WITH_SPACES.trim(); + + await spectator.fixture.whenStable(); + + expect(spectator.query(byTestId('input-to-trim'))).toExist(); + expect(input.value).toBe(STRING_WITH_SPACES); + + spectator.dispatchFakeEvent(input, 'blur'); + spectator.detectComponentChanges(); + + expect(input.value).toBe(expectedValue); + }); +}); diff --git a/core-web/libs/ui/src/lib/directives/dot-trim-input/dot-trim-input.directive.ts b/core-web/libs/ui/src/lib/directives/dot-trim-input/dot-trim-input.directive.ts new file mode 100644 index 000000000000..18866c6f6ffb --- /dev/null +++ b/core-web/libs/ui/src/lib/directives/dot-trim-input/dot-trim-input.directive.ts @@ -0,0 +1,27 @@ +import { AfterViewInit, Directive, ElementRef, HostListener, Optional, Self } from '@angular/core'; +import { NgControl } from '@angular/forms'; + +/** + * Directive for trimming the input value on blur. + */ +@Directive({ + selector: '[dotTrimInput]', + standalone: true +}) +export class DotTrimInputDirective implements AfterViewInit { + constructor( + @Optional() @Self() private readonly ngControl: NgControl, + private readonly el: ElementRef + ) {} + + @HostListener('blur') + onBlur() { + this.ngControl.control.setValue(this.ngControl.value.trim()); + } + + ngAfterViewInit(): void { + if (this.el.nativeElement.tagName.toLowerCase() !== 'input') { + console.warn('DotTrimInputDirective is for use with Inputs'); + } + } +}