AAE-23976 Fix not able to delete custom filter if the name is the same as default filter (#9991)

This commit is contained in:
Kasia Biernat
2024-07-31 10:31:31 +02:00
committed by GitHub
parent fcd9d640d2
commit 6f2255faaa
10 changed files with 84 additions and 86 deletions
@@ -8,7 +8,7 @@
<span *ngIf="showTitle"> {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}}</span> <span *ngIf="showTitle"> {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}}</span>
<div *ngIf="showFilterActions" class="adf-cloud-edit-process-filter-actions"> <div *ngIf="showFilterActions" class="adf-cloud-edit-process-filter-actions">
<ng-container *ngIf="toggleFilterActions"> <ng-container *ngIf="toggleFilterActions">
<button *ngFor="let filterAction of processFilterActions" mat-icon-button title="{{ filterAction.tooltip | translate}}" [attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType" [disabled]="isDisabledAction(filterAction)" (click)="executeFilterActions($event, filterAction)"> <button *ngFor="let filterAction of processFilterActions" mat-icon-button [title]="filterAction.tooltip | translate" [attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType" [disabled]="isDisabledAction(filterAction)" (click)="executeFilterActions($event, filterAction)">
<adf-icon [value]="filterAction.icon"></adf-icon> <adf-icon [value]="filterAction.icon"></adf-icon>
</button> </button>
</ng-container> </ng-container>
@@ -6,12 +6,12 @@
<mat-card-content class="adf-process-filter-dialog-card-content"> <mat-card-content class="adf-process-filter-dialog-card-content">
<form [formGroup]="filterForm"> <form [formGroup]="filterForm">
<mat-form-field class="adf-process-filter-name" [floatLabel]="'auto'"> <mat-form-field class="adf-process-filter-name" [floatLabel]="'auto'">
<input matInput placeholder="{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.FILTER_NAME' | translate }}" formControlName="name" id="adf-filter-name-id"> <input matInput placeholder="{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.FILTER_NAME' | translate }}" [formControl]="filterForm.controls.name" id="adf-filter-name-id">
</mat-form-field> </mat-form-field>
</form> </form>
</mat-card-content> </mat-card-content>
<mat-card-actions class='adf-process-filter-dialog-actions'> <mat-card-actions class='adf-process-filter-dialog-actions'>
<button mat-button (click)="onSaveClick()" id="adf-save-button-id" [disabled]="!isValid()"> <button mat-button (click)="onSaveClick()" id="adf-save-button-id" [disabled]="!filterForm.valid">
{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.SAVE' | translate}} {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.SAVE' | translate}}
</button> </button>
<button mat-button (click)="onCancelClick()" id="adf-cancel-button-id"> <button mat-button (click)="onCancelClick()" id="adf-cancel-button-id">
@@ -107,7 +107,6 @@ describe('ProcessFilterDialogCloudComponent', () => {
}); });
it('should able close dialog on click of cancel button', () => { it('should able close dialog on click of cancel button', () => {
component.data = { data: { name: '' } };
const cancelButton = fixture.debugElement.nativeElement.querySelector('#adf-cancel-button-id'); const cancelButton = fixture.debugElement.nativeElement.querySelector('#adf-cancel-button-id');
fixture.detectChanges(); fixture.detectChanges();
cancelButton.click(); cancelButton.click();
@@ -15,53 +15,37 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, Component, inject, ViewEncapsulation } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
@Component({ @Component({
selector: 'adf-cloud-process-filter-dialog-cloud', selector: 'adf-cloud-process-filter-dialog-cloud',
templateUrl: './process-filter-dialog-cloud.component.html', templateUrl: './process-filter-dialog-cloud.component.html',
styleUrls: ['./process-filter-dialog-cloud.component.scss'], styleUrls: ['./process-filter-dialog-cloud.component.scss'],
encapsulation: ViewEncapsulation.None changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
}) })
export class ProcessFilterDialogCloudComponent implements OnInit { export class ProcessFilterDialogCloudComponent {
public readonly dialogRef = inject(MatDialogRef<ProcessFilterDialogCloudComponent>);
public readonly data = inject(MAT_DIALOG_DATA);
// eslint-disable-next-line @typescript-eslint/naming-convention
public static ACTION_SAVE = 'SAVE'; public static ACTION_SAVE = 'SAVE';
defaultIcon = 'inbox'; defaultIcon = 'inbox';
filterForm: UntypedFormGroup; filterForm = new FormGroup({
name: new FormControl(this.data.name, [Validators.required])
constructor( });
private fb: UntypedFormBuilder,
public dialogRef: MatDialogRef<ProcessFilterDialogCloudComponent>,
@Inject(MAT_DIALOG_DATA) public data) {
}
ngOnInit() {
this.filterForm = this.fb.group({
name: [this.data.name, Validators.required]
});
}
onSaveClick() { onSaveClick() {
this.dialogRef.close({ this.dialogRef.close({
action: ProcessFilterDialogCloudComponent.ACTION_SAVE, action: ProcessFilterDialogCloudComponent.ACTION_SAVE,
icon: this.defaultIcon, icon: this.defaultIcon,
name: this.nameController.value name: this.filterForm.controls.name.value
}); });
} }
onCancelClick() { onCancelClick() {
this.dialogRef.close(); this.dialogRef.close();
} }
get nameController(): AbstractControl {
return this.filterForm.get('name');
}
isValid(): boolean {
return this.filterForm.valid;
}
} }
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; import { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
@@ -59,12 +59,13 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
error = new EventEmitter<any>(); error = new EventEmitter<any>();
filters$: Observable<ProcessFilterCloudModel[]>; filters$: Observable<ProcessFilterCloudModel[]>;
currentFilter: ProcessFilterCloudModel; currentFilter?: ProcessFilterCloudModel;
filters: ProcessFilterCloudModel[] = []; filters: ProcessFilterCloudModel[] = [];
private onDestroy$ = new Subject<boolean>(); private onDestroy$ = new Subject<boolean>();
constructor(private processFilterCloudService: ProcessFilterCloudService, private translationService: TranslationService) {} private readonly processFilterCloudService = inject(ProcessFilterCloudService);
private readonly translationService = inject(TranslationService);
ngOnInit() { ngOnInit() {
if (this.appName === '') { if (this.appName === '') {
@@ -90,17 +91,17 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
getFilters(appName: string): void { getFilters(appName: string): void {
this.filters$ = this.processFilterCloudService.getProcessFilters(appName); this.filters$ = this.processFilterCloudService.getProcessFilters(appName);
this.filters$.pipe(takeUntil(this.onDestroy$)).subscribe( this.filters$.pipe(takeUntil(this.onDestroy$)).subscribe({
(res) => { next: (res) => {
this.resetFilter(); this.resetFilter();
this.filters = res || []; this.filters = res || [];
this.selectFilterAndEmit(this.filterParam); this.selectFilterAndEmit(this.filterParam);
this.success.emit(res); this.success.emit(res);
}, },
(err: any) => { error: (err: any) => {
this.error.emit(err); this.error.emit(err);
} }
); });
} }
/** /**
@@ -109,15 +110,20 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
* @param paramFilter filter model * @param paramFilter filter model
*/ */
selectFilter(paramFilter: FilterParamsModel) { selectFilter(paramFilter: FilterParamsModel) {
if (paramFilter) { if (!paramFilter) {
this.currentFilter = this.filters.find( return;
}
const preferredFilter = this.filters.find((filter) => paramFilter.id === filter.id);
this.currentFilter =
preferredFilter ??
this.filters.find(
(filter, index) => (filter, index) =>
paramFilter.id === filter.id || paramFilter.id === filter.id ||
(paramFilter.name && this.checkFilterNamesEquality(paramFilter.name, filter.name)) || (paramFilter.name && this.checkFilterNamesEquality(paramFilter.name, filter.name)) ||
(paramFilter.key && paramFilter.key === filter.key) || (paramFilter.key && paramFilter.key === filter.key) ||
paramFilter.index === index paramFilter.index === index
); ); // fallback to preserve the previous behavior
}
} }
/** /**
@@ -53,7 +53,7 @@ describe('ProcessFilterCloudService', () => {
}); });
service = TestBed.inject(ProcessFilterCloudService); service = TestBed.inject(ProcessFilterCloudService);
const preferenceCloudService = service.preferenceService; const preferenceCloudService = TestBed.inject(PROCESS_FILTERS_SERVICE_TOKEN);
const identityUserService = TestBed.inject(IdentityUserService); const identityUserService = TestBed.inject(IdentityUserService);
createPreferenceSpy = spyOn(preferenceCloudService, 'createPreference').and.returnValue(of(fakeProcessCloudFilters)); createPreferenceSpy = spyOn(preferenceCloudService, 'createPreference').and.returnValue(of(fakeProcessCloudFilters));
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable, Inject } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Observable, of, BehaviorSubject } from 'rxjs'; import { Observable, of, BehaviorSubject } from 'rxjs';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
import { switchMap, map } from 'rxjs/operators'; import { switchMap, map } from 'rxjs/operators';
@@ -29,10 +29,10 @@ export class ProcessFilterCloudService {
private filtersSubject: BehaviorSubject<ProcessFilterCloudModel[]>; private filtersSubject: BehaviorSubject<ProcessFilterCloudModel[]>;
filters$: Observable<ProcessFilterCloudModel[]>; filters$: Observable<ProcessFilterCloudModel[]>;
constructor( private readonly preferenceService = inject<PreferenceCloudServiceInterface>(PROCESS_FILTERS_SERVICE_TOKEN);
@Inject(PROCESS_FILTERS_SERVICE_TOKEN) public preferenceService: PreferenceCloudServiceInterface, private readonly identityUserService = inject(IdentityUserService);
private identityUserService: IdentityUserService
) { constructor() {
this.filtersSubject = new BehaviorSubject([]); this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable(); this.filters$ = this.filtersSubject.asObservable();
} }
@@ -10,7 +10,7 @@
<ng-container *ngIf="toggleFilterActions"> <ng-container *ngIf="toggleFilterActions">
<button *ngFor="let filterAction of taskFilterActions" <button *ngFor="let filterAction of taskFilterActions"
mat-icon-button mat-icon-button
title="{{ filterAction.tooltip | translate}}" [title]="filterAction.tooltip | translate"
[attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType" [attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType"
[disabled]="isDisabledAction(filterAction)" [disabled]="isDisabledAction(filterAction)"
(click)="executeFilterActions(filterAction)"> (click)="executeFilterActions(filterAction)">
@@ -62,7 +62,7 @@
(keyup)="onDateChanged($any($event).target.value, taskFilterProperty)" (keyup)="onDateChanged($any($event).target.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)" (dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController" [matDatepicker]="dateController"
placeholder="{{taskFilterProperty.label | translate}}" [placeholder]="taskFilterProperty.label | translate"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"> [attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix <mat-datepicker-toggle matSuffix
[for]="dateController" [for]="dateController"
@@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, OnChanges, Output, SimpleChanges, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, OnChanges, Output, SimpleChanges, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { FilterParamsModel, ServiceTaskFilterCloudModel } from '../models/filter-cloud.model'; import { FilterParamsModel, ServiceTaskFilterCloudModel } from '../models/filter-cloud.model';
import { TranslationService } from '@alfresco/adf-core';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { BaseTaskFiltersCloudComponent } from './base-task-filters-cloud.component'; import { BaseTaskFiltersCloudComponent } from './base-task-filters-cloud.component';
import { ServiceTaskFilterCloudService } from '../services/service-task-filter-cloud.service'; import { ServiceTaskFilterCloudService } from '../services/service-task-filter-cloud.service';
import { TranslationService } from '@alfresco/adf-core';
@Component({ @Component({
selector: 'adf-cloud-service-task-filters', selector: 'adf-cloud-service-task-filters',
@@ -30,7 +30,6 @@ import { ServiceTaskFilterCloudService } from '../services/service-task-filter-c
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges { export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges {
/** Emitted when a filter is being selected based on the filterParam input. */ /** Emitted when a filter is being selected based on the filterParam input. */
@Output() @Output()
filterSelected = new EventEmitter<ServiceTaskFilterCloudModel>(); filterSelected = new EventEmitter<ServiceTaskFilterCloudModel>();
@@ -43,10 +42,8 @@ export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudCompon
filters: ServiceTaskFilterCloudModel[] = []; filters: ServiceTaskFilterCloudModel[] = [];
currentFilter: ServiceTaskFilterCloudModel; currentFilter: ServiceTaskFilterCloudModel;
constructor(private serviceTaskFilterCloudService: ServiceTaskFilterCloudService, private readonly serviceTaskFilterCloudService = inject(ServiceTaskFilterCloudService);
private translationService: TranslationService) { private readonly translationService = inject(TranslationService);
super();
}
ngOnInit() { ngOnInit() {
this.getFilters(this.appName); this.getFilters(this.appName);
@@ -89,15 +86,21 @@ export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudCompon
* @param paramFilter filter model * @param paramFilter filter model
*/ */
selectFilter(paramFilter: FilterParamsModel) { selectFilter(paramFilter: FilterParamsModel) {
if (paramFilter) { if (!paramFilter) {
this.currentFilter = this.filters.find((filter, index) => return;
paramFilter.index === index ||
paramFilter.key === filter.key ||
paramFilter.id === filter.id ||
(paramFilter.name &&
(paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase())
));
} }
const preferredFilter = this.filters.find((filter) => filter.id === paramFilter.id);
this.currentFilter =
preferredFilter ??
this.filters.find(
(filter, index) =>
paramFilter.index === index ||
paramFilter.key === filter.key ||
paramFilter.id === filter.id ||
(paramFilter.name && paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase())
); // fallback to preserve the previous behavior
} }
public selectFilterAndEmit(newParamFilter: FilterParamsModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, OnChanges, Output, SimpleChanges, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, OnChanges, Output, SimpleChanges, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { TaskFilterCloudService } from '../services/task-filter-cloud.service'; import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
import { TaskFilterCloudModel, FilterParamsModel } from '../models/filter-cloud.model'; import { TaskFilterCloudModel, FilterParamsModel } from '../models/filter-cloud.model';
@@ -32,7 +32,6 @@ import { TaskCloudEngineEvent } from '../../../models/engine-event-cloud.model';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges { export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges {
/** Emitted when a filter is being selected based on the filterParam input. */ /** Emitted when a filter is being selected based on the filterParam input. */
@Output() @Output()
filterSelected = new EventEmitter<TaskFilterCloudModel>(); filterSelected = new EventEmitter<TaskFilterCloudModel>();
@@ -50,11 +49,9 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
currentFilter: TaskFilterCloudModel; currentFilter: TaskFilterCloudModel;
enableNotifications: boolean; enableNotifications: boolean;
constructor(private taskFilterCloudService: TaskFilterCloudService, private readonly taskFilterCloudService = inject(TaskFilterCloudService);
private translationService: TranslationService, private readonly translationService = inject(TranslationService);
private appConfigService: AppConfigService) { private readonly appConfigService = inject(AppConfigService);
super();
}
ngOnInit() { ngOnInit() {
this.enableNotifications = this.appConfigService.get('notifications', true); this.enableNotifications = this.appConfigService.get('notifications', true);
@@ -106,7 +103,8 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
initFilterCounterNotifications() { initFilterCounterNotifications() {
if (this.appName && this.enableNotifications) { if (this.appName && this.enableNotifications) {
this.taskFilterCloudService.getTaskNotificationSubscription(this.appName) this.taskFilterCloudService
.getTaskNotificationSubscription(this.appName)
.pipe(debounceTime(1000)) .pipe(debounceTime(1000))
.subscribe((result: TaskCloudEngineEvent[]) => { .subscribe((result: TaskCloudEngineEvent[]) => {
result.map((taskEvent: TaskCloudEngineEvent) => { result.map((taskEvent: TaskCloudEngineEvent) => {
@@ -128,20 +126,28 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
} }
isFilterPresent(filter: TaskFilterCloudModel, filterNotification: TaskDetailsCloudModel): boolean { isFilterPresent(filter: TaskFilterCloudModel, filterNotification: TaskDetailsCloudModel): boolean {
return filter.status === filterNotification.status return (
&& (filter.assignee === filterNotification.assignee || filterNotification.assignee === undefined); filter.status === filterNotification.status &&
(filter.assignee === filterNotification.assignee || filterNotification.assignee === undefined)
);
} }
public selectFilter(paramFilter: FilterParamsModel) { public selectFilter(paramFilter: FilterParamsModel) {
if (paramFilter) { if (!paramFilter) {
this.currentFilter = this.filters.find((filter, index) => return;
paramFilter.index === index ||
paramFilter.key === filter.key ||
paramFilter.id === filter.id ||
(paramFilter.name &&
(paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase())
));
} }
const preferredFilter = this.filters.find((filter) => filter.id === paramFilter.id);
this.currentFilter =
preferredFilter ??
this.filters.find(
(filter, index) =>
paramFilter.index === index ||
paramFilter.key === filter.key ||
paramFilter.id === filter.id ||
(paramFilter.name && paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase())
); // fallback to preserve the previous behavior
} }
public selectFilterAndEmit(newParamFilter: FilterParamsModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {