TSK-492 Access validation, type ahead component created.
This commit is contained in:
parent
e2a781521e
commit
1c93702063
|
|
@ -38,10 +38,19 @@
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "5.5.2",
|
"ajv": "5.5.2",
|
||||||
"chokidar": "1.7.0",
|
"chokidar": "1.7.0",
|
||||||
"rxjs": "5.5.6",
|
"rxjs": "5.5.10",
|
||||||
"source-map": "0.5.7"
|
"source-map": "0.5.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"rxjs": {
|
||||||
|
"version": "5.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz",
|
||||||
|
"integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"symbol-observable": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
|
|
@ -57,7 +66,18 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ngtools/json-schema": "1.2.0",
|
"@ngtools/json-schema": "1.2.0",
|
||||||
"rxjs": "5.5.6"
|
"rxjs": "5.5.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"rxjs": {
|
||||||
|
"version": "5.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz",
|
||||||
|
"integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"symbol-observable": "1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/animations": {
|
"@angular/animations": {
|
||||||
|
|
@ -117,7 +137,7 @@
|
||||||
"postcss-url": "7.3.1",
|
"postcss-url": "7.3.1",
|
||||||
"raw-loader": "0.5.1",
|
"raw-loader": "0.5.1",
|
||||||
"resolve": "1.5.0",
|
"resolve": "1.5.0",
|
||||||
"rxjs": "5.5.6",
|
"rxjs": "5.5.10",
|
||||||
"sass-loader": "6.0.7",
|
"sass-loader": "6.0.7",
|
||||||
"semver": "5.5.0",
|
"semver": "5.5.0",
|
||||||
"silent-error": "1.1.0",
|
"silent-error": "1.1.0",
|
||||||
|
|
@ -176,6 +196,15 @@
|
||||||
"osenv": "0.1.4"
|
"osenv": "0.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rxjs": {
|
||||||
|
"version": "5.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz",
|
||||||
|
"integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"symbol-observable": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
|
||||||
|
|
@ -345,9 +374,20 @@
|
||||||
"integrity": "sha512-7aVP4994Hu8vRdTTohXkfGWEwLhrdNP3EZnWyBootm5zshWqlQojUGweZe5zwewsKcixeVOiy2YtW+aI4aGSLA==",
|
"integrity": "sha512-7aVP4994Hu8vRdTTohXkfGWEwLhrdNP3EZnWyBootm5zshWqlQojUGweZe5zwewsKcixeVOiy2YtW+aI4aGSLA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"rxjs": "5.5.6",
|
"rxjs": "5.5.10",
|
||||||
"semver": "5.5.0",
|
"semver": "5.5.0",
|
||||||
"semver-intersect": "1.3.1"
|
"semver-intersect": "1.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"rxjs": {
|
||||||
|
"version": "5.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz",
|
||||||
|
"integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"symbol-observable": "1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/jasmine": {
|
"@types/jasmine": {
|
||||||
|
|
@ -2096,7 +2136,7 @@
|
||||||
},
|
},
|
||||||
"compression": {
|
"compression": {
|
||||||
"version": "1.7.2",
|
"version": "1.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.2.tgz",
|
"resolved": "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz",
|
||||||
"integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=",
|
"integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|
@ -9482,9 +9522,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rxjs": {
|
"rxjs": {
|
||||||
"version": "5.5.6",
|
"version": "5.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.9.tgz",
|
||||||
"integrity": "sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg==",
|
"integrity": "sha512-DHG9AHmCmgaFWgjBcXp6NxFDmh3MvIA62GqTWmLnTzr/3oZ6h5hLD8NA+9j+GF0jEwklNIpI4KuuyLG8UWMEvQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"symbol-observable": "1.0.1"
|
"symbol-observable": "1.0.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,21 +23,21 @@
|
||||||
"@angular/platform-browser": "5.2.10",
|
"@angular/platform-browser": "5.2.10",
|
||||||
"@angular/platform-browser-dynamic": "5.2.10",
|
"@angular/platform-browser-dynamic": "5.2.10",
|
||||||
"@angular/router": "5.2.10",
|
"@angular/router": "5.2.10",
|
||||||
"file-saver": "1.3.3",
|
|
||||||
"angular-svg-icon": "5.0.0",
|
"angular-svg-icon": "5.0.0",
|
||||||
"angular-tree-component": "7.1.0",
|
"angular-tree-component": "7.1.0",
|
||||||
"bootstrap": "3.3.7",
|
"bootstrap": "3.3.7",
|
||||||
"bootstrap-sass": "3.3.7",
|
"bootstrap-sass": "3.3.7",
|
||||||
|
"chart.js": "2.7.1",
|
||||||
"core-js": "2.5.3",
|
"core-js": "2.5.3",
|
||||||
|
"file-saver": "1.3.3",
|
||||||
"jquery": "3.3.1",
|
"jquery": "3.3.1",
|
||||||
"magic-string": "0.22.4",
|
"magic-string": "0.22.4",
|
||||||
|
"ng2-auto-complete": "0.12.0",
|
||||||
|
"ng2-charts": "1.6.0",
|
||||||
"ngx-bootstrap": "2.0.1",
|
"ngx-bootstrap": "2.0.1",
|
||||||
"node-sass": "4.7.2",
|
"node-sass": "4.7.2",
|
||||||
"rxjs": "5.5.6",
|
"rxjs": "5.5.9",
|
||||||
"zone.js": "0.8.20",
|
"zone.js": "0.8.20"
|
||||||
"chart.js": "2.7.1",
|
|
||||||
"ng2-charts": "1.6.0",
|
|
||||||
"ng2-auto-complete": "0.12.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "1.7.3",
|
"@angular/cli": "1.7.3",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { AlertModule } from 'ngx-bootstrap';
|
import { AlertModule } from 'ngx-bootstrap';
|
||||||
import { SharedModule } from 'app/shared/shared.module';
|
import { SharedModule } from 'app/shared/shared.module';
|
||||||
import { AdministrationRoutingModule } from './administration-routing.module';
|
import { AdministrationRoutingModule } from './administration-routing.module';
|
||||||
|
import { TypeaheadModule } from 'ngx-bootstrap';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components
|
* Components
|
||||||
|
|
@ -39,7 +40,6 @@ import { ClassificationsService } from './services/classifications/classificatio
|
||||||
import { ClassificationTypesService } from './services/classification-types/classification-types.service';
|
import { ClassificationTypesService } from './services/classification-types/classification-types.service';
|
||||||
import { ClassificationCategoriesService } from './services/classification-categories-service/classification-categories.service';
|
import { ClassificationCategoriesService } from './services/classification-categories-service/classification-categories.service';
|
||||||
|
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
|
@ -47,7 +47,8 @@ const MODULES = [
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
AlertModule,
|
AlertModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
AdministrationRoutingModule
|
AdministrationRoutingModule,
|
||||||
|
TypeaheadModule
|
||||||
];
|
];
|
||||||
|
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,13 @@
|
||||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="input-group text-align text-width ">
|
<td class="input-group text-align text-width taskana-type-ahead" [ngClass]="{
|
||||||
<div [ngClass]="{
|
|
||||||
'has-warning': (accessItemsClone[index].accessId !== accessItem.accessId),
|
'has-warning': (accessItemsClone[index].accessId !== accessItem.accessId),
|
||||||
'has-error': !accessItem.accessId }">
|
'has-error': !accessItem.accessId } ">
|
||||||
<input type="text" required #accessItemName="ngModel" class="form-control" name="accessItem.accessId-{{index}}" [(ngModel)]="accessItem.accessId"
|
|
||||||
placeholder="{{accessItemName.invalid? 'Access id is required': ''}}">
|
<taskana-type-ahead required #accessItemName="ngModel" [(ngModel)]="accessItem.accessId" name="accessItem.accessId-{{index}}"
|
||||||
</div>
|
[(ngModel)]="accessItem.accessIdr" placeHolderMessage="Access id is required"></taskana-type-ahead>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td [ngClass]="{'has-changes': (accessItemsClone[index].permRead !== accessItem.permRead)}">
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permRead !== accessItem.permRead)}">
|
||||||
<input type="checkbox" disabled="disabled" name="accessItem.permRead-{{index}}" [(ngModel)]="accessItem.permRead">
|
<input type="checkbox" disabled="disabled" name="accessItem.permRead-{{index}}" [(ngModel)]="accessItem.permRead">
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,14 @@ td > input[type="checkbox"] {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
.text-width{
|
.text-width{
|
||||||
|
width: 100%;
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
}
|
}
|
||||||
|
.required-header {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
.required-header:after {
|
.required-header:after {
|
||||||
|
|
||||||
content:" *";
|
content:" *";
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
@ -17,3 +22,11 @@ td {
|
||||||
border-bottom: 1px solid #f0ad4e;;
|
border-bottom: 1px solid #f0ad4e;;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.table > thead > tr > th {
|
||||||
|
max-width: 150px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-warning.taskana-type-ahead {
|
||||||
|
border-bottom: 1px solid #f0ad4e;
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { SimpleChange } from '@angular/core';
|
import { SimpleChange, Component, forwardRef, Input } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { HttpModule, JsonpModule } from '@angular/http';
|
import { HttpModule, JsonpModule } from '@angular/http';
|
||||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
|
|
@ -26,6 +26,37 @@ import { DomainService } from 'app/services/domain/domain.service';
|
||||||
import { DomainServiceMock } from 'app/services/domain/domain.service.mock';
|
import { DomainServiceMock } from 'app/services/domain/domain.service.mock';
|
||||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||||
|
|
||||||
|
|
||||||
|
@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>;
|
||||||
|
|
@ -33,7 +64,7 @@ describe('AccessItemsComponent', () => {
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent],
|
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent, TaskanaTypeAheadComponent],
|
||||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, ReactiveFormsModule],
|
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, ReactiveFormsModule],
|
||||||
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService, RequestInProgressService,
|
providers: [WorkbasketService, AlertService, ErrorModalService, SavingWorkbasketService, RequestInProgressService,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,10 @@ 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 { TitlesService } from 'app/services/titles/titles.service';
|
||||||
import { CustomFieldsService } from '../../../../services/custom-fields/custom-fields.service';
|
import { CustomFieldsService } from '../../../../services/custom-fields/custom-fields.service';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
|
||||||
|
|
||||||
declare var $: any;
|
declare var $: any;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-workbasket-access-items',
|
selector: 'taskana-workbasket-access-items',
|
||||||
templateUrl: './access-items.component.html',
|
templateUrl: './access-items.component.html',
|
||||||
|
|
@ -25,7 +26,6 @@ declare var $: any;
|
||||||
})
|
})
|
||||||
export class AccessItemsComponent implements OnChanges, OnDestroy {
|
export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
workbasket: Workbasket;
|
workbasket: Workbasket;
|
||||||
@Input()
|
@Input()
|
||||||
|
|
@ -65,7 +65,11 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
private errorModalService: ErrorModalService,
|
private errorModalService: ErrorModalService,
|
||||||
private savingWorkbaskets: SavingWorkbasketService,
|
private savingWorkbaskets: SavingWorkbasketService,
|
||||||
private requestInProgressService: RequestInProgressService,
|
private requestInProgressService: RequestInProgressService,
|
||||||
private customFieldService: CustomFieldsService) { }
|
private customFieldService: CustomFieldsService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') {
|
if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') {
|
||||||
|
|
@ -75,6 +79,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
this.setBadge();
|
this.setBadge();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
if (!this.workbasket._links.accessItems) {
|
if (!this.workbasket._links.accessItems) {
|
||||||
|
|
@ -133,6 +138,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
|
||||||
})
|
})
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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}`;
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,8 @@
|
||||||
</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>
|
||||||
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
|
<taskana-type-ahead required #owner="ngModel" name="owner" [(ngModel)]="workbasket.owner" placeHolderMessage="Owner is required"></taskana-type-ahead>
|
||||||
name="workbasket.owner">
|
<div *ngIf="!owner?.valid" class="required-text">
|
||||||
<div *ngIf="!owner.valid" class="required-text">
|
|
||||||
* Owner is required
|
* Owner is required
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -98,15 +97,18 @@
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="custom2Field.visible" class="form-group">
|
<div *ngIf="custom2Field.visible" class="form-group">
|
||||||
<label for="wb-custom-2" class="control-label">{{custom2Field.field}}</label>
|
<label for="wb-custom-2" class="control-label">{{custom2Field.field}}</label>
|
||||||
<input type="text" class="form-control" id="wb-custom-2" [placeholder]="custom2Field.field" [(ngModel)]="workbasket.custom2" name="workbasket.custom2">
|
<input type="text" class="form-control" id="wb-custom-2" [placeholder]="custom2Field.field" [(ngModel)]="workbasket.custom2"
|
||||||
|
name="workbasket.custom2">
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="custom3Field.visible" class="form-group">
|
<div *ngIf="custom3Field.visible" class="form-group">
|
||||||
<label for="wb-custom-3" class="control-label">{{custom3Field.field}}</label>
|
<label for="wb-custom-3" class="control-label">{{custom3Field.field}}</label>
|
||||||
<input type="text" class="form-control" id="wb-custom-3" [placeholder]="custom3Field.field" [(ngModel)]="workbasket.custom3" name="workbasket.custom3">
|
<input type="text" class="form-control" id="wb-custom-3" [placeholder]="custom3Field.field" [(ngModel)]="workbasket.custom3"
|
||||||
|
name="workbasket.custom3">
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="custom4Field.visible" class="form-group">
|
<div *ngIf="custom4Field.visible" class="form-group">
|
||||||
<label for="wb-custom-4" class="control-label">{{custom4Field.field}}</label>
|
<label for="wb-custom-4" class="control-label">{{custom4Field.field}}</label>
|
||||||
<input type="text" class="form-control" id="wb-custom-4" [placeholder]="custom4Field.field" [(ngModel)]="workbasket.custom4" name="workbasket.custom4">
|
<input type="text" class="form-control" id="wb-custom-4" [placeholder]="custom4Field.field" [(ngModel)]="workbasket.custom4"
|
||||||
|
name="workbasket.custom4">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||||
import { WorkbasketService } from 'app/administration/services/workbasket/workbasket.service';
|
import { WorkbasketService } from 'app/administration/services/workbasket/workbasket.service';
|
||||||
import { WorkbasketInformationComponent } from './workbasket-information.component';
|
import { WorkbasketInformationComponent } from './workbasket-information.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, ControlValueAccessor, NG_VALUE_ACCESSOR } 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 } from '@angular/core';
|
import { Component, Input, forwardRef } from '@angular/core';
|
||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { AppModule } from 'app/app.module'
|
import { AppModule } from 'app/app.module'
|
||||||
|
|
||||||
|
|
@ -37,6 +37,36 @@ import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.se
|
||||||
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 }
|
||||||
|
|
@ -50,7 +80,8 @@ describe('InformationComponent', () => {
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
|
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
|
||||||
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent, DummyDetailComponent],
|
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent, DummyDetailComponent,
|
||||||
|
TaskanaTypeAheadComponent],
|
||||||
imports: [FormsModule,
|
imports: [FormsModule,
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ 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');
|
||||||
|
|
||||||
|
|
||||||
private workbasketSubscription: Subscription;
|
private workbasketSubscription: Subscription;
|
||||||
private routeSubscription: Subscription;
|
private routeSubscription: Subscription;
|
||||||
|
|
||||||
|
|
@ -132,7 +131,6 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private beforeRequest() {
|
private beforeRequest() {
|
||||||
this.requestInProgressService.setRequestInProgress(true);
|
this.requestInProgressService.setRequestInProgress(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input, forwardRef } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed, } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed, } from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { Router, Routes } from '@angular/router';
|
import { Router, Routes } from '@angular/router';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, NG_VALUE_ACCESSOR, ControlValueAccessor } 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';
|
||||||
|
|
@ -58,6 +58,37 @@ 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>;
|
||||||
|
|
@ -77,7 +108,8 @@ describe('WorkbasketDetailsComponent', () => {
|
||||||
imports: [RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
imports: [RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
||||||
declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent,
|
declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent,
|
||||||
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
||||||
DistributionTargetsComponent, FilterComponent, DualListComponent, DummyDetailComponent, SelectWorkBasketPipe],
|
DistributionTargetsComponent, FilterComponent, DualListComponent, DummyDetailComponent,
|
||||||
|
TaskanaTypeAheadComponent, SelectWorkBasketPipe],
|
||||||
providers: [WorkbasketService, MasterAndDetailService, ErrorModalService, RequestInProgressService,
|
providers: [WorkbasketService, MasterAndDetailService, ErrorModalService, RequestInProgressService,
|
||||||
AlertService, SavingWorkbasketService, {
|
AlertService, SavingWorkbasketService, {
|
||||||
provide: DomainService,
|
provide: DomainService,
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,11 @@ import { APP_BASE_HREF } from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
|
TabsModule.forRoot(),
|
||||||
|
AlertModule.forRoot(),
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
TabsModule.forRoot(),
|
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
AlertModule.forRoot(),
|
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
|
|
@ -66,7 +66,7 @@ const MODULES = [
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
NavBarComponent,
|
NavBarComponent,
|
||||||
UserInformationComponent
|
UserInformationComponent,
|
||||||
];
|
];
|
||||||
|
|
||||||
export function startupServiceFactory(startupService: StartupService): () => Promise<any> {
|
export function startupServiceFactory(startupService: StartupService): () => Promise<any> {
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
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()
|
|
||||||
export class AdminGuard implements CanActivate {
|
|
||||||
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) { }
|
|
||||||
|
|
||||||
canActivate() {
|
|
||||||
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
|
||||||
if (userInfo.roles.length === 0) {
|
|
||||||
return this.navigateToWorplace();
|
|
||||||
}
|
|
||||||
const adminRole = userInfo.roles.find(role => {
|
|
||||||
if (role === 'ADMIN') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (adminRole) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return this.navigateToWorplace();
|
|
||||||
}).catch(() => {
|
|
||||||
return Observable.of(this.navigateToWorplace())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateToWorplace(): boolean {
|
|
||||||
this.router.navigate(['workplace']);
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,10 +6,12 @@ import { DomainService } from 'app/services/domain/domain.service';
|
||||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||||
import { ErrorModel } from 'app/models/modal-error';
|
import { ErrorModel } from 'app/models/modal-error';
|
||||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||||
|
import { WindowRefService } from 'app/services/window/window.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BusinessAdminGuard implements CanActivate {
|
export class BusinessAdminGuard implements CanActivate {
|
||||||
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) { }
|
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router,
|
||||||
|
private window: WindowRefService) { }
|
||||||
|
|
||||||
canActivate() {
|
canActivate() {
|
||||||
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
||||||
|
|
@ -17,7 +19,7 @@ export class BusinessAdminGuard implements CanActivate {
|
||||||
return this.navigateToWorplace();
|
return this.navigateToWorplace();
|
||||||
}
|
}
|
||||||
const adminRole = userInfo.roles.find(role => {
|
const adminRole = userInfo.roles.find(role => {
|
||||||
if (role === 'BUSINESS_ADMIN' || role === 'ADMIN' ) {
|
if (role === 'BUSINESS_ADMIN' || role === 'ADMIN') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -32,7 +34,9 @@ export class BusinessAdminGuard implements CanActivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToWorplace(): boolean {
|
navigateToWorplace(): boolean {
|
||||||
|
if (this.window.nativeWindow.location.href.indexOf('administration') !== -1) {
|
||||||
this.router.navigate(['workplace']);
|
this.router.navigate(['workplace']);
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,12 @@ import { DomainService } from 'app/services/domain/domain.service';
|
||||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||||
import { ErrorModel } from 'app/models/modal-error';
|
import { ErrorModel } from 'app/models/modal-error';
|
||||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||||
|
import { WindowRefService } from 'app/services/window/window.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MonitorGuard implements CanActivate {
|
export class MonitorGuard implements CanActivate {
|
||||||
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) { }
|
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router,
|
||||||
|
private window: WindowRefService) { }
|
||||||
|
|
||||||
canActivate() {
|
canActivate() {
|
||||||
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
||||||
|
|
@ -17,7 +19,7 @@ export class MonitorGuard implements CanActivate {
|
||||||
return this.navigateToWorplace();
|
return this.navigateToWorplace();
|
||||||
}
|
}
|
||||||
const adminRole = userInfo.roles.find(role => {
|
const adminRole = userInfo.roles.find(role => {
|
||||||
if (role === 'MONITOR' || role === 'ADMIN' ) {
|
if (role === 'MONITOR' || role === 'ADMIN') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -32,7 +34,9 @@ export class MonitorGuard implements CanActivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToWorplace(): boolean {
|
navigateToWorplace(): boolean {
|
||||||
|
if (this.window.nativeWindow.location.href.indexOf('monitor') !== -1) {
|
||||||
this.router.navigate(['workplace']);
|
this.router.navigate(['workplace']);
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { LinksClassification } from 'app/models/links-classfication';
|
||||||
|
|
||||||
|
export class AccessIdDefinition {
|
||||||
|
constructor(
|
||||||
|
public accessId: string = undefined,
|
||||||
|
public name: string = undefined) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AccessIdsService } from './access-ids.service';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { HttpModule } from '@angular/http';
|
||||||
|
|
||||||
|
describe('ValidateAccessItemsService', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [HttpClientModule, HttpModule],
|
||||||
|
providers: [AccessIdsService]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', inject([AccessIdsService], (service: AccessIdsService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
|
||||||
|
|
||||||
|
import { AccessIdDefinition } from 'app/models/access-id';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AccessIdsService {
|
||||||
|
|
||||||
|
private url = environment.taskanaRestUrl + '/v1/validate-access-id';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private httpClient: HttpClient) { }
|
||||||
|
|
||||||
|
getAccessItemsInformation(token): Observable<Array<AccessIdDefinition>> {
|
||||||
|
if (!token) {
|
||||||
|
return Observable.of([]);
|
||||||
|
}
|
||||||
|
return this.httpClient.get<Array<AccessIdDefinition>>(`${this.url}?search=${token}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -6,12 +6,14 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||||
import { AlertModule } from 'ngx-bootstrap';
|
import { AlertModule } from 'ngx-bootstrap';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { TreeModule } from 'angular-tree-component';
|
import { TreeModule } from 'angular-tree-component';
|
||||||
|
import { TypeaheadModule } from 'ngx-bootstrap';
|
||||||
|
|
||||||
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 { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
||||||
import { AlertComponent } from 'app/shared/alert/alert.component';
|
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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipes
|
* Pipes
|
||||||
|
|
@ -22,17 +24,24 @@ import { SelectWorkBasketPipe } from './pipes/selectedWorkbasket/seleted-workbas
|
||||||
import { SpreadNumberPipe } from './pipes/spreadNumber/spread-number';
|
import { SpreadNumberPipe } from './pipes/spreadNumber/spread-number';
|
||||||
import { OrderBy } from './pipes/orderBy/orderBy';
|
import { OrderBy } from './pipes/orderBy/orderBy';
|
||||||
import { MapToIterable } from './pipes/mapToIterable/mapToIterable';
|
import { MapToIterable } from './pipes/mapToIterable/mapToIterable';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Services
|
||||||
|
*/
|
||||||
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';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
AlertModule.forRoot(),
|
AlertModule.forRoot(),
|
||||||
|
TypeaheadModule.forRoot(),
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
TreeModule
|
TreeModule,
|
||||||
];
|
];
|
||||||
|
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
|
|
@ -41,6 +50,7 @@ const DECLARATIONS = [
|
||||||
AlertComponent,
|
AlertComponent,
|
||||||
MasterAndDetailComponent,
|
MasterAndDetailComponent,
|
||||||
TaskanaTreeComponent,
|
TaskanaTreeComponent,
|
||||||
|
TypeAheadComponent,
|
||||||
MapValuesPipe,
|
MapValuesPipe,
|
||||||
RemoveNoneTypePipe,
|
RemoveNoneTypePipe,
|
||||||
SelectWorkBasketPipe,
|
SelectWorkBasketPipe,
|
||||||
|
|
@ -58,7 +68,8 @@ const DECLARATIONS = [
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
useClass: HttpClientInterceptor,
|
useClass: HttpClientInterceptor,
|
||||||
multi: true
|
multi: true
|
||||||
}
|
},
|
||||||
|
AccessIdsService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule {
|
export class SharedModule {
|
||||||
|
|
|
||||||
|
|
@ -134,3 +134,10 @@
|
||||||
.no-display{
|
.no-display{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.type-ahead-spinner {
|
||||||
|
position: relative;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<div *ngIf="dataSource" class="custom-form-control">
|
||||||
|
<ng-template class="wrapper-text" #customItemTemplate let-model="item" let-index="indexTemplate" let-query="query">
|
||||||
|
<div (mousedown)="typeaheadOnSelect({'item':model})">
|
||||||
|
<div>
|
||||||
|
<span [innerHTML]="join(model.accessId, query)">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span [innerHTML]="join(model.name, query)">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<div [ngClass]="{'hidden': !dataSource.selected || typing}" class="wrapper-text" (click)="setTyping(true)">
|
||||||
|
<span>
|
||||||
|
<label>
|
||||||
|
{{dataSource.selected?.accessId}}
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<div>{{dataSource.selected?.name}}</div>
|
||||||
|
</div>
|
||||||
|
<div [ngClass]="{'hidden': dataSource.selected && !typing}">
|
||||||
|
<span class="field-label-wrapper">
|
||||||
|
<label>
|
||||||
|
{{dataSource.selected?.name}}
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<div *ngIf="typeaheadLoading" class="loading">
|
||||||
|
<taskana-spinner [isRunning]="typeaheadLoading" positionClass="type-ahead-spinner"></taskana-spinner>
|
||||||
|
</div>
|
||||||
|
<input #inputTypeAhead class=" form-control input-text" (blur)="typeaheadOnSelect({'item':dataSource.selected})" name="accessItem-{{index}}"
|
||||||
|
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
|
||||||
|
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView"
|
||||||
|
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)"
|
||||||
|
placeholder="{{accessItemName.invalid? placeHolderMessage: ''}}">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
$blue: #2e9eca;
|
||||||
|
$grey: #ddd;
|
||||||
|
.wrapper-text {
|
||||||
|
height: 47px;
|
||||||
|
& label {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
& div {
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid $grey;
|
||||||
|
margin-top:6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-text {
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0px;
|
||||||
|
border-radius: 0px;
|
||||||
|
//margin-top: 18px;
|
||||||
|
height: 22px;
|
||||||
|
border-bottom: 1px solid $grey;
|
||||||
|
&:focus{
|
||||||
|
border-bottom: 1px solid $blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-label-wrapper{
|
||||||
|
position: relative;
|
||||||
|
//left: 8px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
border-color: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
import { Component, OnInit, Input, EventEmitter, Output, ViewChild, ElementRef, forwardRef } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
const noop = () => {
|
||||||
|
};
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-type-ahead',
|
||||||
|
templateUrl: './type-ahead.component.html',
|
||||||
|
styleUrls: ['./type-ahead.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => TypeAheadComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
})
|
||||||
|
export class TypeAheadComponent implements OnInit, ControlValueAccessor {
|
||||||
|
|
||||||
|
dataSource: any;
|
||||||
|
typing = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
placeHolderMessage;
|
||||||
|
|
||||||
|
@ViewChild('inputTypeAhead')
|
||||||
|
private inputTypeAhead;
|
||||||
|
|
||||||
|
typeaheadLoading = false;
|
||||||
|
typeaheadMinLength = 2;
|
||||||
|
typeaheadWaitMs = 500;
|
||||||
|
typeaheadOptionsInScrollableView = 6;
|
||||||
|
|
||||||
|
// The internal data model
|
||||||
|
private innerValue: any = '';
|
||||||
|
|
||||||
|
// Placeholders for the callbacks which are later provided
|
||||||
|
// by the Control Value Accessor
|
||||||
|
private onTouchedCallback: () => void = noop;
|
||||||
|
private onChangeCallback: (_: any) => void = noop;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
this.initializeDataSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From ControlValueAccessor interface
|
||||||
|
registerOnChange(fn: any) {
|
||||||
|
this.onChangeCallback = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From ControlValueAccessor interface
|
||||||
|
registerOnTouched(fn: any) {
|
||||||
|
this.onTouchedCallback = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private accessIdsService: AccessIdsService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeDataSource() {
|
||||||
|
this.dataSource = Observable.create((observer: any) => {
|
||||||
|
observer.next(this.value);
|
||||||
|
}).mergeMap((token: string) => this.getUsersAsObservable(token));
|
||||||
|
this.accessIdsService.getAccessItemsInformation(this.value).subscribe(items => {
|
||||||
|
if (items.length > 0) {
|
||||||
|
this.dataSource.selected = items.find(item => item.accessId === this.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getUsersAsObservable(token: string): Observable<any> {
|
||||||
|
return this.accessIdsService.getAccessItemsInformation(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
typeaheadOnSelect(event: TypeaheadMatch): void {
|
||||||
|
if (event && event.item) {
|
||||||
|
this.value = event.item.accessId;
|
||||||
|
this.dataSource.selected = event.item;
|
||||||
|
}
|
||||||
|
this.setTyping(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTyping(value) {
|
||||||
|
if (value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.inputTypeAhead.nativeElement.focus();
|
||||||
|
}, 1)
|
||||||
|
|
||||||
|
}
|
||||||
|
this.typing = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTypeaheadLoading(e: boolean): void {
|
||||||
|
this.typeaheadLoading = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
join(text: string, str: string) {
|
||||||
|
return text.toLocaleLowerCase().split(str).join(`<strong>${str}</strong>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
@import 'site';
|
@import 'site';
|
||||||
@import 'forms';
|
@import 'forms';
|
||||||
@import 'tree';
|
@import 'tree';
|
||||||
|
@import 'type-ahead';
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
typeahead-container >ul.dropdown-menu{
|
||||||
|
width: 215px;
|
||||||
|
& >li.active {
|
||||||
|
&>a {
|
||||||
|
background-color: $green;
|
||||||
|
}
|
||||||
|
&>a:hover {
|
||||||
|
background-color: $green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5">
|
||||||
|
<output url="file://$MODULE_DIR$/target/classes" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Loading…
Reference in New Issue