Fix process cloud page (#4075)

* Fix process cloud page

* Use FilterParamModel

* Rollback method

* Fix core unit test related to identity service

* Fix process filters cloud
Get user info from different keys

* Select the my-task filter in case the task has been created

* Add family_name and given_name to the jwt token
This commit is contained in:
Maurizio Vitale
2018-12-12 15:43:57 +00:00
committed by Eugenio Romano
parent 511087f6b1
commit e241779f3a
29 changed files with 261 additions and 240 deletions

View File

@@ -5,7 +5,12 @@
Task Filters Task Filters
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<adf-cloud-task-filters *ngIf="panelOpenStateTask" [appName]="appName" [showIcons]="true" (filterClick)="onTaskFilterSelected($event)"> <adf-cloud-task-filters
*ngIf="panelOpenStateTask"
[appName]="appName"
[showIcons]="true"
[filterParam]="currentTaskFilter$ | async"
(filterClick)="onTaskFilterSelected($event)">
</adf-cloud-task-filters> </adf-cloud-task-filters>
</mat-expansion-panel> </mat-expansion-panel>
@@ -15,7 +20,12 @@
Process Filters Process Filters
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<adf-cloud-process-filters *ngIf="panelOpenStateProcess" [appName]="appName" [showIcons]="true" (filterClick)="onProcessFilterSelected($event)"> <adf-cloud-process-filters
*ngIf="panelOpenStateProcess"
[appName]="appName"
[showIcons]="true"
[filterParam]="currentProcessFilter$ | async"
(filterClick)="onProcessFilterSelected($event)">
</adf-cloud-process-filters> </adf-cloud-process-filters>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>

View File

@@ -15,34 +15,45 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, ViewEncapsulation, Output, Input } from '@angular/core'; import { Component, ViewEncapsulation, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { CloudLayoutService } from './services/cloud-layout.service';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-cloud-fillters-demo', selector: 'app-cloud-filters-demo',
templateUrl: './cloud-filters-demo.component.html', templateUrl: './cloud-filters-demo.component.html',
styleUrls: ['cloud-filters-demo.component.scss'], styleUrls: ['cloud-filters-demo.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class CloudFiltersDemoComponent { export class CloudFiltersDemoComponent implements OnInit {
@Input() @Input()
appName: string; appName: string;
@Output()
taskFilterSelect: EventEmitter<any> = new EventEmitter<any>();
@Output()
processFilterSelect: EventEmitter<any> = new EventEmitter<any>();
panelOpenStateTask: boolean; panelOpenStateTask: boolean;
panelOpenStateProcess: boolean; panelOpenStateProcess: boolean;
currentTaskFilter$: Observable<any>;
currentProcessFilter$: Observable<any>;
constructor(private cloudLayoutService: CloudLayoutService, private router: Router) {
}
ngOnInit() {
this.currentTaskFilter$ = this.cloudLayoutService.getCurrentTaskFilterParam();
this.currentProcessFilter$ = this.cloudLayoutService.getCurrentProcessFilterParam();
}
onTaskFilterSelected(filter) { onTaskFilterSelected(filter) {
this.taskFilterSelect.emit(filter); this.cloudLayoutService.setCurrentTaskFilterParam({id: filter.id});
const currentFilter = Object.assign({}, filter);
this.router.navigate([`/cloud/${this.appName}/tasks/`], { queryParams: currentFilter });
} }
onProcessFilterSelected(filter) { onProcessFilterSelected(filter) {
this.processFilterSelect.emit(filter); this.cloudLayoutService.setCurrentProcessFilterParam({id: filter.id});
const currentFilter = Object.assign({}, filter);
this.router.navigate([`/cloud/${this.appName}/processes/`], { queryParams: currentFilter });
} }
} }

View File

@@ -17,7 +17,7 @@
</button> </button>
</div> </div>
</adf-sidebar-action-menu> </adf-sidebar-action-menu>
<app-cloud-fillters-demo [appName]="applicationName" (taskFilterSelect)="onTaskFilterSelected($event)" (processFilterSelect)="onProcessFilterSelected($event)"></app-cloud-fillters-demo> <app-cloud-filters-demo [appName]="applicationName"></app-cloud-filters-demo>
</ng-template> </ng-template>
</adf-sidenav-layout-navigation> </adf-sidenav-layout-navigation>
<adf-sidenav-layout-content> <adf-sidenav-layout-content>

View File

@@ -36,17 +36,7 @@ export class CloudLayoutComponent implements OnInit {
}); });
} }
onTaskFilterSelected(filter) {
const currentFilter = Object.assign({}, filter);
this.router.navigate([`/cloud/${this.applicationName}/tasks/`], { queryParams: currentFilter });
}
onStartTask() { onStartTask() {
this.router.navigate([`/cloud/${this.applicationName}/start-task/`]); this.router.navigate([`/cloud/${this.applicationName}/start-task/`]);
} }
onProcessFilterSelected(filter) {
const currentFilter = Object.assign({}, filter);
this.router.navigate([`/cloud/${this.applicationName}/processes/`], { queryParams: currentFilter });
}
} }

View File

@@ -3,7 +3,7 @@
[appName]="applicationName" [appName]="applicationName"
[id]="filterId" [id]="filterId"
(filterChange)="onFilterChange($event)" (filterChange)="onFilterChange($event)"
(action)="onEditActions($event)"> (action)="onProcessFilterAction($event)">
</adf-cloud-edit-process-filter> </adf-cloud-edit-process-filter>
<div fxLayout="column" fxFlex fxLayoutAlign="space-between" *ngIf="editedFilter"> <div fxLayout="column" fxFlex fxLayoutAlign="space-between" *ngIf="editedFilter">
<adf-cloud-process-list fxFlex class="adf-cloud-layout-overflow" <adf-cloud-process-list fxFlex class="adf-cloud-layout-overflow"

View File

