TSK-611 Add validation form errors on save
- Add custom form validation on save with highlighting animation and snack bar warning - Added validation for classifications, workbaskets information and access items. - Enable save button always - Refactored animations - Test configuration cleanup
This commit is contained in:
parent
cc62283437
commit
42197bee6c
|
@ -11,7 +11,7 @@
|
||||||
<div *ngIf="classification" id="classification" class="panel panel-default classification">
|
<div *ngIf="classification" id="classification" class="panel panel-default classification">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<button type="button" [disabled]="!ClassificationForm.form.valid" (click)="onSave()" class="btn btn-default btn-primary"
|
<button type="button" (click)="onSubmit()" class="btn btn-default btn-primary"
|
||||||
data-toggle="tooltip" title="Save">
|
data-toggle="tooltip" title="Save">
|
||||||
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<label for="classification-key" class="control-label">Key</label>
|
<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"
|
<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">
|
placeholder="Key" [(ngModel)]="classification.key" name="classification.key">
|
||||||
<div *ngIf="!key.valid && action === 'CREATE'" class="required-text">
|
<div *ngIf="!key.valid && action === 'CREATE'" class="required-text" [@validation]="this.toogleValidationMap.get('classification.key')">
|
||||||
* Key is required
|
* Key is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<label for="classification-name" class="control-label">Name</label>
|
<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"
|
<input type="text" required #name="ngModel" class="form-control" id="classification-name" placeholder="Name" [(ngModel)]="classification.name"
|
||||||
name="classification.name">
|
name="classification.name">
|
||||||
<div *ngIf="!name.valid" class="required-text">
|
<div *ngIf="!name.valid" class="required-text" [@validation]="this.toogleValidationMap.get('classification.name')">
|
||||||
* Name is required
|
* Name is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import { ACTION } from 'app/models/action';
|
||||||
import { ErrorModel } from 'app/models/modal-error';
|
import { ErrorModel } from 'app/models/modal-error';
|
||||||
import { AlertModel, AlertType } from 'app/models/alert';
|
import { AlertModel, AlertType } from 'app/models/alert';
|
||||||
|
|
||||||
|
import { highlight } from 'app/shared/animations/validation.animation';
|
||||||
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
||||||
|
|
||||||
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
|
import { ClassificationsService } from 'app/administration/services/classifications/classifications.service';
|
||||||
|
@ -24,10 +25,13 @@ import { ClassificationCategoriesService } from 'app/administration/services/cla
|
||||||
import { DomainService } from 'app/services/domain/domain.service';
|
import { DomainService } from 'app/services/domain/domain.service';
|
||||||
import { CustomFieldsService } from '../../../services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from '../../../services/custom-fields/custom-fields.service';
|
||||||
import { Pair } from 'app/models/pair';
|
import { Pair } from 'app/models/pair';
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-classification-details',
|
selector: 'taskana-classification-details',
|
||||||
templateUrl: './classification-details.component.html',
|
templateUrl: './classification-details.component.html',
|
||||||
|
animations: [highlight],
|
||||||
styleUrls: ['./classification-details.component.scss']
|
styleUrls: ['./classification-details.component.scss']
|
||||||
})
|
})
|
||||||
export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
|
@ -62,6 +66,9 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
private categoriesSubscription: Subscription;
|
private categoriesSubscription: Subscription;
|
||||||
private domainSubscription: Subscription;
|
private domainSubscription: Subscription;
|
||||||
|
|
||||||
|
@ViewChild('ClassificationForm') classificationForm: NgForm;
|
||||||
|
toogleValidationMap = new Map<string, boolean>();
|
||||||
|
|
||||||
constructor(private classificationsService: ClassificationsService,
|
constructor(private classificationsService: ClassificationsService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
@ -74,7 +81,8 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
private categoryService: ClassificationCategoriesService,
|
private categoryService: ClassificationCategoriesService,
|
||||||
private domainService: DomainService,
|
private domainService: DomainService,
|
||||||
private customFieldsService: CustomFieldsService,
|
private customFieldsService: CustomFieldsService,
|
||||||
private removeConfirmationService: RemoveConfirmationService) { }
|
private removeConfirmationService: RemoveConfirmationService,
|
||||||
|
private formsValidatorService: FormsValidatorService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.classificationTypeService.getClassificationTypes().subscribe((classificationTypes: Array<string>) => {
|
this.classificationTypeService.getClassificationTypes().subscribe((classificationTypes: Array<string>) => {
|
||||||
|
@ -133,7 +141,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`);
|
`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSave() {
|
onSubmit() {
|
||||||
|
if (this.formsValidatorService.validate(this.classificationForm, this.toogleValidationMap)) {
|
||||||
|
this.onSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSave() {
|
||||||
this.requestInProgressService.setRequestInProgress(true);
|
this.requestInProgressService.setRequestInProgress(true);
|
||||||
if (this.action === ACTION.CREATE) {
|
if (this.action === ACTION.CREATE) {
|
||||||
this.classificationSavingSubscription = this.classificationsService.postClassification(this.classification)
|
this.classificationSavingSubscription = this.classificationsService.postClassification(this.classification)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<button type="button" (click)="onSave()" [disabled]="!AccessItemsForm.valid || action === 'COPY'" class="btn btn-default btn-primary"
|
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" class="btn btn-default btn-primary" data-toggle="tooltip"
|
||||||
data-toggle="tooltip" title="Save">
|
title="Save">
|
||||||
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" (click)="clear()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
|
<button type="button" (click)="clear()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
|
||||||
|
@ -49,14 +49,16 @@
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="accessIdField.lookupField else accessIdInput" class="input-group text-align text-width taskana-type-ahead" [ngClass]="{
|
<td *ngIf="accessIdField.lookupField else accessIdInput" class="input-group text-align text-width taskana-type-ahead" [ngClass]="{
|
||||||
'has-warning': (accessItemsClone[index].accessId !== accessItem.value.accessId),
|
'has-warning': (accessItemsClone[index].accessId !== accessItem.value.accessId),
|
||||||
'has-error': !accessItem.value.accessId } ">
|
'has-error': !accessItem.value.accessId }">
|
||||||
<taskana-type-ahead [(ngModel)]="accessItem.value.accessId" formControlName="accessId" placeHolderMessage="Access id is required"></taskana-type-ahead>
|
<taskana-type-ahead [(ngModel)]="accessItem.value.accessId" formControlName="accessId" placeHolderMessage="* Access id is required"
|
||||||
|
[validationValue]="toogleValidationAccessIdMap.get(index)"></taskana-type-ahead>
|
||||||
</td>
|
</td>
|
||||||
<ng-template #accessIdInput>
|
<ng-template #accessIdInput>
|
||||||
<td class="input-group text-align text-width ">
|
<td class="input-group text-align text-width">
|
||||||
<div [ngClass]="{ 'has-warning': (accessItemsClone[index].accessId !== accessItem.value.accessId),
|
<div [ngClass]="{ 'has-warning': (accessItemsClone[index].accessId !==accessItem.value.accessId), 'has-error':
|
||||||
'has-error': !accessItem.value.accessId }">
|
!accessItem.value.accessId }">
|
||||||
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid? 'Access id is required': ''}}">
|
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid?
|
||||||
|
'* Access id is required': ''}}" [@validation]="toogleValidationAccessIdMap.get(index)">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -64,71 +66,71 @@
|
||||||
<input id="checkbox-{{index}}-00" type="checkbox" (change)="checkAll(index, $event)">
|
<input id="checkbox-{{index}}-00" type="checkbox" (change)="checkAll(index, $event)">
|
||||||
<label for="checkbox-{{index}}-00"></label>
|
<label for="checkbox-{{index}}-00"></label>
|
||||||
</td>
|
</td>
|
||||||
<td [ngClass]="{'has-changes': (accessItemsClone[index].permRead !== accessItem.value.permRead)}">
|
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permRead !== accessItem.value.permRead)}">
|
||||||
<input id="checkbox-{{index}}-0" type="checkbox" formControlName="permRead" class="regular-checkbox">
|
<input id="checkbox-{{index}}-0" type="checkbox" formControlName="permRead" class="regular-checkbox">
|
||||||
<label for="checkbox-{{index}}-0"></label>
|
<label for="checkbox-{{index}}-0"></label>
|
||||||
</td>
|
</td>
|
||||||
<td [ngClass]="{'has-changes': (accessItemsClone[index].permOpen !== accessItem.value.permOpen)}">
|
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permOpen !== accessItem.value.permOpen)}">
|
||||||
<input id="checkbox-{{index}}-1" type="checkbox" formControlName="permOpen">
|
<input id="checkbox-{{index}}-1" type="checkbox" formControlName="permOpen">
|
||||||
<label for="checkbox-{{index}}-1"></label>
|
<label for="checkbox-{{index}}-1"></label>
|
||||||
</td>
|
</td>
|
||||||
<td [ngClass]="{'has-changes': (accessItemsClone[index].permAppend !== accessItem.value.permAppend)}">
|
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permAppend !== accessItem.value.permAppend)}">
|
||||||
<input id="checkbox-{{index}}-2" type="checkbox" formControlName="permAppend">
|
<input id="checkbox-{{index}}-2" type="checkbox" formControlName="permAppend">
|
||||||
<label for="checkbox-{{index}}-2"></label>
|
<label for="checkbox-{{index}}-2"></label>
|
||||||
</td>
|
</td>
|
||||||
<td [ngClass]="{'has-changes': (accessItemsClone[index].permTransfer !== accessItem.value.permTransfer)}">
|
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permTransfer !== accessItem.value.permTransfer)}">
|
||||||
<input id="checkbox-{{index}}-3" type="checkbox" formControlName="permTransfer">
|
<input id="checkbox-{{index}}-3" type="checkbox" formControlName="permTransfer">
|
||||||
<label for="checkbox-{{index}}-3"></label>
|
<label for="checkbox-{{index}}-3"></label>
|
||||||
</td>
|
</td>
|
||||||
<td [ngClass]="{'has-changes': (accessItemsClone[index].permDistribute !== accessItem.value.permDistribute)}">
|
<td [ngClass]="{ 'has-changes': (accessItemsClone[index].permDistribute !== accessItem.value.permDistribute)}">
|
||||||
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
||||||
<label for="checkbox-{{index}}-4"></label>
|
<label for="checkbox-{{index}}-4"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom1Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom1 !== accessItem.value.permCustom1)}">
|
<td *ngIf="custom1Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom1 !== accessItem.value.permCustom1)}">
|
||||||
<input id="checkbox-{{index}}-5" type="checkbox" formControlName="permCustom1">
|
<input id="checkbox-{{index}}-5" type="checkbox" formControlName="permCustom1">
|
||||||
<label for="checkbox-{{index}}-5"></label>
|
<label for="checkbox-{{index}}-5"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom2Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom2 !== accessItem.value.permCustom2)}">
|
<td *ngIf="custom2Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom2 !== accessItem.value.permCustom2)}">
|
||||||
<input id="checkbox-{{index}}-6" type="checkbox" formControlName="permCustom2">
|
<input id="checkbox-{{index}}-6" type="checkbox" formControlName="permCustom2">
|
||||||
<label for="checkbox-{{index}}-6"></label>
|
<label for="checkbox-{{index}}-6"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom3Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom3 !== accessItem.value.permCustom3)}">
|
<td *ngIf="custom3Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom3 !== accessItem.value.permCustom3)}">
|
||||||
<input id="checkbox-{{index}}-7" type="checkbox" formControlName="permCustom3">
|
<input id="checkbox-{{index}}-7" type="checkbox" formControlName="permCustom3">
|
||||||
<label for="checkbox-{{index}}-7"></label>
|
<label for="checkbox-{{index}}-7"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom4Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom4 !== accessItem.value.permCustom4)}">
|
<td *ngIf="custom4Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom4 !== accessItem.value.permCustom4)}">
|
||||||
<input id="checkbox-{{index}}-8" type="checkbox" formControlName="permCustom4">
|
<input id="checkbox-{{index}}-8" type="checkbox" formControlName="permCustom4">
|
||||||
<label for="checkbox-{{index}}-8"></label>
|
<label for="checkbox-{{index}}-8"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom5Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom5 !== accessItem.value.permCustom5)}">
|
<td *ngIf="custom5Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom5 !== accessItem.value.permCustom5)}">
|
||||||
<input id="checkbox-{{index}}-9" type="checkbox" formControlName="permCustom5">
|
<input id="checkbox-{{index}}-9" type="checkbox" formControlName="permCustom5">
|
||||||
<label for="checkbox-{{index}}-9"></label>
|
<label for="checkbox-{{index}}-9"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom6Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom6 !== accessItem.value.permCustom6)}">
|
<td *ngIf="custom6Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom6 !== accessItem.value.permCustom6)}">
|
||||||
<input id="checkbox-{{index}}-10" type="checkbox" formControlName="permCustom6">
|
<input id="checkbox-{{index}}-10" type="checkbox" formControlName="permCustom6">
|
||||||
<label for="checkbox-{{index}}-10"></label>
|
<label for="checkbox-{{index}}-10"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom7Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom7 !== accessItem.value.permCustom7)}">
|
<td *ngIf="custom7Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom7 !== accessItem.value.permCustom7)}">
|
||||||
<input id="checkbox-{{index}}-11" type="checkbox" formControlName="permCustom7">
|
<input id="checkbox-{{index}}-11" type="checkbox" formControlName="permCustom7">
|
||||||
<label for="checkbox-{{index}}-11"></label>
|
<label for="checkbox-{{index}}-11"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom8Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom8 !== accessItem.value.permCustom8)}">
|
<td *ngIf="custom8Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom8 !== accessItem.value.permCustom8)}">
|
||||||
<input id="checkbox-{{index}}-12" type="checkbox" formControlName="permCustom8">
|
<input id="checkbox-{{index}}-12" type="checkbox" formControlName="permCustom8">
|
||||||
<label for="checkbox-{{index}}-12"></label>
|
<label for="checkbox-{{index}}-12"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom9Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom9 !== accessItem.value.permCustom9)}">
|
<td *ngIf="custom9Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom9 !== accessItem.value.permCustom9)}">
|
||||||
<input id="checkbox-{{index}}-13" type="checkbox" formControlName="permCustom9">
|
<input id="checkbox-{{index}}-13" type="checkbox" formControlName="permCustom9">
|
||||||
<label for="checkbox-{{index}}-13"></label>
|
<label for="checkbox-{{index}}-13"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom10Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom10 !== accessItem.value.permCustom10)}">
|
<td *ngIf="custom10Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom10 !== accessItem.value.permCustom10)}">
|
||||||
<input id="checkbox-{{index}}-14" type="checkbox" formControlName="permCustom10">
|
<input id="checkbox-{{index}}-14" type="checkbox" formControlName="permCustom10">
|
||||||
<label for="checkbox-{{index}}-14"></label>
|
<label for="checkbox-{{index}}-14"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom11Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom11 !== accessItem.value.permCustom11)}">
|
<td *ngIf="custom11Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom11 !== accessItem.value.permCustom11)}">
|
||||||
<input id="checkbox-{{index}}-15" type="checkbox" formControlName="permCustom11">
|
<input id="checkbox-{{index}}-15" type="checkbox" formControlName="permCustom11">
|
||||||
<label for="checkbox-{{index}}-15"></label>
|
<label for="checkbox-{{index}}-15"></label>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="custom12Field.visible" [ngClass]="{'has-changes': (accessItemsClone[index].permCustom12 !== accessItem.value.permCustom12)}">
|
<td *ngIf="custom12Field.visible" [ngClass]="{ 'has-changes': (accessItemsClone[index].permCustom12 !== accessItem.value.permCustom12)}">
|
||||||
<input id="checkbox-{{index}}-16" type="checkbox" formControlName="permCustom12">
|
<input id="checkbox-{{index}}-16" type="checkbox" formControlName="permCustom12">
|
||||||
<label for="checkbox-{{index}}-16"></label>
|
<label for="checkbox-{{index}}-16"></label>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { HttpClientModule } from '@angular/common/http';
|
||||||
import { HttpModule } from '@angular/http';
|
import { HttpModule } from '@angular/http';
|
||||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { configureTests } from 'app/app.test.configuration';
|
||||||
|
|
||||||
import { Workbasket } from 'app/models/workbasket';
|
import { Workbasket } from 'app/models/workbasket';
|
||||||
import { AlertModel, AlertType } from 'app/models/alert';
|
import { AlertModel, AlertType } from 'app/models/alert';
|
||||||
|
@ -16,46 +17,16 @@ import { ICONTYPES } from 'app/models/type';
|
||||||
import { AccessItemsComponent } from './access-items.component';
|
import { AccessItemsComponent } from './access-items.component';
|
||||||
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
||||||
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
|
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
|
||||||
|
import { TaskanaTypeAheadMockComponent } from 'app/shared/type-ahead/type-ahead.mock.component';
|
||||||
|
|
||||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||||
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||||
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||||
import { AlertService } from 'app/services/alert/alert.service';
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||||
import { configureTests } from 'app/app.test.configuration';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'taskana-type-ahead',
|
|
||||||
template: 'dummydetail',
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: NG_VALUE_ACCESSOR,
|
|
||||||
multi: true,
|
|
||||||
useExisting: forwardRef(() => TaskanaTypeAheadComponent),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class TaskanaTypeAheadComponent implements ControlValueAccessor {
|
|
||||||
@Input()
|
|
||||||
placeHolderMessage;
|
|
||||||
|
|
||||||
writeValue(obj: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
registerOnChange(fn: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
registerOnTouched(fn: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
setDisabledState?(isDisabled: boolean): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('AccessItemsComponent', () => {
|
describe('AccessItemsComponent', () => {
|
||||||
let component: AccessItemsComponent;
|
let component: AccessItemsComponent;
|
||||||
let fixture: ComponentFixture<AccessItemsComponent>;
|
let fixture: ComponentFixture<AccessItemsComponent>;
|
||||||
|
@ -65,7 +36,7 @@ describe('AccessItemsComponent', () => {
|
||||||
beforeEach(done => {
|
beforeEach(done => {
|
||||||
const configure = (testBed: TestBed) => {
|
const configure = (testBed: TestBed) => {
|
||||||
testBed.configureTestingModule({
|
testBed.configureTestingModule({
|
||||||
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent, TaskanaTypeAheadComponent],
|
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent, TaskanaTypeAheadMockComponent],
|
||||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, ReactiveFormsModule],
|
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, ReactiveFormsModule],
|
||||||
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService, RequestInProgressService,
|
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService, RequestInProgressService,
|
||||||
CustomFieldsService]
|
CustomFieldsService]
|
||||||
|
@ -124,7 +95,7 @@ describe('AccessItemsComponent', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show alert successfull after saving', () => {
|
it('should show alert successfull after saving', () => {
|
||||||
component.onSave();
|
component.onSubmit();
|
||||||
expect(alertService.triggerAlert).toHaveBeenCalledWith(
|
expect(alertService.triggerAlert).toHaveBeenCalledWith(
|
||||||
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
|
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { Component, OnInit, Input, AfterViewInit, OnDestroy, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
|
import { Component, Input, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { NgForm, FormGroup, FormControl, FormBuilder, Validators, FormArray } from '@angular/forms';
|
import { FormBuilder, Validators, FormArray } from '@angular/forms';
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
|
|
||||||
import { Workbasket } from 'app/models/workbasket';
|
import { Workbasket } from 'app/models/workbasket';
|
||||||
import { WorkbasketAccessItems } from 'app/models/workbasket-access-items';
|
import { WorkbasketAccessItems } from 'app/models/workbasket-access-items';
|
||||||
|
@ -15,14 +14,14 @@ import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||||
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||||
import { AlertService } from 'app/services/alert/alert.service';
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||||
import { TitlesService } from 'app/services/titles/titles.service';
|
|
||||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||||
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
|
import { highlight } from 'app/shared/animations/validation.animation';
|
||||||
|
|
||||||
declare var $: any;
|
declare const $: any;
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-workbasket-access-items',
|
selector: 'taskana-workbasket-access-items',
|
||||||
templateUrl: './access-items.component.html',
|
templateUrl: './access-items.component.html',
|
||||||
|
animations: [highlight],
|
||||||
styleUrls: ['./access-items.component.scss']
|
styleUrls: ['./access-items.component.scss']
|
||||||
})
|
})
|
||||||
export class AccessItemsComponent implements OnChanges, OnDestroy {
|
export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
|
@ -61,6 +60,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
accessItemsGroups: this.formBuilder.array([
|
accessItemsGroups: this.formBuilder.array([
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
toogleValidationAccessIdMap = new Map<number, boolean>();
|
||||||
|
|
||||||
private initialized = false;
|
private initialized = false;
|
||||||
|
|
||||||
|
@ -141,7 +141,33 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
this.accessItemsClone.splice(index, 1);
|
this.accessItemsClone.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSave() {
|
onSubmit() {
|
||||||
|
let valid = true;
|
||||||
|
for (let i = 0; i < this.accessItemsGroups.length; i++) {
|
||||||
|
if (this.accessItemsGroups.controls[i].invalid) {
|
||||||
|
const validationState = this.toogleValidationAccessIdMap.get(i);
|
||||||
|
validationState ? this.toogleValidationAccessIdMap.set(i, !validationState) : this.toogleValidationAccessIdMap.set(i, true);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!valid) {
|
||||||
|
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, `There are some empty fields which are required.`))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.onSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAll(row: number, value: any) {
|
||||||
|
const checkAll = value.target.checked;
|
||||||
|
const workbasketAccessItemsObj = new WorkbasketAccessItems();
|
||||||
|
for (const property in workbasketAccessItemsObj) {
|
||||||
|
if (property !== 'accessId' && property !== '_links' && property !== 'workbasketId' && property !== 'accessItemId') {
|
||||||
|
this.accessItemsGroups.controls[row].get(property).setValue(checkAll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSave() {
|
||||||
this.requestInProgressService.setRequestInProgress(true);
|
this.requestInProgressService.setRequestInProgress(true);
|
||||||
this.workbasketService.updateWorkBasketAccessItem(this.accessItemsResource._links.self.href, this.AccessItemsForm.value.accessItemsGroups)
|
this.workbasketService.updateWorkBasketAccessItem(this.accessItemsResource._links.self.href, this.AccessItemsForm.value.accessItemsGroups)
|
||||||
.subscribe(response => {
|
.subscribe(response => {
|
||||||
|
@ -156,16 +182,6 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAll(row: number, value: any) {
|
|
||||||
const checkAll = value.target.checked;
|
|
||||||
const workbasketAccessItemsObj = new WorkbasketAccessItems();
|
|
||||||
for (const property in workbasketAccessItemsObj) {
|
|
||||||
if (property !== 'accessId' && property !== '_links' && property !== 'workbasketId' && property !== 'accessItemId') {
|
|
||||||
this.accessItemsGroups.controls[row].get(property).setValue(checkAll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private setBadge() {
|
private setBadge() {
|
||||||
if (this.action === ACTION.COPY) {
|
if (this.action === ACTION.COPY) {
|
||||||
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
|
this.badgeMessage = `Copying workbasket: ${this.workbasket.key}`;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div [@toggle]="toolbarState" *ngIf="toolbarState" class="row">
|
<div [@toggleDown]="toolbarState" *ngIf="toolbarState" class="row">
|
||||||
<taskana-filter class="col-xs-12" (performFilter)="performAvailableFilter($event)"></taskana-filter>
|
<taskana-filter class="col-xs-12" (performFilter)="performAvailableFilter($event)"></taskana-filter>
|
||||||
</div>
|
</div>
|
||||||
<taskana-spinner [isRunning]="requestInProgress" positionClass="centered-spinner" class="floating"></taskana-spinner>
|
<taskana-spinner [isRunning]="requestInProgress" positionClass="centered-spinner" class="floating"></taskana-spinner>
|
||||||
|
|
|
@ -1,28 +1,14 @@
|
||||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { WorkbasketSummary } from 'app/models/workbasket-summary';
|
import { WorkbasketSummary } from 'app/models/workbasket-summary';
|
||||||
import { trigger, state, style, transition, animate, keyframes } from '@angular/animations';
|
|
||||||
import { FilterModel } from 'app/models/filter';
|
import { FilterModel } from 'app/models/filter';
|
||||||
import { filter } from 'rxjs/operators';
|
|
||||||
import { Side } from '../distribution-targets.component';
|
import { Side } from '../distribution-targets.component';
|
||||||
|
import { expandDown } from 'app/shared/animations/expand.animation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-dual-list',
|
selector: 'taskana-dual-list',
|
||||||
templateUrl: './dual-list.component.html',
|
templateUrl: './dual-list.component.html',
|
||||||
styleUrls: ['./dual-list.component.scss'],
|
styleUrls: ['./dual-list.component.scss'],
|
||||||
animations: [
|
animations: [expandDown]
|
||||||
trigger('toggle', [
|
|
||||||
state('*', style({ opacity: '1' })),
|
|
||||||
state('void', style({ opacity: '0' })),
|
|
||||||
transition('void => *', animate('300ms ease-in', keyframes([
|
|
||||||
style({ opacity: 0, height: '0px' }),
|
|
||||||
style({ opacity: 0.5, height: '50px' }),
|
|
||||||
style({ opacity: 1, height: '*' })]))),
|
|
||||||
transition('* => void', animate('300ms ease-out', keyframes([
|
|
||||||
style({ opacity: 1, height: '*' }),
|
|
||||||
style({ opacity: 0.5, height: '50px' }),
|
|
||||||
style({ opacity: 0, height: '0px' })])))
|
|
||||||
]
|
|
||||||
)],
|
|
||||||
})
|
})
|
||||||
export class DualListComponent implements OnInit {
|
export class DualListComponent implements OnInit {
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<button type="button" [disabled]="!WorkbasketForm.form.valid" (click)="onSave()" class="btn btn-default btn-primary" data-toggle="tooltip"
|
<button type="button" (click)="onSubmit()" class="btn btn-default btn-primary" data-toggle="tooltip" title="Save">
|
||||||
title="Save">
|
|
||||||
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" (click)="onClear()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
|
<button type="button" (click)="onClear()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
|
||||||
|
@ -30,7 +29,7 @@
|
||||||
<label for="wb-key" class="control-label">Key</label>
|
<label for="wb-key" class="control-label">Key</label>
|
||||||
<input type="text" required #key="ngModel" class="form-control" id="wb-key" placeholder="Key" [(ngModel)]="workbasket.key"
|
<input type="text" required #key="ngModel" class="form-control" id="wb-key" placeholder="Key" [(ngModel)]="workbasket.key"
|
||||||
name="workbasket.key">
|
name="workbasket.key">
|
||||||
<div *ngIf="!key.valid" class="required-text">
|
<div *ngIf="!key.valid" class="required-text" [@validation]="this.toogleValidationMap.get('workbasket.key')">
|
||||||
* Key is required
|
* Key is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,18 +37,18 @@
|
||||||
<label for="wb-name" class="control-label">Name</label>
|
<label for="wb-name" class="control-label">Name</label>
|
||||||
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name" [(ngModel)]="workbasket.name"
|
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name" [(ngModel)]="workbasket.name"
|
||||||
name="workbasket.name">
|
name="workbasket.name">
|
||||||
<div *ngIf="!name.valid" class="required-text">
|
<div *ngIf="!name.valid" class="required-text" [@validation]="this.toogleValidationMap.get('workbasket.name')">
|
||||||
* Name is required
|
* Name is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label for="wb-owner" class="control-label">Owner</label>
|
<label for="wb-owner" class="control-label">Owner</label>
|
||||||
<taskana-type-ahead *ngIf="ownerField.lookupField else ownerInput" required #owner="ngModel" name="owner" [(ngModel)]="workbasket.owner"
|
<taskana-type-ahead *ngIf="ownerField.lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner" [(ngModel)]="workbasket.owner"
|
||||||
placeHolderMessage="Owner is required"></taskana-type-ahead>
|
placeHolderMessage="* Owner is required" [validationValue]="this.toogleValidationMap.get('workbasket.owner')"></taskana-type-ahead>
|
||||||
<ng-template #ownerInput>
|
<ng-template #ownerInput>
|
||||||
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
|
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
|
||||||
name="workbasket.owner">
|
name="workbasket.owner">
|
||||||
<div *ngIf="!owner?.valid" class="required-text">
|
<div *ngIf="!owner?.valid" class="required-text" [@validation]="this.toogleValidationMap.get('workbasket.owner')">
|
||||||
* Owner is required
|
* Owner is required
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing';
|
||||||
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||||
import { WorkbasketInformationComponent } from './workbasket-information.component';
|
import { WorkbasketInformationComponent } from './workbasket-information.component';
|
||||||
import { FormsModule, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { HttpModule } from '@angular/http';
|
import { HttpModule } from '@angular/http';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Component, Input, forwardRef } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
|
|
||||||
import { Workbasket } from 'app/models/workbasket';
|
import { Workbasket } from 'app/models/workbasket';
|
||||||
|
@ -18,11 +18,13 @@ import { Links } from 'app/models/links';
|
||||||
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
|
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
|
||||||
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
||||||
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
|
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
|
||||||
|
import { TaskanaTypeAheadMockComponent } from 'app/shared/type-ahead/type-ahead.mock.component';
|
||||||
|
|
||||||
import { MapValuesPipe } from 'app/shared/pipes/mapValues/map-values.pipe';
|
import { MapValuesPipe } from 'app/shared/pipes/mapValues/map-values.pipe';
|
||||||
import { RemoveNoneTypePipe } from 'app/shared/pipes/removeNoneType/remove-none-type.pipe';
|
import { RemoveNoneTypePipe } from 'app/shared/pipes/removeNoneType/remove-none-type.pipe';
|
||||||
|
|
||||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||||
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||||
import { AlertService } from 'app/services/alert/alert.service';
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||||
|
@ -35,36 +37,6 @@ import { configureTests } from 'app/app.test.configuration';
|
||||||
export class DummyDetailComponent {
|
export class DummyDetailComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'taskana-type-ahead',
|
|
||||||
template: 'dummydetail',
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: NG_VALUE_ACCESSOR,
|
|
||||||
multi: true,
|
|
||||||
useExisting: forwardRef(() => TaskanaTypeAheadComponent),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class TaskanaTypeAheadComponent implements ControlValueAccessor {
|
|
||||||
@Input()
|
|
||||||
placeHolderMessage;
|
|
||||||
|
|
||||||
writeValue(obj: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
registerOnChange(fn: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
registerOnTouched(fn: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
setDisabledState?(isDisabled: boolean): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' },
|
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' },
|
||||||
{ path: 'someNewId', component: DummyDetailComponent }
|
{ path: 'someNewId', component: DummyDetailComponent }
|
||||||
|
@ -80,7 +52,7 @@ describe('InformationComponent', () => {
|
||||||
testBed.configureTestingModule({
|
testBed.configureTestingModule({
|
||||||
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
|
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
|
||||||
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent, DummyDetailComponent,
|
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent, DummyDetailComponent,
|
||||||
TaskanaTypeAheadComponent],
|
TaskanaTypeAheadMockComponent],
|
||||||
imports: [FormsModule,
|
imports: [FormsModule,
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
@ -153,7 +125,7 @@ describe('InformationComponent', () => {
|
||||||
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
|
||||||
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket));
|
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket));
|
||||||
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket));
|
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket));
|
||||||
component.onSave();
|
component.onSubmit();
|
||||||
expect(component.requestInProgress).toBeFalsy();
|
expect(component.requestInProgress).toBeFalsy();
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
@ -164,7 +136,8 @@ describe('InformationComponent', () => {
|
||||||
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }));
|
||||||
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket));
|
spyOn(workbasketService, 'updateWorkbasket').and.returnValue(Observable.of(component.workbasket));
|
||||||
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket));
|
spyOn(workbasketService, 'triggerWorkBasketSaved').and.returnValue(Observable.of(component.workbasket));
|
||||||
component.onSave();
|
fixture.detectChanges();
|
||||||
|
component.onSubmit();
|
||||||
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
|
expect(workbasketService.triggerWorkBasketSaved).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -177,8 +150,8 @@ describe('InformationComponent', () => {
|
||||||
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
new Workbasket('someNewId', 'created', 'keyModified', 'domain', ICONTYPES.TOPIC, 'modified', 'name', 'description',
|
||||||
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
'owner', 'custom1', 'custom2', 'custom3', 'custom4', 'orgLevel1', 'orgLevel2',
|
||||||
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }))));
|
'orgLevel3', 'orgLevel4', new Links({ 'href': 'someUrl' }))));
|
||||||
|
fixture.detectChanges();
|
||||||
component.onSave();
|
component.onSubmit();
|
||||||
expect(alertService.triggerAlert).toHaveBeenCalled();
|
expect(alertService.triggerAlert).toHaveBeenCalled();
|
||||||
expect(component.workbasket.workbasketId).toBe('someNewId');
|
expect(component.workbasket.workbasketId).toBe('someNewId');
|
||||||
});
|
});
|
||||||
|
@ -199,8 +172,8 @@ describe('InformationComponent', () => {
|
||||||
|
|
||||||
spyOn(savingWorkbasketService, 'triggerDistributionTargetSaving');
|
spyOn(savingWorkbasketService, 'triggerDistributionTargetSaving');
|
||||||
spyOn(savingWorkbasketService, 'triggerAccessItemsSaving');
|
spyOn(savingWorkbasketService, 'triggerAccessItemsSaving');
|
||||||
|
fixture.detectChanges();
|
||||||
component.onSave();
|
component.onSubmit();
|
||||||
expect(alertService.triggerAlert).toHaveBeenCalled();
|
expect(alertService.triggerAlert).toHaveBeenCalled();
|
||||||
expect(component.workbasket.workbasketId).toBe('someNewId');
|
expect(component.workbasket.workbasketId).toBe('someNewId');
|
||||||
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
|
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
|
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
|
||||||
import { ICONTYPES } from 'app/models/type';
|
import { ICONTYPES } from 'app/models/type';
|
||||||
import { ErrorModel } from 'app/models/modal-error';
|
import { ErrorModel } from 'app/models/modal-error';
|
||||||
|
@ -16,9 +17,12 @@ import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||||
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
|
||||||
|
import { highlight } from 'app/shared/animations/validation.animation';
|
||||||
|
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-workbasket-information',
|
selector: 'taskana-workbasket-information',
|
||||||
|
animations: [highlight],
|
||||||
templateUrl: './workbasket-information.component.html',
|
templateUrl: './workbasket-information.component.html',
|
||||||
styleUrls: ['./workbasket-information.component.scss']
|
styleUrls: ['./workbasket-information.component.scss']
|
||||||
})
|
})
|
||||||
|
@ -28,6 +32,7 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
|
||||||
@Input()
|
@Input()
|
||||||
workbasket: Workbasket;
|
workbasket: Workbasket;
|
||||||
workbasketClone: Workbasket;
|
workbasketClone: Workbasket;
|
||||||
|
workbasketErrors
|
||||||
@Input()
|
@Input()
|
||||||
action: string;
|
action: string;
|
||||||
|
|
||||||
|
@ -41,8 +46,11 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
|
||||||
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'workbaskets.information.custom3');
|
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'workbaskets.information.custom3');
|
||||||
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'workbaskets.information.custom4');
|
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'workbaskets.information.custom4');
|
||||||
|
|
||||||
|
toogleValidationMap = new Map<string, boolean>();
|
||||||
|
|
||||||
private workbasketSubscription: Subscription;
|
private workbasketSubscription: Subscription;
|
||||||
private routeSubscription: Subscription;
|
private routeSubscription: Subscription;
|
||||||
|
@ViewChild('WorkbasketForm') workbasketForm: NgForm;
|
||||||
|
|
||||||
constructor(private workbasketService: WorkbasketService,
|
constructor(private workbasketService: WorkbasketService,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
|
@ -52,7 +60,8 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
|
||||||
private savingWorkbasket: SavingWorkbasketService,
|
private savingWorkbasket: SavingWorkbasketService,
|
||||||
private requestInProgressService: RequestInProgressService,
|
private requestInProgressService: RequestInProgressService,
|
||||||
private customFieldsService: CustomFieldsService,
|
private customFieldsService: CustomFieldsService,
|
||||||
private removeConfirmationService: RemoveConfirmationService) {
|
private removeConfirmationService: RemoveConfirmationService,
|
||||||
|
private formsValidatorService: FormsValidatorService) {
|
||||||
this.allTypes = new Map([['PERSONAL', 'Personal'], ['GROUP', 'Group'],
|
this.allTypes = new Map([['PERSONAL', 'Personal'], ['GROUP', 'Group'],
|
||||||
['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']])
|
['CLEARANCE', 'Clearance'], ['TOPIC', 'Topic']])
|
||||||
|
|
||||||
|
@ -75,7 +84,13 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
|
||||||
this.workbasket.type = type;
|
this.workbasket.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSave() {
|
onSubmit() {
|
||||||
|
if (this.workbasketForm && this.formsValidatorService.validate(this.workbasketForm, this.toogleValidationMap)) {
|
||||||
|
this.onSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSave() {
|
||||||
this.beforeRequest();
|
this.beforeRequest();
|
||||||
if (!this.workbasket.workbasketId) {
|
if (!this.workbasket.workbasketId) {
|
||||||
this.postNewWorkbasket();
|
this.postNewWorkbasket();
|
||||||
|
|
|
@ -21,6 +21,10 @@ import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||||
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
|
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
|
||||||
import { AlertService } from 'app/services/alert/alert.service';
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||||
|
import { ErrorModalService } from 'app/services/errorModal/error-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';
|
||||||
|
|
||||||
import { WorkbasketDetailsComponent } from './workbasket-details.component';
|
import { WorkbasketDetailsComponent } from './workbasket-details.component';
|
||||||
import { WorkbasketInformationComponent } from './information/workbasket-information.component';
|
import { WorkbasketInformationComponent } from './information/workbasket-information.component';
|
||||||
|
@ -31,13 +35,14 @@ import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
||||||
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
|
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
|
||||||
import { AlertComponent } from 'app/shared/alert/alert.component';
|
import { AlertComponent } from 'app/shared/alert/alert.component';
|
||||||
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
|
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
|
||||||
|
import { TaskanaTypeAheadMockComponent } from 'app/shared/type-ahead/type-ahead.mock.component';
|
||||||
|
|
||||||
import { MapValuesPipe } from 'app/shared/pipes/mapValues/map-values.pipe';
|
import { MapValuesPipe } from 'app/shared/pipes/mapValues/map-values.pipe';
|
||||||
import { RemoveNoneTypePipe } from 'app/shared/pipes/removeNoneType/remove-none-type.pipe';
|
import { RemoveNoneTypePipe } from 'app/shared/pipes/removeNoneType/remove-none-type.pipe';
|
||||||
import { SelectWorkBasketPipe } from 'app/shared/pipes/selectedWorkbasket/seleted-workbasket.pipe';
|
import { SelectWorkBasketPipe } from 'app/shared/pipes/selectedWorkbasket/seleted-workbasket.pipe';
|
||||||
import { ErrorModalService } from 'app/services/errorModal/error-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';
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-filter',
|
selector: 'taskana-filter',
|
||||||
template: ''
|
template: ''
|
||||||
|
@ -55,37 +60,6 @@ export class FilterComponent {
|
||||||
export class DummyDetailComponent {
|
export class DummyDetailComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'taskana-type-ahead',
|
|
||||||
template: 'dummydetail',
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: NG_VALUE_ACCESSOR,
|
|
||||||
multi: true,
|
|
||||||
useExisting: forwardRef(() => TaskanaTypeAheadComponent),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class TaskanaTypeAheadComponent implements ControlValueAccessor {
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
placeHolderMessage;
|
|
||||||
|
|
||||||
writeValue(obj: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
registerOnChange(fn: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
registerOnTouched(fn: any): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
setDisabledState?(isDisabled: boolean): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('WorkbasketDetailsComponent', () => {
|
describe('WorkbasketDetailsComponent', () => {
|
||||||
let component: WorkbasketDetailsComponent;
|
let component: WorkbasketDetailsComponent;
|
||||||
let fixture: ComponentFixture<WorkbasketDetailsComponent>;
|
let fixture: ComponentFixture<WorkbasketDetailsComponent>;
|
||||||
|
@ -107,7 +81,7 @@ describe('WorkbasketDetailsComponent', () => {
|
||||||
declarations: [WorkbasketDetailsComponent, WorkbasketInformationComponent, SpinnerComponent,
|
declarations: [WorkbasketDetailsComponent, WorkbasketInformationComponent, SpinnerComponent,
|
||||||
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
||||||
DistributionTargetsComponent, FilterComponent, DualListComponent, DummyDetailComponent,
|
DistributionTargetsComponent, FilterComponent, DualListComponent, DummyDetailComponent,
|
||||||
TaskanaTypeAheadComponent, SelectWorkBasketPipe],
|
TaskanaTypeAheadMockComponent, SelectWorkBasketPipe],
|
||||||
providers: [WorkbasketService, MasterAndDetailService, ErrorModalService, RequestInProgressService,
|
providers: [WorkbasketService, MasterAndDetailService, ErrorModalService, RequestInProgressService,
|
||||||
AlertService, SavingWorkbasketService,
|
AlertService, SavingWorkbasketService,
|
||||||
CustomFieldsService]
|
CustomFieldsService]
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div [@toggle]="toolbarState" *ngIf="toolbarState" class="row no-overflow">
|
<div [@toggleDown]="toolbarState" *ngIf="toolbarState" class="row no-overflow">
|
||||||
<taskana-filter (performFilter)="filtering($event)"></taskana-filter>
|
<taskana-filter (performFilter)="filtering($event)"></taskana-filter>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,34 +1,21 @@
|
||||||
import { Component, OnInit, Input, Output, EventEmitter, AfterViewChecked } from '@angular/core';
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { trigger, state, style, transition, animate, keyframes } from '@angular/animations';
|
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
import { SortingModel } from 'app/models/sorting';
|
import { SortingModel } from 'app/models/sorting';
|
||||||
import { FilterModel } from 'app/models/filter';
|
import { FilterModel } from 'app/models/filter';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { WorkbasketSummary } from 'app/models/workbasket-summary';
|
import { WorkbasketSummary } from 'app/models/workbasket-summary';
|
||||||
import { ErrorModel } from 'app/models/modal-error';
|
|
||||||
import { AlertModel, AlertType } from 'app/models/alert';
|
|
||||||
|
|
||||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||||
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||||
import { AlertService } from 'app/services/alert/alert.service';
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
import { ImportType } from 'app/models/import-type';
|
import { ImportType } from 'app/models/import-type';
|
||||||
|
import { expandDown } from 'app/shared/animations/expand.animation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-workbasket-list-toolbar',
|
selector: 'taskana-workbasket-list-toolbar',
|
||||||
animations: [
|
animations: [expandDown],
|
||||||
trigger('toggle', [
|
|
||||||
transition('void => *', animate('300ms ease-in', keyframes([
|
|
||||||
style({ height: '0px' }),
|
|
||||||
style({ height: '50px' }),
|
|
||||||
style({ height: '*' })]))),
|
|
||||||
transition('* => void', animate('300ms ease-out', keyframes([
|
|
||||||
style({ height: '*' }),
|
|
||||||
style({ height: '50px' }),
|
|
||||||
style({ height: '0px' })])))
|
|
||||||
]
|
|
||||||
)],
|
|
||||||
templateUrl: './workbasket-list-toolbar.component.html',
|
templateUrl: './workbasket-list-toolbar.component.html',
|
||||||
styleUrls: ['./workbasket-list-toolbar.component.scss']
|
styleUrls: ['./workbasket-list-toolbar.component.scss']
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,6 +20,8 @@ import { ErrorModalService } from './services/errorModal/error-modal.service';
|
||||||
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
|
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
|
||||||
import { OrientationService } from './services/orientation/orientation.service';
|
import { OrientationService } from './services/orientation/orientation.service';
|
||||||
import { SelectedRouteService } from './services/selected-route/selected-route';
|
import { SelectedRouteService } from './services/selected-route/selected-route';
|
||||||
|
import { FormsValidatorService } from './shared/services/forms/forms-validator.service';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
|
||||||
export const configureTests = (configure: (testBed: TestBed) => void) => {
|
export const configureTests = (configure: (testBed: TestBed) => void) => {
|
||||||
|
@ -33,9 +35,10 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
|
||||||
|
|
||||||
configure(testBed);
|
configure(testBed);
|
||||||
testBed.configureTestingModule({
|
testBed.configureTestingModule({
|
||||||
|
imports: [BrowserAnimationsModule],
|
||||||
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
|
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
|
||||||
{ provide: DomainService, useClass: DomainServiceMock }, CustomFieldsService, RemoveConfirmationService,
|
{ provide: DomainService, useClass: DomainServiceMock }, CustomFieldsService, RemoveConfirmationService,
|
||||||
AlertService, ErrorModalService, RequestInProgressService, OrientationService, SelectedRouteService]
|
AlertService, ErrorModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
|
||||||
});
|
});
|
||||||
|
|
||||||
return testBed.compileComponents().then(() => testBed);
|
return testBed.compileComponents().then(() => testBed);
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { TaskanaTypeAheadMockComponent } from 'app/shared/type-ahead/type-ahead.mock.component';
|
||||||
|
|
||||||
|
const MODULES = [
|
||||||
|
];
|
||||||
|
|
||||||
|
const DECLARATIONS = [
|
||||||
|
TaskanaTypeAheadMockComponent
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: DECLARATIONS,
|
||||||
|
imports: MODULES,
|
||||||
|
providers: []
|
||||||
|
})
|
||||||
|
export class AppTestModule {
|
||||||
|
}
|
|
@ -30,7 +30,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div [@toggle]="showNavbar" *ngIf="showNavbar" class="navbar-inverse sidenav full-height col-xs-9 col-sm-3" data-html="false"
|
<div [@toggleRight]="showNavbar" *ngIf="showNavbar" class="navbar-inverse sidenav full-height col-xs-9 col-sm-3" data-html="false"
|
||||||
aria-expanded="true">
|
aria-expanded="true">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
|
|
|
@ -2,29 +2,18 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { environment } from 'environments/environment';
|
import { environment } from 'environments/environment';
|
||||||
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
|
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { trigger, state, style, transition, keyframes, animate } from '@angular/animations';
|
|
||||||
import { DomainService } from 'app/services/domain/domain.service';
|
import { DomainService } from 'app/services/domain/domain.service';
|
||||||
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
|
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
|
||||||
import { MonitorGuard } from 'app/guards/monitor-guard';
|
import { MonitorGuard } from 'app/guards/monitor-guard';
|
||||||
import { WindowRefService } from 'app/services/window/window.service';
|
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 { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service';
|
||||||
|
import { expandRight } from 'app/shared/animations/expand.animation';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-nav-bar',
|
selector: 'taskana-nav-bar',
|
||||||
templateUrl: './nav-bar.component.html',
|
templateUrl: './nav-bar.component.html',
|
||||||
styleUrls: ['./nav-bar.component.scss'],
|
styleUrls: ['./nav-bar.component.scss'],
|
||||||
animations: [
|
animations: [expandRight],
|
||||||
trigger('toggle', [
|
|
||||||
transition('void => *', animate('300ms ease-in', keyframes([
|
|
||||||
style({ opacity: 0, width: '0px' }),
|
|
||||||
style({ opacity: 1, width: '150px' }),
|
|
||||||
style({ opacity: 1, width: '*' })]))),
|
|
||||||
transition('* => void', animate('300ms ease-out', keyframes([
|
|
||||||
style({ opacity: 1, width: '*' }),
|
|
||||||
style({ opacity: 0, width: '150px' }),
|
|
||||||
style({ opacity: 0, width: '0px' })])))
|
|
||||||
]
|
|
||||||
)],
|
|
||||||
})
|
})
|
||||||
export class NavBarComponent implements OnInit, OnDestroy {
|
export class NavBarComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { environment } from 'environments/environment';
|
|
||||||
import { UserInfoModel } from 'app/models/user-info';
|
import { UserInfoModel } from 'app/models/user-info';
|
||||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TaskanaEngineServiceMock {
|
export class TaskanaEngineServiceMock {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div *ngIf="alert" [@alertState]="alert" class="alert alert-{{alert.type}} {{alert.autoClosing? '':'alert-dismissible'}} footer"
|
<div *ngIf="alert" [@toggleTop]="alert" class="alert alert-{{alert.type}} {{alert.autoClosing? '':'alert-dismissible'}} footer"
|
||||||
role="alert">
|
role="alert">
|
||||||
<span class="glyphicon {{alert.type === 'success'? 'glyphicon-thumbs-up': 'glyphicon-exclamation-sign' }}" aria-hidden="true"></span>
|
<span class="glyphicon {{alert.type === 'success'? 'glyphicon-thumbs-up': 'glyphicon-exclamation-sign' }}" aria-hidden="true"></span>
|
||||||
{{alert.text}}
|
{{alert.text}}
|
||||||
|
|
|
@ -1,25 +1,14 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { trigger, state, style, animate, transition } from '@angular/animations';
|
|
||||||
|
|
||||||
import { AlertModel } from 'app/models/alert';
|
import { AlertModel } from 'app/models/alert';
|
||||||
import { AlertService } from 'app/services/alert/alert.service';
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
|
import { expandTop } from '../animations/expand.animation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-alert',
|
selector: 'taskana-alert',
|
||||||
templateUrl: './alert.component.html',
|
templateUrl: './alert.component.html',
|
||||||
styleUrls: ['./alert.component.scss'],
|
styleUrls: ['./alert.component.scss'],
|
||||||
animations: [
|
animations: [expandTop]
|
||||||
trigger('alertState', [
|
|
||||||
state('in', style({ transform: 'translateY(0)', overflow: 'hidden' })),
|
|
||||||
transition('void => *', [
|
|
||||||
style({ transform: 'translateY(100%)', overflow: 'hidden' }),
|
|
||||||
animate(100)
|
|
||||||
]),
|
|
||||||
transition('* => void', [
|
|
||||||
animate(100, style({ transform: 'translateY(100%)', overflow: 'hidden' }))
|
|
||||||
])
|
|
||||||
])
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export class AlertComponent implements OnInit {
|
export class AlertComponent implements OnInit {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { trigger, style, transition, animate, keyframes, state } from '@angular/core';
|
||||||
|
|
||||||
|
export const expandDown =
|
||||||
|
trigger('toggleDown', [
|
||||||
|
state('*', style({ opacity: '1' })),
|
||||||
|
state('void', style({ opacity: '0' })),
|
||||||
|
transition('void => *', animate('300ms ease-in', keyframes([
|
||||||
|
style({ opacity: 0, height: '0px' }),
|
||||||
|
style({ opacity: 0.5, height: '50px' }),
|
||||||
|
style({ opacity: 1, height: '*' })]))),
|
||||||
|
transition('* => void', animate('300ms ease-out', keyframes([
|
||||||
|
style({ opacity: 1, height: '*' }),
|
||||||
|
style({ opacity: 0.5, height: '50px' }),
|
||||||
|
style({ opacity: 0, height: '0px' })])))
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
export const expandRight = trigger('toggleRight', [
|
||||||
|
transition('void => *', animate('300ms ease-in', keyframes([
|
||||||
|
style({ opacity: 0, width: '0px' }),
|
||||||
|
style({ opacity: 1, width: '150px' }),
|
||||||
|
style({ opacity: 1, width: '*' })]))),
|
||||||
|
transition('* => void', animate('300ms ease-out', keyframes([
|
||||||
|
style({ opacity: 1, width: '*' }),
|
||||||
|
style({ opacity: 0, width: '150px' }),
|
||||||
|
style({ opacity: 0, width: '0px' })])))
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const expandTop = trigger('toggleTop', [
|
||||||
|
state('in', style({ transform: 'translateY(0)', overflow: 'hidden' })),
|
||||||
|
transition('void => *', [
|
||||||
|
style({ transform: 'translateY(100%)', overflow: 'hidden' }),
|
||||||
|
animate(100)
|
||||||
|
]),
|
||||||
|
transition('* => void', [
|
||||||
|
animate(100, style({ transform: 'translateY(100%)', overflow: 'hidden' }))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
export const opacity = trigger('toggleOpacity', [
|
||||||
|
state('*', style({ opacity: '1' })),
|
||||||
|
state('void', style({ opacity: '0' })),
|
||||||
|
transition('void => *', animate('300ms ease-in', keyframes([
|
||||||
|
style({ opacity: 0 }),
|
||||||
|
style({ opacity: 0.5 }),
|
||||||
|
style({ opacity: 1 })]))),
|
||||||
|
transition('* => void', animate('300ms ease-out', keyframes([
|
||||||
|
style({ opacity: 1 }),
|
||||||
|
style({ opacity: 0.5 }),
|
||||||
|
style({ opacity: 0 })])))
|
||||||
|
])
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { trigger, style, transition, animate, keyframes } from '@angular/core';
|
||||||
|
|
||||||
|
export const highlight = trigger('validation', [
|
||||||
|
transition('true => false, false => true, * => true', animate('1500ms', keyframes([
|
||||||
|
style({ opacity: '1', }),
|
||||||
|
style({ opacity: '0.3' }),
|
||||||
|
style({ opacity: '1' }),
|
||||||
|
style({ opacity: '0.3' }),
|
||||||
|
style({ opacity: '1' }),
|
||||||
|
style({ opacity: '0.3' }),
|
||||||
|
style({ opacity: '1' })])))
|
||||||
|
]);
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { AlertService } from 'app/services/alert/alert.service';
|
||||||
|
import { AlertModel, AlertType } from 'app/models/alert';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FormsValidatorService {
|
||||||
|
constructor(
|
||||||
|
private alertService: AlertService) { }
|
||||||
|
|
||||||
|
public validate(form: NgForm, toogleValidationMap: Map<any, boolean>): boolean {
|
||||||
|
let valid = true;
|
||||||
|
for (const control in form.form.controls) {
|
||||||
|
if (form.form.controls[control].invalid) {
|
||||||
|
const validationState = toogleValidationMap.get(control);
|
||||||
|
validationState ? toogleValidationMap.set(control, !validationState) : toogleValidationMap.set(control, true);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!valid) {
|
||||||
|
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, `There are some empty fields which are required.`))
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import { AlertComponent } from 'app/shared/alert/alert.component';
|
||||||
import { MasterAndDetailComponent } from 'app/shared/master-and-detail/master-and-detail.component';
|
import { MasterAndDetailComponent } from 'app/shared/master-and-detail/master-and-detail.component';
|
||||||
import { TaskanaTreeComponent } from 'app/shared/tree/tree.component';
|
import { TaskanaTreeComponent } from 'app/shared/tree/tree.component';
|
||||||
import { TypeAheadComponent } from 'app/shared/type-ahead/type-ahead.component';
|
import { TypeAheadComponent } from 'app/shared/type-ahead/type-ahead.component';
|
||||||
|
import { SortComponent } from './sort/sort.component';
|
||||||
import { RemoveConfirmationComponent } from 'app/shared/remove-confirmation/remove-confirmation.component';
|
import { RemoveConfirmationComponent } from 'app/shared/remove-confirmation/remove-confirmation.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +32,7 @@ import { MapToIterable } from './pipes/mapToIterable/mapToIterable';
|
||||||
*/
|
*/
|
||||||
import { HttpClientInterceptor } from './services/httpClientInterceptor/http-client-interceptor.service';
|
import { HttpClientInterceptor } from './services/httpClientInterceptor/http-client-interceptor.service';
|
||||||
import { AccessIdsService } from './services/access-ids/access-ids.service';
|
import { AccessIdsService } from './services/access-ids/access-ids.service';
|
||||||
import { SortComponent } from './sort/sort.component';
|
import { FormsValidatorService } from './services/forms/forms-validator.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +74,8 @@ const DECLARATIONS = [
|
||||||
useClass: HttpClientInterceptor,
|
useClass: HttpClientInterceptor,
|
||||||
multi: true
|
multi: true
|
||||||
},
|
},
|
||||||
AccessIdsService
|
AccessIdsService,
|
||||||
|
FormsValidatorService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule {
|
export class SharedModule {
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
|
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
|
||||||
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView"
|
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView"
|
||||||
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)"
|
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)"
|
||||||
placeholder="{{accessItemName.invalid? placeHolderMessage: ''}}">
|
placeholder="{{accessItemName.invalid? placeHolderMessage: ''}}" [@validation]="validationValue">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,20 +1,25 @@
|
||||||
$blue: #2e9eca;
|
$blue: #2e9eca;
|
||||||
$grey: #ddd;
|
$grey: #ddd;
|
||||||
|
$invalid: #a94442;
|
||||||
.wrapper-text {
|
.wrapper-text {
|
||||||
height: 47px;
|
height: 47px;
|
||||||
& label {
|
& label {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
|
padding-left: 12px;
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
& div {
|
& div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid $grey;
|
border-bottom: 1px solid $grey;
|
||||||
margin-top:6px;
|
margin-top:6px;
|
||||||
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
> div{
|
> div{
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +35,7 @@ $grey: #ddd;
|
||||||
&:focus{
|
&:focus{
|
||||||
border-bottom: 1px solid $blue;
|
border-bottom: 1px solid $blue;
|
||||||
}
|
}
|
||||||
|
padding-left: 12px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,3 +56,15 @@ $grey: #ddd;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||||
|
color: $invalid;
|
||||||
|
opacity: 1; /* Firefox */
|
||||||
|
}
|
||||||
|
:-ms-input-placeholder { /* Internet Explorer 10-11 */
|
||||||
|
color: $invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-ms-input-placeholder { /* Microsoft Edge */
|
||||||
|
color: $invalid;
|
||||||
|
}
|
|
@ -1,18 +1,17 @@
|
||||||
import { Component, OnInit, Input, EventEmitter, Output, ViewChild, ElementRef, forwardRef } from '@angular/core';
|
import { Component, OnInit, Input, ViewChild, forwardRef } from '@angular/core';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
|
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
|
||||||
|
|
||||||
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
||||||
import { AccessItemsComponent } from 'app/administration/workbasket/details/access-items/access-items.component';
|
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
import { highlight } from 'app/shared/animations/validation.animation';
|
||||||
|
|
||||||
const noop = () => {
|
|
||||||
};
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-type-ahead',
|
selector: 'taskana-type-ahead',
|
||||||
templateUrl: './type-ahead.component.html',
|
templateUrl: './type-ahead.component.html',
|
||||||
styleUrls: ['./type-ahead.component.scss'],
|
styleUrls: ['./type-ahead.component.scss'],
|
||||||
|
animations: [highlight],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
@ -29,6 +28,9 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
|
||||||
@Input()
|
@Input()
|
||||||
placeHolderMessage;
|
placeHolderMessage;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
validationValue;
|
||||||
|
|
||||||
@ViewChild('inputTypeAhead')
|
@ViewChild('inputTypeAhead')
|
||||||
private inputTypeAhead;
|
private inputTypeAhead;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Component, forwardRef, Input } from '@angular/core';
|
||||||
|
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-type-ahead',
|
||||||
|
template: 'dummydetail',
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
multi: true,
|
||||||
|
useExisting: forwardRef(() => TaskanaTypeAheadMockComponent),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class TaskanaTypeAheadMockComponent implements ControlValueAccessor {
|
||||||
|
@Input()
|
||||||
|
placeHolderMessage;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
validationValue;
|
||||||
|
|
||||||
|
writeValue(obj: any): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
setDisabledState?(isDisabled: boolean): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,12 @@
|
||||||
import { Component, OnInit, HostListener } from '@angular/core';
|
import { Component, OnInit, HostListener } from '@angular/core';
|
||||||
import { trigger, transition, keyframes, style, animate, state } from '@angular/animations';
|
import { trigger, transition, keyframes, style, animate, state } from '@angular/animations';
|
||||||
|
import { opacity } from 'app/shared/animations/expand.animation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-code',
|
selector: 'taskana-code',
|
||||||
templateUrl: './code.component.html',
|
templateUrl: './code.component.html',
|
||||||
styleUrls: ['./code.component.scss'],
|
styleUrls: ['./code.component.scss'],
|
||||||
animations: [
|
animations: [opacity]
|
||||||
trigger('toggle', [
|
|
||||||
state('*', style({ opacity: '1' })),
|
|
||||||
state('void', style({ opacity: '0' })),
|
|
||||||
transition('void => *', animate('300ms ease-in', keyframes([
|
|
||||||
style({ opacity: 0 }),
|
|
||||||
style({ opacity: 0.5 }),
|
|
||||||
style({ opacity: 1 })]))),
|
|
||||||
transition('* => void', animate('300ms ease-out', keyframes([
|
|
||||||
style({ opacity: 1 }),
|
|
||||||
style({ opacity: 0.5 }),
|
|
||||||
style({ opacity: 0 })])))
|
|
||||||
])
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class CodeComponent implements OnInit {
|
export class CodeComponent implements OnInit {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.required-text {
|
.required-text {
|
||||||
padding-left: 15px;
|
padding-left: 3px;
|
||||||
color: $invalid;
|
color: $invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue