diff --git a/src/ui_ng/src/app/account/password/password-setting.component.ts b/src/ui_ng/src/app/account/password/password-setting.component.ts index 38b3c191c..614231d2c 100644 --- a/src/ui_ng/src/app/account/password/password-setting.component.ts +++ b/src/ui_ng/src/app/account/password/password-setting.component.ts @@ -65,10 +65,13 @@ export class PasswordSettingComponent implements AfterViewChecked { let cont = this.pwdForm.controls[key]; if (cont) { this.validationStateMap[key] = cont.valid; - if (key === "reNewPassword" && cont.valid) { - let compareCont = this.pwdForm.controls["newPassword"]; - if (compareCont) { - this.validationStateMap[key] = cont.value === compareCont.value; + if (cont.valid) { + if (key === "reNewPassword" || key === "newPassword") { + let cpKey = key === "reNewPassword" ? "newPassword" : "reNewPassword"; + let compareCont = this.pwdForm.controls[cpKey]; + if (compareCont && compareCont.valid) { + this.validationStateMap["reNewPassword"] = cont.value === compareCont.value; + } } } } diff --git a/src/ui_ng/src/app/account/password/reset-password.component.ts b/src/ui_ng/src/app/account/password/reset-password.component.ts index df0a12ab5..c30732992 100644 --- a/src/ui_ng/src/app/account/password/reset-password.component.ts +++ b/src/ui_ng/src/app/account/password/reset-password.component.ts @@ -74,7 +74,7 @@ export class ResetPasswordComponent implements OnInit { } public close(): void { - //If already reset password ok, navigator to sign-in + //If already reset password ok, navigator to sign-in if (this.resetOk) { this.router.navigateByUrl(CommonRoutes.EMBEDDED_SIGN_IN); } @@ -114,7 +114,10 @@ export class ResetPasswordComponent implements OnInit { this.validationState[key] = true; } } else { - this.validationState[key] = this.getControlValidationState(key) + this.validationState[key] = this.getControlValidationState(key); + if (this.validationState[key]) { + this.validationState["reNewPassword"] = this.samePassword(); + } } } diff --git a/src/ui_ng/src/app/account/sign-in/sign-in.component.css b/src/ui_ng/src/app/account/sign-in/sign-in.component.css index d288cb98f..47c1f9d49 100644 --- a/src/ui_ng/src/app/account/sign-in/sign-in.component.css +++ b/src/ui_ng/src/app/account/sign-in/sign-in.component.css @@ -38,6 +38,6 @@ .more-info-link { position: relative; - top: 100px; + top: 90px; left: 330px; } \ No newline at end of file diff --git a/src/ui_ng/src/app/base/harbor-shell/harbor-shell.component.css b/src/ui_ng/src/app/base/harbor-shell/harbor-shell.component.css index aee1769b8..bb817a7e2 100644 --- a/src/ui_ng/src/app/base/harbor-shell/harbor-shell.component.css +++ b/src/ui_ng/src/app/base/harbor-shell/harbor-shell.component.css @@ -9,6 +9,7 @@ .start-content-padding { padding: 0px !important; background-color: white; + overflow-y: hidden !important; } .content-area-override { diff --git a/src/ui_ng/src/app/base/navigator/navigator.component.ts b/src/ui_ng/src/app/base/navigator/navigator.component.ts index ff58b090e..420cdca55 100644 --- a/src/ui_ng/src/app/base/navigator/navigator.component.ts +++ b/src/ui_ng/src/app/base/navigator/navigator.component.ts @@ -27,7 +27,7 @@ export class NavigatorComponent implements OnInit { private selectedLang: string = enLang; private appTitle: string = 'APP_TITLE.HARBOR'; - + constructor( private session: SessionService, private router: Router, @@ -36,8 +36,8 @@ export class NavigatorComponent implements OnInit { private appConfigService: AppConfigService, private msgHandler: MessageHandlerService, private searchTrigger: SearchTriggerService) { - - } + + } ngOnInit(): void { this.selectedLang = this.translate.currentLang; @@ -80,8 +80,8 @@ export class NavigatorComponent implements OnInit { public get canChangePassword(): boolean { return this.session.getCurrentUser() && - this.appConfigService.getConfig() && - this.appConfigService.getConfig().auth_mode != 'ldap_auth'; + this.appConfigService.getConfig() && + this.appConfigService.getConfig().auth_mode != 'ldap_auth'; } matchLang(lang: string): boolean { @@ -114,16 +114,14 @@ export class NavigatorComponent implements OnInit { //Log out system logOut(): void { - this.session.signOff() - .then(() => { - //Naviagte to the sign in route - this.router.navigate([CommonRoutes.EMBEDDED_SIGN_IN]); - }) - .catch(error => { - this.msgHandler.handleError(error); - }); + //Naviagte to the sign in route + //Appending 'signout' means destroy session cache + let navigatorExtra: NavigationExtras = { + queryParams: { "signout": true } + }; + this.router.navigate([CommonRoutes.EMBEDDED_SIGN_IN], navigatorExtra); //Confirm search result panel is close - this.searchTrigger.closeSearch(true); + this.searchTrigger.closeSearch(true); } //Switch languages @@ -135,7 +133,7 @@ export class NavigatorComponent implements OnInit { //TODO: console.error('Language ' + lang.trim() + ' is not suppoted'); } - setTimeout(()=>{ + setTimeout(() => { window.location.reload(); }, 500); } diff --git a/src/ui_ng/src/app/project/project.component.html b/src/ui_ng/src/app/project/project.component.html index 6dc92b80b..22332d4e5 100644 --- a/src/ui_ng/src/app/project/project.component.html +++ b/src/ui_ng/src/app/project/project.component.html @@ -1,8 +1,10 @@
-

{{'PROJECT.PROJECTS' | translate}}

-
- +
+

{{'PROJECT.PROJECTS' | translate}}

+
+ +
diff --git a/src/ui_ng/src/app/project/project.component.ts b/src/ui_ng/src/app/project/project.component.ts index 70e740276..fb32fce99 100644 --- a/src/ui_ng/src/app/project/project.component.ts +++ b/src/ui_ng/src/app/project/project.component.ts @@ -25,6 +25,7 @@ import { State } from 'clarity-angular'; import { AppConfigService } from '../app-config.service'; import { SessionService } from '../shared/session.service'; import { ProjectTypes } from '../shared/shared.const'; +import { StatisticHandler } from '../shared/statictics/statistic-handler.service'; @Component({ selector: 'project', @@ -61,7 +62,8 @@ export class ProjectComponent implements OnInit, OnDestroy { private messageHandlerService: MessageHandlerService, private appConfigService: AppConfigService, private sessionService: SessionService, - private deletionDialogService: ConfirmationDialogService) { + private deletionDialogService: ConfirmationDialogService, + private statisticHandler: StatisticHandler) { this.subscription = deletionDialogService.confirmationConfirm$.subscribe(message => { if (message && message.state === ConfirmationState.CONFIRMED && @@ -72,8 +74,8 @@ export class ProjectComponent implements OnInit, OnDestroy { .subscribe( response => { this.messageHandlerService.showSuccess('PROJECT.DELETED_SUCCESS'); - console.log('Successful delete project with ID:' + projectId); this.retrieve(); + this.statisticHandler.refresh(); }, error =>{ if(error && error.status === 412) { @@ -123,7 +125,6 @@ export class ProjectComponent implements OnInit, OnDestroy { response => { this.totalRecordCount = response.headers.get('x-total-count'); this.totalPage = Math.ceil(this.totalRecordCount / this.pageSize); - console.log('TotalRecordCount:' + this.totalRecordCount + ', totalPage:' + this.totalPage); this.changedProjects = response.json(); }, error => this.messageHandlerService.handleError(error) @@ -138,17 +139,16 @@ export class ProjectComponent implements OnInit, OnDestroy { if (created) { this.projectName = ''; this.retrieve(); + this.statisticHandler.refresh(); } } doSearchProjects(projectName: string): void { - console.log('Search for project name:' + projectName); this.projectName = projectName; this.retrieve(); } doFilterProjects(filteredType: number): void { - console.log('Filter projects with type:' + this.projectTypes[filteredType]); this.isPublic = filteredType; this.currentFilteredType = filteredType; this.retrieve(); @@ -162,7 +162,7 @@ export class ProjectComponent implements OnInit, OnDestroy { .subscribe( response => { this.messageHandlerService.showSuccess('PROJECT.TOGGLED_SUCCESS'); - console.log('Successful toggled project_id:' + p.project_id); + this.statisticHandler.refresh(); }, error => this.messageHandlerService.handleError(error) ); @@ -182,6 +182,7 @@ export class ProjectComponent implements OnInit, OnDestroy { refresh(): void { this.retrieve(); + this.statisticHandler.refresh(); } } \ No newline at end of file diff --git a/src/ui_ng/src/app/replication/destination/destination.component.ts b/src/ui_ng/src/app/replication/destination/destination.component.ts index 6fa72e37e..a64684d6b 100644 --- a/src/ui_ng/src/app/replication/destination/destination.component.ts +++ b/src/ui_ng/src/app/replication/destination/destination.component.ts @@ -42,7 +42,6 @@ export class DestinationComponent implements OnInit { .subscribe( response => { this.messageHandlerService.showSuccess('DESTINATION.DELETED_SUCCESS'); - console.log('Successful deleted target with ID:' + targetId); this.reload(); }, error => { @@ -51,7 +50,6 @@ export class DestinationComponent implements OnInit { } else { this.messageHandlerService.handleError(error); } - console.log('Failed to delete target with ID:' + targetId + ', error:' + error); }); } }); diff --git a/src/ui_ng/src/app/replication/replication.component.ts b/src/ui_ng/src/app/replication/replication.component.ts index e1151e9d2..b743634b3 100644 --- a/src/ui_ng/src/app/replication/replication.component.ts +++ b/src/ui_ng/src/app/replication/replication.component.ts @@ -90,7 +90,6 @@ export class ReplicationComponent implements OnInit { ngOnInit(): void { this.projectId = +this.route.snapshot.parent.params['id']; - console.log('Get projectId from route params snapshot:' + this.projectId); this.search = new SearchOption(); this.currentRuleStatus = this.ruleStatus[0]; this.currentJobStatus = this.jobStatus[0]; @@ -125,13 +124,11 @@ export class ReplicationComponent implements OnInit { } openModal(): void { - console.log('Open modal to create policy.'); this.createEditPolicyComponent.openCreateEditPolicy(true); } openEditPolicy(policy: Policy) { if(policy) { - console.log('Open modal to edit policy ID:' + policy.id); let editable = true; if(policy.enabled === 1) { editable = false; diff --git a/src/ui_ng/src/app/replication/replication.service.ts b/src/ui_ng/src/app/replication/replication.service.ts index 1b823ec1f..7274ebd7b 100644 --- a/src/ui_ng/src/app/replication/replication.service.ts +++ b/src/ui_ng/src/app/replication/replication.service.ts @@ -19,7 +19,6 @@ export class ReplicationService { if(!projectId) { projectId = ''; } - console.log('Get policies with project ID:' + projectId + ', policy name:' + policyName); return this.http .get(`/api/policies/replication?project_id=${projectId}&name=${policyName}`) .map(response=>response.json() as Policy[]) @@ -27,7 +26,6 @@ export class ReplicationService { } getPolicy(policyId: number): Observable { - console.log('Get policy with ID:' + policyId); return this.http .get(`/api/policies/replication/${policyId}`) .map(response=>response.json() as Policy) @@ -35,7 +33,6 @@ export class ReplicationService { } createPolicy(policy: Policy): Observable { - console.log('Create policy with project ID:' + policy.project_id + ', policy:' + JSON.stringify(policy)); return this.http .post(`/api/policies/replication`, JSON.stringify(policy)) .map(response=>response.status) @@ -107,7 +104,6 @@ export class ReplicationService { // /api/jobs/replication/?page=1&page_size=20&end_time=&policy_id=1&start_time=&status=&repository= listJobs(policyId: number, status: string = '', repoName: string = '', startTime: string = '', endTime: string = '', page: number, pageSize: number): Observable { - console.log('Get jobs under policy ID:' + policyId); return this.http .get(`/api/jobs/replication?policy_id=${policyId}&status=${status}&repository=${repoName}&start_time=${startTime}&end_time=${endTime}&page=${page}&page_size=${pageSize}`) .map(response=>response) @@ -115,7 +111,6 @@ export class ReplicationService { } listTargets(targetName: string): Observable { - console.log('Get targets.'); return this.http .get(`/api/targets?name=${targetName}`) .map(response=>response.json() as Target[]) @@ -123,7 +118,6 @@ export class ReplicationService { } listTargetPolicies(targetId: number): Observable { - console.log('List target with policy.'); return this.http .get(`/api/targets/${targetId}/policies`) .map(response=>response.json() as Policy[]) @@ -131,7 +125,6 @@ export class ReplicationService { } getTarget(targetId: number): Observable { - console.log('Get target by ID:' + targetId); return this.http .get(`/api/targets/${targetId}`) .map(response=>response.json() as Target) @@ -139,7 +132,6 @@ export class ReplicationService { } createTarget(target: Target): Observable { - console.log('Create target:' + JSON.stringify(target)); return this.http .post(`/api/targets`, JSON.stringify(target)) .map(response=>response.status) @@ -147,7 +139,6 @@ export class ReplicationService { } pingTarget(target: Target): Observable { - console.log('Ping target.'); let body = new URLSearchParams(); body.set('endpoint', target.endpoint); body.set('username', target.username); @@ -159,7 +150,6 @@ export class ReplicationService { } updateTarget(target: Target): Observable { - console.log('Update target with target ID' + target.id); return this.http .put(`/api/targets/${target.id}`, JSON.stringify(target)) .map(response=>response.status) @@ -167,7 +157,6 @@ export class ReplicationService { } deleteTarget(targetId: number): Observable { - console.log('Deleting target with ID:' + targetId); return this.http .delete(`/api/targets/${targetId}`) .map(response=>response.status) diff --git a/src/ui_ng/src/app/replication/total-replication/total-replication.component.ts b/src/ui_ng/src/app/replication/total-replication/total-replication.component.ts index 07a26ce46..e9156e040 100644 --- a/src/ui_ng/src/app/replication/total-replication/total-replication.component.ts +++ b/src/ui_ng/src/app/replication/total-replication/total-replication.component.ts @@ -50,7 +50,6 @@ export class TotalReplicationComponent implements OnInit { openEditPolicy(policy: Policy) { if(policy) { - console.log('Open modal to edit policy ID:' + policy.id); let editable = true; if(policy.enabled === 1) { editable = false; diff --git a/src/ui_ng/src/app/shared/gauge/gauge.component.ts b/src/ui_ng/src/app/shared/gauge/gauge.component.ts index cdde6616c..398c3e4e3 100644 --- a/src/ui_ng/src/app/shared/gauge/gauge.component.ts +++ b/src/ui_ng/src/app/shared/gauge/gauge.component.ts @@ -154,7 +154,6 @@ export class GaugeComponent implements AfterViewInit { @ViewChild('barTwo') private barTwo: ElementRef; private determineColors() { - console.info(this._used, this._threasHold); let percent: number = 0; if (this._threasHold !== 0) { percent = (this._used / this._threasHold) * 100; diff --git a/src/ui_ng/src/app/shared/new-user-form/new-user-form.component.ts b/src/ui_ng/src/app/shared/new-user-form/new-user-form.component.ts index 77fbdcdff..d536c26e7 100644 --- a/src/ui_ng/src/app/shared/new-user-form/new-user-form.component.ts +++ b/src/ui_ng/src/app/shared/new-user-form/new-user-form.component.ts @@ -142,10 +142,11 @@ export class NewUserFormComponent implements AfterViewChecked, OnInit { } //Check password confirmation - if (key === "confirmPassword") { - let peerCont = this.newUserForm.controls["newPassword"]; - if (peerCont) { - this.validationStateMap[key] = cont.value === peerCont.value; + if (key === "confirmPassword" || key === "newPassword") { + let cpKey = key === "confirmPassword" ? "newPassword" : "confirmPassword"; + let peerCont = this.newUserForm.controls[cpKey]; + if (peerCont && peerCont.valid) { + this.validationStateMap["confirmPassword"] = cont.value === peerCont.value; } } } diff --git a/src/ui_ng/src/app/shared/route/auth-user-activate.service.ts b/src/ui_ng/src/app/shared/route/auth-user-activate.service.ts index 74898bbd2..8ed218e11 100644 --- a/src/ui_ng/src/app/shared/route/auth-user-activate.service.ts +++ b/src/ui_ng/src/app/shared/route/auth-user-activate.service.ts @@ -36,7 +36,6 @@ export class AuthCheckGuard implements CanActivate, CanActivateChild { //When routing change, clear this.msgHandler.clear(); this.searchTrigger.closeSearch(true); - return new Promise((resolve, reject) => { //Before activating, we firstly need to confirm whether the route is coming from peer part - admiral let queryParams = route.queryParams; diff --git a/src/ui_ng/src/app/shared/route/sign-in-guard-activate.service.ts b/src/ui_ng/src/app/shared/route/sign-in-guard-activate.service.ts index 18d0400ee..b4358cb22 100644 --- a/src/ui_ng/src/app/shared/route/sign-in-guard-activate.service.ts +++ b/src/ui_ng/src/app/shared/route/sign-in-guard-activate.service.ts @@ -15,19 +15,33 @@ export class SignInGuard implements CanActivate, CanActivateChild { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise | boolean { //If user has logged in, should not login again return new Promise((resolve, reject) => { - let user = this.authService.getCurrentUser(); - if (user === null) { - this.authService.retrieveUser() + //If signout appended + let queryParams = route.queryParams; + if (queryParams && queryParams['signout']) { + this.authService.signOff() .then(() => { - this.router.navigate([CommonRoutes.HARBOR_DEFAULT]); - return resolve(false); + this.authService.clear();//Destroy session cache + return resolve(true); }) .catch(error => { - return resolve(true); + console.error(error); + return resolve(false); }); } else { - this.router.navigate([CommonRoutes.HARBOR_DEFAULT]); - return resolve(false); + let user = this.authService.getCurrentUser(); + if (user === null) { + this.authService.retrieveUser() + .then(() => { + this.router.navigate([CommonRoutes.HARBOR_DEFAULT]); + return resolve(false); + }) + .catch(error => { + return resolve(true); + }); + } else { + this.router.navigate([CommonRoutes.HARBOR_DEFAULT]); + return resolve(false); + } } }); } diff --git a/src/ui_ng/src/app/shared/session.service.ts b/src/ui_ng/src/app/shared/session.service.ts index 10e53cc10..c1baaeba4 100644 --- a/src/ui_ng/src/app/shared/session.service.ts +++ b/src/ui_ng/src/app/shared/session.service.ts @@ -93,7 +93,7 @@ export class SessionService { return this.http.get(signOffEndpoint, { headers: this.headers }).toPromise() .then(() => { //Destroy current session cache - this.currentUser = null; + //this.currentUser = null; }) //Nothing returned .catch(error => this.handleError(error)) } diff --git a/src/ui_ng/src/app/shared/shared.module.ts b/src/ui_ng/src/app/shared/shared.module.ts index b3806a7cc..f1804fff0 100644 --- a/src/ui_ng/src/app/shared/shared.module.ts +++ b/src/ui_ng/src/app/shared/shared.module.ts @@ -40,6 +40,7 @@ import { ListRepositoryROComponent } from './list-repository-ro/list-repository- import { MessageHandlerService } from './message-handler/message-handler.service'; import { EmailValidatorDirective } from './email.directive'; import { GaugeComponent } from './gauge/gauge.component'; +import { StatisticHandler } from './statictics/statistic-handler.service'; @NgModule({ imports: [ @@ -97,7 +98,8 @@ import { GaugeComponent } from './gauge/gauge.component'; SignInGuard, LeavingConfigRouteDeactivate, MemberGuard, - MessageHandlerService + MessageHandlerService, + StatisticHandler ] }) export class SharedModule { diff --git a/src/ui_ng/src/app/shared/statictics/statistic-handler.service.ts b/src/ui_ng/src/app/shared/statictics/statistic-handler.service.ts new file mode 100644 index 000000000..f22bf64f8 --- /dev/null +++ b/src/ui_ng/src/app/shared/statictics/statistic-handler.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +@Injectable() +export class StatisticHandler { + + private refreshSource = new Subject(); + + refreshChan$ = this.refreshSource.asObservable(); + + refresh() { + this.refreshSource.next(true); + } +} \ No newline at end of file diff --git a/src/ui_ng/src/app/shared/statictics/statistics-panel.component.ts b/src/ui_ng/src/app/shared/statictics/statistics-panel.component.ts index c2cfe37dd..c428fc583 100644 --- a/src/ui_ng/src/app/shared/statictics/statistics-panel.component.ts +++ b/src/ui_ng/src/app/shared/statictics/statistics-panel.component.ts @@ -1,4 +1,5 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, OnDestroy } from '@angular/core'; +import { Subscription } from 'rxjs/Subscription'; import { StatisticsService } from './statistics.service'; import { Statistics } from './statistics'; @@ -7,6 +8,7 @@ import { SessionService } from '../session.service'; import { Volumes } from './volumes'; import { MessageHandlerService } from '../message-handler/message-handler.service'; +import { StatisticHandler } from './statistic-handler.service'; @Component({ selector: 'statistics-panel', @@ -15,26 +17,40 @@ import { MessageHandlerService } from '../message-handler/message-handler.servic providers: [StatisticsService] }) -export class StatisticsPanelComponent implements OnInit { +export class StatisticsPanelComponent implements OnInit, OnDestroy { private originalCopy: Statistics = new Statistics(); private volumesInfo: Volumes = new Volumes(); + refreshSub: Subscription; constructor( private statistics: StatisticsService, private msgHandler: MessageHandlerService, - private session: SessionService) { } + private session: SessionService, + private statisticHandler: StatisticHandler) { + } ngOnInit(): void { + //Refresh + this.refreshSub = this.statisticHandler.refreshChan$.subscribe(clear => { + this.getStatistics(); + }); + if (this.session.getCurrentUser()) { this.getStatistics(); } - + if (this.isValidSession) { this.getVolumes(); } } + ngOnDestroy() { + if (this.refreshSub) { + this.refreshSub.unsubscribe(); + } + } + public get totalStorage(): number { return this.getGBFromBytes(this.volumesInfo.storage.total); } diff --git a/src/ui_ng/src/app/shared/statictics/statistics.component.css b/src/ui_ng/src/app/shared/statictics/statistics.component.css index 0d1f120de..989a14db0 100644 --- a/src/ui_ng/src/app/shared/statictics/statistics.component.css +++ b/src/ui_ng/src/app/shared/statictics/statistics.component.css @@ -10,7 +10,7 @@ .statistic-data { font-size: 16px; font-weight: 900; - font-family: "Metropolis Semibold"; + font-family: 'Metropolis,"Avenir Next","Helvetica Neue",Arial,sans-serif'; line-height: 16px; } @@ -18,7 +18,7 @@ font-size: 10px; line-height: 10px; text-transform: uppercase; - font-family: "Metropolis Regular"; + font-family: 'Metropolis,"Avenir Next","Helvetica Neue",Arial,sans-serif'; } .statistic-column-block { @@ -30,7 +30,7 @@ position: relative; text-transform: uppercase; font-size: 14px; - font-family: "Metropolis Regular"; + font-family: 'Metropolis,"Avenir Next","Helvetica Neue",Arial,sans-serif'; } .statistic-column-title-pro { diff --git a/src/ui_ng/src/index.html b/src/ui_ng/src/index.html index 0d977b6c1..53dc44c22 100644 --- a/src/ui_ng/src/index.html +++ b/src/ui_ng/src/index.html @@ -10,7 +10,11 @@ - Loading... + +
+ Loading... +
+
\ No newline at end of file diff --git a/src/ui_ng/src/styles.css b/src/ui_ng/src/styles.css index e69de29bb..a2f595bf9 100644 --- a/src/ui_ng/src/styles.css +++ b/src/ui_ng/src/styles.css @@ -0,0 +1,9 @@ +.app-loading { + position: absolute; + top: 50%; + left: 50%; + margin-top: -54px; + margin-left: -54px; + width: 108px !important; + height: 108px !important; +} \ No newline at end of file