From beaf86d9876e65c20b58cd32c9a4af94c0024d4c Mon Sep 17 00:00:00 2001 From: Wiktor Danielewski <63188869+wiktord2000@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:50:52 +0100 Subject: [PATCH] AAE-28106 Make the header ( label + style ) optional with a checkbox [Preview/Runtime display] (#10408) * AAE-28106 Update ContainerModel * AAE-28106 Update HeaderWidgetComponent * AAE-28106 Reorganize span element * AAE-28106 Update tests --- .../widgets/core/container.model.spec.ts | 151 +++++++++++++++++- .../widgets/core/container.model.ts | 37 ++--- .../widgets/header/header.widget.html | 47 ++++-- .../widgets/header/header.widget.spec.ts | 79 +++++++-- .../widgets/header/header.widget.ts | 6 +- 5 files changed, 264 insertions(+), 56 deletions(-) diff --git a/lib/core/src/lib/form/components/widgets/core/container.model.spec.ts b/lib/core/src/lib/form/components/widgets/core/container.model.spec.ts index 47a0d7be6a..0394b05d73 100644 --- a/lib/core/src/lib/form/components/widgets/core/container.model.spec.ts +++ b/lib/core/src/lib/form/components/widgets/core/container.model.spec.ts @@ -17,13 +17,154 @@ import { ContainerModel } from './container.model'; import { FormFieldModel } from './form-field.model'; -import { FormModel } from './form.model'; +import { FormFieldTypes } from './form-field-types'; describe('ContainerModel', () => { + let field: FormFieldModel; - it('should store the form reference', () => { - const form = new FormModel(); - const model = new ContainerModel(new FormFieldModel(form)); - expect(model.form).toBe(form); + beforeEach(() => { + field = new FormFieldModel(null, { + id: 'group-id', + name: 'group-name', + type: FormFieldTypes.GROUP, + params: { + allowCollapse: false, + collapseByDefault: false, + hideHeader: false + }, + numberOfColumns: 1, + tab: null + }); + }); + + it('should initialize with default values', () => { + const container = new ContainerModel(field); + + expect(container.field).toBe(field); + expect(container.columns).toEqual([]); + expect(container.isExpanded).toBe(true); + expect(container.rowspan).toBe(1); + expect(container.colspan).toBe(1); + }); + + describe('isVisible getter', () => { + it('should return true when field is visible', () => { + const container = new ContainerModel(field); + + expect(container.isVisible).toBe(true); + }); + + it('should return false when field is NOT visible', () => { + field.isVisible = false; + const container = new ContainerModel(field); + + expect(container.isVisible).toBe(false); + }); + }); + + describe('isTypeFieldGroup getter', () => { + it('should return true when field is a group', () => { + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + }); + + it('should return false when field is NOT a group', () => { + const container = new ContainerModel(new FormFieldModel(null, { type: FormFieldTypes.CONTAINER })); + + expect(container.isTypeFieldGroup).toBe(false); + }); + }); + + describe('isCollapsible getter', () => { + it('should return false when field is NOT a group', () => { + const container = new ContainerModel(new FormFieldModel(null, { type: FormFieldTypes.CONTAINER })); + + expect(container.isTypeFieldGroup).toBe(false); + expect(container.isCollapsible).toBe(false); + }); + + it('should return false when field is group and allowCollapse is false', () => { + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + expect(container.isCollapsible).toBe(false); + }); + + it('should return true when field is a group and allowCollapse is true', () => { + field.params.allowCollapse = true; + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + expect(container.isCollapsible).toBe(true); + }); + + it('should return false when field is a group and allowCollapse is NOT set', () => { + field.params.allowCollapse = undefined; + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + expect(container.isCollapsible).toBe(false); + }); + }); + + describe('isCollapsedByDefault getter', () => { + it('should return false when field is NOT a group', () => { + const container = new ContainerModel(new FormFieldModel(null, { type: FormFieldTypes.CONTAINER })); + + expect(container.isTypeFieldGroup).toBe(false); + expect(container.isCollapsedByDefault).toBe(false); + }); + + it('should return false when field is group and collapseByDefault is false', () => { + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + expect(container.isCollapsedByDefault).toBe(false); + }); + + it('should return true when field is a group and collapseByDefault is true', () => { + field.params.collapseByDefault = true; + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + expect(container.isCollapsedByDefault).toBe(true); + }); + + it('should return false when field is a group and collapseByDefault is NOT set', () => { + field.params.collapseByDefault = undefined; + const container = new ContainerModel(field); + + expect(container.isTypeFieldGroup).toBe(true); + expect(container.isCollapsedByDefault).toBe(false); + }); + }); + + describe('hideHeader getter', () => { + it('should return false when field is NOT a group', () => { + const container = new ContainerModel(new FormFieldModel(null, { type: FormFieldTypes.CONTAINER })); + + expect(container.hideHeader).toBe(false); + }); + + it('should return false when field is a group and hideHeader is false', () => { + const container = new ContainerModel(field); + + expect(container.hideHeader).toBe(false); + }); + + it('should return true when field is a group and hideHeader is true', () => { + field.params.hideHeader = true; + const container = new ContainerModel(field); + + expect(container.hideHeader).toBe(true); + }); + + it('should return false when field is a group and hideHeader is NOT set', () => { + field.params.hideHeader = undefined; + const container = new ContainerModel(field); + + expect(container.hideHeader).toBe(false); + }); }); }); diff --git a/lib/core/src/lib/form/components/widgets/core/container.model.ts b/lib/core/src/lib/form/components/widgets/core/container.model.ts index 093f28ac7a..6a166ce620 100644 --- a/lib/core/src/lib/form/components/widgets/core/container.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/container.model.ts @@ -15,7 +15,7 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ import { FormFieldModel } from './form-field.model'; import { FormWidgetModel } from './form-widget.model'; @@ -23,7 +23,6 @@ import { ContainerColumnModel } from './container-column.model'; import { FormFieldTypes } from './form-field-types'; export class ContainerModel extends FormWidgetModel { - field: FormFieldModel; readonly columns: ContainerColumnModel[] = []; @@ -31,43 +30,35 @@ export class ContainerModel extends FormWidgetModel { readonly rowspan: number = 1; readonly colspan: number = 1; - get isVisible(): boolean { - return this.field.isVisible; - } - constructor(field: FormFieldModel) { super(field.form, field.json); if (field) { this.field = field; this.columns = field.columns || []; - this.isExpanded = !this.isCollapsedByDefault(); + this.isExpanded = !this.isCollapsedByDefault; this.colspan = field.colspan; this.rowspan = field.rowspan; } } - isGroup(): boolean { + get isVisible(): boolean { + return this.field.isVisible; + } + + get isTypeFieldGroup(): boolean { return this.type === FormFieldTypes.GROUP; } - isCollapsible(): boolean { - let allowCollapse = false; - - if (this.isGroup() && this.field.params['allowCollapse']) { - allowCollapse = this.field.params['allowCollapse']; - } - - return allowCollapse; + get isCollapsible(): boolean { + return this.isTypeFieldGroup && (this.field.params?.allowCollapse ?? false); } - isCollapsedByDefault(): boolean { - let collapseByDefault = false; + get isCollapsedByDefault(): boolean { + return this.isTypeFieldGroup && (this.field.params?.collapseByDefault ?? false); + } - if (this.isCollapsible() && this.field.params['collapseByDefault']) { - collapseByDefault = this.field.params['collapseByDefault']; - } - - return collapseByDefault; + get hideHeader(): boolean { + return this.isTypeFieldGroup && (this.field.params?.hideHeader ?? false); } } diff --git a/lib/core/src/lib/form/components/widgets/header/header.widget.html b/lib/core/src/lib/form/components/widgets/header/header.widget.html index 7afef5293f..ea2ae9acc7 100644 --- a/lib/core/src/lib/form/components/widgets/header/header.widget.html +++ b/lib/core/src/lib/form/components/widgets/header/header.widget.html @@ -1,18 +1,37 @@ -
-

- - +
+
+ +
+

+ + {{ element.name | translate }}

+ + + +
diff --git a/lib/core/src/lib/form/components/widgets/header/header.widget.spec.ts b/lib/core/src/lib/form/components/widgets/header/header.widget.spec.ts index e5cebb9506..fa9bf0b33d 100644 --- a/lib/core/src/lib/form/components/widgets/header/header.widget.spec.ts +++ b/lib/core/src/lib/form/components/widgets/header/header.widget.spec.ts @@ -16,11 +16,12 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; import { ContainerModel } from '../core/container.model'; import { FormFieldTypes } from '../core/form-field-types'; import { FormFieldModel } from '../core/form-field.model'; import { HeaderWidgetComponent } from './header.widget'; +import { NoopTranslateModule } from '../../../../testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; describe('HeaderWidgetComponent', () => { let component: HeaderWidgetComponent; @@ -28,8 +29,8 @@ describe('HeaderWidgetComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [HeaderWidgetComponent, TranslateModule.forRoot()] - }).compileComponents(); + imports: [HeaderWidgetComponent, NoopTranslateModule, NoopAnimationsModule] + }); }); beforeEach(() => { @@ -46,24 +47,80 @@ describe('HeaderWidgetComponent', () => { type: FormFieldTypes.GROUP, name: 'test-name', id: 'test-id', - params: { allowCollapse: true } + params: { + hideHeader: false, + allowCollapse: false, + collapseByDefault: false + } } ) ) ); - fixture.detectChanges(); }); - it('should render the header widget template', () => { - const nativeElement = fixture.nativeElement; - expect(nativeElement.querySelector('.adf-container-widget-header')).toBeTruthy(); - expect(nativeElement.querySelector('#container-header-label-test-id').textContent.trim()).toEqual('test-name'); + it('should render header widget template when type is group', () => { + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.adf-container-widget-header')).not.toBe(null); + expect(fixture.nativeElement.querySelector('#container-header-label-test-id').textContent.trim()).toEqual('test-name'); + }); + + it('should NOT render header widget template when type is different then group', () => { + spyOnProperty(component.element, 'isTypeFieldGroup').and.returnValue(false); + + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.adf-container-widget-header')).toBe(null); + }); + + it('should display header text when hideHeader is set to false', () => { + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.adf-container-widget-header__text')).not.toBe(null); + }); + + it('should NOT display header text when hideHeader is set to true', () => { + component.element.json.params.hideHeader = true; + + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.adf-container-widget-header__text')).toBe(null); + }); + + it('should display expander when allowCollapse is set to true', () => { + component.element.json.params.allowCollapse = true; + + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.mdl-button--icon')).not.toBe(null); + }); + + it('should NOT display expander when allowCollapse is set to false', () => { + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.mdl-button--icon')).toBe(null); }); it('should call onExpanderClicked method when expander is clicked', () => { + component.element.json.params.allowCollapse = true; + fixture.detectChanges(); + spyOn(component, 'onExpanderClicked'); - const expander = fixture.nativeElement.querySelector('#container-header-label-test-id'); + + const expander = fixture.nativeElement.querySelector('.mdl-button--icon'); expander.click(); - expect(component.onExpanderClicked).toHaveBeenCalled(); + + expect(component.onExpanderClicked).toHaveBeenCalledWith(component.element); + }); + + it('should call onExpanderClicked method when header text is clicked', () => { + fixture.detectChanges(); + + spyOn(component, 'onExpanderClicked'); + + const headerText = fixture.nativeElement.querySelector('#container-header-label-test-id'); + headerText.click(); + + expect(component.onExpanderClicked).toHaveBeenCalledWith(component.element); }); }); diff --git a/lib/core/src/lib/form/components/widgets/header/header.widget.ts b/lib/core/src/lib/form/components/widgets/header/header.widget.ts index 49d94b9cb4..05d6daa09a 100644 --- a/lib/core/src/lib/form/components/widgets/header/header.widget.ts +++ b/lib/core/src/lib/form/components/widgets/header/header.widget.ts @@ -19,7 +19,7 @@ import { Component, Input, ViewEncapsulation } from '@angular/core'; import { ContainerModel } from '../core/container.model'; import { FieldStylePipe } from './../../../pipes/field-style.pipe'; import { MatIconModule } from '@angular/material/icon'; -import { NgIf } from '@angular/common'; +import { NgIf, NgTemplateOutlet } from '@angular/common'; import { TranslateModule } from '@ngx-translate/core'; import { MatButtonModule } from '@angular/material/button'; @@ -29,13 +29,13 @@ import { MatButtonModule } from '@angular/material/button'; styleUrls: ['./header.widget.scss'], standalone: true, encapsulation: ViewEncapsulation.None, - imports: [FieldStylePipe, MatIconModule, MatButtonModule, TranslateModule, NgIf] + imports: [FieldStylePipe, MatIconModule, MatButtonModule, TranslateModule, NgIf, NgTemplateOutlet] }) export class HeaderWidgetComponent { @Input() element: ContainerModel; onExpanderClicked(content: ContainerModel) { - if (content?.isCollapsible()) { + if (content?.isCollapsible) { content.isExpanded = !content.isExpanded; } }