initial commit
This commit is contained in:
Lars Leo Grätz 2018-03-29 12:14:43 +02:00 committed by Martin Rojas Miguel Angel
parent 251257ac80
commit fa8bc9cb69
19 changed files with 276 additions and 212 deletions

View File

@ -1,13 +1,12 @@
import { Component, Input } from '@angular/core'; import {Component} from '@angular/core';
import { DataService } from './services/data.service'; import {DataService} from './services/data.service';
import { RestConnectorService } from './services/rest-connector.service'; import {environment} from '../environments/environment';
import { environment } from '../environments/environment';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'], styleUrls: ['./app.component.scss'],
providers: [ DataService, RestConnectorService ] providers: [DataService]
}) })
export class AppComponent { export class AppComponent {

View File

@ -1,22 +1,23 @@
import { BrowserModule } from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { FormsModule } from '@angular/forms'; import {FormsModule} from '@angular/forms';
import { HttpModule } from '@angular/http'; import {Ng2AutoCompleteModule} from 'ng2-auto-complete';
import { Ng2AutoCompleteModule } from 'ng2-auto-complete'; import {HttpClientModule} from '@angular/common/http';
import { HttpClientModule } from '@angular/common/http'; import {AngularSvgIconModule} from 'angular-svg-icon';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { AppComponent } from './app.component'; import {AppComponent} from './app.component';
import { AppRoutingModule } from './app-routing.module'; import {AppRoutingModule} from './app-routing.module';
import { AlertModule } from 'ngx-bootstrap'; import {AlertModule} from 'ngx-bootstrap';
import { SelectorComponent } from './workbasket-selector/workbasket-selector.component'; import {SelectorComponent} from './workbasket-selector/workbasket-selector.component';
import { TasklistComponent } from './tasklist/tasklist.component'; import {TasklistComponent} from './tasklist/tasklist.component';
import { TaskdetailsComponent } from './taskdetails/taskdetails.component'; import {TaskdetailsComponent} from './taskdetails/taskdetails.component';
import { OrderTasksByPipe } from './util/orderTasksBy.pipe'; import {OrderTasksByPipe} from './util/orderTasksBy.pipe';
import { TaskComponent } from './task/task.component'; import {TaskComponent} from './task/task.component';
import { TasksComponent } from './tasks/tasks.component'; import {TasksComponent} from './tasks/tasks.component';
import {TaskService} from './services/task.service';
import {WorkbasketService} from './services/workbasket.service';
@NgModule({ @NgModule({
@ -32,14 +33,18 @@ import { TasksComponent } from './tasks/tasks.component';
imports: [ imports: [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
HttpModule,
AlertModule.forRoot(), AlertModule.forRoot(),
Ng2AutoCompleteModule, Ng2AutoCompleteModule,
AppRoutingModule, AppRoutingModule,
HttpClientModule, HttpClientModule,
AngularSvgIconModule AngularSvgIconModule
], ],
providers: [HttpClientModule], providers: [
HttpClientModule,
TaskService,
WorkbasketService
],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule {
}

View File

@ -0,0 +1,15 @@
import {Links} from './links';
export class Classification {
constructor(public classificationId: string,
public key: string,
public category: string,
public type: string,
public domain: string,
public name: string,
public parentId: string,
public priority: number,
public serviceLevel: string,
public _links: Links = new Links()) {
}
}

View File

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

View File

@ -1,38 +1,26 @@
import {Classification} from './classification';
import {Workbasket} from './workbasket';
export class Task { export class Task {
constructor(public businessProcessId: string,
id: string; public parentBusinessProcessId: string,
created: any; public owner: string,
claimed: any; public taskId: string,
completed: any; public created: string, // ISO-8601
modified: any; public claimed: string, // ISO-8601
planned: any; public completed: string, // ISO-8601
due: any; public modified: string, // ISO-8601
name: string; public planned: string, // ISO-8601
description: string; public due: string, // ISO-8601
priority: number; public name: string,
state: string; public creator: string,
type: string; public description: string,
workbasket: string; public note: string,
owner: string; public state: any,
public isRead: boolean,
static create(data) { public isTransferred: boolean,
return new Task(data); public priority: number,
} public classificationSummaryResource: Classification,
public workbasketSummaryResource: Workbasket) {
constructor(data) {
this.id = data.id;
this.created = data.created;
this.claimed = data.claimed;
this.completed = data.completed;
this.modified = data.modified;
this.planned = data.planned;
this.due = data.due;
this.name = data.name;
this.description = data.description;
this.priority = data.priority;
this.state = data.state;
this.type = data.type;
this.workbasket = data.workbasket;
this.owner = data.owner;
} }
} }

View File

@ -1,8 +1,23 @@
import {Links} from './links';
export class Workbasket { export class Workbasket {
key: string;
created: string; constructor(public workbasketId: string,
modified: string; public created: string = undefined,
name: string; public key: string = undefined,
description: string; public domain: string = undefined,
owner: string; public modified: string = undefined,
public name: string = undefined,
public description: string = undefined,
public owner: string = undefined,
public custom1: string = undefined,
public custom2: string = undefined,
public custom3: string = undefined,
public custom4: string = undefined,
public orgLevel1: string = undefined,
public orgLevel2: string = undefined,
public orgLevel3: string = undefined,
public orgLevel4: string = undefined,
public _links: Links = new Links()) {
}
} }

View File

@ -1,15 +0,0 @@
import { TestBed, inject } from '@angular/core/testing';
import { RestConnectorService } from './rest-connector.service';
describe('RestConnectorService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [RestConnectorService]
});
});
it('should be created', inject([RestConnectorService], (service: RestConnectorService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -1,52 +0,0 @@
import { Injectable } from '@angular/core';
import { Headers, RequestOptions, Http, Response } from '@angular/http';
import { Workbasket } from '../model/workbasket';
import { Task } from '../model/task';
import { environment } from '../../environments/environment';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class RestConnectorService {
constructor(private http: Http) { }
getAllWorkBaskets(): Observable<Workbasket[]> {
return this.http.get(environment.taskanaRestUrl + '/v1/workbaskets?requiredPermission=OPEN', this.createAuthorizationHeader())
.map(res => res.json());
}
findTaskWithWorkbaskets(basketKey: string): Observable<Task[]> {
return this.http.get(environment.taskanaRestUrl + '/v1/tasks?workbasketkey='
+ basketKey + '&state=READY&state=CLAIMED', this.createAuthorizationHeader())
.map(res => res.json());
}
getTask(id: string): Observable<Task> {
return this.http.get(environment.taskanaRestUrl + '/v1/tasks/' + id, this.createAuthorizationHeader())
.map(res => res.json());
}
completeTask(id: string): Observable<Task> {
return this.http.post(environment.taskanaRestUrl + '/v1/tasks/' + id + '/complete', '', this.createAuthorizationHeader())
.map(res => res.json());
}
claimTask(id: string): Observable<Task> {
return this.http.post(environment.taskanaRestUrl + '/v1/tasks/' + id + '/claim', 'test', this.createAuthorizationHeader())
.map(res => res.json());
}
transferTask(taskId: string, workbasketKey: string) {
return this.http.post(environment.taskanaRestUrl + '/v1/tasks/' + taskId
+ '/transfer/' + workbasketKey, '', this.createAuthorizationHeader())
.map(res => res.json());
}
private createAuthorizationHeader() {
const headers: Headers = new Headers();
headers.append('Authorization', 'Basic dXNlcl8xXzE6dXNlcl8xXzE=');
return new RequestOptions({ headers: headers });
}
}

View File

@ -0,0 +1,42 @@
import {Task} from '../model/task';
import {Observable} from 'rxjs/Observable';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {environment} from '../../environments/environment';
@Injectable()
export class TaskService {
url = environment.taskanaRestUrl + '/v1/tasks';
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/hal+json',
'Authorization': 'Basic dXNlcl8xXzE6dXNlcl8xXzE',
'user': 'user_1_1'
})
};
constructor(private httpClient: HttpClient) {
}
findTaskWithWorkbaskets(basketKey: string): Observable<Task[]> {
return this.httpClient.get<Task[]>(this.url + '?workbasketId=' + basketKey, this.httpOptions);
}
getTask(id: string): Observable<Task> {
return this.httpClient.get<Task>(this.url + '/' + id, this.httpOptions);
}
completeTask(id: string): Observable<Task> {
return this.httpClient.post<Task>(this.url + '/' + id + '/complete', '', this.httpOptions);
}
claimTask(id: string): Observable<Task> {
return this.httpClient.post<Task>(this.url + '/' + id + '/claim', 'test', this.httpOptions);
}
transferTask(taskId: string, workbasketKey: string): Observable<Task> {
return this.httpClient.post<Task>(this.url + '/' + taskId
+ '/transfer/' + workbasketKey, '', this.httpOptions);
}
}

View File

@ -0,0 +1,25 @@
import {Injectable} from '@angular/core';
import {Workbasket} from '../model/workbasket';
import {environment} from '../../environments/environment';
import {Observable} from 'rxjs/Observable';
import {HttpClient, HttpHeaders} from '@angular/common/http';
@Injectable()
export class WorkbasketService {
url = environment.taskanaRestUrl + '/v1/workbaskets';
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/hal+json',
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
})
};
constructor(private httpClient: HttpClient) {
}
getAllWorkBaskets(): Observable<Workbasket[]> {
return this.httpClient.get<Workbasket[]>(this.url + '?required-permission=OPEN', this.httpOptions);
}
}

