TSK-336 TaskDetails prototype

This commit is contained in:
Lars Leo Grätz 2018-04-30 16:44:35 +02:00 committed by Martin Rojas Miguel Angel
parent 1c93702063
commit 3f23005fa2
23 changed files with 540 additions and 235 deletions

View File

@ -0,0 +1,7 @@
import {Links} from './links';
import {Workbasket} from './workbasket';
export class WorkbasketResource {
constructor(public _embedded: { 'workbaskets': Array<Workbasket> } = { 'workbaskets': [] },
public _links: Links = undefined) {}
}

View File

@ -15,5 +15,9 @@
<h3 class="grey">Select a classification</h3> <h3 class="grey">Select a classification</h3>
<svg-icon class="img-responsive empty-icon" src="./assets/icons/classification-empty.svg"></svg-icon> <svg-icon class="img-responsive empty-icon" src="./assets/icons/classification-empty.svg"></svg-icon>
</div> </div>
</div> <div *ngIf="currentRoute === 'tasks'" class="center-block no-detail">
</div> <h3 class="grey">Select a Task</h3>
<!--TODO: ICON for task?-->
</div>
</div>
</div>

View File

@ -11,7 +11,8 @@ import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-
export class MasterAndDetailComponent implements OnInit { export class MasterAndDetailComponent implements OnInit {
private classifications = 'classifications'; private classifications = 'classifications';
private workbaskets = 'workbaskets'; private workbaskets = 'workbaskets';
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'classifications/(detail']; private tasks = 'tasks';
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'classifications/(detail', 'tasks/(detail'];
private sub: any; private sub: any;
showDetail: Boolean = false; showDetail: Boolean = false;
@ -56,6 +57,8 @@ export class MasterAndDetailComponent implements OnInit {
this.currentRoute = this.workbaskets; this.currentRoute = this.workbaskets;
} else if (url.indexOf(this.classifications) !== -1) { } else if (url.indexOf(this.classifications) !== -1) {
this.currentRoute = this.classifications; this.currentRoute = this.classifications;
} else if (url.indexOf(this.tasks) !== -1) {
this.currentRoute = this.tasks;
} }
} }
} }

View File

@ -0,0 +1,7 @@
import {Links} from '../../models/links';
import {Task} from './task';
export class TaskResource {
constructor(public _embedded: { 'tasks': Array<Task> } = { 'tasks': [] },
public _links: Links = undefined) {}
}

View File

@ -22,6 +22,21 @@ export class Task {
public priority: number, public priority: number,
public classificationSummaryResource: Classification, public classificationSummaryResource: Classification,
public workbasketSummaryResource: Workbasket, public workbasketSummaryResource: Workbasket,
public custom1: any) { public custom1: string,
public custom2: string,
public custom3: string,
public custom4: string,
public custom5: string,
public custom6: string,
public custom7: string,
public custom8: string,
public custom9: string,
public custom10: string,
public custom11: string,
public custom12: string,
public custom13: string,
public custom14: string,
public custom15: string,
public custom16: string) {
} }
} }

View File

@ -1,7 +0,0 @@
import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
workbasketKey: string;
workbasketName: string;
}

View File

@ -1,34 +1,38 @@
import { Task } from '../models/task'; import {Task} from 'app/workplace/models/task';
import { Observable } from 'rxjs/Observable'; import {Observable} from 'rxjs/Observable';
import { HttpClient, HttpHeaders } from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import { Injectable } from '@angular/core'; import {Injectable} from '@angular/core';
import { environment } from 'app/../environments/environment'; import {environment} from 'app/../environments/environment';
import {TaskResource} from 'app/workplace/models/task-resource';
@Injectable() @Injectable()
export class TaskService { export class TaskService {
url = environment.taskanaRestUrl + '/v1/tasks'; url = `${environment.taskanaRestUrl}/v1/tasks`;
constructor(private httpClient: HttpClient) { constructor(private httpClient: HttpClient) {
} }
findTaskWithWorkbaskets(basketKey: string): Observable<Task[]> { findTasksWithWorkbasket(basketKey: string): Observable<TaskResource> {
return this.httpClient.get<Task[]>(this.url + '?workbasketId=' + basketKey); return this.httpClient.get<TaskResource>(`${this.url}?workbasket-id=${basketKey}`);
} }
getTask(id: string): Observable<Task> { getTask(id: string): Observable<Task> {
return this.httpClient.get<Task>(this.url + '/' + id); return this.httpClient.get<Task>(`${this.url}/${id}`);
} }
completeTask(id: string): Observable<Task> { completeTask(id: string): Observable<Task> {
return this.httpClient.post<Task>(this.url + '/' + id + '/complete', ''); return this.httpClient.post<Task>(`${this.url}/${id}/complete`, '');
} }
claimTask(id: string): Observable<Task> { claimTask(id: string): Observable<Task> {
return this.httpClient.post<Task>(this.url + '/' + id + '/claim', 'test'); return this.httpClient.post<Task>(`${this.url}/${id}/claim`, 'test');
} }
transferTask(taskId: string, workbasketKey: string): Observable<Task> { transferTask(taskId: string, workbasketKey: string): Observable<Task> {
return this.httpClient.post<Task>(this.url + '/' + taskId return this.httpClient.post<Task>(`${this.url}/${taskId}/transfer/${workbasketKey}`, '');
+ '/transfer/' + workbasketKey, ''); }
updateTask(task: Task): Observable<Task> {
return this.httpClient.put<Task>(`${this.url}/${task.taskId}`, task);
} }
} }

