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
@@ -1,28 +1,30 @@
<mat-form-field floatLabel="auto" [attr.data-automation-id]="processFilterProperty.key">
<mat-label>{{ processFilterProperty.label | translate }}</mat-label>
<mat-select
placeholder="{{ processFilterProperty.label | translate }}"
[value]="type"
(selectionChange)="onSelectionChange($event)"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
<mat-option *ngFor="let propertyOption of filteredProperties" [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + propertyOption.value.toString()">
{{ propertyOption.label | translate }}
</mat-option>
</mat-select>
<mat-label>{{ processFilterProperty.label | translate }}</mat-label>
<mat-select
placeholder="{{ processFilterProperty.label | translate }}"
[value]="type"
(selectionChange)="onSelectionChange($event)"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
@for (propertyOption of filteredProperties; track propertyOption) {
<mat-option [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + propertyOption.value.toString()">
{{ propertyOption.label | translate }}
</mat-option>
}
</mat-select>
</mat-form-field>
<ng-container *ngIf="isDateRangeType()">
<mat-form-field floatLabel="auto" class="adf-cloud-date-range-picker">
<mat-label>{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE_TITLE' | translate }}</mat-label>
<mat-date-range-input [formGroup]="dateRangeForm" [rangePicker]="picker">
<input matStartDate formControlName="from" placeholder="{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.START_DATE' | translate }}">
<input matEndDate formControlName="to" placeholder="{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.END_DATE' | translate }}">
</mat-date-range-input>
<mat-datepicker-toggle
matSuffix
[for]="picker"
[attr.data-automation-id]="'adf-cloud-edit-process-property-date-range-' + processFilterProperty.key" />
<mat-date-range-picker #picker (closed)="onDateRangeClosed()" />
</mat-form-field>
</ng-container>
@if (isDateRangeType()) {
<mat-form-field floatLabel="auto" class="adf-cloud-date-range-picker">
<mat-label>{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE_TITLE' | translate }}</mat-label>
<mat-date-range-input [formGroup]="dateRangeForm" [rangePicker]="picker">
<input matStartDate formControlName="from" placeholder="{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.START_DATE' | translate }}">
<input matEndDate formControlName="to" placeholder="{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.END_DATE' | translate }}">
</mat-date-range-input>
<mat-datepicker-toggle
matSuffix
[for]="picker"
[attr.data-automation-id]="'adf-cloud-edit-process-property-date-range-' + processFilterProperty.key" />
<mat-date-range-picker #picker (closed)="onDateRangeClosed()" />
</mat-form-field>
}
@@ -23,7 +23,7 @@ import { DateRangeFilter, DateCloudFilterType } from '../../models/date-cloud-fi
import { endOfDay, isValid, startOfDay } from 'date-fns';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import { ADF_DATE_FORMATS, AdfDateFnsAdapter } from '@alfresco/adf-core';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -35,7 +35,7 @@ interface DateRangeFormProps {
@Component({
selector: 'adf-cloud-date-range-filter',
imports: [CommonModule, TranslatePipe, MatDatepickerModule, MatFormFieldModule, ReactiveFormsModule, MatSelectModule],
imports: [TranslatePipe, MatDatepickerModule, MatFormFieldModule, ReactiveFormsModule, MatSelectModule],
styleUrls: ['./date-range-filter.component.scss'],
templateUrl: './date-range-filter.component.html',
providers: [
@@ -1,107 +1,126 @@
<div *ngIf="!hasForm()">
@if (!hasForm()) {
<div>
<ng-content select="[empty-form]" />
</div>
</div>
}
<div
*ngIf="hasForm()"
@if (hasForm()) {
<div
class="adf-cloud-form-container adf-cloud-form-{{ displayConfiguration?.options?.fullscreen ? 'fullscreen' : 'inline' }}-container"
[style]="formStyle"
>
>
<div
class="adf-cloud-form-content"
[class.adf-cloud-form-content-standalone-fullscreen]="displayMode === 'standalone' && displayConfiguration?.options?.fullscreen"
[class.adf-cloud-form-content-toolbar]="!!displayConfiguration?.options?.displayToolbar"
[cdkTrapFocus]="displayConfiguration?.options?.trapFocus"
cdkTrapFocusAutoCapture>
<adf-toolbar class="adf-cloud-form-toolbar" *ngIf="displayConfiguration?.options?.displayToolbar">
<div class="adf-cloud-form__form-title">
<span class="adf-cloud-form__display-name" [title]="form.taskName">
{{ form.taskName }}
<ng-container *ngIf="!form.taskName">
{{ 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
</ng-container>
</span>
</div>
<adf-toolbar-divider *ngIf="displayConfiguration?.options?.displayCloseButton" />
class="adf-cloud-form-content"
[class.adf-cloud-form-content-standalone-fullscreen]="displayMode === 'standalone' && displayConfiguration?.options?.fullscreen"
[class.adf-cloud-form-content-toolbar]="!!displayConfiguration?.options?.displayToolbar"
[cdkTrapFocus]="displayConfiguration?.options?.trapFocus"
cdkTrapFocusAutoCapture>
@if (displayConfiguration?.options?.displayToolbar) {
<adf-toolbar class="adf-cloud-form-toolbar">
<div class="adf-cloud-form__form-title">
<span class="adf-cloud-form__display-name" [title]="form.taskName">
{{ form.taskName }}
@if (!form.taskName) {
{{ 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
}
</span>
</div>
@if (displayConfiguration?.options?.displayCloseButton) {
<adf-toolbar-divider />
}
@if (displayConfiguration?.options?.displayCloseButton) {
<button
*ngIf="displayConfiguration?.options?.displayCloseButton"
class="adf-cloud-form-close-button"
data-automation-id="adf-toolbar-right-back"
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
[attr.data-automation-id]="'adf-cloud-form-close-button'"
[title]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
mat-icon-button
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}"
(click)="switchToDisplayMode()"
>
<mat-icon adf-icon="close" />
class="adf-cloud-form-close-button"
data-automation-id="adf-toolbar-right-back"
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
[attr.data-automation-id]="'adf-cloud-form-close-button'"
[title]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
mat-icon-button
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}"
(click)="switchToDisplayMode()"
>
<mat-icon adf-icon="close" />
</button>
}
</adf-toolbar>
<mat-card
appearance="outlined"
class="adf-cloud-form-content-card"
[class.adf-cloud-form-content-card-fullscreen]="displayMode === 'fullScreen'"
[class.adf-cloud-form-content-card-fullscreen-toolbar]="displayMode === 'fullScreen' && displayConfiguration?.options?.displayToolbar"
}
<mat-card
appearance="outlined"
class="adf-cloud-form-content-card"
[class.adf-cloud-form-content-card-fullscreen]="displayMode === 'fullScreen'"
[class.adf-cloud-form-content-card-fullscreen-toolbar]="displayMode === 'fullScreen' && displayConfiguration?.options?.displayToolbar"
>
<div class="adf-cloud-form-content-card-container">
<mat-card-header *ngIf="showTitle || showRefreshButton || showValidationIcon">
<mat-card-title>
<h4>
<div *ngIf="showValidationIcon" class="adf-form-validation-button">
<i id="adf-valid-form-icon" class="material-icons" *ngIf="form.isValid; else no_valid_form">check_circle</i>
<ng-template #no_valid_form>
<i id="adf-invalid-form-icon" class="material-icons adf-invalid-color">error</i>
</ng-template>
</div>
<div
*ngIf="!displayConfiguration?.options?.fullscreen && findDisplayConfiguration('fullScreen')"
class="adf-cloud-form-fullscreen-button"
>
<button
mat-icon-button
(click)="switchToDisplayMode('fullScreen')"
[attr.data-automation-id]="'adf-cloud-form-fullscreen-button'"
>
<mat-icon adf-icon="fullscreen" />
</button>
</div>
<div *ngIf="showRefreshButton" class="adf-cloud-form-reload-button" [title]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<button mat-icon-button (click)="onRefreshClicked()" [attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<mat-icon adf-icon="refresh" />
</button>
</div>
<span *ngIf="isTitleEnabled()" class="adf-cloud-form-title" [title]="form.taskName"
>{{ form.taskName }}
<ng-container *ngIf="!form.taskName">
{{ 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
</ng-container>
</span>
</h4>
</mat-card-title>
</mat-card-header>
<mat-card-content class="adf-form-container-card-content">
<adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" />
</mat-card-content>
<mat-card-actions *ngIf="form.hasOutcomes()" class="adf-cloud-form-content-card-actions" align="end">
<ng-content select="adf-cloud-form-custom-outcomes" />
<ng-container *ngFor="let outcome of form.outcomes">
<button
*ngIf="outcome.isVisible"
[id]="'adf-form-' + outcome.name | formatSpace"
[color]="getColorForOutcome(outcome.name)"
mat-button
[disabled]="!isOutcomeButtonEnabled(outcome)"
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
class="adf-cloud-form-custom-outcome-button"
(click)="onOutcomeClicked(outcome)"
>
{{ getCustomOutcomeButtonText(outcome) || (outcome.name | translate | uppercase) }}
</button>
</ng-container>
</mat-card-actions>
</div>
</mat-card>
<div class="adf-cloud-form-content-card-container">
@if (showTitle || showRefreshButton || showValidationIcon) {
<mat-card-header>
<mat-card-title>
<h4>
@if (showValidationIcon) {
<div class="adf-form-validation-button">
@if (form.isValid) {
<i id="adf-valid-form-icon" class="material-icons">check_circle</i>
} @else {
<i id="adf-invalid-form-icon" class="material-icons adf-invalid-color">error</i>
}
</div>
}
@if (!displayConfiguration?.options?.fullscreen && findDisplayConfiguration('fullScreen')) {
<div
class="adf-cloud-form-fullscreen-button"
>
<button
mat-icon-button
(click)="switchToDisplayMode('fullScreen')"
[attr.data-automation-id]="'adf-cloud-form-fullscreen-button'"
>
<mat-icon adf-icon="fullscreen" />
</button>
</div>
}
@if (showRefreshButton) {
<div class="adf-cloud-form-reload-button" [title]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<button mat-icon-button (click)="onRefreshClicked()" [attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<mat-icon adf-icon="refresh" />
</button>
</div>
}
@if (isTitleEnabled()) {
<span class="adf-cloud-form-title" [title]="form.taskName"
>{{ form.taskName }}
@if (!form.taskName) {
{{ 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
}
</span>
}
</h4>
</mat-card-title>
</mat-card-header>
}
<mat-card-content class="adf-form-container-card-content">
<adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" />
</mat-card-content>
@if (form.hasOutcomes()) {
<mat-card-actions class="adf-cloud-form-content-card-actions" align="end">
<ng-content select="adf-cloud-form-custom-outcomes" />
@for (outcome of form.outcomes; track outcome) {
@if (outcome.isVisible) {
<button
[id]="'adf-form-' + outcome.name | formatSpace"
[color]="getColorForOutcome(outcome.name)"
mat-button
[disabled]="!isOutcomeButtonEnabled(outcome)"
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
class="adf-cloud-form-custom-outcome-button"
(click)="onOutcomeClicked(outcome)"
>
{{ getCustomOutcomeButtonText(outcome) || (outcome.name | translate | uppercase) }}
</button>
}
}
</mat-card-actions>
}
</div>
</mat-card>
</div>
</div>
</div>
}
@@ -1,46 +1,54 @@
<div class="adf-attach-file-widget-container">
<div class="adf-attach-widget {{field.className}}"
[class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id + '-label'">{{field.name}}
<span class="adf-asterisk" *ngIf="isRequired()">*</span>
</label>
<div class="adf-attach-widget-container" (focusout)="markAsTouched()">
<div class="adf-attach-widget__menu-upload" *ngIf="isUploadButtonVisible()">
<button
(click)="openSelectDialog()"
mat-raised-button
class="adf-attach-widget__menu-upload__button"
color="primary"
[id]="field.id"
[title]="field.tooltip">
{{ 'FORM.FIELD.ATTACH' | translate }}
<mat-icon class="adf-attach-widget__menu-upload__button__icon" [adf-icon]="getWidgetIcon()" />
</button>
</div>
<div class="adf-attach-widget {{field.className}}"
[class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id + '-label'">{{field.name}}
@if (isRequired()) {
<span class="adf-asterisk">*</span>
}
</label>
<div class="adf-attach-widget-container" (focusout)="markAsTouched()">
@if (isUploadButtonVisible()) {
<div class="adf-attach-widget__menu-upload">
<button
(click)="openSelectDialog()"
mat-raised-button
class="adf-attach-widget__menu-upload__button"
color="primary"
[id]="field.id"
[title]="field.tooltip">
{{ 'FORM.FIELD.ATTACH' | translate }}
<mat-icon class="adf-attach-widget__menu-upload__button__icon" [adf-icon]="getWidgetIcon()" />
</button>
</div>
}
</div>
</div>
<div data-automation-id="adf-attach-widget-readonly-list" class="adf-attach-widget-readonly-table">
<adf-cloud-file-properties-table
[uploadedFiles]="uploadedFiles"
[hasFile]="hasFile"
[selectedNode]="selectedNode"
[field]="field"
[displayedColumns]="displayedColumns"
[mimeTypeIcon]="mimeTypeIcon"
(rowClick)="onRowClicked($event)"
(attachFileClick)="onAttachFileClicked($event)"
(downloadFile)="downloadContent($event)"
(uploadNewFileVersion)="onUploadNewFileVersion($event)"
(contentModelFileHandler)="contentModelFormFileHandler($event)"
(removeAttachFile)="onRemoveAttachFile($event)"
/>
<div *ngIf="!hasFile && field.readOnly" id="{{'adf-attach-empty-list-'+field.id}}">
{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}
</div>
<div data-automation-id="adf-attach-widget-readonly-list" class="adf-attach-widget-readonly-table">
<adf-cloud-file-properties-table
[uploadedFiles]="uploadedFiles"
[hasFile]="hasFile"
[selectedNode]="selectedNode"
[field]="field"
[displayedColumns]="displayedColumns"
[mimeTypeIcon]="mimeTypeIcon"
(rowClick)="onRowClicked($event)"
(attachFileClick)="onAttachFileClicked($event)"
(downloadFile)="downloadContent($event)"
(uploadNewFileVersion)="onUploadNewFileVersion($event)"
(contentModelFileHandler)="contentModelFormFileHandler($event)"
(removeAttachFile)="onRemoveAttachFile($event)"
/>
@if (!hasFile && field.readOnly) {
<div id="{{'adf-attach-empty-list-'+field.id}}">
{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}
</div>
}
</div>
</div>
<error-widget [error]="field.validationSummary" />
<error-widget *ngIf="!field.isValid && isTouched() && !isSelected()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
<error-widget [error]="field.validationSummary" />
@if (!field.isValid && isTouched() && !isSelected()) {
<error-widget required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
}
</div>
@@ -39,7 +39,7 @@ import {
NewVersionUploaderService,
VersionManagerUploadData
} from '@alfresco/adf-content-services';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { FilePropertiesTableCloudComponent } from './file-properties-table/file-properties-table-cloud.component';
import { MatButtonModule } from '@angular/material/button';
@@ -52,7 +52,7 @@ const VALID_ALIAS = [ALIAS_ROOT_FOLDER, ALIAS_USER_FOLDER, '-shared-'];
@Component({
selector: 'adf-cloud-attach-file-cloud-widget',
imports: [CommonModule, ErrorWidgetComponent, TranslatePipe, IconModule, FilePropertiesTableCloudComponent, MatButtonModule],
imports: [ErrorWidgetComponent, TranslatePipe, IconModule, FilePropertiesTableCloudComponent, MatButtonModule],
templateUrl: './attach-file-cloud-widget.component.html',
styleUrls: ['./attach-file-cloud-widget.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,91 +1,106 @@
<div class="adf-file-properties-table-container">
<table mat-table [dataSource]="uploadedFiles" class="adf-properties-table adf-file-properties-table mat-elevation-z0" *ngIf="hasFile">
<ng-container matColumnDef="icon">
<th mat-header-cell *matHeaderCellDef></th>
<td class="adf-file-properties-table-cell" mat-cell *matCellDef="let element">
<mat-icon matListItemLine class="adf-datatable-selected" *ngIf="selectedNode && element.id === selectedNode.id" (click)="onRowClicked(element)" adf-icon="check_circle" />
<img matListItemLine class="adf-attach-widget__icon"
*ngIf="!selectedNode || element.id !== selectedNode.id" [id]="'file-'+element?.id+'-icon'"
(click)="onRowClicked(element)"
(keyup.enter)="onRowClicked(element)"
[src]="element.content ? getIcon(element.content.mimeType) : getIcon(element['mimeType'])"
[alt]="mimeTypeIcon" role="button" tabindex="0" />
</td>
@if (hasFile) {
<table mat-table [dataSource]="uploadedFiles" class="adf-properties-table adf-file-properties-table mat-elevation-z0">
<ng-container matColumnDef="icon">
<th mat-header-cell *matHeaderCellDef></th>
<td class="adf-file-properties-table-cell" mat-cell *matCellDef="let element">
@if (selectedNode && element.id === selectedNode.id) {
<mat-icon matListItemLine class="adf-datatable-selected" (click)="onRowClicked(element)" adf-icon="check_circle" />
}
@if (!selectedNode || element.id !== selectedNode.id) {
<img matListItemLine class="adf-attach-widget__icon"
[id]="'file-'+element?.id+'-icon'"
(click)="onRowClicked(element)"
(keyup.enter)="onRowClicked(element)"
[src]="element.content ? getIcon(element.content.mimeType) : getIcon(element['mimeType'])"
[alt]="mimeTypeIcon" role="button" tabindex="0" />
}
</td>
</ng-container>
<ng-container matColumnDef="fileName">
<th mat-header-cell *matHeaderCellDef>{{ 'FORM.FIELD.FILE_NAME' | translate }}</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let element">
<span matLine id="{{'file-'+element?.id}}"
role="button"
tabindex="0"
class="adf-file"
(keyup.enter)="onAttachFileClicked(element)"
(click)="onAttachFileClicked(element)"
>{{ element.name }}</span>
</td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef>{{ 'FORM.FIELD.TITLE' | translate }}</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let element">{{ element.title }}</td>
</ng-container>
@for (prop of field?.params?.displayableCMProperties; track prop) {
<ng-container [matColumnDef]="prop.name">
<th mat-header-cell *matHeaderCellDef>{{prop.title ? prop.title : prop.name | titlecase }}</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let row">
<span matLine id="{{'fileProperty-'+row?.id+'-'+prop?.name}}" role="button" tabindex="0"
(keyup.enter)="onRowClicked(row)"
(click)="onRowClicked(row)">{{ getColumnValue(row, prop) }}</span>
</td>
</ng-container>
<ng-container matColumnDef="fileName">
<th mat-header-cell *matHeaderCellDef>{{ 'FORM.FIELD.FILE_NAME' | translate }}</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let element">
<span matLine id="{{'file-'+element?.id}}"
role="button"
tabindex="0"
class="adf-file"
(keyup.enter)="onAttachFileClicked(element)"
(click)="onAttachFileClicked(element)"
>{{ element.name }}</span>
</td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef>{{ 'FORM.FIELD.TITLE' | translate }}</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let element">{{ element.title }}</td>
</ng-container>
<ng-container *ngFor="let prop of field?.params?.displayableCMProperties" [matColumnDef]="prop.name">
<th mat-header-cell *matHeaderCellDef>{{prop.title ? prop.title : prop.name | titlecase }}</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let row">
<span matLine id="{{'fileProperty-'+row?.id+'-'+prop?.name}}" role="button" tabindex="0"
(keyup.enter)="onRowClicked(row)"
(click)="onRowClicked(row)">{{ getColumnValue(row, prop) }}</span>
</td>
</ng-container>
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let element">
<button id="{{'file-'+element?.id+'-option-menu'}}" mat-icon-button [matMenuTriggerFor]="fileActionMenu"
*ngIf="!!element.content?.mimeType"
[attr.aria-label]="'ADF_PROCESS_LIST.DETAILS.BUTTON.FILE_OPTION_MENU' | translate">
<mat-icon adf-icon="more_vert" />
}
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let element">
@if (!!element.content?.mimeType) {
<button id="{{'file-'+element?.id+'-option-menu'}}" mat-icon-button [matMenuTriggerFor]="fileActionMenu"
[attr.aria-label]="'ADF_PROCESS_LIST.DETAILS.BUTTON.FILE_OPTION_MENU' | translate">
<mat-icon adf-icon="more_vert" />
</button>
}
<mat-menu #fileActionMenu="matMenu" xPosition="before">
@if (displayMenuOption('show') && !!element.content?.mimeType) {
<button
id="{{'file-'+element?.id+'-show-file'}}" mat-menu-item
(click)="onAttachFileClicked(element)">
<mat-icon adf-icon="visibility" />
<span>{{ 'FORM.FIELD.VIEW_FILE' | translate }}</span>
</button>
}
@if (displayMenuOption('download') && !!element.content?.mimeType) {
<button
id="{{'file-'+element?.id+'-download-file'}}" mat-menu-item
(click)="downloadContent(element)">
<mat-icon adf-icon="file_download" />
<span>{{ 'FORM.FIELD.DOWNLOAD_FILE' | translate }}</span>
</button>
}
@if (displayMenuOption('retrieveMetadata') && !!element.content?.mimeType) {
<button
id="{{'file-'+element?.id+'-retrieve-file-metadata'}}" mat-menu-item
(click)="contentModelFormFileHandler(element)">
<mat-icon class="mat-24" adf-icon="low_priority" />
<span>{{ 'ADF_CLOUD_FORM_COMPONENT.RETRIEVE_METADATA' | translate }}</span>
</button>
}
@if (!field.readOnly && displayMenuOption('remove')) {
<button
mat-menu-item
[id]="'file-'+element?.id+'-remove'"
(click)="onRemoveAttachFile(element);" (keyup.enter)="onRemoveAttachFile(element);">
<mat-icon class="mat-24" adf-icon="highlight_off" />
<span>{{ 'FORM.FIELD.REMOVE_FILE' | translate }}</span>
</button>
}
@if (displayMenuOption('newVersion')) {
<div>
<button [adf-upload]="true" [mode]="['click']"
(upload-files)="onUploadNewFileVersion($event, element);"
id="{{'file-'+ element?.id +'-upload-new-version'}}" mat-menu-item>
<mat-icon class="mat-24" adf-icon="file_upload" />
<span>{{ 'ADF_VERSION_LIST.ACTIONS.UPLOAD.TITLE' | translate }}</span>
</button>
<mat-menu #fileActionMenu="matMenu" xPosition="before">
<button *ngIf="displayMenuOption('show') && !!element.content?.mimeType"
id="{{'file-'+element?.id+'-show-file'}}" mat-menu-item
(click)="onAttachFileClicked(element)">
<mat-icon adf-icon="visibility" />
<span>{{ 'FORM.FIELD.VIEW_FILE' | translate }}</span>
</button>
<button *ngIf="displayMenuOption('download') && !!element.content?.mimeType"
id="{{'file-'+element?.id+'-download-file'}}" mat-menu-item
(click)="downloadContent(element)">
<mat-icon adf-icon="file_download" />
<span>{{ 'FORM.FIELD.DOWNLOAD_FILE' | translate }}</span>
</button>
<button *ngIf="displayMenuOption('retrieveMetadata') && !!element.content?.mimeType"
id="{{'file-'+element?.id+'-retrieve-file-metadata'}}" mat-menu-item
(click)="contentModelFormFileHandler(element)">
<mat-icon class="mat-24" adf-icon="low_priority" />
<span>{{ 'ADF_CLOUD_FORM_COMPONENT.RETRIEVE_METADATA' | translate }}</span>
</button>
<button *ngIf="!field.readOnly && displayMenuOption('remove')"
mat-menu-item
[id]="'file-'+element?.id+'-remove'"
(click)="onRemoveAttachFile(element);" (keyup.enter)="onRemoveAttachFile(element);">
<mat-icon class="mat-24" adf-icon="highlight_off" />
<span>{{ 'FORM.FIELD.REMOVE_FILE' | translate }}</span>
</button>
<div *ngIf="displayMenuOption('newVersion')">
<button [adf-upload]="true" [mode]="['click']"
(upload-files)="onUploadNewFileVersion($event, element);"
id="{{'file-'+ element?.id +'-upload-new-version'}}" mat-menu-item>
<mat-icon class="mat-24" adf-icon="file_upload" />
<span>{{ 'ADF_VERSION_LIST.ACTIONS.UPLOAD.TITLE' | translate }}</span>
</button>
</div>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row class="adf-file-properties-table-header-row" *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</div>
}
</mat-menu>
</td>
</ng-container>
<tr mat-header-row class="adf-file-properties-table-header-row" *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
}
</div>
@@ -1,31 +1,31 @@
<div class="adf-data-table-widget-container">
<div class="adf-data-table-widget-label">
<label
class="adf-label"
[class.adf-left-label]="field.leftLabels"
[attr.for]="field.id">
{{field.name | translate }}
</label>
</div>
<div class="adf-data-table-widget-label">
<label
class="adf-label"
[class.adf-left-label]="field.leftLabels"
[attr.for]="field.id">
{{field.name | translate }}
</label>
</div>
<ng-container *ngIf="!previewState; else previewTemplate">
<adf-datatable data-automation-id="adf-data-table-widget" [data]="dataSource">
<adf-no-content-template>
<ng-template>
<adf-empty-content
icon="border_all"
[title]="'FORM.FIELD.DATA_TABLE_EMPTY_CONTENT' | translate" />
</ng-template>
</adf-no-content-template>
</adf-datatable>
@if (!previewState) {
<adf-datatable data-automation-id="adf-data-table-widget" [data]="dataSource">
<adf-no-content-template>
<ng-template>
<adf-empty-content
icon="border_all"
[title]="'FORM.FIELD.DATA_TABLE_EMPTY_CONTENT' | translate" />
</ng-template>
</adf-no-content-template>
</adf-datatable>
@if (dataTableLoadFailed) {
<error-widget
class="adf-data-table-widget-failed-message"
[required]="'FORM.FIELD.DATA_TABLE_LOAD_FAILED' | translate" />
}
} @else {
<adf-datatable data-automation-id="adf-data-table-widget-preview" />
<div class="adf-preview-placeholder"></div>
}
<error-widget *ngIf="dataTableLoadFailed"
class="adf-data-table-widget-failed-message"
[required]="'FORM.FIELD.DATA_TABLE_LOAD_FAILED' | translate" />
</ng-container>
<ng-template #previewTemplate>
<adf-datatable data-automation-id="adf-data-table-widget-preview" />
<div class="adf-preview-placeholder"></div>
</ng-template>
</div>
@@ -27,7 +27,7 @@ import {
NoContentTemplateDirective,
EmptyContentComponent
} from '@alfresco/adf-core';
import { NgIf } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { FormCloudService } from '../../../services/form-cloud.service';
import { TaskVariableCloud } from '../../../models/task-variable-cloud.model';
@@ -36,7 +36,7 @@ import { DataTablePathParserHelper } from './helpers/data-table-path-parser.help
@Component({
standalone: true,
imports: [NgIf, TranslatePipe, FormBaseModule, DataTableComponent, NoContentTemplateDirective, EmptyContentComponent],
imports: [TranslatePipe, FormBaseModule, DataTableComponent, NoContentTemplateDirective, EmptyContentComponent],
selector: 'data-table',
templateUrl: './data-table.widget.html',
styleUrls: ['./data-table.widget.scss'],
@@ -1,42 +1,46 @@
<div
class="{{field.className}}"
id="data-widget"
[class.adf-invalid]="dateInputControl.invalid && dateInputControl.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
class="{{field.className}}"
id="data-widget"
[class.adf-invalid]="dateInputControl.invalid && dateInputControl.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>
}
<div class="adf-date-widget-container">
<mat-form-field class="adf-date-widget adf-form-field-input" [class.adf-left-label-input-datepicker]="field.leftLabels">
@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"
[matDatepicker]="datePicker"
[id]="field.id"
[formControl]="dateInputControl"
[placeholder]="field.placeholder"
[required]="field.required && field.isVisible"
[min]="minDate"
[max]="maxDate"
[title]="field.tooltip"
/>
<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>
<mat-form-field class="adf-date-widget adf-form-field-input" [class.adf-left-label-input-datepicker]="field.leftLabels">
@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"
[matDatepicker]="datePicker"
[id]="field.id"
[formControl]="dateInputControl"
[placeholder]="field.placeholder"
[required]="field.required && field.isVisible"
[min]="minDate"
[max]="maxDate"
[title]="field.tooltip"
/>
<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" />
}
</div>
</div>
</div>
</div>
@@ -33,7 +33,7 @@ import {
import { MatDatepickerModule } from '@angular/material/datepicker';
import { addDays, parseISO } from 'date-fns';
import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
import { NgIf } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
@@ -41,7 +41,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({
selector: 'date-widget',
imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, MatDatepickerModule, ReactiveFormsModule, ErrorWidgetComponent],
imports: [TranslatePipe, MatFormFieldModule, MatInputModule, MatDatepickerModule, ReactiveFormsModule, ErrorWidgetComponent],
providers: [
{ provide: MAT_DATE_FORMATS, useValue: ADF_DATE_FORMATS },
{ provide: DateAdapter, useClass: AdfDateFnsAdapter }
@@ -1,42 +1,46 @@
<div
class="adf-textfield adf-display-external-property-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>
</div>
class="adf-textfield adf-display-external-property-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>
<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"
data-automation-id="adf-display-external-property-widget"
[id]="field.id"
[formControl]="propertyControl"
[required]="field.required"
/>
<ng-container *ngIf="previewState">
<span class="adf-display-external-property-widget-preview" data-automation-id="adf-display-external-property-widget-preview">
{{ field.params.externalPropertyLabel }}
</span>
</ng-container>
</mat-form-field>
<div
class="adf-error-messages-container"
[ngClass]="!previewState ? 'adf-error-messages-container-visible' : 'adf-error-messages-container-hidden'"
>
<error-widget *ngIf="propertyLoadFailed" [required]="'FORM.FIELD.EXTERNAL_PROPERTY_LOAD_FAILED' | translate" />
</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>
<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"
data-automation-id="adf-display-external-property-widget"
[id]="field.id"
[formControl]="propertyControl"
[required]="field.required"
/>
@if (previewState) {
<span class="adf-display-external-property-widget-preview" data-automation-id="adf-display-external-property-widget-preview">
{{ field.params.externalPropertyLabel }}
</span>
}
</mat-form-field>
<div
class="adf-error-messages-container"
[ngClass]="!previewState ? 'adf-error-messages-container-visible' : 'adf-error-messages-container-hidden'"
>
@if (propertyLoadFailed) {
<error-widget [required]="'FORM.FIELD.EXTERNAL_PROPERTY_LOAD_FAILED' | translate" />
}
</div>
</div>
</div>
@@ -1,34 +1,37 @@
<div
class="adf-dropdown-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
>
</div>
class="adf-dropdown-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>
<adf-cloud-group
[mode]="mode"
[title]="title"
[readOnly]="field.readOnly"
[validate]="validate"
[roles]="roles"
[searchGroupsControl]="search"
[required]="field.required"
(changedGroups)="onChangedGroup($event)"
[preSelectGroups]="preSelectGroup"
(blur)="markAsTouched()"
[attr.title]="field.tooltip"
[label] = "field.name | translate"
<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>
<adf-cloud-group
[mode]="mode"
[title]="title"
[readOnly]="field.readOnly"
[validate]="validate"
[roles]="roles"
[searchGroupsControl]="search"
[required]="field.required"
(changedGroups)="onChangedGroup($event)"
[preSelectGroups]="preSelectGroup"
(blur)="markAsTouched()"
[attr.title]="field.tooltip"
[label] = "field.name | translate"
/>
<error-widget [error]="field.validationSummary" />
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
class="adf-dropdown-required-message"
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
class="adf-dropdown-required-message"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
/>
}
</div>
</div>
</div>
@@ -22,7 +22,7 @@ import { filter } from 'rxjs/operators';
import { ComponentSelectionMode } from '../../../../types';
import { IdentityGroupModel } from '../../../../group/models/identity-group.model';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { GroupCloudComponent } from '../../../../group/components/group-cloud.component';
@@ -30,7 +30,7 @@ import { GroupCloudComponent } from '../../../../group/components/group-cloud.co
@Component({
selector: 'group-cloud-widget',
imports: [CommonModule, TranslatePipe, ErrorWidgetComponent, GroupCloudComponent],
imports: [TranslatePipe, ErrorWidgetComponent, GroupCloudComponent],
templateUrl: './group-cloud.widget.html',
host: {
'(click)': 'event($event)',
@@ -1,31 +1,34 @@
<div class="adf-dropdown-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>
</div>
[class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
@if (field.leftLabels) {
<div>
<adf-cloud-people
[preSelectUsers]="preSelectUsers"
[appName]="appName"
[readOnly]="field.readOnly"
[validate]="validate"
[searchUserCtrl]="search"
[required]="field.required"
(changedUsers)="onChangedUser($event)"
[roles]="roles"
[mode]="mode"
[groupsRestriction]="groupsRestriction"
(blur)="markAsTouched()"
[attr.title]="field.tooltip"
[label]="field.name | translate"
/>
<error-widget [error]="field.validationSummary" />
<error-widget
class="adf-dropdown-required-message"
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
<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>
<adf-cloud-people
[preSelectUsers]="preSelectUsers"
[appName]="appName"
[readOnly]="field.readOnly"
[validate]="validate"
[searchUserCtrl]="search"
[required]="field.required"
(changedUsers)="onChangedUser($event)"
[roles]="roles"
[mode]="mode"
[groupsRestriction]="groupsRestriction"
(blur)="markAsTouched()"
[attr.title]="field.tooltip"
[label]="field.name | translate"
/>
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired() && isTouched()) {
<error-widget
class="adf-dropdown-required-message"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
}
</div>
</div>
@@ -23,7 +23,7 @@ import { ComponentSelectionMode } from '../../../../types';
import { IdentityUserModel } from '../../../../people/models/identity-user.model';
import { IdentityUserService } from '../../../../people/services/identity-user.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { PeopleCloudComponent } from '../../../../people/components/people-cloud.component';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -32,7 +32,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
@Component({
selector: 'people-cloud-widget',
imports: [CommonModule, TranslatePipe, ErrorWidgetComponent, PeopleCloudComponent, MatFormFieldModule],
imports: [TranslatePipe, ErrorWidgetComponent, PeopleCloudComponent, MatFormFieldModule],
templateUrl: './people-cloud.widget.html',
host: {
'(click)': 'event($event)',
@@ -1,4 +1,5 @@
<adf-content-metadata
@if (!loading) {
<adf-content-metadata
[displayDefaultProperties]="displayDefaultProperties"
[expanded]="expanded"
[node]="node"
@@ -11,10 +12,9 @@
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
[displayTags]="false"
[displayCategories]="false"
*ngIf="!loading; else loadingTemplate"
/>
<ng-template #loadingTemplate>
<div class="adf-properties-viewer-wrapper-loading">
<mat-progress-spinner />
</div>
</ng-template>
/>
} @else {
<div class="adf-properties-viewer-wrapper-loading">
<mat-progress-spinner />
</div>
}
@@ -19,13 +19,13 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChange
import { PresetConfig, NodesApiService, ContentMetadataComponent } from '@alfresco/adf-content-services';
import { Node } from '@alfresco/js-api';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { CommonModule } from '@angular/common';
/* eslint-disable @angular-eslint/component-selector */
@Component({
selector: 'adf-properties-viewer-wrapper',
imports: [CommonModule, MatProgressSpinnerModule, ContentMetadataComponent],
imports: [MatProgressSpinnerModule, ContentMetadataComponent],
templateUrl: './properties-viewer-wrapper.component.html',
encapsulation: ViewEncapsulation.None
})
@@ -1,27 +1,28 @@
<div class="adf-file-viewer-widget {{field.className}}" [class.adf-invalid]="!field.isValid" [class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id"
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
<label class="adf-label" [attr.for]="field.id"
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
>
<ng-template
#properties
[ngTemplateOutlet]="properties"
let-properties="properties"
[ngTemplateOutletContext]="{ properties: field.params?.propertiesViewerOptions }"
>
#properties
[ngTemplateOutlet]="properties"
let-properties="properties"
[ngTemplateOutletContext]="{ properties: field.params?.propertiesViewerOptions }"
>
@if (field.value) {
<adf-properties-viewer-wrapper
*ngIf="field.value"
[nodeId]="field.value"
[displayDefaultProperties]="properties?.displayDefaultProperties !== undefined ? properties?.displayDefaultProperties : true"
[expanded]="properties?.expanded !== undefined ? properties?.expanded : true"
[preset]="properties?.preset"
[displayEmpty]="properties?.displayEmpty !== undefined ? properties?.displayEmpty : false"
[editable]="properties?.editable !== undefined ? properties?.editable : false"
[multi]="properties?.multi !== undefined ? properties?.multi : false"
[displayAspect]="properties?.displayAspect !== undefined ? properties?.displayAspect : null"
[copyToClipboardAction]="properties?.copyToClipboardAction !== undefined ? properties?.copyToClipboardAction : true"
[useChipsForMultiValueProperty]="properties?.useChipsForMultiValueProperty !== undefined ? properties?.useChipsForMultiValueProperty : true"
(nodeContentLoaded)="onNodeContentLoaded($event)"
/>
[nodeId]="field.value"
[displayDefaultProperties]="properties?.displayDefaultProperties !== undefined ? properties?.displayDefaultProperties : true"
[expanded]="properties?.expanded !== undefined ? properties?.expanded : true"
[preset]="properties?.preset"
[displayEmpty]="properties?.displayEmpty !== undefined ? properties?.displayEmpty : false"
[editable]="properties?.editable !== undefined ? properties?.editable : false"
[multi]="properties?.multi !== undefined ? properties?.multi : false"
[displayAspect]="properties?.displayAspect !== undefined ? properties?.displayAspect : null"
[copyToClipboardAction]="properties?.copyToClipboardAction !== undefined ? properties?.copyToClipboardAction : true"
[useChipsForMultiValueProperty]="properties?.useChipsForMultiValueProperty !== undefined ? properties?.useChipsForMultiValueProperty : true"
(nodeContentLoaded)="onNodeContentLoaded($event)"
/>
}
</ng-template>
<error-widget [error]="field.validationSummary" />
</div>
</div>
@@ -1,26 +1,28 @@
<div class="adf-radio-buttons-widget-cloud {{field.className}}"
[class.adf-readonly]="field.readOnly" [id]="field.id">
<div [ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-button-container': 'adf-radio-button-container-horizontal'">
<label class="adf-label"
[attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
<mat-radio-group
[ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-group': 'adf-radio-group-horizontal'"
class="adf-radio-group"
[(ngModel)]="field.value"
[disabled]="field.readOnly">
<mat-radio-button
[title]="field.tooltip"
[id]="field.id + '-' + opt.id"
[name]="field.id"
[value]="opt.id"
[checked]="isChecked(opt)"
(change)="onOptionClick(opt.id)"
color="primary"
class="adf-radio-button" *ngFor="let opt of field.options" >
{{opt.name}}
</mat-radio-button>
</mat-radio-group>
</div>
<error-widget class="adf-radio-group-error-message" [error]="hasError()" />
[class.adf-readonly]="field.readOnly" [id]="field.id">
<div [ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-button-container': 'adf-radio-button-container-horizontal'">
<label class="adf-label"
[attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</label>
<mat-radio-group
[ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-group': 'adf-radio-group-horizontal'"
class="adf-radio-group"
[(ngModel)]="field.value"
[disabled]="field.readOnly">
@for (opt of field.options; track opt) {
<mat-radio-button
[title]="field.tooltip"
[id]="field.id + '-' + opt.id"
[name]="field.id"
[value]="opt.id"
[checked]="isChecked(opt)"
(change)="onOptionClick(opt.id)"
color="primary"
class="adf-radio-button" >
{{opt.name}}
</mat-radio-button>
}
</mat-radio-group>
</div>
<error-widget class="adf-radio-group-error-message" [error]="hasError()" />
</div>
@@ -1,54 +1,65 @@
<div class="adf-upload-widget {{field.className}}" [class.adf-invalid]="!field.isValid" [class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id"
>{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
<label class="adf-label" [attr.for]="field.id"
>{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
>
<div class="adf-cloud-upload-widget-container">
<div>
<mat-list *ngIf="hasFile">
<mat-list-item class="adf-upload-files-row" *ngFor="let file of uploadedFiles">
<img
matListItemLine
class="adf-upload-widget__icon"
[id]="'file-'+file.id+'-icon'"
[src]="getIcon(file.content.mimeType)"
[alt]="mimeTypeIcon"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
role="button"
tabindex="0"
/>
<span
class="adf-upload-widget__button adf-file"
matLine
id="{{'file-'+file.id}}"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
role="button"
tabindex="0"
>{{file.name}}</span
>
<div>
@if (hasFile) {
<mat-list>
@for (file of uploadedFiles; track file) {
<mat-list-item class="adf-upload-files-row">
<img
matListItemLine
class="adf-upload-widget__icon"
[id]="'file-'+file.id+'-icon'"
[src]="getIcon(file.content.mimeType)"
[alt]="mimeTypeIcon"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
role="button"
tabindex="0"
/>
<span
class="adf-upload-widget__button adf-file"
matLine
id="{{'file-'+file.id}}"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
role="button"
tabindex="0"
>{{file.name}}</span
>
@if (!field.readOnly) {
<button
*ngIf="!field.readOnly"
mat-icon-button
[id]="'file-'+file.id+'-remove'"
(click)="removeFile(file);"
(keyup.enter)="removeFile(file);"
>
<mat-icon class="mat-24" adf-icon="highlight_off" />
mat-icon-button
[id]="'file-'+file.id+'-remove'"
(click)="removeFile(file);"
(keyup.enter)="removeFile(file);"
>
<mat-icon class="mat-24" adf-icon="highlight_off" />
</button>
}
</mat-list-item>
}
</mat-list>
}
</div>
<div *ngIf="(!hasFile || multipleOption) && !field.readOnly">
@if ((!hasFile || multipleOption) && !field.readOnly) {
<div>
<button mat-raised-button color="primary" (click)="uploadFiles.click()" [title]="field.tooltip">
{{ 'FORM.FIELD.UPLOAD' | translate }}<mat-icon adf-icon="file_upload" />
<input #uploadFiles [multiple]="multipleOption" type="file" [id]="field.form.nodeId" (change)="onFileChanged($event)" />
{{ 'FORM.FIELD.UPLOAD' | translate }}<mat-icon adf-icon="file_upload" />
<input #uploadFiles [multiple]="multipleOption" type="file" [id]="field.form.nodeId" (change)="onFileChanged($event)" />
</button>
</div>
</div>
}
<div *ngIf="!hasFile && field.readOnly">{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}</div>
@if (!hasFile && field.readOnly) {
<div>{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}</div>
}
</div>
<error-widget [error]="field.validationSummary" />
@if (isInvalidFieldRequired()) {
<error-widget required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
}
</div>
<error-widget [error]="field.validationSummary" />
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
</div>
@@ -25,7 +25,7 @@ import { WidgetComponent, ThumbnailService, NotificationService, ErrorWidgetComp
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
import { FileSourceTypes, DestinationFolderPathType } from '../../../models/form-cloud-representation.model';
import { VersionManagerUploadData } from '@alfresco/adf-content-services';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { MatListModule } from '@angular/material/list';
@@ -33,7 +33,7 @@ import { MatLineModule } from '@angular/material/core';
@Component({
selector: 'upload-cloud-widget',
imports: [CommonModule, TranslatePipe, ErrorWidgetComponent, IconModule, MatButtonModule, MatListModule, MatLineModule],
imports: [TranslatePipe, ErrorWidgetComponent, IconModule, MatButtonModule, MatListModule, MatLineModule],
templateUrl: './upload-cloud.widget.html',
styleUrls: ['./upload-cloud.widget.scss'],
host: {
@@ -1,86 +1,106 @@
<form>
<mat-form-field class="adf-cloud-group adf-form-field-input" [class.adf-invalid]="hasError() && isDirty()">
@if (label || required) { <mat-label><span>{{label}}</span></mat-label> }
<mat-chip-grid [required]="required" #groupChipList data-automation-id="adf-cloud-group-chip-list">
<mat-chip-row
*ngFor="let group of selectedGroups"
[removable]="!(group.readonly)"
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
(removed)="onRemove(group)"
[disabled]="readOnly || isValidationLoading()"
title="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}">
{{group.name}}
<mat-icon *ngIf="!(group.readonly || readOnly)" matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name" adf-icon="cancel" />
</mat-chip-row>
<input [disabled]="readOnly || isValidationLoading()" matInput
[formControl]="searchGroupsControl"
[matAutocomplete]="auto"
[matChipInputFor]="groupChipList"
[placeholder]="title | translate"
[required]="required"
(focus)="setFocus(true)"
(blur)="setFocus(false); markAsTouched()"
class="adf-group-input"
data-automation-id="adf-cloud-group-search-input" #groupInput>
</mat-chip-grid>
<mat-form-field class="adf-cloud-group adf-form-field-input" [class.adf-invalid]="hasError() && isDirty()">
@if (label || required) { <mat-label><span>{{label}}</span></mat-label> }
<mat-chip-grid [required]="required" #groupChipList data-automation-id="adf-cloud-group-chip-list">
@for (group of selectedGroups; track group) {
<mat-chip-row
[removable]="!(group.readonly)"
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
(removed)="onRemove(group)"
[disabled]="readOnly || isValidationLoading()"
title="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}">
{{group.name}}
@if (!(group.readonly || readOnly)) {
<mat-icon matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name" adf-icon="cancel" />
}
</mat-chip-row>
}
<input [disabled]="readOnly || isValidationLoading()" matInput
[formControl]="searchGroupsControl"
[matAutocomplete]="auto"
[matChipInputFor]="groupChipList"
[placeholder]="title | translate"
[required]="required"
(focus)="setFocus(true)"
(blur)="setFocus(false); markAsTouched()"
class="adf-group-input"
data-automation-id="adf-cloud-group-search-input" #groupInput>
</mat-chip-grid>
<mat-autocomplete
autoActiveFirstOption
#auto="matAutocomplete"
class="adf-cloud-group-list"
(optionSelected)="onSelect($event.option.value)"
[displayWith]="getDisplayName"
data-automation-id="adf-cloud-group-autocomplete">
<ng-container *ngIf="(searchGroups$ | async)?.length else noResults">
<mat-option *ngFor="let group of searchGroups$ | async; let i = index" [value]="group"
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
class="adf-cloud-group-option-active">
<div
class="adf-cloud-group-row"
id="adf-group-{{i}}"
data-automation-id="adf-cloud-group-row">
<button class="adf-group-short-name" mat-fab>{{getGroupNameInitials(group)}}</button>
<span>{{group.name}}</span>
</div>
</mat-option>
</ng-container>
<ng-template #noResults>
<mat-option *ngIf="searchGroupsControl.hasError('searchTypingError') && !searchLoading" disabled
class="adf-cloud-group-option-not-active"
data-automation-id="adf-cloud-group-no-results">
<span> {{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</span>
</mat-option>
</ng-template>
</mat-autocomplete>
</mat-form-field>
<mat-progress-bar *ngIf="validationLoading" mode="indeterminate" />
<mat-autocomplete
autoActiveFirstOption
#auto="matAutocomplete"
class="adf-cloud-group-list"
(optionSelected)="onSelect($event.option.value)"
[displayWith]="getDisplayName"
data-automation-id="adf-cloud-group-autocomplete">
@if ((searchGroups$ | async)?.length) {
@for (group of searchGroups$ | async; track group; let i = $index) {
<mat-option [value]="group"
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
class="adf-cloud-group-option-active">
<div
class="adf-cloud-group-row"
id="adf-group-{{i}}"
data-automation-id="adf-cloud-group-row">
<button class="adf-group-short-name" mat-fab>{{getGroupNameInitials(group)}}</button>
<span>{{group.name}}</span>
</div>
</mat-option>
}
} @else {
@if (searchGroupsControl.hasError('searchTypingError') && !searchLoading) {
<mat-option disabled
class="adf-cloud-group-option-not-active"
data-automation-id="adf-cloud-group-no-results">
<span> {{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</span>
</mat-option>
}
}
</mat-autocomplete>
</mat-form-field>
@if (validationLoading) {
<mat-progress-bar mode="indeterminate" />
}
<div class="adf-error-container adf-error-messages-container">
<mat-error *ngIf="hasPreselectError() && !isValidationLoading()" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
</mat-error>
<mat-error *ngIf="searchGroupsControl.hasError('pattern')" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}</div>
</mat-error>
<mat-error *ngIf="searchGroupsControl.hasError('maxlength')" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}</div>
</mat-error>
<mat-error *ngIf="searchGroupsControl.hasError('minlength')" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}</div>
</mat-error>
<mat-error *ngIf="(searchGroupsControl.hasError('required') || groupChipsCtrl.hasError('required')) && isDirty()"
[@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }} </div>
</mat-error>
<mat-error *ngIf="searchGroupsControl.hasError('searchTypingError') && !this.isFocused"
data-automation-id="invalid-groups-typing-error" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
</mat-error>
</div>
<div class="adf-error-container adf-error-messages-container">
@if (hasPreselectError() && !isValidationLoading()) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
</mat-error>
}
@if (searchGroupsControl.hasError('pattern')) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}</div>
</mat-error>
}
@if (searchGroupsControl.hasError('maxlength')) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}</div>
</mat-error>
}
@if (searchGroupsControl.hasError('minlength')) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}</div>
</mat-error>
}
@if ((searchGroupsControl.hasError('required') || groupChipsCtrl.hasError('required')) && isDirty()) {
<mat-error
[@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }} </div>
</mat-error>
}
@if (searchGroupsControl.hasError('searchTypingError') && !this.isFocused) {
<mat-error
data-automation-id="invalid-groups-typing-error" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
</mat-error>
}
</div>
</form>
@@ -1,111 +1,134 @@
<form>
<mat-form-field
[subscriptSizing]="formFieldSubscriptSizing"
class="adf-people-cloud adf-form-field-input"
[class.adf-invalid]="hasError() && isDirty()"
<mat-form-field
[subscriptSizing]="formFieldSubscriptSizing"
class="adf-people-cloud adf-form-field-input"
[class.adf-invalid]="hasError() && isDirty()"
>
<mat-label *ngIf="!title">
<span>{{label}}</span>
</mat-label>
<mat-label *ngIf="title">{{ title | translate }}</mat-label>
@if (!title) {
<mat-label>
<span>{{label}}</span>
</mat-label>
}
@if (title) {
<mat-label>{{ title | translate }}</mat-label>
}
<mat-chip-grid [required]="required" #userMultipleChipList data-automation-id="adf-cloud-people-chip-list">
<mat-chip-row
*ngFor="let user of selectedUsers"
[removable]="!user.readonly"
[attr.data-automation-id]="'adf-people-cloud-chip-' + user.username"
(removed)="onRemove(user)"
[disabled]="isReadonly() || isValidationLoading()"
title="{{ (user.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"
[matTooltip]="showFullNameOnHover ? (user | fullName : true) : user.email"
<mat-chip-grid [required]="required" #userMultipleChipList data-automation-id="adf-cloud-people-chip-list">
@for (user of selectedUsers; track user) {
<mat-chip-row
[removable]="!user.readonly"
[attr.data-automation-id]="'adf-people-cloud-chip-' + user.username"
(removed)="onRemove(user)"
[disabled]="isReadonly() || isValidationLoading()"
title="{{ (user.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"
[matTooltip]="showFullNameOnHover ? (user | fullName : true) : user.email"
>
{{ user | fullName }}
@if (!(user.readonly || readOnly)) {
<mat-icon matChipRemove [attr.data-automation-id]="'adf-people-cloud-chip-remove-icon-' + user.username" adf-icon="cancel" />
}
</mat-chip-row>
}
<input
matInput
[disabled]="isReadonly()"
[formControl]="searchUserCtrl"
[matAutocomplete]="auto"
[matChipInputFor]="userMultipleChipList"
[required]="required"
[placeholder]="placeholder"
[disabled]="isReadonly() || isValidationLoading()"
(focus)="setFocus(true)"
(blur)="setFocus(false); markAsTouched()"
class="adf-cloud-input"
data-automation-id="adf-people-cloud-search-input"
#userInput
/>
</mat-chip-grid>
<mat-autocomplete
autoActiveFirstOption
class="adf-people-cloud-list"
#auto="matAutocomplete"
(optionSelected)="onSelect($event.option.value)"
[displayWith]="getDisplayName"
>
@if ((searchUsers$ | async)?.length) {
@for (user of searchUsers$ | async; track user; let i = $index) {
<mat-option [value]="user" class="adf-people-cloud-option-active">
<div class="adf-people-cloud-row" id="adf-people-cloud-user-{{ user.username }}" data-automation-id="adf-people-cloud-row">
<div [outerHTML]="user | usernameInitials : 'adf-people-cloud-pic'"></div>
<span class="adf-people-label-name"> {{ user | fullName : true }}</span>
</div>
</mat-option>
}
} @else {
@if (searchUserCtrl.hasError('searchTypingError') && !searchLoading) {
<mat-option
disabled
class="adf-people-cloud-option-not-active"
data-automation-id="adf-people-cloud-no-results"
>
{{ user | fullName }}
<mat-icon matChipRemove *ngIf="!(user.readonly || readOnly)" [attr.data-automation-id]="'adf-people-cloud-chip-remove-icon-' + user.username" adf-icon="cancel" />
</mat-chip-row>
<input
matInput
[disabled]="isReadonly()"
[formControl]="searchUserCtrl"
[matAutocomplete]="auto"
[matChipInputFor]="userMultipleChipList"
[required]="required"
[placeholder]="placeholder"
[disabled]="isReadonly() || isValidationLoading()"
(focus)="setFocus(true)"
(blur)="setFocus(false); markAsTouched()"
class="adf-cloud-input"
data-automation-id="adf-people-cloud-search-input"
#userInput
/>
</mat-chip-grid>
<span> {{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: searchedValue } }}</span>
</mat-option>
}
}
</mat-autocomplete>
</mat-form-field>
<mat-autocomplete
autoActiveFirstOption
class="adf-people-cloud-list"
#auto="matAutocomplete"
(optionSelected)="onSelect($event.option.value)"
[displayWith]="getDisplayName"
>
<ng-container *ngIf="(searchUsers$ | async)?.length; else noResults">
<mat-option *ngFor="let user of searchUsers$ | async; let i = index" [value]="user" class="adf-people-cloud-option-active">
<div class="adf-people-cloud-row" id="adf-people-cloud-user-{{ user.username }}" data-automation-id="adf-people-cloud-row">
<div [outerHTML]="user | usernameInitials : 'adf-people-cloud-pic'"></div>
<span class="adf-people-label-name"> {{ user | fullName : true }}</span>
</div>
</mat-option>
</ng-container>
<ng-template #noResults>
<mat-option
*ngIf="searchUserCtrl.hasError('searchTypingError') && !searchLoading"
disabled
class="adf-people-cloud-option-not-active"
data-automation-id="adf-people-cloud-no-results"
>
<span> {{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: searchedValue } }}</span>
</mat-option>
</ng-template>
</mat-autocomplete>
</mat-form-field>
@if (validationLoading) {
<mat-progress-bar mode="indeterminate" />
}
<mat-progress-bar *ngIf="validationLoading" mode="indeterminate" />
<div class="adf-error-container adf-error-messages-container" *ngIf="showErrors">
<mat-error *ngIf="hasPreselectError() && !isValidationLoading()" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: validateUsersMessage } }}</div>
@if (showErrors) {
<div class="adf-error-container adf-error-messages-container">
@if (hasPreselectError() && !isValidationLoading()) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: validateUsersMessage } }}</div>
</mat-error>
<mat-error *ngIf="searchUserCtrl.hasError('pattern')" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate : { pattern: getValidationPattern() } }}</div>
}
@if (searchUserCtrl.hasError('pattern')) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate : { pattern: getValidationPattern() } }}</div>
</mat-error>
<mat-error *ngIf="searchUserCtrl.hasError('maxlength')" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate : { requiredLength: getValidationMaxLength() } }}
</div>
}
@if (searchUserCtrl.hasError('maxlength')) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate : { requiredLength: getValidationMaxLength() } }}
</div>
</mat-error>
<mat-error *ngIf="searchUserCtrl.hasError('minlength')" [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate : { requiredLength: getValidationMinLength() } }}
</div>
}
@if (searchUserCtrl.hasError('minlength')) {
<mat-error [@transitionMessages]="subscriptAnimationState" class="adf-error">
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate : { requiredLength: getValidationMinLength() } }}
</div>
</mat-error>
}
@if ((searchUserCtrl.hasError('required') || userChipsCtrl.hasError('required')) && isDirty()) {
<mat-error
*ngIf="(searchUserCtrl.hasError('required') || userChipsCtrl.hasError('required')) && isDirty()"
[@transitionMessages]="subscriptAnimationState"
class="adf-error"
>
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }}</div>
[@transitionMessages]="subscriptAnimationState"
class="adf-error"
>
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }}</div>
</mat-error>
}
@if (searchUserCtrl.hasError('searchTypingError') && !this.isFocused) {
<mat-error
*ngIf="searchUserCtrl.hasError('searchTypingError') && !this.isFocused"
[@transitionMessages]="subscriptAnimationState"
data-automation-id="invalid-users-typing-error"
class="adf-error"
>
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: searchedValue } }}</div>
[@transitionMessages]="subscriptAnimationState"
data-automation-id="invalid-users-typing-error"
class="adf-error"
>
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: searchedValue } }}</div>
</mat-error>
}
</div>
}
</form>
@@ -1,116 +1,143 @@
<mat-accordion [hideToggle]="isLoading" class="adf-edit-process-filter">
<mat-expansion-panel (afterExpand)="onExpand()" (closed)="onClose()">
<mat-expansion-panel-header *ngIf="processFilter" id="adf-edit-process-filter-expansion-header" class="adf-edit-process-filter-header">
<ng-container *ngIf="!isLoading; else loadingTemplate">
<mat-panel-title *ngIf="showProcessFilterName" id="adf-edit-process-filter-title-id" class="adf-edit-process-filter-header__title">
{{processFilter.name | translate}}</mat-panel-title>
<mat-panel-description class="adf-edit-process-filter-header__description" id="adf-edit-process-filter-sub-title-id">
<span *ngIf="showTitle"> {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}}</span>
<div *ngIf="showFilterActions" class="adf-cloud-edit-process-filter-actions">
<ng-container *ngIf="toggleFilterActions">
<button
*ngFor="let filterAction of processFilterActions"
mat-icon-button
[title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions($event, filterAction)"
>
@if (filterAction.icon.includes(':')) {
<mat-icon [svgIcon]="filterAction.icon" aria-hidden="true" />
} @else {
<mat-icon [adf-icon]="filterAction.icon" aria-hidden="true" />
}
</button>
</ng-container>
</div>
</mat-panel-description>
</ng-container>
<ng-template #loadingTemplate>
<div class="adf-cloud-edit-process-filter-loading-margin">
<mat-spinner [diameter]="30" />
</div>
</ng-template>
</mat-expansion-panel-header>
<ng-container *ngIf="!isLoading">
<form [formGroup]="editProcessFilterForm" *ngIf="editProcessFilterForm" class="adf-edit-process-filter-content">
<div class="adf-edit-process-filter-form">
<ng-container *ngFor="let processFilterProperty of processFilterProperties; trackBy: filterTracker">
<mat-form-field [floatLabel]="'auto'" *ngIf="processFilterProperty.type === 'select'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label class="adf-edit-process-filter-content__select-label">{{processFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="processFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
<mat-option
*ngFor="let propertyOption of processFilterProperty.options"
[value]="propertyOption.value"
[attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + processFilterProperty.key"
>{{ propertyOption.label | translate }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'" *ngIf="processFilterProperty.type === 'multi-select'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label class="adf-edit-process-filter-content__select-label">{{processFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="processFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"
[multiple]="true">
<mat-option *ngFor="let propertyOption of processFilterProperty.options" [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + processFilterProperty.key">
{{ propertyOption.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'" *ngIf="processFilterProperty.type === 'text'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label class="adf-edit-process-filter-content__text-label">{{processFilterProperty.label | translate}}</mat-label>
<input matInput
[formControlName]="processFilterProperty.key"
type="text"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"/>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'" *ngIf="processFilterProperty.type === 'number'" [attr.data-automation-id]="processFilterProperty.key">
<input matInput
[formControlName]="processFilterProperty.key"
type="number" min="0"
placeholder="{{processFilterProperty.label | translate}}"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"/>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'" *ngIf="processFilterProperty.type === 'date'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label>{{processFilterProperty.label | translate}}</mat-label>
<input
matInput
[formControlName]="processFilterProperty.key"
(keyup)="onDateChanged($any($event).target.value, processFilterProperty)"
(dateChange)="onDateChanged($event.value, processFilterProperty)"
[matDatepicker]="dateController"
placeholder="{{processFilterProperty.label | translate}}"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
<mat-datepicker-toggle
matSuffix [for]="dateController"
[attr.data-automation-id]="'adf-cloud-edit-process-property-date-toggle-' + processFilterProperty.key" />
<mat-datepicker #dateController [attr.data-automation-id]="'adf-cloud-edit-process-property-date-picker-' + processFilterProperty.key" />
<div class="adf-edit-process-filter-date-error-container">
<div *ngIf="hasError(processFilterProperty)">
<div class="adf-error-text">{{'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.DATE' | translate}}</div>
<mat-icon class="adf-error-icon" adf-icon="warning" />
</div>
</div>
</mat-form-field>
<adf-cloud-date-range-filter *ngIf="processFilterProperty.type === 'date-range'"
[processFilterProperty]="processFilterProperty"
[options]="processFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, processFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, processFilterProperty)" />
<adf-cloud-people
*ngIf="processFilterProperty.type === 'people'"
[preSelectUsers]="initiatorOptions"
[title]="processFilterProperty.label"
[validate]="true"
[appName]="appName"
[mode]="processFilterProperty.selectionMode"
(changedUsers)="onChangedUser($event, processFilterProperty)" />
</ng-container>
</div>
</form>
</ng-container>
</mat-expansion-panel>
<mat-expansion-panel (afterExpand)="onExpand()" (closed)="onClose()">
@if (processFilter) {
<mat-expansion-panel-header id="adf-edit-process-filter-expansion-header" class="adf-edit-process-filter-header">
@if (!isLoading) {
@if (showProcessFilterName) {
<mat-panel-title id="adf-edit-process-filter-title-id" class="adf-edit-process-filter-header__title">
{{processFilter.name | translate}}</mat-panel-title>
}
<mat-panel-description class="adf-edit-process-filter-header__description" id="adf-edit-process-filter-sub-title-id">
@if (showTitle) {
<span> {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}}</span>
}
@if (showFilterActions) {
<div class="adf-cloud-edit-process-filter-actions">
@if (toggleFilterActions) {
@for (filterAction of processFilterActions; track filterAction) {
<button
mat-icon-button
[title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions($event, filterAction)"
>
@if (filterAction.icon.includes(':')) {
<mat-icon [svgIcon]="filterAction.icon" aria-hidden="true" />
} @else {
<mat-icon [adf-icon]="filterAction.icon" aria-hidden="true" />
}
</button>
}
}
</div>
}
</mat-panel-description>
} @else {
<div class="adf-cloud-edit-process-filter-loading-margin">
<mat-spinner [diameter]="30" />
</div>
}
</mat-expansion-panel-header>
}
@if (!isLoading) {
@if (editProcessFilterForm) {
<form [formGroup]="editProcessFilterForm" class="adf-edit-process-filter-content">
<div class="adf-edit-process-filter-form">
@for (processFilterProperty of processFilterProperties; track filterTracker($index, processFilterProperty)) {
@if (processFilterProperty.type === 'select') {
<mat-form-field [floatLabel]="'auto'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label class="adf-edit-process-filter-content__select-label">{{processFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="processFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
@for (propertyOption of processFilterProperty.options; track propertyOption) {
<mat-option
[value]="propertyOption.value"
[attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + processFilterProperty.key"
>{{ propertyOption.label | translate }}</mat-option>
}
</mat-select>
</mat-form-field>
}
@if (processFilterProperty.type === 'multi-select') {
<mat-form-field [floatLabel]="'auto'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label class="adf-edit-process-filter-content__select-label">{{processFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="processFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"
[multiple]="true">
@for (propertyOption of processFilterProperty.options; track propertyOption) {
<mat-option [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + processFilterProperty.key">
{{ propertyOption.label | translate }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
@if (processFilterProperty.type === 'text') {
<mat-form-field [floatLabel]="'auto'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label class="adf-edit-process-filter-content__text-label">{{processFilterProperty.label | translate}}</mat-label>
<input matInput
[formControlName]="processFilterProperty.key"
type="text"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"/>
</mat-form-field>
}
@if (processFilterProperty.type === 'number') {
<mat-form-field [floatLabel]="'auto'" [attr.data-automation-id]="processFilterProperty.key">
<input matInput
[formControlName]="processFilterProperty.key"
type="number" min="0"
placeholder="{{processFilterProperty.label | translate}}"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"/>
</mat-form-field>
}
@if (processFilterProperty.type === 'date') {
<mat-form-field [floatLabel]="'auto'" [attr.data-automation-id]="processFilterProperty.key">
<mat-label>{{processFilterProperty.label | translate}}</mat-label>
<input
matInput
[formControlName]="processFilterProperty.key"
(keyup)="onDateChanged($any($event).target.value, processFilterProperty)"
(dateChange)="onDateChanged($event.value, processFilterProperty)"
[matDatepicker]="dateController"
placeholder="{{processFilterProperty.label | translate}}"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
<mat-datepicker-toggle
matSuffix [for]="dateController"
[attr.data-automation-id]="'adf-cloud-edit-process-property-date-toggle-' + processFilterProperty.key" />
<mat-datepicker #dateController [attr.data-automation-id]="'adf-cloud-edit-process-property-date-picker-' + processFilterProperty.key" />
<div class="adf-edit-process-filter-date-error-container">
@if (hasError(processFilterProperty)) {
<div>
<div class="adf-error-text">{{'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.DATE' | translate}}</div>
<mat-icon class="adf-error-icon" adf-icon="warning" />
</div>
}
</div>
</mat-form-field>
}
@if (processFilterProperty.type === 'date-range') {
<adf-cloud-date-range-filter
[processFilterProperty]="processFilterProperty"
[options]="processFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, processFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, processFilterProperty)" />
}
@if (processFilterProperty.type === 'people') {
<adf-cloud-people
[preSelectUsers]="initiatorOptions"
[title]="processFilterProperty.label"
[validate]="true"
[appName]="appName"
[mode]="processFilterProperty.selectionMode"
(changedUsers)="onChangedUser($event, processFilterProperty)" />
}
}
</div>
</form>
}
}
</mat-expansion-panel>
</mat-accordion>
@@ -41,7 +41,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { TranslatePipe } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { NgForOf, NgIf } from '@angular/common';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
@@ -80,21 +80,19 @@ interface ProcessFilterFormProps {
@Component({
selector: 'adf-cloud-edit-process-filter',
imports: [
MatProgressSpinnerModule,
TranslatePipe,
MatButtonModule,
NgForOf,
NgIf,
MatExpansionModule,
MatFormFieldModule,
MatSelectModule,
ReactiveFormsModule,
MatInputModule,
MatDatepickerModule,
IconModule,
DateRangeFilterComponent,
PeopleCloudComponent
],
MatProgressSpinnerModule,
TranslatePipe,
MatButtonModule,
MatExpansionModule,
MatFormFieldModule,
MatSelectModule,
ReactiveFormsModule,
MatInputModule,
MatDatepickerModule,
IconModule,
DateRangeFilterComponent,
PeopleCloudComponent
],
templateUrl: './edit-process-filter-cloud.component.html',
styleUrls: ['./edit-process-filter-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,37 +1,42 @@
<mat-action-list class="adf-process-filters" *ngIf="filters$ | async as filterList; else loading">
<button
*ngFor="let filter of filterList"
@if (filters$ | async; as filterList) {
<mat-action-list class="adf-process-filters">
@for (filter of filterList; track filter) {
<button
mat-list-item
(click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
[class.adf-active]="currentFilter === filter"
>
>
<div class="adf-process-filters__entry">
<div>
<mat-icon data-automation-id="adf-filter-icon" *ngIf="showIcons" [adf-icon]="filter.icon" aria-hidden="true" />
<span
data-automation-id="adf-filter-label"
class="adf-filter-action-button__label">
{{ filter.name | translate }}
</span>
</div>
<div>
@if (showIcons) {
<mat-icon data-automation-id="adf-filter-icon" [adf-icon]="filter.icon" aria-hidden="true" />
}
<span
*ngIf="counters[filter.key]"
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-process-filters__entry-counter"
[class.adf-active]="isFilterUpdated(filter.key)"
>
{{ counters[filter.key] }}
data-automation-id="adf-filter-label"
class="adf-filter-action-button__label">
{{ filter.name | translate }}
</span>
</div>
@if (counters[filter.key]) {
<span
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-process-filters__entry-counter"
[class.adf-active]="isFilterUpdated(filter.key)"
>
{{ counters[filter.key] }}
</span>
}
</div>
</button>
</mat-action-list>
<ng-template #loading>
<ng-container>
<div class="adf-app-list-spinner">
<mat-spinner />
</div>
</ng-container>
</ng-template>
</button>
}
</mat-action-list>
} @else {
<ng-container>
<div class="adf-app-list-spinner">
<mat-spinner />
</div>
</ng-container>
}
@@ -26,13 +26,13 @@ import { ProcessListCloudService } from '../../../process-list/services/process-
import { ProcessFilterCloudAdapter } from '../../../process-list/models/process-cloud-query-request.model';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { TranslatePipe } from '@ngx-translate/core';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatListModule } from '@angular/material/list';
@Component({
selector: 'adf-cloud-process-filters',
imports: [TranslatePipe, IconModule, NgIf, MatProgressSpinnerModule, NgForOf, MatListModule, AsyncPipe],
imports: [TranslatePipe, IconModule, MatProgressSpinnerModule, MatListModule, AsyncPipe],
templateUrl: './process-filters-cloud.component.html',
styleUrls: ['./process-filters-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,5 +1,7 @@
<mat-card appearance="outlined" *ngIf="processInstanceDetails" class="adf-process-header-cloud-card">
<mat-card-content>
<adf-card-view [properties]="properties" />
</mat-card-content>
</mat-card>
@if (processInstanceDetails) {
<mat-card appearance="outlined" class="adf-process-header-cloud-card">
<mat-card-content>
<adf-card-view [properties]="properties" />
</mat-card-content>
</mat-card>
}
@@ -29,11 +29,11 @@ import { ProcessInstanceCloud } from '../../start-process/models/process-instanc
import { ProcessCloudService } from '../../services/process-cloud.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatCardModule } from '@angular/material/card';
import { NgIf } from '@angular/common';
@Component({
selector: 'adf-cloud-process-header',
imports: [CardViewComponent, MatCardModule, NgIf],
imports: [CardViewComponent, MatCardModule],
templateUrl: './process-header-cloud.component.html',
encapsulation: ViewEncapsulation.None,
styleUrls: ['./process-header-cloud.component.scss'],
@@ -1,55 +1,58 @@
<adf-datatable
[rows]="rows"
[columns]="columns"
[data]="dataAdapter"
[stickyHeader]="stickyHeader"
[loading]="isLoading$ | async"
[sorting]="formattedSorting"
[selectionMode]="selectionMode"
[multiselect]="multiselect"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
[showMainDatatableActions]="showMainDatatableActions"
[showProvidedActions]="showProvidedActions"
[isResizingEnabled]="isResizingEnabled"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(rowClick)="onRowClick($any($event))"
(row-select)="onRowSelect($any($event))"
(row-unselect)="onRowUnselect($any($event))"
(row-keyup)="onRowKeyUp($any($event))"
(sorting-changed)="onSortingChanged($any($event))"
(columnOrderChanged)="onColumnOrderChanged($event)"
(columnsWidthChanged)="onColumnsWidthChanged($event)"
>
<adf-loading-content-template>
<ng-template>
<mat-progress-spinner
*ngIf="!customLoadingContent"
class="adf-cloud-process-list-loading-margin"
[color]="'primary'"
[mode]="'indeterminate'" />
<ng-content select="adf-custom-loading-content-template" />
</ng-template>
</adf-loading-content-template>
<adf-no-content-template>
<ng-template>
<adf-empty-content *ngIf="!emptyCustomContent"
icon="assessment"
[title]="'ADF_CLOUD_PROCESS_LIST.MESSAGES.TITLE' | translate"
[subtitle]="'ADF_CLOUD_PROCESS_LIST.MESSAGES.SUBTITLE'| translate" />
<ng-content select="adf-custom-empty-content-template" />
</ng-template>
</adf-no-content-template>
[rows]="rows"
[columns]="columns"
[data]="dataAdapter"
[stickyHeader]="stickyHeader"
[loading]="isLoading$ | async"
[sorting]="formattedSorting"
[selectionMode]="selectionMode"
[multiselect]="multiselect"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
[showMainDatatableActions]="showMainDatatableActions"
[showProvidedActions]="showProvidedActions"
[isResizingEnabled]="isResizingEnabled"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(rowClick)="onRowClick($any($event))"
(row-select)="onRowSelect($any($event))"
(row-unselect)="onRowUnselect($any($event))"
(row-keyup)="onRowKeyUp($any($event))"
(sorting-changed)="onSortingChanged($any($event))"
(columnOrderChanged)="onColumnOrderChanged($event)"
(columnsWidthChanged)="onColumnsWidthChanged($event)"
>
<adf-loading-content-template>
<ng-template>
@if (!customLoadingContent) {
<mat-progress-spinner
class="adf-cloud-process-list-loading-margin"
[color]="'primary'"
[mode]="'indeterminate'" />
}
<ng-content select="adf-custom-loading-content-template" />
</ng-template>
</adf-loading-content-template>
<adf-no-content-template>
<ng-template>
@if (!emptyCustomContent) {
<adf-empty-content
icon="assessment"
[title]="'ADF_CLOUD_PROCESS_LIST.MESSAGES.TITLE' | translate"
[subtitle]="'ADF_CLOUD_PROCESS_LIST.MESSAGES.SUBTITLE'| translate" />
}
<ng-content select="adf-custom-empty-content-template" />
</ng-template>
</adf-no-content-template>
<adf-main-menu-datatable-template>
<ng-template let-mainMenuTrigger>
<adf-datatable-column-selector
[columns]="columns"
[mainMenuTrigger]="mainMenuTrigger"
(submitColumnsVisibility)="onColumnsVisibilityChange($event)" />
</ng-template>
</adf-main-menu-datatable-template>
<adf-main-menu-datatable-template>
<ng-template let-mainMenuTrigger>
<adf-datatable-column-selector
[columns]="columns"
[mainMenuTrigger]="mainMenuTrigger"
(submitColumnsVisibility)="onColumnsVisibilityChange($event)" />
</ng-template>
</adf-main-menu-datatable-template>
</adf-datatable>
@@ -64,7 +64,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ProcessVariableFilterModel } from '../../../models/process-variable-filter.model';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { TranslatePipe } from '@ngx-translate/core';
import { AsyncPipe, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { PaginatedList } from '@alfresco/js-api';
import { ProcessInstanceCloud } from '../../start-process/models/process-instance-cloud.model';
@@ -75,17 +75,16 @@ const PRESET_KEY = 'adf-cloud-process-list.presets';
@Component({
selector: 'adf-cloud-process-list',
imports: [
DataTableComponent,
MatProgressSpinnerModule,
TranslatePipe,
ColumnsSelectorComponent,
MainMenuDataTableTemplateDirective,
EmptyContentComponent,
NoContentTemplateDirective,
LoadingContentTemplateDirective,
NgIf,
AsyncPipe
],
DataTableComponent,
MatProgressSpinnerModule,
TranslatePipe,
ColumnsSelectorComponent,
MainMenuDataTableTemplateDirective,
EmptyContentComponent,
NoContentTemplateDirective,
LoadingContentTemplateDirective,
AsyncPipe
],
templateUrl: './process-list-cloud.component.html',
styleUrls: ['./process-list-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,164 +1,165 @@
@if (processDefinitionLoaded && !isFormCloudLoading) {
<mat-card appearance="outlined" class="adf-start-process">
<mat-card-content>
@if (showTitle) {
<mat-card-title class="adf-title">
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.TITLE' | translate }}
</mat-card-title>
}
<mat-card appearance="outlined" class="adf-start-process">
<mat-card-content>
@if (showTitle) {
<mat-card-title class="adf-title">
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.TITLE' | translate }}
</mat-card-title>
}
@if (errorMessageId) {
<mat-card-subtitle class="adf-error-message" id="error-message">
{{ errorMessageId | translate }}
</mat-card-subtitle>
}
@if (errorMessageId) {
<mat-card-subtitle class="adf-error-message" id="error-message">
{{ errorMessageId | translate }}
</mat-card-subtitle>
}
@if (!isProcessDefinitionsEmpty) {
<div>
<form [formGroup]="processForm" class="adf-select-process-form">
@if (showSelectProcessDropdown) {
<mat-form-field
class="adf-process-input-container"
floatLabel="always"
data-automation-id="adf-select-cloud-process-dropdown"
>
<mat-label class="adf-start-process-input-label">{{
'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.TYPE' | translate
}}</mat-label>
<input matInput formControlName="processDefinition" [matAutocomplete]="auto" id="processDefinitionName" />
@if (!isProcessDefinitionsEmpty) {
<div>
<form [formGroup]="processForm" class="adf-select-process-form">
@if (showSelectProcessDropdown) {
<mat-form-field
class="adf-process-input-container"
floatLabel="always"
data-automation-id="adf-select-cloud-process-dropdown"
>
<mat-label class="adf-start-process-input-label">{{
'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.TYPE' | translate
}}</mat-label>
<input matInput formControlName="processDefinition" [matAutocomplete]="auto" id="processDefinitionName" />
<div class="adf-process-input-autocomplete">
<mat-autocomplete
#auto="matAutocomplete"
id="processDefinitionOptions"
[displayWith]="displayProcessNameOnDropdown"
(optionSelected)="setProcessDefinitionOnForm($event.option.value)"
>
<mat-option
*ngFor="let processDef of filteredProcesses"
[value]="getProcessDefinitionValue(processDef)"
(click)="processDefinitionSelectionChanged(processDef)"
>
{{ getProcessDefinitionValue(processDef) }}
</mat-option>
</mat-autocomplete>
<button
id="adf-select-process-dropdown"
title="{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.SELECT_PROCESS_DROPDOWN' | translate }}"
mat-icon-button
(click)="displayDropdown($event)"
>
<mat-icon adf-icon="arrow_drop_down" />
</button>
</div>
@if (processDefinition.hasError('required')) {
<mat-error class="adf-error-pb">
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.PROCESS_DEFINITION_REQUIRED' | translate }}
</mat-error>
}
</mat-form-field>
}
<adf-inplace-form-input [control]="processInstanceName">
<ng-container label>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.NAME' | translate }}
</ng-container>
<ng-container error>
@if (processInstanceName.hasError('required')) {
<span>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.PROCESS_NAME_REQUIRED' | translate }}
</span>
}
@if (processInstanceName.hasError('maxlength')) {
<span id="adf-start-process-maxlength-error">
{{
'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.MAXIMUM_LENGTH'
| translate: { characters: maxNameLength }
}}
</span>
}
@if (processInstanceName.hasError('pattern')) {
<span>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.SPACE_VALIDATOR' | translate }}
</span>
}
</ng-container>
</adf-inplace-form-input>
</form>
@if (hasForm) {
<adf-cloud-form
#startForm
[appName]="appName"
[appVersion]="processDefinitionCurrent.appVersion"
[data]="resolvedValues"
[formId]="processDefinitionCurrent.formKey"
[displayModeConfigurations]="displayModeConfigurations"
[enableParentVisibilityCheck]="enableParentVisibilityCheck"
[showSaveButton]="showSaveButton"
[showCompleteButton]="showCompleteButton"
[showRefreshButton]="false"
[showValidationIcon]="false"
[showTitle]="false"
(formContentClicked)="onFormContentClicked($event)"
(formLoaded)="onFormLoaded($event)"
(executeOutcome)="onCustomOutcomeClicked($event)"
<div class="adf-process-input-autocomplete">
<mat-autocomplete
#auto="matAutocomplete"
id="processDefinitionOptions"
[displayWith]="displayProcessNameOnDropdown"
(optionSelected)="setProcessDefinitionOnForm($event.option.value)"
>
@for (processDef of filteredProcesses; track processDef) {
<mat-option
[value]="getProcessDefinitionValue(processDef)"
(click)="processDefinitionSelectionChanged(processDef)"
>
<adf-cloud-form-custom-outcomes>
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
</adf-cloud-form-custom-outcomes>
</adf-cloud-form>
} @else if (hasScreen) {
<adf-cloud-start-process-screen-cloud
[screenId]="processDefinitionCurrent.formKey"
(screenStartProcessPayloadChange)="onScreenStartProcessPayloadChange($event)"
(disableStartProcessButton)="onDisableStartProcessButtonForScreen($event)"
>
<adf-cloud-form-custom-outcomes>
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
</adf-cloud-form-custom-outcomes>
</adf-cloud-start-process-screen-cloud>
} @else {
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
{{ getProcessDefinitionValue(processDef) }}
</mat-option>
}
</mat-autocomplete>
<button
id="adf-select-process-dropdown"
title="{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.SELECT_PROCESS_DROPDOWN' | translate }}"
mat-icon-button
(click)="displayDropdown($event)"
>
<mat-icon adf-icon="arrow_drop_down" />
</button>
</div>
} @else {
@if (processDefinitionLoaded) {
<mat-card-content>
<mat-card-subtitle class="error-message" id="no-process-message">
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.NO_PROCESS_DEFINITIONS' | translate | uppercase }}
</mat-card-subtitle>
</mat-card-content>
@if (processDefinition.hasError('required')) {
<mat-error class="adf-error-pb">
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.PROCESS_DEFINITION_REQUIRED' | translate }}
</mat-error>
}
</mat-form-field>
}
</mat-card-content>
</mat-card>
<adf-inplace-form-input [control]="processInstanceName">
<ng-container label>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.NAME' | translate }}
</ng-container>
<ng-container error>
@if (processInstanceName.hasError('required')) {
<span>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.PROCESS_NAME_REQUIRED' | translate }}
</span>
}
@if (processInstanceName.hasError('maxlength')) {
<span id="adf-start-process-maxlength-error">
{{
'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.MAXIMUM_LENGTH'
| translate: { characters: maxNameLength }
}}
</span>
}
@if (processInstanceName.hasError('pattern')) {
<span>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.SPACE_VALIDATOR' | translate }}
</span>
}
</ng-container>
</adf-inplace-form-input>
</form>
@if (hasForm) {
<adf-cloud-form
#startForm
[appName]="appName"
[appVersion]="processDefinitionCurrent.appVersion"
[data]="resolvedValues"
[formId]="processDefinitionCurrent.formKey"
[displayModeConfigurations]="displayModeConfigurations"
[enableParentVisibilityCheck]="enableParentVisibilityCheck"
[showSaveButton]="showSaveButton"
[showCompleteButton]="showCompleteButton"
[showRefreshButton]="false"
[showValidationIcon]="false"
[showTitle]="false"
(formContentClicked)="onFormContentClicked($event)"
(formLoaded)="onFormLoaded($event)"
(executeOutcome)="onCustomOutcomeClicked($event)"
>
<adf-cloud-form-custom-outcomes>
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
</adf-cloud-form-custom-outcomes>
</adf-cloud-form>
} @else if (hasScreen) {
<adf-cloud-start-process-screen-cloud
[screenId]="processDefinitionCurrent.formKey"
(screenStartProcessPayloadChange)="onScreenStartProcessPayloadChange($event)"
(disableStartProcessButton)="onDisableStartProcessButtonForScreen($event)"
>
<adf-cloud-form-custom-outcomes>
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
</adf-cloud-form-custom-outcomes>
</adf-cloud-start-process-screen-cloud>
} @else {
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
}
</div>
} @else {
@if (processDefinitionLoaded) {
<mat-card-content>
<mat-card-subtitle class="error-message" id="no-process-message">
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.NO_PROCESS_DEFINITIONS' | translate | uppercase }}
</mat-card-subtitle>
</mat-card-content>
}
}
</mat-card-content>
</mat-card>
} @else {
<div class="adf-loading-container">
<mat-progress-spinner class="adf-loading" color="primary" mode="indeterminate" />
</div>
<div class="adf-loading-container">
<mat-progress-spinner class="adf-loading" color="primary" mode="indeterminate" />
</div>
}
<ng-template #taskFormCloudButtons>
<div class="adf-start-process-cloud-actions">
@if (showCancelButton) {
<button mat-button (click)="cancelStartProcess()" id="cancel_process">
{{ cancelButtonLabel }}
</button>
}
@if (showStartProcessButton$ | async) {
<button
mat-flat-button
[disabled]="disableStartButton || !isProcessFormValid"
(click)="startProcess()"
data-automation-id="btn-start"
id="button-start"
class="adf-btn-start"
>
{{ startProcessButtonLabel }}
</button>
}
</div>
<div class="adf-start-process-cloud-actions">
@if (showCancelButton) {
<button mat-button (click)="cancelStartProcess()" id="cancel_process">
{{ cancelButtonLabel }}
</button>
}
@if (showStartProcessButton$ | async) {
<button
mat-flat-button
[disabled]="disableStartButton || !isProcessFormValid"
(click)="startProcess()"
data-automation-id="btn-start"
id="button-start"
class="adf-btn-start"
>
{{ startProcessButtonLabel }}
</button>
}
</div>
</ng-template>
@@ -18,12 +18,12 @@
import { ChangeDetectionStrategy, Component, input, output, signal } from '@angular/core';
import { BaseScreenCloudComponent } from '../base-screen/base-screen-cloud.component';
import { MatCardModule } from '@angular/material/card';
import { CommonModule } from '@angular/common';
import { StartProcessScreenCloud } from './start-process-screen.model';
@Component({
selector: 'adf-cloud-start-process-screen-cloud',
imports: [CommonModule, MatCardModule],
imports: [MatCardModule],
templateUrl: './start-process-screen-cloud.component.html',
host: { class: 'adf-cloud-start-process-screen-cloud' },
styleUrls: ['./start-process-screen-cloud.component.scss'],
@@ -1,123 +1,142 @@
<mat-accordion [hideToggle]="isLoading" class="adf-edit-task-filter">
<mat-expansion-panel (afterExpand)="onExpand()" (closed)="onClose()">
<mat-expansion-panel-header *ngIf="taskFilter" id="adf-edit-task-filter-expansion-header" class="adf-edit-task-filter-header">
<ng-container *ngIf="!isLoading; else loadingTemplate">
<mat-panel-title *ngIf="showTaskFilterName" id="adf-edit-task-filter-title-id" class="adf-edit-task-filter-header__title"
>{{taskFilter.name | translate}}</mat-panel-title>
<mat-panel-description class="adf-edit-task-filter-header__description" id="adf-edit-task-filter-sub-title-id">
<span *ngIf="showTitle">{{ 'ADF_CLOUD_EDIT_TASK_FILTER.TITLE' | translate}}</span>
<div *ngIf="showFilterActions" class="adf-cloud-edit-task-filter-actions">
<ng-container *ngIf="toggleFilterActions">
<button
*ngFor="let filterAction of taskFilterActions"
mat-icon-button
[title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions(filterAction)"
>
@if (filterAction.icon.includes(':')) {
<mat-icon [svgIcon]="filterAction.icon" aria-hidden="true" />
} @else {
<mat-icon [adf-icon]="filterAction.icon" aria-hidden="true" />
}
</button>
</ng-container>
</div>
</mat-panel-description>
</ng-container>
<ng-template #loadingTemplate>
<div class="adf-cloud-edit-task-filter-loading-margin">
<mat-progress-spinner mode="indeterminate" [diameter]="30" />
<mat-expansion-panel (afterExpand)="onExpand()" (closed)="onClose()">
@if (taskFilter) {
<mat-expansion-panel-header id="adf-edit-task-filter-expansion-header" class="adf-edit-task-filter-header">
@if (!isLoading) {
@if (showTaskFilterName) {
<mat-panel-title id="adf-edit-task-filter-title-id" class="adf-edit-task-filter-header__title"
>{{taskFilter.name | translate}}</mat-panel-title>
}
<mat-panel-description class="adf-edit-task-filter-header__description" id="adf-edit-task-filter-sub-title-id">
@if (showTitle) {
<span>{{ 'ADF_CLOUD_EDIT_TASK_FILTER.TITLE' | translate}}</span>
}
@if (showFilterActions) {
<div class="adf-cloud-edit-task-filter-actions">
@if (toggleFilterActions) {
@for (filterAction of taskFilterActions; track filterAction) {
<button
mat-icon-button
[title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions(filterAction)"
>
@if (filterAction.icon.includes(':')) {
<mat-icon [svgIcon]="filterAction.icon" aria-hidden="true" />
} @else {
<mat-icon [adf-icon]="filterAction.icon" aria-hidden="true" />
}
</button>
}
}
</div>
}
</mat-panel-description>
} @else {
<div class="adf-cloud-edit-task-filter-loading-margin">
<mat-progress-spinner mode="indeterminate" [diameter]="30" />
</div>
}
</mat-expansion-panel-header>
}
@if (!isLoading;) {
@if (editTaskFilterForm) {
<form [formGroup]="editTaskFilterForm" class="adf-edit-task-filter-content">
<div class="adf-edit-task-filter-form">
@for (taskFilterProperty of taskFilterProperties; track taskFilterProperty) {
@if (taskFilterProperty.type === 'select') {
<mat-form-field [floatLabel]="'auto'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__select-label">{{taskFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"
(selectionChange)="onStatusChange($event)">
@for (propertyOption of taskFilterProperty.options; track propertyOption) {
<mat-option
[value]="propertyOption.value"
[attr.data-automation-id]="'adf-cloud-edit-task-property-options-' + taskFilterProperty.key">
{{ propertyOption.label | translate }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
@if (taskFilterProperty.type === 'text') {
<mat-form-field [floatLabel]="'auto'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__text-label">{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
[formControlName]="taskFilterProperty.key"
type="text"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key" />
</mat-form-field>
}
@if (taskFilterProperty.type === 'date') {
<mat-form-field [floatLabel]="'auto'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label>{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
(keyup)="onDateChanged($any($event).target.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController"
[placeholder]="taskFilterProperty.label | translate"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix
[for]="dateController"
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-toggle-' + taskFilterProperty.key" />
<mat-datepicker #dateController
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-picker-' + taskFilterProperty.key" />
<div class="adf-edit-task-filter-date-error-container">
@if (hasError(taskFilterProperty)) {
<div>
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon" adf-icon="warning" />
</div>
}
</div>
</mat-form-field>
}
@if (taskFilterProperty.type === 'checkbox') {
<div class="adf-edit-task-filter-checkbox"
>
<mat-checkbox color="primary"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="taskFilterProperty.key"
>{{taskFilterProperty.label | translate}}</mat-checkbox>
</div>
</ng-template>
</mat-expansion-panel-header>
<ng-container *ngIf="!isLoading;">
<form *ngIf="editTaskFilterForm" [formGroup]="editTaskFilterForm" class="adf-edit-task-filter-content">
<div class="adf-edit-task-filter-form">
<ng-container *ngFor="let taskFilterProperty of taskFilterProperties">
<mat-form-field [floatLabel]="'auto'"
*ngIf="taskFilterProperty.type === 'select'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__select-label">{{taskFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"
(selectionChange)="onStatusChange($event)">
<mat-option *ngFor="let propertyOption of taskFilterProperty.options"
[value]="propertyOption.value"
[attr.data-automation-id]="'adf-cloud-edit-task-property-options-' + taskFilterProperty.key">
{{ propertyOption.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'"
*ngIf="taskFilterProperty.type === 'text'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__text-label">{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
[formControlName]="taskFilterProperty.key"
type="text"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key" />
</mat-form-field>
<mat-form-field [floatLabel]="'auto'"
*ngIf="taskFilterProperty.type === 'date'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label>{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
(keyup)="onDateChanged($any($event).target.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController"
[placeholder]="taskFilterProperty.label | translate"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix
[for]="dateController"
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-toggle-' + taskFilterProperty.key" />
<mat-datepicker #dateController
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-picker-' + taskFilterProperty.key" />
<div class="adf-edit-task-filter-date-error-container">
<div *ngIf="hasError(taskFilterProperty)">
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon" adf-icon="warning" />
</div>
</div>
</mat-form-field>
<div class="adf-edit-task-filter-checkbox"
*ngIf="taskFilterProperty.type === 'checkbox'">
<mat-checkbox color="primary"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="taskFilterProperty.key"
>{{taskFilterProperty.label | translate}}</mat-checkbox>
</div>
<adf-cloud-date-range-filter
*ngIf="taskFilterProperty.type === 'date-range'"
[processFilterProperty]="taskFilterProperty"
[options]="taskFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, taskFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, taskFilterProperty)" />
<adf-cloud-people
class="{{ 'adf-edit-task-filter-' + taskFilterProperty.key }}"
*ngIf="taskFilterProperty.type === 'people'"
[preSelectUsers]="taskFilterProperty.value"
[title]="taskFilterProperty.label"
[validate]="true"
[appName]="appName"
[mode]="taskFilterProperty.selectionMode"
(changedUsers)="onChangedUser($event, taskFilterProperty)" />
<adf-cloud-task-assignment-filter
*ngIf="taskFilterProperty.type === 'assignment'"
[taskFilterProperty]="taskFilterProperty"
[status]="selectedStatus"
[appName]="appName"
(assignedUsersChange)="onAssignedUsersChange($event)"
(assignedGroupsChange)="onAssignedGroupsChange($event)"
(assignmentTypeChange)="onAssignmentTypeChange($event)" />
</ng-container>
</div>
</form>
</ng-container>
</mat-expansion-panel>
}
@if (taskFilterProperty.type === 'date-range') {
<adf-cloud-date-range-filter
[processFilterProperty]="taskFilterProperty"
[options]="taskFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, taskFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, taskFilterProperty)" />
}
@if (taskFilterProperty.type === 'people') {
<adf-cloud-people
class="{{ 'adf-edit-task-filter-' + taskFilterProperty.key }}"
[preSelectUsers]="taskFilterProperty.value"
[title]="taskFilterProperty.label"
[validate]="true"
[appName]="appName"
[mode]="taskFilterProperty.selectionMode"
(changedUsers)="onChangedUser($event, taskFilterProperty)" />
}
@if (taskFilterProperty.type === 'assignment') {
<adf-cloud-task-assignment-filter
[taskFilterProperty]="taskFilterProperty"
[status]="selectedStatus"
[appName]="appName"
(assignedUsersChange)="onAssignedUsersChange($event)"
(assignedGroupsChange)="onAssignedGroupsChange($event)"
(assignmentTypeChange)="onAssignmentTypeChange($event)" />
}
}
</div>
</form>
}
}
</mat-expansion-panel>
</mat-accordion>
@@ -21,7 +21,7 @@ import { ServiceTaskFilterCloudModel, TaskFilterAction, TaskFilterProperties } f
import { ServiceTaskFilterCloudService } from '../../../services/service-task-filter-cloud.service';
import { BaseEditTaskFilterCloudComponent, DropdownOption } from '../base-edit-task-filter-cloud.component';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatButtonModule } from '@angular/material/button';
@@ -40,22 +40,21 @@ import { TaskAssignmentFilterCloudComponent } from '../../task-assignment-filter
@Component({
selector: 'adf-cloud-edit-service-task-filter',
imports: [
CommonModule,
TranslatePipe,
MatExpansionModule,
MatButtonModule,
MatProgressSpinnerModule,
ReactiveFormsModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule,
MatDatepickerModule,
IconModule,
MatCheckboxModule,
DateRangeFilterComponent,
PeopleCloudComponent,
TaskAssignmentFilterCloudComponent
],
TranslatePipe,
MatExpansionModule,
MatButtonModule,
MatProgressSpinnerModule,
ReactiveFormsModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule,
MatDatepickerModule,
IconModule,
MatCheckboxModule,
DateRangeFilterComponent,
PeopleCloudComponent,
TaskAssignmentFilterCloudComponent
],
templateUrl: './edit-service-task-filter-cloud.component.html',
styleUrls: ['./edit-service-task-filter-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,123 +1,142 @@
<mat-accordion [hideToggle]="isLoading" class="adf-edit-task-filter">
<mat-expansion-panel (afterExpand)="onExpand()" (closed)="onClose()">
<mat-expansion-panel-header *ngIf="taskFilter" id="adf-edit-task-filter-expansion-header" class="adf-edit-task-filter-header">
<ng-container *ngIf="!isLoading; else loadingTemplate">
<mat-panel-title *ngIf="showTaskFilterName" id="adf-edit-task-filter-title-id" class="adf-edit-task-filter-header__title"
>{{taskFilter.name | translate}}</mat-panel-title>
<mat-panel-description class="adf-edit-task-filter-header__description" id="adf-edit-task-filter-sub-title-id">
<span *ngIf="showTitle">{{ 'ADF_CLOUD_EDIT_TASK_FILTER.TITLE' | translate}}</span>
<div *ngIf="showFilterActions" class="adf-cloud-edit-task-filter-actions">
<ng-container *ngIf="toggleFilterActions">
<button
*ngFor="let filterAction of taskFilterActions"
mat-icon-button
[title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions(filterAction)"
>
@if (filterAction.icon.includes(':')) {
<mat-icon [svgIcon]="filterAction.icon" aria-hidden="true" />
} @else {
<mat-icon [adf-icon]="filterAction.icon" aria-hidden="true" />
}
</button>
</ng-container>
</div>
</mat-panel-description>
</ng-container>
<ng-template #loadingTemplate>
<div class="adf-cloud-edit-task-filter-loading-margin">
<mat-progress-spinner mode="indeterminate" [diameter]="30" />
<mat-expansion-panel (afterExpand)="onExpand()" (closed)="onClose()">
@if (taskFilter) {
<mat-expansion-panel-header id="adf-edit-task-filter-expansion-header" class="adf-edit-task-filter-header">
@if (!isLoading) {
@if (showTaskFilterName) {
<mat-panel-title id="adf-edit-task-filter-title-id" class="adf-edit-task-filter-header__title"
>{{taskFilter.name | translate}}</mat-panel-title>
}
<mat-panel-description class="adf-edit-task-filter-header__description" id="adf-edit-task-filter-sub-title-id">
@if (showTitle) {
<span>{{ 'ADF_CLOUD_EDIT_TASK_FILTER.TITLE' | translate}}</span>
}
@if (showFilterActions) {
<div class="adf-cloud-edit-task-filter-actions">
@if (toggleFilterActions) {
@for (filterAction of taskFilterActions; track filterAction) {
<button
mat-icon-button
[title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions(filterAction)"
>
@if (filterAction.icon.includes(':')) {
<mat-icon [svgIcon]="filterAction.icon" aria-hidden="true" />
} @else {
<mat-icon [adf-icon]="filterAction.icon" aria-hidden="true" />
}
</button>
}
}
</div>
}
</mat-panel-description>
} @else {
<div class="adf-cloud-edit-task-filter-loading-margin">
<mat-progress-spinner mode="indeterminate" [diameter]="30" />
</div>
}
</mat-expansion-panel-header>
}
@if (!isLoading;) {
@if (editTaskFilterForm) {
<form [formGroup]="editTaskFilterForm" class="adf-edit-task-filter-content">
<div class="adf-edit-task-filter-form">
@for (taskFilterProperty of taskFilterProperties; track taskFilterProperty) {
@if (taskFilterProperty.type === 'select') {
<mat-form-field [floatLabel]="'auto'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__select-label">{{taskFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"
(selectionChange)="onStatusChange($event)">
@for (propertyOption of taskFilterProperty.options; track propertyOption) {
<mat-option
[value]="propertyOption.value"
[attr.data-automation-id]="'adf-cloud-edit-task-property-options-' + taskFilterProperty.key">
{{ propertyOption.label | translate }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
@if (taskFilterProperty.type === 'text') {
<mat-form-field [floatLabel]="'auto'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__text-label">{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
[formControlName]="taskFilterProperty.key"
type="text"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key" />
</mat-form-field>
}
@if (taskFilterProperty.type === 'date') {
<mat-form-field [floatLabel]="'auto'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label>{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
(keyup)="onDateChanged($any($event).target.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController"
[placeholder]="taskFilterProperty.label | translate"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix
[for]="dateController"
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-toggle-' + taskFilterProperty.key" />
<mat-datepicker #dateController
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-picker-' + taskFilterProperty.key" />
<div class="adf-edit-task-filter-date-error-container">
@if (hasError(taskFilterProperty)) {
<div>
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon" adf-icon="warning" />
</div>
}
</div>
</mat-form-field>
}
@if (taskFilterProperty.type === 'checkbox') {
<div class="adf-edit-task-filter-checkbox"
>
<mat-checkbox color="primary"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="taskFilterProperty.key"
>{{taskFilterProperty.label | translate}}</mat-checkbox>
</div>
</ng-template>
</mat-expansion-panel-header>
<ng-container *ngIf="!isLoading;">
<form *ngIf="editTaskFilterForm" [formGroup]="editTaskFilterForm" class="adf-edit-task-filter-content">
<div class="adf-edit-task-filter-form">
<ng-container *ngFor="let taskFilterProperty of taskFilterProperties">
<mat-form-field [floatLabel]="'auto'"
*ngIf="taskFilterProperty.type === 'select'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__select-label">{{taskFilterProperty.label | translate}}</mat-label>
<mat-select
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"
(selectionChange)="onStatusChange($event)">
<mat-option *ngFor="let propertyOption of taskFilterProperty.options"
[value]="propertyOption.value"
[attr.data-automation-id]="'adf-cloud-edit-task-property-options-' + taskFilterProperty.key">
{{ propertyOption.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'"
*ngIf="taskFilterProperty.type === 'text'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label class="adf-edit-task-filter-content__text-label">{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
[formControlName]="taskFilterProperty.key"
type="text"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key" />
</mat-form-field>
<mat-form-field [floatLabel]="'auto'"
*ngIf="taskFilterProperty.type === 'date'"
[attr.data-automation-id]="taskFilterProperty.key">
<mat-label>{{taskFilterProperty.label | translate}}</mat-label>
<input matInput
(keyup)="onDateChanged($any($event).target.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController"
[placeholder]="taskFilterProperty.label | translate"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix
[for]="dateController"
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-toggle-' + taskFilterProperty.key" />
<mat-datepicker #dateController
[attr.data-automation-id]="'adf-cloud-edit-task-property-date-picker-' + taskFilterProperty.key" />
<div class="adf-edit-task-filter-date-error-container">
<div *ngIf="hasError(taskFilterProperty)">
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon" adf-icon="warning" />
</div>
</div>
</mat-form-field>
<div class="adf-edit-task-filter-checkbox"
*ngIf="taskFilterProperty.type === 'checkbox'">
<mat-checkbox color="primary"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="taskFilterProperty.key"
>{{taskFilterProperty.label | translate}}</mat-checkbox>
</div>
<adf-cloud-date-range-filter #dateRange
*ngIf="taskFilterProperty.type === 'date-range'"
[processFilterProperty]="taskFilterProperty"
[options]="taskFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, taskFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, taskFilterProperty)" />
<adf-cloud-people
class="{{ 'adf-edit-task-filter-' + taskFilterProperty.key }}"
*ngIf="taskFilterProperty.type === 'people'"
[preSelectUsers]="taskFilterProperty.value"
[title]="taskFilterProperty.label"
[validate]="true"
[appName]="appName"
[mode]="taskFilterProperty.selectionMode"
(changedUsers)="onChangedUser($event, taskFilterProperty)" />
<adf-cloud-task-assignment-filter
*ngIf="taskFilterProperty.type === 'assignment'"
[taskFilterProperty]="taskFilterProperty"
[status]="selectedStatus"
[appName]="appName"
(assignedUsersChange)="onAssignedUsersChange($event)"
(assignedGroupsChange)="onAssignedGroupsChange($event)"
(assignmentTypeChange)="onAssignmentTypeChange($event)" />
</ng-container>
</div>
</form>
</ng-container>
</mat-expansion-panel>
}
@if (taskFilterProperty.type === 'date-range') {
<adf-cloud-date-range-filter #dateRange
[processFilterProperty]="taskFilterProperty"
[options]="taskFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, taskFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, taskFilterProperty)" />
}
@if (taskFilterProperty.type === 'people') {
<adf-cloud-people
class="{{ 'adf-edit-task-filter-' + taskFilterProperty.key }}"
[preSelectUsers]="taskFilterProperty.value"
[title]="taskFilterProperty.label"
[validate]="true"
[appName]="appName"
[mode]="taskFilterProperty.selectionMode"
(changedUsers)="onChangedUser($event, taskFilterProperty)" />
}
@if (taskFilterProperty.type === 'assignment') {
<adf-cloud-task-assignment-filter
[taskFilterProperty]="taskFilterProperty"
[status]="selectedStatus"
[appName]="appName"
(assignedUsersChange)="onAssignedUsersChange($event)"
(assignedGroupsChange)="onAssignedGroupsChange($event)"
(assignmentTypeChange)="onAssignmentTypeChange($event)" />
}
}
</div>
</form>
}
}
</mat-expansion-panel>
</mat-accordion>
@@ -24,7 +24,7 @@ import { DateCloudFilterType } from '../../../../../models/date-cloud-filter.mod
import { BaseEditTaskFilterCloudComponent, DropdownOption } from '../base-edit-task-filter-cloud.component';
import { set } from 'date-fns';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatButtonModule } from '@angular/material/button';
@@ -43,22 +43,21 @@ import { TaskAssignmentFilterCloudComponent } from '../../task-assignment-filter
@Component({
selector: 'adf-cloud-edit-task-filter',
imports: [
CommonModule,
TranslatePipe,
MatExpansionModule,
MatButtonModule,
MatProgressSpinnerModule,
MatFormFieldModule,
ReactiveFormsModule,
MatSelectModule,
MatInputModule,
MatDatepickerModule,
IconModule,
MatCheckboxModule,
DateRangeFilterComponent,
PeopleCloudComponent,
TaskAssignmentFilterCloudComponent
],
TranslatePipe,
MatExpansionModule,
MatButtonModule,
MatProgressSpinnerModule,
MatFormFieldModule,
ReactiveFormsModule,
MatSelectModule,
MatInputModule,
MatDatepickerModule,
IconModule,
MatCheckboxModule,
DateRangeFilterComponent,
PeopleCloudComponent,
TaskAssignmentFilterCloudComponent
],
templateUrl: './edit-task-filter-cloud.component.html',
styleUrls: ['./edit-task-filter-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,35 +1,40 @@
<mat-action-list class="adf-task-filters" *ngIf="filters$ | async as filterList; else loading">
<button
*ngFor="let filter of filterList"
mat-list-item
(click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
[class.adf-active]="currentFilter === filter"
@if (filters$ | async; as filterList) {
<mat-action-list class="adf-task-filters">
@for (filter of filterList; track filter) {
<button
mat-list-item
(click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
[class.adf-active]="currentFilter === filter"
>
<div class="adf-task-filters__entry">
<div class="adf-task-filters__entry-label">
<mat-icon data-automation-id="adf-filter-icon" *ngIf="showIcons" [adf-icon]="filter.icon" aria-hidden="true" />
<span data-automation-id="adf-filter-label">
{{ filter.name | translate }}
</span>
</div>
<span
*ngIf="counters[filter.key]"
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-task-filters__entry-counter"
[class.adf-active]="wasFilterUpdated(filter.key)"
>
{{ counters[filter.key] }}
</span>
</div>
</button>
</mat-action-list>
<ng-template #loading>
<ng-container>
<div class="adf-app-list-spinner">
<mat-spinner />
<div class="adf-task-filters__entry">
<div class="adf-task-filters__entry-label">
@if (showIcons) {
<mat-icon data-automation-id="adf-filter-icon" [adf-icon]="filter.icon" aria-hidden="true" />
}
<span data-automation-id="adf-filter-label">
{{ filter.name | translate }}
</span>
</div>
@if (counters[filter.key]) {
<span
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-task-filters__entry-counter"
[class.adf-active]="wasFilterUpdated(filter.key)"
>
{{ counters[filter.key] }}
</span>
}
</div>
</ng-container>
</ng-template>
</button>
}
</mat-action-list>
} @else {
<ng-container>
<div class="adf-app-list-spinner">
<mat-spinner />
</div>
</ng-container>
}
@@ -1,37 +1,43 @@
<div class="adf-cloud-assignment-container">
<mat-form-field floatLabel="auto" class="adf-task-assignment-filter-container">
<mat-label class="adf-task-assignment-filter-label"
[ngClass]="{'adf-task-assignment-filter-label--focus': typeDropdown.focused}">
{{ 'ADF_CLOUD_TASK_ASSIGNMENT_FILTER.ASSIGNMENT_TYPE' | translate }}
</mat-label>
<mat-select class="adf-task-assignment-filter"
[(ngModel)]="assignmentType" #typeDropdown
[attr.data-automation-id]="'adf-task-assignment-filter-select'"
(selectionChange)="onAssignmentTypeChange($event)">
<mat-option *ngFor="let assignmentType of assignmentTypeOptions"
class="adf-task-assignment-filter-option"
[ngClass]="{'adf-task-assignment-filter-option--selected': filterOption.selected}"
[value]="assignmentType.value" #filterOption
[attr.data-automation-id]="'adf-task-assignment-filter-' + assignmentType.value">
{{ assignmentType.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field floatLabel="auto" class="adf-task-assignment-filter-container">
<mat-label class="adf-task-assignment-filter-label"
[ngClass]="{'adf-task-assignment-filter-label--focus': typeDropdown.focused}">
{{ 'ADF_CLOUD_TASK_ASSIGNMENT_FILTER.ASSIGNMENT_TYPE' | translate }}
</mat-label>
<mat-select class="adf-task-assignment-filter"
[(ngModel)]="assignmentType" #typeDropdown
[attr.data-automation-id]="'adf-task-assignment-filter-select'"
(selectionChange)="onAssignmentTypeChange($event)">
@for (assignmentType of assignmentTypeOptions; track assignmentType) {
<mat-option
class="adf-task-assignment-filter-option"
[ngClass]="{'adf-task-assignment-filter-option--selected': filterOption.selected}"
[value]="assignmentType.value" #filterOption
[attr.data-automation-id]="'adf-task-assignment-filter-' + assignmentType.value">
{{ assignmentType.label | translate }}
</mat-option>
}
</mat-select>
</mat-form-field>
<adf-cloud-group *ngIf="isCandidateGroupsType()"
class="adf-group-cloud-filter"
data-automation-id="adf-group-cloud-candidate-groups-filter"
[appName]="appName"
[preSelectGroups]="candidateGroups"
[mode]="taskFilterProperty.selectionMode"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.CANDIDATE_GROUP'"
(changedGroups)="onChangedGroups($event)" />
@if (isCandidateGroupsType()) {
<adf-cloud-group
class="adf-group-cloud-filter"
data-automation-id="adf-group-cloud-candidate-groups-filter"
[appName]="appName"
[preSelectGroups]="candidateGroups"
[mode]="taskFilterProperty.selectionMode"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.CANDIDATE_GROUP'"
(changedGroups)="onChangedGroups($event)" />
}
<adf-cloud-people *ngIf="isAssignedToType()"
class="adf-group-cloud-filter"
data-automation-id="adf-group-cloud-assigned-to-filter"
[preSelectUsers]="assignedUsers"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
[appName]="appName"
(changedUsers)="onChangedAssignedUsers($event)" />
@if (isAssignedToType()) {
<adf-cloud-people
class="adf-group-cloud-filter"
data-automation-id="adf-group-cloud-assigned-to-filter"
[preSelectUsers]="assignedUsers"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
[appName]="appName"
(changedUsers)="onChangedAssignedUsers($event)" />
}
</div>
@@ -18,7 +18,7 @@
import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { AbstractControl, ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatInputModule } from '@angular/material/input';
import { MatCardModule } from '@angular/material/card';
@@ -26,7 +26,7 @@ import { MatButtonModule } from '@angular/material/button';
@Component({
selector: 'adf-cloud-task-filter-dialog',
imports: [CommonModule, TranslatePipe, MatInputModule, ReactiveFormsModule, MatDialogModule, MatCardModule, MatButtonModule],
imports: [TranslatePipe, MatInputModule, ReactiveFormsModule, MatDialogModule, MatCardModule, MatButtonModule],
templateUrl: './task-filter-dialog-cloud.component.html',
styleUrls: ['./task-filter-dialog-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,35 +1,40 @@
<mat-action-list class="adf-task-filters" *ngIf="filters$ | async as filterList; else loading">
<button
*ngFor="let filter of filterList"
mat-list-item
(click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
[class.adf-active]="currentFilter === filter"
@if (filters$ | async; as filterList) {
<mat-action-list class="adf-task-filters">
@for (filter of filterList; track filter) {
<button
mat-list-item
(click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
[class.adf-active]="currentFilter === filter"
>
<div class="adf-task-filters__entry">
<div class="adf-task-filters__entry-label">
<mat-icon data-automation-id="adf-filter-icon" *ngIf="showIcons" [adf-icon]="filter.icon" aria-hidden="true" />
<span data-automation-id="adf-filter-label">
{{ filter.name | translate }}
</span>
</div>
<span
*ngIf="counters[filter.key]"
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-task-filters__entry-counter"
[class.adf-active]="wasFilterUpdated(filter.key)"
>
{{ counters[filter.key] }}
</span>
</div>
</button>
</mat-action-list>
<ng-template #loading>
<ng-container>
<div class="adf-app-list-spinner">
<mat-spinner />
<div class="adf-task-filters__entry">
<div class="adf-task-filters__entry-label">
@if (showIcons) {
<mat-icon data-automation-id="adf-filter-icon" [adf-icon]="filter.icon" aria-hidden="true" />
}
<span data-automation-id="adf-filter-label">
{{ filter.name | translate }}
</span>
</div>
@if (counters[filter.key]) {
<span
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-task-filters__entry-counter"
[class.adf-active]="wasFilterUpdated(filter.key)"
>
{{ counters[filter.key] }}
</span>
}
</div>
</ng-container>
</ng-template>
</button>
}
</mat-action-list>
} @else {
<ng-container>
<div class="adf-app-list-spinner">
<mat-spinner />
</div>
</ng-container>
}
@@ -24,13 +24,13 @@ import { DropdownCloudWidgetComponent } from '../../../../form/components/widget
import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces';
import { TaskCloudService } from '../../../services/task-cloud.service';
import { TaskDetailsCloudModel } from '../../../models/task-details-cloud.model';
import { CommonModule } from '@angular/common';
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
import { FormCustomOutcomesComponent } from '../../../../form/components/form-cloud-custom-outcomes.component';
@Component({
selector: 'adf-cloud-task-form',
imports: [CommonModule, UserTaskCloudButtonsComponent, FormCustomOutcomesComponent, FormCloudComponent],
imports: [UserTaskCloudButtonsComponent, FormCustomOutcomesComponent, FormCloudComponent],
templateUrl: './task-form-cloud.component.html',
styleUrls: ['./task-form-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,8 +1,10 @@
<button *ngIf="showCancelButton" mat-button id="adf-cloud-cancel-task" (click)="onCancelClick()">
@if (showCancelButton) {
<button mat-button id="adf-cloud-cancel-task" (click)="onCancelClick()">
{{ customCancelButtonText || ('ADF_CLOUD_TASK_FORM.EMPTY_FORM.BUTTONS.CANCEL' | translate) }}
</button>
<button
*ngIf="canClaimTask"
</button>
}
@if (canClaimTask) {
<button
adf-cloud-claim-task
class="adf-user-task-cloud-claim-btn"
mat-button
@@ -10,11 +12,12 @@
[taskId]="taskId"
(success)="onClaimTask()"
(error)="onError($event)"
>
>
{{ 'ADF_CLOUD_TASK_FORM.EMPTY_FORM.BUTTONS.CLAIM' | translate }}
</button>
<button
*ngIf="canUnclaimTask"
</button>
}
@if (canUnclaimTask) {
<button
adf-cloud-unclaim-task
class="adf-user-task-cloud-unclaim-btn"
mat-button
@@ -22,6 +25,7 @@
[taskId]="taskId"
(success)="onUnclaimTask()"
(error)="onError($event)"
>
>
{{ 'ADF_CLOUD_TASK_FORM.EMPTY_FORM.BUTTONS.UNCLAIM' | translate }}
</button>
</button>
}
@@ -16,7 +16,7 @@
*/
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { UnClaimTaskCloudDirective } from './unclaim-task/unclaim-task-cloud.directive';
@@ -24,7 +24,7 @@ import { ClaimTaskCloudDirective } from './claim-task/claim-task-cloud.directive
@Component({
selector: 'adf-cloud-user-task-cloud-buttons',
imports: [CommonModule, TranslatePipe, UnClaimTaskCloudDirective, ClaimTaskCloudDirective, MatButtonModule],
imports: [TranslatePipe, UnClaimTaskCloudDirective, ClaimTaskCloudDirective, MatButtonModule],
styles: ['button { margin-right: 8px; }'],
templateUrl: './user-task-cloud-buttons.component.html'
})
@@ -1,115 +1,117 @@
<div class="adf-user-task-cloud-container">
<div *ngIf="!loading; else loadingTemplate">
<ng-container [ngSwitch]="taskType">
<ng-container *ngSwitchCase="taskTypeEnum.Form">
<adf-cloud-task-form
#adfCloudTaskForm
[appName]="appName"
[candidateUsers]="candidateUsers"
[candidateGroups]="candidateGroups"
[displayModeConfigurations]="displayModeConfigurations"
[enableParentVisibilityCheck]="enableParentVisibilityCheck"
[showValidationIcon]="showValidationIcon"
[showTitle]="showTitle"
[taskId]="taskId"
[taskDetails]="taskDetails"
[showCancelButton]="showCancelButton"
[showSaveButton]="showSaveButton && canCompleteTask()"
[showCompleteButton]="showCompleteButton && canCompleteTask()"
[customCancelButtonText]="customCancelButtonText"
[customSaveButtonText]="customSaveButtonText"
[customCompleteButtonText]="customCompleteButtonText"
(cancelClick)="onCancelForm()"
(executeOutcome)="onExecuteOutcome($event)"
(error)="onError($event)"
(formLoaded)="onFormLoaded($event)"
(formSaved)="onFormSaved()"
(formContentClicked)="onFormContentClicked($event)"
(taskCompleted)="onCompleteTaskForm()"
(taskClaimed)="onClaimTask()"
(taskUnclaimed)="onTaskUnclaimed()"
@if (!loading) {
<div>
@switch (taskType) {
@case (taskTypeEnum.Form) {
<adf-cloud-task-form
#adfCloudTaskForm
[appName]="appName"
[candidateUsers]="candidateUsers"
[candidateGroups]="candidateGroups"
[displayModeConfigurations]="displayModeConfigurations"
[enableParentVisibilityCheck]="enableParentVisibilityCheck"
[showValidationIcon]="showValidationIcon"
[showTitle]="showTitle"
[taskId]="taskId"
[taskDetails]="taskDetails"
[showCancelButton]="showCancelButton"
[showSaveButton]="showSaveButton && canCompleteTask()"
[showCompleteButton]="showCompleteButton && canCompleteTask()"
[customCancelButtonText]="customCancelButtonText"
[customSaveButtonText]="customSaveButtonText"
[customCompleteButtonText]="customCompleteButtonText"
(cancelClick)="onCancelForm()"
(executeOutcome)="onExecuteOutcome($event)"
(error)="onError($event)"
(formLoaded)="onFormLoaded($event)"
(formSaved)="onFormSaved()"
(formContentClicked)="onFormContentClicked($event)"
(taskCompleted)="onCompleteTaskForm()"
(taskClaimed)="onClaimTask()"
(taskUnclaimed)="onTaskUnclaimed()"
/>
}
@case (taskTypeEnum.Screen) {
<adf-cloud-task-screen
#adfCloudTaskScreen
[appName]="appName"
[canClaimTask]="canClaimTask()"
[canUnclaimTask]="canUnclaimTask()"
[processInstanceId]="taskDetails.processInstanceId"
[rootProcessInstanceId]="taskDetails.rootProcessInstanceId"
[screenId]="screenId"
[showCancelButton]="showCancelButton"
[taskName]="taskDetails.name"
[taskId]="taskId"
[showNextTaskCheckbox]="showNextTaskCheckbox && canCompleteTask()"
[isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked"
(cancelTask)="onCancelClick()"
(claimTask)="onClaimTask()"
(error)="onError($event)"
(taskCompleted)="onCompleteTask($event, taskType)"
(taskSaved)="onFormSaved()"
(unclaimTask)="onUnclaimTask()"
(nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)"
/>
}
@case (taskTypeEnum.None) {
<mat-card appearance="outlined" class="adf-task-form-container">
@if (showTitle) {
<mat-card-header>
<mat-card-title>
<h4>
<span class="adf-form-title">
{{ taskDetails?.name || 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
</span>
</h4>
</mat-card-title>
</mat-card-header>
}
<mat-card-content>
<adf-empty-content
[icon]="'description'"
[title]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.TITLE'"
[subtitle]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.SUBTITLE'"
/>
</ng-container>
<ng-container *ngSwitchCase="taskTypeEnum.Screen">
<adf-cloud-task-screen
#adfCloudTaskScreen
[appName]="appName"
[canClaimTask]="canClaimTask()"
[canUnclaimTask]="canUnclaimTask()"
[processInstanceId]="taskDetails.processInstanceId"
[rootProcessInstanceId]="taskDetails.rootProcessInstanceId"
[screenId]="screenId"
[showCancelButton]="showCancelButton"
[taskName]="taskDetails.name"
[taskId]="taskId"
[showNextTaskCheckbox]="showNextTaskCheckbox && canCompleteTask()"
[isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked"
(cancelTask)="onCancelClick()"
(claimTask)="onClaimTask()"
(error)="onError($event)"
(taskCompleted)="onCompleteTask($event, taskType)"
(taskSaved)="onFormSaved()"
(unclaimTask)="onUnclaimTask()"
(nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)"
/>
</ng-container>
<ng-container *ngSwitchCase="taskTypeEnum.None">
<mat-card appearance="outlined" class="adf-task-form-container">
<mat-card-header *ngIf="showTitle">
<mat-card-title>
<h4>
<span class="adf-form-title">
{{ taskDetails?.name || 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
</span>
</h4>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<adf-empty-content
[icon]="'description'"
[title]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.TITLE'"
[subtitle]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.SUBTITLE'"
/>
</mat-card-content>
<mat-card-actions class="adf-task-form-actions" align="end">
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
<button
*ngIf="canCompleteTask()"
mat-flat-button
adf-cloud-complete-task
[appName]="appName"
[taskId]="taskId"
(success)="onCompleteTask(false, taskType)"
(error)="onError($event)"
color="primary"
id="adf-form-complete"
>
{{ customCompleteButtonText || ('ADF_CLOUD_TASK_FORM.EMPTY_FORM.BUTTONS.COMPLETE' | translate) }}
</button>
</mat-card-actions>
</mat-card>
</ng-container>
</ng-container>
</mat-card-content>
<mat-card-actions class="adf-task-form-actions" align="end">
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
@if (canCompleteTask()) {
<button
mat-flat-button
adf-cloud-complete-task
[appName]="appName"
[taskId]="taskId"
(success)="onCompleteTask(false, taskType)"
(error)="onError($event)"
color="primary"
id="adf-form-complete"
>
{{ customCompleteButtonText || ('ADF_CLOUD_TASK_FORM.EMPTY_FORM.BUTTONS.COMPLETE' | translate) }}
</button>
}
</mat-card-actions>
</mat-card>
}
}
</div>
} @else {
<mat-spinner class="adf-user-task-cloud-spinner" />
}
</div>
<ng-template #loadingTemplate>
<mat-spinner class="adf-user-task-cloud-spinner" />
</ng-template>
<ng-template #taskFormCloudButtons>
<adf-cloud-user-task-cloud-buttons
[appName]="appName"
[canClaimTask]="canClaimTask()"
[canUnclaimTask]="canUnclaimTask()"
[showCancelButton]="showCancelButton"
[customCancelButtonText]="customCancelButtonText"
[taskId]="taskId"
(cancelClick)="onCancelClick()"
(claimTask)="onClaimTask()"
(unclaimTask)="onUnclaimTask()"
(error)="onError($event)"
<adf-cloud-user-task-cloud-buttons
[appName]="appName"
[canClaimTask]="canClaimTask()"
[canUnclaimTask]="canUnclaimTask()"
[showCancelButton]="showCancelButton"
[customCancelButtonText]="customCancelButtonText"
[taskId]="taskId"
(cancelClick)="onCancelClick()"
(claimTask)="onClaimTask()"
(unclaimTask)="onUnclaimTask()"
(error)="onError($event)"
/>
</ng-template>
@@ -1,20 +1,24 @@
<h3 *ngIf="showTitle" class="adf-task-title">{{ taskDetails?.name }}</h3>
@if (showTitle) {
<h3 class="adf-task-title">{{ taskDetails?.name }}</h3>
}
<div class="adf-task-header-container">
<mat-card appearance="outlined" *ngIf="isTaskValid()" class="adf-card-container">
<mat-card-content>
<adf-card-view
*ngIf="!isLoading; else loadingTemplate"
[displayNoneOption]="false"
[properties]="properties"
[editable]="isTaskEditable()"
[displayClearAction]="displayDateClearAction" />
</mat-card-content>
@if (isTaskValid()) {
<mat-card appearance="outlined" class="adf-card-container">
<mat-card-content>
@if (!isLoading) {
<adf-card-view
[displayNoneOption]="false"
[properties]="properties"
[editable]="isTaskEditable()"
[displayClearAction]="displayDateClearAction" />
} @else {
<div class="adf-task-header-loading">
<mat-spinner />
</div>
}
</mat-card-content>
</mat-card>
}
</div>
<ng-template #loadingTemplate>
<div class="adf-task-header-loading">
<mat-spinner />
</div>
</ng-template>
@@ -36,13 +36,13 @@ import {
import { TaskDetailsCloudModel } from '../../models/task-details-cloud.model';
import { TaskCloudService } from '../../services/task-cloud.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatCardModule } from '@angular/material/card';
@Component({
selector: 'adf-cloud-task-header',
imports: [CommonModule, MatProgressSpinnerModule, CardViewComponent, MatCardModule],
imports: [MatProgressSpinnerModule, CardViewComponent, MatCardModule],
templateUrl: './task-header-cloud.component.html',
styleUrls: ['./task-header-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -1,58 +1,60 @@
<div *ngIf="!rows">{{ 'ADF_CLOUD_TASK_LIST.FILTERS.MESSAGES.NONE' | translate }}</div>
<ng-container *ngIf="rows">
<adf-datatable
[rows]="rows"
[columns]="columns"
[data]="dataAdapter"
[loading]="isLoading$ | async"
[sorting]="formattedSorting"
[multiselect]="multiselect"
[selectionMode]="selectionMode"
[stickyHeader]="stickyHeader"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
[resolverFn]="boundReplacePriorityValues"
[showProvidedActions]="showProvidedActions"
[showMainDatatableActions]="showMainDatatableActions"
[isResizingEnabled]="isResizingEnabled"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(row-select)="onRowSelect($any($event))"
(row-unselect)="onRowUnselect($any($event))"
(rowClick)="onRowClick($any($event))"
(row-keyup)="onRowKeyUp($any($event))"
(sorting-changed)="onSortingChanged($any($event))"
(columnOrderChanged)="onColumnOrderChanged($event)"
(columnsWidthChanged)="onColumnsWidthChanged($event)"
>
<adf-loading-content-template>
<ng-template>
<mat-progress-spinner
class="adf-cloud-task-list-loading-margin"
[color]="'primary'"
[mode]="'indeterminate'" />
</ng-template>
</adf-loading-content-template>
<adf-no-content-template>
<ng-template>
<adf-empty-content
*ngIf="!emptyCustomContent"
icon="assignment"
[title]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.TITLE' | translate"
[subtitle]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.SUBTITLE' | translate" />
<ng-content select="adf-custom-empty-content-template" />
</ng-template>
</adf-no-content-template>
<adf-main-menu-datatable-template>
<ng-template let-mainMenuTrigger>
<adf-datatable-column-selector
[columns]="columns"
[mainMenuTrigger]="mainMenuTrigger"
(submitColumnsVisibility)="onColumnsVisibilityChange($event)" />
</ng-template>
</adf-main-menu-datatable-template>
</adf-datatable>
</ng-container>
@if (!rows) {
<div>{{ 'ADF_CLOUD_TASK_LIST.FILTERS.MESSAGES.NONE' | translate }}</div>
}
@if (rows) {
<adf-datatable
[rows]="rows"
[columns]="columns"
[data]="dataAdapter"
[loading]="isLoading$ | async"
[sorting]="formattedSorting"
[multiselect]="multiselect"
[selectionMode]="selectionMode"
[stickyHeader]="stickyHeader"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
[resolverFn]="boundReplacePriorityValues"
[showProvidedActions]="showProvidedActions"
[showMainDatatableActions]="showMainDatatableActions"
[isResizingEnabled]="isResizingEnabled"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(row-select)="onRowSelect($any($event))"
(row-unselect)="onRowUnselect($any($event))"
(rowClick)="onRowClick($any($event))"
(row-keyup)="onRowKeyUp($any($event))"
(sorting-changed)="onSortingChanged($any($event))"
(columnOrderChanged)="onColumnOrderChanged($event)"
(columnsWidthChanged)="onColumnsWidthChanged($event)"
>
<adf-loading-content-template>
<ng-template>
<mat-progress-spinner
class="adf-cloud-task-list-loading-margin"
[color]="'primary'"
[mode]="'indeterminate'" />
</ng-template>
</adf-loading-content-template>
<adf-no-content-template>
<ng-template>
@if (!emptyCustomContent) {
<adf-empty-content
icon="assignment"
[title]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.TITLE' | translate"
[subtitle]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.SUBTITLE' | translate" />
}
<ng-content select="adf-custom-empty-content-template" />
</ng-template>
</adf-no-content-template>
<adf-main-menu-datatable-template>
<ng-template let-mainMenuTrigger>
<adf-datatable-column-selector
[columns]="columns"
[mainMenuTrigger]="mainMenuTrigger"
(submitColumnsVisibility)="onColumnsVisibilityChange($event)" />
</ng-template>
</adf-main-menu-datatable-template>
</adf-datatable>
}
@@ -1,58 +1,60 @@
<div *ngIf="!rows">{{ 'ADF_CLOUD_TASK_LIST.FILTERS.MESSAGES.NONE' | translate }}</div>
<ng-container *ngIf="rows">
<adf-datatable
[rows]="rows"
[columns]="columns"
[data]="dataAdapter"
[loading]="isLoading$ | async"
[sorting]="formattedSorting"
[multiselect]="multiselect"
[selectionMode]="selectionMode"
[stickyHeader]="stickyHeader"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
[resolverFn]="boundReplacePriorityValues"
[showProvidedActions]="showProvidedActions"
[showMainDatatableActions]="showMainDatatableActions"
[isResizingEnabled]="isResizingEnabled"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(row-select)="onRowSelect($any($event))"
(row-unselect)="onRowUnselect($any($event))"
(rowClick)="onRowClick($any($event))"
(row-keyup)="onRowKeyUp($any($event))"
(sorting-changed)="onSortingChanged($any($event))"
(columnOrderChanged)="onColumnOrderChanged($event)"
(columnsWidthChanged)="onColumnsWidthChanged($event)"
>
<adf-loading-content-template>
<ng-template>
<mat-progress-spinner
class="adf-cloud-task-list-loading-margin"
[color]="'primary'"
[mode]="'indeterminate'" />
</ng-template>
</adf-loading-content-template>
<adf-no-content-template>
<ng-template>
<adf-empty-content
*ngIf="!emptyCustomContent"
icon="assignment"
[title]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.TITLE' | translate"
[subtitle]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.SUBTITLE' | translate" />
<ng-content select="adf-custom-empty-content-template" />
</ng-template>
</adf-no-content-template>
<adf-main-menu-datatable-template>
<ng-template let-mainMenuTrigger>
<adf-datatable-column-selector
[columns]="columns"
[mainMenuTrigger]="mainMenuTrigger"
(submitColumnsVisibility)="onColumnsVisibilityChange($event)" />
</ng-template>
</adf-main-menu-datatable-template>
</adf-datatable>
</ng-container>
@if (!rows) {
<div>{{ 'ADF_CLOUD_TASK_LIST.FILTERS.MESSAGES.NONE' | translate }}</div>
}
@if (rows) {
<adf-datatable
[rows]="rows"
[columns]="columns"
[data]="dataAdapter"
[loading]="isLoading$ | async"
[sorting]="formattedSorting"
[multiselect]="multiselect"
[selectionMode]="selectionMode"
[stickyHeader]="stickyHeader"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
[resolverFn]="boundReplacePriorityValues"
[showProvidedActions]="showProvidedActions"
[showMainDatatableActions]="showMainDatatableActions"
[isResizingEnabled]="isResizingEnabled"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(row-select)="onRowSelect($any($event))"
(row-unselect)="onRowUnselect($any($event))"
(rowClick)="onRowClick($any($event))"
(row-keyup)="onRowKeyUp($any($event))"
(sorting-changed)="onSortingChanged($any($event))"
(columnOrderChanged)="onColumnOrderChanged($event)"
(columnsWidthChanged)="onColumnsWidthChanged($event)"
>
<adf-loading-content-template>
<ng-template>
<mat-progress-spinner
class="adf-cloud-task-list-loading-margin"
[color]="'primary'"
[mode]="'indeterminate'" />
</ng-template>
</adf-loading-content-template>
<adf-no-content-template>
<ng-template>
@if (!emptyCustomContent) {
<adf-empty-content
icon="assignment"
[title]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.TITLE' | translate"
[subtitle]="'ADF_CLOUD_TASK_LIST.LIST.MESSAGES.SUBTITLE' | translate" />
}
<ng-content select="adf-custom-empty-content-template" />
</ng-template>
</adf-no-content-template>
<adf-main-menu-datatable-template>
<ng-template let-mainMenuTrigger>
<adf-datatable-column-selector
[columns]="columns"
[mainMenuTrigger]="mainMenuTrigger"
(submitColumnsVisibility)="onColumnsVisibilityChange($event)" />
</ng-template>
</adf-main-menu-datatable-template>
</adf-datatable>
}