@@ -19,13 +19,13 @@ import { Component, ViewChild, OnInit } from '@angular/core';
import { import {
ProcessListCloudComponent, ProcessListCloudComponent,
ProcessFilterCloudModel, ProcessFilterCloudModel,
EditProcessFilterCloudComponent,
ProcessListCloudSortingModel, ProcessListCloudSortingModel,
ProcessFiltersCloudComponent ProcessFiltersCloudComponent
} from '@alfresco/adf-process-services-cloud'; } from '@alfresco/adf-process-services-cloud';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { UserPreferencesService } from '@alfresco/adf-core'; import { UserPreferencesService } from '@alfresco/adf-core';
import { CloudLayoutService } from './services/cloud-layout.service';
@Component({ @Component({
templateUrl: './processes-cloud-demo.component.html', templateUrl: './processes-cloud-demo.component.html',
@@ -48,8 +48,10 @@ export class ProcessesCloudDemoComponent implements OnInit {
editedFilter: ProcessFilterCloudModel; editedFilter: ProcessFilterCloudModel;
constructor(private route: ActivatedRoute, constructor(
private userPreference: UserPreferencesService) { private route: ActivatedRoute,
private cloudLayoutService: CloudLayoutService,
private userPreference: UserPreferencesService) {
} }
ngOnInit() { ngOnInit() {
@@ -78,27 +80,7 @@ export class ProcessesCloudDemoComponent implements OnInit {
this.sortArray = [new ProcessListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order })]; this.sortArray = [new ProcessListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order })];
} }
onEditActions(event: any) { onProcessFilterAction(filter: any) {
if (event.actionType === EditProcessFilterCloudComponent.ACTION_SAVE) { this.cloudLayoutService.setCurrentProcessFilterParam({id: filter.id});
this.save(event.id); }
} else if (event.actionType === EditProcessFilterCloudComponent.ACTION_SAVE_AS) {
this.saveAs(event.id);
} else if (event.actionType === EditProcessFilterCloudComponent.ACTION_DELETE) {
this.deleteFilter();
}
}
saveAs(filterId) {
this.processFiltersCloud.filterParam = <any> {id : filterId};
this.processFiltersCloud.getFilters(this.applicationName);
}
save(filterId) {
this.processFiltersCloud.filterParam = <any> {id : filterId};
this.processFiltersCloud.getFilters(this.applicationName);
}
deleteFilter() {
this.processFiltersCloud.getFilters(this.applicationName);
}
} }

View File