View File

@ -1,17 +1,20 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Workbasket } from 'app/models/workbasket';
import { environment } from 'app/../environments/environment'; import { environment } from 'app/../environments/environment';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import {WorkbasketResource} from 'app/models/workbasket-resource';
@Injectable() @Injectable()
export class WorkbasketService { export class WorkbasketService {
url = environment.taskanaRestUrl + '/v1/workbaskets'; url = `${environment.taskanaRestUrl}/v1/workbaskets`;
workbasketKey: string;
workbasketName: string;
constructor(private httpClient: HttpClient) { constructor(private httpClient: HttpClient) {
} }
getAllWorkBaskets(): Observable<Workbasket[]> { getAllWorkBaskets(): Observable<WorkbasketResource> {
return this.httpClient.get<Workbasket[]>(this.url + '?required-permission=OPEN'); return this.httpClient.get<WorkbasketResource>(`${this.url}?required-permission=OPEN`);
} }
} }

View File

@ -1,21 +1,52 @@
<nav class="navbar navbar-default"> <taskana-spinner [isRunning]="requestInProgress" ></taskana-spinner>
<div class="container-fluid"> <div class="panel panel-default">
<div class="navbar-header"> <div class="panel-heading">
<p> <div class="pull-right">
<a class="navbar-brand" href="#"> <div class="col-md-6">
{{ task?.name }} <input class="form-control" auto-complete [(ngModel)]="workbasket" [source]="autoCompleteData"
</a> placeholder="Transfer ..."/>
</p> </div>
<button (click)="transferTask()" class="btn-link"><span title="Transfer task to another workbasket"
class="glyphicon glyphicon-new-window text-muted"></span>
</button>
<button (click)="cancelTask()" class="btn-link"><span title="Cancel task and return to task list"
class="glyphicon glyphicon-remove-circle text-muted"></span>
</button>
<button (click)="completeTask()" class="btn-link"><span title="Complete task and return to task list"
class="glyphicon glyphicon-ok-circle text-success"></span>
</button>
</div> </div>
<ul class="nav navbar-nav navbar-right"> <h4 class="panel-header"><b>{{task?.name}}</b></h4>
<li><input class="form-control" auto-complete [(ngModel)]="workbasket" [source]="autoCompleteData" placeholder="Transfer ..." style="margin-top:10px;"/></li>
<li><a><button (click)="transferTask()" class="btn-link"><span title="Transfer task to another workbasket" class="glyphicon glyphicon-new-window text-muted"></span></button></a></li>
<li><a><button (click)="cancelTask()" class="btn-link"><span title="Cancel task and return to task list" class="glyphicon glyphicon-remove-circle text-muted"></span></button></a></li>
<li><a><button (click)="completeTask()" class="btn-link"><span title="Complete task and return to task list" class="glyphicon glyphicon-ok-circle text-success"></span></button></a></li>
</ul>
</div> </div>
</nav>
<div class="container-fluid"> <div class="panel-body" *ngIf="task">
<iframe [src]="link"></iframe> <form #TaskForm="ngForm">
<div class="col-md-6">
<div class="form-group">
<label for="task-description" class="control-label">Description</label>
<textarea class="form-control" disabled rows="5" id="task-description" placeholder="Description"
[(ngModel)]="task.description"
name="task.description"></textarea>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="task-note" class="control-label">Note</label>
<input type="text" disabled class="form-control" id="task-note" placeholder="Task has no Note"
[(ngModel)]="task.note"
name="task.note">
</div>
<div class="form-group">
<label for="task-due" class="control-label">Due Date</label>
<input type="text" disabled class="form-control" id="task-due" placeholder="No deadline set"
[(ngModel)]="task.due"
name="task.due">
</div>
</div>
</form>
</div>
</div> </div>
<iframe [src]="link"></iframe>

