mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
Merge pull request #1408 from vmware/feature/account-settings
Complete account settings component
This commit is contained in:
commit
d000fe2914
@ -1,32 +1,49 @@
|
||||
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title">Accout Settings</h3>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<form #accountSettingsFrom="ngForm" class="form">
|
||||
<section class="form-block">
|
||||
<div class="form-group">
|
||||
<label for="account_settings_username" class="col-md-4">Username</label>
|
||||
<input type="text" class="col-md-8" id="account_settings_username" size="20">
|
||||
<input type="text" name="account_settings_username" [(ngModel)]="account.username" disabled id="account_settings_username" size="51">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="account_settings_email" class="col-md-4">Email</label>
|
||||
<input type="text" class="col-md-8" id="account_settings_email" size="20">
|
||||
<label for="account_settings_email" class="col-md-4 required">Email</label>
|
||||
<label for="account_settings_email" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-right" [class.invalid]="eamilInput.invalid && (eamilInput.dirty || eamilInput.touched)">
|
||||
<input name="account_settings_email" type="text" #eamilInput="ngModel" [(ngModel)]="account.email"
|
||||
required
|
||||
pattern='^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$' id="account_settings_email" size="48">
|
||||
<span class="tooltip-content">
|
||||
Email should be a valid email address like name@example.com
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="account_settings_full_name" class="col-md-4">Full name</label>
|
||||
<input type="text" class="col-md-8" id="account_settings_full_name" size="20">
|
||||
<label for="account_settings_full_name" class="col-md-4 required">Full name</label>
|
||||
<label for="account_settings_email" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-right" [class.invalid]="fullNameInput.invalid && (fullNameInput.dirty || fullNameInput.touched)">
|
||||
<input type="text" name="account_settings_full_name" #fullNameInput="ngModel" [(ngModel)]="account.realname" required maxLength="20" maxLengthExt="20" id="account_settings_full_name" size="48">
|
||||
<span class="tooltip-content">
|
||||
Max length of full name is 20
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="account_settings_comments" class="col-md-4">Comments</label>
|
||||
<input type="text" class="col-md-8" id="account_settings_comments" size="20">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="col-md-4" class="btn btn-outline">Change Password</button>
|
||||
<input type="text" name="account_settings_comments" [(ngModel)]="account.comment" id="account_settings_comments" size="51">
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
<clr-alert [clrAlertType]="'alert-danger'" [clrAlertClosable]="true" [hidden]='errorMessage === ""'>
|
||||
<div class="alert-item">
|
||||
<span class="alert-text">
|
||||
This alert indicates success.
|
||||
</span>
|
||||
</div>
|
||||
</clr-alert>
|
||||
</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()">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" (click)="submit()">Ok</button>
|
||||
<button type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="submit()">Ok</button>
|
||||
</div>
|
||||
</clr-modal>
|
@ -1,15 +1,63 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit, ViewChild, AfterViewChecked } from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
|
||||
import { SessionUser } from '../../shared/session-user';
|
||||
import { SessionService } from '../../shared/session.service';
|
||||
|
||||
@Component({
|
||||
selector: "account-settings-modal",
|
||||
templateUrl: "account-settings-modal.component.html"
|
||||
})
|
||||
|
||||
export class AccountSettingsModalComponent{
|
||||
opened:boolean = false;
|
||||
export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
|
||||
opened: boolean = false;
|
||||
staticBackdrop: boolean = true;
|
||||
account: SessionUser;
|
||||
error: any;
|
||||
|
||||
private isOnCalling: boolean = false;
|
||||
private formValueChanged: boolean = false;
|
||||
|
||||
accountFormRef: NgForm;
|
||||
@ViewChild("accountSettingsFrom") accountForm: NgForm;
|
||||
|
||||
constructor(private session: SessionService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
//Value copy
|
||||
this.account = Object.assign({}, this.session.getCurrentUser());
|
||||
}
|
||||
|
||||
public get isValid(): boolean {
|
||||
return this.accountForm && this.accountForm.valid;
|
||||
}
|
||||
|
||||
public get showProgress(): boolean {
|
||||
return this.isOnCalling;
|
||||
}
|
||||
|
||||
public get errorMessage(): string {
|
||||
return this.error ? (this.error.message ? this.error.message : this.error) : "";
|
||||
}
|
||||
|
||||
ngAfterViewChecked(): void {
|
||||
if (this.accountFormRef != this.accountForm) {
|
||||
this.accountFormRef = this.accountForm;
|
||||
if (this.accountFormRef) {
|
||||
this.accountFormRef.valueChanges.subscribe(data => {
|
||||
if (this.error) {
|
||||
this.error = null;
|
||||
}
|
||||
this.formValueChanged = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
this.account = Object.assign({}, this.session.getCurrentUser());
|
||||
this.formValueChanged = false;
|
||||
|
||||
this.opened = true;
|
||||
}
|
||||
|
||||
@ -18,8 +66,27 @@ export class AccountSettingsModalComponent{
|
||||
}
|
||||
|
||||
submit() {
|
||||
console.info("ok here!");
|
||||
this.close();
|
||||
if (!this.isValid || this.isOnCalling) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Double confirm session is valid
|
||||
let cUser = this.session.getCurrentUser();
|
||||
if (!cUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isOnCalling = true;
|
||||
|
||||
this.session.updateAccountSettings(this.account)
|
||||
.then(() => {
|
||||
this.isOnCalling = false;
|
||||
this.close();
|
||||
})
|
||||
.catch(error => {
|
||||
this.isOnCalling = false;
|
||||
this.error = error
|
||||
});
|
||||
}
|
||||
|
||||
}
|
51
harbor-app/src/app/shared/max-length-ext.directive.ts
Normal file
51
harbor-app/src/app/shared/max-length-ext.directive.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { Directive, OnChanges, Input, SimpleChanges } from '@angular/core';
|
||||
import { ValidatorFn, AbstractControl, Validator, NG_VALIDATORS, Validators } from '@angular/forms';
|
||||
|
||||
export const assiiChars = /[\u4e00-\u9fa5]/;
|
||||
|
||||
export function maxLengthExtValidator(length: number): ValidatorFn {
|
||||
return (control: AbstractControl): { [key: string]: any } => {
|
||||
const value: string = control.value
|
||||
if (!value || value.trim() === "") {
|
||||
return { 'maxLengthExt': 0 };
|
||||
}
|
||||
|
||||
const regExp = new RegExp(assiiChars, 'i');
|
||||
let count = 0;
|
||||
let len = value.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (regExp.test(value[i])) {
|
||||
count += 2;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count > length ? { 'maxLengthExt': count } : null;
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: '[maxLengthExt]',
|
||||
providers: [{ provide: NG_VALIDATORS, useExisting: MaxLengthExtValidatorDirective, multi: true }]
|
||||
})
|
||||
|
||||
export class MaxLengthExtValidatorDirective implements Validator, OnChanges {
|
||||
@Input() maxLengthExt: number;
|
||||
private valFn = Validators.nullValidator;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const change = changes['maxLengthExt'];
|
||||
if (change) {
|
||||
const val: number = change.currentValue;
|
||||
this.valFn = maxLengthExtValidator(val);
|
||||
} else {
|
||||
this.valFn = Validators.nullValidator;
|
||||
}
|
||||
console.info(changes, this.maxLengthExt);
|
||||
}
|
||||
|
||||
validate(control: AbstractControl): { [key: string]: any } {
|
||||
return this.valFn(control);
|
||||
}
|
||||
}
|
@ -3,7 +3,9 @@ export class SessionUser {
|
||||
user_id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
role_name: string;
|
||||
role_id: number;
|
||||
has_admin_role: number;
|
||||
realname: string;
|
||||
role_name?: string;
|
||||
role_id?: number;
|
||||
has_admin_role?: number;
|
||||
comment: string;
|
||||
}
|
@ -6,6 +6,7 @@ import { SessionUser } from './session-user';
|
||||
|
||||
const currentUserEndpint = "/api/users/current";
|
||||
const signOffEndpoint = "/log_out";
|
||||
const accountEndpoint = "/api/users/:id";
|
||||
/**
|
||||
* Define related methods to handle account and session corresponding things
|
||||
*
|
||||
@ -62,4 +63,29 @@ export class SessionService {
|
||||
return Promise.reject(error);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Update accpunt settings
|
||||
*
|
||||
* @param {SessionUser} account
|
||||
* @returns {Promise<any>}
|
||||
*
|
||||
* @memberOf SessionService
|
||||
*/
|
||||
updateAccountSettings(account: SessionUser): Promise<any>{
|
||||
if(!account){
|
||||
return Promise.reject("Invalid account settings");
|
||||
}
|
||||
console.info(account);
|
||||
let putUrl = accountEndpoint.replace(":id", account.user_id+"");
|
||||
return this.http.put(putUrl, JSON.stringify(account), { headers: this.headers }).toPromise()
|
||||
.then(() => {
|
||||
//Retrieve current session user
|
||||
return this.retrieveUser();
|
||||
})
|
||||
.catch(error => {
|
||||
return Promise.reject(error);
|
||||
})
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import { AccountModule } from '../account/account.module';
|
||||
import { SessionService } from '../shared/session.service';
|
||||
import { MessageComponent } from '../global-message/message.component';
|
||||
import { MessageService } from '../global-message/message.service';
|
||||
import { MaxLengthExtValidatorDirective } from './max-length-ext.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -12,12 +13,14 @@ import { MessageService } from '../global-message/message.service';
|
||||
AccountModule
|
||||
],
|
||||
declarations: [
|
||||
MessageComponent
|
||||
MessageComponent,
|
||||
MaxLengthExtValidatorDirective
|
||||
],
|
||||
exports: [
|
||||
CoreModule,
|
||||
AccountModule,
|
||||
MessageComponent
|
||||
MessageComponent,
|
||||
MaxLengthExtValidatorDirective
|
||||
],
|
||||
providers: [SessionService, MessageService]
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user