@@ -0,0 +1,52 @@
/*!
* @license
* Copyright 2016 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 { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class CloudLayoutService {
private filterTaskSubject: BehaviorSubject<any> = new BehaviorSubject({index: 0});
private filterTask$: Observable<any>;
private filterProcessSubject: BehaviorSubject<any> = new BehaviorSubject({index: 0});
private filterProcess$: Observable<any>;
constructor() {
this.filterTask$ = this.filterTaskSubject.asObservable();
this.filterProcess$ = this.filterProcessSubject.asObservable();
}
getCurrentTaskFilterParam() {
return this.filterTask$;
}
setCurrentTaskFilterParam(param) {
this.filterTaskSubject.next(param);
}
getCurrentProcessFilterParam() {
return this.filterProcess$;
}
setCurrentProcessFilterParam(param) {
this.filterProcessSubject.next(param);
}
}

View File

@@ -18,7 +18,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { NotificationService } from '@alfresco/adf-core'; import { NotificationService } from '@alfresco/adf-core';
import { CloudLayoutService } from './services/cloud-layout.service';
@Component({ @Component({
templateUrl: './start-task-cloud-demo.component.html', templateUrl: './start-task-cloud-demo.component.html',
styleUrls: ['./start-task-cloud-demo.component.scss'] styleUrls: ['./start-task-cloud-demo.component.scss']
@@ -28,6 +28,7 @@ export class StartTaskCloudDemoComponent implements OnInit {
applicationName; applicationName;
constructor( constructor(
private cloudLayoutService: CloudLayoutService,
private route: ActivatedRoute, private route: ActivatedRoute,
private notificationService: NotificationService, private notificationService: NotificationService,
private router: Router) { private router: Router) {
@@ -41,6 +42,7 @@ export class StartTaskCloudDemoComponent implements OnInit {
onStartTaskSuccess() { onStartTaskSuccess() {
this.router.navigate([`/cloud/${this.applicationName}`]); this.router.navigate([`/cloud/${this.applicationName}`]);
this.cloudLayoutService.setCurrentTaskFilterParam({key: 'my-tasks'});
} }
onCancelStartTask() { onCancelStartTask() {

View File

@@ -2,6 +2,7 @@
<adf-cloud-edit-task-filter <adf-cloud-edit-task-filter
[appName]="applicationName" [appName]="applicationName"
[id]="filterId" [id]="filterId"
(action)="onTaskFilterAction($event)"
(filterChange)="onFilterChange($event)"> (filterChange)="onFilterChange($event)">
</adf-cloud-edit-task-filter> </adf-cloud-edit-task-filter>

View File

@@ -19,7 +19,7 @@ import { Component, ViewChild, OnInit } from '@angular/core';
import { TaskListCloudComponent, TaskListCloudSortingModel, TaskFilterCloudModel } from '@alfresco/adf-process-services-cloud'; import { TaskListCloudComponent, TaskListCloudSortingModel, TaskFilterCloudModel } from '@alfresco/adf-process-services-cloud';
import { UserPreferencesService } from '@alfresco/adf-core'; import { UserPreferencesService } from '@alfresco/adf-core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { CloudLayoutService } from './services/cloud-layout.service';
@Component({ @Component({
templateUrl: 'tasks-cloud-demo.component.html', templateUrl: 'tasks-cloud-demo.component.html',
styleUrls: ['tasks-cloud-demo.component.scss'] styleUrls: ['tasks-cloud-demo.component.scss']
@@ -41,6 +41,7 @@ export class TasksCloudDemoComponent implements OnInit {
filterId; filterId;
constructor( constructor(
private cloudLayoutService: CloudLayoutService,
private route: ActivatedRoute, private route: ActivatedRoute,
private userPreference: UserPreferencesService) { private userPreference: UserPreferencesService) {
} }
@@ -70,4 +71,8 @@ export class TasksCloudDemoComponent implements OnInit {
this.editedFilter = Object.assign({}, filter); this.editedFilter = Object.assign({}, filter);
this.sortArray = [new TaskListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order})]; this.sortArray = [new TaskListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order})];
} }
onTaskFilterAction(filter: any) {
this.cloudLayoutService.setCurrentTaskFilterParam({id: filter.id});
}
} }

View File

@@ -22,7 +22,7 @@ Shows all available filters.
| Name | Type | Default value | Description | | Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- | | ---- | ---- | ------------- | ----------- |
| appName | `string` | | Display filters available to the current user for the application with the specified name. | | appName | `string` | | Display filters available to the current user for the application with the specified name. |
| filterParam | [`TaskFilterCloudModel`](../../lib/process-services/task-list/models/filter.model.ts) | | Parameters to use for the task filter cloud. If there is no match then the default filter (the first one in the list) is selected. | | filterParam | [`FilterParamsModel`](../../lib/process-services/task-list/models/filter.model.ts) | | Parameters to use for the task filter cloud. If there is no match then the default filter (the first one in the list) is selected. |
| showIcons | `boolean` | false | Toggles display of the filter's icons. | | showIcons | `boolean` | false | Toggles display of the filter's icons. |
### Events ### Events
@@ -45,7 +45,7 @@ Use the `filterParam` property to restrict the range of filters that are shown:
</adf-cloud-task-filters> </adf-cloud-task-filters>
``` ```
You can use properties from [`TaskFilterCloudModel`](../../lib/process-services/task-list/models/filter.model.ts) You can use properties from [`FilterParamsModel`](../../lib/process-services/task-list/models/filter.model.ts)
as the value of `filterParam` as shown in the table below: as the value of `filterParam` as shown in the table below:
| Name | Type | Description | | Name | Type | Description |

View File

@@ -15,8 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
export let mockToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.' + export let mockToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ' +
'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydW' + 'zdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZmFtaWx5X25hbWUiOiJEb2UiLCJnaXZ' +
'UsImVtYWlsIjoiam9obkRvZUBnbWFpbC5jb20iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJqb' + 'lbl9uYW1lIjoiSm9obiIsImFkbWluIjp0cnVlLCJlbWFpbCI6ImpvaG5Eb2VAZ21haWwuY29tIiwicHJ' +
'2huRG9lMSIsImp0aSI6IjYyZDdiMDg1LWE1MmMtNGNmYS1iMDZmLWE4MWE3YjA2NGNkMiIsImlhdC' + 'lZmVycmVkX3VzZXJuYW1lIjoiam9obkRvZTEiLCJqdGkiOiI2MmQ3YjA4NS1hNTJjLTRjZmEtYjA2Zi1' +
'I6MTU0MzQxMDQ3NywiZXhwIjoxNTQzNDE1MjEzfQ.d0xX5QA - d6qGz2TpeWAPQE46B99BVMo_MyOXAMdfcIA'; 'hODFhN2IwNjRjZDIiLCJpYXQiOjE1NDM0MTA0NzcsImV4cCI6MTU0MzQxNTIxM30.pSP86kmX3keuU5E3ndaOUq2TzKdJRsuMnBdFz3Y-UEU';

View File

@@ -548,7 +548,7 @@ describe('User info component', () => {
beforeEach(async(() => { beforeEach(async(() => {
spyOn(authService, 'isOauth').and.returnValue(true); spyOn(authService, 'isOauth').and.returnValue(true);
spyOn(authService, 'isLoggedIn').and.returnValue(true); spyOn(authService, 'isLoggedIn').and.returnValue(true);
getCurrentUserInfoStub = spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(of(identityUserMock)); getCurrentUserInfoStub = spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(identityUserMock);
})); }));
it('should able to fetch identity userInfo', async(() => { it('should able to fetch identity userInfo', async(() => {
@@ -583,7 +583,7 @@ describe('User info component', () => {
it('should show last name if first name is null', async(() => { it('should show last name if first name is null', async(() => {
fixture.detectChanges(); fixture.detectChanges();
let fakeIdentityUser: IdentityUserModel = new IdentityUserModel(identityUserWithOutFirstNameMock); let fakeIdentityUser: IdentityUserModel = new IdentityUserModel(identityUserWithOutFirstNameMock);
getCurrentUserInfoStub.and.returnValue(of(fakeIdentityUser)); getCurrentUserInfoStub.and.returnValue(fakeIdentityUser);
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {

View File

@@ -23,7 +23,7 @@ import { IdentityUserModel } from './../models/identity-user.model';
import { BpmUserService } from './../services/bpm-user.service'; import { BpmUserService } from './../services/bpm-user.service';
import { EcmUserService } from './../services/ecm-user.service'; import { EcmUserService } from './../services/ecm-user.service';
import { IdentityUserService } from '../services/identity-user.service'; import { IdentityUserService } from '../services/identity-user.service';
import { Observable } from 'rxjs'; import { of, Observable } from 'rxjs';
@Component({ @Component({
selector: 'adf-userinfo', selector: 'adf-userinfo',
@@ -100,7 +100,7 @@ export class UserInfoComponent implements OnInit {
} }
loadIdentityUserInfo() { loadIdentityUserInfo() {
this.identityUser$ = this.identityUserService.getCurrentUserInfo(); this.identityUser$ = of(this.identityUserService.getCurrentUserInfo());
} }
stopClosing(event) { stopClosing(event) {

View File

@@ -64,17 +64,14 @@ describe('IdentityUserService', () => {
}); });
}); });
it('should fetch identity user info from Jwt token', (done) => { it('should fetch identity user info from Jwt token', () => {
localStorage.setItem('access_token', mockToken); localStorage.setItem('access_token', mockToken);
service.getCurrentUserInfo().subscribe( const user = service.getCurrentUserInfo();
(user) => { expect(user).toBeDefined();
expect(user).toBeDefined(); expect(user.firstName).toEqual('John');
expect(user.firstName).toEqual('John'); expect(user.lastName).toEqual('Doe');
expect(user.lastName).toEqual('Doe'); expect(user.email).toEqual('johnDoe@gmail.com');
expect(user.email).toEqual('johnDoe@gmail.com'); expect(user.username).toEqual('johnDoe1');
expect(user.username).toEqual('johnDoe1');
done();
});
}); });
it('should fetch users ', (done) => { it('should fetch users ', (done) => {
@@ -189,7 +186,7 @@ describe('IdentityUserService', () => {
it('should fetch users by roles without current user', (done) => { it('should fetch users by roles without current user', (done) => {
spyOn(service, 'getUsers').and.returnValue(of(mockUsers)); spyOn(service, 'getUsers').and.returnValue(of(mockUsers));
spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles)); spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles));
spyOn(service, 'getCurrentUserInfo').and.returnValue(of(mockUsers[0])); spyOn(service, 'getCurrentUserInfo').and.returnValue(mockUsers[0]);
service.getUsersByRolesWithoutCurrentUser([mockRoles[0].name]).then( service.getUsersByRolesWithoutCurrentUser([mockRoles[0].name]).then(
(res: IdentityUserModel[]) => { (res: IdentityUserModel[]) => {
@@ -202,23 +199,4 @@ describe('IdentityUserService', () => {
} }
); );
}); });
it('Should not fetch users by roles without current user if error occurred', (done) => {
const errorResponse = new HttpErrorResponse({
error: 'Mock Error',
status: 404, statusText: 'Not Found'
});
spyOn(service, 'getCurrentUserInfo').and.returnValue(throwError(errorResponse));
service.getUsersByRolesWithoutCurrentUser([mockRoles[0].name])
.catch(
(error) => {
expect(error.status).toEqual(404);
expect(error.statusText).toEqual('Not Found');
expect(error.error).toEqual('Mock Error');
done();
}
);
});
}); });

View File

@@ -16,7 +16,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { of, Observable, from } from 'rxjs'; import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { IdentityUserModel } from '../models/identity-user.model'; import { IdentityUserModel } from '../models/identity-user.model';
@@ -31,6 +31,8 @@ import { IdentityRoleModel } from '../models/identity-role.model';
export class IdentityUserService { export class IdentityUserService {
static USER_NAME = 'name'; static USER_NAME = 'name';
static FAMILY_NAME = 'family_name';
static GIVEN_NAME = 'given_name';
static USER_EMAIL = 'email'; static USER_EMAIL = 'email';
static USER_ACCESS_TOKEN = 'access_token'; static USER_ACCESS_TOKEN = 'access_token';
static USER_PREFERRED_USERNAME = 'preferred_username'; static USER_PREFERRED_USERNAME = 'preferred_username';
@@ -40,13 +42,13 @@ export class IdentityUserService {
private apiService: AlfrescoApiService, private apiService: AlfrescoApiService,
private appConfigService: AppConfigService) {} private appConfigService: AppConfigService) {}
getCurrentUserInfo(): Observable<IdentityUserModel> { getCurrentUserInfo(): IdentityUserModel {
const fullName = this.getValueFromToken<string>(IdentityUserService.USER_NAME); const familyName = this.getValueFromToken<string>(IdentityUserService.FAMILY_NAME);
const givenName = this.getValueFromToken<string>(IdentityUserService.GIVEN_NAME);
const email = this.getValueFromToken<string>(IdentityUserService.USER_EMAIL); const email = this.getValueFromToken<string>(IdentityUserService.USER_EMAIL);
const username = this.getValueFromToken<string>(IdentityUserService.USER_PREFERRED_USERNAME); const username = this.getValueFromToken<string>(IdentityUserService.USER_PREFERRED_USERNAME);
const nameParts = fullName.split(' '); const user = { firstName: givenName, lastName: familyName, email: email, username: username };
const user = { firstName: nameParts[0], lastName: nameParts[1], email: email, username: username }; return new IdentityUserModel(user);
return of(new IdentityUserModel(user));
} }
getValueFromToken<T>(key: string): T { getValueFromToken<T>(key: string): T {
@@ -110,7 +112,7 @@ export class IdentityUserService {
async getUsersByRolesWithoutCurrentUser(roleNames: string[]): Promise<IdentityUserModel[]> { async getUsersByRolesWithoutCurrentUser(roleNames: string[]): Promise<IdentityUserModel[]> {
const filteredUsers: IdentityUserModel[] = []; const filteredUsers: IdentityUserModel[] = [];
if (roleNames && roleNames.length > 0) { if (roleNames && roleNames.length > 0) {
const currentUser = await this.getCurrentUserInfo().toPromise(); const currentUser = this.getCurrentUserInfo();
let users = await this.getUsers().toPromise(); let users = await this.getUsers().toPromise();
users = users.filter((user) => { return user.username !== currentUser.username; }); users = users.filter((user) => { return user.username !== currentUser.username; });

View File

@@ -19,7 +19,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { setupTestBed } from '@alfresco/adf-core'; import { setupTestBed, IdentityUserService } from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { of } from 'rxjs'; import { of } from 'rxjs';
@@ -32,6 +32,7 @@ import { ProcessFilterCloudService } from '../services/process-filter-cloud.serv
describe('EditProcessFilterCloudComponent', () => { describe('EditProcessFilterCloudComponent', () => {
let component: EditProcessFilterCloudComponent; let component: EditProcessFilterCloudComponent;
let service: ProcessFilterCloudService; let service: ProcessFilterCloudService;
let identityService: IdentityUserService;
let fixture: ComponentFixture<EditProcessFilterCloudComponent>; let fixture: ComponentFixture<EditProcessFilterCloudComponent>;
let dialog: MatDialog; let dialog: MatDialog;
@@ -56,6 +57,7 @@ describe('EditProcessFilterCloudComponent', () => {
fixture = TestBed.createComponent(EditProcessFilterCloudComponent); fixture = TestBed.createComponent(EditProcessFilterCloudComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
service = TestBed.get(ProcessFilterCloudService); service = TestBed.get(ProcessFilterCloudService);
identityService = TestBed.get(IdentityUserService);
dialog = TestBed.get(MatDialog); dialog = TestBed.get(MatDialog);
spyOn(dialog, 'open').and.returnValue({ afterClosed() { return of({ spyOn(dialog, 'open').and.returnValue({ afterClosed() { return of({
action: ProcessFilterDialogCloudComponent.ACTION_SAVE, action: ProcessFilterDialogCloudComponent.ACTION_SAVE,
@@ -236,6 +238,7 @@ describe('EditProcessFilterCloudComponent', () => {
}); });
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(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue({username: 'currentUser'});
const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter); const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter);
let saveSpy: jasmine.Spy = spyOn(component.action, 'emit'); let saveSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -257,6 +260,7 @@ describe('EditProcessFilterCloudComponent', () => {
})); }));
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(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue({username: 'currentUser'});
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough(); const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough();
let deleteSpy: jasmine.Spy = spyOn(component.action, 'emit'); let deleteSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -265,16 +269,17 @@ describe('EditProcessFilterCloudComponent', () => {
const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement;
stateElement.click(); stateElement.click();
fixture.detectChanges(); fixture.detectChanges();
let deleteButton = fixture.debugElement.nativeElement.querySelector('#adf-delete-id');
deleteButton.click();
fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
let deleteButton = fixture.debugElement.nativeElement.querySelector('#adf-delete-id');
deleteButton.click();
fixture.detectChanges();
expect(deleteFilterSpy).toHaveBeenCalled(); expect(deleteFilterSpy).toHaveBeenCalled();
expect(deleteSpy).toHaveBeenCalled(); expect(deleteSpy).toHaveBeenCalled();
}); });
})); }));
it('should emit saveAs event and add filter on click of saveAs button', async(() => { it('should emit saveAs event and add filter on click saveAs button', async(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue({username: 'currentUser'});
const saveAsFilterSpy = spyOn(service, 'addFilter').and.callThrough(); const saveAsFilterSpy = spyOn(service, 'addFilter').and.callThrough();
let saveAsSpy: jasmine.Spy = spyOn(component.action, 'emit'); let saveAsSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -283,35 +288,17 @@ describe('EditProcessFilterCloudComponent', () => {
const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement;
stateElement.click(); stateElement.click();
fixture.detectChanges(); fixture.detectChanges();
const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id');
const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
stateOptions[2].nativeElement.click();
fixture.detectChanges();
saveButton.click();
fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id');
const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
stateOptions[2].nativeElement.click();
fixture.detectChanges();
saveButton.click();
fixture.detectChanges();
expect(saveAsFilterSpy).toHaveBeenCalled(); expect(saveAsFilterSpy).toHaveBeenCalled();
expect(saveAsSpy).toHaveBeenCalled(); expect(saveAsSpy).toHaveBeenCalled();
expect(dialog.open).toHaveBeenCalled(); expect(dialog.open).toHaveBeenCalled();
}); });
})); }));
it('should able to open save dialog on click of saveAs button', async(() => {
fixture.detectChanges();
let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement;
stateElement.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id');
const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
stateOptions[2].nativeElement.click();
fixture.detectChanges();
saveButton.click();
fixture.detectChanges();
expect(dialog.open).toHaveBeenCalled();
});
}));
}); });
}); });

View File

@@ -20,6 +20,7 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { setupTestBed } from '@alfresco/adf-core'; import { setupTestBed } from '@alfresco/adf-core';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
import { FilterParamsModel } from '../../task-cloud/models/filter-cloud.model';
import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; import { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
import { ProcessFiltersCloudComponent } from './process-filters-cloud.component'; import { ProcessFiltersCloudComponent } from './process-filters-cloud.component';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
@@ -62,14 +63,6 @@ describe('ProcessFiltersCloudComponent', () => {
resolve(fakeGlobalFilter); resolve(fakeGlobalFilter);
}); });
let fakeGlobalEmptyFilter = {
message: 'invalid data'
};
let fakeGlobalEmptyFilterPromise = new Promise(function (resolve, reject) {
resolve(fakeGlobalEmptyFilter);
});
let mockErrorFilterList = { let mockErrorFilterList = {
error: 'wrong request' error: 'wrong request'
}; };
@@ -187,25 +180,10 @@ describe('ProcessFiltersCloudComponent', () => {
})); }));
it('should be able to fetch and select the default filters if the input filter is not valid', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(from(fakeGlobalEmptyFilterPromise));
spyOn(component, 'createFilters').and.callThrough();
const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true);
component.ngOnChanges({ 'appName': change });
component.success.subscribe((res) => {
expect(res).toBeDefined();
expect(component.createFilters).not.toHaveBeenCalled();
done();
});
});
it('should select the filter based on the input by name param', (done) => { it('should select the filter based on the input by name param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterCloudModel({ name: 'FakeRunningProcesses' }); component.filterParam = new FilterParamsModel({ name: 'FakeRunningProcesses' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -224,7 +202,7 @@ describe('ProcessFiltersCloudComponent', () => {
it('should select the filter based on the input by key param', (done) => { it('should select the filter based on the input by key param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterCloudModel({ key: 'completed-processes' }); component.filterParam = new FilterParamsModel({ key: 'completed-processes' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -244,7 +222,7 @@ describe('ProcessFiltersCloudComponent', () => {
it('should select the default filter if filter input does not exist', (done) => { it('should select the default filter if filter input does not exist', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterCloudModel({ name: 'UnexistableFilter' }); component.filterParam = new FilterParamsModel({ name: 'UnexistableFilter' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -265,7 +243,7 @@ describe('ProcessFiltersCloudComponent', () => {
it('should select the filter based on the input by index param', (done) => { it('should select the filter based on the input by index param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterCloudModel({ index: 2 }); component.filterParam = new FilterParamsModel({ index: 2 });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -285,7 +263,7 @@ describe('ProcessFiltersCloudComponent', () => {
it('should select the filter based on the input by id param', (done) => { it('should select the filter based on the input by id param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterCloudModel({ id: '12' }); component.filterParam = new FilterParamsModel({ id: '12' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -304,7 +282,7 @@ describe('ProcessFiltersCloudComponent', () => {
it('should emit an event when a filter is selected', (done) => { it('should emit an event when a filter is selected', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterCloudModel({ id: '10' }); component.filterParam = new FilterParamsModel({ id: '10' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);

View File

@@ -19,6 +19,7 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from
import { Observable } from 'rxjs'; import { Observable } 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';
import { FilterParamsModel } from '../../task-cloud/models/filter-cloud.model';
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
@Component({ @Component({
selector: 'adf-cloud-process-filters', selector: 'adf-cloud-process-filters',
@@ -33,7 +34,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** (optional) The filter to be selected by default */ /** (optional) The filter to be selected by default */
@Input() @Input()
filterParam: ProcessFilterCloudModel; filterParam: FilterParamsModel;
/** (optional) The flag hides/shows icon against each filter */ /** (optional) The flag hides/shows icon against each filter */
@Input() @Input()
@@ -59,7 +60,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
constructor( constructor(
private processFilterCloudService: ProcessFilterCloudService, private processFilterCloudService: ProcessFilterCloudService,
private translate: TranslationService ) { } private translationService: TranslationService ) { }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
const appName = changes['appName']; const appName = changes['appName'];
@@ -67,7 +68,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
if (appName && appName.currentValue) { if (appName && appName.currentValue) {
this.getFilters(appName.currentValue); this.getFilters(appName.currentValue);
} else if (filter && filter.currentValue !== filter.previousValue) { } else if (filter && filter.currentValue !== filter.previousValue) {
this.selectFilterAndEmit(filter.currentValue); this.selectFilter(filter.currentValue);
} }
} }
@@ -79,12 +80,8 @@ export class ProcessFiltersCloudComponent implements OnChanges {
this.filters$.subscribe( this.filters$.subscribe(
(res: ProcessFilterCloudModel[]) => { (res: ProcessFilterCloudModel[]) => {
if (res.length === 0) { this.resetFilter();
this.createFilters(appName); this.filters = Object.assign([], res);
} else {
this.resetFilter();
this.filters = res;
}
this.selectFilterAndEmit(this.filterParam); this.selectFilterAndEmit(this.filterParam);
this.success.emit(res); this.success.emit(res);
}, },
@@ -94,33 +91,16 @@ export class ProcessFiltersCloudComponent implements OnChanges {
); );
} }
/**
* Create default filters by appName
*/
createFilters(appName?: string) {
this.filters$ = this.processFilterCloudService.createDefaultFilters(appName);
this.filters$.subscribe(
(resDefault: ProcessFilterCloudModel[]) => {
this.resetFilter();
this.filters = resDefault;
},
(errDefault: any) => {
this.error.emit(errDefault);
}
);
}
/** /**
* Pass the selected filter as next * Pass the selected filter as next
*/ */
public selectFilter(filterParam: ProcessFilterCloudModel) { public selectFilter(paramFilter: FilterParamsModel) {
if (filterParam) { if (paramFilter) {
this.currentFilter = this.filters.find((filter, index) => { this.currentFilter = this.filters.find((filter, index) => {
return filterParam.id === filter.id || return paramFilter.id === filter.id ||
(filterParam.name && this.checkFilterNamesEquality(filterParam.name, filter.name)) || (paramFilter.name && this.checkFilterNamesEquality(paramFilter.name, filter.name)) ||
(filterParam.key && (filterParam.key === filter.key)) || (paramFilter.key && (paramFilter.key === filter.key)) ||
filterParam.index === index; paramFilter.index === index;
}); });
} }
if (!this.currentFilter) { if (!this.currentFilter) {
@@ -132,8 +112,8 @@ export class ProcessFiltersCloudComponent implements OnChanges {
* Check equality of the filter names by translating the given name strings * Check equality of the filter names by translating the given name strings
*/ */
private checkFilterNamesEquality(name1: string, name2: string ): boolean { private checkFilterNamesEquality(name1: string, name2: string ): boolean {
const translatedName1 = this.translate.instant(name1); const translatedName1 = this.translationService.instant(name1);
const translatedName2 = this.translate.instant(name2); const translatedName2 = this.translationService.instant(name2);
return translatedName1.toLocaleLowerCase() === translatedName2.toLocaleLowerCase(); return translatedName1.toLocaleLowerCase() === translatedName2.toLocaleLowerCase();
} }
@@ -141,8 +121,8 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** /**
* Select and emit the given filter * Select and emit the given filter
*/ */
public selectFilterAndEmit(newFilter: ProcessFilterCloudModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
this.selectFilter(newFilter); this.selectFilter(newParamFilter);
this.filterClick.emit(this.currentFilter); this.filterClick.emit(this.currentFilter);
} }

View File

@@ -15,15 +15,22 @@
* limitations under the License. * limitations under the License.
*/ */
import { StorageService } from '@alfresco/adf-core'; import { StorageService, IdentityUserService, IdentityUserModel } from '@alfresco/adf-core';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable, BehaviorSubject } from 'rxjs';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
@Injectable() @Injectable()
export class ProcessFilterCloudService { export class ProcessFilterCloudService {
constructor(private storage: StorageService) { private filtersSubject: BehaviorSubject<ProcessFilterCloudModel[]>;
filters$: Observable<ProcessFilterCloudModel[]>;
constructor(
private storage: StorageService,
private identityUserService: IdentityUserService) {
this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable();
} }
/** /**
@@ -31,15 +38,13 @@ export class ProcessFilterCloudService {
* @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 just created
*/ */
public createDefaultFilters(appName: string): Observable<ProcessFilterCloudModel[]> { private createDefaultFilters(appName: string) {
const allProcessesFilter = this.getAllProcessesFilter(appName); const allProcessesFilter = this.getAllProcessesFilter(appName);
this.addFilter(allProcessesFilter); this.addFilter(allProcessesFilter);
const runningProcessesFilter = this.getRunningProcessesFilter(appName); const runningProcessesFilter = this.getRunningProcessesFilter(appName);
this.addFilter(runningProcessesFilter); this.addFilter(runningProcessesFilter);
const completedProcessesFilter = this.getCompletedProcessesFilter(appName); const completedProcessesFilter = this.getCompletedProcessesFilter(appName);
this.addFilter(completedProcessesFilter); this.addFilter(completedProcessesFilter);
return this.getProcessFilters(appName);
} }
/** /**
@@ -48,12 +53,16 @@ export class ProcessFilterCloudService {
* @returns Observable of process filter details * @returns Observable of process filter details
*/ */
getProcessFilters(appName: string): Observable<ProcessFilterCloudModel[]> { getProcessFilters(appName: string): Observable<ProcessFilterCloudModel[]> {
let key = 'process-filters-' + appName; const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo();
const key = `process-filters-${appName}-${user.username}`;
const filters = JSON.parse(this.storage.getItem(key) || '[]'); const filters = JSON.parse(this.storage.getItem(key) || '[]');
return new Observable(function(observer) {
observer.next(filters); if (filters.length === 0) {
observer.complete(); this.createDefaultFilters(appName);
}); } else {
this.addFiltersToStream(filters);
}
return this.filters$;
} }
/** /**
@@ -63,7 +72,8 @@ export class ProcessFilterCloudService {
* @returns Details of process filter * @returns Details of process filter
*/ */
getProcessFilterById(appName: string, id: string): ProcessFilterCloudModel { getProcessFilterById(appName: string, id: string): ProcessFilterCloudModel {
const key = 'process-filters-' + appName; const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo();
const key = `process-filters-${appName}-${user.username}`;
let filters = []; let filters = [];
filters = JSON.parse(this.storage.getItem(key)) || []; filters = JSON.parse(this.storage.getItem(key)) || [];
return filters.filter((filterTmp: ProcessFilterCloudModel) => id === filterTmp.id)[0]; return filters.filter((filterTmp: ProcessFilterCloudModel) => id === filterTmp.id)[0];
@@ -75,11 +85,14 @@ export class ProcessFilterCloudService {
* @returns Details of process filter just added * @returns Details of process filter just added
*/ */
addFilter(filter: ProcessFilterCloudModel) { addFilter(filter: ProcessFilterCloudModel) {
const key = 'process-filters-' + filter.appName; const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo();
const key = `process-filters-${filter.appName}-${user.username}`;
const storedFilters = JSON.parse(this.storage.getItem(key) || '[]'); const storedFilters = JSON.parse(this.storage.getItem(key) || '[]');
storedFilters.push(filter); storedFilters.push(filter);
this.storage.setItem(key, JSON.stringify(storedFilters)); this.storage.setItem(key, JSON.stringify(storedFilters));
this.addFiltersToStream(storedFilters);
} }
/** /**
@@ -87,12 +100,14 @@ export class ProcessFilterCloudService {
* @param filter The new filter to update * @param filter The new filter to update
*/ */
updateFilter(filter: ProcessFilterCloudModel) { updateFilter(filter: ProcessFilterCloudModel) {
const key = 'process-filters-' + filter.appName; const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo();
const key = `process-filters-${filter.appName}-${user.username}`;
if (key) { if (key) {
let filters = JSON.parse(this.storage.getItem(key) || '[]'); let filters = JSON.parse(this.storage.getItem(key) || '[]');
let itemIndex = filters.findIndex((flt: ProcessFilterCloudModel) => flt.id === filter.id); let itemIndex = filters.findIndex((flt: ProcessFilterCloudModel) => flt.id === filter.id);
filters[itemIndex] = filter; filters[itemIndex] = filter;
this.storage.setItem(key, JSON.stringify(filters)); this.storage.setItem(key, JSON.stringify(filters));
this.addFiltersToStream(filters);
} }
} }
@@ -101,11 +116,17 @@ export class ProcessFilterCloudService {
* @param filter The new filter to delete * @param filter The new filter to delete
*/ */
deleteFilter(filter: ProcessFilterCloudModel) { deleteFilter(filter: ProcessFilterCloudModel) {
const key = 'process-filters-' + filter.appName; const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo();
const key = `process-filters-${filter.appName}-${user.username}`;
if (key) { if (key) {
let filters = JSON.parse(this.storage.getItem(key) || '[]'); let filters = JSON.parse(this.storage.getItem(key) || '[]');
filters = filters.filter((item) => item.id !== filter.id); filters = filters.filter((item) => item.id !== filter.id);
this.storage.setItem(key, JSON.stringify(filters)); this.storage.setItem(key, JSON.stringify(filters));
if (filters.length === 0) {
this.createDefaultFilters(filter.appName);
} else {
this.addFiltersToStream(filters);
}
} }
} }
@@ -159,4 +180,8 @@ export class ProcessFilterCloudService {
order: 'DESC' order: 'DESC'
}); });
} }
private addFiltersToStream(filters: ProcessFilterCloudModel []) {
this.filtersSubject.next(filters);
}
} }

View File

@@ -63,7 +63,7 @@ describe('PeopleCloudComponent', () => {
})); }));
it('should not list the current logged in user when showCurrentUser is false', async(() => { it('should not list the current logged in user when showCurrentUser is false', async(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue(of(mockUsers[1])); spyOn(identityService, 'getCurrentUserInfo').and.returnValue(mockUsers[1]);
component.showCurrentUser = false; component.showCurrentUser = false;
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {

View File

@@ -62,7 +62,7 @@ describe('StartTaskCloudComponent', () => {
createNewTaskSpy = spyOn(service, 'createNewTask').and.returnValue(of(taskDetailsMock)); createNewTaskSpy = spyOn(service, 'createNewTask').and.returnValue(of(taskDetailsMock));
getRolesByUserIdSpy = spyOn(identityService, 'getUserRoles').and.returnValue(of(mockRoles)); getRolesByUserIdSpy = spyOn(identityService, 'getUserRoles').and.returnValue(of(mockRoles));
getUserSpy = spyOn(identityService, 'getUsers').and.returnValue(of(mockUsers)); getUserSpy = spyOn(identityService, 'getUsers').and.returnValue(of(mockUsers));
spyOn(identityService, 'getCurrentUserInfo').and.returnValue(of(new IdentityUserModel({username: 'currentUser'}))); spyOn(identityService, 'getCurrentUserInfo').and.returnValue(new IdentityUserModel({username: 'currentUser'}));
fixture.detectChanges(); fixture.detectChanges();
})); }));

View File

@@ -128,8 +128,8 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
StartTaskCloudComponent.MAX_NAME_LENGTH : this.maxNameLength; StartTaskCloudComponent.MAX_NAME_LENGTH : this.maxNameLength;
} }
private async loadCurrentUser() { private loadCurrentUser() {
this.currentUser = await this.identityUserService.getCurrentUserInfo().toPromise(); this.currentUser = this.identityUserService.getCurrentUserInfo();
} }
public saveTask() { public saveTask() {

View File

@@ -44,7 +44,20 @@ export class TaskFilterCloudModel {
} }
} }
} }
export class FilterParamsModel {
id?: string;
name?: string;
key?: string;
index?: number;
constructor(obj?: any) {
if (obj) {
this.id = obj.id || null;
this.name = obj.name || null;
this.key = obj.key || null;
this.index = obj.index;
}
}
}
export interface FilterActionType { export interface FilterActionType {
actionType: string; actionType: string;
id: string; id: string;

View File

@@ -35,7 +35,7 @@ export class TaskFilterCloudService {
* @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 just created
*/ */
public createDefaultFilters(appName: string) { private createDefaultFilters(appName: string) {
let myTasksFilter = this.getMyTasksFilterInstance(appName); let myTasksFilter = this.getMyTasksFilterInstance(appName);
this.addFilter(myTasksFilter); this.addFilter(myTasksFilter);
@@ -102,6 +102,7 @@ export class TaskFilterCloudService {
let itemIndex = filters.findIndex((flt: TaskFilterCloudModel) => flt.id === filter.id); let itemIndex = filters.findIndex((flt: TaskFilterCloudModel) => flt.id === filter.id);
filters[itemIndex] = filter; filters[itemIndex] = filter;
this.storage.setItem(key, JSON.stringify(filters)); this.storage.setItem(key, JSON.stringify(filters));
this.addFiltersToStream(filters);
} }
} }

View File

@@ -19,7 +19,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { setupTestBed } from '@alfresco/adf-core'; import { setupTestBed, IdentityUserService } from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { TaskFilterCloudModel } from '../models/filter-cloud.model'; import { TaskFilterCloudModel } from '../models/filter-cloud.model';
import { TaskCloudModule } from './../task-cloud.module'; import { TaskCloudModule } from './../task-cloud.module';
@@ -32,6 +32,7 @@ import { TaskFilterDialogCloudComponent } from './task-filter-dialog-cloud.compo
describe('EditTaskFilterCloudComponent', () => { describe('EditTaskFilterCloudComponent', () => {
let component: EditTaskFilterCloudComponent; let component: EditTaskFilterCloudComponent;
let service: TaskFilterCloudService; let service: TaskFilterCloudService;
let identityService: IdentityUserService;
let fixture: ComponentFixture<EditTaskFilterCloudComponent>; let fixture: ComponentFixture<EditTaskFilterCloudComponent>;
let dialog: MatDialog; let dialog: MatDialog;
@@ -56,6 +57,7 @@ describe('EditTaskFilterCloudComponent', () => {
fixture = TestBed.createComponent(EditTaskFilterCloudComponent); fixture = TestBed.createComponent(EditTaskFilterCloudComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
service = TestBed.get(TaskFilterCloudService); service = TestBed.get(TaskFilterCloudService);
identityService = TestBed.get(IdentityUserService);
dialog = TestBed.get(MatDialog); dialog = TestBed.get(MatDialog);
spyOn(dialog, 'open').and.returnValue({ afterClosed() { return of({ spyOn(dialog, 'open').and.returnValue({ afterClosed() { return of({
action: TaskFilterDialogCloudComponent.ACTION_SAVE, action: TaskFilterDialogCloudComponent.ACTION_SAVE,
@@ -223,6 +225,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(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue({username: 'currentUser'});
const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter); const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter);
let saveSpy: jasmine.Spy = spyOn(component.action, 'emit'); let saveSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -244,6 +247,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(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue({username: 'currentUser'});
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough(); const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough();
let deleteSpy: jasmine.Spy = spyOn(component.action, 'emit'); let deleteSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -262,6 +266,7 @@ describe('EditTaskFilterCloudComponent', () => {
})); }));
it('should emit saveAs event and add filter on click saveAs button', async(() => { it('should emit saveAs event and add filter on click saveAs button', async(() => {
spyOn(identityService, 'getCurrentUserInfo').and.returnValue({username: 'currentUser'});
const saveAsFilterSpy = spyOn(service, 'addFilter').and.callThrough(); const saveAsFilterSpy = spyOn(service, 'addFilter').and.callThrough();
let saveAsSpy: jasmine.Spy = spyOn(component.action, 'emit'); let saveAsSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -272,7 +277,7 @@ describe('EditTaskFilterCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id'); const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id');
const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
stateOptions[3].nativeElement.click(); stateOptions[2].nativeElement.click();
fixture.detectChanges(); fixture.detectChanges();
saveButton.click(); saveButton.click();
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -1,6 +1,6 @@
<div class="menu-container"> <div class="menu-container">
<mat-list class="adf-menu-list" *ngIf="filters$ | async as filterList; else loading"> <mat-list class="adf-menu-list" *ngIf="filters$ | async as filterList; else loading">
<mat-list-item (click)="selectFilterAndEmit(filter)" *ngFor="let filter of filterList" <mat-list-item (click)="selectFilterAndEmit({id: filter.id})" *ngFor="let filter of filterList"
class="adf-filters__entry" [class.adf-active]="currentFilter === filter"> class="adf-filters__entry" [class.adf-active]="currentFilter === filter">
<mat-icon *ngIf="showIcons && filter.icon" matListIcon class="adf-filters__entry-icon">{{filter.icon}} <mat-icon *ngIf="showIcons && filter.icon" matListIcon class="adf-filters__entry-icon">{{filter.icon}}
</mat-icon> </mat-icon>

View File

@@ -19,7 +19,7 @@ import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { setupTestBed } from '@alfresco/adf-core'; import { setupTestBed } from '@alfresco/adf-core';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { TaskFilterCloudModel } from '../models/filter-cloud.model'; import { TaskFilterCloudModel, FilterParamsModel } from '../models/filter-cloud.model';
import { TaskFilterCloudService } from '../services/task-filter-cloud.service'; import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
import { TaskFiltersCloudComponent } from './task-filters-cloud.component'; import { TaskFiltersCloudComponent } from './task-filters-cloud.component';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
@@ -201,7 +201,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should select the task filter based on the input by name param', async(() => { it('should select the task filter based on the input by name param', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new TaskFilterCloudModel({ name: 'FakeMyTasks1' }); component.filterParam = new FilterParamsModel({ name: 'FakeMyTasks1' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -219,7 +219,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should select the default task filter if filter input does not exist', async(() => { it('should select the default task filter if filter input does not exist', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new TaskFilterCloudModel({ name: 'UnexistableFilter' }); component.filterParam = new FilterParamsModel({ name: 'UnexistableFilter' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -238,7 +238,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should select the task filter based on the input by index param', async(() => { it('should select the task filter based on the input by index param', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new TaskFilterCloudModel({ index: 2 }); component.filterParam = new FilterParamsModel({ index: 2 });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -257,8 +257,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should select the task filter based on the input by id param', async(() => { it('should select the task filter based on the input by id param', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new TaskFilterCloudModel({ id: 12 }); component.filterParam = new FilterParamsModel({ id: 12 });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -276,7 +275,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should emit an event when a filter is selected', async(() => { it('should emit an event when a filter is selected', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new TaskFilterCloudModel({ id: 12 }); component.filterParam = new FilterParamsModel({ id: 12 });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -286,7 +285,7 @@ describe('TaskFiltersCloudComponent', () => {
spyOn(component, 'selectFilterAndEmit').and.stub(); spyOn(component, 'selectFilterAndEmit').and.stub();
let filterButton = fixture.debugElement.nativeElement.querySelector('span[data-automation-id="fake-my-tast1-filter"]'); let filterButton = fixture.debugElement.nativeElement.querySelector('span[data-automation-id="fake-my-tast1-filter"]');
filterButton.click(); filterButton.click();
expect(component.selectFilterAndEmit).toHaveBeenCalledWith(fakeGlobalFilter[1]); expect(component.selectFilterAndEmit).toHaveBeenCalledWith({id: fakeGlobalFilter[1].id});
})); }));
it('should reload filters by appName on binding changes', () => { it('should reload filters by appName on binding changes', () => {
@@ -347,7 +346,7 @@ describe('TaskFiltersCloudComponent', () => {
}); });
it('should return the current filter after one is selected', () => { it('should return the current filter after one is selected', () => {
let filter = new TaskFilterCloudModel({ name: 'FakeInvolvedTasks' }); let filter = new FilterParamsModel({ name: 'FakeInvolvedTasks' });
component.filters = fakeGlobalFilter; component.filters = fakeGlobalFilter;
expect(component.currentFilter).toBeUndefined(); expect(component.currentFilter).toBeUndefined();

View File

@@ -18,7 +18,7 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } 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 } 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';
@Component({ @Component({
selector: 'adf-cloud-task-filters', selector: 'adf-cloud-task-filters',
@@ -35,7 +35,7 @@ export class TaskFiltersCloudComponent implements OnChanges {
* (the first one in the list) is selected. * (the first one in the list) is selected.
*/ */
@Input() @Input()
filterParam: TaskFilterCloudModel; filterParam: FilterParamsModel;
/** Toggles display of the filter's icons. */ /** Toggles display of the filter's icons. */
@Input() @Input()
@@ -91,14 +91,14 @@ export class TaskFiltersCloudComponent implements OnChanges {
); );
} }
public selectFilter(newFilter: TaskFilterCloudModel) { public selectFilter(paramFilter: FilterParamsModel) {
if (newFilter) { if (paramFilter) {
this.currentFilter = this.filters.find( (filter: TaskFilterCloudModel, index) => this.currentFilter = this.filters.find( (filter: TaskFilterCloudModel, index) =>
newFilter.index === index || paramFilter.index === index ||
newFilter.key === filter.key || paramFilter.key === filter.key ||
newFilter.id === filter.id || paramFilter.id === filter.id ||
(newFilter.name && (paramFilter.name &&
(newFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase()) (paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase())
)); ));
} }
if (!this.currentFilter) { if (!this.currentFilter) {
@@ -106,8 +106,8 @@ export class TaskFiltersCloudComponent implements OnChanges {
} }
} }
public selectFilterAndEmit(newFilter: TaskFilterCloudModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
this.selectFilter(newFilter); this.selectFilter(newParamFilter);
this.filterClick.emit(this.currentFilter); this.filterClick.emit(this.currentFilter);
} }