[ACS-7768] ADF Form fields cleanup (#11484)

* [ACS-7768] ADF Form fields cleanup

* [ACS-7768] CR fixes

* [ACS-7768] Bring back label condition

* ACS-7768 Fixing storybook build

* [ACS-7768] Fix rebase issues

---------

Co-authored-by: Ehsan Rezaei <ehsan.rezaei@hyland.com>
This commit is contained in:
Michal Kinas
2026-01-27 08:10:15 +01:00
committed by GitHub
co-authored by Ehsan Rezaei
parent b2c105dd67
commit 1028df91da
78 changed files with 620 additions and 1167 deletions
@@ -44,11 +44,10 @@ export abstract class BaseCardView<T extends CardViewItem> {
}
get isReadonlyProperty(): boolean {
return this.editable && !this.property.editable;
return !this.property.editable;
}
get hasIcon(): boolean {
return !!this.property.icon;
}
}
@@ -1,109 +1,113 @@
<mat-label
class="adf-property-label"
[attr.data-automation-id]="'card-dateitem-label-' + property.key"
*ngIf="showProperty && !isEditable"
[attr.for]="'card-view-dateitem-' + property.key"
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty, 'adf-property-value-editable': editable }"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
>
{{ property.label | translate }}
</mat-label>
<div class="adf-property-value" [ngClass]="{ 'adf-property-value-editable': editable, 'adf-property-readonly-value': isReadonlyProperty }">
<span *ngIf="!isEditable && !property.multivalued" [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
<span
*ngIf="showProperty"
[attr.data-automation-id]="'card-dateitem-' + property.key"
(dblclick)="copyToClipboard(property.displayValue)"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
>{{ property.displayValue }}</span
>
</span>
<mat-form-field *ngIf="isEditable && !property.multivalued" class="adf-property-field adf-dateitem-editable hxp-input" [floatLabel]="property.default ? 'always' : null">
<mat-label
class="adf-property-label"
[attr.data-automation-id]="'card-dateitem-label-' + property.key"
*ngIf="isEditable"
[attr.for]="'card-view-dateitem-' + property.key"
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty, 'adf-property-value-editable': editable }"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
>
{{ property.label | translate }}
</mat-label>
<div class="adf-dateitem-editable-controls">
<span
class="adf-datepicker-span-button"
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
(click)="showDatePicker()"
tabindex="0"
role="button"
(keyup.enter)="showDatePicker()"
<div class="adf-property-value" [ngClass]="{ 'adf-property-value-editable': editable, 'adf-property-readonly-value': isReadonlyProperty || !editable }">
@if (!property.multivalued) {
<mat-form-field class="adf-property-field adf-dateitem-editable" [floatLabel]="property.default ? 'always' : null">
<mat-label
class="adf-property-label"
[attr.data-automation-id]="'card-dateitem-label-' + property.key"
[attr.for]="'card-view-dateitem-' + property.key"
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty || !editable, 'adf-property-value-editable': editable }"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
>
<span *ngIf="showProperty; else elseEmptyValueBlock" [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
{{ property.displayValue }}</span
{{ property.label | translate }}
</mat-label>
<div class="adf-dateitem-editable-controls">
<span
class="adf-datepicker-span-button"
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
(click)="showDatePicker()"
(dblclick)="copyToClipboard(property.displayValue)"
tabindex="0"
role="button"
(keyup.enter)="showDatePicker()"
>
</span>
</div>
<input
matInput
class="adf-invisible-date-input"
[attr.tabIndex]="-1"
[matDatetimepicker]="datetimePicker"
[value]="valueDate"
(dateChange)="onDateChanged($event)"
[attr.id]="'card-view-dateitem-' + property.key"
/>
<mat-icon
matIconSuffix
*ngIf="showClearAction"
class="adf-date-reset-icon"
(click)="onDateClear()"
[attr.title]="'CORE.METADATA.ACTIONS.CLEAR' | translate"
[attr.data-automation-id]="'datepicker-date-clear-' + property.key"
adf-icon="clear"
/>
<mat-datetimepicker-toggle
matIconSuffix
[attr.tabindex]="-1"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'datepickertoggle-' + property.key"
[for]="datetimePicker"
class="adf-dateitem-picker-toggle"
/>
<span [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
@if (showProperty) {
{{ property.displayValue }}
} @else {
{{ property.default | translate }}
}
<mat-datetimepicker
#datetimePicker
[type]="$any(property).type"
[timeInterval]="5"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate"
/>
</mat-form-field>
<ng-template #elseEmptyValueBlock>
{{ property.default | translate }}
</ng-template>
<div *ngIf="property.multivalued" class="adf-property-field adf-dateitem-chip-list-container adf-dateitem-editable">
<mat-chip-listbox #chipList class="adf-textitem-chip-list">
<mat-chip-option
*ngFor="let propertyValue of property.displayValue; let idx = index"
[removable]="isEditable"
(removed)="removeValueFromList(idx)"
>
{{ propertyValue }}
<mat-icon *ngIf="isEditable" matChipRemove adf-icon="cancel" />
</mat-chip-option>
</mat-chip-listbox>
<div
*ngIf="isEditable"
class="adf-property-field adf-dateitem-editable-controls"
(click)="showDatePicker()"
tabindex="0"
role="button"
(keyup.enter)="showDatePicker()"
>
</span>
</span>
</div>
<input
matInput
[disabled]="isReadonlyProperty || !editable"
class="adf-invisible-date-input"
[attr.tabIndex]="-1"
[matDatetimepicker]="datetimePicker"
[value]="valueDate"
(dateChange)="onDateChanged($event)"
[attr.id]="'card-view-dateitem-' + property.key"
/>
@if (showClearAction) {
<mat-icon
matIconSuffix
class="adf-date-reset-icon"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
(click)="onDateClear()"
[attr.title]="'CORE.METADATA.ACTIONS.CLEAR' | translate"
[attr.data-automation-id]="'datepicker-date-clear-' + property.key"
adf-icon="clear"
/>
}
<mat-datetimepicker-toggle
matIconSuffix
[attr.tabindex]="-1"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'datepickertoggle-' + property.key"
[for]="datetimePicker"
class="adf-dateitem-picker-toggle"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
<mat-datetimepicker
#datetimePicker
[type]="$any(property).type"
[timeInterval]="5"
[disabled]="isReadonlyProperty || !editable"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
</mat-form-field>
} @else {
<mat-form-field class="adf-property-field adf-dateitem-editable" [floatLabel]="property.default ? 'always' : null">
<mat-label
class="adf-property-label"
[attr.data-automation-id]="'card-dateitem-label-' + property.key"
[attr.for]="'card-view-dateitem-' + property.key"
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty || !editable, 'adf-property-value-editable': editable }"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
>
{{ property.label | translate }}
</mat-label>
<mat-chip-listbox #chipList class="adf-textitem-chip-list" [disabled]="isReadonlyProperty || !editable">
<mat-chip-option
*ngFor="let propertyValue of property.displayValue; let idx = index"
[removable]="isEditable"
(removed)="removeValueFromList(idx)"
>
{{ propertyValue }}
@if (isEditable) {
<mat-icon matChipRemove adf-icon="cancel" />
}
</mat-chip-option>
</mat-chip-listbox>
<div class="adf-dateitem-editable-controls">
<span
class="adf-datepicker-span-button"
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
(click)="showDatePicker()"
(dblclick)="copyToClipboard(property.displayValue)"
tabindex="0"
role="button"
(keyup.enter)="showDatePicker()"
></span>
</div>
<input
matInput
[disabled]="isReadonlyProperty || !editable"
class="adf-invisible-date-input"
[attr.tabIndex]="-1"
[matDatetimepicker]="datetimePicker"
@@ -116,6 +120,7 @@
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'datepickertoggle-' + property.key"
[for]="datetimePicker"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
<mat-datetimepicker
#datetimePicker
@@ -123,7 +128,9 @@
[timeInterval]="5"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate"
[disabled]="isReadonlyProperty || !editable"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
</div>
</div>
</mat-form-field>
}
</div>
@@ -4,9 +4,12 @@
display: flow-root;
.adf-dateitem-editable {
cursor: pointer;
width: 100%;
.adf-date-reset-icon {
padding: 0;
}
&-controls {
display: flex;
align-items: center;
@@ -31,11 +34,6 @@
position: relative;
}
}
#{ms.$mat-line-ripple},
#{ms.$mat-form-field-subscript-wrapper} {
display: none;
}
}
.adf-property-value {
@@ -49,10 +47,6 @@
border-bottom: inherit;
padding-left: 0;
}
&.adf-property-readonly-value {
padding: 0 0 0 12px;
}
}
.adf-invisible-date-input {
@@ -64,14 +64,16 @@ describe('CardViewDateItemComponent', () => {
afterEach(() => fixture.destroy());
const getPropertyLabel = (): string => testingUtils.getInnerTextByCSS('.adf-property-label');
const getPropertyValue = (): string => testingUtils.getInnerTextByCSS('.adf-property-value');
const getDateTime = (): string => testingUtils.getInnerTextByCSS('.adf-datepicker-span-button');
const getPropertyValue = (): string => testingUtils.getInputByCSS('.adf-invisible-date-input').value;
const getDefaultValue = (): string =>
testingUtils.getInnerTextByDataAutomationId('card-' + component.property.type + '-value-' + component.property.key);
const getDateTime = (): string => testingUtils.getInnerTextByDataAutomationId('datepicker-label-toggle-' + component.property.key);
it('should render the label and value', () => {
fixture.detectChanges();
expect(getPropertyLabel()).toBe('Date label');
expect(getPropertyValue().trim()).toBe('Jul 10, 2017');
expect(getPropertyValue().trim()).toBe('07/10/2017');
});
it('should NOT render the default as value if the value is empty, editable:false and displayEmpty is false', () => {
@@ -103,7 +105,7 @@ describe('CardViewDateItemComponent', () => {
component.displayEmpty = true;
fixture.detectChanges();
expect(getPropertyValue().trim()).toBe('FAKE-DEFAULT-KEY');
expect(getDefaultValue()).toBe('FAKE-DEFAULT-KEY');
});
it('should render the default as value if the value is empty and editable:true', () => {
@@ -148,8 +150,8 @@ describe('CardViewDateItemComponent', () => {
const datePicker = testingUtils.getByDataAutomationId(`datepicker-${component.property.key}`);
const datePickerToggle = testingUtils.getByDataAutomationId(`datepickertoggle-${component.property.key}`);
expect(datePicker).toBeNull('Datepicker should NOT be in DOM');
expect(datePickerToggle).toBeNull('Datepicker toggle should NOT be shown');
expect(datePicker.classes['cdk-visually-hidden']).toBeTrue();
expect(datePickerToggle.classes['cdk-visually-hidden']).toBeTrue();
});
it('should NOT render the picker and toggle in case of editable:true but (general) editable:false', () => {
@@ -160,8 +162,8 @@ describe('CardViewDateItemComponent', () => {
expect(component.isEditable).toBe(false);
const datePicker = testingUtils.getByDataAutomationId(`datepicker-${component.property.key}`);
const datePickerToggle = testingUtils.getByDataAutomationId(`datepickertoggle-${component.property.key}`);
expect(datePicker).toBeNull('Datepicker should NOT be in DOM');
expect(datePickerToggle).toBeNull('Datepicker toggle should NOT be shown');
expect(datePicker.classes['cdk-visually-hidden']).toBeTrue();
expect(datePickerToggle.classes['cdk-visually-hidden']).toBeTrue();
});
it('should open the datepicker when clicking on the label', () => {
@@ -213,7 +215,7 @@ describe('CardViewDateItemComponent', () => {
component.editable = false;
fixture.detectChanges();
testingUtils.doubleClickByDataAutomationId(`card-dateitem-${component.property.key}`);
testingUtils.doubleClickByDataAutomationId('datepicker-label-toggle-' + component.property.key);
fixture.detectChanges();
expect(clipboardService.copyContentToClipboard).toHaveBeenCalledWith('Jul 10, 2017', 'CORE.METADATA.ACCESSIBILITY.COPY_TO_CLIPBOARD_MESSAGE');
@@ -110,7 +110,6 @@ describe('CardViewItemDispatcherComponent', () => {
const expectedCustomInput = 1;
const expectedDisplayNoneOption = false;
const expectedDisplayClearAction = false;
const expectedDisplayLabel = true;
component.ngOnChanges({
editable: new SimpleChange(true, expectedEditable, false),
@@ -118,8 +117,7 @@ describe('CardViewItemDispatcherComponent', () => {
property: new SimpleChange(null, expectedProperty, false),
customInput: new SimpleChange(0, expectedCustomInput, false),
displayNoneOption: new SimpleChange(true, expectedDisplayNoneOption, false),
displayClearAction: new SimpleChange(true, expectedDisplayClearAction, false),
displayLabelForChips: new SimpleChange(false, expectedDisplayLabel, false)
displayClearAction: new SimpleChange(true, expectedDisplayClearAction, false)
});
const shinyCustomElementItemComponent = testingUtils.getByCSS('whatever-you-want-to-have').componentInstance;
@@ -129,7 +127,6 @@ describe('CardViewItemDispatcherComponent', () => {
expect(shinyCustomElementItemComponent.customInput).toBe(expectedCustomInput);
expect(shinyCustomElementItemComponent.displayNoneOption).toBe(expectedDisplayNoneOption);
expect(shinyCustomElementItemComponent.displayClearAction).toBe(expectedDisplayClearAction);
expect(shinyCustomElementItemComponent.displayLabelForChips).toBe(expectedDisplayLabel);
});
});
@@ -49,9 +49,6 @@ export class CardViewItemDispatcherComponent implements OnChanges {
@Input()
multiValueSeparator: string = DEFAULT_SEPARATOR;
@Input()
displayLabelForChips: boolean = false;
private loaded: boolean = false;
private componentReference: any = null;
@@ -103,7 +100,6 @@ export class CardViewItemDispatcherComponent implements OnChanges {
this.componentReference.instance.copyToClipboardAction = this.copyToClipboardAction;
this.componentReference.instance.useChipsForMultiValueProperty = this.useChipsForMultiValueProperty;
this.componentReference.instance.multiValueSeparator = this.multiValueSeparator;
this.componentReference.instance.displayLabelForChips = this.displayLabelForChips;
}
private proxy(methodName, ...args) {
@@ -1,66 +1,51 @@
<ng-container *ngIf="!property.isEmpty() || isEditable">
<ng-container *ngIf="showProperty || isEditable">
<div [ngSwitch]="templateType">
<div *ngSwitchDefault>
<div *ngIf="!isEditable"
[attr.data-automation-id]="'card-select-label-' + property.key"
class="adf-property-label adf-property-label-non-editable"
>{{ property.label | translate }}
</div>
<div class="adf-property-field">
<div
*ngIf="!isEditable"
class="adf-property-value adf-property-read-only"
[attr.data-automation-id]="'select-readonly-value-' + property.key"
data-automation-class="read-only-value"
[title]="property.displayValue | async | translate"
>
{{ property.displayValue | async | translate }}
</div>
<div *ngIf="isEditable">
<mat-form-field class="adf-property-value">
<mat-label
[attr.data-automation-id]="'card-select-label-' + property.key"
class="adf-property-label adf-property-value-editable"
[ngClass]="{
'adf-property-readonly-value': isReadonlyProperty
}"
>{{ property.label | translate }}
</mat-label>
<mat-select
[(ngModel)]="value"
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty }"
panelClass="adf-select-filter"
(selectionChange)="onChange($event)"
data-automation-class="select-box"
[aria-label]="property.label | translate"
adf-card-view-property-validator
[property]="property"
(validated)="onValidation($event)"
>
<adf-select-filter-input *ngIf="showInputFilter" (change)="onFilterInputChange($event)" />
<mat-option *ngIf="displayNoneOption">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
<mat-option *ngFor="let option of list$ | async" [value]="option.key">
{{ option.label | translate }}
</mat-option>
</mat-select>
<mat-error [innerHTML]="error" />
</mat-form-field>
</div>
<mat-form-field class="adf-property-value">
<mat-label
[attr.data-automation-id]="'card-select-label-' + property.key"
class="adf-property-label"
[ngClass]="{
'adf-property-value-editable': isEditable,
'adf-property-readonly-value': isReadonlyProperty
}"
>{{ property.label | translate }}
</mat-label>
<mat-select
[(ngModel)]="value"
[disabled]="isReadonlyProperty || !editable"
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty || !editable }"
panelClass="adf-select-filter"
(selectionChange)="onChange($event)"
data-automation-id="select-box"
[aria-label]="property.label | translate"
adf-card-view-property-validator
[property]="property"
(validated)="onValidation($event)"
>
<adf-select-filter-input *ngIf="showInputFilter" (change)="onFilterInputChange($event)" />
<mat-option *ngIf="displayNoneOption">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
<mat-option *ngFor="let option of list$ | async" [value]="option.key">
{{ option.label | translate }}
</mat-option>
</mat-select>
<mat-error [innerHTML]="error" />
</mat-form-field>
</div>
</div>
<div *ngSwitchCase="'autocompleteBased'">
<mat-form-field
class="adf-property-field adf-card-selectitem-autocomplete "
[ngClass]="{ 'adf-property-read-only': !isEditable }"
[ngClass]="{ 'adf-property-read-only': isReadonlyProperty || !editable }"
[floatLabel]="property.default ? 'always' : null"
>
<mat-label
*ngIf="showProperty || isEditable"
[attr.data-automation-id]="'card-autocomplete-based-selectitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{
'adf-property-value-editable': isEditable,
'adf-property-readonly-value': isReadonlyProperty
'adf-property-readonly-value': isReadonlyProperty || !editable
}"
>
{{ property.label | translate }}
@@ -71,7 +56,7 @@
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': isEditable,
'adf-property-readonly-value': isReadonlyProperty
'adf-property-readonly-value': isReadonlyProperty || !editable
}"
title="{{ property.label | translate }}"
[placeholder]="property.default"
@@ -44,10 +44,6 @@
padding-left: 10px;
}
#{ms.$mat-form-field-subscript-wrapper} {
display: block;
}
.adf-property-read-only {
text-overflow: ellipsis;
overflow: hidden;
@@ -63,11 +59,4 @@
.adf-property-readonly-value {
color: var(--adf-metadata-property-panel-label-color);
}
.adf-property-label {
&-non-editable {
cursor: default;
font-size: 10px;
}
}
}
@@ -62,7 +62,7 @@ describe('CardViewSelectItemComponent', () => {
editable: true
};
const getSelectElement = (): DebugElement => testingUtils.getByDataAutomationClass('select-box');
const getSelectElement = (): DebugElement => testingUtils.getByDataAutomationId('select-box');
beforeEach(() => {
TestBed.configureTestingModule({
@@ -82,8 +82,6 @@ describe('CardViewSelectItemComponent', () => {
});
describe('Rendering', () => {
const getReadOnlyElement = (): DebugElement => testingUtils.getByDataAutomationClass('read-only-value');
it('should render custom label when editable is set to false', () => {
component.property = new CardViewSelectItemModel({
...mockDefaultProps,
@@ -93,7 +91,7 @@ describe('CardViewSelectItemComponent', () => {
expect(testingUtils.getInnerTextByCSS('.adf-property-label')).toBe('Select box label');
});
it('should render readOnly value is editable property is FALSE', () => {
it('should render disable select when editable property is FALSE', async () => {
component.property = new CardViewSelectItemModel({
...mockDefaultProps,
editable: false
@@ -101,19 +99,9 @@ describe('CardViewSelectItemComponent', () => {
component.ngOnChanges({});
fixture.detectChanges();
const selectBox = await testingUtils.getMatSelectByDataAutomationId('select-box');
expect(getReadOnlyElement()).not.toBeNull();
expect(getSelectElement()).toBeNull();
});
it('should read only value have title', () => {
component.property = new CardViewSelectItemModel({
...mockDefaultProps,
editable: false
});
fixture.detectChanges();
expect(getReadOnlyElement().nativeElement.title).toBe('Two');
expect(await selectBox.isDisabled()).toBe(true);
});
it('should be possible edit selectBox item', async () => {
@@ -1,6 +1,6 @@
<div class="adf-select-filter-input-container">
<mat-form-field subscriptSizing="dynamic">
<mat-form-field>
<input matInput
autocomplete="off"
(keydown)="handleKeydown($event)"
@@ -1,167 +1,158 @@
<div class="adf-card-textitem-field-container" [ngSwitch]="templateType">
<div *ngSwitchDefault>
<mat-form-field
subscriptSizing="dynamic"
[floatLabel]="'always'"
class="adf-property-field adf-card-textitem-field"
[ngClass]="{
'adf-property-read-only': !isEditable
}"
@if (showProperty || isEditable) {
<div class="adf-card-textitem-field-container" [ngSwitch]="templateType">
<div *ngSwitchDefault>
<mat-form-field
class="adf-property-field adf-card-textitem-field"
[ngClass]="{
'adf-property-read-only': isReadonlyProperty
}"
>
<mat-label
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty || !editable
}"
>
{{ property.label | translate }}
</mat-label>
<input
matInput
*ngIf="!property.multiline"
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty || !editable,
'adf-property-value-has-error': isEditable && hasErrors,
'adf-property-value-not-editable': !editable
}"
[disabled]="isReadonlyProperty || !editable"
title="{{ property.label | translate }}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="textInput"
(dblclick)="copyToClipboard(property.displayValue)"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
(keydown)="undoText($event)"
(blur)="update()"
[aria-describedby]="'adf-card-textitem-error-' + property.key"
/>
<textarea
matInput
*ngIf="property.multiline"
title="{{ property.label | translate }}"
[cdkTextareaAutosize]="true"
[cdkAutosizeMinRows]="1"
[cdkAutosizeMaxRows]="5"
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty || !editable,
}"
[disabled]="isReadonlyProperty || !editable"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="textInput"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
>
</textarea>
</mat-form-field>
</div>
<div
*ngSwitchCase="'chipsTemplate'"
class="adf-property-field adf-textitem-chip-list-container"
[ngClass]="{ 'adf-property-read-only': isReadonlyProperty }"
>
<mat-label
*ngIf="showProperty || isEditable"
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty
}"
<mat-form-field
class="adf-property-field adf-textitem-chip-list-input"
[ngClass]="{ 'adf-property-read-only': isReadonlyProperty }"
>
{{ property.label | translate }}
</mat-label>
<input
matInput
*ngIf="!property.multiline"
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty,
'adf-property-value-has-error': isEditable && hasErrors,
'adf-property-value-not-editable': !editable
}"
title="{{ property.label | translate }}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="textInput"
(dblclick)="copyToClipboard(property.displayValue)"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
(keydown)="undoText($event)"
(blur)="update()"
[aria-describedby]="'adf-card-textitem-error-' + property.key"
/>
<textarea
matInput
*ngIf="property.multiline"
title="{{ property.label | translate }}"
[cdkTextareaAutosize]="true"
[cdkAutosizeMinRows]="1"
[cdkAutosizeMaxRows]="5"
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty
}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="textInput"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
>
</textarea>
</mat-form-field>
</div>
<div
*ngSwitchCase="'chipsTemplate'"
class="adf-property-field adf-textitem-chip-list-container"
[ngClass]="{ 'adf-property-read-only': !isEditable }"
>
<mat-label
*ngIf="showLabelForChips"
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{ 'adf-property-value-editable': editable }"
<mat-label
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{ 'adf-property-value-editable': editable }"
>
{{ property.label | translate }}
</mat-label>
<mat-chip-grid #chipElement class="adf-textitem-chip-list" [disabled]="isReadonlyProperty || !editable">
<mat-chip-row *ngFor="let propertyValue of editedValue; let idx = index" [removable]="isEditable" (removed)="removeValueFromList(idx)">
{{ propertyValue }}
<mat-icon *ngIf="isEditable" matChipRemove adf-icon="cancel" />
</mat-chip-row>
</mat-chip-grid>
<input
matInput
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty || !editable
}"
title="{{ property.label | translate }}"
[placeholder]="editedValue ? '' : (property.default | translate)"
[attr.aria-label]="property.label | translate"
[matChipInputFor]="chipElement"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addValueToList($event)"
[disabled]="isReadonlyProperty || !editable"
[attr.data-automation-id]="'card-textitem-editchipinput-' + property.key"
/>
</mat-form-field>
</div>
<div
*ngSwitchCase="'clickableTemplate'"
role="button"
class="adf-textitem-clickable"
[ngClass]="{ 'adf-property-read-only': isReadonlyProperty }"
[attr.data-automation-id]="'card-textitem-toggle-' + property.key"
tabindex="0"
(keyup.enter)="clicked()"
(click)="clicked()"
>
{{ property.label | translate }}
</mat-label>
<mat-chip-grid #chipElement class="adf-textitem-chip-list">
<mat-chip-row *ngFor="let propertyValue of editedValue; let idx = index" [removable]="isEditable" (removed)="removeValueFromList(idx)">
{{ propertyValue }}
<mat-icon *ngIf="isEditable" matChipRemove adf-icon="cancel" />
</mat-chip-row>
</mat-chip-grid>
<mat-form-field
*ngIf="isEditable"
[floatLabel]="'always'"
class="adf-property-field adf-textitem-chip-list-input"
[ngClass]="{ 'adf-property-read-only': !isEditable }"
>
<input
matInput
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty
}"
title="{{ property.label | translate }}"
[placeholder]="editedValue ? '' : (property.default | translate)"
[attr.aria-label]="property.label | translate"
[matChipInputFor]="chipElement"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addValueToList($event)"
[attr.data-automation-id]="'card-textitem-editchipinput-' + property.key"
/>
</mat-form-field>
</div>
<div
*ngSwitchCase="'clickableTemplate'"
role="button"
class="adf-textitem-clickable"
[ngClass]="{ 'adf-property-read-only': !isEditable }"
[attr.data-automation-id]="'card-textitem-toggle-' + property.key"
tabindex="0"
(keyup.enter)="clicked()"
(click)="clicked()"
>
<mat-form-field class="adf-property-field adf-card-textitem-field" [floatLabel]="'always'">
<mat-label
*ngIf="showProperty || isEditable"
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{ 'adf-property-value-editable': editable }"
>
{{ property.label | translate }}
</mat-label>
<input
matInput
[type]="property.inputType"
class="adf-property-value"
title="{{ property.label | translate }}"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-textitem-clickable-value': isClickable,
'adf-property-readonly-value': isReadonlyProperty,
'adf-property-value-has-error': isEditable && hasErrors,
'adf-property-value-has-icon-suffix': showClickableIcon
}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[(ngModel)]="editedValue"
(blur)="update()"
(keydown.enter)="update()"
[readonly]="!isEditable"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
[aria-describedby]="'adf-card-textitem-error-' + property.key"
/>
<button
mat-icon-button
matSuffix
*ngIf="showClickableIcon"
class="adf-textitem-action"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'card-textitem-clickable-icon-' + property.key"
>
<mat-icon class="adf-textitem-icon" [adf-icon]="property?.icon" />
</button>
</mat-form-field>
</div>
<div *ngSwitchCase="'emptyTemplate'">
<span class="adf-textitem-default-value">{{ property.default | translate }}</span>
</div>
<mat-form-field class="adf-property-field adf-card-textitem-field">
<mat-label
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{ 'adf-property-value-editable': editable }"
>
{{ property.label | translate }}
</mat-label>
<input
matInput
[type]="property.inputType"
class="adf-property-value"
title="{{ property.label | translate }}"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-textitem-clickable-value': isClickable,
'adf-property-readonly-value': isReadonlyProperty || !editable,
'adf-property-value-has-error': isEditable && hasErrors,
'adf-property-value-has-icon-suffix': showClickableIcon
}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[(ngModel)]="editedValue"
(blur)="update()"
(keydown.enter)="update()"
[disabled]="isReadonlyProperty || !editable"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
[aria-describedby]="'adf-card-textitem-error-' + property.key"
/>
<button
mat-icon-button
matSuffix
*ngIf="showClickableIcon"
class="adf-textitem-action"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'card-textitem-clickable-icon-' + property.key"
>
<mat-icon class="adf-textitem-icon" [adf-icon]="property?.icon" />
</button>
</mat-form-field>
</div>
<mat-error
*ngIf="isEditable && hasErrors"
@@ -175,3 +166,4 @@
</ul>
</mat-error>
</div>
}
@@ -2,9 +2,6 @@
.adf-card-view-textitem {
.adf-textitem-error {
font-size: var(--theme-caption-font-size);
padding-top: 6px;
&::before {
display: none;
}
@@ -50,12 +47,8 @@
margin-top: 6px;
}
#{ms.$mat-form-field-infix} {
padding-top: 0;
.adf-property-value {
margin-left: 0;
}
.adf-property-value {
margin-left: 0;
}
}
@@ -75,10 +68,6 @@
}
}
.adf-textitem-default-value {
color: var(--adf-theme-foreground-text-color-064);
}
.adf-property-value-not-editable {
color: var(--adf-metadata-property-panel-title-color);
}
@@ -355,7 +355,7 @@ describe('CardViewTextItemComponent', () => {
expect(await testingUtils.checkIfMatChipGridExists()).toBe(false);
});
it('should display the label for multi-valued chips if displayLabelForChips is true', async () => {
it('should display the label for multi-valued chips', async () => {
const cardViewTextItemObject = {
label: 'Text label',
value: ['item1', 'item2', 'item3'],
@@ -367,7 +367,6 @@ describe('CardViewTextItemComponent', () => {
component.editable = true;
component.property = new CardViewTextItemModel(cardViewTextItemObject);
component.displayLabelForChips = true;
component.ngOnChanges({ property: new SimpleChange(null, null, true) });
fixture.detectChanges();
@@ -376,37 +375,14 @@ describe('CardViewTextItemComponent', () => {
expect(testingUtils.getInnerTextByCSS('.adf-property-label')).toBe('Text label');
});
it('should NOT display the label for multi-valued chips if displayLabelForChips is false', async () => {
const cardViewTextItemObject = {
label: 'Text label',
value: ['item1', 'item2', 'item3'],
key: 'textkey',
default: ['FAKE-DEFAULT-KEY'],
editable: true,
multivalued: true
};
component.editable = true;
component.property = new CardViewTextItemModel(cardViewTextItemObject);
component.displayLabelForChips = false;
component.ngOnChanges({ property: new SimpleChange(null, null, true) });
fixture.detectChanges();
await fixture.whenStable();
expect(testingUtils.getByCSS('.adf-property-label')).toBeNull();
});
it('should return true when editable is true, and property.editable is false', () => {
component.editable = true;
it('should return true when property.editable is false', () => {
component.property.editable = false;
fixture.detectChanges();
expect(component.isReadonlyProperty).toBe(true);
});
it('should return false when editable is false, and property.editable is false', () => {
component.editable = false;
component.property.editable = false;
it('should return false when and property.editable is true', () => {
component.property.editable = true;
fixture.detectChanges();
expect(component.isReadonlyProperty).toBe(false);
});
@@ -595,7 +571,7 @@ describe('CardViewTextItemComponent', () => {
);
});
it('should input be readonly if item it NOT editable', async () => {
it('should input be disabled if item it NOT editable', async () => {
component.editable = false;
component.property.clickable = true;
component.ngOnChanges({});
@@ -605,7 +581,7 @@ describe('CardViewTextItemComponent', () => {
const inputHarness = await testingUtils.getMatInputByDataAutomationId(`card-textitem-value-${component.property.key}`);
expect(component.isEditable).toBe(false);
expect(await inputHarness.isReadonly()).toBe(true);
expect(await inputHarness.isDisabled()).toBe(true);
});
});
@@ -67,8 +67,7 @@ export const ChipsCardViewTextItem: Story = {
multivalued: true,
icon: 'icon',
editable: true
}),
displayLabelForChips: false
})
}
};
@@ -107,22 +106,3 @@ export const DefaultCardViewTextItem: Story = {
})
}
};
export const DisplayLabelForChipsCardTextItem: Story = {
render: (args) => ({
props: args
}),
args: {
property: new CardViewTextItemModel({
label: 'CardView Text Item - Multi-Valued Chips template',
value: ['Chip 1', 'Chip 2', 'Chip 3'],
key: 'multivalued',
default: 'default value',
multiline: true,
multivalued: true,
icon: 'icon',
editable: true
}),
displayLabelForChips: false
}
};
@@ -38,7 +38,6 @@ const templateTypes = {
clickableTemplate: 'clickableTemplate',
multilineTemplate: 'multilineTemplate',
chipsTemplate: 'chipsTemplate',
emptyTemplate: 'emptyTemplate',
defaultTemplate: 'defaultTemplate'
};
@@ -74,9 +73,6 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
@Input()
multiValueSeparator: string = DEFAULT_SEPARATOR;
@Input()
displayLabelForChips = false;
editedValue: string | string[];
errors: CardViewItemValidator[];
templateType: string;
@@ -128,7 +124,7 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
this.templateType = templateTypes.defaultTemplate;
}
} else {
this.templateType = templateTypes.emptyTemplate;
this.templateType = templateTypes.defaultTemplate;
}
}
@@ -253,10 +249,6 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
return this.property.multivalued && this.useChipsForMultiValueProperty;
}
get showLabelForChips(): boolean {
return this.displayLabelForChips;
}
private prepareIntLongValue(value: string): string {
return String(Math.trunc(Number(value)));
}
@@ -9,8 +9,7 @@
[displayClearAction]="displayClearAction"
[copyToClipboardAction]="copyToClipboardAction"
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
[multiValueSeparator]="multiValueSeparator"
[displayLabelForChips]="displayLabelForChips" />
[multiValueSeparator]="multiValueSeparator" />
</div>
</div>
</div>
@@ -5,21 +5,6 @@
border-color: var(--adf-theme-foreground-divider-color);
border-radius: 0;
.adf-property-label {
color: var(--adf-metadata-property-panel-text-color);
display: flex;
line-height: 20px;
margin-bottom: 4px;
&.adf-property-readonly-value {
color: var(--adf-metadata-property-panel-label-color);
}
&.adf-property-value-editable {
color: var(--adf-metadata-property-panel-title-color);
}
}
.adf-property-container {
margin-bottom: 12px;
}
@@ -22,8 +22,6 @@ import { CardViewComponent } from './card-view.component';
import { CardViewSelectItemModel } from '../../models/card-view-selectitem.model';
import { of } from 'rxjs';
import { CardViewSelectItemOption } from '../../interfaces/card-view-selectitem-properties.interface';
import { CardViewItem } from '../../interfaces/card-view-item.interface';
import { CardViewItemDispatcherComponent } from '../card-view-item-dispatcher/card-view-item-dispatcher.component';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatDialogModule } from '@angular/material/dialog';
@@ -53,7 +51,7 @@ describe('CardViewComponent', () => {
const getPropertyLabel = (): string => testingUtils.getInnerTextByCSS('.adf-property-label');
const getPropertyValue = (): string => testingUtils.getByCSS('.adf-property-value').nativeElement.value;
const getPropertyValueText = (): string => testingUtils.getInnerTextByCSS('.adf-property-value');
const getPropertyValueText = (): string => testingUtils.getInnerTextByCSS('.adf-datepicker-span-button');
const getPropertyValueByDataAutomationId = (dataAutomationId: string): string =>
testingUtils.getByDataAutomationId(dataAutomationId).nativeElement.value;
@@ -223,34 +221,4 @@ describe('CardViewComponent', () => {
expect(await currentOptions[0].getText()).toContain(options[0].label);
expect(await currentOptions[1].getText()).toContain(options[1].label);
});
it('should show/hide the label for multivalued chip property based on displayLabelForChips input', () => {
const multiValueProperty: CardViewItem = new CardViewTextItemModel({
label: 'My Multivalue Label',
value: ['Value 1', 'Value 2', 'Value 3'],
key: 'multi-key'
});
component.properties = [multiValueProperty];
fixture.detectChanges();
const cardViewItemDispatcherComponent = getCardViewItemDispatcherComponent();
expect(cardViewItemDispatcherComponent.displayLabelForChips).toBe(false);
component.displayLabelForChips = true;
fixture.detectChanges();
expect(cardViewItemDispatcherComponent.displayLabelForChips).toBe(true);
});
/**
* Return the card view item dispatcher component
*
* @returns the dispatcher component instance
*/
function getCardViewItemDispatcherComponent(): CardViewItemDispatcherComponent {
const cardViewItemDispatcherDebugElement = testingUtils.getByDirective(CardViewItemDispatcherComponent);
return cardViewItemDispatcherDebugElement.componentInstance as CardViewItemDispatcherComponent;
}
});
@@ -60,8 +60,4 @@ export class CardViewComponent {
/** String separator between multi-value property items. */
@Input()
multiValueSeparator: string = DEFAULT_SEPARATOR;
/** Toggles whether or not to show label for multivalued chip property. */
@Input()
displayLabelForChips: boolean = false;
}
@@ -92,14 +92,6 @@ export const cardViewArgTypes: ArgTypes = {
type: { summary: 'string' },
defaultValue: { summary: ', ' }
}
},
displayLabelForChips: {
control: 'boolean',
description: 'Display label for chips property',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
}
};
@@ -113,8 +105,7 @@ export const cardViewDefaultArgs: Record<string, unknown> = {
displayClearAction: true,
copyToClipboardAction: true,
useChipsForMultiValueProperty: true,
multiValueSeparator: ', ',
displayLabelForChips: false
multiValueSeparator: ', '
};
/**
@@ -3,14 +3,14 @@
{{'COMMENTS.HEADER' | translate: { count: comments?.length } }}
</div>
<div *ngIf="!readOnly" class="adf-comments-input-container adf-comments-divider">
<mat-form-field>
<mat-form-field class="adf-comments-input-form-field">
<mat-label>{{ 'COMMENTS.ADD' | translate }}</mat-label>
<textarea
#commentInput
matInput
id="comment-input"
class="adf-text-text-area"
[placeholder]='("COMMENTS.ADD" | translate) + "*"'
[attr.aria-label]="'COMMENTS.ADD' | translate"
[attr.aria-label]='("COMMENTS.ADD" | translate) + "*"'
[formControl]="commentControl"
(keydown.escape)="clearMessage($event)"
>
@@ -8,35 +8,11 @@ adf-comments {
.adf-comments-input-container {
width: 100%;
padding-bottom: 8px;
padding: 10px 0;
#{ms.$mat-form-field} {
.adf-comments-input-form-field {
width: 100%;
&#{ms.$mat-form-field-invalid} {
#{ms.$mat-input-element} {
&::placeholder,
&:focus::placeholder {
color: var(--theme-warn-color);
}
}
}
}
#{ms.$mat-form-field-wrapper} {
#{ms.$mat-form-field-flex} {
#{ms.$mat-form-field-infix} {
padding-bottom: 2px;
padding-top: 25px;
}
}
#{ms.$mat-input-element} {
&:focus::placeholder {
color: var(--theme-primary-color);
-webkit-font-smoothing: subpixel-antialiased;
}
}
margin-bottom: 10px;
}
textarea {
@@ -46,10 +22,6 @@ adf-comments {
}
}
.adf-comments-divider {
border-bottom: 1px solid var(--adf-theme-foreground-divider-color);
}
.adf-comments-header {
padding: 10px 0;
font-size: var(--theme-body-1-font-size);
@@ -57,7 +29,6 @@ adf-comments {
}
.adf-comments-input-actions {
padding-top: 16px;
display: flex;
justify-content: flex-end;
}
@@ -22,16 +22,18 @@
<mat-divider class="adf-columns-selector-divider" aria-hidden="true" />
<div class="adf-columns-selector-search-input-container">
<mat-icon class="adf-columns-selector-search-input-icon" adf-icon="search" />
<mat-form-field class="adf-columns-selector-search-input-form">
<mat-label>{{ 'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate }}</mat-label>
<input
[formControl]="searchInputControl"
class="adf-columns-selector-search-input"
data-automation-id="adf-columns-selector-search-input"
matInput
type="text"
[placeholder]='"ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH" | translate'>
</div>
data-automation-id="adf-columns-selector-search-input"
[placeholder]="'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate"
[formControl]="searchInputControl"/>
<mat-icon matSuffix>
search
</mat-icon>
</mat-form-field>
<mat-selection-list
class="adf-columns-selector-list-container"
@@ -83,33 +83,9 @@ adf-datatable-column-selector {
margin: 16px 0;
}
&-search-input-container {
@include adf-columns-selector-side-padding;
position: relative;
&-search-input-form {
display: flex;
align-items: center;
margin-bottom: 9px;
}
&-search-input {
padding: 10px 10px 10px 29px;
width: 100%;
outline: 0;
border-radius: 6px;
border: 1px solid var(--theme-background-color);
background: var(--theme-background-color);
&:focus {
outline: none;
}
}
&-search-input-icon {
position: absolute;
left: 17px;
top: 10px;
font-size: var(--theme-adf-icon-1-font-size);
padding: 10px 12px 0;
}
}
}
@@ -34,6 +34,9 @@ describe('ColumnsSelectorComponent', () => {
const menuOpenedTrigger = new Subject<void>();
const menuClosedTrigger = new Subject<void>();
const getSelectorInputValue = (): Promise<string> => testingUtils.getMatInputValueByDataAutomationId('adf-columns-selector-search-input');
const fillSelectorInput = (value: string): Promise<void> =>
testingUtils.fillMatInputByDataAutomationId('adf-columns-selector-search-input', value);
let mainMenuTrigger: { menuOpened: Observable<void>; menuClosed: Observable<void> };
@@ -93,21 +96,19 @@ describe('ColumnsSelectorComponent', () => {
afterEach(() => fixture.destroy());
it('should clear search after closing menu', fakeAsync(() => {
it('should clear search after closing menu', fakeAsync(async () => {
menuOpenedTrigger.next();
fixture.detectChanges();
let searchInput = testingUtils.getByCSS('.adf-columns-selector-search-input').nativeElement;
testingUtils.fillInputByCSS('.adf-columns-selector-search-input', 'TEST');
await fillSelectorInput('TEST');
tick(300);
expect(searchInput.value).toBe('TEST');
expect(await getSelectorInputValue()).toBe('TEST');
menuClosedTrigger.next();
tick(300);
searchInput = testingUtils.getByCSS('.adf-columns-selector-search-input').nativeElement;
expect(searchInput.value).toBe('');
expect(await getSelectorInputValue()).toBe('');
}));
it('should list only columns with title', async () => {
@@ -130,7 +131,7 @@ describe('ColumnsSelectorComponent', () => {
fixture.detectChanges();
menuOpenedTrigger.next();
testingUtils.fillInputByCSS('.adf-columns-selector-search-input', inputColumns[0].title);
await fillSelectorInput(inputColumns[0].title);
tick(400);
fixture.detectChanges();
@@ -28,6 +28,8 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ColumnsSearchFilterPipe } from './columns-search-filter.pipe';
import { MatListOption, MatSelectionList, MatSelectionListChange } from '@angular/material/list';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { IconModule } from '../../../icon/icon.module';
@Component({
@@ -42,7 +44,9 @@ import { IconModule } from '../../../icon/icon.module';
MatCheckboxModule,
ColumnsSearchFilterPipe,
MatSelectionList,
MatListOption
MatListOption,
MatFormFieldModule,
MatInputModule
],
templateUrl: './columns-selector.component.html',
styleUrls: ['./columns-selector.component.scss'],
@@ -1,5 +1,5 @@
<div class="{{ field.className }} date-widget-container" id="data-widget" [class.adf-invalid]="dateInputControl.invalid && dateInputControl.touched">
<mat-form-field [floatLabel]="'always'" class="adf-date-widget adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
<mat-form-field class="adf-date-widget adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
<mat-label class="adf-label"
[id]="field.id + '-label'"
[attr.for]="field.id">
@@ -57,7 +57,9 @@
.adf-login-card-wide {
border-radius: 8px;
background-color: var(--adf-theme-background-dialog-color);
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 0 2px 0 rgba(0, 0, 0, 0.12);
box-shadow:
0 2px 2px 0 rgba(0, 0, 0, 0.24),
0 0 2px 0 rgba(0, 0, 0, 0.12);
width: 450px;
min-width: 320px;
padding: 21px 64px 34px;
@@ -182,11 +184,11 @@
}
.adf-login-form-field .adf-login-password-icon.adf-login-form-password-icon {
display: flex;
justify-content: center;
align-items: center;
color: var(--adf-theme-foreground-text-color);
font-size: var(--theme-subheading-2-font-size);
top: 9px;
position: relative;
left: 7px;
}
.adf-login-controls:has(div) {
@@ -205,10 +207,6 @@
font-size: var(--theme-subheading-2-font-size);
#{ms.$mat-form-field-infix} {
min-height: 0;
padding-bottom: 3px;
padding-top: 20px;
.adf-login-form-input-label {
font-size: var(--theme-subheading-2-font-size);
}
@@ -3,7 +3,7 @@
[@transitionMessages]="subscriptAnimationState"
(@transitionMessages.done)="applySearchFocus($event)">
<button mat-icon-button
*ngIf="expandable"
*ngIf="expandable && !isSearchBarActive()"
id="adf-search-button"
class="adf-search-button"
[ngClass]="{'adf-search-button-inactive': subscriptAnimationState.value === 'inactive'}"
@@ -1,14 +1,8 @@
@use '../styles/mat-selectors' as ms;
.adf-search-container {
&:has(.adf-input-form-field-divider) {
overflow: hidden;
}
#{ms.$mat-form-field-subscript-wrapper} {
display: none;
}
.adf-search-container-transition {
display: flex;
align-items: center;
@@ -80,6 +80,7 @@ describe('SearchTextInputComponent', () => {
describe('search button', () => {
let searchButton: DebugElement;
beforeEach(fakeAsync(() => {
fixture.detectChanges();
tick(100);
@@ -89,13 +90,14 @@ describe('SearchTextInputComponent', () => {
it('should NOT display a autocomplete list control when configured not to', fakeAsync(() => {
component.subscriptAnimationState.value = 'active';
component.showClearButton = true;
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('active');
searchButton.triggerEventHandler('click', null);
testingUtils.clickByDataAutomationId('adf-clear-search-button');
fixture.detectChanges();
tick(100);
fixture.detectChanges();
@@ -118,30 +120,6 @@ describe('SearchTextInputComponent', () => {
discardPeriodicTasks();
}));
it('Search button should not change the input state too often', fakeAsync(() => {
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('active');
searchButton.triggerEventHandler('click', null);
fixture.detectChanges();
tick(100);
searchButton.triggerEventHandler('click', null);
fixture.detectChanges();
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('inactive');
discardPeriodicTasks();
}));
it('Search bar should close when user press ESC button', fakeAsync(() => {
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
@@ -186,7 +164,7 @@ describe('SearchTextInputComponent', () => {
function testMarginValue(isLtr: boolean): void {
userPreferencesService.setWithoutStore('textOrientation', isLtr ? 'ltr' : 'rtl');
clickSearchButton();
const expectedResult = isLtr ? { 'margin-left': 13 } : { 'margin-right': 13 };
const expectedResult = isLtr ? { 'margin-left': 0 } : { 'margin-right': 0 };
expect(component.subscriptAnimationState.params).toEqual(expectedResult);
discardPeriodicTasks();
}
@@ -206,8 +184,7 @@ describe('SearchTextInputComponent', () => {
*/
function testTransformValue(isLtr: boolean): void {
userPreferencesService.setWithoutStore('textOrientation', isLtr ? 'ltr' : 'rtl');
component.subscriptAnimationState.value = 'active';
clickSearchButton();
component.subscriptAnimationState.value = 'inactive';
const expectedValue = isLtr ? 'translateX(100%)' : 'translateX(-100%)';
expect(component.subscriptAnimationState.params).toEqual({ transform: expectedValue });
discardPeriodicTasks();
@@ -364,7 +341,7 @@ describe('SearchTextInputComponent', () => {
component.expandable = true;
component.showClearButton = true;
fixture.detectChanges();
component.subscriptAnimationState.value = 'active';
component.subscriptAnimationState.value = 'inactive';
fixture.detectChanges();
tick(200);
}));
@@ -387,6 +364,8 @@ describe('SearchTextInputComponent', () => {
});
it('should contain correct translation key for clear button title', () => {
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
const clearButton = testingUtils.getByDataAutomationId('adf-clear-search-button');
expect(clearButton.nativeElement.getAttribute('title')).toBe('CORE.SEARCH.FILTER.BUTTONS.CLOSE');
});
@@ -216,11 +216,11 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
private toggleAnimation() {
if (this.dir === 'ltr') {
return this.subscriptAnimationState.value === 'inactive'
? { value: 'active', params: { 'margin-left': 13 } }
? { value: 'active', params: { 'margin-left': 0 } }
: { value: 'inactive', params: { transform: 'translateX(100%)' } };
} else {
return this.subscriptAnimationState.value === 'inactive'
? { value: 'active', params: { 'margin-right': 13 } }
? { value: 'active', params: { 'margin-right': 0 } }
: { value: 'inactive', params: { transform: 'translateX(-100%)' } };
}
}
@@ -9,20 +9,15 @@ $mat-tab-body: '.mat-mdc-tab-body';
$mat-tab-header: '.mat-mdc-tab-header';
$mat-tab-body-content: '.mat-mdc-tab-body-content';
$mat-tab-ink-bar: '.mdc-tab-indicator';
$mat-tab-body-wrapper: '.mat-mdc-tab-body-wrapper';
$mat-tab-body-content: '.mat-mdc-card-content';
$mat-chip: '.mat-mdc-chip';
$mat-chip-list: '.mat-mdc-chip-list';
$mat-checkbox: '.mat-mdc-checkbox';
$mat-checkbox-label: '.mdc-label';
$mat-button: '.mat-mdc-button';
$mat-button-label: '.mdc-button__label';
$mat-form-field-input-control: '.mat-mdc-form-field-input-control';
$mat-form-field: '.mat-mdc-form-field';
$mat-form-field-flex: '.mat-mdc-form-field-flex';
$mat-form-field-wrapper: '.mat-mdc-text-field-wrapper';
$mat-line-ripple: '.mdc-line-ripple';
$mat-form-field-subscript-wrapper: '.mat-mdc-form-field-subscript-wrapper';
$mat-form-field-prefix: '.mat-mdc-form-field-text-prefix';
$mat-form-field-suffix: '.mat-mdc-form-field-text-suffix';
$mat-form-text-field-infix: '.mat-mdc-form-text-infix';
@@ -38,7 +33,6 @@ $mat-table: '.mat-mdc-table';
$mat-header-row: '.mat-mdc-header-row';
$mat-row: '.mat-mdc-row';
$mat-select: '.mat-mdc-select';
$mat-select-value: '.mat-select-value';
$mat-select-panel: '.mat-mdc-select-panel';
$mat-grid-tile: '.mat-grid-tile';
$mat-sidenav-content: '.mat-sidenav-content';
@@ -56,36 +50,24 @@ $mat-calendar-table-header: '.mat-calendar-table-header';
$mat-calendar-body-disabled: '.mat-calendar-body-disabled';
$mat-toolbar: '.mat-toolbar';
$mat-list-item-unscoped-content: '.mat-mdc-list-item-unscoped-content';
$mat-list-item: '.mat-mdc-list-item';
$mat-list-item-end: '.mdc-list-item__end';
$mat-text-field-no-label: '.mdc-text-field--no-label';
$mat-form-field-infix: '.mat-mdc-form-field-infix';
$mat-form-field-error-wrapper: '.mat-mdc-form-field-error-wrapper';
$mat-form-field-error: '.mat-mdc-form-field-error';
$mat-checkbox-background: '.mdc-checkbox__background';
$mat-floating-label: '.mdc-floating-label';
$mat-floating-label-above: '.mdc-floating-label--float-above';
$mat-dialog-surface: '.mat-mdc-dialog-surface';
$mat-floating-label-required: '.mdc-floating-label--required';
$mat-evolution-chip: '.mdc-evolution-chip';
$mat-evolution-chip-action: '.mdc-evolution-chip__action';
$mat-evolution-chip-text-label: '.mdc-evolution-chip__text-label';
$mat-notched-outline: '.mdc-notched-outline';
$mat-evolution-chip-graphic: '.mdc-evolution-chip__graphic';
$mat-select-trigger: '.mat-mdc-select-trigger';
$mat-button-base: '.mat-mdc-button-base';
$mat-button-touch-target: '.mat-mdc-button-touch-target';
$cdk-drag-preview: '.cdk-drag-preview';
$mat-snackbar: '.mdc-snackbar';
$mat-snack-bar-container: '.mat-mdc-snack-bar-container';
$mat-snackbar-label: '.mdc-snackbar__label';
$mat-datetimepicker-dialog: '.mat-datetimepicker-dialog';
$mat-tab-indicator-underline: '.mdc-tab-indicator__content--underline';
$mat-list-item: '.mdc-list-item';
$mat-form-field-icon-suffix: '.mat-mdc-form-field-icon-suffix';
$mat-text-field: '.mdc-text-field';
$mat-select-value: '.mat-mdc-select-value';
$mat-card-header: '.mat-mdc-card-header';
$mat-datetimepicker-calendar: '.mat-datetimepicker-calendar';
$mat-datetimepicker-calendar-header: '.mat-datetimepicker-calendar-header';
$mat-datetimepicker-calendar-table-header: '.mat-datetimepicker-calendar-table-header';
@@ -95,4 +77,3 @@ $mat-datetimepicker-calendar-header-time: '.mat-datetimepicker-calendar-header-t
$mat-datetimepicker-calendar-content: '.mat-datetimepicker-calendar-content';
$mat-datetimepicker-calendar-body-disabled: '.mat-datetimepicker-calendar-body-disabled';
$mat-datetimepicker-toggle: '.mat-datetimepicker-toggle';
$mat-form-field-underline: '.mat-form-field-underline';
@@ -95,6 +95,11 @@ export class UnitTestingUtils {
element.triggerEventHandler('dblclick', new MouseEvent('dblclick'));
}
doubleClickByCSS(selector: string): void {
const element = this.getByCSS(selector);
element.triggerEventHandler('dblclick', new MouseEvent('dblclick'));
}
blurByCSS(selector: string): void {
const element = this.getByCSS(selector);
element.triggerEventHandler('blur', new FocusEvent('blur'));
@@ -267,6 +272,14 @@ export class UnitTestingUtils {
return select.getOptions();
}
async getMatSelect(): Promise<MatSelectHarness> {
return this.loader.getHarness(MatSelectHarness);
}
async getMatSelectByDataAutomationId(dataAutomationId: string): Promise<MatSelectHarness> {
return this.loader.getHarness(MatSelectHarness.with({ selector: `[data-automation-id="${dataAutomationId}"]` }));
}
async getMatSelectHost(): Promise<TestElement> {
const select = await this.loader.getHarness(MatSelectHarness);
return select.host();
@@ -388,6 +401,11 @@ export class UnitTestingUtils {
return input.getValue();
}
async getMatInputValueByDataAutomationId(dataAutomationId: string): Promise<string> {
const input = await this.getMatInputByDataAutomationId(dataAutomationId);
return input.getValue();
}
async sendKeysToMatInput(keys: (string | TestKey)[]): Promise<void> {
const input = await this.getMatInput();
const host = await input.host();