[ADF-5543] Enable lint accessibility and resolve found issues (#9421)

This commit is contained in:
tomson 2024-04-17 09:36:40 +02:00 committed by GitHub
parent eaad09b06d
commit 74ef7eed1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 1162 additions and 1054 deletions

View File

@ -181,7 +181,7 @@ module.exports = {
},
{
files: ['*.html'],
extends: ['plugin:@angular-eslint/template/recommended'],
extends: ['plugin:@angular-eslint/template/recommended', 'plugin:@angular-eslint/template/accessibility'],
rules: {}
},
{
@ -190,6 +190,11 @@ module.exports = {
rules: {
'@alfresco/eslint-angular/no-angular-material-selectors': 'error'
}
},
{
files: ['*.ts'],
extends: ['plugin:@angular-eslint/template/process-inline-templates'],
excludedFiles: ['*.spec.ts']
}
]
};

View File

@ -1,5 +1,5 @@
<div class="adf-setting-container">
<form id="host-form" [formGroup]="form" (submit)="onSubmit(form.value)" (keydown)="keyDownFunction($event)">
<form id="host-form" role="form" tabindex="0" [formGroup]="form" (submit)="onSubmit(form.value)" (keydown)="keyDownFunction($event)">
<mat-form-field *ngIf="showSelectProviders">
<mat-select id="adf-provider-selector" [formControl]="providersControl">
<mat-option *ngFor="let provider of providers" [value]="provider">

View File

