[ADF-4711] User Preferences in Task Filter (#4891)

* [ADF-4711] User Preferences in Task Filter
This commit is contained in:
mcchrys
2019-07-08 20:59:47 +05:30
committed by Eugenio Romano
parent 3af702f58e
commit abc376ff33
10 changed files with 776 additions and 201 deletions

View File

@@ -62,7 +62,7 @@ export class CloudFiltersDemoComponent implements OnInit {
} }
onTaskFilterSelected(filter) { onTaskFilterSelected(filter) {
this.cloudLayoutService.setCurrentTaskFilterParam({id: filter.id}); this.cloudLayoutService.setCurrentTaskFilterParam({id: filter && filter.id ? filter.id : ''});
const currentFilter = Object.assign({}, filter); const currentFilter = Object.assign({}, filter);
this.router.navigate([`/cloud/${this.appName}/tasks/`], { queryParams: currentFilter }); this.router.navigate([`/cloud/${this.appName}/tasks/`], { queryParams: currentFilter });
} }

View File

@@ -1,68 +1,77 @@
<mat-accordion *ngIf="taskFilter"> <mat-accordion [hideToggle]="isLoading">
<mat-expansion-panel (afterExpand)="onExpand($event)" (closed)="onClose($event)"> <mat-expansion-panel (afterExpand)="onExpand($event)" (closed)="onClose($event)">
<mat-expansion-panel-header id="adf-edit-task-filter-expansion-header"> <mat-expansion-panel-header *ngIf="taskFilter" id="adf-edit-task-filter-expansion-header">
<mat-panel-title fxLayoutAlign="space-between center" id="adf-edit-task-filter-title-id">{{taskFilter.name | translate}}</mat-panel-title> <ng-container *ngIf="!isLoading; else loadingTemplate">
<mat-panel-description fxLayoutAlign="space-between center" id="adf-edit-task-filter-sub-title-id"> <mat-panel-title fxLayoutAlign="space-between center" id="adf-edit-task-filter-title-id">{{taskFilter.name | translate}}</mat-panel-title>
<span *ngIf="showTitle">{{ 'ADF_CLOUD_EDIT_TASK_FILTER.TITLE' | translate}}</span> <mat-panel-description fxLayoutAlign="space-between center" id="adf-edit-task-filter-sub-title-id">
<div *ngIf="showActions()" class="adf-cloud-edit-task-filter-actions"> <span *ngIf="showTitle">{{ 'ADF_CLOUD_EDIT_TASK_FILTER.TITLE' | translate}}</span>
<ng-container *ngIf="toggleFilterActions"> <div *ngIf="showActions()" class="adf-cloud-edit-task-filter-actions">
<button *ngFor="let filterAction of taskFilterActions" mat-icon-button matTooltip="{{ filterAction.tooltip | translate}}" [attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType" [disabled]="hasFormChanged(filterAction)" (click)="executeFilterActions(filterAction)"> <ng-container *ngIf="toggleFilterActions">
<mat-icon>{{filterAction.icon}}</mat-icon> <button *ngFor="let filterAction of taskFilterActions" mat-icon-button matTooltip="{{ filterAction.tooltip | translate}}" [attr.data-automation-id]="'adf-filter-action-' + filterAction.actionType" [disabled]="hasFormChanged(filterAction)" (click)="executeFilterActions(filterAction)">
</button> <mat-icon>{{filterAction.icon}}</mat-icon>
</ng-container> </button>
</div> </ng-container>
</mat-panel-description>
</mat-expansion-panel-header>
<form [formGroup]="editTaskFilterForm">
<div fxLayout="row wrap" fxLayout.xs="column" fxLayoutGap="10px" fxLayoutAlign="start center">
<ng-container *ngFor="let taskFilterProperty of taskFilterProperties">
<mat-form-field fxFlex="23%" *ngIf="isSelectType(taskFilterProperty)" [attr.data-automation-id]="taskFilterProperty.key">
<mat-select
placeholder="{{taskFilterProperty.label | translate}}"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-option *ngFor="let propertyOption of taskFilterProperty.options" [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-task-property-options-' + taskFilterProperty.key">
{{ propertyOption.label }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="23%" *ngIf="isTextType(taskFilterProperty)" [attr.data-automation-id]="taskFilterProperty.key">
<input matInput
[formControlName]="taskFilterProperty.key"
type="text"
placeholder="{{taskFilterProperty.label | translate}}"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"/>
</mat-form-field>
<mat-form-field fxFlex="23%" *ngIf="isDateType(taskFilterProperty)" [attr.data-automation-id]="taskFilterProperty.key">
<mat-label>{{taskFilterProperty.label | translate}}</mat-label>
<input
matInput
(keyup)="onDateChanged($event.srcElement.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController"
placeholder="{{taskFilterProperty.label | translate}}"
[(ngModel)]="dateFilter[taskFilterProperty.key]"
[ngModelOptions]="{standalone: true}"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix [for]="dateController" [attr.data-automation-id]="'adf-cloud-edit-task-property-date-toggle-' + taskFilterProperty.key"></mat-datepicker-toggle>
<mat-datepicker #dateController [attr.data-automation-id]="'adf-cloud-edit-task-property-date-picker-' + taskFilterProperty.key"></mat-datepicker>
<div class="adf-edit-task-filter-date-error-container">
<div *ngIf="hasError(taskFilterProperty)">
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon">warning</mat-icon>
</div>
</div> </div>
</mat-form-field> </mat-panel-description>
<div fxFlex="23%" class="adf-edit-task-filter-checkbox" *ngIf="isCheckBoxType(taskFilterProperty)">
<mat-checkbox
color="primary"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="taskFilterProperty.key">
{{taskFilterProperty.label | translate}}
</mat-checkbox>
</div>
</ng-container> </ng-container>
</div> <ng-template #loadingTemplate>
</form> <div class="adf-cloud-edit-task-filter-loading-margin">
<mat-spinner [diameter]="30"></mat-spinner>
</div>
</ng-template>
</mat-expansion-panel-header>
<ng-container *ngIf="!isLoading;">
<form [formGroup]="editTaskFilterForm" *ngIf="editTaskFilterForm">
<div fxLayout="row wrap" fxLayout.xs="column" fxLayoutGap="10px" fxLayoutAlign="start center">
<ng-container *ngFor="let taskFilterProperty of taskFilterProperties">
<mat-form-field fxFlex="23%" *ngIf="isSelectType(taskFilterProperty)" [attr.data-automation-id]="taskFilterProperty.key">
<mat-select
placeholder="{{taskFilterProperty.label | translate}}"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key">
<mat-option *ngFor="let propertyOption of taskFilterProperty.options" [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-task-property-options-' + taskFilterProperty.key">
{{ propertyOption.label }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="23%" *ngIf="isTextType(taskFilterProperty)" [attr.data-automation-id]="taskFilterProperty.key">
<input matInput
[formControlName]="taskFilterProperty.key"
type="text"
placeholder="{{taskFilterProperty.label | translate}}"
[attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key"/>
</mat-form-field>
<mat-form-field fxFlex="23%" *ngIf="isDateType(taskFilterProperty)" [attr.data-automation-id]="taskFilterProperty.key">
<mat-label>{{taskFilterProperty.label | translate}}</mat-label>
<input
matInput
(keyup)="onDateChanged($event.srcElement.value, taskFilterProperty)"
(dateChange)="onDateChanged($event.value, taskFilterProperty)"
[matDatepicker]="dateController"
placeholder="{{taskFilterProperty.label | translate}}"
[(ngModel)]="dateFilter[taskFilterProperty.key]"
[ngModelOptions]="{standalone: true}"
[attr.data-automation-id]="'adf-cloud-edit-task-`perty-' + taskFilterProperty.key">
<mat-datepicker-toggle matSuffix [for]="dateController" [attr.data-automation-id]="'adf-cloud-edit-task-property-date-toggle-' + taskFilterProperty.key"></mat-datepicker-toggle>
<mat-datepicker #dateController [attr.data-automation-id]="'adf-cloud-edit-task-property-date-picker-' + taskFilterProperty.key"></mat-datepicker>
<div class="adf-edit-task-filter-date-error-container">
<div *ngIf="hasError(taskFilterProperty)">
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon">warning</mat-icon>
</div>
</div>
</mat-form-field>
<div fxFlex="23%" class="adf-edit-task-filter-checkbox" *ngIf="isCheckBoxType(taskFilterProperty)">
<mat-checkbox
color="primary"
[formControlName]="taskFilterProperty.key"
[attr.data-automation-id]="taskFilterProperty.key">
{{taskFilterProperty.label | translate}}
</mat-checkbox>
</div>
</ng-container>
</div>
</form>
</ng-container>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>

View File

@@ -34,4 +34,11 @@
color: mat-color($warn); color: mat-color($warn);
} }
} }
.adf {
&-cloud-edit-process-filter-loading-margin {
margin-left: calc((100% - 100px) / 2);
margin-right: calc((100% - 100px) / 2);
}
}
} }

View File

@@ -29,6 +29,7 @@ import { fakeApplicationInstance } from '../../../app/mock/app-model.mock';
import { TaskFiltersCloudModule } from '../task-filters-cloud.module'; import { TaskFiltersCloudModule } from '../task-filters-cloud.module';
import { EditTaskFilterCloudComponent } from './edit-task-filter-cloud.component'; import { EditTaskFilterCloudComponent } from './edit-task-filter-cloud.component';
import { TaskFilterCloudService } from '../services/task-filter-cloud.service'; import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
import { UserPreferenceCloudService } from '../../../services/user-preference.cloud.service';
import { TaskFilterDialogCloudComponent } from './task-filter-dialog-cloud.component'; import { TaskFilterDialogCloudComponent } from './task-filter-dialog-cloud.component';
import { fakeFilter, fakeAllTaskFilter } from '../mock/task-filters-cloud.mock'; import { fakeFilter, fakeAllTaskFilter } from '../mock/task-filters-cloud.mock';
import { AbstractControl } from '@angular/forms'; import { AbstractControl } from '@angular/forms';
@@ -45,7 +46,7 @@ describe('EditTaskFilterCloudComponent', () => {
setupTestBed({ setupTestBed({
imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule], imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule],
providers: [MatDialog] providers: [MatDialog, UserPreferenceCloudService]
}); });
beforeEach(() => { beforeEach(() => {
@@ -59,7 +60,7 @@ describe('EditTaskFilterCloudComponent', () => {
icon: 'icon', icon: 'icon',
name: 'fake-name' name: 'fake-name'
}); }}); }); }});
getTaskFilterSpy = spyOn(service, 'getTaskFilterById').and.returnValue(fakeFilter); getTaskFilterSpy = spyOn(service, 'getTaskFilterById').and.returnValue(of(fakeFilter));
getRunningApplicationsSpy = spyOn(appsService, 'getDeployedApplicationsByStatus').and.returnValue(of(fakeApplicationInstance)); getRunningApplicationsSpy = spyOn(appsService, 'getDeployedApplicationsByStatus').and.returnValue(of(fakeApplicationInstance));
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -68,7 +69,7 @@ describe('EditTaskFilterCloudComponent', () => {
expect(component instanceof EditTaskFilterCloudComponent).toBeTruthy(); expect(component instanceof EditTaskFilterCloudComponent).toBeTruthy();
}); });
it('should fetch task filter by taskId', async(() => { it('should fetch task filter by taskId', () => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true); const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange}); component.ngOnChanges({ 'id': taskFilterIDchange});
fixture.detectChanges(); fixture.detectChanges();
@@ -80,9 +81,9 @@ describe('EditTaskFilterCloudComponent', () => {
expect(component.taskFilter.order).toEqual('ASC'); expect(component.taskFilter.order).toEqual('ASC');
expect(component.taskFilter.sort).toEqual('id'); expect(component.taskFilter.sort).toEqual('id');
}); });
})); });
it('should display filter name as title', () => { it('should display filter name as title', async(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true); const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange}); component.ngOnChanges({ 'id': taskFilterIDchange});
fixture.detectChanges(); fixture.detectChanges();
@@ -92,7 +93,37 @@ describe('EditTaskFilterCloudComponent', () => {
expect(subTitle).toBeDefined(); expect(subTitle).toBeDefined();
expect(title.innerText).toEqual('FakeInvolvedTasks'); expect(title.innerText).toEqual('FakeInvolvedTasks');
expect(subTitle.innerText.trim()).toEqual('ADF_CLOUD_EDIT_TASK_FILTER.TITLE'); expect(subTitle.innerText.trim()).toEqual('ADF_CLOUD_EDIT_TASK_FILTER.TITLE');
}); }));
it('should not display mat-spinner if isloading set to false', async(() => {
const taskFilterIDchange = new SimpleChange(null, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange });
fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-task-filter-title-id');
const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-task-filter-sub-title-id');
const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-task-filter-loading-margin');
fixture.whenStable().then(() => {
expect(matSpinnerElement).toBeNull();
expect(title).toBeDefined();
expect(subTitle).toBeDefined();
expect(title.innerText).toEqual('FakeInvolvedTasks');
expect(subTitle.innerText.trim()).toEqual('ADF_CLOUD_EDIT_TASK_FILTER.TITLE');
});
}));
it('should display mat-spinner if isloading set to true', async(() => {
component.isLoading = true;
const taskFilterIDchange = new SimpleChange(null, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange });
fixture.detectChanges();
const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-task-filter-loading-margin');
fixture.whenStable().then(() => {
expect(matSpinnerElement).toBeDefined();
});
}));
describe('EditTaskFilter form', () => { describe('EditTaskFilter form', () => {
@@ -196,7 +227,7 @@ describe('EditTaskFilterCloudComponent', () => {
it('should select \'All\' option in Task Status if All filter is set', async(() => { it('should select \'All\' option in Task Status if All filter is set', async(() => {
getTaskFilterSpy.and.returnValue(fakeAllTaskFilter); getTaskFilterSpy.and.returnValue(of(fakeAllTaskFilter));
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true); const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange}); component.ngOnChanges({ 'id': taskFilterIDchange});
@@ -303,7 +334,11 @@ describe('EditTaskFilterCloudComponent', () => {
it('should display sort properties when sort properties are specified', async(() => { it('should display sort properties when sort properties are specified', async(() => {
component.sortProperties = ['id', 'name', 'processInstanceId']; component.sortProperties = ['id', 'name', 'processInstanceId'];
getTaskFilterSpy.and.returnValue({ sort: 'my-custom-sort', processInstanceId: 'process-instance-id', priority: '12' }); getTaskFilterSpy.and.returnValue(of({
sort: 'my-custom-sort',
processInstanceId: 'process-instance-id',
priority: '12'
}));
fixture.detectChanges(); fixture.detectChanges();
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true); const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange}); component.ngOnChanges({ 'id': taskFilterIDchange});
@@ -451,7 +486,7 @@ describe('EditTaskFilterCloudComponent', () => {
it('should emit save event and save the filter on click save button', async(() => { it('should emit save event and save the filter on click save button', async(() => {
component.toggleFilterActions = true; component.toggleFilterActions = true;
const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter); const saveFilterSpy = spyOn(service, 'updateFilter');
const saveSpy: jasmine.Spy = spyOn(component.action, 'emit'); const saveSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
@@ -474,7 +509,7 @@ describe('EditTaskFilterCloudComponent', () => {
it('should emit delete event and delete the filter on click of delete button', async(() => { it('should emit delete event and delete the filter on click of delete button', async(() => {
component.toggleFilterActions = true; component.toggleFilterActions = true;
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough(); const deleteFilterSpy = spyOn(service, 'deleteFilter');
const deleteSpy: jasmine.Spy = spyOn(component.action, 'emit'); const deleteSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');

View File

@@ -15,31 +15,32 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnChanges, Input, Output, EventEmitter, SimpleChanges, OnInit } from '@angular/core'; import { Component, OnChanges, Input, Output, EventEmitter, SimpleChanges, OnInit, OnDestroy } from '@angular/core';
import { AbstractControl, FormGroup, FormBuilder } from '@angular/forms'; import { AbstractControl, FormGroup, FormBuilder } from '@angular/forms';
import { TaskFilterCloudModel, TaskFilterProperties, FilterOptions, TaskFilterAction } from './../models/filter-cloud.model';
import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
import { MatDialog, DateAdapter } from '@angular/material'; import { MatDialog, DateAdapter } from '@angular/material';
import { TaskFilterDialogCloudComponent } from './task-filter-dialog-cloud.component'; import { debounceTime, filter, takeUntil } from 'rxjs/operators';
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core'; import { Subject } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators';
import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service';
import { ApplicationInstanceModel } from '../../../app/models/application-instance.model';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { TaskFilterCloudModel, TaskFilterProperties, FilterOptions, TaskFilterAction } from './../models/filter-cloud.model';
import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
import { TaskFilterDialogCloudComponent } from './task-filter-dialog-cloud.component';
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service';
import { ApplicationInstanceModel } from '../../../app/models/application-instance.model';
@Component({ @Component({
selector: 'adf-cloud-edit-task-filter', selector: 'adf-cloud-edit-task-filter',
templateUrl: './edit-task-filter-cloud.component.html', templateUrl: './edit-task-filter-cloud.component.html',
styleUrls: ['./edit-task-filter-cloud.component.scss'] styleUrls: ['./edit-task-filter-cloud.component.scss']
}) })
export class EditTaskFilterCloudComponent implements OnInit, OnChanges { export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestroy {
public static ACTION_SAVE = 'save'; public static ACTION_SAVE = 'save';
public static ACTION_SAVE_AS = 'saveAs'; public static ACTION_SAVE_AS = 'saveAs';
public static ACTION_DELETE = 'delete'; public static ACTION_DELETE = 'delete';
public static APP_RUNNING_STATUS: string = 'RUNNING'; public static APP_RUNNING_STATUS: string = 'RUNNING';
public static MIN_VALUE = 1;
public static APPLICATION_NAME: string = 'appName'; public static APPLICATION_NAME: string = 'appName';
public static LAST_MODIFIED: string = 'lastModified'; public static LAST_MODIFIED: string = 'lastModified';
public static SORT: string = 'sort'; public static SORT: string = 'sort';
@@ -109,6 +110,9 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
taskFilterActions: TaskFilterAction[] = []; taskFilterActions: TaskFilterAction[] = [];
toggleFilterActions: boolean = false; toggleFilterActions: boolean = false;
private onDestroy$ = new Subject<boolean>();
isLoading: boolean = false;
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
public dialog: MatDialog, public dialog: MatDialog,
@@ -128,14 +132,13 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
const id = changes['id']; const id = changes['id'];
if (id && id.currentValue !== id.previousValue) { if (id && id.currentValue !== id.previousValue) {
this.taskFilterProperties = this.createAndFilterProperties(); this.retrieveTaskFilterAndBuildForm();
this.taskFilterActions = this.createAndFilterActions();
this.buildForm(this.taskFilterProperties);
} }
} }
retrieveTaskFilter(): TaskFilterCloudModel { ngOnDestroy() {
return new TaskFilterCloudModel(this.taskFilterCloudService.getTaskFilterById(this.appName, this.id)); this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
buildForm(taskFilterProperties: TaskFilterProperties[]) { buildForm(taskFilterProperties: TaskFilterProperties[]) {
@@ -177,7 +180,25 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
formValues.lastModifiedTo = lastModifiedToFilterValue.toDate(); formValues.lastModifiedTo = lastModifiedToFilterValue.toDate();
} }
} }
createAndFilterProperties(): TaskFilterProperties[] {
/**
* Fetches task filter by application name and filter id and creates filter properties, build form
*/
retrieveTaskFilterAndBuildForm() {
this.isLoading = true;
this.taskFilterCloudService.getTaskFilterById(this.appName, this.id)
.pipe(takeUntil(this.onDestroy$)).subscribe((response) => {
this.isLoading = false;
this.taskFilter = new TaskFilterCloudModel(response);
this.taskFilterProperties = this.createAndFilterProperties();
this.taskFilterActions = this.createAndFilterActions();
this.buildForm(this.taskFilterProperties);
}, (error) => {
this.isLoading = false;
});
}
createAndFilterProperties() {
this.checkMandatoryFilterProperties(); this.checkMandatoryFilterProperties();
if (this.checkForApplicationNameProperty()) { if (this.checkForApplicationNameProperty()) {
@@ -185,7 +206,6 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
this.getRunningApplications(); this.getRunningApplications();
} }
this.taskFilter = this.retrieveTaskFilter();
const defaultProperties = this.createTaskFilterProperties(this.taskFilter); const defaultProperties = this.createTaskFilterProperties(this.taskFilter);
let filteredProperties = defaultProperties.filter((filterProperty: TaskFilterProperties) => this.isValidProperty(this.filterProperties, filterProperty)); let filteredProperties = defaultProperties.filter((filterProperty: TaskFilterProperties) => this.isValidProperty(this.filterProperties, filterProperty));
@@ -196,7 +216,6 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
if (this.hasLastModifiedProperty()) { if (this.hasLastModifiedProperty()) {
filteredProperties = [...filteredProperties, ...this.createLastModifiedProperty()]; filteredProperties = [...filteredProperties, ...this.createLastModifiedProperty()];
} }
return filteredProperties; return filteredProperties;
} }
@@ -285,15 +304,16 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
} }
/** /**
* Check if both filters are same * Return true if both filters are same
* @param editedQuery, @param currentQuery
*/ */
compareFilters(editedQuery, currentQuery): boolean { compareFilters(editedQuery: TaskFilterCloudModel, currentQuery: TaskFilterCloudModel): boolean {
return JSON.stringify(editedQuery).toLowerCase() === JSON.stringify(currentQuery).toLowerCase(); return JSON.stringify(editedQuery).toLowerCase() === JSON.stringify(currentQuery).toLowerCase();
} }
getRunningApplications() { getRunningApplications() {
this.appsProcessCloudService.getDeployedApplicationsByStatus(EditTaskFilterCloudComponent.APP_RUNNING_STATUS) this.appsProcessCloudService.getDeployedApplicationsByStatus(EditTaskFilterCloudComponent.APP_RUNNING_STATUS)
.subscribe((applications: ApplicationInstanceModel[]) => { .pipe(takeUntil(this.onDestroy$)).subscribe((applications: ApplicationInstanceModel[]) => {
if (applications && applications.length > 0) { if (applications && applications.length > 0) {
applications.map((application) => { applications.map((application) => {
this.applicationNames.push({ label: application.name, value: application.name }); this.applicationNames.push({ label: application.name, value: application.name });
@@ -313,16 +333,20 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
} }
save(saveAction: TaskFilterAction) { save(saveAction: TaskFilterAction) {
this.taskFilterCloudService.updateFilter(this.changedTaskFilter); this.taskFilterCloudService.updateFilter(this.changedTaskFilter)
saveAction.filter = this.changedTaskFilter; .pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
this.action.emit(saveAction); saveAction.filter = this.changedTaskFilter;
this.formHasBeenChanged = this.compareFilters(this.changedTaskFilter, this.taskFilter); this.action.emit(saveAction);
this.formHasBeenChanged = this.compareFilters(this.changedTaskFilter, this.taskFilter);
});
} }
delete(deleteAction: TaskFilterAction) { delete(deleteAction: TaskFilterAction) {
this.taskFilterCloudService.deleteFilter(this.taskFilter); this.taskFilterCloudService.deleteFilter(this.taskFilter)
deleteAction.filter = this.taskFilter; .pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
this.action.emit(deleteAction); deleteAction.filter = this.taskFilter;
this.action.emit(deleteAction);
});
} }
saveAs(saveAsAction: TaskFilterAction) { saveAs(saveAsAction: TaskFilterAction) {
@@ -343,21 +367,30 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
id: filterId, id: filterId,
key: 'custom-' + filterKey key: 'custom-' + filterKey
}; };
const resultFilter = Object.assign({}, this.changedTaskFilter, newFilter); const resultFilter: TaskFilterCloudModel = Object.assign({}, this.changedTaskFilter, newFilter);
this.taskFilterCloudService.addFilter(resultFilter); this.taskFilterCloudService.addFilter(resultFilter)
saveAsAction.filter = resultFilter; .pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
this.action.emit(saveAsAction); saveAsAction.filter = resultFilter;
this.action.emit(saveAsAction);
});
} }
}); });
} }
getSanitizeFilterName(filterName): string { /**
* Return filter name
* @param filterName
*/
getSanitizeFilterName(filterName: string): string {
const nameWithHyphen = this.replaceSpaceWithHyphen(filterName.trim()); const nameWithHyphen = this.replaceSpaceWithHyphen(filterName.trim());
return nameWithHyphen.toLowerCase(); return nameWithHyphen.toLowerCase();
} }
replaceSpaceWithHyphen(name) { /**
* Return name with hyphen
* @param name
*/
replaceSpaceWithHyphen(name: string): string {
const regExt = new RegExp(' ', 'g'); const regExt = new RegExp(' ', 'g');
return name.replace(regExt, '-'); return name.replace(regExt, '-');
} }

View File

@@ -26,6 +26,7 @@ import { By } from '@angular/platform-browser';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { TaskFiltersCloudModule } from '../task-filters-cloud.module'; import { TaskFiltersCloudModule } from '../task-filters-cloud.module';
import { fakeGlobalFilter } from '../mock/task-filters-cloud.mock'; import { fakeGlobalFilter } from '../mock/task-filters-cloud.mock';
import { UserPreferenceCloudService } from '../../../services/user-preference.cloud.service';
describe('TaskFiltersCloudComponent', () => { describe('TaskFiltersCloudComponent', () => {
@@ -52,7 +53,7 @@ describe('TaskFiltersCloudComponent', () => {
setupTestBed({ setupTestBed({
imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule], imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule],
providers: [TaskFilterCloudService] providers: [TaskFilterCloudService, UserPreferenceCloudService]
}); });
beforeEach(() => { beforeEach(() => {

View File

@@ -15,17 +15,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable, Subject } 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';
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-cloud-task-filters', selector: 'adf-cloud-task-filters',
templateUrl: './task-filters-cloud.component.html', templateUrl: './task-filters-cloud.component.html',
styleUrls: ['task-filters-cloud.component.scss'] styleUrls: ['task-filters-cloud.component.scss']
}) })
export class TaskFiltersCloudComponent implements OnChanges { export class TaskFiltersCloudComponent implements OnChanges, OnDestroy {
/** Display filters available to the current user for the application with the specified name. */ /** Display filters available to the current user for the application with the specified name. */
@Input() @Input()
appName: string; appName: string;
@@ -59,6 +61,8 @@ export class TaskFiltersCloudComponent implements OnChanges {
filters: TaskFilterCloudModel [] = []; filters: TaskFilterCloudModel [] = [];
private onDestroy$ = new Subject<boolean>();
constructor(private taskFilterCloudService: TaskFilterCloudService, private translationService: TranslationService) { constructor(private taskFilterCloudService: TaskFilterCloudService, private translationService: TranslationService) {
} }
@@ -72,13 +76,18 @@ export class TaskFiltersCloudComponent implements OnChanges {
} }
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
/** /**
* Return the filter list filtered by appName * Return the filter list filtered by appName
*/ */
getFilters(appName: string) { getFilters(appName: string) {
this.filters$ = this.taskFilterCloudService.getTaskListFilters(appName); this.filters$ = this.taskFilterCloudService.getTaskListFilters(appName);
this.filters$.subscribe( this.filters$.pipe(takeUntil(this.onDestroy$)).subscribe(
(res: TaskFilterCloudModel[]) => { (res: TaskFilterCloudModel[]) => {
this.resetFilter(); this.resetFilter();
this.filters = Object.assign([], res); this.filters = Object.assign([], res);

View File

@@ -67,3 +67,167 @@ export let fakeAllTaskFilter = new TaskFilterCloudModel({
order: 'ASC', order: 'ASC',
sort: 'id' sort: 'id'
}); });
export const fakeTaskCloudPreferenceList = {
list: {
entries: [
{
entry: {
key: 'task-filters-fakeAppName-mock-username',
value: JSON.stringify([
{
name: 'FAKE_TASK_1',
id: '1',
key: 'all-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'ALL',
order: 'DESC'
},
{
name: 'FAKE_TASK_2',
id: '2',
key: 'run-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'RUNNING',
order: 'DESC'
},
{
name: 'FAKE_TASK_3',
id: '3',
key: 'complete-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'COMPLETED',
order: 'DESC'
}
])
}
},
{
entry: {
key: 'mock-key-2',
value: {
name: 'FAKE_TASK_2',
id: '2',
key: 'run-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'RUNNING',
order: 'DESC'
}
}
},
{
entry: {
key: 'mock-key-3',
value: {
name: 'FAKE_TASK_3',
id: '3',
key: 'complete-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'COMPLETED`',
order: 'DESC'
}
}
}
],
pagination: {
skipCount: 0,
maxItems: 100,
count: 3,
hasMoreItems: false,
totalItems: 3
}
}
};
export const fakeEmptyTaskCloudPreferenceList = {
list: {
entries: [],
pagination: {
skipCount: 0,
maxItems: 100,
count: 0,
hasMoreItems: false,
totalItems: 0
}
}
};
export const fakePreferenceWithNoTaskFilterPreference = {
list: {
entries: [
{
entry: {
key: 'my-mock-key-1',
value: 'my-mock-value-2'
}
},
{
entry: {
key: 'my-mock-key-2',
value: 'my-mock-key-2'
}
}
],
pagination: {
skipCount: 0,
maxItems: 100,
count: 4,
hasMoreItems: false,
totalItems: 2
}
}
};
export const fakeTaskFilter = new TaskFilterCloudModel({
name: 'FAKE_TASK_1',
id: '1',
key: 'all-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
order: 'DESC',
status: 'ALL'
});
export const fakeTaskCloudFilters = [
{
name: 'FAKE_TASK_1',
id: '1',
key: 'all-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'ALL',
order: 'DESC'
},
{
name: 'FAKE_TASK_2',
id: '2',
key: 'run-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'RUNNING',
order: 'DESC'
},
{
name: 'FAKE_TASK_3',
id: '3',
key: 'complete-fake-task',
icon: 'adjust',
appName: 'fakeAppName',
sort: 'startDate',
status: 'COMPLETED',
order: 'DESC'
}
];

View File

@@ -0,0 +1,210 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { async, TestBed } from '@angular/core/testing';
import { setupTestBed, CoreModule, IdentityUserService } from '@alfresco/adf-core';
import { of } from 'rxjs';
import { TaskFilterCloudService } from './task-filter-cloud.service';
import { UserPreferenceCloudService } from '../../../services/user-preference.cloud.service';
import {
fakeTaskCloudPreferenceList,
fakeTaskCloudFilters,
fakeEmptyTaskCloudPreferenceList,
fakePreferenceWithNoTaskFilterPreference,
fakeTaskFilter
} from '../mock/task-filters-cloud.mock';
describe('Task Filter Cloud Service', () => {
let service: TaskFilterCloudService;
let userPreferenceCloudService: UserPreferenceCloudService;
let identityUserService: IdentityUserService;
let getPreferencesSpy: jasmine.Spy;
let getPreferenceByKeySpy: jasmine.Spy;
let createPreferenceSpy: jasmine.Spy;
let updatePreferenceSpy: jasmine.Spy;
let getCurrentUserInfoSpy: jasmine.Spy;
const identityUserMock = { username: 'fakeusername', firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
setupTestBed({
imports: [
CoreModule.forRoot()
],
providers: [TaskFilterCloudService, UserPreferenceCloudService, IdentityUserService]
});
beforeEach(async(() => {
service = TestBed.get(TaskFilterCloudService);
userPreferenceCloudService = TestBed.get(UserPreferenceCloudService);
identityUserService = TestBed.get(IdentityUserService);
createPreferenceSpy = spyOn(userPreferenceCloudService, 'createPreference').and.returnValue(of(fakeTaskCloudFilters));
updatePreferenceSpy = spyOn(userPreferenceCloudService, 'updatePreference').and.returnValue(of(fakeTaskCloudFilters));
getPreferencesSpy = spyOn(userPreferenceCloudService, 'getPreferences').and.returnValue(of(fakeTaskCloudPreferenceList));
getPreferenceByKeySpy = spyOn(userPreferenceCloudService, 'getPreferenceByKey').and.returnValue(of(fakeTaskCloudFilters));
getCurrentUserInfoSpy = spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(identityUserMock);
}));
it('should create TaskFilterCloudService instance', () => {
expect(service).toBeDefined();
});
it('should create task filter key by using appName and the username', (done) => {
service.getTaskListFilters('fakeAppName').subscribe((res: any) => {
expect(res).toBeDefined();
expect(getCurrentUserInfoSpy).toHaveBeenCalled();
done();
});
});
it('should create default task filters if there are no task filter preferences', (done) => {
getPreferencesSpy.and.returnValue(of(fakeEmptyTaskCloudPreferenceList));
service.getTaskListFilters('fakeAppName').subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.length).toBe(3);
expect(res[0].appName).toBe('fakeAppName');
expect(res[0].id).toBe('1');
expect(res[0].name).toBe('FAKE_TASK_1');
expect(res[0].status).toBe('ALL');
expect(res[1].appName).toBe('fakeAppName');
expect(res[1].id).toBe('2');
expect(res[1].name).toBe('FAKE_TASK_2');
expect(res[1].status).toBe('RUNNING');
expect(res[2].appName).toBe('fakeAppName');
expect(res[2].id).toBe('3');
expect(res[2].name).toBe('FAKE_TASK_3');
expect(res[2].status).toBe('COMPLETED');
done();
});
expect(createPreferenceSpy).toHaveBeenCalled();
});
it('should return the task filters if filters available', (done) => {
service.getTaskListFilters('fakeAppName').subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.length).toBe(3);
expect(res[0].appName).toBe('fakeAppName');
expect(res[0].id).toBe('1');
expect(res[0].name).toBe('FAKE_TASK_1');
expect(res[0].status).toBe('ALL');
expect(res[1].appName).toBe('fakeAppName');
expect(res[1].id).toBe('2');
expect(res[1].name).toBe('FAKE_TASK_2');
expect(res[1].status).toBe('RUNNING');
expect(res[2].appName).toBe('fakeAppName');
expect(res[2].id).toBe('3');
expect(res[2].name).toBe('FAKE_TASK_3');
expect(res[2].status).toBe('COMPLETED');
done();
});
expect(getPreferencesSpy).toHaveBeenCalled();
});
it('should create the task filters if the user preference does not have task filters', (done) => {
getPreferencesSpy.and.returnValue(of(fakePreferenceWithNoTaskFilterPreference));
service.getTaskListFilters('fakeAppName').subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.length).toBe(3);
expect(res[0].appName).toBe('fakeAppName');
expect(res[0].id).toBe('1');
expect(res[0].name).toBe('FAKE_TASK_1');
expect(res[0].status).toBe('ALL');
expect(res[1].appName).toBe('fakeAppName');
expect(res[1].id).toBe('2');
expect(res[1].name).toBe('FAKE_TASK_2');
expect(res[1].status).toBe('RUNNING');
expect(res[2].appName).toBe('fakeAppName');
expect(res[2].id).toBe('3');
expect(res[2].name).toBe('FAKE_TASK_3');
expect(res[2].status).toBe('COMPLETED');
done();
});
expect(getPreferencesSpy).toHaveBeenCalled();
expect(createPreferenceSpy).toHaveBeenCalled();
});
it('should return filter by task filter id', (done) => {
service.getTaskFilterById('fakeAppName', '2').subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('fakeAppName');
expect(res.id).toBe('2');
expect(res.name).toBe('FAKE_TASK_2');
expect(res.status).toBe('RUNNING');
done();
});
expect(getPreferenceByKeySpy).toHaveBeenCalled();
});
it('should add task filter if filter is not exist in the filters', (done) => {
getPreferenceByKeySpy.and.returnValue(of([]));
service.getTaskFilterById('fakeAppName', '2').subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('fakeAppName');
expect(res.id).toBe('2');
expect(res.name).toBe('FAKE_TASK_2');
expect(res.status).toBe('RUNNING');
done();
});
});
it('should update filter', (done) => {
createPreferenceSpy.and.returnValue(of(fakeTaskCloudFilters));
service.updateFilter(fakeTaskFilter).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.length).toBe(3);
expect(res[0].appName).toBe('fakeAppName');
expect(res[1].appName).toBe('fakeAppName');
expect(res[2].appName).toBe('fakeAppName');
done();
});
});
it('should create task filter when trying to update in case filter is not exist in the filters', (done) => {
getPreferenceByKeySpy.and.returnValue(of([]));
service.updateFilter(fakeTaskFilter).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.length).toBe(3);
expect(res[0].appName).toBe('fakeAppName');
expect(res[1].appName).toBe('fakeAppName');
expect(res[2].appName).toBe('fakeAppName');
done();
});
expect(createPreferenceSpy).toHaveBeenCalled();
});
it('should delete filter', (done) => {
service.deleteFilter(fakeTaskFilter).subscribe((res: any) => {
expect(res).toBeDefined();
done();
});
expect(updatePreferenceSpy).toHaveBeenCalled();
});
});

View File

@@ -15,10 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { StorageService, JwtHelperService } from '@alfresco/adf-core'; import { IdentityUserService, IdentityUserModel } from '@alfresco/adf-core';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs'; import { Observable, of, BehaviorSubject, throwError } from 'rxjs';
import { TaskFilterCloudModel } from '../models/filter-cloud.model'; import { TaskFilterCloudModel } from '../models/filter-cloud.model';
import { UserPreferenceCloudService } from '../../../services/public-api';
import { switchMap, map, catchError } from 'rxjs/operators';
@Injectable() @Injectable()
export class TaskFilterCloudService { export class TaskFilterCloudService {
@@ -26,38 +28,85 @@ export class TaskFilterCloudService {
private filtersSubject: BehaviorSubject<TaskFilterCloudModel[]>; private filtersSubject: BehaviorSubject<TaskFilterCloudModel[]>;
filters$: Observable<TaskFilterCloudModel[]>; filters$: Observable<TaskFilterCloudModel[]>;
constructor(private storage: StorageService, private jwtHelperService: JwtHelperService) { constructor( private identityUserService: IdentityUserService,
private preferenceService: UserPreferenceCloudService) {
this.filtersSubject = new BehaviorSubject([]); this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable(); this.filters$ = this.filtersSubject.asObservable();
} }
/** /**
* Creates and returns the default filters for a process app. * Creates and returns the default task filters for an app.
* @param appName Name of the target app * @param appName Name of the target app
* @returns Observable of default filters just created * @returns Observable of default filters task filters just created or created filters
*/ */
private createDefaultFilters(appName: string) { private createDefaultFilters(appName: string) {
const myTasksFilter = this.getMyTasksFilterInstance(appName); const key: string = this.prepareKey(appName);
this.addFilter(myTasksFilter); this.preferenceService.getPreferences(appName).pipe(
switchMap((response: any) => {
const completedTasksFilter = this.getCompletedTasksFilterInstance(appName); const preferences = (response && response.list && response.list.entries) ? response.list.entries : [];
this.addFilter(completedTasksFilter); if (!this.hasPreferences(preferences)) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else if (!this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else {
return of(this.findFiltersByKeyInPrefrences(preferences, key));
}
}),
catchError((err) => this.handleTaskError(err))
).subscribe((filters) => {
this.addFiltersToStream(filters);
});
} }
/** /**
* Gets all task filters for a process app. * Checks user preference are empty or not
* @param preferences User preferences of the target app
* @returns Boolean value if the preferences are not empty
*/
private hasPreferences(preferences: any): boolean {
return preferences && preferences.length > 0;
}
/**
* Checks for task filters in given user preferences
* @param preferences User preferences of the target app
* @param key Key of the task filters
* @param filters Details of create filter
* @returns Boolean value if the preference has task filters
*/
private hasTaskFilters(preferences: any, key: string): boolean {
const filters = preferences.find((filter: any) => { return filter.entry.key === key; });
return (filters && filters.entry) ? JSON.parse(filters.entry.value).length > 0 : false;
}
/**
* Calls create preference api to create task filters
* @param appName Name of the target app
* @param key Key of the task instance filters
* @param filters Details of new task filter
* @returns Observable of created task filters
*/
private createTaskFilters(appName: string, key: string, filters: TaskFilterCloudModel[]): Observable<TaskFilterCloudModel[]> {
return this.preferenceService.createPreference(appName, key, filters);
}
/**
* Calls get preference api to get task filter by preference key
* @param appName Name of the target app
* @param key Key of the task filters
* @returns Observable of task filters
*/
private getTaskFiltersByKey(appName: string, key: string): Observable<TaskFilterCloudModel[]> {
return this.preferenceService.getPreferenceByKey(appName, key);
}
/**
* Gets all task filters for a task app.
* @param appName Name of the target app * @param appName Name of the target app
* @returns Observable of task filter details * @returns Observable of task filter details
*/ */
getTaskListFilters(appName?: string): Observable<TaskFilterCloudModel[]> { getTaskListFilters(appName?: string): Observable<TaskFilterCloudModel[]> {
const username = this.getUsername(); this.createDefaultFilters(appName);
const key = `task-filters-${appName}-${username}`;
const filters = JSON.parse(this.storage.getItem(key) || '[]');
if (filters.length === 0) {
this.createDefaultFilters(appName);
} else {
this.addFiltersToStream(filters);
}
return this.filters$; return this.filters$;
} }
@@ -67,68 +116,109 @@ export class TaskFilterCloudService {
* @param id ID of the task * @param id ID of the task
* @returns Details of the task filter * @returns Details of the task filter
*/ */
getTaskFilterById(appName: string, id: string): TaskFilterCloudModel { getTaskFilterById(appName: string, id: string): any {
const username = this.getUsername(); const key: string = this.prepareKey(appName);
const key = `task-filters-${appName}-${username}`; return this.getTaskFiltersByKey(appName, key).pipe(
let filters = []; switchMap((filters: TaskFilterCloudModel[]) => {
filters = JSON.parse(this.storage.getItem(key)) || []; if (filters && filters.length === 0) {
return filters.filter((filterTmp: TaskFilterCloudModel) => id === filterTmp.id)[0]; return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else {
return of(filters);
}
}),
map((filters: TaskFilterCloudModel[]) => {
return filters.filter((filter: TaskFilterCloudModel) => {
return filter.id === id;
})[0];
}),
catchError((err) => this.handleTaskError(err))
);
} }
/** /**
* Adds a new task filter. * Adds a new task filter.
* @param filter The new filter to add * @param filter The new filter to add
* @returns Details of task filter just added * @returns Obervable of task instance filters with newly added filter
*/ */
addFilter(filter: TaskFilterCloudModel) { addFilter(newFilter: TaskFilterCloudModel) {
const username = this.getUsername(); const key: string = this.prepareKey(newFilter.appName);
const key = `task-filters-${filter.appName}-${username}`; return this.getTaskFiltersByKey(newFilter.appName, key).pipe(
const filters = JSON.parse(this.storage.getItem(key) || '[]'); switchMap((filters: TaskFilterCloudModel[]) => {
if (filters && filters.length === 0) {
filters.push(filter); return this.createTaskFilters(newFilter.appName, key, [newFilter]);
} else {
this.storage.setItem(key, JSON.stringify(filters)); filters.push(newFilter);
return this.preferenceService.updatePreference(newFilter.appName, key, filters);
this.addFiltersToStream(filters); }
}),
map((filters: TaskFilterCloudModel[]) => {
this.addFiltersToStream(filters);
return filters;
}),
catchError((err) => this.handleTaskError(err))
);
} }
private addFiltersToStream(filters: TaskFilterCloudModel []) { private addFiltersToStream(filters: TaskFilterCloudModel[]) {
this.filtersSubject.next(filters); this.filtersSubject.next(filters);
} }
/** /**
* Updates a task filter. * Updates a task filter.
* @param filter The filter to update * @param filter The filter to update
* @returns Observable of task instance filters with updated filter
*/ */
updateFilter(filter: TaskFilterCloudModel) { updateFilter(updatedFilter: TaskFilterCloudModel): Observable<TaskFilterCloudModel[]> {
const username = this.getUsername(); const key: string = this.prepareKey(updatedFilter.appName);
const key = `task-filters-${filter.appName}-${username}`; return this.getTaskFiltersByKey(updatedFilter.appName, key).pipe(
if (key) { switchMap((filters: any) => {
const filters = JSON.parse(this.storage.getItem(key) || '[]'); if (filters && filters.length === 0) {
const itemIndex = filters.findIndex((flt: TaskFilterCloudModel) => flt.id === filter.id); return this.createTaskFilters(updatedFilter.appName, key, [updatedFilter]);
filters[itemIndex] = filter; } else {
this.storage.setItem(key, JSON.stringify(filters)); const itemIndex = filters.findIndex((filter: TaskFilterCloudModel) => filter.id === updatedFilter.id);
this.addFiltersToStream(filters); filters[itemIndex] = updatedFilter;
} return this.updateProcessFilters(updatedFilter.appName, key, filters);
}
}),
map((updatedFilters: TaskFilterCloudModel[]) => {
this.addFiltersToStream(updatedFilters);
return updatedFilters;
}),
catchError((err) => this.handleTaskError(err))
);
} }
/** /**
* Deletes a task filter * Deletes a task filter
* @param filter The filter to delete * @param filter The filter to delete
* @returns Observable of task instance filters without deleted filter
*/ */
deleteFilter(filter: TaskFilterCloudModel) { deleteFilter(deletedFilter: TaskFilterCloudModel): Observable<TaskFilterCloudModel[]> {
const username = this.getUsername(); const key = this.prepareKey(deletedFilter.appName);
const key = `task-filters-${filter.appName}-${username}`; return this.getTaskFiltersByKey(deletedFilter.appName, key).pipe(
if (key) { switchMap((filters: any) => {
let filters: TaskFilterCloudModel[] = JSON.parse(this.storage.getItem(key) || '[]'); if (filters && filters.length > 0) {
filters = filters.filter((item) => item.id !== filter.id); filters = filters.filter((filter: TaskFilterCloudModel) => filter.id !== deletedFilter.id);
this.storage.setItem(key, JSON.stringify(filters)); return this.updateProcessFilters(deletedFilter.appName, key, filters);
if (filters.length === 0) { }
this.createDefaultFilters(filter.appName); }),
} else { map((filters: TaskFilterCloudModel[]) => {
this.addFiltersToStream(filters); this.addFiltersToStream(filters);
} return filters;
} }),
catchError((err) => this.handleTaskError(err))
);
}
/**
* Calls update preference api to update task filter
* @param appName Name of the target app
* @param key Key of the task filters
* @param filters Details of update filter
* @returns Observable of updated task filters
*/
private updateProcessFilters(appName: string, key: string, filters: TaskFilterCloudModel[]): Observable<TaskFilterCloudModel[]> {
return this.preferenceService.updatePreference(appName, key, filters);
} }
/** /**
@@ -136,43 +226,60 @@ export class TaskFilterCloudService {
* @returns Username string * @returns Username string
*/ */
getUsername(): string { getUsername(): string {
return this.jwtHelperService.getValueFromLocalAccessToken<string>(JwtHelperService.USER_PREFERRED_USERNAME); const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo();
return user.username;
} }
/** /**
* Creates and returns a filter for "My Tasks" task instances. * Creates a uniq key with appName and username
* @param appName Name of the target app * @param appName Name of the target app
* @returns The newly created filter * @returns String of task filters preference key
*/ */
getMyTasksFilterInstance(appName: string): TaskFilterCloudModel { private prepareKey(appName: string): string {
const username = this.getUsername(); return `task-filters-${appName}-${this.getUsername()}`;
return new TaskFilterCloudModel({
name: 'ADF_CLOUD_TASK_FILTERS.MY_TASKS',
key: 'my-tasks',
icon: 'inbox',
appName: appName,
status: 'ASSIGNED',
assignee: username,
sort: 'createdDate',
order: 'DESC'
});
} }
/** /**
* Creates and returns a filter for "Completed" task instances. * Finds and returns the task filters from preferences
* @param appName Name of the target app * @param appName Name of the target app
* @returns The newly created filter * @returns Array of TaskFilterCloudModel
*/ */
getCompletedTasksFilterInstance(appName: string): TaskFilterCloudModel { private findFiltersByKeyInPrefrences(preferences: any, key: string): TaskFilterCloudModel[] {
return new TaskFilterCloudModel({ const result = preferences.find((filter: any) => { return filter.entry.key === key; });
name: 'ADF_CLOUD_TASK_FILTERS.COMPLETED_TASKS', return result && result.entry ? JSON.parse(result.entry.value) : [];
key: 'completed-tasks', }
icon: 'done',
appName: appName, private handleTaskError(error: any) {
status: 'COMPLETED', return throwError(error || 'Server error');
assignee: '', }
sort: 'createdDate',
order: 'DESC' /**
}); * Creates and returns the default filters for a task app.
* @param appName Name of the target app
* @returns Array of TaskFilterCloudModel
*/
private defaultTaskFilters(appName: string): TaskFilterCloudModel[] {
return [
new TaskFilterCloudModel({
name: 'ADF_CLOUD_TASK_FILTERS.MY_TASKS',
key: 'my-tasks',
icon: 'inbox',
appName: appName,
status: 'ASSIGNED',
assignee: this.getUsername(),
sort: 'createdDate',
order: 'DESC'
}),
new TaskFilterCloudModel({
name: 'ADF_CLOUD_TASK_FILTERS.COMPLETED_TASKS',
key: 'completed-tasks',
icon: 'done',
appName: appName,
status: 'COMPLETED',
assignee: '',
sort: 'createdDate',
order: 'DESC'
})
];
} }
} }