chore: migrate to Angular 20 and Material 20

- Update Angular from 19.2.18 to 20.3.9
- Update Angular Material/CDK from 19.2.19 to 20.2.14
- Update TypeScript from 5.8.3 to 5.9.3
- Update @typescript-eslint from 6.21.0 to 8.18.2
- Update @angular-eslint from 19.8.1 to 20.0.0
- Update ng-packagr from 19.2.2 to 20.3.2
- Update @mat-datetimepicker/core from 15.0.2 to 16.0.1 (Angular 20 compatible)

Angular Migrations Applied:
- Convert templates to new control flow syntax (@if, @for, @switch)
- Migrate DOCUMENT imports from @angular/common to @angular/core
- Update Router.getCurrentNavigation() to currentNavigation signal
- Replace deprecated InjectFlags enum usage
- Replace TestBed.get with TestBed.inject

Breaking Changes Fixed:
- Remove deprecated Directionality.value setter (read-only in Angular 20)
- Update ESLint config: replace @typescript-eslint/no-var-requires with no-require-imports
- Remove @typescript-eslint/brace-style rule (deprecated in v8)

Configuration:
- Add .npmrc with legacy-peer-deps for CI/CD compatibility
- Update ESLint rules for @typescript-eslint v8 compatibility

BREAKING CHANGE: Requires Angular 20+ and @mat-datetimepicker/core@16.0.1

Note: Nx build system currently has plugin worker issues. TypeScript compilation
verified successfully. Full builds and tests pending Nx worker resolution.

