TSK-179 Create filtering component and apply filtering on workbasket list.

This commit is contained in:
Martin Rojas Miguel Angel 2018-02-20 12:45:36 +01:00 committed by Holger Hagen
parent 2652810461
commit 274fa67a53
14 changed files with 366 additions and 196 deletions

View File

@ -9,7 +9,7 @@
"build:prod": "ng build --environment=prod --no-progress",
"test": "./node_modules/.bin/karma start --single-run --browsers Firefox",
"test-phantom": "./node_modules/.bin/karma start --single-run --browsers PhantomJS",
"test:watch": "./node_modules/.bin/karma start --browsers Firefox",
"test:watch": "./node_modules/.bin/karma start --browsers Chrome",
"lint": "ng lint",
"e2e": "ng e2e"
},

View File

@ -26,6 +26,7 @@ import { WorkbasketDetailsComponent } from './workbasket/details/workbasket-deta
import { WorkbasketInformationComponent } from './workbasket/details/information/workbasket-information.component';
import { NoAccessComponent } from './workbasket/noAccess/no-access.component';
import { SpinnerComponent } from './shared/spinner/spinner.component';
import { FilterComponent } from './shared/filter/filter.component';
//Shared
import { MasterAndDetailComponent} from './shared/masterAndDetail/master-and-detail.component';
@ -56,7 +57,7 @@ const MODULES = [
HttpClientModule
];
const COMPONENTS = [
const DECLARATIONS = [
AppComponent,
WorkbasketListComponent,
CategorieslistComponent,
@ -70,10 +71,12 @@ const COMPONENTS = [
WorkbasketInformationComponent,
NoAccessComponent,
SpinnerComponent,
FilterComponent,
MapValuesPipe
];
@NgModule({
declarations: COMPONENTS,
declarations: DECLARATIONS,
imports: MODULES,
providers: [
WorkbasketService,

View File

@ -10,8 +10,8 @@ import { Subject } from 'rxjs/Subject';
//sort direction
export enum Direction{
ASC = "asc",
DESC = "desc"
ASC = 'asc',
DESC = 'desc'
};
@Injectable()
@ -22,20 +22,21 @@ export class WorkbasketService {
constructor(private httpClient: HttpClient) { }
//Sorting
readonly SORTBY="sortBy";
readonly ORDER="order";
readonly SORTBY='sortBy';
readonly ORDER='order';
//Filtering
readonly NAME="name";
readonly NAMELIKE="nameLike";
readonly DESCLIKE="descLike";
readonly OWNER="owner";
readonly OWNERLIKE="ownerLike";
readonly TYPE="type";
readonly KEY="key";
readonly NAME='name';
readonly NAMELIKE='nameLike';
readonly DESCLIKE='descLike';
readonly OWNER='owner';
readonly OWNERLIKE='ownerLike';
readonly TYPE='type';
readonly KEY='key';
readonly KEYLIKE='keyLike';
//Access
readonly REQUIREDPERMISSION="requiredPermission";
readonly REQUIREDPERMISSION='requiredPermission';
httpOptions = {
headers: new HttpHeaders({
@ -53,10 +54,12 @@ export class WorkbasketService {
owner:string = undefined,
ownerLike:string = undefined,
type:string = undefined,
key:string = undefined,
keyLike:string = undefined,
requiredPermission: string = undefined): Observable<WorkbasketSummary[]> {
return this.httpClient.get<WorkbasketSummary[]>(`${environment.taskanaRestUrl}/v1/workbaskets/${this.getWorkbasketSummaryQueryParameters(sortBy, order, name,
nameLike, descLike, owner, ownerLike, type, requiredPermission)}`,this.httpOptions)
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission)}`,this.httpOptions)
}
@ -65,31 +68,31 @@ export class WorkbasketService {
}
createWorkbasket(workbasket: WorkbasketSummary): Observable<WorkbasketSummary> {
return this.httpClient.post<WorkbasketSummary>(environment.taskanaRestUrl + "/v1/workbaskets", workbasket, this.httpOptions);
return this.httpClient.post<WorkbasketSummary>(environment.taskanaRestUrl + '/v1/workbaskets', workbasket, this.httpOptions);
}
deleteWorkbasket(id: string) {
return this.httpClient.delete(environment.taskanaRestUrl + "/v1/workbaskets/" + id, this.httpOptions);
return this.httpClient.delete(environment.taskanaRestUrl + '/v1/workbaskets/' + id, this.httpOptions);
}
updateWorkbasket(workbasket: WorkbasketSummary): Observable<WorkbasketSummary> {
return this.httpClient.put<WorkbasketSummary>(environment.taskanaRestUrl + "/v1/workbaskets/" + workbasket.workbasketId, workbasket, this.httpOptions);
return this.httpClient.put<WorkbasketSummary>(environment.taskanaRestUrl + '/v1/workbaskets/' + workbasket.workbasketId, workbasket, this.httpOptions);
}
getAllWorkBasketAuthorizations(id: String): Observable<WorkbasketAuthorization[]> {
return this.httpClient.get<WorkbasketAuthorization[]>(environment.taskanaRestUrl + "/v1/workbaskets/" + id + "/authorizations", this.httpOptions);
return this.httpClient.get<WorkbasketAuthorization[]>(environment.taskanaRestUrl + '/v1/workbaskets/' + id + '/authorizations', this.httpOptions);
}
createWorkBasketAuthorization(workbasketAuthorization: WorkbasketAuthorization): Observable<WorkbasketAuthorization> {
return this.httpClient.post<WorkbasketAuthorization>(environment.taskanaRestUrl + "/v1/workbaskets/authorizations", workbasketAuthorization, this.httpOptions);
return this.httpClient.post<WorkbasketAuthorization>(environment.taskanaRestUrl + '/v1/workbaskets/authorizations', workbasketAuthorization, this.httpOptions);
}
updateWorkBasketAuthorization(workbasketAuthorization: WorkbasketAuthorization): Observable<WorkbasketAuthorization> {
return this.httpClient.put<WorkbasketAuthorization>(environment.taskanaRestUrl + "/v1/workbaskets/authorizations/" + workbasketAuthorization.id, workbasketAuthorization, this.httpOptions)
return this.httpClient.put<WorkbasketAuthorization>(environment.taskanaRestUrl + '/v1/workbaskets/authorizations/' + workbasketAuthorization.id, workbasketAuthorization, this.httpOptions)
}
deleteWorkBasketAuthorization(workbasketAuthorization: WorkbasketAuthorization) {
return this.httpClient.delete(environment.taskanaRestUrl + "/v1/workbaskets/authorizations/" + workbasketAuthorization.id, this.httpOptions);
return this.httpClient.delete(environment.taskanaRestUrl + '/v1/workbaskets/authorizations/' + workbasketAuthorization.id, this.httpOptions);
}
//Service extras
@ -106,11 +109,13 @@ export class WorkbasketService {
name: string,
nameLike: string,
descLike: string,
owner:string,
ownerLike:string,
type:string,
owner: string,
ownerLike: string,
type: string,
key: string,
keyLike: string,
requiredPermission: string): string{
let query: string = "?";
let query: string = '?';
query += sortBy? `${this.SORTBY}=${sortBy}&`:'';
query += order? `${this.ORDER}=${order}&`:'';
query += name? `${this.NAME}=${name}&`:'';
@ -119,6 +124,8 @@ export class WorkbasketService {
query += owner? `${this.OWNER}=${owner}&`:'';
query += ownerLike? `${this.OWNERLIKE}=${ownerLike}&`:'';
query += type? `${this.TYPE}=${type}&`:'';
query += key? `${this.KEY}=${key}&`:'';
query += keyLike? `${this.KEYLIKE}=${keyLike}&`:'';
query += requiredPermission? `${this.REQUIREDPERMISSION}=${requiredPermission}&`:'';
if(query.lastIndexOf('&') === query.length-1){

View File

@ -0,0 +1,51 @@
<div type="text" id="{{target}}" class="list-group-seach collapse">
<div class="row">
<div class="dropdown col-xs-2">
<button class="btn btn-default {{!filter.type? 'glyphicon glyphicon-asterisk blue' : '' }}" type="button" id="dropdownMenufilter" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<svg-icon *ngIf="filter.type" class="small blue" src="./assets/icons/{{(filter.type === 'PERSONAL')? 'user.svg': (filter.type === 'GROUP')? 'users.svg' :''}}"></svg-icon>
</button>
<ul class="dropdown-menu dropdown-menu-users" role="menu">
<li>
<button type="button" (click)="selectType(-1)" placeholder="individual" class="btn btn-default glyphicon glyphicon-asterisk btn-users-list blue" data-toggle="tooltip" title="all">
</button>
</li>
<li>
<button type="button" (click)="selectType(0)" placeholder="individual" class="btn btn-default btn-users-list" data-toggle="tooltip" title="individual">
<svg-icon class="small blue" src="./assets/icons/user.svg"></svg-icon>
</button>
</li>
<li>
<button type="button" (click)="selectType(1)" placeholder="group" data-toggle="tooltip" title="group" class="btn btn-default btn-users-list">
<svg-icon class="small blue" src="./assets/icons/users.svg"></svg-icon>
</button>
</li>
</ul>
</div>
<div class="col-xs-4">
<input type="text" [(ngModel)]= "filter.name" (keyup.enter)="search()" class="form-control" id="wb-display-name-filter" placeholder="Filter name">
</div>
<div class="col-xs-4">
<input type="text" [(ngModel)]= "filter.key" (keyup.enter)="search()" class="form-control" id="wb-display-key-filter" placeholder="Filter key">
</div>
<button (click)="clear()" type="button"
class="btn btn-default glyphicon glyphicon-remove-circle blue pull-right margin-right" data-toggle="tooltip" title="Clear">
</button>
</div>
<div class="row">
<div class="col-xs-2">
</div>
<div class="col-xs-8">
<input type="text" [(ngModel)]= "filter.description" (keyup.enter)="search()" class="form-control" id="wb-display-description-filter" placeholder="Filter by description">
</div>
</div>
<div class="row">
<div class="col-xs-2">
</div>
<div class="col-xs-8">
<input type="text" [(ngModel)]= "filter.owner" (keyup.enter)="search()" class="form-control" id="wb-display-task-owner-filter" placeholder="Filter by Task owner">
</div>
<button (click)="search()" type="button"
class="btn btn-default glyphicon glyphicon-search blue pull-right margin-right" data-toggle="tooltip" title="Search">
</button>
</div>
</div>

View File

@ -0,0 +1,7 @@
.dropdown-menu-users {
&>li{
margin-bottom: 5px;
}
margin-left: 15px;
}

View File

@ -0,0 +1,73 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';
import { FilterComponent, FilterModel } from './filter.component';
describe('FilterComponent', () => {
let component: FilterComponent,
fixture: ComponentFixture<FilterComponent>,
debugElement: any;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FilterComponent ],
imports: [AngularSvgIconModule, FormsModule, HttpClientModule, HttpModule ]
})
.compileComponents();
fixture = TestBed.createComponent(FilterComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement;
fixture.detectChanges();
}));
afterEach(() => {
document.body.removeChild(debugElement);
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should create a component with id target', () => {
expect(debugElement.querySelector('#some-id')).toBeNull();
component.target = 'some-id'
fixture.detectChanges();
expect(debugElement.querySelector('#some-id')).toBeDefined();
});
it('should have filter by: name, description, key, owner and type defined', () => {
expect(debugElement.querySelector('#wb-display-name-filter')).toBeDefined();
expect(debugElement.querySelector('#wb-display-description-filter')).toBeDefined();
expect(debugElement.querySelector('#wb-display-key-filter')).toBeDefined();
expect(debugElement.querySelector('#wb-display-owner-filter')).toBeDefined();
expect(debugElement.querySelector('#wb-display-type-filter')).toBeDefined();
});
it('should be able to clear all fields after pressing clear button', () => {
component.filter = new FilterModel('a','a','a','a');
debugElement.querySelector('[title="Clear"]').click();
expect(component.filter.name).toBe('');
expect(component.filter.description).toBe('');
expect(component.filter.owner).toBe('');
expect(component.filter.type).toBe('');
});
it('should be able to select a type and return it based on a number', () => {
expect(component).toBeTruthy();
});
it('should be able to emit a filter after clicking on search button', (done) => {
component.filter = new FilterModel('a', 'name1', 'a', 'a');
component.performFilter.subscribe(filter => {
expect(filter.name).toBe('name1');
done();
})
debugElement.querySelector('[title="Search"]').click();
});
});

View File

@ -0,0 +1,45 @@
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
export class FilterModel {
type:string;
name:string;
description:string;
owner:string;
constructor(type:string = '', name:string = '', description:string = '', owner:string = ''){
this.type = type;
this.name = name;
this.description= description;
this.owner = owner;
}
}
@Component({
selector: 'taskana-filter',
templateUrl: './filter.component.html',
styleUrls: ['./filter.component.scss']
})
export class FilterComponent{
constructor() { }
filter: FilterModel = new FilterModel();
@Input()
target:string;
@Output()
performFilter = new EventEmitter<FilterModel>();
selectType(type: number){
this.filter.type = type === 0 ? 'PERSONAL': type === 1? 'GROUP': '';
}
clear(){
this.filter = new FilterModel();
}
search(){
this.performFilter.emit(this.filter);
}
}

View File

@ -1,6 +1,6 @@
<div class="container-scrollable" >
<taskana-spinner [isRunning]="requestInProgress" class = "centered-horizontally"></taskana-spinner>
<app-no-access *ngIf="!hasPermission" ></app-no-access>
<app-no-access *ngIf="!hasPermission || !workbasket && selectedId" ></app-no-access>
<div id ="workbasket-details" class="workbasket-details" *ngIf="workbasket">
<ul class="nav nav-tabs" role="tablist">
<li *ngIf="showDetail" class="visible-xs visible-sm hidden">

View File

@ -13,7 +13,7 @@ import { Subscription } from 'rxjs';
})
export class WorkbasketDetailsComponent implements OnInit {
selectedId: number = -1;
workbasket: Workbasket;
workbasketClone: Workbasket;
showDetail: boolean = false;
@ -46,8 +46,10 @@ export class WorkbasketDetailsComponent implements OnInit {
});
this.routeSubscription = this.route.params.subscribe(params => {
if( params['id'] && params['id'] !== '') {
this.service.selectWorkBasket( params['id']);
let id = params['id'];
if( id && id !== '') {
this.selectedId = id;
this.service.selectWorkBasket(id);
}
});

View File

@ -2,7 +2,7 @@
<ul id = "wb-list-container" class="list-group footer-space">
<li id="wb-action-toolbar" class="list-group-item">
<div class="row">
<div class="col-xs-9 mod-col-9">
<div class="col-xs-9">
<button type="button" data-toggle="tooltip" title="Add" class="btn btn-default">
<span class="glyphicon glyphicon-plus green" aria-hidden="true"></span>
</button>
@ -19,67 +19,47 @@
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</div>
<div class="clearfix btn-group">
<button class="btn btn-default collapsed" type="button" id="collapsedMenuSearchWb" data-toggle="collapse" data-target="#wb-search-bar" aria-expanded="false">
<span class="glyphicon glyphicon-filter blue wb-search-toggle"></span>
</button>
</div>
<div class="dropdown clearfix btn-group">
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="glyphicon {{sortDirection === 'asc'? 'glyphicon-sort-by-attributes-alt' : 'glyphicon-sort-by-attributes' }} blue"
data-toggle= "tooltip" title="{{sortDirection === 'asc'? 'A-Z' : 'Z-A' }}"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right sortby-dropdown popup" aria-labelledby="sortingDropdown">
<li>
<div class="col-xs-6">
<h5>Sort By</h5>
</div>
<button id="sort-by-direction-asc" type="button" (click)="changeOrder('asc')" data-toggle="tooltip" title="A-Z" class="btn btn-default {{sortDirection === 'asc'? 'selected' : '' }}">
<span class="glyphicon glyphicon-sort-by-attributes-alt blue" aria-hidden="true"></span>
</button>
<button id= "sort-by-direction-desc" type="button" (click)="changeOrder('desc')" data-toggle="tooltip" title="Z-A" class="btn btn-default {{sortDirection === 'desc'? 'selected' : '' }}" >
<span class="glyphicon glyphicon-sort-by-attributes blue" aria-hidden="true"></span>
</button>
</li>
<li role="separator" class="divider"></li>
<li id="sort-by-{{sortingField.key}}"(click)="changeSortBy(sortingField.key)" *ngFor="let sortingField of sortingFields | mapValues">
<a>
<label>
<span class="glyphicon {{sortBy === sortingField.key? 'glyphicon-check': 'glyphicon-unchecked'}} blue" aria-hidden="true"></span>
{{sortingField.value}}
</label>
</a>
</li>
</ul>
<div class = "pull-right margin-right">
<div class="dropdown clearfix btn-group">
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="glyphicon {{sortDirection === 'asc'? 'glyphicon-sort-by-attributes-alt' : 'glyphicon-sort-by-attributes' }} blue"
data-toggle= "tooltip" title="{{sortDirection === 'asc'? 'A-Z' : 'Z-A' }}"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right sortby-dropdown popup" aria-labelledby="sortingDropdown">
<li>
<div class="col-xs-6">
<h5>Sort By</h5>
</div>
<button id="sort-by-direction-asc" type="button" (click)="changeOrder('asc')" data-toggle="tooltip" title="A-Z" class="btn btn-default {{sortDirection === 'asc'? 'selected' : '' }}">
<span class="glyphicon glyphicon-sort-by-attributes-alt blue" aria-hidden="true"></span>
</button>
<button id= "sort-by-direction-desc" type="button" (click)="changeOrder('desc')" data-toggle="tooltip" title="Z-A" class="btn btn-default {{sortDirection === 'desc'? 'selected' : '' }}" >
<span class="glyphicon glyphicon-sort-by-attributes blue" aria-hidden="true"></span>
</button>
</li>
<li role="separator" class="divider"></li>
<li id="sort-by-{{sortingField.key}}"(click)="changeSortBy(sortingField.key)" *ngFor="let sortingField of sortingFields | mapValues">
<a>
<label>
<span class="glyphicon {{sortBy === sortingField.key? 'glyphicon-check': 'glyphicon-unchecked'}} blue" aria-hidden="true"></span>
{{sortingField.value}}
</label>
</a>
</li>
</ul>
</div>
<div class="clearfix btn-group">
<button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" data-toggle="collapse" data-target="#wb-filter-bar" aria-expanded="false">
<span class="glyphicon glyphicon-filter blue wb-filter-toggle"></span>
</button>
</div>
</div>
</div>
<div class = "row">
<taskana-filter target="wb-filter-bar" (performFilter)="performFilter($event)"></taskana-filter>
</div>
</li>
<taskana-spinner [isRunning]="requestInProgress" class = "centered-horizontally"></taskana-spinner>
<li type="text" id="wb-search-bar" class="list-group-seach collapse">
<div class="row">
<dl class="pull-left padding-left-5">
<dt class="dropdown"> <button class="btn btn-default" type="button" id="dropdownMenuSearch" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<svg-icon class="small blue" src="./assets/icons/user.svg"></svg-icon>
</button> <ul class="dropdown-menu dropdown-menu-users" role="menu">
<li>
<button type="button" placeholder="individual" class="btn btn-default btn-users-list" data-toggle="tooltip" title="individual">
<svg-icon class="small blue" src="./assets/icons/user.svg"></svg-icon>
</button>
</li>
<li>
<button type="button" placeholder="multiple" data-toggle="tooltip" title="multiple" class="btn btn-default btn-users-list">
<svg-icon class="small blue" src="./assets/icons/users.svg"></svg-icon>
</button>
</li>
</ul></dt>
</dl>
<dl class="col-xs-10">
<dt><input type="text" class="form-control" id="wb-display-name-search" placeholder="Filter by name"> </dt>
<dt><input type="text" class="form-control" id="wb-display-description-search" placeholder="Filter by description"> </dt>
<dt><input type="text" class="form-control" id="wb-display-task-owner-search" placeholder="Filter by Task owner"> </dt>
</dl>
</div>
</li>
<li class="list-group-item" *ngFor= "let workbasket of workbaskets" [class.active]="workbasket.workbasketId == selectedId" type="text" (click) ="selectWorkbasket(workbasket.workbasketId)" [routerLink]="[ {outlets: { detail: [workbasket.workbasketId] } }]">
<div class="row">
<dl class="col-xs-1">

View File

@ -1,7 +1,3 @@
.padding-left-5 {
padding-left:5px;
}
.workbasket-list-full-height{
height: calc(100vh - 55px);
}

View File

@ -11,6 +11,7 @@ import { RouterTestingModule } from '@angular/router/testing';
import { Observable } from 'rxjs/Observable';
import { SpinnerComponent } from '../../shared/spinner/spinner.component';
import { MapValuesPipe } from '../../pipes/map-values.pipe';
import { FilterModel } from '../../shared/filter/filter.component';
@Component({
selector: 'dummy-detail',
@ -20,6 +21,14 @@ export class DummyDetailComponent {
}
@Component({
selector: 'taskana-filter',
template: ''
})
export class FilterComponent {
}
const workbasketSummary: WorkbasketSummary[] = [ new WorkbasketSummary("1", "key1", "NAME1", "description 1", "owner 1", "", "", "PERSONAL", "", "", "", ""),
new WorkbasketSummary("2", "key2", "NAME2", "description 2", "owner 2", "", "", "MULTIPLE", "", "", "", "")
];
@ -38,7 +47,7 @@ describe('WorkbasketListComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ WorkbasketListComponent, DummyDetailComponent, MapValuesPipe, SpinnerComponent],
declarations: [ WorkbasketListComponent, DummyDetailComponent, MapValuesPipe, SpinnerComponent, FilterComponent],
imports:[
AngularSvgIconModule,
HttpModule,
@ -76,23 +85,25 @@ describe('WorkbasketListComponent', () => {
})
});
it('should have wb-action-toolbar, wb-search-bar, wb-list-container and wb-pagination created in the html',() => {
it('should have wb-action-toolbar, wb-search-bar, wb-list-container, wb-pagination, collapsedMenufilterWb and taskana-filter created in the html',() => {
expect(debugElement.querySelector('#wb-action-toolbar')).toBeDefined();
expect(debugElement.querySelector('#wb-search-bar')).toBeDefined();
expect(debugElement.querySelector('#wb-pagination')).toBeDefined();
expect(debugElement.querySelector('#wb-list-container')).toBeDefined();
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(4);
expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined();
expect(debugElement.querySelector('taskana-filter')).toBeDefined();
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3);
});
it('should have two workbasketsummary rows created with the second one selected.',() => {
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(4);
expect(debugElement.querySelectorAll('#wb-list-container > li')[2].getAttribute('class')).toBe('list-group-item');
expect(debugElement.querySelectorAll('#wb-list-container > li')[3].getAttribute('class')).toBe('list-group-item active');
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3);
expect(debugElement.querySelectorAll('#wb-list-container > li')[1].getAttribute('class')).toBe('list-group-item');
expect(debugElement.querySelectorAll('#wb-list-container > li')[2].getAttribute('class')).toBe('list-group-item active');
});
it('should have two workbasketsummary rows created with two different icons: user and users',() => {
expect(debugElement.querySelectorAll('#wb-list-container > li')[2].querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/user.svg');
expect(debugElement.querySelectorAll('#wb-list-container > li')[3].querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/users.svg');
expect(debugElement.querySelectorAll('#wb-list-container > li')[1].querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/user.svg');
expect(debugElement.querySelectorAll('#wb-list-container > li')[2].querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/users.svg');
});
it('should have rendered sort by: name, id, description, owner and type', () => {
@ -104,24 +115,12 @@ describe('WorkbasketListComponent', () => {
});
it('should have changed sort direction and perform a request after clicking sort direction buttons', fakeAsync( () => {
debugElement.querySelector('#sort-by-direction-desc').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('key', Direction.DESC);
debugElement.querySelector('#sort-by-direction-asc').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('key', Direction.ASC);
}));
it('should have performRequest after performFilter is triggered', fakeAsync( () => {
let type='PERSONAL', name = 'someName', description = 'someDescription', owner = 'someOwner'
let filter = new FilterModel(type, name, description, owner);
component.performFilter(filter);
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('key', 'asc', undefined, name, description, undefined, owner, type );
it('should have changed sortBy field and perform a request after clicking on to any sort by rows', fakeAsync( () => {
debugElement.querySelector('#sort-by-key').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('key', jasmine.any(String));
debugElement.querySelector('#sort-by-name').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('name', jasmine.any(String));
debugElement.querySelector('#sort-by-description').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('description', jasmine.any(String));
debugElement.querySelector('#sort-by-owner').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('owner', jasmine.any(String));
debugElement.querySelector('#sort-by-type').click();
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith('type', jasmine.any(String));
}));
});

View File

@ -2,95 +2,105 @@ import { Component, OnInit, EventEmitter } from '@angular/core';
import { WorkbasketSummary } from '../../model/workbasketSummary';
import { WorkbasketService, Direction } from '../../services/workbasketservice.service'
import { Subscription } from 'rxjs/Subscription';
import { FilterModel } from '../../shared/filter/filter.component'
import { filter } from 'rxjs/operator/filter';
@Component({
selector: 'workbasket-list',
outputs: ['selectedWorkbasket'],
templateUrl: './workbasket-list.component.html',
styleUrls: ['./workbasket-list.component.scss']
selector: 'workbasket-list',
outputs: ['selectedWorkbasket'],
templateUrl: './workbasket-list.component.html',
styleUrls: ['./workbasket-list.component.scss']
})
export class WorkbasketListComponent implements OnInit {
public selectedWorkbasket: EventEmitter<WorkbasketSummary> = new EventEmitter();
public selectedWorkbasket: EventEmitter<WorkbasketSummary> = new EventEmitter();
newWorkbasket: WorkbasketSummary;
selectedId: string = undefined;
workbaskets : Array<WorkbasketSummary> = [];
requestInProgress: boolean = false;
newWorkbasket: WorkbasketSummary;
selectedId: string = undefined;
workbaskets: Array<WorkbasketSummary> = [];
requestInProgress: boolean = false;
sortBy: string = 'key';
sortDirection: Direction = Direction.ASC;
sortingFields : Map<string, string> = new Map([['name', 'Name'], ['key', 'Key'], ['description', 'Description'], ['owner', 'Owner'], ['type', 'Type']]);
sortBy: string = 'key';
sortDirection: Direction = Direction.ASC;
sortingFields: Map<string, string> = new Map([['name', 'Name'], ['key', 'Id'], ['description', 'Description'], ['owner', 'Owner'], ['type', 'Type']]);
filterBy: FilterModel = new FilterModel();
private workBasketSummarySubscription: Subscription;
private workbasketServiceSubscription: Subscription;
private workBasketSummarySubscription: Subscription;
private workbasketServiceSubscription: Subscription;
constructor(private workbasketService: WorkbasketService) { }
constructor(private workbasketService: WorkbasketService) { }
ngOnInit() {
this.requestInProgress = true;
this.workBasketSummarySubscription = this.workbasketService.getWorkBasketsSummary().subscribe(resultList => {
this.workbaskets = resultList;
this.requestInProgress = false;
});
ngOnInit() {
this.requestInProgress = true;
this.workBasketSummarySubscription = this.workbasketService.getWorkBasketsSummary().subscribe(resultList => {
this.workbaskets = resultList;
this.requestInProgress = false;
});
this.workbasketServiceSubscription = this.workbasketService.getSelectedWorkBasket().subscribe( workbasketIdSelected => {
this.selectedId = workbasketIdSelected;
});
}
this.workbasketServiceSubscription = this.workbasketService.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
this.selectedId = workbasketIdSelected;
});
}
selectWorkbasket(id:string){
this.selectedId = id;
}
selectWorkbasket(id: string) {
this.selectedId = id;
}
changeOrder(sortDirection: string) {
this.sortDirection = (sortDirection === Direction.ASC)? Direction.ASC: Direction.DESC;
this.performRequest();
}
changeOrder(sortDirection: string) {
this.sortDirection = (sortDirection === Direction.ASC) ? Direction.ASC : Direction.DESC;
this.performRequest();
}
changeSortBy(sortBy: string){
this.sortBy = sortBy;
this.performRequest();
}
changeSortBy(sortBy: string) {
this.sortBy = sortBy;
this.performRequest();
}
onDelete(workbasket: WorkbasketSummary) {
this.workbasketService.deleteWorkbasket(workbasket.workbasketId).subscribe(result => {
var index = this.workbaskets.indexOf(workbasket);
if (index > -1) {
this.workbaskets.splice(index, 1);
}
});
}
performFilter(filterBy: FilterModel) {
this.filterBy = filterBy;
this.performRequest();
}
onAdd() {
this.workbasketService.createWorkbasket(this.newWorkbasket).subscribe(result => {
this.workbaskets.push(result);
this.onClear();
});
}
onDelete(workbasket: WorkbasketSummary) {
this.workbasketService.deleteWorkbasket(workbasket.workbasketId).subscribe(result => {
var index = this.workbaskets.indexOf(workbasket);
if (index > -1) {
this.workbaskets.splice(index, 1);
}
});
}
onClear() {
this.newWorkbasket.workbasketId = "";
this.newWorkbasket.name = "";
this.newWorkbasket.description = "";
this.newWorkbasket.owner = "";
}
onAdd() {
this.workbasketService.createWorkbasket(this.newWorkbasket).subscribe(result => {
this.workbaskets.push(result);
this.onClear();
});
}
getEmptyObject() {
return new WorkbasketSummary("", "", "", "", "", "", "", "", "", "", "", "");
}
onClear() {
this.newWorkbasket.workbasketId = "";
this.newWorkbasket.name = "";
this.newWorkbasket.description = "";
this.newWorkbasket.owner = "";
}
private performRequest(): void{
this.requestInProgress = true;
this.workbaskets = undefined;
this.workbasketServiceSubscription.add(this.workbasketService.getWorkBasketsSummary(this.sortBy,this.sortDirection).subscribe(resultList => {
this.workbaskets = resultList;
this.requestInProgress = false;
}));
}
getEmptyObject() {
return new WorkbasketSummary("", "", "", "", "", "", "", "", "", "", "", "");
}
private ngOnDestroy(){
this.workBasketSummarySubscription.unsubscribe();
this.workbasketServiceSubscription.unsubscribe();
}
private performRequest(): void {
this.requestInProgress = true;
this.workbaskets = undefined;
this.workbasketServiceSubscription.add(this.workbasketService.getWorkBasketsSummary(this.sortBy, this.sortDirection, undefined,
this.filterBy.name, this.filterBy.description, undefined, this.filterBy.owner,
this.filterBy.type).subscribe(resultList => {
this.workbaskets = resultList;
this.requestInProgress = false;
}));
}
private ngOnDestroy() {
this.workBasketSummarySubscription.unsubscribe();
this.workbasketServiceSubscription.unsubscribe();
}
}

View File

@ -115,8 +115,9 @@
overflow-x: hidden;
}
.margin-right {
margin-right: 2px;
.margin-right
{
margin-right: 5px;
}
.no-border-bottom {
@ -190,10 +191,6 @@ li > div.row > dl {
color: crimson;
}
.dropdown-menu-users >li {
margin-bottom: 5px;
}
.btn-users-list {
border: 0px solid transparent;
/* this was 1px earlier */