mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACS-5645] Property Panel Feature (#8995)
* [ACS-5645]Added edit functionality for each panel and updated test cases * metadata e2e fix * [ACS-5725]fixed failing e2es * added unit test cases for new functionality * minor fixes * minor fixes * minor fixes * [ACS-5645]code modification * [ACS-5645]removed unwanted code * [ACS-5645]modified the changes * [ACS-5645]removed unwanted space * [ACS-5645]removed unwanted code * [ACS-5645]Implemented changes as per the review comments * linting fixes * [ACS-5645]minor fixes * [ACS-5645] removed unwanted code * [ACS-5645]modified the change * [ACS-5645]aligned input * [ACS-5645]modified changes * [ACS-5645]Implemented the changes as per the review comments * [ACS-5645]linting fixes * [ACS-5645]fixed sonarcloud issue * [ACS-5645]fixed errors * [ACS-5645]rename the function * [ACS-5645]fixes linting * [ACS-5540]lint fixes * [ACS-5645]Implemented the changes as per review comments * [ACS-5645] Removed unused code * [ACS-5645]linting fixes * [ACS-5645]fixes for lint * [ACS-5645] e2e fixes * [ACS-5645]Added translation * [ACS-5645]fixes for e2e * [ACS-5645]fixes for e2e * [ACS-5645]e2e fixes * [ACS-5645] Renamed the theme * [ACS-5645]modified changes * [ACS-5645] fixed lock-file bug * [ACS-5645] added tooltips for save and cancel icons * [ACS-5645] Modified the changes * [ACS-5645]Modified the changes * [ACS-5645] Implemented the changes as per the review comments * [ACS-5645] Implemented the changes as per the review comments * [ACS-5645]Modified the changes * [ACS-5645] added group panel lock changes * [ACS-5645] Resolved sonarcloud issue * [ACS-5645] added test cases for tags component * [ACS-5645] updated the documentation * [ACS-5645] updated the documentation * [ACS-5645] updated the documentation * [ACS-5645] Implemented changes as per review comments * [ACS-5645] lint fixes * [ACS-5645] Implemented the review comments * [ACS-5645] added focus * [ACS-5645] modified the changes * [ACS-5645] Lint fixes * [ACS-5645] Lint fixes * [ACS-5645] Lint fixes * [ACS-5645] Removed unwanted code * [ACS-5645] fixed sonarcloud issue * [ACS-5645] Added missing translation key * [ACS-5645] renamed the methods * [ACS-5645]Added edit functionality for each panel and updated test cases * [ACS-5645]code modification * [ACS-5645]removed unwanted code * [ACS-5645]Implemented changes as per the review comments * [ACS-5645]Implemented the changes as per review comments * [ACS-5645]linting fixes * [ACS-5645] fixed lock-file bug * [ACS-5645] Modified the changes * [ACS-5645] added group panel lock changes * [ACS-5645]Added edit functionality for each panel and updated test cases * minor fixes * [ACS-5645] Modified the changes * [ACS-5645] added group panel lock changes * [ACS-5645]Added edit functionality for each panel and updated test cases * metadata e2e fix * [ACS-5725]fixed failing e2es * minor fixes * [ACS-5645]removed unwanted code * [ACS-5645]Implemented changes as per the review comments * [ACS-5551] property panel design * [ACS-5551] minor changes * [ACS-5551]minor change * [ACS-5551] updated checks for non -editable field * [ACS-5551] modified the changes * [ACS-5551] modified changes * [ACS-5551] content-metadata updated * [ACS-5551] code updated * [ACS-5551] remove extra space * fixed scrollbar issue * [ACS-5551] margin adjusted * Fixed ACS-6110 * [ACS-5551] design updated * [ACCS-5551] unit test added * [ACS-5551] margin issue fixed * scroll issue fixed * [ACS-5551] color updated * [ACS-5551] design modify * [ACS-5551] add missing methods * [ACS-5654] translation added * [ACS-5645] style updated * [ACS-5654] hide toggle button for aspects * [ACS-5645] theme updated * [ACS-5645] tags and category tyle update * [ACS-5645] unit test update * [ACS-5645] code updated as per comments * [ACS-5645] linting issue fix * [ACS-5645] fixed the failed unit test cases * [ACS-5645] e2e fixes * [ACS-5645] e2e modify * [ACS-5645] aspect issue resolved * [ACS-5645] Address the comments * [ACS-5645] Address the comments * [ACS-5645] tags list design modify * [ACS-5645] design modify for chips * [ACS-5645] Removed unused property * [ACS-5645] Stop reload on panel cancel changes * [ACS-5645] Linting issue fixed * revert file change * [ACS-5645] update aspect issue fix * Revert "[ACS-5645] update aspect issue fix" This reverts commit 5212112f2293ad4c29afdd7c7faaf897cd3d00f6. * reduce layout duplicates, header panel component * code improvements * remove useless logging * cleanup css, remove mat-divider, fix tests * remove useless styles * cleanup e2e * cleanup useless events * rename nodeIcon to just icon * disable transition animation for tabs * remove "editable" hacks * improved naming for state properties * bug fixes for process cloud * css stylelint fixes * rework component, cleanup useless code * fix allowable operations and readonly state * wait for button * cleanup css, disable e2e * remove demo-shell only content, fix metadata * restore reset date functionality * fix incorrect styling * fix clear date button styles * cleanup text item styles * remove useless classes * text item rework, code cleanup * style bug fixes * cleanup useless tests * fix styles and tests * bug fixes for select item styles, revert PR changes * rework categories styles * rework tags creator styles * rollback divider module * fix css variable naming * fix issue with hidden properties * fix key value pairs layout and styles * fix tag creator validation * remove incorrect styles, raise proper errors * fix unit tests * fix theme vars naming * remove css hacks for date items * fix error borders * fix css bugs * reduce code * cleanup e2e and en.json * fix css linting * cleanup unused template refs * remove useless div for metadata container * cleanup expanders api * cleanup and remove useless tests * cleanup i18n * cleanup tests * cleanup css * cleanup css * [ACS-5654] added the missing theme variables * review comments resolved * fixed css issue * [ACS-5654] removesd extra div * [ACS-5654] save and cancel button bug fix * [ACS-5654] unit test fix for expand the panel * [ACS-5645] design issues fix * [ACS-5654] cards design fixed * [ACS-5654] node icon added to thumbnail service * [ACS-5645] linting issue fixed * [ACS-5645] thumbnail unit test updated * [ACS-5645] linting updated * [ACS-5645] removed extra div * [ACS-5645] important removed * [ACS-5645] tags text issue fix * [ACS-5645] add missed class * [ACS-5645] removed unused classes * [ACS-5645] removed unused code * revert flags to original state * fix missing semicolon * fix linting issues * reduce code duplication * code cleanup * [ACS-5645] unit test fix * [ACS-5645] e2e fix for edit button * fix linting issue for e2e * Replaced getNodeIcon from thumbnail to content service * fix indentation * refactor css variable * use rgba color value --------- Co-authored-by: Yasa-Nataliya <yasa.nataliya@globallogic.com> Co-authored-by: pkundu <priyanka.kundu@hyland.com> Co-authored-by: rbahirsheth <raviraj.bahirsheth@globallogic.com> Co-authored-by: Denys Vuika <denys.vuika@gmail.com>
This commit is contained in:
@@ -26,6 +26,9 @@ import { takeUntil } from 'rxjs/operators';
|
||||
export abstract class BaseCardView<T extends CardViewItem> implements OnDestroy {
|
||||
protected cardViewUpdateService = inject(CardViewUpdateService);
|
||||
|
||||
@Input()
|
||||
editable = false;
|
||||
|
||||
@Input()
|
||||
property: T;
|
||||
|
||||
@@ -39,6 +42,18 @@ export abstract class BaseCardView<T extends CardViewItem> implements OnDestroy
|
||||
});
|
||||
}
|
||||
|
||||
get isEditable(): boolean {
|
||||
return this.editable && this.property.editable;
|
||||
}
|
||||
|
||||
get isReadonlyProperty(): boolean {
|
||||
return this.editable && !this.property.editable;
|
||||
}
|
||||
|
||||
get hasIcon(): boolean {
|
||||
return !!this.property.icon;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next(true);
|
||||
this.destroy$.complete();
|
||||
|
@@ -33,11 +33,7 @@ export class CardViewArrayItemComponent extends BaseCardView<CardViewArrayItemMo
|
||||
}
|
||||
|
||||
showClickableIcon(): boolean {
|
||||
return this.hasIcon() && this.isClickable();
|
||||
}
|
||||
|
||||
hasIcon(): boolean {
|
||||
return !!this.property.icon;
|
||||
return this.hasIcon && this.isClickable();
|
||||
}
|
||||
|
||||
displayCount(): number {
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<ng-container *ngIf="!property.isEmpty() || isEditable()">
|
||||
<ng-container *ngIf="!property.isEmpty() || isEditable">
|
||||
<div class="adf-property-value">
|
||||
<mat-checkbox [attr.data-automation-id]="'card-boolean-' + property.key"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.TOGGLE' | translate"
|
||||
[checked]="property.displayValue"
|
||||
[disabled]="!isEditable()"
|
||||
[disabled]="!isEditable"
|
||||
color="primary"
|
||||
(change)="changed($event)">
|
||||
<div [attr.data-automation-id]="'card-boolean-label-' + property.key"
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||
import { CardViewBoolItemModel } from '../../models/card-view-boolitem.model';
|
||||
import { BaseCardView } from '../base-card-view';
|
||||
@@ -26,13 +26,6 @@ import { BaseCardView } from '../base-card-view';
|
||||
})
|
||||
|
||||
export class CardViewBoolItemComponent extends BaseCardView<CardViewBoolItemModel> {
|
||||
@Input()
|
||||
editable: boolean;
|
||||
|
||||
isEditable() {
|
||||
return this.editable && this.property.editable;
|
||||
}
|
||||
|
||||
changed(change: MatCheckboxChange) {
|
||||
this.cardViewUpdateService.update({ ...this.property } as CardViewBoolItemModel, change.checked );
|
||||
this.property.value = change.checked;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
<label class="adf-property-label"
|
||||
[attr.data-automation-id]="'card-dateitem-label-' + property.key"
|
||||
*ngIf="showProperty() || isEditable()"
|
||||
[attr.for]="'card-view-dateitem-' + property.key">
|
||||
*ngIf="showProperty() || isEditable"
|
||||
[attr.for]="'card-view-dateitem-' + property.key"
|
||||
[ngClass]="{'adf-property-readonly-value': isReadonlyProperty, 'adf-property-value-editable': editable}">
|
||||
{{ property.label | translate }}
|
||||
</label>
|
||||
<div class="adf-property-value adf-property-value-padding-top">
|
||||
<span *ngIf="!isEditable() && !property.multivalued"
|
||||
<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"
|
||||
@@ -13,45 +14,47 @@
|
||||
matTooltipShowDelay="1000"
|
||||
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate">{{ property.displayValue}}</span>
|
||||
</span>
|
||||
<div *ngIf="isEditable() && !property.multivalued"
|
||||
class="adf-dateitem-editable">
|
||||
<div *ngIf="isEditable && !property.multivalued" class="adf-dateitem-editable">
|
||||
<div class="adf-dateitem-editable-controls">
|
||||
<span class="adf-datepicker-toggle"
|
||||
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
|
||||
(click)="showDatePicker()">
|
||||
<span *ngIf="showProperty(); else elseEmptyValueBlock"
|
||||
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
|
||||
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
|
||||
{{ property.displayValue }}</span>
|
||||
</span>
|
||||
|
||||
<mat-icon *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">
|
||||
<mat-icon
|
||||
*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">
|
||||
clear
|
||||
</mat-icon>
|
||||
|
||||
<mat-datetimepicker-toggle [attr.tabindex]="-1"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.data-automation-id]="'datepickertoggle-' + property.key"
|
||||
[for]="datetimePicker">
|
||||
<mat-datetimepicker-toggle
|
||||
[attr.tabindex]="-1"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.data-automation-id]="'datepickertoggle-' + property.key"
|
||||
[for]="datetimePicker">
|
||||
</mat-datetimepicker-toggle>
|
||||
</div>
|
||||
|
||||
<input class="adf-invisible-date-input"
|
||||
[attr.tabIndex]="-1"
|
||||
[matDatetimepicker]="datetimePicker"
|
||||
[value]="valueDate"
|
||||
(dateChange)="onDateChanged($event)"
|
||||
[attr.id]="'card-view-dateitem-' + property.key"
|
||||
>
|
||||
<input
|
||||
class="adf-invisible-date-input"
|
||||
[attr.tabIndex]="-1"
|
||||
[matDatetimepicker]="datetimePicker"
|
||||
[value]="valueDate"
|
||||
(dateChange)="onDateChanged($event)"
|
||||
[attr.id]="'card-view-dateitem-' + property.key">
|
||||
|
||||
<mat-datetimepicker #datetimePicker
|
||||
[type]="$any(property).type"
|
||||
[timeInterval]="5"
|
||||
[attr.data-automation-id]="'datepicker-' + property.key"
|
||||
[startAt]="valueDate">
|
||||
<mat-datetimepicker
|
||||
#datetimePicker
|
||||
[type]="$any(property).type"
|
||||
[timeInterval]="5"
|
||||
[attr.data-automation-id]="'datepicker-' + property.key"
|
||||
[startAt]="valueDate">
|
||||
</mat-datetimepicker>
|
||||
</div>
|
||||
<ng-template #elseEmptyValueBlock>
|
||||
@@ -60,41 +63,37 @@
|
||||
|
||||
<div *ngIf="property.multivalued"
|
||||
class="adf-property-field adf-dateitem-chip-list-container adf-dateitem-editable">
|
||||
<mat-chip-list #chipList
|
||||
class="adf-textitem-chip-list">
|
||||
<mat-chip *ngFor="let propertyValue of property.displayValue; let idx = index"
|
||||
[removable]="isEditable()"
|
||||
(removed)="removeValueFromList(idx)">
|
||||
<mat-chip-list #chipList class="adf-textitem-chip-list">
|
||||
<mat-chip
|
||||
*ngFor="let propertyValue of property.displayValue; let idx = index"
|
||||
[removable]="isEditable"
|
||||
(removed)="removeValueFromList(idx)">
|
||||
{{ propertyValue }}
|
||||
<mat-icon *ngIf="isEditable()"
|
||||
matChipRemove>cancel</mat-icon>
|
||||
<mat-icon *ngIf="isEditable" matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<mat-form-field *ngIf="isEditable()"
|
||||
class="adf-property-field adf-dateitem-editable-controls"
|
||||
[floatLabel]="'never'"
|
||||
(click)="showDatePicker()">
|
||||
<input matInput
|
||||
class="adf-invisible-date-input"
|
||||
[attr.tabIndex]="-1"
|
||||
[matDatetimepicker]="datetimePicker"
|
||||
(dateChange)="addDateToList($event)"
|
||||
[attr.id]="'card-view-dateitem-' + property.key"
|
||||
>
|
||||
<mat-datetimepicker-toggle [attr.tabindex]="-1"
|
||||
matSuffix
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.data-automation-id]="'datepickertoggle-' + property.key"
|
||||
[for]="datetimePicker">
|
||||
<div *ngIf="isEditable" class="adf-property-field adf-dateitem-editable-controls" (click)="showDatePicker()">
|
||||
<input
|
||||
class="adf-invisible-date-input"
|
||||
[attr.tabIndex]="-1"
|
||||
[matDatetimepicker]="datetimePicker"
|
||||
(dateChange)="addDateToList($event)"
|
||||
[attr.id]="'card-view-dateitem-' + property.key">
|
||||
<mat-datetimepicker-toggle
|
||||
[attr.tabindex]="-1"
|
||||
matSuffix
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.data-automation-id]="'datepickertoggle-' + property.key"
|
||||
[for]="datetimePicker">
|
||||
</mat-datetimepicker-toggle>
|
||||
|
||||
<mat-datetimepicker #datetimePicker
|
||||
[type]="$any(property).type"
|
||||
[timeInterval]="5"
|
||||
[attr.data-automation-id]="'datepicker-' + property.key"
|
||||
[startAt]="valueDate">
|
||||
<mat-datetimepicker
|
||||
#datetimePicker
|
||||
[type]="$any(property).type"
|
||||
[timeInterval]="5"
|
||||
[attr.data-automation-id]="'datepicker-' + property.key"
|
||||
[startAt]="valueDate">
|
||||
</mat-datetimepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,6 +1,21 @@
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
.adf {
|
||||
&-invisible-date-input {
|
||||
.adf-card-view-dateitem {
|
||||
.adf-property-value {
|
||||
padding: 6px 0;
|
||||
line-height: 20px;
|
||||
border-bottom: 1px solid var(--adf-metadata-property-panel-border-color);
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
|
||||
&.adf-property-value-editable {
|
||||
border-radius: 6px;
|
||||
border-bottom: inherit;
|
||||
}
|
||||
|
||||
&.adf-property-readonly-value {
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-invisible-date-input {
|
||||
height: 2px;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
@@ -11,33 +26,24 @@
|
||||
float: right;
|
||||
}
|
||||
|
||||
&-dateitem-chip-list-container.adf-property-field {
|
||||
.adf-dateitem-chip-list-container.adf-property-field {
|
||||
margin-bottom: -7px !important;
|
||||
border-bottom: 0;
|
||||
cursor: pointer;
|
||||
|
||||
.adf-dateitem-editable-controls {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.mat-datetimepicker-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-dateitem-editable {
|
||||
.adf-dateitem-editable {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid var(--adf-theme-foreground-text-color-042);
|
||||
padding-bottom: 6px;
|
||||
padding: 0 12px;
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
&-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 6px;
|
||||
|
||||
button.mat-icon-button {
|
||||
.mat-icon-button {
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
@@ -47,29 +53,21 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover mat-icon {
|
||||
opacity: 1;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-datepicker-toggle {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
mat-icon.adf-date-reset-icon {
|
||||
.adf-date-reset-icon {
|
||||
line-height: 10px;
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
padding-left: 8px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&:hover mat-icon.adf-date-reset-icon {
|
||||
opacity: 1;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -166,7 +166,7 @@ describe('CardViewDateItemComponent', () => {
|
||||
component.property.editable = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isEditable()).toBe(false);
|
||||
expect(component.isEditable).toBe(false);
|
||||
const datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`));
|
||||
const datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`));
|
||||
expect(datePicker).toBeNull('Datepicker should NOT be in DOM');
|
||||
|
@@ -20,7 +20,6 @@ import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
|
||||
import { DatetimeAdapter, MAT_DATETIME_FORMATS, MatDatetimepickerComponent, MatDatetimepickerInputEvent } from '@mat-datetimepicker/core';
|
||||
import { CardViewDateItemModel } from '../../models/card-view-dateitem.model';
|
||||
import { UserPreferencesService, UserPreferenceValues } from '../../../common/services/user-preferences.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { BaseCardView } from '../base-card-view';
|
||||
import { ClipboardService } from '../../../clipboard/clipboard.service';
|
||||
@@ -45,24 +44,16 @@ import { isValid } from 'date-fns';
|
||||
})
|
||||
export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemModel> implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
property: CardViewDateItemModel;
|
||||
displayEmpty = true;
|
||||
|
||||
@Input()
|
||||
editable: boolean = false;
|
||||
|
||||
@Input()
|
||||
displayEmpty: boolean = true;
|
||||
|
||||
@Input()
|
||||
displayClearAction: boolean = true;
|
||||
displayClearAction = true;
|
||||
|
||||
@ViewChild('datetimePicker')
|
||||
public datepicker: MatDatetimepickerComponent<any>;
|
||||
|
||||
valueDate: Date;
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
private dateAdapter: DateAdapter<Date>,
|
||||
private userPreferencesService: UserPreferencesService,
|
||||
@@ -75,7 +66,7 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
||||
ngOnInit() {
|
||||
this.userPreferencesService
|
||||
.select(UserPreferenceValues.Locale)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((locale) => {
|
||||
this.property.locale = locale;
|
||||
});
|
||||
@@ -94,8 +85,7 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
showProperty(): boolean {
|
||||
@@ -106,10 +96,6 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
||||
return this.displayClearAction && (!this.property.isEmpty() || !!this.property.default);
|
||||
}
|
||||
|
||||
isEditable(): boolean {
|
||||
return this.editable && this.property.editable;
|
||||
}
|
||||
|
||||
showDatePicker() {
|
||||
this.datepicker.open();
|
||||
}
|
||||
|
@@ -2,11 +2,8 @@
|
||||
class="adf-property-label">{{ property.label | translate }}</div>
|
||||
<div class="adf-property-field">
|
||||
|
||||
<div *ngIf="!isEditable()"
|
||||
class="adf-card-view__key-value-pairs__read-only adf-property-value">
|
||||
<mat-table #table
|
||||
[dataSource]="matTableValues"
|
||||
class="mat-elevation-z8">
|
||||
<div *ngIf="!isEditable" class="adf-card-view__key-value-pairs__read-only adf-property-value">
|
||||
<mat-table #table [dataSource]="matTableValues" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef>{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}
|
||||
</mat-header-cell>
|
||||
@@ -23,50 +20,44 @@
|
||||
</mat-table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="adf-card-view__key-value-pairs adf-property-value"
|
||||
*ngIf="isEditable() && values && values.length">
|
||||
<div class="adf-card-view__key-value-pairs adf-property-value" *ngIf="isEditable && values && values.length">
|
||||
<div class="adf-card-view__key-value-pairs__row">
|
||||
<div class="adf-card-view__key-value-pairs__col">{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}</div>
|
||||
<div class="adf-card-view__key-value-pairs__col">{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}</div>
|
||||
<div class="adf-property-col-key">{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}</div>
|
||||
<div class="adf-property-col-value">{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}</div>
|
||||
</div>
|
||||
|
||||
<div class="adf-card-view__key-value-pairs__row"
|
||||
*ngFor="let item of values; let i = index">
|
||||
<div class="adf-card-view__key-value-pairs__col">
|
||||
<mat-form-field>
|
||||
<input matInput
|
||||
placeholder="{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}"
|
||||
(blur)="onBlur(item.value)"
|
||||
[attr.data-automation-id]="'card-'+ property.key +'-name-input-' + i"
|
||||
[(ngModel)]="values[i].name">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="adf-card-view__key-value-pairs__col">
|
||||
<mat-form-field>
|
||||
<input matInput
|
||||
placeholder="{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}"
|
||||
(blur)="onBlur(item.value)"
|
||||
[attr.data-automation-id]="'card-'+ property.key +'-value-input-' + i"
|
||||
[(ngModel)]="values[i].value">
|
||||
<button matSuffix
|
||||
mat-icon-button
|
||||
(click)="remove(i)"
|
||||
class="adf-card-view__key-value-pairs__remove-btn">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="adf-card-view__key-value-pairs__row" *ngFor="let item of values; let i = index">
|
||||
<input
|
||||
matInput
|
||||
class="adf-property-col-key adf-property-value-input"
|
||||
placeholder="{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}"
|
||||
(blur)="onBlur(item.value)"
|
||||
[attr.data-automation-id]="'card-'+ property.key +'-name-input-' + i"
|
||||
[(ngModel)]="values[i].name">
|
||||
|
||||
<input
|
||||
matInput
|
||||
class="adf-property-col-value adf-property-value-input"
|
||||
placeholder="{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}"
|
||||
(blur)="onBlur(item.value)"
|
||||
[attr.data-automation-id]="'card-'+ property.key +'-value-input-' + i"
|
||||
[(ngModel)]="values[i].value">
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="remove(i)"
|
||||
class="adf-property-col-delete">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isEditable()"
|
||||
class="adf-property-value adf-card-view__key-value-pairs__add-btn-container">
|
||||
<div *ngIf="isEditable" class="adf-property-value adf-card-view__key-value-pairs__add-btn-container">
|
||||
<button (click)="add()"
|
||||
mat-button
|
||||
class="adf-card-view__key-value-pairs__add-btn"
|
||||
[attr.data-automation-id]="'card-key-value-pairs-button-' + property.key">
|
||||
{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.ADD' | translate }}
|
||||
<mat-icon>add</mat-icon>
|
||||
{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.ADD' | translate }}
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,43 +1,48 @@
|
||||
.adf-card-view {
|
||||
&__key-value-pairs {
|
||||
&__row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.adf-card-view-key-value-pairs-item {
|
||||
.adf-property-col-key {
|
||||
width: 50%;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&__col {
|
||||
width: 50%;
|
||||
.adf-property-col-value {
|
||||
margin-left: 4px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
width: 100%;
|
||||
font-size: var(--theme-body-1-font-size);
|
||||
.adf-property-col-delete {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.adf-card-view {
|
||||
&__key-value-pairs {
|
||||
&__row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-form-field-appearance-legacy .mat-form-field-label {
|
||||
color: var(--adf-theme-foreground-text-color-040) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&__add-btn-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__add-btn.mat-button {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__read-only {
|
||||
padding-bottom: 20px;
|
||||
|
||||
.mat-table {
|
||||
box-shadow: none;
|
||||
&__add-btn-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mat-header-row,
|
||||
.mat-row {
|
||||
padding: 0;
|
||||
&__add-btn.mat-button {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__read-only {
|
||||
padding-bottom: 20px;
|
||||
|
||||
.mat-table {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.mat-header-row,
|
||||
.mat-row {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -75,7 +75,7 @@ describe('CardViewKeyValuePairsItemComponent', () => {
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isEditable()).toBe(false);
|
||||
expect(component.isEditable).toBe(false);
|
||||
const table = fixture.debugElement.query(By.css('.adf-card-view__key-value-pairs__read-only'));
|
||||
const form = fixture.debugElement.query(By.css('.adf-card-view__key-value-pairs'));
|
||||
|
||||
@@ -111,7 +111,7 @@ describe('CardViewKeyValuePairsItemComponent', () => {
|
||||
addButton.triggerEventHandler('click', null);
|
||||
fixture.detectChanges();
|
||||
|
||||
const removeButton = fixture.debugElement.query(By.css('.adf-card-view__key-value-pairs__remove-btn'));
|
||||
const removeButton = fixture.debugElement.query(By.css('.adf-property-col-delete'));
|
||||
removeButton.triggerEventHandler('click', null);
|
||||
fixture.detectChanges();
|
||||
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, OnChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { CardViewKeyValuePairsItemModel } from '../../models/card-view.models';
|
||||
import { CardViewKeyValuePairsItemType } from '../../interfaces/card-view.interfaces';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
@@ -30,10 +30,6 @@ import { BaseCardView } from '../base-card-view';
|
||||
})
|
||||
|
||||
export class CardViewKeyValuePairsItemComponent extends BaseCardView<CardViewKeyValuePairsItemModel> implements OnChanges {
|
||||
|
||||
@Input()
|
||||
editable: boolean = false;
|
||||
|
||||
values: CardViewKeyValuePairsItemType[];
|
||||
matTableValues: MatTableDataSource<CardViewKeyValuePairsItemType>;
|
||||
|
||||
@@ -42,10 +38,6 @@ export class CardViewKeyValuePairsItemComponent extends BaseCardView<CardViewKey
|
||||
this.matTableValues = new MatTableDataSource(this.values);
|
||||
}
|
||||
|
||||
isEditable(): boolean {
|
||||
return this.editable && this.property.editable;
|
||||
}
|
||||
|
||||
add(): void {
|
||||
this.values.push({ name: '', value: '' });
|
||||
}
|
||||
@@ -55,8 +47,8 @@ export class CardViewKeyValuePairsItemComponent extends BaseCardView<CardViewKey
|
||||
this.save(true);
|
||||
}
|
||||
|
||||
onBlur(value): void {
|
||||
if (value.length) {
|
||||
onBlur(value: any): void {
|
||||
if (value?.length) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
@@ -26,9 +26,6 @@ import { BaseCardView } from '../base-card-view';
|
||||
})
|
||||
|
||||
export class CardViewMapItemComponent extends BaseCardView<CardViewMapItemModel> {
|
||||
@Input()
|
||||
property: CardViewMapItemModel;
|
||||
|
||||
@Input()
|
||||
displayEmpty: boolean = true;
|
||||
|
||||
|
@@ -1,28 +1,30 @@
|
||||
<ng-container *ngIf="!property.isEmpty() || isEditable()">
|
||||
<ng-container *ngIf="!property.isEmpty() || isEditable">
|
||||
<div
|
||||
[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 }}</div>
|
||||
<div class="adf-property-field">
|
||||
<div
|
||||
*ngIf="!isEditable()"
|
||||
class="adf-select-item-padding adf-property-value"
|
||||
*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">{{ (property.displayValue | async) | translate }}
|
||||
</div>
|
||||
<div *ngIf="isEditable()">
|
||||
<mat-form-field class="adf-select-item-padding-editable adf-property-value">
|
||||
<div *ngIf="isEditable">
|
||||
<mat-form-field class="adf-property-value" [ngClass]="{'adf-property-value-editable': isEditable}">
|
||||
<mat-select
|
||||
[(value)]="value"
|
||||
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty }"
|
||||
panelClass="adf-select-filter"
|
||||
(selectionChange)="onChange($event)"
|
||||
data-automation-class="select-box"
|
||||
[aria-label]="property.label | translate"
|
||||
>
|
||||
|
||||
[aria-label]="property.label | translate">
|
||||
<adf-select-filter-input *ngIf="showInputFilter" (change)="onFilterInputChange($event)"></adf-select-filter-input>
|
||||
|
||||
<mat-option *ngIf="showNoneOption()">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
|
||||
<mat-option *ngIf="displayNoneOption">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
|
||||
<mat-option
|
||||
*ngFor="let option of list$ | async"
|
||||
[value]="option.key">
|
||||
|
@@ -1,22 +1,36 @@
|
||||
.mat-form-field-type-mat-select {
|
||||
width: 100%;
|
||||
}
|
||||
.adf-card-view-selectitem {
|
||||
.adf-property-value {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.adf-select-item-padding {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.adf-select-filter-input {
|
||||
background: var(--adf-theme-background-card-color);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.adf-select-item-padding-editable {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
.adf-property-value-editable {
|
||||
mat-select {
|
||||
padding: 6px 0 6px 12px;
|
||||
margin-top: 0;
|
||||
border-radius: 6px;
|
||||
|
||||
.adf-select-filter-input {
|
||||
background: var(--adf-theme-background-card-color);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
.mat-select-value {
|
||||
color: var(--adf-metadata-action-button-clear-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-property-read-only {
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid var(--adf-metadata-property-panel-border-color);
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
}
|
||||
|
||||
.adf-property-readonly-value {
|
||||
color: var(--adf-metadata-property-panel-label-color);
|
||||
}
|
||||
}
|
||||
|
@@ -108,7 +108,7 @@ describe('CardViewSelectItemComponent', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.value).toEqual('two');
|
||||
expect(component.isEditable()).toBe(true);
|
||||
expect(component.isEditable).toBe(true);
|
||||
|
||||
const select = await loader.getHarness(MatSelectHarness);
|
||||
await select.open();
|
||||
@@ -131,7 +131,7 @@ describe('CardViewSelectItemComponent', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.value).toEqual(2);
|
||||
expect(component.isEditable()).toBe(true);
|
||||
expect(component.isEditable).toBe(true);
|
||||
|
||||
const select = await loader.getHarness(MatSelectHarness);
|
||||
await select.open();
|
||||
@@ -154,7 +154,7 @@ describe('CardViewSelectItemComponent', () => {
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isEditable()).toBe(true);
|
||||
expect(component.isEditable).toBe(true);
|
||||
|
||||
const select = await loader.getHarness(MatSelectHarness);
|
||||
await select.open();
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, inject, ViewEncapsulation } from '@angular/core';
|
||||
import { CardViewSelectItemModel } from '../../models/card-view-selectitem.model';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
import { CardViewSelectItemOption } from '../../interfaces/card-view.interfaces';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
import { BaseCardView } from '../base-card-view';
|
||||
@@ -35,8 +35,6 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
private appConfig = inject(AppConfigService);
|
||||
static HIDE_FILTER_LIMIT = 5;
|
||||
|
||||
@Input() editable: boolean = false;
|
||||
|
||||
@Input() options$: Observable<CardViewSelectItemOption<string | number>[]>;
|
||||
|
||||
@Input()
|
||||
@@ -46,11 +44,8 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
displayEmpty: boolean = true;
|
||||
|
||||
value: string | number;
|
||||
filter$: BehaviorSubject<string> = new BehaviorSubject('');
|
||||
filter$ = new BehaviorSubject<string>('');
|
||||
showInputFilter: boolean = false;
|
||||
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
list$: Observable<CardViewSelectItemOption<string | number>[]> = null;
|
||||
|
||||
ngOnChanges(): void {
|
||||
@@ -59,8 +54,8 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
|
||||
ngOnInit() {
|
||||
this.getOptions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((options: CardViewSelectItemOption<string>[]) => {
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((options) => {
|
||||
this.showInputFilter = options.length > this.optionsLimit;
|
||||
});
|
||||
|
||||
@@ -71,21 +66,17 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
this.filter$.next(value.toString());
|
||||
}
|
||||
|
||||
isEditable(): boolean {
|
||||
return this.editable && this.property.editable;
|
||||
}
|
||||
|
||||
getOptions(): Observable<CardViewSelectItemOption<string | number>[]> {
|
||||
private getOptions(): Observable<CardViewSelectItemOption<string | number>[]> {
|
||||
return this.options$ || this.property.options$;
|
||||
}
|
||||
|
||||
getList(): Observable<CardViewSelectItemOption<string | number>[]> {
|
||||
return combineLatest([this.getOptions(), this.filter$])
|
||||
.pipe(
|
||||
map(([items, filter]) => items.filter((item: CardViewSelectItemOption<string>) =>
|
||||
map(([items, filter]) => items.filter((item) =>
|
||||
filter ? item.label.toLowerCase().includes(filter.toLowerCase())
|
||||
: true)),
|
||||
takeUntil(this.onDestroy$)
|
||||
takeUntil(this.destroy$)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -95,17 +86,12 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
this.property.value = selectedOption;
|
||||
}
|
||||
|
||||
showNoneOption() {
|
||||
return this.displayNoneOption;
|
||||
}
|
||||
|
||||
get showProperty(): boolean {
|
||||
return this.displayEmpty || !this.property.isEmpty();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
private get optionsLimit(): number {
|
||||
|
@@ -1,70 +1,70 @@
|
||||
<div [ngSwitch]="templateType">
|
||||
<div *ngSwitchDefault>
|
||||
<mat-form-field class="adf-property-field adf-card-textitem-field"
|
||||
[ngClass]="{ 'adf-property-read-only': !isEditable, 'adf-property-field-has-error mat-form-field-invalid': isEditable && hasErrors }"
|
||||
[floatLabel]="'never'"
|
||||
[ngClass]="{
|
||||
'adf-property-read-only': !isEditable
|
||||
}"
|
||||
[floatLabel]="'always'"
|
||||
appearance="standard">
|
||||
<mat-label *ngIf="showProperty || isEditable" [attr.data-automation-id]="'card-textitem-label-' + property.key" class="adf-property-label">
|
||||
|
||||
<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
|
||||
}">
|
||||
{{ property.label | translate }}
|
||||
</mat-label>
|
||||
<input matInput
|
||||
*ngIf="!property.multiline"
|
||||
class="adf-property-value"
|
||||
title="{{property.label | translate }}"
|
||||
[placeholder]="property.default"
|
||||
[attr.aria-label]="property.label | translate"
|
||||
[formControl]="textInput"
|
||||
(dblclick)="copyToClipboard(property.displayValue)"
|
||||
matTooltipShowDelay="1000"
|
||||
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
|
||||
[matTooltipDisabled]="isEditable"
|
||||
[attr.data-automation-id]="'card-textitem-value-' + property.key"
|
||||
(keydown)="undoText($event)">
|
||||
<textarea matInput
|
||||
*ngIf="property.multiline"
|
||||
title="{{property.label | translate }}"
|
||||
[cdkTextareaAutosize]="true"
|
||||
[cdkAutosizeMaxRows]="1"
|
||||
[cdkAutosizeMaxRows]="5"
|
||||
class="adf-property-value"
|
||||
[placeholder]="property.default"
|
||||
[attr.aria-label]="property.label | translate"
|
||||
[formControl]="textInput"
|
||||
[attr.data-automation-id]="'card-textitem-value-' + property.key">
|
||||
</textarea>
|
||||
|
||||
<button
|
||||
*ngIf="isEditable"
|
||||
matSuffix
|
||||
class="adf-textitem-clear-icon"
|
||||
[attr.aria-label]="'CORE.METADATA.ACTIONS.CLEAR' | translate"
|
||||
(click)="clearValue()">
|
||||
<mat-icon>cancel</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="isEditable"
|
||||
matSuffix
|
||||
class="adf-textitem-edit-icon"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate">
|
||||
<mat-icon>mode_edit</mat-icon>
|
||||
</button>
|
||||
|
||||
<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
|
||||
}"
|
||||
title="{{property.label | translate }}"
|
||||
[placeholder]="property.default"
|
||||
[attr.aria-label]="property.label | translate"
|
||||
[formControl]="textInput"
|
||||
(dblclick)="copyToClipboard(property.displayValue)"
|
||||
matTooltipShowDelay="1000"
|
||||
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
|
||||
[matTooltipDisabled]="isEditable"
|
||||
[attr.data-automation-id]="'card-textitem-value-' + property.key"
|
||||
(keydown)="undoText($event)">
|
||||
<textarea matInput
|
||||
*ngIf="property.multiline"
|
||||
title="{{property.label | translate }}"
|
||||
[cdkTextareaAutosize]="true"
|
||||
[cdkAutosizeMaxRows]="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">
|
||||
<mat-label *ngIf="showLabelForChips" [attr.data-automation-id]="'card-textitem-label-' + property.key" class="adf-property-label">
|
||||
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}">
|
||||
{{ property.label | translate }}
|
||||
</mat-label>
|
||||
<mat-chip-list #chipList
|
||||
class="adf-textitem-chip-list">
|
||||
<mat-chip-list #chipList class="adf-textitem-chip-list">
|
||||
<mat-chip *ngFor="let propertyValue of editedValue; let idx = index"
|
||||
[removable]="isEditable"
|
||||
(removed)="removeValueFromList(idx)">
|
||||
{{ propertyValue }}
|
||||
<mat-icon *ngIf="isEditable"
|
||||
matChipRemove>cancel</mat-icon>
|
||||
<mat-icon *ngIf="isEditable" matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
[floatLabel]="'never'">
|
||||
<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"
|
||||
@@ -81,8 +85,6 @@
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addValueToList($event)"
|
||||
[attr.data-automation-id]="'card-textitem-editchipinput-' + property.key">
|
||||
<mat-icon matSuffix
|
||||
class="adf-textitem-edit-icon">mode_edit</mat-icon>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@@ -100,8 +102,13 @@
|
||||
<input matInput
|
||||
[type]=property.inputType
|
||||
class="adf-property-value"
|
||||
title="{{property.label | translate }}"
|
||||
[ngClass]="{ 'adf-textitem-clickable-value': !isEditable }"
|
||||
title="{{ property.label | translate }}"
|
||||
[ngClass]="{
|
||||
'adf-property-value-editable': editable,
|
||||
'adf-textitem-clickable-value': !isEditable,
|
||||
'adf-property-readonly-value': isReadonlyProperty,
|
||||
'adf-property-value-has-error': isEditable && hasErrors
|
||||
}"
|
||||
[placeholder]="property.default"
|
||||
[attr.aria-label]="property.label | translate"
|
||||
[(ngModel)]="editedValue"
|
||||
@@ -125,9 +132,10 @@
|
||||
<span class="adf-textitem-default-value">{{ property.default | translate }}</span>
|
||||
</div>
|
||||
|
||||
<mat-error [attr.data-automation-id]="'card-textitem-error-' + property.key"
|
||||
class="adf-textitem-editable-error"
|
||||
*ngIf="isEditable && hasErrors">
|
||||
<mat-error
|
||||
*ngIf="isEditable && hasErrors"
|
||||
class="adf-textitem-error"
|
||||
[attr.data-automation-id]="'card-textitem-error-' + property.key">
|
||||
<ul>
|
||||
<li *ngFor="let error of errors">{{ error.message | translate: error }}</li>
|
||||
</ul>
|
||||
|
@@ -1,204 +1,67 @@
|
||||
.adf {
|
||||
&-textitem-edit-icon.mat-icon {
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--adf-theme-foreground-text-color-025);
|
||||
.adf-card-view-textitem {
|
||||
.adf-textitem-error {
|
||||
font-size: var(--theme-caption-font-size);
|
||||
padding-top: 6px;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-textitem-action.mat-icon-button {
|
||||
.adf-textitem-action {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
color: var(--adf-theme-foreground-text-color-025);
|
||||
}
|
||||
|
||||
&-textitem-action:hover,
|
||||
&-textitem-action:focus {
|
||||
color: var(--adf-theme-foreground-text-color);
|
||||
}
|
||||
|
||||
&-update-icon {
|
||||
padding-left: 13px;
|
||||
}
|
||||
|
||||
&-textitem-readonly {
|
||||
cursor: pointer !important;
|
||||
|
||||
&:hover .adf-textitem-action,
|
||||
&:focus .adf-textitem-action {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--adf-theme-foreground-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
&-textitem-chip-list-container {
|
||||
margin-bottom: 25px !important;
|
||||
margin-top: 6px;
|
||||
|
||||
.adf-textitem-chip-list-container {
|
||||
.mat-form-field-label {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
&-textitem-clickable {
|
||||
cursor: pointer !important;
|
||||
.adf-textitem-clickable {
|
||||
cursor: pointer;
|
||||
padding-top: 3px;
|
||||
|
||||
.adf-textitem-edit-icon.mat-icon {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
&:hover .adf-textitem-action {
|
||||
.adf-textitem-action:hover {
|
||||
color: var(--adf-theme-foreground-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
&-textitem-clickable-value {
|
||||
cursor: pointer !important;
|
||||
color: var(--theme-primary-color) !important;
|
||||
}
|
||||
|
||||
&-textitem-editable {
|
||||
&-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
mat-icon:not(.adf-button-disabled):hover {
|
||||
color: var(--adf-theme-foreground-text-color);
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
textarea:focus {
|
||||
border: 1px solid var(--theme-accent-color-a200);
|
||||
}
|
||||
}
|
||||
|
||||
&-error {
|
||||
font-size: var(--theme-caption-font-size);
|
||||
padding-top: 6px;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-textitem-default-value {
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-form-field-wrapper {
|
||||
margin: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-form-field-underline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-form-field-infix {
|
||||
padding: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-form-field-label-wrapper {
|
||||
padding-top: 2em;
|
||||
position: static;
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-form-field-label {
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-input-element {
|
||||
font-family: inherit;
|
||||
position: relative;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
&-textitem-editable .mat-input-element:focus {
|
||||
padding: 5px;
|
||||
left: -6px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&-textitem-editable input.mat-input-element {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
&-textitem-editable input.mat-input-element:focus {
|
||||
margin-bottom: -8px;
|
||||
}
|
||||
|
||||
&-textitem-scroll {
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb {
|
||||
display: block;
|
||||
background-color: var(--adf-theme-foreground-text-color-025);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&-textitem-multiline {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-property-field {
|
||||
.adf-property-clear-value,
|
||||
.adf-textitem-edit-value {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-form-field:not(.adf-textitem-chip-list-input) {
|
||||
.mat-form-field-suffix {
|
||||
.adf-textitem-edit-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.adf-textitem-clear-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.adf-textitem-edit-icon,
|
||||
.adf-textitem-clear-icon {
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
.adf-property-field {
|
||||
.mat-input-element {
|
||||
color: var(--theme-primary-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.adf-textitem-edit-icon {
|
||||
display: none;
|
||||
}
|
||||
.adf-textitem-default-value {
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
}
|
||||
|
||||
.adf-textitem-clear-icon {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.adf-property-read-only {
|
||||
border-bottom: 1px solid var(--adf-metadata-property-panel-border-color);
|
||||
}
|
||||
|
||||
.adf-property-readonly-value {
|
||||
color: var(--adf-metadata-property-panel-label-color);
|
||||
}
|
||||
|
||||
.adf-property-value-editable {
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
}
|
||||
}
|
||||
|
@@ -189,24 +189,6 @@ describe('CardViewTextItemComponent', () => {
|
||||
expect(value).toBe('Lorem ipsum');
|
||||
});
|
||||
|
||||
it('should render the edit icon in case of editable:true', () => {
|
||||
component.editable = true;
|
||||
component.property.editable = true;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const editIcon = fixture.debugElement.query(By.css('.adf-textitem-edit-icon'));
|
||||
expect(editIcon).not.toBeNull('Edit icon should be shown');
|
||||
});
|
||||
|
||||
it('should NOT render the edit icon in case of editable:false', async () => {
|
||||
component.editable = false;
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const editIcon = fixture.debugElement.query(By.css('.adf-textitem-edit-icon'));
|
||||
expect(editIcon).toBeNull('Edit icon should NOT be shown');
|
||||
});
|
||||
|
||||
it('should NOT render the picker and toggle in case of editable:true but (general) editable:false', async () => {
|
||||
component.editable = false;
|
||||
component.property.editable = true;
|
||||
@@ -313,6 +295,20 @@ describe('CardViewTextItemComponent', () => {
|
||||
const labelElement = fixture.debugElement.query(By.css(`.adf-property-label`));
|
||||
expect(labelElement).toBeNull();
|
||||
});
|
||||
|
||||
it('should return true when editable is true, and property.editable is false', () => {
|
||||
component.editable = true;
|
||||
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;
|
||||
fixture.detectChanges();
|
||||
expect(component.isReadonlyProperty).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clickable', () => {
|
||||
@@ -491,26 +487,6 @@ describe('CardViewTextItemComponent', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should clear value when clear value icon is clicked', async () => {
|
||||
spyOn(component, 'update');
|
||||
component.property.value = 'testValue';
|
||||
component.property.icon = 'FAKE_ICON';
|
||||
component.property.clickable = true;
|
||||
component.property.editable = true;
|
||||
component.editable = true;
|
||||
component.property.isValid = () => true;
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
const clickEl = fixture.debugElement.query(By.css(`.adf-textitem-clear-icon`));
|
||||
clickEl.triggerEventHandler('click', new MouseEvent('click'));
|
||||
|
||||
fixture.detectChanges();
|
||||
const elementValue = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
|
||||
expect(elementValue.nativeElement.textContent).toEqual('');
|
||||
expect(component.update).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update', () => {
|
||||
@@ -593,7 +569,7 @@ describe('CardViewTextItemComponent', () => {
|
||||
component.editable = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const errorMessage: HTMLElement = fixture.debugElement.nativeElement.querySelector('.adf-textitem-editable-error');
|
||||
const errorMessage: HTMLElement = fixture.debugElement.nativeElement.querySelector('.adf-textitem-error');
|
||||
expect(errorMessage.textContent).toBe(expectedErrorMessages[0].message);
|
||||
});
|
||||
|
||||
@@ -602,13 +578,13 @@ describe('CardViewTextItemComponent', () => {
|
||||
component.editable = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
let errorMessage: HTMLElement = fixture.debugElement.nativeElement.querySelector('.adf-textitem-editable-error');
|
||||
let errorMessage: HTMLElement = fixture.debugElement.nativeElement.querySelector('.adf-textitem-error');
|
||||
expect(errorMessage.textContent).toBe(expectedErrorMessages[0].message);
|
||||
|
||||
component.editable = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
errorMessage = fixture.debugElement.nativeElement.querySelector('.adf-textitem-editable-error');
|
||||
errorMessage = fixture.debugElement.nativeElement.querySelector('.adf-textitem-error');
|
||||
expect(errorMessage).toBeNull();
|
||||
});
|
||||
|
||||
|
@@ -24,7 +24,6 @@ import { TranslationService } from '../../../translation/translation.service';
|
||||
import { CardViewItemValidator } from '../../interfaces/card-view-item-validator.interface';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { debounceTime, takeUntil, filter } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export const DEFAULT_SEPARATOR = ', ';
|
||||
const templateTypes = {
|
||||
@@ -44,30 +43,24 @@ const templateTypes = {
|
||||
})
|
||||
export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemModel> implements OnChanges, OnDestroy {
|
||||
@Input()
|
||||
editable: boolean = false;
|
||||
displayEmpty = true;
|
||||
|
||||
@Input()
|
||||
displayEmpty: boolean = true;
|
||||
copyToClipboardAction = true;
|
||||
|
||||
@Input()
|
||||
copyToClipboardAction: boolean = true;
|
||||
|
||||
@Input()
|
||||
useChipsForMultiValueProperty: boolean = true;
|
||||
useChipsForMultiValueProperty = true;
|
||||
|
||||
@Input()
|
||||
multiValueSeparator: string = DEFAULT_SEPARATOR;
|
||||
|
||||
@Input()
|
||||
displayLabelForChips: boolean = false;
|
||||
displayLabelForChips = false;
|
||||
|
||||
editedValue: string | string[];
|
||||
errors: CardViewItemValidator[];
|
||||
templateType: string;
|
||||
|
||||
textInput: UntypedFormControl = new UntypedFormControl();
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
textInput = new UntypedFormControl();
|
||||
|
||||
constructor(private clipboardService: ClipboardService, private translateService: TranslationService, private cd: ChangeDetectorRef) {
|
||||
super();
|
||||
@@ -79,7 +72,7 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
.pipe(
|
||||
filter((textInputValue) => textInputValue !== this.editedValue && textInputValue !== null),
|
||||
debounceTime(50),
|
||||
takeUntil(this.onDestroy$)
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe((textInputValue) => {
|
||||
this.editedValue = textInputValue;
|
||||
@@ -198,8 +191,7 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
get showProperty(): boolean {
|
||||
@@ -210,18 +202,10 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
return this.hasIcon && this.editable;
|
||||
}
|
||||
|
||||
get isEditable(): boolean {
|
||||
return this.editable && this.property.editable;
|
||||
}
|
||||
|
||||
get isClickable(): boolean {
|
||||
return this.property.clickable;
|
||||
}
|
||||
|
||||
get hasIcon(): boolean {
|
||||
return !!this.property.icon;
|
||||
}
|
||||
|
||||
get hasErrors(): boolean {
|
||||
return !!this.errors?.length;
|
||||
}
|
||||
|
@@ -1,28 +1,110 @@
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
.adf-property-list {
|
||||
background: var(--adf-card-view-background);
|
||||
border: var(--adf-card-view-border);
|
||||
border-color: var(--adf-card-view-border-color);
|
||||
border-radius: var(--adf-card-view-border-radius);
|
||||
|
||||
.adf-property {
|
||||
margin-bottom: 20px;
|
||||
.adf-property-label {
|
||||
color: var(--adf-metadata-property-panel-text-color);
|
||||
display: flex;
|
||||
padding: 6px 0;
|
||||
line-height: 20px;
|
||||
|
||||
.adf-property-value-padding-top {
|
||||
margin-top: 6px;
|
||||
&.adf-property-value-editable {
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
}
|
||||
|
||||
&.adf-property-readonly-value {
|
||||
color: var(--adf-metadata-property-panel-label-color);
|
||||
}
|
||||
}
|
||||
|
||||
.adf-property {
|
||||
.adf-property-field {
|
||||
width: 100%;
|
||||
margin-bottom: -25px;
|
||||
|
||||
.mat-form-field-underline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mat-input-element {
|
||||
text-overflow: ellipsis;
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
margin-top: 32px;
|
||||
padding: 6px 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.adf-card-view__key-value-pairs__row {
|
||||
.mat-input-element {
|
||||
margin-top: 0;
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-form-field-infix {
|
||||
display: flex;
|
||||
border-top-width: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mat-form-field-flex {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.mat-form-field-wrapper {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.mat-form-field-label {
|
||||
margin-top: 6px;
|
||||
padding: 6px 0;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 20px;
|
||||
transform: translateY(-1.3437em) scale(1);
|
||||
}
|
||||
|
||||
.mat-form-field-label-wrapper {
|
||||
padding-top: 0;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-property-value {
|
||||
color: var(--adf-metadata-property-panel-text-color);
|
||||
|
||||
&.adf-property-value-editable {
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
background-color: var(--adf-metadata-buttons-background-color);
|
||||
border-radius: 6px;
|
||||
|
||||
&.mat-input-element {
|
||||
color: var(--adf-metadata-action-button-clear-color);
|
||||
padding: 6px 0 6px 12px;
|
||||
margin: 32px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-property-readonly-value {
|
||||
color: var(--adf-metadata-property-panel-label-color);
|
||||
|
||||
&.mat-input-element {
|
||||
color: var(--adf-metadata-property-panel-label-color);
|
||||
}
|
||||
}
|
||||
|
||||
&-has-error {
|
||||
border: 1px solid var(--theme-warn-color);
|
||||
}
|
||||
|
||||
&-input {
|
||||
background-color: var(--adf-metadata-buttons-background-color);
|
||||
border-radius: 6px;
|
||||
padding: 6px 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -186,7 +186,7 @@ export class ThumbnailService {
|
||||
*
|
||||
* @returns URL string
|
||||
*/
|
||||
public getDefaultMimeTypeIcon(): string {
|
||||
getDefaultMimeTypeIcon(): string {
|
||||
return DEFAULT_ICON;
|
||||
}
|
||||
}
|
||||
|
@@ -193,7 +193,7 @@
|
||||
},
|
||||
"METADATA": {
|
||||
"BASIC": {
|
||||
"HEADER": "Properties",
|
||||
"HEADER": "General info",
|
||||
"NAME": "Name",
|
||||
"TITLE": "Title",
|
||||
"DESCRIPTION": "Description",
|
||||
@@ -401,10 +401,6 @@
|
||||
"SIDEBAR": {
|
||||
"THUMBNAILS": {
|
||||
"PAGE": "Page {{ pageNum }}"
|
||||
},
|
||||
"METADATA": {
|
||||
"MORE_INFORMATION": "More information",
|
||||
"LESS_INFORMATION": "Less information"
|
||||
}
|
||||
},
|
||||
"PDF_DIALOG": {
|
||||
@@ -573,5 +569,8 @@
|
||||
"ADF_DROPDOWN": {
|
||||
"LOADING": "Loading...",
|
||||
"SELECTION_ARIA_LABEL": "{{placeholder}} combobox {{selectedOption}}"
|
||||
},
|
||||
"INFO_DRAWER": {
|
||||
"ICON": "Node Icon"
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<div *ngIf="showHeader" class="adf-info-drawer-layout-header">
|
||||
<div class="adf-info-drawer-layout-header-title">
|
||||
<ng-content select="[info-drawer-node-icon]"></ng-content>
|
||||
<ng-content select="[info-drawer-title]"></ng-content>
|
||||
</div>
|
||||
<div class="adf-info-drawer-layout-header-buttons">
|
||||
|
@@ -14,44 +14,44 @@ $adf-info-drawer-icon-size-half: 24px !default;
|
||||
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
background-color: var(--theme-background-color);
|
||||
background-color: var(--theme-card-background-color);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.27);
|
||||
|
||||
& .mat-tab-label {
|
||||
font-weight: bold;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-header {
|
||||
padding: 13px 0 0 23px;
|
||||
padding: 8px 0 0 24px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 56px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
&-buttons {
|
||||
padding-right: 18px;
|
||||
|
||||
mat-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
width: 197px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
font-size: $adf-info-drawer-layout-title-font-size;
|
||||
line-height: 1.6;
|
||||
letter-spacing: -0.5px;
|
||||
line-height: 28px;
|
||||
letter-spacing: 0.15px;
|
||||
text-align: left;
|
||||
align-items: start;
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
overflow: hidden;
|
||||
|
||||
& > div {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--adf-metadata-property-panel-title-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,13 @@
|
||||
<adf-info-drawer-layout [showHeader]="showHeader">
|
||||
<div role="heading" aria-level="1" *ngIf="title" info-drawer-title>{{ title | translate }}</div>
|
||||
<img *ngIf="icon" class="adf-info-drawer-icon" alt="{{ 'INFO_DRAWER.ICON' | translate }}" src="{{ icon }}" info-drawer-node-icon>
|
||||
<div *ngIf="title" role="heading" aria-level="1" title="{{ title | translate }}" info-drawer-title>{{ title | translate }}</div>
|
||||
|
||||
<ng-content *ngIf="!title" info-drawer-title select="[info-drawer-title]"></ng-content>
|
||||
|
||||
<ng-content info-drawer-buttons select="[info-drawer-buttons]"></ng-content>
|
||||
|
||||
<ng-container info-drawer-content *ngIf="showTabLayout(); then tabLayout else singleLayout"></ng-container>
|
||||
|
||||
<ng-template #tabLayout>
|
||||
<mat-tab-group [(selectedIndex)]="selectedIndex" class="adf-info-drawer-tabs" (selectedTabChange)="onTabChange($event)">
|
||||
<mat-tab-group [(selectedIndex)]="selectedIndex" class="adf-info-drawer-tabs" (selectedTabChange)="onTabChange($event)" [animationDuration]="0">
|
||||
<mat-tab *ngFor="let contentBlock of contentBlocks"
|
||||
#tab
|
||||
[labelClass]="[
|
||||
|
@@ -1,12 +1,21 @@
|
||||
.adf {
|
||||
&-info-drawer {
|
||||
display: block;
|
||||
.adf-metadata-properties-panel {
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mat-tab-label {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
& &-layout {
|
||||
.adf-info-drawer-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&-content {
|
||||
padding: 0;
|
||||
|
||||
@@ -38,16 +47,16 @@
|
||||
}
|
||||
|
||||
.mat-ink-bar {
|
||||
height: 4px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.mat-tab-body {
|
||||
padding: 10px;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.mat-tab-body-content {
|
||||
/* stylelint-disable */
|
||||
overflow: initial;
|
||||
overflow: auto;
|
||||
/* stylelint-enable */
|
||||
}
|
||||
}
|
||||
|
@@ -28,8 +28,8 @@ import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
describe('InfoDrawerComponent', () => {
|
||||
let element: HTMLElement;
|
||||
let component: InfoDrawerComponent;
|
||||
let fixture: ComponentFixture<InfoDrawerComponent>;
|
||||
let translateService: TranslateService;
|
||||
let fixture: ComponentFixture<InfoDrawerComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -87,24 +87,27 @@ describe('InfoDrawerComponent', () => {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<adf-info-drawer [selectedIndex]="tabIndex" title="Fake Title Custom">
|
||||
<adf-info-drawer-tab label="Tab1">
|
||||
</adf-info-drawer-tab>
|
||||
<adf-info-drawer-tab label="Tab2">
|
||||
</adf-info-drawer-tab>
|
||||
<adf-info-drawer-tab label="Tab3" icon="tab-icon">
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
`
|
||||
<adf-info-drawer [selectedIndex]="tabIndex" [icon]="icon" title="Fake Title Custom">
|
||||
<adf-info-drawer-tab label="Tab1">
|
||||
</adf-info-drawer-tab>
|
||||
<adf-info-drawer-tab label="Tab2">
|
||||
</adf-info-drawer-tab>
|
||||
<adf-info-drawer-tab label="Tab3" icon="tab-icon">
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
`
|
||||
})
|
||||
class CustomInfoDrawerComponent extends InfoDrawerComponent {
|
||||
tabIndex: number;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
describe('Custom InfoDrawer', () => {
|
||||
let fixture: ComponentFixture<CustomInfoDrawerComponent>;
|
||||
let component: CustomInfoDrawerComponent;
|
||||
let translateService: TranslateService;
|
||||
const getNodeIcon = () =>
|
||||
fixture.debugElement.queryAll(By.css('[info-drawer-node-icon]'));
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -139,7 +142,7 @@ describe('Custom InfoDrawer', () => {
|
||||
fixture.detectChanges();
|
||||
const tab: any = fixture.debugElement.queryAll(By.css('.mat-tab-label-active'));
|
||||
expect(tab.length).toBe(1);
|
||||
expect(tab[0].nativeElement.innerText).toContain('TAB1');
|
||||
expect(tab[0].nativeElement.innerText).toContain('Tab1');
|
||||
});
|
||||
|
||||
it('should select the tab 2 (index 1)', () => {
|
||||
@@ -147,7 +150,7 @@ describe('Custom InfoDrawer', () => {
|
||||
fixture.detectChanges();
|
||||
const tab: any = fixture.debugElement.queryAll(By.css('.mat-tab-label-active'));
|
||||
expect(tab.length).toBe(1);
|
||||
expect(tab[0].nativeElement.innerText).toContain('TAB2');
|
||||
expect(tab[0].nativeElement.innerText).toContain('Tab2');
|
||||
});
|
||||
|
||||
it('should render a tab with icon', () => {
|
||||
@@ -157,21 +160,33 @@ describe('Custom InfoDrawer', () => {
|
||||
expect(tab[0].nativeElement.innerText).not.toBe('TAB3');
|
||||
expect(tab[0].nativeElement.innerText).toContain('tab-icon');
|
||||
});
|
||||
|
||||
it('should render a icon with title', () => {
|
||||
component.icon = '/assets/images/ft_ic_miscellaneous.svg';
|
||||
fixture.detectChanges();
|
||||
const icon = getNodeIcon();
|
||||
const srcAttribute = icon[0].nativeElement.getAttribute('src');
|
||||
expect(icon.length).toBe(1);
|
||||
expect(srcAttribute).toContain('/assets/images/ft_ic_miscellaneous.svg');
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<adf-info-drawer [showHeader]="showHeader" title="Fake Visibility Info Drawer Title">
|
||||
<adf-info-drawer [showHeader]="showHeader" [icon]="icon" title="Fake Visibility Info Drawer Title">
|
||||
</adf-info-drawer>
|
||||
`
|
||||
`
|
||||
})
|
||||
class VisibilityInfoDrawerComponent extends InfoDrawerComponent {
|
||||
showHeader: boolean;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
describe('Header visibility InfoDrawer', () => {
|
||||
let fixture: ComponentFixture<VisibilityInfoDrawerComponent>;
|
||||
let component: VisibilityInfoDrawerComponent;
|
||||
const getNodeIcon = () =>
|
||||
fixture.debugElement.queryAll(By.css('[info-drawer-node-icon]'));
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -189,18 +204,24 @@ describe('Header visibility InfoDrawer', () => {
|
||||
});
|
||||
|
||||
it('should show info drawer header by default', () => {
|
||||
component.icon = '/assets/images/ft_ic_miscellaneous.svg';
|
||||
fixture.detectChanges();
|
||||
const title: any = fixture.debugElement.queryAll(By.css('[info-drawer-title]'));
|
||||
const icon = getNodeIcon();
|
||||
const srcAttribute = icon[0].nativeElement.getAttribute('src');
|
||||
expect(title.length).toBe(1);
|
||||
expect(icon.length).toBe(1);
|
||||
expect(srcAttribute).toContain('/assets/images/ft_ic_miscellaneous.svg');
|
||||
expect(title[0].nativeElement.innerText).toBe('Fake Visibility Info Drawer Title');
|
||||
expect(component.showHeader).toEqual(true);
|
||||
});
|
||||
|
||||
it('should not show info drawer header when showHeader is false', () => {
|
||||
fixture.detectChanges();
|
||||
it('should not show info drawer header with icon when showHeader is false', () => {
|
||||
component.showHeader = false;
|
||||
fixture.detectChanges();
|
||||
const title: any = fixture.debugElement.queryAll(By.css('[info-drawer-title]'));
|
||||
const icon = getNodeIcon();
|
||||
expect(title.length).toBe(0);
|
||||
expect(icon.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
@@ -47,6 +47,9 @@ export class InfoDrawerComponent {
|
||||
@Input()
|
||||
title: string|null = null;
|
||||
|
||||
@Input()
|
||||
icon: string | null = null;
|
||||
|
||||
/** The selected index tab. */
|
||||
@Input()
|
||||
selectedIndex: number = 0;
|
||||
|
@@ -1,3 +1,4 @@
|
||||
/* stylelint-disable scss/no-global-function-names */
|
||||
@use './reference-variables' as *;
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
@@ -52,7 +53,6 @@
|
||||
--adf-identity-user-info-line-height: $adf-ref-line-height,
|
||||
--adf-identity-user-info-font-size: var(--theme-adf-picture-1-font-size),
|
||||
--adf-user-info-container-margin-right: $adf-ref-margin-right,
|
||||
|
||||
--adf-info-drawer-tab-default-color: mat.get-color-from-palette($accent),
|
||||
--adf-info-drawer-tab-default-background: mat.get-color-from-palette($background, card),
|
||||
--adf-info-drawer-tab-default-bottom-line:$adf-ref-tab-bottom-line-default,
|
||||
@@ -70,8 +70,13 @@
|
||||
--adf-people-cloud-input-label-focus-color: mat.get-color-from-palette($primary),
|
||||
--adf-people-cloud-autosuggest-result-active-color: mat.get-color-from-palette($foreground, text),
|
||||
--adf-people-cloud-autosuggest-result-disabled-color: mat.get-color-from-palette($foreground, secondary-text),
|
||||
--adf-people-cloud-input-caption-error-color: mat.get-color-from-palette($warn)
|
||||
|
||||
--adf-people-cloud-input-caption-error-color: mat.get-color-from-palette($warn),
|
||||
--adf-metadata-property-panel-border-color: $adf-ref-metadata-property-panel-border-color,
|
||||
--adf-metadata-buttons-background-color: $adf-ref-metadata-buttons-background-color,
|
||||
--adf-metadata-action-button-clear-color: $adf-ref-metadata-action-button-clear-color,
|
||||
--adf-metadata-property-panel-text-color: $adf-ref-metadata-property-panel-text-color,
|
||||
--adf-metadata-property-panel-label-color: $adf-ref-metadata-property-panel-label-color,
|
||||
--adf-metadata-property-panel-title-color: $adf-ref-metadata-property-panel-title-color,
|
||||
);
|
||||
|
||||
// propagates SCSS variables into the CSS variables scope
|
||||
|
@@ -57,7 +57,6 @@
|
||||
--adf-theme-foreground-text-color-075: mat.get-color-from-palette($foreground, text, 0.75),
|
||||
--adf-theme-foreground-text-color-064: mat.get-color-from-palette($foreground, text, 0.64),
|
||||
--adf-theme-foreground-text-color-054: mat.get-color-from-palette($foreground, text, 0.54),
|
||||
--adf-theme-foreground-text-color-042: mat.get-color-from-palette($foreground, text, 0.42),
|
||||
--adf-theme-foreground-text-color-040: mat.get-color-from-palette($foreground, text, 0.4),
|
||||
--adf-theme-foreground-text-color-027: mat.get-color-from-palette($foreground, text, 0.27),
|
||||
--adf-theme-foreground-text-color-025: mat.get-color-from-palette($foreground, text, 0.25),
|
||||
|
@@ -17,3 +17,9 @@ $adf-ref-line-height: 40px;
|
||||
$adf-ref-margin-right: 8px;
|
||||
$adf-ref-tab-bottom-line-default: unset;
|
||||
$adf-ref-tab-bottom-line-active: unset;
|
||||
$adf-ref-metadata-property-panel-border-color: rgba(0, 0, 0, 0.12);
|
||||
$adf-ref-metadata-buttons-background-color: rgba(33, 33, 33, 0.05);
|
||||
$adf-ref-metadata-action-button-clear-color: rgba(33, 35, 40, 0.698);
|
||||
$adf-ref-metadata-property-panel-text-color: rgba(33, 35, 40, 0.7);
|
||||
$adf-ref-metadata-property-panel-label-color: rgba(33, 33, 33, 0.24);
|
||||
$adf-ref-metadata-property-panel-title-color: rgb(33, 33, 33);
|
||||
|
Reference in New Issue
Block a user