See MIGRATION_SUMMARY.md for complete details.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Denys Vuika
2026-02-25 12:33:27 +00:00
co-authored by Cursor
parent 93d42b85a4
commit 711e5b4eac
399 changed files with 15570 additions and 16664 deletions
@@ -20,50 +20,51 @@ import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu';
import { BreadcrumbItemComponent } from '../components/breadcrumb-item/breadcrumb-item.component';
import { BreadcrumbComponent } from '../components/breadcrumb/breadcrumb.component';
import { NgIf } from '@angular/common';
import { IconModule } from '@alfresco/adf-core';
@Component({
selector: 'adf-demo-breadcrumb',
template: `
<adf-breadcrumb [compact]="compact">
<adf-breadcrumb-item>
<a href="/">Home</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">Alfresco</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com">External Link 1</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">External Link 2</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">External Link 3</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item *ngIf="showBreadcrumbItemWithMenu" aria-current="location" aria-haspopup="true">
<div>
Current Page
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Menu">
<mat-icon adf-icon="menu_open" />
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>Menu Item 1</button>
<button mat-menu-item>Menu Item 2</button>
</mat-menu>
</div>
<adf-breadcrumb-item>
<a href="/">Home</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">Alfresco</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com">External Link 1</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">External Link 2</a>
</adf-breadcrumb-item>
<adf-breadcrumb-item>
<a href="https://www.alfresco.com/">External Link 3</a>
</adf-breadcrumb-item>
@if (showBreadcrumbItemWithMenu) {
<adf-breadcrumb-item aria-current="location" aria-haspopup="true">
<div>
Current Page
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Menu">
<mat-icon adf-icon="menu_open" />
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>Menu Item 1</button>
<button mat-menu-item>Menu Item 2</button>
</mat-menu>
</div>
</adf-breadcrumb-item>
}
</adf-breadcrumb>
`,
`,
standalone: true,
imports: [MatButtonModule, MatMenuModule, IconModule, BreadcrumbItemComponent, BreadcrumbComponent, NgIf]
imports: [MatButtonModule, MatMenuModule, IconModule, BreadcrumbItemComponent, BreadcrumbComponent]
})
export class DemoBreadcrumbComponent {
compact = false;
@@ -1,25 +1,28 @@
<ng-container>
<nav class="adf-breadcrumb" [class.adf-breadcrumb--compact]="compact" [attr.aria-label]="'CORE.BREADCRUMBS.TITLE' | translate" >
<ol>
<ng-container *ngFor="let breadcrumbTemplate of selectedBreadcrumbs; last as last">
@for (breadcrumbTemplate of selectedBreadcrumbs; track breadcrumbTemplate; let last = $last) {
<li adf-breadcrumb-focus class="adf-breadcrumb__item-wrapper">
<ng-container *ngTemplateOutlet="breadcrumbTemplate" />
<div *ngIf="!last" class="adf-breadcrumb__chevron" [class.adf-breadcrumb__chevron-before--compact]="compact" ></div>
@if (!last) {
<div class="adf-breadcrumb__chevron" [class.adf-breadcrumb__chevron-before--compact]="compact" ></div>
}
</li>
<li *ngIf="!last && compact === true" class="adf-breadcrumb__show-all-button-wrapper">
<button
mat-icon-button
(click)="toggleCompact()"
color="primary"
[title]="'CORE.BREADCRUMBS.SHOWALL' | translate"
[attr.aria-label]="'CORE.BREADCRUMBS.SHOWALL' | translate"
>
<mat-icon class="adf-breadcrumb__show-all-button-icon--rotate" adf-icon="more_vert" />
</button>
<div class="adf-breadcrumb__chevron" [class.adf-breadcrumb__chevron-after--compact]="compact" ></div>
</li>
</ng-container>
@if (!last && compact === true) {
<li class="adf-breadcrumb__show-all-button-wrapper">
<button
mat-icon-button
(click)="toggleCompact()"
color="primary"
[title]="'CORE.BREADCRUMBS.SHOWALL' | translate"
[attr.aria-label]="'CORE.BREADCRUMBS.SHOWALL' | translate"
>
<mat-icon class="adf-breadcrumb__show-all-button-icon--rotate" adf-icon="more_vert" />
</button>
<div class="adf-breadcrumb__chevron" [class.adf-breadcrumb__chevron-after--compact]="compact" ></div>
</li>
}
}
</ol>
</nav>
</ng-container>
@@ -41,9 +41,12 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
`
],
template: `
<span [ngClass]="['activity-indicator', size]" *ngIf="isEnabled; else inActive">🟢</span>
<ng-template #inActive><span [ngClass]="['activity-indicator', size]">🔴</span></ng-template>
`,
@if (isEnabled) {
<span [ngClass]="['activity-indicator', size]">🟢</span>
} @else {
<span [ngClass]="['activity-indicator', size]">🔴</span>
}
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
@@ -13,20 +13,23 @@
</button>
</mat-toolbar>
<ng-container *ngIf="flags$ | async as flags">
@if (flags$ | async; as flags) {
<table mat-table [dataSource]="flags" class="adf-feature-flags-overrides-table mat-elevation-z0">
<ng-container matColumnDef="icon">
<th mat-header-cell class="adf-icon-col adf-header-cell" *matHeaderCellDef>
<mat-icon class="material-icons-outlined adf-search-icon" adf-icon="search" />
</th>
<td mat-cell class="adf-icon-col" *matCellDef="let element">
<button mat-icon-button *ngIf="element.fictive; else flagFromApi" class="adf-fictive-flag-button" (click)="onDelete(element.flag)">
<mat-icon class="material-icons-outlined adf-custom-flag-icon" adf-icon="memory" />
<mat-icon class="material-icons-outlined adf-trash-icon" adf-icon="delete" />
</button>
@if (element.fictive) {
<button mat-icon-button class="adf-fictive-flag-button" (click)="onDelete(element.flag)">
<mat-icon class="material-icons-outlined adf-custom-flag-icon" adf-icon="memory" />
<mat-icon class="material-icons-outlined adf-trash-icon" adf-icon="delete" />
</button>
} @else {
<mat-icon class="material-icons-outlined" adf-icon="cloud" />
}
</td>
</ng-container>
<ng-container matColumnDef="flag">
<th mat-header-cell class="flag-col header-cell" *matHeaderCellDef>
<mat-form-field class="adf-flag-form-field" appearance="fill" floatLabel="auto">
@@ -35,16 +38,19 @@
</th>
<td mat-cell class="flag-col" *matCellDef="let element">{{ element.flag }}</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell class="adf-val-col header-cell" *matHeaderCellDef>
<div class="adf-input-field-buttons-container">
<button *ngIf="showPlusButton$ | async" mat-icon-button title="{{'CORE.FEATURE-FLAGS.ADD_NEW' | translate}}" color="accent" (click)="onAddButtonClick()">
<mat-icon class="material-icons-outlined" adf-icon="add_circle" />
</button>
<button *ngIf="inputValue" matSuffix mat-icon-button aria-label="Clear" (click)="onClearInput()" class="adf-clear-button">
<mat-icon adf-icon="cancel" />
</button>
@if (showPlusButton$ | async) {
<button mat-icon-button title="{{'CORE.FEATURE-FLAGS.ADD_NEW' | translate}}" color="accent" (click)="onAddButtonClick()">
<mat-icon class="material-icons-outlined" adf-icon="add_circle" />
</button>
}
@if (inputValue) {
<button matSuffix mat-icon-button aria-label="Clear" (click)="onClearInput()" class="adf-clear-button">
<mat-icon adf-icon="cancel" />
</button>
}
</div>
</th>
<td mat-cell class="adf-val-col" *matCellDef="let element">
@@ -54,13 +60,9 @@
[disabled]="!isEnabled" />
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</ng-container>
}
<ng-template #flagFromApi>
<mat-icon class="material-icons-outlined" adf-icon="cloud" />
</ng-template>
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { inject, provideAppInitializer } from '@angular/core';
import { inject, provideAppInitializer, DOCUMENT } from '@angular/core';
import {
FlagsOverrideToken,
FeaturesServiceToken,
@@ -28,7 +28,7 @@ import {
import { StorageFeaturesService } from '../services/storage-features.service';
import { DebugFeaturesService } from '../services/debug-features.service';
import { QaFeaturesHelper } from '../services/qa-features.helper';
import { DOCUMENT } from '@angular/common';
/**
*
@@ -104,7 +104,7 @@ export class ShellLayoutComponent implements OnInit {
)
.subscribe((event: NavigationEnd) => {
this.minimizeSidenav = this.shellService.minimizeSidenavConditions.some((el) => {
const previousNavigation = this.router.getCurrentNavigation()?.previousNavigation?.finalUrl;
const previousNavigation = this.router.currentNavigation()?.previousNavigation?.finalUrl;
const previousPath = previousNavigation ? this.router.serializeUrl(previousNavigation) : '';
return event.urlAfterRedirects.includes(el) && !previousPath.includes(el);
});
@@ -1,10 +1,12 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
@for (column of columns; track column) {
<ng-container [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns" />
<mat-row *matRowDef="let row; columns: displayedColumns" />
@@ -17,7 +17,7 @@
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { ExtensionRef } from '@alfresco/adf-extensions';
import { CommonModule } from '@angular/common';
import { MatTableModule } from '@angular/material/table';
import { TranslatePipe } from '@ngx-translate/core';
@@ -26,7 +26,7 @@ import { TranslatePipe } from '@ngx-translate/core';
templateUrl: './about-extension-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, MatTableModule, TranslatePipe]
imports: [MatTableModule, TranslatePipe]
})
export class AboutExtensionListComponent {
columns = [
@@ -1,12 +1,14 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row"
class="adf-about-license-cell"
[innerHTML]="column.cell(row)" />
</ng-container>
@for (column of columns; track column) {
<ng-container [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row"
class="adf-about-license-cell"
[innerHTML]="column.cell(row)" />
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns" />
<mat-row *matRowDef="let row; columns: displayedColumns" />
@@ -17,7 +17,7 @@
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation, inject } from '@angular/core';
import { LicenseData } from '../interfaces';
import { CommonModule } from '@angular/common';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { MatTableModule } from '@angular/material/table';
@@ -27,7 +27,7 @@ import { MatTableModule } from '@angular/material/table';
styleUrls: ['./about-license-list.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, TranslatePipe, MatTableModule]
imports: [TranslatePipe, MatTableModule]
})
export class AboutLicenseListComponent {
private readonly translateService = inject(TranslateService);
@@ -1,10 +1,12 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
@for (column of columns; track column) {
<ng-container [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns" />
<mat-row *matRowDef="let row; columns: displayedColumns" />
@@ -16,7 +16,7 @@
*/
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatTableModule } from '@angular/material/table';
@@ -30,7 +30,7 @@ interface ModuleInfo {
templateUrl: './module-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, TranslatePipe, MatTableModule]
imports: [TranslatePipe, MatTableModule]
})
export class ModuleListComponent {
columns = [
@@ -1,10 +1,12 @@
<mat-table [dataSource]="data" class="adf-package-list-table">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef class="adf-package-list-table__header-cell">
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row" class="adf-package-list-table__row-cell">{{ column.cell(row) }}</mat-cell>
</ng-container>
@for (column of columns; track column) {
<ng-container [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef class="adf-package-list-table__header-cell">
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row" class="adf-package-list-table__row-cell">{{ column.cell(row) }}</mat-cell>
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns" class="adf-package-list-table__header-row" />
<mat-row *matRowDef="let row; columns: displayedColumns" class="adf-package-list-table__row" />
@@ -17,7 +17,7 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { PackageInfo } from '../interfaces';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatTableModule } from '@angular/material/table';
@@ -26,7 +26,7 @@ import { MatTableModule } from '@angular/material/table';
templateUrl: './package-list.component.html',
styleUrls: ['./package-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, TranslatePipe, MatTableModule]
imports: [TranslatePipe, MatTableModule]
})
export class PackageListComponent implements OnInit {
@Input()
@@ -1,16 +1,22 @@
<div>
<article *ngIf="licenseEntries">
<header>{{ 'ABOUT.LICENSE.TITLE' | translate }}</header>
<adf-about-license-list [data]="licenseEntries" />
@if (licenseEntries) {
<article>
<header>{{ 'ABOUT.LICENSE.TITLE' | translate }}</header>
<adf-about-license-list [data]="licenseEntries" />
</article>
}
<article *ngIf="statusEntries">
<header>{{ 'ABOUT.STATUS.TITLE' | translate }}</header>
<adf-about-status-list [data]="statusEntries" />
@if (statusEntries) {
<article>
<header>{{ 'ABOUT.STATUS.TITLE' | translate }}</header>
<adf-about-status-list [data]="statusEntries" />
</article>
}
<article *ngIf="data?.modules">
<header>{{ 'ABOUT.MODULES.TITLE' | translate }}</header>
<adf-about-module-list [data]="data.modules" />
@if (data?.modules) {
<article>
<header>{{ 'ABOUT.MODULES.TITLE' | translate }}</header>
<adf-about-module-list [data]="data.modules" />
</article>
}
</div>
@@ -19,7 +19,7 @@ import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { ObjectUtils, StringUtils } from '../../common/utils';
import { LicenseData, StatusData } from '../interfaces';
import { RepositoryInfo } from './repository-info.interface';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { AboutLicenseListComponent } from '../about-license-list/about-license-list.component';
import { ModuleListComponent } from '../about-module-list/module-list.component';
@@ -30,7 +30,7 @@ import { AboutStatusListComponent } from '../about-status-list/about-status-list
templateUrl: './about-repository-info.component.html',
styleUrls: ['./about-repository-info.component.scss'],
encapsulation: ViewEncapsulation.None,
imports: [CommonModule, TranslatePipe, AboutLicenseListComponent, ModuleListComponent, AboutStatusListComponent]
imports: [TranslatePipe, AboutLicenseListComponent, ModuleListComponent, AboutStatusListComponent]
})
export class AboutRepositoryInfoComponent implements OnInit {
@Input()
@@ -17,7 +17,7 @@
import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatCardModule } from '@angular/material/card';
@@ -26,7 +26,7 @@ import { MatCardModule } from '@angular/material/card';
templateUrl: './about-server-settings.component.html',
styleUrls: ['./about-server-settings.component.scss'],
encapsulation: ViewEncapsulation.None,
imports: [CommonModule, TranslatePipe, MatCardModule]
imports: [TranslatePipe, MatCardModule]
})
export class AboutServerSettingsComponent implements OnInit {
private readonly appConfig = inject(AppConfigService);
@@ -1,10 +1,12 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
@for (column of columns; track column) {
<ng-container [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns" />
<mat-row *matRowDef="let row; columns: displayedColumns" />
@@ -17,7 +17,7 @@
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { StatusData } from '../interfaces';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatTableModule } from '@angular/material/table';
@@ -26,7 +26,7 @@ import { MatTableModule } from '@angular/material/table';
templateUrl: './about-status-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, TranslatePipe, MatTableModule]
imports: [TranslatePipe, MatTableModule]
})
export class AboutStatusListComponent {
columns = [
+8 -8
View File
@@ -1,10 +1,10 @@
<mat-accordion [togglePosition]="'before'" class="adf-about-panel">
<ng-container *ngFor="let panel of panels">
<mat-expansion-panel [attr.data-automation-id]="panel.automationId">
<mat-expansion-panel-header class="adf-about-panel-header">
<mat-panel-title class="adf-about-panel-header__title">{{panel.label}}</mat-panel-title>
</mat-expansion-panel-header>
<ng-container *ngTemplateOutlet="panel.layoutTemplate" />
</mat-expansion-panel>
</ng-container>
@for (panel of panels; track panel) {
<mat-expansion-panel [attr.data-automation-id]="panel.automationId">
<mat-expansion-panel-header class="adf-about-panel-header">
<mat-panel-title class="adf-about-panel-header__title">{{panel.label}}</mat-panel-title>
</mat-expansion-panel-header>
<ng-container *ngTemplateOutlet="panel.layoutTemplate" />
</mat-expansion-panel>
}
</mat-accordion>
@@ -1,7 +1,8 @@
<div class="adf-avatar">
<img (error)="src = ''" *ngIf="src; else initialsTemplate" class="adf-avatar__image" [src]="src" [alt]="initials" [title]="tooltip" />
@if (src) {
<img (error)="src = ''" class="adf-avatar__image" [src]="src" [alt]="initials" [title]="tooltip" />
} @else {
<div class="adf-avatar__image adf-avatar__initials" [title]="tooltip">{{ initials }}</div>
}
</div>
<ng-template #initialsTemplate>
<div class="adf-avatar__image adf-avatar__initials" [title]="tooltip">{{ initials }}</div>
</ng-template>
+2 -2
View File
@@ -16,11 +16,11 @@
*/
import { Component, HostBinding, Input, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'adf-avatar',
imports: [CommonModule],
imports: [],
templateUrl: './avatar.component.html',
styleUrls: ['./avatar.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,66 +1,78 @@
<div [attr.data-automation-id]="'card-array-label-' + property.key" class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-value adf-card-view-array-item-container">
<ng-container *ngIf="(property.displayValue | async) as items; else elseEmptyValueBlock">
<mat-chip-listbox *ngIf="items.length > 0; else elseEmptyValueBlock" data-automation-id="card-arrayitem-chip-list-container">
<ng-container *ngIf="displayCount > 0; else withOutDisplayCount" >
<mat-chip
*ngFor="let item of items.slice(0, displayCount)"
(keyup.enter)="clicked()"
(click)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<div class="adf-card-view-array-chip-content">
<mat-icon *ngIf="item?.icon" class="adf-array-item-icon" [adf-icon]="item.icon" />
<span>{{item?.value}}</span>
</div>
</mat-chip>
<mat-chip
*ngIf="items.length > displayCount"
data-automation-id="card-arrayitem-more-chip"
[matMenuTriggerFor]="menu">
<span>{{items.length - displayCount}} {{'CORE.CARDVIEW.MORE' | translate}}</span>
</mat-chip>
</ng-container>
<ng-template #withOutDisplayCount>
<mat-chip
*ngFor="let item of items"
(keyup.enter)="clicked()"
(click)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<div class="adf-card-view-array-chip-content">
<mat-icon *ngIf="item?.icon" class="adf-array-item-icon" [adf-icon]="item.icon" />
<span>{{item?.value}}</span>
</div>
</mat-chip>
</ng-template>
</mat-chip-listbox>
<mat-menu #menu="matMenu">
<mat-card appearance="outlined" class="adf-array-item-more-chip-container">
<mat-card-content>
<mat-chip-listbox>
<mat-chip (click)="clicked()" (keyup.enter)="clicked()"
*ngFor="let item of items.slice(displayCount, items.length)"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<div class="adf-card-view-array-chip-content">
<mat-icon *ngIf="item?.icon" class="adf-array-item-icon" [adf-icon]="item.icon" />
<span>{{item?.value}}</span>
</div>
</mat-chip>
</mat-chip-listbox>
</mat-card-content>
</mat-card>
</mat-menu>
</ng-container>
<ng-template #elseEmptyValueBlock>
<span class="adf-card-array-item-default" data-automation-id="card-arrayitem-default">{{ property?.default | translate }}</span>
</ng-template>
@if (showClickableIcon) {
<button mat-icon-button
(click)="clicked()"
(keydown.enter)="clicked()"
[attr.aria-label]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'card-array-item-clickable-icon-' + property.key">
<mat-icon class="adf-array-item-button-icon" [adf-icon]="property.icon" />
</button>
@if ((property.displayValue | async); as items) {
@if (items.length > 0) {
<mat-chip-listbox data-automation-id="card-arrayitem-chip-list-container">
@if (displayCount > 0) {
@for (item of items.slice(0, displayCount); track item) {
<mat-chip
(keyup.enter)="clicked()"
(click)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<div class="adf-card-view-array-chip-content">
@if (item?.icon) {
<mat-icon class="adf-array-item-icon" [adf-icon]="item.icon" />
}
<span>{{item?.value}}</span>
</div>
</mat-chip>
}
@if (items.length > displayCount) {
<mat-chip
data-automation-id="card-arrayitem-more-chip"
[matMenuTriggerFor]="menu">
<span>{{items.length - displayCount}} {{'CORE.CARDVIEW.MORE' | translate}}</span>
</mat-chip>
}
} @else {
@for (item of items; track item) {
<mat-chip
(keyup.enter)="clicked()"
(click)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<div class="adf-card-view-array-chip-content">
@if (item?.icon) {
<mat-icon class="adf-array-item-icon" [adf-icon]="item.icon" />
}
<span>{{item?.value}}</span>
</div>
</mat-chip>
}
}
</mat-chip-listbox>
} @else {
<span class="adf-card-array-item-default" data-automation-id="card-arrayitem-default">{{ property?.default | translate }}</span>
}
<mat-menu #menu="matMenu">
<mat-card appearance="outlined" class="adf-array-item-more-chip-container">
<mat-card-content>
<mat-chip-listbox>
@for (item of items.slice(displayCount, items.length); track item) {
<mat-chip (click)="clicked()" (keyup.enter)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<div class="adf-card-view-array-chip-content">
@if (item?.icon) {
<mat-icon class="adf-array-item-icon" [adf-icon]="item.icon" />
}
<span>{{item?.value}}</span>
</div>
</mat-chip>
}
</mat-chip-listbox>
</mat-card-content>
</mat-card>
</mat-menu>
} @else {
<span class="adf-card-array-item-default" data-automation-id="card-arrayitem-default">{{ property?.default | translate }}</span>
}
@if (showClickableIcon) {
<button mat-icon-button
(click)="clicked()"
(keydown.enter)="clicked()"
[attr.aria-label]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'card-array-item-clickable-icon-' + property.key">
<mat-icon class="adf-array-item-button-icon" [adf-icon]="property.icon" />
</button>
}
</div>
@@ -1,24 +1,24 @@
<ng-container *ngIf="!property.isEmpty() || isEditable">
<div class="adf-property-value">
<mat-checkbox
#checkbox="ngModel"
adf-card-view-property-validator
[attr.data-automation-id]="'card-boolean-' + property.key"
[attr.title]="'CORE.METADATA.ACTIONS.TOGGLE' | translate"
[checked]="property.displayValue"
[disabled]="!isEditable"
[ngModel]="property.displayValue"
[property]="property"
(ngModelChange)="changed($event)"
(validated)="onValidation($event)"
>
<div
[attr.data-automation-id]="'card-boolean-label-' + property.key"
class="adf-property-label"
>{{ property.label | translate }}</div>
@if(checkbox.touched && error){
<mat-error [innerHTML]="error" />
}
</mat-checkbox>
</div>
</ng-container>
@if (!property.isEmpty() || isEditable) {
<div class="adf-property-value">
<mat-checkbox
#checkbox="ngModel"
adf-card-view-property-validator
[attr.data-automation-id]="'card-boolean-' + property.key"
[attr.title]="'CORE.METADATA.ACTIONS.TOGGLE' | translate"
[checked]="property.displayValue"
[disabled]="!isEditable"
[ngModel]="property.displayValue"
[property]="property"
(ngModelChange)="changed($event)"
(validated)="onValidation($event)"
>
<div
[attr.data-automation-id]="'card-boolean-label-' + property.key"
class="adf-property-label"
>{{ property.label | translate }}</div>
@if(checkbox.touched && error){
<mat-error [innerHTML]="error" />
}
</mat-checkbox>
</div>
}
@@ -19,7 +19,7 @@ import { Component, Input } from '@angular/core';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { CardViewBoolItemModel } from '../../models/card-view-boolitem.model';
import { BaseCardView } from '../base-card-view';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { CardViewPropertyValidatorDirective } from '../../directives/card-view-property-validator.directive';
import { FormsModule } from '@angular/forms';
@@ -27,7 +27,7 @@ import { MatError } from '@angular/material/form-field';
@Component({
selector: 'adf-card-view-boolitem',
imports: [CommonModule, MatCheckboxModule, TranslatePipe, CardViewPropertyValidatorDirective, FormsModule, MatError],
imports: [MatCheckboxModule, TranslatePipe, CardViewPropertyValidatorDirective, FormsModule, MatError],
templateUrl: './card-view-boolitem.component.html',
styles: [
`
@@ -1,136 +1,137 @@
<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"
>
{{ 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 [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
@if (showProperty) {
{{ property.displayValue }}
} @else {
{{ property.default | translate }}
}
@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"
>
{{ 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 [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
@if (showProperty) {
{{ property.displayValue }}
} @else {
{{ property.default | translate }}
}
</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}"
/>
</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"
<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">
@for (propertyValue of property.displayValue; track propertyValue; let idx = $index) {
<mat-chip-option
[removable]="isEditable"
(removed)="removeValueFromList(idx)"
>
{{ 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"
(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"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
<mat-datetimepicker
#datetimePicker
[type]="$any(property).type"
[timeInterval]="5"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate"
[disabled]="isReadonlyProperty || !editable"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
</mat-form-field>
}
{{ 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"
(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"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
<mat-datetimepicker
#datetimePicker
[type]="$any(property).type"
[timeInterval]="5"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate"
[disabled]="isReadonlyProperty || !editable"
[ngClass]="{ 'cdk-visually-hidden': !editable || isReadonlyProperty}"
/>
</mat-form-field>
}
</div>
@@ -1,63 +1,67 @@
<div [attr.data-automation-id]="'card-key-value-pairs-label-' + property.key"
class="adf-property-label">{{ property.label | translate }}</div>
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">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let item">{{item.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="value">
<mat-header-cell *matHeaderCellDef>{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let item">{{item.value}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['name', 'value']" />
<mat-row *matRowDef="let row; columns: ['name', 'value'];" />
</mat-table>
@if (!isEditable) {
<div 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>
<mat-cell *matCellDef="let item">{{item.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="value">
<mat-header-cell *matHeaderCellDef>{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let item">{{item.value}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['name', 'value']" />
<mat-row *matRowDef="let row; columns: ['name', 'value'];" />
</mat-table>
</div>
}
<div class="adf-card-view__key-value-pairs adf-property-value" *ngIf="isEditable && values && values.length">
@if (isEditable && values && values.length) {
<div class="adf-card-view__key-value-pairs adf-property-value">
<div class="adf-card-view__key-value-pairs__row">
<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>
@for (item of values; track item; let i = $index) {
<div class="adf-card-view__key-value-pairs__row">
<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">
<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 adf-icon="close" />
</button>
<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 adf-icon="close" />
</button>
</div>
}
</div>
<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 adf-icon="add" />
</button>
}
@if (isEditable) {
<div 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 adf-icon="add" />
</button>
</div>
}
</div>
@@ -20,7 +20,7 @@ import { CardViewKeyValuePairsItemModel } from '../../models/card-view.models';
import { CardViewKeyValuePairsItemType } from '../../interfaces/card-view.interfaces';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { BaseCardView } from '../base-card-view';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatInputModule } from '@angular/material/input';
import { FormsModule } from '@angular/forms';
@@ -29,7 +29,7 @@ import { IconModule } from '../../../icon/icon.module';
@Component({
selector: 'adf-card-view-key-value-pairs-item',
imports: [CommonModule, TranslatePipe, MatTableModule, MatInputModule, FormsModule, MatButtonModule, IconModule],
imports: [TranslatePipe, MatTableModule, MatInputModule, FormsModule, MatButtonModule, IconModule],
templateUrl: './card-view-keyvaluepairsitem.component.html',
styleUrls: ['./card-view-keyvaluepairsitem.component.scss'],
encapsulation: ViewEncapsulation.None,
@@ -1,24 +1,30 @@
<div [attr.data-automation-id]="'card-mapitem-label-' + property.key"
class="adf-property-label"
*ngIf="showProperty">{{ property.label | translate }}</div>
@if (showProperty) {
<div [attr.data-automation-id]="'card-mapitem-label-' + property.key"
class="adf-property-label"
>{{ property.label | translate }}</div>
}
<div class="adf-property-value adf-map-item-padding">
<div>
<span *ngIf="!isClickable; else clickableTemplate"
[attr.data-automation-id]="'card-mapitem-value-' + property.key">
<span *ngIf="showProperty;">{{ property.displayValue }}</span>
</span>
</div>
<ng-template #clickableTemplate>
<span class="adf-mapitem-clickable-value"
(click)="clicked()"
tabindex="0"
role="button"
(keyup.enter)="clicked()"
[attr.data-automation-id]="'card-mapitem-value-' + property.key">
<span *ngIf="showProperty; else emptyValueTemplate">{{ property.displayValue }}</span>
</span>
</ng-template>
<ng-template #emptyValueTemplate>
{{ property.default | translate }}
</ng-template>
<div>
@if (!isClickable) {
<span
[attr.data-automation-id]="'card-mapitem-value-' + property.key">
@if (showProperty;) {
<span>{{ property.displayValue }}</span>
}
</span>
} @else {
<span class="adf-mapitem-clickable-value"
(click)="clicked()"
tabindex="0"
role="button"
(keyup.enter)="clicked()"
[attr.data-automation-id]="'card-mapitem-value-' + property.key">
@if (showProperty) {
<span>{{ property.displayValue }}</span>
} @else {
{{ property.default | translate }}
}
</span>
}
</div>
</div>
@@ -18,12 +18,12 @@
import { Component, Input } from '@angular/core';
import { CardViewMapItemModel } from '../../models/card-view-mapitem.model';
import { BaseCardView } from '../base-card-view';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
@Component({
selector: 'adf-card-view-mapitem',
imports: [CommonModule, TranslatePipe],
imports: [TranslatePipe],
templateUrl: './card-view-mapitem.component.html',
styleUrls: ['./card-view-mapitem.component.scss']
})
@@ -1,80 +1,93 @@
<ng-container *ngIf="showProperty || isEditable">
<div [ngSwitch]="templateType">
<div *ngSwitchDefault>
<div class="adf-property-field">
<mat-form-field class="adf-property-value">
<mat-label
[attr.data-automation-id]="'card-select-label-' + property.key"
class="adf-property-label"
@if (showProperty || isEditable) {
<div>
@switch (templateType) {
@default {
<div>
<div class="adf-property-field">
<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': isReadonlyProperty || !editable }"
[floatLabel]="property.default ? 'always' : null"
>
<mat-label
[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 || !editable
}"
>{{ 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)"
>
{{ property.label | translate }}
</mat-label>
<input
matInput
[matAutocomplete]="auto"
class="adf-property-value"
@if (showInputFilter) {
<adf-select-filter-input (change)="onFilterInputChange($event)" />
}
@if (displayNoneOption) {
<mat-option>{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
}
@for (option of list$ | async; track option) {
<mat-option [value]="option.key">
{{ option.label | translate }}
</mat-option>
}
</mat-select>
<mat-error [innerHTML]="error" />
</mat-form-field>
</div>
</div>
}
@case ('autocompleteBased') {
<div>
<mat-form-field
class="adf-property-field adf-card-selectitem-autocomplete "
[ngClass]="{ 'adf-property-read-only': isReadonlyProperty || !editable }"
[floatLabel]="property.default ? 'always' : null"
>
<mat-label
[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 || !editable
}"
title="{{ property.label | translate }}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="autocompleteControl"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
[attr.data-automation-id]="'card-autocomplete-based-selectitem-value-' + property.key"
/>
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" (optionSelected)="onOptionSelected($event)">
<mat-option
*ngFor="let option of property.options$ | async"
[value]="option.key"
[attr.data-automation-id]="'card-autocomplete-based-selectitem-option-' + property.key"
>
{{ option.label }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
>
{{ property.label | translate }}
</mat-label>
<input
matInput
[matAutocomplete]="auto"
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': isEditable,
'adf-property-readonly-value': isReadonlyProperty || !editable
}"
title="{{ property.label | translate }}"
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="autocompleteControl"
[title]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
[attr.data-automation-id]="'card-autocomplete-based-selectitem-value-' + property.key"
/>
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" (optionSelected)="onOptionSelected($event)">
@for (option of property.options$ | async; track option) {
<mat-option
[value]="option.key"
[attr.data-automation-id]="'card-autocomplete-based-selectitem-option-' + property.key"
>
{{ option.label }}
</mat-option>
}
</mat-autocomplete>
</mat-form-field>
</div>
</div>
</ng-container>
}
}
</div>
}
@@ -1,26 +1,27 @@
<div class="adf-select-filter-input-container">
<mat-form-field>
<input matInput
autocomplete="off"
(keydown)="handleKeydown($event)"
[placeholder]="'SELECT_FILTER.INPUT.PLACEHOLDER' | translate"
#selectFilterInput
[ngModel]="term"
(ngModelChange)="onModelChange($event)"
[attr.aria-label]="'SELECT_FILTER.INPUT.ARIA_LABEL' | translate"
(change)="$event.stopPropagation()"
/>
<mat-form-field>
<input matInput
autocomplete="off"
(keydown)="handleKeydown($event)"
[placeholder]="'SELECT_FILTER.INPUT.PLACEHOLDER' | translate"
#selectFilterInput
[ngModel]="term"
(ngModelChange)="onModelChange($event)"
[attr.aria-label]="'SELECT_FILTER.INPUT.ARIA_LABEL' | translate"
(change)="$event.stopPropagation()"
/>
<button
matSuffix
mat-icon-button
class="adf-select-filter-clear-button"
[attr.aria-label]="'SELECT_FILTER.BUTTON.ARIA_LABEL' | translate"
*ngIf="term"
(keydown.enter)="reset($event)"
(click)="reset()">
<mat-icon adf-icon="close" />
</button>
</mat-form-field>
@if (term) {
<button
matSuffix
mat-icon-button
class="adf-select-filter-clear-button"
[attr.aria-label]="'SELECT_FILTER.BUTTON.ARIA_LABEL' | translate"
(keydown.enter)="reset($event)"
(click)="reset()">
<mat-icon adf-icon="close" />
</button>
}
</mat-form-field>
</div>
@@ -17,7 +17,7 @@
import { Component, DestroyRef, ElementRef, EventEmitter, inject, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { FormsModule } from '@angular/forms';
@@ -28,7 +28,7 @@ import { IconModule } from '../../../../icon/icon.module';
@Component({
selector: 'adf-select-filter-input',
imports: [CommonModule, MatFormFieldModule, MatInputModule, FormsModule, MatButtonModule, IconModule, TranslatePipe],
imports: [MatFormFieldModule, MatInputModule, FormsModule, MatButtonModule, IconModule, TranslatePipe],
templateUrl: './select-filter-input.component.html',
styleUrls: ['./select-filter-input.component.scss'],
host: { class: 'adf-select-filter-input' },
@@ -1,15 +1,17 @@
<div class="adf-property-list">
<div *ngFor="let property of properties" class="adf-property-container">
<div [attr.data-automation-id]="'header-'+property.key" class="adf-property">
<adf-card-view-item-dispatcher
[property]="property"
[editable]="editable"
[displayEmpty]="displayEmpty"
[displayNoneOption]="property['displayNoneOption'] !== undefined ? property['displayNoneOption'] : displayNoneOption"
[displayClearAction]="displayClearAction"
[copyToClipboardAction]="copyToClipboardAction"
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
[multiValueSeparator]="multiValueSeparator" />
</div>
@for (property of properties; track property) {
<div class="adf-property-container">
<div [attr.data-automation-id]="'header-'+property.key" class="adf-property">
<adf-card-view-item-dispatcher
[property]="property"
[editable]="editable"
[displayEmpty]="displayEmpty"
[displayNoneOption]="property['displayNoneOption'] !== undefined ? property['displayNoneOption'] : displayNoneOption"
[displayClearAction]="displayClearAction"
[copyToClipboardAction]="copyToClipboardAction"
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
[multiValueSeparator]="multiValueSeparator" />
</div>
</div>
}
</div>
@@ -18,12 +18,12 @@
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { CardViewItem } from '../../interfaces/card-view-item.interface';
import { DEFAULT_SEPARATOR } from '../card-view-textitem/card-view-textitem.component';
import { CommonModule } from '@angular/common';
import { CardViewItemDispatcherComponent } from '../card-view-item-dispatcher/card-view-item-dispatcher.component';
@Component({
selector: 'adf-card-view',
imports: [CommonModule, CardViewItemDispatcherComponent],
imports: [CardViewItemDispatcherComponent],
templateUrl: './card-view.component.html',
styleUrls: ['./card-view.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { Injectable, inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { Injectable, inject, DOCUMENT } from '@angular/core';
import { NotificationService } from '../notifications/services/notification.service';
@Injectable({ providedIn: 'root' })
@@ -1,17 +1,23 @@
<mat-list class="adf-comment-list">
<mat-list-item *ngFor="let comment of comments"
(click)="selectComment(comment)"
class="adf-comment-list-item">
<div class="adf-comment-img-container">
<div *ngIf="!comment.hasAvatarPicture" class="adf-comment-user-icon">{{ comment.userInitials }}</div>
<img *ngIf="comment.hasAvatarPicture" class="adf-people-img"
[alt]="'COMMENTS.PROFILE_IMAGE' | translate"
[src]="getUserImage(comment.createdBy.id.toString())" />
</div>
<div class="adf-comment-contents">
<div matLine class="adf-comment-user-name">{{ comment.userDisplayName }}</div>
<div matLine class="adf-comment-message">{{ comment.message }}</div>
<div matLine class="adf-comment-message-time">{{ comment.created | adfTimeAgo }}</div>
</div>
<mat-list class="adf-comment-list">
@for (comment of comments; track comment) {
<mat-list-item
(click)="selectComment(comment)"
class="adf-comment-list-item">
<div class="adf-comment-img-container">
@if (!comment.hasAvatarPicture) {
<div class="adf-comment-user-icon">{{ comment.userInitials }}</div>
}
@if (comment.hasAvatarPicture) {
<img class="adf-people-img"
[alt]="'COMMENTS.PROFILE_IMAGE' | translate"
[src]="getUserImage(comment.createdBy.id.toString())" />
}
</div>
<div class="adf-comment-contents">
<div matLine class="adf-comment-user-name">{{ comment.userDisplayName }}</div>
<div matLine class="adf-comment-message">{{ comment.message }}</div>
<div matLine class="adf-comment-message-time">{{ comment.created | adfTimeAgo }}</div>
</div>
</mat-list-item>
}
</mat-list>
@@ -19,7 +19,7 @@ import { Component, EventEmitter, inject, Input, Output, ViewEncapsulation } fro
import { CommentModel } from '../../models/comment.model';
import { CommentsService } from '../interfaces/comments-service.interface';
import { ADF_COMMENTS_SERVICE } from '../interfaces/comments.token';
import { CommonModule } from '@angular/common';
import { MatListModule } from '@angular/material/list';
import { MatLineModule } from '@angular/material/core';
import { TimeAgoPipe } from '../../pipes';
@@ -27,7 +27,7 @@ import { TranslatePipe } from '@ngx-translate/core';
@Component({
selector: 'adf-comment-list',
imports: [CommonModule, MatListModule, MatLineModule, TimeAgoPipe, TranslatePipe],
imports: [MatListModule, MatLineModule, TimeAgoPipe, TranslatePipe],
templateUrl: './comment-list.component.html',
styleUrls: ['./comment-list.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,35 +1,40 @@
<div class="adf-comments-container">
<div id="comment-header" class="adf-comments-header adf-comments-divider">
{{'COMMENTS.HEADER' | translate: { count: comments?.length } }}
<div id="comment-header" class="adf-comments-header adf-comments-divider">
{{'COMMENTS.HEADER' | translate: { count: comments?.length } }}
</div>
@if (!readOnly) {
<div class="adf-comments-input-container adf-comments-divider">
<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"
[attr.aria-label]='("COMMENTS.ADD" | translate) + "*"'
[formControl]="commentControl"
(keydown.escape)="clearMessage($event)"
>
</textarea>
@if (commentControl.invalid && commentControl.touched) {
<mat-error>{{ 'COMMENTS.EMPTY_ERROR' | translate }}</mat-error>
}
</mat-form-field>
<div class="adf-comments-input-actions">
<button
mat-button
data-automation-id="comments-input-add"
color="primary"
(click)="addComment()"
[disabled]="commentControl.invalid"
>
{{ 'COMMENTS.ADD' | translate }}
</button>
</div>
</div>
<div *ngIf="!readOnly" class="adf-comments-input-container adf-comments-divider">
<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"
[attr.aria-label]='("COMMENTS.ADD" | translate) + "*"'
[formControl]="commentControl"
(keydown.escape)="clearMessage($event)"
>
</textarea>
<mat-error *ngIf="commentControl.invalid && commentControl.touched">{{ 'COMMENTS.EMPTY_ERROR' | translate }}</mat-error>
</mat-form-field>
}
<div class="adf-comments-input-actions">
<button
mat-button
data-automation-id="comments-input-add"
color="primary"
(click)="addComment()"
[disabled]="commentControl.invalid"
>
{{ 'COMMENTS.ADD' | translate }}
</button>
</div>
</div>
<adf-comment-list *ngIf="comments?.length > 0" [comments]="comments" />
@if (comments?.length > 0) {
<adf-comment-list [comments]="comments" />
}
</div>
@@ -19,7 +19,7 @@ import { CommentModel } from '../models/comment.model';
import { Component, ElementRef, EventEmitter, inject, Input, OnChanges, Output, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { ADF_COMMENTS_SERVICE } from './interfaces/comments.token';
import { CommentsService } from './interfaces/comments-service.interface';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
@@ -30,15 +30,14 @@ import { CommentListComponent } from './comment-list';
@Component({
selector: 'adf-comments',
imports: [
CommonModule,
TranslatePipe,
MatFormFieldModule,
MatInputModule,
FormsModule,
MatButtonModule,
CommentListComponent,
ReactiveFormsModule
],
TranslatePipe,
MatFormFieldModule,
MatInputModule,
FormsModule,
MatButtonModule,
CommentListComponent,
ReactiveFormsModule
],
templateUrl: './comments.component.html',
styleUrls: ['./comments.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -15,14 +15,14 @@
* limitations under the License.
*/
import { inject, Injectable, RendererFactory2, Signal } from '@angular/core';
import { inject, Injectable, RendererFactory2, Signal, DOCUMENT } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { StorageService } from './storage.service';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { LanguageItem } from './language-item.interface';
import { DOCUMENT } from '@angular/common';
import { Directionality, Direction } from '@angular/cdk/bidi';
import { DEFAULT_LANGUAGE_LIST } from '../models/default-languages.model';
import { toSignal } from '@angular/core/rxjs-interop';
@@ -46,7 +46,6 @@ export class UserPreferencesService {
private readonly document = inject(DOCUMENT);
private readonly rendererFactory = inject(RendererFactory2);
private readonly directionality = inject(Directionality);
defaults = {
paginationSize: 25,
@@ -135,7 +134,6 @@ export class UserPreferencesService {
this.select('textOrientation').subscribe((direction: Direction) => {
renderer.setAttribute(this.document.body, 'dir', direction);
(this.directionality as any).value = direction;
});
}
@@ -1,15 +1,19 @@
<div mat-menu class="mat-mdc-menu-panel mdc-menu-surface mdc-menu-surface--open" @panelAnimation>
<div id="adf-context-menu-content" class="mat-mdc-menu-content">
<ng-container *ngFor="let link of links">
<button *ngIf="link.model?.visible"
[attr.data-automation-id]="'context-' + (link.title || link.model?.title | translate)"
mat-menu-item
[disabled]="link.model?.disabled"
[title]="link.model?.tooltip | translate"
(click)="onMenuItemClick($event, link)">
<mat-icon *ngIf="link.model?.icon" [adf-icon]="link.model.icon" />
<span>{{ link.title || link.model?.title | translate }}</span>
</button>
</ng-container>
</div>
<div id="adf-context-menu-content" class="mat-mdc-menu-content">
@for (link of links; track link) {
@if (link.model?.visible) {
<button
[attr.data-automation-id]="'context-' + (link.title || link.model?.title | translate)"
mat-menu-item
[disabled]="link.model?.disabled"
[title]="link.model?.tooltip | translate"
(click)="onMenuItemClick($event, link)">
@if (link.model?.icon) {
<mat-icon [adf-icon]="link.model.icon" />
}
<span>{{ link.title || link.model?.title | translate }}</span>
</button>
}
}
</div>
</div>
@@ -22,7 +22,7 @@ import { ContextMenuOverlayRef } from './context-menu-overlay';
import { contextMenuAnimation } from './animations';
import { CONTEXT_MENU_DATA } from './context-menu.tokens';
import { AfterViewInit, Component, HostListener, QueryList, ViewChildren, ViewEncapsulation, inject } from '@angular/core';
import { NgForOf, NgIf } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
import { IconModule } from '../icon/icon.module';
@@ -37,7 +37,7 @@ import { ContextMenuItem } from './interfaces';
class: 'adf-context-menu'
},
encapsulation: ViewEncapsulation.None,
imports: [IconModule, MatMenuModule, NgForOf, NgIf, TranslatePipe],
imports: [IconModule, MatMenuModule, TranslatePipe],
animations: [trigger('panelAnimation', contextMenuAnimation)]
})
export class ContextMenuListComponent implements AfterViewInit {
@@ -1,77 +1,80 @@
<div
class="adf-columns-selector"
role="presentation"
data-automation-id="adf-columns-selector"
(keyup.enter)="$event.stopPropagation()"
(click)="$event.stopPropagation();"
>
<div class="adf-columns-selector-header">
<span class="adf-columns-selector-header-label">
{{"ADF-DATATABLE.COLUMNS_SELECTOR.COLUMNS" | translate}}
</span>
class="adf-columns-selector"
role="presentation"
data-automation-id="adf-columns-selector"
(keyup.enter)="$event.stopPropagation()"
(click)="$event.stopPropagation();"
>
<div class="adf-columns-selector-header">
<span class="adf-columns-selector-header-label">
{{"ADF-DATATABLE.COLUMNS_SELECTOR.COLUMNS" | translate}}
</span>
<button
data-automation-id="adf-columns-selector-close-button"
mat-icon-button
[attr.aria-label]="'CLOSE' | translate"
(click)="closeMenu()"
>
<mat-icon adf-icon="close" />
</button>
</div>
<button
data-automation-id="adf-columns-selector-close-button"
mat-icon-button
[attr.aria-label]="'CLOSE' | translate"
(click)="closeMenu()"
>
<mat-icon adf-icon="close" />
</button>
</div>
<mat-divider class="adf-columns-selector-divider" aria-hidden="true" />
<mat-divider class="adf-columns-selector-divider" aria-hidden="true" />
<mat-form-field class="adf-columns-selector-search-input-form">
<mat-label>{{ 'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate }}</mat-label>
<input
matInput
type="text"
data-automation-id="adf-columns-selector-search-input"
[placeholder]="'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate"
[formControl]="searchInputControl"/>
<mat-icon adf-icon="search" matSuffix />
</mat-form-field>
<mat-form-field class="adf-columns-selector-search-input-form">
<mat-label>{{ 'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate }}</mat-label>
<input
matInput
type="text"
data-automation-id="adf-columns-selector-search-input"
[placeholder]="'ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH' | translate"
[formControl]="searchInputControl"/>
<mat-icon adf-icon="search" matSuffix />
</mat-form-field>
<mat-selection-list
class="adf-columns-selector-list-container"
(selectionChange)="changeColumnVisibility($event)"
[attr.aria-label]='"ADF-DATATABLE.COLUMNS_SELECTOR.COLUMNS_VISIBILITY" | translate'>
<div *ngFor="let column of (columnItems | columnsSearchFilter: searchQuery)" class="adf-columns-selector-list-item">
<mat-list-option
color="primary"
class="adf-columns-selector-column-checkbox"
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
[selected]="!column.isHidden"
[disabled]="isCheckboxDisabled(column)"
[value]="column.id">
<div class="adf-columns-selector-list-content">
{{column.title | translate}}
</div>
<div
*ngIf="column.subtitle"
<mat-selection-list
class="adf-columns-selector-list-container"
(selectionChange)="changeColumnVisibility($event)"
[attr.aria-label]='"ADF-DATATABLE.COLUMNS_SELECTOR.COLUMNS_VISIBILITY" | translate'>
@for (column of (columnItems | columnsSearchFilter: searchQuery); track column) {
<div class="adf-columns-selector-list-item">
<mat-list-option
color="primary"
class="adf-columns-selector-column-checkbox"
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
[selected]="!column.isHidden"
[disabled]="isCheckboxDisabled(column)"
[value]="column.id">
<div class="adf-columns-selector-list-content">
{{column.title | translate}}
</div>
@if (column.subtitle) {
<div
class="
adf-columns-selector-list-content
adf-columns-selector-subtitle
"
>
<span>
{{column.subtitle | translate}}
</span>
</div>
</mat-list-option>
</div>
</mat-selection-list>
>
<span>
{{column.subtitle | translate}}
</span>
</div>
}
</mat-list-option>
</div>
}
</mat-selection-list>
<mat-divider class="adf-columns-selector-divider" aria-hidden="true" />
<mat-divider class="adf-columns-selector-divider" aria-hidden="true" />
<div class="adf-columns-selector-footer">
<button
mat-flat-button
data-automation-id="adf-columns-selector-apply-button"
color="primary"
(click)="apply()">
{{"ADF-DATATABLE.COLUMNS_SELECTOR.APPLY" | translate}}
</button>
</div>
<div class="adf-columns-selector-footer">
<button
mat-flat-button
data-automation-id="adf-columns-selector-apply-button"
color="primary"
(click)="apply()">
{{"ADF-DATATABLE.COLUMNS_SELECTOR.APPLY" | translate}}
</button>
</div>
</div>
@@ -20,7 +20,7 @@ import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
import { MatMenuTrigger } from '@angular/material/menu';
import { debounceTime } from 'rxjs/operators';
import { DataColumn } from '../../data/data-column.model';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
@@ -35,19 +35,18 @@ import { IconModule } from '../../../icon/icon.module';
@Component({
selector: 'adf-datatable-column-selector',
imports: [
CommonModule,
TranslatePipe,
MatButtonModule,
IconModule,
MatDividerModule,
ReactiveFormsModule,
MatCheckboxModule,
ColumnsSearchFilterPipe,
MatSelectionList,
MatListOption,
MatFormFieldModule,
MatInputModule
],
TranslatePipe,
MatButtonModule,
IconModule,
MatDividerModule,
ReactiveFormsModule,
MatCheckboxModule,
ColumnsSearchFilterPipe,
MatSelectionList,
MatListOption,
MatFormFieldModule,
MatInputModule
],
templateUrl: './columns-selector.component.html',
styleUrls: ['./columns-selector.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,57 +1,57 @@
<div
@if (data) {
<div
role="grid"
*ngIf="data"
class="adf-datatable-list"
[class.adf-sticky-header]="isStickyHeaderEnabled()"
[class.adf-datatable--empty]="(isEmpty() && !isHeaderVisible()) || loading"
[class.adf-datatable--empty--header-visible]="isEmpty() && isHeaderVisible()"
>
<div *ngIf="isHeaderVisible()" class="adf-datatable-header" role="rowgroup" [ngClass]="{ 'adf-sr-only': !isHeaderVisible() }">
>
@if (isHeaderVisible()) {
<div class="adf-datatable-header" role="rowgroup" [ngClass]="{ 'adf-sr-only': !isHeaderVisible() }">
<adf-datatable-row
cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListSortPredicate]="filterDisabledColumns"
data-automation-id="datatable-row-header"
class="adf-datatable-row"
role="row">
<!-- Drag -->
<div *ngIf="enableDragRows" class="adf-datatable-cell-header adf-drag-column">
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.DRAG' | translate }}</span>
cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListSortPredicate]="filterDisabledColumns"
data-automation-id="datatable-row-header"
class="adf-datatable-row"
role="row">
<!-- Drag -->
@if (enableDragRows) {
<div class="adf-datatable-cell-header adf-drag-column">
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.DRAG' | translate }}</span>
</div>
<!-- Actions (left) -->
<div *ngIf="actions && actionsPosition === 'left'" class="adf-actions-column adf-datatable-cell-header">
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
}
<!-- Actions (left) -->
@if (actions && actionsPosition === 'left') {
<div class="adf-actions-column adf-datatable-cell-header">
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
</div>
<!-- Columns -->
<div *ngIf="multiselect" class="adf-datatable-cell-header adf-datatable-checkbox">
<mat-checkbox
[indeterminate]="isSelectAllIndeterminate"
[checked]="isSelectAllChecked"
(change)="onSelectAllClick($event)"
class="adf-checkbox-sr-only"
[aria-label]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate"
[matTooltip]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate"
#tooltip="matTooltip"
(focusin)="tooltip.show()"
(focusout)="tooltip.hide()"
}
<!-- Columns -->
@if (multiselect) {
<div class="adf-datatable-cell-header adf-datatable-checkbox">
<mat-checkbox
[indeterminate]="isSelectAllIndeterminate"
[checked]="isSelectAllChecked"
(change)="onSelectAllClick($event)"
class="adf-checkbox-sr-only"
[aria-label]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate"
[matTooltip]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate"
#tooltip="matTooltip"
(focusin)="tooltip.show()"
(focusout)="tooltip.hide()"
>
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate }}
</mat-checkbox>
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate }}
</mat-checkbox>
</div>
<ng-container
*ngFor="
let col of getVisibleColumns();
let columnIndex = index
let lastColumn = last"
>
<div
}
@for (
col of getVisibleColumns(); track
col; let columnIndex = $index
let lastColumn) {
@if (col.title || !showProvidedActions) {
<div
class="adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-header adf-datatable-cell-data"
*ngIf="col.title || !showProvidedActions"
[attr.data-automation-id]="'auto_id_' + col.key"
[ngClass]="{
'adf-sortable': col.sortable,
@@ -71,13 +71,12 @@
(mouseleave)="hoveredHeaderColumnIndex = -1"
adf-drop-zone dropTarget="header"
[dropColumn]="col"
>
<div
adf-resizable
#resizableElement="adf-resizable"
[attr.tabindex]="col.sortable ? 0 : null"
[attr.role]="col.sortable ? 'button' : null"
>
<div
adf-resizable
#resizableElement="adf-resizable"
[attr.tabindex]="col.sortable ? 0 : null"
[attr.role]="col.sortable ? 'button' : null"
[attr.aria-description]="
isColumnSortActive(col) ? (getSortLiveAnnouncement(col) | translate: { string: col.title | translate }) : null
"
@@ -89,71 +88,76 @@
(col.title | translate) +
(col.subtitle ? ' ' + (col.subtitle | translate) : '')
"
(click)="onColumnHeaderClick(col, $event)"
(keyup.enter)="onColumnHeaderClick(col, $event)"
[coverPadding]="10"
(resizing)="onResizing($event, columnIndex)"
(keyboardResizing)="onResizing($event, columnIndex)"
(resizeStart)="resizingColumnIndex = columnIndex"
(resizeEnd)="onResizingEnd()"
[attr.data-automation-id]="'auto_header_content_id_' + col.key"
class="adf-datatable-cell-header-content"
(click)="onColumnHeaderClick(col, $event)"
(keyup.enter)="onColumnHeaderClick(col, $event)"
[coverPadding]="10"
(resizing)="onResizing($event, columnIndex)"
(keyboardResizing)="onResizing($event, columnIndex)"
(resizeStart)="resizingColumnIndex = columnIndex"
(resizeEnd)="onResizingEnd()"
[attr.data-automation-id]="'auto_header_content_id_' + col.key"
class="adf-datatable-cell-header-content"
[ngClass]="{ 'adf-datatable-cell-header-content--hovered':
hoveredHeaderColumnIndex === columnIndex &&
!isDraggingHeaderColumn &&
!isResizing && col.sortable}"
>
<ng-container *ngIf="!col.header">
<span
*ngIf="col.title"
>
@if (!col.header) {
@if (col.title) {
<span
title="{{col.title | translate}}"
class="adf-datatable-cell-value"
>
>
{{col.title | translate}}
</span>
<span
*ngIf="col.subtitle"
</span>
}
@if (col.subtitle) {
<span
title="{{col.subtitle | translate}}"
class="adf-datatable-cell-value adf-datatable-cell-header_subtitle"
>
>
({{col.subtitle | translate}})
</span>
<span *ngIf="col.title && col.sortable && isDraggingHeaderColumn" class="adf-sr-only" aria-live="polite">
</span>
}
@if (col.title && col.sortable && isDraggingHeaderColumn) {
<span class="adf-sr-only" aria-live="polite">
{{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }}
</span>
<span *ngIf="!col.title && !col.sortable && !headerFilterTemplate" [attr.title]="'ADF-DATATABLE.ACCESSIBILITY.EMPTY_HEADER' | translate"></span>
</ng-container>
<div *ngIf="col.header" class="adf-datatable-cell-value">
<ng-template [ngTemplateOutlet]="col.header" [ngTemplateOutletContext]="{$implicit: col}" />
</div>
<span
</span>
}
@if (!col.title && !col.sortable && !headerFilterTemplate) {
<span [attr.title]="'ADF-DATATABLE.ACCESSIBILITY.EMPTY_HEADER' | translate"></span>
}
}
@if (col.header) {
<div class="adf-datatable-cell-value">
<ng-template [ngTemplateOutlet]="col.header" [ngTemplateOutletContext]="{$implicit: col}" />
</div>
}
<span
[class.adf-datatable__header--sorted-asc]="isColumnSorted(col, 'asc')"
[class.adf-datatable__header--sorted-desc]="isColumnSorted(col, 'desc')">
</span>
<ng-template *ngIf="allowFiltering" [ngTemplateOutlet]="headerFilterTemplate" [ngTemplateOutletContext]="{$implicit: col}" />
<span
*ngIf="col.draggable"
cdkDragHandle
[ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }"
>
<mat-icon
*ngIf="hoveredHeaderColumnIndex === columnIndex && !isResizing"
svgIcon="adf:drag_indicator"
class="adf-datatable-cell-header-drag-icon-visible"
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-'+col.key"
aria-hidden="true"
/>
</span>
</div>
<div
*ngIf="isResizingEnabled && col.resizable && !lastColumn"
</span>
@if (allowFiltering) {
<ng-template [ngTemplateOutlet]="headerFilterTemplate" [ngTemplateOutletContext]="{$implicit: col}" />
}
@if (col.draggable) {
<span
cdkDragHandle
[ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }"
>
@if (hoveredHeaderColumnIndex === columnIndex && !isResizing) {
<mat-icon
svgIcon="adf:drag_indicator"
class="adf-datatable-cell-header-drag-icon-visible"
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-'+col.key"
aria-hidden="true"
/>
}
</span>
}
</div>
@if (isResizingEnabled && col.resizable && !lastColumn) {
<div
[ngClass]="hoveredHeaderColumnIndex === columnIndex && !isResizing || resizingColumnIndex === columnIndex ? 'adf-datatable__resize-handle-visible' : 'adf-datatable__resize-handle-hidden'"
adf-resize-handle
tabindex="0"
@@ -167,155 +171,167 @@
class="adf-datatable__resize-handle"
[resizableContainer]="resizableElement">
<div class="adf-datatable__resize-handle--divider"></div>
</div>
<div class="adf-drop-header-cell-placeholder" *cdkDragPlaceholder></div>
</div>
</ng-container>
<!-- Header actions (right) -->
</div>
}
<div class="adf-drop-header-cell-placeholder" *cdkDragPlaceholder></div>
</div>
}
}
<!-- Header actions (right) -->
@if ((actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions)) {
<div
*ngIf="(actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions)"
class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell"
[class.adf-datatable-actions-menu-provided]="showProvidedActions"
>
<ng-container *ngIf="mainActionTemplate">
<button
data-automation-id="adf-datatable-main-menu-button"
title="{{ 'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate }}"
mat-icon-button
#mainMenuTrigger="matMenuTrigger"
(click)="onMainMenuOpen()"
[matMenuTriggerFor]="mainMenu">
<mat-icon adf-icon="view_week_outline" />
</button>
<mat-menu #mainMenu (closed)="onMainMenuClosed()">
<div #mainMenuTemplate role="presentation" (keydown.tab)="$event.stopPropagation()">
<ng-container
[ngTemplateOutlet]="mainActionTemplate"
class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell"
[class.adf-datatable-actions-menu-provided]="showProvidedActions"
>
@if (mainActionTemplate) {
<button
data-automation-id="adf-datatable-main-menu-button"
title="{{ 'ADF-DATATABLE.CONTENT-ACTIONS.SELECT_COLUMNS' | translate }}"
mat-icon-button
#mainMenuTrigger="matMenuTrigger"
(click)="onMainMenuOpen()"
[matMenuTriggerFor]="mainMenu">
<mat-icon adf-icon="view_week_outline" />
</button>
<mat-menu #mainMenu (closed)="onMainMenuClosed()">
<div #mainMenuTemplate role="presentation" (keydown.tab)="$event.stopPropagation()">
<ng-container
[ngTemplateOutlet]="mainActionTemplate"
[ngTemplateOutletContext]="{
$implicit: mainMenuTrigger
}" />
</div>
</mat-menu>
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
</ng-container>
</div>
</mat-menu>
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
}
</div>
}
</adf-datatable-row>
</div>
<div
*ngIf="!loading; else loadingRowTemplate"
</div>
}
@if (!loading) {
<div
class="adf-datatable-body"
[ngClass]="{ 'adf-blur-datatable-body': blurOnResize && (isDraggingHeaderColumn || isResizing), 'adf-datatable-body__draggable': enableDragRows && !isDraggingRow, 'adf-datatable-body__dragging': isDraggingRow }"
cdkDropList
[cdkDropListDisabled]="!enableDragRows"
role="rowgroup">
<ng-container *ngIf="!noPermission; else noPermissionsRowTemplate">
<adf-datatable-row *ngFor="let row of data.getRows(); let idx = index"
cdkDrag
[cdkDragDisabled]="!enableDragRows"
(cdkDragDropped)="onDragDrop($event)"
(cdkDragStarted)="onDragStart()"
(cdkDragEnded)="onDragEnd()"
[cdkDragBoundary]="'.adf-datatable-body'"
[row]="row"
(select)="onEnterKeyPressed(row, $event)"
(keyup)="onRowKeyUp(row, $event)"
(keydown)="onRowEnterKeyDown(row, $event)"
[adf-upload]="rowAllowsDrop(row)"
[adf-upload-data]="row"
[ngStyle]="rowStyle"
[ngClass]="getRowStyle(row)"
[class.adf-datatable-row__dragging]="isDraggingRow"
[attr.data-automation-id]="'datatable-row-' + idx"
(contextmenu)="markRowAsContextMenuSource(row)"
[disabled]="!(data?.allowFocusOnRows ?? true)"
>
<!-- Drag button -->
<div *ngIf="enableDragRows"
role="gridcell"
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-hover-only">
<button mat-icon-button
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.DRAG' | translate">
<mat-icon adf-icon="drag_indicator" />
</button>
</div>
<!-- Actions (left) -->
<div *ngIf="actions && actionsPosition === 'left'" role="gridcell" class="adf-datatable-cell">
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_left_' + idx"
[attr.data-automation-id]="'action_menu_' + idx">
<mat-icon adf-icon="more_vert" />
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let action of getRowActions(row)"
[attr.data-automation-id]="action.title"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
<mat-icon *ngIf="action.icon" [adf-icon]="action.icon" />
<span>{{ action.title | translate }}</span>
</button>
</mat-menu>
</div>
<label *ngIf="multiselect"
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
(click)="onCheckboxLabelClick(row, $event)"
[for]="'select-file-' + idx"
class="adf-datatable-cell adf-datatable-checkbox adf-datatable-checkbox-single"
[attr.tabindex]="null">
<mat-checkbox
[id]="'select-file-' + idx"
[disabled]="!row?.isSelectable"
[class.adf-datatable-checkbox-selected]="row.isSelected"
[class.adf-datatable-hover-only]="displayCheckboxesOnHover"
[checked]="row.isSelected"
[attr.aria-checked]="row.isSelected"
[aria-label]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate"
data-adf-datatable-row-checkbox
(change)="onCheckboxChange(row, $event)"
(keydown.enter)="$event.stopPropagation()"
class="adf-checkbox-sr-only"
>
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate }}
</mat-checkbox>
</label>
@if (!noPermission) {
@for (row of data.getRows(); track row; let idx = $index) {
<adf-datatable-row
cdkDrag
[cdkDragDisabled]="!enableDragRows"
(cdkDragDropped)="onDragDrop($event)"
(cdkDragStarted)="onDragStart()"
(cdkDragEnded)="onDragEnd()"
[cdkDragBoundary]="'.adf-datatable-body'"
[row]="row"
(select)="onEnterKeyPressed(row, $event)"
(keyup)="onRowKeyUp(row, $event)"
(keydown)="onRowEnterKeyDown(row, $event)"
[adf-upload]="rowAllowsDrop(row)"
[adf-upload-data]="row"
[ngStyle]="rowStyle"
[ngClass]="getRowStyle(row)"
[class.adf-datatable-row__dragging]="isDraggingRow"
[attr.data-automation-id]="'datatable-row-' + idx"
(contextmenu)="markRowAsContextMenuSource(row)"
[disabled]="!(data?.allowFocusOnRows ?? true)"
>
<!-- Drag button -->
@if (enableDragRows) {
<div
*ngFor="let col of getVisibleColumns(); let lastColumn = last;"
role="gridcell"
class="adf-datatable-cell adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-data adf-datatable-cell--{{getAutomationValue(row)}}"
[attr.title]="col.title | translate"
[attr.data-automation-id]="getAutomationValue(row)"
[attr.aria-selected]="row.isSelected"
[attr.aria-label]="col.title ? (col.title | translate) : null"
(click)="onRowClick(row, $event)"
[attr.tabindex]="null"
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
[adf-context-menu]="getContextMenuActions(row, col)"
[adf-context-menu-enabled]="contextMenu"
adf-drop-zone dropTarget="cell" [dropColumn]="col" [dropRow]="row"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
>
<div *ngIf="!col.template" class="adf-datatable-cell-container">
<ng-container [ngSwitch]="data.getColumnType(row, col)">
<div *ngSwitchCase="'image'" class="adf-cell-value">
<mat-icon
[attr.aria-label]="col.srTitle? (col.srTitle | translate) : null"
[attr.aria-hidden]="!asIconValue(row, col)"
*ngIf="isIconValue(row, col); else no_iconvalue"
[adf-icon]="asIconValue(row, col)"
role="gridcell"
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-hover-only">
<button mat-icon-button
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.DRAG' | translate">
<mat-icon adf-icon="drag_indicator" />
</button>
</div>
}
<!-- Actions (left) -->
@if (actions && actionsPosition === 'left') {
<div role="gridcell" class="adf-datatable-cell">
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_left_' + idx"
[attr.data-automation-id]="'action_menu_' + idx">
<mat-icon adf-icon="more_vert" />
</button>
<mat-menu #menu="matMenu">
@for (action of getRowActions(row); track action) {
<button mat-menu-item
[attr.data-automation-id]="action.title"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
@if (action.icon) {
<mat-icon [adf-icon]="action.icon" />
}
<span>{{ action.title | translate }}</span>
</button>
}
</mat-menu>
</div>
}
@if (multiselect) {
<label
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
(click)="onCheckboxLabelClick(row, $event)"
[for]="'select-file-' + idx"
class="adf-datatable-cell adf-datatable-checkbox adf-datatable-checkbox-single"
[attr.tabindex]="null">
<mat-checkbox
[id]="'select-file-' + idx"
[disabled]="!row?.isSelectable"
[class.adf-datatable-checkbox-selected]="row.isSelected"
[class.adf-datatable-hover-only]="displayCheckboxesOnHover"
[checked]="row.isSelected"
[attr.aria-checked]="row.isSelected"
[aria-label]="'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate"
data-adf-datatable-row-checkbox
(change)="onCheckboxChange(row, $event)"
(keydown.enter)="$event.stopPropagation()"
class="adf-checkbox-sr-only"
>
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_FILE' | translate }}
</mat-checkbox>
</label>
}
@for (col of getVisibleColumns(); track col; let lastColumn = $last) {
<div
role="gridcell"
class="adf-datatable-cell adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-data adf-datatable-cell--{{getAutomationValue(row)}}"
[attr.title]="col.title | translate"
[attr.data-automation-id]="getAutomationValue(row)"
[attr.aria-selected]="row.isSelected"
[attr.aria-label]="col.title ? (col.title | translate) : null"
(click)="onRowClick(row, $event)"
[attr.tabindex]="null"
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
[adf-context-menu]="getContextMenuActions(row, col)"
[adf-context-menu-enabled]="contextMenu"
adf-drop-zone dropTarget="cell" [dropColumn]="col" [dropRow]="row"
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
>
@if (!col.template) {
<div class="adf-datatable-cell-container">
@switch (data.getColumnType(row, col)) {
@case ('image') {
<div class="adf-cell-value">
@if (isIconValue(row, col)) {
<mat-icon
[attr.aria-label]="col.srTitle? (col.srTitle | translate) : null"
[attr.aria-hidden]="!asIconValue(row, col)"
[adf-icon]="asIconValue(row, col)"
/>
<ng-template #no_iconvalue>
<mat-icon class="adf-datatable-selected"
*ngIf="row.isSelected && !multiselect; else no_selected_row" svgIcon="selected" />
<ng-template #no_selected_row>
<img class="adf-datatable-center-img-ie"
} @else {
@if (row.isSelected && !multiselect) {
<mat-icon class="adf-datatable-selected"
svgIcon="selected" />
} @else {
<img class="adf-datatable-center-img-ie"
[attr.aria-label]="(data.getValue(row, col) | fileType) === 'disable' ?
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
@@ -326,174 +342,213 @@
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
}"
src="{{ data.getValue(row, col) }}"
(error)="onImageLoadingError($event, row)">
</ng-template>
</ng-template>
</div>
<div *ngSwitchCase="'icon'" class="adf-cell-value">
<adf-icon-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)"
/>
</div>
<div
*ngSwitchCase="'date'"
class="adf-cell-value adf-cell-date"
[attr.data-automation-id]="'date_' + (data.getValue(row, col, resolverFn) | adfLocalizedDate: 'medium') ">
<adf-date-cell class="adf-datatable-center-date-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)"
[dateConfig]="col.dateConfig" />
</div>
<div *ngSwitchCase="'location'" class="adf-cell-value"
[attr.data-automation-id]="'location' + data.getValue(row, col, resolverFn)">
<adf-location-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
<div *ngSwitchCase="'fileSize'" class="adf-cell-value"
[attr.data-automation-id]="'fileSize_' + data.getValue(row, col, resolverFn)">
<adf-filesize-cell class="adf-datatable-center-size-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
<div *ngSwitchCase="'text'" class="adf-cell-value"
[attr.data-automation-id]="'text_' + data.getValue(row, col, resolverFn)">
<adf-datatable-cell
[copyContent]="col.copyContent"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
<div *ngSwitchCase="'boolean'" class="adf-cell-value"
[attr.data-automation-id]="'boolean_' + data.getValue(row, col, resolverFn)">
<adf-boolean-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
<div *ngSwitchCase="'json'" class="adf-cell-value">
<adf-json-cell
[editable]="col.editable"
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row" />
</div>
<div *ngSwitchCase="'amount'"
class="adf-cell-value"
[attr.data-automation-id]="'amount_' + data.getValue(row, col, resolverFn)">
<adf-amount-cell
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[currencyConfig]="col.currencyConfig" />
</div>
<div *ngSwitchCase="'number'"
class="adf-cell-value"
[attr.data-automation-id]="'number_' + data.getValue(row, col, resolverFn)">
<adf-number-cell
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[decimalConfig]="col.decimalConfig" />
</div>
<span *ngSwitchDefault class="adf-cell-value">
<!-- empty cell for unknown column type -->
</span>
</ng-container>
src="{{ data.getValue(row, col) }}"
(error)="onImageLoadingError($event, row)">
}
}
</div>
}
@case ('icon') {
<div class="adf-cell-value">
<adf-icon-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)"
/>
</div>
}
@case ('date') {
<div
class="adf-cell-value adf-cell-date"
[attr.data-automation-id]="'date_' + (data.getValue(row, col, resolverFn) | adfLocalizedDate: 'medium') ">
<adf-date-cell class="adf-datatable-center-date-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)"
[dateConfig]="col.dateConfig" />
</div>
}
@case ('location') {
<div class="adf-cell-value"
[attr.data-automation-id]="'location' + data.getValue(row, col, resolverFn)">
<adf-location-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
}
@case ('fileSize') {
<div class="adf-cell-value"
[attr.data-automation-id]="'fileSize_' + data.getValue(row, col, resolverFn)">
<adf-filesize-cell class="adf-datatable-center-size-column-ie"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
}
@case ('text') {
<div class="adf-cell-value"
[attr.data-automation-id]="'text_' + data.getValue(row, col, resolverFn)">
<adf-datatable-cell
[copyContent]="col.copyContent"
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
}
@case ('boolean') {
<div class="adf-cell-value"
[attr.data-automation-id]="'boolean_' + data.getValue(row, col, resolverFn)">
<adf-boolean-cell
[data]="data"
[column]="col"
[row]="row"
[resolverFn]="resolverFn"
[tooltip]="getCellTooltip(row, col)" />
</div>
}
@case ('json') {
<div class="adf-cell-value">
<adf-json-cell
[editable]="col.editable"
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row" />
</div>
}
@case ('amount') {
<div
class="adf-cell-value"
[attr.data-automation-id]="'amount_' + data.getValue(row, col, resolverFn)">
<adf-amount-cell
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[currencyConfig]="col.currencyConfig" />
</div>
}
@case ('number') {
<div
class="adf-cell-value"
[attr.data-automation-id]="'number_' + data.getValue(row, col, resolverFn)">
<adf-number-cell
[data]="data"
[column]="col"
[resolverFn]="resolverFn"
[row]="row"
[decimalConfig]="col.decimalConfig" />
</div>
}
@default {
<span class="adf-cell-value">
<!-- empty cell for unknown column type -->
</span>
}
}
</div>
<div *ngIf="col.template" class="adf-datatable-cell-container">
<div class="adf-cell-value">
<ng-container
[ngTemplateOutlet]="col.template"
[ngTemplateOutletContext]="{ $implicit: { data: data, row: row, col: col }, value: data.getValue(row, col, resolverFn) }" />
</div>
}
@if (col.template) {
<div class="adf-datatable-cell-container">
<div class="adf-cell-value">
<ng-container
[ngTemplateOutlet]="col.template"
[ngTemplateOutletContext]="{ $implicit: { data: data, row: row, col: col }, value: data.getValue(row, col, resolverFn) }" />
</div>
</div>
}
</div>
<!-- Row actions (right) -->
<div *ngIf="
!showProvidedActions &&
((actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions))"
role="gridcell"
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-center-actions-column-ie adf-datatable-actions-menu">
<ng-container *ngIf="(actions && actionsPosition === 'right')">
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_right_' + idx"
[attr.data-automation-id]="'action_menu_' + idx"
(keydown.enter)="actionsMenuTrigger.openMenu()">
<mat-icon adf-icon="more_vert" />
}
<!-- Row actions (right) -->
@if (
!showProvidedActions &&
((actions && actionsPosition === 'right') ||
(mainActionTemplate && showMainDatatableActions))) {
<div
role="gridcell"
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-center-actions-column-ie adf-datatable-actions-menu">
@if ((actions && actionsPosition === 'right')) {
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_right_' + idx"
[attr.data-automation-id]="'action_menu_' + idx"
(keydown.enter)="actionsMenuTrigger.openMenu()">
<mat-icon adf-icon="more_vert" />
</button>
<mat-menu #menu="matMenu">
@for (action of getRowActions(row); track action) {
<button mat-menu-item
[attr.data-automation-id]="action.title"
[attr.aria-label]="action.title | translate"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
@if (action.icon) {
<mat-icon [adf-icon]="action.icon" />
}
<span>{{ action.title | translate }}</span>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let action of getRowActions(row)"
[attr.data-automation-id]="action.title"
[attr.aria-label]="action.title | translate"
[disabled]="action.disabled"
(click)="onExecuteRowAction(row, action)">
<mat-icon *ngIf="action.icon" [adf-icon]="action.icon" />
<span>{{ action.title | translate }}</span>
</button>
</mat-menu>
</ng-container>
}
</mat-menu>
}
</div>
}
</adf-datatable-row>
<div *ngIf="isEmpty()" role="row" class="adf-datatable-row">
<div class="adf-no-content-container adf-datatable-cell" role="gridcell">
<ng-template *ngIf="noContentTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="noContentTemplate" />
<ng-content select="adf-empty-list" />
</div>
}
@if (isEmpty()) {
<div role="row" class="adf-datatable-row">
<div class="adf-no-content-container adf-datatable-cell" role="gridcell">
@if (noContentTemplate) {
@for ( of [data]; track ) {
<ng-template
[ngForOf]="[data]"
[ngForTemplate]="noContentTemplate" />
}
}
<ng-content select="adf-empty-list" />
</div>
</div>
</ng-container>
<ng-template #noPermissionsRowTemplate>
<div
role="row"
class="adf-datatable-row adf-no-permission__row">
<div class="adf-no-permission__cell adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="noPermissionTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="noPermissionTemplate" />
</div>
</div>
</ng-template>
</div>
<ng-template #loadingRowTemplate>
<div class="adf-datatable-row adf-datatable-data-loading">
<div class="adf-no-content-container adf-datatable-cell">
<ng-template *ngIf="loadingTemplate"
ngFor [ngForOf]="[data]"
[ngForTemplate]="loadingTemplate" />
}
} @else {
<div
role="row"
class="adf-datatable-row adf-no-permission__row">
<div class="adf-no-permission__cell adf-no-content-container adf-datatable-cell">
@if (noPermissionTemplate) {
@for ( of [data]; track ) {
<ng-template
[ngForOf]="[data]"
[ngForTemplate]="noPermissionTemplate" />
}
}
</div>
</div>
}
</div>
} @else {
<div class="adf-datatable-row adf-datatable-data-loading">
<div class="adf-no-content-container adf-datatable-cell">
@if (loadingTemplate) {
@for ( of [data]; track ) {
<ng-template
[ngForOf]="[data]"
[ngForTemplate]="loadingTemplate" />
}
}
</div>
</ng-template>
</div>
</div>
}
</div>
}
@@ -1,42 +1,44 @@
<h1 mat-dialog-title data-automation-id="adf-confirm-dialog-title">{{ title | translate }}</h1>
<mat-dialog-content>
<div class="adf-confirm-dialog-content">
<p *ngIf="!htmlContent; else customContent" data-automation-id="adf-confirm-dialog-base-message">{{ message | translate }}</p>
<ng-template #customContent>
<span [innerHTML]="sanitizedHtmlContent()" data-automation-id="adf-confirm-dialog-custom-content"></span>
</ng-template>
</div>
<div class="adf-confirm-dialog-content">
@if (!htmlContent) {
<p data-automation-id="adf-confirm-dialog-base-message">{{ message | translate }}</p>
} @else {
<span [innerHTML]="sanitizedHtmlContent()" data-automation-id="adf-confirm-dialog-custom-content"></span>
}
</div>
</mat-dialog-content>
<mat-dialog-actions>
<span class="adf-dialog-spacer" data-automation-id="adf-confirm-dialog-spacer"></span>
<button
id="adf-confirm-cancel"
class="adf-confirm-dialog-button"
mat-button
[mat-dialog-close]="false"
data-automation-id="adf-confirm-dialog-reject"
<span class="adf-dialog-spacer" data-automation-id="adf-confirm-dialog-spacer"></span>
<button
id="adf-confirm-cancel"
class="adf-confirm-dialog-button"
mat-button
[mat-dialog-close]="false"
data-automation-id="adf-confirm-dialog-reject"
>
{{ noLabel | translate }}
</button>
{{ noLabel | translate }}
</button>
@if (thirdOptionLabel) {
<button
*ngIf="thirdOptionLabel"
id="adf-confirm-all"
class="adf-confirm-dialog-button"
mat-button
[mat-dialog-close]="thirdOptionLabel"
data-automation-id="adf-confirm-dialog-confirm-all"
>
{{ thirdOptionLabel | translate }}
id="adf-confirm-all"
class="adf-confirm-dialog-button"
mat-button
[mat-dialog-close]="thirdOptionLabel"
data-automation-id="adf-confirm-dialog-confirm-all"
>
{{ thirdOptionLabel | translate }}
</button>
<button
id="adf-confirm-accept"
class="adf-confirm-dialog-button"
mat-button
color="primary"
data-automation-id="adf-confirm-dialog-confirmation"
[mat-dialog-close]="true"
cdkFocusInitial
}
<button
id="adf-confirm-accept"
class="adf-confirm-dialog-button"
mat-button
color="primary"
data-automation-id="adf-confirm-dialog-confirmation"
[mat-dialog-close]="true"
cdkFocusInitial
>
{{ yesLabel | translate }}
</button>
{{ yesLabel | translate }}
</button>
</mat-dialog-actions>
@@ -19,7 +19,7 @@ import { Component, SecurityContext, ViewEncapsulation, inject } from '@angular/
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { DomSanitizer } from '@angular/platform-browser';
import { TranslatePipe } from '@ngx-translate/core';
import { NgIf } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
export interface ConfirmDialogComponentProps {
@@ -38,7 +38,7 @@ export interface ConfirmDialogComponentProps {
host: { class: 'adf-confirm-dialog' },
encapsulation: ViewEncapsulation.None,
standalone: true,
imports: [TranslatePipe, MatDialogModule, NgIf, MatButtonModule]
imports: [TranslatePipe, MatDialogModule, MatButtonModule]
})
export class ConfirmDialogComponent {
private readonly sanitizer = inject(DomSanitizer);
@@ -1,88 +1,94 @@
<div
data-automation-id="adf-dialog-container"
class="adf-dialog-container {{ dialogSize }}"
>
<div
mat-dialog-title
data-automation-id="adf-dialog-header"
class="adf-dialog-header"
[ngClass]="{ 'adf-centered-header': data.headerIcon }"
data-automation-id="adf-dialog-container"
class="adf-dialog-container {{ dialogSize }}"
>
<div
mat-dialog-title
data-automation-id="adf-dialog-header"
class="adf-dialog-header"
[ngClass]="{ 'adf-centered-header': data.headerIcon }"
>
<div class="adf-dialog-title-container" [ngClass]="{ 'adf-centered-title': data.headerIcon }">
<mat-icon
*ngIf="data.headerIcon"
color="primary"
class="adf-dialog-header-icon"
[adf-icon]="data.headerIcon"
/>
<h2 class="adf-dialog-title">{{ data.title | translate }}</h2>
</div>
<button
*ngIf="!isCloseButtonHidden"
mat-icon-button
mat-dialog-close
title="{{'CLOSE' | translate }}"
data-automation-id="adf-dialog-close-button"
<div class="adf-dialog-title-container" [ngClass]="{ 'adf-centered-title': data.headerIcon }">
@if (data.headerIcon) {
<mat-icon
color="primary"
class="adf-dialog-header-icon"
[adf-icon]="data.headerIcon"
/>
}
<h2 class="adf-dialog-title">{{ data.title | translate }}</h2>
</div>
@if (!isCloseButtonHidden) {
<button
mat-icon-button
mat-dialog-close
title="{{'CLOSE' | translate }}"
data-automation-id="adf-dialog-close-button"
>
<mat-icon adf-icon="close" />
</button>
</div>
<mat-icon adf-icon="close" />
</button>
}
</div>
<div
[ngTemplateOutlet]="data.descriptionTemplate"
[ngClass]="{ 'adf-description': data.description || data.descriptionTemplate }"
<div
[ngTemplateOutlet]="data.descriptionTemplate"
[ngClass]="{ 'adf-description': data.description || data.descriptionTemplate }"
>
<ng-container>{{ data.description | translate }}</ng-container>
</div>
<ng-container>{{ data.description | translate }}</ng-container>
</div>
<mat-dialog-content *ngIf="data.contentTemplate || data.contentComponent || data.contentText" class="adf-dialog-content">
<ng-container [ngTemplateOutlet]="data.contentTemplate" />
<ng-container *ngComponentOutlet="data.contentComponent; injector: dataInjector" />
<ng-container>{{ data.contentText | translate }}</ng-container>
@if (data.contentTemplate || data.contentComponent || data.contentText) {
<mat-dialog-content class="adf-dialog-content">
<ng-container [ngTemplateOutlet]="data.contentTemplate" />
<ng-container *ngComponentOutlet="data.contentComponent; injector: dataInjector" />
<ng-container>{{ data.contentText | translate }}</ng-container>
</mat-dialog-content>
}
<mat-dialog-actions
class="adf-dialog-actions"
[ngClass]="{ 'adf-additional-actions': data.actionsTemplate || additionalActionButtons }"
<mat-dialog-actions
class="adf-dialog-actions"
[ngClass]="{ 'adf-additional-actions': data.actionsTemplate || additionalActionButtons }"
>
<div class="adf-additional-actions-container">
<ng-container *ngIf="!additionalActionButtons && data.actionsTemplate">
<ng-container [ngTemplateOutlet]="data.actionsTemplate" />
</ng-container>
<div class="adf-additional-actions-container">
@if (!additionalActionButtons && data.actionsTemplate) {
<ng-container [ngTemplateOutlet]="data.actionsTemplate" />
}
<ng-container *ngIf="!data.actionsTemplate && additionalActionButtons">
<button
*ngFor="let additionalButton of additionalActionButtons"
mat-button
color="primary"
class="{{ additionalButton.class }}"
(click)="additionalButton.onClick()"
>
{{ additionalButton.title | translate }}
</button>
</ng-container>
</div>
<div class="adf-main-actions-container">
<button
*ngIf="!isCancelButtonHidden"
mat-stroked-button
color="primary"
mat-dialog-close
data-automation-id="adf-dialog-actions-cancel"
@if (!data.actionsTemplate && additionalActionButtons) {
@for (additionalButton of additionalActionButtons; track additionalButton) {
<button
mat-button
color="primary"
class="{{ additionalButton.class }}"
(click)="additionalButton.onClick()"
>
{{ cancelButtonTitle | translate }}
</button>
{{ additionalButton.title | translate }}
</button>
}
}
</div>
<button
mat-flat-button
color="primary"
data-automation-id="adf-dialog-actions-confirm"
[disabled]="isConfirmButtonDisabled$ | async"
(click)="onConfirm()"
>
{{ confirmButtonTitle | translate }}
</button>
</div>
</mat-dialog-actions>
<div class="adf-main-actions-container">
@if (!isCancelButtonHidden) {
<button
mat-stroked-button
color="primary"
mat-dialog-close
data-automation-id="adf-dialog-actions-cancel"
>
{{ cancelButtonTitle | translate }}
</button>
}
<button
mat-flat-button
color="primary"
data-automation-id="adf-dialog-actions-confirm"
[disabled]="isConfirmButtonDisabled$ | async"
(click)="onConfirm()"
>
{{ confirmButtonTitle | translate }}
</button>
</div>
</mat-dialog-actions>
</div>
@@ -1,13 +1,15 @@
<h1 mat-dialog-title>{{ title | translate }}</h1>
<mat-dialog-content class="adf-edit-json-dialog-content">
<textarea [(ngModel)]="value" [attr.readonly]="!editable ? true : null"></textarea>
<textarea [(ngModel)]="value" [attr.readonly]="!editable ? true : null"></textarea>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close cdkFocusInitial>
{{ 'CORE.DIALOG.EDIT_JSON.CLOSE' | translate }}
</button>
<button *ngIf="editable" mat-button [mat-dialog-close]="value">
{{ 'CORE.DIALOG.EDIT_JSON.UPDATE' | translate }}
<button mat-button mat-dialog-close cdkFocusInitial>
{{ 'CORE.DIALOG.EDIT_JSON.CLOSE' | translate }}
</button>
@if (editable) {
<button mat-button [mat-dialog-close]="value">
{{ 'CORE.DIALOG.EDIT_JSON.UPDATE' | translate }}
</button>
}
</mat-dialog-actions>
@@ -1,35 +1,37 @@
<h1 mat-dialog-title class="adf-unsaved-changes-dialog-header">
{{ dialogData.headerText | translate }}
<button
data-automation-id="adf-unsaved-changes-dialog-close-button"
class="adf-unsaved-changes-dialog-header-close-button"
mat-icon-button
[title]="'CLOSE' | translate"
[mat-dialog-close]="false">
<mat-icon adf-icon="close" />
</button>
{{ dialogData.headerText | translate }}
<button
data-automation-id="adf-unsaved-changes-dialog-close-button"
class="adf-unsaved-changes-dialog-header-close-button"
mat-icon-button
[title]="'CLOSE' | translate"
[mat-dialog-close]="false">
<mat-icon adf-icon="close" />
</button>
</h1>
<mat-dialog-content class="adf-unsaved-changes-dialog-content">
{{ dialogData.descriptionText | translate }}
<div class="adf-unsaved-changes-dialog-content-checkbox" *ngIf="dialogData.checkboxText.length">
<mat-checkbox data-automation-id="adf-unsaved-changes-dialog-content-checkbox"
(change)="onToggleCheckboxPreferences($event)"
>{{ dialogData.checkboxText | translate }}</mat-checkbox>
{{ dialogData.descriptionText | translate }}
@if (dialogData.checkboxText.length) {
<div class="adf-unsaved-changes-dialog-content-checkbox">
<mat-checkbox data-automation-id="adf-unsaved-changes-dialog-content-checkbox"
(change)="onToggleCheckboxPreferences($event)"
>{{ dialogData.checkboxText | translate }}</mat-checkbox>
</div>
}
</mat-dialog-content>
<mat-dialog-actions align="end" class="adf-unsaved-changes-dialog-actions">
<button
data-automation-id="adf-unsaved-changes-dialog-cancel-button"
mat-button
[mat-dialog-close]="false"
class="adf-unsaved-changes-dialog-actions-cancel-button">
{{ 'CANCEL' | translate | titlecase }}
</button>
<button
data-automation-id="adf-unsaved-changes-dialog-discard-changes-button"
mat-button
[mat-dialog-close]="true"
class="adf-unsaved-changes-dialog-actions-discard-changes-button">
{{ dialogData.confirmButtonText | translate }}
</button>
<button
data-automation-id="adf-unsaved-changes-dialog-cancel-button"
mat-button
[mat-dialog-close]="false"
class="adf-unsaved-changes-dialog-actions-cancel-button">
{{ 'CANCEL' | translate | titlecase }}
</button>
<button
data-automation-id="adf-unsaved-changes-dialog-discard-changes-button"
mat-button
[mat-dialog-close]="true"
class="adf-unsaved-changes-dialog-actions-discard-changes-button">
{{ dialogData.confirmButtonText | translate }}
</button>
</mat-dialog-actions>
@@ -16,7 +16,7 @@
*/
import { Component, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';
import { InfiniteSelectScrollDirective } from './infinite-select-scroll.directive';
import { MatSelect, MatSelectModule } from '@angular/material/select';
@@ -26,12 +26,14 @@ import { UnitTestingUtils } from '../testing/unit-testing-utils';
@Component({
template: ` <mat-select adf-infinite-select-scroll (scrollEnd)="load()">
<mat-option *ngFor="let option of options; let idx = index">
{{ option.text }}
</mat-option>
</mat-select>`,
@for (option of options; track option; let idx = $index) {
<mat-option>
{{ option.text }}
</mat-option>
}
</mat-select>`,
standalone: true,
imports: [MatSelectModule, InfiniteSelectScrollDirective, CommonModule]
imports: [MatSelectModule, InfiniteSelectScrollDirective]
})
class TestComponent {
options = new Array(50).fill({ text: 'dummy' });
@@ -1,6 +1,14 @@
<div @tooltip class="adf-tooltip-card" [style.width.px]="width">
<img *ngIf="image " [src]="image" [width]="width" alt="{{text}}">
<hr *ngIf="image" />
<p *ngIf="text">{{text}}</p>
<div *ngIf="htmlContent" [innerHTML]="sanitizedHtmlContent()" class="adf-tooltip-card-content"></div>
@if (image ) {
<img [src]="image" [width]="width" alt="{{text}}">
}
@if (image) {
<hr />
}
@if (text) {
<p>{{text}}</p>
}
@if (htmlContent) {
<div [innerHTML]="sanitizedHtmlContent()" class="adf-tooltip-card-content"></div>
}
</div>
@@ -18,11 +18,11 @@
import { Component, Input, SecurityContext, inject } from '@angular/core';
import { animate, style, transition, trigger } from '@angular/animations';
import { DomSanitizer } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
@Component({
selector: 'adf-tooltip-card-component',
imports: [CommonModule],
imports: [],
templateUrl: './tooltip-card.component.html',
styleUrls: ['./tooltip-card.component.scss'],
animations: [
@@ -1,44 +1,46 @@
<div
class="adf-dynamic-chip-list-container"
[class.adf-dynamic-chip-list-flex-column]="limitChipsDisplayed && (!calculationsDone || columnFlexDirection)"
[class.adf-dynamic-chip-list-button-in-next-line]="moveLoadMoreButtonToNextRow"
[class.adf-dynamic-chip-list-paginated]="paginationData"
#nodeListContainer>
<mat-chip-set
[class.adf-dynamic-chip-list-full-width]="limitChipsDisplayed && !calculationsDone"
role="list"
[attr.aria-label]="'METADATA.BASIC.TAGS' | translate">
<mat-chip
*ngFor="let chip of chipsToDisplay; let idx = index"
class="adf-dynamic-chip-list-chip"
[style.border-radius]="roundUpChips ? '20px' : '10px'"
[style.font-weight]="'bold'"
role="listitem"
[attr.aria-label]="chip.name"
(removed)="removedChip.emit(chip.id)">
<span id="adf-dynamic-chip-list-chip-name-{{ idx }}">{{ chip.name }}</span>
<mat-icon
*ngIf="showDelete"
id="adf-dynamic-chip-list-delete-{{ chip.name }}"
class="adf-dynamic-chip-list-delete-icon"
[disabled]="disableDelete"
adf-icon="close"
matChipRemove
class="adf-dynamic-chip-list-container"
[class.adf-dynamic-chip-list-flex-column]="limitChipsDisplayed && (!calculationsDone || columnFlexDirection)"
[class.adf-dynamic-chip-list-button-in-next-line]="moveLoadMoreButtonToNextRow"
[class.adf-dynamic-chip-list-paginated]="paginationData"
#nodeListContainer>
<mat-chip-set
[class.adf-dynamic-chip-list-full-width]="limitChipsDisplayed && !calculationsDone"
role="list"
[attr.aria-label]="'METADATA.BASIC.TAGS' | translate">
@for (chip of chipsToDisplay; track chip; let idx = $index) {
<mat-chip
class="adf-dynamic-chip-list-chip"
[style.border-radius]="roundUpChips ? '20px' : '10px'"
[style.font-weight]="'bold'"
role="listitem"
[attr.aria-label]="chip.name"
(removed)="removedChip.emit(chip.id)">
<span id="adf-dynamic-chip-list-chip-name-{{ idx }}">{{ chip.name }}</span>
@if (showDelete) {
<mat-icon
id="adf-dynamic-chip-list-delete-{{ chip.name }}"
class="adf-dynamic-chip-list-delete-icon"
[disabled]="disableDelete"
adf-icon="close"
matChipRemove
/>
</mat-chip>
</mat-chip-set>
<button
data-automation-id="adf-dynamic-chip-list-view-more-button"
mat-button
[hidden]="chipsToDisplay?.length === 0 || !limitChipsDisplayed"
[style.left.px]="viewMoreButtonLeftOffset"
[style.top.px]="!!pagination ? viewMoreButtonTop : ''"
class="adf-dynamic-chip-list-view-more-button"
[class.adf-dynamic-chip-list-hidden-btn]="!calculationsDone"
(click)="displayNextChips($event)">
{{
paginationData ? ('DYNAMIC_CHIP_LIST.LOAD_MORE' | translate) :
('TAG_NODE_LIST.VIEW_MORE' | translate: { count: undisplayedChipsCount })
}}
</button>
}
</mat-chip>
}
</mat-chip-set>
<button
data-automation-id="adf-dynamic-chip-list-view-more-button"
mat-button
[hidden]="chipsToDisplay?.length === 0 || !limitChipsDisplayed"
[style.left.px]="viewMoreButtonLeftOffset"
[style.top.px]="!!pagination ? viewMoreButtonTop : ''"
class="adf-dynamic-chip-list-view-more-button"
[class.adf-dynamic-chip-list-hidden-btn]="!calculationsDone"
(click)="displayNextChips($event)">
{{
paginationData ? ('DYNAMIC_CHIP_LIST.LOAD_MORE' | translate) :
('TAG_NODE_LIST.VIEW_MORE' | translate: { count: undisplayedChipsCount })
}}
</button>
</div>
@@ -16,7 +16,7 @@
*/
import { Pagination } from '@alfresco/js-api';
import { NgForOf, NgIf } from '@angular/common';
import {
AfterViewInit,
ChangeDetectorRef,
@@ -48,7 +48,7 @@ import { IconModule } from '../icon/icon.module';
selector: 'adf-dynamic-chip-list',
templateUrl: './dynamic-chip-list.component.html',
styleUrls: ['./dynamic-chip-list.component.scss'],
imports: [MatChipsModule, TranslatePipe, NgForOf, IconModule, NgIf, MatButtonModule],
imports: [MatChipsModule, TranslatePipe, IconModule, MatButtonModule],
encapsulation: ViewEncapsulation.None
})
export class DynamicChipListComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy {
@@ -1,135 +1,158 @@
<div id="adf-form-renderer" class="{{ formDefinition.className }} adf-form-renderer"
[ngClass]="{ 'adf-readonly-form': formDefinition.readOnly }">
<div *ngIf="formDefinition.hasTabs()">
<div *ngIf="hasTabs()" class="alfresco-tabs-widget">
<mat-tab-group [preserveContent]="true">
<mat-tab *ngFor="let tab of visibleTabs()" [label]="tab.title | translate ">
<ng-template matTabContent>
<div class="adf-form-tab-content">
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: tab.fields }" />
</div>
</ng-template>
</mat-tab>
</mat-tab-group>
[ngClass]="{ 'adf-readonly-form': formDefinition.readOnly }">
@if (formDefinition.hasTabs()) {
<div>
@if (hasTabs()) {
<div class="alfresco-tabs-widget">
<mat-tab-group [preserveContent]="true">
@for (tab of visibleTabs(); track tab) {
<mat-tab [label]="tab.title | translate ">
<ng-template matTabContent>
<div class="adf-form-tab-content">
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: tab.fields }" />
</div>
</ng-template>
</mat-tab>
}
</mat-tab-group>
</div>
}
</div>
}
<div *ngIf="!formDefinition.hasTabs() && formDefinition.hasFields()">
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: formDefinition.fields }" />
@if (!formDefinition.hasTabs() && formDefinition.hasFields()) {
<div>
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: formDefinition.fields }" />
</div>
}
</div>
<ng-template #render let-fieldToRender="fieldToRender">
<div *ngFor="let currentRootElement of fieldToRender">
<div *ngIf="currentRootElement.type === 'section'" [id]="'field-' + currentRootElement?.id + '-container'" class="adf-container-widget">
<adf-form-section [field]="currentRootElement" />
@for (currentRootElement of fieldToRender; track currentRootElement) {
<div>
@if (currentRootElement.type === 'section') {
<div [id]="'field-' + currentRootElement?.id + '-container'" class="adf-container-widget">
<adf-form-section [field]="currentRootElement" />
</div>
<div *ngIf="currentRootElement.type === 'container' || currentRootElement.type === 'group'"
[id]="'field-' + currentRootElement?.id + '-container'"
class="adf-container-widget"
[hidden]="!currentRootElement?.isVisible">
<adf-header-widget [element]="currentRootElement" />
<div *ngIf="currentRootElement?.form?.enableFixedSpace; else fixingTemplate">
}
@if (currentRootElement.type === 'container' || currentRootElement.type === 'group') {
<div
[id]="'field-' + currentRootElement?.id + '-container'"
class="adf-container-widget"
[hidden]="!currentRootElement?.isVisible">
<adf-header-widget [element]="currentRootElement" />
@if (currentRootElement?.form?.enableFixedSpace) {
<div>
@if (currentRootElement?.isExpanded) {
<div class="adf-grid-list"
[ngStyle]="{ 'grid-template-columns': 'repeat(' + getNumberOfColumns(currentRootElement) + ', 1fr)' }"
*ngIf="currentRootElement?.isExpanded">
[ngStyle]="{ 'grid-template-columns': 'repeat(' + getNumberOfColumns(currentRootElement) + ', 1fr)' }"
>
@for (field of getContainerFields(currentRootElement); track field) {
<div class="adf-grid-list-item"
*ngFor="let field of getContainerFields(currentRootElement)"
[ngStyle]="{ 'grid-area': 'auto / auto / span ' + (field?.rowspan || 1) + ' / span ' + (field?.colspan || 1) }">
<adf-form-field *ngIf="field" [field]="field" />
[ngStyle]="{ 'grid-area': 'auto / auto / span ' + (field?.rowspan || 1) + ' / span ' + (field?.colspan || 1) }">
@if (field) {
<adf-form-field [field]="field" />
}
</div>
}
</div>
}
</div>
<ng-template #fixingTemplate>
<section class="adf-grid-list-column-view" *ngIf="currentRootElement?.isExpanded">
<div class="adf-grid-list-single-column"
*ngFor="let column of currentRootElement?.columns"
[style.width.%]="getColumnWidth(currentRootElement)"
} @else {
@if (currentRootElement?.isExpanded) {
<section class="adf-grid-list-column-view">
@for (column of currentRootElement?.columns; track column) {
<div class="adf-grid-list-single-column"
[style.width.%]="getColumnWidth(currentRootElement)"
>
<ng-container *ngFor="let field of column?.fields">
<ng-container *ngIf="field.type === 'section'; else formField">
<adf-form-section [field]="field"/>
</ng-container>
<ng-template #formField>
<div class="adf-grid-list-column-view-item">
<adf-form-field [field]="field"/>
</div>
</ng-template>
</ng-container>
</div>
</section>
</ng-template>
<ng-template #columnViewItem let-column="column">
<div class="adf-grid-list-column-view-item" *ngFor="let field of column?.fields">
<adf-form-field *ngIf="field" [field]="field" />
</div>
</ng-template>
</div>
@if (currentRootElement.type === 'repeatable-section') {
<div
[id]="'field-' + currentRootElement?.id + '-container'"
class="adf-container-widget"
[hidden]="!currentRootElement?.isVisible"
>
<adf-repeat-widget [element]="currentRootElement" [isEditor]="false">
@for (row of currentRootElement.field.rows; track row.id; let rowIndex = $index) {
@let hasMultipleRows = currentRootElement.field.rows.length > 1;
<div
class="adf-grid-list-container"
[class.adf-grid-list-container-multiple]="hasMultipleRows"
[class.adf-grid-list-container-disabled]="currentRootElement.field.readOnly"
>
<div class="adf-grid-list-row">
<span class="adf-grid-list-row-label">{{ 'FORM.FORM_RENDERER.ROW_LABEL' | translate: {number: rowIndex + 1} }}</span>
@let shouldDisplayRemoveRowButton = !currentRootElement.field.rows[rowIndex].isInitial || (currentRootElement.field.rows[rowIndex].isInitial && currentRootElement.field.params.allowInitialRowsDelete);
@if (shouldDisplayRemoveRowButton) {
<button
mat-icon-button
class="adf-grid-list-row-remove-button"
[disabled]="currentRootElement.field.readOnly"
[matTooltip]="'FORM.FORM_RENDERER.DELETE_ROW' | translate"
(click)="displayDialogToRemoveRow(currentRootElement.field, rowIndex)"
>
<mat-icon adf-icon="close" />
</button>
}
</div>
<section class="adf-grid-list-column-view">
@for (column of row.columns; track $index) {
<div
class="adf-grid-list-single-column"
[style.width.%]="getColumnWidth(currentRootElement)"
>
@for (field of column?.fields; track $index) {
@if (field.type === 'section') {
<adf-form-section [field]="field"/>
} @else {
<div class="adf-grid-list-column-view-item">
<adf-form-field [field]="field"/>
</div>
}
}
</div>
}
</section>
@for (field of column?.fields; track field) {
@if (field.type === 'section') {
<adf-form-section [field]="field"/>
} @else {
<div class="adf-grid-list-column-view-item">
<adf-form-field [field]="field"/>
</div>
}
}
</adf-repeat-widget>
</div>
}
<div *ngIf="currentRootElement.type === 'dynamic-table'" class="adf-container-widget">
<adf-form-field [field]="currentRootElement" />
</div>
}
</section>
}
}
<ng-template #columnViewItem let-column="column">
@for (field of column?.fields; track field) {
<div class="adf-grid-list-column-view-item">
@if (field) {
<adf-form-field [field]="field" />
}
</div>
}
</ng-template>
</div>
}
@if (currentRootElement.type === 'repeatable-section') {
<div
[id]="'field-' + currentRootElement?.id + '-container'"
class="adf-container-widget"
[hidden]="!currentRootElement?.isVisible"
>
<adf-repeat-widget [element]="currentRootElement" [isEditor]="false">
@for (row of currentRootElement.field.rows; track row.id; let rowIndex = $index) {
@let hasMultipleRows = currentRootElement.field.rows.length > 1;
<div
class="adf-grid-list-container"
[class.adf-grid-list-container-multiple]="hasMultipleRows"
[class.adf-grid-list-container-disabled]="currentRootElement.field.readOnly"
>
<div class="adf-grid-list-row">
<span class="adf-grid-list-row-label">{{ 'FORM.FORM_RENDERER.ROW_LABEL' | translate: {number: rowIndex + 1} }}</span>
@let shouldDisplayRemoveRowButton = !currentRootElement.field.rows[rowIndex].isInitial || (currentRootElement.field.rows[rowIndex].isInitial && currentRootElement.field.params.allowInitialRowsDelete);
@if (shouldDisplayRemoveRowButton) {
<button
mat-icon-button
class="adf-grid-list-row-remove-button"
[disabled]="currentRootElement.field.readOnly"
[matTooltip]="'FORM.FORM_RENDERER.DELETE_ROW' | translate"
(click)="displayDialogToRemoveRow(currentRootElement.field, rowIndex)"
>
<mat-icon adf-icon="close" />
</button>
}
</div>
<section class="adf-grid-list-column-view">
@for (column of row.columns; track $index) {
<div
class="adf-grid-list-single-column"
[style.width.%]="getColumnWidth(currentRootElement)"
>
@for (field of column?.fields; track $index) {
@if (field.type === 'section') {
<adf-form-section [field]="field"/>
} @else {
<div class="adf-grid-list-column-view-item">
<adf-form-field [field]="field"/>
</div>
}
}
</div>
}
</section>
</div>
}
</adf-repeat-widget>
</div>
}
@if (currentRootElement.type === 'dynamic-table') {
<div class="adf-container-widget">
<adf-form-field [field]="currentRootElement" />
</div>
}
@if (currentRootElement.type === 'readonly' && currentRootElement.field.params.field.type === 'dynamic-table') {
<div class="adf-container-widget"
*ngIf="currentRootElement.type === 'readonly' && currentRootElement.field.params.field.type === 'dynamic-table'">
<adf-form-field [field]="currentRootElement.field"/>
>
<adf-form-field [field]="currentRootElement.field"/>
</div>
}
</div>
}
</ng-template>
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { NgClass, NgForOf, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectorRef, Component, inject, Injector, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
@@ -51,22 +51,20 @@ import { IconModule } from '../../icon/icon.module';
}
],
imports: [
NgIf,
MatTabsModule,
NgForOf,
NgTemplateOutlet,
TranslatePipe,
MatButtonModule,
IconModule,
NgStyle,
FormFieldComponent,
FormsModule,
NgClass,
HeaderWidgetComponent,
FormSectionComponent,
RepeatWidgetComponent,
MatTooltipModule
],
MatTabsModule,
NgTemplateOutlet,
TranslatePipe,
MatButtonModule,
IconModule,
NgStyle,
FormFieldComponent,
FormsModule,
NgClass,
HeaderWidgetComponent,
FormSectionComponent,
RepeatWidgetComponent,
MatTooltipModule
],
encapsulation: ViewEncapsulation.None
})
export class FormRendererComponent<T> implements OnInit, OnDestroy {
@@ -1,11 +1,15 @@
<div class="adf-grid-list-section-single-column"
[id]="'field-' + field?.id + '-container'"
[style.display]="field?.isVisible ? 'flex' : 'none'">
<div *ngFor="let sectionColumn of field.columns"
[style.width.%]="getSectionColumnWidth(field.numberOfColumns, sectionColumn.fields)"
>
<div *ngFor="let sectionField of sectionColumn.fields" class="adf-grid-list-section-column-view-item">
<adf-form-field [field]="sectionField"/>
[id]="'field-' + field?.id + '-container'"
[style.display]="field?.isVisible ? 'flex' : 'none'">
@for (sectionColumn of field.columns; track sectionColumn) {
<div
[style.width.%]="getSectionColumnWidth(field.numberOfColumns, sectionColumn.fields)"
>
@for (sectionField of sectionColumn.fields; track sectionField) {
<div class="adf-grid-list-section-column-view-item">
<adf-form-field [field]="sectionField"/>
</div>
}
</div>
}
</div>
@@ -19,14 +19,14 @@ import { Component, inject, Input, OnInit, ViewEncapsulation } from '@angular/co
import { WidgetVisibilityService } from '../../services/widget-visibility.service';
import { FormFieldModel } from '../widgets/core/form-field.model';
import { FormFieldComponent } from '../form-field/form-field.component';
import { NgFor } from '@angular/common';
@Component({
selector: 'adf-form-section',
templateUrl: './form-section.component.html',
encapsulation: ViewEncapsulation.None,
styleUrls: ['./form-section.component.scss'],
imports: [NgFor, FormFieldComponent]
imports: [FormFieldComponent]
})
export class FormSectionComponent implements OnInit {
@Input()
@@ -1,42 +1,45 @@
<div
class="adf-amount-widget__container adf-amount-widget {{field.className}}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels"
>
<div *ngIf="field.leftLabels">
<label class="adf-label adf-left-label" [attr.for]="field.id"
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
class="adf-amount-widget__container adf-amount-widget {{field.className}}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels"
>
@if (field.leftLabels) {
<div>
<label class="adf-label adf-left-label" [attr.for]="field.id"
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
>
</div>
</div>
}
<div class="adf-amount-widget-container">
<mat-form-field class="adf-amount-widget__input adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
@if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{field.name | translate }}</mat-label> }
@if(!enableDisplayBasedOnLocale) {
<span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }}&nbsp;</span>
}
<input
matInput
[title]="field.tooltip"
class="adf-input"
type="text"
[id]="field.id"
[required]="field.required && field.isVisible"
[placeholder]="placeholder"
[value]="amountWidgetValue"
[(ngModel)]="amountWidgetValue"
(ngModelChange)="onFieldChangedAmountWidget()"
[disabled]="field.readOnly"
(focus)="amountWidgetOnFocus()"
(blur)="amountWidgetOnBlur()"
/>
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
<mat-form-field class="adf-amount-widget__input adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
@if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{field.name | translate }}</mat-label> }
@if(!enableDisplayBasedOnLocale) {
<span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }}&nbsp;</span>
}
<input
matInput
[title]="field.tooltip"
class="adf-input"
type="text"
[id]="field.id"
[required]="field.required && field.isVisible"
[placeholder]="placeholder"
[value]="amountWidgetValue"
[(ngModel)]="amountWidgetValue"
(ngModelChange)="onFieldChangedAmountWidget()"
[disabled]="field.readOnly"
(focus)="amountWidgetOnFocus()"
(blur)="amountWidgetOnBlur()"
/>
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
</div>
}
</div>
</div>
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { CurrencyPipe, NgIf } from '@angular/common';
import { CurrencyPipe } from '@angular/common';
import { Component, OnInit, ViewEncapsulation, InjectionToken, inject, DestroyRef } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -52,7 +52,7 @@ export const ADF_AMOUNT_SETTINGS = new InjectionToken<Observable<AmountWidgetSet
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, TranslatePipe, NgIf],
imports: [MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, TranslatePipe],
providers: [CurrencyPipe],
encapsulation: ViewEncapsulation.None
})
@@ -1,24 +1,25 @@
<div [ngClass]="field.className"
[class.adf-invalid]="!field.isValid && isTouched()" class="adf-checkbox-widget-container"
>
<mat-checkbox [id]="field.id"
color="primary"
class="adf-checkbox"
[required]="isRequired()"
[disabled]="field.readOnly || readOnly"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[title]="field.tooltip"
(click)="markAsTouched()"
>
{{ field.name | translate }}
<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</mat-checkbox>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
[class.adf-invalid]="!field.isValid && isTouched()" class="adf-checkbox-widget-container"
>
<mat-checkbox [id]="field.id"
color="primary"
class="adf-checkbox"
[required]="isRequired()"
[disabled]="field.readOnly || readOnly"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[title]="field.tooltip"
(click)="markAsTouched()"
>
{{ field.name | translate }}
<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</mat-checkbox>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
</div>
}
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
import { NgClass, NgIf } from '@angular/common';
import { NgClass } from '@angular/common';
import { Component, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -47,7 +47,7 @@ import { WidgetComponent } from '../widget.component';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [NgClass, MatCheckboxModule, FormsModule, TranslatePipe, ErrorWidgetComponent, NgIf],
imports: [NgClass, MatCheckboxModule, FormsModule, TranslatePipe, ErrorWidgetComponent],
encapsulation: ViewEncapsulation.None
})
export class CheckboxWidgetComponent extends WidgetComponent {}
@@ -1,44 +1,48 @@
<div class="{{ field.className }}"
id="data-time-widget"
[class.adf-invalid]="datetimeInputControl.invalid && datetimeInputControl.touched"
[class.adf-left-label-input-container]="field.leftLabels">
<div *ngIf="field.leftLabels">
<label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
id="data-time-widget"
[class.adf-invalid]="datetimeInputControl.invalid && datetimeInputControl.touched"
[class.adf-left-label-input-container]="field.leftLabels">
@if (field.leftLabels) {
<div>
<label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
</div>
<div class="adf-date-time-widget-container">
<mat-form-field class="adf-date-time-widget adf-form-field-input"
[class.adf-left-label-input-datepicker]="field.leftLabels"
[floatLabel]="field.placeholder ? 'always' : null">
@if( (field.name || field?.required) && !field.leftLabels) {
<mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})
</mat-label>
}
<input matInput
class="adf-input"
[matDatetimepicker]="datetimePicker"
[readonly]="field.readOnly"
[required]="field.required && field.isVisible"
[id]="field.id"
[formControl]="datetimeInputControl"
(keydown.enter)="datetimePicker.open()"
[placeholder]="field.placeholder"
[title]="field.tooltip"
[min]="minDate"
[max]="maxDate">
<mat-datetimepicker-toggle matSuffix [for]="datetimePicker"
[disabled]="field.readOnly" />
<mat-datetimepicker #datetimePicker
data-automation-id="adf-date-time-widget-picker"
type="datetime"
[touchUi]="true"
[timeInterval]="5"
[disabled]="field.readOnly" />
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget *ngIf="datetimeInputControl.invalid && datetimeInputControl.touched" [error]="field.validationSummary" />
</div>
}
<div class="adf-date-time-widget-container">
<mat-form-field class="adf-date-time-widget adf-form-field-input"
[class.adf-left-label-input-datepicker]="field.leftLabels"
[floatLabel]="field.placeholder ? 'always' : null">
@if( (field.name || field?.required) && !field.leftLabels) {
<mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})
</mat-label>
}
<input matInput
class="adf-input"
[matDatetimepicker]="datetimePicker"
[readonly]="field.readOnly"
[required]="field.required && field.isVisible"
[id]="field.id"
[formControl]="datetimeInputControl"
(keydown.enter)="datetimePicker.open()"
[placeholder]="field.placeholder"
[title]="field.tooltip"
[min]="minDate"
[max]="maxDate">
<mat-datetimepicker-toggle matSuffix [for]="datetimePicker"
[disabled]="field.readOnly" />
<mat-datetimepicker #datetimePicker
data-automation-id="adf-date-time-widget-picker"
type="datetime"
[touchUi]="true"
[timeInterval]="5"
[disabled]="field.readOnly" />
</mat-form-field>
<div class="adf-error-messages-container">
@if (datetimeInputControl.invalid && datetimeInputControl.touched) {
<error-widget [error]="field.validationSummary" />
}
</div>
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { NgIf } from '@angular/common';
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
@@ -46,7 +46,7 @@ import { ReactiveFormWidget } from '../reactive-widget.interface';
host: {
'(click)': 'event($event)'
},
imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, MatDatetimepickerModule, ReactiveFormsModule, ErrorWidgetComponent],
imports: [TranslatePipe, MatFormFieldModule, MatInputModule, MatDatetimepickerModule, ReactiveFormsModule, ErrorWidgetComponent],
encapsulation: ViewEncapsulation.None
})
export class DateTimeWidgetComponent extends WidgetComponent implements OnInit, ReactiveFormWidget {
@@ -1,29 +1,30 @@
<div class="{{ field.className }} date-widget-container" id="data-widget" [class.adf-invalid]="dateInputControl.invalid && dateInputControl.touched">
<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">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})
</mat-label>
<input matInput
[matDatepicker]="datePicker"
[id]="field.id"
[formControl]="dateInputControl"
[placeholder]="field.placeholder"
[min]="minDate"
[max]="maxDate"
[required]="field.required && field.isVisible"
[readonly]="field.readOnly"
<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">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})
</mat-label>
<input matInput
[matDatepicker]="datePicker"
[id]="field.id"
[formControl]="dateInputControl"
[placeholder]="field.placeholder"
[min]="minDate"
[max]="maxDate"
[required]="field.required && field.isVisible"
[readonly]="field.readOnly"
/>
<mat-datepicker-toggle matSuffix [for]="datePicker" [disabled]="field.readOnly" />
<mat-datepicker #datePicker
[startAt]="startAt"
[disabled]="field.readOnly" />
</mat-form-field>
<div class="adf-error-messages-container">
@if (dateInputControl.invalid && dateInputControl.touched) {
<error-widget
[error]="field.validationSummary"
/>
<mat-datepicker-toggle matSuffix [for]="datePicker" [disabled]="field.readOnly" />
<mat-datepicker #datePicker
[startAt]="startAt"
[disabled]="field.readOnly" />
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget
*ngIf="dateInputControl.invalid && dateInputControl.touched"
[error]="field.validationSummary"
/>
</div>
}
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { NgIf } from '@angular/common';
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
@@ -53,7 +53,7 @@ import { ReactiveFormWidget } from '../reactive-widget.interface';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [MatFormFieldModule, TranslatePipe, MatInputModule, MatDatepickerModule, ReactiveFormsModule, ErrorWidgetComponent, NgIf],
imports: [MatFormFieldModule, TranslatePipe, MatInputModule, MatDatepickerModule, ReactiveFormsModule, ErrorWidgetComponent],
encapsulation: ViewEncapsulation.None
})
export class DateWidgetComponent extends WidgetComponent implements OnInit, ReactiveFormWidget {
@@ -1,36 +1,39 @@
<div class="adf-textfield adf-decimal-widget {{ field.className }}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
<div *ngIf="field.leftLabels">
<label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
@if (field.leftLabels) {
<div>
<label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
</div>
}
<div class="adf-decimal-widget-container">
<mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
@if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{ field.name | translate }}</mat-label> }
<input matInput
class="adf-input"
type="text"
pattern="-?[0-9]*(\.[0-9]*)?"
[id]="field.id"
[required]="field.required && field.isVisible"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()" />
</mat-form-field>
<div class="adf-decimal-widget-container">
<mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
@if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{ field.name | translate }}</mat-label> }
<input matInput
class="adf-input"
type="text"
pattern="-?[0-9]*(\.[0-9]*)?"
[id]="field.id"
[required]="field.required && field.isVisible"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()" />
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
</div>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
}
</div>
</div>
</div>
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { NgIf } from '@angular/common';
import { Component, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -39,7 +39,7 @@ import { WidgetComponent } from '../widget.component';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent],
imports: [TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent],
encapsulation: ViewEncapsulation.None
})
export class DecimalWidgetComponent extends WidgetComponent {}
@@ -1,10 +1,14 @@
<div class="adf-error-container adf-error-widget-container">
<div *ngIf="error?.isActive()" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ error.message | translate:translateParameters }}</div>
@if (error?.isActive()) {
<div [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ error.message | translate:translateParameters }}</div>
</div>
<div *ngIf="required" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ required }}</div>
}
@if (required) {
<div [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ required }}</div>
</div>
}
</div>
@@ -18,7 +18,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { animate, state, style, transition, trigger } from '@angular/animations';
import { NgIf } from '@angular/common';
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { TranslatePipe } from '@ngx-translate/core';
import { ErrorMessageModel } from '../core';
@@ -52,7 +52,7 @@ import { IconModule } from '../../../../icon/icon.module';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [NgIf, IconModule, TranslatePipe],
imports: [IconModule, TranslatePipe],
encapsulation: ViewEncapsulation.None
})
export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
@@ -1,42 +1,45 @@
<div
class="adf-multiline-text-widget {{ field.className }}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
>
<mat-form-field
floatPlaceholder="never"
class="adf-form-field-input"
[floatLabel]="field.placeholder ? 'always' : null"
class="adf-multiline-text-widget {{ field.className }}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
>
<mat-form-field
floatPlaceholder="never"
class="adf-form-field-input"
[floatLabel]="field.placeholder ? 'always' : null"
>
@if(field.name || field.required) {
<mat-label class="adf-label" [attr.for]="field.id"> {{ field.name | translate }} </mat-label>
}
<textarea
matInput
class="adf-input"
[cdkTextareaAutosize]="true"
type="text"
rows="3"
[id]="field.id"
[required]="field.required"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly || readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()"
>
</textarea>
</mat-form-field>
<div *ngIf="field.maxLength > 0" class="adf-multiline-word-counter">
<span class="adf-multiline-word-counter-value">{{ field?.value?.length || 0 }}/{{ field.maxLength }}</span>
@if(field.name || field.required) {
<mat-label class="adf-label" [attr.for]="field.id"> {{ field.name | translate }} </mat-label>
}
<textarea
matInput
class="adf-input"
[cdkTextareaAutosize]="true"
type="text"
rows="3"
[id]="field.id"
[required]="field.required"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly || readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()"
>
</textarea>
</mat-form-field>
@if (field.maxLength > 0) {
<div class="adf-multiline-word-counter">
<span class="adf-multiline-word-counter-value">{{ field?.value?.length || 0 }}/{{ field.maxLength }}</span>
</div>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget
*ngIf="isInvalidFieldRequired() && isTouched()"
class="adf-multiline-required-message"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
}
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
class="adf-multiline-required-message"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
</div>
}
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { NgIf } from '@angular/common';
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
@@ -44,7 +44,7 @@ import { WidgetComponent } from '../widget.component';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [MatFormFieldModule, NgIf, TranslatePipe, MatInputModule, FormsModule, ErrorWidgetComponent],
imports: [MatFormFieldModule, TranslatePipe, MatInputModule, FormsModule, ErrorWidgetComponent],
encapsulation: ViewEncapsulation.None
})
export class MultilineTextWidgetComponentComponent extends WidgetComponent implements OnInit {
@@ -1,40 +1,43 @@
<div class="adf-textfield adf-number-widget {{ field.className }}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
<div *ngIf="field.leftLabels">
<label class="adf-label adf-left-label"
[attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
@if (field.leftLabels) {
<div>
<label class="adf-label adf-left-label"
[attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
</div>
<div class="adf-number-widget-container">
<mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
@if( (field.name || this.field?.required) && !field.leftLabels) {
<mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }}
</mat-label>
}
<input matInput
class="adf-input"
type="text"
pattern="-?[0-9]*(\.[0-9]+)?"
[id]="field.id"
[required]="field.required"
[value]="displayValue"
[(ngModel)]="field.value"
(ngModelChange)="onNumberChange($event)"
[disabled]="field.readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()">
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
</div>
}
<div class="adf-number-widget-container">
<mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
@if( (field.name || this.field?.required) && !field.leftLabels) {
<mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }}
</mat-label>
}
<input matInput
class="adf-input"
type="text"
pattern="-?[0-9]*(\.[0-9]+)?"
[id]="field.id"
[required]="field.required"
[value]="displayValue"
[(ngModel)]="field.value"
(ngModelChange)="onNumberChange($event)"
[disabled]="field.readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()">
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
}
</div>
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
import { NgIf } from '@angular/common';
import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -42,7 +42,7 @@ import { WidgetComponent } from '../widget.component';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent],
imports: [TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent],
providers: [DecimalNumberPipe],
encapsulation: ViewEncapsulation.None
})
@@ -1,39 +1,43 @@
<div class="adf-textfield adf-text-widget {{ field.className }}"
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
<div *ngIf="field.leftLabels">
<label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
@if (field.leftLabels) {
<div>
<label class="adf-label adf-left-label" [attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
</div>
<div class="adf-text-widget-container">
<mat-form-field class="adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
@if ( (field.name || this.field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }}
</mat-label>
}
<input matInput
class="adf-input"
type="text"
[id]="field.id"
[required]="field.required"
[value]="field.value"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly || readOnly"
[textMask]="{mask: mask, isReversed: isMaskReversed}"
[placeholder]="placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()">
</mat-form-field>
<ng-container *ngTemplateOutlet="fieldStatusTemplate ?? defaultErrorMessageTemplate; context: { $implicit: this }" />
<ng-template #defaultErrorMessageTemplate>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
</div>
</ng-template>
}
<div class="adf-text-widget-container">
<mat-form-field class="adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
@if ( (field.name || this.field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }}
</mat-label>
}
<input matInput
class="adf-input"
type="text"
[id]="field.id"
[required]="field.required"
[value]="field.value"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly || readOnly"
[textMask]="{mask: mask, isReversed: isMaskReversed}"
[placeholder]="placeholder"
[title]="field.tooltip"
(blur)="markAsTouched()">
</mat-form-field>
<ng-container *ngTemplateOutlet="fieldStatusTemplate ?? defaultErrorMessageTemplate; context: { $implicit: this }" />
<ng-template #defaultErrorMessageTemplate>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
}
</div>
</ng-template>
</div>
</div>
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { NgIf, NgTemplateOutlet } from '@angular/common';
import { NgTemplateOutlet } from '@angular/common';
import { Component, DestroyRef, Directive, inject, InjectionToken, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
@@ -63,7 +63,7 @@ export class FieldStatusTemplateDirective {
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, InputMaskDirective, NgTemplateOutlet],
imports: [TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, InputMaskDirective, NgTemplateOutlet],
encapsulation: ViewEncapsulation.None
})
export class TextWidgetComponent extends WidgetComponent implements OnInit {
+35 -31
View File
@@ -1,43 +1,47 @@
<ng-container [ngSwitch]="variant">
<ng-container *ngSwitchCase="'minimal'">
<adf-toolbar [color]="color">
<adf-toolbar-title>
<ng-container *ngTemplateOutlet="toolbarTitleContent" />
</adf-toolbar-title>
<ng-container *ngTemplateOutlet="navbarTemplate" />
<div class="adf-toolbar--spacer"></div>
<ng-container *ngTemplateOutlet="toolbarActions" />
</adf-toolbar>
</ng-container>
<ng-container *ngSwitchCase="'extended'">
<adf-toolbar [color]="color">
<adf-toolbar-title>
<ng-container *ngTemplateOutlet="toolbarTitleContent" />
</adf-toolbar-title>
<ng-container *ngTemplateOutlet="toolbarActions" />
</adf-toolbar>
<adf-toolbar [color]="color">
<ng-container *ngTemplateOutlet="navbarTemplate" />
</adf-toolbar>
</ng-container>
</ng-container>
@switch (variant) {
@case ('minimal') {
<adf-toolbar [color]="color">
<adf-toolbar-title>
<ng-container *ngTemplateOutlet="toolbarTitleContent" />
</adf-toolbar-title>
<ng-container *ngTemplateOutlet="navbarTemplate" />
<div class="adf-toolbar--spacer"></div>
<ng-container *ngTemplateOutlet="toolbarActions" />
</adf-toolbar>
}
@case ('extended') {
<adf-toolbar [color]="color">
<adf-toolbar-title>
<ng-container *ngTemplateOutlet="toolbarTitleContent" />
</adf-toolbar-title>
<ng-container *ngTemplateOutlet="toolbarActions" />
</adf-toolbar>
<adf-toolbar [color]="color">
<ng-container *ngTemplateOutlet="navbarTemplate" />
</adf-toolbar>
}
}
<ng-template #toolbarTitleContent>
<img *ngIf="logoSrc" [src]="logoSrc" [alt]="logoAlt" class="adf-toolbar-logo"/>
<span *ngIf="variant==='extended'">{{ title }}</span>
@if (logoSrc) {
<img [src]="logoSrc" [alt]="logoAlt" class="adf-toolbar-logo"/>
}
@if (variant==='extended') {
<span>{{ title }}</span>
}
</ng-template>
<ng-template #toolbarActions>
<div class="adf-toolbar-actions">
<ng-content select="[adf-toolbar-actions]" />
</div>
<div class="adf-toolbar-actions">
<ng-content select="[adf-toolbar-actions]" />
</div>
</ng-template>
<ng-template #navbarTemplate>
<adf-navbar [items]="navbarItems">
<ng-content select="adf-navbar-item" />
</adf-navbar>
<adf-navbar [items]="navbarItems">
<ng-content select="adf-navbar-item" />
</adf-navbar>
</ng-template>
@@ -1,10 +1,11 @@
<button *ngIf="routerLink; else noRouterLink" class="adf-navbar-item-btn"
[routerLink]="routerLink"
routerLinkActive="adf-navbar-item-active"
mat-button>{{ label }}
</button>
<ng-template #noRouterLink>
<button class="adf-navbar-item-btn" mat-button>
{{ label }}
</button>
</ng-template>
@if (routerLink) {
<button class="adf-navbar-item-btn"
[routerLink]="routerLink"
routerLinkActive="adf-navbar-item-active"
mat-button>{{ label }}
</button>
} @else {
<button class="adf-navbar-item-btn" mat-button>
{{ label }}
</button>
}
@@ -17,7 +17,7 @@
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
export interface NavbarItem {
@@ -30,7 +30,7 @@ export interface NavbarItem {
templateUrl: 'navbar-item.component.html',
styleUrls: ['./navbar-item.component.scss'],
encapsulation: ViewEncapsulation.None,
imports: [MatButtonModule, CommonModule, RouterModule],
imports: [MatButtonModule, RouterModule],
host: { class: 'adf-navbar-item' }
})
export class NavbarItemComponent {
@@ -1,4 +1,6 @@
<adf-navbar-item *ngFor="let item of items"
[routerLink]="item.routerLink"
[label]="item.label" />
@for (item of items; track item) {
<adf-navbar-item
[routerLink]="item.routerLink"
[label]="item.label" />
}
<ng-content />
@@ -17,7 +17,7 @@
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { MatToolbarModule } from '@angular/material/toolbar';
import { CommonModule } from '@angular/common';
import { NavbarItem, NavbarItemComponent } from './navbar-item.component';
@Component({
@@ -25,7 +25,7 @@ import { NavbarItem, NavbarItemComponent } from './navbar-item.component';
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss'],
encapsulation: ViewEncapsulation.None,
imports: [MatToolbarModule, CommonModule, NavbarItemComponent],
imports: [MatToolbarModule, NavbarItemComponent],
host: { class: 'adf-navbar' }
})
export class NavbarComponent {
@@ -1,41 +1,44 @@
<div
*ngIf="isLoggedIn"
@if (isLoggedIn) {
<div
id="userinfo_container"
[class.adf-userinfo-name-right]="showOnRight"
(keyup)="onKeyPress($event)"
tabindex="0"
role="button"
class="adf-userinfo-container"
>
<span *ngIf="showName" id="adf-userinfo-identity-name-display" class="adf-userinfo-name">
>
@if (showName) {
<span id="adf-userinfo-identity-name-display" class="adf-userinfo-name">
{{ identityUser | fullName }}
</span>
</span>
}
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button adf-identity-userinfo-button" data-automation-id="adf-user-profile">
<div class="adf-userinfo-button-profile" id="user-profile">
<div id="identity-user-image">
<div [innerHTML]="identityUser | usernameInitials : 'adf-userinfo-pic'"></div>
</div>
<div class="adf-userinfo-button-profile" id="user-profile">
<div id="identity-user-image">
<div [innerHTML]="identityUser | usernameInitials : 'adf-userinfo-pic'"></div>
</div>
</div>
</button>
<mat-menu
#menu="matMenu"
id="user-profile-lists"
[xPosition]="menuPositionX"
[yPosition]="menuPositionY"
[overlapTrigger]="false"
class="adf-userinfo-menu adf-identity-userinfo-menu"
>
<mat-card class="adf-userinfo-card adf-identity-userinfo-card">
<mat-card-header class="adf-userinfo-card-header" [style.background-image]="'url(' + bpmBackgroundImage + ')'">
<div class="mat-headline-6" id="identity-username">{{ identityUser | fullName }}</div>
</mat-card-header>
<mat-card-content>
<div class="adf-userinfo-supporting-text">
<h2 id="identity-full-name" class="adf-userinfo__detail-title">{{ identityUser | fullName }}</h2>
<span id="identity-email"> {{ identityUser.email }} </span>
<a href="#/profile"> {{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
</div>
</mat-card-content>
</mat-card>
#menu="matMenu"
id="user-profile-lists"
[xPosition]="menuPositionX"
[yPosition]="menuPositionY"
[overlapTrigger]="false"
class="adf-userinfo-menu adf-identity-userinfo-menu"
>
<mat-card class="adf-userinfo-card adf-identity-userinfo-card">
<mat-card-header class="adf-userinfo-card-header" [style.background-image]="'url(' + bpmBackgroundImage + ')'">
<div class="mat-headline-6" id="identity-username">{{ identityUser | fullName }}</div>
</mat-card-header>
<mat-card-content>
<div class="adf-userinfo-supporting-text">
<h2 id="identity-full-name" class="adf-userinfo__detail-title">{{ identityUser | fullName }}</h2>
<span id="identity-email"> {{ identityUser.email }} </span>
<a href="#/profile"> {{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
</div>
</mat-card-content>
</mat-card>
</mat-menu>
</div>
</div>
}
@@ -18,7 +18,7 @@
import { Component, Input, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatMenuModule, MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/menu';
import { IdentityUserModel } from '../auth/models/identity-user.model';
import { CommonModule } from '@angular/common';
import { FullNamePipe, InitialUsernamePipe } from '../pipes';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
@@ -26,7 +26,7 @@ import { TranslatePipe } from '@ngx-translate/core';
@Component({
selector: 'adf-identity-user-info',
imports: [CommonModule, FullNamePipe, MatMenuModule, InitialUsernamePipe, MatButtonModule, MatCardModule, TranslatePipe],
imports: [FullNamePipe, MatMenuModule, InitialUsernamePipe, MatButtonModule, MatCardModule, TranslatePipe],
templateUrl: './identity-user-info.component.html',
styleUrls: ['./identity-user-info.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,12 +1,14 @@
<div *ngIf="showHeader" class="adf-info-drawer-layout-header">
@if (showHeader) {
<div class="adf-info-drawer-layout-header">
<div class="adf-info-drawer-layout-header-title">
<ng-content select="[info-drawer-node-icon]" />
<ng-content select="[info-drawer-title]" />
<ng-content select="[info-drawer-node-icon]" />
<ng-content select="[info-drawer-title]" />
</div>
<div class="adf-info-drawer-layout-header-buttons">
<ng-content select="[info-drawer-buttons]" />
<ng-content select="[info-drawer-buttons]" />
</div>
</div>
</div>
}
<div class="adf-info-drawer-layout-content">
<ng-content select="[info-drawer-content]" />
<ng-content select="[info-drawer-content]" />
</div>
@@ -16,11 +16,11 @@
*/
import { Component, Directive, Input, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'adf-info-drawer-layout',
imports: [CommonModule],
imports: [],
templateUrl: './info-drawer-layout.component.html',
styleUrls: ['./info-drawer-layout.component.scss'],
encapsulation: ViewEncapsulation.None,
@@ -1,33 +1,41 @@
<adf-info-drawer-layout [showHeader]="showHeader">
<img *ngIf="icon" class="adf-info-drawer-icon" alt="{{ 'INFO_DRAWER.ICON' | translate }}" src="{{ icon }}" info-drawer-node-icon aria-hidden="true">
<div *ngIf="title" role="heading" aria-level="1" title="{{ title | translate }}" info-drawer-title>{{ title | translate }}</div>
@if (icon) {
<img class="adf-info-drawer-icon" alt="{{ 'INFO_DRAWER.ICON' | translate }}" src="{{ icon }}" info-drawer-node-icon aria-hidden="true">
}
@if (title) {
<div 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 info-drawer-buttons select="[info-drawer-buttons]" />
<ng-container info-drawer-content *ngIf="showTabLayout(); then tabLayout else singleLayout" />
<ng-template #tabLayout>
<mat-tab-group [(selectedIndex)]="selectedIndex" class="adf-info-drawer-tabs" (selectedTabChange)="onTabChange($event)" [animationDuration]="0">
<mat-tab *ngFor="let contentBlock of contentBlocks"
#tab
@if (!title) {
<ng-content info-drawer-title select="[info-drawer-title]" />
}
<ng-content info-drawer-buttons select="[info-drawer-buttons]" />
@if (showTabLayout()) {
<mat-tab-group [(selectedIndex)]="selectedIndex" class="adf-info-drawer-tabs" (selectedTabChange)="onTabChange($event)" [animationDuration]="0">
@for (contentBlock of contentBlocks; track contentBlock) {
<mat-tab
#tab
[labelClass]="[
'adf-info-drawer-tab',
tab.isActive ? 'adf-info-drawer-tab--active' : '',
]"
[label]="contentBlock.label | translate"
class="adf-info-drawer-tab">
[label]="contentBlock.label | translate"
class="adf-info-drawer-tab">
<ng-template mat-tab-label>
@if (contentBlock.icon) {
<mat-icon [adf-icon]="contentBlock.icon" />
}
@if (contentBlock.label) {
<span>{{ contentBlock.label | translate }}</span>
}
</ng-template>
<ng-container *ngTemplateOutlet="contentBlock.content" />
</mat-tab>
}
</mat-tab-group>
} @else {
<ng-content select="[info-drawer-content]" />
}
<ng-template mat-tab-label>
<mat-icon *ngIf="contentBlock.icon" [adf-icon]="contentBlock.icon" />
<span *ngIf="contentBlock.label">{{ contentBlock.label | translate }}</span>
</ng-template>
<ng-container *ngTemplateOutlet="contentBlock.content" />
</mat-tab>
</mat-tab-group>
</ng-template>
<ng-template #singleLayout>
<ng-content select="[info-drawer-content]" />
</ng-template>
</adf-info-drawer-layout>
@@ -28,7 +28,7 @@ import {
ViewEncapsulation
} from '@angular/core';
import { MatTabChangeEvent, MatTabsModule } from '@angular/material/tabs';
import { CommonModule } from '@angular/common';
import {
InfoDrawerButtonsDirective,
InfoDrawerContentDirective,
@@ -59,16 +59,15 @@ export class InfoDrawerTabComponent {
@Component({
selector: 'adf-info-drawer',
imports: [
CommonModule,
InfoDrawerLayoutComponent,
TranslatePipe,
MatTabsModule,
IconModule,
InfoDrawerButtonsDirective,
InfoDrawerTitleDirective,
InfoDrawerContentDirective,
InfoDrawerTabComponent
],
InfoDrawerLayoutComponent,
TranslatePipe,
MatTabsModule,
IconModule,
InfoDrawerButtonsDirective,
InfoDrawerTitleDirective,
InfoDrawerContentDirective,
InfoDrawerTabComponent
],
templateUrl: './info-drawer.component.html',
styleUrls: ['./info-drawer.component.scss'],
encapsulation: ViewEncapsulation.None,
@@ -26,10 +26,12 @@ import { MatMenuItem, MatMenuModule } from '@angular/material/menu';
selector: 'adf-language-menu',
imports: [CommonModule, MatMenuModule],
template: `
<button mat-menu-item *ngFor="let language of languages$ | async" [attr.lang]="language.key" (click)="changeLanguage(language)">
@for (language of languages$ | async; track language) {
<button mat-menu-item [attr.lang]="language.key" (click)="changeLanguage(language)">
{{ language.label }}
</button>
`
</button>
}
`
})
export class LanguageMenuComponent {
private readonly languageService = inject(LanguageService);
@@ -17,7 +17,7 @@
import { AfterViewInit, Component, EventEmitter, Output, QueryList, ViewChild } from '@angular/core';
import { LanguageItem } from '../common/services/language-item.interface';
import { CommonModule } from '@angular/common';
import { MatMenu, MatMenuItem, MatMenuModule } from '@angular/material/menu';
import { TranslatePipe } from '@ngx-translate/core';
import { LanguageMenuComponent } from './language-menu.component';
@@ -25,7 +25,7 @@ import { IconModule } from '../icon/icon.module';
@Component({
selector: 'adf-picker-button',
imports: [CommonModule, MatMenuModule, TranslatePipe, LanguageMenuComponent, IconModule],
imports: [MatMenuModule, TranslatePipe, LanguageMenuComponent, IconModule],
template: `
<button mat-menu-item [matMenuTriggerFor]="langMenu">
<mat-icon adf-icon="language" />
@@ -1,48 +1,52 @@
<mat-toolbar
class="adf-toolbar-container-row"
[color]="color"
[style.background-color]="color"
[style.background-image]="backgroundImage ? 'url(' + backgroundImage + ')' : 'none'">
class="adf-toolbar-container-row"
[color]="color"
[style.background-color]="color"
[style.background-image]="backgroundImage ? 'url(' + backgroundImage + ')' : 'none'">
@if (showSidenavToggle && position === 'start') {
<button
*ngIf="showSidenavToggle && position === 'start'"
id="adf-sidebar-toggle-start"
data-automation-id="adf-menu-icon"
class="adf-menu-icon adf-header-icon-button"
mat-icon-button
(click)="toggleMenu()"
[attr.aria-expanded]="expandedSidenav"
[attr.aria-label]="'CORE.HEADER.ACCESSIBILITY.SIDEBAR_TOGGLE_BUTTON_ARIA_LABEL' | translate">
<mat-icon class="adf-menu-icon-header" role="img" aria-hidden="true" [adf-icon]="toggleIcon" />
id="adf-sidebar-toggle-start"
data-automation-id="adf-menu-icon"
class="adf-menu-icon adf-header-icon-button"
mat-icon-button
(click)="toggleMenu()"
[attr.aria-expanded]="expandedSidenav"
[attr.aria-label]="'CORE.HEADER.ACCESSIBILITY.SIDEBAR_TOGGLE_BUTTON_ARIA_LABEL' | translate">
<mat-icon class="adf-menu-icon-header" role="img" aria-hidden="true" [adf-icon]="toggleIcon" />
</button>
}
<a *ngIf="showLogo" [routerLink]="redirectUrl" title="{{ tooltip }}">
<img
src="{{ logo }}"
class="adf-app-logo"
alt="{{ 'CORE.HEADER.LOGO_ARIA' | translate }}"
@if (showLogo) {
<a [routerLink]="redirectUrl" title="{{ tooltip }}">
<img
src="{{ logo }}"
class="adf-app-logo"
alt="{{ 'CORE.HEADER.LOGO_ARIA' | translate }}"
/>
</a>
}
<h1
role="link"
[attr.aria-label]="title | translate"
[routerLink]="redirectUrl"
class="adf-app-title"
>
{{ title }}
</h1>
<h1
role="link"
[attr.aria-label]="title | translate"
[routerLink]="redirectUrl"
class="adf-app-title"
>
{{ title }}
</h1>
<ng-content />
<ng-content />
@if (showSidenavToggle && position === 'end') {
<button
*ngIf="showSidenavToggle && position === 'end'"
id="adf-sidebar-toggle-end"
data-automation-id="adf-menu-icon"
class="adf-menu-icon adf-header-icon-button"
mat-icon-button
(click)="toggleMenu()"
[attr.aria-expanded]="expandedSidenav"
[attr.aria-label]="'CORE.HEADER.ACCESSIBILITY.SIDEBAR_TOGGLE_BUTTON_ARIA_LABEL' | translate">
<mat-icon class="adf-menu-icon-header" role="img" aria-hidden="true" [adf-icon]="toggleIcon" />
id="adf-sidebar-toggle-end"
data-automation-id="adf-menu-icon"
class="adf-menu-icon adf-header-icon-button"
mat-icon-button
(click)="toggleMenu()"
[attr.aria-expanded]="expandedSidenav"
[attr.aria-label]="'CORE.HEADER.ACCESSIBILITY.SIDEBAR_TOGGLE_BUTTON_ARIA_LABEL' | translate">
<mat-icon class="adf-menu-icon-header" role="img" aria-hidden="true" [adf-icon]="toggleIcon" />
</button>
}
</mat-toolbar>
@@ -18,7 +18,7 @@
import { Component, Input, Output, EventEmitter, ViewEncapsulation, OnInit, inject } from '@angular/core';
import { ThemePalette } from '@angular/material/core';
import { AppConfigService } from '../../../app-config/app-config.service';
import { CommonModule } from '@angular/common';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@@ -27,7 +27,7 @@ import { IconModule } from '../../../icon/icon.module';
@Component({
selector: 'adf-layout-header',
imports: [CommonModule, MatToolbarModule, MatButtonModule, IconModule, RouterModule, TranslatePipe],
imports: [MatToolbarModule, MatButtonModule, IconModule, RouterModule, TranslatePipe],
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
encapsulation: ViewEncapsulation.None,
@@ -18,12 +18,12 @@
import { Component, Input, ViewChild, OnInit, OnDestroy, ViewEncapsulation, OnChanges, SimpleChanges } from '@angular/core';
import { MatSidenav, MatSidenavModule } from '@angular/material/sidenav';
import { Direction } from '@angular/cdk/bidi';
import { CommonModule } from '@angular/common';
import { animate, state, style, transition, trigger } from '@angular/animations';
@Component({
selector: 'adf-layout-container',
imports: [CommonModule, MatSidenavModule],
imports: [MatSidenavModule],
templateUrl: './layout-container.component.html',
styleUrls: ['./layout-container.component.scss'],
encapsulation: ViewEncapsulation.None,
@@ -1,16 +1,22 @@
<div class="adf-sidebar-action-menu">
<button *ngIf="isExpanded()" mat-raised-button class="adf-sidebar-action-menu-button" data-automation-id="create-button" [matMenuTriggerFor]="adfSidebarMenu">
<span *ngIf="title" class="adf-sidebar-action-menu-text">{{ title }}</span>
<ng-content select="[adf-sidebar-menu-title-icon], [sidebar-menu-title-icon]" />
@if (isExpanded()) {
<button mat-raised-button class="adf-sidebar-action-menu-button" data-automation-id="create-button" [matMenuTriggerFor]="adfSidebarMenu">
@if (title) {
<span class="adf-sidebar-action-menu-text">{{ title }}</span>
}
<ng-content select="[adf-sidebar-menu-title-icon], [sidebar-menu-title-icon]" />
</button>
}
<div *ngIf="!isExpanded()" class="adf-sidebar-action-menu-icon" [matMenuTriggerFor]="adfSidebarMenu">
<ng-content select="[adf-sidebar-menu-expand-icon], [sidebar-menu-expand-icon]" />
@if (!isExpanded()) {
<div class="adf-sidebar-action-menu-icon" [matMenuTriggerFor]="adfSidebarMenu">
<ng-content select="[adf-sidebar-menu-expand-icon], [sidebar-menu-expand-icon]" />
</div>
}
<mat-menu #adfSidebarMenu="matMenu" class="adf-sidebar-action-menu-panel" [overlapTrigger]="false" yPosition="below">
<div class="adf-sidebar-action-menu-options" [style.width.px]="width">
<ng-content select="[adf-sidebar-menu-options], [sidebar-menu-options]" />
</div>
</mat-menu>
<mat-menu #adfSidebarMenu="matMenu" class="adf-sidebar-action-menu-panel" [overlapTrigger]="false" yPosition="below">
<div class="adf-sidebar-action-menu-options" [style.width.px]="width">
<ng-content select="[adf-sidebar-menu-options], [sidebar-menu-options]" />
</div>
</mat-menu>
</div>
@@ -18,7 +18,7 @@
import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SidebarActionMenuComponent } from './sidebar-action-menu.component';
import { CommonModule } from '@angular/common';
import { MatMenuModule } from '@angular/material/menu';
import { UnitTestingUtils } from '../../../testing/unit-testing-utils';
import { IconModule } from '../../../icon/icon.module';
@@ -52,7 +52,7 @@ describe('SidebarActionMenuComponent', () => {
});
@Component({
imports: [CommonModule, SidebarActionMenuComponent, IconModule, MatMenuModule],
imports: [SidebarActionMenuComponent, IconModule, MatMenuModule],
// eslint-disable-next-line @alfresco/eslint-angular/no-angular-material-selectors
template: `
<adf-sidebar-action-menu [expanded]="expanded" [title]="title">
@@ -16,13 +16,13 @@
*/
import { ChangeDetectionStrategy, Component, Directive, Input, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu';
@Component({
selector: 'adf-sidebar-action-menu',
imports: [CommonModule, MatButtonModule, MatMenuModule],
imports: [MatButtonModule, MatMenuModule],
templateUrl: './sidebar-action-menu.component.html',
styleUrls: ['./sidebar-action-menu.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -1,30 +1,30 @@
<div class="adf-sidenav-layout-full-space">
<ng-container *ngIf="!isHeaderInside">
<ng-container class="adf-sidenav-layout-outer-header"
*ngTemplateOutlet="headerTemplate; context:templateContext" />
@if (!isHeaderInside) {
<ng-container class="adf-sidenav-layout-outer-header"
*ngTemplateOutlet="headerTemplate; context:templateContext" />
}
<adf-layout-container #container
[direction]="dir"
[position]="position"
[sidenavMin]="sidenavMin"
[sidenavMax]="sidenavMax"
[mediaQueryList]="mediaQueryList"
[hideSidenav]="hideSidenav"
[expandedSidenav]="expandedSidenav"
data-automation-id="adf-layout-container"
class="adf-layout__content">
<ng-container app-layout-navigation
*ngTemplateOutlet="navigationTemplate; context:templateContext" />
<ng-container app-layout-content>
@if (isHeaderInside) {
<ng-container *ngTemplateOutlet="headerTemplate; context:templateContext" />
}
<ng-container *ngTemplateOutlet="contentTemplate; context:templateContext" />
</ng-container>
</adf-layout-container>
<adf-layout-container #container
[direction]="dir"
[position]="position"
[sidenavMin]="sidenavMin"
[sidenavMax]="sidenavMax"
[mediaQueryList]="mediaQueryList"
[hideSidenav]="hideSidenav"
[expandedSidenav]="expandedSidenav"
data-automation-id="adf-layout-container"
class="adf-layout__content">
<ng-container app-layout-navigation
*ngTemplateOutlet="navigationTemplate; context:templateContext" />
<ng-container app-layout-content>
<ng-container *ngIf="isHeaderInside">
<ng-container *ngTemplateOutlet="headerTemplate; context:templateContext" />
</ng-container>
<ng-container *ngTemplateOutlet="contentTemplate; context:templateContext" />
</ng-container>
</adf-layout-container>
<ng-template #emptyTemplate />
<ng-template #emptyTemplate />
</div>
@@ -1,200 +1,225 @@
<div class="adf-login-content" [style.background-image]="'url(' + backgroundImageUrl + ')'">
<div class="adf-ie11FixerParent">
<div class="adf-ie11FixerChild">
<div class="adf-ie11FixerParent">
<div class="adf-ie11FixerChild">
<mat-card class="adf-login-card-wide">
<form id="adf-login-form"
[formGroup]="form"
autocomplete="off"
(submit)="onSubmit(form.value)">
<mat-card-header class="adf-login-card-header-text">
<mat-card-title>
<div class="adf-alfresco-logo">
<!--HEADER TEMPLATE-->
<ng-template *ngIf="headerTemplate"
ngFor
[ngForOf]="[data]"
[ngForTemplate]="headerTemplate" />
<img *ngIf="!headerTemplate"
id="adf-login-img-logo"
class="adf-img-logo"
[src]="logoImageUrl"
alt="{{ 'LOGIN.LOGO' | translate }}">
</div>
</mat-card-title>
</mat-card-header>
<mat-card class="adf-login-card-wide">
<form id="adf-login-form"
[formGroup]="form"
autocomplete="off"
(submit)="onSubmit(form.value)">
<mat-card-header class="adf-login-card-header-text">
<mat-card-title>
<div class="adf-alfresco-logo">
<!--HEADER TEMPLATE-->
@if (headerTemplate) {
@for ( of [data]; track ) {
<ng-template
[ngForOf]="[data]"
[ngForTemplate]="headerTemplate" />
}
}
@if (!headerTemplate) {
<img
id="adf-login-img-logo"
class="adf-img-logo"
[src]="logoImageUrl"
alt="{{ 'LOGIN.LOGO' | translate }}">
}
</div>
</mat-card-title>
</mat-card-header>
<mat-card-content class="adf-login-controls">
<mat-card-content class="adf-login-controls">
<!--ERRORS AREA-->
<div class="adf-error-container">
<div *ngIf="isError"
id="login-error"
data-automation-id="login-error"
class="adf-error adf-error-message">
<mat-icon class="adf-error-icon" adf-icon="warning" />
<span class="adf-login-error-message">
{{ errorMsg | translate }}
</span>
</div>
</div>
<div *ngIf="!ssoLogin">
<!--USERNAME FIELD-->
<div class="adf-login__field adf-login-container"
[ngClass]="{'adf-is-invalid': isErrorStyle(form.controls.username)}">
<mat-form-field class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<mat-label class="adf-login-form-input-label">
{{'LOGIN.LABEL.USERNAME' | translate }}
</mat-label>
<input matInput
type="text"
class="adf-login-input"
formControlName="username"
id="username"
data-automation-id="username"
autocapitalize="none"
(blur)="trimUsername($event)">
</mat-form-field>
<span *ngIf="formError['username']"
class="adf-login-validation"
for="username">
<span id="username-error"
class="adf-login-error"
data-automation-id="username-error">
{{ formError['username'] | translate }}
</span>
</span>
</div>
<!--PASSWORD FIELD-->
<div class="adf-login__field">
<mat-form-field class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<mat-label class="adf-login-form-input-label">
{{'LOGIN.LABEL.PASSWORD' | translate }}
</mat-label>
<input matInput
[type]="isPasswordShow ? 'text' : 'password'"
formControlName="password"
class="adf-login-input"
id="password"
data-automation-id="password">
<button matSuffix
mat-icon-button
type="button"
[attr.aria-label]="(isPasswordShow ? 'LOGIN.ARIA-LABEL.HIDE-PASSWORD' : 'LOGIN.ARIA-LABEL.SHOW-PASSWORD') | translate"
(click)="toggleShowPassword($event)"
(keyup.enter)="toggleShowPassword($event)"
[attr.data-automation-id]="isPasswordShow ? 'hide_password' : 'show_password'">
<mat-icon class="adf-login-form-password-icon adf-login-password-icon" [adf-icon]="isPasswordShow ? 'visibility' : 'visibility_off'" />
</button>
</mat-form-field>
<span class="adf-login-validation"
for="password"
*ngIf="formError['password']">
<span id="password-required"
class="adf-login-error"
data-automation-id="password-required">
{{ formError['password'] | translate }}
</span>
</span>
</div>
<!--CUSTOM CONTENT-->
<ng-content />
<br>
<button type="submit"
id="login-button"
class="adf-login-button"
mat-raised-button
color="accent"
[class.adf-isChecking]="actualLoginStep === LoginSteps.Checking"
[class.adf-isWelcome]="actualLoginStep === LoginSteps.Welcome"
data-automation-id="login-button"
[disabled]="!form.valid"
[attr.aria-label]="'LOGIN.BUTTON.LOGIN' | translate">
<span *ngIf="actualLoginStep === LoginSteps.Landing"
class="adf-login-button-label">
{{ 'LOGIN.BUTTON.LOGIN' | translate }}
</span>
<div *ngIf="actualLoginStep === LoginSteps.Checking"
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.CHECKING' | translate }}
</span>
<div class="adf-login-spinner-container">
<mat-spinner id="checking-spinner"
class="adf-login-checking-spinner"
[strokeWidth]="4"
[diameter]="25" />
</div>
</div>
<div *ngIf="actualLoginStep === LoginSteps.Welcome"
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.WELCOME' | translate }}
</span>
<mat-icon class="adf-welcome-icon" adf-icon="done" />
</div>
</button>
<div *ngIf="showRememberMe" class="adf-login__remember-me">
<mat-checkbox id="adf-login-remember"
color="primary"
class="adf-login-remember-me"
[checked]="rememberMe"
(change)="rememberMe = !rememberMe">
<div class="adf-login-remember-me-label">
{{ 'LOGIN.LABEL.REMEMBER' | translate }}
</div>
</mat-checkbox>
</div>
</div>
<div *ngIf="ssoLogin">
<button type="button"
(click)="implicitLogin()"
id="login-button-sso"
[attr.aria-label]="'LOGIN.BUTTON.SSO' | translate"
class="adf-login-button"
mat-raised-button color="primary"
data-automation-id="login-button-sso">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.SSO' | translate }}
</span>
</button>
</div>
</mat-card-content>
<mat-card-actions *ngIf="footerTemplate || showLoginActions">
<div class="adf-login-action-container">
<!--FOOTER TEMPLATE-->
<ng-template *ngIf="footerTemplate"
ngFor
[ngForOf]="[data]"
[ngForTemplate]="footerTemplate" />
<div class="adf-login-action" *ngIf="!footerTemplate && showLoginActions">
<div id="adf-login-action-left" class="adf-login-action-left">
<a href="{{ needHelpLink }}">{{ 'LOGIN.ACTION.HELP' | translate }}</a>
</div>
<div id="adf-login-action-right" class="adf-login-action-right">
<a href="{{ registerLink }}">{{ 'LOGIN.ACTION.REGISTER' | translate }}</a>
</div>
</div>
</div>
</mat-card-actions>
</form>
</mat-card>
<div class="adf-copyright" data-automation-id="login-copyright">
{{ copyrightText }}
<!--ERRORS AREA-->
<div class="adf-error-container">
@if (isError) {
<div
id="login-error"
data-automation-id="login-error"
class="adf-error adf-error-message">
<mat-icon class="adf-error-icon" adf-icon="warning" />
<span class="adf-login-error-message">
{{ errorMsg | translate }}
</span>
</div>
}
</div>
@if (!ssoLogin) {
<div>
<!--USERNAME FIELD-->
<div class="adf-login__field adf-login-container"
[ngClass]="{'adf-is-invalid': isErrorStyle(form.controls.username)}">
<mat-form-field class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<mat-label class="adf-login-form-input-label">
{{'LOGIN.LABEL.USERNAME' | translate }}
</mat-label>
<input matInput
type="text"
class="adf-login-input"
formControlName="username"
id="username"
data-automation-id="username"
autocapitalize="none"
(blur)="trimUsername($event)">
</mat-form-field>
@if (formError['username']) {
<span
class="adf-login-validation"
for="username">
<span id="username-error"
class="adf-login-error"
data-automation-id="username-error">
{{ formError['username'] | translate }}
</span>
</span>
}
</div>
<!--PASSWORD FIELD-->
<div class="adf-login__field">
<mat-form-field class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<mat-label class="adf-login-form-input-label">
{{'LOGIN.LABEL.PASSWORD' | translate }}
</mat-label>
<input matInput
[type]="isPasswordShow ? 'text' : 'password'"
formControlName="password"
class="adf-login-input"
id="password"
data-automation-id="password">
<button matSuffix
mat-icon-button
type="button"
[attr.aria-label]="(isPasswordShow ? 'LOGIN.ARIA-LABEL.HIDE-PASSWORD' : 'LOGIN.ARIA-LABEL.SHOW-PASSWORD') | translate"
(click)="toggleShowPassword($event)"
(keyup.enter)="toggleShowPassword($event)"
[attr.data-automation-id]="isPasswordShow ? 'hide_password' : 'show_password'">
<mat-icon class="adf-login-form-password-icon adf-login-password-icon" [adf-icon]="isPasswordShow ? 'visibility' : 'visibility_off'" />
</button>
</mat-form-field>
@if (formError['password']) {
<span class="adf-login-validation"
for="password"
>
<span id="password-required"
class="adf-login-error"
data-automation-id="password-required">
{{ formError['password'] | translate }}
</span>
</span>
}
</div>
<!--CUSTOM CONTENT-->
<ng-content />
<br>
<button type="submit"
id="login-button"
class="adf-login-button"
mat-raised-button
color="accent"
[class.adf-isChecking]="actualLoginStep === LoginSteps.Checking"
[class.adf-isWelcome]="actualLoginStep === LoginSteps.Welcome"
data-automation-id="login-button"
[disabled]="!form.valid"
[attr.aria-label]="'LOGIN.BUTTON.LOGIN' | translate">
@if (actualLoginStep === LoginSteps.Landing) {
<span
class="adf-login-button-label">
{{ 'LOGIN.BUTTON.LOGIN' | translate }}
</span>
}
@if (actualLoginStep === LoginSteps.Checking) {
<div
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.CHECKING' | translate }}
</span>
<div class="adf-login-spinner-container">
<mat-spinner id="checking-spinner"
class="adf-login-checking-spinner"
[strokeWidth]="4"
[diameter]="25" />
</div>
</div>
}
@if (actualLoginStep === LoginSteps.Welcome) {
<div
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.WELCOME' | translate }}
</span>
<mat-icon class="adf-welcome-icon" adf-icon="done" />
</div>
}
</button>
@if (showRememberMe) {
<div class="adf-login__remember-me">
<mat-checkbox id="adf-login-remember"
color="primary"
class="adf-login-remember-me"
[checked]="rememberMe"
(change)="rememberMe = !rememberMe">
<div class="adf-login-remember-me-label">
{{ 'LOGIN.LABEL.REMEMBER' | translate }}
</div>
</mat-checkbox>
</div>
}
</div>
}
@if (ssoLogin) {
<div>
<button type="button"
(click)="implicitLogin()"
id="login-button-sso"
[attr.aria-label]="'LOGIN.BUTTON.SSO' | translate"
class="adf-login-button"
mat-raised-button color="primary"
data-automation-id="login-button-sso">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.SSO' | translate }}
</span>
</button>
</div>
}
</mat-card-content>
@if (footerTemplate || showLoginActions) {
<mat-card-actions>
<div class="adf-login-action-container">
<!--FOOTER TEMPLATE-->
@if (footerTemplate) {
@for ( of [data]; track ) {
<ng-template
[ngForOf]="[data]"
[ngForTemplate]="footerTemplate" />
}
}
@if (!footerTemplate && showLoginActions) {
<div class="adf-login-action">
<div id="adf-login-action-left" class="adf-login-action-left">
<a href="{{ needHelpLink }}">{{ 'LOGIN.ACTION.HELP' | translate }}</a>
</div>
<div id="adf-login-action-right" class="adf-login-action-right">
<a href="{{ registerLink }}">{{ 'LOGIN.ACTION.REGISTER' | translate }}</a>
</div>
</div>
}
</div>
</mat-card-actions>
}
</form>
</mat-card>
<div class="adf-copyright" data-automation-id="login-copyright">
{{ copyrightText }}
</div>
</div>
</div>
</div>
</div>
@@ -1,81 +1,85 @@
<button
mat-button
[matMenuTriggerFor]="menu"
aria-hidden="false"
[attr.aria-label]="('NOTIFICATIONS.' + (notifications.length ? 'UNREAD_MESSAGES' : 'NO_MESSAGE') | translate) + ' ' + ('NOTIFICATIONS.OPEN_HISTORY' | translate)"
title="{{ 'NOTIFICATIONS.OPEN_HISTORY' | translate }}"
class="adf-notification-history-menu_button"
id="adf-notification-history-open-button"
(menuOpened)="onMenuOpened()"
>
<mat-icon aria-hidden="false" matBadge="&#8288;" [matBadgeHidden]="!notifications.length" class="adf-notification-history-menu_button-icon" matBadgeColor="accent" matBadgeSize="small" adf-icon="notifications" />
mat-button
[matMenuTriggerFor]="menu"
aria-hidden="false"
[attr.aria-label]="('NOTIFICATIONS.' + (notifications.length ? 'UNREAD_MESSAGES' : 'NO_MESSAGE') | translate) + ' ' + ('NOTIFICATIONS.OPEN_HISTORY' | translate)"
title="{{ 'NOTIFICATIONS.OPEN_HISTORY' | translate }}"
class="adf-notification-history-menu_button"
id="adf-notification-history-open-button"
(menuOpened)="onMenuOpened()"
>
<mat-icon aria-hidden="false" matBadge="&#8288;" [matBadgeHidden]="!notifications.length" class="adf-notification-history-menu_button-icon" matBadgeColor="accent" matBadgeSize="small" adf-icon="notifications" />
</button>
<mat-menu #menu="matMenu"
[xPosition]="menuPositionX"
[yPosition]="menuPositionY"
id="adf-notification-history-menu"
class="adf-notification-history-menu adf-notification-history-menu-panel">
<div class="adf-notification-history-list-header" aria-hidden="true">
<span class="adf-notification-history-menu-title">{{ 'NOTIFICATIONS.TITLE' | translate }}</span>
<button mat-icon-button
*ngIf="notifications.length"
data-automation-id="adf-notification-history-mark-as-read"
class="adf-notification-history-mark-as-read"
title="{{ 'NOTIFICATIONS.MARK_AS_READ' | translate }}"
(click)="markAsRead()"
#markAsReadButton
(keydown)="manageFocus($event)">
<mat-icon class="adf-notification-history-mark-as-read-icon" adf-icon="done_all" />
[xPosition]="menuPositionX"
[yPosition]="menuPositionY"
id="adf-notification-history-menu"
class="adf-notification-history-menu adf-notification-history-menu-panel">
<div class="adf-notification-history-list-header" aria-hidden="true">
<span class="adf-notification-history-menu-title">{{ 'NOTIFICATIONS.TITLE' | translate }}</span>
@if (notifications.length) {
<button mat-icon-button
data-automation-id="adf-notification-history-mark-as-read"
class="adf-notification-history-mark-as-read"
title="{{ 'NOTIFICATIONS.MARK_AS_READ' | translate }}"
(click)="markAsRead()"
#markAsReadButton
(keydown)="manageFocus($event)">
<mat-icon class="adf-notification-history-mark-as-read-icon" adf-icon="done_all" />
</button>
}
</div>
<mat-divider aria-hidden="true" />
<div class="adf-notification-history-item-list">
@if (notifications.length) {
@for (notification of paginatedNotifications; track notification) {
<button mat-menu-item
(click)="onNotificationClick(notification, $event)"
class="adf-notification-history-menu-item"
(keydown)="manageFocus($event)">
<div class="adf-notification-history-menu-item-content">
@if (notification.initiator) {
<div
[outerHTML]="notification.initiator | usernameInitials : 'adf-notification-initiator-pic'"></div>
} @else {
<mat-icon class="adf-notification-history-menu-initiator" [adf-icon]="notification.icon" />
}
<div class="adf-notification-history-menu-item-content-message">
@for (message of notification.messages; track message) {
<p class="adf-notification-history-menu-text adf-notification-history-menu-message"
[title]="message">{{ message }}</p>
}
<p class="adf-notification-history-menu-text adf-notification-history-menu-date"
> {{ notification.datetime | adfTimeAgo }} </p>
</div>
</div>
</button>
</div>
}
} @else {
<p id="adf-notification-history-component-no-message"
class="adf-notification-history-menu-no-message-text">
{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}
</p>
}
</div>
<mat-divider aria-hidden="true" />
<div class="adf-notification-history-item-list">
<ng-container *ngIf="notifications.length; else empty_list_template">
<button mat-menu-item
*ngFor="let notification of paginatedNotifications"
(click)="onNotificationClick(notification, $event)"
class="adf-notification-history-menu-item"
(keydown)="manageFocus($event)">
<div class="adf-notification-history-menu-item-content">
<div *ngIf="notification.initiator; else no_avatar"
[outerHTML]="notification.initiator | usernameInitials : 'adf-notification-initiator-pic'"></div>
<ng-template #no_avatar>
<mat-icon class="adf-notification-history-menu-initiator" [adf-icon]="notification.icon" />
</ng-template>
<div class="adf-notification-history-menu-item-content-message">
<p class="adf-notification-history-menu-text adf-notification-history-menu-message"
*ngFor="let message of notification.messages"
[title]="message">{{ message }}</p>
<p class="adf-notification-history-menu-text adf-notification-history-menu-date"
> {{ notification.datetime | adfTimeAgo }} </p>
</div>
</div>
</button>
</ng-container>
<ng-template #empty_list_template>
<p id="adf-notification-history-component-no-message"
class="adf-notification-history-menu-no-message-text">
{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}
</p>
</ng-template>
</div>
<mat-divider aria-hidden="true" />
<mat-divider aria-hidden="true" />
@if (hasMoreNotifications()) {
<div
class="adf-notification-history-load-more"
*ngIf="hasMoreNotifications()"
aria-hidden="true">
<button
data-automation-id="adf-notification-history-load-more"
mat-button
(click)="loadMore($event)"
#loadMoreButton
(keydown)="manageFocus($event)">
{{ 'NOTIFICATIONS.LOAD_MORE' | translate }}
</button>
class="adf-notification-history-load-more"
aria-hidden="true">
<button
data-automation-id="adf-notification-history-load-more"
mat-button
(click)="loadMore($event)"
#loadMoreButton
(keydown)="manageFocus($event)">
{{ 'NOTIFICATIONS.LOAD_MORE' | translate }}
</button>
</div>
}
</mat-menu>

Some files were not shown because too many files have changed in this diff Show More