TSK-389 Fix linting and add it to build process.

This commit is contained in:
Martin Rojas Miguel Angel 2018-03-19 12:34:40 +01:00
parent c7208cf882
commit e4c761bb04
57 changed files with 852 additions and 891 deletions

View File

@ -1,59 +1,54 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": { "project": {
"name": "admin" "name": "admin"
}, },
"apps": [ "apps": [
{ {
"root": "src", "root": "src",
"outDir": "dist", "outDir": "dist",
"assets": [ "assets": [
"assets", "assets",
"taskana.ico" "taskana.ico"
], ],
"index": "index.html", "index": "index.html",
"main": "main.ts", "main": "main.ts",
"polyfills": "polyfills.ts", "polyfills": "polyfills.ts",
"test": "test.ts", "test": "test.ts",
"tsconfig": "tsconfig.app.json", "tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json", "testTsconfig": "tsconfig.spec.json",
"prefix": "app", "prefix": "app",
"styles": [ "styles": [
"../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss", "../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss",
"./assets/_site.scss", "./assets/_site.scss",
"./assets/_forms.scss" "./assets/_forms.scss"
], ],
"scripts": ["../node_modules/jquery/dist/jquery.min.js","../node_modules/bootstrap/dist/js/bootstrap.min.js"], "scripts": [
"environmentSource": "environments/environment.ts", "../node_modules/jquery/dist/jquery.min.js",
"environments": { "../node_modules/bootstrap/dist/js/bootstrap.min.js"
"dev": "environments/environment.ts", ],
"prod": "environments/environment.prod.ts" "environmentSource": "environments/environment.ts",
} "environments": {
} "dev": "environments/environment.ts",
], "prod": "environments/environment.prod.ts"
"e2e": { }
"protractor": { }
"config": "./protractor.conf.js" ],
} "lint": [
}, {
"lint": [ "project": "src/tsconfig.app.json"
{ },
"project": "src/tsconfig.app.json" {
}, "project": "src/tsconfig.spec.json"
{ }
"project": "src/tsconfig.spec.json" ],
}, "test": {
{ "karma": {
"project": "e2e/tsconfig.e2e.json" "config": "./karma.conf.js"
} }
], },
"test": { "defaults": {
"karma": { "styleExt": "scss",
"config": "./karma.conf.js" "component": {}
} }
},
"defaults": {
"styleExt": "scss",
"component": {}
}
} }

View File

