TSK-1315: Now uses maxlength for validation in classification
This commit is contained in:
parent
da4a90c998
commit
33845db647
|
@ -1,21 +1,26 @@
|
||||||
<div class="container-scrollable">
|
<div class="container-scrollable">
|
||||||
<taskana-shared-spinner [isRunning]="requestInProgress" class="floating" (spinnerIsRunning)="spinnerRunning($event)"></taskana-shared-spinner>
|
<taskana-shared-spinner [isRunning]="requestInProgress" class="floating"
|
||||||
|
(spinnerIsRunning)="spinnerRunning($event)"></taskana-shared-spinner>
|
||||||
<div id="classification-details" *ngIf="classification && !spinnerIsRunning">
|
<div id="classification-details" *ngIf="classification && !spinnerIsRunning">
|
||||||
<div id="classification" class="panel panel-default classification">
|
<div id="classification" class="panel panel-default classification">
|
||||||
|
|
||||||
<!-- TITLE + ACTION BUTTONS -->
|
<!-- TITLE + ACTION BUTTONS -->
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right btn-group">
|
<div class="pull-right btn-group">
|
||||||
<button type="button" (click)="onSubmit()" class="btn btn-default btn-primary" data-toggle="tooltip" title="Save">
|
<button type="button" (click)="onSubmit()" class="btn btn-default btn-primary"
|
||||||
|
data-toggle="tooltip" title="Save">
|
||||||
<span class="material-icons md-20">save</span>
|
<span class="material-icons md-20">save</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" (click)="onRestore()" class="btn btn-default" data-toggle="tooltip" title="Restore Previous Version">
|
<button type="button" (click)="onRestore()" class="btn btn-default" data-toggle="tooltip"
|
||||||
|
title="Restore Previous Version">
|
||||||
<span class="material-icons md-20 blue">restore</span>
|
<span class="material-icons md-20 blue">restore</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" (click)="onCopy()" data-toggle="tooltip" title="Copy" class="btn btn-default" id="copyButton">
|
<button type="button" (click)="onCopy()" data-toggle="tooltip" title="Copy"
|
||||||
|
class="btn btn-default" id="copyButton">
|
||||||
<span class="material-icons md-20 green-blue">content_copy</span>
|
<span class="material-icons md-20 green-blue">content_copy</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" (click)="removeClassification()" data-toggle="tooltip" title="Delete" class="btn btn-default">
|
<button type="button" (click)="removeClassification()" data-toggle="tooltip"
|
||||||
|
title="Delete" class="btn btn-default">
|
||||||
<span class="material-icons md-20 red">delete</span>
|
<span class="material-icons md-20 red">delete</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,19 +39,23 @@
|
||||||
<!-- KEY -->
|
<!-- KEY -->
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label for="classification-key" class="control-label">Key</label>
|
<label for="classification-key" class="control-label">Key</label>
|
||||||
<input type="text" required #key="ngModel" [disabled]="!isCreatingNewClassification" class="form-control"
|
<input type="text" required maxlength="32" #key="ngModel" [disabled]="!isCreatingNewClassification" class="form-control"
|
||||||
id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key">
|
id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key" (keypress)="onKeyPressed($event, key, 32)">
|
||||||
<taskana-shared-field-error-display [displayError]="key.invalid"
|
<div *ngIf="tooLongMap.get(key.name)" class="error">{{lengthError}}</div>
|
||||||
[validationTrigger]="this.toggleValidationMap.get('classification.key')" errorMessage="* Key is required">
|
<taskana-shared-field-error-display [displayError]="key.invalid && key.dirty"
|
||||||
|
errorMessage="* Key is required">
|
||||||
</taskana-shared-field-error-display>
|
</taskana-shared-field-error-display>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- NAME -->
|
<!-- NAME -->
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label for="classification-name" class="control-label">Name</label>
|
<label for="classification-name" class="control-label">Name</label>
|
||||||
<input type="text" required ="255" #name="ngModel" class="form-control" id="classification-name" placeholder="Name"
|
<input type="text" required maxlength="255" #name="ngModel"
|
||||||
[(ngModel)]="classification.name" name="classification.name">
|
class="form-control"
|
||||||
<taskana-shared-field-error-display [displayError]="name.invalid"
|
id="classification-name" placeholder="Name"
|
||||||
|
[(ngModel)]="classification.name" name="classification.name" (keypress)="onKeyPressed($event, name, 255)">
|
||||||
|
<div *ngIf="tooLongMap.get(name.name)" class="error">{{lengthError}}</div>
|
||||||
|
<taskana-shared-field-error-display [displayError]="name.invalid && name.dirty"
|
||||||
errorMessage="* Name is required">
|
errorMessage="* Name is required">
|
||||||
</taskana-shared-field-error-display>
|
</taskana-shared-field-error-display>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,12 +64,14 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="classification-domain" class="control-label">Domain</label>
|
<label for="classification-domain" class="control-label">Domain</label>
|
||||||
<input type="text" disabled #domain class="form-control" id="classification-domain"
|
<input type="text" disabled #domain class="form-control" id="classification-domain"
|
||||||
placeholder="Domain" [(ngModel)]="classification.domain" name="classification.domain">
|
placeholder="Domain" [(ngModel)]="classification.domain"
|
||||||
|
name="classification.domain">
|
||||||
<a *ngIf="!masterDomainSelected()" (click)="validChanged()">
|
<a *ngIf="!masterDomainSelected()" (click)="validChanged()">
|
||||||
<label>
|
<label>
|
||||||
<b>Valid in Domain:</b>
|
<b>Valid in Domain:</b>
|
||||||
<span class="material-icons md-20 blue ">{{classification.isValidInDomain ? 'check_box':
|
<span class="material-icons md-20 blue ">{{classification.isValidInDomain
|
||||||
'check_box_outline_blank'}}</span>
|
? 'check_box' :
|
||||||
|
'check_box_outline_blank'}}</span>
|
||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,29 +80,40 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group required col-xs-6">
|
<div class="form-group required col-xs-6">
|
||||||
<label for="classification-priority" class="control-label">Priority</label>
|
<label for="classification-priority" class="control-label">Priority</label>
|
||||||
<taskana-shared-number-picker [(ngModel)]="classification.priority" name="classification.priority" id="classification-priority" [required]="true"></taskana-shared-number-picker>
|
<taskana-shared-number-picker [(ngModel)]="classification.priority"
|
||||||
<taskana-shared-field-error-display [displayError]="!isFieldValid('classification.priority')" [validationTrigger]="this.toggleValidationMap.get('classification.priority')"
|
name="classification.priority"
|
||||||
errorMessage="* Priority is required">
|
id="classification-priority"
|
||||||
|
[required]="true"></taskana-shared-number-picker>
|
||||||
|
<taskana-shared-field-error-display
|
||||||
|
[displayError]="!isFieldValid('classification.priority')"
|
||||||
|
[validationTrigger]="this.toggleValidationMap.get('classification.priority.name')"
|
||||||
|
errorMessage="* Priority is required">
|
||||||
</taskana-shared-field-error-display>
|
</taskana-shared-field-error-display>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group required btn-group col-xs-6">
|
<div class="form-group required btn-group col-xs-6">
|
||||||
<label for="classification-category" class="control-label">Category</label>
|
<label for="classification-category" class="control-label">Category</label>
|
||||||
<div class="dropdown clearfix ">
|
<div class="dropdown clearfix">
|
||||||
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true"
|
<button class="btn btn-default" type="button" data-toggle="dropdown"
|
||||||
aria-expanded="true" id="classification-category">
|
aria-haspopup="true"
|
||||||
|
aria-expanded="true" id="classification-category">
|
||||||
<span class="text-top">
|
<span class="text-top">
|
||||||
<svg-icon class="blue fa-fw" src="{{(getCategoryIcon(classification.category) | async)?.name}}"
|
<svg-icon class="blue fa-fw"
|
||||||
data-toggle="tooltip" [title]="(getCategoryIcon(classification.category) | async)?.text"></svg-icon>
|
src="{{(getCategoryIcon(classification.category) | async)?.name}}"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
[title]="(getCategoryIcon(classification.category) | async)?.text"></svg-icon>
|
||||||
</span>
|
</span>
|
||||||
{{classification.category}}
|
{{classification.category}}
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
|
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
|
||||||
<li>
|
<li>
|
||||||
<a *ngFor="let category of getAvailableCategories(classification.type) | async" (click)="selectCategory(category)">
|
<a *ngFor="let category of getAvailableCategories(classification.type) | async"
|
||||||
|
(click)="selectCategory(category)">
|
||||||
<span class="text-top">
|
<span class="text-top">
|
||||||
<svg-icon class="blue fa-fw" src="{{(getCategoryIcon(category) | async)?.name}}" data-toggle="tooltip"
|
<svg-icon class="blue fa-fw"
|
||||||
[title]="(getCategoryIcon(category) | async)?.text"></svg-icon>
|
src="{{(getCategoryIcon(category) | async)?.name}}"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
[title]="(getCategoryIcon(category) | async)?.text"></svg-icon>
|
||||||
{{category}}
|
{{category}}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -105,35 +127,51 @@
|
||||||
|
|
||||||
<!-- SERVICE LEVEL -->
|
<!-- SERVICE LEVEL -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="classification-service-level" class="control-label">Service Level</label>
|
<label for="classification-service-level" class="control-label">Service
|
||||||
<input type="text" maxlength="255" class="form-control" id="classification-service-level" placeholder="Service Level"
|
Level</label>
|
||||||
[(ngModel)]="classification.serviceLevel" name="classification.serviceLevel">
|
<input type="text" maxlength="255" class="form-control"
|
||||||
|
id="classification-service-level" placeholder="Service Level"
|
||||||
|
[(ngModel)]="classification.serviceLevel" name="classification.serviceLevel" #serviceLevel="ngModel" (keypress)="onKeyPressed($event, serviceLevel, 255)">
|
||||||
|
<div *ngIf="tooLongMap.get(serviceLevel.name)" class="error">{{lengthError}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- APPLICATION ENTRY POINT -->
|
<!-- APPLICATION ENTRY POINT -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="classification-application-entry-point" class="control-label">Application entry point</label>
|
<label for="classification-application-entry-point" class="control-label">
|
||||||
<input type="text" maxlength="255" class="form-control" id="classification-application-entry-point" placeholder="Application entry point"
|
Application entry point</label>
|
||||||
[(ngModel)]="classification.applicationEntryPoint" name="classification.applicationEntryPoint">
|
<input type="text" maxlength="255" class="form-control"
|
||||||
|
id="classification-application-entry-point"
|
||||||
|
placeholder="Application entry point"
|
||||||
|
[(ngModel)]="classification.applicationEntryPoint"
|
||||||
|
name="classification.applicationEntryPoint" #appEntryPoint="ngModel" (keypress)="onKeyPressed($event, appEntryPoint, 255)">
|
||||||
|
<div *ngIf="tooLongMap.get(appEntryPoint.name)" class="error">{{lengthError}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- DESCRIPTION -->
|
<!-- DESCRIPTION -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="classification-description" class="control-label">Description</label>
|
<label for="classification-description" class="control-label">Description</label>
|
||||||
<textarea class="form-control" maxlength="255" rows="5" id="classification-description" placeholder="Description"
|
<textarea class="form-control" maxlength="255" rows="5"
|
||||||
[(ngModel)]="classification.description" name="classification.description"></textarea>
|
id="classification-description" placeholder="Description"
|
||||||
|
[(ngModel)]="classification.description"
|
||||||
|
name="classification.description" #description="ngModel" (keypress)="onKeyPressed($event, description, 255)"></textarea>
|
||||||
|
<div *ngIf="tooLongMap.get(description.name)" class="error">{{lengthError}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CUSTOM FIELDS -->
|
<!-- CUSTOM FIELDS -->
|
||||||
<div class="row custom-field-row">
|
<div class="row custom-field-row">
|
||||||
<div class="custom-classification-form" *ngFor="let customField of (customFields$ | async), let i = index"
|
<div class="custom-classification-form"
|
||||||
|
*ngFor="let customField of (customFields$ | async), let i = index"
|
||||||
style="width: 50%;">
|
style="width: 50%;">
|
||||||
<div *ngIf="customField.visible" class="form-group custom-field-wrapper">
|
<div *ngIf="customField.visible" class="form-group custom-field-wrapper">
|
||||||
<label for="classification-custom-{{i + 1}}" class="control-label">{{customField.field}}</label>
|
<label for="classification-custom-{{i + 1}}"
|
||||||
<input type="text" maxlength="255" class="form-control" id="classification-custom-{{i + 1}}" placeholder="{{customField.field}}"
|
class="control-label">{{customField.field}}</label>
|
||||||
[(ngModel)]="classification[getClassificationCustom(i + 1)]" name="classification.custom{{i + 1}}">
|
<input type="text" maxlength="255" class="form-control"
|
||||||
|
id="classification-custom-{{i + 1}}" placeholder="{{customField.field}}"
|
||||||
|
[(ngModel)]="classification[getClassificationCustom(i + 1)]"
|
||||||
|
name="classification.custom{{i + 1}}" #custom="ngModel" (keypress)="onKeyPressed($event, custom, 255)">
|
||||||
|
<div *ngIf="tooLongMap.get(custom.name)" class="error">{{lengthError}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import "src/theme/_colors.scss";
|
||||||
|
|
||||||
.custom-field-row {
|
.custom-field-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -14,3 +16,11 @@
|
||||||
.dropdown-menu > li {
|
.dropdown-menu > li {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input:invalid.dirty {
|
||||||
|
border-color: $invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.error {
|
||||||
|
color: $invalid;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { Select, Store } from '@ngxs/store';
|
import { Select, Store } from '@ngxs/store';
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { combineLatest, Observable, Subject, Subscription, timer } from 'rxjs';
|
||||||
|
|
||||||
import { highlight } from 'theme/animations/validation.animation';
|
import { highlight } from 'theme/animations/validation.animation';
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import { RequestInProgressService } from 'app/shared/services/request-in-progres
|
||||||
|
|
||||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||||
import { Pair } from 'app/shared/models/pair';
|
import { Pair } from 'app/shared/models/pair';
|
||||||
import { NgForm } from '@angular/forms';
|
import { NgForm, NgModel } from '@angular/forms';
|
||||||
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
||||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||||
import { map, take, takeUntil } from 'rxjs/operators';
|
import { map, take, takeUntil } from 'rxjs/operators';
|
||||||
|
@ -52,9 +52,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
isCreatingNewClassification: boolean = false;
|
isCreatingNewClassification: boolean = false;
|
||||||
|
|
||||||
@ViewChild('ClassificationForm', { static: false }) classificationForm: NgForm;
|
@ViewChild('ClassificationForm', { static: false }) classificationForm: NgForm;
|
||||||
toogleValidationMap = new Map<string, boolean>();
|
toggleValidationMap = new Map<string, boolean>();
|
||||||
destroy$ = new Subject<void>();
|
destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
private timeout = new Map<string, Subscription>();
|
||||||
|
readonly lengthError = 'You have reached the maximal length';
|
||||||
|
tooLongMap = new Map<string, boolean>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private location: Location,
|
private location: Location,
|
||||||
private requestInProgressService: RequestInProgressService,
|
private requestInProgressService: RequestInProgressService,
|
||||||
|
@ -233,4 +237,14 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications'));
|
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onKeyPressed(event: KeyboardEvent, model: NgModel, max: Number): void {
|
||||||
|
if (this.timeout.has(model.name)) {
|
||||||
|
this.timeout.get(model.name).unsubscribe();
|
||||||
|
}
|
||||||
|
if (model.value.length >= max && !event.altKey && !event.ctrlKey) {
|
||||||
|
this.tooLongMap.set(model.name, true);
|
||||||
|
this.timeout.set(model.name, timer(3000).subscribe(() => this.tooLongMap.set(model.name, false)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue