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
This commit is contained in:
Wiktor Danielewski 2024-11-20 16:50:52 +01:00 committed by GitHub
parent b4516bc998
commit beaf86d987
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 264 additions and 56 deletions

View File

@ -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);
});
});
});

View File

@ -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);
}
}

View File

@ -1,18 +1,37 @@
<div [hidden]="!element?.isGroup()" [style]="element | adfFieldStyle" class="adf-container-widget-header">
<h4 class="adf-container-widget-header__text" id="container-header"
[class.adf-collapsible]="element?.isCollapsible()">
<button *ngIf="element?.isCollapsible()"
mat-icon-button
class="mdl-button--icon"
(click)="onExpanderClicked(element)">
<mat-icon>{{ element?.isExpanded ? 'expand_more' : 'expand_less' }}</mat-icon>
</button>
<span (click)="onExpanderClicked(element)"
role="button"
tabindex="0"
(keyup.enter)="onExpanderClicked(element)"
[id]="'container-header-label-' + element?.id">
<div
*ngIf="element?.isTypeFieldGroup"
[style]="element | adfFieldStyle"
class="adf-container-widget-header"
>
<div *ngIf="element?.hideHeader">
<ng-container *ngTemplateOutlet="expandButton; context: { $implicit: element }" />
</div>
<h4
*ngIf="!element?.hideHeader"
id="container-header"
class="adf-container-widget-header__text"
[class.adf-collapsible]="element?.isCollapsible"
>
<ng-container *ngTemplateOutlet="expandButton; context: { $implicit: element }" />
<span
[id]="'container-header-label-' + element?.id"
role="button"
tabindex="0"
(keyup.enter)="onExpanderClicked(element)"
(click)="onExpanderClicked(element)"
>
{{ element.name | translate }}
</span>
</h4>
<ng-template #expandButton let-element>
<button
*ngIf="element?.isCollapsible"
mat-icon-button
class="mdl-button--icon"
(click)="onExpanderClicked(element)"
>
<mat-icon> {{ element?.isExpanded ? 'expand_more' : 'expand_less' }} </mat-icon>
</button>
</ng-template>
</div>

View File

@ -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);
});
});

View File

@ -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;
}
}