TSK-24 create new task

initial new Task creation.
Also moved Classification services to general tab.
This commit is contained in:
Lars Leo Grätz 2018-09-12 17:06:55 +02:00 committed by Jose Ignacio Recuerda Cambil
parent 785c07eb6d
commit 8116c89d7e
30 changed files with 444 additions and 230 deletions

View File

@ -28,8 +28,8 @@ import {WorkbasketService} from 'app/services/workbasket/workbasket.service';
import {SavingWorkbasketService} from './services/saving-workbaskets/saving-workbaskets.service';
import {ClassificationDefinitionService} from './services/classification-definition/classification-definition.service';
import {WorkbasketDefinitionService} from './services/workbasket-definition/workbasket-definition.service';
import {ClassificationsService} from './services/classifications/classifications.service';
import {ClassificationCategoriesService} from './services/classification-categories-service/classification-categories.service';
import {ClassificationsService} from '../services/classifications/classifications.service';
import {ClassificationCategoriesService} from 'app/services/classifications/classification-categories.service';
import { AccessItemsManagementComponent } from 'app/administration/access-items-management/access-items-management.component';
const MODULES = [

View File

@ -15,11 +15,11 @@ import { LinksClassification } from 'app/models/links-classfication';
import { Pair } from 'app/models/pair';
// tslint:disable:max-line-length
import { ClassificationCategoriesService } from 'app/administration/services/classification-categories-service/classification-categories.service';
import { ClassificationCategoriesService } from 'app/services/classifications/classification-categories.service';
// tslint:enable:max-line-length
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
import { ClassificationsService } from 'app/services/classifications/classifications.service';
import { TreeNodeModel } from 'app/models/tree-node';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { AlertService } from 'app/services/alert/alert.service';

View File

@ -10,7 +10,7 @@ import { AlertModel, AlertType } from 'app/models/alert';
import { highlight } from 'app/shared/animations/validation.animation';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
import { ClassificationsService } from 'app/services/classifications/classifications.service';
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
@ -19,7 +19,7 @@ import { TreeService } from 'app/services/tree/tree.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
// tslint:disable:max-line-length
import { ClassificationCategoriesService } from 'app/administration/services/classification-categories-service/classification-categories.service';
import { ClassificationCategoriesService } from 'app/services/classifications/classification-categories.service';
// tslint:enable:max-line-length
import { DomainService } from 'app/services/domain/domain.service';
import { CustomFieldsService } from '../../../services/custom-fields/custom-fields.service';

View File

@ -15,7 +15,7 @@ import { ClassificationTypesSelectorComponent } from 'app/shared/classification-
import { WorkbasketDefinitionService } from 'app/administration/services/workbasket-definition/workbasket-definition.service';
import { AlertService } from 'app/services/alert/alert.service';
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
import { ClassificationsService } from 'app/services/classifications/classifications.service';
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition/classification-definition.service';
import { DomainService } from 'app/services/domain/domain.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
@ -23,7 +23,7 @@ import { RequestInProgressService } from 'app/services/requestInProgress/request
import { configureTests } from 'app/app.test.configuration';
import {
ClassificationCategoriesService
} from 'app/administration/services/classification-categories-service/classification-categories.service';
} from 'app/services/classifications/classification-categories.service';
import { Pair } from 'app/models/pair';
import { TreeService } from 'app/services/tree/tree.service';

View File

@ -6,10 +6,10 @@ import { TaskanaType } from 'app/models/taskana-type';
import { Classification } from 'app/models/classification';
import { TreeNodeModel } from 'app/models/tree-node';
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
import { ClassificationsService } from 'app/services/classifications/classifications.service';
import {
ClassificationCategoriesService
} from 'app/administration/services/classification-categories-service/classification-categories.service';
} from 'app/services/classifications/classification-categories.service';
import { Pair } from 'app/models/pair';
import { ClassificationDefinition } from '../../../../models/classification-definition';

View File

@ -17,7 +17,7 @@ export class DomainGuard implements CanActivate {
}),
catchError(() => {
this.errorModalService.triggerError(new ErrorModel(
'There was an error, please contact with your administrator', 'There was an error getting Domains'))
'There was an error, please contact with your administrator', 'There was an error getting Domains'));
return of(false)
})
);

View File

@ -1,15 +1,15 @@
import { Links } from 'app/models/links';
import {Links} from 'app/models/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()) {
constructor(public classificationId: string = undefined,
public key: string = undefined,
public category: string = undefined,
public type: string = undefined,
public domain: string = undefined,
public name: string = undefined,
public parentId: string = undefined,
public priority: number = undefined,
public serviceLevel: string = undefined,
public _links: Links = new Links()) {
}
}

