TSK-747 add new history screen

This commit is contained in:
Martin Rojas Miguel Angel 2018-12-04 12:01:23 +01:00 committed by Holger Hagen
parent ebc2a5327f
commit 3819b4c5b2
89 changed files with 4781 additions and 6675 deletions

View File

@ -35,42 +35,6 @@
<spring.ldap.version>2.3.2.RELEASE</spring.ldap.version>
</properties>
<profiles>
<profile>
<id>history.plugin</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<build.profile.id>history.plugin</build.profile.id>
</properties>
<dependencies>
<dependency>
<groupId>pro.taskana.simplehistory</groupId>
<artifactId>taskana-simplehistory-provider</artifactId>
<version>0.0.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<includes>
<include>**/*Plugin*Test.java</include>
</includes>
<excludes>
<exclude>**/Test/*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>pro.taskana</groupId>
@ -82,6 +46,11 @@
<artifactId>taskana-history-rest-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>pro.taskana.simplehistory</groupId>
<artifactId>taskana-simplehistory-provider</artifactId>
<version>0.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

View File

@ -732,6 +732,20 @@ include::../../../{snippets}/GetCurrentUserInfoDocTest/http-response.adoc[]
include::../../../{snippets}/GetCurrentUserInfoDocTest/response-fields.adoc[]
=== History-Provider-Is-Enabled
This resource returns if history provider is enabled.
include::../../../{snippets}/GetHistoryProviderIsEnabled/http-request.adoc[]
==== Example Response
include::../../../{snippets}/GetHistoryProviderIsEnabled/http-response.adoc[]
==== Response Structure
include::../../../{snippets}/GetHistoryProviderIsEnabled/response-fields.adoc[]
[[resource-subsets]]
== Resource-Subsets

View File

@ -129,4 +129,14 @@ public class TaskanaEngineControllerRestDocumentation {
.andDo(MockMvcRestDocumentation.document("GetCurrentUserInfoDocTest",
responseFields(currentUserInfoFieldDescriptors)));
}
@Test
public void getHistoryProviderIsEnabled() throws Exception {
this.mockMvc.perform(RestDocumentationRequestBuilders
.get("http://127.0.0.1:" + port + "/v1/history-provider-enabled")
.accept("application/json")
.header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcRestDocumentation.document("GetHistoryProviderIsEnabled"));
}
}

View File

@ -1,5 +1,3 @@
SET SCHEMA TASKANA;
INSERT INTO HISTORY_EVENTS (BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY, ATTACHMENT_CLASSIFICATION_KEY, COMMENT, OLD_VALUE, NEW_VALUE, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, OLD_DATA, NEW_DATA) VALUES
-- BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY , POR_SYSTEM, POR_INSTANCE , POR_TYPE , POR_VALUE , TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY , ATTACHMENT_CLASSIFICATION_KEY , COMMENT , OLD_VALUE , NEW_VALUE , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , OLD_DATA , NEW_DATA
('BPI:01' ,'', 'TKI:000000000000000000000000000000000000', 'CREATE', CURRENT_TIMESTAMP, 'USER_2_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', 'L140101' , 'TASK' ,'' , 'this task has been created' ,'old_val' ,'new_val' ,'custom1' ,'custom2' , 'custom3' ,'custom4' ,'123' ,'456'),

View File

@ -71,6 +71,11 @@ public class TaskanaEngineController {
return new ResponseEntity<>(resource, HttpStatus.OK);
}
@GetMapping(path = "/v1/history-provider-enabled", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Boolean> getIsHistoryProviderEnabled() {
return new ResponseEntity<>(taskanaEngineImpl.getHistoryEventProducer().isEnabled(), HttpStatus.OK);
}
/**
* Get the current application version.
*

9388
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,15 +13,15 @@
},
"private": true,
"dependencies": {
"@angular/animations": "6.0.9",
"@angular/common": "6.0.9",
"@angular/compiler": "6.0.9",
"@angular/core": "6.0.9",
"@angular/forms": "6.0.9",
"@angular/http": "6.0.9",
"@angular/platform-browser": "6.0.9",
"@angular/platform-browser-dynamic": "6.0.9",
"@angular/router": "6.0.9",
"@angular/animations": "7.1.3",
"@angular/common": "7.1.3",
"@angular/compiler": "7.1.3",
"@angular/core": "7.1.3",
"@angular/forms": "7.1.3",
"@angular/http": "7.1.3",
"@angular/platform-browser": "7.1.3",
"@angular/platform-browser-dynamic": "7.1.3",
"@angular/router": "7.1.3",
"ajv": "6.5.2",
"angular-svg-icon": "6.0.0",
"angular-tree-component": "7.1.0",
@ -36,22 +36,22 @@
"ng2-charts": "1.6.0",
"ngx-bootstrap": "3.2.0",
"ngx-infinite-scroll": "6.0.1",
"node-sass": "4.9.2",
"node-sass": "^4.11.0",
"popper.js": "1.14.3",
"rxjs": "6.2.2",
"rxjs": "6.3.3",
"zone.js": "0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "0.6.8",
"@angular/cli": "6.0.8",
"@angular/compiler-cli": "6.0.9",
"@angular-devkit/build-angular": "^0.13.2",
"@angular/cli": "7.1.3",
"@angular/compiler-cli": "^7.2.5",
"@types/jasmine": "2.8.4",
"@types/node": "9.3.0",
"codelyzer": "4.4.2",
"hoek": "5.0.3",
"jasmine-core": "2.9.1",
"jasmine-spec-reporter": "4.2.1",
"karma": "3.1.1",
"karma": "^4.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.3.3",
@ -64,6 +64,6 @@
"ts-mockito": "2.3.0",
"ts-node": "4.1.0",
"tslint": "5.9.1",
"typescript": "2.7.2"
"typescript": "3.1.6"
}
}

View File

@ -165,16 +165,13 @@
data-target="#myModal">
Belonging groups
</button>
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Belonging groups</h4>
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body">
<ul *ngIf="belongingGroups !== undefined && belongingGroups.length > 0 " class="list-group">
<li *ngFor="let group of belongingGroups" class="list-group-item">{{group.name}}</li>
@ -182,21 +179,19 @@
<p *ngIf="belongingGroups === undefined || belongingGroups.length === 0">The user is not associated to
any groups</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="pull-right btn-group">
<button *ngIf="AccessItemsForm" type="button" (click)="revokeAccess()" class="btn btn-default" data-toggle="tooltip" title="Revoke access"
[disabled]=isGroup>
<button *ngIf="AccessItemsForm" type="button" (click)="revokeAccess()" class="btn btn-default" data-toggle="tooltip"
title="Revoke access" [disabled]=isGroup>
<span class="material-icons md-20 red">clear</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@ -11,8 +11,8 @@ import { AccessItemWorkbasket } from 'app/models/access-item-workbasket';
import { AccessIdsService } from '../../shared/services/access-ids/access-ids.service';
import { SortingModel } from 'app/models/sorting';
import { RequestInProgressService } from '../../services/requestInProgress/request-in-progress.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { ErrorModel } from 'app/models/modal-error';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import { AlertModel, AlertType } from 'app/models/alert';
import { AlertService } from 'app/services/alert/alert.service';
@ -78,7 +78,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private alertService: AlertService,
private errorModalService: ErrorModalService) { }
private generalModalService: GeneralModalService) { }
ngOnInit() {
}
@ -101,8 +101,8 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorModalService.triggerError(
new ErrorModel(
this.generalModalService.triggerMessage(
new MessageModal(
'There was error while retrieving your access ids with groups',
error
)
@ -136,8 +136,8 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorModalService.triggerError(
new ErrorModel(
this.generalModalService.triggerMessage(
new MessageModal(
'There was error while retrieving your access items',
error
)
@ -172,8 +172,8 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorModalService.triggerError(
new ErrorModel(
this.generalModalService.triggerMessage(
new MessageModal(
`You can't delete a group`,
error
)

View File

@ -6,7 +6,7 @@ import { WorkbasketDetailsComponent } from 'app/administration/workbasket/detail
import { MasterAndDetailComponent } from 'app/shared/master-and-detail/master-and-detail.component';
import { ClassificationListComponent } from 'app/administration/classification/master/list/classification-list.component';
import { ClassificationDetailsComponent } from 'app/administration/classification/details/classification-details.component';
import { DomainGuard } from 'app/guards/domain-guard';
import { DomainGuard } from 'app/guards/domain.guard';
import { AccessItemsManagementComponent } from './access-items-management/access-items-management.component';
const routes: Routes = [

View File

@ -21,6 +21,7 @@ import {ClassificationListComponent} from './classification/master/list/classifi
import {ClassificationDetailsComponent} from './classification/details/classification-details.component';
import {ImportExportComponent} from './components/import-export/import-export.component';
import {ClassificationTypesSelectorComponent} from 'app/shared/classification-types-selector/classification-types-selector.component';
/**
* Services
*/

View File

