mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 04:05:40 +01:00
Fix UI/UX issues:
Use blur event to instead focusout Fix mail/ldap server testing spinner and button disabling issues Fix content area/more info margins and make alert as overlay fix reset password form issues fix reset password style issue fix tootip display inssue on reset form commit index.html change
This commit is contained in:
parent
69ebc92f87
commit
8f0285b4cb
@ -1,5 +1,6 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Harbor</title>
|
||||
@ -7,11 +8,20 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico?v=2">
|
||||
</head>
|
||||
<body>
|
||||
<harbor-app>Loading...</harbor-app>
|
||||
<script type="text/javascript" src="/static/inline.bundle.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts.bundle.js">
|
||||
</script><script type="text/javascript" src="/static/styles.bundle.js">
|
||||
</script><script type="text/javascript" src="/static/vendor.bundle.js"></script>
|
||||
<script type="text/javascript" src="/static/main.bundle.js"></script></body>
|
||||
</html>
|
||||
|
||||
<body style="overflow-y: hidden;">
|
||||
<harbor-app>
|
||||
<div class="spinner spinner-lg app-loading">
|
||||
Loading...
|
||||
</div>
|
||||
</harbor-app>
|
||||
<script type="text/javascript" src="/static/inline.bundle.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts.bundle.js">
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/styles.bundle.js">
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/vendor.bundle.js"></script>
|
||||
<script type="text/javascript" src="/static/main.bundle.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -4,7 +4,7 @@
|
||||
"description": "Harbor UI with Clarity",
|
||||
"angular-cli": {},
|
||||
"scripts": {
|
||||
"start": "ng serve --ssl 1 --ssl-key --ssl-cert --host 0.0.0.0 --proxy-config proxy.config.json",
|
||||
"start": "ng serve --ssl 1 --ssl-key ssl/server.key --ssl-cert ssl/server.crt --host 0.0.0.0 --proxy-config proxy.config.json",
|
||||
"lint": "tslint \"src/**/*.ts\"",
|
||||
"test": "ng test --single-run",
|
||||
"pree2e": "webdriver-manager update",
|
||||
|
@ -16,7 +16,7 @@
|
||||
email
|
||||
id="account_settings_email" size="30"
|
||||
(input)='handleValidation("account_settings_email", false)'
|
||||
(focusout)='handleValidation("account_settings_email", true)'>
|
||||
(blur)='handleValidation("account_settings_email", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{emailTooltip | translate}}
|
||||
</span>
|
||||
@ -25,7 +25,7 @@
|
||||
<div class="form-group form-group-override">
|
||||
<label for="account_settings_full_name" class="required form-group-label-override">{{'PROFILE.FULL_NAME' | translate}}</label>
|
||||
<label for="account_settings_full_name" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left" [class.invalid]='!getValidationState("account_settings_full_name")'>
|
||||
<input type="text" name="account_settings_full_name" #fullNameInput="ngModel" [(ngModel)]="account.realname" required maxLengthExt="20" id="account_settings_full_name" size="30" (input)='handleValidation("account_settings_full_name", false)' (focusout)='handleValidation("account_settings_full_name", true)'>
|
||||
<input type="text" name="account_settings_full_name" #fullNameInput="ngModel" [(ngModel)]="account.realname" required maxLengthExt="20" id="account_settings_full_name" size="30" (input)='handleValidation("account_settings_full_name", false)' (blur)='handleValidation("account_settings_full_name", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.FULL_NAME' | translate}}
|
||||
</span>
|
||||
|
@ -14,7 +14,7 @@
|
||||
id="reset_pwd_email"
|
||||
size="40"
|
||||
(input)="handleValidation(true)"
|
||||
(focusout)="handleValidation(false)">
|
||||
(blur)="handleValidation(false)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.EMAIL' | translate}}
|
||||
</span>
|
||||
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span>
|
||||
<button type="button" class="btn btn-outline" (click)="close()">{{btnCancelCaption | translate}}</button>
|
||||
<button type="button" class="btn" [class.btn-outline]="!isSuccess" [class.btn-primary]="isSuccess" (click)="close()">{{btnCancelCaption | translate}}</button>
|
||||
<button *ngIf="!isSuccess" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.SEND' | translate}}</button>
|
||||
</div>
|
||||
</clr-modal>
|
@ -27,7 +27,7 @@
|
||||
[(ngModel)]="newPwd"
|
||||
#newPassInput="ngModel" size="42"
|
||||
(input)='handleValidation("newPassword", false)'
|
||||
(focusout)='handleValidation("newPassword", true)'>
|
||||
(blur)='handleValidation("newPassword", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.PASSWORD' | translate}}
|
||||
</span>
|
||||
@ -44,7 +44,7 @@
|
||||
[(ngModel)]="reNewPwd"
|
||||
#reNewPassInput="ngModel" size="42"
|
||||
(input)='handleValidation("reNewPassword", false)'
|
||||
(focusout)='handleValidation("reNewPassword", true)'>
|
||||
(blur)='handleValidation("reNewPassword", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.CONFIRM_PWD' | translate}}
|
||||
</span>
|
||||
|
@ -1,12 +1,13 @@
|
||||
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="true" [clrModalClosable]="false">
|
||||
<h3 class="modal-title">{{'RESET_PWD.TITLE' | translate}}</h3>
|
||||
<label class="modal-title reset-modal-title-override">{{'RESET_PWD.CAPTION2' | translate}}</label>
|
||||
<inline-alert class="modal-title"></inline-alert>
|
||||
<div class="modal-body" style="overflow-y: hidden;">
|
||||
<form #resetPwdForm="ngForm" class="form">
|
||||
<section class="form-block">
|
||||
<div class="form-group">
|
||||
<label for="newPassword" class="form-group-label-override">{{'CHANGE_PWD.NEW_PWD' | translate}}</label>
|
||||
<label for="newPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("newPassword") === false'>
|
||||
<label for="newPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='!getValidationState("newPassword")'>
|
||||
<input [disabled]="resetOk" type="password" id="newPassword" placeholder='{{"PLACEHOLDER.NEW_PWD" | translate}}'
|
||||
required
|
||||
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$"
|
||||
@ -14,8 +15,8 @@
|
||||
[(ngModel)]="password"
|
||||
#newPassInput="ngModel"
|
||||
size="25"
|
||||
(input)='handleValidation("newPassword", true)'
|
||||
(focusout)='handleValidation("newPassword", false)'>
|
||||
(input)='handleValidation("newPassword", false)'
|
||||
(blur)='handleValidation("newPassword", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.PASSWORD' | translate}}
|
||||
</span>
|
||||
@ -23,7 +24,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="reNewPassword" class="form-group-label-override">{{'CHANGE_PWD.CONFIRM_PWD' | translate}}</label>
|
||||
<label for="reNewPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("reNewPassword") === false'>
|
||||
<label for="reNewPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left" [class.invalid]='!getValidationState("reNewPassword")'>
|
||||
<input [disabled]="resetOk" type="password" id="reNewPassword" placeholder='{{"PLACEHOLDER.CONFIRM_PWD" | translate}}'
|
||||
required
|
||||
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$"
|
||||
@ -31,21 +32,19 @@
|
||||
[(ngModel)]="confirmPwd"
|
||||
#reNewPassInput
|
||||
size="25"
|
||||
(input)='handleValidation("reNewPassword", true)'
|
||||
(focusout)='handleValidation("reNewPassword", false)'>
|
||||
(input)='handleValidation("reNewPassword", false)'
|
||||
(blur)='handleValidation("reNewPassword", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.CONFIRM_PWD' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
<inline-alert></inline-alert>
|
||||
<div style="height: 30px;"></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span>
|
||||
<button type="button" class="btn btn-outline" (click)="close()">{{btnCancelCaption | translate}}</button>
|
||||
<button type="button" class="btn" [class.btn-outline]="!resetOk" [class.btn-primary]="resetOk" (click)="close()">{{btnCancelCaption | translate}}</button>
|
||||
<button *ngIf="!resetOk" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.OK' | translate}}</button>
|
||||
</div>
|
||||
</clr-modal>
|
@ -56,8 +56,7 @@ export class ResetPasswordComponent implements OnInit {
|
||||
|
||||
public getValidationState(key: string): boolean {
|
||||
return this.validationState &&
|
||||
this.validationState[key] &&
|
||||
key === 'reNewPassword' ? this.samePassword() : true;
|
||||
this.validationState[key];
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
@ -109,10 +108,8 @@ export class ResetPasswordComponent implements OnInit {
|
||||
}
|
||||
|
||||
public handleValidation(key: string, flag: boolean): void {
|
||||
if (flag) {
|
||||
if (!this.validationState[key]) {
|
||||
this.validationState[key] = true;
|
||||
}
|
||||
if (!flag) {
|
||||
this.validationState[key] = true;
|
||||
} else {
|
||||
this.validationState[key] = this.getControlValidationState(key);
|
||||
if (this.validationState[key]) {
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
.more-info-link {
|
||||
position: relative;
|
||||
top: 90px;
|
||||
left: 330px;
|
||||
top: 80px;
|
||||
left: 294px;
|
||||
padding-right: 36px;
|
||||
}
|
@ -13,5 +13,15 @@
|
||||
}
|
||||
|
||||
.content-area-override {
|
||||
padding: 24px 36px !important;
|
||||
padding: 36px !important;
|
||||
padding-right: 21px !important;
|
||||
}
|
||||
|
||||
.global-message-alert {
|
||||
position: fixed;
|
||||
top: 55px;
|
||||
left: 260px;
|
||||
width: 100%;
|
||||
z-index: 999;
|
||||
padding-right: 276px;
|
||||
}
|
@ -3,7 +3,9 @@
|
||||
<navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator>
|
||||
<div class="content-container">
|
||||
<div class="content-area" [class.container-override]="showSearch" [class.content-area-override]="!shouldOverrideContent" [class.start-content-padding]="shouldOverrideContent">
|
||||
<global-message [isAppLevel]="false"></global-message>
|
||||
<div class="global-message-alert">
|
||||
<global-message [isAppLevel]="false"></global-message>
|
||||
</div>
|
||||
<!-- Only appear when searching -->
|
||||
<search-result></search-result>
|
||||
<router-outlet></router-outlet>
|
||||
|
@ -65,7 +65,8 @@
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="testMailServer()" *ngIf="showTestServerBtn" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button>
|
||||
<span class="spinner spinner-inline" [hidden]="!testingInProgress"></span>
|
||||
<span id="forTestingMail" class="spinner spinner-inline" [hidden]="hideMailTestingSpinner"></span>
|
||||
<span id="forTestingLDAP" class="spinner spinner-inline" [hidden]="hideLDAPTestingSpinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -17,7 +17,7 @@ import { AppConfigService } from '../app-config.service';
|
||||
import { SessionService } from '../shared/session.service';
|
||||
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
|
||||
|
||||
const fakePass = "fakepassword";
|
||||
const fakePass = "aWpLOSYkIzJTTU4wMDkx";
|
||||
const TabLinkContentMap = {
|
||||
"config-auth": "authentication",
|
||||
"config-replication": "replication",
|
||||
@ -36,7 +36,8 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
private currentTabId: string = "config-auth";//default tab
|
||||
private originalCopy: Configuration;
|
||||
private confirmSub: Subscription;
|
||||
private testingOnGoing: boolean = false;
|
||||
private testingMailOnGoing: boolean = false;
|
||||
private testingLDAPOnGoing: boolean = false;
|
||||
|
||||
@ViewChild("repoConfigFrom") repoConfigForm: NgForm;
|
||||
@ViewChild("systemConfigFrom") systemConfigForm: NgForm;
|
||||
@ -131,10 +132,6 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
return this.onGoing;
|
||||
}
|
||||
|
||||
public get testingInProgress(): boolean {
|
||||
return this.testingOnGoing;
|
||||
}
|
||||
|
||||
public isValid(): boolean {
|
||||
return this.repoConfigForm &&
|
||||
this.repoConfigForm.valid &&
|
||||
@ -152,7 +149,8 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
|
||||
public isMailConfigValid(): boolean {
|
||||
return this.mailConfig &&
|
||||
this.mailConfig.isValid();
|
||||
this.mailConfig.isValid() &&
|
||||
!this.testingMailOnGoing;
|
||||
}
|
||||
|
||||
public get showTestServerBtn(): boolean {
|
||||
@ -165,8 +163,18 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
this.allConfig.auth_mode.value === "ldap_auth";
|
||||
}
|
||||
|
||||
public get hideMailTestingSpinner(): boolean {
|
||||
return !this.testingMailOnGoing || !this.showTestServerBtn;
|
||||
}
|
||||
|
||||
public get hideLDAPTestingSpinner(): boolean {
|
||||
return !this.testingLDAPOnGoing || !this.showLdapServerBtn;
|
||||
}
|
||||
|
||||
public isLDAPConfigValid(): boolean {
|
||||
return this.authConfig && this.authConfig.isValid();
|
||||
return this.authConfig &&
|
||||
this.authConfig.isValid() &&
|
||||
!this.testingLDAPOnGoing;
|
||||
}
|
||||
|
||||
public tabLinkClick(tabLink: string) {
|
||||
@ -239,6 +247,9 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public testMailServer(): void {
|
||||
if(this.testingMailOnGoing){
|
||||
return;//Should not come here
|
||||
}
|
||||
let mailSettings = {};
|
||||
for (let prop in this.allConfig) {
|
||||
if (prop.startsWith("email_")) {
|
||||
@ -255,23 +266,27 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
delete mailSettings["email_password"];
|
||||
}
|
||||
|
||||
this.testingOnGoing = true;
|
||||
this.testingMailOnGoing = true;
|
||||
this.configService.testMailServer(mailSettings)
|
||||
.then(response => {
|
||||
this.testingOnGoing = false;
|
||||
this.testingMailOnGoing = false;
|
||||
this.msgHandler.showSuccess("CONFIG.TEST_MAIL_SUCCESS");
|
||||
})
|
||||
.catch(error => {
|
||||
this.testingOnGoing = false;
|
||||
this.testingMailOnGoing = false;
|
||||
let err = error._body;
|
||||
if(!err){
|
||||
if (!err) {
|
||||
err = "UNKNOWN";
|
||||
}
|
||||
this.msgHandler.showError("CONFIG.TEST_MAIL_FAILED", {'param': err});
|
||||
this.msgHandler.showError("CONFIG.TEST_MAIL_FAILED", { 'param': err });
|
||||
});
|
||||
}
|
||||
|
||||
public testLDAPServer(): void {
|
||||
if(this.testingLDAPOnGoing){
|
||||
return;//Should not come here
|
||||
}
|
||||
|
||||
let ldapSettings = {};
|
||||
for (let prop in this.allConfig) {
|
||||
if (prop.startsWith("ldap_")) {
|
||||
@ -281,25 +296,25 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
|
||||
let allChanges = this.getChanges();
|
||||
let ldapSearchPwd = allChanges["ldap_search_password"];
|
||||
if(ldapSearchPwd){
|
||||
if (ldapSearchPwd) {
|
||||
ldapSettings['ldap_search_password'] = ldapSearchPwd;
|
||||
}else{
|
||||
} else {
|
||||
delete ldapSettings['ldap_search_password'];
|
||||
}
|
||||
|
||||
this.testingOnGoing = true;
|
||||
this.testingLDAPOnGoing = true;
|
||||
this.configService.testLDAPServer(ldapSettings)
|
||||
.then(respone => {
|
||||
this.testingOnGoing = false;
|
||||
this.testingLDAPOnGoing = false;
|
||||
this.msgHandler.showSuccess("CONFIG.TEST_LDAP_SUCCESS");
|
||||
})
|
||||
.catch(error => {
|
||||
this.testingOnGoing = false;
|
||||
this.testingLDAPOnGoing = false;
|
||||
let err = error._body;
|
||||
if(!err){
|
||||
if (!err) {
|
||||
err = "UNKNOWN";
|
||||
}
|
||||
this.msgHandler.showError("CONFIG.TEST_LDAP_FAILED", {'param': err});
|
||||
this.msgHandler.showError("CONFIG.TEST_LDAP_FAILED", { 'param': err });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ export class MessageComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Make the message alert bar dismiss after several intervals.
|
||||
//Only for this case
|
||||
this.timer = setTimeout(() => this.onClose(), dismissInterval);
|
||||
//this.timer = setTimeout(() => this.onClose(), dismissInterval);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<div class="row flex-items-xs-between flex-items-xs-top">
|
||||
<div class="row flex-items-xs-between flex-items-xs-top" style="padding-left: 15px; padding-right: 15px;">
|
||||
<h2 class="header-title">{{'PROJECT.PROJECTS' | translate}}</h2>
|
||||
<div>
|
||||
<statistics-panel></statistics-panel>
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
<div class="option-right">
|
||||
<div class="select" style="float: left;">
|
||||
<select (change)="doFilterProjects($event)">
|
||||
<select (change)="doFilterProjects($event)">
|
||||
<option value="0">{{projectTypes[0] | translate}}</option>
|
||||
<option value="1">{{projectTypes[1] | translate}}</option>
|
||||
</select>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<label for="username" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("username")'>
|
||||
<input type="text" required pattern='[^"~#$%]+' maxLengthExt="20" #usernameInput="ngModel" name="username" [(ngModel)]="newUser.username" id="username" size="36"
|
||||
(input)='handleValidation("username", false)'
|
||||
(focusout)='handleValidation("username", true)'>
|
||||
(blur)='handleValidation("username", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{usernameTooltip | translate}}
|
||||
</span>
|
||||
@ -20,7 +20,7 @@
|
||||
email
|
||||
id="email" size="36"
|
||||
(input)='handleValidation("email", false)'
|
||||
(focusout)='handleValidation("email", true)'>
|
||||
(blur)='handleValidation("email", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{emailTooltip | translate}}
|
||||
</span>
|
||||
@ -33,7 +33,7 @@
|
||||
<label for="realname" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("realname")'>
|
||||
<input type="text" name="realname" #fullNameInput="ngModel" [(ngModel)]="newUser.realname" required maxLengthExt="20" id="realname" size="36"
|
||||
(input)='handleValidation("realname", false)'
|
||||
(focusout)='handleValidation("realname", true)'>
|
||||
(blur)='handleValidation("realname", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.FULL_NAME' | translate}}
|
||||
</span>
|
||||
@ -49,7 +49,7 @@
|
||||
[(ngModel)]="newUser.password"
|
||||
#newPassInput="ngModel" size="36"
|
||||
(input)='handleValidation("newPassword", false)'
|
||||
(focusout)='handleValidation("newPassword", true)'>
|
||||
(blur)='handleValidation("newPassword", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.PASSWORD' | translate}}
|
||||
</span>
|
||||
@ -66,7 +66,7 @@
|
||||
[(ngModel)]="confirmedPwd"
|
||||
#confirmPassInput="ngModel" size="36"
|
||||
(input)='handleValidation("confirmPassword", false)'
|
||||
(focusout)='handleValidation("confirmPassword", true)'>
|
||||
(blur)='handleValidation("confirmPassword", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.CONFIRM_PWD' | translate}}
|
||||
</span>
|
||||
@ -77,7 +77,7 @@
|
||||
<label for="comment" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("comment")'>
|
||||
<input type="text" #commentInput="ngModel" name="comment" [(ngModel)]="newUser.comment" maxLengthExt="20" id="comment" size="36"
|
||||
(input)='handleValidation("comment", false)'
|
||||
(focusout)='handleValidation("comment", true)'>
|
||||
(blur)='handleValidation("comment", true)'>
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.COMMENT' | translate}}
|
||||
</span>
|
||||
|
Loading…
Reference in New Issue
Block a user