TSK-185 Add create, copy and delete workbasket item.
This commit is contained in:
parent
32449a4d52
commit
40c670991f
|
@ -7,7 +7,8 @@ import { MasterAndDetailComponent } from './shared/masterAndDetail/master-and-de
|
||||||
import { NoAccessComponent } from './workbasket/noAccess/no-access.component';
|
import { NoAccessComponent } from './workbasket/noAccess/no-access.component';
|
||||||
|
|
||||||
const appRoutes: Routes = [
|
const appRoutes: Routes = [
|
||||||
{ path: 'workbaskets',
|
{
|
||||||
|
path: 'workbaskets',
|
||||||
component: MasterAndDetailComponent,
|
component: MasterAndDetailComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
@ -27,7 +28,8 @@ const appRoutes: Routes = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ path: 'clasifications',
|
{
|
||||||
|
path: 'clasifications',
|
||||||
component: MasterAndDetailComponent,
|
component: MasterAndDetailComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,37 +1,51 @@
|
||||||
<nav class="navbar navbar-fixed-top">
|
<nav class="navbar navbar-fixed-top">
|
||||||
<div class="navbar show no-border-radius navbar-inverse no-gutter">
|
<div class="navbar show no-border-radius navbar-inverse no-gutter">
|
||||||
<div class="col-xs-3 col-md-4">
|
<div class="col-xs-3 col-md-4">
|
||||||
<svg-icon class="logo hidden visible-xs visible-sm" src="./assets/icons/logo.svg"></svg-icon>
|
<svg-icon class="logo hidden visible-xs visible-sm" src="./assets/icons/logo.svg"></svg-icon>
|
||||||
<ul class="nav logo">
|
<ul class="nav logo">
|
||||||
<svg-icon class="logo hidden-xs hidden-sm" src="./assets/icons/logo.svg"></svg-icon>
|
<svg-icon class="logo hidden-xs hidden-sm" src="./assets/icons/logo.svg"></svg-icon>
|
||||||
<p class="navbar-brand no-margin hidden-xs hidden-sm" > <a [href]="adminUrl">{{title}}</a></p>
|
<p class="navbar-brand no-margin hidden-xs hidden-sm">
|
||||||
</ul>
|
<a [href]="adminUrl">{{title}}</a>
|
||||||
</div>
|
</p>
|
||||||
<div class="col-xs-8 col-md-7 logo-container">
|
</ul>
|
||||||
<ul class="nav nav-tabs no-border-bottom" id="myTabs" role="tablist">
|
</div>
|
||||||
<li role="presentation" class="{{workbasketsRoute? 'active' : 'inactive'}}" role="tab" data-toggle="tab" ><a routerLink="/workbaskets" aria-controls="Work baskets" routerLinkActive="active">Workbaskets</a></li>
|
<div class="col-xs-8 col-md-7 logo-container">
|
||||||
<li role="presentation" class="{{workbasketsRoute? 'inactive' : 'active'}}" role="tab" data-toggle="tab" ><a routerLink="/clasifications" aria-controls="Clasifications" routerLinkActive="active">Clasifications</a></li>
|
<ul class="nav nav-tabs no-border-bottom" id="myTabs" role="tablist">
|
||||||
</ul>
|
<li role="presentation" class="{{workbasketsRoute? 'active' : 'inactive'}}" role="tab" data-toggle="tab">
|
||||||
</div>
|
<a routerLink="/workbaskets" aria-controls="Work baskets" routerLinkActive="active">Workbaskets</a>
|
||||||
<div class="col-xs-1">
|
</li>
|
||||||
<button type="button" class="navbar-toggle collapsed show" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
<li role="presentation" class="{{workbasketsRoute? 'inactive' : 'active'}}" role="tab" data-toggle="tab">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<a routerLink="/clasifications" aria-controls="Clasifications" routerLinkActive="active">Clasifications</a>
|
||||||
<span class="icon-bar"></span>
|
</li>
|
||||||
<span class="icon-bar"></span>
|
</ul>
|
||||||
<span class="icon-bar"></span>
|
</div>
|
||||||
</button>
|
<div class="col-xs-1">
|
||||||
</div>
|
<button type="button" class="navbar-toggle collapsed show" data-toggle="collapse" data-target="#navbar" aria-expanded="false"
|
||||||
</div>
|
aria-controls="navbar">
|
||||||
<div id="navbar" class="collapse pull-right navbar-inverse" data-html="false">
|
<span class="sr-only">Toggle navigation</span>
|
||||||
<ul class="nav navbar-nav navbar-right content-margin">
|
<span class="icon-bar"></span>
|
||||||
<li><a [href]="monitorUrl">Monitor</a></li>
|
<span class="icon-bar"></span>
|
||||||
<li><a [href]="workplaceUrl">Workplace</a></li>
|
<span class="icon-bar"></span>
|
||||||
</ul>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="navbar" class="collapse pull-right navbar-inverse" data-html="false">
|
||||||
|
<ul class="nav navbar-nav navbar-right content-margin">
|
||||||
|
<li>
|
||||||
|
<a [href]="monitorUrl">Monitor</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a [href]="workplaceUrl">Workplace</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container-fluid container-main">
|
<div class="container-fluid container-main">
|
||||||
<div class ="row ">
|
<div class="row ">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
<taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
|
||||||
|
<taskana-spinner [isRunning]="requestInProgress" isModal="true"></taskana-spinner>
|
||||||
|
<taskana-alert></taskana-alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -5,6 +5,12 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { Router, Routes } from '@angular/router';
|
import { Router, Routes } from '@angular/router';
|
||||||
|
import { GeneralMessageModalComponent } from './shared/general-message-modal/general-message-modal.component'
|
||||||
|
import { SpinnerComponent } from './shared/spinner/spinner.component'
|
||||||
|
import { ErrorModalService } from './services/error-modal.service';
|
||||||
|
import { RequestInProgressService } from './services/request-in-progress.service';
|
||||||
|
import { AlertComponent } from './shared/alert/alert.component';
|
||||||
|
import { AlertService } from './services/alert.service';
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
|
|
||||||
|
@ -17,13 +23,14 @@ describe('AppComponent', () => {
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent
|
AppComponent, GeneralMessageModalComponent, SpinnerComponent, AlertComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
RouterTestingModule.withRoutes(routes),
|
RouterTestingModule.withRoutes(routes),
|
||||||
HttpClientModule
|
HttpClientModule
|
||||||
]
|
],
|
||||||
|
providers: [ErrorModalService, RequestInProgressService, AlertService]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { Router, ActivatedRoute, NavigationStart } from '@angular/router';
|
import { Router, NavigationStart } from '@angular/router';
|
||||||
|
import { ErrorModalService } from './services/error-modal.service';
|
||||||
|
import { ErrorModel } from './model/modal-error';
|
||||||
|
import { RequestInProgressService } from './services/request-in-progress.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-root',
|
selector: 'taskana-root',
|
||||||
|
@ -15,7 +18,15 @@ export class AppComponent implements OnInit {
|
||||||
workplaceUrl: string = environment.taskanaWorkplaceUrl;
|
workplaceUrl: string = environment.taskanaWorkplaceUrl;
|
||||||
workbasketsRoute = true;
|
workbasketsRoute = true;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private router: Router) {
|
modalErrorMessage = '';
|
||||||
|
modalTitle = '';
|
||||||
|
|
||||||
|
requestInProgress = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private router: Router,
|
||||||
|
private errorModalService: ErrorModalService,
|
||||||
|
private requestInProgressService: RequestInProgressService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -26,5 +37,14 @@ export class AppComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.errorModalService.getError().subscribe((error: ErrorModel) => {
|
||||||
|
this.modalErrorMessage = error.message;
|
||||||
|
this.modalTitle = error.title;
|
||||||
|
})
|
||||||
|
|
||||||
|
this.requestInProgressService.getRequestInProgress().subscribe((value: boolean) => {
|
||||||
|
this.requestInProgress = value;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
*/
|
*/
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { WorkbasketListComponent } from './workbasket/list/workbasket-list.component';
|
import { WorkbasketListComponent } from './workbasket/list/workbasket-list.component';
|
||||||
|
import { WorkbasketListToolbarComponent } from './workbasket/list/workbasket-list-toolbar/workbasket-list-toolbar.component'
|
||||||
import { WorkbasketDetailsComponent } from './workbasket/details/workbasket-details.component';
|
import { WorkbasketDetailsComponent } from './workbasket/details/workbasket-details.component';
|
||||||
import { WorkbasketInformationComponent } from './workbasket/details/information/workbasket-information.component';
|
import { WorkbasketInformationComponent } from './workbasket/details/information/workbasket-information.component';
|
||||||
import { DistributionTargetsComponent } from './workbasket/details/distribution-targets/distribution-targets.component';
|
import { DistributionTargetsComponent } from './workbasket/details/distribution-targets/distribution-targets.component';
|
||||||
|
@ -42,6 +43,11 @@ import { HttpClientInterceptor } from './services/http-client-interceptor.servic
|
||||||
import { PermissionService } from './services/permission.service';
|
import { PermissionService } from './services/permission.service';
|
||||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
import { AlertService } from './services/alert.service';
|
import { AlertService } from './services/alert.service';
|
||||||
|
import { ErrorModalService } from './services/error-modal.service';
|
||||||
|
import { RequestInProgressService } from './services/request-in-progress.service';
|
||||||
|
import { SavingWorkbasketService } from './services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipes
|
* Pipes
|
||||||
|
@ -66,6 +72,7 @@ const MODULES = [
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
WorkbasketListComponent,
|
WorkbasketListComponent,
|
||||||
|
WorkbasketListToolbarComponent,
|
||||||
AccessItemsComponent,
|
AccessItemsComponent,
|
||||||
WorkbasketDetailsComponent,
|
WorkbasketDetailsComponent,
|
||||||
MasterAndDetailComponent,
|
MasterAndDetailComponent,
|
||||||
|
@ -96,7 +103,10 @@ const DECLARATIONS = [
|
||||||
useClass: HttpClientInterceptor,
|
useClass: HttpClientInterceptor,
|
||||||
multi: true
|
multi: true
|
||||||
},
|
},
|
||||||
AlertService
|
AlertService,
|
||||||
|
ErrorModalService,
|
||||||
|
RequestInProgressService,
|
||||||
|
SavingWorkbasketService
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
export enum ACTION {
|
||||||
|
CREATE = 'CREATE',
|
||||||
|
COPY = 'COPY'
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
export class Links {
|
export class Links {
|
||||||
constructor(
|
constructor(
|
||||||
public self: { 'href': string },
|
public self: { 'href': string } = undefined,
|
||||||
public distributionTargets: { 'href': string } = undefined,
|
public distributionTargets: { 'href': string } = undefined,
|
||||||
public accessItems: { 'href': string } = undefined
|
public accessItems: { 'href': string } = undefined
|
||||||
) { }
|
) { }
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export class ErrorModel {
|
||||||
|
constructor(
|
||||||
|
public title: string = undefined,
|
||||||
|
public message: string = undefined
|
||||||
|
) { }
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
export enum ICONTYPES {
|
||||||
|
NONE = '',
|
||||||
|
PERSONAL = 'PERSONAL',
|
||||||
|
GROUP = 'GROUP',
|
||||||
|
CLEARANCE = 'CLEARANCE',
|
||||||
|
TOPIC = 'TOPIC'
|
||||||
|
}
|
|
@ -1,19 +1,20 @@
|
||||||
import { Links } from './links';
|
import { Links } from './links';
|
||||||
|
import { ICONTYPES } from './type';
|
||||||
|
|
||||||
export class WorkbasketSummary {
|
export class WorkbasketSummary {
|
||||||
constructor(
|
constructor(
|
||||||
public workbasketId: string,
|
public workbasketId: string = undefined,
|
||||||
public key: string,
|
public key: string = undefined,
|
||||||
public name: string,
|
public name: string = undefined,
|
||||||
public description: string,
|
public description: string = undefined,
|
||||||
public owner: string,
|
public owner: string = undefined,
|
||||||
public modified: string,
|
public modified: string = undefined,
|
||||||
public domain: string,
|
public domain: string = undefined,
|
||||||
public type: string,
|
public type: string = ICONTYPES.PERSONAL,
|
||||||
public orgLevel1: string,
|
public orgLevel1: string = undefined,
|
||||||
public orgLevel2: string,
|
public orgLevel2: string = undefined,
|
||||||
public orgLevel3: string,
|
public orgLevel3: string = undefined,
|
||||||
public orgLevel4: string,
|
public orgLevel4: string = undefined,
|
||||||
public _links: Links = undefined) {
|
public _links: Links = undefined) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Links } from './links';
|
import { Links } from './links';
|
||||||
|
import { ICONTYPES } from './type';
|
||||||
export class Workbasket {
|
export class Workbasket {
|
||||||
|
|
||||||
public static equals(org: Workbasket, comp: Workbasket): boolean {
|
public static equals(org: Workbasket, comp: Workbasket): boolean {
|
||||||
|
@ -28,7 +29,7 @@ export class Workbasket {
|
||||||
public created: string = undefined,
|
public created: string = undefined,
|
||||||
public key: string = undefined,
|
public key: string = undefined,
|
||||||
public domain: string = undefined,
|
public domain: string = undefined,
|
||||||
public type: string = undefined,
|
public type: ICONTYPES = ICONTYPES.PERSONAL,
|
||||||
public modified: string = undefined,
|
public modified: string = undefined,
|
||||||
public name: string = undefined,
|
public name: string = undefined,
|
||||||
public description: string = undefined,
|
public description: string = undefined,
|
||||||
|
@ -41,6 +42,6 @@ export class Workbasket {
|
||||||
public orgLevel2: string = undefined,
|
public orgLevel2: string = undefined,
|
||||||
public orgLevel3: string = undefined,
|
public orgLevel3: string = undefined,
|
||||||
public orgLevel4: string = undefined,
|
public orgLevel4: string = undefined,
|
||||||
public _links: Links = undefined) {
|
public _links: Links = new Links()) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { ErrorModel } from '../model/modal-error';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ErrorModalService {
|
||||||
|
|
||||||
|
public errorTriggered = new Subject<ErrorModel>();
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
triggerError(error: ErrorModel) {
|
||||||
|
this.errorTriggered.next(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
getError(): Observable<ErrorModel> {
|
||||||
|
return this.errorTriggered.asObservable();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RequestInProgressService {
|
||||||
|
|
||||||
|
public requestInProgressTriggered = new Subject<boolean>();
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
setRequestInProgress(value: boolean) {
|
||||||
|
this.requestInProgressTriggered.next(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequestInProgress(): Observable<boolean> {
|
||||||
|
return this.requestInProgressTriggered.asObservable();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SavingWorkbasketService } from './saving-workbaskets.service';
|
||||||
|
|
||||||
|
describe('SavingWorkbasketsService', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [SavingWorkbasketService]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', inject([SavingWorkbasketService], (service: SavingWorkbasketService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
export class SavingInformation {
|
||||||
|
|
||||||
|
constructor(public url: string,
|
||||||
|
public workbasketId: string) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SavingWorkbasketService {
|
||||||
|
|
||||||
|
public distributionTargetsSavingInformation = new Subject<SavingInformation>();
|
||||||
|
public accessItemsSavingInformation = new Subject<SavingInformation>();
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
triggerDistributionTargetSaving(distributionTargetInformation: SavingInformation) {
|
||||||
|
this.distributionTargetsSavingInformation.next(distributionTargetInformation);
|
||||||
|
}
|
||||||
|
triggerAccessItemsSaving(accessItemsInformation: SavingInformation) {
|
||||||
|
this.accessItemsSavingInformation.next(accessItemsInformation);
|
||||||
|
}
|
||||||
|
triggeredDistributionTargetsSaving(): Observable<SavingInformation> {
|
||||||
|
return this.distributionTargetsSavingInformation.asObservable();
|
||||||
|
}
|
||||||
|
triggeredAccessItemsSaving(): Observable<SavingInformation> {
|
||||||
|
return this.accessItemsSavingInformation.asObservable();
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,7 +75,7 @@ export class WorkbasketService {
|
||||||
// POST
|
// POST
|
||||||
createWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
createWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.post<Workbasket>(url, this.httpOptions);
|
.post<Workbasket>(url, workbasket, this.httpOptions);
|
||||||
}
|
}
|
||||||
// PUT
|
// PUT
|
||||||
updateWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
updateWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
||||||
|
|
|
@ -4,4 +4,5 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
.list-group-search {
|
.list-group-search {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
margin-top: 12px;
|
|
||||||
border-top: 1px solid #ddd;
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.list-group-search {
|
||||||
|
border-top: none;
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
|
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
|
||||||
import { IconTypeComponent, ICONTYPES } from '../type-icon/icon-type.component'
|
import { IconTypeComponent } from '../type-icon/icon-type.component'
|
||||||
|
import { ICONTYPES } from '../../model/type';
|
||||||
|
|
||||||
export class FilterModel {
|
export class FilterModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<div class="no-gutter">
|
<div class="no-gutter">
|
||||||
<div class="{{showDetail? 'col-md-4 hidden-xs hidden-sm':'col-xs-12 col-md-4'}} vertical-right-divider" >
|
<div class="{{showDetail? 'col-md-4 hidden-xs hidden-sm':'col-xs-12 col-md-4'}} vertical-right-divider">
|
||||||
<router-outlet name="master"></router-outlet>
|
<router-outlet name="master"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<div class="{{showDetail? 'col-xs-12 col-md-8': 'hidden'}}" >
|
<div class="{{showDetail? 'col-xs-12 col-md-8': 'hidden'}}">
|
||||||
<router-outlet name="detail">
|
<router-outlet name="detail">
|
||||||
</router-outlet>
|
</router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<div class="{{showDetail? 'hidden': 'hidden-xs hidden-sm col-md-8 container-no-detail'}}">
|
<div class="{{showDetail? 'hidden': 'hidden-xs hidden-sm col-md-8 container-no-detail'}}">
|
||||||
<div class = "center-block no-detail" >
|
<div class="center-block no-detail">
|
||||||
<h3 class = "grey">Select a worbasket</h3>
|
<h3 class="grey">Select a worbasket</h3>
|
||||||
<svg-icon class="img-responsive no-detail-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
|
<svg-icon class="img-responsive no-detail-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
.container-no-detail{
|
.container-no-detail{
|
||||||
top:30vh;
|
top:30vh;
|
||||||
|
height: 65vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center-block.no-detail {
|
.center-block.no-detail {
|
||||||
|
|
|
@ -8,17 +8,18 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
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: 'taskana-dummy-master',
|
selector: 'taskana-dummy-master',
|
||||||
template: 'dummymaster'
|
template: 'dummymaster'
|
||||||
})
|
})
|
||||||
export class DummyMasterComponent {
|
export class DummyMasterComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-dummy-detail',
|
selector: 'taskana-dummy-detail',
|
||||||
template: 'dummydetail'
|
template: 'dummydetail'
|
||||||
})
|
})
|
||||||
export class DummyDetailComponent {
|
export class DummyDetailComponent {
|
||||||
|
|
||||||
|
@ -26,83 +27,86 @@ export class DummyDetailComponent {
|
||||||
|
|
||||||
describe('MasterAndDetailComponent ', () => {
|
describe('MasterAndDetailComponent ', () => {
|
||||||
|
|
||||||
let component, fixture, debugElement, location, router;
|
let component, fixture, debugElement, location, router;
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'workbaskets',
|
path: 'workbaskets',
|
||||||
component: MasterAndDetailComponent,
|
component: MasterAndDetailComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: DummyMasterComponent,
|
component: DummyMasterComponent,
|
||||||
outlet: 'master'
|
outlet: 'master'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
component: DummyDetailComponent,
|
component: DummyDetailComponent,
|
||||||
outlet: 'detail'
|
outlet: 'detail'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [MasterAndDetailComponent, DummyMasterComponent, DummyDetailComponent],
|
declarations: [
|
||||||
imports: [
|
MasterAndDetailComponent,
|
||||||
RouterTestingModule.withRoutes(routes),
|
DummyMasterComponent,
|
||||||
AngularSvgIconModule,
|
DummyDetailComponent],
|
||||||
HttpClientModule
|
imports: [
|
||||||
],
|
RouterTestingModule.withRoutes(routes),
|
||||||
providers: [MasterAndDetailService]
|
AngularSvgIconModule,
|
||||||
})
|
HttpClientModule
|
||||||
.compileComponents();
|
],
|
||||||
|
providers: [MasterAndDetailService]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(MasterAndDetailComponent);
|
fixture = TestBed.createComponent(MasterAndDetailComponent);
|
||||||
component = fixture.debugElement.componentInstance;
|
component = fixture.debugElement.componentInstance;
|
||||||
debugElement = fixture.debugElement.nativeElement;
|
debugElement = fixture.debugElement.nativeElement;
|
||||||
location = TestBed.get(Location);
|
location = TestBed.get(Location);
|
||||||
router = TestBed.get(Router);
|
router = TestBed.get(Router);
|
||||||
router.initialNavigation();
|
router.initialNavigation();
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
afterEach(async(() => {
|
afterEach(async(() => {
|
||||||
document.body.removeChild(debugElement);
|
document.body.removeChild(debugElement);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
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();
|
||||||
router.navigateByUrl('/workbaskets');
|
router.navigateByUrl('/workbaskets');
|
||||||
expect(component.showDetail).toBe(false);
|
expect(component.showDetail).toBe(false);
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
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();
|
||||||
router.navigateByUrl('/workbaskets/(detail:2)');
|
router.navigateByUrl('/workbaskets/(detail:2)');
|
||||||
expect(component.showDetail).toBe(true);
|
expect(component.showDetail).toBe(true);
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
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)');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(spy.calls.first().args[0]).toBe('/workbaskets/(detail:2)');
|
expect(spy.calls.first().args[0]).toBe('/workbaskets/(detail:2)');
|
||||||
component.backClicked();
|
component.backClicked();
|
||||||
expect(spy.calls.mostRecent().args.length).toBe(2);
|
expect(spy.calls.mostRecent().args.length).toBe(2);
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { ICONTYPES } from '../../model/type';
|
||||||
|
|
||||||
export enum ICONTYPES {
|
|
||||||
NONE = '',
|
|
||||||
PERSONAL = 'PERSONAL',
|
|
||||||
GROUP = 'GROUP',
|
|
||||||
CLEARANCE = 'CLEARANCE',
|
|
||||||
TOPIC = 'TOPIC'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-icon-type',
|
selector: 'taskana-icon-type',
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
<taskana-spinner [isRunning]="requestInProgress" [isModal]="modalSpinner" class="centered-horizontally floating"></taskana-spinner>
|
<taskana-spinner [isRunning]="requestInProgress" [isModal]="modalSpinner" class="centered-horizontally floating"></taskana-spinner>
|
||||||
<taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
|
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||||
<div *ngIf="workbasket && accessItems" id="wb-information" class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<button type="button" (click)="onSave()" [disabled]="!AccessItemsForm.form.valid" class="btn btn-default btn-primary">Save</button>
|
<button type="button" (click)="onSave()" [disabled]="!AccessItemsForm.form.valid || action === 'COPY'" class="btn btn-default btn-primary">Save</button>
|
||||||
<button type="button" (click)="clear()" class="btn btn-default">Undo changes</button>
|
<button type="button" (click)="clear()" class="btn btn-default">Undo changes</button>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="panel-header">{{workbasket.name}}</h4>
|
<h4 class="panel-header">{{workbasket.name}}
|
||||||
|
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form #AccessItemsForm="ngForm">
|
<form #AccessItemsForm="ngForm">
|
||||||
|
|
|
@ -13,6 +13,9 @@ import { Observable } from 'rxjs/Observable';
|
||||||
import { AccessItemsComponent } from './access-items.component';
|
import { AccessItemsComponent } from './access-items.component';
|
||||||
import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
|
import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
|
||||||
import { WorkbasketAccessItemsResource } from '../../../model/workbasket-access-items-resource';
|
import { WorkbasketAccessItemsResource } from '../../../model/workbasket-access-items-resource';
|
||||||
|
import { ICONTYPES } from '../../../model/type';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { SavingWorkbasketService, SavingInformation } from '../../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
|
||||||
describe('AccessItemsComponent', () => {
|
describe('AccessItemsComponent', () => {
|
||||||
let component: AccessItemsComponent;
|
let component: AccessItemsComponent;
|
||||||
|
@ -23,7 +26,7 @@ describe('AccessItemsComponent', () => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent],
|
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent],
|
||||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, ReactiveFormsModule],
|
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, ReactiveFormsModule],
|
||||||
providers: [WorkbasketService, AlertService]
|
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService]
|
||||||
|
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
@ -32,7 +35,7 @@ describe('AccessItemsComponent', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(AccessItemsComponent);
|
fixture = TestBed.createComponent(AccessItemsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
component.workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
component.workbasket = new Workbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||||
new Links(undefined, undefined, { 'href': 'someurl' }));
|
new Links(undefined, undefined, { 'href': 'someurl' }));
|
||||||
workbasketService = TestBed.get(WorkbasketService);
|
workbasketService = TestBed.get(WorkbasketService);
|
||||||
alertService = TestBed.get(AlertService);
|
alertService = TestBed.get(AlertService);
|
||||||
|
|
|
@ -7,6 +7,10 @@ import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
|
||||||
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 { WorkbasketAccessItemsResource } from '../../../model/workbasket-access-items-resource';
|
import { WorkbasketAccessItemsResource } from '../../../model/workbasket-access-items-resource';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { ErrorModel } from '../../../model/modal-error';
|
||||||
|
import { SavingWorkbasketService, SavingInformation } from '../../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
import { ACTION } from '../../../model/action';
|
||||||
|
|
||||||
declare var $: any;
|
declare var $: any;
|
||||||
|
|
||||||
|
@ -19,6 +23,9 @@ export class AccessItemsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
workbasket: Workbasket;
|
workbasket: Workbasket;
|
||||||
|
@Input()
|
||||||
|
action: string;
|
||||||
|
badgeMessage = '';
|
||||||
|
|
||||||
accessItemsResource: WorkbasketAccessItemsResource;
|
accessItemsResource: WorkbasketAccessItemsResource;
|
||||||
accessItems: Array<WorkbasketAccessItems>;
|
accessItems: Array<WorkbasketAccessItems>;
|
||||||
|
@ -29,11 +36,19 @@ export class AccessItemsComponent implements OnInit, OnDestroy {
|
||||||
modalTitle: string;
|
modalTitle: string;
|
||||||
modalErrorMessage: string;
|
modalErrorMessage: string;
|
||||||
accessItemsubscription: Subscription;
|
accessItemsubscription: Subscription;
|
||||||
|
savingAccessItemsSubscription: Subscription;
|
||||||
|
|
||||||
|
|
||||||
constructor(private workbasketService: WorkbasketService, private alertService: AlertService) { }
|
constructor(
|
||||||
|
private workbasketService: WorkbasketService,
|
||||||
|
private alertService: AlertService,
|
||||||
|
private errorModalService: ErrorModalService,
|
||||||
|
private savingWorkbaskets: SavingWorkbasketService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
if (!this.workbasket._links.accessItems) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href)
|
this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href)
|
||||||
.subscribe((accessItemsResource: WorkbasketAccessItemsResource) => {
|
.subscribe((accessItemsResource: WorkbasketAccessItemsResource) => {
|
||||||
this.accessItemsResource = accessItemsResource;
|
this.accessItemsResource = accessItemsResource;
|
||||||
|
@ -41,7 +56,17 @@ export class AccessItemsComponent implements OnInit, OnDestroy {
|
||||||
this.accessItemsClone = this.cloneAccessItems(this.accessItems);
|
this.accessItemsClone = this.cloneAccessItems(this.accessItems);
|
||||||
this.accessItemsResetClone = this.cloneAccessItems(this.accessItems);
|
this.accessItemsResetClone = this.cloneAccessItems(this.accessItems);
|
||||||
})
|
})
|
||||||
|
this.savingAccessItemsSubscription = this.savingWorkbaskets.triggeredAccessItemsSaving()
|
||||||
|
.subscribe((savingInformation: SavingInformation) => {
|
||||||
|
if (this.action === ACTION.COPY) {
|
||||||
|
this.accessItemsResource._links.self.href = savingInformation.url;
|
||||||
|
this.setWorkbasketIdForCopy(savingInformation.workbasketId);
|
||||||
|
this.onSave();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (this.action === ACTION.COPY) {
|
||||||
|
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addAccessItem() {
|
addAccessItem() {
|
||||||
|
@ -70,12 +95,11 @@ export class AccessItemsComponent implements OnInit, OnDestroy {
|
||||||
AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`));
|
AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`));
|
||||||
this.requestInProgress = false;
|
this.requestInProgress = false;
|
||||||
return true;
|
return true;
|
||||||
},
|
}, error => {
|
||||||
error => {
|
this.errorModalService.triggerError(new ErrorModel(`There was error while saving your workbasket's access items`, error))
|
||||||
this.modalErrorMessage = error.message;
|
this.requestInProgress = false;
|
||||||
this.requestInProgress = false;
|
return false;
|
||||||
return false;
|
})
|
||||||
})
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +110,15 @@ export class AccessItemsComponent implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
return accessItemClone;
|
return accessItemClone;
|
||||||
}
|
}
|
||||||
|
private setWorkbasketIdForCopy(workbasketId: string) {
|
||||||
|
this.accessItems.forEach(element => {
|
||||||
|
element.accessItemId = undefined;
|
||||||
|
element.workbasketId = workbasketId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.accessItemsubscription) { this.accessItemsubscription.unsubscribe(); }
|
if (this.accessItemsubscription) { this.accessItemsubscription.unsubscribe(); }
|
||||||
|
if (this.savingAccessItemsSubscription) { this.savingAccessItemsSubscription.unsubscribe(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
<taskana-spinner [isRunning]="requestInProgress" isModal="true" (requestTimeoutExceeded)="requestTimeoutExceeded($event)"
|
<taskana-spinner [isRunning]="requestInProgress" isModal="true" (requestTimeoutExceeded)="requestTimeoutExceeded($event)"
|
||||||
class="centered-horizontally floating"></taskana-spinner>
|
class="centered-horizontally floating"></taskana-spinner>
|
||||||
<taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
|
|
||||||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<button type="button" (click)="onSave()" class="btn btn-default btn-primary">Save</button>
|
<button type="button" (click)="onSave()" [disabled]="action === 'COPY'" class="btn btn-default btn-primary">Save</button>
|
||||||
<button type="button" (click)="onClear()" class="btn btn-default">Undo changes</button>
|
<button type="button" (click)="onClear()" class="btn btn-default">Undo changes</button>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="panel-header">{{workbasket.name}}</h4>
|
<h4 class="panel-header">{{workbasket.name}}
|
||||||
|
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<taskana-dual-list id="dual-list-Left" [(distributionTargets)]="distributionTargetsLeft" [distributionTargetsSelected]="distributionTargetsSelected"
|
<taskana-dual-list id="dual-list-Left" [(distributionTargets)]="distributionTargetsLeft" [distributionTargetsSelected]="distributionTargetsSelected"
|
||||||
|
|
|
@ -20,6 +20,9 @@ import { Workbasket } from '../../../model/workbasket';
|
||||||
import { WorkbasketDistributionTargetsResource } from '../../../model/workbasket-distribution-targets-resource';
|
import { WorkbasketDistributionTargetsResource } from '../../../model/workbasket-distribution-targets-resource';
|
||||||
import { FilterModel } from '../../../shared/filter/filter.component';
|
import { FilterModel } from '../../../shared/filter/filter.component';
|
||||||
import { DualListComponent } from './dual-list/dual-list.component';
|
import { DualListComponent } from './dual-list/dual-list.component';
|
||||||
|
import { ICONTYPES } from '../../../model/type';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { SavingWorkbasketService, SavingInformation } from '../../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
|
||||||
const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource({
|
const workbasketSummaryResource: WorkbasketSummaryResource = new WorkbasketSummaryResource({
|
||||||
'workbaskets': new Array<WorkbasketSummary>(
|
'workbaskets': new Array<WorkbasketSummary>(
|
||||||
|
@ -43,7 +46,7 @@ describe('DistributionTargetsComponent', () => {
|
||||||
let component: DistributionTargetsComponent;
|
let component: DistributionTargetsComponent;
|
||||||
let fixture: ComponentFixture<DistributionTargetsComponent>;
|
let fixture: ComponentFixture<DistributionTargetsComponent>;
|
||||||
let workbasketService;
|
let workbasketService;
|
||||||
const workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
const workbasket = new Workbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||||
new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' }));
|
new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' }));
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
@ -51,7 +54,7 @@ describe('DistributionTargetsComponent', () => {
|
||||||
imports: [AngularSvgIconModule, HttpClientModule, HttpModule, JsonpModule],
|
imports: [AngularSvgIconModule, HttpClientModule, HttpModule, JsonpModule],
|
||||||
declarations: [DistributionTargetsComponent, SpinnerComponent, GeneralMessageModalComponent,
|
declarations: [DistributionTargetsComponent, SpinnerComponent, GeneralMessageModalComponent,
|
||||||
FilterComponent, SelectWorkBasketPipe, IconTypeComponent, DualListComponent],
|
FilterComponent, SelectWorkBasketPipe, IconTypeComponent, DualListComponent],
|
||||||
providers: [WorkbasketService, AlertService]
|
providers: [WorkbasketService, AlertService, SavingWorkbasketService, ErrorModalService]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -12,6 +12,10 @@ 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';
|
||||||
|
import { SavingWorkbasketService, SavingInformation } from '../../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { ErrorModel } from '../../../model/modal-error';
|
||||||
|
import { ACTION } from '../../../model/action';
|
||||||
|
|
||||||
export enum Side {
|
export enum Side {
|
||||||
LEFT,
|
LEFT,
|
||||||
|
@ -26,10 +30,14 @@ export class DistributionTargetsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
workbasket: Workbasket;
|
workbasket: Workbasket;
|
||||||
|
@Input()
|
||||||
|
action: string;
|
||||||
|
badgeMessage = '';
|
||||||
|
|
||||||
distributionTargetsSubscription: Subscription;
|
distributionTargetsSubscription: Subscription;
|
||||||
workbasketSubscription: Subscription;
|
workbasketSubscription: Subscription;
|
||||||
workbasketFilterSubscription: Subscription;
|
workbasketFilterSubscription: Subscription;
|
||||||
|
savingDistributionTargetsSubscription: Subscription;
|
||||||
|
|
||||||
distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource;
|
distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource;
|
||||||
distributionTargetsLeft: Array<WorkbasketSummary>;
|
distributionTargetsLeft: Array<WorkbasketSummary>;
|
||||||
|
@ -45,10 +53,17 @@ export class DistributionTargetsComponent implements OnInit, OnDestroy {
|
||||||
modalErrorMessage: string;
|
modalErrorMessage: string;
|
||||||
side = Side;
|
side = Side;
|
||||||
|
|
||||||
constructor(private workbasketService: WorkbasketService, private alertService: AlertService) { }
|
constructor(
|
||||||
|
private workbasketService: WorkbasketService,
|
||||||
|
private alertService: AlertService,
|
||||||
|
private savingWorkbaskets: SavingWorkbasketService,
|
||||||
|
private errorModalService: ErrorModalService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.onRequest(undefined);
|
this.onRequest(undefined);
|
||||||
|
if (!this.workbasket._links.distributionTargets) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.distributionTargetsSubscription = this.workbasketService.getWorkBasketsDistributionTargets(
|
this.distributionTargetsSubscription = this.workbasketService.getWorkBasketsDistributionTargets(
|
||||||
this.workbasket._links.distributionTargets.href).subscribe(
|
this.workbasket._links.distributionTargets.href).subscribe(
|
||||||
(distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource) => {
|
(distributionTargetsSelectedResource: WorkbasketDistributionTargetsResource) => {
|
||||||
|
@ -64,6 +79,18 @@ export class DistributionTargetsComponent implements OnInit, OnDestroy {
|
||||||
this.onRequest(undefined, true);
|
this.onRequest(undefined, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.savingDistributionTargetsSubscription = this.savingWorkbaskets.triggeredDistributionTargetsSaving()
|
||||||
|
.subscribe((savingInformation: SavingInformation) => {
|
||||||
|
if (this.action === ACTION.COPY) {
|
||||||
|
this.distributionTargetsSelectedResource._links.self.href = savingInformation.url;
|
||||||
|
this.onSave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.action === ACTION.COPY) {
|
||||||
|
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveDistributionTargets(side: number) {
|
moveDistributionTargets(side: number) {
|
||||||
|
@ -92,7 +119,7 @@ export class DistributionTargetsComponent implements OnInit, OnDestroy {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
this.modalErrorMessage = error.message;
|
this.errorModalService.triggerError(new ErrorModel(`There was error while saving your workbasket's distribution targets`, error))
|
||||||
this.requestInProgress = false;
|
this.requestInProgress = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -161,6 +188,8 @@ export class DistributionTargetsComponent implements OnInit, OnDestroy {
|
||||||
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(); }
|
||||||
|
if (this.savingDistributionTargetsSubscription) { this.savingDistributionTargetsSubscription.unsubscribe(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
<taskana-spinner [isRunning]="requestInProgress" [isModal]="modalSpinner" class="centered-horizontally floating"></taskana-spinner>
|
<taskana-spinner [isRunning]="requestInProgress" [isModal]="modalSpinner" class="centered-horizontally floating"></taskana-spinner>
|
||||||
<taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
|
|
||||||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<button type="button" [disabled]="!WorkbasketForm.form.valid" (click)="onSave()" class="btn btn-default btn-primary">Save</button>
|
<button type="button" [disabled]="!WorkbasketForm.form.valid" (click)="onSave()" class="btn btn-default btn-primary">Save</button>
|
||||||
<button type="button" (click)="onClear()" class="btn btn-default">Undo changes</button>
|
<button type="button" (click)="onClear()" class="btn btn-default">Undo changes</button>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="panel-header">{{workbasket.name}}</h4>
|
<h4 class="panel-header">{{workbasket.name}}
|
||||||
|
<span *ngIf="!workbasket.workbasketId" class="badge warning"> {{badgeMessage}}</span>
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form #WorkbasketForm="ngForm">
|
<form #WorkbasketForm="ngForm">
|
||||||
|
@ -24,7 +25,7 @@
|
||||||
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name" [(ngModel)]="workbasket.name"
|
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name" [(ngModel)]="workbasket.name"
|
||||||
name="workbasket.name">
|
name="workbasket.name">
|
||||||
<div [hidden]="name.valid" class="required-text">
|
<div [hidden]="name.valid" class="required-text">
|
||||||
* Name is required
|
* Name is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
|
@ -32,7 +33,15 @@
|
||||||
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
|
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
|
||||||
name="workbasket.owner">
|
name="workbasket.owner">
|
||||||
<div [hidden]="owner.valid" class="required-text">
|
<div [hidden]="owner.valid" class="required-text">
|
||||||
* Owner is required
|
* Owner is required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group required">
|
||||||
|
<label for="wb-domain" class="control-label">Domain</label>
|
||||||
|
<input type="text" required #domain="ngModel" class="form-control" id="wb-domain" placeholder="Domain" [(ngModel)]="workbasket.domain"
|
||||||
|
name="workbasket.domain">
|
||||||
|
<div [hidden]="domain.valid" class="required-text">
|
||||||
|
* Domain is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -43,7 +52,7 @@
|
||||||
{{allTypes.get(workbasket.type)}}
|
{{allTypes.get(workbasket.type)}}
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu1">
|
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
|
||||||
<li>
|
<li>
|
||||||
<a *ngFor="let type of allTypes | mapValues | removeEmptyType" (click)="selectType(type.key)">
|
<a *ngFor="let type of allTypes | mapValues | removeEmptyType" (click)="selectType(type.key)">
|
||||||
<taskana-icon-type class="vertical-align" [type]='type.key'></taskana-icon-type>
|
<taskana-icon-type class="vertical-align" [type]='type.key'></taskana-icon-type>
|
||||||
|
@ -53,11 +62,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label for="wb-domain" class="control-label">Domain</label>
|
|
||||||
<input type="text" class="form-control" id="wb-domain" placeholder="Domain" [(ngModel)]="workbasket.domain" name="workbasket.domain"
|
|
||||||
disabled="">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="wb-description" class="control-label">Description</label>
|
<label for="wb-description" class="control-label">Description</label>
|
||||||
<textarea class="form-control" rows="5" id="wb-description" placeholder="Description" [(ngModel)]="workbasket.description"
|
<textarea class="form-control" rows="5" id="wb-description" placeholder="Description" [(ngModel)]="workbasket.description"
|
||||||
|
@ -100,4 +104,4 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,3 +1,3 @@
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { HttpModule, JsonpModule } from '@angular/http';
|
import { HttpModule, JsonpModule } from '@angular/http';
|
||||||
import { Workbasket } from 'app/model/workbasket';
|
import { Workbasket } from 'app/model/workbasket';
|
||||||
import { ICONTYPES, IconTypeComponent } from '../../../shared/type-icon/icon-type.component';
|
import { IconTypeComponent } from '../../../shared/type-icon/icon-type.component';
|
||||||
import { SpinnerComponent } from '../../../shared/spinner/spinner.component';
|
import { SpinnerComponent } from '../../../shared/spinner/spinner.component';
|
||||||
import { GeneralMessageModalComponent } from '../../../shared/general-message-modal/general-message-modal.component';
|
import { GeneralMessageModalComponent } from '../../../shared/general-message-modal/general-message-modal.component';
|
||||||
import { MapValuesPipe } from '../../../pipes/map-values.pipe';
|
import { MapValuesPipe } from '../../../pipes/map-values.pipe';
|
||||||
|
@ -15,18 +15,22 @@ import { AlertService } from '../../../services/alert.service';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { Links } from '../../../model/links';
|
import { Links } from '../../../model/links';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { ICONTYPES } from '../../../model/type';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { SavingWorkbasketService, SavingInformation } from '../../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
import { ACTION } from '../../../model/action';
|
||||||
|
|
||||||
describe('InformationComponent', () => {
|
describe('InformationComponent', () => {
|
||||||
let component: WorkbasketInformationComponent;
|
let component: WorkbasketInformationComponent;
|
||||||
let fixture: ComponentFixture<WorkbasketInformationComponent>;
|
let fixture: ComponentFixture<WorkbasketInformationComponent>;
|
||||||
let debugElement, workbasketService;
|
let debugElement, workbasketService, alertService, savingWorkbasketService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
|
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
|
||||||
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent],
|
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent],
|
||||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, RouterTestingModule],
|
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, RouterTestingModule],
|
||||||
providers: [WorkbasketService, AlertService]
|
providers: [WorkbasketService, AlertService, SavingWorkbasketService, ErrorModalService]
|
||||||
|
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
@ -34,6 +38,9 @@ describe('InformationComponent', () => {
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
debugElement = fixture.debugElement.nativeElement;
|
debugElement = fixture.debugElement.nativeElement;
|
||||||
workbasketService = TestBed.get(WorkbasketService);
|
workbasketService = TestBed.get(WorkbasketService);
|
||||||
|
alertService = TestBed.get(AlertService);
|
||||||
|
savingWorkbasketService = TestBed.get(SavingWorkbasketService);
|
||||||
|
spyOn(alertService, 'triggerAlert');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -45,12 +52,12 @@ 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',
|
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
|
||||||
'modified', 'name', 'description', 'owner', 'custom1', 'custom2', 'custom3', 'custom4',
|
'modified', 'name', 'description', 'owner', 'custom1', 'custom2', 'custom3', 'custom4',
|
||||||
'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
|
'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.trim()).toBe('name');
|
||||||
expect(debugElement.querySelectorAll('#wb-information > .panel-body > form').length).toBe(1);
|
expect(debugElement.querySelectorAll('#wb-information > .panel-body > form').length).toBe(1);
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
expect(debugElement.querySelector('#wb-information > .panel-body > form > div > div > input ').value).toBe('keyModified');
|
expect(debugElement.querySelector('#wb-information > .panel-body > form > div > div > input ').value).toBe('keyModified');
|
||||||
|
@ -60,8 +67,6 @@ describe('InformationComponent', () => {
|
||||||
|
|
||||||
it('selectType should set workbasket.type to personal with 0 and group in other case', () => {
|
it('selectType should set workbasket.type to personal with 0 and group in other case', () => {
|
||||||
component.workbasket = new Workbasket('id1');
|
component.workbasket = new Workbasket('id1');
|
||||||
expect(component.workbasket.type).toEqual(undefined);
|
|
||||||
component.selectType(ICONTYPES.PERSONAL);
|
|
||||||
expect(component.workbasket.type).toEqual('PERSONAL');
|
expect(component.workbasket.type).toEqual('PERSONAL');
|
||||||
component.selectType(ICONTYPES.GROUP);
|
component.selectType(ICONTYPES.GROUP);
|
||||||
expect(component.workbasket.type).toEqual('GROUP');
|
expect(component.workbasket.type).toEqual('GROUP');
|
||||||
|
@ -70,7 +75,7 @@ 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',
|
component.workbasket = new Workbasket('id', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
|
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2', 'orgLevel3', 'orgLevel4', null);
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
@ -78,20 +83,19 @@ 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', ICONTYPES.TOPIC, '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.requestInProgress).toBeFalsy();
|
expect(component.requestInProgress).toBeFalsy();
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
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', ICONTYPES.TOPIC, '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));
|
||||||
|
@ -100,4 +104,43 @@ describe('InformationComponent', () => {
|
||||||
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
|
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should post a new workbasket when no workbasketId is defined and update workbasket', () => {
|
||||||
|
const workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||||
|
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||||
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
|
||||||
|
component.workbasket = workbasket
|
||||||
|
spyOn(workbasketService, 'createWorkbasket').and.returnValue(Observable.of(
|
||||||
|
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||||
|
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||||
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }))));
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
expect(alertService.triggerAlert).toHaveBeenCalled();
|
||||||
|
expect(component.workbasket.workbasketId).toBe('someNewId');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should post a new workbasket, new distribution targets and new access ' +
|
||||||
|
'items when no workbasketId is defined and action is copy', () => {
|
||||||
|
const workbasket = new Workbasket(undefined, 'created', 'keyModified', 'domain', ICONTYPES.TOPIC,
|
||||||
|
'modified', 'name', 'description', 'owner', 'custom1', 'custom2',
|
||||||
|
'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||||
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
|
||||||
|
component.workbasket = workbasket
|
||||||
|
component.action = ACTION.COPY;
|
||||||
|
|
||||||
|
spyOn(workbasketService, 'createWorkbasket').and.returnValue(Observable.of(
|
||||||
|
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||||
|
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||||
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }, { 'href': 'someUrl' }, { 'href': 'someUrl' }))));
|
||||||
|
|
||||||
|
spyOn(savingWorkbasketService, 'triggerDistributionTargetSaving');
|
||||||
|
spyOn(savingWorkbasketService, 'triggerAccessItemsSaving');
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
expect(alertService.triggerAlert).toHaveBeenCalled();
|
||||||
|
expect(component.workbasket.workbasketId).toBe('someNewId');
|
||||||
|
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
|
||||||
|
expect(savingWorkbasketService.triggerAccessItemsSaving).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
import { Component, OnInit, Input, Output, OnDestroy } 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 } from '../../../shared/type-icon/icon-type.component';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
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';
|
||||||
|
import { ICONTYPES } from '../../../model/type';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { ErrorModel } from '../../../model/modal-error';
|
||||||
|
import { DatePipe } from '@angular/common';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { ACTION } from '../../../model/action';
|
||||||
|
import { SavingWorkbasketService, SavingInformation } from '../../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
|
||||||
|
const dateFormat = 'yyyy-MM-ddTHH:mm:ss';
|
||||||
|
const dateLocale = 'en-US';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-workbasket-information',
|
selector: 'taskana-workbasket-information',
|
||||||
templateUrl: './workbasket-information.component.html',
|
templateUrl: './workbasket-information.component.html',
|
||||||
|
@ -16,12 +25,15 @@ export class WorkbasketInformationComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
workbasket: Workbasket;
|
workbasket: Workbasket;
|
||||||
workbasketClone: Workbasket;
|
workbasketClone: Workbasket;
|
||||||
|
@Input()
|
||||||
|
action: string;
|
||||||
|
|
||||||
allTypes: Map<string, string>;
|
allTypes: Map<string, string>;
|
||||||
requestInProgress = false;
|
requestInProgress = false;
|
||||||
modalSpinner = false;
|
modalSpinner = false;
|
||||||
modalErrorMessage: string;
|
hasChanges = false;
|
||||||
modalTitle = 'There was error while saving your workbasket';
|
badgeMessage = '';
|
||||||
|
|
||||||
|
|
||||||
private workbasketSubscription: Subscription;
|
private workbasketSubscription: Subscription;
|
||||||
private routeSubscription: Subscription;
|
private routeSubscription: Subscription;
|
||||||
|
@ -29,17 +41,20 @@ export class WorkbasketInformationComponent implements OnInit, OnDestroy {
|
||||||
constructor(private workbasketService: WorkbasketService,
|
constructor(private workbasketService: WorkbasketService,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router, ) {
|
private router: Router,
|
||||||
|
private errorModalService: ErrorModalService,
|
||||||
|
private savingWorkbasket: SavingWorkbasketService) {
|
||||||
this.allTypes = IconTypeComponent.allTypes;
|
this.allTypes = IconTypeComponent.allTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.workbasketClone = { ...this.workbasket };
|
this.workbasketClone = { ...this.workbasket };
|
||||||
this.routeSubscription = this.router.events.subscribe(event => {
|
if (this.action === ACTION.CREATE) {
|
||||||
if (event instanceof NavigationStart) {
|
this.badgeMessage = 'Creating new workbasket';
|
||||||
this.checkForChanges();
|
} else if (this.action === ACTION.COPY) {
|
||||||
}
|
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
|
||||||
});
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectType(type: ICONTYPES) {
|
selectType(type: ICONTYPES) {
|
||||||
|
@ -48,6 +63,11 @@ export class WorkbasketInformationComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
this.beforeRequest();
|
this.beforeRequest();
|
||||||
|
if (!this.workbasket.workbasketId) {
|
||||||
|
this.postNewWorkbasket();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
this.workbasketSubscription = (this.workbasketService.updateWorkbasket(this.workbasket._links.self.href, this.workbasket).subscribe(
|
this.workbasketSubscription = (this.workbasketService.updateWorkbasket(this.workbasket._links.self.href, this.workbasket).subscribe(
|
||||||
workbasketUpdated => {
|
workbasketUpdated => {
|
||||||
this.afterRequest();
|
this.afterRequest();
|
||||||
|
@ -57,7 +77,7 @@ export class WorkbasketInformationComponent implements OnInit, OnDestroy {
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
this.afterRequest();
|
this.afterRequest();
|
||||||
this.modalErrorMessage = error;
|
this.errorModalService.triggerError(new ErrorModel('There was error while saving your workbasket', error))
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -65,12 +85,12 @@ export class WorkbasketInformationComponent implements OnInit, OnDestroy {
|
||||||
onClear() {
|
onClear() {
|
||||||
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'))
|
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'))
|
||||||
this.workbasket = { ...this.workbasketClone };
|
this.workbasket = { ...this.workbasketClone };
|
||||||
|
this.hasChanges = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private beforeRequest() {
|
private beforeRequest() {
|
||||||
this.requestInProgress = true;
|
this.requestInProgress = true;
|
||||||
this.modalSpinner = true;
|
this.modalSpinner = true;
|
||||||
this.modalErrorMessage = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private afterRequest() {
|
private afterRequest() {
|
||||||
|
@ -79,13 +99,34 @@ export class WorkbasketInformationComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkForChanges() {
|
private postNewWorkbasket() {
|
||||||
if (!Workbasket.equals(this.workbasket, this.workbasketClone)) {
|
this.addDateToWorkbasket();
|
||||||
this.openDiscardChangesModal();
|
this.workbasketService.createWorkbasket(this.workbasket._links.self.href,
|
||||||
}
|
this.workbasket)
|
||||||
|
.subscribe((workbasketUpdated: Workbasket) => {
|
||||||
|
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Workbasket ${workbasketUpdated.key} was created successfully`))
|
||||||
|
this.workbasket = workbasketUpdated;
|
||||||
|
this.afterRequest();
|
||||||
|
this.workbasketService.triggerWorkBasketSaved();
|
||||||
|
this.workbasketService.selectWorkBasket(this.workbasket.workbasketId);
|
||||||
|
this.router.navigate(['../' + this.workbasket.workbasketId], { relativeTo: this.route });
|
||||||
|
if (this.action === ACTION.COPY) {
|
||||||
|
this.savingWorkbasket.triggerDistributionTargetSaving(
|
||||||
|
new SavingInformation(this.workbasket._links.distributionTargets.href, this.workbasket.workbasketId));
|
||||||
|
this.savingWorkbasket.triggerAccessItemsSaving(
|
||||||
|
new SavingInformation(this.workbasket._links.accessItems.href, this.workbasket.workbasketId));
|
||||||
|
}
|
||||||
|
}, error => {
|
||||||
|
this.errorModalService.triggerError(new ErrorModel('There was an error creating a workbasket', error.error.message))
|
||||||
|
this.requestInProgress = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private openDiscardChangesModal() {
|
private addDateToWorkbasket() {
|
||||||
|
const datePipe = new DatePipe(dateLocale);
|
||||||
|
const date = datePipe.transform(Date.now(), dateFormat) + 'Z';
|
||||||
|
this.workbasket.created = date;
|
||||||
|
this.workbasket.modified = date;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
<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>
|
||||||
<taskana-no-access *ngIf="!requestInProgress && (!hasPermission || !workbasket && selectedId)" ></taskana-no-access>
|
<taskana-no-access *ngIf="!requestInProgress && (!hasPermission && !workbasket || !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">
|
||||||
<a (click) = "backClicked()"><span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back</a>
|
<a (click)="backClicked()">
|
||||||
|
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="active">
|
<li role="presentation" class="active">
|
||||||
<a href="#work-baskets" aria-controls="work baskets" role="tab" data-toggle="tab" aria-expanded="true">Information</a>
|
<a href="#work-baskets" aria-controls="work baskets" role="tab" data-toggle="tab" aria-expanded="true">Information</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="">
|
<li role="presentation" [ngClass]="{'disabled': !workbasket._links?.accessItems}">
|
||||||
<a href="#access-items" aria-controls="Acccess" role="tab" data-toggle="tab" aria-expanded="true">Access</a>
|
<a href="#access-items" aria-controls="Acccess" role="tab" data-toggle="tab" aria-expanded="true">Access</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="">
|
<li role="presentation" [ngClass]="{'disabled': !workbasket._links?.distributionTargets}">
|
||||||
<a href="#distribution-targets" aria-controls="distribution targets" role="tab" data-toggle="tab" aria-expanded="true">Distribution targets</a>
|
<a href="#distribution-targets" aria-controls="distribution targets" role="tab" data-toggle="tab" aria-expanded="true">Distribution targets</a>
|
||||||
</li>
|
</li>
|
||||||
</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 fade in active" id="work-baskets">
|
||||||
<taskana-workbasket-information [workbasket]="workbasket"></taskana-workbasket-information>
|
<taskana-workbasket-information [workbasket]="workbasket" [action]="action"></taskana-workbasket-information>
|
||||||
</div>
|
|
||||||
<div role="tabpanel" class="tab-pane inactive" id="access-items">
|
|
||||||
<taskana-workbasket-access-items [workbasket]="workbasket"></taskana-workbasket-access-items>
|
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane inactive" id="distribution-targets">
|
<div role="tabpanel" class="tab-pane fade" id="access-items">
|
||||||
<taskana-workbaskets-distribution-targets [workbasket]="workbasket"></taskana-workbaskets-distribution-targets>
|
<taskana-workbasket-access-items [workbasket]="workbasket" [action]="action"></taskana-workbasket-access-items>
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane fade" id="distribution-targets">
|
||||||
|
<taskana-workbaskets-distribution-targets [workbasket]="workbasket" [action]="action"></taskana-workbaskets-distribution-targets>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<taskana-alert></taskana-alert>
|
</div>
|
||||||
</div>
|
|
|
@ -21,4 +21,11 @@
|
||||||
& > p{
|
& > p{
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
& > li.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li.disabled > a {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { DualListComponent } from './distribution-targets//dual-list/dual-list.c
|
||||||
import { Workbasket } from 'app/model/workbasket';
|
import { Workbasket } from 'app/model/workbasket';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { SpinnerComponent } from '../../shared/spinner/spinner.component';
|
import { SpinnerComponent } from '../../shared/spinner/spinner.component';
|
||||||
import { ICONTYPES, IconTypeComponent } from '../../shared/type-icon/icon-type.component';
|
import { IconTypeComponent } from '../../shared/type-icon/icon-type.component';
|
||||||
import { MapValuesPipe } from '../../pipes/map-values.pipe';
|
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';
|
||||||
|
@ -22,6 +22,8 @@ import { WorkbasketService } from '../../services/workbasket.service';
|
||||||
import { MasterAndDetailService } from '../../services/master-and-detail.service';
|
import { MasterAndDetailService } from '../../services/master-and-detail.service';
|
||||||
import { PermissionService } from '../../services/permission.service';
|
import { PermissionService } from '../../services/permission.service';
|
||||||
import { AlertService } from '../../services/alert.service';
|
import { AlertService } from '../../services/alert.service';
|
||||||
|
import { ErrorModalService } from '../../services/error-modal.service';
|
||||||
|
import { SavingWorkbasketService } from '../../services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
@ -31,101 +33,116 @@ import { HttpModule } from '@angular/http';
|
||||||
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';
|
||||||
import { WorkbasketAccessItemsResource } from '../../model/workbasket-access-items-resource';
|
import { WorkbasketAccessItemsResource } from '../../model/workbasket-access-items-resource';
|
||||||
|
import { ICONTYPES } from '../../model/type';
|
||||||
|
import { Router, Routes } from '@angular/router';
|
||||||
|
import { ACTION } from '../../model/action';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-filter',
|
selector: 'taskana-filter',
|
||||||
template: ''
|
template: ''
|
||||||
})
|
})
|
||||||
export class FilterComponent {
|
export class FilterComponent {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
target: string;
|
target: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-dummy-detail',
|
||||||
|
template: 'dummydetail'
|
||||||
|
})
|
||||||
|
export class DummyDetailComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
describe('WorkbasketDetailsComponent', () => {
|
describe('WorkbasketDetailsComponent', () => {
|
||||||
let component: WorkbasketDetailsComponent;
|
let component: WorkbasketDetailsComponent;
|
||||||
let fixture: ComponentFixture<WorkbasketDetailsComponent>;
|
let fixture: ComponentFixture<WorkbasketDetailsComponent>;
|
||||||
let debugElement;
|
let debugElement;
|
||||||
let masterAndDetailService;
|
let masterAndDetailService;
|
||||||
let workbasketService;
|
let workbasketService;
|
||||||
const workbasket = new Workbasket('1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
let router;
|
||||||
new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' }));
|
const workbasket = new Workbasket('1', '', '', '', ICONTYPES.TOPIC, '', '', '', '', '', '', '', '', '', '', '', '',
|
||||||
|
new Links({ 'href': 'someurl' }, { 'href': 'someurl' }, { 'href': 'someurl' }));
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' }
|
||||||
|
];
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [RouterTestingModule, FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
imports: [RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
||||||
declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent,
|
declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent,
|
||||||
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
||||||
DistributionTargetsComponent, FilterComponent, DualListComponent, SelectWorkBasketPipe],
|
DistributionTargetsComponent, FilterComponent, DualListComponent, DummyDetailComponent, SelectWorkBasketPipe],
|
||||||
providers: [WorkbasketService, MasterAndDetailService, PermissionService, AlertService]
|
providers: [WorkbasketService, MasterAndDetailService, PermissionService,
|
||||||
})
|
AlertService, ErrorModalService, SavingWorkbasketService]
|
||||||
.compileComponents();
|
})
|
||||||
}));
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(WorkbasketDetailsComponent);
|
fixture = TestBed.createComponent(WorkbasketDetailsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
debugElement = fixture.debugElement.nativeElement;
|
component.hasPermission = false;
|
||||||
fixture.detectChanges();
|
debugElement = fixture.debugElement.nativeElement;
|
||||||
masterAndDetailService = TestBed.get(MasterAndDetailService);
|
router = TestBed.get(Router)
|
||||||
workbasketService = TestBed.get(WorkbasketService);
|
fixture.detectChanges();
|
||||||
spyOn(masterAndDetailService, 'getShowDetail').and.callFake(() => { return Observable.of(true) })
|
masterAndDetailService = TestBed.get(MasterAndDetailService);
|
||||||
spyOn(workbasketService, 'getSelectedWorkBasket').and.callFake(() => { return Observable.of('id1') })
|
workbasketService = TestBed.get(WorkbasketService);
|
||||||
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => {
|
spyOn(masterAndDetailService, 'getShowDetail').and.callFake(() => { return Observable.of(true) })
|
||||||
return Observable.of(new WorkbasketSummaryResource(
|
spyOn(workbasketService, 'getSelectedWorkBasket').and.callFake(() => { return Observable.of('id1') })
|
||||||
{
|
spyOn(workbasketService, 'getWorkBasketsSummary').and.callFake(() => {
|
||||||
'workbaskets': new Array<WorkbasketSummary>(
|
return Observable.of(new WorkbasketSummaryResource(
|
||||||
new WorkbasketSummary('id1', '', '', '', '', '', '', '', '', '', '', '',
|
{
|
||||||
new Links({ 'href': 'someurl' })))
|
'workbaskets': new Array<WorkbasketSummary>(
|
||||||
}, new Links({ 'href': 'someurl' })))
|
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(() => {
|
spyOn(workbasketService, 'getWorkBasketAccessItems').and.callFake(() => {
|
||||||
return Observable.of(new WorkbasketAccessItemsResource(
|
return Observable.of(new WorkbasketAccessItemsResource(
|
||||||
{ 'accessItems': new Array<WorkbasketAccessItems>() }, new Links({ 'href': 'url' })))
|
{ 'accessItems': new Array<WorkbasketAccessItems>() }, new Links({ 'href': 'url' })))
|
||||||
})
|
})
|
||||||
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => {
|
spyOn(workbasketService, 'getWorkBasketsDistributionTargets').and.callFake(() => {
|
||||||
return Observable.of(new WorkbasketSummaryResource(
|
return Observable.of(new WorkbasketSummaryResource(
|
||||||
{ 'workbaskets': new Array<WorkbasketSummary>() }, new Links({ 'href': 'url' })))
|
{ 'workbaskets': new Array<WorkbasketSummary>() }, new Links({ 'href': 'url' })))
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
document.body.removeChild(debugElement);
|
document.body.removeChild(debugElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should has created taskana-no-access if workbasket is not defined', () => {
|
it('should has created taskana-no-access if workbasket is not defined and hasPermission is false', () => {
|
||||||
expect(component.workbasket).toBeUndefined();
|
expect(component.workbasket).toBeUndefined();
|
||||||
expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
|
component.hasPermission = false;
|
||||||
});
|
fixture.detectChanges();
|
||||||
|
expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should has created taskana-workbasket-details if workbasket is defined and taskana-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('taskana-no-access')).toBeTruthy();
|
component.hasPermission = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
|
||||||
|
|
||||||
component.workbasket = workbasket;
|
component.workbasket = workbasket;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(debugElement.querySelector('taskana-no-access')).toBeFalsy();
|
expect(debugElement.querySelector('taskana-no-access')).toBeFalsy();
|
||||||
expect(debugElement.querySelector('taskana-workbasket-information')).toBeTruthy();
|
expect(debugElement.querySelector('taskana-workbasket-information')).toBeTruthy();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show back button with classes "visible-xs visible-sm hidden" when showDetail property is true', () => {
|
|
||||||
|
|
||||||
component.workbasket = workbasket;
|
|
||||||
component.ngOnInit();
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(debugElement.querySelector('.visible-xs.visible-sm.hidden > a').textContent).toBe('Back');
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,10 @@ import { PermissionService } from '../../services/permission.service';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
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';
|
||||||
|
import { ICONTYPES } from '../../model/type';
|
||||||
|
import { ErrorModel } from '../../model/modal-error';
|
||||||
|
import { ErrorModalService } from '../../services/error-modal.service';
|
||||||
|
import { ACTION } from '../../model/action';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-workbasket-details',
|
selector: 'taskana-workbasket-details',
|
||||||
|
@ -17,10 +21,12 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
|
||||||
workbasket: Workbasket;
|
workbasket: Workbasket;
|
||||||
selectedId = -1;
|
workbasketCopy: Workbasket;
|
||||||
|
selectedId: string = undefined;
|
||||||
showDetail = false;
|
showDetail = false;
|
||||||
hasPermission = true;
|
hasPermission = true;
|
||||||
requestInProgress = false;
|
requestInProgress = false;
|
||||||
|
action: string;
|
||||||
|
|
||||||
private workbasketSelectedSubscription: Subscription;
|
private workbasketSelectedSubscription: Subscription;
|
||||||
private workbasketSubscription: Subscription;
|
private workbasketSubscription: Subscription;
|
||||||
|
@ -32,22 +38,37 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private masterAndDetailService: MasterAndDetailService,
|
private masterAndDetailService: MasterAndDetailService,
|
||||||
private permissionService: PermissionService) { }
|
private permissionService: PermissionService,
|
||||||
|
private errorModalService: ErrorModalService) { }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.workbasketSelectedSubscription = this.service.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
|
this.workbasketSelectedSubscription = this.service.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
|
||||||
this.workbasket = undefined;
|
this.workbasket = undefined;
|
||||||
this.requestInProgress = true;
|
|
||||||
this.getWorkbasketInformation(workbasketIdSelected);
|
this.getWorkbasketInformation(workbasketIdSelected);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.routeSubscription = this.route.params.subscribe(params => {
|
this.routeSubscription = this.route.params.subscribe(params => {
|
||||||
const id = params['id'];
|
let id = params['id'];
|
||||||
|
this.action = undefined;
|
||||||
|
if (id && id.indexOf('new-workbasket') !== -1) {
|
||||||
|
this.action = ACTION.CREATE;
|
||||||
|
id = undefined;
|
||||||
|
this.getWorkbasketInformation(id);
|
||||||
|
} else if (id && id.indexOf('copy-workbasket') !== -1) {
|
||||||
|
if (!this.selectedId) {
|
||||||
|
this.router.navigate(['./'], { relativeTo: this.route.parent });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.action = ACTION.COPY;
|
||||||
|
this.workbasketCopy = this.workbasket;
|
||||||
|
id = undefined
|
||||||
|
this.getWorkbasketInformation(id, this.selectedId);
|
||||||
|
}
|
||||||
|
|
||||||
if (id && id !== '') {
|
if (id && id !== '') {
|
||||||
this.selectedId = id;
|
this.selectWorkbasket(id);
|
||||||
this.service.selectWorkBasket(id);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -69,8 +90,25 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
||||||
this.router.navigate(['./'], { relativeTo: this.route.parent });
|
this.router.navigate(['./'], { relativeTo: this.route.parent });
|
||||||
}
|
}
|
||||||
|
|
||||||
private getWorkbasketInformation(workbasketIdSelected: string) {
|
private selectWorkbasket(id: string) {
|
||||||
this.service.getWorkBasketsSummary().subscribe((workbasketSummary: WorkbasketSummaryResource) => {
|
this.selectedId = id;
|
||||||
|
this.service.selectWorkBasket(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWorkbasketInformation(workbasketIdSelected: string, copyId: string = undefined) {
|
||||||
|
this.requestInProgress = true;
|
||||||
|
this.service.getWorkBasketsSummary(true).subscribe((workbasketSummary: WorkbasketSummaryResource) => {
|
||||||
|
if (!workbasketIdSelected && this.action === ACTION.CREATE) { // CREATE
|
||||||
|
this.workbasket = new Workbasket(undefined);
|
||||||
|
this.workbasket._links.self = workbasketSummary._links.self;
|
||||||
|
this.requestInProgress = false;
|
||||||
|
} else if (!workbasketIdSelected && this.action === ACTION.COPY) { // COPY
|
||||||
|
this.workbasket = { ...this.workbasketCopy };
|
||||||
|
this.workbasket._links.self = workbasketSummary._links.self;
|
||||||
|
this.workbasket.workbasketId = undefined;
|
||||||
|
this.requestInProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
const 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 => {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<li id="wb-action-toolbar" class="list-group-item tab-align">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-9">
|
||||||
|
<button type="button" (click)="addWorkbasket()" data-toggle="tooltip" title="Add" class="btn btn-default">
|
||||||
|
<span class="glyphicon glyphicon-plus green" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<button type="button" data-toggle="tooltip" title="Edit" class="btn btn-default">
|
||||||
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="workbasketIdSelected" type="button" (click)="copyWorkbasket()" data-toggle="tooltip" title="copy" class="btn btn-default">
|
||||||
|
<span class="glyphicon glyphicon-copy" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="workbasketIdSelected" type="button" data-toggle="tooltip" title="Remove distibution target" class="btn btn-default">
|
||||||
|
<span class="glyphicon glyphicon-erase" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="workbasketIdSelected" type="button" (click)="removeWorkbasket()" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
|
||||||
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right margin-right">
|
||||||
|
<taskana-sort (performSorting)="sorting($event)"></taskana-sort>
|
||||||
|
<div class="clearfix btn-group">
|
||||||
|
<button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" data-toggle="collapse" data-target="#wb-filter-bar"
|
||||||
|
aria-expanded="false">
|
||||||
|
<span class="glyphicon glyphicon-filter blue"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<taskana-filter target="wb-filter-bar" (performFilter)="filtering($event)"></taskana-filter>
|
||||||
|
</div>
|
||||||
|
</li>
|
|
@ -0,0 +1,12 @@
|
||||||
|
.list-group-item {
|
||||||
|
padding: 0px 15px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-align{
|
||||||
|
margin-bottom: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
&>div{
|
||||||
|
margin: 6px 0px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
|
import { HttpModule } from '@angular/http';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { Router, Routes } from '@angular/router';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { WorkbasketService } from '../../../services/workbasket.service';
|
||||||
|
import { RequestInProgressService } from '../../../services/request-in-progress.service';
|
||||||
|
import { AlertService } from '../../../services/alert.service';
|
||||||
|
import { SortComponent, SortingModel } from '../../../shared/sort/sort.component';
|
||||||
|
import { FilterComponent, FilterModel } from '../../../shared/filter/filter.component';
|
||||||
|
import { IconTypeComponent } from '../../../shared/type-icon/icon-type.component';
|
||||||
|
import { MapValuesPipe } from '../../../pipes/map-values.pipe';
|
||||||
|
import { WorkbasketListToolbarComponent } from './workbasket-list-toolbar.component';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { WorkbasketSummary } from '../../../model/workbasket-summary';
|
||||||
|
import { Links } from '../../../model/links';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-dummy-detail',
|
||||||
|
template: 'dummydetail'
|
||||||
|
})
|
||||||
|
export class DummyDetailComponent {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WorkbasketListToolbarComponent', () => {
|
||||||
|
let component: WorkbasketListToolbarComponent;
|
||||||
|
let fixture: ComponentFixture<WorkbasketListToolbarComponent>;
|
||||||
|
let debugElement, workbasketService, requestInProgressService, router;
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' }
|
||||||
|
];
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, AngularSvgIconModule, HttpModule,
|
||||||
|
HttpClientModule, RouterTestingModule.withRoutes(routes)],
|
||||||
|
declarations: [WorkbasketListToolbarComponent, SortComponent,
|
||||||
|
FilterComponent, IconTypeComponent, DummyDetailComponent, MapValuesPipe],
|
||||||
|
providers: [ErrorModalService, WorkbasketService, RequestInProgressService, AlertService]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(WorkbasketListToolbarComponent);
|
||||||
|
workbasketService = TestBed.get(WorkbasketService);
|
||||||
|
requestInProgressService = TestBed.get(RequestInProgressService);
|
||||||
|
router = TestBed.get(Router);
|
||||||
|
spyOn(workbasketService, 'deleteWorkbasket').and.returnValue(Observable.of(''));
|
||||||
|
spyOn(workbasketService, 'triggerWorkBasketSaved');
|
||||||
|
spyOn(requestInProgressService, 'setRequestInProgress');
|
||||||
|
|
||||||
|
debugElement = fixture.debugElement.nativeElement;
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
component.workbaskets = new Array<WorkbasketSummary>(
|
||||||
|
new WorkbasketSummary('1', 'key1', 'NAME1', 'description 1', 'owner 1',
|
||||||
|
undefined, undefined, undefined, undefined, undefined, undefined, undefined, new Links({ 'href': 'selfLink' })));
|
||||||
|
component.workbasketIdSelected = '1';
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.removeChild(debugElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to new-workbasket when click on add new workbasket', () => {
|
||||||
|
const spy = spyOn(router, 'navigate');
|
||||||
|
component.addWorkbasket();
|
||||||
|
expect(spy.calls.first().args[0][0].outlets.detail[0]).toBe('new-workbasket');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should navigate to copy-workbasket when click on add copy workbasket', () => {
|
||||||
|
const spy = spyOn(router, 'navigate');
|
||||||
|
component.copyWorkbasket();
|
||||||
|
expect(spy.calls.first().args[0][0].outlets.detail[0]).toBe('copy-workbasket');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should call to workbasket service to remove workbasket after click on remove workbasket', () => {
|
||||||
|
const spy = spyOn(router, 'navigate');
|
||||||
|
component.removeWorkbasket();
|
||||||
|
expect(requestInProgressService.setRequestInProgress).toHaveBeenCalledWith(true);
|
||||||
|
expect(workbasketService.deleteWorkbasket).toHaveBeenCalledWith('selfLink');
|
||||||
|
expect(requestInProgressService.setRequestInProgress).toHaveBeenCalledWith(false);
|
||||||
|
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
|
||||||
|
expect(spy.calls.first().args[0][0]).toBe('/workbaskets');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit performSorting when sorting is triggered', () => {
|
||||||
|
let sort: SortingModel;
|
||||||
|
const compareSort = new SortingModel();
|
||||||
|
|
||||||
|
component.performSorting.subscribe((value) => { sort = value })
|
||||||
|
component.sorting(compareSort);
|
||||||
|
expect(sort).toBe(compareSort);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit performFilter when filter is triggered', () => {
|
||||||
|
let filter: FilterModel;
|
||||||
|
const compareFilter = new FilterModel();
|
||||||
|
|
||||||
|
component.performFilter.subscribe((value) => { filter = value })
|
||||||
|
component.filtering(compareFilter);
|
||||||
|
expect(filter).toBe(compareFilter);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { SortingModel } from '../../../shared/sort/sort.component';
|
||||||
|
import { FilterModel } from '../../../shared/filter/filter.component';
|
||||||
|
import { WorkbasketService } from '../../../services/workbasket.service';
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
import { WorkbasketSummary } from '../../../model/workbasket-summary';
|
||||||
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
import { ErrorModel } from '../../../model/modal-error';
|
||||||
|
import { ErrorModalService } from '../../../services/error-modal.service';
|
||||||
|
import { RequestInProgressService } from '../../../services/request-in-progress.service';
|
||||||
|
import { AlertService, AlertModel, AlertType } from '../../../services/alert.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-workbasket-list-toolbar',
|
||||||
|
templateUrl: './workbasket-list-toolbar.component.html',
|
||||||
|
styleUrls: ['./workbasket-list-toolbar.component.scss']
|
||||||
|
})
|
||||||
|
export class WorkbasketListToolbarComponent implements OnInit {
|
||||||
|
|
||||||
|
|
||||||
|
@Input() workbaskets: Array<WorkbasketSummary>;
|
||||||
|
@Input() workbasketIdSelected: string;
|
||||||
|
@Input() workbasketIdSelectedChanged: string;
|
||||||
|
@Output() performSorting = new EventEmitter<SortingModel>();
|
||||||
|
@Output() performFilter = new EventEmitter<FilterModel>();
|
||||||
|
workbasketServiceSubscription: Subscription;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private workbasketService: WorkbasketService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private errorModalService: ErrorModalService,
|
||||||
|
private requestInProgressService: RequestInProgressService,
|
||||||
|
private alertService: AlertService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
sorting(sort: SortingModel) {
|
||||||
|
this.performSorting.emit(sort);
|
||||||
|
}
|
||||||
|
|
||||||
|
filtering(filterBy: FilterModel) {
|
||||||
|
this.performFilter.emit(filterBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
addWorkbasket() {
|
||||||
|
this.router.navigate([{ outlets: { detail: ['new-workbasket'] } }], { relativeTo: this.route });
|
||||||
|
}
|
||||||
|
|
||||||
|
removeWorkbasket() {
|
||||||
|
this.requestInProgressService.setRequestInProgress(true);
|
||||||
|
this.workbasketService.deleteWorkbasket(this.findWorkbasketSelectedObject()._links.self.href).subscribe(response => {
|
||||||
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
|
this.workbasketService.triggerWorkBasketSaved();
|
||||||
|
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS,
|
||||||
|
`Workbasket ${this.workbasketIdSelected} was removed successfully`))
|
||||||
|
this.router.navigate(['/workbaskets']);
|
||||||
|
}, error => {
|
||||||
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
|
this.errorModalService.triggerError(new ErrorModel(
|
||||||
|
`There was an error deleting workbasket ${this.workbasketIdSelected}`, error.error.message))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
copyWorkbasket() {
|
||||||
|
this.router.navigate([{ outlets: { detail: ['copy-workbasket'] } }], { relativeTo: this.route });
|
||||||
|
}
|
||||||
|
|
||||||
|
private findWorkbasketSelectedObject() {
|
||||||
|
return this.workbaskets.find(element => element.workbasketId === this.workbasketIdSelected);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,40 +1,8 @@
|
||||||
<div class="workbasket-list-full-height">
|
<div class="workbasket-list-full-height">
|
||||||
<ul id="wb-list-container" class="list-group footer-space">
|
<ul id="wb-list-container" class="list-group footer-space">
|
||||||
<li id="wb-action-toolbar" class="list-group-item tab-align">
|
<taskana-workbasket-list-toolbar [workbaskets]="workbaskets" (performFilter)="performFilter($event)" (performSorting)="performSorting ($event)"
|
||||||
<div class="row">
|
[(workbasketIdSelected)]="selectedId"></taskana-workbasket-list-toolbar>
|
||||||
<div class="col-xs-9">
|
|
||||||
<button type="button" data-toggle="tooltip" title="Add" class="btn btn-default">
|
|
||||||
<span class="glyphicon glyphicon-plus green" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
<button type="button" data-toggle="tooltip" title="Edit" class="btn btn-default">
|
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
<button type="button" data-toggle="tooltip" title="copy" class="btn btn-default">
|
|
||||||
<span class="glyphicon glyphicon-copy" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
<button type="button" data-toggle="tooltip" title="Remove distibution target" class="btn btn-default">
|
|
||||||
<span class="glyphicon glyphicon-erase" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
<button type="button" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
|
|
||||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="pull-right margin-right">
|
|
||||||
<taskana-sort (performSorting)="performSorting($event)"></taskana-sort>
|
|
||||||
<div class="clearfix btn-group">
|
|
||||||
<button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" data-toggle="collapse" data-target="#wb-filter-bar"
|
|
||||||
aria-expanded="false">
|
|
||||||
<span class="glyphicon glyphicon-filter blue"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<taskana-filter target="wb-filter-bar" (performFilter)="performFilter($event)"></taskana-filter>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<taskana-spinner [isRunning]="requestInProgress" class="centered-horizontally"></taskana-spinner>
|
<taskana-spinner [isRunning]="requestInProgress" class="centered-horizontally"></taskana-spinner>
|
||||||
|
|
||||||
<li class="list-group-item" *ngFor="let workbasket of workbaskets" [class.active]="workbasket.workbasketId == selectedId"
|
<li class="list-group-item" *ngFor="let workbasket of workbaskets" [class.active]="workbasket.workbasketId == selectedId"
|
||||||
type="text" (click)="selectWorkbasket(workbasket.workbasketId)">
|
type="text" (click)="selectWorkbasket(workbasket.workbasketId)">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -44,8 +12,10 @@
|
||||||
</dt>
|
</dt>
|
||||||
</dl>
|
</dl>
|
||||||
<dl class="col-xs-10">
|
<dl class="col-xs-10">
|
||||||
<dt>{{workbasket.name}} ({{workbasket.key}}) </dt>
|
<dt>{{workbasket.name}},
|
||||||
<dd>{{workbasket.description}}</dd>
|
<i>{{workbasket.key}} </i>
|
||||||
|
</dt>
|
||||||
|
<dd>{{workbasket.description}} </dd>
|
||||||
<dd>{{workbasket.owner}} </dd>
|
<dd>{{workbasket.owner}} </dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,13 @@ a > label{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-align{
|
dt > i {
|
||||||
border-bottom: 1px solid #ddd;
|
font-weight: normal;
|
||||||
padding-bottom: 12px;
|
}
|
||||||
|
|
||||||
|
li > div.row > dl {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
li > div.row > dl:first-child {
|
||||||
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
|
||||||
import { WorkbasketListComponent } from './workbasket-list.component';
|
import { WorkbasketListComponent } from './workbasket-list.component';
|
||||||
|
import { WorkbasketListToolbarComponent } from './workbasket-list-toolbar/workbasket-list-toolbar.component';
|
||||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { WorkbasketSummary } from '../../model/workbasket-summary';
|
import { WorkbasketSummary } from '../../model/workbasket-summary';
|
||||||
|
@ -17,7 +18,9 @@ import { RemoveNoneTypePipe } from '../../pipes/remove-none-type';
|
||||||
import { MapValuesPipe } from '../../pipes/map-values.pipe';
|
import { MapValuesPipe } from '../../pipes/map-values.pipe';
|
||||||
import { WorkbasketSummaryResource } from '../../model/workbasket-summary-resource';
|
import { WorkbasketSummaryResource } from '../../model/workbasket-summary-resource';
|
||||||
import { Links } from '../../model/links';
|
import { Links } from '../../model/links';
|
||||||
|
import { ErrorModalService } from '../../services/error-modal.service';
|
||||||
|
import { RequestInProgressService } from '../../services/request-in-progress.service';
|
||||||
|
import { AlertService } from '../../services/alert.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-dummy-detail',
|
selector: 'taskana-dummy-detail',
|
||||||
|
@ -55,7 +58,7 @@ describe('WorkbasketListComponent', () => {
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [WorkbasketListComponent, DummyDetailComponent, SpinnerComponent, FilterComponent,
|
declarations: [WorkbasketListComponent, DummyDetailComponent, SpinnerComponent, FilterComponent, WorkbasketListToolbarComponent,
|
||||||
RemoveNoneTypePipe, IconTypeComponent, SortComponent, MapValuesPipe],
|
RemoveNoneTypePipe, IconTypeComponent, SortComponent, MapValuesPipe],
|
||||||
imports: [
|
imports: [
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
|
@ -63,7 +66,7 @@ describe('WorkbasketListComponent', () => {
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
RouterTestingModule.withRoutes(routes)
|
RouterTestingModule.withRoutes(routes)
|
||||||
],
|
],
|
||||||
providers: [WorkbasketService]
|
providers: [WorkbasketService, ErrorModalService, RequestInProgressService, AlertService]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
@ -102,19 +105,19 @@ describe('WorkbasketListComponent', () => {
|
||||||
expect(debugElement.querySelector('#wb-list-container')).toBeDefined();
|
expect(debugElement.querySelector('#wb-list-container')).toBeDefined();
|
||||||
expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined();
|
expect(debugElement.querySelector('#collapsedMenufilterWb')).toBeDefined();
|
||||||
expect(debugElement.querySelector('taskana-filter')).toBeDefined();
|
expect(debugElement.querySelector('taskana-filter')).toBeDefined();
|
||||||
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(3);
|
expect(debugElement.querySelectorAll('#wb-list-container > li').length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
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(2);
|
||||||
expect(debugElement.querySelectorAll('#wb-list-container > li')[1].getAttribute('class')).toBe('list-group-item');
|
expect(debugElement.querySelectorAll('#wb-list-container > li')[0].getAttribute('class')).toBe('list-group-item');
|
||||||
expect(debugElement.querySelectorAll('#wb-list-container > li')[2].getAttribute('class')).toBe('list-group-item active');
|
expect(debugElement.querySelectorAll('#wb-list-container > li')[1].getAttribute('class')).toBe('list-group-item active');
|
||||||
});
|
});
|
||||||
|
|
||||||
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]
|
expect(debugElement.querySelectorAll('#wb-list-container > li')[0]
|
||||||
.querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/user.svg');
|
.querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/user.svg');
|
||||||
expect(debugElement.querySelectorAll('#wb-list-container > li')[2]
|
expect(debugElement.querySelectorAll('#wb-list-container > li')[1]
|
||||||
.querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/users.svg');
|
.querySelector('svg-icon').getAttribute('ng-reflect-src')).toBe('./assets/icons/users.svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, OnInit, EventEmitter, OnDestroy } from '@angular/core';
|
import { Component, OnInit, EventEmitter, OnDestroy, ChangeDetectorRef } 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'
|
||||||
|
@ -14,8 +14,7 @@ import { Router, ActivatedRoute } from '@angular/router';
|
||||||
})
|
})
|
||||||
export class WorkbasketListComponent implements OnInit, OnDestroy {
|
export class WorkbasketListComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
newWorkbasket: WorkbasketSummary;
|
selectedId = '';
|
||||||
selectedId: string = undefined;
|
|
||||||
workbaskets: Array<WorkbasketSummary> = [];
|
workbaskets: Array<WorkbasketSummary> = [];
|
||||||
requestInProgress = false;
|
requestInProgress = false;
|
||||||
|
|
||||||
|
@ -26,7 +25,11 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
||||||
private workbasketServiceSubscription: Subscription;
|
private workbasketServiceSubscription: Subscription;
|
||||||
private workbasketServiceSavedSubscription: Subscription;
|
private workbasketServiceSavedSubscription: Subscription;
|
||||||
|
|
||||||
constructor(private workbasketService: WorkbasketService, private router: Router, private route: ActivatedRoute) { }
|
constructor(
|
||||||
|
private workbasketService: WorkbasketService,
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private cdRef: ChangeDetectorRef) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.requestInProgress = true;
|
this.requestInProgress = true;
|
||||||
|
@ -37,6 +40,7 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
this.workbasketServiceSubscription = this.workbasketService.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
|
this.workbasketServiceSubscription = this.workbasketService.getSelectedWorkBasket().subscribe(workbasketIdSelected => {
|
||||||
this.selectedId = workbasketIdSelected;
|
this.selectedId = workbasketIdSelected;
|
||||||
|
this.cdRef.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.workbasketServiceSavedSubscription = this.workbasketService.workbasketSavedTriggered().subscribe(value => {
|
this.workbasketServiceSavedSubscription = this.workbasketService.workbasketSavedTriggered().subscribe(value => {
|
||||||
|
@ -51,13 +55,11 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.router.navigate([{ outlets: { detail: [this.selectedId] } }], { relativeTo: this.route });
|
this.router.navigate([{ outlets: { detail: [this.selectedId] } }], { relativeTo: this.route });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
performSorting(sort: SortingModel) {
|
performSorting(sort: SortingModel) {
|
||||||
this.sort = sort;
|
this.sort = sort;
|
||||||
this.performRequest();
|
this.performRequest();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
performFilter(filterBy: FilterModel) {
|
performFilter(filterBy: FilterModel) {
|
||||||
|
@ -65,17 +67,6 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
||||||
this.performRequest();
|
this.performRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete(workbasket: WorkbasketSummary) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
onAdd() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
onClear() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private performRequest(): void {
|
private performRequest(): void {
|
||||||
this.requestInProgress = true;
|
this.requestInProgress = true;
|
||||||
this.workbaskets = [];
|
this.workbaskets = [];
|
||||||
|
|
|
@ -34,8 +34,7 @@
|
||||||
.container-scrollable {
|
.container-scrollable {
|
||||||
max-height: calc(100vh - 55px);
|
max-height: calc(100vh - 55px);
|
||||||
height: calc(100vh - 55px);
|
height: calc(100vh - 55px);
|
||||||
overflow-y: auto;
|
overflow: hidden;
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical-center {
|
.vertical-center {
|
||||||
|
@ -99,6 +98,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.panel-default > .panel-heading .badge.warning {
|
||||||
|
background-color: #f0ad4e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*Remove bootstrap cols padding for master and detail component
|
*Remove bootstrap cols padding for master and detail component
|
||||||
*/
|
*/
|
||||||
|
@ -131,10 +136,6 @@
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
li > div.row > dl {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
.selected {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
|
|
Loading…
Reference in New Issue