TSK-1401: Update Typeahead component with material design (#1312)
* TSK-1401: remove bootstrap from typeahead component * TSK-1401: rebase * TSK-1401: modify typeahead component * TSK-1401: fixed CI error * TSK-1401: fixed test error * TSK-1401: fixed format error * TSK-1401: add blur function after selection * TSK-1401: fix CI error * TSK-1401: integrate requested changes * TSK-1401: integrate changes * TSK-1401: update sidenav and typeahead * TSK-1401: fix tabs * TSK-1401: fix CI error * TSK-1401: add pipe for tab bar
This commit is contained in:
parent
d997ab1923
commit
ea38c7ddba
|
@ -7,9 +7,8 @@
|
|||
<div class="panel-body">
|
||||
<div class="col-md-6 col-md-offset-3 margin">
|
||||
<taskana-shared-type-ahead name="accessIdSelected" [(ngModel)]="accessIdSelected"
|
||||
placeHolderMessage="Search for access id..."
|
||||
(selectedItem)="onSelectAccessId($event)"
|
||||
displayError=true>
|
||||
placeHolderMessage="Search for access id..." (selectedItem)="onSelectAccessId($event)" displayError=true
|
||||
isRequired="false">
|
||||
</taskana-shared-type-ahead>
|
||||
</div>
|
||||
|
||||
|
@ -25,131 +24,128 @@
|
|||
<!-- TABLE WITH ACCESS ID -->
|
||||
<table id="table-access-items" class="table table-striped table-center">
|
||||
<thead>
|
||||
<!-- TABLE FIRST ROW -->
|
||||
<tr>
|
||||
<th>
|
||||
<taskana-shared-sort [sortingFields]="sortingFields"
|
||||
(performSorting)="sorting($event)"
|
||||
menuPosition="left">
|
||||
</taskana-shared-sort>
|
||||
</th>
|
||||
<th class="text-align min-width">Workbasket Key</th>
|
||||
<th colspan="2" class="text-align">Access Id</th>
|
||||
<th>Read</th>
|
||||
<th>Open</th>
|
||||
<th>Append</th>
|
||||
<th>Transfer</th>
|
||||
<th>Distribute</th>
|
||||
<ng-container *ngFor="let customField of customFields$ | async">
|
||||
<th *ngIf="customField.visible">
|
||||
{{customField.field}}
|
||||
<!-- TABLE FIRST ROW -->
|
||||
<tr>
|
||||
<th>
|
||||
<taskana-shared-sort [sortingFields]="sortingFields" (performSorting)="sorting($event)"
|
||||
menuPosition="left">
|
||||
</taskana-shared-sort>
|
||||
</th>
|
||||
</ng-container>
|
||||
</tr>
|
||||
<!-- TABLE SECOND ROW -->
|
||||
<tr>
|
||||
<th colspan="2" class="text-align"><label>
|
||||
<input type="text" formControlName="workbasketKeyFilter" (keyup.enter)="searchForAccessItemsWorkbaskets()"
|
||||
class="form-control" placeholder="Workbasket filter">
|
||||
</label></th>
|
||||
<th class="text-align"><label>
|
||||
<input type="text" formControlName="accessIdFilter" (keyup.enter)="searchForAccessItemsWorkbaskets()"
|
||||
class="form-control" placeholder="Access id filter">
|
||||
</label></th>
|
||||
<th>
|
||||
<button type="button" (click)="searchForAccessItemsWorkbaskets()" class="btn btn-default"
|
||||
data-toggle="tooltip"
|
||||
title="Search">
|
||||
<span class="material-icons md-20 blue">search</span>
|
||||
</button>
|
||||
</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<th class="text-align min-width">Workbasket Key</th>
|
||||
<th colspan="2" class="text-align">Access Id</th>
|
||||
<th>Read</th>
|
||||
<th>Open</th>
|
||||
<th>Append</th>
|
||||
<th>Transfer</th>
|
||||
<th>Distribute</th>
|
||||
<ng-container *ngFor="let customField of customFields$ | async">
|
||||
<th *ngIf="customField.visible">
|
||||
{{customField.field}}
|
||||
</th>
|
||||
</ng-container>
|
||||
</tr>
|
||||
<!-- TABLE SECOND ROW -->
|
||||
<tr>
|
||||
<th colspan="2" class="text-align"><label>
|
||||
<input type="text" formControlName="workbasketKeyFilter"
|
||||
(keyup.enter)="searchForAccessItemsWorkbaskets()" class="form-control"
|
||||
placeholder="Workbasket filter">
|
||||
</label></th>
|
||||
<th class="text-align"><label>
|
||||
<input type="text" formControlName="accessIdFilter" (keyup.enter)="searchForAccessItemsWorkbaskets()"
|
||||
class="form-control" placeholder="Access id filter">
|
||||
</label></th>
|
||||
<th>
|
||||
<button type="button" (click)="searchForAccessItemsWorkbaskets()" class="btn btn-default"
|
||||
data-toggle="tooltip" title="Search">
|
||||
<span class="material-icons md-20 blue">search</span>
|
||||
</button>
|
||||
</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<!-- ACCESS ITEMS GROUPS -->
|
||||
<tbody formArrayName="accessItemsGroups">
|
||||
<tr class="table__access-item-groups" *ngFor="let accessItem of accessItemsGroups.controls; let index = index;"
|
||||
<tr class="table__access-item-groups"
|
||||
*ngFor="let accessItem of accessItemsGroups.controls; let index = index;"
|
||||
[formGroupName]="index.toString()">
|
||||
<td colspan="2">
|
||||
<label class="wrap">{{accessItem.value.workbasketKey}}</label>
|
||||
</td>
|
||||
<td *ngIf="(accessItemsCustomization$ | async)?.accessId.lookupField else accessIdInput" colspan="2"
|
||||
<td colspan="2">
|
||||
<label class="wrap">{{accessItem.value.workbasketKey}}</label>
|
||||
</td>
|
||||
<td *ngIf="(accessItemsCustomization$ | async)?.accessId.lookupField else accessIdInput" colspan="2"
|
||||
class="text-align text-width taskana-type-ahead" style="padding-top: 0;">
|
||||
<div>
|
||||
<taskana-shared-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required"
|
||||
[validationValue]="toggleValidationAccessIdMap.get(index)"
|
||||
[displayError]="!isFieldValid('accessItem.value.accessId', index)"
|
||||
[disable]=true></taskana-shared-type-ahead>
|
||||
</div>
|
||||
</td>
|
||||
<ng-template #accessIdInput>
|
||||
<td colspan="2" class="text-align text-width">
|
||||
<div>
|
||||
<label>
|
||||
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid?
|
||||
'* Access id is required': ''}}">
|
||||
</label>
|
||||
<taskana-shared-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required"
|
||||
[validationValue]="toggleValidationAccessIdMap.get(index)"
|
||||
[displayError]="!isFieldValid('accessItem.value.accessId', index)" [disable]=true>
|
||||
</taskana-shared-type-ahead>
|
||||
</div>
|
||||
</td>
|
||||
</ng-template>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-0" type="checkbox" formControlName="permRead" class="regular-checkbox">
|
||||
<label for="checkbox-{{index}}-0"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-1" type="checkbox" formControlName="permOpen">
|
||||
<label for="checkbox-{{index}}-1"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-2" type="checkbox" formControlName="permAppend">
|
||||
<label for="checkbox-{{index}}-2"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-3" type="checkbox" formControlName="permTransfer">
|
||||
<label for="checkbox-{{index}}-3"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
||||
<label for="checkbox-{{index}}-4"></label>
|
||||
</td>
|
||||
<ng-container *ngFor="let customField of customFields$ | async; let customIndex = index">
|
||||
<td *ngIf="customField.visible">
|
||||
<input id="checkbox-{{index}}-{{customIndex + 5}}" type="checkbox"
|
||||
formControlName="permCustom{{customIndex + 1}}">
|
||||
<label for="checkbox-{{index}}-{{customIndex + 5}}"></label>
|
||||
<ng-template #accessIdInput>
|
||||
<td colspan="2" class="text-align text-width">
|
||||
<div>
|
||||
<label>
|
||||
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid?
|
||||
'* Access id is required': ''}}">
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</ng-template>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-0" type="checkbox" formControlName="permRead" class="regular-checkbox">
|
||||
<label for="checkbox-{{index}}-0"></label>
|
||||
</td>
|
||||
</ng-container>
|
||||
</tr>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-1" type="checkbox" formControlName="permOpen">
|
||||
<label for="checkbox-{{index}}-1"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-2" type="checkbox" formControlName="permAppend">
|
||||
<label for="checkbox-{{index}}-2"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-3" type="checkbox" formControlName="permTransfer">
|
||||
<label for="checkbox-{{index}}-3"></label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
|
||||
<label for="checkbox-{{index}}-4"></label>
|
||||
</td>
|
||||
<ng-container *ngFor="let customField of customFields$ | async; let customIndex = index">
|
||||
<td *ngIf="customField.visible">
|
||||
<input id="checkbox-{{index}}-{{customIndex + 5}}" type="checkbox"
|
||||
formControlName="permCustom{{customIndex + 1}}">
|
||||
<label for="checkbox-{{index}}-{{customIndex + 5}}"></label>
|
||||
</td>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- BELONGING GROUPS BUTTONS -->
|
||||
<button class="btn btn-primary pull-left btn-group" type="button"
|
||||
data-toggle="modal"
|
||||
data-target="#myModal">
|
||||
<button class="btn btn-primary pull-left btn-group" type="button" data-toggle="modal" data-target="#myModal">
|
||||
Belonging groups
|
||||
</button>
|
||||
<!-- REVOKE ACCESS BUTTON -->
|
||||
<div class="pull-right btn-group">
|
||||
<button *ngIf="accessItemsForm" type="button" (click)="revokeAccess()" class="btn btn-default"
|
||||
data-toggle="tooltip"
|
||||
title="Revoke access" [disabled]=isGroup>
|
||||
data-toggle="tooltip" title="Revoke access" [disabled]=isGroup>
|
||||
<span class="material-icons md-20 red">clear</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -178,4 +174,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -23,6 +23,11 @@ import { StartupService } from '../../../shared/services/startup/startup.service
|
|||
import { TaskanaEngineService } from '../../../shared/services/taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from '../../../shared/services/window/window.service';
|
||||
import { engineConfigurationMock } from '../../../shared/store/mock-data/mock-store';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
|
||||
const isFieldValidFn = jest.fn().mockReturnValue(true);
|
||||
const formValidatorServiceSpy = jest.fn().mockImplementation(
|
||||
|
@ -67,7 +72,12 @@ describe('AccessItemsManagementComponent', () => {
|
|||
MatSnackBarModule,
|
||||
MatDialogModule,
|
||||
TypeaheadModule.forRoot(),
|
||||
BrowserAnimationsModule
|
||||
BrowserAnimationsModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
MatAutocompleteModule,
|
||||
MatInputModule,
|
||||
MatProgressBarModule
|
||||
],
|
||||
declarations: [
|
||||
AccessItemsManagementComponent,
|
||||
|
|
|
@ -27,6 +27,7 @@ import { AccessItemsManagementSelector } from '../../../shared/store/access-item
|
|||
export class AccessItemsManagementComponent implements OnInit {
|
||||
accessIdSelected: string;
|
||||
accessIdPrevious: string;
|
||||
isRequired: boolean = false;
|
||||
|
||||
accessItemsForm: FormGroup;
|
||||
toggleValidationAccessIdMap = new Map<number, boolean>();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { DomainService } from '../../../shared/services/domain/domain.service';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
|
@ -15,8 +15,18 @@ export class AdministrationOverviewComponent implements OnInit {
|
|||
selectedDomain: string;
|
||||
|
||||
destroy$ = new Subject<void>();
|
||||
url$: Observable<any>;
|
||||
|
||||
constructor(private router: Router, private domainService: DomainService) {}
|
||||
constructor(private router: Router, private domainService: DomainService) {
|
||||
router.events.pipe(takeUntil(this.destroy$)).subscribe((e) => {
|
||||
const urlPaths = this.router.url.split('/');
|
||||
if (this.router.url.includes('detail')) {
|
||||
this.selectedTab = urlPaths[urlPaths.length - 2];
|
||||
} else {
|
||||
this.selectedTab = urlPaths[urlPaths.length - 1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.domainService
|
||||
|
@ -32,13 +42,6 @@ export class AdministrationOverviewComponent implements OnInit {
|
|||
.subscribe((domain) => {
|
||||
this.selectedDomain = domain;
|
||||
});
|
||||
|
||||
const urlPaths = this.router.url.split('/');
|
||||
if (this.router.url.includes('detail')) {
|
||||
this.selectedTab = urlPaths[urlPaths.length - 2];
|
||||
} else {
|
||||
this.selectedTab = urlPaths[urlPaths.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
switchDomain(domain) {
|
||||
|
|
|
@ -33,6 +33,10 @@ import {
|
|||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ACTION } from '../../../shared/models/action';
|
||||
import { WorkbasketAccessItems } from '../../../shared/models/workbasket-access-items';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
|
||||
@Component({ selector: 'taskana-shared-spinner', template: '' })
|
||||
|
@ -90,6 +94,10 @@ describe('WorkbasketAccessItemsComponent', () => {
|
|||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
BrowserAnimationsModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatAutocompleteModule,
|
||||
MatProgressBarModule
|
||||
],
|
||||
declarations: [WorkbasketAccessItemsComponent, TypeAheadComponent, SpinnerStub],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
|
||||
<div *ngIf="workbasket" id="wb-information">
|
||||
<!--
|
||||
<!--
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right btn-group">
|
||||
<button type="button" (click)="onSubmit()" data-toggle="tooltip" title="Save"
|
||||
|
@ -45,30 +45,25 @@
|
|||
<mat-form-field appearance="outline">
|
||||
<mat-label>Key</mat-label>
|
||||
<label for="workbasket-key"></label>
|
||||
<input matInput required type="text" #key="ngModel" maxlength="64"
|
||||
[disabled]="action == 0 || action == 3"
|
||||
id="workbasket-key" placeholder="Key" [(ngModel)]="workbasket.key"
|
||||
name="workbasket.key" (input)="validateInputOverflow(key, 64, $event)">
|
||||
<input matInput required type="text" #key="ngModel" maxlength="64" [disabled]="action == 0 || action == 3"
|
||||
id="workbasket-key" placeholder="Key" [(ngModel)]="workbasket.key" name="workbasket.key"
|
||||
(input)="validateInputOverflow(key, 64, $event)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(key.name)" class="error">{{lengthError}}</div>
|
||||
<taskana-shared-field-error-display [displayError]="!isFieldValid('workbasket.key')"
|
||||
[validationTrigger]="this.toggleValidationMap.get('workbasket.key')"
|
||||
errorMessage="* Key is required">
|
||||
[validationTrigger]="this.toggleValidationMap.get('workbasket.key')" errorMessage="* Key is required">
|
||||
</taskana-shared-field-error-display>
|
||||
|
||||
<!-- NAME -->
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Name</mat-label>
|
||||
<label for="workbasket-name"></label>
|
||||
<input matInput type="text" required maxlength="255" #name="ngModel"
|
||||
id="workbasket-name" placeholder="Name"
|
||||
[(ngModel)]="workbasket.name" name="workbasket.name"
|
||||
(input)="validateInputOverflow(name, 255)">
|
||||
<input matInput type="text" required maxlength="255" #name="ngModel" id="workbasket-name" placeholder="Name"
|
||||
[(ngModel)]="workbasket.name" name="workbasket.name" (input)="validateInputOverflow(name, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(name.name)" class="error">{{lengthError}}</div>
|
||||
<taskana-shared-field-error-display [displayError]="!isFieldValid('workbasket.name')"
|
||||
[validationTrigger]="this.toggleValidationMap.get('workbasket.name')"
|
||||
errorMessage="* Name is required">
|
||||
[validationTrigger]="this.toggleValidationMap.get('workbasket.name')" errorMessage="* Name is required">
|
||||
</taskana-shared-field-error-display>
|
||||
|
||||
|
||||
|
@ -79,9 +74,8 @@
|
|||
<mat-form-field class="workbasket-information__mat-form-field" appearance="outline">
|
||||
<mat-label>Domain</mat-label>
|
||||
<label for="workbasket-domain"></label>
|
||||
<input matInput type="text" disabled id="workbasket-domain"
|
||||
placeholder="Domain" [(ngModel)]="workbasket.domain"
|
||||
name="classification.domain">
|
||||
<input matInput type="text" disabled id="workbasket-domain" placeholder="Domain"
|
||||
[(ngModel)]="workbasket.domain" name="classification.domain">
|
||||
</mat-form-field>
|
||||
|
||||
<!-- TYPE -->
|
||||
|
@ -93,8 +87,7 @@
|
|||
{{allTypes.get(workbasket.type)}}
|
||||
</mat-select-trigger>
|
||||
<mat-option *ngFor="let type of allTypes | mapValues | removeEmptyType" value="{{type.key}}">
|
||||
<taskana-administration-icon-type
|
||||
[type]='type.key' [text]="type.value">
|
||||
<taskana-administration-icon-type [type]='type.key' [text]="type.value">
|
||||
</taskana-administration-icon-type>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
@ -107,80 +100,70 @@
|
|||
<mat-form-field appearance="outline">
|
||||
<mat-label>Description</mat-label>
|
||||
<label for="workbasket-description"></label>
|
||||
<textarea matInput
|
||||
cdkTextareaAutosize
|
||||
cdkAutosizeMinRows="1"
|
||||
cdkAutosizeMaxRows="5"
|
||||
maxlength="255"
|
||||
id="workbasket-description" placeholder="Description"
|
||||
[(ngModel)]="workbasket.description"
|
||||
name="workbasket.description" #description="ngModel"
|
||||
(input)="validateInputOverflow(description, 255)"></textarea>
|
||||
<textarea matInput cdkTextareaAutosize cdkAutosizeMinRows="1" cdkAutosizeMaxRows="5" maxlength="255"
|
||||
id="workbasket-description" placeholder="Description" [(ngModel)]="workbasket.description"
|
||||
name="workbasket.description" #description="ngModel"
|
||||
(input)="validateInputOverflow(description, 255)"></textarea>
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(description.name)" class="error">{{lengthError}}</div>
|
||||
|
||||
|
||||
<!-- OWNER -->
|
||||
<div class="input-group form-group col-xs-12 required">
|
||||
<label for="wb-owner" class="control-label ">Owner</label>
|
||||
<taskana-shared-type-ahead *ngIf="lookupField else ownerInput" required maxlength="128" #owner="ngModel"
|
||||
name="workbasket.owner"
|
||||
[(ngModel)]="workbasket.owner"
|
||||
placeHolderMessage="* Owner is required"
|
||||
[validationValue]="this.toggleValidationMap.get('workbasket.owner')"
|
||||
[displayError]="!isFieldValid('workbasket.owner')"
|
||||
width="100%" (input)="validateInputOverflow(owner, 128)">
|
||||
<div *ngIf="inputOverflowMap.get(owner.name)" class="error">{{lengthError}}</div>
|
||||
</taskana-shared-type-ahead>
|
||||
|
||||
<ng-template #ownerInput>
|
||||
<input type="text" required maxlength="128" #owner="ngModel" class="form-control" id="wb-owner"
|
||||
placeholder="Owner"
|
||||
[(ngModel)]="workbasket.owner" name="workbasket.owner" (input)="validateInputOverflow(owner, 128)">
|
||||
<div *ngIf="inputOverflowMap.get(owner.name)" class="error">{{lengthError}}</div>
|
||||
<taskana-shared-field-error-display [displayError]="!isFieldValid('workbasket.owner')"
|
||||
[validationTrigger]="this.toggleValidationMap.get('workbasket.owner')"
|
||||
errorMessage="* Owner is required">
|
||||
</taskana-shared-field-error-display>
|
||||
</ng-template>
|
||||
</div>
|
||||
<taskana-shared-type-ahead *ngIf="lookupField else ownerInput" isRequired="true" maxlength="128"
|
||||
#owner="ngModel" name="workbasket.owner" [(ngModel)]="workbasket.owner" placeHolderMessage="Owner"
|
||||
[validationValue]="this.toggleValidationMap.get('workbasket.owner') "
|
||||
[displayError]="!isFieldValid('workbasket.owner')" width="100%" (input)="validateInputOverflow(owner, 128)">
|
||||
<div *ngIf="inputOverflowMap.get(owner.name)" class="error">{{lengthError}}</div>
|
||||
</taskana-shared-type-ahead>
|
||||
|
||||
<ng-template #ownerInput>
|
||||
<input type="text" required maxlength="128" #owner="ngModel" class="form-control" id="wb-owner"
|
||||
placeholder="Owner" [(ngModel)]="workbasket.owner" name="workbasket.owner"
|
||||
(input)="validateInputOverflow(owner, 128)">
|
||||
<div *ngIf="inputOverflowMap.get(owner.name)" class="error">{{lengthError}}</div>
|
||||
<taskana-shared-field-error-display [displayError]="!isFieldValid('workbasket.owner')"
|
||||
[validationTrigger]="this.toggleValidationMap.get('workbasket.owner')" errorMessage="* Owner is required">
|
||||
</taskana-shared-field-error-display>
|
||||
</ng-template>
|
||||
|
||||
|
||||
<!-- ORGASATIONAL LEVELS -->
|
||||
<h6 class="workbasket-information__subheading" style="margin-top: 65px;"> Organisational Levels </h6>
|
||||
<mat-divider class="workbasket-information__horizontal-line"> </mat-divider>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 1</mat-label>
|
||||
<input matInput type="text" #orgLevel1="ngModel" maxlength="255"
|
||||
placeholder="OrgLevel 1" [(ngModel)]="workbasket.orgLevel1"
|
||||
name="workbasket.orgLevel1" (input)="validateInputOverflow(orgLevel1, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel1.name)" class="error">{{lengthError}}</div>
|
||||
<!-- ORGASATIONAL LEVELS -->
|
||||
<h6 class="workbasket-information__subheading" style="margin-top: 65px;"> Organisational Levels </h6>
|
||||
<mat-divider class="workbasket-information__horizontal-line"> </mat-divider>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 2</mat-label>
|
||||
<input matInput type="text" #orgLevel2="ngModel" maxlength="255"
|
||||
placeholder="OrgLevel 2" [(ngModel)]="workbasket.orgLevel2"
|
||||
name="workbasket.orgLevel2" (input)="validateInputOverflow(orgLevel2, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel2.name)" class="error">{{lengthError}}</div>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 1</mat-label>
|
||||
<input matInput type="text" #orgLevel1="ngModel" maxlength="255" placeholder="OrgLevel 1"
|
||||
[(ngModel)]="workbasket.orgLevel1" name="workbasket.orgLevel1"
|
||||
(input)="validateInputOverflow(orgLevel1, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel1.name)" class="error">{{lengthError}}</div>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 3</mat-label>
|
||||
<input matInput type="text" #orgLevel3="ngModel" maxlength="255"
|
||||
placeholder="OrgLevel 3" [(ngModel)]="workbasket.orgLevel3"
|
||||
name="workbasket.orgLevel3" (input)="validateInputOverflow(orgLevel3, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel3.name)" class="error">{{lengthError}}</div>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 2</mat-label>
|
||||
<input matInput type="text" #orgLevel2="ngModel" maxlength="255" placeholder="OrgLevel 2"
|
||||
[(ngModel)]="workbasket.orgLevel2" name="workbasket.orgLevel2"
|
||||
(input)="validateInputOverflow(orgLevel2, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel2.name)" class="error">{{lengthError}}</div>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 4</mat-label>
|
||||
<input matInput type="text" #orgLevel4="ngModel" maxlength="255"
|
||||
placeholder="OrgLevel 4" [(ngModel)]="workbasket.orgLevel4"
|
||||
name="workbasket.orgLevel4" (input)="validateInputOverflow(orgLevel4, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel4.name)" class="error">{{lengthError}}</div>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 3</mat-label>
|
||||
<input matInput type="text" #orgLevel3="ngModel" maxlength="255" placeholder="OrgLevel 3"
|
||||
[(ngModel)]="workbasket.orgLevel3" name="workbasket.orgLevel3"
|
||||
(input)="validateInputOverflow(orgLevel3, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel3.name)" class="error">{{lengthError}}</div>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>OrgLevel 4</mat-label>
|
||||
<input matInput type="text" #orgLevel4="ngModel" maxlength="255" placeholder="OrgLevel 4"
|
||||
[(ngModel)]="workbasket.orgLevel4" name="workbasket.orgLevel4"
|
||||
(input)="validateInputOverflow(orgLevel4, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(orgLevel4.name)" class="error">{{lengthError}}</div>
|
||||
|
||||
|
||||
<!-- CUSTOM FIELDS -->
|
||||
|
@ -193,14 +176,10 @@
|
|||
<mat-form-field appearance="outline" class="workbasket-information__custom-fields">
|
||||
<mat-label>{{customField.field}}</mat-label>
|
||||
<label for='wb-custom-{{index+1}}'></label>
|
||||
<input matInput type="text"
|
||||
[placeholder]="customField.field"
|
||||
[(ngModel)]="workbasket[getWorkbasketCustomProperty(index + 1)]"
|
||||
id="wb-custom-{{index+1}}"
|
||||
name="workbasket[{{getWorkbasketCustomProperty(index + 1)}}]"
|
||||
maxlength="255"
|
||||
#custom="ngModel"
|
||||
(input)="validateInputOverflow(custom, 255)">
|
||||
<input matInput type="text" [placeholder]="customField.field"
|
||||
[(ngModel)]="workbasket[getWorkbasketCustomProperty(index + 1)]" id="wb-custom-{{index+1}}"
|
||||
name="workbasket[{{getWorkbasketCustomProperty(index + 1)}}]" maxlength="255" #custom="ngModel"
|
||||
(input)="validateInputOverflow(custom, 255)">
|
||||
</mat-form-field>
|
||||
<div *ngIf="inputOverflowMap.get(custom.name)" class="error">{{lengthError}}</div>
|
||||
</div>
|
||||
|
@ -209,4 +188,4 @@
|
|||
|
||||
</ng-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,6 +1,6 @@
|
|||
.workbasket-information-wrapper {
|
||||
height: calc(100vh - 213px);
|
||||
overflow-y: auto ;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.workbasket-information {
|
||||
padding: 15px;
|
||||
|
|
|
@ -39,6 +39,7 @@ import { MatDividerModule } from '@angular/material/divider';
|
|||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
|
||||
@Component({ selector: 'taskana-shared-spinner', template: '' })
|
||||
class SpinnerStub {
|
||||
|
@ -114,7 +115,8 @@ describe('WorkbasketInformationComponent', () => {
|
|||
MatDividerModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatSelectModule
|
||||
MatSelectModule,
|
||||
MatAutocompleteModule
|
||||
],
|
||||
declarations: [
|
||||
WorkbasketInformationComponent,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
@import 'src/theme/_colors.scss';
|
||||
|
||||
|
||||
.workbasket-list {
|
||||
height: calc(100vh - 156px);
|
||||
overflow-x: hidden;
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
<mat-sidenav-container class="sidenav">
|
||||
<mat-sidenav #sidenav mode="over" class="sidenav__drawer" [autoFocus]="false">
|
||||
<div class="sidenav__drawer-logout">
|
||||
<button mat-icon-button data-toggle="tooltip" title="Logout" (click)="logout()" aria-expanded="true"
|
||||
aria-controls="logout">
|
||||
<mat-icon>exit_to_app</mat-icon>
|
||||
</button>
|
||||
<div class="sidenav__drawer__container">
|
||||
<div class="sidenav__drawer__container-menu">
|
||||
<button mat-icon-button class="navbar_button-toggle" (click)="toggleSidenav()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="sidenav__drawer__container-logout">
|
||||
<button mat-icon-button data-toggle="tooltip" title="Logout" (click)="logout()" aria-expanded="true"
|
||||
aria-controls="logout">
|
||||
<mat-icon>exit_to_app</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<taskana-shared-user-information class="sidenav__drawer-user-info"></taskana-shared-user-information>
|
||||
<taskana-sidenav-list></taskana-sidenav-list>
|
||||
|
@ -23,4 +30,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
</mat-sidenav-container>
|
|
@ -21,9 +21,22 @@
|
|||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.sidenav__drawer-logout {
|
||||
text-align: end;
|
||||
.sidenav__drawer__container {
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
justify-content: space-between;
|
||||
color: white;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.sidenav__drawer__container-menu {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.sidenav__drawer__container-logout {
|
||||
text-align: end;
|
||||
margin-right: 15px;
|
||||
|
||||
}
|
||||
|
||||
.sidenav__drawer-version {
|
||||
|
@ -40,6 +53,10 @@
|
|||
margin-left: -16px;
|
||||
}
|
||||
|
||||
.mat-icon-button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
mat-sidenav-content {
|
||||
height: unset;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
uploadingFileSubscription: Subscription;
|
||||
error: ErrorModel;
|
||||
version: string;
|
||||
toggle: boolean = false;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
|
@ -86,6 +87,11 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
this.window.nativeWindow.location.href = environment.taskanaLogoutUrl;
|
||||
}
|
||||
|
||||
toggleSidenav() {
|
||||
this.toggle = !this.toggle;
|
||||
this.sidenavService.toggleSidenav();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.sidenavService.setSidenav(this.sidenav);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ import { MatListModule } from '@angular/material/list';
|
|||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
const MODULES = [
|
||||
TabsModule.forRoot(),
|
||||
|
@ -78,6 +79,7 @@ const MODULES = [
|
|||
MatListModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatSelectModule,
|
||||
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
|
||||
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 })
|
||||
];
|
||||
|
|
|
@ -25,13 +25,11 @@
|
|||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.filter__name-and-key-input{
|
||||
.filter__name-and-key-input {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.dropdown-menu-users {
|
||||
& > li {
|
||||
margin-bottom: 5px;
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
</div>
|
||||
<div class="navbar__logo">
|
||||
<svg-icon class="navbar__logo-icon" src="./assets/icons/logo-copy.svg"></svg-icon>
|
||||
<div class="navbar__title">{{ title }}</div>
|
||||
<div class="navbar__title">{{title}}</div>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
</mat-toolbar>
|
|
@ -6,7 +6,7 @@
|
|||
mat-paginator {
|
||||
background-color: #fafafa;
|
||||
width: 70%;
|
||||
font-feature-settings: "tnum";
|
||||
font-feature-settings: 'tnum';
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
//Original
|
||||
|
@ -22,6 +22,6 @@ mat-paginator {
|
|||
.pagination__go-to-label {
|
||||
margin: 0 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(0,0,0,.54);
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
<mat-nav-list class="navlist">
|
||||
<a mat-list-item class="navlist__item navlist__admin" [routerLink]=[administrationsUrl] [routerLinkActive]="['active']"
|
||||
*ngIf="administrationAccess" (click)="toggleSidenav()">Administration</a>
|
||||
<a mat-list-item class="navlist__item navlist__admin" [routerLink]=[administrationsUrl]
|
||||
[routerLinkActive]="['active']" *ngIf="administrationAccess" (click)="toggleSidenav()">Administration</a>
|
||||
<div class="navlist__admin-item">
|
||||
<a mat-list-item class="navlist__item navlist__admin-workbaskets" [routerLink]=[workbasketsUrl]
|
||||
[routerLinkActive]="['active']" *ngIf="administrationAccess" (click)="toggleSidenav()">Workbaskets</a>
|
||||
<a mat-list-item class="navlist__item navlist__admin-classifications" [routerLink]=[classificationUrl]
|
||||
[routerLinkActive]="['active']" *ngIf="administrationAccess" (click)="toggleSidenav()">Classifications</a>
|
||||
<a mat-list-item class="navlist__item navlist__admin-access-items" [routerLink]=[accessUrl]
|
||||
[routerLinkActive]="['active']" (click)="toggleSidenav()" *ngIf="administrationAccess">Access Items</a>
|
||||
<a mat-list-item class="navlist__item navlist__admin-workbaskets" [routerLink]=[workbasketsUrl]
|
||||
[routerLinkActive]="['active__sub']" *ngIf="administrationAccess" (click)="toggleSidenav()">Workbaskets</a>
|
||||
<a mat-list-item class="navlist__item navlist__admin-classifications" [routerLink]=[classificationUrl]
|
||||
[routerLinkActive]="['active__sub']" *ngIf="administrationAccess"
|
||||
(click)="toggleSidenav()">Classifications</a>
|
||||
<a mat-list-item class="navlist__item navlist__admin-access-items" [routerLink]=[accessUrl]
|
||||
[routerLinkActive]="['active__sub']" (click)="toggleSidenav()" *ngIf="administrationAccess">Access Items</a>
|
||||
</div>
|
||||
<a mat-list-item class="navlist__item navlist__monitor" [routerLink]=[monitorUrl] [routerLinkActive]="['active']"
|
||||
*ngIf="monitorAccess" (click)="toggleSidenav()">Monitor</a>
|
||||
<a mat-list-item class="navlist__item navlist__workplace" [routerLink]=[workplaceUrl] [routerLinkActive]="['active']"
|
||||
*ngIf="workplaceAccess" (click)="toggleSidenav()">Workplace</a>
|
||||
<a mat-list-item class="navlist__item navlist__workplace" [routerLink]=[workplaceUrl]
|
||||
[routerLinkActive]="['active']" *ngIf="workplaceAccess" (click)="toggleSidenav()">Workplace</a>
|
||||
<a mat-list-item class="navlist__item navlist__history" [routerLink]=[historyUrl] [routerLinkActive]="['active']"
|
||||
*ngIf="historyAccess" (click)="toggleSidenav()">History</a>
|
||||
</mat-nav-list>
|
||||
</mat-nav-list>
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
.navlist__item {
|
||||
color: #ddd;
|
||||
|
||||
}
|
||||
|
||||
.active {
|
||||
|
@ -14,6 +13,10 @@
|
|||
border-left: 5px solid $aquamarine;
|
||||
}
|
||||
|
||||
.active__sub {
|
||||
color: $aquamarine;
|
||||
}
|
||||
|
||||
::ng-deep .mat-drawer-container {
|
||||
background-color: white;
|
||||
}
|
||||
|
|
|
@ -4,4 +4,3 @@
|
|||
color: $aquamarine;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +1,16 @@
|
|||
<div *ngIf="dataSource" class="custom-form-control" [ngStyle]="{'width': width ? width : auto }">
|
||||
<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,
|
||||
'disable': disable}" class="wrapper-text"
|
||||
(click)="setTyping(true)">
|
||||
<span>
|
||||
<label>
|
||||
{{dataSource.selected?.name}}
|
||||
</label>
|
||||
</span>
|
||||
<div class="input-group form-control">
|
||||
<div>{{dataSource.selected?.accessId}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div [ngClass]="{'hidden': dataSource.selected && !typing}">
|
||||
<span class="field-label-wrapper">
|
||||
<label>
|
||||
{{dataSource.selected?.name}}
|
||||
</label>
|
||||
</span>
|
||||
<div class="input-group">
|
||||
<input #inputTypeAhead class="form-control input-text" [ngClass]="{'invalid': !dataSource.length && isRequired}" (blur)="typeaheadOnSelect({'item':dataSource.selected})"
|
||||
name="accessItem-{{index}}" [required]="isRequired ? 'required' : null" #accessItemName="ngModel" [(ngModel)]="value"
|
||||
[typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
|
||||
(typeaheadOnSelect)="typeaheadOnSelect($event)" [typeaheadScrollable]="true"
|
||||
[typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView" [typeaheadMinLength]="typeaheadMinLength"
|
||||
[typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)" placeholder="{{displayError? placeHolderMessage: ''}}"
|
||||
[@validation]="validationValue" data-cy="typeahead_input">
|
||||
<button *ngIf="!typeaheadLoading" type="button" title="search" class="btn rounded blue search-button" >
|
||||
<span class="material-icons md-20 blue">search</span>
|
||||
</button>
|
||||
<div *ngIf="typeaheadLoading" class="loading">
|
||||
<taskana-shared-spinner [isRunning]="typeaheadLoading" positionClass="type-ahead-spinner"></taskana-shared-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="dataSource" class="typeahead">
|
||||
<form>
|
||||
<mat-form-field class="typeahead__form" appearance="outline">
|
||||
<mat-label>{{dataSource.selected?.name ? 'Owner: ' + dataSource.selected?.name : placeHolderMessage}}</mat-label>
|
||||
<input #inputTypeAhead [required]="isRequired" class="typeahead__form-input align" matInput type="text"
|
||||
[matAutocomplete]="auto" placeholder="{{placeHolderMessage}}" [(ngModel)]="value" name="accessId"
|
||||
(ngModelChange)="initializeDataSource()" />
|
||||
<mat-autocomplete #autoComplete autoActiveFirstOption (optionSelected)="typeaheadOnSelect($event)"
|
||||
#auto="matAutocomplete">
|
||||
<mat-option class="typeahead__form-options" *ngFor="let item of items" [value]="item.accessId">
|
||||
<small>{{item.accessId}} {{item.name}}</small>
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</div>
|
|
@ -1,99 +1,9 @@
|
|||
@import '../../../../theme/colors';
|
||||
|
||||
.wrapper-text {
|
||||
min-width: 150px;
|
||||
height: 47px;
|
||||
& label {
|
||||
margin-bottom: 0px;
|
||||
//font-style: italic;
|
||||
//color: grey;
|
||||
overflow: hidden;
|
||||
}
|
||||
& > div {
|
||||
& > div {
|
||||
margin-top: 2px;
|
||||
max-width: 175px;
|
||||
}
|
||||
}
|
||||
> div {
|
||||
border-bottom: 1px solid $pallete-blue !important;
|
||||
border-radius: 4px !important;
|
||||
height: 32px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-right: 35px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
.custom-form-control {
|
||||
margin-top: -5px;
|
||||
max-height: 57px;
|
||||
& .input-group {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.input-text {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 16px;
|
||||
background: white;
|
||||
box-shadow: none;
|
||||
border-radius: 4px !important;
|
||||
//border-color: lightgray;
|
||||
border-bottom: 1px solid $pallete-blue !important;
|
||||
min-width: 150px;
|
||||
height: 32px;
|
||||
padding: 13px 0 13px 12px;
|
||||
}
|
||||
|
||||
.field-label-wrapper {
|
||||
position: relative;
|
||||
height: 28px;
|
||||
box-sizing: content-box;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
label {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
//border-color: unset;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.loading {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.btn.rounded {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
padding-top: 0;
|
||||
}
|
||||
.search-button {
|
||||
z-index: 999;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
::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;
|
||||
}
|
||||
|
||||
.disable {
|
||||
cursor: not-allowed;
|
||||
|
@ -102,3 +12,15 @@
|
|||
.invalid {
|
||||
color: $invalid;
|
||||
}
|
||||
|
||||
.typeahead__form {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.typeahead__form-options {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.align {
|
||||
left: 50%;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
||||
import { TypeAheadComponent } from './type-ahead.component';
|
||||
import { BrowserModule, By } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { of } from 'rxjs/internal/observable/of';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { compileComponentFromMetadata, componentFactoryName } from '@angular/compiler';
|
||||
import { AccessIdDefinition } from 'app/shared/models/access-id';
|
||||
|
||||
const AccessIdsServiceSpy = jest.fn().mockImplementation(
|
||||
(): Partial<AccessIdsService> => ({
|
||||
getAccessItems: jest.fn().mockReturnValue(of()),
|
||||
searchForAccessId: jest.fn().mockReturnValue(of())
|
||||
})
|
||||
);
|
||||
|
||||
describe('TypeAheadComponent', () => {
|
||||
let component: TypeAheadComponent;
|
||||
let fixture: ComponentFixture<TypeAheadComponent>;
|
||||
let debugElement: DebugElement;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TypeAheadComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
RouterModule,
|
||||
RouterTestingModule,
|
||||
HttpClientTestingModule,
|
||||
MatSelectModule,
|
||||
MatAutocompleteModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
FormsModule,
|
||||
BrowserAnimationsModule
|
||||
],
|
||||
providers: [{ provide: AccessIdsService, useClass: AccessIdsServiceSpy }]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TypeAheadComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
component = fixture.debugElement.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create component', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should change value via the input field', async(() => {
|
||||
component.value = 'val_1';
|
||||
component.initializeDataSource();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
let input = debugElement.query(By.css('.typeahead__form-input'));
|
||||
let el = input.nativeElement;
|
||||
expect(el.value).toBe('val_1');
|
||||
el.value = 'val_2';
|
||||
el.dispatchEvent(new Event('input'));
|
||||
expect(component.value).toBe('val_2');
|
||||
component.initializeDataSource();
|
||||
expect(component.items.length).toBeNull;
|
||||
});
|
||||
}));
|
||||
});
|
|
@ -9,10 +9,9 @@ import {
|
|||
AfterViewInit
|
||||
} from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
|
||||
|
||||
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { highlight } from 'app/shared/animations/validation.animation';
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
import { AccessIdDefinition } from 'app/shared/models/access-id';
|
||||
|
@ -34,6 +33,8 @@ export class TypeAheadComponent implements AfterViewInit, ControlValueAccessor {
|
|||
dataSource: any;
|
||||
typing = false;
|
||||
|
||||
items = [];
|
||||
|
||||
@Input()
|
||||
placeHolderMessage;
|
||||
|
||||
|
@ -50,7 +51,7 @@ export class TypeAheadComponent implements AfterViewInit, ControlValueAccessor {
|
|||
disable;
|
||||
|
||||
@Input()
|
||||
isRequired = true;
|
||||
isRequired;
|
||||
|
||||
@Output()
|
||||
selectedItem = new EventEmitter<AccessIdDefinition>();
|
||||
|
@ -83,7 +84,6 @@ export class TypeAheadComponent implements AfterViewInit, ControlValueAccessor {
|
|||
set value(v: any) {
|
||||
if (v !== this.innerValue) {
|
||||
this.innerValue = v;
|
||||
this.onChangeCallback(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,9 +116,7 @@ export class TypeAheadComponent implements AfterViewInit, ControlValueAccessor {
|
|||
observer.next(this.value);
|
||||
}).pipe(mergeMap((token: string) => this.getUsersAsObservable(token)));
|
||||
this.accessIdsService.searchForAccessId(this.value).subscribe((items) => {
|
||||
if (items.length > 0) {
|
||||
this.dataSource.selected = items.find((item) => item.accessId.toLowerCase() === this.value.toLowerCase());
|
||||
}
|
||||
this.items = items;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -126,32 +124,15 @@ export class TypeAheadComponent implements AfterViewInit, ControlValueAccessor {
|
|||
return this.accessIdsService.searchForAccessId(accessId);
|
||||
}
|
||||
|
||||
typeaheadOnSelect(event: TypeaheadMatch): void {
|
||||
if (event && event.item) {
|
||||
this.value = event.item.accessId;
|
||||
this.dataSource.selected = event.item;
|
||||
typeaheadOnSelect(event): void {
|
||||
if (event) {
|
||||
if (this.items.length > 0) {
|
||||
this.dataSource.selected = this.items.find((item) => item.accessId.toLowerCase() === this.value.toLowerCase());
|
||||
}
|
||||
this.selectedItem.emit(this.dataSource.selected);
|
||||
}
|
||||
this.setTyping(false);
|
||||
}
|
||||
|
||||
setTyping(value) {
|
||||
if (this.disable) {
|
||||
return;
|
||||
if (document.activeElement instanceof HTMLElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
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>`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
@ -59,6 +59,7 @@ import { MatMenuModule } from '@angular/material/menu';
|
|||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
|
||||
const MODULES = [
|
||||
CommonModule,
|
||||
|
@ -73,7 +74,8 @@ const MODULES = [
|
|||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
RouterModule,
|
||||
TreeModule.forRoot()
|
||||
TreeModule.forRoot(),
|
||||
MatAutocompleteModule
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
@ -113,7 +115,8 @@ const DECLARATIONS = [
|
|||
MatMenuModule,
|
||||
MatTooltipModule,
|
||||
MatPaginatorModule,
|
||||
MatSelectModule
|
||||
MatSelectModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
exports: DECLARATIONS,
|
||||
providers: [
|
||||
|
|
Loading…
Reference in New Issue