diff --git a/src/portal/src/app/base/account-settings/account-settings-modal.component.html b/src/portal/src/app/base/account-settings/account-settings-modal.component.html
index 81d9b3255..fa66164af 100644
--- a/src/portal/src/app/base/account-settings/account-settings-modal.component.html
+++ b/src/portal/src/app/base/account-settings/account-settings-modal.component.html
@@ -93,7 +93,7 @@
-
diff --git a/src/portal/src/app/base/account-settings/account-settings-modal.component.ts b/src/portal/src/app/base/account-settings/account-settings-modal.component.ts
index a3fcc1f7b..3dc54ce3f 100644
--- a/src/portal/src/app/base/account-settings/account-settings-modal.component.ts
+++ b/src/portal/src/app/base/account-settings/account-settings-modal.component.ts
@@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { ChangeDetectorRef } from '@angular/core';
-import { Component, OnInit, ViewChild, AfterViewChecked } from "@angular/core";
+import { AfterViewChecked, Component, OnInit, ViewChild } from "@angular/core";
import { NgForm } from "@angular/forms";
-import { Router, NavigationExtras } from "@angular/router";
+import { NavigationExtras, Router } from "@angular/router";
import { SessionUser } from "../../shared/entities/session-user";
import { SessionService } from "../../shared/services/session.service";
import { MessageHandlerService } from "../../shared/services/message-handler.service";
@@ -30,229 +29,235 @@ import { InlineAlertComponent } from "../../shared/components/inline-alert/inlin
import { ConfirmationMessage } from "../global-confirmation-dialog/confirmation-message";
@Component({
- selector: "account-settings-modal",
- templateUrl: "account-settings-modal.component.html",
- styleUrls: ["./account-settings-modal.component.scss", "../../common.scss"]
+ selector: "account-settings-modal",
+ templateUrl: "account-settings-modal.component.html",
+ styleUrls: ["./account-settings-modal.component.scss", "../../common.scss"]
})
export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
- opened = false;
- staticBackdrop = true;
- originalStaticData: SessionUser;
- account: SessionUser;
- error: any = null;
- emailTooltip = "TOOLTIP.EMAIL";
- mailAlreadyChecked = {};
- isOnCalling = false;
- formValueChanged = false;
- checkOnGoing = false;
- RenameOnGoing = false;
- originAdminName = "admin";
- newAdminName = "admin@harbor.local";
- renameConfirmation = false;
- showSecretDetail = false;
- resetForms = new ResetSecret();
- showGenerateCli: boolean = false;
- @ViewChild("confirmationDialog")
- confirmationDialogComponent: ConfirmationDialogComponent;
+ opened = false;
+ staticBackdrop = true;
+ originalStaticData: SessionUser;
+ account: SessionUser;
+ error: any = null;
+ emailTooltip = "TOOLTIP.EMAIL";
+ mailAlreadyChecked = {};
+ isOnCalling = false;
+ formValueChanged = false;
+ checkOnGoing = false;
+ RenameOnGoing = false;
+ originAdminName = "admin";
+ newAdminName = "admin@harbor.local";
+ renameConfirmation = false;
+ showSecretDetail = false;
+ resetForms = new ResetSecret();
+ showGenerateCli: boolean = false;
+ @ViewChild("confirmationDialog")
+ confirmationDialogComponent: ConfirmationDialogComponent;
- accountFormRef: NgForm;
- @ViewChild("accountSettingsFrom", {static: true}) accountForm: NgForm;
- @ViewChild("resetSecretFrom", {static: true}) resetSecretFrom: NgForm;
- @ViewChild("accountSettingInlineAlert") inlineAlert: InlineAlertComponent;
- @ViewChild("resetSecretInlineAlert") resetSecretInlineAlert: InlineAlertComponent;
- @ViewChild("copyInput") copyInput: CopyInputComponent;
- showInputSecret: boolean = false;
- showConfirmSecret: boolean = false;
- constructor(
- private session: SessionService,
- private msgHandler: MessageHandlerService,
- private router: Router,
- private searchTrigger: SearchTriggerService,
- private accountSettingsService: AccountSettingsModalService,
- private ref: ChangeDetectorRef
- ) {}
+ accountFormRef: NgForm;
+ @ViewChild("accountSettingsFrom", {static: true}) accountForm: NgForm;
+ @ViewChild("resetSecretFrom", {static: true}) resetSecretFrom: NgForm;
+ @ViewChild("accountSettingInlineAlert") inlineAlert: InlineAlertComponent;
+ @ViewChild("resetSecretInlineAlert") resetSecretInlineAlert: InlineAlertComponent;
+ @ViewChild("copyInput") copyInput: CopyInputComponent;
+ showInputSecret: boolean = false;
+ showConfirmSecret: boolean = false;
- private validationStateMap: any = {
- account_settings_email: true,
- account_settings_full_name: true
- };
- ngOnInit(): void {
- // Value copy
- this.account = Object.assign({}, this.session.getCurrentUser());
- this.originalStaticData = Object.assign({}, this.session.getCurrentUser());
- }
-
- 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;
- if (this.account.username === this.originAdminName) {
- this.inlineAlert.close();
- }
- });
- }
+ constructor(
+ private session: SessionService,
+ private msgHandler: MessageHandlerService,
+ private router: Router,
+ private searchTrigger: SearchTriggerService,
+ private accountSettingsService: AccountSettingsModalService,
+ ) {
}
- }
- getValidationState(key: string): boolean {
- return this.validationStateMap[key];
- }
+ private validationStateMap: any = {
+ account_settings_email: true,
+ account_settings_full_name: true
+ };
- handleValidation(key: string, flag: boolean): void {
- if (flag) {
- // Checking
- let cont = this.accountForm.controls[key];
- if (cont) {
- this.validationStateMap[key] = cont.valid;
- // Check email existing from backend
- if (cont.valid && key === "account_settings_email") {
- if (
- this.formValueChanged &&
- this.account.email !== this.originalStaticData.email
- ) {
- if (this.mailAlreadyChecked[this.account.email]) {
- this.validationStateMap[key] = !this.mailAlreadyChecked[
- this.account.email
- ].result;
- if (!this.validationStateMap[key]) {
- this.emailTooltip = "TOOLTIP.EMAIL_EXISTING";
- }
- return;
+ ngOnInit(): void {
+ this.refreshAccount();
+ }
+
+ refreshAccount() {
+ // Value copy
+ this.account = Object.assign({}, this.session.getCurrentUser());
+ this.originalStaticData = Object.assign({}, this.session.getCurrentUser());
+ }
+
+ 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;
+ if (this.account.username === this.originAdminName) {
+ this.inlineAlert.close();
+ }
+ });
}
+ }
+ }
- // Mail changed
- this.checkOnGoing = true;
- this.session
- .checkUserExisting("email", this.account.email)
- .subscribe((res: boolean) => {
- this.checkOnGoing = false;
- this.validationStateMap[key] = !res;
- if (res) {
- this.emailTooltip = "TOOLTIP.EMAIL_EXISTING";
+ getValidationState(key: string): boolean {
+ return this.validationStateMap[key];
+ }
+
+ handleValidation(key: string, flag: boolean): void {
+ if (flag) {
+ // Checking
+ let cont = this.accountForm.controls[key];
+ if (cont) {
+ this.validationStateMap[key] = cont.valid;
+ // Check email existing from backend
+ if (cont.valid && key === "account_settings_email") {
+ if (
+ this.formValueChanged &&
+ this.account.email !== this.originalStaticData.email
+ ) {
+ if (this.mailAlreadyChecked[this.account.email]) {
+ this.validationStateMap[key] = !this.mailAlreadyChecked[
+ this.account.email
+ ].result;
+ if (!this.validationStateMap[key]) {
+ this.emailTooltip = "TOOLTIP.EMAIL_EXISTING";
+ }
+ return;
+ }
+
+ // Mail changed
+ this.checkOnGoing = true;
+ this.session
+ .checkUserExisting("email", this.account.email)
+ .subscribe((res: boolean) => {
+ this.checkOnGoing = false;
+ this.validationStateMap[key] = !res;
+ if (res) {
+ this.emailTooltip = "TOOLTIP.EMAIL_EXISTING";
+ }
+ this.mailAlreadyChecked[this.account.email] = {
+ result: res
+ }; // Tag it checked
+ }, error => {
+ this.checkOnGoing = false;
+ this.validationStateMap[key] = false; // Not valid @ backend
+ });
+ }
}
- this.mailAlreadyChecked[this.account.email] = {
- result: res
- }; // Tag it checked
- }, error => {
- this.checkOnGoing = false;
- this.validationStateMap[key] = false; // Not valid @ backend
- });
- }
- }
- }
- } else {
- // Reset
- this.validationStateMap[key] = true;
- this.emailTooltip = "TOOLTIP.EMAIL";
- }
- }
-
- isUserDataChange(): boolean {
- if (!this.originalStaticData || !this.account) {
- return false;
- }
- for (let prop in this.originalStaticData) {
- if (this.originalStaticData[prop] !== this.account[prop]) {
- return true;
- }
- }
- return false;
- }
-
- public get isValid(): boolean {
- return (
- this.accountForm &&
- this.accountForm.valid &&
- this.error === null &&
- this.validationStateMap["account_settings_email"]
- ); // backend check is valid as well
- }
-
- public get showProgress(): boolean {
- return this.isOnCalling;
- }
-
- public get checkProgress(): boolean {
- return this.checkOnGoing;
- }
-
- public get canRename(): boolean {
- return (
- this.account &&
- this.account.has_admin_role &&
- this.originalStaticData.username === "admin" &&
- this.account.user_id === 1
- );
- }
-
- onRename(): void {
- this.account.username = this.newAdminName;
- this.RenameOnGoing = true;
- }
-
- confirmRename(): void {
- if (this.canRename) {
- this.session
- .updateAccountSettings(this.account)
- .subscribe(() => {
- this.session.renameAdmin(this.account)
- .subscribe(() => {
- this.msgHandler.showSuccess("PROFILE.RENAME_SUCCESS");
- this.opened = false;
- this.logOut();
- }, error => {
- this.msgHandler.handleError(error);
- });
- }, error => {
- this.isOnCalling = false;
- this.error = error;
- if (this.msgHandler.isAppLevel(error)) {
- this.opened = false;
- this.msgHandler.handleError(error);
+ }
} else {
- this.inlineAlert.showInlineError(error);
+ // Reset
+ this.validationStateMap[key] = true;
+ this.emailTooltip = "TOOLTIP.EMAIL";
}
- });
}
- }
- // Log out system
- logOut(): void {
- // Naviagte to the sign in router-guard
- // 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);
- }
+ isUserDataChange(): boolean {
+ if (!this.originalStaticData || !this.account) {
+ return false;
+ }
+ for (let prop in this.originalStaticData) {
+ if (this.originalStaticData[prop] !== this.account[prop]) {
+ return true;
+ }
+ }
+ return false;
+ }
- open() {
- // Keep the initial data for future diff
- this.originalStaticData = Object.assign({}, this.session.getCurrentUser());
- this.account = Object.assign({}, this.session.getCurrentUser());
- this.formValueChanged = false;
+ public get isValid(): boolean {
+ return (
+ this.accountForm &&
+ this.accountForm.valid &&
+ this.error === null &&
+ this.validationStateMap["account_settings_email"]
+ ); // backend check is valid as well
+ }
- // Confirm inline alert is closed
- this.inlineAlert.close();
+ public get showProgress(): boolean {
+ return this.isOnCalling;
+ }
- // Clear check history
- this.mailAlreadyChecked = {};
+ public get checkProgress(): boolean {
+ return this.checkOnGoing;
+ }
- // Reset validation status
- this.validationStateMap = {
- account_settings_email: true,
- account_settings_full_name: true
- };
- this.showGenerateCli = false;
- this.opened = true;
- }
+ public get canRename(): boolean {
+ return (
+ this.account &&
+ this.account.has_admin_role &&
+ this.originalStaticData.username === "admin" &&
+ this.account.user_id === 1
+ );
+ }
+
+ onRename(): void {
+ this.account.username = this.newAdminName;
+ this.RenameOnGoing = true;
+ }
+
+ confirmRename(): void {
+ if (this.canRename) {
+ this.session
+ .updateAccountSettings(this.account)
+ .subscribe(() => {
+ this.session.renameAdmin(this.account)
+ .subscribe(() => {
+ this.msgHandler.showSuccess("PROFILE.RENAME_SUCCESS");
+ this.opened = false;
+ this.logOut();
+ }, error => {
+ this.msgHandler.handleError(error);
+ });
+ }, error => {
+ this.isOnCalling = false;
+ this.error = error;
+ if (this.msgHandler.isAppLevel(error)) {
+ this.opened = false;
+ this.msgHandler.handleError(error);
+ } else {
+ this.inlineAlert.showInlineError(error);
+ }
+ });
+ }
+ }
+
+ // Log out system
+ logOut(): void {
+ // Naviagte to the sign in router-guard
+ // 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);
+ }
+
+ open() {
+ // Keep the initial data for future diff
+ this.originalStaticData = Object.assign({}, this.session.getCurrentUser());
+ this.account = Object.assign({}, this.session.getCurrentUser());
+ this.formValueChanged = false;
+
+ // Confirm inline alert is closed
+ this.inlineAlert.close();
+
+ // Clear check history
+ this.mailAlreadyChecked = {};
+
+ // Reset validation status
+ this.validationStateMap = {
+ account_settings_email: true,
+ account_settings_full_name: true
+ };
+ this.showGenerateCli = false;
+ this.opened = true;
+ }
close() {
if (this.formValueChanged) {
@@ -304,6 +309,10 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
this.isOnCalling = false;
this.opened = false;
this.msgHandler.showSuccess("PROFILE.SAVE_SUCCESS");
+ // get user info from back-end then refresh account
+ this.session.retrieveUser().subscribe(() => {
+ this.refreshAccount();
+ });
}, error => {
this.isOnCalling = false;
this.error = error;
@@ -317,68 +326,77 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
}
}
- confirmNo($event: any): void {
- if (this.RenameOnGoing) {
- this.RenameOnGoing = false;
+ confirmNo($event: any): void {
+ if (this.RenameOnGoing) {
+ this.RenameOnGoing = false;
+ }
+ if (this.renameConfirmation) {
+ this.renameConfirmation = false;
+ }
}
- if (this.renameConfirmation) {
- this.renameConfirmation = false;
- }
- }
- confirmYes($event: any): void {
- if (this.RenameOnGoing) {
- this.RenameOnGoing = false;
- }
- if (this.renameConfirmation) {
- this.renameConfirmation = false;
- }
- this.inlineAlert.close();
- this.opened = false;
- }
- onSuccess(event) {
- this.inlineAlert.showInlineSuccess({message: 'PROFILE.COPY_SUCCESS'});
- }
- onError(event) {
- this.inlineAlert.showInlineError({message: 'PROFILE.COPY_ERROR'});
- }
- generateCli(userId): void {
- let generateCliMessage = new ConfirmationMessage(
- 'PROFILE.CONFIRM_TITLE_CLI_GENERATE',
- 'PROFILE.CONFIRM_BODY_CLI_GENERATE',
- '',
- userId,
- ConfirmationTargets.TARGET,
- ConfirmationButtons.CONFIRM_CANCEL);
- this.confirmationDialogComponent.open(generateCliMessage);
- }
- showGenerateCliFn() {
- this.showGenerateCli = !this.showGenerateCli;
- }
- confirmGenerate(event): void {
- this.account.oidc_user_meta.secret = randomWord(9);
- this.resetCliSecret(this.account.oidc_user_meta.secret);
- }
- resetCliSecret(secret) {
- let userId = this.account.user_id;
- this.accountSettingsService.saveNewCli(userId, {secret: secret}).subscribe(cliSecret => {
- this.account.oidc_user_meta.secret = secret;
- this.closeReset();
- this.inlineAlert.showInlineSuccess({message: 'PROFILE.GENERATE_SUCCESS'});
- }, error => {
- this.resetSecretInlineAlert.showInlineError({message: 'PROFILE.GENERATE_ERROR'});
- });
- }
- disableChangeCliSecret() {
- return this.resetSecretFrom.invalid || (this.resetSecretFrom.value.input_secret !== this.resetSecretFrom.value.confirm_secret);
- }
- closeReset() {
- this.showSecretDetail = false;
- this.showGenerateCliFn();
- this.resetSecretFrom.resetForm(new ResetSecret());
- }
- openSecretDetail() {
- this.showSecretDetail = true;
- this.resetSecretInlineAlert.close();
- }
+ confirmYes($event: any): void {
+ if (this.RenameOnGoing) {
+ this.RenameOnGoing = false;
+ }
+ if (this.renameConfirmation) {
+ this.renameConfirmation = false;
+ }
+ this.inlineAlert.close();
+ this.opened = false;
+ }
+
+ onSuccess(event) {
+ this.inlineAlert.showInlineSuccess({message: 'PROFILE.COPY_SUCCESS'});
+ }
+
+ onError(event) {
+ this.inlineAlert.showInlineError({message: 'PROFILE.COPY_ERROR'});
+ }
+
+ generateCli(userId): void {
+ let generateCliMessage = new ConfirmationMessage(
+ 'PROFILE.CONFIRM_TITLE_CLI_GENERATE',
+ 'PROFILE.CONFIRM_BODY_CLI_GENERATE',
+ '',
+ userId,
+ ConfirmationTargets.TARGET,
+ ConfirmationButtons.CONFIRM_CANCEL);
+ this.confirmationDialogComponent.open(generateCliMessage);
+ }
+
+ showGenerateCliFn() {
+ this.showGenerateCli = !this.showGenerateCli;
+ }
+
+ confirmGenerate(event): void {
+ this.account.oidc_user_meta.secret = randomWord(9);
+ this.resetCliSecret(this.account.oidc_user_meta.secret);
+ }
+
+ resetCliSecret(secret) {
+ let userId = this.account.user_id;
+ this.accountSettingsService.saveNewCli(userId, {secret: secret}).subscribe(cliSecret => {
+ this.account.oidc_user_meta.secret = secret;
+ this.closeReset();
+ this.inlineAlert.showInlineSuccess({message: 'PROFILE.GENERATE_SUCCESS'});
+ }, error => {
+ this.resetSecretInlineAlert.showInlineError({message: 'PROFILE.GENERATE_ERROR'});
+ });
+ }
+
+ disableChangeCliSecret() {
+ return this.resetSecretFrom.invalid || (this.resetSecretFrom.value.input_secret !== this.resetSecretFrom.value.confirm_secret);
+ }
+
+ closeReset() {
+ this.showSecretDetail = false;
+ this.showGenerateCliFn();
+ this.resetSecretFrom.resetForm(new ResetSecret());
+ }
+
+ openSecretDetail() {
+ this.showSecretDetail = true;
+ this.resetSecretInlineAlert.close();
+ }
}
diff --git a/src/portal/src/app/shared/services/session.service.ts b/src/portal/src/app/shared/services/session.service.ts
index 659fe93ea..f5db71220 100644
--- a/src/portal/src/app/shared/services/session.service.ts
+++ b/src/portal/src/app/shared/services/session.service.ts
@@ -35,7 +35,7 @@ const signOffEndpoint = "/c/log_out";
const accountEndpoint = CURRENT_BASE_HREF + "/users/:id";
const langEndpoint = "/language";
const userExistsEndpoint = "/c/userExists";
-const renameAdminEndpoint = CURRENT_BASE_HREF + '/internal/renameadmin';
+const renameAdminEndpoint = 'api/internal/renameadmin';
const langMap = {
"zh": "zh-CN",
"en": "en-US"