View File

@ -1,10 +1,10 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import { Task } from '../models/task'; import {Task} from 'app/workplace/models/task';
import { Workbasket } from 'app/models/workbasket'; import {Workbasket} from 'app/models/workbasket';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
import { TaskService } from '../services/task.service'; import {TaskService} from 'app/workplace/services/task.service';
import { WorkbasketService } from '../services/workbasket.service'; import {WorkbasketService} from 'app/workplace/services/workbasket.service';
@Component({ @Component({
@ -13,31 +13,36 @@ import { WorkbasketService } from '../services/workbasket.service';
styleUrls: ['./task.component.scss'] styleUrls: ['./task.component.scss']
}) })
export class TaskComponent implements OnInit { export class TaskComponent implements OnInit {
task: Task = null; task: Task = null;
link: SafeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl('https://duckduckgo.com/?q='); address = 'https://bing.com';
link: SafeResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.address);
autoCompleteData: string[] = []; autoCompleteData: string[] = [];
workbasket: string = null; workbasket: string = null;
workbasketKey: string; workbasketKey: string;
workbaskets: Workbasket[]; workbaskets: Workbasket[];
requestInProgress = false;
private sub: any;
constructor(private taskService: TaskService, constructor(private taskService: TaskService,
private workbasketService: WorkbasketService, private workbasketService: WorkbasketService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private sanitizer: DomSanitizer) { private sanitizer: DomSanitizer) {
} }
ngOnInit() { ngOnInit() {
const id = this.route.snapshot.params['id']; const id = this.route.snapshot.params['id'];
this.getTask(id);
}
getTask(id: string) {
this.requestInProgress = true;
this.taskService.getTask(id).subscribe( this.taskService.getTask(id).subscribe(
t => { task => {
this.task = t; this.requestInProgress = false;
this.link = this.sanitizer.bypassSecurityTrustResourceUrl('https://duckduckgo.com/?q=' + this.task.name); this.task = task;
this.workbasketService.getAllWorkBaskets().subscribe(w => { this.link = this.sanitizer.bypassSecurityTrustResourceUrl(`${this.address}/?q=${this.task.name}`);
this.workbaskets = w['_embedded']['workbaskets']; this.workbasketService.getAllWorkBaskets().subscribe(workbaskets => {
this.workbaskets = workbaskets._embedded ? workbaskets._embedded.workbaskets : [];
this.workbaskets.forEach(workbasket => { this.workbaskets.forEach(workbasket => {
if (workbasket.key !== this.task.workbasketSummaryResource.key) { if (workbasket.key !== this.task.workbasketSummaryResource.key) {
this.autoCompleteData.push(workbasket.name); this.autoCompleteData.push(workbasket.name);
@ -54,8 +59,11 @@ export class TaskComponent implements OnInit {
this.workbasketKey = workbasket.key; this.workbasketKey = workbasket.key;
} }
}); });
this.requestInProgress = true;
this.taskService.transferTask(this.task.taskId, this.workbasketKey).subscribe( this.taskService.transferTask(this.task.taskId, this.workbasketKey).subscribe(
task => { task => {
this.requestInProgress = false;
this.task = task this.task = task
}); });
this.navigateBack(); this.navigateBack();
@ -67,14 +75,16 @@ export class TaskComponent implements OnInit {
} }
completeTask() { completeTask() {
this.requestInProgress = true;
this.taskService.completeTask(this.task.taskId).subscribe( this.taskService.completeTask(this.task.taskId).subscribe(
task => { task => {
this.requestInProgress = false;
this.task = task this.task = task
}); });
this.navigateBack(); this.navigateBack();
} }
private navigateBack() { private navigateBack() {
this.router.navigate(['./'], { relativeTo: this.route.parent }); this.router.navigate([{outlets: {detail: `taskdetail/${this.task.taskId}`}}], {relativeTo: this.route.parent});
} }
} }

View File

@ -1,29 +1,222 @@
<div *ngIf="task != null" class="panel panel-primary"> <taskana-spinner [isRunning]="requestInProgress" ></taskana-spinner>
<div class="panel panel-default" *ngIf="task">
<div class="panel-heading"> <div class="panel-heading">
<div class="col-xs-2"> <div class="pull-right">
<a type="button" class="glyphicon glyphicon-arrow-left white" (click)="goBack()"></a> <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>
</button>
<button type="button" title="Update Task" class="btn btn-default" (click)="updateTask()">
<span class="glyphicon glyphicon-saved" aria-hidden="true"></span>
</button>
</div> </div>
Details for task '{{ task.name }}' (ID={{ task.taskId }}) <h4 class="panel-header"><b>{{task?.name}}</b></h4>
</div> </div>
<div class="panel-body">
<p>{{ task.description }}</p> <div class="panel-body list-group">
<p><b>Owner:</b> {{ task.owner }}</p> <form #TaskForm="ngForm">
<p><b>State:</b> {{ task.state }}</p> <div class="col-md-6">
<p><b>Creation Date:</b> {{ task.created | date:'medium' }}</p> <div class="form-group">
<p><b>Claim Date:</b> {{ task.claimed | date:'medium' }}</p> <label for="task-description" class="control-label">Description</label>
<p><b>Completion Date:</b> {{ task.completed | date:'medium' }}</p> <input type="text" class="form-control" id="task-description" placeholder="Description"
<p><b>Modification Date:</b> {{ task.modified | date:'medium' }}</p> [(ngModel)]="task.description"
<p><b>Planning Date:</b> {{ task.planned | date:'medium' }}</p> name="task.description">
<p><b>Due Date:</b> {{ task.due | date:'medium' }}</p> </div>
<p><b>Priority:</b> {{ task.priority }}</p> <div class="form-group">
<p><b>Creator:</b> {{task.creator}}</p> <label for="task-owner" class="control-label">Owner</label>
<p><b>Note:</b> {{task.note}}</p> <input type="text" class="form-control" id="task-owner" placeholder="Owner" [(ngModel)]="task.owner"
<p><b>Workbasket:</b> {{ task.workbasketSummaryResource.workbasketId }}</p> name="task.owner">
<p><b>Classification:</b> {{task.classificationSummaryResource.classificationId}}</p> </div>
<p><b>BusinessProcessID:</b> {{task.businessProcessId}}</p> <div class="form-group">
<p><b>ParentBusinessProcessID:</b> {{task.parentBusinessProcessId}}</p> <label for="task-created" class="control-label">Creation Date</label>
<p><b>Read:</b> {{task.read}}</p> <input type="text" disabled class="form-control" id="task-created" [(ngModel)]="task.created"
<p><b>Transferred:</b> {{task.transferred}}</p> name="task.created">
<p><b>custom1:</b> {{task.custom1}}</p> </div>
<div class="form-group">
<label for="task-claimed" class="control-label">Claim Date</label>
<input type="text" disabled class="form-control" id="task-claimed" placeholder="Not claimed yet"
[(ngModel)]="task.claimed"
name="task.claimed">
</div>
<div class="form-group">
<label for="task-completed" class="control-label">Completion Date</label>
<input type="text" disabled class="form-control" id="task-completed" placeholder="Not completed yet"
[(ngModel)]="task.completed"
name="task.completed">
</div>
<div class="form-group">
<label for="task-modified" class="control-label">Modification Date</label>
<input type="text" disabled class="form-control" id="task-modified" placeholder="Has not been modified"
[(ngModel)]="task.modified"
name="task.modified">
</div>
<div class="form-group">
<label for="task-planned" class="control-label">Planned Date</label>
<input type="text" disabled class="form-control" id="task-planned" placeholder="No plan set"
[(ngModel)]="task.planned"
name="task.planned">
</div>
<div class="form-group">
<label for="task-due" class="control-label">Due Date</label>
<input type="text" disabled class="form-control" id="task-due" placeholder="No deadline set"
[(ngModel)]="task.due"
name="task.due">
</div>
<div class="form-group">
<label for="task-priority" class="control-label">Priority</label>
<input type="text" class="form-control" id="task-priority" placeholder="no priotity set"
[(ngModel)]="task.priority"
name="task.priority">
</div>
<div class="form-group">
<label for="task-state" class="control-label">State</label>
<input type="text" disabled class="form-control" id="task-state" placeholder="Task has no State"
[(ngModel)]="task.state"
name="task.state">
</div>
<div class="form-group">
<label for="task-note" class="control-label">Note</label>
<input type="text" class="form-control" id="task-note" placeholder="Task has no Note" [(ngModel)]="task.note"
name="task.note">
</div>
<div class="form-group">
<label for="task-workbasket" class="control-label">Workbasket ID</label>
<input type="text" disabled class="form-control" id="task-workbasket"
placeholder="Task does not belong to a Workbasket"
[(ngModel)]="task.workbasketSummaryResource.workbasketId"
name="task.workbasket">
</div>
<div class="form-group">
<label for="task-classification" class="control-label">Classification ID</label>
<input type="text" disabled class="form-control" id="task-classification"
placeholder="Task does not belong to a Classification"
[(ngModel)]="task.classificationSummaryResource.classificationId"
name="task.classification">
</div>
<div class="form-group">
<label for="task-businessProcessId" class="control-label">Business Process ID</label>
<input type="text" disabled class="form-control" id="task-businessProcessId" placeholder="Task has no BPI"
[(ngModel)]="task.businessProcessId"
name="task.businessProcessId">
</div>
<div class="form-group">
<label for="task-parentBusinessProcessId" class="control-label">Parent Business Process ID</label>
<input type="text" disabled class="form-control" id="task-parentBusinessProcessId"
placeholder="Task has no PBPI"
[(ngModel)]="task.businessProcessId"
name="task.parentBusinessProcessId">
</div>
<div class="form-group">
<label for="task-read" class="control-label">Task Read?</label>
<input type="text" disabled class="form-control" id="task-read" placeholder="Task not been read"
[(ngModel)]="task.read"
name="task.read">
</div>
<div class="form-group">
<label for="task-transferred" class="control-label">Task Transferred?</label>
<input type="text" disabled class="form-control" id="task-transferred" placeholder="Task not been transferred"
[(ngModel)]="task.transferred"
name="task.transferred">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="task-custom1" class="control-label">Custom1</label>
<input type="text" class="form-control" id="task-custom1" placeholder="No custom1 set"
[(ngModel)]="task.custom1"
name="task.custom1">
</div>
<div class="form-group">
<label for="task-custom2" class="control-label">Custom2</label>
<input type="text" class="form-control" id="task-custom2" placeholder="No custom2 set"
[(ngModel)]="task.custom2"
name="task.custom2">
</div>
<div class="form-group">
<label for="task-custom3" class="control-label">Custom3</label>
<input type="text" class="form-control" id="task-custom3" placeholder="No custom3 set"
[(ngModel)]="task.custom3"
name="task.custom3">
</div>
<div class="form-group">
<label for="task-custom4" class="control-label">Custom4</label>
<input type="text" class="form-control" id="task-custom4" placeholder="No custom4 set"
[(ngModel)]="task.custom4"
name="task.custom4">
</div>
<div class="form-group">
<label for="task-custom5" class="control-label">Custom5</label>
<input type="text" class="form-control" id="task-custom5" placeholder="No custom5 set"
[(ngModel)]="task.custom5"
name="task.custom5">
</div>
<div class="form-group">
<label for="task-custom6" class="control-label">Custom6</label>
<input type="text" class="form-control" id="task-custom6" placeholder="No custom6 set"
[(ngModel)]="task.custom6"
name="task.custom6">
</div>
<div class="form-group">
<label for="task-custom7" class="control-label">Custom7</label>
<input type="text" class="form-control" id="task-custom7" placeholder="No custom7 set"
[(ngModel)]="task.custom7"
name="task.custom7">
</div>
<div class="form-group">
<label for="task-custom8" class="control-label">Custom8</label>
<input type="text" class="form-control" id="task-custom8" placeholder="No custom8 set"
[(ngModel)]="task.custom8"
name="task.custom8">
</div>
<div class="form-group">
<label for="task-custom9" class="control-label">Custom9</label>
<input type="text" class="form-control" id="task-custom9" placeholder="No custom9 set"
[(ngModel)]="task.custom9"
name="task.custom9">
</div>
<div class="form-group">
<label for="task-custom10" class="control-label">Custom10</label>
<input type="text" class="form-control" id="task-custom10" placeholder="No custom10 set"
[(ngModel)]="task.custom10"
name="task.custom10">
</div>
<div class="form-group">
<label for="task-custom11" class="control-label">Custom11</label>
<input type="text" class="form-control" id="task-custom11" placeholder="No custom11 set"
[(ngModel)]="task.custom11"
name="task.custom11">
</div>
<div class="form-group">
<label for="task-custom12" class="control-label">Custom12</label>
<input type="text" class="form-control" id="task-custom12" placeholder="No custom12 set"
[(ngModel)]="task.custom12"
name="task.custom12">
</div>
<div class="form-group">
<label for="task-custom13" class="control-label">Custom13</label>
<input type="text" class="form-control" id="task-custom13" placeholder="No custom13 set"
[(ngModel)]="task.custom13"
name="task.custom13">
</div>
<div class="form-group">
<label for="task-custom14" class="control-label">Custom14</label>
<input type="text" class="form-control" id="task-custom14" placeholder="No custom14 set"
[(ngModel)]="task.custom14"
name="task.custom14">
</div>
<div class="form-group">
<label for="task-custom15" class="control-label">Custom15</label>
<input type="text" class="form-control" id="task-custom15" placeholder="No custom15 set"
[(ngModel)]="task.custom15"
name="task.custom15">
</div>
<div class="form-group">
<label for="task-custom16" class="control-label">Custom16</label>
<input type="text" class="form-control" id="task-custom16" placeholder="No custom16 set"
[(ngModel)]="task.custom16"
name="task.custom16">
</div>
</div>
</form>
</div> </div>
</div> </div>

View File

@ -0,0 +1,6 @@
.list-group {
max-height: 84vh;
margin-bottom: 10px;
overflow:scroll;
-webkit-overflow-scrolling: touch;
}

View File

@ -1,8 +1,8 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {Task} from '../models/task'; import {Task} from '../models/task';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {TaskService} from '../services/task.service'; import {TaskService} from '../services/task.service';
import {Location} from '@angular/common'; import {Subscription} from 'rxjs/Subscription';
@Component({ @Component({
selector: 'taskana-task-details', selector: 'taskana-task-details',
@ -11,24 +11,39 @@ import {Location} from '@angular/common';
}) })
export class TaskdetailsComponent implements OnInit { export class TaskdetailsComponent implements OnInit {
task: Task = null; task: Task = null;
requestInProgress = false;
private routeSubscription: Subscription;
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private taskService: TaskService, private taskService: TaskService,
private location: Location) { private router: Router) {
} }
ngOnInit() { ngOnInit() {
this.getTask(); this.routeSubscription = this.route.params.subscribe(params => {
} const id = params['id'];
this.getTask(id);
getTask(): void {
const id = this.route.snapshot.paramMap.get('id');
this.taskService.getTask(id).subscribe(task => {
this.task = task
}); });
} }
goBack(): void { getTask(id: string): void {
this.location.back(); this.requestInProgress = true;
this.taskService.getTask(id).subscribe(task => {
this.requestInProgress = false;
this.task = task;
});
}
updateTask() {
this.requestInProgress = true;
this.taskService.updateTask(this.task).subscribe(task => {
this.requestInProgress = false;
this.task = task;
});
}
openTask(taskId: string) {
this.router.navigate([{outlets: {detail: `task/${taskId}`}}], {relativeTo: this.route.parent});
} }
} }

View File

@ -1,29 +1,22 @@
<table class="table table-hover"> <div class="task-list-full-height">
<thead> <taskana-workbasket-selector (tasksChanged)="loadTasks($event)"></taskana-workbasket-selector>
<tr> <!--TODO: add toolbar for sorting, also add pagination-->
<th class="clickable" (click)="orderTasks('id')">ID</th> <div>
<th class="clickable" (click)="orderTasks('name')">Name</th> <ul #taskList id="task-list-container" class="list-group">
<th class="clickable" (click)="orderTasks('due')">Due Date</th> <li class="list-group-item" *ngIf="tasks === undefined || tasks.length === 0" type="text"> There are no Tasks for this workbasket </li>
<th class="clickable" (click)="orderTasks('priority')">Priority</th> <li class="list-group-item" *ngFor="let task of tasks" [class.active]="task.taskId == selectedId"
<th class="clickable" (click)="orderTasks('state')">State</th> type="text" (click)="selectTask(task.taskId)">
<th>Actions</th> <div class="row">
</tr> <dl class="col-xs-10">
</thead> <dt data-toggle="tooltip" title="{{task.name}}">{{task.name}},
<tr *ngFor="let task of tasks"> <i data-toggle="tooltip" title="{{task.taskId}}">{{task.taskId}} </i>
<td>{{ task.taskId }}</td> </dt>
<td>{{ task.name }}</td> <dd data-toggle="tooltip" title="{{task.due}}">Due: {{task.due}} &nbsp;</dd>
<td>{{ task.due | date:'medium' }}</td> <dd data-toggle="tooltip" title="{{task.priority}}">Priority: {{task.priority}} &nbsp;</dd>
<td>{{ task.priority }}</td> <dd data-toggle="tooltip" title="{{task.state}}">State: {{task.state}} &nbsp;</dd>
<td>{{ task.state }}</td> </dl>
<td> </div>
<button type="button" title="Open task to work on it" class="btn btn-default" aria-label="Left Align" </li>
(click)="openTask(task.taskId)"> </ul>
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> </div>
</button> </div>
<a type="button" title="View details for task" class="btn btn-default" aria-label="Left Align"
routerLink="taskdetail/{{task.taskId}}">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
</a>
</td>
</tr>
</table>

View File

@ -1,3 +1,52 @@
.clickable { .clickable {
cursor: pointer; cursor: pointer;
} }
.task-list-full-height{
height: calc(100vh - 55px);
}
.row.list-group {
margin-left: 2px;
}
.list-group > li {
border-left: none;
border-right: none;
}
ul {
max-height: 90vh;
margin-bottom: 10px;
overflow:scroll;
-webkit-overflow-scrolling: touch;
}
a > label{
height: 2em;
width: 100%;
}
dd, dt {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
dt > i {
font-weight: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
li > div.row > dl {
margin-bottom: 0px;
}
li > div.row > dl:first-child {
margin-left: 10px;
}
.no-space {
border-top: none;
padding: 0px
}

View File

@ -11,6 +11,7 @@ export class TasklistComponent implements OnInit {
private columnForOrdering: string; private columnForOrdering: string;
selectedId = '';
@Input() tasks: Task[]; @Input() tasks: Task[];
constructor(private router: Router, constructor(private router: Router,
@ -25,7 +26,12 @@ export class TasklistComponent implements OnInit {
this.columnForOrdering = column; this.columnForOrdering = column;
} }
openTask(id: string) { loadTasks(tasks: Task[]) {
this.router.navigate(['tasks/', id], {relativeTo: this.route.parent}); this.tasks = tasks;
}
selectTask(taskId: string) {
this.selectedId = taskId;
this.router.navigate([{outlets: {detail: `taskdetail/${this.selectedId}`}}], {relativeTo: this.route});
} }
} }

View File

@ -1,10 +0,0 @@
<div class="container-fluid">
<div class="row form-group">
<taskana-workbasket-selector (tasksChanged)="loadTasks($event)"></taskana-workbasket-selector>
</div>
<div *ngIf="tasks?.length > 0" class="row form-group">
<div class="col-md-6">
<taskana-task-list [tasks]="tasks" (task)="selectTask($event)"></taskana-task-list>
</div>
</div>
</div>

View File

@ -1,3 +0,0 @@
.container-fluid > .row {
min-height: 50px;
}

View File

@ -1,25 +0,0 @@
import {Component, Input} from '@angular/core';
import {Task} from '../models/task';
@Component({
selector: 'taskana-tasks',
templateUrl: './tasks.component.html',
styleUrls: ['./tasks.component.scss']
})
export class TasksComponent {
@Input()
tasks: Task[];
@Input()
task: Task;
loadTasks(tasks: Task[]) {
this.tasks = tasks;
}
selectTask(task: Task) {
this.task = task;
}
}

View File

@ -1,5 +1,5 @@
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-md-12">
<div class="input-group"> <div class="input-group">
<input class="form-control dropdown-toggle" auto-complete [(ngModel)]="result" [source]="autoCompleteData" <input class="form-control dropdown-toggle" auto-complete [(ngModel)]="result" [source]="autoCompleteData"
placeholder="Search for Workbasket ..."/> placeholder="Search for Workbasket ..."/>

View File

@ -1,9 +1,8 @@
import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import { DataService } from '../services/data.service'; import {Task} from 'app/workplace/models/task';
import { Task } from '../models/task'; import {Workbasket} from 'app/models/workbasket';
import { Workbasket } from 'app/models/workbasket'; import {TaskService} from 'app/workplace/services/task.service';
import { TaskService } from '../services/task.service'; import {WorkbasketService} from 'app/workplace/services/workbasket.service';
import { WorkbasketService } from '../services/workbasket.service';
@Component({ @Component({
selector: 'taskana-workbasket-selector', selector: 'taskana-workbasket-selector',
@ -22,20 +21,19 @@ export class SelectorComponent implements OnInit {
workbaskets: Workbasket[]; workbaskets: Workbasket[];
constructor(private taskService: TaskService, constructor(private taskService: TaskService,
private workbasketService: WorkbasketService, private workbasketService: WorkbasketService) {
private dataService: DataService) {
} }
ngOnInit() { ngOnInit() {
this.workbasketService.getAllWorkBaskets().subscribe(w => { this.workbasketService.getAllWorkBaskets().subscribe(workbaskets => {
this.workbaskets = w['_embedded']['workbaskets']; this.workbaskets = workbaskets._embedded ? workbaskets._embedded.workbaskets : [];
this.workbaskets.forEach(workbasket => { this.workbaskets.forEach(workbasket => {
this.autoCompleteData.push(workbasket.name); this.autoCompleteData.push(workbasket.name);
}); });
}); });
if (this.dataService.workbasketKey) { if (this.workbasketService.workbasketKey) {
this.getTasks(this.dataService.workbasketKey); this.getTasks(this.workbasketService.workbasketKey);
this.result = this.dataService.workbasketName; this.result = this.workbasketService.workbasketName;
} }
} }
@ -47,16 +45,20 @@ export class SelectorComponent implements OnInit {
} }
}); });
this.getTasks(this.resultKey); this.getTasks(this.resultKey);
this.dataService.workbasketKey = this.resultKey; this.workbasketService.workbasketKey = this.resultKey;
this.dataService.workbasketName = this.result; this.workbasketService.workbasketName = this.result;
this.tasksChanged.emit(this.tasks); this.tasksChanged.emit(this.tasks);
} }
} }
getTasks(workbasketKey: string) { getTasks(workbasketKey: string) {
this.taskService.findTaskWithWorkbaskets(workbasketKey).subscribe( this.taskService.findTasksWithWorkbasket(workbasketKey).subscribe(
tasks2 => { tasks => {
tasks2['_embedded']['tasks'].forEach(e => this.tasks.push(e)); if (!tasks || tasks._embedded === undefined) {
this.tasks.length = 0;
return;
}
tasks._embedded.tasks.forEach(e => this.tasks.push(e));
}); });
} }
} }

View File

@ -1,36 +1,42 @@
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router'; import {RouterModule, Routes} from '@angular/router';
import {WorkplaceComponent} from './workplace.component' import {MasterAndDetailComponent} from '../shared/master-and-detail/master-and-detail.component';
import {TasksComponent} from 'app/workplace/tasks/tasks.component'; import {WorkplaceComponent} from './workplace.component';
import {TaskComponent} from 'app/workplace/task/task.component'; import {TaskComponent} from './task/task.component';
import {TaskdetailsComponent} from './taskdetails/taskdetails.component'; import {TaskdetailsComponent} from './taskdetails/taskdetails.component';
import {TasklistComponent} from './tasklist/tasklist.component';
const routes: Routes = [ const routes: Routes = [
{ {
path: '', path: 'tasks',
component: WorkplaceComponent, component: MasterAndDetailComponent,
redirectTo: 'tasks', children: [
pathMatch: 'full' {
}, path: '',
{ component: TasklistComponent,
path: '', outlet: 'master'
component: WorkplaceComponent, },
children: [ {
{ path: 'taskdetail/:id',
path: 'tasks', component: TaskdetailsComponent,
component: TasksComponent outlet: 'detail'
}, },
{ {
path: 'tasks/:id', path: 'task/:id',
component: TaskComponent component: TaskComponent,
}, outlet: 'detail'
{ }
path: 'tasks/taskdetail/:id', ]
component: TaskdetailsComponent },
} {
] path: '',
} component: WorkplaceComponent,
]; redirectTo: 'tasks',
pathMatch: 'full'
}
]
;
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],

View File

@ -1,28 +1,26 @@
import { CommonModule } from '@angular/common'; import {CommonModule} from '@angular/common';
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { FormsModule } from '@angular/forms'; import {FormsModule} from '@angular/forms';
import { Ng2AutoCompleteModule } from 'ng2-auto-complete'; import {Ng2AutoCompleteModule} from 'ng2-auto-complete';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon'; import {AngularSvgIconModule} from 'angular-svg-icon';
import { WorkplaceRoutingModule } from './workplace-routing.module'; import {WorkplaceRoutingModule} from './workplace-routing.module';
import { AlertModule } from 'ngx-bootstrap'; import {AlertModule} from 'ngx-bootstrap';
import { SharedModule } from 'app/shared/shared.module';
import { WorkplaceComponent } from './workplace.component'; import { WorkplaceComponent } from './workplace.component';
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 { TaskComponent } from './task/task.component'; import { TaskComponent } from './task/task.component';
import { TasksComponent } from './tasks/tasks.component';
import { CodeComponent } from './components/code/code.component'; import { CodeComponent } from './components/code/code.component';
import { OrderTasksByPipe } from './util/orderTasksBy.pipe'; import { OrderTasksByPipe } from './util/orderTasksBy.pipe';
import { DataService } from './services/data.service'; import {TaskService} from './services/task.service';
import { TaskService } from './services/task.service'; import {WorkbasketService} from './services/workbasket.service';
import { WorkbasketService } from './services/workbasket.service'; import {SharedModule} from '../shared/shared.module';
import { CustomHttpClientInterceptor } from './services/custom-http-interceptor/custom-http-interceptor.service'; import {CustomHttpClientInterceptor} from './services/custom-http-interceptor/custom-http-interceptor.service';
const MODULES = [ const MODULES = [
@ -42,7 +40,6 @@ const DECLARATIONS = [
TasklistComponent, TasklistComponent,
TaskdetailsComponent, TaskdetailsComponent,
TaskComponent, TaskComponent,
TasksComponent,
CodeComponent, CodeComponent,
OrderTasksByPipe OrderTasksByPipe
]; ];
@ -51,7 +48,6 @@ const DECLARATIONS = [
declarations: DECLARATIONS, declarations: DECLARATIONS,
imports: MODULES, imports: MODULES,
providers: [ providers: [
DataService,
TaskService, TaskService,
WorkbasketService, WorkbasketService,
{ {