View File

@ -8,7 +8,7 @@ import { Classification } from 'app/models/classification';
import { ClassificationDefinition } from 'app/models/classification-definition';
import { ClassificationResource } from 'app/models/classification-resource';
import { ClassificationCategoriesService } from '../classification-categories-service/classification-categories.service';
import { ClassificationCategoriesService } from './classification-categories.service';
import { DomainService } from 'app/services/domain/domain.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Direction } from 'app/models/sorting';

View File

@ -1,5 +1,5 @@
<div class="dropdown dropdown-fix">
<button [disabled]="!enabled" class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="glyphicon {{sort.sortDirection === 'asc'? 'glyphicon-sort-by-attributes-alt' : 'glyphicon-sort-by-attributes' }} blue"
data-toggle="tooltip" title="{{sort.sortDirection === 'asc'? 'A-Z' : 'Z-A' }}"></span>
</button>

View File

@ -8,7 +8,6 @@ import {Direction, SortingModel} from 'app/models/sorting';
})
export class SortComponent implements OnInit {
@Input() sortingFields: Map<string, string>;
@Input() enabled = true;
@Input() menuPosition = 'right';
@Output() performSorting = new EventEmitter<SortingModel>();

View File

@ -8,7 +8,7 @@ import { TaskanaTreeComponent } from './tree.component';
import { TreeService } from 'app/services/tree/tree.service';
import {
ClassificationCategoriesService
} from 'app/administration/services/classification-categories-service/classification-categories.service';
} from 'app/services/classifications/classification-categories.service';
import { configureTests } from 'app/app.test.configuration';
import { Pair } from 'app/models/pair';

View File

@ -8,7 +8,7 @@ import { KEYS, ITreeOptions, TreeComponent, TreeNode } from 'angular-tree-compon
import { TreeService } from '../../services/tree/tree.service';
import {
ClassificationCategoriesService
} from 'app/administration/services/classification-categories-service/classification-categories.service';
} from 'app/services/classifications/classification-categories.service';
import { Pair } from 'app/models/pair';
import { Subscription } from 'rxjs';

View File

@ -0,0 +1,9 @@
export class ObjectReference {
constructor(public id: string = undefined,
public company: string = undefined,
public system: string = undefined,
public systemInstance: string = undefined,
public type: string = undefined,
public value: string = undefined) {
}
}

View File

@ -1,45 +1,47 @@
import {Classification} from 'app/models/classification';
import {Workbasket} from 'app/models/workbasket';
import {ObjectReference} from './object-reference';
export class Task {
constructor(public businessProcessId: string,
public parentBusinessProcessId: string,
public owner: string,
public taskId: string,
public created: string, // ISO-8601
public claimed: string, // ISO-8601
public completed: string, // ISO-8601
public modified: string, // ISO-8601
public planned: string, // ISO-8601
public due: string, // ISO-8601
public name: string,
public creator: string,
public description: string,
public note: string,
public state: any,
public read: boolean,
public transferred: boolean,
public priority: number,
public classificationSummaryResource: Classification,
public workbasketSummaryResource: Workbasket,
constructor(public taskId: string,
public primaryObjRef: ObjectReference = undefined,
public workbasketSummaryResource: Workbasket = undefined,
public classificationSummaryResource: Classification = undefined,
public businessProcessId: string = undefined,
public parentBusinessProcessId: string = undefined,
public owner: string = undefined,
public created: string = undefined, // ISO-8601
public claimed: string = undefined, // ISO-8601
public completed: string = undefined, // ISO-8601
public modified: string = undefined, // ISO-8601
public planned: string = undefined, // ISO-8601
public due: string = undefined, // ISO-8601
public name: string = undefined,
public creator: string = undefined,
public description: string = undefined,
public note: string = undefined,
public state: any = undefined,
public read: boolean = undefined,
public transferred: boolean = undefined,
public priority: number = undefined,
public customAttributes: Array<CustomAttribute> = [],
public callbackInfo: Array<CustomAttribute> = [],
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) {
public custom1: string = undefined,
public custom2: string = undefined,
public custom3: string = undefined,
public custom4: string = undefined,
public custom5: string = undefined,
public custom6: string = undefined,
public custom7: string = undefined,
public custom8: string = undefined,
public custom9: string = undefined,
public custom10: string = undefined,
public custom11: string = undefined,
public custom12: string = undefined,
public custom13: string = undefined,
public custom14: string = undefined,
public custom15: string = undefined,
public custom16: string = undefined) {
}
}

View File

@ -5,6 +5,7 @@ import {Injectable} from '@angular/core';
import {environment} from 'environments/environment';
import {TaskResource} from 'app/workplace/models/task-resource';
import {Direction} from 'app/models/sorting';
import {Workbasket} from 'app/models/workbasket';
@Injectable()
export class TaskService {
@ -17,11 +18,15 @@ export class TaskService {
STATE = 'state';
url = `${environment.taskanaRestUrl}/v1/tasks`;
taskChangedSource = new Subject<Task>();
taskChangedStream = this.taskChangedSource.asObservable();
taskDeletedSource = new Subject<Task>();
taskDeletedStream = this.taskDeletedSource.asObservable();
private taskSelected = new Subject<Task>();
taskAddedSource = new Subject<Task>();
taskAddedStream = this.taskAddedSource.asObservable();
taskSelectedSource = new Subject<Task>();
taskSelectedStream = this.taskSelectedSource.asObservable();
constructor(private httpClient: HttpClient) {
}
@ -34,12 +39,16 @@ export class TaskService {
this.taskDeletedSource.next(task);
}
publishAddedTask(task: Task) {
this.taskAddedSource.next(task);
}
selectTask(task: Task) {
this.taskSelected.next(task);
this.taskSelectedSource.next(task);
}
getSelectedTask(): Observable<Task> {
return this.taskSelected.asObservable();
return this.taskSelectedStream;
}
/**
@ -82,6 +91,10 @@ export class TaskService {
return this.httpClient.delete<Task>(`${this.url}/${task.taskId}`);
}
createTask(task: Task): Observable<Task> {
return this.httpClient.post<Task>(`${this.url}`, task);
}
private getTaskQueryParameters(basketId: string,
sortBy: string,
sortDirection: string,

View File

@ -0,0 +1,19 @@
import {Injectable} from '@angular/core';
import {Observable, Subject} from 'rxjs/index';
import {Workbasket} from 'app/models/workbasket';
@Injectable()
export class WorkplaceService {
currentWorkbasket: Workbasket = undefined;
workbasketSelectedSource = new Subject<Workbasket>();
workbasketSelectedStream = this.workbasketSelectedSource.asObservable();
selectWorkbasket(workbasket: Workbasket) {
this.currentWorkbasket = workbasket;
this.workbasketSelectedSource.next(workbasket);
}
getSelectedWorkbasket(): Observable<Workbasket> {
return this.workbasketSelectedStream;
}
}

View File

@ -1,108 +1,162 @@
<ng-container *ngIf="task">
<ng-container *ngIf="task && !requestInProgress">
<div class="col-md-12">
<div class="form-group">
<label for="task-description" class="control-label">Description</label>
<textarea class="form-control" id="task-description" placeholder="Description"
<textarea class="form-control" id="task-description"
placeholder="Task has no description"
[(ngModel)]="task.description"
name="task.description"></textarea>
</div>
</div>
<div class="col-md-6">
<div class="form-group required">
<label for="task-objectRef-company" class="control-label">Reference Company</label>
<input type="text" class="form-control" id="task-objectRef-company" required
placeholder="Company description not provided"
[(ngModel)]="task.primaryObjRef.company"
name="task-objectRef-company">
</div>
<div class="form-group required">
<label for="task-objectRef-system" class="control-label">Reference System</label>
<input type="text" class="form-control" id="task-objectRef-system" required
placeholder="System description not provided"
[(ngModel)]="task.primaryObjRef.system"
name="task-objectRef-system">
</div>
<div class="form-group required">
<label for="task-objectRef-system-instance" class="control-label">Reference System Instance</label>
<input type="text" class="form-control" id="task-objectRef-system-instance" required
placeholder="System Instance description not provided"
[(ngModel)]="task.primaryObjRef.systemInstance"
name="task-objectRef-system-instance">
</div>
<div class="form-group">
<label for="task-owner" class="control-label">Owner</label>
<input type="text" class="form-control" id="task-owner" placeholder="Owner" [(ngModel)]="task.owner"
<input type="text" class="form-control" id="task-owner"
placeholder="Task has no owner"
[(ngModel)]="task.owner"
name="task.owner">
</div>
<div class="form-group">
<label for="task-priority" disabled class="control-label">Priority</label>
<input type="text" class="form-control" id="task-priority" placeholder="no priotity set"
<input type="text" class="form-control" id="task-priority"
placeholder="Task has no priority"
[(ngModel)]="task.priority"
name="task.priority">
</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"
<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-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-created" class="control-label">Creation Date</label>
<input type="text" disabled class="form-control" id="task-created" [(ngModel)]="task.created"
name="task.created">
</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">
<div *ngIf="task.taskId" 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"
<input type="text" disabled class="form-control" id="task-modified"
placeholder="Task has not been modified"
[(ngModel)]="task.modified"
name="task.modified">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-completed" class="control-label">Completion Date</label>
<input type="text" disabled class="form-control" id="task-completed"
placeholder="Task has not been completed"
[(ngModel)]="task.completed"
name="task.completed">
</div>
<div *ngIf="task.taskId" 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 *ngIf="task.taskId" 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>
<div class="col-md-6">
<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 class="form-group required">
<label for="task-objectRef-type" class="control-label">Reference Type</label>
<input type="text" class="form-control" id="task-objectRef-type" required
placeholder="Reference Type is not provided"
[(ngModel)]="task.primaryObjRef.type"
name="task-objectRef-type">
</div>
<div class="form-group required">
<label for="task-objectRef-value" class="control-label">Reference Value</label>
<input type="text" class="form-control" id="task-objectRef-value" required
placeholder="Reference Value is not provided"
[(ngModel)]="task.primaryObjRef.value"
name="task-objectRef-value">
</div>
<div class="form-group required">
<div class="dropdown clearfix btn-group">
<label for="classificationDropdownMenu" class="control-label">Classification</label><br>
<button class="btn btn-default" type="button" id="classificationDropdownMenu" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
{{task.classificationSummaryResource ? selectedClassification.name :
'Task does not belong to a Classification'}}
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu">
<li>
<a *ngFor="let classification of classifications" (click)="selectClassification(classification)">
{{classification.name}}
</a>
</li>
</ul>
</div>
</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">
<label for="task-parent-business-p-id" class="control-label">Parent Business Process ID</label>
<input type="text" class="form-control" id="task-parent-business-p-id"
placeholder="Task has no Parent Business Process ID"
[(ngModel)]="task.parentBusinessProcessId"
name="task.parentBusinessProcessId">
</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 Key</label>
<input type="text" disabled class="form-control" id="task-classification"
placeholder="Task does not belong to a Classification"
[(ngModel)]="task.classificationSummaryResource.key"
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"
<label for="task-business-p-id" class="control-label">Business Process ID</label>
<input type="text" class="form-control" id="task-business-p-id"
placeholder="Task has no Business Process ID"
[(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">
<label for="task-due" class="control-label">Due Date</label>
<input type="text" class="form-control" id="task-due"
placeholder="Task has no deadline"
[(ngModel)]="task.due"
name="task.due">
</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 *ngIf="task.taskId" class="form-group">
<label for="task-claimed" class="control-label">Claim Date</label>
<input type="text" disabled class="form-control" id="task-claimed"
placeholder="Task has not been claimed"
[(ngModel)]="task.claimed"
name="task.claimed">
</div>
<div class="form-group">
<div *ngIf="task.taskId" class="form-group">
<label for="task-planned" class="control-label">Planned Date</label>
<input type="text" disabled class="form-control" id="task-planned"
placeholder="Task has no planned date set"
[(ngModel)]="task.planned"
name="task.planned">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-created" class="control-label">Creation Date</label>
<input type="text" disabled class="form-control" id="task-created"
placeholder="Task has not been created"
[(ngModel)]="task.created"
name="task.created">
</div>
<div *ngIf="task.taskId" 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"

View File

@ -0,0 +1,4 @@
ul {
overflow: auto;
overflow-y: scroll;
}

View File

@ -1,19 +1,44 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Task } from 'app/workplace/models/task';
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Task} from 'app/workplace/models/task';
import {Classification} from '../../../models/classification';
import {ClassificationsService} from '../../../services/classifications/classifications.service';
@Component({
selector: 'taskana-task-details-general-fields',
templateUrl: './general-fields.component.html'
templateUrl: './general-fields.component.html',
styleUrls: ['./general-fields.component.scss']
})
export class TaskdetailsGeneralFieldsComponent implements OnInit {
@Input() task: Task;
@Output() taskChange: EventEmitter<Task> = new EventEmitter<Task>();
task: Task;
constructor() {
@Output() taskChange: EventEmitter<Task> = new EventEmitter<Task>();
@Output() classificationsReceived: EventEmitter<Classification[]> = new EventEmitter<Classification[]>();
requestInProgress = false;
selectedClassification: Classification = new Classification();
classifications: Classification[] = undefined;
constructor(private classificationService: ClassificationsService) {
}
ngOnInit() {
this.requestInProgress = true;
this.classificationService.getClassifications().subscribe(classificationList => {
this.requestInProgress = false;
this.classifications = classificationList;
this.classificationsReceived.emit(this.classifications);
});
}
@Input()
set _task(task: Task) {
this.task = task;
this.selectedClassification = task.classificationSummaryResource;
}
selectClassification(classification: Classification) {
this.selectedClassification = classification;
this.task.classificationSummaryResource = classification;
}
}

View File

@ -31,11 +31,12 @@
<div class="panel panel-default" *ngIf="task && !requestInProgress">
<div class="panel-heading">
<div class="pull-right btn-group">
<button type="button" (click)="updateTask()" class="btn btn-default btn-primary" data-toggle="tooltip" title="Save">
<button type="button" (click)="onSave()" class="btn btn-default btn-primary" data-toggle="tooltip"
title="Save">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
</button>
<button type="button" title="Open task to work on it" class="btn btn-default" aria-label="Left Align"
[disabled]="workOnTaskDisabled()" (click)="openTask(task.taskId)">
[disabled]="workOnTaskDisabled()" (click)="openTask()">
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
</button>
<button type="button" (click)="resetTask()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
@ -45,14 +46,16 @@
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
<h4 class="panel-header"><b>{{task?.name}}</b></h4>
<h4 class="panel-header">{{task.name}}&nbsp;
<span *ngIf="!task.taskId" class="badge warning"> {{'Creating Task'}}</span>
</h4>
</div>
<div class="panel-body">
<form #TaskForm="ngForm">
<div class="tab-content">
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'general'}">
<taskana-task-details-general-fields [task]="task"></taskana-task-details-general-fields>
<taskana-task-details-general-fields [_task]="task"></taskana-task-details-general-fields>
</div>
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'custom'}">
@ -62,7 +65,8 @@
<taskana-task-details-attributes [attributes]="task.customAttributes"></taskana-task-details-attributes>
</div>
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'callback-info'}">
<taskana-task-details-attributes [attributes]="task.callbackInfo" [callbackInfo]="true"></taskana-task-details-attributes>
<taskana-task-details-attributes [attributes]="task.callbackInfo"
[callbackInfo]="true"></taskana-task-details-attributes>
</div>
</div>
</form>

View File

@ -0,0 +1,3 @@
.panel > .panel-body {
max-height: calc(100vh - 150px);
}

View File

@ -1,16 +1,20 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Subscription} from 'rxjs';
import {ActivatedRoute, Router} from '@angular/router';
import { TaskService } from 'app/workplace/services/task.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import {TaskService} from 'app/workplace/services/task.service';
import {RemoveConfirmationService} from 'app/services/remove-confirmation/remove-confirmation.service';
import { Task } from 'app/workplace/models/task';
import { ErrorModel } from '../../models/modal-error';
import { ErrorModalService } from '../../services/errorModal/error-modal.service';
import { RequestInProgressService } from '../../services/requestInProgress/request-in-progress.service';
import { AlertService } from '../../services/alert/alert.service';
import { AlertModel, AlertType } from '../../models/alert';
import {Task} from 'app/workplace/models/task';
import {ErrorModel} from 'app/models/modal-error';
import {ErrorModalService} from 'app/services/errorModal/error-modal.service';
import {RequestInProgressService} from 'app/services/requestInProgress/request-in-progress.service';
import {AlertService} from 'app/services/alert/alert.service';
import {AlertModel, AlertType} from 'app/models/alert';
import {TaskanaDate} from 'app/shared/util/taskana.date';
import {ObjectReference} from 'app/workplace/models/object-reference';
import {Workbasket} from 'app/models/workbasket';
import {WorkplaceService} from 'app/workplace/services/workplace.service';
@Component({
selector: 'taskana-task-details',
@ -18,63 +22,104 @@ import { AlertModel, AlertType } from '../../models/alert';
styleUrls: ['./taskdetails.component.scss']
})
export class TaskdetailsComponent implements OnInit, OnDestroy {
task: Task = null;
taskClone: Task = null;
task: Task = undefined;
taskClone: Task = undefined;
requestInProgress = false;
tabSelected = 'general';
currentWorkbasket: Workbasket = undefined;
currentId: string = undefined;
private routeSubscription: Subscription;
private workbasketSubscription: Subscription;
constructor(private route: ActivatedRoute,
private taskService: TaskService,
private router: Router,
private removeConfirmationService: RemoveConfirmationService,
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private errorModalService: ErrorModalService) {
private taskService: TaskService,
private workplaceService: WorkplaceService,
private router: Router,
private removeConfirmationService: RemoveConfirmationService,
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private errorModalService: ErrorModalService) {
}
ngOnInit() {
this.currentWorkbasket = this.workplaceService.currentWorkbasket;
this.workbasketSubscription = this.workplaceService.getSelectedWorkbasket().subscribe(workbasket => {
this.currentWorkbasket = workbasket;
});
this.routeSubscription = this.route.params.subscribe(params => {
const id = params['id'];
this.getTask(id);
this.currentId = params['id'];
if (!this.currentWorkbasket && this.currentId === 'new-task') {
this.router.navigate(['']);
}
this.getTask();
});
}
resetTask(): void {
this.task = { ...this.taskClone };
this.task = {...this.taskClone};
this.task.customAttributes = this.taskClone.customAttributes.slice(0);
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
this.task.primaryObjRef = {...this.taskClone.primaryObjRef};
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
}
getTask(id: string): void {
getTask(): void {
this.requestInProgress = true;
this.taskService.getTask(id).subscribe(task => {
if (this.currentId === 'new-task') {
this.requestInProgress = false;
this.task = task;
this.task = new Task(undefined, new ObjectReference(), this.currentWorkbasket);
this.cloneTask();
this.taskService.selectTask(task);
}, err => {
this.errorModalService.triggerError(
new ErrorModel('An error occurred while fetching the task', err));
});
} else {
this.taskService.getTask(this.currentId).subscribe(task => {
this.requestInProgress = false;
this.task = task;
this.cloneTask();
this.taskService.selectTask(task);
}, err => {
this.errorModalService.triggerError(
new ErrorModel('An error occurred while fetching the task', err));
});
}
}
onSave() {
this.requestInProgressService.setRequestInProgress(true);
this.currentId === 'new-task' ? this.createTask() : this.updateTask();
}
updateTask() {
this.requestInProgressService.setRequestInProgress(true);
this.taskService.updateTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.task = task;
this.cloneTask();
this.taskService.publishUpdatedTask(task);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Update successful!'))
}, err => {this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'Update not successful!'))});
}, err => {
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'Update not successful!'))
});
}
openTask(taskId: string) {
this.router.navigate([{ outlets: { detail: `task/${taskId}` } }], { relativeTo: this.route.parent });
createTask() {
this.addDateToTask();
this.taskService.createTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Task ${this.currentId} was created successfully`));
this.task = task;
this.taskService.selectTask(this.task);
this.taskService.publishAddedTask(task);
this.router.navigate(['../' + task.taskId], {relativeTo: this.route});
});
}
private addDateToTask() {
const date = TaskanaDate.getDate();
this.task.created = date;
this.task.modified = date;
}
openTask() {
this.router.navigate([{outlets: {detail: `task/${this.currentId}`}}], {relativeTo: this.route.parent});
}
workOnTaskDisabled(): boolean {
@ -83,10 +128,9 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
deleteTask(): void {
this.removeConfirmationService.setRemoveConfirmation(this.deleteTaskConfirmation.bind(this),
`You are going to delete Task: ${this.task.taskId}. Can you confirm this action?`);
`You are going to delete Task: ${this.currentId}. Can you confirm this action?`);
}
deleteTaskConfirmation(): void {
this.taskService.deleteTask(this.task).subscribe();
this.taskService.publishDeletedTask(this.task);
@ -101,7 +145,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
backClicked(): void {
this.task = undefined;
this.taskService.selectTask(this.task);
this.router.navigate(['./'], { relativeTo: this.route.parent });
this.router.navigate(['./'], {relativeTo: this.route.parent});
}
ngOnDestroy(): void {
@ -111,8 +155,9 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
}
private cloneTask() {
this.taskClone = { ...this.task };
this.taskClone = {...this.task};
this.taskClone.customAttributes = this.task.customAttributes.slice(0);
this.taskClone.callbackInfo = this.task.callbackInfo.slice(0);
this.taskClone.primaryObjRef = {...this.task.primaryObjRef};
}
}

View File

@ -1,8 +1,15 @@
<li id="tasklist-action-toolbar" class="list-group-item tab-align">
<div class="row">
<div class="col-xs-9">
<div *ngIf="currentBasket">
<button (click)="createTask()" type="button"
class="btn btn-default pull-left green-blue"
title="Add Task to current Workbasket">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
<div class="col-xs-8">
<div class="input-group">
<input [(ngModel)]="result" [typeahead]="workbasketNames" class="form-control"
<input [(ngModel)]="resultName" [typeahead]="workbasketNames" class="form-control"
(typeaheadOnSelect)="workbasketSelected = true" (typeaheadNoResults)="workbasketSelected = false"
placeholder="Search for Workbasket ..."/>
<span class="input-group-btn">
@ -14,10 +21,9 @@
<div class="pull-right margin-right">
<taskana-sort
[enabled]="currentBasket"
[sortingFields]="sortingFields"
(performSorting)="sorting($event)"></taskana-sort>
<button [disabled]="!currentBasket" class="btn btn-default collapsed" type="button"
<button class="btn btn-default collapsed" type="button"
id="collapsedMenufilterWb" aria-expanded="false"
(click)="toolbarState=!toolbarState">
<span class="glyphicon glyphicon-filter blue"></span>

View File

@ -1,12 +1,14 @@
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { Task } from 'app/workplace/models/task';
import { Workbasket } from 'app/models/workbasket';
import { TaskService } from 'app/workplace/services/task.service';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { SortingModel } from 'app/models/sorting';
import { FilterModel } from 'app/models/filter';
import { TaskanaType } from 'app/models/taskana-type';
import { expandDown } from 'app/shared/animations/expand.animation';
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {Task} from 'app/workplace/models/task';
import {Workbasket} from 'app/models/workbasket';
import {TaskService} from 'app/workplace/services/task.service';
import {WorkbasketService} from 'app/services/workbasket/workbasket.service';
import {SortingModel} from 'app/models/sorting';
import {FilterModel} from 'app/models/filter';
import {TaskanaType} from 'app/models/taskana-type';
import {expandDown} from 'app/shared/animations/expand.animation';
import {ActivatedRoute, Router} from '@angular/router';
import {WorkplaceService} from 'app/workplace/services/workplace.service';
@Component({
selector: 'taskana-tasklist-toolbar',
@ -16,16 +18,16 @@ import { expandDown } from 'app/shared/animations/expand.animation';
})
export class TaskListToolbarComponent implements OnInit {
@Output() basketChanged = new EventEmitter<Workbasket>();
@Output() performSorting = new EventEmitter<SortingModel>();
@Output() performFilter = new EventEmitter<FilterModel>();
sortingFields = new Map([['name', 'Name'], ['priority', 'Priority'], ['due', 'Due'], ['planned', 'Planned']]);
filterParams = { name: '', key: '', owner: '', priority: '', state: '' };
filterParams = {name: '', key: '', owner: '', priority: '', state: ''};
tasks: Task[] = [];
workbasketNames: string[] = [];
result = '';
resultName = '';
resultId = '';
workbaskets: Workbasket[];
currentBasket: Workbasket;
@ -34,7 +36,10 @@ export class TaskListToolbarComponent implements OnInit {
filterType = TaskanaType.TASKS;
constructor(private taskService: TaskService,
private workbasketService: WorkbasketService) {
private workbasketService: WorkbasketService,
private workplaceService: WorkplaceService,
private router: Router,
private route: ActivatedRoute) {
}
ngOnInit() {
@ -45,10 +50,11 @@ export class TaskListToolbarComponent implements OnInit {
});
});
this.taskService.getSelectedTask().subscribe(t => {
if (!this.result) {
this.result = t.workbasketSummaryResource.name;
if (!this.resultName) {
this.resultName = t.workbasketSummaryResource.name;
this.resultId = t.workbasketSummaryResource.workbasketId;
this.currentBasket = t.workbasketSummaryResource;
this.workplaceService.selectWorkbasket(this.currentBasket);
this.workbasketSelected = true;
}
})
@ -58,18 +64,20 @@ export class TaskListToolbarComponent implements OnInit {
this.toolbarState = false;
if (this.workbaskets) {
this.workbaskets.forEach(workbasket => {
if (workbasket.name === this.result) {
if (workbasket.name === this.resultName) {
this.resultId = workbasket.workbasketId;
this.currentBasket = workbasket;
this.workplaceService.selectWorkbasket(this.currentBasket);
}
});
if (!this.resultId) {
this.currentBasket = undefined;
this.workplaceService.selectWorkbasket(undefined);
}
this.basketChanged.emit(this.currentBasket);
}
this.resultId = '';
this.router.navigate(['']);
}
sorting(sort: SortingModel) {
@ -79,4 +87,9 @@ export class TaskListToolbarComponent implements OnInit {
filtering(filterBy: FilterModel) {
this.performFilter.emit(filterBy);
}
createTask() {
this.taskService.selectTask(undefined);
this.router.navigate([{outlets: {detail: 'taskdetail/new-task'}}], {relativeTo: this.route});
}
}

View File

@ -1,6 +1,5 @@
<div class="task-list-full-height">
<taskana-tasklist-toolbar (basketChanged)="loadBasketID($event)"
(performSorting)="performSorting($event)"
<div class="task-list-full-height taskana-task-list">
<taskana-tasklist-toolbar (performSorting)="performSorting($event)"
(performFilter)="performFilter($event)">
</taskana-tasklist-toolbar>
<div *ngIf="!requestInProgress">

View File

@ -3,7 +3,7 @@
}
.task-list-full-height {
height: calc(100vh - 55px);
// height: calc(100vh - 55px);
}
.row.list-group {
@ -18,8 +18,7 @@
ul {
max-height: 90vh;
margin-bottom: 10px;
overflow: hidden;
overflow-y: scroll;
overflow-y: auto;
}
a > label {

View File

@ -8,6 +8,7 @@ import {Workbasket} from 'app/models/workbasket';
import {FilterModel} from 'app/models/filter';
import {AlertService} from 'app/services/alert/alert.service';
import {AlertModel, AlertType} from 'app/models/alert';
import {WorkplaceService} from 'app/workplace/services/workplace.service';
@Component({
selector: 'taskana-task-list',
@ -34,10 +35,13 @@ export class TasklistComponent implements OnInit, OnDestroy {
private taskChangeSubscription: Subscription;
private taskDeletedSubscription: Subscription;
private taskAddedSubscription: Subscription;
private workbasketChangeSubscription: Subscription;
constructor(private router: Router,
private route: ActivatedRoute,
private taskService: TaskService,
private workplaceService: WorkplaceService,
private alertService: AlertService) {
this.taskChangeSubscription = this.taskService.taskChangedStream.subscribe(task => {
for (let i = 0; i < this.tasks.length; i++) {
@ -52,7 +56,15 @@ export class TasklistComponent implements OnInit, OnDestroy {
this.tasks.splice(i, 1);
}
}
})
});
this.workbasketChangeSubscription = this.workplaceService.workbasketSelectedStream.subscribe(workbasket => {
this.currentBasket = workbasket;
this.getTasks();
});
this.taskAddedSubscription = this.taskService.taskAddedStream.subscribe(task => {
this.getTasks();
this.selectedId = task.taskId;
});
}
ngOnInit() {
@ -74,11 +86,6 @@ export class TasklistComponent implements OnInit, OnDestroy {
this.router.navigate([{outlets: {detail: `taskdetail/${this.selectedId}`}}], {relativeTo: this.route});
}
loadBasketID(workbasket: Workbasket) {
this.currentBasket = workbasket;
this.getTasks();
}
performSorting(sort: SortingModel) {
this.sort = sort;
this.getTasks();
@ -91,22 +98,28 @@ export class TasklistComponent implements OnInit, OnDestroy {
getTasks(): void {
this.requestInProgress = true;
this.taskService.findTasksWithWorkbasket(this.currentBasket.workbasketId, this.sort.sortBy, this.sort.sortDirection,
this.filterBy.filterParams.name, this.filterBy.filterParams.owner, this.filterBy.filterParams.priority,
this.filterBy.filterParams.state)
.subscribe(tasks => {
this.requestInProgress = false;
if (tasks._embedded) {
this.tasks = tasks._embedded.tasks;
} else {
this.tasks = [];
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'The selected Workbasket is empty!'));
}
});
if (this.currentBasket === undefined) {
this.requestInProgress = false;
this.tasks = [];
} else {
this.taskService.findTasksWithWorkbasket(this.currentBasket.workbasketId, this.sort.sortBy, this.sort.sortDirection,
this.filterBy.filterParams.name, this.filterBy.filterParams.owner, this.filterBy.filterParams.priority,
this.filterBy.filterParams.state)
.subscribe(tasks => {
this.requestInProgress = false;
if (tasks._embedded) {
this.tasks = tasks._embedded.tasks;
} else {
this.tasks = [];
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'The selected Workbasket is empty!'));
}
});
}
}
ngOnDestroy(): void {
this.taskChangeSubscription.unsubscribe();
this.taskDeletedSubscription.unsubscribe();
this.workbasketChangeSubscription.unsubscribe();
}
}

View File

@ -19,9 +19,12 @@ import {CodeComponent} from './components/code/code.component';
import {OrderTasksByPipe} from './util/orderTasksBy.pipe';
import {TaskService} from './services/task.service';
import {ClassificationsService} from 'app/services/classifications/classifications.service';
import {WorkbasketService} from 'app/services/workbasket/workbasket.service';
import {SharedModule} from '../shared/shared.module';
import {SharedModule} from 'app/shared/shared.module';
import {CustomHttpClientInterceptor} from './services/custom-http-interceptor/custom-http-interceptor.service';
import {ClassificationCategoriesService} from 'app/services/classifications/classification-categories.service';
import {WorkplaceService} from './services/workplace.service';
const MODULES = [
@ -52,6 +55,9 @@ const DECLARATIONS = [
imports: MODULES,
providers: [
TaskService,
ClassificationsService,
ClassificationCategoriesService,
WorkplaceService,
WorkbasketService,
{
provide: HTTP_INTERCEPTORS,

View File

@ -280,7 +280,8 @@ body{
}
taskana-workbasket-information,taskana-task-details, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets, taskana-monitor-tasks,
taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management, taskana-classification-details,taskana-workbasket-details {
taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management, taskana-classification-details,taskana-workbasket-details,
taskana-task-list{
& .panel{
border: none;
box-shadow: none;