@ -18,11 +18,6 @@ Run `ng build` to build the project. The build artifacts will be stored in the `
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
## Further help ## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -1,14 +0,0 @@
import { AdminPage } from './app.po';
describe('admin App', () => {
let page: AdminPage;
beforeEach(() => {
page = new AdminPage();
});
it('should display message saying app works', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('app works!');
});
});

View File

@ -1,11 +0,0 @@
import { browser, by, element } from 'protractor';
export class AdminPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

View File

@ -1,12 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"node"
]
}
}

View File

@ -5,13 +5,12 @@
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": " ng build --env=dev", "build": " npm run lint && ng build --env=dev ",
"build:prod": "ng build --environment=prod --no-progress", "build:prod": "npm run lint && ng build --target=production --environment=prod --no-progress",
"test": "./node_modules/.bin/karma start --single-run --browsers Firefox", "test": "./node_modules/.bin/karma start --single-run --browsers Firefox",
"test-phantom": "./node_modules/.bin/karma start --single-run --browsers PhantomJS", "test-phantom": "./node_modules/.bin/karma start --single-run --browsers PhantomJS",
"test:watch": "./node_modules/.bin/karma start --browsers Chrome", "test:watch": "./node_modules/.bin/karma start --browsers Chrome",
"lint": "ng lint", "lint": "ng lint"
"e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {

View File

@ -1,30 +0,0 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
},
onPrepare() {
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@ -8,53 +8,53 @@ import { Router, Routes } from '@angular/router';
describe('AppComponent', () => { describe('AppComponent', () => {
var app, fixture, debugElement; let app, fixture, debugElement;
const routes: Routes = [ const routes: Routes = [
{ path: 'categories', component: AppComponent } { path: 'categories', component: AppComponent }
]; ];
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [
AppComponent AppComponent
], ],
imports:[ imports: [
AngularSvgIconModule, AngularSvgIconModule,
RouterTestingModule.withRoutes(routes), RouterTestingModule.withRoutes(routes),
HttpClientModule HttpClientModule
] ]
}).compileComponents(); }).compileComponents();
fixture = TestBed.createComponent(AppComponent); fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance; app = fixture.debugElement.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
})); }));
afterEach(async(()=>{ afterEach(async(() => {
document.body.removeChild(debugElement); document.body.removeChild(debugElement);
})); }));
it('should create the app', (() => { it('should create the app', (() => {
expect(app).toBeTruthy(); expect(app).toBeTruthy();
})); }));
it(`should have as title 'Taskana administration'`, (() => { it(`should have as title 'Taskana administration'`, (() => {
expect(app.title).toEqual('Taskana administration'); expect(app.title).toEqual('Taskana administration');
})); }));
it('should render title in a <a> tag', (() => { it('should render title in a <a> tag', (() => {
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('ul p a').textContent).toContain('Taskana administration'); expect(debugElement.querySelector('ul p a').textContent).toContain('Taskana administration');
})); }));
it('should call Router.navigateByUrl("categories") and workbasketRoute should be false', (inject([Router], (router: Router) => { it('should call Router.navigateByUrl("categories") and workbasketRoute should be false', (inject([Router], (router: Router) => {
expect(app.workbasketsRoute).toBe(true); expect(app.workbasketsRoute).toBe(true);
fixture.detectChanges(); fixture.detectChanges();
router.navigateByUrl(`/categories`); router.navigateByUrl(`/categories`);
expect(app.workbasketsRoute).toBe(false); expect(app.workbasketsRoute).toBe(false);
}))); })));
}) })

View File

@ -3,28 +3,28 @@ import { environment } from '../environments/environment';
import { Router, ActivatedRoute, NavigationStart } from '@angular/router'; import { Router, ActivatedRoute, NavigationStart } from '@angular/router';
@Component({ @Component({
selector: 'app-root', selector: 'taskana-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent implements OnInit{ export class AppComponent implements OnInit {
title = 'Taskana administration'; title = 'Taskana administration';
adminUrl: string = environment.taskanaAdminUrl; adminUrl: string = environment.taskanaAdminUrl;
monitorUrl: string = environment.taskanaMonitorUrl; monitorUrl: string = environment.taskanaMonitorUrl;
workplaceUrl: string = environment.taskanaWorkplaceUrl; workplaceUrl: string = environment.taskanaWorkplaceUrl;
workbasketsRoute : boolean = true; workbasketsRoute = true;
constructor( private route: ActivatedRoute, private router: Router) { constructor(private route: ActivatedRoute, private router: Router) {
} }
ngOnInit(){ ngOnInit() {
this.router.events.subscribe(event => { this.router.events.subscribe(event => {
if(event instanceof NavigationStart) { if (event instanceof NavigationStart) {
if(event.url.indexOf('categories') !== -1){ if (event.url.indexOf('categories') !== -1) {
this.workbasketsRoute = false; this.workbasketsRoute = false;
} }
} }
}); });
} }
} }

View File

@ -2,8 +2,8 @@
* Modules * Modules
*/ */
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule, } from '@angular/core'; import { NgModule, } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AlertModule } from 'ngx-bootstrap'; import { AlertModule } from 'ngx-bootstrap';
@ -30,8 +30,8 @@ import { AlertComponent } from './shared/alert/alert.component';
import { SortComponent } from './shared/sort/sort.component'; import { SortComponent } from './shared/sort/sort.component';
import { GeneralMessageModalComponent } from './shared/general-message-modal/general-message-modal.component'; import { GeneralMessageModalComponent } from './shared/general-message-modal/general-message-modal.component';
//Shared // Shared
import { MasterAndDetailComponent} from './shared/masterAndDetail/master-and-detail.component'; import { MasterAndDetailComponent } from './shared/masterAndDetail/master-and-detail.component';
/** /**
* Services * Services
@ -50,54 +50,54 @@ import { MapValuesPipe } from './pipes/map-values.pipe';
import { RemoveNoneTypePipe } from './pipes/remove-none-type'; import { RemoveNoneTypePipe } from './pipes/remove-none-type';
import { SelectWorkBasketPipe } from './pipes/seleted-workbasket.pipe'; import { SelectWorkBasketPipe } from './pipes/seleted-workbasket.pipe';
const MODULES = [ const MODULES = [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
TabsModule.forRoot(), TabsModule.forRoot(),
TreeModule, TreeModule,
AppRoutingModule, AppRoutingModule,
AlertModule.forRoot(), AlertModule.forRoot(),
AngularSvgIconModule, AngularSvgIconModule,
HttpClientModule, HttpClientModule,
BrowserAnimationsModule, BrowserAnimationsModule,
ReactiveFormsModule ReactiveFormsModule
]; ];
const DECLARATIONS = [ const DECLARATIONS = [
AppComponent, AppComponent,
WorkbasketListComponent, WorkbasketListComponent,
AccessItemsComponent, AccessItemsComponent,
WorkbasketDetailsComponent, WorkbasketDetailsComponent,
MasterAndDetailComponent, MasterAndDetailComponent,
WorkbasketInformationComponent, WorkbasketInformationComponent,
NoAccessComponent, NoAccessComponent,
SpinnerComponent, SpinnerComponent,
FilterComponent, FilterComponent,
IconTypeComponent, IconTypeComponent,
AlertComponent, AlertComponent,
GeneralMessageModalComponent, GeneralMessageModalComponent,
DistributionTargetsComponent, DistributionTargetsComponent,
SortComponent, SortComponent,
DualListComponent, DualListComponent,
MapValuesPipe, MapValuesPipe,
RemoveNoneTypePipe, RemoveNoneTypePipe,
SelectWorkBasketPipe SelectWorkBasketPipe
]; ];
@NgModule({ @NgModule({
declarations: DECLARATIONS, declarations: DECLARATIONS,
imports: MODULES, imports: MODULES,
providers: [ providers: [
WorkbasketService, WorkbasketService,
MasterAndDetailService, MasterAndDetailService,
PermissionService, PermissionService,
{ {
provide: HTTP_INTERCEPTORS, provide: HTTP_INTERCEPTORS,
useClass: HttpClientInterceptor, useClass: HttpClientInterceptor,
multi: true multi: true
}, },
AlertService AlertService
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

View File

@ -1,7 +1,7 @@
export class Links { export class Links {
constructor( constructor(
public self: {'href': string}, public self: { 'href': string },
public distributionTargets: {'href': string} = undefined, public distributionTargets: { 'href': string } = undefined,
public accessItems: {'href': string} = undefined public accessItems: { 'href': string } = undefined
){} ) { }
} }

View File

@ -1,5 +1,5 @@
import { Links } from "./links"; import { Links } from './links';
import { WorkbasketAccessItems } from "./workbasket-access-items"; import { WorkbasketAccessItems } from './workbasket-access-items';
export class WorkbasketAccessItemsResource { export class WorkbasketAccessItemsResource {
constructor( constructor(

View File

@ -1,4 +1,4 @@
import { Links } from "./links"; import { Links } from './links';
export class WorkbasketAccessItems { export class WorkbasketAccessItems {
constructor( constructor(

View File

@ -1,7 +1,8 @@
import { WorkbasketSummary } from './workbasket-summary'; import { WorkbasketSummary } from './workbasket-summary';
import { Links } from './links'; import { Links } from './links';
export class WorkbasketDistributionTargetsResource { export class WorkbasketDistributionTargetsResource {
constructor(public _embedded: {'distributionTargets': Array<WorkbasketSummary> } = {'distributionTargets': []}, public _links: Links = null) { constructor(public _embedded: { 'distributionTargets': Array<WorkbasketSummary> } =
{ 'distributionTargets': [] }, public _links: Links = null) {
} }
} }

View File

@ -2,6 +2,7 @@ import { WorkbasketSummary } from './workbasket-summary';
import { Links } from './links'; import { Links } from './links';
export class WorkbasketSummaryResource { export class WorkbasketSummaryResource {
constructor(public _embedded: {'workbaskets': Array<WorkbasketSummary> } = {'workbaskets': []}, public _links: Links = null) { constructor(public _embedded: { 'workbaskets': Array<WorkbasketSummary> } =
{ 'workbaskets': [] }, public _links: Links = null) {
} }
} }

View File

@ -1,6 +1,6 @@
import {Links} from './links'; import { Links } from './links';
export class WorkbasketSummary{ export class WorkbasketSummary {
constructor( constructor(
public workbasketId: string, public workbasketId: string,
public key: string, public key: string,
@ -14,6 +14,6 @@ export class WorkbasketSummary{
public orgLevel2: string, public orgLevel2: string,
public orgLevel3: string, public orgLevel3: string,
public orgLevel4: string, public orgLevel4: string,
public _links: Links = undefined){ public _links: Links = undefined) {
} }
} }

View File

@ -1,25 +1,5 @@
import { Links } from './links'; import { Links } from './links';
export class Workbasket{ export class Workbasket {
constructor(
public workbasketId: string,
public created: string = undefined,
public key: string = undefined,
public domain: string = undefined,
public type: string = undefined,
public modified: string = undefined,
public name: string = undefined,
public description: string = undefined,
public owner: string = undefined,
public custom1: string = undefined,
public custom2: string = undefined,
public custom3: string = undefined,
public custom4: string = undefined,
public orgLevel1: string = undefined,
public orgLevel2: string = undefined,
public orgLevel3: string = undefined,
public orgLevel4: string = undefined,
public _links:Links = undefined) {
}
public static equals(org: Workbasket, comp: Workbasket): boolean { public static equals(org: Workbasket, comp: Workbasket): boolean {
if (org.workbasketId !== comp.workbasketId) { return false; } if (org.workbasketId !== comp.workbasketId) { return false; }
@ -42,4 +22,25 @@ export class Workbasket{
return true; return true;
} }
constructor(
public workbasketId: string,
public created: string = undefined,
public key: string = undefined,
public domain: string = undefined,
public type: string = undefined,
public modified: string = undefined,
public name: string = undefined,
public description: string = undefined,
public owner: string = undefined,
public custom1: string = undefined,
public custom2: string = undefined,
public custom3: string = undefined,
public custom4: string = undefined,
public orgLevel1: string = undefined,
public orgLevel2: string = undefined,
public orgLevel3: string = undefined,
public orgLevel4: string = undefined,
public _links: Links = undefined) {
}
} }

View File

@ -1,18 +0,0 @@
import {Links} from './links';
export class WorkbasketSummary {
constructor(
public workbasketId: string,
public key: string,
public name: string,
public description: string,
public owner: string,
public modified: string,
public domain: string,
public type: string,
public orgLevel1: string,
public orgLevel2: string,
public orgLevel3: string,
public orgLevel4: string,
public links: Array<Links> = undefined){}
}

View File

@ -1,9 +1,9 @@
import {Pipe, PipeTransform} from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'mapValues'}) @Pipe({ name: 'mapValues' })
export class MapValuesPipe implements PipeTransform { export class MapValuesPipe implements PipeTransform {
transform(value: any, args?: any[]): Object[] { transform(value: any, args?: any[]): Object[] {
let returnArray = []; const returnArray = [];
value.forEach((entryVal, entryKey) => { value.forEach((entryVal, entryKey) => {
returnArray.push({ returnArray.push({

View File

@ -3,13 +3,14 @@ import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'removeEmptyType' }) @Pipe({ name: 'removeEmptyType' })
export class RemoveNoneTypePipe implements PipeTransform { export class RemoveNoneTypePipe implements PipeTransform {
transform(value: any): Object[] { transform(value: any): Object[] {
let returnArray = []; const returnArray = [];
value.forEach((entry) => { value.forEach((entry) => {
if (entry.key !== '') if (entry.key !== '') {
returnArray.push({ returnArray.push({
key: entry.key, key: entry.key,
value: entry.value value: entry.value
}); });
}
}); });
return returnArray; return returnArray;
} }

View File

@ -9,8 +9,12 @@ export class SelectWorkBasketPipe implements PipeTransform {
} }
for (let index = originArray.length - 1; index >= 0; index--) { for (let index = originArray.length - 1; index >= 0; index--) {
if ((arg1 && !selectionArray.some(elementToRemove => { return originArray[index].workbasketId === elementToRemove.workbasketId })) || if ((arg1 && !selectionArray.some(elementToRemove => {
!arg1 && selectionArray.some(elementToRemove => { return originArray[index].workbasketId === elementToRemove.workbasketId })) { return originArray[index].workbasketId === elementToRemove.workbasketId
})) ||
!arg1 && selectionArray.some(elementToRemove => {
return originArray[index].workbasketId === elementToRemove.workbasketId
})) {
originArray.splice(index, 1); originArray.splice(index, 1);
} }
} }

View File

@ -1,5 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs'; import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
export enum AlertType { export enum AlertType {
SUCCESS = 'success', SUCCESS = 'success',
@ -11,9 +13,9 @@ export enum AlertType {
export class AlertModel { export class AlertModel {
constructor(public type: string = AlertType.SUCCESS, constructor(public type: string = AlertType.SUCCESS,
public text: string = 'Success', public text: string = 'Success',
public autoClosing: boolean = true, public autoClosing: boolean = true,
public closingDelay: number = 2500){ public closingDelay: number = 2500) {
} }
} }

View File

@ -6,14 +6,14 @@ import { HttpClientInterceptor } from './http-client-interceptor.service';
import { PermissionService } from './permission.service'; import { PermissionService } from './permission.service';
describe('HttpExtensionService', () => { describe('HttpExtensionService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports:[HttpClientModule, HttpModule], imports: [HttpClientModule, HttpModule],
providers: [HttpClientInterceptor, PermissionService] providers: [HttpClientInterceptor, PermissionService]
}); });
}); });
it('should be created', inject([HttpClientInterceptor], (service: HttpClientInterceptor) => { it('should be created', inject([HttpClientInterceptor], (service: HttpClientInterceptor) => {
expect(service).toBeTruthy(); expect(service).toBeTruthy();
})); }));
}); });

View File

@ -6,24 +6,22 @@ import 'rxjs/add/observable/throw';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { PermissionService } from './permission.service'; import { PermissionService } from './permission.service';
@Injectable() @Injectable()
export class HttpClientInterceptor implements HttpInterceptor { export class HttpClientInterceptor implements HttpInterceptor {
permissionService: PermissionService; permissionService: PermissionService;
constructor(permissionService: PermissionService) { constructor(permissionService: PermissionService) {
this.permissionService = permissionService; this.permissionService = permissionService;
} }
intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).do(event => { return next.handle(req).do(event => {
setTimeout(() => {this.permissionService.setPermission(true);},1) this.permissionService.setPermission(true);
}, err => { }, err => {
if (err instanceof HttpErrorResponse && (err.status === 401 || err.status ===403 )) { if (err instanceof HttpErrorResponse && (err.status === 401 || err.status === 403)) {
setTimeout(() => {this.permissionService.setPermission(false);},1) this.permissionService.setPermission(false)
} }
}); });
} }
} }

View File

@ -9,11 +9,11 @@ export class MasterAndDetailService {
constructor() { } constructor() { }
setShowDetail(newValue : boolean){ setShowDetail(newValue: boolean) {
this.showDetail.next(newValue) this.showDetail.next(newValue);
} }
getShowDetail(){ getShowDetail() {
return this.showDetail.asObservable(); return this.showDetail.asObservable();
} }

View File

@ -2,51 +2,52 @@ import { TestBed, inject, async } from '@angular/core/testing';
import { WorkbasketService } from './workbasket.service'; import { WorkbasketService } from './workbasket.service';
import { Direction } from '../shared/sort/sort.component'; import { Direction } from '../shared/sort/sort.component';
import { HttpModule, Http } from '@angular/http'; import { HttpModule, Http } from '@angular/http';
import { HttpClientModule, HttpClient } from '@angular/common/http'; import { HttpClientModule, HttpClient } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
describe('WorkbasketService ', () => { describe('WorkbasketService ', () => {
var workbasketService, httpClient; let workbasketService, httpClient;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientModule, HttpClientTestingModule], imports: [HttpClientModule, HttpClientTestingModule],
providers: [WorkbasketService, HttpClient, HttpTestingController] providers: [WorkbasketService, HttpClient, HttpTestingController]
}); });
httpClient = TestBed.get(HttpClient); httpClient = TestBed.get(HttpClient);
workbasketService = TestBed.get(WorkbasketService); workbasketService = TestBed.get(WorkbasketService);
}); });
describe(' WorkbasketSummary GET method ',() => { describe(' WorkbasketSummary GET method ', () => {
beforeEach(() => { beforeEach(() => {
spyOn(httpClient, 'get').and.returnValue(''); spyOn(httpClient, 'get').and.returnValue('');
}); });
it('should have a valid query parameter expression sortBy=key, order=asc as default', () => { it('should have a valid query parameter expression sortBy=key, order=asc as default', () => {
workbasketService.getWorkBasketsSummary(); workbasketService.getWorkBasketsSummary();
expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/?sortBy=key&order=asc', jasmine.any(Object)); expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/?sortBy=key&order=asc',
}); jasmine.any(Object));
});
it('should have a valid query parameter expression with sortBy=name and order=desc', () => { it('should have a valid query parameter expression with sortBy=name and order=desc', () => {
workbasketService.getWorkBasketsSummary(undefined, 'name', Direction.DESC); workbasketService.getWorkBasketsSummary(undefined, 'name', Direction.DESC);
expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/?sortBy=name&order=desc', jasmine.any(Object)); expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/?sortBy=name&order=desc',
}); jasmine.any(Object));
});
it('should have a valid query parameter expression with sortBy=name and order=desc and descLike=some description ',() => {
workbasketService.getWorkBasketsSummary(undefined,'name', Direction.DESC, undefined, undefined, 'some description');
expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/?sortBy=name&order=desc&descLike=some description', jasmine.any(Object));
});
it('should have a valid query parameter expression with sortBy=key, order=asc, descLike=some description and type=group ',() => {
workbasketService.getWorkBasketsSummary(undefined,'name', Direction.DESC, undefined, undefined, 'some description', undefined, undefined, 'group');
expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/?sortBy=name&order=desc&descLike=some description&type=group', jasmine.any(Object));
});
});
it('should have a valid query parameter expression with sortBy=name and order=desc and descLike=some description ', () => {
workbasketService.getWorkBasketsSummary(undefined, 'name', Direction.DESC, undefined, undefined, 'some description');
expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/' +
'?sortBy=name&order=desc&descLike=some description', jasmine.any(Object));
});
it('should have a valid query parameter expression with sortBy=key, order=asc, descLike=some description and type=group ', () => {
workbasketService.getWorkBasketsSummary(undefined, 'name', Direction.DESC,
undefined, undefined, 'some description', undefined, undefined, 'group');
expect(httpClient.get).toHaveBeenCalledWith('http://localhost:8080/v1/workbaskets/' +
'?sortBy=name&order=desc&descLike=some description&type=group', jasmine.any(Object));
});
});
}); });

View File

@ -18,13 +18,11 @@ export class WorkbasketService {
public workBasketSelected = new Subject<string>(); public workBasketSelected = new Subject<string>();
public workBasketSaved = new Subject<number>(); public workBasketSaved = new Subject<number>();
constructor(private httpClient: HttpClient) { } // Sorting
//Sorting
readonly SORTBY = 'sortBy'; readonly SORTBY = 'sortBy';
readonly ORDER = 'order'; readonly ORDER = 'order';
//Filtering // Filtering
readonly NAME = 'name'; readonly NAME = 'name';
readonly NAMELIKE = 'nameLike'; readonly NAMELIKE = 'nameLike';
readonly DESCLIKE = 'descLike'; readonly DESCLIKE = 'descLike';
@ -34,19 +32,21 @@ export class WorkbasketService {
readonly KEY = 'key'; readonly KEY = 'key';
readonly KEYLIKE = 'keyLike'; readonly KEYLIKE = 'keyLike';
//Access // Access
readonly REQUIREDPERMISSION = 'requiredPermission'; readonly REQUIREDPERMISSION = 'requiredPermission';
httpOptions = { httpOptions = {
headers: new HttpHeaders({ headers: new HttpHeaders({
'Content-Type': 'application/hal+json', 'Content-Type': 'application/json',
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x' 'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
}) })
}; };
private workbasketSummaryRef: Observable<WorkbasketSummaryResource>; private workbasketSummaryRef: Observable<WorkbasketSummaryResource>;
//#region "REST calls" constructor(private httpClient: HttpClient) { }
// #region "REST calls"
// GET // GET
getWorkBasketsSummary(forceRequest: boolean = false, getWorkBasketsSummary(forceRequest: boolean = false,
sortBy: string = this.KEY, sortBy: string = this.KEY,
@ -63,8 +63,9 @@ export class WorkbasketService {
if (this.workbasketSummaryRef && !forceRequest) { if (this.workbasketSummaryRef && !forceRequest) {
return this.workbasketSummaryRef; return this.workbasketSummaryRef;
} }
return this.workbasketSummaryRef = this.httpClient.get<WorkbasketSummaryResource>(`${environment.taskanaRestUrl}/v1/workbaskets/${this.getWorkbasketSummaryQueryParameters(sortBy, order, name, return this.workbasketSummaryRef = this.httpClient.get<WorkbasketSummaryResource>(
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission)}`, this.httpOptions); `${environment.taskanaRestUrl}/v1/workbaskets/${this.getWorkbasketSummaryQueryParameters(sortBy, order, name,
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission)}`, this.httpOptions);
} }
// GET // GET
@ -92,7 +93,7 @@ export class WorkbasketService {
} }
// POST // POST
createWorkBasketAccessItem(url: string, workbasketAccessItem: WorkbasketAccessItems): Observable<WorkbasketAccessItems> { createWorkBasketAccessItem(url: string, workbasketAccessItem: WorkbasketAccessItems): Observable<WorkbasketAccessItems> {
return this.httpClient.post<WorkbasketAccessItems>(url , workbasketAccessItem, this.httpOptions); return this.httpClient.post<WorkbasketAccessItems>(url, workbasketAccessItem, this.httpOptions);
} }
// PUT // PUT
updateWorkBasketAccessItem(url: string, workbasketAccessItem: Array<WorkbasketAccessItems>): Observable<string> { updateWorkBasketAccessItem(url: string, workbasketAccessItem: Array<WorkbasketAccessItems>): Observable<string> {
@ -106,14 +107,13 @@ export class WorkbasketService {
} }
// PUT // PUT
updateWorkBasketsDistributionTargets(url: string, distributionTargetsIds :Array<string>): Observable<WorkbasketDistributionTargetsResource> { updateWorkBasketsDistributionTargets(url: string, distributionTargetsIds: Array<string>):
Observable<WorkbasketDistributionTargetsResource> {
return this.httpClient.put<WorkbasketDistributionTargetsResource>(url, distributionTargetsIds, this.httpOptions); return this.httpClient.put<WorkbasketDistributionTargetsResource>(url, distributionTargetsIds, this.httpOptions);
} }
// #endregion
//#endregion // #region "Service extras"
//#region "Service extras"
selectWorkBasket(id: string) { selectWorkBasket(id: string) {
this.workBasketSelected.next(id); this.workBasketSelected.next(id);
} }
@ -129,9 +129,9 @@ export class WorkbasketService {
workbasketSavedTriggered(): Observable<number> { workbasketSavedTriggered(): Observable<number> {
return this.workBasketSaved.asObservable(); return this.workBasketSaved.asObservable();
} }
//#endregion // #endregion
//#region private // #region private
private getWorkbasketSummaryQueryParameters(sortBy: string, private getWorkbasketSummaryQueryParameters(sortBy: string,
order: string, order: string,
name: string, name: string,
@ -143,7 +143,7 @@ export class WorkbasketService {
key: string, key: string,
keyLike: string, keyLike: string,
requiredPermission: string): string { requiredPermission: string): string {
let query: string = '?'; let query = '?';
query += sortBy ? `${this.SORTBY}=${sortBy}&` : ''; query += sortBy ? `${this.SORTBY}=${sortBy}&` : '';
query += order ? `${this.ORDER}=${order}&` : ''; query += order ? `${this.ORDER}=${order}&` : '';
query += name ? `${this.NAME}=${name}&` : ''; query += name ? `${this.NAME}=${name}&` : '';
@ -176,5 +176,5 @@ export class WorkbasketService {
return Observable.throw(errMsg); return Observable.throw(errMsg);
} }
//#endregion // #endregion
} }

View File

@ -12,7 +12,7 @@ describe('AlertComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports:[BrowserAnimationsModule], imports: [BrowserAnimationsModule],
declarations: [AlertComponent], declarations: [AlertComponent],
providers: [AlertService] providers: [AlertService]
}) })
@ -36,35 +36,35 @@ describe('AlertComponent', () => {
}); });
it('should show alert message', () => { it('should show alert message', () => {
alertService.triggerAlert(new AlertModel(AlertType.SUCCESS,'some custom text',)); alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'some custom text', ));
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('.alert.alert-success')).toBeDefined(); expect(debugElement.querySelector('.alert.alert-success')).toBeDefined();
expect(debugElement.querySelector('.alert.alert-success').innerText).toBe('some custom text'); expect(debugElement.querySelector('.alert.alert-success').innerText).toBe('some custom text');
}); });
it('should have differents alert types', () => { it('should have differents alert types', () => {
alertService.triggerAlert(new AlertModel(AlertType.DANGER,'some custom text',)); alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'some custom text', ));
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('.alert.alert-danger')).toBeDefined(); expect(debugElement.querySelector('.alert.alert-danger')).toBeDefined();
alertService.triggerAlert(new AlertModel(AlertType.WARNING,'some custom text',)); alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'some custom text', ));
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('.alert.alert-warning')).toBeDefined(); expect(debugElement.querySelector('.alert.alert-warning')).toBeDefined();
}); });
it('should define a closing timeout if alert has autoclosing property', (done) => { it('should define a closing timeout if alert has autoclosing property', (done) => {
alertService.triggerAlert(new AlertModel(AlertType.SUCCESS,'some custom text',true, 5)); alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'some custom text', true, 5));
fixture.detectChanges(); fixture.detectChanges();
expect(component.alert).toBeDefined(); expect(component.alert).toBeDefined();
setTimeout(()=>{ setTimeout(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(component.alert).toBeUndefined(); expect(component.alert).toBeUndefined();
done(); done();
},6) }, 6)
}); });
it('should have defined a closing button if alert has no autoclosing property', () => { it('should have defined a closing button if alert has no autoclosing property', () => {
alertService.triggerAlert(new AlertModel(AlertType.DANGER,'some custom text',false)); alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'some custom text', false));
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('.alert.alert-danger > button')).toBeDefined(); expect(debugElement.querySelector('.alert.alert-danger > button')).toBeDefined();
}); });

View File

@ -15,10 +15,10 @@ describe('FilterComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ FilterComponent, IconTypeComponent, MapValuesPipe ], declarations: [FilterComponent, IconTypeComponent, MapValuesPipe],
imports: [AngularSvgIconModule, FormsModule, HttpClientModule, HttpModule ] imports: [AngularSvgIconModule, FormsModule, HttpClientModule, HttpModule]
}) })
.compileComponents(); .compileComponents();
fixture = TestBed.createComponent(FilterComponent); fixture = TestBed.createComponent(FilterComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
@ -50,7 +50,7 @@ describe('FilterComponent', () => {
}); });
it('should be able to clear all fields after pressing clear button', () => { it('should be able to clear all fields after pressing clear button', () => {
component.filter = new FilterModel('a','a','a','a','a'); component.filter = new FilterModel('a', 'a', 'a', 'a', 'a');
debugElement.querySelector('[title="Clear"]').click(); debugElement.querySelector('[title="Clear"]').click();
expect(component.filter.name).toBe(''); expect(component.filter.name).toBe('');
expect(component.filter.description).toBe(''); expect(component.filter.description).toBe('');
@ -60,11 +60,11 @@ describe('FilterComponent', () => {
}); });
it('should be able to select a type and return it based on a number', () => { it('should be able to select a type and return it based on a number', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should be able to emit a filter after clicking on search button', (done) => { it('should be able to emit a filter after clicking on search button', (done) => {
component.filter = new FilterModel('a', 'name1', 'a', 'a'); component.filter = new FilterModel('a', 'name1', 'a', 'a');
component.performFilter.subscribe(filter => { component.performFilter.subscribe(filter => {
expect(filter.name).toBe('name1'); expect(filter.name).toBe('name1');
done(); done();

View File

@ -2,49 +2,53 @@ import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
import { IconTypeComponent, ICONTYPES } from '../type-icon/icon-type.component' import { IconTypeComponent, ICONTYPES } from '../type-icon/icon-type.component'
export class FilterModel { export class FilterModel {
type:string; type: string;
name:string; name: string;
description:string; description: string;
owner:string; owner: string;
key: string; key: string;
constructor(type:string = '', name:string = '', description:string = '', owner:string = '', key:string = ''){ constructor(type: string = '', name: string = '', description: string = '', owner: string = '', key: string = '') {
this.type = type; this.type = type;
this.name = name; this.name = name;
this.description= description; this.description = description;
this.owner = owner; this.owner = owner;
this.key = key; this.key = key;
} }
} }
@Component({ @Component({
selector: 'taskana-filter', selector: 'taskana-filter',
templateUrl: './filter.component.html', templateUrl: './filter.component.html',
styleUrls: ['./filter.component.scss'] styleUrls: ['./filter.component.scss']
}) })
export class FilterComponent{ export class FilterComponent {
constructor() {
this.allTypes = IconTypeComponent.allTypes;
}
allTypes: Map<string, string>;
filter: FilterModel = new FilterModel();
@Input() allTypes: Map<string, string>;
target:string; filter: FilterModel = new FilterModel();
@Output() @Input()
performFilter = new EventEmitter<FilterModel>(); target: string;
selectType(type: ICONTYPES){ @Output()
this.filter.type = type; performFilter = new EventEmitter<FilterModel>();
}
clear(){ toggleDropDown = false;
this.filter = new FilterModel();
}
search(){ constructor() {
this.performFilter.emit(this.filter); this.allTypes = IconTypeComponent.allTypes;
} }
selectType(type: ICONTYPES) {
this.filter.type = type;
}
clear() {
this.filter = new FilterModel();
}
search() {
this.performFilter.emit(this.filter);
}
} }

View File

@ -8,14 +8,14 @@ declare var $: any;
}) })
export class GeneralMessageModalComponent implements OnChanges { export class GeneralMessageModalComponent implements OnChanges {
@Input() message: string; @Input() message: string;
@Output() messageChange = new EventEmitter<string>(); @Output() messageChange = new EventEmitter<string>();
@Input() @Input()
title: string = ''; title = '';
@Input() @Input()
error: boolean = false; error = false;
@ViewChild('generalModal') @ViewChild('generalModal')
private modal; private modal;

View File

@ -1,4 +1,4 @@
import {Location} from "@angular/common"; import { Location } from '@angular/common';
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { TestBed, async, inject, fakeAsync } from '@angular/core/testing'; import { TestBed, async, inject, fakeAsync } from '@angular/core/testing';
import { MasterAndDetailComponent } from './master-and-detail.component'; import { MasterAndDetailComponent } from './master-and-detail.component';
@ -9,16 +9,16 @@ import { HttpClientModule } from '@angular/common/http';
import { MasterAndDetailService } from '../../services/master-and-detail.service' import { MasterAndDetailService } from '../../services/master-and-detail.service'
@Component({ @Component({
selector: 'dummy-master', selector: 'taskana-dummy-master',
template: 'dummymaster' template: 'dummymaster'
}) })
export class DummyMasterComponent { export class DummyMasterComponent {
} }
@Component({ @Component({
selector: 'dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {
@ -26,37 +26,38 @@ export class DummyDetailComponent {
describe('MasterAndDetailComponent ', () => { describe('MasterAndDetailComponent ', () => {
var component, fixture, debugElement, location, router; let component, fixture, debugElement, location, router;
const routes: Routes = [ const routes: Routes = [
{ path: 'workbaskets', {
component: MasterAndDetailComponent, path: 'workbaskets',
children: [ component: MasterAndDetailComponent,
{ children: [
path: '', {
component: DummyMasterComponent, path: '',
outlet: 'master' component: DummyMasterComponent,
}, outlet: 'master'
{ },
path: ':id', {
component: DummyDetailComponent, path: ':id',
outlet: 'detail' component: DummyDetailComponent,
} outlet: 'detail'
] }
]
} }
]; ];
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ MasterAndDetailComponent, DummyMasterComponent, DummyDetailComponent ], declarations: [MasterAndDetailComponent, DummyMasterComponent, DummyDetailComponent],
imports:[ imports: [
RouterTestingModule.withRoutes(routes), RouterTestingModule.withRoutes(routes),
AngularSvgIconModule, AngularSvgIconModule,
HttpClientModule HttpClientModule
], ],
providers: [MasterAndDetailService] providers: [MasterAndDetailService]
}) })
.compileComponents(); .compileComponents();
fixture = TestBed.createComponent(MasterAndDetailComponent); fixture = TestBed.createComponent(MasterAndDetailComponent);
component = fixture.debugElement.componentInstance; component = fixture.debugElement.componentInstance;
@ -67,7 +68,7 @@ describe('MasterAndDetailComponent ', () => {
})); }));
afterEach(async(()=>{ afterEach(async(() => {
document.body.removeChild(debugElement); document.body.removeChild(debugElement);
})); }));
@ -75,7 +76,7 @@ describe('MasterAndDetailComponent ', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should call Router.navigateByUrl("/wokbaskets") and showDetail property should be false', async ( () => { it('should call Router.navigateByUrl("/wokbaskets") and showDetail property should be false', async(() => {
expect(component.showDetail).toBe(false); expect(component.showDetail).toBe(false);
fixture.detectChanges(); fixture.detectChanges();
@ -84,7 +85,7 @@ describe('MasterAndDetailComponent ', () => {
})); }));
it('should call Router.navigateByUrl("/wokbaskets/(detail:Id)") and showDetail property should be true', async ( () => { it('should call Router.navigateByUrl("/wokbaskets/(detail:Id)") and showDetail property should be true', async(() => {
expect(component.showDetail).toBe(false); expect(component.showDetail).toBe(false);
fixture.detectChanges(); fixture.detectChanges();
@ -93,7 +94,7 @@ describe('MasterAndDetailComponent ', () => {
})); }));
it('should navigate to parent state when backIsClicked', async( () => { it('should navigate to parent state when backIsClicked', async(() => {
const spy = spyOn(router, 'navigateByUrl'); const spy = spyOn(router, 'navigateByUrl');
router.navigateByUrl('/workbaskets/(detail:2)'); router.navigateByUrl('/workbaskets/(detail:2)');

View File

@ -1,28 +1,28 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, Routes, ActivatedRoute, NavigationStart, RouterEvent } from '@angular/router'; import { Router, Routes, ActivatedRoute, NavigationStart, RouterEvent } from '@angular/router';
import { MasterAndDetailService } from '../../services/master-and-detail.service' import { MasterAndDetailService } from '../../services/master-and-detail.service'
@Component({ @Component({
selector: 'master-and-detail', selector: 'taskana-master-and-detail',
templateUrl: './master-and-detail.component.html', templateUrl: './master-and-detail.component.html',
styleUrls: ['./master-and-detail.component.scss'], styleUrls: ['./master-and-detail.component.scss'],
}) })
export class MasterAndDetailComponent implements OnInit{ export class MasterAndDetailComponent implements OnInit {
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'clasifications']; private detailRoutes: Array<string> = ['/workbaskets/(detail', 'clasifications'];
private sub: any; private sub: any;
showDetail: Boolean = false; showDetail: Boolean = false;
constructor(private route: ActivatedRoute, private router: Router, private masterAndDetailService: MasterAndDetailService){ constructor(private route: ActivatedRoute, private router: Router, private masterAndDetailService: MasterAndDetailService) {
} }
ngOnInit(): void { ngOnInit(): void {
this.showDetail = this.showDetails(); this.showDetail = this.showDetails();
this.masterAndDetailService.setShowDetail(this.showDetail? true: false); this.masterAndDetailService.setShowDetail(this.showDetail ? true : false);
this.router.events.subscribe(event => { this.router.events.subscribe(event => {
if(event instanceof NavigationStart) { if (event instanceof NavigationStart) {
this.showDetail = this.showDetails(event); this.showDetail = this.showDetails(event);
this.masterAndDetailService.setShowDetail(this.showDetail? true: false); this.masterAndDetailService.setShowDetail(this.showDetail ? true : false);
} }
}); });
} }
@ -31,16 +31,16 @@ export class MasterAndDetailComponent implements OnInit{
this.router.navigate(['../'], { relativeTo: this.route }); this.router.navigate(['../'], { relativeTo: this.route });
} }
private showDetails(event? : RouterEvent): Boolean { private showDetails(event?: RouterEvent): Boolean {
if(event === undefined) { if (event === undefined) {
return this.checkUrl(this.router.url); return this.checkUrl(this.router.url);
} }
return this.checkUrl(event.url) return this.checkUrl(event.url)
} }
private checkUrl(url: string): Boolean { private checkUrl(url: string): Boolean {
for(let routeDetail of this.detailRoutes){ for (const routeDetail of this.detailRoutes) {
if(url.indexOf(routeDetail) !== -1){ if (url.indexOf(routeDetail) !== -1) {
return true; return true;
} }
} }

View File

@ -1,19 +1,19 @@
import { Component, OnInit, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Output, EventEmitter } from '@angular/core';
export enum Direction { export enum Direction {
ASC = 'asc', ASC = 'asc',
DESC = 'desc' DESC = 'desc'
}; };
export class SortingModel { export class SortingModel {
sortBy:string; sortBy: string;
sortDirection:string; sortDirection: string;
constructor(sortBy:string = 'key', sortDirection:Direction = Direction.ASC){ constructor(sortBy: string = 'key', sortDirection: Direction = Direction.ASC) {
this.sortBy = sortBy; this.sortBy = sortBy;
this.sortDirection = sortDirection; this.sortDirection = sortDirection;
}
} }
}
@Component({ @Component({
selector: 'taskana-sort', selector: 'taskana-sort',
@ -21,28 +21,30 @@ export enum Direction {
styleUrls: ['./sort.component.scss'] styleUrls: ['./sort.component.scss']
}) })
export class SortComponent implements OnInit { export class SortComponent implements OnInit {
readonly sortingFields: Map<string, string> = new Map([['name', 'Name'], ['key', 'Id'], ['description', 'Description'], ['owner', 'Owner'], ['type', 'Type']]); readonly sortingFields: Map<string, string> = new Map(
[['name', 'Name'], ['key', 'Id'], ['description', 'Description'], ['owner', 'Owner'], ['type', 'Type']]);
constructor() { }
@Output() @Output()
performSorting = new EventEmitter<SortingModel>(); performSorting = new EventEmitter<SortingModel>();
sort: SortingModel = new SortingModel(); sort: SortingModel = new SortingModel();
constructor() { }
ngOnInit() { ngOnInit() {
} }
changeOrder(sortDirection: string) { changeOrder(sortDirection: string) {
this.sort.sortDirection = (sortDirection === Direction.ASC) ? Direction.ASC : Direction.DESC; this.sort.sortDirection = (sortDirection === Direction.ASC) ? Direction.ASC : Direction.DESC;
this.search(); this.search();
} }
changeSortBy(sortBy: string) { changeSortBy(sortBy: string) {
this.sort.sortBy = sortBy; this.sort.sortBy = sortBy;
this.search(); this.search();
} }
private search(){ private search() {
this.performSorting.emit(this.sort); this.performSorting.emit(this.sort);
} }

View File

@ -8,9 +8,9 @@ describe('SpinnerComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SpinnerComponent ] declarations: [SpinnerComponent]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -1,4 +1,4 @@
import { Component, Input, ElementRef, Output, EventEmitter } from '@angular/core'; import { Component, Input, ElementRef, Output, EventEmitter, OnDestroy } from '@angular/core';
import { ViewChild } from '@angular/core'; import { ViewChild } from '@angular/core';
declare var $: any; declare var $: any;
@ -7,15 +7,15 @@ declare var $: any;
templateUrl: './spinner.component.html', templateUrl: './spinner.component.html',
styleUrls: ['./spinner.component.scss'] styleUrls: ['./spinner.component.scss']
}) })
export class SpinnerComponent { export class SpinnerComponent implements OnDestroy {
private currentTimeout: any; private currentTimeout: any;
private requestTimeout: any; private requestTimeout: any;
private maxRequestTimeout: number = 10000; private maxRequestTimeout = 10000;
isDelayedRunning: boolean = false; isDelayedRunning = false;
@Input() @Input()
delay: number = 200; delay = 200;
@Input() @Input()
set isRunning(value: boolean) { set isRunning(value: boolean) {
@ -34,7 +34,7 @@ export class SpinnerComponent {
} }
@Input() @Input()
isModal: boolean = false; isModal = false;
@Input() @Input()
positionClass: string = undefined; positionClass: string = undefined;
@ -48,13 +48,13 @@ export class SpinnerComponent {
private runSpinner(value) { private runSpinner(value) {
this.currentTimeout = setTimeout(() => { this.currentTimeout = setTimeout(() => {
if (this.isModal) { $(this.modal.nativeElement).modal('toggle'); } if (this.isModal) { $(this.modal.nativeElement).modal('toggle'); }
this.isDelayedRunning = value; this.isDelayedRunning = value;
this.cancelTimeout(); this.cancelTimeout();
this.requestTimeout = setTimeout(() => { this.requestTimeout = setTimeout(() => {
this.requestTimeoutExceeded.emit('There was an error with your request, please make sure you have internet connection'); this.requestTimeoutExceeded.emit('There was an error with your request, please make sure you have internet connection');
this.cancelTimeout(); this.cancelTimeout();
this.isRunning = false; this.isRunning = false;
},this.maxRequestTimeout); }, this.maxRequestTimeout);
}, this.delay); }, this.delay);
} }
private closeModal() { private closeModal() {

View File

@ -10,10 +10,10 @@ describe('IconTypeComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports:[AngularSvgIconModule,HttpClientModule, HttpModule], imports: [AngularSvgIconModule, HttpClientModule, HttpModule],
declarations: [ IconTypeComponent ] declarations: [IconTypeComponent]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -17,20 +17,24 @@ export enum ICONTYPES {
}) })
export class IconTypeComponent implements OnInit { export class IconTypeComponent implements OnInit {
public static get allTypes(): Map<string, string> { return new Map([['', 'None'], ['PERSONAL', 'Personal'], ['GROUP', 'Group'], ['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']])};
constructor() { }
@Input() @Input()
type: ICONTYPES = ICONTYPES.PERSONAL; type: ICONTYPES = ICONTYPES.PERSONAL;
@Input() @Input()
selected: boolean = false; selected = false;
@Input() @Input()
tooltip: boolean = false; tooltip = false;
public static get allTypes(): Map<string, string> {
return new Map([['', 'None'], ['PERSONAL', 'Personal'], ['GROUP', 'Group'], ['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']])
};
constructor() { }
ngOnInit() { ngOnInit() {
} }
} }

View File

@ -32,14 +32,18 @@ describe('AccessItemsComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(AccessItemsComponent); fixture = TestBed.createComponent(AccessItemsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.workbasket = new Workbasket('1','','','','','','','','','','','','','','','', '', new Links(undefined,undefined, {'href': 'someurl' })); component.workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
new Links(undefined, undefined, { 'href': 'someurl' }));
workbasketService = TestBed.get(WorkbasketService); workbasketService = TestBed.get(WorkbasketService);
alertService = TestBed.get(AlertService); alertService = TestBed.get(AlertService);
spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(Observable.of(new WorkbasketAccessItemsResource( spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(Observable.of(new WorkbasketAccessItemsResource(
{'accessItems': new Array<WorkbasketAccessItems>( {
new WorkbasketAccessItems('id1', '1', 'accessID1', false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), 'accessItems': new Array<WorkbasketAccessItems>(
new WorkbasketAccessItems('id2', '1', 'accessID2')) }, new Links({ 'href': 'someurl' }) new WorkbasketAccessItems('id1', '1', 'accessID1', false, false, false, false, false, false, false, false,
))); false, false, false, false, false, false, false, false, false),
new WorkbasketAccessItems('id2', '1', 'accessID2'))
}, new Links({ 'href': 'someurl' })
)));
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(Observable.of(true)), spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(Observable.of(true)),
spyOn(alertService, 'triggerAlert').and.returnValue(Observable.of(true)), spyOn(alertService, 'triggerAlert').and.returnValue(Observable.of(true)),
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
@ -62,7 +66,7 @@ describe('AccessItemsComponent', () => {
}); });
it('should show Add new access item button', () => { it('should show Add new access item button', () => {
expect(debugElement.querySelector('#button-add-access-item')).toBeTruthy; expect(debugElement.querySelector('#button-add-access-item')).toBeTruthy();
}); });
it('should remove an access item if remove button is clicked', () => { it('should remove an access item if remove button is clicked', () => {
@ -74,7 +78,8 @@ describe('AccessItemsComponent', () => {
it('should show alert successfull after saving', () => { it('should show alert successfull after saving', () => {
component.onSave(); component.onSave();
expect(alertService.triggerAlert).toHaveBeenCalledWith(new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`)); expect(alertService.triggerAlert).toHaveBeenCalledWith(
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
}); });
}); });

View File

@ -1,5 +1,5 @@
import { Component, OnInit, Input, AfterViewInit } from '@angular/core'; import { Component, OnInit, Input, AfterViewInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs/Subscription';
import { Workbasket } from '../../../model/workbasket'; import { Workbasket } from '../../../model/workbasket';
import { WorkbasketAccessItems } from '../../../model/workbasket-access-items'; import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
@ -15,7 +15,7 @@ declare var $: any;
templateUrl: './access-items.component.html', templateUrl: './access-items.component.html',
styleUrls: ['./access-items.component.scss'] styleUrls: ['./access-items.component.scss']
}) })
export class AccessItemsComponent implements OnInit { export class AccessItemsComponent implements OnInit, OnDestroy {
@Input() @Input()
workbasket: Workbasket; workbasket: Workbasket;
@ -24,8 +24,8 @@ export class AccessItemsComponent implements OnInit {
accessItems: Array<WorkbasketAccessItems>; accessItems: Array<WorkbasketAccessItems>;
accessItemsClone: Array<WorkbasketAccessItems>; accessItemsClone: Array<WorkbasketAccessItems>;
accessItemsResetClone: Array<WorkbasketAccessItems>; accessItemsResetClone: Array<WorkbasketAccessItems>;
requestInProgress: boolean = false; requestInProgress = false;
modalSpinner: boolean = true; modalSpinner = true;
modalTitle: string; modalTitle: string;
modalErrorMessage: string; modalErrorMessage: string;
accessItemsubscription: Subscription; accessItemsubscription: Subscription;
@ -34,17 +34,18 @@ export class AccessItemsComponent implements OnInit {
constructor(private workbasketService: WorkbasketService, private alertService: AlertService) { } constructor(private workbasketService: WorkbasketService, private alertService: AlertService) { }
ngOnInit() { ngOnInit() {
this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href).subscribe( (accessItemsResource: WorkbasketAccessItemsResource) =>{ this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href)
this.accessItemsResource = accessItemsResource; .subscribe((accessItemsResource: WorkbasketAccessItemsResource) => {
this.accessItems = accessItemsResource._embedded?accessItemsResource._embedded.accessItems: []; this.accessItemsResource = accessItemsResource;
this.accessItemsClone = this.cloneAccessItems(this.accessItems); this.accessItems = accessItemsResource._embedded ? accessItemsResource._embedded.accessItems : [];
this.accessItemsResetClone = this.cloneAccessItems(this.accessItems); this.accessItemsClone = this.cloneAccessItems(this.accessItems);
}) this.accessItemsResetClone = this.cloneAccessItems(this.accessItems);
})
} }
addAccessItem() { addAccessItem() {
this.accessItems.push(new WorkbasketAccessItems(undefined,this.workbasket.workbasketId, undefined, true)); this.accessItems.push(new WorkbasketAccessItems(undefined, this.workbasket.workbasketId, undefined, true));
this.accessItemsClone.push(new WorkbasketAccessItems()); this.accessItemsClone.push(new WorkbasketAccessItems());
} }
@ -55,38 +56,38 @@ export class AccessItemsComponent implements OnInit {
} }
remove(index: number) { remove(index: number) {
this.accessItems.splice(index,1); this.accessItems.splice(index, 1);
this.accessItemsClone.splice(index,1); this.accessItemsClone.splice(index, 1);
} }
onSave(): boolean { onSave(): boolean {
this.requestInProgress = true; this.requestInProgress = true;
this.workbasketService.updateWorkBasketAccessItem(this.accessItemsResource._links.self.href , this.accessItems).subscribe(response =>{ this.workbasketService.updateWorkBasketAccessItem(this.accessItemsResource._links.self.href, this.accessItems)
this.accessItemsClone = this.cloneAccessItems(this.accessItems); .subscribe(response => {
this.accessItemsResetClone = this.cloneAccessItems(this.accessItems); this.accessItemsClone = this.cloneAccessItems(this.accessItems);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`)); this.accessItemsResetClone = this.cloneAccessItems(this.accessItems);
this.requestInProgress = false; this.alertService.triggerAlert(new AlertModel(
return true; AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`));
}, this.requestInProgress = false;
error => { return true;
this.modalErrorMessage = error.message; },
this.requestInProgress = false; error => {
return false; this.modalErrorMessage = error.message;
}) this.requestInProgress = false;
return false;
})
return false; return false;
} }
setValue() { debugger; } private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
const accessItemClone = new Array<WorkbasketAccessItems>();
private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems>{
let accessItemClone = new Array<WorkbasketAccessItems>();
inputaccessItem.forEach(accessItem => { inputaccessItem.forEach(accessItem => {
accessItemClone.push({... accessItem}); accessItemClone.push({ ...accessItem });
}); });
return accessItemClone; return accessItemClone;
} }
private ngOnDestroy(): void { ngOnDestroy(): void {
if (this.accessItemsubscription) { this.accessItemsubscription.unsubscribe(); } if (this.accessItemsubscription) { this.accessItemsubscription.unsubscribe(); }
} }
} }

View File

@ -23,8 +23,8 @@ import { DualListComponent } from './dual-list/dual-list.component';
const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource({ const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource({
'workbaskets': new Array<WorkbasketSummary>( 'workbaskets': new Array<WorkbasketSummary>(
new WorkbasketSummary("1", "key1", "NAME1", "description 1", "owner 1", "", "", "PERSONAL", "", "", "", ""), new WorkbasketSummary('1', 'key1', 'NAME1', 'description 1', 'owner 1', '', '', 'PERSONAL', '', '', '', ''),
new WorkbasketSummary("2", "key2", "NAME2", "description 2", "owner 2", "", "", "GROUP", "", "", "", "")) new WorkbasketSummary('2', 'key2', 'NAME2', 'description 2', 'owner 2', '', '', 'GROUP', '', '', '', ''))
}, new Links({ 'href': 'url' })); }, new Links({ 'href': 'url' }));
@Component({ @Component({
@ -43,12 +43,14 @@ describe('DistributionTargetsComponent', () => {
let component: DistributionTargetsComponent; let component: DistributionTargetsComponent;
let fixture: ComponentFixture<DistributionTargetsComponent>; let fixture: ComponentFixture<DistributionTargetsComponent>;
let workbasketService; let workbasketService;
let workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' })); const workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' }));
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule, HttpModule, JsonpModule], imports: [AngularSvgIconModule, HttpClientModule, HttpModule, JsonpModule],
declarations: [DistributionTargetsComponent, SpinnerComponent, GeneralMessageModalComponent, FilterComponent, SelectWorkBasketPipe, IconTypeComponent, DualListComponent], declarations: [DistributionTargetsComponent, SpinnerComponent, GeneralMessageModalComponent,
FilterComponent, SelectWorkBasketPipe, IconTypeComponent, DualListComponent],
providers: [WorkbasketService, AlertService] providers: [WorkbasketService, AlertService]
}) })
.compileComponents(); .compileComponents();
@ -70,7 +72,10 @@ describe('DistributionTargetsComponent', () => {
}) })
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => { spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => {
return Observable.of(new WorkbasketDistributionTargetsResource( return Observable.of(new WorkbasketDistributionTargetsResource(
{ 'distributionTargets': new Array<WorkbasketSummary>(new WorkbasketSummary('id2', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }))) }, new Links({ 'href': 'someurl' }))) {
'distributionTargets': new Array<WorkbasketSummary>(
new WorkbasketSummary('id2', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' })))
}, new Links({ 'href': 'someurl' })))
}) })
fixture.detectChanges(); fixture.detectChanges();
@ -95,13 +100,13 @@ describe('DistributionTargetsComponent', () => {
expect(component.distributionTargetsRight.length).toBe(1); expect(component.distributionTargetsRight.length).toBe(1);
component.distributionTargetsLeft.forEach(leftElement => { component.distributionTargetsLeft.forEach(leftElement => {
component.distributionTargetsRight.forEach(rightElement => { component.distributionTargetsRight.forEach(rightElement => {
if (leftElement.workbasketId === rightElement.workbasketId) repeteadElemens = true; if (leftElement.workbasketId === rightElement.workbasketId) { repeteadElemens = true };
}) })
}) })
expect(repeteadElemens).toBeFalsy(); expect(repeteadElemens).toBeFalsy();
}); });
it('should filter left list and keep selected elements as selected', () => { it('should filter left list and keep selected elements as selected', () => {
component.performFilter({filterBy:new FilterModel(), side: Side.LEFT}); component.performFilter({ filterBy: new FilterModel(), side: Side.LEFT });
component.distributionTargetsLeft = new Array<WorkbasketSummary>( component.distributionTargetsLeft = new Array<WorkbasketSummary>(
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' })) new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }))
) )
@ -111,8 +116,10 @@ describe('DistributionTargetsComponent', () => {
expect(component.distributionTargetsRight[0].workbasketId).toBe('id2'); expect(component.distributionTargetsRight[0].workbasketId).toBe('id2');
}); });
it('should reset distribution target and distribution target selected on reset', () => { it('should reset distribution target and distribution target selected on reset', () => {
component.distributionTargetsLeft.push(new WorkbasketSummary('id4', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }))); component.distributionTargetsLeft.push(
component.distributionTargetsRight.push(new WorkbasketSummary('id5', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }))); new WorkbasketSummary('id4', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' })));
component.distributionTargetsRight.push(
new WorkbasketSummary('id5', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' })));
expect(component.distributionTargetsLeft.length).toBe(3); expect(component.distributionTargetsLeft.length).toBe(3);
expect(component.distributionTargetsRight.length).toBe(2); expect(component.distributionTargetsRight.length).toBe(2);

View File

@ -1,4 +1,4 @@
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { Workbasket } from '../../../model/workbasket'; import { Workbasket } from '../../../model/workbasket';
import { WorkbasketSummary } from '../../../model/workbasket-summary'; import { WorkbasketSummary } from '../../../model/workbasket-summary';
import { WorkbasketAccessItems } from '../../../model/workbasket-access-items'; import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
@ -8,7 +8,7 @@ import { TREE_ACTIONS, KEYS, IActionMapping, ITreeOptions } from 'angular-tree-c
import { WorkbasketService } from '../../../services/workbasket.service'; import { WorkbasketService } from '../../../services/workbasket.service';
import { AlertService, AlertModel, AlertType } from '../../../services/alert.service'; import { AlertService, AlertModel, AlertType } from '../../../services/alert.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs/Subscription';
import { element } from 'protractor'; import { element } from 'protractor';
import { WorkbasketSummaryResource } from '../../../model/workbasket-summary-resource'; import { WorkbasketSummaryResource } from '../../../model/workbasket-summary-resource';
import { WorkbasketDistributionTargetsResource } from '../../../model/workbasket-distribution-targets-resource'; import { WorkbasketDistributionTargetsResource } from '../../../model/workbasket-distribution-targets-resource';
@ -22,7 +22,7 @@ export enum Side {
templateUrl: './distribution-targets.component.html', templateUrl: './distribution-targets.component.html',
styleUrls: ['./distribution-targets.component.scss'] styleUrls: ['./distribution-targets.component.scss']
}) })
export class DistributionTargetsComponent implements OnInit { export class DistributionTargetsComponent implements OnInit, OnDestroy {
@Input() @Input()
workbasket: Workbasket; workbasket: Workbasket;
@ -39,9 +39,9 @@ export class DistributionTargetsComponent implements OnInit {
distributionTargetsSelectedClone: Array<WorkbasketSummary>; distributionTargetsSelectedClone: Array<WorkbasketSummary>;
requestInProgress: boolean = false; requestInProgress = false;
requestInProgressLeft: boolean = false; requestInProgressLeft = false;
requestInProgressRight: boolean = false; requestInProgressRight = false;
modalErrorMessage: string; modalErrorMessage: string;
side = Side; side = Side;
@ -49,27 +49,30 @@ export class DistributionTargetsComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.onRequest(undefined); this.onRequest(undefined);
this.distributionTargetsSubscription = this.workbasketService.getWorkBasketsDistributionTargets(this.workbasket._links.distributionTargets.href).subscribe((distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource) => { this.distributionTargetsSubscription = this.workbasketService.getWorkBasketsDistributionTargets(
this.distributionTargetsSelectedResource = distributionTargetsSelectedResource; this.workbasket._links.distributionTargets.href).subscribe(
this.distributionTargetsSelected = distributionTargetsSelectedResource._embedded ? distributionTargetsSelectedResource._embedded.distributionTargets : []; (distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource) => {
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected); this.distributionTargetsSelectedResource = distributionTargetsSelectedResource;
this.workbasketSubscription = this.workbasketService.getWorkBasketsSummary().subscribe((distributionTargetsAvailable: WorkbasketSummaryResource) => { this.distributionTargetsSelected = distributionTargetsSelectedResource._embedded ?
this.distributionTargetsLeft = Object.assign([], distributionTargetsAvailable._embedded.workbaskets); distributionTargetsSelectedResource._embedded.distributionTargets : [];
this.distributionTargetsRight = Object.assign([], distributionTargetsAvailable._embedded.workbaskets); this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
this.distributionTargetsClone = Object.assign([], distributionTargetsAvailable._embedded.workbaskets); this.workbasketSubscription = this.workbasketService.getWorkBasketsSummary().subscribe(
this.onRequest(undefined, true); (distributionTargetsAvailable: WorkbasketSummaryResource) => {
}); this.distributionTargetsLeft = Object.assign([], distributionTargetsAvailable._embedded.workbaskets);
}); this.distributionTargetsRight = Object.assign([], distributionTargetsAvailable._embedded.workbaskets);
this.distributionTargetsClone = Object.assign([], distributionTargetsAvailable._embedded.workbaskets);
this.onRequest(undefined, true);
});
});
} }
moveDistributionTargets(side: number) { moveDistributionTargets(side: number) {
if (side === Side.LEFT) { if (side === Side.LEFT) {
let itemsSelected = this.getSelectedItems(this.distributionTargetsLeft, this.distributionTargetsRight) const itemsSelected = this.getSelectedItems(this.distributionTargetsLeft, this.distributionTargetsRight)
this.distributionTargetsSelected = this.distributionTargetsSelected.concat(itemsSelected); this.distributionTargetsSelected = this.distributionTargetsSelected.concat(itemsSelected);
this.distributionTargetsRight = this.distributionTargetsRight.concat(itemsSelected); this.distributionTargetsRight = this.distributionTargetsRight.concat(itemsSelected);
} } else {
else { const itemsSelected = this.getSelectedItems(this.distributionTargetsRight, this.distributionTargetsLeft);
let itemsSelected = this.getSelectedItems(this.distributionTargetsRight, this.distributionTargetsLeft);
this.distributionTargetsSelected = this.removeSeletedItems(this.distributionTargetsSelected, itemsSelected); this.distributionTargetsSelected = this.removeSeletedItems(this.distributionTargetsSelected, itemsSelected);
this.distributionTargetsRight = this.removeSeletedItems(this.distributionTargetsRight, itemsSelected); this.distributionTargetsRight = this.removeSeletedItems(this.distributionTargetsRight, itemsSelected);
this.distributionTargetsLeft = this.distributionTargetsLeft.concat(itemsSelected); this.distributionTargetsLeft = this.distributionTargetsLeft.concat(itemsSelected);
@ -78,20 +81,22 @@ export class DistributionTargetsComponent implements OnInit {
onSave() { onSave() {
this.requestInProgress = true; this.requestInProgress = true;
this.workbasketService.updateWorkBasketsDistributionTargets(this.distributionTargetsSelectedResource._links.self.href, this.getSeletedIds()).subscribe(response => { this.workbasketService.updateWorkBasketsDistributionTargets(
this.requestInProgress = false; this.distributionTargetsSelectedResource._links.self.href, this.getSeletedIds()).subscribe(response => {
this.distributionTargetsSelected = response._embedded ? response._embedded.distributionTargets : [];
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
this.distributionTargetsClone = Object.assign([], this.distributionTargetsLeft);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`));
return true;
},
error => {
this.modalErrorMessage = error.message;
this.requestInProgress = false; this.requestInProgress = false;
return false; this.distributionTargetsSelected = response._embedded ? response._embedded.distributionTargets : [];
} this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
) this.distributionTargetsClone = Object.assign([], this.distributionTargetsLeft);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS,
`Workbasket ${this.workbasket.name} Access items were saved successfully`));
return true;
},
error => {
this.modalErrorMessage = error.message;
this.requestInProgress = false;
return false;
}
)
return false; return false;
} }
@ -122,12 +127,12 @@ export class DistributionTargetsComponent implements OnInit {
} }
private getSelectedItems(originList: any, destinationList: any): Array<any> { private getSelectedItems(originList: any, destinationList: any): Array<any> {
return originList.filter((element: any) => { return (element.selected === true) }); return originList.filter((item: any) => { return (item.selected === true) });
} }
private removeSeletedItems(originList: any, selectedItemList) { private removeSeletedItems(originList: any, selectedItemList) {
for (let index = originList.length - 1; index >= 0; index--) { for (let index = originList.length - 1; index >= 0; index--) {
if (selectedItemList.some(elementToRemove => { return originList[index].workbasketId === elementToRemove.workbasketId })) { if (selectedItemList.some(itemToRemove => { return originList[index].workbasketId === itemToRemove.workbasketId })) {
originList.splice(index, 1); originList.splice(index, 1);
} }
} }
@ -145,14 +150,14 @@ export class DistributionTargetsComponent implements OnInit {
} }
private getSeletedIds(): Array<string> { private getSeletedIds(): Array<string> {
let distributionTargetsSelelected: Array<string> = []; const distributionTargetsSelelected: Array<string> = [];
this.distributionTargetsSelected.forEach(element => { this.distributionTargetsSelected.forEach(item => {
distributionTargetsSelelected.push(element.workbasketId); distributionTargetsSelelected.push(item.workbasketId);
}) })
return distributionTargetsSelelected; return distributionTargetsSelelected;
} }
private ngOnDestroy(): void { ngOnDestroy(): void {
if (this.distributionTargetsSubscription) { this.distributionTargetsSubscription.unsubscribe(); } if (this.distributionTargetsSubscription) { this.distributionTargetsSubscription.unsubscribe(); }
if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); } if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); }
if (this.workbasketFilterSubscription) { this.workbasketFilterSubscription.unsubscribe(); } if (this.workbasketFilterSubscription) { this.workbasketFilterSubscription.unsubscribe(); }

View File

@ -11,20 +11,22 @@ import { Side } from '../distribution-targets.component';
}) })
export class DualListComponent implements OnInit { export class DualListComponent implements OnInit {
constructor() { }
ngOnInit() {
this.sideNumber = this.side === Side.LEFT ? 0 : 1;
}
@Input() distributionTargets: Array<WorkbasketSummary>; @Input() distributionTargets: Array<WorkbasketSummary>;
@Output() distributionTargetsChange = new EventEmitter<Array<WorkbasketSummary>>(); @Output() distributionTargetsChange = new EventEmitter<Array<WorkbasketSummary>>();
@Input() distributionTargetsSelected: Array<WorkbasketSummary>; @Input() distributionTargetsSelected: Array<WorkbasketSummary>;
@Output() performDualListFilter = new EventEmitter<{ filterBy: FilterModel, side: Side }>(); @Output() performDualListFilter = new EventEmitter<{ filterBy: FilterModel, side: Side }>();
@Input() requestInProgress: boolean = false; @Input() requestInProgress = false;
@Input() side: Side; @Input() side: Side;
sideNumber: number = 0;
sideNumber = 0;
toggleDtl = false;
constructor() { }
ngOnInit() {
this.sideNumber = this.side === Side.LEFT ? 0 : 1;
}
selectAll(selected: boolean) { selectAll(selected: boolean) {
this.distributionTargets.forEach((element: any) => { this.distributionTargets.forEach((element: any) => {
@ -32,9 +34,7 @@ export class DualListComponent implements OnInit {
}); });
} }
performAvailableFilter(filterModel: FilterModel) { performAvailableFilter(filterModel: FilterModel) {
this.performDualListFilter.emit({ filterBy: filterModel, side: this.side }); this.performDualListFilter.emit({ filterBy: filterModel, side: this.side });
} }
} }

View File

@ -23,7 +23,8 @@ describe('InformationComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent], declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, RouterTestingModule], imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, RouterTestingModule],
providers: [WorkbasketService, AlertService] providers: [WorkbasketService, AlertService]
@ -44,7 +45,9 @@ describe('InformationComponent', () => {
}); });
it('should create a panel with heading and form with all fields', async(() => { it('should create a panel with heading and form with all fields', async(() => {
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description', 'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null); component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type',
'modified', 'name', 'description', 'owner', 'custom1', 'custom2', 'custom3', 'custom4',
'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('#wb-information')).toBeDefined(); expect(debugElement.querySelector('#wb-information')).toBeDefined();
expect(debugElement.querySelector('#wb-information > .panel-heading > h4').textContent).toBe('name'); expect(debugElement.querySelector('#wb-information > .panel-heading > h4').textContent).toBe('name');
@ -67,7 +70,8 @@ describe('InformationComponent', () => {
it('should create a copy of workbasket when workbasket is selected', () => { it('should create a copy of workbasket when workbasket is selected', () => {
expect(component.workbasketClone).toBeUndefined(); expect(component.workbasketClone).toBeUndefined();
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description', 'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null); component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
component.ngOnInit(); component.ngOnInit();
fixture.detectChanges(); fixture.detectChanges();
expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId); expect(component.workbasket.workbasketId).toEqual(component.workbasketClone.workbasketId);
@ -76,12 +80,12 @@ describe('InformationComponent', () => {
it('should reset requestInProgress after saving request is done', fakeAsync(() => { it('should reset requestInProgress after saving request is done', fakeAsync(() => {
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description', component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
'orgLevel3', 'orgLevel4', new Links({'href': 'someUrl'})); 'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket)); spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket));
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket)); spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket));
component.onSave(); component.onSave();
expect(component.modalSpinner).toBeTruthy(); expect(component.modalSpinner).toBeTruthy();
expect(component.modalErrorMessage).toBeUndefined expect(component.modalErrorMessage).toBeUndefined();
expect(component.requestInProgress).toBeFalsy(); expect(component.requestInProgress).toBeFalsy();
})); }));
@ -89,7 +93,7 @@ describe('InformationComponent', () => {
it('should trigger triggerWorkBasketSaved method after saving request is done', () => { it('should trigger triggerWorkBasketSaved method after saving request is done', () => {
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description', component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', 'type', 'modified', 'name', 'description',
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
'orgLevel3', 'orgLevel4', new Links({'href': 'someUrl'})); 'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket)); spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket));
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket)); spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket));
component.onSave(); component.onSave();

View File

@ -1,27 +1,27 @@
import { Component, OnInit, Input, Output } from '@angular/core'; import { Component, OnInit, Input, Output, OnDestroy } from '@angular/core';
import { Workbasket } from '../../../model/workbasket'; import { Workbasket } from '../../../model/workbasket';
import { WorkbasketService } from '../../../services/workbasket.service'; import { WorkbasketService } from '../../../services/workbasket.service';
import { IconTypeComponent, ICONTYPES } from '../../../shared/type-icon/icon-type.component'; import { IconTypeComponent, ICONTYPES } from '../../../shared/type-icon/icon-type.component';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs/Subscription';
import { AlertService, AlertModel, AlertType } from '../../../services/alert.service'; import { AlertService, AlertModel, AlertType } from '../../../services/alert.service';
import { ActivatedRoute, Params, Router, NavigationStart } from '@angular/router'; import { ActivatedRoute, Params, Router, NavigationStart } from '@angular/router';
@Component({ @Component({
selector: 'workbasket-information', selector: 'taskana-workbasket-information',
templateUrl: './workbasket-information.component.html', templateUrl: './workbasket-information.component.html',
styleUrls: ['./workbasket-information.component.scss'] styleUrls: ['./workbasket-information.component.scss']
}) })
export class WorkbasketInformationComponent implements OnInit { export class WorkbasketInformationComponent implements OnInit, OnDestroy {
@Input() @Input()
workbasket: Workbasket; workbasket: Workbasket;
workbasketClone: Workbasket; workbasketClone: Workbasket;
allTypes: Map<string, string>; allTypes: Map<string, string>;
requestInProgress: boolean = false; requestInProgress = false;
modalSpinner: boolean = false; modalSpinner = false;
modalErrorMessage: string; modalErrorMessage: string;
modalTitle: string = 'There was error while saving your workbasket'; modalTitle = 'There was error while saving your workbasket';
private workbasketSubscription: Subscription; private workbasketSubscription: Subscription;
private routeSubscription: Subscription; private routeSubscription: Subscription;
@ -52,7 +52,7 @@ export class WorkbasketInformationComponent implements OnInit {
workbasketUpdated => { workbasketUpdated => {
this.afterRequest(); this.afterRequest();
this.workbasket = workbasketUpdated; this.workbasket = workbasketUpdated;
this.workbasketClone = {...this.workbasket}; this.workbasketClone = { ...this.workbasket };
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Workbasket ${workbasketUpdated.key} was saved successfully`)) this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Workbasket ${workbasketUpdated.key} was saved successfully`))
}, },
error => { error => {
@ -67,13 +67,13 @@ export class WorkbasketInformationComponent implements OnInit {
this.workbasket = { ...this.workbasketClone }; this.workbasket = { ...this.workbasketClone };
} }
private beforeRequest(){ private beforeRequest() {
this.requestInProgress = true; this.requestInProgress = true;
this.modalSpinner = true; this.modalSpinner = true;
this.modalErrorMessage = undefined; this.modalErrorMessage = undefined;
} }
private afterRequest(){ private afterRequest() {
this.requestInProgress = false; this.requestInProgress = false;
this.workbasketService.triggerWorkBasketSaved(); this.workbasketService.triggerWorkBasketSaved();
@ -89,7 +89,7 @@ export class WorkbasketInformationComponent implements OnInit {
} }
private ngOnDestroy() { ngOnDestroy() {
if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); } if (this.workbasketSubscription) { this.workbasketSubscription.unsubscribe(); }
if (this.routeSubscription) { this.routeSubscription.unsubscribe(); } if (this.routeSubscription) { this.routeSubscription.unsubscribe(); }
} }

View File

@ -1,6 +1,6 @@
<div class="container-scrollable" > <div class="container-scrollable" >
<taskana-spinner [isRunning]="requestInProgress" class = "centered-horizontally"></taskana-spinner> <taskana-spinner [isRunning]="requestInProgress" class = "centered-horizontally"></taskana-spinner>
<app-no-access *ngIf="!requestInProgress && (!hasPermission || !workbasket && selectedId)" ></app-no-access> <taskana-no-access *ngIf="!requestInProgress && (!hasPermission || !workbasket && selectedId)" ></taskana-no-access>
<div id ="workbasket-details" *ngIf="workbasket && !requestInProgress"> <div id ="workbasket-details" *ngIf="workbasket && !requestInProgress">
<ul class="nav nav-tabs" role="tablist"> <ul class="nav nav-tabs" role="tablist">
<li *ngIf="showDetail" class="visible-xs visible-sm hidden"> <li *ngIf="showDetail" class="visible-xs visible-sm hidden">
@ -18,7 +18,7 @@
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="work-baskets"> <div role="tabpanel" class="tab-pane active" id="work-baskets">
<workbasket-information [workbasket]="workbasket"></workbasket-information> <taskana-workbasket-information [workbasket]="workbasket"></taskana-workbasket-information>
</div> </div>
<div role="tabpanel" class="tab-pane inactive" id="access-items"> <div role="tabpanel" class="tab-pane inactive" id="access-items">
<taskana-workbasket-access-items [workbasket]="workbasket"></taskana-workbasket-access-items> <taskana-workbasket-access-items [workbasket]="workbasket"></taskana-workbasket-access-items>

View File

@ -49,13 +49,16 @@ describe('WorkbasketDetailsComponent', () => {
let debugElement; let debugElement;
let masterAndDetailService; let masterAndDetailService;
let workbasketService; let workbasketService;
let workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' })); const workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' }));
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [RouterTestingModule, FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule], imports: [RouterTestingModule, FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent, IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent, DistributionTargetsComponent, FilterComponent, DualListComponent, SelectWorkBasketPipe], declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent,
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
DistributionTargetsComponent, FilterComponent, DualListComponent, SelectWorkBasketPipe],
providers: [WorkbasketService, MasterAndDetailService, PermissionService, AlertService] providers: [WorkbasketService, MasterAndDetailService, PermissionService, AlertService]
}) })
.compileComponents(); .compileComponents();
@ -72,12 +75,22 @@ describe('WorkbasketDetailsComponent', () => {
spyOn(workbasketService, 'getSelectedWorkBasket').and.callFake(() => { return Observable.of('id1') }) spyOn(workbasketService, 'getSelectedWorkBasket').and.callFake(() => { return Observable.of('id1') })
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => { spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => {
return Observable.of(new WorkbasketSummaryResource( return Observable.of(new WorkbasketSummaryResource(
{ 'workbaskets': new Array<WorkbasketSummary>(new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '', new Links({ 'href': 'someurl' }))) }, new Links({ 'href': 'someurl' }))) {
'workbaskets': new Array<WorkbasketSummary>(
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '',
new Links({ 'href': 'someurl' })))
}, new Links({ 'href': 'someurl' })))
}) })
spyOn(workbasketService, 'getWorkBasket').and.callFake(() => { return Observable.of(workbasket) }) spyOn(workbasketService, 'getWorkBasket').and.callFake(() => { return Observable.of(workbasket) })
spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => { return Observable.of(new WorkbasketAccessItemsResource({ 'accessItems': new Array<WorkbasketAccessItems>() }, new Links({ 'href': 'url' }))) }) spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => {
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => { return Observable.of(new WorkbasketSummaryResource({ 'workbaskets': new Array<WorkbasketSummary>() }, new Links({ 'href': 'url' }))) }) return Observable.of(new WorkbasketAccessItemsResource(
{ 'accessItems': new Array<WorkbasketAccessItems>() }, new Links({ 'href': 'url' })))
})
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => {
return Observable.of(new WorkbasketSummaryResource(
{ 'workbaskets': new Array<WorkbasketSummary>() }, new Links({ 'href': 'url' })))
})
}); });
@ -89,20 +102,20 @@ describe('WorkbasketDetailsComponent', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should has created app-no-access if workbasket is not defined', () => { it('should has created taskana-no-access if workbasket is not defined', () => {
expect(component.workbasket).toBeUndefined(); expect(component.workbasket).toBeUndefined();
expect(debugElement.querySelector('app-no-access')).toBeTruthy; expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
}); });
it('should has created workbasket-details if workbasket is defined and app-no-access should dissapear', () => { it('should has created taskana-workbasket-details if workbasket is defined and taskana-no-access should dissapear', () => {
expect(component.workbasket).toBeUndefined(); expect(component.workbasket).toBeUndefined();
expect(debugElement.querySelector('app-no-access')).toBeTruthy; expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
component.workbasket = workbasket; component.workbasket = workbasket;
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.querySelector('app-no-access')).toBeFalsy; expect(debugElement.querySelector('taskana-no-access')).toBeFalsy();
expect(debugElement.querySelector('worbasket-details')).toBeTruthy; expect(debugElement.querySelector('taskana-workbasket-information')).toBeTruthy();
}); });

View File

@ -1,26 +1,26 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
import { Workbasket } from '../../model/workbasket'; import { Workbasket } from '../../model/workbasket';
import { WorkbasketService } from '../../services/workbasket.service' import { WorkbasketService } from '../../services/workbasket.service'
import { MasterAndDetailService } from '../../services/master-and-detail.service' import { MasterAndDetailService } from '../../services/master-and-detail.service'
import { ActivatedRoute, Params, Router, NavigationStart } from '@angular/router'; import { ActivatedRoute, Params, Router, NavigationStart } from '@angular/router';
import { PermissionService } from '../../services/permission.service'; import { PermissionService } from '../../services/permission.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs/Subscription';
import { WorkbasketSummary } from '../../model/workbasket-summary'; import { WorkbasketSummary } from '../../model/workbasket-summary';
import { WorkbasketSummaryResource } from '../../model/workbasket-summary-resource'; import { WorkbasketSummaryResource } from '../../model/workbasket-summary-resource';
@Component({ @Component({
selector: 'workbasket-details', selector: 'taskana-workbasket-details',
templateUrl: './workbasket-details.component.html', templateUrl: './workbasket-details.component.html',
styleUrls: ['./workbasket-details.component.scss'] styleUrls: ['./workbasket-details.component.scss']
}) })
export class WorkbasketDetailsComponent implements OnInit { export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
selectedId: number = -1;
workbasket: Workbasket; workbasket: Workbasket;
showDetail: boolean = false; selectedId = -1;
hasPermission: boolean = true; showDetail = false;
requestInProgress: boolean = false; hasPermission = true;
requestInProgress = false;
private workbasketSelectedSubscription: Subscription; private workbasketSelectedSubscription: Subscription;
private workbasketSubscription: Subscription; private workbasketSubscription: Subscription;
@ -44,7 +44,7 @@ export class WorkbasketDetailsComponent implements OnInit {
}); });
this.routeSubscription = this.route.params.subscribe(params => { this.routeSubscription = this.route.params.subscribe(params => {
let id = params['id']; const id = params['id'];
if (id && id !== '') { if (id && id !== '') {
this.selectedId = id; this.selectedId = id;
this.service.selectWorkBasket(id); this.service.selectWorkBasket(id);
@ -71,7 +71,7 @@ export class WorkbasketDetailsComponent implements OnInit {
private getWorkbasketInformation(workbasketIdSelected: string) { private getWorkbasketInformation(workbasketIdSelected: string) {
this.service.getWorkBasketsSummary().subscribe((workbasketSummary: WorkbasketSummaryResource) => { this.service.getWorkBasketsSummary().subscribe((workbasketSummary: WorkbasketSummaryResource) => {
let workbasketSummarySelected = this.getWorkbasketSummaryById(workbasketSummary._embedded.workbaskets, workbasketIdSelected); const workbasketSummarySelected = this.getWorkbasketSummaryById(workbasketSummary._embedded.workbaskets, workbasketIdSelected);
if (workbasketSummarySelected && workbasketSummarySelected._links) { if (workbasketSummarySelected && workbasketSummarySelected._links) {
this.workbasketSubscription = this.service.getWorkBasket(workbasketSummarySelected._links.self.href).subscribe(workbasket => { this.workbasketSubscription = this.service.getWorkBasket(workbasketSummarySelected._links.self.href).subscribe(workbasket => {
this.workbasket = workbasket; this.workbasket = workbasket;

View File

@ -20,7 +20,7 @@ import { Links } from '../../model/links';
@Component({ @Component({
selector: 'dummy-detail', selector: 'taskana-dummy-detail',
template: 'dummydetail' template: 'dummydetail'
}) })
export class DummyDetailComponent { export class DummyDetailComponent {
@ -37,8 +37,8 @@ export class FilterComponent {
const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource({ const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource({
'workbaskets': new Array<WorkbasketSummary>( 'workbaskets': new Array<WorkbasketSummary>(
new WorkbasketSummary("1", "key1", "NAME1", "description 1", "owner 1", "", "", "PERSONAL", "", "", "", ""), new WorkbasketSummary('1', 'key1', 'NAME1', 'description 1', 'owner 1', '', '', 'PERSONAL', '', '', '', ''),
new WorkbasketSummary("2", "key2", "NAME2", "description 2", "owner 2", "", "", "GROUP", "", "", "", "")) new WorkbasketSummary('2', 'key2', 'NAME2', 'description 2', 'owner 2', '', '', 'GROUP', '', '', '', ''))
}, new Links({ 'href': 'url' })); }, new Links({ 'href': 'url' }));
@ -55,7 +55,8 @@ describe('WorkbasketListComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [WorkbasketListComponent, DummyDetailComponent, SpinnerComponent, FilterComponent, RemoveNoneTypePipe, IconTypeComponent, SortComponent, MapValuesPipe], declarations: [WorkbasketListComponent, DummyDetailComponent, SpinnerComponent, FilterComponent,
RemoveNoneTypePipe, IconTypeComponent, SortComponent, MapValuesPipe],
imports: [ imports: [
AngularSvgIconModule, AngularSvgIconModule,
HttpModule, HttpModule,
@ -93,15 +94,16 @@ describe('WorkbasketListComponent', () => {
}) })
}); });
it('should have wb-action-toolbar, wb-search-bar, wb-list-container, wb-pagination, collapsedMenufilterWb and taskana-filter created in the html', () => { it('should have wb-action-toolbar, wb-search-bar, wb-list-container, wb-pagination,' +
expect(debugElement.querySelector('#wb-action-toolbar')).toBeDefined(); ' collapsedMenufilterWb and taskana-filter created in the html', () => {
expect(debugElement.querySelector('#wb-search-bar')).toBeDefined(); expect(debugElement.querySelector('#wb-action-toolbar')).toBeDefined();
expect(debugElement.querySelector('#wb-pagination')).toBeDefined(); expect(debugElement.querySelector('#wb-search-bar')).toBeDefined();
expect(debugElement.querySelector('#wb-list-container')).toBeDefined(); expect(debugElement.querySelector('#wb-pagination')).toBeDefined();
expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined(); expect(debugElement.querySelector('#wb-list-container')).toBeDefined();
expect(debugElement.querySelector('taskana-filter')).toBeDefined(); expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined();
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3); 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.', () => { it('should have two workbasketsummary rows created with the second one selected.', () => {
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3); expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3);
@ -110,8 +112,10 @@ describe('WorkbasketListComponent', () => {
}); });
it('should have two workbasketsummary rows created with two different icons: user and users', () => { it('should have two workbasketsummary rows created with two different icons: user and users', () => {
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')[1]
expect(debugElement.querySelectorAll('#wb-list-container > li')[2].querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/users.svg'); .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', () => { it('should have rendered sort by: name, id, description, owner and type', () => {
@ -124,10 +128,11 @@ describe('WorkbasketListComponent', () => {
}); });
it('should have performRequest with forced = true after performFilter is triggered', (() => { it('should have performRequest with forced = true after performFilter is triggered', (() => {
let type = 'PERSONAL', name = 'someName', description = 'someDescription', owner = 'someOwner', key = 'someKey'; const type = 'PERSONAL', name = 'someName', description = 'someDescription', owner = 'someOwner', key = 'someKey';
let filter = new FilterModel(type, name, description, owner, key); const filter = new FilterModel(type, name, description, owner, key);
component.performFilter(filter); component.performFilter(filter);
expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith(true, 'key', 'asc', undefined, name, description, undefined, owner, type, undefined, key); expect(workbasketService.getWorkBasketsSummary).toHaveBeenCalledWith(true, 'key', 'asc', undefined,
name, description, undefined, owner, type, undefined, key);
})); }));

View File

@ -1,4 +1,4 @@
import { Component, OnInit, EventEmitter } from '@angular/core'; import { Component, OnInit, EventEmitter, OnDestroy } from '@angular/core';
import { WorkbasketSummaryResource } from '../../model/workbasket-summary-resource'; import { WorkbasketSummaryResource } from '../../model/workbasket-summary-resource';
import { WorkbasketSummary } from '../../model/workbasket-summary'; import { WorkbasketSummary } from '../../model/workbasket-summary';
import { WorkbasketService } from '../../services/workbasket.service' import { WorkbasketService } from '../../services/workbasket.service'
@ -8,18 +8,16 @@ import { Direction, SortingModel } from '../../shared/sort/sort.component'
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
@Component({ @Component({
selector: 'workbasket-list', selector: 'taskana-workbasket-list',
outputs: ['selectedWorkbasket'],
templateUrl: './workbasket-list.component.html', templateUrl: './workbasket-list.component.html',
styleUrls: ['./workbasket-list.component.scss'] styleUrls: ['./workbasket-list.component.scss']
}) })
export class WorkbasketListComponent implements OnInit { export class WorkbasketListComponent implements OnInit, OnDestroy {
public selectedWorkbasket: EventEmitter<WorkbasketSummary> = new EventEmitter();
newWorkbasket: WorkbasketSummary; newWorkbasket: WorkbasketSummary;
selectedId: string = undefined; selectedId: string = undefined;
workbaskets: Array<WorkbasketSummary> = []; workbaskets: Array<WorkbasketSummary> = [];
requestInProgress: boolean = false; requestInProgress = false;
sort: SortingModel = new SortingModel(); sort: SortingModel = new SortingModel();
filterBy: FilterModel = new FilterModel(); filterBy: FilterModel = new FilterModel();
@ -33,7 +31,7 @@ export class WorkbasketListComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.requestInProgress = true; this.requestInProgress = true;
this.workBasketSummarySubscription = this.workbasketService.getWorkBasketsSummary().subscribe(resultList => { this.workBasketSummarySubscription = this.workbasketService.getWorkBasketsSummary().subscribe(resultList => {
this.workbaskets = resultList._embedded.workbaskets; this.workbaskets = resultList._embedded ? resultList._embedded.workbaskets : [];
this.requestInProgress = false; this.requestInProgress = false;
}); });
@ -48,11 +46,11 @@ export class WorkbasketListComponent implements OnInit {
selectWorkbasket(id: string) { selectWorkbasket(id: string) {
this.selectedId = id; this.selectedId = id;
if(!this.selectedId) { if (!this.selectedId) {
this.router.navigate(['/workbaskets']); this.router.navigate(['/workbaskets']);
return return
} }
this.router.navigate([{outlets: { detail: [this.selectedId] } }], { relativeTo: this.route }); this.router.navigate([{ outlets: { detail: [this.selectedId] } }], { relativeTo: this.route });
} }
@ -81,23 +79,24 @@ export class WorkbasketListComponent implements OnInit {
private performRequest(): void { private performRequest(): void {
this.requestInProgress = true; this.requestInProgress = true;
this.workbaskets = []; this.workbaskets = [];
this.workbasketServiceSubscription.add(this.workbasketService.getWorkBasketsSummary(true, this.sort.sortBy, this.sort.sortDirection, undefined, this.workbasketServiceSubscription.add(this.workbasketService.getWorkBasketsSummary(true, this.sort.sortBy,
this.sort.sortDirection, undefined,
this.filterBy.name, this.filterBy.description, undefined, this.filterBy.owner, this.filterBy.name, this.filterBy.description, undefined, this.filterBy.owner,
this.filterBy.type, undefined, this.filterBy.key).subscribe(resultList => { this.filterBy.type, undefined, this.filterBy.key).subscribe(resultList => {
this.workbaskets = resultList._embedded? resultList._embedded.workbaskets:[]; this.workbaskets = resultList._embedded ? resultList._embedded.workbaskets : [];
this.requestInProgress = false; this.requestInProgress = false;
this.unSelectWorkbasket(); this.unSelectWorkbasket();
})); }));
} }
private unSelectWorkbasket() : void{ private unSelectWorkbasket(): void {
if (!this.workbaskets.find( wb => wb.workbasketId === this.selectedId)){ if (!this.workbaskets.find(wb => wb.workbasketId === this.selectedId)) {
this.selectWorkbasket(undefined); this.selectWorkbasket(undefined);
} }
} }
private ngOnDestroy() { ngOnDestroy() {
this.workBasketSummarySubscription.unsubscribe(); this.workBasketSummarySubscription.unsubscribe();
this.workbasketServiceSubscription.unsubscribe(); this.workbasketServiceSubscription.unsubscribe();
this.workbasketServiceSavedSubscription.unsubscribe(); this.workbasketServiceSavedSubscription.unsubscribe();

View File

@ -8,38 +8,40 @@ import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
describe('NoAccessComponent', () => { describe('NoAccessComponent', () => {
let component: NoAccessComponent; let component: NoAccessComponent;
let fixture: ComponentFixture<NoAccessComponent>; let fixture: ComponentFixture<NoAccessComponent>;
let debugElement; let debugElement;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports:[RouterTestingModule, AngularSvgIconModule, HttpModule, HttpClientModule], imports: [RouterTestingModule, AngularSvgIconModule, HttpModule, HttpClientModule],
declarations: [ NoAccessComponent ] declarations: [NoAccessComponent]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(NoAccessComponent); fixture = TestBed.createComponent(NoAccessComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement; debugElement = fixture.debugElement.nativeElement;
}); });
afterEach(() =>{ afterEach(() => {
document.body.removeChild(debugElement); document.body.removeChild(debugElement);
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should have a back button with the following classes "btn btn-default back-button pull-left visible-xs visible-sm hidden blue"', () => { it('should have a back button with the following classes "btn btn-default back-button' +
expect(debugElement.querySelector('button').attributes.class.value).toBe('btn btn-default back-button pull-left visible-xs visible-sm hidden blue'); 'pull-left visible-xs visible-sm hidden blue"', () => {
}); expect(debugElement.querySelector('button').attributes.class.value)
.toBe('btn btn-default back-button pull-left visible-xs visible-sm hidden blue');
});
it('should have a div with title and svg', () => { it('should have a div with title and svg', () => {
expect(debugElement.querySelector('div.center-block.no-access > h3' ).textContent).toBeDefined(); expect(debugElement.querySelector('div.center-block.no-access > h3').textContent).toBeDefined();
expect(debugElement.querySelector('div.center-block.no-access > svg-icon' ).attributes.src.value).toBe('./assets/icons/noaccess.svg'); expect(debugElement.querySelector('div.center-block.no-access > svg-icon').attributes.src.value).toBe('./assets/icons/noaccess.svg');
}); });
}); });

View File

@ -1,9 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {Router, ActivatedRoute} from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
@Component({ @Component({
selector: 'app-no-access', selector: 'taskana-no-access',
templateUrl: './no-access.component.html', templateUrl: './no-access.component.html',
styleUrls: ['./no-access.component.scss'] styleUrls: ['./no-access.component.scss']
}) })

View File

@ -102,7 +102,7 @@
/* /*
*Remove bootstrap cols padding for master and detail component *Remove bootstrap cols padding for master and detail component
*/ */
.no-gutter > master-and-detail > [class*='col-'] { .no-gutter > taskana-master-and-detail > [class*='col-'] {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
} }
@ -229,7 +229,7 @@ li > div.row > dl {
margin-top: 4px; margin-top: 4px;
} }
workbasket-information, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets { taskana-workbasket-information, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets {
&> .panel{ &> .panel{
border: none; border: none;
box-shadow: none; box-shadow: none;

View File

@ -7,11 +7,11 @@
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="taskana.ico"> <link rel="icon" type="image/x-icon" href="./taskana.ico">
</head> </head>
<body> <body>
<app-root></app-root> <taskana-root></taskana-root>
</body> </body>

View File

@ -1,130 +1,126 @@
{ {
"rulesDirectory": [ "rulesDirectory": [
"node_modules/codelyzer" "node_modules/codelyzer"
], ],
"rules": { "rules": {
"callable-types": true, "callable-types": true,
"class-name": true, "class-name": true,
"comment-format": [ "comment-format": [
true, true,
"check-space" "check-space"
], ],
"curly": true, "curly": true,
"eofline": true, "eofline": true,
"forin": true, "forin": true,
"import-blacklist": [ "import-blacklist": [
true, true,
"rxjs" "rxjs"
], ],
"import-spacing": true, "import-spacing": true,
"indent": [ "indent": [
true, true,
"spaces" "tab"
], ],
"interface-over-type-literal": true, "interface-over-type-literal": true,
"label-position": true, "label-position": true,
"max-line-length": [ "max-line-length": [
true, true,
140 140
], ],
"member-access": false, "member-access": false,
"member-ordering": [ "member-ordering": [
true, true,
"static-before-instance", "static-before-instance",
"variables-before-functions" "variables-before-functions"
], ],
"no-arg": true, "no-arg": true,
"no-bitwise": true, "no-bitwise": true,
"no-console": [ "no-console": [
true, true,
"debug", "debug",
"info", "info",
"time", "time",
"timeEnd", "timeEnd",
"trace" "trace"
], ],
"no-construct": true, "no-construct": true,
"no-debugger": true, "no-debugger": true,
"no-empty": false, "no-empty": false,
"no-empty-interface": true, "no-empty-interface": true,
"no-eval": true, "no-eval": true,
"no-inferrable-types": [ "no-inferrable-types": [
true, true,
"ignore-params" "ignore-params"
], ],
"no-shadowed-variable": true, "no-shadowed-variable": true,
"no-string-literal": false, "no-string-literal": false,
"no-string-throw": true, "no-string-throw": true,
"no-switch-case-fall-through": true, "no-switch-case-fall-through": true,
"no-trailing-whitespace": true, "no-trailing-whitespace": true,
"no-unused-expression": true, "no-unused-expression": true,
"no-use-before-declare": true, "no-use-before-declare": true,
"no-var-keyword": true, "no-var-keyword": true,
"object-literal-sort-keys": false, "object-literal-sort-keys": false,
"one-line": [ "one-line": [
true, true,
"check-open-brace", "check-open-brace",
"check-catch", "check-catch",
"check-else", "check-else",
"check-whitespace" "check-whitespace"
], ],
"prefer-const": true, "prefer-const": true,
"quotemark": [ "quotemark": [
true, true,
"single" "single"
], ],
"radix": true, "radix": true,
"semicolon": [ "semicolon": [
"always" "always"
], ],
"triple-equals": [ "triple-equals": [
true, true,
"allow-null-check" "allow-null-check"
], ],
"typedef-whitespace": [ "typedef-whitespace": [
true, true,
{ {
"call-signature": "nospace", "call-signature": "nospace",
"index-signature": "nospace", "index-signature": "nospace",
"parameter": "nospace", "parameter": "nospace",
"property-declaration": "nospace", "property-declaration": "nospace",
"variable-declaration": "nospace" "variable-declaration": "nospace"
} }
], ],
"typeof-compare": true, "unified-signatures": true,
"unified-signatures": true, "variable-name": false,
"variable-name": false, "whitespace": [
"whitespace": [ true,
true, "check-branch",
"check-branch", "check-decl",
"check-decl", "check-operator",
"check-operator", "check-separator",
"check-separator", "check-type"
"check-type" ],
], "directive-selector": [
"directive-selector": [ true,
true, "attribute",
"attribute", "taskana",
"app", "camelCase"
"camelCase" ],
], "component-selector": [
"component-selector": [ true,
true, "element",
"element", "taskana",
"app", "kebab-case"
"kebab-case" ],
], "use-input-property-decorator": true,
"use-input-property-decorator": true, "use-output-property-decorator": true,
"use-output-property-decorator": true, "use-host-property-decorator": true,
"use-host-property-decorator": true, "no-input-rename": true,
"no-input-rename": true, "no-output-rename": true,
"no-output-rename": true, "use-life-cycle-interface": true,
"use-life-cycle-interface": true, "use-pipe-transform-interface": true,
"use-pipe-transform-interface": true, "component-class-suffix": true,
"component-class-suffix": true, "directive-class-suffix": true
"directive-class-suffix": true, }
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
}
} }