View File

@ -1,9 +1,10 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import { Task } from '../model/task'; import {Task} from '../model/task';
import { RestConnectorService } from '../services/rest-connector.service'; import {Workbasket} from '../model/workbasket';
import { Workbasket } from '../model/workbasket'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
import { SafeResourceUrl, DomSanitizer} from '@angular/platform-browser'; import {TaskService} from '../services/task.service';
import {WorkbasketService} from '../services/workbasket.service';
@Component({ @Component({
@ -15,27 +16,30 @@ export class TaskComponent implements OnInit {
task: Task = null; task: Task = null;
link: SafeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl('https://duckduckgo.com/?q='); link: SafeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl('https://duckduckgo.com/?q=');
autoCompleteData: string[] = new Array; autoCompleteData: string[] = [];
workbasket: string = null; workbasket: string = null;
workbasketKey: string; workbasketKey: string;
workbaskets: Workbasket[]; workbaskets: Workbasket[];
private sub: any; private sub: any;
constructor(private restConnectorService: RestConnectorService, constructor(private taskService: TaskService,
private route: ActivatedRoute, private router: Router, private workbasketService: WorkbasketService,
private sanitizer: DomSanitizer) { } private route: ActivatedRoute,
private router: Router,
private sanitizer: DomSanitizer) {
}
ngOnInit() { ngOnInit() {
const id = this.route.snapshot.params['id']; const id = this.route.snapshot.params['id'];
this.restConnectorService.getTask(id).subscribe( this.taskService.getTask(id).subscribe(
t => { t => {
this.task = t; this.task = t;
this.link = this.sanitizer.bypassSecurityTrustResourceUrl('https://duckduckgo.com/?q=' + this.task.name ); this.link = this.sanitizer.bypassSecurityTrustResourceUrl('https://duckduckgo.com/?q=' + this.task.name);
this.restConnectorService.getAllWorkBaskets().subscribe( w => { this.workbasketService.getAllWorkBaskets().subscribe(w => {
this.workbaskets = w; this.workbaskets = w['_embedded']['workbaskets'];
this.workbaskets.forEach(workbasket => { this.workbaskets.forEach(workbasket => {
if (workbasket.key !== this.task.workbasket) { if (workbasket.key !== this.task.workbasketSummaryResource.key) {
this.autoCompleteData.push(workbasket.name); this.autoCompleteData.push(workbasket.name);
} }
}); });
@ -50,8 +54,10 @@ export class TaskComponent implements OnInit {
this.workbasketKey = workbasket.key; this.workbasketKey = workbasket.key;
} }
}); });
this.restConnectorService.transferTask(this.task.id, this.workbasketKey).subscribe( this.taskService.transferTask(this.task.taskId, this.workbasketKey).subscribe(
task => {this.task = task}); task => {
this.task = task
});
this.router.navigate(['tasks/']); this.router.navigate(['tasks/']);
} }
} }
@ -61,8 +67,10 @@ export class TaskComponent implements OnInit {
} }
completeTask() { completeTask() {
this.restConnectorService.completeTask(this.task.id).subscribe( this.taskService.completeTask(this.task.taskId).subscribe(
task => {this.task = task}); task => {
this.task = task
});
this.router.navigate(['tasks/']); this.router.navigate(['tasks/']);
} }
} }

View File

@ -1,6 +1,6 @@
<div *ngIf="task != null" class="panel panel-primary"> <div *ngIf="task != null" class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
Details for task '{{ task.name }}' (ID={{ task.id }}) Details for task '{{ task.name }}' (ID={{ task.taskId }})
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p>{{ task.description }}</p> <p>{{ task.description }}</p>
@ -13,7 +13,6 @@
<p><b>Due Date:</b> {{ task.due | date:'medium' }}</p> <p><b>Due Date:</b> {{ task.due | date:'medium' }}</p>
<p><b>Priority:</b> {{ task.priority }}</p> <p><b>Priority:</b> {{ task.priority }}</p>
<p><b>State:</b> {{ task.state }}</p> <p><b>State:</b> {{ task.state }}</p>
<p><b>Type:</b> {{ task.type }}</p> <p><b>Workbasket:</b> {{ task.workbasketSummaryResource.workbasketId }}</p>
<p><b>Workbasket:</b> {{ task.workbasket }}</p>
</div> </div>
</div> </div>

View File

@ -10,16 +10,18 @@
</tr> </tr>
</thead> </thead>
<tr *ngFor="let task of tasks"> <tr *ngFor="let task of tasks">
<td>{{ task.id }}</td> <td>{{ task.taskId }}</td>
<td>{{ task.name }}</td> <td>{{ task.name }}</td>
<td>{{ task.due | date:'medium' }}</td> <td>{{ task.due | date:'medium' }}</td>
<td>{{ task.priority }}</td> <td>{{ task.priority }}</td>
<td>{{ task.state }}</td> <td>{{ task.state }}</td>
<td> <td>
<button type="button" title="Open task to work on it" class="btn btn-default" aria-label="Left Align" (click)="openTask(task.id)"> <button type="button" title="Open task to work on it" class="btn btn-default" aria-label="Left Align"
(click)="openTask(task.taskId)">
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
</button> </button>
<button type="button" title="View details for task" class="btn btn-default" aria-label="Left Align" (click)="selectTask(task)"> <button type="button" title="View details for task" class="btn btn-default" aria-label="Left Align"
(click)="selectTask(task)">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
</button> </button>
</td> </td>

View File

@ -1,7 +1,7 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import { Task } from '../model/task'; import {Task} from '../model/task';
import { Router } from '@angular/router'; import {Router} from '@angular/router';
import { RestConnectorService } from '../services/rest-connector.service'; import {TaskService} from '../services/task.service';
@Component({ @Component({
selector: 'tasklist', selector: 'tasklist',
@ -17,7 +17,7 @@ export class TasklistComponent implements OnInit {
@Input() tasks: Task[]; @Input() tasks: Task[];
constructor(private restConnectorService: RestConnectorService, private router: Router) { constructor(private taskService: TaskService, private router: Router) {
this.columnForOrdering = 'id'; // default: order tasks by id this.columnForOrdering = 'id'; // default: order tasks by id
} }
@ -33,7 +33,7 @@ export class TasklistComponent implements OnInit {
} }
openTask(id: string) { openTask(id: string) {
this.restConnectorService.claimTask(id).subscribe(); this.taskService.claimTask(id).subscribe();
this.router.navigate(['tasks/', id]); this.router.navigate(['tasks/', id]);
} }
} }

View File

@ -1,13 +1,14 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row form-group"> <div class="row form-group">
<workbasket-selector (tasks) = "loadTasks($event)"></workbasket-selector> <workbasket-selector (tasks)="loadTasks($event)"></workbasket-selector>
</div> </div>
<div *ngIf="tasks?.length > 0" class="row form-group"> <div *ngIf="tasks?.length > 0" class="row form-group">
<div class="col-md-6"> <div class="col-md-6">
<tasklist [tasks]="tasks" (task)="selectTask($event)"></tasklist> <tasklist [tasks]="tasks" (task)="selectTask($event)"></tasklist>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<taskdetails [task]="task"></taskdetails> <taskdetails [task]="task" *ngIf="taskDetailEnabled"></taskdetails>
<div class="overlay" [ngClass]="{overlayActive:taskDetailEnabled}" (click)="taskDetailEnabled = false"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,12 @@
.overlay {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
display: none;
}
.overlayActive {
display: block;
}

View File

@ -1,6 +1,5 @@
import { Component, Input } from '@angular/core'; import {Component, Input} from '@angular/core';
import { Task } from '../model/task'; import {Task} from '../model/task';
import { environment } from '../../environments/environment';
@Component({ @Component({
selector: 'app-tasks', selector: 'app-tasks',
@ -9,6 +8,8 @@ import { environment } from '../../environments/environment';
}) })
export class TasksComponent { export class TasksComponent {
taskDetailEnabled: boolean;
@Input() @Input()
tasks: Task[]; tasks: Task[];
@ -20,6 +21,7 @@ export class TasksComponent {
} }
selectTask(task: Task) { selectTask(task: Task) {
this.taskDetailEnabled = true;
this.task = task; this.task = task;
} }

View File

@ -1,9 +1,11 @@
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="input-group"> <div class="input-group">
<input class="form-control dropdown-toggle" auto-complete [(ngModel)]="result" [source]="autoCompleteData" placeholder="Search for Workbasket ..."/> <input class="form-control dropdown-toggle" auto-complete [(ngModel)]="result" [source]="autoCompleteData"
placeholder="Search for Workbasket ..."/>
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-primary" type="button" (click)="searchBasket()" [disabled]="result==null || result.length==0" >Go!</button> <button class="btn btn-primary" type="button" (click)="searchBasket()"
[disabled]="result==null || result.length==0">Go!</button>
</span> </span>
</div> </div>
<!-- /input-group --> <!-- /input-group -->
@ -12,4 +14,3 @@
</div> </div>
<!-- /.row --> <!-- /.row -->

View File

@ -1,8 +1,9 @@
import { Component, OnInit, Output, EventEmitter } from '@angular/core'; import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import { RestConnectorService } from '../services/rest-connector.service'; import {DataService} from '../services/data.service';
import { DataService } from '../services/data.service'; import {Task} from '../model/task';
import { Task } from '../model/task'; import {Workbasket} from '../model/workbasket';
import { Workbasket } from '../model/workbasket'; import {TaskService} from '../services/task.service';
import {WorkbasketService} from '../services/workbasket.service';
@Component({ @Component({
selector: 'workbasket-selector', selector: 'workbasket-selector',
@ -11,18 +12,23 @@ import { Workbasket } from '../model/workbasket';
}) })
export class SelectorComponent implements OnInit { export class SelectorComponent implements OnInit {
@Output() tasks = new EventEmitter<Task[]>(); @Output('tasks') tasksEmitter = new EventEmitter<Task[]>();
autoCompleteData: string[] = new Array; tasks: Task[] = [];
autoCompleteData: string[] = [];
result: string; result: string;
resultKey: string; resultKey: string;
workbaskets: Workbasket[]; workbaskets: Workbasket[];
constructor(private restConnectorService: RestConnectorService, private dataService: DataService) { } constructor(private taskService: TaskService,
private workbasketService: WorkbasketService,
private dataService: DataService) {
}
ngOnInit() { ngOnInit() {
this.restConnectorService.getAllWorkBaskets().subscribe( w => { this.workbasketService.getAllWorkBaskets().subscribe(w => {
this.workbaskets = w; this.workbaskets = w['_embedded']['workbaskets'];
this.workbaskets.forEach(workbasket => { this.workbaskets.forEach(workbasket => {
this.autoCompleteData.push(workbasket.name); this.autoCompleteData.push(workbasket.name);
}); });
@ -37,17 +43,20 @@ export class SelectorComponent implements OnInit {
if (this.workbaskets) { if (this.workbaskets) {
this.workbaskets.forEach(workbasket => { this.workbaskets.forEach(workbasket => {
if (workbasket.name === this.result) { if (workbasket.name === this.result) {
this.resultKey = workbasket.key; this.resultKey = workbasket.workbasketId;
} }
}); });
this.getTasks(this.resultKey); this.getTasks(this.resultKey);
this.dataService.workbasketKey = this.resultKey; this.dataService.workbasketKey = this.resultKey;
this.dataService.workbasketName = this.result; this.dataService.workbasketName = this.result;
this.tasksEmitter.emit(this.tasks);
} }
} }
getTasks(workbasketKey: string) { getTasks(workbasketKey: string) {
this.restConnectorService.findTaskWithWorkbaskets(workbasketKey).subscribe( this.taskService.findTaskWithWorkbaskets(workbasketKey).subscribe(
tasks2 => {this.tasks.next(tasks2)}); tasks2 => {
tasks2['_embedded']['tasks'].forEach(e => this.tasks.push(e));
});
} }
} }