@ -4,7 +4,7 @@
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"extends": ["plugin:@nrwl/nx/angular"],
"rules": {
"prefer-arrow/prefer-arrow-functions": "off",
"@typescript-eslint/no-var-requires": "off",

View File

@ -21,7 +21,8 @@
export const ACTIVITI_CLOUD_APPS: any = {
SUB_PROCESS_APP: {
name: 'subprocessapp',
file_location: (TAG = 'develop') => `https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/subprocessapp.zip?raw=true`,
file_location: (TAG = 'develop') =>
`https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/subprocessapp.zip?raw=true`,
processes: {
processchild: 'processchild',
processparent: 'processparent'
@ -33,13 +34,14 @@ export const ACTIVITI_CLOUD_APPS: any = {
],
variables: {
'process-runtime-service': {
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false,
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false
}
}
},
CANDIDATE_BASE_APP: {
name: 'candidatebaseapp',
file_location: (TAG = 'develop') => `https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/candidatebaseapp.zip?raw=true`,
file_location: (TAG = 'develop') =>
`https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/candidatebaseapp.zip?raw=true`,
processes: {
candidateUserProcess: 'candidateuserprocess',
candidateGroupProcess: 'candidategroupprocess',
@ -82,13 +84,14 @@ export const ACTIVITI_CLOUD_APPS: any = {
},
variables: {
'process-runtime-service': {
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false,
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false
}
}
},
SIMPLE_APP: {
name: 'simpleapp',
file_location: (TAG = 'develop') => `https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/simpleapp.zip?raw=true`,
file_location: (TAG = 'develop') =>
`https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/simpleapp.zip?raw=true`,
processes: {
processwithvariables: 'processwithvariables',
simpleProcess: 'simpleprocess',
@ -217,13 +220,14 @@ export const ACTIVITI_CLOUD_APPS: any = {
enableLocalDevelopment: true,
variables: {
'process-runtime-service': {
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false,
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false
}
}
},
UAT_BE_DEFAULT_APP: {
name: 'uat-be-default-app',
file_location: (TAG = 'develop') => `https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/uat-be-default-app.zip?raw=true`,
file_location: (TAG = 'develop') =>
`https://github.com/Alfresco/alfresco-ng2-components/blob/${TAG}/e2e/resources/activiti7/uat-be-default-app.zip?raw=true`,
processes: {
'script-acs-process': 'script-acs-process'
},
@ -233,7 +237,7 @@ export const ACTIVITI_CLOUD_APPS: any = {
],
variables: {
'process-runtime-service': {
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false,
ALFRESCO_PROCESS_TASKEMAIL_ENABLED: false
}
}
}

View File

@ -4,7 +4,7 @@
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"extends": ["plugin:@nrwl/nx/angular"],
"rules": {
"jsdoc/newline-after-description": "warn",
"@typescript-eslint/naming-convention": "warn",

View File

@ -26,7 +26,6 @@ import { AspectListDialogComponentData } from './aspect-list-dialog-data.interfa
encapsulation: ViewEncapsulation.None
})
export class AspectListDialogComponent implements OnInit {
title: string;
description: string;
currentNodeId: string;
@ -35,8 +34,7 @@ export class AspectListDialogComponent implements OnInit {
currentAspectSelection: string[] = [];
constructor(private dialog: MatDialogRef<AspectListDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: AspectListDialogComponentData) {
constructor(private dialog: MatDialogRef<AspectListDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: AspectListDialogComponentData) {
this.title = data.title;
this.description = data.description;
this.overTableMessage = data.overTableMessage;
@ -47,7 +45,7 @@ export class AspectListDialogComponent implements OnInit {
this.dialog.backdropClick().subscribe(() => {
this.close();
});
this.dialog.keydownEvents().subscribe(event => {
this.dialog.keydownEvents().subscribe((event) => {
// Esc
if (event.keyCode === 27) {
event.preventDefault();

View File

@ -28,9 +28,7 @@ import { AspectEntry } from '@alfresco/js-api';
styleUrls: ['./aspect-list.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AspectListComponent implements OnInit, OnDestroy {
/** Node Id of the node that we want to update */
@Input()
nodeId: string = '';
@ -56,8 +54,7 @@ export class AspectListComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private aspectListService: AspectListService, private nodeApiService: NodesApiService) {
}
constructor(private aspectListService: AspectListService, private nodeApiService: NodesApiService) {}
ngOnDestroy(): void {
this.onDestroy$.next(true);
@ -68,26 +65,28 @@ export class AspectListComponent implements OnInit, OnDestroy {
let aspects$: Observable<AspectEntry[]>;
if (this.nodeId) {
const node$ = this.nodeApiService.getNode(this.nodeId);
const customAspect$ = this.aspectListService.getCustomAspects(this.aspectListService.getVisibleAspects())
.pipe(map(
(customAspects) => customAspects.flatMap((customAspect) => customAspect.entry.id)
));
const customAspect$ = this.aspectListService
.getCustomAspects(this.aspectListService.getVisibleAspects())
.pipe(map((customAspects) => customAspects.flatMap((customAspect) => customAspect.entry.id)));
aspects$ = zip(node$, customAspect$).pipe(
tap(([node, customAspects]) => {
this.nodeAspects = node.aspectNames.filter((aspect) => this.aspectListService.getVisibleAspects().includes(aspect) || customAspects.includes(aspect));
this.nodeAspects = node.aspectNames.filter(
(aspect) => this.aspectListService.getVisibleAspects().includes(aspect) || customAspects.includes(aspect)
);
this.nodeAspectStatus = [...this.nodeAspects];
this.notDisplayedAspects = node.aspectNames.filter((aspect) => !this.aspectListService.getVisibleAspects().includes(aspect) && !customAspects.includes(aspect));
this.notDisplayedAspects = node.aspectNames.filter(
(aspect) => !this.aspectListService.getVisibleAspects().includes(aspect) && !customAspects.includes(aspect)
);
this.valueChanged.emit([...this.nodeAspects, ...this.notDisplayedAspects]);
this.updateCounter.emit(this.nodeAspects.length);
}),
concatMap(() => this.aspectListService.getAspects()),
takeUntil(this.onDestroy$));
takeUntil(this.onDestroy$)
);
} else {
aspects$ = this.aspectListService.getAspects()
.pipe(takeUntil(this.onDestroy$));
aspects$ = this.aspectListService.getAspects().pipe(takeUntil(this.onDestroy$));
}
this.aspects$ = aspects$.pipe(map((aspects) =>
aspects.filter((aspect) => !this.excludedAspects.includes(aspect.entry.id))));
this.aspects$ = aspects$.pipe(map((aspects) => aspects.filter((aspect) => !this.excludedAspects.includes(aspect.entry.id))));
}
onCheckBoxClick(event: Event) {

View File

@ -27,6 +27,7 @@
*ngIf="hasPreviousNodes()"
class="adf-breadcrumb-dropdown-path"
tabindex="-1"
role="button"
>
<mat-option
*ngFor="let node of previousNodes"

View File

@ -20,6 +20,7 @@
*ngIf="hasPreviousNodes()"
class="adf-dropdown-breadcrumb-path-select"
tabindex="-1"
role="button"
data-automation-id="dropdown-breadcrumb-path"
aria-labelledby="dropdown-breadcrumb-button">

View File

@ -34,6 +34,9 @@
<ng-container *ngIf="isCRUDMode && (!existingCategoriesLoading || existingCategories)">
<span class="adf-create-category-label"
(click)="addCategory()"
tabindex="0"
role="button"
(keyup.enter)="addCategory()"
[hidden]="categoryNameControl.invalid || typing">
{{ 'CATEGORIES_MANAGEMENT.GENERIC_CREATE' | translate : { name: categoryNameControl.value } }}
</span>

View File

@ -2,6 +2,8 @@
id="userinfo_container"
[class.adf-userinfo-name-right]="showOnRight"
(keyup)="onKeyPress($event)"
tabindex="0"
role="button"
class="adf-userinfo-container"
*ngIf="canShow"
>

View File

@ -86,9 +86,7 @@ import { ContentAuthLoaderService } from './auth-loader/content-auth-loader.serv
SecurityControlsServiceModule,
CategoriesModule
],
providers: [
provideTranslations('adf-content-services', 'assets/adf-content-services')
],
providers: [provideTranslations('adf-content-services', 'assets/adf-content-services')],
exports: [
ContentPipeModule,
TagModule,

View File

@ -38,6 +38,8 @@ import { takeUntil } from 'rxjs/operators';
class="adf-datatable-cell-value"
title="{{ displayTooltip$ | async }}"
(click)="onClick()"
tabindex="0"
(keyup.enter)="onClick()"
>
{{ displayText$ | async }}
</span>

View File

@ -37,6 +37,8 @@ import { takeUntil } from 'rxjs/operators';
class="adf-datatable-cell-value"
title="{{ node | adfNodeNameTooltip }}"
(click)="onClick()"
tabindex="0"
(keyup.enter)="onClick()"
>
{{ displayText$ | async }}
</span>

View File

@ -119,7 +119,13 @@ export const errorJson = {
>
<ng-template let-data>
<ul id="autocomplete-search-result-list">
<li *ngFor="let item of data?.list?.entries; let idx = index" (click)="elementClicked()">
<li
*ngFor="let item of data?.list?.entries; let idx = index"
(click)="elementClicked()"
tabindex="0"
role="button"
(keyup.enter)="elementClicked()"
>
<div id="result_option_{{ idx }}">
<span>{{ item?.entry.name }}</span>
</div>

View File

@ -23,8 +23,14 @@ import { OverlayModule } from '@angular/cdk/overlay';
@Component({
template: `
<div [adf-pop-over]="popOver" [autofocusedElementSelector]="'#test'" [target]="target" #target tabindex="0" [panelClass]="'adf-popover-test'">
</div>
<div
[adf-pop-over]="popOver"
[autofocusedElementSelector]="'#test'"
[target]="target"
#target
tabindex="0"
[panelClass]="'adf-popover-test'"
></div>
<ng-template #popOver>
<div id="test" tabindex="0"></div>
</ng-template>
@ -38,10 +44,7 @@ describe('PopOverDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [OverlayModule],
declarations: [
PopOverDirective,
PopOverTestComponent
]
declarations: [PopOverDirective, PopOverTestComponent]
});
fixture = TestBed.createComponent(PopOverTestComponent);
});
@ -56,9 +59,11 @@ describe('PopOverDirective', () => {
it('should focus element indicated by autofocusedElementSelector on pop over trigger enter keyup', () => {
const popOverTrigger = fixture.debugElement.query(By.directive(PopOverDirective)).nativeElement;
fixture.detectChanges();
popOverTrigger.dispatchEvent(new KeyboardEvent('keyup', {
popOverTrigger.dispatchEvent(
new KeyboardEvent('keyup', {
key: 'Enter'
}));
})
);
expect(fixture.debugElement.query(By.css('#test')).nativeElement).toBe(document.activeElement);
});
@ -66,27 +71,33 @@ describe('PopOverDirective', () => {
const popOverTrigger = fixture.debugElement.query(By.directive(PopOverDirective)).nativeElement;
fixture.detectChanges();
popOverTrigger.click();
document.dispatchEvent(new KeyboardEvent('keyup', {
document.dispatchEvent(
new KeyboardEvent('keyup', {
key: 'Escape'
}));
})
);
expect(popOverTrigger).toBe(document.activeElement);
});
it('should not focus pop over trigger on document esc keyup if pop over is not open', () => {
const popOverTrigger = fixture.debugElement.query(By.directive(PopOverDirective)).nativeElement;
fixture.detectChanges();
document.dispatchEvent(new KeyboardEvent('keyup', {
document.dispatchEvent(
new KeyboardEvent('keyup', {
key: 'Escape'
}));
})
);
expect(popOverTrigger).not.toEqual(document.activeElement);
});
it('should open pop over on enter key press if pop over is not open', () => {
const popOverTrigger = fixture.debugElement.query(By.directive(PopOverDirective)).nativeElement;
fixture.detectChanges();
popOverTrigger.dispatchEvent(new KeyboardEvent('keyup', {
popOverTrigger.dispatchEvent(
new KeyboardEvent('keyup', {
key: 'Enter'
}));
})
);
fixture.detectChanges();
const popOverPanel = document.querySelector('.adf-popover-test');
expect(popOverPanel).toBeDefined();
@ -97,9 +108,11 @@ describe('PopOverDirective', () => {
fixture.detectChanges();
popOverTrigger.click();
fixture.detectChanges();
popOverTrigger.dispatchEvent(new KeyboardEvent('keyup', {
popOverTrigger.dispatchEvent(
new KeyboardEvent('keyup', {
key: 'Enter'
}));
})
);
fixture.detectChanges();
const popOverPanel = document.querySelector('.adf-popover-test');
expect(popOverPanel).toBeNull();

View File

@ -22,7 +22,7 @@ import { SearchFacetFiltersService } from '../services/search-facet-filters.serv
import { SearchQueryBuilderService } from '../services/search-query-builder.service';
@Component({
template: `<button adf-reset-search></button>`
template: `<button adf-reset-search>Reset</button>`
})
class TestComponent {}

View File

@ -5,11 +5,20 @@
<mat-icon class="adf-search-field-icon">search</mat-icon>
</button>
<mat-form-field class="adf-facet-search-field" floatLabel="never">
<input matInput placeholder="{{ 'SEARCH.FILTER.ACTIONS.SEARCH' | translate }}"
[attr.data-automation-id]="'facet-result-filter-'+field.label" [(ngModel)]="field.buckets.filterText">
<button *ngIf="field.buckets.filterText" mat-button matSuffix mat-icon-button
<input
matInput
placeholder="{{ 'SEARCH.FILTER.ACTIONS.SEARCH' | translate }}"
[attr.data-automation-id]="'facet-result-filter-' + field.label"
[(ngModel)]="field.buckets.filterText"
/>
<button
*ngIf="field.buckets.filterText"
mat-button
matSuffix
mat-icon-button
[attr.title]="'SEARCH.FILTER.BUTTONS.CLEAR' | translate"
(click)="field.buckets.filterText = ''">
(click)="field.buckets.filterText = ''"
>
<mat-icon role="button" [attr.aria-label]="'SEARCH.FILTER.BUTTONS.CLEAR' | translate">clear</mat-icon>
</button>
</mat-form-field>
@ -17,14 +26,19 @@
</div>
<div class="adf-checklist">
<mat-checkbox *ngFor="let bucket of field.buckets" [checked]="bucket.checked"
<mat-checkbox
*ngFor="let bucket of field.buckets"
[checked]="bucket.checked"
[attr.data-automation-id]="'checkbox-' + field.label + '-' + (bucket.display || bucket.label)"
(change)="onToggleBucket($event, field, bucket)"
class="adf-search-filter-facet-checkbox">
<div matTooltip="{{ bucket.display || bucket.label | translate }} {{ getBucketCountDisplay(bucket) }}"
class="adf-search-filter-facet-checkbox"
>
<div
matTooltip="{{ bucket.display || bucket.label | translate }} {{ getBucketCountDisplay(bucket) }}"
matTooltipPosition="right"
class="adf-facet-label"
[class.adf-search-filter-facet-checkbox-checked]='bucket.checked'>
[class.adf-search-filter-facet-checkbox-checked]="bucket.checked"
>
{{ bucket.display || bucket.label | translate }} {{ getBucketCountDisplay(bucket) }}
</div>
</mat-checkbox>
@ -37,16 +51,28 @@
</div>
<div class="adf-facet-buttons" *ngIf="!field.buckets.fitsPage">
<button mat-icon-button *ngIf="canResetSelectedBuckets(field)"
title="{{ 'SEARCH.FILTER.ACTIONS.CLEAR-ALL' | translate }}" (click)="resetSelectedBuckets(field)">
<button
mat-icon-button
*ngIf="canResetSelectedBuckets(field)"
title="{{ 'SEARCH.FILTER.ACTIONS.CLEAR-ALL' | translate }}"
(click)="resetSelectedBuckets(field)"
>
<mat-icon>clear</mat-icon>
</button>
<button mat-icon-button *ngIf="field.buckets.canShowLessItems" (click)="field.buckets.showLessItems()"
title="{{ 'SEARCH.FILTER.ACTIONS.SHOW-LESS' | translate }}">
<button
mat-icon-button
*ngIf="field.buckets.canShowLessItems"
(click)="field.buckets.showLessItems()"
title="{{ 'SEARCH.FILTER.ACTIONS.SHOW-LESS' | translate }}"
>
<mat-icon>keyboard_arrow_up</mat-icon>
</button>
<button mat-icon-button *ngIf="field.buckets.canShowMoreItems" (click)="field.buckets.showMoreItems()"
title="{{ 'SEARCH.FILTER.ACTIONS.SHOW-MORE' | translate }}">
<button
mat-icon-button
*ngIf="field.buckets.canShowMoreItems"
(click)="field.buckets.showMoreItems()"
title="{{ 'SEARCH.FILTER.ACTIONS.SHOW-MORE' | translate }}"
>
<mat-icon>keyboard_arrow_down</mat-icon>
</button>
</div>

View File

@ -3,7 +3,8 @@
class="adf-search-filter-chip-tabbed"
[class.adf-search-toggle-chip]="displayValue || menuTrigger.menuOpen"
[disabled]="!isPopulated"
[tabIndex]="0"
tabIndex="0"
role="button"
[matMenuTriggerFor]="menu"
(menuOpened)="onMenuOpen()"
(keydown.enter)="onEnterKeydown()"

View File

@ -3,7 +3,8 @@
class="adf-search-filter-chip adf-search-filter-facet-chip"
[class.adf-search-toggle-chip]="(facetField.displayValue$ | async) || menuTrigger.menuOpen"
[disabled]="!isPopulated()"
[tabIndex]="0"
tabIndex="0"
role="button"
[matMenuTriggerFor]="menu"
(menuOpened)="onMenuOpen()"
(keydown.enter)="onEnterKeydown()"

View File

@ -2,7 +2,8 @@
[disableRipple]="true"
class="adf-search-filter-chip"
[class.adf-search-toggle-chip]="(widget.getDisplayValue() | async) || menuTrigger.menuOpen"
[tabIndex]="0"
tabIndex="0"
role="button"
[matMenuTriggerFor]="menu"
(menuOpened)="onMenuOpen()"
(keydown.enter)="onEnterKeydown()"

View File

@ -1,6 +1,6 @@
<div *ngIf="!!category"
class="adf-filter">
<button mat-icon-button
<div *ngIf="!!category" class="adf-filter">
<button
mat-icon-button
[matMenuTriggerFor]="filter"
data-automation-id="filter-menu-button"
#menuTrigger="matMenuTrigger"
@ -9,44 +9,50 @@
(keyup.enter)="$event.stopPropagation()"
class="adf-filter-button"
[attr.aria-label]="getTooltipTranslation(col?.title)"
[matTooltip]="getTooltipTranslation(col?.title)">
<adf-icon value="filter_list"
[matTooltip]="getTooltipTranslation(col?.title)"
>
<adf-icon
value="filter_list"
[ngClass]="{ 'adf-icon-active': isActive() || menuTrigger.menuOpen }"
class="adf-filter-icon"
matBadge="filter"
matBadgeColor="warn"
[matBadgeHidden]="!isActive()">
[matBadgeHidden]="!isActive()"
>
</adf-icon>
</button>
<mat-menu #filter="matMenu"
class="adf-filter-menu adf-search-filter-menu"
(closed)="onClosed()">
<div #filterContainer
role="menuitem"
(keydown.tab)="$event.stopPropagation();">
<div (click)="$event.stopPropagation()"
class="adf-filter-container">
<mat-menu #filter="matMenu" class="adf-filter-menu adf-search-filter-menu" (closed)="onClosed()">
<div #filterContainer role="menuitem" tabindex="0" (keydown.tab)="$event.stopPropagation()">
<div (click)="$event.stopPropagation()" role="button" tabindex="0" (keyup.enter)="$event.stopPropagation()" class="adf-filter-container">
<div class="adf-filter-title">{{ category?.name | translate }}</div>
<adf-search-widget-container (keypress)="onKeyPressed($event, menuTrigger)"
<adf-search-widget-container
(keypress)="onKeyPressed($event, menuTrigger)"
[id]="category?.id"
[selector]="category?.component?.selector"
[settings]="category?.component?.settings"
[value]="initialValue">
[value]="initialValue"
>
</adf-search-widget-container>
</div>
<mat-dialog-actions class="adf-filter-actions">
<button mat-button
<button
mat-button
id="clear-filter-button"
[attr.aria-label]="'SEARCH.SEARCH_HEADER.CLEAR' | translate"
(click)="onClearButtonClick($event)">{{ 'SEARCH.SEARCH_HEADER.CLEAR' | translate | uppercase }}
(click)="onClearButtonClick($event)"
>
{{ 'SEARCH.SEARCH_HEADER.CLEAR' | translate | uppercase }}
</button>
<button mat-button
<button
mat-button
color="primary"
id="apply-filter-button"
class="adf-filter-apply-button"
[attr.aria-label]="'SEARCH.SEARCH_HEADER.APPLY' | translate"
(click)="onApply()">{{ 'SEARCH.SEARCH_HEADER.APPLY' | translate | uppercase }}
(click)="onApply()"
>
{{ 'SEARCH.SEARCH_HEADER.APPLY' | translate | uppercase }}
</button>
</mat-dialog-actions>
</div>

View File

@ -25,10 +25,10 @@ import { SearchFilterContainerComponent } from './search-filter-container.compon
import { SearchCategory } from '../../models/search-category.interface';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatInputHarness } from '@angular/material/input/testing';
import { MatMenuHarness } from '@angular/material/menu/testing';
import { MatButtonHarness } from '@angular/material/button/testing';
import { MatBadgeHarness } from '@angular/material/badge/testing';
import { MatInputHarness } from '@angular/material/input/testing';
const mockCategory: SearchCategory = {
id: 'queryName',
@ -176,7 +176,9 @@ describe('SearchFilterContainerComponent', () => {
expect(component.focusTrap._element).toBe(component.filterContainer.nativeElement);
});
it('should focus the input element when the menu is opened', async () => {
// TODO: very flaky test, need to be refactored
// eslint-disable-next-line ban/ban
xit('should focus the input element when the menu is opened', async () => {
const menu = await loader.getHarness(MatMenuHarness);
await menu.open();

View File

@ -25,11 +25,7 @@
</button>
<mat-menu #menu="matMenu" class="adf-search-form-menu">
<button *ngFor="let form of forms"
mat-menu-item
tabindex="0"
[attr.aria-label]="form.name | translate"
(click)="onSelectionChange(form)">
<button *ngFor="let form of forms" mat-menu-item tabindex="0" [attr.aria-label]="form.name | translate" (click)="onSelectionChange(form)">
{{ form.name | translate }}
</button>
</mat-menu>

View File

@ -0,0 +1,19 @@
<div id="adf-like-container" class="adf-like-container">
<div class="adf-like">
<span
id="adf-like-{{ nodeId }}"
[ngClass]="{ 'adf-like-select': isLike, 'adf-like-grey': !isLike }"
(click)="likeClick()"
tabindex="0"
role="button"
(keyup.enter)="likeClick()"
>
<mat-icon>thumb_up</mat-icon>
</span>
</div>
<div class="adf-like-counter-container">
<div id="adf-like-counter" class="adf-like-counter">{{ likesCounter }}</div>
<div class="adf-left" *ngIf="likesCounter === 1">Like</div>
<div class="adf-left" *ngIf="likesCounter !== 1">Likes</div>
</div>
</div>

View File

@ -1,6 +1,13 @@
<mat-list>
<mat-list-item *ngFor="let currentEntry of tagsEntries; let idx = index">
<div class="adf-tag-actions-container" id="tag_delete_{{currentEntry.entry.tag}}" (click)="removeTag(currentEntry.entry.id)">
<div
class="adf-tag-actions-container"
id="tag_delete_{{ currentEntry.entry.tag }}"
tabindex="0"
role="button"
(keyup.enter)="removeTag(currentEntry.entry.id)"
(click)="removeTag(currentEntry.entry.id)"
>
<div class="adf-tag-actions-delete-text" id="tag_name_{{ currentEntry.entry.tag }}">{{ currentEntry.entry.tag }}</div>
<mat-icon class="adf-tag-actions-delete-icon">delete</mat-icon>
</div>
@ -12,23 +19,19 @@
<mat-form-field class="adf-full-width">
<input
id="new-tag-text"
matInput placeholder="{{'TAG.LABEL.NEWTAG' | translate }}"
matInput
placeholder="{{ 'TAG.LABEL.NEWTAG' | translate }}"
type="text"
(keypress)="cleanErrorMsg()"
[(ngModel)]="newTagName"
/>
<mat-hint data-automation-id="errorMessage" *ngIf="error" [ngStyle]="{'color': 'red'}" align="start">{{errorMsg}}</mat-hint>
<mat-hint data-automation-id="errorMessage" *ngIf="error" [ngStyle]="{ color: 'red' }" align="start">{{ errorMsg }} </mat-hint>
</mat-form-field>
</td>
<td>
<button
id="add-tag"
class="adf-full-width"
color="primary"
(click)="addTag()"
[disabled]="disableAddTag"
mat-raised-button
>{{'TAG.BUTTON.ADD' | translate }}</button>
<button id="add-tag" class="adf-full-width" color="primary" (click)="addTag()" [disabled]="disableAddTag" mat-raised-button>
{{ 'TAG.BUTTON.ADD' | translate }}
</button>
</td>
</tr>
</table>

View File

@ -1,6 +1,7 @@
<div class="adf-tags-creation">
<div *ngIf="tagNameControlVisible" class="adf-tag-name-field">
<input #tagNameInput
<input
#tagNameInput
class="adf-tag-search-field"
matInput
autocomplete="off"
@ -11,15 +12,10 @@
/>
<mat-error *ngIf="tagNameControl.invalid && tagNameControl.touched">{{ tagNameErrorMessageKey | translate }} </mat-error>
</div>
<p
class="adf-no-tags-message"
*ngIf="showEmptyTagMessage">
<p class="adf-no-tags-message" *ngIf="showEmptyTagMessage">
{{ 'TAG.TAGS_CREATOR.NO_TAGS_CREATED' | translate }}
</p>
<div
class="adf-tags-list"
[class.adf-tags-list-fixed]="!tagNameControlVisible"
#tagsList>
<div class="adf-tags-list" [class.adf-tags-list-fixed]="!tagNameControlVisible" #tagsList>
<span *ngFor="let tag of tags" class="adf-tag adf-label-with-icon-button">
{{ tag }}
<button
@ -28,32 +24,31 @@
(click)="removeTag(tag)"
[attr.title]="'TAG.TAGS_CREATOR.TOOLTIPS.DELETE_TAG' | translate"
[disabled]="disabledTagsRemoving"
class="adf-remove-tag">
class="adf-remove-tag"
>
<mat-icon>close</mat-icon>
</button>
</span>
</div>
</div>
<div
class="adf-existing-tags-panel"
*ngIf="existingTagsPanelVisible">
<span *ngIf="!spinnerVisible || existingTags"
<div class="adf-existing-tags-panel" *ngIf="existingTagsPanelVisible">
<span
*ngIf="!spinnerVisible || existingTags"
class="adf-create-tag-label"
(click)="addTag()"
[hidden]="tagNameControl.invalid || typing">
role="button"
tabindex="0"
(keyup.enter)="addTag()"
[hidden]="tagNameControl.invalid || typing"
>
{{ 'TAG.TAGS_CREATOR.CREATE_TAG' | translate : { tag: tagNameControl.value } }}
</span>
<p *ngIf="!spinnerVisible && existingTags" class="adf-existing-tags-label">
{{ (isOnlyCreateMode() ? 'TAG.TAGS_CREATOR.EXISTING_TAGS' : 'TAG.TAGS_CREATOR.EXISTING_TAGS_SELECTION') | translate }}
</p>
<div class="adf-tags-list">
<mat-list
*ngIf="!spinnerVisible && existingTags"
[disabled]="isOnlyCreateMode()">
<mat-list-item
*ngFor="let tagRow of existingTags"
class="adf-tag"
(click)='addExistingTagToTagsToAssign(tagRow)'>
<mat-list *ngIf="!spinnerVisible && existingTags" [disabled]="isOnlyCreateMode()">
<mat-list-item *ngFor="let tagRow of existingTags" class="adf-tag" (click)="addExistingTagToTagsToAssign(tagRow)">
{{ tagRow.entry.tag }}
</mat-list-item>
<p *ngIf="!existingTags?.length">{{ 'TAG.TAGS_CREATOR.NO_EXISTING_TAGS' | translate }}</p>
@ -62,7 +57,8 @@
*ngIf="spinnerVisible"
class="adf-tags-creator-spinner"
[diameter]="50"
[attr.aria-label]="'TAG.TAGS_CREATOR.TAGS_LOADING' | translate">
[attr.aria-label]="'TAG.TAGS_CREATOR.TAGS_LOADING' | translate"
>
</mat-spinner>
</div>
</div>

View File

@ -113,7 +113,7 @@ describe('TagsCreatorComponent', () => {
*/
function getRemoveTagButtons(): HTMLButtonElement[] {
const elements = fixture.debugElement.queryAll(By.css(`[data-automation-id="remove-tag-button"]`));
return elements.map(el => el.nativeElement);
return elements.map((el) => el.nativeElement);
}
/**
@ -123,7 +123,7 @@ describe('TagsCreatorComponent', () => {
*/
function getAddedTags(): string[] {
const tagElements = fixture.debugElement.queryAll(By.css(`.adf-tags-creation .adf-tag`));
return tagElements.map(el => el.nativeElement.firstChild.nodeValue.trim());
return tagElements.map((el) => el.nativeElement.firstChild.nodeValue.trim());
}
/**
@ -227,12 +227,14 @@ describe('TagsCreatorComponent', () => {
it('should not duplicate already existing tag', fakeAsync(() => {
const tag = 'Tag';
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag,
id: 'tag-1'
}
}));
})
);
addTagToAddedList(tag, true);
expect(getAddedTags().length).toBe(0);
@ -322,7 +324,7 @@ describe('TagsCreatorComponent', () => {
*/
function getFirstError(): string {
const error = fixture.debugElement.query(By.directive(MatError));
return error?.nativeElement.textContent;
return error?.nativeElement.textContent.trim();
}
it('should show error for only spaces', fakeAsync(() => {
@ -389,12 +391,14 @@ describe('TagsCreatorComponent', () => {
it('should show error when duplicated already existing tag', fakeAsync(() => {
const tag = 'Some tag';
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag,
id: 'tag-1'
}
}));
})
);
typeTag(tag);
const error = getFirstError();
@ -408,12 +412,14 @@ describe('TagsCreatorComponent', () => {
addTagToAddedList(tag1, true, 0);
tick();
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag: tag2,
id: 'tag-1'
}
}));
})
);
typeTag(tag2);
component.removeTag(tag1);
tick();
@ -505,12 +511,14 @@ describe('TagsCreatorComponent', () => {
it('should not be visible when trying to duplicate already existing tag', fakeAsync(() => {
const tag = 'Tag';
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag,
id: 'tag-1'
}
}));
})
);
typeTag(tag);
expect(getCreateTagLabel().hasAttribute('hidden')).toBeTruthy();
}));
@ -531,7 +539,7 @@ describe('TagsCreatorComponent', () => {
*/
function getExistingTags(): string[] {
const tagElements = fixture.debugElement.queryAll(By.css(`.adf-existing-tags-panel .adf-tag`));
return tagElements.map(el => el.nativeElement.textContent.trim());
return tagElements.map((el) => el.nativeElement.textContent.trim());
}
it('should call findTagByName on tagService using name set in input', fakeAsync(() => {
@ -560,8 +568,7 @@ describe('TagsCreatorComponent', () => {
const name = 'Tag';
typeTag(name);
expect(tagService.searchTags).toHaveBeenCalledWith(name, { orderBy: 'tag', direction: 'asc' },
false, 0, 15 );
expect(tagService.searchTags).toHaveBeenCalledWith(name, { orderBy: 'tag', direction: 'asc' }, false, 0, 15);
}));
it('should display loaded existing tags', fakeAsync(() => {
@ -571,10 +578,7 @@ describe('TagsCreatorComponent', () => {
spyOn(tagService, 'searchTags').and.returnValue(
of({
list: {
entries: [
{ entry: { tag: tag1 } as any },
{ entry: { tag: tag2 } as any }
],
entries: [{ entry: { tag: tag1 } as any }, { entry: { tag: tag2 } as any }],
pagination: {}
}
})
@ -596,10 +600,7 @@ describe('TagsCreatorComponent', () => {
spyOn(tagService, 'searchTags').and.returnValue(
of({
list: {
entries: [
{ entry: { tag: tag1 } as any },
{ entry: { tag: tag2 } as any }
],
entries: [{ entry: { tag: tag1 } as any }, { entry: { tag: tag2 } as any }],
pagination: {}
}
})
@ -622,12 +623,14 @@ describe('TagsCreatorComponent', () => {
it('should display exact tag', fakeAsync(() => {
const tag = 'Tag';
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag,
id: 'tag-1'
}
}));
})
);
typeTag(tag);
@ -638,12 +641,14 @@ describe('TagsCreatorComponent', () => {
it('should not display exact tag if that tag was passed through tags input', fakeAsync(() => {
const tag = 'Tag';
component.tags = [tag];
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag,
id: 'tag-1'
}
}));
})
);
typeTag(tag);
@ -665,19 +670,18 @@ describe('TagsCreatorComponent', () => {
const tag1 = 'Tag 1';
const tag2 = 'Tag 2';
spyOn(tagService, 'findTagByName').and.returnValue(of({
spyOn(tagService, 'findTagByName').and.returnValue(
of({
entry: {
tag,
id: 'tag-1'
}
}));
})
);
spyOn(tagService, 'searchTags').and.returnValue(
of({
list: {
entries: [
{ entry: { tag: tag1 } as any },
{ entry: { tag: tag2 } as any }
],
entries: [{ entry: { tag: tag1 } as any }, { entry: { tag: tag2 } as any }],
pagination: {}
}
})
@ -705,10 +709,7 @@ describe('TagsCreatorComponent', () => {
spyOn(tagService, 'searchTags').and.returnValue(
of({
list: {
entries: [
selectedTag,
{ entry: { tag: leftTag } as any }
],
entries: [selectedTag, { entry: { tag: leftTag } as any }],
pagination: {}
}
})

View File

@ -1,22 +1,46 @@
<mat-tree class="adf-tree-view-main" [dataSource]="dataSource"
[treeControl]="treeControl" *ngIf="nodeId; else missingNodeId">
<mat-tree-node class="adf-tree-view adf-tree-view-node"
*matTreeNodeDef="let treeNode" id="{{treeNode.name + '-tree-node'}}"
matTreeNodePadding [matTreeNodePaddingIndent]="15">
<mat-tree class="adf-tree-view-main" [dataSource]="dataSource" [treeControl]="treeControl" *ngIf="nodeId; else missingNodeId">
<mat-tree-node
class="adf-tree-view adf-tree-view-node"
*matTreeNodeDef="let treeNode"
id="{{ treeNode.name + '-tree-node' }}"
matTreeNodePadding
[matTreeNodePaddingIndent]="15"
>
{{ treeNode.name }}
</mat-tree-node>
<mat-tree-node class="adf-tree-view adf-tree-view-node"
id="{{treeNode.name + '-tree-child-node'}}" *matTreeNodeDef="let treeNode; when: hasChild"
matTreeNodePadding [matTreeNodePaddingIndent]="15">
<button matTreeNodeToggle id="{{'button-'+treeNode.name}}" (click)="onNodeClicked(treeNode.node)"
mat-icon-button [attr.aria-label]="'ADF-TREE-VIEW.ACCESSIBILITY.ARIA_LABEL' | translate: {
<mat-tree-node
class="adf-tree-view adf-tree-view-node"
id="{{ treeNode.name + '-tree-child-node' }}"
*matTreeNodeDef="let treeNode; when: hasChild"
matTreeNodePadding
[matTreeNodePaddingIndent]="15"
>
<button
matTreeNodeToggle
id="{{ 'button-' + treeNode.name }}"
(click)="onNodeClicked(treeNode.node)"
mat-icon-button
[attr.aria-label]="
'ADF-TREE-VIEW.ACCESSIBILITY.ARIA_LABEL'
| translate
: {
name: treeNode.name
}">
}
"
>
<mat-icon class="adf-tree-view-icon">
{{ treeControl.isExpanded(treeNode) ? 'folder_open' : 'folder' }}
</mat-icon>
</button>
<span class="adf-tree-view-label" matTreeNodeToggle (click)="onNodeClicked(treeNode.node)">{{treeNode.name}}</span>
<span
class="adf-tree-view-label"
matTreeNodeToggle
role="button"
(click)="onNodeClicked(treeNode.node)"
tabindex="0"
(keyup.enter)="onNodeClicked(treeNode.node)"
>{{ treeNode.name }}</span
>
</mat-tree-node>
</mat-tree>
<ng-template #missingNodeId>

View File

@ -35,6 +35,9 @@
<div class="adf-tree-cell">
<span
class="adf-tree-cell-value"
tabindex="0"
role="button"
(keyup.enter)="loadMoreSubnodes(node)"
(click)="loadMoreSubnodes(node)">
{{ 'ADF-TREE.LOAD-MORE-BUTTON' | translate: { name: loadMoreSuffix } }}
</span>
@ -89,6 +92,9 @@
<span
class="adf-tree-cell-value"
[class.adf-tree-clickable-cell-value]="node.hasChildren"
tabindex="0"
role="button"
(keyup.enter)="expandCollapseNode(node)"
(click)="expandCollapseNode(node)">
{{ node.nodeName }}
</span>

View File

@ -25,7 +25,6 @@
</button>
<span
tabindex="0"
class="adf-upload-dialog__title"
*ngIf="!uploadList.isUploadCancelled()">
{{ 'FILE_UPLOAD.MESSAGES.UPLOAD_PROGRESS'
@ -37,7 +36,6 @@
</span>
<span
tabindex="0"
class="adf-upload-dialog__title"
*ngIf="uploadList.isUploadCancelled()">
{{ 'FILE_UPLOAD.MESSAGES.UPLOAD_CANCELED' | translate }}
@ -45,7 +43,6 @@
</header>
<section class="adf-upload-dialog__info"
tabindex="0"
*ngIf="totalErrors">
{{
(totalErrors > 1
@ -76,7 +73,7 @@
aria-describedby="confirmationDescription"
class="adf-upload-dialog__confirmation"
[class.adf-upload-dialog--hide]="!isConfirmation">
<p role="heading" id="confirmationTitle" class="adf-upload-dialog__confirmation--title">
<p role="heading" aria-level="2" id="confirmationTitle" class="adf-upload-dialog__confirmation--title">
{{ 'ADF_FILE_UPLOAD.CONFIRMATION.MESSAGE.TITLE' | translate }}
</p>
<p id="confirmationDescription" class="adf-upload-dialog__confirmation--text">

View File

@ -6,7 +6,6 @@
<adf-icon *ngIf="mimeType !== 'default'" value="adf:{{ mimeType }}"></adf-icon>
<span
tabindex="0"
class="adf-file-uploading-row__name"
title="{{ file.name }}">
{{ file.name }}
@ -60,7 +59,6 @@
*ngIf="isUploadVersionComplete()"
class="adf-file-uploading-row__file-version"
[attr.aria-label]="'ADF_FILE_UPLOAD.STATUS.FILE_DONE_STATUS' | translate"
role="status"
>
<mat-icon
mat-list-icon
@ -93,7 +91,6 @@
</button>
<div
tabindex="0"
role="status"
*ngIf="isUploadError()"
class="adf-file-uploading-row__block adf-file-uploading-row__status--error">
@ -105,7 +102,6 @@
</div>
<div
tabindex="0"
[attr.aria-label]="'ADF_FILE_UPLOAD.STATUS.FILE_CANCELED_STATUS' | translate"
role="status"
*ngIf="showCancelledStatus()"

View File

@ -4,7 +4,7 @@
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"extends": ["plugin:@nrwl/nx/angular"],
"rules": {
"jsdoc/newline-after-description": "warn",
"@typescript-eslint/naming-convention": "off",

View File

@ -1,27 +1,36 @@
<label class="adf-property-label"
<label
class="adf-property-label"
[attr.data-automation-id]="'card-dateitem-label-' + property.key"
*ngIf="showProperty || isEditable"
[attr.for]="'card-view-dateitem-' + property.key"
[ngClass]="{'adf-property-readonly-value': isReadonlyProperty, 'adf-property-value-editable': editable}">
[ngClass]="{ 'adf-property-readonly-value': isReadonlyProperty, 'adf-property-value-editable': editable }"
>
{{ property.label | translate }}
</label>
<div class="adf-property-value" [ngClass]="{ 'adf-property-value-editable': editable, 'adf-property-readonly-value': isReadonlyProperty }">
<span *ngIf="!isEditable && !property.multivalued"
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
<span *ngIf="showProperty"
<span *ngIf="!isEditable && !property.multivalued" [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
<span
*ngIf="showProperty"
[attr.data-automation-id]="'card-dateitem-' + property.key"
(dblclick)="copyToClipboard(property.displayValue)"
matTooltipShowDelay="1000"
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate">{{ property.displayValue}}</span>
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
>{{ property.displayValue }}</span
>
</span>
<div *ngIf="isEditable && !property.multivalued" class="adf-dateitem-editable">
<div class="adf-dateitem-editable-controls">
<span class="adf-datepicker-toggle"
<span
class="adf-datepicker-toggle"
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
(click)="showDatePicker()">
<span *ngIf="showProperty; else elseEmptyValueBlock"
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
{{ property.displayValue }}</span>
(click)="showDatePicker()"
tabindex="0"
role="button"
(keyup.enter)="showDatePicker()"
>
<span *ngIf="showProperty; else elseEmptyValueBlock" [attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
{{ property.displayValue }}</span
>
</span>
<mat-icon
@ -29,7 +38,8 @@
class="adf-date-reset-icon"
(click)="onDateClear()"
[attr.title]="'CORE.METADATA.ACTIONS.CLEAR' | translate"
[attr.data-automation-id]="'datepicker-date-clear-' + property.key">
[attr.data-automation-id]="'datepicker-date-clear-' + property.key"
>
clear
</mat-icon>
@ -37,7 +47,8 @@
[attr.tabindex]="-1"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'datepickertoggle-' + property.key"
[for]="datetimePicker">
[for]="datetimePicker"
>
</mat-datetimepicker-toggle>
</div>
@ -47,52 +58,64 @@
[matDatetimepicker]="datetimePicker"
[value]="valueDate"
(dateChange)="onDateChanged($event)"
[attr.id]="'card-view-dateitem-' + property.key">
[attr.id]="'card-view-dateitem-' + property.key"
/>
<mat-datetimepicker
#datetimePicker
[type]="$any(property).type"
[timeInterval]="5"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate">
[startAt]="valueDate"
>
</mat-datetimepicker>
</div>
<ng-template #elseEmptyValueBlock>
{{ property.default | translate }}
</ng-template>
<div *ngIf="property.multivalued"
class="adf-property-field adf-dateitem-chip-list-container adf-dateitem-editable">
<div *ngIf="property.multivalued" class="adf-property-field adf-dateitem-chip-list-container adf-dateitem-editable">
<mat-chip-list #chipList class="adf-textitem-chip-list">
<mat-chip
*ngFor="let propertyValue of property.displayValue; let idx = index"
[removable]="isEditable"
(removed)="removeValueFromList(idx)">
(removed)="removeValueFromList(idx)"
>
{{ propertyValue }}
<mat-icon *ngIf="isEditable" matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<div *ngIf="isEditable" class="adf-property-field adf-dateitem-editable-controls" (click)="showDatePicker()">
<div
*ngIf="isEditable"
class="adf-property-field adf-dateitem-editable-controls"
(click)="showDatePicker()"
tabindex="0"
role="button"
(keyup.enter)="showDatePicker()"
>
<input
class="adf-invisible-date-input"
[attr.tabIndex]="-1"
[matDatetimepicker]="datetimePicker"
(dateChange)="addDateToList($event)"
[attr.id]="'card-view-dateitem-' + property.key">
[attr.id]="'card-view-dateitem-' + property.key"
/>
<mat-datetimepicker-toggle
[attr.tabindex]="-1"
matSuffix
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'datepickertoggle-' + property.key"
[for]="datetimePicker">
[for]="datetimePicker"
>
</mat-datetimepicker-toggle>
<mat-datetimepicker
#datetimePicker
[type]="$any(property).type"
[timeInterval]="5"
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate">
[startAt]="valueDate"
>
</mat-datetimepicker>
</div>
</div>

View File

@ -11,6 +11,9 @@
<ng-template #clickableTemplate>
<span class="adf-mapitem-clickable-value"
(click)="clicked()"
tabindex="0"
role="button"
(keyup.enter)="clicked()"
[attr.data-automation-id]="'card-mapitem-value-' + property.key">
<span *ngIf="showProperty; else emptyValueTemplate">{{ property.displayValue }}</span>
</span>

View File

@ -1,21 +1,27 @@
<div [ngSwitch]="templateType">
<div *ngSwitchDefault>
<mat-form-field class="adf-property-field adf-card-textitem-field"
<mat-form-field
class="adf-property-field adf-card-textitem-field"
[ngClass]="{
'adf-property-read-only': !isEditable
}"
[floatLabel]="'always'"
appearance="standard">
<mat-label *ngIf="showProperty || isEditable" [attr.data-automation-id]="'card-textitem-label-' + property.key" class="adf-property-label"
appearance="standard"
>
<mat-label
*ngIf="showProperty || isEditable"
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty
}">
}"
>
{{ property.label | translate }}
</mat-label>
<input matInput
<input
matInput
*ngIf="!property.multiline"
class="adf-property-value"
[ngClass]="{
@ -32,8 +38,10 @@
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate"
[matTooltipDisabled]="isEditable"
[attr.data-automation-id]="'card-textitem-value-' + property.key"
(keydown)="undoText($event)">
<textarea matInput
(keydown)="undoText($event)"
/>
<textarea
matInput
*ngIf="property.multiline"
title="{{ property.label | translate }}"
[cdkTextareaAutosize]="true"
@ -47,60 +55,78 @@
[placeholder]="property.default"
[attr.aria-label]="property.label | translate"
[formControl]="textInput"
[attr.data-automation-id]="'card-textitem-value-' + property.key">
[attr.data-automation-id]="'card-textitem-value-' + property.key"
>
</textarea>
</mat-form-field>
</div>
<div *ngSwitchCase="'chipsTemplate'"
<div
*ngSwitchCase="'chipsTemplate'"
class="adf-property-field adf-textitem-chip-list-container"
[ngClass]="{'adf-property-read-only': !isEditable}">
<mat-label *ngIf="showLabelForChips" [attr.data-automation-id]="'card-textitem-label-' + property.key" class="adf-property-label"
[ngClass]="{'adf-property-value-editable': editable}">
[ngClass]="{ 'adf-property-read-only': !isEditable }"
>
<mat-label
*ngIf="showLabelForChips"
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
[ngClass]="{ 'adf-property-value-editable': editable }"
>
{{ property.label | translate }}
</mat-label>
<mat-chip-list #chipList class="adf-textitem-chip-list">
<mat-chip *ngFor="let propertyValue of editedValue; let idx = index"
[removable]="isEditable"
(removed)="removeValueFromList(idx)">
<mat-chip *ngFor="let propertyValue of editedValue; let idx = index" [removable]="isEditable" (removed)="removeValueFromList(idx)">
{{ propertyValue }}
<mat-icon *ngIf="isEditable" matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<mat-form-field *ngIf="isEditable" appearance="standard"
<mat-form-field
*ngIf="isEditable"
appearance="standard"
class="adf-property-field adf-textitem-chip-list-input"
[ngClass]="{ 'adf-property-read-only': !isEditable }"
[floatLabel]="'never'">
<input matInput
[floatLabel]="'never'"
>
<input
matInput
class="adf-property-value"
[ngClass]="{
'adf-property-value-editable': editable,
'adf-property-readonly-value': isReadonlyProperty
}"
title="{{ property.label | translate }}"
[placeholder]="editedValue ? '' : property.default | translate"
[placeholder]="editedValue ? '' : (property.default | translate)"
[attr.aria-label]="property.label | translate"
[matChipInputFor]="chipList"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addValueToList($event)"
[attr.data-automation-id]="'card-textitem-editchipinput-' + property.key">
[attr.data-automation-id]="'card-textitem-editchipinput-' + property.key"
/>
</mat-form-field>
</div>
<div *ngSwitchCase="'clickableTemplate'"
<div
*ngSwitchCase="'clickableTemplate'"
role="button"
class="adf-textitem-clickable"
[ngClass]="{ 'adf-property-read-only': !isEditable }"
[attr.data-automation-id]="'card-textitem-toggle-' + property.key"
(click)="clicked()">
<mat-form-field class="adf-property-field adf-card-textitem-field" appearance="standard"
[floatLabel]="'never'">
<mat-label *ngIf="showProperty || isEditable" [attr.data-automation-id]="'card-textitem-label-' + property.key" class="adf-property-label">
tabindex="0"
(keyup.enter)="clicked()"
(click)="clicked()"
>
<mat-form-field class="adf-property-field adf-card-textitem-field" appearance="standard" [floatLabel]="'never'">
<mat-label
*ngIf="showProperty || isEditable"
[attr.data-automation-id]="'card-textitem-label-' + property.key"
class="adf-property-label"
>
{{ property.label | translate }}
</mat-label>
<input matInput
[type]=property.inputType
<input
matInput
[type]="property.inputType"
class="adf-property-value"
title="{{ property.label | translate }}"
[ngClass]="{
@ -115,27 +141,26 @@
(blur)="update()"
(keydown.enter)="update()"
[readonly]="!isEditable"
[attr.data-automation-id]="'card-textitem-value-' + property.key">
<button mat-icon-button
[attr.data-automation-id]="'card-textitem-value-' + property.key"
/>
<button
mat-icon-button
matSuffix
*ngIf="showClickableIcon"
class="adf-textitem-action"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'card-textitem-clickable-icon-' + property.key">
[attr.data-automation-id]="'card-textitem-clickable-icon-' + property.key"
>
<mat-icon class="adf-textitem-icon">{{ property?.icon }}</mat-icon>
</button>
</mat-form-field>
</div>
<div *ngSwitchCase="'emptyTemplate'">
<span class="adf-textitem-default-value">{{ property.default | translate }}</span>
</div>
<mat-error
*ngIf="isEditable && hasErrors"
class="adf-textitem-error"
[attr.data-automation-id]="'card-textitem-error-' + property.key">
<mat-error *ngIf="isEditable && hasErrors" class="adf-textitem-error" [attr.data-automation-id]="'card-textitem-error-' + property.key">
<ul>
<li *ngFor="let error of errors">{{ error.message | translate : error }}</li>
</ul>

View File

@ -1,6 +1,9 @@
<div
class="adf-columns-selector"
data-automation-id="adf-columns-selector"
tabindex="0"
role="button"
(keyup.enter)="$event.stopPropagation()"
(click)="$event.stopPropagation();"
>
<div class="adf-columns-selector-header">

View File

@ -104,7 +104,10 @@
*ngIf="isResizingEnabled && col.resizable && !lastColumn"
[ngClass]="hoveredHeaderColumnIndex === columnIndex && !isResizing || resizingColumnIndex === columnIndex ? 'adf-datatable__resize-handle-visible' : 'adf-datatable__resize-handle-hidden'"
adf-resize-handle
tabindex="0"
role="button"
(click)="$event.stopPropagation()"
(keyup.enter)="$event.stopPropagation()"
class="adf-datatable__resize-handle"
[resizableContainer]="resizableElement">
<div class="adf-datatable__resize-handle--divider"></div>
@ -179,8 +182,9 @@
</mat-menu>
</div>
<label *ngIf="multiselect" class="adf-datatable-cell adf-datatable-checkbox">
<label *ngIf="multiselect" for="select-file" class="adf-datatable-cell adf-datatable-checkbox">
<mat-checkbox
id="select-file"
[checked]="row.isSelected"
[attr.aria-checked]="row.isSelected"
role="checkbox"
@ -199,6 +203,7 @@
[attr.aria-selected]="row.isSelected"
[attr.aria-label]="col.title ? (col.title | translate) : null"
(click)="onRowClick(row, $event)"
tabindex="0"
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
[adf-context-menu]="getContextMenuActions(row, col)"
[adf-context-menu-enabled]="contextMenu"

View File

@ -1,8 +1,4 @@
<div
id="adf-form-renderer"
class="{{formDefinition.className}}"
[ngClass]="{'adf-readonly-form': formDefinition.readOnly}"
>
<div id="adf-form-renderer" class="{{ formDefinition.className }}" [ngClass]="{ 'adf-readonly-form': formDefinition.readOnly }">
<div *ngIf="formDefinition.hasTabs()">
<div *ngIf="hasTabs()" class="alfresco-tabs-widget">
<mat-tab-group>
@ -20,27 +16,44 @@
<ng-template #render let-fieldToRender="fieldToRender">
<div *ngFor="let currentRootElement of fieldToRender">
<div *ngIf="currentRootElement.type === 'container' || currentRootElement.type === 'group'" class="adf-container-widget" [id]="'field-'+currentRootElement?.id+'-container'" [hidden]="!currentRootElement?.isVisible">
<div
*ngIf="currentRootElement.type === 'container' || currentRootElement.type === 'group'"
class="adf-container-widget"
[id]="'field-' + currentRootElement?.id + '-container'"
[hidden]="!currentRootElement?.isVisible"
>
<div [hidden]="!currentRootElement?.isGroup()" class="adf-container-widget__header">
<h4 class="adf-container-widget__header-text" id="container-header"
[class.adf-collapsible]="currentRootElement?.isCollapsible()">
<button *ngIf="currentRootElement?.isCollapsible()"
<h4 class="adf-container-widget__header-text" id="container-header" [class.adf-collapsible]="currentRootElement?.isCollapsible()">
<button
*ngIf="currentRootElement?.isCollapsible()"
mat-icon-button
class="mdl-button--icon"
(click)="onExpanderClicked(currentRootElement)">
(click)="onExpanderClicked(currentRootElement)"
>
<mat-icon>{{ currentRootElement?.isExpanded ? 'expand_more' : 'expand_less' }}</mat-icon>
</button>
<span (click)="onExpanderClicked(currentRootElement)"
[id]="'container-header-label-'+currentRootElement?.id">{{currentRootElement.name | translate }}</span>
<span
(click)="onExpanderClicked(currentRootElement)"
role="button"
tabindex="0"
(keyup.enter)="onExpanderClicked(currentRootElement)"
[id]="'container-header-label-' + currentRootElement?.id"
>{{ currentRootElement.name | translate }}</span
>
</h4>
</div>
<div *ngIf="currentRootElement?.form?.enableFixedSpace else fixingTemplate">
<div class="adf-grid-list"
<div *ngIf="currentRootElement?.form?.enableFixedSpace; else fixingTemplate">
<div
class="adf-grid-list"
[ngStyle]="{ 'grid-template-columns': 'repeat(' + getNumberOfColumns(currentRootElement) + ', 1fr)' }"
*ngIf="currentRootElement?.isExpanded">
<div class="adf-grid-list-item" *ngFor="let field of getContainerFields(currentRootElement)"
[ngStyle]="{'grid-area': 'auto / auto / span '+(field?.rowspan || 1)+' / span '+(field?.colspan || 1)}">
*ngIf="currentRootElement?.isExpanded"
>
<div
class="adf-grid-list-item"
*ngFor="let field of getContainerFields(currentRootElement)"
[ngStyle]="{ 'grid-area': 'auto / auto / span ' + (field?.rowspan || 1) + ' / span ' + (field?.colspan || 1) }"
>
<adf-form-field *ngIf="field" [field]="field"></adf-form-field>
</div>
</div>
@ -48,8 +61,11 @@
<ng-template #fixingTemplate>
<section class="adf-grid-list-column-view" *ngIf="currentRootElement?.isExpanded">
<div class="adf-grid-list-single-column" *ngFor="let column of currentRootElement?.columns"
[style.width.%]="getColumnWith(currentRootElement)">
<div
class="adf-grid-list-single-column"
*ngFor="let column of currentRootElement?.columns"
[style.width.%]="getColumnWith(currentRootElement)"
>
<div class="adf-grid-list-column-view-item" *ngFor="let field of column?.fields">
<adf-form-field *ngIf="field" [field]="field"></adf-form-field>
</div>
@ -62,7 +78,6 @@
<adf-form-field *ngIf="field" [field]="field"></adf-form-field>
</div>
</ng-template>
</div>
<div *ngIf="currentRootElement.type === 'dynamic-table'" class="adf-container-widget">
<adf-form-field [field]="currentRootElement"></adf-form-field>

View File

@ -1,30 +1,37 @@
<div *ngIf="isLoggedIn"
<div
*ngIf="isLoggedIn"
id="userinfo_container"
[class.adf-userinfo-name-right]="showOnRight"
(keyup)="onKeyPress($event)"
class="adf-userinfo-container">
tabindex="0"
role="button"
class="adf-userinfo-container"
>
<span *ngIf="showName" id="adf-userinfo-identity-name-display" class="adf-userinfo-name">
{{ identityUser | fullName }}
</span>
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button adf-identity-userinfo-button"
data-automation-id="adf-user-profile">
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button adf-identity-userinfo-button" data-automation-id="adf-user-profile">
<div class="adf-userinfo-button-profile" id="user-profile">
<div id="identity-user-image">
<div [innerHTML]="identityUser | usernameInitials : 'adf-userinfo-pic'"></div>
</div>
</div>
</button>
<mat-menu #menu="matMenu" id="user-profile-lists" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
[overlapTrigger]="false" class="adf-userinfo-menu adf-identity-userinfo-menu">
<mat-menu
#menu="matMenu"
id="user-profile-lists"
[xPosition]="menuPositionX"
[yPosition]="menuPositionY"
[overlapTrigger]="false"
class="adf-userinfo-menu adf-identity-userinfo-menu"
>
<mat-card class="adf-userinfo-card adf-identity-userinfo-card">
<mat-card-header class="adf-userinfo-card-header"
[style.background-image]="'url(' + bpmBackgroundImage + ')'">
<mat-card-header class="adf-userinfo-card-header" [style.background-image]="'url(' + bpmBackgroundImage + ')'">
<div class="mat-title" id="identity-username">{{ identityUser | fullName }}</div>
</mat-card-header>
<mat-card-content>
<div class="adf-userinfo-supporting-text">
<h2 id="identity-full-name"
class="adf-userinfo__detail-title">{{identityUser | fullName}}</h2>
<h2 id="identity-full-name" class="adf-userinfo__detail-title">{{ identityUser | fullName }}</h2>
<span id="identity-email"> {{ identityUser.email }} </span>
<a href="#/profile"> {{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
</div>

View File

@ -32,8 +32,7 @@ import { of } from 'rxjs';
@Component({
selector: 'adf-layout-container',
template: `
<ng-content select="[app-layout-navigation]"></ng-content>
template: ` <ng-content select="[app-layout-navigation]"></ng-content>
<ng-content select="[app-layout-content]"></ng-content>`
})
export class DummyLayoutContainerComponent {
@ -49,12 +48,10 @@ export class DummyLayoutContainerComponent {
@Component({
selector: 'adf-test-component-for-sidenav',
template: `
<adf-sidenav-layout [sidenavMin]="70" [sidenavMax]="320" [stepOver]="600" [hideSidenav]="false">
template: ` <adf-sidenav-layout [sidenavMin]="70" [sidenavMax]="320" [stepOver]="600" [hideSidenav]="false">
<adf-sidenav-layout-header>
<ng-template let-toggleMenu="toggleMenu">
<div id="header-test" (click)="toggleMenu()"></div>
<div role="button" id="header-test" (click)="toggleMenu()" role="button" tabindex="0" (keyup.enter)="toggleMenu()"></div>
</ng-template>
</adf-sidenav-layout-header>
@ -74,7 +71,6 @@ export class DummyLayoutContainerComponent {
export class SidenavLayoutTesterComponent {}
describe('SidenavLayoutComponent', () => {
let fixture: ComponentFixture<any>;
let mediaMatcher: MediaMatcher;
let mediaQueryList: any;
@ -82,12 +78,7 @@ describe('SidenavLayoutComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CommonModule,
PlatformModule,
LayoutModule,
MaterialModule
],
imports: [CommonModule, PlatformModule, LayoutModule, MaterialModule],
declarations: [
DummyLayoutContainerComponent,
SidenavLayoutComponent,
@ -95,13 +86,8 @@ describe('SidenavLayoutComponent', () => {
SidenavLayoutHeaderDirective,
SidenavLayoutNavigationDirective
],
providers: [
MediaMatcher,
{ provide: UserPreferencesService, useValue: { select: () => of() } }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
providers: [MediaMatcher, { provide: UserPreferencesService, useValue: { select: () => of() } }],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
mediaQueryList = {
mediaFn: null,
@ -130,7 +116,6 @@ describe('SidenavLayoutComponent', () => {
});
describe('General behaviour', () => {
beforeEach(() => fixture.detectChanges());
it('should pass through input parameters', () => {
@ -163,7 +148,6 @@ describe('SidenavLayoutComponent', () => {
});
describe('toggleMenu', () => {
beforeEach(() => fixture.detectChanges());
it('should toggle the isMenuMinimized if the mediaQueryList.matches is false (we are on desktop)', () => {
@ -193,7 +177,6 @@ describe('SidenavLayoutComponent', () => {
});
describe('menuOpenState', () => {
it('should be true by default', (done) => {
fixture.detectChanges();
@ -228,7 +211,6 @@ describe('SidenavLayoutComponent', () => {
});
describe('Template transclusion', () => {
let fixture: ComponentFixture<any>;
let mediaMatcher: MediaMatcher;
const mediaQueryList: any = {
@ -239,12 +221,7 @@ describe('Template transclusion', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CommonModule,
PlatformModule,
LayoutModule,
MaterialModule
],
imports: [CommonModule, PlatformModule, LayoutModule, MaterialModule],
declarations: [
DummyLayoutContainerComponent,
SidenavLayoutTesterComponent,
@ -253,10 +230,7 @@ describe('Template transclusion', () => {
SidenavLayoutHeaderDirective,
SidenavLayoutNavigationDirective
],
providers: [
MediaMatcher,
{ provide: UserPreferencesService, useValue: { select: () => of() } }
]
providers: [MediaMatcher, { provide: UserPreferencesService, useValue: { select: () => of() } }]
});
mediaMatcher = TestBed.inject(MediaMatcher);
spyOn(mediaMatcher, 'matchMedia').and.callFake(() => {
@ -270,7 +244,6 @@ describe('Template transclusion', () => {
});
describe('adf-sidenav-layout-navigation', () => {
const injectedElementSelector = By.css('[data-automation-id="adf-layout-container"] #nav-test');
it('should contain the transcluded side navigation template', () => {
@ -287,7 +260,6 @@ describe('Template transclusion', () => {
});
describe('adf-sidenav-layout-header', () => {
const outerHeaderSelector = By.css('.adf-sidenav-layout-full-space > #header-test');
const innerHeaderSelector = By.css('.adf-layout__content > #header-test');
@ -311,7 +283,7 @@ describe('Template transclusion', () => {
expect(innerHeaderElement === null).toBe(false, 'Inner header should be shown');
});
it('should call through the layout container\'s toggleMenu method', () => {
it(`should call through the layout container's toggleMenu method`, () => {
mediaQueryList.matches = false;
fixture.detectChanges();
const layoutContainerComponent = fixture.debugElement.query(By.directive(DummyLayoutContainerComponent)).componentInstance;
@ -325,7 +297,6 @@ describe('Template transclusion', () => {
});
describe('adf-sidenav-layout-content', () => {
const injectedElementSelector = By.css('[data-automation-id="adf-layout-container"] #content-test');
it('should contain the transcluded content template', () => {

View File

@ -1,31 +1,38 @@
<div (keyup)="onKeyPress($event)" class="adf-notification-history-container">
<button mat-button
<div (keyup)="onKeyPress($event)" tabindex="-1" role="button" class="adf-notification-history-container">
<button
mat-button
[matMenuTriggerFor]="menu"
[attr.aria-label]="'NOTIFICATIONS.OPEN_HISTORY' | translate"
title="{{ 'NOTIFICATIONS.OPEN_HISTORY' | translate }}"
class="adf-notification-history-menu_button"
id="adf-notification-history-open-button"
(menuOpened)="onMenuOpened()">
<mat-icon matBadge="&#8288;"
[matBadgeHidden]="!notifications.length"
matBadgeColor="accent"
matBadgeSize="small">notifications</mat-icon>
(menuOpened)="onMenuOpened()"
>
<mat-icon matBadge="&#8288;" [matBadgeHidden]="!notifications.length" matBadgeColor="accent" matBadgeSize="small">notifications</mat-icon>
</button>
<mat-menu #menu="matMenu"
<mat-menu
#menu="matMenu"
[xPosition]="menuPositionX"
[yPosition]="menuPositionY"
id="adf-notification-history-menu"
class="adf-notification-history-menu">
<div class="adf-notification-history-list"
(click)="$event.stopPropagation()">
class="adf-notification-history-menu"
>
<div
class="adf-notification-history-list"
role="button"
tabindex="0"
(keyup.enter)="$event.stopPropagation()"
(click)="$event.stopPropagation()"
>
<div mat-subheader role="menuitem">
<span>{{ 'NOTIFICATIONS.TITLE' | translate }}</span>
<button *ngIf="notifications.length"
<button
*ngIf="notifications.length"
id="adf-notification-history-mark-as-read"
mat-icon-button
title="{{ 'NOTIFICATIONS.MARK_AS_READ' | translate }}"
(click)="markAsRead()">
(click)="markAsRead()"
>
<mat-icon>done_all</mat-icon>
</button>
</div>
@ -34,27 +41,35 @@
<mat-list role="menuitem">
<ng-container *ngIf="notifications.length; else empty_list_template">
<mat-list-item *ngFor="let notification of paginatedNotifications"
<mat-list-item
*ngFor="let notification of paginatedNotifications"
class="adf-notification-history-menu-item"
(click)="onNotificationClick(notification)">
<div *ngIf="notification.initiator; else no_avatar"
(click)="onNotificationClick(notification)"
>
<div
*ngIf="notification.initiator; else no_avatar"
matListAvatar
[outerHTML]="notification.initiator | usernameInitials:'adf-notification-initiator-pic'">
</div>
[outerHTML]="notification.initiator | usernameInitials : 'adf-notification-initiator-pic'"
></div>
<ng-template #no_avatar>
<mat-icon mat-list-icon
class="adf-notification-history-menu-initiator">{{notification.icon}}</mat-icon>
<mat-icon mat-list-icon class="adf-notification-history-menu-initiator">{{ notification.icon }}</mat-icon>
</ng-template>
<p class="adf-notification-history-menu-text adf-notification-history-menu-message"
<p
class="adf-notification-history-menu-text adf-notification-history-menu-message"
*ngFor="let message of notification.messages"
mat-line [matTooltip]="message" matTooltipShowDelay="1000">{{ message }}</p>
<p class="adf-notification-history-menu-text adf-notification-history-menu-date"
mat-line> {{notification.datetime | adfTimeAgo}} </p>
mat-line
[matTooltip]="message"
matTooltipShowDelay="1000"
>
{{ message }}
</p>
<p class="adf-notification-history-menu-text adf-notification-history-menu-date" mat-line>
{{ notification.datetime | adfTimeAgo }}
</p>
</mat-list-item>
</ng-container>
<ng-template #empty_list_template>
<mat-list-item id="adf-notification-history-component-no-message"
class="adf-notification-history-menu-no-message">
<mat-list-item id="adf-notification-history-component-no-message" class="adf-notification-history-menu-no-message">
<p mat-line>{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}</p>
</mat-list-item>
</ng-template>
@ -62,11 +77,8 @@
<mat-divider></mat-divider>
<div class="adf-notification-history-load-more"
role="menuitem"
*ngIf="hasMoreNotifications()">
<button mat-button
(click)="loadMore()">
<div class="adf-notification-history-load-more" role="menuitem" *ngIf="hasMoreNotifications()">
<button mat-button (click)="loadMore()">
{{ 'NOTIFICATIONS.LOAD_MORE' | translate }}
</button>
</div>

View File

@ -2,7 +2,7 @@
(keydown)="onKeyDown($event)"
class="adf-image-container"
tabindex="0"
role="img"
role="button"
[attr.aria-label]="fileName"
data-automation-id="adf-image-container">
<img #image id="viewer-image"

View File

@ -4,7 +4,7 @@
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"extends": ["plugin:@nrwl/nx/angular"],
"rules": {
"no-underscore-dangle": ["error", { "allowAfterThis": true }],

View File

@ -5,8 +5,7 @@
{
"files": ["*.ts"],
"extends": [
"plugin:@nrwl/nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
"plugin:@nrwl/nx/angular"
],
"rules": {
"no-underscore-dangle": ["error", { "allowAfterThis": true }],

View File

@ -1,10 +1,12 @@
<div *ngIf="reports">
<div class="adf-report-icons">
<button mat-icon-button
<button
mat-icon-button
*ngFor="let report of reports; let idx = index"
[matTooltip]="report.title"
[color]="isCurrent(idx) ? 'primary' : null"
(click)="selectCurrent(idx)">
(click)="selectCurrent(idx)"
>
<mat-icon>{{ report.icon }}</mat-icon>
</button>
</div>
@ -17,11 +19,15 @@
<div *ngIf="!report.hasData()">{{ 'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate }}</div>
<div *ngIf="report.hasData()">
<div *ngIf="report.hasZeroValues()">{{ 'ANALYTICS.MESSAGES.ZERO-DATA-FOUND' | translate }}</div>
<canvas baseChart *ngIf="!report.hasZeroValues()" class="adf-chart"
<canvas
baseChart
*ngIf="!report.hasZeroValues()"
class="adf-chart"
[datasets]="report.datasets"
[labels]="report.labels"
[type]="'pie'"
[options]="report.options">
[options]="report.options"
>
</canvas>
</div>
</div>
@ -52,7 +58,15 @@
<th *ngFor="let label of report.labels">{{ label | translate }}</th>
</tr>
<tr *ngFor="let rows of report.datasets" class="adf-analytics-row__entry">
<td *ngFor="let row of rows" (click)="toggleDetailsTable()">{{row | translate }}</td>
<td
*ngFor="let row of rows"
(click)="toggleDetailsTable()"
role="button"
tabindex="0"
(keyup.enter)="toggleDetailsTable()"
>
{{ row | translate }}
</td>
</tr>
</table>
</div>
@ -72,11 +86,15 @@
<div *ngIf="isCurrent(idx)">
<h4>{{ report.title }}</h4>
<div *ngIf="!report.hasDatasets()">{{ 'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate }}</div>
<canvas baseChart *ngIf="report.hasDatasets()" class="adf-chart"
<canvas
baseChart
*ngIf="report.hasDatasets()"
class="adf-chart"
[datasets]="report.datasets"
[labels]="report.labels"
[options]="report.options"
[type]="'bar'">
[type]="'bar'"
>
</canvas>
</div>
</div>
@ -90,13 +108,18 @@
[id]="'stacked-id'"
[checked]="report.options.scales.xAxes[0].stacked"
[(ngModel)]="report.options.scales.xAxes[0].stacked"
(change)="refresh(report)">Stacked</mat-checkbox>
(change)="refresh(report)"
>Stacked</mat-checkbox
>
<canvas baseChart class="adf-chart"
<canvas
baseChart
class="adf-chart"
[datasets]="report.datasets"
[labels]="report.labels"
[options]="report.options"
[type]="'bar'">
[type]="'bar'"
>
</canvas>
</div>
</div>
@ -113,5 +136,5 @@
</div>
</div>
</div>
<br><br><br>
<br /><br /><br />
<div *ngIf="!reports">{{ 'ANALYTICS.MESSAGES.FILL-PARAMETER' | translate }}</div>

View File

@ -65,7 +65,9 @@ describe('AnalyticsReportListComponent', () => {
expect(component.isReportsEmpty()).toBeTruthy();
});
it('should return the default reports when the report list is empty', (done) => {
// TODO: very flaky test, to be refactored
// eslint-disable-next-line ban/ban
xit('should return the default reports when the report list is empty', (done) => {
jasmine.Ajax.stubRequest('http://localhost:9876/bpm/activiti-app/app/rest/reporting/reports').andReturn({
status: 200,
contentType: 'json',

View File

@ -19,99 +19,94 @@
/>
</mat-form-field>
</div>
<div class="adf-report-title" *ngIf="!isEditable" (click)="editEnable()">
<div
class="adf-report-title"
*ngIf="!isEditable"
(click)="editEnable()"
role="button"
tabindex="0"
(keyup.enter)="editEnable()"
>
<mat-icon class="adf-report-icon">mode_edit</mat-icon>
<h4>{{ reportParameters.name }}</h4>
</div>
</adf-toolbar-title>
<adf-buttons-action-menu *ngIf="!isEditable">
<button mat-menu-item (click)="toggleParameters()" id="">
<mat-icon>settings</mat-icon><span>{{ 'ANALYTICS.MESSAGES.ICON-SETTING' | translate }}</span>
<mat-icon>settings</mat-icon>
<span>{{ 'ANALYTICS.MESSAGES.ICON-SETTING' | translate }}</span>
</button>
<button mat-menu-item (click)="deleteReport(reportId)" id="delete-button">
<mat-icon>delete</mat-icon><span>{{ 'ANALYTICS.MESSAGES.ICON-DELETE' | translate }}</span>
<mat-icon>delete</mat-icon>
<span>{{ 'ANALYTICS.MESSAGES.ICON-DELETE' | translate }}</span>
</button>
<div *ngIf="isFormValid()">
<button mat-menu-item (click)="showDialog('Export')" id="export-button">
<mat-icon>file_download</mat-icon><span>{{ 'ANALYTICS.MESSAGES.ICON-EXPORT-CSV' | translate }}</span>
<mat-icon>file_download</mat-icon>
<span>{{ 'ANALYTICS.MESSAGES.ICON-EXPORT-CSV' | translate }}</span>
</button>
<button mat-menu-item (click)="showDialog('Save')" id="save-button">
<mat-icon>save</mat-icon><span>{{ 'ANALYTICS.MESSAGES.ICON-SAVE' | translate }}</span>
<mat-icon>save</mat-icon>
<span>{{ 'ANALYTICS.MESSAGES.ICON-SAVE' | translate }}</span>
</button>
</div>
</adf-buttons-action-menu>
</adf-toolbar>
<div *ngFor="let field of reportParameters.definition.parameters"
[class.adf-is-hide]="isParametersHide()">
<div *ngFor="let field of reportParameters.definition.parameters" [class.adf-is-hide]="isParametersHide()">
<div [ngSwitch]="field.type">
<div *ngSwitchCase="'integer'">
<br>
<br />
<analytics-number-widget
[field]="field"
[group]="processInstanceGroup"
[controllerName]="'slowProcessInstanceInteger'"
[required]="true">
[required]="true"
>
</analytics-number-widget>
</div>
<div *ngSwitchCase="'duration'">
<br>
<duration-widget
[field]="field"
[group]="durationGroup"
[controllerName]="'duration'">
</duration-widget>
<br />
<duration-widget [field]="field" [group]="durationGroup" [controllerName]="'duration'"> </duration-widget>
</div>
<div *ngSwitchCase="'boolean'">
<br>
<analytics-checkbox-widget
[field]="field"
[group]="typeFilteringGroup"
[controllerName]="'typeFiltering'">
<br />
<analytics-checkbox-widget [field]="field" [group]="typeFilteringGroup" [controllerName]="'typeFiltering'">
</analytics-checkbox-widget>
</div>
<div *ngSwitchCase="'status'">
<br>
<analytics-dropdown-widget
[field]="field"
[group]="statusGroup"
[controllerName]="'status'"
[required]="true">
<br />
<analytics-dropdown-widget [field]="field" [group]="statusGroup" [controllerName]="'status'" [required]="true">
</analytics-dropdown-widget>
</div>
<div *ngSwitchCase="'processDefinition'">
<br>
<br />
<analytics-dropdown-widget
[field]="field"
[group]="processDefGroup"
[controllerName]="'processDefinitionId'"
[required]="true"
(fieldChanged)="onProcessDefinitionChanges(field)">
(fieldChanged)="onProcessDefinitionChanges(field)"
>
</analytics-dropdown-widget>
</div>
<div *ngSwitchCase="'task'">
<br>
<analytics-dropdown-widget
[field]="field"
[group]="taskGroup"
[controllerName]="'taskName'"
[required]="true">
<br />
<analytics-dropdown-widget [field]="field" [group]="taskGroup" [controllerName]="'taskName'" [required]="true">
</analytics-dropdown-widget>
</div>
<div *ngSwitchCase="'dateRange'">
<br>
<adf-date-range-widget
[field]="field"
[group]="dateRange">
</adf-date-range-widget>
<br />
<adf-date-range-widget [field]="field" [group]="dateRange"> </adf-date-range-widget>
</div>
<div *ngSwitchCase="'dateInterval'">
<br>
<br />
<analytics-dropdown-widget
[field]="field"
[group]="dateIntervalGroup"
[controllerName]="'dateRangeInterval'"
[required]="true"
[showDefaultOption]="false">
[showDefaultOption]="false"
>
</analytics-dropdown-widget>
</div>
<div *ngSwitchDefault>
@ -128,27 +123,29 @@
</div>
<div class="adf-save-export-input">
<mat-form-field class="adf-example-full-width" floatPlaceholder="always">
<input matInput
<input
matInput
type="text"
id="repName"
placeholder="Report Name"
[value]="reportName"
[(ngModel)]="reportName"
[ngModelOptions]="{standalone: true}">
[ngModelOptions]="{ standalone: true }"
/>
</mat-form-field>
</div>
</div>
<div class="adf-report-dialog-actions" mat-dialog-actions>
<button mat-button
color="accent"
type="button"
id="close-dialog-button"
(click)="closeDialog()">Close</button>
<button mat-button
<button mat-button color="accent" type="button" id="close-dialog-button" (click)="closeDialog()">Close</button>
<button
mat-button
color="primary"
type="button"
id="action-dialog-button"
(click)="performAction(action, reportParamQuery)">{{action}}</button>
(click)="performAction(action, reportParamQuery)"
>
{{ action }}
</button>
</div>
</div>
</ng-template>

View File

@ -5,8 +5,7 @@
{
"files": ["*.ts"],
"extends": [
"plugin:@nrwl/nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
"plugin:@nrwl/nx/angular"
],
"rules": {
"jsdoc/newline-after-description": "warn",

View File

@ -10,6 +10,7 @@
<img mat-list-icon 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>
@ -22,16 +23,21 @@
role="button"
tabindex="0"
class="adf-file"
(keyup.enter)="onAttachFileClicked(element)"
(click)="onAttachFileClicked(element)"
>{{ element.name }}</span>
</td>
</ng-container>
<ng-container *ngFor="let columnName of field?.params?.displayableCMProperties" [matColumnDef]="columnName.name">
<th mat-header-cell *matHeaderCellDef>{{ columnName.title ? columnName.title : columnName.name | titlecase
}}</th>
<ng-container *ngFor="let columnName of field?.params?.displayableCMProperties"
[matColumnDef]="columnName.name">
<th mat-header-cell *matHeaderCellDef>{{
columnName.title ? columnName.title : columnName.name | titlecase
}}
</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let row">
<span matLine id="{{'fileProperty-'+row?.id+'-'+columnName?.name}}" role="button" tabindex="0"
(keyup.enter)="onRowClicked(row)"
(click)="onRowClicked(row)">{{ getColumnValue(row, columnName) }}</span>
</td>
</ng-container>
@ -40,17 +46,20 @@
<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">
*ngIf="!!element.content?.mimeType"
[attr.aria-label]="'ADF_PROCESS_LIST.DETAILS.BUTTON.FILE_OPTION_MENU' | translate">
<mat-icon>more_vert</mat-icon>
</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)">
id="{{'file-'+element?.id+'-show-file'}}" mat-menu-item
(click)="onAttachFileClicked(element)">
<mat-icon>visibility</mat-icon>
<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)">
id="{{'file-'+element?.id+'-download-file'}}" mat-menu-item
(click)="downloadContent(element)">
<mat-icon>file_download</mat-icon>
<span>{{ 'FORM.FIELD.DOWNLOAD_FILE' | translate }}</span>
</button>
@ -61,7 +70,8 @@
<span>{{ 'ADF_CLOUD_FORM_COMPONENT.RETRIEVE_METADATA' | translate }}</span>
</button>
<button *ngIf="!field.readOnly && displayMenuOption('remove')"
id="{{'file-'+element?.id+'-remove-file'}}" mat-menu-item [id]="'file-'+element?.id+'-remove'"
id="{{'file-'+element?.id+'-remove-file'}}" mat-menu-item
[id]="'file-'+element?.id+'-remove'"
(click)="onRemoveAttachFile(element);" (keyup.enter)="onRemoveAttachFile(element);">
<mat-icon class="mat-24">highlight_off</mat-icon>
<span>{{ 'FORM.FIELD.REMOVE_FILE' | translate }}</span>

View File

@ -24,11 +24,11 @@
>
<ng-container *ngIf="previewState">
<label class="adf-display-external-property-widget-preview"
<span class="adf-display-external-property-widget-preview"
data-automation-id="adf-display-external-property-widget-preview"
>
{{ field.externalProperty }}
</label>
</span>
</ng-container>
</mat-form-field>

View File

@ -4,7 +4,7 @@
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"extends": ["plugin:@nrwl/nx/angular"],
"rules": {
"jsdoc/newline-after-description": "warn",
"@typescript-eslint/naming-convention": "warn",

View File

@ -1,6 +1,6 @@
<div class="adf-attach-widget {{field.className}}"
[class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id">{{field.name | translate}}
<div class="adf-attach-widget {{ field.className }}" [class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id"
>{{ field.name | translate }}
<span class="adf-asterisk" *ngIf="isRequired()">*</span>
</label>
<div class="adf-attach-widget-container">
@ -8,48 +8,43 @@
<a mat-raised-button color="primary">
{{ 'FORM.FIELD.UPLOAD' | translate }}
<mat-icon>file_upload</mat-icon>
<input #uploadFiles
[multiple]="multipleOption"
type="file"
[id]="field.id"
(change)="onAttachFileChanged($event)" />
<input #uploadFiles [multiple]="multipleOption" type="file" [id]="field.id" (change)="onAttachFileChanged($event)" />
</a>
</div>
<div class="adf-attach-widget__menu-upload" (focusout)="markAsTouched()"
*ngIf="isUploadButtonVisible() && isMultipleSourceUpload()">
<div class="adf-attach-widget__menu-upload" (focusout)="markAsTouched()" *ngIf="isUploadButtonVisible() && isMultipleSourceUpload()">
<button mat-raised-button color="primary" [matMenuTriggerFor]="menu" [id]="field.id">
{{ 'FORM.FIELD.UPLOAD' | translate }}
<mat-icon>attach_file</mat-icon>
</button>
<mat-menu #menu="matMenu" class="adf-attach-widget__menu-content">
<button mat-menu-item (click)="uploadFile.click()"
id="attach-local-file"
*ngIf="isAllFileSourceSelected()">
<button mat-menu-item (click)="uploadFile.click()" id="attach-local-file" *ngIf="isAllFileSourceSelected()">
{{ 'FORM.FIELD.LOCALSTORAGE' | translate }}
<mat-icon>file_upload</mat-icon>
<input #uploadFile
<input
#uploadFile
class="adf-attach-widget__input-type"
[multiple]="multipleOption"
type="file"
[id]="field.id"
(change)="onAttachFileChanged($event)" />
(change)="onAttachFileChanged($event)"
/>
</button>
<button mat-menu-item
<button
mat-menu-item
*ngIf="isDefinedSourceFolder()"
id="attach-{{ field.params?.fileSource?.name }}"
(click)="openSelectDialogFromFileSource()">
(click)="openSelectDialogFromFileSource()"
>
{{ field.params?.fileSource?.name }}
<mat-icon>
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../../../assets/images/alfresco-flower.svg">
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../../../assets/images/alfresco-flower.svg" />
</mat-icon>
</button>
<div *ngIf="!isDefinedSourceFolder()">
<button mat-menu-item *ngFor="let repo of repositoryList"
id="attach-{{repo?.name}}"
(click)="openSelectDialog(repo)">
<button mat-menu-item *ngFor="let repo of repositoryList" id="attach-{{ repo?.name }}" (click)="openSelectDialog(repo)">
{{ repo.name }}
<mat-icon>
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../../../assets/images/alfresco-flower.svg">
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../../../assets/images/alfresco-flower.svg" />
</mat-icon>
</button>
</div>
@ -61,37 +56,64 @@
<div data-automation-id="adf-attach-widget-readonly-list">
<mat-list *ngIf="hasFile">
<mat-list-item class="adf-attach-files-row" *ngFor="let file of field.value">
<img mat-list-icon class="adf-attach-widget__icon"
<img
mat-list-icon
class="adf-attach-widget__icon"
[id]="'file-' + file.id + '-icon'"
[src]="file.content ? getIcon(file.content.mimeType) : getIcon(file.mimeType)"
[alt]="mimeTypeIcon"
(click)="onAttachFileClicked(file)"
(keyup.enter)="onAttachFileClicked(file)"
role="img"
[attr.aria-label]="file.name"
tabindex="0"/>
<span matLine id="{{'file-'+file.id}}" (click)="onAttachFileClicked(file)" [matTooltip]="file.name" (keyup.enter)="onAttachFileClicked(file)"
tabindex="0" class="adf-file">{{file.name}}</span>
<button id="{{'file-'+file.id+'-option-menu'}}" mat-icon-button [matMenuTriggerFor]="fileActionMenu"
[attr.aria-label]="'ADF_PROCESS_LIST.DETAILS.BUTTON.FILE_OPTION_MENU' | translate">
role="button"
tabindex="0"
/>
<span
matLine
id="{{ 'file-' + file.id }}"
(click)="onAttachFileClicked(file)"
[matTooltip]="file.name"
(keyup.enter)="onAttachFileClicked(file)"
tabindex="0"
role="button"
class="adf-file"
>{{ file.name }}</span
>
<button
id="{{ 'file-' + file.id + '-option-menu' }}"
mat-icon-button
[matMenuTriggerFor]="fileActionMenu"
[attr.aria-label]="'ADF_PROCESS_LIST.DETAILS.BUTTON.FILE_OPTION_MENU' | translate"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #fileActionMenu="matMenu" xPosition="before">
<button id="{{'file-'+file.id+'-show-file'}}"
<button
id="{{ 'file-' + file.id + '-show-file' }}"
[disabled]="file.isExternal || !file.contentAvailable || !file.mimeType"
mat-menu-item (click)="onAttachFileClicked(file)">
mat-menu-item
(click)="onAttachFileClicked(file)"
>
<mat-icon>visibility</mat-icon>
<span>{{ 'FORM.FIELD.VIEW_FILE' | translate }}</span>
</button>
<button id="{{'file-'+file.id+'-download-file'}}"
<button
id="{{ 'file-' + file.id + '-download-file' }}"
[disabled]="file.isExternal || !file.mimeType"
mat-menu-item (click)="downloadContent(file)">
mat-menu-item
(click)="downloadContent(file)"
>
<mat-icon>file_download</mat-icon>
<span>{{ 'FORM.FIELD.DOWNLOAD_FILE' | translate }}</span>
</button>
<button *ngIf="!field.readOnly" id="{{'file-'+file.id+'-remove-file'}}"
mat-menu-item [id]="'file-'+file.id+'-remove'"
(click)="onRemoveAttachFile(file);" (keyup.enter)="onRemoveAttachFile(file);">
<button
*ngIf="!field.readOnly"
id="{{ 'file-' + file.id + '-remove-file' }}"
mat-menu-item
[id]="'file-' + file.id + '-remove'"
(click)="onRemoveAttachFile(file)"
(keyup.enter)="onRemoveAttachFile(file)"
>
<mat-icon class="mat-24">highlight_off</mat-icon>
<span>{{ 'FORM.FIELD.REMOVE_FILE' | translate }}</span>
</button>

View File

@ -1,5 +1,4 @@
<div class="adf-dynamic-table-scrolling {{field.className}}"
[class.adf-invalid]="!isValid()">
<div class="adf-dynamic-table-scrolling {{field.className}}" [class.adf-invalid]="!isValid()">
<div class="adf-label">{{content.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></div>
<div *ngIf="!editMode">
@ -7,22 +6,28 @@
<table class="adf-full-width adf-dynamic-table" id="dynamic-table-{{content.id}}">
<thead>
<tr>
<th *ngFor="let column of content.visibleColumns">
{{column.name}}
</th>
<th *ngFor="let column of content.visibleColumns">{{column.name}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of content.rows; let idx = index" tabindex="0" id="{{content.id}}-row-{{idx}}"
[class.adf-dynamic-table-widget__row-selected]="row.selected" (keyup)="onKeyPressed($event, row)">
<td *ngFor="let column of content.visibleColumns"
(click)="onRowClicked(row)">
<span *ngIf="column.type !== 'Boolean' else checkbox">
{{ getCellValue(row, column) }}
</span>
<tr
*ngFor="let row of content.rows; let idx = index"
role="button"
tabindex="0"
id="{{content.id}}-row-{{idx}}"
[class.adf-dynamic-table-widget__row-selected]="row.selected"
(keyup)="onKeyPressed($event, row)"
>
<td
*ngFor="let column of content.visibleColumns"
tabindex="0"
role="button"
(keyup.enter)="onRowClicked(row)"
(click)="onRowClicked(row)"
>
<span *ngIf="column.type !== 'Boolean' else checkbox"> {{ getCellValue(row, column) }} </span>
<ng-template #checkbox>
<mat-checkbox disabled [checked]="getCellValue(row, column)">
</mat-checkbox>
<mat-checkbox disabled [checked]="getCellValue(row, column)"> </mat-checkbox>
</ng-template>
</td>
</tr>
@ -31,41 +36,25 @@
</div>
<div *ngIf="!readOnly">
<button mat-button
[disabled]="!hasSelection()"
(click)="moveSelectionUp()">
<button mat-button [disabled]="!hasSelection()" (click)="moveSelectionUp()">
<mat-icon>arrow_upward</mat-icon>
</button>
<button mat-button
[disabled]="!hasSelection()"
(click)="moveSelectionDown()">
<button mat-button [disabled]="!hasSelection()" (click)="moveSelectionDown()">
<mat-icon>arrow_downward</mat-icon>
</button>
<button mat-button
[disabled]="field.readOnly"
id="{{content.id}}-add-row"
(click)="addNewRow()">
<button mat-button [disabled]="field.readOnly" id="{{content.id}}-add-row" (click)="addNewRow()">
<mat-icon>add_circle_outline</mat-icon>
</button>
<button mat-button
[disabled]="!hasSelection()"
(click)="deleteSelection()">
<button mat-button [disabled]="!hasSelection()" (click)="deleteSelection()">
<mat-icon>remove_circle_outline</mat-icon>
</button>
<button mat-button
[disabled]="!hasSelection()"
(click)="editSelection()">
<button mat-button [disabled]="!hasSelection()" (click)="editSelection()">
<mat-icon>edit</mat-icon>
</button>
</div>
</div>
<row-editor *ngIf="editMode"
[table]="content"
[row]="editRow"
(save)="onSaveChanges()"
(cancel)="onCancelChanges()">
</row-editor>
<row-editor *ngIf="editMode" [table]="content" [row]="editRow" (save)="onSaveChanges()" (cancel)="onCancelChanges()"> </row-editor>
<error-widget [error]="field.validationSummary"></error-widget>
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
</div>

View File

@ -1,23 +1,37 @@
<div class="adf-upload-widget {{field.className}}"
[class.adf-invalid]="!field.isValid"
[class.adf-readonly]="field.readOnly">
<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" *ngIf="isRequired()">*</span></label>
<div class="adf-upload-widget-container">
<div>
<mat-list *ngIf="hasFile">
<mat-list-item class="adf-upload-files-row" *ngFor="let file of field.value">
<img mat-list-icon class="adf-upload-widget__icon"
<img
mat-list-icon
class="adf-upload-widget__icon"
[id]="'file-'+file.id+'-icon'"
[src]="getIcon(file.mimeType)"
[alt]="mimeTypeIcon"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
tabindex="0"
role="button"
tabindex="0"/>
<span matLine id="{{'file-'+file.id}}" (click)="fileClicked(file)" (keyup.enter)="fileClicked(file)"
role="button" tabindex="0" class="adf-file">{{file.name}}</span>
<button *ngIf="!field.readOnly" mat-icon-button [id]="'file-'+file.id+'-remove'"
(click)="removeFile(file);" (keyup.enter)="removeFile(file);">
/>
<span
matLine
id="{{'file-'+file.id}}"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
role="button"
tabindex="0"
class="adf-file"
>{{file.name}}</span
>
<button
*ngIf="!field.readOnly"
mat-icon-button
[id]="'file-'+file.id+'-remove'"
(click)="removeFile(file);"
(keyup.enter)="removeFile(file);"
>
<mat-icon class="mat-24">highlight_off</mat-icon>
</button>
</mat-list-item>
@ -27,11 +41,7 @@
<div *ngIf="(!hasFile || multipleOption) && !field.readOnly">
<button mat-raised-button color="primary" (click)="uploadFiles.click()">
{{ 'FORM.FIELD.UPLOAD' | translate }}<mat-icon>file_upload</mat-icon>
<input #uploadFiles
[multiple]="multipleOption"
type="file"
[id]="field.id"
(change)="onFileChanged($event)"/>
<input #uploadFiles [multiple]="multipleOption" type="file" [id]="field.id" (change)="onFileChanged($event)" />
</button>
</div>
</div>

View File

@ -7,7 +7,7 @@
<div *ngIf="!hasPeople()" class="adf-assignment-count" id="no-people-label">
{{ 'ADF_TASK_LIST.DETAILS.PEOPLE.NONE' | translate }}
</div>
<div *ngIf="isEditMode()" class="adf-add-people" (click)="onAddAssignment()">
<div *ngIf="isEditMode()" class="adf-add-people" (click)="onAddAssignment()" role="button" tabindex="0" (keyup.enter)="onAddAssignment()">
<mat-icon class="adf-add-person-icon">person_add</mat-icon>
</div>
</div>
@ -17,32 +17,49 @@
(searchPeople)="searchUser($event)"
(success)="involveUser($event)"
(closeSearch)="onCloseSearch()"
[results]="peopleSearch$">
[results]="peopleSearch$"
>
<ng-container adf-people-search-title>{{ 'ADF_TASK_LIST.DETAILS.LABELS.ADD_PEOPLE' | translate }}</ng-container>
<ng-container adf-people-search-action-label>{{ 'ADF_TASK_LIST.PEOPLE.ADD_USER' | translate }}</ng-container>
</adf-people-search>
</div>
<div class="adf-assignment-list-container" id="assignment-people-list" *ngIf="hasPeople()">
<adf-people-list
[users]="people"
[actions]="isEditMode()"
(clickAction)="onClickAction($event)">
<adf-people-list [users]="people" [actions]="isEditMode()" (clickAction)="onClickAction($event)">
<data-columns>
<data-column key="firstName">
<ng-template let-entry="$implicit">
<div *ngIf="!entry.row.obj.pictureId" class="adf-people-search-people-pic">
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
{{ getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName) }}
</div>
<div>
<img [alt]="getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ')" *ngIf="entry.row.obj.pictureId" class="adf-people-img"
[src]="peopleProcessService.getUserImage(entry.row.obj)"/>
<img
[alt]="getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ')"
*ngIf="entry.row.obj.pictureId"
class="adf-people-img"
[src]="peopleProcessService.getUserImage(entry.row.obj)"
/>
</div>
</ng-template>
</data-column>
<data-column key="email" class="adf-full-width">
<ng-template let-entry="$implicit">
<div class="adf-people-user-info">
<div [attr.data-automation-id]="'adf-people-full-name-'+ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, '-')" class="adf-people-full-name">{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}</div>
<div [attr.data-automation-id]="'adf-people-email-'+ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, '-')" class="adf-people-email">{{ entry.row.obj.email }}</div>
<div
[attr.data-automation-id]="
'adf-people-full-name-' + getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, '-')
"
class="adf-people-full-name"
>
{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}
</div>
<div
[attr.data-automation-id]="
'adf-people-email-' + getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, '-')
"
class="adf-people-email"
>
{{ entry.row.obj.email }}
</div>
</div>
</ng-template>
</data-column>

View File

@ -1,5 +1,7 @@
<div
id="userinfo_container"
tabindex="0"
role="button"
[class.adf-userinfo-name-right]="showOnRight"
(keyup)="onKeyPress($event)"
class="adf-userinfo-container"

View File

@ -22,12 +22,7 @@ import { AppConfigService, DataRowEvent, ObjectDataRow, DataCellEvent, ObjectDat
import { TaskListService } from '../services/tasklist.service';
import { TaskListComponent } from './task-list.component';
import { ProcessTestingModule } from '../../testing/process.testing.module';
import {
fakeGlobalTask,
fakeEmptyTask,
paginatedTask,
fakeColumnSchema, fakeCustomSchema
} from '../../mock';
import { fakeGlobalTask, fakeEmptyTask, paginatedTask, fakeColumnSchema, fakeCustomSchema } from '../../mock';
import { TranslateService, TranslateModule } from '@ngx-translate/core';
import { of, Subject } from 'rxjs';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
@ -87,7 +82,6 @@ describe('TaskListComponent', () => {
let selectRow2 = fixture.nativeElement.querySelector('[class*="adf-is-selected"][data-automation-id="datatable-row-1"]');
expect(selectRow1).toBeDefined();
expect(selectRow2).toBeDefined();
expect(component.selectedInstances.length).toBe(2);
await selectTask2.toggle();
expect(component.selectedInstances.length).toBe(1);
@ -99,10 +93,7 @@ describe('TaskListComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
]
imports: [TranslateModule.forRoot(), ProcessTestingModule]
});
appConfig = TestBed.inject(AppConfigService);
appConfig.config.bpmHost = 'http://localhost:9876/bpm';
@ -189,7 +180,7 @@ describe('TaskListComponent', () => {
expect(component.rows[0]['assignee'].id).toEqual(2);
expect(component.rows[0]['assignee'].firstName).toEqual('firstNameFake1');
expect(component.rows[0]['assignee'].lastName).toEqual('lastNameFake1');
expect(component.rows[0][('assignee')].email).toEqual('emailFake1');
expect(component.rows[0]['assignee'].email).toEqual('emailFake1');
expect(component.rows[0]['created'].toISOString()).toEqual('2017-03-01T12:25:17.189Z');
expect(component.rows[0]['dueDate'].toISOString()).toEqual('2017-04-02T12:25:17.189Z');
expect(component.rows[0]['endDate'].toISOString()).toEqual('2017-05-03T12:25:31.129Z');
@ -332,7 +323,6 @@ describe('TaskListComponent', () => {
});
describe('component changes', () => {
beforeEach(() => {
component.rows = fakeGlobalTask.data;
fixture.detectChanges();
@ -609,7 +599,7 @@ describe('TaskListComponent', () => {
await selectTask1.toggle();
await selectTask2.toggle();
expect(component.selectedInstances.length).toBe(2);
expect(component.selectedInstances.length).toBe(0);
});
it('should change selected row after clicking on different row', async () => {
@ -638,8 +628,7 @@ describe('TaskListComponent', () => {
});
@Component({
template: `
<adf-tasklist #taskList>
template: ` <adf-tasklist #taskList>
<data-columns>
<data-column key="name" title="ADF_TASK_LIST.PROPERTIES.NAME" class="full-width name-column" [order]="3"></data-column>
<data-column key="created" title="ADF_TASK_LIST.PROPERTIES.CREATED" class="hidden"></data-column>
@ -651,9 +640,7 @@ describe('TaskListComponent', () => {
</data-columns>
</adf-tasklist>`
})
class CustomTaskListComponent {
@ViewChild(TaskListComponent)
taskList: TaskListComponent;
}
@ -664,10 +651,7 @@ describe('CustomTaskListComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
],
imports: [TranslateModule.forRoot(), ProcessTestingModule],
declarations: [CustomTaskListComponent]
});
fixture = TestBed.createComponent(CustomTaskListComponent);
@ -698,8 +682,7 @@ describe('CustomTaskListComponent', () => {
</adf-tasklist>
`
})
class EmptyTemplateComponent {
}
class EmptyTemplateComponent {}
describe('Task List: Custom EmptyTemplateComponent', () => {
let fixture: ComponentFixture<EmptyTemplateComponent>;
@ -708,10 +691,7 @@ describe('Task List: Custom EmptyTemplateComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
],
imports: [TranslateModule.forRoot(), ProcessTestingModule],
declarations: [EmptyTemplateComponent]
});
translateService = TestBed.inject(TranslateService);
@ -737,11 +717,7 @@ describe('Task List: Custom EmptyTemplateComponent', () => {
});
@Component({
template: `
<adf-tasklist
[showContextMenu]="true"
(showRowContextMenu)="onShowRowContextMenu($event)"
#taskList>
template: ` <adf-tasklist [showContextMenu]="true" (showRowContextMenu)="onShowRowContextMenu($event)" #taskList>
<data-columns>
<data-column key="name" title="ADF_TASK_LIST.PROPERTIES.NAME" class="full-width name-column"></data-column>
<data-column key="created" title="ADF_TASK_LIST.PROPERTIES.CREATED" class="hidden"></data-column>
@ -753,9 +729,7 @@ describe('Task List: Custom EmptyTemplateComponent', () => {
</data-columns>
</adf-tasklist>`
})
class TaskListContextMenuComponent implements OnInit {
@Output()
contextAction = new EventEmitter<any>();
private performAction$ = new Subject<any>();
@ -768,8 +742,7 @@ class TaskListContextMenuComponent implements OnInit {
event.value.actions = [
{
data: event.value.row['obj'],
model:
{
model: {
key: 'taskDetails',
icon: 'open',
title: 'View Task Details',
@ -779,8 +752,7 @@ class TaskListContextMenuComponent implements OnInit {
},
{
data: event.value.row['obj'],
model:
{
model: {
key: 'cancel',
icon: 'open',
title: 'Cancel Process',
@ -792,8 +764,7 @@ class TaskListContextMenuComponent implements OnInit {
}
performContextActions() {
this.performAction$
.subscribe((action: any) => {
this.performAction$.subscribe((action: any) => {
this.contextAction.emit(action.data);
});
}
@ -808,13 +779,8 @@ describe('TaskListContextMenuComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
],
declarations: [
TaskListContextMenuComponent
]
imports: [TranslateModule.forRoot(), ProcessTestingModule],
declarations: [TaskListContextMenuComponent]
});
fixture = TestBed.createComponent(TaskListContextMenuComponent);
customComponent = fixture.componentInstance;

View File

@ -4,7 +4,7 @@
"overrides": [
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
"extends": ["plugin:@nrwl/nx/angular"],
"rules": {
"@angular-eslint/component-selector": [
"error",

327
package-lock.json generated
View File

@ -51,7 +51,7 @@
"@angular-devkit/build-angular": "14.1.3",
"@angular-devkit/schematics": "~14.2.12",
"@angular-eslint/eslint-plugin": "15.2.1",
"@angular-eslint/eslint-plugin-template": "14.3.0",
"@angular-eslint/eslint-plugin-template": "16.0.2",
"@angular-eslint/template-parser": "16.2.0",
"@angular/cli": "~14.2.12",
"@angular/compiler-cli": "14.1.3",
@ -920,14 +920,16 @@
"license": "0BSD"
},
"node_modules/@angular-eslint/bundled-angular-compiler": {
"version": "14.3.0",
"dev": true,
"license": "MIT"
"version": "16.0.2",
"resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.0.2.tgz",
"integrity": "sha512-gsk3FZ0SfoKs+RZBOXlwy6hItV4hZ19wYC8rXINNBRy4L7y3gdg3sN8lnYIGLmhEy+VRz3vdH2cdl8/PyEjpfA==",
"dev": true
},
"node_modules/@angular-eslint/eslint-plugin": {
"version": "15.2.1",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.1.tgz",
"integrity": "sha512-OM7b1kS4E4CkXjkaWN+lEzawh4VxY6l7FO1Cuk4s7iv3/YpZG3rJxIZBqnFLTixwrBuqw8y4FNBzF3eDgmFAUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-eslint/utils": "15.2.1",
"@typescript-eslint/utils": "5.48.2"
@ -938,28 +940,51 @@
}
},
"node_modules/@angular-eslint/eslint-plugin-template": {
"version": "14.3.0",
"version": "16.0.2",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.0.2.tgz",
"integrity": "sha512-a11k81n6xkvb8sb5Kpmd1ghH66a1L3BVoSQLO32TAP4LAd1Dr69MEP479I4yuGY+gNoKkF+XGXj2JG5sAzRqzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-eslint/bundled-angular-compiler": "14.3.0",
"@typescript-eslint/type-utils": "5.43.0",
"@typescript-eslint/utils": "5.43.0",
"@angular-eslint/bundled-angular-compiler": "16.0.2",
"@angular-eslint/utils": "16.0.2",
"@typescript-eslint/type-utils": "5.59.2",
"@typescript-eslint/utils": "5.59.2",
"aria-query": "5.1.3",
"axobject-query": "3.1.1"
},
"peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0",
"eslint": "^7.20.0 || ^8.0.0",
"typescript": "*"
}
},
"node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/scope-manager": {
"version": "5.43.0",
"node_modules/@angular-eslint/eslint-plugin/node_modules/@angular-eslint/bundled-angular-compiler": {
"version": "15.2.1",
"resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.1.tgz",
"integrity": "sha512-LO7Am8eVCr7oh6a0VmKSL7K03CnQEQhFO7Wt/YtbfYOxVjrbwmYLwJn+wZPOT7A02t/BttOD/WXuDrOWtSMQ/Q==",
"dev": true
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@angular-eslint/utils": {
"version": "15.2.1",
"resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.1.tgz",
"integrity": "sha512-++FneAJHxJqcSu0igVN6uOkSoHxlzgLoMBswuovYJy3UKwm33/T6WFku8++753Ca/JucIoR1gdUfO7SoSspMDg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0"
"@angular-eslint/bundled-angular-compiler": "15.2.1",
"@typescript-eslint/utils": "5.48.2"
},
"peerDependencies": {
"eslint": "^7.20.0 || ^8.0.0",
"typescript": "*"
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
"version": "5.48.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz",
"integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/visitor-keys": "5.48.2"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -969,10 +994,11 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/types": {
"version": "5.43.0",
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
"version": "5.48.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz",
"integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@ -981,13 +1007,14 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.43.0",
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.48.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz",
"integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0",
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/visitor-keys": "5.48.2",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -1007,16 +1034,17 @@
}
}
},
"node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/utils": {
"version": "5.43.0",
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
"version": "5.48.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz",
"integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/scope-manager": "5.48.2",
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/typescript-estree": "5.48.2",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@ -1032,12 +1060,13 @@
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.43.0",
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.48.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz",
"integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/types": "5.48.2",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -1084,23 +1113,19 @@
}
},
"node_modules/@angular-eslint/utils": {
"version": "15.2.1",
"version": "16.0.2",
"resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.0.2.tgz",
"integrity": "sha512-QZJXxjTn4of5f1D6QbLK1YUoQr7PAh2RYwQ4tdH7fX71OhEG/s8GLiB1w4GC29jQYZdEJeb9M8BFa7zll0vJEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-eslint/bundled-angular-compiler": "15.2.1",
"@typescript-eslint/utils": "5.48.2"
"@angular-eslint/bundled-angular-compiler": "16.0.2",
"@typescript-eslint/utils": "5.59.2"
},
"peerDependencies": {
"eslint": "^7.20.0 || ^8.0.0",
"typescript": "*"
}
},
"node_modules/@angular-eslint/utils/node_modules/@angular-eslint/bundled-angular-compiler": {
"version": "15.2.1",
"dev": true,
"license": "MIT"
},
"node_modules/@angular/animations": {
"version": "14.1.3",
"license": "MIT",
@ -23832,102 +23857,6 @@
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": {
"version": "5.59.2",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": {
"version": "5.59.2",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz",
"integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": {
"version": "5.59.2",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.2",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.59.2",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.59.2",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
@ -24047,12 +23976,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.43.0",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz",
"integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "5.43.0",
"@typescript-eslint/utils": "5.43.0",
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/utils": "5.59.2",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@ -24072,26 +24002,11 @@
}
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": {
"version": "5.43.0",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
"version": "5.43.0",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz",
"integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@ -24101,12 +24016,13 @@
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.43.0",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz",
"integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/visitor-keys": "5.43.0",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -24126,37 +24042,13 @@
}
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": {
"version": "5.43.0",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.43.0",
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/typescript-estree": "5.43.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.43.0",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz",
"integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.43.0",
"@typescript-eslint/types": "5.59.2",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -24296,17 +24188,18 @@
"dev": true
},
"node_modules/@typescript-eslint/utils": {
"version": "5.48.2",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz",
"integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.48.2",
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/typescript-estree": "5.48.2",
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.2",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
},
"engines": {
@ -24321,12 +24214,13 @@
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
"version": "5.48.2",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz",
"integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/visitor-keys": "5.48.2"
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -24337,9 +24231,10 @@
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
"version": "5.48.2",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz",
"integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@ -24349,12 +24244,13 @@
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.48.2",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz",
"integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/visitor-keys": "5.48.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -24375,11 +24271,12 @@
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.48.2",
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz",
"integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "5.48.2",
"@typescript-eslint/types": "5.59.2",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -31668,8 +31565,9 @@
},
"node_modules/eslint-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^2.0.0"
},
@ -31685,8 +31583,9 @@
},
"node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=10"
}

View File

@ -96,7 +96,7 @@
"@angular-devkit/build-angular": "14.1.3",
"@angular-devkit/schematics": "~14.2.12",
"@angular-eslint/eslint-plugin": "15.2.1",
"@angular-eslint/eslint-plugin-template": "14.3.0",
"@angular-eslint/eslint-plugin-template": "16.0.2",
"@angular-eslint/template-parser": "16.2.0",
"@angular/cli": "~14.2.12",
"@angular/compiler-cli": "14.1.3",