mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-30 14:13:43 +01:00
Complete account settings component
This commit is contained in:
parent
d8047740ea
commit
9126ee1258
@ -1,32 +1,49 @@
|
|||||||
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalSize]="'lg'">
|
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalSize]="'lg'">
|
||||||
<h3 class="modal-title">Accout Settings</h3>
|
<h3 class="modal-title">Accout Settings</h3>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form>
|
<form #accountSettingsFrom="ngForm" class="form">
|
||||||
<section class="form-block">
|
<section class="form-block">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="account_settings_username" class="col-md-4">Username</label>
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="account_settings_email" class="col-md-4">Email</label>
|
<label for="account_settings_email" class="col-md-4 required">Email</label>
|
||||||
<input type="text" class="col-md-8" id="account_settings_email" size="20">
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="account_settings_full_name" class="col-md-4">Full name</label>
|
<label for="account_settings_full_name" class="col-md-4 required">Full name</label>
|
||||||
<input type="text" class="col-md-8" id="account_settings_full_name" size="20">
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="account_settings_comments" class="col-md-4">Comments</label>
|
<label for="account_settings_comments" class="col-md-4">Comments</label>
|
||||||
<input type="text" class="col-md-8" id="account_settings_comments" size="20">
|
<input type="text" name="account_settings_comments" [(ngModel)]="account.comment" id="account_settings_comments" size="51">
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button type="button" class="col-md-4" class="btn btn-outline">Change Password</button>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</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>
|
||||||
<div class="modal-footer">
|
<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-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>
|
</div>
|
||||||
</clr-modal>
|
</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({
|
@Component({
|
||||||
selector: "account-settings-modal",
|
selector: "account-settings-modal",
|
||||||
templateUrl: "account-settings-modal.component.html"
|
templateUrl: "account-settings-modal.component.html"
|
||||||
})
|
})
|
||||||
|
|
||||||
export class AccountSettingsModalComponent{
|
export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
|
||||||
opened:boolean = false;
|
opened: boolean = false;
|
||||||
staticBackdrop: boolean = true;
|
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() {
|
open() {
|
||||||
|
this.account = Object.assign({}, this.session.getCurrentUser());
|
||||||
|
this.formValueChanged = false;
|
||||||
|
|
||||||
this.opened = true;
|
this.opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,8 +66,27 @@ export class AccountSettingsModalComponent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
console.info("ok here!");
|
if (!this.isValid || this.isOnCalling) {
|
||||||
this.close();
|
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;
|
user_id: number;
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
role_name: string;
|
realname: string;
|
||||||
role_id: number;
|
role_name?: string;
|
||||||
has_admin_role: number;
|
role_id?: number;
|
||||||
|
has_admin_role?: number;
|
||||||
|
comment: string;
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ import { SessionUser } from './session-user';
|
|||||||
|
|
||||||
const currentUserEndpint = "/api/users/current";
|
const currentUserEndpint = "/api/users/current";
|
||||||
const signOffEndpoint = "/log_out";
|
const signOffEndpoint = "/log_out";
|
||||||
|
const accountEndpoint = "/api/users/:id";
|
||||||
/**
|
/**
|
||||||
* Define related methods to handle account and session corresponding things
|
* Define related methods to handle account and session corresponding things
|
||||||
*
|
*
|
||||||
@ -62,4 +63,29 @@ export class SessionService {
|
|||||||
return Promise.reject(error);
|
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 { SessionService } from '../shared/session.service';
|
||||||
import { MessageComponent } from '../global-message/message.component';
|
import { MessageComponent } from '../global-message/message.component';
|
||||||
import { MessageService } from '../global-message/message.service';
|
import { MessageService } from '../global-message/message.service';
|
||||||
|
import { MaxLengthExtValidatorDirective } from './max-length-ext.directive';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -12,12 +13,14 @@ import { MessageService } from '../global-message/message.service';
|
|||||||
AccountModule
|
AccountModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
MessageComponent
|
MessageComponent,
|
||||||
|
MaxLengthExtValidatorDirective
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
CoreModule,
|
CoreModule,
|
||||||
AccountModule,
|
AccountModule,
|
||||||
MessageComponent
|
MessageComponent,
|
||||||
|
MaxLengthExtValidatorDirective
|
||||||
],
|
],
|
||||||
providers: [SessionService, MessageService]
|
providers: [SessionService, MessageService]
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user