@ -32,125 +32,132 @@
</div>
<div class="panel-body">
<form #ClassificationForm="ngForm">
<div class="col-md-6">
<div class="form-group required">
<label for="classification-key" class="control-label">Key</label>
<input type="text" required #key="ngModel" [disabled]="action!== 'CREATE'? true : false" class="form-control"
id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key">
<taskana-field-error-display *ngIf="action === 'CREATE'" [displayError]="!isFieldValid('classification.key')"
[validationTrigger]="this.toogleValidationMap.get('classification.key')" errorMessage="* Key is required">
</taskana-field-error-display>
</div>
<div class="form-group required">
<label for="classification-name" class="control-label">Name</label>
<input type="text" required #name="ngModel" class="form-control" id="classification-name" placeholder="Name"
[(ngModel)]="classification.name" name="classification.name">
<taskana-field-error-display [displayError]="!isFieldValid('classification.name')" [validationTrigger]="this.toogleValidationMap.get('classification.name')"
errorMessage="* Name is required">
</taskana-field-error-display>
</div>
<div class="form-group">
<label for="classification-domain" class="control-label">Domain</label>
<input type="text" disabled #domain="ngModel" class="form-control" id="classification-domain" placeholder="Domain"
[(ngModel)]="classification.domain" name="classification.domain">
<div class="row">
<a *ngIf="!masterDomainSelected()" (click)="validChanged()">
<label>
<b>Valid in Domain:</b>
<span class="material-icons md-20 blue ">{{classification.isValidInDomain ? 'check_box':
'check_box_outline_blank'}}</span>
</label>
</a>
</div>
<div class="form-group required btn-group">
<label for="classification-category" class="control-label">Category</label>
<div class="dropdown clearfix ">
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="text-top">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(classification.category).name}}" data-toggle="tooltip"
[title]="getCategoryIcon(classification.category).text"></svg-icon>
</span>
{{classification.category}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
<li>
<a *ngFor="let category of categories" (click)="selectCategory(category)">
<div class="col-md-6">
<div class="form-group required">
<label for="classification-key" class="control-label">Key</label>
<input type="text" required #key="ngModel" [disabled]="action!== 'CREATE'? true : false" class="form-control"
id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key">
<taskana-field-error-display *ngIf="action === 'CREATE'" [displayError]="!isFieldValid('classification.key')"
[validationTrigger]="this.toogleValidationMap.get('classification.key')" errorMessage="* Key is required">
</taskana-field-error-display>
</div>
<div class="form-group required">
<label for="classification-name" class="control-label">Name</label>
<input type="text" required #name="ngModel" class="form-control" id="classification-name" placeholder="Name"
[(ngModel)]="classification.name" name="classification.name">
<taskana-field-error-display [displayError]="!isFieldValid('classification.name')" [validationTrigger]="this.toogleValidationMap.get('classification.name')"
errorMessage="* Name is required">
</taskana-field-error-display>
</div>
<div class="form-group">
<label for="classification-domain" class="control-label">Domain</label>
<input type="text" disabled #domain="ngModel" class="form-control" id="classification-domain"
placeholder="Domain" [(ngModel)]="classification.domain" name="classification.domain">
<a *ngIf="!masterDomainSelected()" (click)="validChanged()">
<label>
<b>Valid in Domain:</b>
<span class="material-icons md-20 blue ">{{classification.isValidInDomain ? 'check_box':
'check_box_outline_blank'}}</span>
</label>
</a>
</div>
<div class="row">
<div class="form-group col-xs-6">
<label for="classification-priority" class="control-label">Priority</label>
<taskana-number-picker [(ngModel)]="classification.priority" name="classification.priority"></taskana-number-picker>
</div>
<div class="form-group required btn-group col-xs-6">
<label for="classification-category" class="control-label">Category</label>
<div class="dropdown clearfix ">
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
<span class="text-top">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(category).name}}" data-toggle="tooltip"
[title]="getCategoryIcon(category).text"></svg-icon>
{{category}}
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(classification.category).name}}"
data-toggle="tooltip" [title]="getCategoryIcon(classification.category).text"></svg-icon>
</span>
</a>
</li>
</ul>
{{classification.category}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
<li>
<a *ngFor="let category of categories" (click)="selectCategory(category)">
<span class="text-top">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(category).name}}" data-toggle="tooltip"
[title]="getCategoryIcon(category).text"></svg-icon>
{{category}}
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="classification-service-level" class="control-label">Service Level</label>
<input type="text" class="form-control" id="classification-service-level" placeholder="Service Level"
[(ngModel)]="classification.serviceLevel" name="classification.serviceLevel">
</div>
<div class="form-group">
<label for="classification-application-entry-point" class="control-label">Application entry point</label>
<input type="text" class="form-control" id="classification-application-entry-point" placeholder="Application entry point"
[(ngModel)]="classification.applicationEntryPoint" name="classification.applicationEntryPoint">
</div>
<div class="form-group">
<label for="classification-description" class="control-label">Description</label>
<textarea class="form-control" rows="5" id="classification-description" placeholder="Description"
[(ngModel)]="classification.description" name="classification.description"></textarea>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="classification-priority" class="control-label">Priority</label>
<input type="text" class="form-control" id="classification-priority" placeholder="Priority" [(ngModel)]="classification.priority"
name="classification.priority">
<div class="row">
<div class="col-md-6">
<div *ngIf="custom1Field.visible" class="form-group">
<label for="classification-custom-1" class="control-label">{{custom1Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-1" placeholder="{{custom1Field.field}}"
[(ngModel)]="classification.custom1" name="classification.custom1">
</div>
<div *ngIf="custom2Field.visible" class="form-group">
<label for="classification-custom-2" class="control-label">{{custom2Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-2" placeholder="{{custom2Field.field}}"
[(ngModel)]="classification.custom2" name="classification.custom2">
</div>
<div *ngIf="custom3Field.visible" class="form-group">
<label for="classification-custom-3" class="control-label">{{custom3Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-3" placeholder="{{custom3Field.field}}"
[(ngModel)]="classification.custom3" name="classification.custom3">
</div>
<div *ngIf="custom4Field.visible" class="form-group">
<label for="classification-custom-4" class="control-label">{{custom4Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-4" placeholder="{{custom4Field.field}}"
[(ngModel)]="classification.custom4" name="classification.custom4">
</div>
</div>
<div class="form-group">
<label for="classification-service-level" class="control-label">Service Level</label>
<input type="text" class="form-control" id="classification-service-level" placeholder="Service Level"
[(ngModel)]="classification.serviceLevel" name="classification.serviceLevel">
</div>
<div class="form-group">
<label for="classification-application-entry-point" class="control-label">Application entry point</label>
<input type="text" class="form-control" id="classification-application-entry-point" placeholder="Application entry point"
[(ngModel)]="classification.applicationEntryPoint" name="classification.applicationEntryPoint">
</div>
<div class="form-group">
<label for="classification-description" class="control-label">Description</label>
<textarea class="form-control" rows="5" id="classification-description" placeholder="Description"
[(ngModel)]="classification.description" name="classification.description"></textarea>
</div>
</div>
<div class="col-md-6">
<div *ngIf="custom1Field.visible" class="form-group">
<label for="classification-custom-1" class="control-label">{{custom1Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-1" placeholder="{{custom1Field.field}}"
[(ngModel)]="classification.custom1" name="classification.custom1">
</div>
<div *ngIf="custom2Field.visible" class="form-group">
<label for="classification-custom-2" class="control-label">{{custom2Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-2" placeholder="{{custom2Field.field}}"
[(ngModel)]="classification.custom2" name="classification.custom2">
</div>
<div *ngIf="custom3Field.visible" class="form-group">
<label for="classification-custom-3" class="control-label">{{custom3Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-3" placeholder="{{custom3Field.field}}"
[(ngModel)]="classification.custom3" name="classification.custom3">
</div>
<div *ngIf="custom4Field.visible" class="form-group">
<label for="classification-custom-4" class="control-label">{{custom4Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-4" placeholder="{{custom4Field.field}}"
[(ngModel)]="classification.custom4" name="classification.custom4">
</div>
</div>
<div class="col-md-6">
<div *ngIf="custom5Field.visible" class="form-group">
<label for="classification-custom-5" class="control-label">{{custom5Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-5" placeholder="{{custom5Field.field}}"
[(ngModel)]="classification.custom5" name="classification.custom5">
</div>
<div *ngIf="custom6Field.visible" class="form-group">
<label for="classification-custom-6" class="control-label">{{custom6Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-6" placeholder="{{custom6Field.field}}"
[(ngModel)]="classification.custom6" name="classification.custom6">
</div>
<div *ngIf="custom7Field.visible" class="form-group">
<label for="classification-custom-7" class="control-label">{{custom7Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-7" placeholder="{{custom7Field.field}}"
[(ngModel)]="classification.custom7" name="classification.custom7">
</div>
<div *ngIf="custom8Field.visible" class="form-group">
<label for="classification-custom-8" class="control-label">{{custom8Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-8" placeholder="{{custom8Field.field}}"
[(ngModel)]="classification.custom8" name="classification.custom8">
<div class="col-md-6">
<div *ngIf="custom5Field.visible" class="form-group">
<label for="classification-custom-5" class="control-label">{{custom5Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-5" placeholder="{{custom5Field.field}}"
[(ngModel)]="classification.custom5" name="classification.custom5">
</div>
<div *ngIf="custom6Field.visible" class="form-group">
<label for="classification-custom-6" class="control-label">{{custom6Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-6" placeholder="{{custom6Field.field}}"
[(ngModel)]="classification.custom6" name="classification.custom6">
</div>
<div *ngIf="custom7Field.visible" class="form-group">
<label for="classification-custom-7" class="control-label">{{custom7Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-7" placeholder="{{custom7Field.field}}"
[(ngModel)]="classification.custom7" name="classification.custom7">
</div>
<div *ngIf="custom8Field.visible" class="form-group">
<label for="classification-custom-8" class="control-label">{{custom8Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-8" placeholder="{{custom8Field.field}}"
[(ngModel)]="classification.custom8" name="classification.custom8">
</div>
</div>
</div>
</form>

View File

@ -21,7 +21,7 @@ import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.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 { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { AlertService } from 'app/services/alert/alert.service';
import { TreeService } from 'app/services/tree/tree.service';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
@ -52,7 +52,7 @@ describe('ClassificationDetailsComponent', () => {
testBed.configureTestingModule({
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes), AngularSvgIconModule],
declarations: [ClassificationDetailsComponent, DummyDetailComponent],
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, HttpClient, ErrorModalService, AlertService,
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, HttpClient, GeneralModalService, AlertService,
TreeService, ClassificationCategoriesService, CustomFieldsService, ImportExportService]
})
};

View File

@ -4,7 +4,7 @@ import { Subscription } from 'rxjs';
import { ClassificationDefinition } from 'app/models/classification-definition';
import { ACTION } from 'app/models/action';
import { ErrorModel } from 'app/models/modal-error';
import { MessageModal } from 'app/models/message-modal';
import { AlertModel, AlertType } from 'app/models/alert';
import { highlight } from 'app/shared/animations/validation.animation';
@ -12,7 +12,7 @@ import { TaskanaDate } from 'app/shared/util/taskana.date';
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 { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { AlertService } from 'app/services/alert/alert.service';
import { TreeService } from 'app/services/tree/tree.service';
@ -74,7 +74,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private router: Router,
private masterAndDetailService: MasterAndDetailService,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private treeService: TreeService,
@ -176,7 +176,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.afterRequest();
},
error => {
this.errorModalService.triggerError(new ErrorModel('There was an error creating a classification', error))
this.generalModalService.triggerMessage(new MessageModal('There was an error creating a classification', error))
this.afterRequest();
});
} else {
@ -188,7 +188,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${classification.key} was saved successfully`));
this.cloneClassification(classification);
}, error => {
this.errorModalService.triggerError(new ErrorModel('There was error while saving your classification', error))
this.generalModalService.triggerMessage(new MessageModal('There was error while saving your classification', error))
this.afterRequest();
})
}
@ -263,7 +263,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private checkDomainAndRedirect() {
this.domainSubscription = this.domainService.getSelectedDomain().subscribe(domain => {
if (this.classification && this.classification.domain !== domain) {
if (domain !== '' && this.classification && this.classification.domain !== domain) {
this.backClicked();
}
});
@ -271,8 +271,8 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private removeClassificationConfirmation() {
if (!this.classification || !this.classification.classificationId) {
this.errorModalService.triggerError(
new ErrorModel('There is no classification selected', 'Please check if you are creating a classification'));
this.generalModalService.triggerMessage(
new MessageModal('There is no classification selected', 'Please check if you are creating a classification'));
return false;
}
this.requestInProgressService.setRequestInProgress(true);
@ -288,7 +288,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.router.navigate(['administration/classifications']);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${key} was removed successfully`))
}, error => {
this.errorModalService.triggerError(new ErrorModel('There was error while removing your classification', error))
this.generalModalService.triggerMessage(new MessageModal('There was error while removing your classification', error))
this.afterRequest();
})
}

View File

@ -18,7 +18,7 @@ import { AlertService } from 'app/services/alert/alert.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';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
import {
@ -55,7 +55,7 @@ describe('ClassificationListComponent', () => {
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule],
providers: [
HttpClient, WorkbasketDefinitionService, AlertService, ClassificationsService, DomainService, ClassificationDefinitionService,
ErrorModalService, RequestInProgressService, ClassificationCategoriesService, TreeService, ImportExportService
GeneralModalService, RequestInProgressService, ClassificationCategoriesService, TreeService, ImportExportService
]
})
};

View File

@ -6,7 +6,7 @@ import { ClassificationDefinitionService } from 'app/administration/services/cla
import { WorkbasketDefinitionService } from '../../services/workbasket-definition/workbasket-definition.service';
import { AlertService } from 'app/services/alert/alert.service';
import { HttpClientModule } from '@angular/common/http';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { configureTests } from 'app/app.test.configuration';
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
@ -22,7 +22,7 @@ describe('ImportExportComponent', () => {
declarations: [ImportExportComponent],
imports: [HttpClientModule, AngularSvgIconModule],
providers: [WorkbasketService, ClassificationDefinitionService, WorkbasketDefinitionService, AlertService,
ErrorModalService, ImportExportService]
GeneralModalService, ImportExportService]
})
};
configureTests(configure).then(testBed => {

View File

@ -3,8 +3,8 @@ import { ClassificationDefinitionService } from 'app/administration/services/cla
import { WorkbasketDefinitionService } from 'app/administration/services/workbasket-definition/workbasket-definition.service';
import { DomainService } from 'app/services/domain/domain.service';
import { TaskanaType } from 'app/models/taskana-type';
import { ErrorModel } from 'app/models/modal-error';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { environment } from 'environments/environment';
import { AlertService } from 'app/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/models/alert';
@ -30,7 +30,7 @@ export class ImportExportComponent implements OnInit {
private domainService: DomainService,
private workbasketDefinitionService: WorkbasketDefinitionService,
private classificationDefinitionService: ClassificationDefinitionService,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private alertService: AlertService,
public uploadservice: UploadService,
private importExportService: ImportExportService) {
@ -84,7 +84,7 @@ export class ImportExportComponent implements OnInit {
break;
default:
file.value = '';
this.errorModalService.triggerError(new ErrorModel(undefined,
this.generalModalService.triggerMessage(new MessageModal(undefined,
`This file format is not allowed! Please use a .json file.`));
}
return check;
@ -117,8 +117,8 @@ export class ImportExportComponent implements OnInit {
}
private errorHandler(title = 'Import was not successful', message) {
this.errorModalService.triggerError(
new ErrorModel(
this.generalModalService.triggerMessage(
new MessageModal(
title,
message
)

View File

@ -15,7 +15,7 @@ import { ICONTYPES } from 'app/models/type';
import { AccessItemsComponent } from './access-items.component';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { AlertService } from 'app/services/alert/alert.service';
@ -35,7 +35,7 @@ describe('AccessItemsComponent', () => {
testBed.configureTestingModule({
declarations: [AccessItemsComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule],
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService, RequestInProgressService,
providers: [WorkbasketService, AlertService, GeneralModalService, SavingWorkbasketService, RequestInProgressService,
CustomFieldsService, AccessIdsService, FormsValidatorService]
})
};

View File

@ -5,12 +5,12 @@ import { FormBuilder, Validators, FormArray } from '@angular/forms';
import { Workbasket } from 'app/models/workbasket';
import { WorkbasketAccessItems } from 'app/models/workbasket-access-items';
import { WorkbasketAccessItemsResource } from 'app/models/workbasket-access-items-resource';
import { ErrorModel } from 'app/models/modal-error';
import { MessageModal } from 'app/models/message-modal';
import { ACTION } from 'app/models/action';
import { AlertModel, AlertType } from 'app/models/alert';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { AlertService } from 'app/services/alert/alert.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
@ -80,7 +80,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
constructor(
private workbasketService: WorkbasketService,
private alertService: AlertService,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private customFieldsService: CustomFieldsService,
@ -181,7 +181,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`));
this.requestInProgressService.setRequestInProgress(false);
}, error => {
this.errorModalService.triggerError(new ErrorModel(`There was error while saving your workbasket's access items`, error))
this.generalModalService.triggerMessage(new MessageModal(`There was error while saving your workbasket's access items`, error))
this.requestInProgressService.setRequestInProgress(false);
})
}

View File

@ -14,7 +14,7 @@ import { WorkbasketDistributionTargetsResource } from 'app/models/workbasket-dis
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { AlertService } from 'app/services/alert/alert.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
@ -36,7 +36,7 @@ describe('DistributionTargetsComponent', () => {
testBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule],
declarations: [DistributionTargetsComponent, DualListComponent],
providers: [WorkbasketService, AlertService, SavingWorkbasketService, ErrorModalService, RequestInProgressService,
providers: [WorkbasketService, AlertService, SavingWorkbasketService, GeneralModalService, RequestInProgressService,
]
})
};

View File

@ -5,14 +5,14 @@ import { Workbasket } from 'app/models/workbasket';
import { WorkbasketSummary } from 'app/models/workbasket-summary';
import { WorkbasketSummaryResource } from 'app/models/workbasket-summary-resource';
import { WorkbasketDistributionTargetsResource } from 'app/models/workbasket-distribution-targets-resource';
import { ErrorModel } from 'app/models/modal-error';
import { MessageModal } from 'app/models/message-modal';
import { ACTION } from 'app/models/action';
import { AlertModel, AlertType } from 'app/models/alert';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { AlertService } from 'app/services/alert/alert.service';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Page } from 'app/models/page';
@ -69,9 +69,9 @@ export class DistributionTargetsComponent implements OnChanges, OnDestroy {
private workbasketService: WorkbasketService,
private alertService: AlertService,
private savingWorkbaskets: SavingWorkbasketService,
private errorModalService: ErrorModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService) { }
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService) { }
ngOnChanges(changes: SimpleChanges): void {
if (!this.initialized && changes.active && changes.active.currentValue === 'distributionTargets') {
@ -121,7 +121,7 @@ export class DistributionTargetsComponent implements OnChanges, OnDestroy {
return true;
},
error => {
this.errorModalService.triggerError(new ErrorModel(`There was error while saving your workbasket's distribution targets`, error))
this.generalModalService.triggerMessage(new MessageModal(`There was error while saving your workbasket's distribution targets`, error))
this.requestInProgressService.setRequestInProgress(false);
return false;
}

View File

@ -14,7 +14,7 @@ import { ICONTYPES } from 'app/models/type';
import { ACTION } from 'app/models/action';
import { Links } from 'app/models/links';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { AlertService } from 'app/services/alert/alert.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
@ -47,7 +47,7 @@ describe('WorkbasketInformationComponent', () => {
AngularSvgIconModule,
HttpClientModule,
RouterTestingModule.withRoutes(routes)],
providers: [WorkbasketService, AlertService, SavingWorkbasketService, ErrorModalService, RequestInProgressService,
providers: [WorkbasketService, AlertService, SavingWorkbasketService, GeneralModalService, RequestInProgressService,
CustomFieldsService, FormsValidatorService]
})

View File

@ -12,14 +12,14 @@ import { Subscription } from 'rxjs';
import { NgForm } from '@angular/forms';
import { ICONTYPES } from 'app/models/type';
import { ErrorModel } from 'app/models/modal-error';
import { MessageModal } from 'app/models/message-modal';
import { ACTION } from 'app/models/action';
import { Workbasket } from 'app/models/workbasket';
import { AlertModel, AlertType } from 'app/models/alert';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { AlertService } from 'app/services/alert/alert.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import {
SavingWorkbasketService,
SavingInformation
@ -81,7 +81,7 @@ export class WorkbasketInformationComponent
private alertService: AlertService,
private route: ActivatedRoute,
private router: Router,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private savingWorkbasket: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private customFieldsService: CustomFieldsService,
@ -168,8 +168,8 @@ export class WorkbasketInformationComponent
);
},
error => {
this.errorModalService.triggerError(
new ErrorModel(
this.generalModalService.triggerMessage(
new MessageModal(
`There was an error removing distribution target for ${
this.workbasket.workbasketId
}.`,
@ -204,8 +204,8 @@ export class WorkbasketInformationComponent
},
error => {
this.afterRequest();
this.errorModalService.triggerError(
new ErrorModel(
this.generalModalService.triggerMessage(
new MessageModal(
'There was error while saving your workbasket',
error
)
@ -256,8 +256,8 @@ export class WorkbasketInformationComponent
}
},
error => {
this.errorModalService.triggerError(
new ErrorModel('There was an error creating a workbasket', error)
this.generalModalService.triggerMessage(
new MessageModal('There was an error creating a workbasket', error)
);
this.requestInProgressService.setRequestInProgress(false);
}
@ -279,8 +279,8 @@ export class WorkbasketInformationComponent
this.requestInProgressService.setRequestInProgress(false);
this.workbasketService.triggerWorkBasketSaved();
if (response) {
this.errorModalService.triggerError(
new ErrorModel('There was an error marking workbasket for deletion',
this.generalModalService.triggerMessage(
new MessageModal('There was an error marking workbasket for deletion',
'It not possible to mark the workbasket for deletion, It has been deleted.')
);
} else {

View File

@ -20,7 +20,7 @@ import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
import { AlertService } from 'app/services/alert/alert.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { configureTests } from 'app/app.test.configuration';
@ -62,7 +62,7 @@ describe('WorkbasketDetailsComponent', () => {
declarations: [WorkbasketDetailsComponent, WorkbasketInformationComponent,
AccessItemsComponent,
DistributionTargetsComponent, DualListComponent, DummyDetailComponent],
providers: [WorkbasketService, MasterAndDetailService, ErrorModalService, RequestInProgressService,
providers: [WorkbasketService, MasterAndDetailService, GeneralModalService, RequestInProgressService,
AlertService, SavingWorkbasketService, CustomFieldsService, ImportExportService]
})
};

View File

@ -4,12 +4,12 @@ import { Subscription } from 'rxjs';
import { Workbasket } from 'app/models/workbasket';
import { ACTION } from 'app/models/action';
import { ErrorModel } from '../../../models/modal-error';
import { MessageModal } from '../../../models/message-modal';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service'
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service'
import { DomainService } from 'app/services/domain/domain.service';
import { ErrorModalService } from '../../../services/errorModal/error-modal.service';
import { GeneralModalService } from '../../../services/general-modal/general-modal.service';
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
@Component({
@ -39,7 +39,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
private router: Router,
private masterAndDetailService: MasterAndDetailService,
private domainService: DomainService,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private importExportService: ImportExportService) { }
@ -118,15 +118,15 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
this.requestInProgress = false;
this.checkDomainAndRedirect();
}, err => {
this.errorModalService.triggerError(
new ErrorModel('An error occurred while fetching the workbasket', err));
this.generalModalService.triggerMessage(
new MessageModal('An error occurred while fetching the workbasket', err));
});
}
}
private checkDomainAndRedirect() {
this.domainSubscription = this.domainService.getSelectedDomain().subscribe(domain => {
if (this.workbasket && this.workbasket.domain !== domain) {
if (domain !== '' && this.workbasket && this.workbasket.domain !== domain) {
this.backClicked();
}
});

View File

@ -1,11 +1,10 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { BusinessAdminGuard } from './guards/business-admin-guard';
import { MonitorGuard } from './guards/monitor-guard';
import { UserGuard } from './guards/user-guard';
import { BusinessAdminGuard } from './guards/business-admin.guard';
import { MonitorGuard } from './guards/monitor.guard';
import { UserGuard } from './guards/user.guard';
import { HistoryGuard } from './guards/history.guard';
import { NoAccessComponent } from './components/no-access/no-access.component';
const appRoutes: Routes = [
@ -24,6 +23,11 @@ const appRoutes: Routes = [
path: 'workplace',
loadChildren: './workplace/workplace.module#WorkplaceModule'
},
{
canActivate: [HistoryGuard],
path: 'history',
loadChildren: './history/history.module#HistoryModule'
},
{
path: 'no-role',
component: NoAccessComponent

View File

@ -2,7 +2,8 @@
<div class="container-fluid container-main" (window:resize)="onResize($event)">
<div class="row ">
<router-outlet></router-outlet>
<taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
<taskana-general-message-modal *ngIf="modalMessage" [(message)]="modalMessage" [title]="modalTitle"
[type]="modalType" error="true"></taskana-general-message-modal>
<taskana-spinner [isRunning]="requestInProgress" isModal=true></taskana-spinner>
<taskana-alert></taskana-alert>
<taskana-remove-confirmation></taskana-remove-confirmation>

View File

@ -2,9 +2,9 @@ import { Component, OnInit, HostListener, OnDestroy } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { Subscription } from 'rxjs';
import { ErrorModel } from './models/modal-error';
import { MessageModal } from './models/message-modal';
import { ErrorModalService } from './services/errorModal/error-modal.service';
import { GeneralModalService } from './services/general-modal/general-modal.service';
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
import { OrientationService } from './services/orientation/orientation.service';
import { SelectedRouteService } from './services/selected-route/selected-route';
@ -20,14 +20,15 @@ export class AppComponent implements OnInit, OnDestroy {
workbasketsRoute = true;
modalErrorMessage = '';
modalMessage = '';
modalTitle = '';
modalType;
selectedRoute = '';
requestInProgress = false;
currentProgressValue = 0;
errorModalSubscription: Subscription;
modalSubscription: Subscription;
requestInProgressSubscription: Subscription;
selectedRouteSubscription: Subscription;
routerSubscription: Subscription;
@ -40,7 +41,7 @@ export class AppComponent implements OnInit, OnDestroy {
constructor(
private router: Router,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService,
private selectedRouteService: SelectedRouteService,
@ -56,15 +57,18 @@ export class AppComponent implements OnInit, OnDestroy {
}
})
this.errorModalSubscription = this.errorModalService.getError().subscribe((error: ErrorModel) => {
if (typeof error.message === 'string') {
this.modalErrorMessage = error.message
} else if (error.message.error instanceof ProgressEvent) {
this.modalErrorMessage = error.message.message;
this.modalSubscription = this.generalModalService.getMessage().subscribe((messageModal: MessageModal) => {
if (typeof messageModal.message === 'string') {
this.modalMessage = messageModal.message
} else if (messageModal.message.error instanceof ProgressEvent) {
this.modalMessage = messageModal.message.message;
} else {
this.modalErrorMessage = error.message.error ? (error.message.error.error + ' ' + error.message.error.message) : error.message.message;
this.modalMessage = messageModal.message.error ?
(messageModal.message.error.error + ' ' + messageModal.message.error.message)
: messageModal.message.message;
}
this.modalTitle = error.title;
this.modalTitle = messageModal.title;
this.modalType = messageModal.type;
})
this.requestInProgressSubscription = this.requestInProgressService.getRequestInProgress().subscribe((value: boolean) => {
@ -84,7 +88,7 @@ export class AppComponent implements OnInit, OnDestroy {
ngOnDestroy() {
if (this.routerSubscription) { this.routerSubscription.unsubscribe(); }
if (this.errorModalSubscription) { this.errorModalSubscription.unsubscribe(); }
if (this.modalSubscription) { this.modalSubscription.unsubscribe(); }
if (this.requestInProgressSubscription) { this.requestInProgressSubscription.unsubscribe(); }
if (this.selectedRouteSubscription) { this.selectedRouteSubscription.unsubscribe(); }
if (this.uploadingFileSubscription) { this.uploadingFileSubscription.unsubscribe(); }

View File

@ -18,7 +18,7 @@ import { SharedModule } from 'app/shared/shared.module';
* Services
*/
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { OrientationService } from 'app/services/orientation/orientation.service';
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
@ -46,10 +46,10 @@ import { NoAccessComponent } from 'app/components/no-access/no-access.component'
/**
* Guards
*/
import { DomainGuard } from './guards/domain-guard';
import { BusinessAdminGuard } from './guards/business-admin-guard';
import { MonitorGuard } from './guards/monitor-guard';
import { UserGuard } from './guards/user-guard';
import { DomainGuard } from './guards/domain.guard';
import { BusinessAdminGuard } from './guards/business-admin.guard';
import { MonitorGuard } from './guards/monitor.guard';
import { UserGuard } from './guards/user.guard';
import { APP_BASE_HREF } from '@angular/common';
@ -88,7 +88,7 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
WindowRefService,
{ provide: APP_BASE_HREF, useValue: '/' },
DomainService,
ErrorModalService,
GeneralModalService,
RequestInProgressService,
OrientationService,
SelectedRouteService,

View File

@ -16,7 +16,7 @@ import { DomainServiceMock } from './services/domain/domain.service.mock';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import { AlertService } from './services/alert/alert.service';
import { ErrorModalService } from './services/errorModal/error-modal.service';
import { GeneralModalService } from './services/general-modal/general-modal.service';
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
import { OrientationService } from './services/orientation/orientation.service';
import { SelectedRouteService } from './services/selected-route/selected-route';
@ -41,7 +41,7 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
imports: [BrowserAnimationsModule, SharedModule, FormsModule, ReactiveFormsModule, HttpClientModule, AngularSvgIconModule],
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
{ provide: DomainService, useClass: DomainServiceMock }, CustomFieldsService, RemoveConfirmationService,
AlertService, ErrorModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
AlertService, GeneralModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
});
return testBed.compileComponents().then(() => testBed);

View File

@ -66,6 +66,9 @@
<div *ngIf="workplaceAccess" class="row menu" [ngClass]="{'selected': selectedRoute.indexOf('workplace') !== -1 || selectedRoute === ''}">
<span (click)="toogleNavBar()" routerLink="{{workplaceUrl}}" aria-controls="Workplace" routerLinkActive="active">Workplace</span>
</div>
<div *ngIf="historyAccess" class="row menu" [ngClass]="{'selected': selectedRoute.indexOf('history') !== -1}">
<span (click)="toogleNavBar()" routerLink="{{historyUrl}}" aria-controls="history" routerLinkActive="active">History</span>
</div>
</div>
<div class="nav-version">
<p id="taskana-version"> Taskana version: {{version}} </p>

View File

@ -9,10 +9,10 @@ import { NavBarComponent } from './nav-bar.component';
import { UserInformationComponent } from 'app/components/user-information/user-information.component';
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
import { MonitorGuard } from 'app/guards/monitor-guard';
import { BusinessAdminGuard } from 'app/guards/business-admin.guard';
import { MonitorGuard } from 'app/guards/monitor.guard';
import { WindowRefService } from 'app/services/window/window.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
@ -41,7 +41,7 @@ describe('NavBarComponent', () => {
BusinessAdminGuard,
MonitorGuard,
WindowRefService,
ErrorModalService,
GeneralModalService,
RequestInProgressService]
})
};

View File

@ -3,10 +3,10 @@ import { environment } from 'environments/environment';
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
import { Subscription } from 'rxjs';
import { DomainService } from 'app/services/domain/domain.service';
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
import { MonitorGuard } from 'app/guards/monitor-guard';
import { BusinessAdminGuard } from 'app/guards/business-admin.guard';
import { MonitorGuard } from 'app/guards/monitor.guard';
import { WindowRefService } from 'app/services/window/window.service';
import { UserGuard } from 'app/guards/user-guard';
import { UserGuard } from 'app/guards/user.guard';
import { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service';
import { expandRight } from 'app/shared/animations/expand.animation';
@Component({
@ -27,6 +27,7 @@ export class NavBarComponent implements OnInit, OnDestroy {
titleAccessItems = 'Access items';
titleMonitor = 'Monitor';
titleWorkplace = 'Workplace';
titleHistory = 'History';
showNavbar = false;
domains: Array<string> = [];
selectedDomain: string;
@ -35,10 +36,12 @@ export class NavBarComponent implements OnInit, OnDestroy {
adminUrl = './administration';
monitorUrl = './monitor';
workplaceUrl = './workplace';
historyUrl = './history';
administrationAccess = false;
monitorAccess = false;
workplaceAccess = false;
historyAccess = false;
selectedRouteSubscription: Subscription;
getDomainsSubscription: Subscription;
@ -69,6 +72,11 @@ export class NavBarComponent implements OnInit, OnDestroy {
this.administrationAccess = this.taskanaEngineService.hasRole(BusinessAdminGuard.roles);
this.monitorAccess = this.taskanaEngineService.hasRole(MonitorGuard.roles);
this.workplaceAccess = this.taskanaEngineService.hasRole(UserGuard.roles);
this.taskanaEngineService.isHistoryProviderEnabled().subscribe(value => {
this.historyAccess = value;
})
}
switchDomain(domain) {
@ -103,6 +111,8 @@ export class NavBarComponent implements OnInit, OnDestroy {
this.title = this.titleWorkplace;
} else if (value.indexOf('access-items') === 0) {
this.title = this.titleAccessItems;
} else if (value.indexOf('history') === 0) {
this.title = this.titleHistory;
}
}

View File

@ -1,8 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service';
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
import { MonitorGuard } from 'app/guards/monitor-guard';
import { UserGuard } from 'app/guards/user-guard';
import { BusinessAdminGuard } from 'app/guards/business-admin.guard';
import { MonitorGuard } from 'app/guards/monitor.guard';
import { UserGuard } from 'app/guards/user.guard';
import { Router } from '@angular/router';
@Component({

View File

@ -1,10 +1,5 @@
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { CanActivate, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { DomainService } from 'app/services/domain/domain.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { ErrorModel } from 'app/models/modal-error';
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
@Injectable()

View File

@ -2,13 +2,13 @@ import { of } from 'rxjs';
import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { DomainService } from 'app/services/domain/domain.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { ErrorModel } from 'app/models/modal-error';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { map, catchError } from 'rxjs/operators';
@Injectable()
export class DomainGuard implements CanActivate {
constructor(private domainService: DomainService, private errorModalService: ErrorModalService) { }
constructor(private domainService: DomainService, private generalModalService: GeneralModalService) { }
canActivate() {
return this.domainService.getDomains().pipe(
@ -16,7 +16,7 @@ export class DomainGuard implements CanActivate {
return true;
}),
catchError(() => {
this.errorModalService.triggerError(new ErrorModel(
this.generalModalService.triggerMessage(new MessageModal(
'There was an error, please contact with your administrator', 'There was an error getting Domains'));
return of(false)
})

View File

@ -0,0 +1,40 @@
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable, of } from 'rxjs';
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
import { map, catchError } from 'rxjs/operators';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
@Injectable({
providedIn: 'root'
})
export class HistoryGuard implements CanActivate {
constructor(
private taskanaEngineService: TaskanaEngineService,
public router: Router,
public generalModalService: GeneralModalService) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.taskanaEngineService.isHistoryProviderEnabled().pipe(
map(value => {
if (value) {
return value;
}
return this.navigateToWorkplace();
}),
catchError(() => {
this.generalModalService.triggerMessage(new MessageModal(
'There was an error, please contact with your administrator', 'There was an error getting history provider'));
return of(this.navigateToWorkplace());
})
);
}
navigateToWorkplace(): boolean {
this.router.navigate(['workplace']);
return false;
}
}

View File

@ -1,12 +1,6 @@
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { CanActivate, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { DomainService } from 'app/services/domain/domain.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { ErrorModel } from 'app/models/modal-error';
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
import { WindowRefService } from 'app/services/window/window.service';
@Injectable()
export class MonitorGuard implements CanActivate {

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TaskQueryComponent } from './task-query/task-query.component';
const routes: Routes = [
{
path: '',
component: TaskQueryComponent
},
{
path: '**',
redirectTo: ''
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class HistoryRoutingModule { }

View File

@ -0,0 +1,13 @@
import { HistoryModule } from './history.module';
describe('HistoryModule', () => {
let historyModule: HistoryModule;
beforeEach(() => {
historyModule = new HistoryModule();
});
it('should create an instance', () => {
expect(historyModule).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HistoryRoutingModule } from './history-routing.module';
import { TaskQueryComponent } from './task-query/task-query.component';
import { SharedModule } from 'app/shared/shared.module';
@NgModule({
imports: [
CommonModule,
HistoryRoutingModule,
SharedModule,
FormsModule,
ReactiveFormsModule
],
declarations: [TaskQueryComponent]
})
export class HistoryModule { }

View File

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

View File

@ -0,0 +1,124 @@
import { Injectable } from '@angular/core';
import { TaskHistoryEventData } from 'app/models/task-history-event';
import { TaskHistoryEventResourceData } from 'app/models/task-history-event-resource';
import { QueryParametersModel } from 'app/models/query-parameters';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Direction } from 'app/models/sorting';
import { Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { environment } from 'environments/environment';
@Injectable({
providedIn: 'root'
})
export class TaskQueryService {
private url = environment.taskanaRestUrl;
constructor(private httpClient: HttpClient) { }
queryTask(
orderBy: string = 'task-id',
sortDirection: string = Direction.ASC,
taskId: string,
parentBPI: string,
BPI: string,
eventType: string,
userId: string,
domain: string,
workbasketKey: string,
porCompany: string,
porSystem: string,
porInstance: string,
porType: string,
porValue: string,
taskClassificationKey: string,
taskClassificationCategory: string,
attachmentClassificationKey: string,
custom1: string,
custom2: string,
custom3: string,
custom4: string,
allPages: boolean = false
): Observable<TaskHistoryEventResourceData> {
return this.httpClient.get<TaskHistoryEventResourceData>(`${this.url}/v1/task-history-event${this.getQueryParameters(
orderBy,
sortDirection,
taskId,
parentBPI,
BPI,
eventType,
userId,
domain,
workbasketKey,
porCompany,
porSystem,
porInstance,
porType,
porValue,
taskClassificationKey,
taskClassificationCategory,
attachmentClassificationKey,
custom1,
custom2,
custom3,
custom4,
allPages
)}`);
}
private getQueryParameters(
orderBy: string,
sortDirection: string,
taskId: string,
parentBPI: string,
BPI: string,
eventType: string,
userId: string,
domain: string,
workbasketKey: string,
porCompany: string,
porSystem: string,
porInstance: string,
porType: string,
porValue: string,
taskClassificationKey: string,
taskClassificationCategory: string,
attachmentClassificationKey: string,
custom1: string,
custom2: string,
custom3: string,
custom4: string,
allPages: boolean = false): string {
const parameters = new QueryParametersModel();
parameters.SORTBY = orderBy
parameters.SORTDIRECTION = sortDirection;
parameters.TASK_ID_LIKE = taskId;
parameters.PARENT_BUSINESS_PROCESS_ID_LIKE = parentBPI;
parameters.BUSINESS_PROCESS_ID_LIKE = BPI;
parameters.EVENT_TYPE_LIKE = eventType;
parameters.USER_ID_LIKE = userId;
parameters.DOMAIN = domain;
parameters.WORKBASKETKEYLIKE = workbasketKey;
parameters.POR_COMPANY_LIKE = porCompany;
parameters.POR_SYSTEM_LIKE = porSystem;
parameters.POR_INSTANCE_LIKE = porInstance;
parameters.POR_TYPE_LIKE = porType;
parameters.POR_VALUE_LIKE = porValue;
parameters.TASK_CLASSIFICATION_KEY_LIKE = taskClassificationKey;
parameters.TASK_CLASSIFICATION_CATEGORY_LIKE = taskClassificationCategory;
parameters.ATTACHMENT_CLASSIFICATION_KEY_LIKE = attachmentClassificationKey;
parameters.CUSTOM_1_LIKE = custom1;
parameters.CUSTOM_2_LIKE = custom2;
parameters.CUSTOM_3_LIKE = custom3;
parameters.CUSTOM_4_LIKE = custom4;
if (allPages) { TaskanaQueryParameters.page = undefined; TaskanaQueryParameters.pageSize = undefined; }
return TaskanaQueryParameters.getQueryParameters(parameters);
}
}

View File

@ -0,0 +1,83 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right btn-group">
<button type="button" class="btn btn-default" data-toggle="tooltip" title="Query">
<span class="material-icons md-20 blue" (click)="search()">search</span>
</button>
<button type="button" class="btn btn-default" data-toggle="tooltip" title="Query">
<span class="material-icons md-20 blue" (click)="clear()">clear</span>
</button>
</div>
<h4 class="panel-header">Taskana history query</h4>
</div>
<div class="panel-body">
<div class="divTable table-striped">
<form [formGroup]="taskQueryForm">
<div class="divTableHeading">
<div class="divTableRow">
<ng-container *ngFor="let taskHeader of taskQueryHeader | mapToIterable">
<div class="divTableHeader" *ngIf="filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)"
(click)="changeOrderBy(taskHeader.key); search();">
<span class="icon-space">
{{getHeaderFieldDescription(taskHeader.key)}}
</span>
<span *ngIf="orderBy.sortBy === taskHeader.key" class="material-icons md-20 blue pull-right" [ngClass]="{'flip': orderBy.sortDirection === 'desc'}">sort</span>
</div>
<div class="divTableHeader divTableHeaderSeparator" [ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
*ngIf="taskHeader.key === 'custom1'" (click)="toggleExpand = !toggleExpand">
<span class="material-icons md-24 blue pull-right">{{toggleExpand? 'chevron_left' : 'chevron_right'}}</span>
</div>
<div class="divTableHeader" *ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && toggleExpand"
(click)="changeOrderBy(taskHeader.key); search();">
<span class="icon-space">
{{getHeaderFieldDescription(taskHeader.key)}}
</span>
<span *ngIf="orderBy.sortBy === taskHeader.key && filterFieldsToAllowQuerying(taskHeader.key)" class="material-icons md-20 blue pull-right"
[ngClass]="{'flip': orderBy.sortDirection === 'desc'}">sort</span>
</div>
</ng-container>
</div>
<div class="divTableRow">
<ng-container *ngFor="let taskHeader of taskQueryHeader | mapToIterable">
<div class="divTableHeader" *ngIf="filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)">
<input type="text" (keyup.enter)="search()" class="form-control input-sm" placeholder="{{getHeaderFieldDescription(taskHeader.key)}}"
formControlName="{{taskHeader.key}}">
</div>
<div class="divTableHeader divTableHeaderSeparator" [ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
*ngIf="taskHeader.key === 'custom1'" (click)="toggleExpand = !toggleExpand">
</div>
<div class="divTableHeader" *ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && toggleExpand">
<input *ngIf="filterFieldsToAllowQuerying(taskHeader.key)" type="text" formControlName="{{taskHeader.key}}"
(keyup.enter)="search()" class="form-control input-sm" placeholder="{{getHeaderFieldDescription(taskHeader.key)}}">
</div>
</ng-container>
</div>
</div>
<div class="divTableBody">
<div *ngFor="let task of taskQuery" class="divTableRow">
<ng-container *ngFor="let taskHeader of taskQueryHeader | mapToIterable">
<div class="divTableCell" *ngIf="filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)">
{{task[taskHeader.key]}}
</div>
<div class="divTableCell divTableCellSeparator" *ngIf="taskHeader.key === 'custom1'" [ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
(click)="toggleExpand = !toggleExpand">
</div>
<div class="divTableCell" *ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && filterFieldsToAllowQuerying(taskHeader.key) && toggleExpand">
{{task[taskHeader.key]}}
</div>
<div class="divTableCell" *ngIf="!filterFieldsToAllowQuerying(taskHeader.key) && toggleExpand">
<button *ngIf="task[taskHeader.key]" type="button" class="btn btn-default btn-xs" (click)="openDetails(taskHeader.key, task[taskHeader.key])">
<span class="material-icons md-16 blue pull-right">open_in_new</span>
</button>
</div>
</ng-container>
</div>
</div>
</form>
</div>
<div class="divTablePagination" *ngIf="taskQueryResource">
<taskana-pagination [(page)]="taskQueryResource.page" [numberOfItems]="taskQuery.length" type="Entries"
(changePage)="changePage($event)"></taskana-pagination>
</div>
</div>
</div>

View File

@ -0,0 +1,28 @@
.divTable{
max-height: calc(100vh - 152px);
padding-right: 15px;
}
.divTableFoot {
display: block;
}
.divTableCell {
height: 34px;
max-height: 34px;
}
.btn-xs{
padding: 0px;
}
.divTable .btn {
border: none;
}
.icon-space{
margin-right: 20px;
}
.divTablePagination {
margin: 0 auto;
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TaskQueryComponent } from './task-query.component';
describe('TaskQueryComponent', () => {
let component: TaskQueryComponent;
let fixture: ComponentFixture<TaskQueryComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TaskQueryComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TaskQueryComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,231 @@
import { Component, OnInit } from '@angular/core';
import { TaskQueryService } from '../services/task-query/task-query.service';
import { TaskHistoryEventData } from '../../models/task-history-event';
import { SortingModel, Direction } from 'app/models/sorting';
import { OrientationService } from 'app/services/orientation/orientation.service';
import { Subscription } from 'rxjs';
import { Orientation } from 'app/models/orientation';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { FormGroup, FormControl } from '@angular/forms';
import { TaskHistoryEventResourceData } from 'app/models/task-history-event-resource';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
@Component({
selector: 'taskana-task-query',
templateUrl: './task-query.component.html',
styleUrls: ['./task-query.component.scss']
})
export class TaskQueryComponent implements OnInit {
taskQueryResource: TaskHistoryEventResourceData;
taskQuery: Array<TaskHistoryEventData>
taskQueryHeader = new TaskHistoryEventData();
orderBy = new SortingModel(TaskanaQueryParameters.parameters.WORKBASKET_KEY);
orientationSubscription: Subscription;
taskQuerySubscription: Subscription;
taskQueryForm = new FormGroup({
});
constructor(
private taskQueryService: TaskQueryService,
private orientationService: OrientationService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService, ) { }
ngOnInit() {
this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => {
this.performRequest();
});
this.initTaskQueryForm();
}
getHeaderFieldDescription(property: string): string {
switch (property) {
case 'parentBusinessProcessId':
return 'Parent BPI';
case 'businessProcessId':
return 'BPI';
case 'taskId':
return 'Task id';
case 'eventType':
return 'Event type';
case 'created':
return 'Created';
case 'userId':
return 'User id';
case 'domain':
return 'Domain';
case 'workbasketKey':
return 'Workbasket key';
case 'porCompany':
return 'Obj company';
case 'porSystem':
return 'Obj system';
case 'porInstance':
return 'Obj instance';
case 'porType':
return 'Obj type';
case 'porValue':
return 'Obj value';
case 'taskClassificationKey':
return 'Classification key';
case 'taskClassificationCategory':
return 'Classification category';
case 'attachmentClassificationKey':
return 'Attachment Classification';
case 'custom1':
return 'Custom 1';
case 'custom2':
return 'Custom 2';
case 'custom3':
return 'Custom 3';
case 'custom4':
return 'Custom 4';
case 'oldData':
return 'Old data';
case 'newData':
return 'New data';
case 'comment':
return 'Comment';
case 'oldValue':
return 'Old value';
case 'newValue':
return 'New value';
default:
return property;
}
}
filterFieldsToAllowQuerying(fieldName: string): boolean {
if (!fieldName || fieldName === 'oldData' || fieldName === 'newData' || fieldName === 'comment'
|| fieldName === 'oldValue' || fieldName === 'newValue') {
return false;
}
return true;
}
filterFieldsToShow(fieldName: string): boolean {
if (fieldName === 'taskHistoryId' || fieldName === 'page' || fieldName === 'created' || fieldName === '_links') {
return false;
}
return true;
}
filterExpandGroup(fieldName: string): boolean {
if (fieldName === 'custom1' || fieldName === 'custom2' || fieldName === 'custom3' || fieldName === 'custom4'
|| fieldName === 'oldData' || fieldName === 'newData' || fieldName === 'comment'
|| fieldName === 'oldValue' || fieldName === 'newValue') {
return true;
}
return false;
}
search() {
this.performRequest();
}
changeOrderBy(key: string) {
if (!this.filterFieldsToAllowQuerying(key)) {
return null;
}
if (this.orderBy.sortBy === key) {
this.orderBy.sortDirection = this.toggleSortDirection(this.orderBy.sortDirection);
}
this.orderBy.sortBy = key;
}
openDetails(key: string, val: string) {
this.generalModalService.triggerMessage(
new MessageModal(
`These are the details of ${this.getHeaderFieldDescription(key)}`,
val,
'code'
)
)
}
getTaskValue(key: string, task: TaskHistoryEventData): string {
return task[key];
}
clear() {
this.taskQueryForm.reset();
this.performRequest();
}
changePage(page) {
TaskanaQueryParameters.page = page;
this.performRequest();
}
private toggleSortDirection(sortDirection: string): Direction {
if (sortDirection === Direction.ASC) {
return Direction.DESC;
}
return Direction.ASC
}
private performRequest() {
setTimeout(() => this.requestInProgressService.setRequestInProgress(true), 1)
this.calculateQueryPages();
this.taskQuerySubscription = this.taskQueryService.queryTask(
this.orderBy.sortBy.replace(/([A-Z])|([0-9])/g, (g) => `-${g[0].toLowerCase()}`),
this.orderBy.sortDirection,
this.taskQueryForm.get('taskId') ? this.taskQueryForm.get('taskId').value : undefined,
this.taskQueryForm.get('parentBusinessProcessId') ? this.taskQueryForm.get('parentBusinessProcessId').value : undefined,
this.taskQueryForm.get('businessProcessId') ? this.taskQueryForm.get('businessProcessId').value : undefined,
this.taskQueryForm.get('eventType') ? this.taskQueryForm.get('eventType').value : undefined,
this.taskQueryForm.get('userId') ? this.taskQueryForm.get('userId').value : undefined,
this.taskQueryForm.get('domain') ? this.taskQueryForm.get('domain').value : undefined,
this.taskQueryForm.get('workbasketKey') ? this.taskQueryForm.get('workbasketKey').value : undefined,
this.taskQueryForm.get('porCompany') ? this.taskQueryForm.get('porCompany').value : undefined,
this.taskQueryForm.get('porSystem') ? this.taskQueryForm.get('porSystem').value : undefined,
this.taskQueryForm.get('porInstance') ? this.taskQueryForm.get('porInstance').value : undefined,
this.taskQueryForm.get('porType') ? this.taskQueryForm.get('porType').value : undefined,
this.taskQueryForm.get('porValue') ? this.taskQueryForm.get('porValue').value : undefined,
this.taskQueryForm.get('taskClassificationKey') ? this.taskQueryForm.get('taskClassificationKey').value : undefined,
this.taskQueryForm.get('taskClassificationCategory') ? this.taskQueryForm.get('taskClassificationCategory').value : undefined,
this.taskQueryForm.get('attachmentClassificationKey') ? this.taskQueryForm.get('attachmentClassificationKey').value : undefined,
this.taskQueryForm.get('custom1') ? this.taskQueryForm.get('custom1').value : undefined,
this.taskQueryForm.get('custom2') ? this.taskQueryForm.get('custom2').value : undefined,
this.taskQueryForm.get('custom3') ? this.taskQueryForm.get('custom3').value : undefined,
this.taskQueryForm.get('custom4') ? this.taskQueryForm.get('custom4').value : undefined,
false).subscribe(taskQueryResource => {
this.requestInProgressService.setRequestInProgress(false)
if (!taskQueryResource._embedded) {
this.taskQuery = null;
this.taskQueryResource = null;
return null;
}
this.taskQueryResource = taskQueryResource;
this.taskQuery = taskQueryResource._embedded.taskHistoryEventResourceList;
})
}
private initTaskQueryForm() {
const me = this;
Object.keys(new TaskHistoryEventData()).forEach(function (key) {
me.taskQueryForm.addControl(key, new FormControl());
});
}
private calculateQueryPages() {
const rowHeight = 34;
const unusedHeight = 300;
const totalHeight = window.innerHeight;
const cards = Math.round((totalHeight - (unusedHeight)) / rowHeight);
TaskanaQueryParameters.page ? TaskanaQueryParameters.page = TaskanaQueryParameters.page : TaskanaQueryParameters.page = 1;
cards > 0 ? TaskanaQueryParameters.pageSize = cards : TaskanaQueryParameters.pageSize = 1;
}
onDestroy() {
if (this.orientationSubscription) { this.orientationSubscription.unsubscribe(); }
if (this.taskQuerySubscription) { this.taskQuerySubscription.unsubscribe(); }
}
}

View File

@ -0,0 +1,7 @@
export class MessageModal {
constructor(
public title: string = undefined,
public message: any = undefined,
public type = 'error'
) { }
}

View File

@ -1,6 +0,0 @@
export class ErrorModel {
constructor(
public title: string = undefined,
public message: any = undefined
) { }
}

View File

@ -0,0 +1,50 @@
export class QueryParametersModel {
SORTBY: string;
SORTDIRECTION: string;
// Filtering
NAME: string;
NAMELIKE: string;
DESCLIKE: string;
OWNER: string;
OWNERLIKE: string;
TYPE: string;
KEY: string;
WORKBASKET_KEY: string;
KEYLIKE: string;
PRIORITY: string;
STATE: string;
WORKBASKET_ID: string;
TASK_PRIMARY_OBJ_REF_TYPE_LIKE: string;
TASK_PRIMARY_OBJ_REF_VALUE_LIKE: string;
// Access
REQUIREDPERMISSION: string;
ACCESSIDS: string;
ACCESSIDLIKE: string;
WORKBASKETKEYLIKE: string;
// Pagination
PAGE: string;
PAGESIZE: string;
// Domain
DOMAIN: string;
// Task history events
TASK_ID_LIKE: string;
PARENT_BUSINESS_PROCESS_ID_LIKE: string;
BUSINESS_PROCESS_ID_LIKE: string;
EVENT_TYPE_LIKE: string;
CREATED_LIKE: string;
USER_ID_LIKE: string;
POR_COMPANY_LIKE: string;
POR_SYSTEM_LIKE: string;
POR_INSTANCE_LIKE: string;
POR_TYPE_LIKE: string;
POR_VALUE_LIKE: string;
TASK_CLASSIFICATION_KEY_LIKE: string;
TASK_CLASSIFICATION_CATEGORY_LIKE: string;
ATTACHMENT_CLASSIFICATION_KEY_LIKE: string;
CUSTOM_1_LIKE: string;
CUSTOM_2_LIKE: string;
CUSTOM_3_LIKE: string;
CUSTOM_4_LIKE: string;
COMMENT_LIKE: string;
}

View File

@ -0,0 +1,7 @@
import { Links } from './links';
import { TaskHistoryEventData } from './task-history-event';
export class TaskHistoryEventResourceData {
public _embedded: { 'taskHistoryEventResourceList': Array<TaskHistoryEventData> }
public _links: Links = undefined
}

View File

@ -0,0 +1,31 @@
import { Page } from './page';
export class TaskHistoryEventData {
taskHistoryId = 0;
taskId = '';
parentBusinessProcessId = '';
businessProcessId = '';
eventType = '';
created = '';
userId = '';
domain = '';
workbasketKey = '';
porCompany = '';
porSystem = '';
porInstance = '';
porType = '';
porValue = '';
taskClassificationKey = '';
taskClassificationCategory = '';
attachmentClassificationKey = '';
custom1 = '';
custom2 = '';
custom3 = '';
custom4 = '';
comment = '';
oldValue = '';
newValue = '';
oldData = '';
newData = '';
page = new Page();
}

View File

@ -1,16 +1,17 @@
<div class="container">
<div>
<ul class="nav nav-tabs" role="tablist">
<li>
<a style="display: none"></a>
</li>
<li role="presentation" class="active">
<li (click)="selectTab('tasks')" role="presentation" class="active" [ngClass]="{'active':tabSelected === 'tasks'}">
<a href="#tasks-tab" data-toggle="tab" aria-controls="Tasks" role="tab" aria-expanded="true">Tasks</a>
</li>
<li role="presentation">
<li (click)="selectTab('workbaskets')" [ngClass]="{'active':tabSelected === 'workbaskets'}">
<a href="#workbaskets-tab" data-toggle="tab" aria-controls="Workbaskets" role="tab" aria-expanded="true">Workbaskets</a>
</li>
<li>
<a href="#classifications-tab" data-toggle="tab" aria-controls="Classifications" role="tab" data-toggle="tab" aria-expanded="true">Classifications</a>
<li (click)="selectTab('classifications')" [ngClass]="{'active':tabSelected === 'classifications'}">
<a href="#classifications-tab" data-toggle="tab" aria-controls="Classifications" role="tab" data-toggle="tab"
aria-expanded="true">Classifications</a>
</li>
</ul>
<div class="tab-content">
@ -24,4 +25,4 @@
<taskana-monitor-classification-tasks></taskana-monitor-classification-tasks>
</div>
</div>
</div>
</div>

View File

@ -8,8 +8,14 @@ import { Component, OnInit, HostListener, OnDestroy } from '@angular/core';
})
export class MonitorComponent implements OnInit, OnDestroy {
tabSelected = 'tasks';
ngOnInit(): void {
}
ngOnDestroy(): void {
}
selectTab(tab) {
this.tabSelected = tab;
}
}

View File

@ -2,8 +2,8 @@
<div class="panel-heading">
<h4>{{reportData.meta.name}} ({{reportData.meta.date | date : 'dd.MM.yyyy HH:mm:ss'}})</h4>
</div>
<div class="panel-body col-xs-12 col-md-8 col-md-offset-2">
<div style="display: block">
<div class="panel-body">
<div style="display: block" class =" col-xs-12 col-md-7 col-md-offset-2">
<canvas baseChart [data]="pieChartData" [labels]="pieChartLabels" [chartType]="pieChartType"></canvas>
</div>
<taskana-report [type]="reportType" [reportData]="reportData"></taskana-report>

View File

@ -12,6 +12,7 @@ import { ClassificationCategoriesService } from './classification-categories.ser
import { DomainService } from 'app/services/domain/domain.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Direction } from 'app/models/sorting';
import { QueryParametersModel } from 'app/models/query-parameters';
@Injectable()
export class ClassificationsService {
@ -27,35 +28,20 @@ export class ClassificationsService {
}
// GET
getClassifications(sortBy: string = TaskanaQueryParameters.KEY,
order: string = Direction.ASC,
name: string = undefined,
nameLike: string = undefined,
descLike: string = undefined,
owner: string = undefined,
ownerLike: string = undefined,
type: string = undefined,
key: string = undefined,
keyLike: string = undefined,
requiredPermission: string = undefined,
allPages: boolean = true): Observable<Array<Classification>> {
getClassifications(): Observable<Array<Classification>> {
return this.domainService.getSelectedDomain().pipe(
mergeMap(domain => {
return this.getClassificationObservable(this.httpClient.get<ClassificationResource>(
`${environment.taskanaRestUrl}/v1/classifications/${TaskanaQueryParameters.getQueryParameters(
sortBy, order, name,
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission,
!allPages ? TaskanaQueryParameters.page : undefined, !allPages ? TaskanaQueryParameters.pageSize : undefined, domain)}`));
`${this.url}${TaskanaQueryParameters.getQueryParameters(this.classificationParameters(domain))}`));
}),
tap(() => { this.domainService.domainChangedComplete(); })
)
}
// GET
getClassification(id: string): Observable<ClassificationDefinition> {
return this.httpClient.get<ClassificationDefinition>(`${environment.taskanaRestUrl}/v1/classifications/${id}`)
return this.httpClient.get<ClassificationDefinition>(`${this.url}${id}`)
.pipe(tap((classification: ClassificationDefinition) => {
if (classification) {
this.classificationCategoriesService.selectClassificationType(classification.type);
@ -99,6 +85,18 @@ export class ClassificationsService {
// #endregion
private classificationParameters(domain: string): QueryParametersModel {
const parameters = new QueryParametersModel();
parameters.SORTBY = TaskanaQueryParameters.parameters.KEY;
parameters.SORTDIRECTION = Direction.ASC;
parameters.DOMAIN = domain;
TaskanaQueryParameters.page = undefined;
TaskanaQueryParameters.pageSize = undefined;
return parameters;
}
private getClassificationObservable(classificationRef: Observable<any>): Observable<any> {
const classificationTypes = this.classificationCategoriesService.getSelectedClassificationType();
return combineLatest(

View File

@ -1,19 +0,0 @@
import { Injectable } from '@angular/core';
import { Subject , Observable } from 'rxjs';
import { ErrorModel } from 'app/models/modal-error';
@Injectable()
export class ErrorModalService {
private errorTriggered = new Subject<ErrorModel>();
constructor() { }
triggerError(error: ErrorModel) {
this.errorTriggered.next(error);
}
getError(): Observable<ErrorModel> {
return this.errorTriggered.asObservable();
}
}

View File

@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import { Subject , Observable } from 'rxjs';
import { MessageModal } from 'app/models/message-modal';
@Injectable()
export class GeneralModalService {
private messageTriggered = new Subject<MessageModal>();
constructor() { }
triggerMessage(message: MessageModal) {
this.messageTriggered.next(message);
}
getMessage(): Observable<MessageModal> {
return this.messageTriggered.asObservable();
}
}

View File

@ -7,7 +7,7 @@ export class SelectedRouteService {
public selectedRouteTriggered = new Subject<string>();
private detailRoutes: Array<string> = ['workbaskets', 'classifications', 'monitor', 'workplace', 'access-items-management'];
private detailRoutes: Array<string> = ['workbaskets', 'classifications', 'monitor', 'workplace', 'access-items-management', 'history'];
constructor(private router: Router) { }

View File

@ -34,6 +34,10 @@ export class TaskanaEngineServiceMock {
return of(version);
}
isHistoryProviderEnabled(): Observable<boolean> {
return of(true);
}
private findRole(roles2Find: Array<string>) {
return this.currentUserInfo.roles.find(role => {
return roles2Find.some(roleLookingFor => {

View File

@ -44,6 +44,10 @@ export class TaskanaEngineService {
}
isHistoryProviderEnabled(): Observable<boolean> {
return this.httpClient.get<boolean>(`${environment.taskanaRestUrl}/v1/history-provider-enabled`);
}
private findRole(roles2Find: Array<string>) {
return this.currentUserInfo.roles.find(role => {
return roles2Find.some(roleLookingFor => {

View File

@ -13,6 +13,7 @@ import { DomainService } from 'app/services/domain/domain.service';
import { WorkbasketResource } from '../../models/workbasket-resource';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { mergeMap, tap, catchError } from 'rxjs/operators';
import { QueryParametersModel } from 'app/models/query-parameters';
@Injectable()
export class WorkbasketService {
@ -29,7 +30,7 @@ export class WorkbasketService {
// #region "REST calls"
// GET
getWorkBasketsSummary(forceRequest: boolean = false,
sortBy: string = TaskanaQueryParameters.KEY,
sortBy: string = TaskanaQueryParameters.parameters.KEY,
order: string = Direction.ASC,
name: string = undefined,
nameLike: string = undefined,
@ -46,12 +47,11 @@ export class WorkbasketService {
return this.workbasketSummaryRef;
}
return this.domainService.getSelectedDomain().pipe(mergeMap(domain => {
return this.workbasketSummaryRef = this.httpClient.get<WorkbasketSummaryResource>(
`${environment.taskanaRestUrl}/v1/workbaskets/${TaskanaQueryParameters.getQueryParameters(
sortBy, order, name,
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission,
!allPages ? TaskanaQueryParameters.page : undefined, !allPages ? TaskanaQueryParameters.pageSize : undefined, domain)}`)
`${environment.taskanaRestUrl}/v1/workbaskets/${TaskanaQueryParameters.getQueryParameters(this.workbasketParameters(sortBy, order, name,
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission, allPages, domain))}`)
.pipe(tap((workbaskets => {
return workbaskets;
})))
@ -82,8 +82,8 @@ export class WorkbasketService {
.put<Workbasket>(url, workbasket).pipe(
catchError(this.handleError)
);
}
// delete
}
// delete
markWorkbasketForDeletion(url: string): Observable<any> {
return this.httpClient
.delete<any>(url);
@ -152,5 +152,41 @@ export class WorkbasketService {
return observableThrowError(errMsg);
}
private workbasketParameters(
sortBy: string = TaskanaQueryParameters.parameters.KEY,
order: string = Direction.ASC,
name: string = undefined,
nameLike: string = undefined,
descLike: string = undefined,
owner: string = undefined,
ownerLike: string = undefined,
type: string = undefined,
key: string = undefined,
keyLike: string = undefined,
requiredPermission: string = undefined,
allPages: boolean = false,
domain: string = ''): QueryParametersModel {
const parameters = new QueryParametersModel();
parameters.SORTBY = sortBy;
parameters.SORTDIRECTION = order;
parameters.NAME = name;
parameters.NAMELIKE = nameLike;
parameters.DESCLIKE = descLike;
parameters.OWNER = owner;
parameters.OWNERLIKE = ownerLike;
parameters.TYPE = type;
parameters.KEY = key;
parameters.KEYLIKE = keyLike;
parameters.REQUIREDPERMISSION = requiredPermission;
parameters.DOMAIN = domain;
if (allPages) {
TaskanaQueryParameters.page = undefined;
TaskanaQueryParameters.pageSize = undefined;
}
return parameters;
}
// #endregion
}

View File

@ -16,12 +16,12 @@
</ul>
</div>
<div class="col-xs-4">
<input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control input-sm" id="display-name-filter"
placeholder="Filter name">
<input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control input-sm"
id="display-name-filter" placeholder="Filter name">
</div>
<div class="col-xs-4">
<input type="text" [(ngModel)]="filter.filterParams.key" (keyup.enter)="search()" class="form-control input-sm" id="display-key-filter"
placeholder="Filter key">
<input type="text" [(ngModel)]="filter.filterParams.key" (keyup.enter)="search()" class="form-control input-sm"
id="display-key-filter" placeholder="Filter key">
</div>
<button (click)="clear(); search()" type="button" class="btn btn-default btn-sm pull-right margin-right"
data-toggle="tooltip" title="Clear">
@ -36,8 +36,8 @@
</div>
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<input type="text" [(ngModel)]="filter.filterParams.owner" (keyup.enter)="search()" class="form-control input-sm" id="display-name-owner"
placeholder="Filter owner">
<input type="text" [(ngModel)]="filter.filterParams.owner" (keyup.enter)="search()" class="form-control input-sm"
id="display-name-owner" placeholder="Filter owner">
</div>
<button (click)="search()" type="button" class="btn btn-default btn-sm pull-right margin-right" data-toggle="tooltip"
title="Search">
@ -48,8 +48,7 @@
<ng-template #tasktype>
<div class="row">
<div class="col-xs-2">
<input type="text" [(ngModel)]="filter.filterParams.priority" (keyup.enter)="search()" data-toggle="tooltip"
title="priority" class="form-control" id="display-priority-filter">
<taskana-number-picker [(ngModel)]="filter.filterParams.priority" (keyup.enter)="search()" title="priority" id="display-priority-filter"></taskana-number-picker>
</div>
<div class="col-xs-4">
<input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control" id="display-name-filter"
@ -66,8 +65,8 @@
</div>
<div class="row">
<div class="dropdown col-xs-2 col-xs-offset-2">
<button class="btn btn-default" data-toggle="dropdown" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true" title="State: {{filter.filterParams.state ? filter.filterParams?.state : 'All'}}">
<button class="btn btn-default" data-toggle="dropdown" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true" title="State: {{filter.filterParams.state ? filter.filterParams?.state : 'All'}}">
<span>{{filter.filterParams.state ? filter.filterParams?.state : 'All'}}</span>
</button>
<ul class="dropdown-menu dropdown-menu-users" role="menu">
@ -85,4 +84,4 @@
</button>
</div>
</ng-template>
</div>
</div>

View File

@ -1,16 +1,20 @@
<div class="modal fade" #generalModal tabindex="-1" data-backdrop="static" data-keyboard="false" role="dialog" aria-labelledby="generalModalLabel">
<div class="modal fade" #generalModal tabindex="-1" data-backdrop="static" data-keyboard="false" role="dialog"
aria-labelledby="generalModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content word-break">
<div class="modal-header">
<h4 class="modal-title" id="generalModalLabel">{{title}}</h4>
</div>
<div *ngIf="error" class="modal-body">
<div *ngIf="type === 'error'" class="modal-body">
<div class="alert alert-danger" role="alert">
<span data-toggle="tooltip" class="material-icons md-20">error</span>
<span class="sr-only">Error:</span>
{{message}}
{{message}}
</div>
</div>
<div *ngIf="type === 'code'">
<pre><code>{{message}}</code></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-danger" data-dismiss="modal" (click)="removeMessage()">Close</button>
</div>

View File

@ -1,5 +1,5 @@
import { Component, Input, ViewChild, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
declare var $: any;
declare var $: any; // jquery
@Component({
selector: 'taskana-general-message-modal',
@ -12,10 +12,10 @@ export class GeneralMessageModalComponent implements OnChanges {
@Output() messageChange = new EventEmitter<string>();
@Input()
title = '';
title: string;
@Input()
error = false;
type: string;
@ViewChild('generalModal')
private modal;

View File

@ -0,0 +1,11 @@
<div class="input-group">
<input class="form-control input-text" name="number" [(ngModel)]="value">
<div class="input-group-btn-vertical">
<button type="button" (click)="increase()" data-toggle="tooltip" title="increase value" class="btn btn-default">
<span class="material-icons md-14 green-blue">arrow_drop_up</span>
</button>
<button type="button" (click)="decrease()" data-toggle="tooltip" title="decrease value" class="btn btn-default">
<span class="material-icons md-14 green-blue">arrow_drop_down</span>
</button>
</div>
</div>

View File

@ -0,0 +1,35 @@
button{
font-size: 1px;
padding: 0px;
}
.input-group{
max-width: 100px;
}
input{
text-align: right;
}
.input-group-btn-vertical {
position: relative;
white-space: nowrap;
vertical-align: middle;
display: table-cell;
}
.input-group-btn-vertical > .btn {
display: block;
float: none;
width: 100%;
max-width: 100%;
padding: 1px;
margin-left: -1px;
position: relative;
border-radius: 0;
}
.input-group-btn-vertical > .btn:first-child {
border-top-right-radius: 4px;
}
.input-group-btn-vertical > .btn:last-child {
margin-top: -3px;
border-bottom-right-radius: 4px;
}

View File

@ -0,0 +1,30 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NumberPickerComponent } from './number-picker.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
describe('NumberPickerComponent', () => {
let component: NumberPickerComponent;
let fixture: ComponentFixture<NumberPickerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
NumberPickerComponent],
imports: [
FormsModule,
ReactiveFormsModule
]
})
.compileComponents();
fixture = TestBed.createComponent(NumberPickerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,68 @@
import { Component, OnInit, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'taskana-number-picker',
templateUrl: './number-picker.component.html',
styleUrls: ['./number-picker.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NumberPickerComponent),
multi: true
}
]
})
export class NumberPickerComponent implements OnInit, ControlValueAccessor {
// The internal data model
private innerValue: any = 0;
// Placeholders for the callbacks which are later provided
// by the Control Value Accessor
private onTouchedCallback: () => {};
private onChangeCallback: (_: any) => {};
// get accessor
get value(): any {
return this.innerValue;
};
// set accessor including call the onchange callback
set value(v: any) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
}
}
// From ControlValueAccessor interface
writeValue(value: any) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
// From ControlValueAccessor interface
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
// From ControlValueAccessor interface
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
constructor() {
}
ngOnInit() {
}
increase() {
this.value++;
}
decrease() {
this.value--;
}
}

View File

@ -32,7 +32,7 @@ export class PaginationComponent implements OnChanges {
constructor() {}
ngOnChanges(changes: SimpleChanges): void {
if (changes.page && changes.page.currentValue !== undefined) {
if (changes.page && changes.page.currentValue) {
this.pageSelected = changes.page.currentValue.number;
}
}

View File

@ -6,6 +6,7 @@ import { Observable, of } from 'rxjs';
import { AccessItemsWorkbasketResource } from 'app/models/access-item-workbasket-resource';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { SortingModel } from 'app/models/sorting';
import { QueryParametersModel } from 'app/models/query-parameters';
@Injectable({
providedIn: 'root'
@ -40,17 +41,33 @@ export class AccessIdsService {
}
return this.accessItemsRef = this.httpClient.get<AccessItemsWorkbasketResource>(encodeURI(
`${environment.taskanaRestUrl}/v1/workbasket-access-items/${TaskanaQueryParameters.getQueryParameters(sortModel.sortBy,
sortModel.sortDirection,
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
accessIds.map((values: AccessIdDefinition) => {
return values.accessId
}).join('|'),
accessIdLike, workbasketKeyLike)}`))
`${environment.taskanaRestUrl}/v1/workbasket-access-items/${TaskanaQueryParameters.getQueryParameters(
this.accessIdsParameters(sortModel,
accessIds,
accessIdLike, workbasketKeyLike))}`))
}
removeAccessItemsPermissions(accessId: string) {
return this.httpClient
.delete<AccessItemsWorkbasketResource>(`${environment.taskanaRestUrl}/v1/workbasket-access-items/?access-id=` + accessId)
.delete<AccessItemsWorkbasketResource>(`${environment.taskanaRestUrl}/v1/workbasket-access-items/?access-id=` + accessId)
}
private accessIdsParameters(
sortModel: SortingModel,
accessIds: Array<AccessIdDefinition>,
accessIdLike: string = undefined,
workbasketKeyLike: string = undefined): QueryParametersModel {
const parameters = new QueryParametersModel();
parameters.SORTBY = sortModel.sortBy;
parameters.SORTDIRECTION = sortModel.sortDirection;
parameters.ACCESSIDS = accessIds.map((values: AccessIdDefinition) => {
return values.accessId
}).join('|');
parameters.ACCESSIDLIKE = accessIdLike;
parameters.WORKBASKETKEYLIKE = workbasketKeyLike;
TaskanaQueryParameters.page = undefined;
TaskanaQueryParameters.pageSize = undefined;
return parameters;
}
}

View File

@ -2,14 +2,14 @@ import { TestBed, inject } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientInterceptor } from './http-client-interceptor.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
describe('HttpExtensionService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [HttpClientInterceptor, ErrorModalService, RequestInProgressService]
providers: [HttpClientInterceptor, GeneralModalService, RequestInProgressService]
});
});

View File

@ -2,9 +2,9 @@ import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ErrorModel } from 'app/models/modal-error';
import { MessageModal } from 'app/models/message-modal';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { environment } from 'environments/environment';
import { tap } from 'rxjs/operators';
@ -13,7 +13,7 @@ import { tap } from 'rxjs/operators';
export class HttpClientInterceptor implements HttpInterceptor {
constructor(
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService) {
}
@ -26,13 +26,13 @@ export class HttpClientInterceptor implements HttpInterceptor {
return next.handle(req).pipe(tap(() => { }, error => {
this.requestInProgressService.setRequestInProgress(false);
if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 403)) {
this.errorModalService.triggerError(
new ErrorModel('You have no access to this resource ', error));
this.generalModalService.triggerMessage(
new MessageModal('You have no access to this resource ', error));
} else if (error instanceof HttpErrorResponse && (error.status === 404) && error.url.indexOf('environment-information.json')) {
// ignore this error message
} else {
this.errorModalService.triggerError(
new ErrorModel('There was error, please contact with your administrator ', error))
this.generalModalService.triggerMessage(
new MessageModal('There was error, please contact with your administrator ', error))
}
}))
}

View File

@ -23,6 +23,7 @@ import { FilterComponent } from 'app/shared/filter/filter.component';
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
import { FieldErrorDisplayComponent } from 'app/shared/field-error-display/field-error-display.component';
import { PaginationComponent } from './pagination/pagination.component';
import { NumberPickerComponent } from './number-picker/number-picker.component';
import { ProgressBarComponent } from './progress-bar/progress-bar.component';
import { DatePickerComponent } from './date-picker/date-picker.component';
@ -76,6 +77,7 @@ const DECLARATIONS = [
RemoveConfirmationComponent,
FieldErrorDisplayComponent,
PaginationComponent,
NumberPickerComponent,
ProgressBarComponent,
DatePickerComponent
];

View File

@ -1,7 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SpinnerComponent } from './spinner.component';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
describe('SpinnerComponent', () => {
let component: SpinnerComponent;
@ -10,7 +10,7 @@ describe('SpinnerComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SpinnerComponent],
providers: [ErrorModalService]
providers: [GeneralModalService]
})
.compileComponents();
}));

View File

@ -1,9 +1,9 @@
import { Component, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
import { ViewChild } from '@angular/core';
import { ErrorModel } from 'app/models/modal-error';
import { MessageModal } from 'app/models/message-modal';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
declare var $: any;
@Component({
@ -53,7 +53,7 @@ export class SpinnerComponent implements OnDestroy {
@ViewChild('spinnerModal')
private modal;
constructor(private errorModalService: ErrorModalService) {
constructor(private generalModalService: GeneralModalService) {
}
@ -63,8 +63,8 @@ export class SpinnerComponent implements OnDestroy {
this.isDelayedRunning = value;
this.cancelTimeout();
this.requestTimeout = setTimeout(() => {
this.errorModalService.triggerError(
new ErrorModel('There was an error with your request, please make sure you have internet connection',
this.generalModalService.triggerMessage(
new MessageModal('There was an error with your request, please make sure you have internet connection',
'Request time execeed'));
this.cancelTimeout();
this.isRunning = false;

View File

@ -1,19 +1,33 @@
import { TaskanaQueryParameters } from './query-parameters';
import { Direction } from 'app/models/sorting';
import { QueryParametersModel } from 'app/models/query-parameters';
describe('TaskanaQueryParameters', () => {
it('should create a empty query', () => {
expect(TaskanaQueryParameters.getQueryParameters()).toBe('');
TaskanaQueryParameters.page = undefined;
TaskanaQueryParameters.pageSize = undefined;
expect(TaskanaQueryParameters.getQueryParameters(new QueryParametersModel())).toBe('?');
TaskanaQueryParameters.page = 1;
TaskanaQueryParameters.pageSize = 9;
});
it('should create a query with pagin information', () => {
expect(TaskanaQueryParameters.getQueryParameters(new QueryParametersModel())).toBe('?page=1&page-size=9');
});
it('should create a query separated with &', () => {
expect(TaskanaQueryParameters.getQueryParameters(TaskanaQueryParameters.KEY,
Direction.ASC).split('&').length).toBe(2);
const parameters = new QueryParametersModel();
parameters.SORTBY = TaskanaQueryParameters.parameters.KEY;
parameters.SORTDIRECTION = Direction.ASC;
expect(TaskanaQueryParameters.getQueryParameters(parameters).split('&').length).toBe(4);
});
it('should remove last & from query', () => {
expect(TaskanaQueryParameters.getQueryParameters(TaskanaQueryParameters.KEY,
Direction.ASC).endsWith('?')).toBeFalsy();
const parameters = new QueryParametersModel();
parameters.SORTBY = TaskanaQueryParameters.parameters.KEY;
parameters.SORTDIRECTION = Direction.ASC;
expect(TaskanaQueryParameters.getQueryParameters(parameters).endsWith('?')).toBeFalsy();
});
});

View File

@ -1,94 +1,80 @@
import { QueryParametersModel } from 'app/models/query-parameters';
export class TaskanaQueryParameters {
// Sorting
static SORTBY = 'sort-by';
static ORDER = 'order';
static parameters = {
// Sorting
SORTBY: 'sort-by',
SORTDIRECTION: 'order',
// Filtering
NAME: 'name',
NAMELIKE: 'name-like',
DESCLIKE: 'description-like',
OWNER: 'owner',
OWNERLIKE: 'owner-like',
TYPE: 'type',
KEY: 'key',
WORKBASKET_KEY: 'workbasket-key',
KEYLIKE: 'key-like',
PRIORITY: 'priority',
STATE: 'state',
WORKBASKET_ID: 'workbasket-id',
TASK_PRIMARY_OBJ_REF_TYPE_LIKE: 'por.type',
TASK_PRIMARY_OBJ_REF_VALUE_LIKE: 'por.value',
// Access
REQUIREDPERMISSION: 'required-permission',
ACCESSIDS: 'access-ids',
ACCESSIDLIKE: 'access-id-like',
WORKBASKETKEYLIKE: 'workbasket-key-like',
// Pagination
PAGE: 'page',
PAGESIZE: 'page-size',
// Domain
DOMAIN: 'domain',
// Filtering
static NAME = 'name';
static NAMELIKE = 'name-like';
static DESCLIKE = 'description-like';
static OWNER = 'owner';
static OWNERLIKE = 'owner-like';
static TYPE = 'type';
static KEY = 'key';
static WORKBASKET_KEY = 'workbasket-key';
static KEYLIKE = 'key-like';
static PRIORITY = 'priority';
static STATE = 'state';
static WORKBASKET_ID = 'workbasket-id';
static TASK_PRIMARY_OBJ_REF_TYPE_LIKE = 'por.type';
static TASK_PRIMARY_OBJ_REF_VALUE_LIKE = 'por.value';
// Task history events
TASK_ID_LIKE: 'task-id-like',
PARENT_BUSINESS_PROCESS_ID_LIKE: 'parent-business-process-id-like',
BUSINESS_PROCESS_ID_LIKE: 'business-process-id-like',
EVENT_TYPE_LIKE: 'event-type-like',
CREATED_LIKE: 'created-like',
USER_ID_LIKE: 'user-id-like',
POR_COMPANY_LIKE: 'por-company-like',
POR_SYSTEM_LIKE: 'por-system-like',
POR_INSTANCE_LIKE: 'por-instance-like',
POR_TYPE_LIKE: 'por-type-like',
POR_VALUE_LIKE: 'por-value-like',
TASK_CLASSIFICATION_KEY_LIKE: 'task-classification-key-like',
TASK_CLASSIFICATION_CATEGORY_LIKE: 'task-classification-category-like',
ATTACHMENT_CLASSIFICATION_KEY_LIKE: 'attachment-classification-key-like',
CUSTOM_1_LIKE: 'custom-1-like',
CUSTOM_2_LIKE: 'custom-2-like',
CUSTOM_3_LIKE: 'custom-3-like',
CUSTOM_4_LIKE: 'custom-4-like',
COMMENT_LIKE: 'comment-like'
}
// Access
static REQUIREDPERMISSION = 'required-permission';
static ACCESSIDS = 'access-ids';
static ACCESSIDLIKE = 'access-id-like';
static WORKBASKETKEYLIKE = 'workbasket-key-like';
// Pagination
static PAGE = 'page';
static PAGESIZE = 'page-size';
static page = 1;
static pageSize = 9;
// Domain
static DOMAIN = 'domain';
public static getQueryParameters(
sortBy: string = undefined,
order: string = undefined,
name: string = undefined,
nameLike: string = undefined,
descLike: string = undefined,
owner: string = undefined,
ownerLike: string = undefined,
type: string = undefined,
key: string = undefined,
keyLike: string = undefined,
requiredPermission: string = undefined,
page: number = undefined,
pageSize: number = undefined,
domain: string = undefined,
accessIds: string = undefined,
accessIdLike: string = undefined,
workbasketKeyLike: string = undefined,
basketId: string = undefined,
priority: string = undefined,
state: string = undefined,
objRefTypeLike: string = undefined,
objRefValueLike: string = undefined
): string {
public static getQueryParameters(queryParametersModel: QueryParametersModel): string {
let query = '?';
query += sortBy ? `${this.SORTBY}=${sortBy}&` : '';
query += order ? `${this.ORDER}=${order}&` : '';
query += name ? `${this.NAME}=${name}&` : '';
query += nameLike ? `${this.NAMELIKE}=${nameLike}&` : '';
query += descLike ? `${this.DESCLIKE}=${descLike}&` : '';
query += owner ? `${this.OWNER}=${owner}&` : '';
query += ownerLike ? `${this.OWNERLIKE}=${ownerLike}&` : '';
query += basketId ? `${this.WORKBASKET_ID}=${basketId}&` : '';
query += priority ? `${this.PRIORITY}=${priority}&` : '';
query += state ? `${this.STATE}=${state}&` : '';
query += type ? `${this.TYPE}=${type}&` : '';
query += key ? `${this.KEY}=${key}&` : '';
query += keyLike ? `${this.KEYLIKE}=${keyLike}&` : '';
query += requiredPermission
? `${this.REQUIREDPERMISSION}=${requiredPermission}&`
: '';
query += page ? `${this.PAGE}=${page}&` : '';
query += pageSize ? `${this.PAGESIZE}=${pageSize}&` : '';
query += domain ? `${this.DOMAIN}=${domain}&` : '';
query += accessIds ? `${this.ACCESSIDS}=${accessIds}&` : '';
query += accessIdLike ? `${this.ACCESSIDLIKE}=${accessIdLike}&` : '';
query += workbasketKeyLike
? `${this.WORKBASKETKEYLIKE}=${workbasketKeyLike}&`
: '';
query += objRefTypeLike ? `${this.TASK_PRIMARY_OBJ_REF_TYPE_LIKE}=${objRefTypeLike}&` : '';
query += objRefValueLike ? `${this.TASK_PRIMARY_OBJ_REF_VALUE_LIKE}=${objRefValueLike}&` : '';
Object.keys(queryParametersModel).forEach(function (key) {
const value = queryParametersModel[key];
query += value ? `${TaskanaQueryParameters.parameters[key]}=${value}&` : '';
});
query += this.page ? `${TaskanaQueryParameters.parameters.PAGE}=${this.page}&` : '';
query += this.pageSize ? `${TaskanaQueryParameters.parameters.PAGESIZE}=${this.pageSize}&` : '';
query = TaskanaQueryParameters.removeLastChar(query);
return query;
}
private static removeLastChar(query: string): string {
if (query.lastIndexOf('&') === query.length - 1) {
query = query.slice(0, query.lastIndexOf('&'));
}
return query === '?' ? '' : query;
return query
}
}

View File

@ -1,13 +1,14 @@
import {Task} from 'app/workplace/models/task';
import {Observable, Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
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 { Task } from 'app/workplace/models/task';
import { Observable, Subject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
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 { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { map } from 'rxjs/operators';
import { QueryParametersModel } from 'app/models/query-parameters';
@Injectable()
export class TaskService {
@ -46,44 +47,37 @@ export class TaskService {
return this.taskSelectedStream;
}
/**
* @param {string} basketId
* @param {string} sortBy name of field, that the tasks should be sorted by, default is priority
* @returns {Observable<TaskResource>}
*/
/**
* @param {string} basketId the id of workbasket
* @param {string} sortBy name of field, that the tasks should be sorted by, default is priority
* @param {string} sortDirection ASC or DESC
* @param {string} nameLike the name of the task
* @param {string} ownerLike the owner of the task
* @param {string} priority the priority of the task
* @param {string} state the state of the task
*/
findTasksWithWorkbasket(basketId: string,
sortBy = 'priority',
sortDirection: string = Direction.ASC,
nameLike: string,
ownerLike: string,
priority: string,
state: string,
objRefTypeLike: string,
objRefValueLike: string,
allPages: boolean = false): Observable<TaskResource> {
const url = `${this.url}${TaskanaQueryParameters.getQueryParameters(
sortBy, sortDirection, undefined, nameLike, undefined, undefined, ownerLike, undefined, undefined, undefined, undefined,
!allPages ? TaskanaQueryParameters.page : undefined, !allPages ? TaskanaQueryParameters.pageSize : undefined,
undefined, undefined, undefined, undefined, basketId, priority, state, objRefTypeLike, objRefValueLike)}`;
sortBy: string,
sortDirection: string,
nameLike: string,
ownerLike: string,
priority: string,
state: string,
objRefTypeLike: string,
objRefValueLike: string,
allPages: boolean = false): Observable<TaskResource> {
const url = `${this.url}${TaskanaQueryParameters.getQueryParameters(this.accessIdsParameters(
basketId,
sortBy,
sortDirection,
nameLike,
ownerLike,
priority,
state,
objRefTypeLike,
objRefValueLike,
allPages))}`;
return this.httpClient.get<TaskResource>(url);
}
getTask(id: string): Observable<Task> {
return this.httpClient.get<Task>(`${this.url}/${id}`)
.pipe(map(
(response: Task) => {
response = this.applyTaskDatesTimeZone(response);
return response;
}));
.pipe(map(
(response: Task) => {
response = this.applyTaskDatesTimeZone(response);
return response;
}));
}
completeTask(id: string): Observable<Task> {
@ -130,4 +124,34 @@ export class TaskService {
if (task.due) { task.due = new Date(task.due).toISOString(); }
return task;
}
private accessIdsParameters(
basketId: string,
sortBy = 'priority',
sortDirection: string = Direction.ASC,
nameLike: string,
ownerLike: string,
priority: string,
state: string,
objRefTypeLike: string,
objRefValueLike: string,
allPages: boolean = false): QueryParametersModel {
const parameters = new QueryParametersModel();
parameters.WORKBASKET_ID = basketId;
parameters.SORTBY = sortBy;
parameters.SORTDIRECTION = sortDirection;
parameters.NAMELIKE = nameLike
parameters.OWNERLIKE = ownerLike;
parameters.PRIORITY = priority;
parameters.STATE = state;
parameters.TASK_PRIMARY_OBJ_REF_TYPE_LIKE = objRefTypeLike;
parameters.TASK_PRIMARY_OBJ_REF_VALUE_LIKE = objRefValueLike;
if (allPages) {
TaskanaQueryParameters.page = undefined;
TaskanaQueryParameters.pageSize = undefined;
}
return parameters;
}
}

View File

@ -12,7 +12,7 @@ import { Component } from '@angular/core';
import { DomainService } from 'app/services/domain/domain.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
@Component({
selector: 'taskana-dummy-detail',
@ -35,7 +35,7 @@ xdescribe('TaskComponent', () => {
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes)],
declarations: [TaskComponent, SpinnerComponent, DummyDetailComponent],
providers: [TaskService, HttpClient, WorkbasketService, DomainService, RequestInProgressService,
SelectedRouteService, ErrorModalService]
SelectedRouteService, GeneralModalService]
}).compileComponents();
}));

View File

@ -79,8 +79,7 @@
</div>
<div class="form-group col-xs-2">
<label for="task-priority" disabled class="control-label">Priority</label>
<input type="text" class="form-control" id="task-priority" placeholder="Priority" [(ngModel)]="task.priority"
name="task.priority">
<taskana-number-picker [(ngModel)]="task.priority" title="priority" id="task-priority" name="task.priority"></taskana-number-picker>
</div>
</div>
</div>

View File

@ -15,7 +15,7 @@ import { WorkplaceService } from '../services/workplace.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { AlertService } from 'app/services/alert/alert.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
@Component({
selector: 'taskana-dummy-detail',
@ -40,7 +40,7 @@ xdescribe('TaskdetailsComponent', () => {
TaskdetailsAttributeComponent, DummyDetailComponent],
imports: [FormsModule, RouterTestingModule.withRoutes(routes), HttpClientModule],
providers: [TaskService, HttpClient, WorkplaceService, RemoveConfirmationService,
RequestInProgressService, AlertService, ErrorModalService]
RequestInProgressService, AlertService, GeneralModalService]
})
.compileComponents();
}));

View File

@ -6,8 +6,8 @@ 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 'app/models/modal-error';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { GeneralModalService } from 'app/services/general-modal/general-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';
@ -42,7 +42,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
private removeConfirmationService: RemoveConfirmationService,
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private errorModalService: ErrorModalService,
private generalModalService: GeneralModalService,
private masterAndDetailService: MasterAndDetailService) {
}
@ -84,8 +84,8 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.cloneTask();
this.taskService.selectTask(task);
}, err => {
this.errorModalService.triggerError(
new ErrorModel('An error occurred while fetching the task', err));
this.generalModalService.triggerMessage(
new MessageModal('An error occurred while fetching the task', err));
});
}
}

View File

@ -142,9 +142,10 @@ export class TasklistComponent implements OnInit, OnDestroy {
if (this.toolbarElement) {
const toolbarSize = this.toolbarElement.nativeElement.offsetHeight;
const cardHeight = 53;
const unusedHeight = 145;
const unusedHeight = 150;
const totalHeight = window.innerHeight;
const cards = Math.round((totalHeight - (unusedHeight + toolbarSize)) / cardHeight);
TaskanaQueryParameters.page = TaskanaQueryParameters.page ? TaskanaQueryParameters.page : 1;
cards > 0 ? TaskanaQueryParameters.pageSize = cards : TaskanaQueryParameters.pageSize = 1;
}
}

View File

@ -13,4 +13,7 @@
@import 'checkboxes';
@import 'buttons';
@import 'tabs';
@import 'table';
@import 'bootstrap-3-backward-compatibility';
@import 'mixin/colors';
@import 'progress-bar';

View File

@ -24,7 +24,7 @@
}
/* Rules for sizing the icon. */
.material-icons.md-15 { font-size: 15px; }
.material-icons.md-14 { font-size: 15px; }
.material-icons.md-18 { font-size: 18px; }
.material-icons.md-20 { font-size: 20px; }
.material-icons.md-24 { font-size: 24px; }

View File

@ -256,7 +256,7 @@ a > svg-icon > svg{
}
/*end buttons and icons vertical align */
.btn > span.flip {
span.flip {
transform: rotateX(180deg);
}
@ -306,7 +306,7 @@ taskana-monitor-workbaskets, taskana-monitor-classification-tasks {
}
}
taskana-task-details, taskana-classification-details, taskana-access-items-management, taskana-task {
taskana-task-details, taskana-classification-details, taskana-access-items-management, taskana-task, taskana-task-query {
& .panel{
border: none;
box-shadow: none;
@ -319,6 +319,15 @@ taskana-task-details, taskana-classification-details, taskana-access-items-manag
}
}
taskana-task-query {
& .panel{
&> .panel-body {
height: calc(100vh - 105px);
max-height: calc(100vh - 105px);
}
}
}
taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management {
& .panel {
&> .panel-heading {

View File

@ -0,0 +1,55 @@
.divTable{
display: table;
}
.divTableRow {
display: table-row;
}
.divTable .divTableHeading > .divTableRow:last-child > .divTableHeader {
background-color: #f9f9f9;
border-bottom: 1px solid $grey
}
.divTable.table-striped .divTableBody > .divTableRow:nth-of-type(odd) {
background-color: #f9f9f9;
}
.divTableCell, .divTableHeader {
display: table-cell;
padding: 3px 3px;
white-space: nowrap;
min-width: 50px;
vertical-align: middle;
}
.divTableCell{
padding: 0px 3px;
}
.divTableHeaderSeparator, .divTableCellSeparator{
border-left: 1px solid $grey;
border-right: 1px solid $grey;
background-color: $light-grey;
&.zoom-in {
cursor: zoom-in;
}
&.zoom-out {
cursor: zoom-out;
}
min-width: 0px;
}
.divTableHeading {
background-color: $light-grey;
display: table-header-group;
font-weight: bold;
cursor: pointer;
}
.divTableFoot {
background-color: $light-grey;
display: table-footer-group;
font-weight: bold;
}
.divTableBody {
display: table-row-group;
}