From 846d690b85c650b5bd60bdec5a3c4f45f3ccd976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E4=B8=96=E5=86=9B?= <30999793+AllForNothing@users.noreply.github.com> Date: Wed, 1 Dec 2021 10:07:46 +0800 Subject: [PATCH] Refactor config component (#16064) Signed-off-by: AllForNothing --- .../config/auth/config-auth.component.html | 4 +- .../config/auth/config-auth.component.spec.ts | 72 +++----- .../config/auth/config-auth.component.ts | 59 +++---- .../config/config.component.html | 38 ++-- .../config/config.component.spec.ts | 93 +++------- .../left-side-nav/config/config.component.ts | 144 +-------------- .../left-side-nav/config/config.module.ts | 25 ++- .../left-side-nav/config/config.msg.utils.ts | 22 --- .../config/config.service.spec.ts | 41 +++++ .../left-side-nav/config/config.service.ts | 102 +++++++++++ .../config/email/config-email.component.html | 4 +- .../email/config-email.component.spec.ts | 32 +++- .../config/email/config-email.component.ts | 46 ++--- .../system/system-settings.component.html | 20 +-- .../system/system-settings.component.spec.ts | 42 ++++- .../system/system-settings.component.ts | 166 ++++++------------ 16 files changed, 416 insertions(+), 494 deletions(-) delete mode 100644 src/portal/src/app/base/left-side-nav/config/config.msg.utils.ts create mode 100644 src/portal/src/app/base/left-side-nav/config/config.service.spec.ts create mode 100644 src/portal/src/app/base/left-side-nav/config/config.service.ts diff --git a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html index 727511161..62a18bc8c 100644 --- a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html +++ b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html @@ -443,9 +443,9 @@
+ [disabled]="!isValid() || !hasChanges() || inProcess()">{{'BUTTON.SAVE' | translate}} + [disabled]="!isValid() || !hasChanges() || inProcess()">{{'BUTTON.CANCEL' | translate}} diff --git a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.spec.ts b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.spec.ts index 715979873..72aadffc1 100644 --- a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.spec.ts @@ -1,17 +1,16 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service'; -import { ConfirmMessageHandler } from '../config.msg.utils'; import { AppConfigService } from '../../../../services/app-config.service'; import { ConfigurationService } from '../../../../services/config.service'; import { ConfigurationAuthComponent } from './config-auth.component'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { FormsModule } from '@angular/forms'; import { of } from 'rxjs'; -import { ErrorHandler } from "../../../../shared/units/error-handler"; import { SystemInfoService } from "../../../../shared/services"; import { clone } from '../../../../shared/units/utils'; import { CONFIG_AUTH_MODE } from '../../../../shared/entities/shared.const'; +import { ConfigService } from "../config.service"; +import { Configuration } from '../config'; +import { SharedTestingModule } from "../../../../shared/shared.module"; describe('ConfigurationAuthComponent', () => { let component: ConfigurationAuthComponent; @@ -27,7 +26,25 @@ describe('ConfigurationAuthComponent', () => { let fakeAppConfigService = { load: () => of(null) }; - let fakeConfirmMessageService = null; + const fakeConfigService = { + config: new Configuration(), + getConfig() { + return this.config; + }, + setConfig(c) { + this.config = c; + }, + getOriginalConfig() { + return new Configuration(); + }, + getLoadingConfigStatus() { + return false; + }, + updateConfig() { + }, + resetConfig() { + } + }; let fakeSystemInfoService = { getSystemInfo: function () { return of({ @@ -39,17 +56,14 @@ describe('ConfigurationAuthComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ - TranslateModule.forRoot(), - FormsModule + SharedTestingModule ], declarations: [ConfigurationAuthComponent], providers: [ - ErrorHandler, - TranslateService, { provide: MessageHandlerService, useValue: fakeMessageHandlerService }, { provide: ConfigurationService, useValue: fakeConfigurationService }, { provide: AppConfigService, useValue: fakeAppConfigService }, - { provide: ConfirmMessageHandler, useValue: fakeConfirmMessageService }, + { provide: ConfigService, useValue: fakeConfigService }, { provide: SystemInfoService, useValue: fakeSystemInfoService } ], schemas: [CUSTOM_ELEMENTS_SCHEMA] @@ -59,46 +73,10 @@ describe('ConfigurationAuthComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ConfigurationAuthComponent); component = fixture.componentInstance; - (component as any).originalConfig = clone(component.currentConfig); - fixture.autoDetectChanges(); + fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); - - it('should save configuration', async () => { - const selfRegInput: HTMLInputElement = fixture.nativeElement.querySelector("#selfReg"); - selfRegInput.dispatchEvent(new Event('click')); - component.currentConfig.self_registration.value = true; - await fixture.whenStable(); - const configAuthSaveBtn: HTMLButtonElement = fixture.nativeElement.querySelector("#config_auth_save"); - component.onGoing = true; - configAuthSaveBtn.dispatchEvent(new Event('click')); - await fixture.whenStable(); - expect(component.onGoing).toBeFalsy(); - }); - it('should select ldap or uaa', () => { - component.handleOnChange({target: {value: 'ldap_auth'}}); - expect(component.currentConfig.self_registration.value).toEqual(false); - }); - it('should ping test server when ldap', async () => { - component.currentConfig.auth_mode.value = CONFIG_AUTH_MODE.LDAP_AUTH; - component.currentConfig.ldap_scope.value = 123456; - await fixture.whenStable(); - const pingTestBtn = fixture.nativeElement.querySelector("#ping-test"); - expect(pingTestBtn).toBeTruthy(); - pingTestBtn.dispatchEvent(new Event('click')); - await fixture.whenStable(); - expect(component.testingOnGoing).toBeFalsy(); - }); - it('should ping test server when oidc', async () => { - component.currentConfig.auth_mode.value = CONFIG_AUTH_MODE.OIDC_AUTH; - await fixture.whenStable(); - const pingTestBtn = fixture.nativeElement.querySelector("#ping-test"); - expect(pingTestBtn).toBeTruthy(); - pingTestBtn.dispatchEvent(new Event('click')); - await fixture.whenStable(); - expect(component.testingOnGoing).toBeFalsy(); - }); }); diff --git a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.ts b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.ts index 31eff8f9c..79f16e811 100644 --- a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.ts +++ b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.ts @@ -11,68 +11,60 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, ViewChild, SimpleChanges, OnChanges, OnInit, Output, EventEmitter } from '@angular/core'; +import { Component, ViewChild, OnInit } from '@angular/core'; import { NgForm } from '@angular/forms'; -import { Subscription } from "rxjs"; import { MessageHandlerService } from '../../../../shared/services/message-handler.service'; -import { ConfirmMessageHandler } from '../config.msg.utils'; import { AppConfigService } from '../../../../services/app-config.service'; import { ConfigurationService } from '../../../../services/config.service'; -import { ErrorHandler } from "../../../../shared/units/error-handler"; import { SystemInfoService } from "../../../../shared/services"; -import { clone, isEmpty, getChanges as getChangesFunc } from "../../../../shared/units/utils"; +import { isEmpty, getChanges as getChangesFunc } from "../../../../shared/units/utils"; import { CONFIG_AUTH_MODE } from "../../../../shared/entities/shared.const"; import { errorHandler } from "../../../../shared/units/shared.utils"; import { Configuration } from "../config"; import { finalize } from "rxjs/operators"; -const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; +import { ConfigService } from "../config.service"; @Component({ selector: 'config-auth', templateUrl: 'config-auth.component.html', styleUrls: ['./config-auth.component.scss', '../config.component.scss'] }) -export class ConfigurationAuthComponent implements OnChanges, OnInit { - changeSub: Subscription; +export class ConfigurationAuthComponent implements OnInit { testingOnGoing = false; onGoing = false; redirectUrl: string; - // tslint:disable-next-line:no-input-rename - @Input('allConfig') currentConfig: Configuration = new Configuration(); - private originalConfig: Configuration; @ViewChild('authConfigFrom') authForm: NgForm; - @Output() refreshAllconfig = new EventEmitter(); + + get currentConfig(): Configuration { + return this.conf.getConfig(); + } + + set currentConfig(c: Configuration) { + this.conf.setConfig(c); + } constructor( private msgHandler: MessageHandlerService, private configService: ConfigurationService, private appConfigService: AppConfigService, - private confirmMessageHandler: ConfirmMessageHandler, + private conf: ConfigService, private systemInfo: SystemInfoService, - private errorHandlerEntity: ErrorHandler, ) { } ngOnInit() { + this.conf.resetConfig(); this.getSystemInfo(); } getSystemInfo(): void { this.systemInfo.getSystemInfo() .subscribe(systemInfo => (this.redirectUrl = systemInfo.external_url) - , error => this.errorHandlerEntity.error(error)); + , error => this.msgHandler.error(error)); } get checkable() { return this.currentConfig && this.currentConfig.self_registration && this.currentConfig.self_registration.value === true; } - - ngOnChanges(changes: SimpleChanges): void { - if (changes && changes["currentConfig"]) { - this.originalConfig = clone(this.currentConfig); - - } - } - public get showLdap(): boolean { return this.currentConfig && this.currentConfig.auth_mode && @@ -99,11 +91,15 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit { } } - public isValid(): boolean { + isValid(): boolean { return this.authForm && this.authForm.valid; } - public hasChanges(): boolean { + inProcess(): boolean { + return this.onGoing || this.conf.getLoadingConfigStatus(); + } + + hasChanges(): boolean { return !isEmpty(this.getChanges()); } @@ -168,7 +164,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit { this.msgHandler.showSuccess('CONFIG.TEST_OIDC_SUCCESS'); }, error => { this.testingOnGoing = false; - this.errorHandlerEntity.error(error); + this.msgHandler.error(error); }); } } @@ -180,12 +176,15 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit { } public isConfigValidForTesting(): boolean { + if (!this.authForm || !this.currentConfig) { + return true; + } return this.isValid() && - !this.testingOnGoing; + !this.testingOnGoing && !this.inProcess(); } public getChanges() { - let allChanges = getChangesFunc(this.originalConfig, this.currentConfig); + let allChanges = getChangesFunc(this.conf.getOriginalConfig(), this.currentConfig); let changes = {}; for (let prop in allChanges) { if (prop.startsWith('ldap_') @@ -235,7 +234,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit { this.configService.saveConfiguration(changes) .subscribe(response => { this.onGoing = false; - this.refreshAllconfig.emit(); + this.conf.updateConfig(); // Reload bootstrap option this.appConfigService.load().subscribe(() => { } , error => console.error('Failed to reload bootstrap option with error: ', error)); @@ -259,7 +258,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit { public cancel(): void { let changes = this.getChanges(); if (!isEmpty(changes)) { - this.confirmMessageHandler.confirmUnsavedChanges(changes); + this.conf.confirmUnsavedChanges(changes); } else { // Invalid situation, should not come here console.error('Nothing changed'); diff --git a/src/portal/src/app/base/left-side-nav/config/config.component.html b/src/portal/src/app/base/left-side-nav/config/config.component.html index 785fe7274..49034ab6c 100644 --- a/src/portal/src/app/base/left-side-nav/config/config.component.html +++ b/src/portal/src/app/base/left-side-nav/config/config.component.html @@ -1,25 +1,23 @@

{{'CONFIG.TITLE' | translate }}

- - - - - - - - - - - - - - - - - - - - +
+ diff --git a/src/portal/src/app/base/left-side-nav/config/config.component.spec.ts b/src/portal/src/app/base/left-side-nav/config/config.component.spec.ts index 4cdac61ae..f2bde71ac 100644 --- a/src/portal/src/app/base/left-side-nav/config/config.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/config/config.component.spec.ts @@ -1,85 +1,44 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { SessionService } from '../../../shared/services/session.service'; -import { MessageHandlerService } from '../../../shared/services/message-handler.service'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { ClarityModule } from "@clr/angular"; -import { AppConfigService } from '../../../services/app-config.service'; -import { ConfigurationService } from '../../../services/config.service'; import { ConfigurationComponent } from './config.component'; -import { of } from 'rxjs'; -import { Configuration } from './config'; -import { ConfirmationState, ConfirmationTargets } from "../../../shared/entities/shared.const"; -import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service"; -import { ConfirmationAcknowledgement } from "../../global-confirmation-dialog/confirmation-state-message"; +import { SharedTestingModule } from "../../../shared/shared.module"; +import { ConfigService } from "./config.service"; +import { Configuration } from "./config"; describe('ConfigurationComponent', () => { let component: ConfigurationComponent; let fixture: ComponentFixture; - let confirmationConfirmFlag = true; - let confirmationConfirm = () => { - return confirmationConfirmFlag ? of(new ConfirmationAcknowledgement(ConfirmationState.CONFIRMED, {}, ConfirmationTargets.CONFIG)) - : of(new ConfirmationAcknowledgement(ConfirmationState.CONFIRMED - , {change: { email_password: 'Harbor12345' }, tabId: '1'}, ConfirmationTargets.CONFIG_TAB)); - }; - let fakeConfirmationDialogService = { - confirmationConfirm$: confirmationConfirm() - }; - let mockConfigurationService = { - getConfiguration: () => of(new Configuration()), - confirmationConfirm$: of(new ConfirmationAcknowledgement(ConfirmationState.CONFIRMED, {}, ConfirmationTargets.CONFIG)) - }; - let fakeSessionService = { - getCurrentUser: function () { - return { - has_admin_role: true, - user_id: 1, - username: 'admin', - email: "", - realname: "admin", - role_name: "admin", - role_id: 1, - comment: "string", - }; + const fakeConfigService = { + getConfig() { + return new Configuration(); }, - updateAccountSettings: () => of(null), - renameAdmin: () => of(null), + getOriginalConfig() { + return new Configuration(); + }, + getLoadingConfigStatus() { + return false; + }, + updateConfig() { + }, + initConfig() { + } }; + let initSpy: jasmine.Spy; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ - TranslateModule.forRoot(), - ClarityModule + SharedTestingModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [ConfigurationComponent], providers: [ - TranslateService, - { - provide: SessionService, useValue: { - getCurrentUser: function () { - return "admin"; - } - } - }, - { provide: ConfirmationDialogService, useValue: fakeConfirmationDialogService }, - { provide: SessionService, useValue: fakeSessionService }, - { provide: MessageHandlerService, useValue: null }, - { - provide: AppConfigService, useValue: { - getConfig: function () { - return { has_ca_root: true }; - } - } - }, - { - provide: ConfigurationService, useValue: mockConfigurationService - } + { provide: ConfigService, useValue: fakeConfigService }, ] }).compileComponents(); })); beforeEach(() => { + initSpy = spyOn(fakeConfigService, "initConfig").and.returnValue(undefined); fixture = TestBed.createComponent(ConfigurationComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -88,16 +47,8 @@ describe('ConfigurationComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); - it('should reset part of allConfig ', async () => { - confirmationConfirmFlag = false; - component.originalCopy.email_password.value = 'Harbor12345'; - component.reset({ - email_password: { - value: 'Harbor12345', - editable: true - } - }); + it('should init config', async () => { await fixture.whenStable(); - expect(component.allConfig.email_password.value).toEqual('Harbor12345'); + expect(initSpy.calls.count()).toEqual(1); }); }); diff --git a/src/portal/src/app/base/left-side-nav/config/config.component.ts b/src/portal/src/app/base/left-side-nav/config/config.component.ts index 0e0e25322..aa568c29b 100644 --- a/src/portal/src/app/base/left-side-nav/config/config.component.ts +++ b/src/portal/src/app/base/left-side-nav/config/config.component.ts @@ -11,155 +11,25 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; -import { Subscription } from "rxjs"; -import { SessionService } from '../../../shared/services/session.service'; -import { MessageHandlerService } from '../../../shared/services/message-handler.service'; -import { AppConfigService } from '../../../services/app-config.service'; -import { ConfigurationAuthComponent } from './auth/config-auth.component'; -import { ConfigurationEmailComponent } from './email/config-email.component'; -import { ConfigurationService } from '../../../services/config.service'; -import { Configuration, StringValueItem } from "./config"; -import { SystemSettingsComponent } from "./system/system-settings.component"; -import { clone, isEmpty } from "../../../shared/units/utils"; -import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service"; -import { ConfirmationState, ConfirmationTargets } from "../../../shared/entities/shared.const"; - -const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; -const TabLinkContentMap = { - 'config-auth': 'authentication', - 'config-replication': 'replication', - 'config-email': 'email', - 'config-system': 'system_settings', - 'config-label': 'system_label', -}; +import { Component, OnInit } from '@angular/core'; +import { ConfigService } from "./config.service"; @Component({ selector: 'config', templateUrl: 'config.component.html', styleUrls: ['config.component.scss'] }) -export class ConfigurationComponent implements OnInit, OnDestroy { - allConfig: Configuration = new Configuration(); - onGoing = false; - currentTabId = 'config-auth'; // default tab - originalCopy: Configuration = new Configuration(); - confirmSub: Subscription; - - @ViewChild(SystemSettingsComponent) systemSettingsConfig: SystemSettingsComponent; - @ViewChild(ConfigurationEmailComponent) mailConfig: ConfigurationEmailComponent; - @ViewChild(ConfigurationAuthComponent) authConfig: ConfigurationAuthComponent; - - constructor( - private msgHandler: MessageHandlerService, - private configService: ConfigurationService, - private confirmService: ConfirmationDialogService, - private appConfigService: AppConfigService, - private session: SessionService) { } - - public get hasAdminRole(): boolean { - return this.session.getCurrentUser() && - this.session.getCurrentUser().has_admin_role; +export class ConfigurationComponent implements OnInit { + get inProgress(): boolean { + return this.conf.getLoadingConfigStatus(); } - public get hasCAFile(): boolean { - return this.appConfigService.getConfig().has_ca_root; + constructor(private conf: ConfigService) { } - public get withAdmiral(): boolean { - return this.appConfigService.getConfig().with_admiral; - } - - refreshAllconfig() { - this.retrieveConfig(); - } ngOnInit(): void { // First load - // Double confirm the current use has admin role - let currentUser = this.session.getCurrentUser(); - if (currentUser && currentUser.has_admin_role) { - this.retrieveConfig(); - } - - this.confirmSub = this.confirmService.confirmationConfirm$.subscribe(confirmation => { - if (confirmation && - confirmation.state === ConfirmationState.CONFIRMED) { - if (confirmation.source === ConfirmationTargets.CONFIG) { - this.reset(confirmation.data); - } else if (confirmation.source === ConfirmationTargets.CONFIG_TAB) { - this.reset(confirmation.data['changes']); - this.currentTabId = confirmation.data['tabId']; - } - } - }); + this.conf.initConfig(); } - ngOnDestroy(): void { - if (this.confirmSub) { - this.confirmSub.unsubscribe(); - } - } - - public get inProgress(): boolean { - return this.onGoing; - } - - handleReadyOnlyChange(event) { - this.msgHandler.handleReadOnly(); - if (!event) { - this.msgHandler.clear(); - } - } - - handleAppConfig(event) { - // Reload bootstrap option - this.appConfigService.load().subscribe(() => {} - , error => console.error('Failed to reload bootstrap option with error: ', error)); - } - - retrieveConfig(): void { - this.onGoing = true; - this.configService.getConfiguration() - .subscribe((configurations: Configuration) => { - this.onGoing = false; - - // Add two password fields - configurations.email_password = new StringValueItem(fakePass, true); - configurations.ldap_search_password = new StringValueItem(fakePass, true); - configurations.uaa_client_secret = new StringValueItem(fakePass, true); - configurations.oidc_client_secret = new StringValueItem(fakePass, true); - this.allConfig = configurations; - // Keep the original copy of the data - this.originalCopy = clone(configurations); - }, error => { - this.onGoing = false; - this.msgHandler.handleError(error); - }); - } - - /** - * - * Reset the configuration form - * - * @private - * ** deprecated param {*} changes - * - * @memberOf ConfigurationComponent - */ - reset(changes: any): void { - if (!isEmpty(changes)) { - for (let prop in changes) { - if (this.originalCopy[prop]) { - this.allConfig[prop] = clone(this.originalCopy[prop]); - } - } - } else { - // force reset - this.retrieveConfig(); - } - } - - disabled(prop: any): boolean { - return !(prop && prop.editable); - } } diff --git a/src/portal/src/app/base/left-side-nav/config/config.module.ts b/src/portal/src/app/base/left-side-nav/config/config.module.ts index d1f80dad2..15555ae43 100644 --- a/src/portal/src/app/base/left-side-nav/config/config.module.ts +++ b/src/portal/src/app/base/left-side-nav/config/config.module.ts @@ -15,16 +15,35 @@ import { NgModule } from "@angular/core"; import { SharedModule } from "../../../shared/shared.module"; import { ConfigurationComponent } from "./config.component"; -import { ConfirmMessageHandler } from "./config.msg.utils"; import { ConfigurationAuthComponent } from "./auth/config-auth.component"; import { ConfigurationEmailComponent } from "./email/config-email.component"; import { SystemSettingsComponent } from "./system/system-settings.component"; import { RouterModule, Routes } from "@angular/router"; +import { ConfigService } from "./config.service"; const routes: Routes = [ { path: '', - component: ConfigurationComponent + component: ConfigurationComponent, + children: [ + { + path: 'auth', + component: ConfigurationAuthComponent + }, + { + path: 'email', + component: ConfigurationEmailComponent + }, + { + path: 'setting', + component: SystemSettingsComponent + }, + { + path: '', + redirectTo: 'auth', + pathMatch: 'full' + } + ] } ]; @NgModule({ @@ -39,7 +58,7 @@ const routes: Routes = [ SystemSettingsComponent ], providers: [ - ConfirmMessageHandler, + ConfigService, ] }) export class ConfigurationModule { diff --git a/src/portal/src/app/base/left-side-nav/config/config.msg.utils.ts b/src/portal/src/app/base/left-side-nav/config/config.msg.utils.ts deleted file mode 100644 index 6a6a87240..000000000 --- a/src/portal/src/app/base/left-side-nav/config/config.msg.utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service"; -import { ConfirmationTargets } from "../../../shared/entities/shared.const"; -import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message"; - -@Injectable() -export class ConfirmMessageHandler { - constructor(private confirmService: ConfirmationDialogService) { - } - - public confirmUnsavedChanges(changes: any) { - let msg = new ConfirmationMessage( - 'CONFIG.CONFIRM_TITLE', - 'CONFIG.CONFIRM_SUMMARY', - '', - changes, - ConfirmationTargets.CONFIG - ); - this.confirmService.openComfirmDialog(msg); - } -} - diff --git a/src/portal/src/app/base/left-side-nav/config/config.service.spec.ts b/src/portal/src/app/base/left-side-nav/config/config.service.spec.ts new file mode 100644 index 000000000..5dfc33608 --- /dev/null +++ b/src/portal/src/app/base/left-side-nav/config/config.service.spec.ts @@ -0,0 +1,41 @@ +import { TestBed, inject } from '@angular/core/testing'; +import { ConfigureService } from 'ng-swagger-gen/services/configure.service'; +import { of } from 'rxjs'; +import { SharedTestingModule } from "../../../shared/shared.module"; +import { Configuration } from './config'; +import { ConfigService } from "./config.service"; + +describe('ConfigService', () => { + const fakedConfigureService = { + getConfigurations() { + return of(null); + } + }; + let getConfigSpy: jasmine.Spy; + beforeEach(() => { + getConfigSpy = spyOn(fakedConfigureService, 'getConfigurations').and.returnValue(of(new Configuration())); + TestBed.configureTestingModule({ + imports: [ + SharedTestingModule + ], + providers: [ + ConfigService, + { provide: ConfigureService, useValue: fakedConfigureService }, + ] + }); + }); + + it('should be created', inject([ConfigService], (service: ConfigService) => { + expect(service).toBeTruthy(); + })); + + it('should init config', inject([ConfigService], (service: ConfigService) => { + expect(getConfigSpy.calls.count()).toEqual(0); + service.initConfig(); + expect(getConfigSpy.calls.count()).toEqual(1); + // only init once + service.initConfig(); + expect(getConfigSpy.calls.count()).toEqual(1); + expect(service).toBeTruthy(); + })); +}); diff --git a/src/portal/src/app/base/left-side-nav/config/config.service.ts b/src/portal/src/app/base/left-side-nav/config/config.service.ts new file mode 100644 index 000000000..4b49b5740 --- /dev/null +++ b/src/portal/src/app/base/left-side-nav/config/config.service.ts @@ -0,0 +1,102 @@ +import { Injectable } from '@angular/core'; +import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service"; +import { ConfirmationState, ConfirmationTargets } from "../../../shared/entities/shared.const"; +import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message"; +import { Configuration, StringValueItem } from "./config"; +import { ConfigureService } from 'ng-swagger-gen/services/configure.service'; +import { clone } from "../../../shared/units/utils"; +import { MessageHandlerService } from "../../../shared/services/message-handler.service"; +import { finalize } from "rxjs/operators"; +import { Subscription } from "rxjs"; + +const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; + +@Injectable() +export class ConfigService { + private _loadingConfig: boolean = false; + private _hasInit: boolean = false; + private _confirmSub: Subscription; + private _currentConfig: Configuration = new Configuration(); + private _originalConfig: Configuration; + + constructor(private confirmService: ConfirmationDialogService, + private configureService: ConfigureService, + private msgHandler: MessageHandlerService) { + this._confirmSub = this.confirmService.confirmationConfirm$.subscribe(confirmation => { + if (confirmation && + confirmation.state === ConfirmationState.CONFIRMED) { + this.resetConfig(); + } + }); + } + + getConfig(): Configuration { + return this._currentConfig; + } + + setConfig(c: Configuration) { + this._currentConfig = c; + } + + + getOriginalConfig(): Configuration { + return this._originalConfig; + } + + setOriginalConfig(c: Configuration) { + this._originalConfig = c; + } + + getLoadingConfigStatus(): boolean { + return this._loadingConfig; + } + + initConfig() { + if (!this._hasInit) { + this.updateConfig(); + this._hasInit = true; + } + } + + updateConfig() { + this._loadingConfig = true; + this.configureService.getConfigurations() + .pipe(finalize(() => this._loadingConfig = false)) + .subscribe(res => { + this._currentConfig = res as Configuration; + // Add password fields + this._currentConfig.email_password = new StringValueItem(fakePass, true); + this._currentConfig.ldap_search_password = new StringValueItem(fakePass, true); + this._currentConfig.uaa_client_secret = new StringValueItem(fakePass, true); + this._currentConfig.oidc_client_secret = new StringValueItem(fakePass, true); + // Keep the original copy of the data + this._originalConfig = clone(this._currentConfig); + // Handle read only + if (this._originalConfig?.read_only?.value) { + this.msgHandler.handleReadOnly(); + } else { + this.msgHandler.clear(); + } + }, error => { + this.msgHandler.handleError(error); + }); + } + + resetConfig() { + if (this._originalConfig) { + this._currentConfig = clone(this._originalConfig); + } + } + + confirmUnsavedChanges(changes: any) { + let msg = new ConfirmationMessage( + 'CONFIG.CONFIRM_TITLE', + 'CONFIG.CONFIRM_SUMMARY', + '', + changes, + ConfirmationTargets.CONFIG + ); + this.confirmService.openComfirmDialog(msg); + } +} + diff --git a/src/portal/src/app/base/left-side-nav/config/email/config-email.component.html b/src/portal/src/app/base/left-side-nav/config/email/config-email.component.html index 2824fa663..b758f3c53 100644 --- a/src/portal/src/app/base/left-side-nav/config/email/config-email.component.html +++ b/src/portal/src/app/base/left-side-nav/config/email/config-email.component.html @@ -76,9 +76,9 @@
- diff --git a/src/portal/src/app/base/left-side-nav/config/email/config-email.component.spec.ts b/src/portal/src/app/base/left-side-nav/config/email/config-email.component.spec.ts index e7da3538d..da38965d9 100644 --- a/src/portal/src/app/base/left-side-nav/config/email/config-email.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/config/email/config-email.component.spec.ts @@ -1,13 +1,13 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service'; -import { ConfirmMessageHandler } from '../config.msg.utils'; import { ConfigurationService } from '../../../../services/config.service'; import { ConfigurationEmailComponent } from './config-email.component'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { FormsModule } from '@angular/forms'; import { clone } from '../../../../shared/units/utils'; import { of } from 'rxjs'; +import { ConfigService } from "../config.service"; +import { SharedTestingModule } from "../../../../shared/shared.module"; +import { Configuration } from "../config"; describe('ConfigurationEmailComponent', () => { let component: ConfigurationEmailComponent; @@ -19,17 +19,34 @@ describe('ConfigurationEmailComponent', () => { let fakeMessageHandlerService = { showSuccess: () => null }; + const fakeConfigService = { + config: new Configuration(), + getConfig() { + return this.config; + }, + setConfig(c) { + this.config = c; + }, + getOriginalConfig() { + return new Configuration(); + }, + getLoadingConfigStatus() { + return false; + }, + updateConfig() { + }, + resetConfig() { + } + }; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ - TranslateModule.forRoot(), - FormsModule + SharedTestingModule ], declarations: [ConfigurationEmailComponent], providers: [ { provide: MessageHandlerService, useValue: fakeMessageHandlerService }, - TranslateService, - { provide: ConfirmMessageHandler, useValue: null }, + { provide: ConfigService, useValue: fakeConfigService }, { provide: ConfigurationService, useValue: fakeConfigurationService } ], schemas: [CUSTOM_ELEMENTS_SCHEMA] @@ -39,7 +56,6 @@ describe('ConfigurationEmailComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ConfigurationEmailComponent); component = fixture.componentInstance; - (component as any).originalConfig = clone(component.currentConfig); fixture.detectChanges(); }); diff --git a/src/portal/src/app/base/left-side-nav/config/email/config-email.component.ts b/src/portal/src/app/base/left-side-nav/config/email/config-email.component.ts index c180cbfda..072ade8d3 100644 --- a/src/portal/src/app/base/left-side-nav/config/email/config-email.component.ts +++ b/src/portal/src/app/base/left-side-nav/config/email/config-email.component.ts @@ -11,33 +11,40 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, ViewChild, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { NgForm } from '@angular/forms'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service'; -import { ConfirmMessageHandler } from '../config.msg.utils'; import { ConfigurationService } from '../../../../services/config.service'; import { Configuration } from "../config"; -import { isEmpty, getChanges as getChangesFunc, clone } from "../../../../shared/units/utils"; +import { isEmpty, getChanges as getChangesFunc } from "../../../../shared/units/utils"; import { errorHandler } from "../../../../shared/units/shared.utils"; +import { ConfigService } from "../config.service"; @Component({ selector: 'config-email', templateUrl: "config-email.component.html", styleUrls: ['./config-email.component.scss', '../config.component.scss'] }) -export class ConfigurationEmailComponent implements OnChanges { - // tslint:disable-next-line:no-input-rename - @Input("mailConfig") currentConfig: Configuration = new Configuration(); - @Output() refreshAllconfig = new EventEmitter(); - private originalConfig: Configuration; +export class ConfigurationEmailComponent implements OnInit { testingMailOnGoing = false; onGoing = false; @ViewChild("mailConfigFrom", {static: true}) mailForm: NgForm; + get currentConfig(): Configuration { + return this.conf.getConfig(); + } + + set currentConfig(c: Configuration) { + this.conf.setConfig(c); + } constructor( private msgHandler: MessageHandlerService, private configService: ConfigurationService, - private confirmMessageHandler: ConfirmMessageHandler) { + private conf: ConfigService) { + } + + ngOnInit(): void { + this.conf.resetConfig(); } disabled(prop: any): boolean { @@ -48,16 +55,20 @@ export class ConfigurationEmailComponent implements OnChanges { this.currentConfig.email_insecure.value = !$event; } - public isValid(): boolean { + isValid(): boolean { return this.mailForm && this.mailForm.valid; } + inProgress(): boolean { + return this.onGoing || this.conf.getLoadingConfigStatus(); + } + public hasChanges(): boolean { return !isEmpty(this.getChanges()); } public getChanges() { - let allChanges = getChangesFunc(this.originalConfig, this.currentConfig); + let allChanges = getChangesFunc(this.conf.getOriginalConfig(), this.currentConfig); let changes = {}; for (let prop in allChanges) { if (prop.startsWith('email_')) { @@ -66,13 +77,6 @@ export class ConfigurationEmailComponent implements OnChanges { } return changes; } - - ngOnChanges(changes: SimpleChanges): void { - if (changes && changes["currentConfig"]) { - this.originalConfig = clone(this.currentConfig); - } - } - /** * * Test the connection of specified mail server @@ -121,7 +125,7 @@ export class ConfigurationEmailComponent implements OnChanges { public isMailConfigValid(): boolean { return this.isValid() && - !this.testingMailOnGoing; + !this.testingMailOnGoing && !this.inProgress(); } /** @@ -138,7 +142,7 @@ export class ConfigurationEmailComponent implements OnChanges { .subscribe(response => { this.onGoing = false; // refresh allConfig - this.refreshAllconfig.emit(); + this.conf.updateConfig(); this.msgHandler.showSuccess('CONFIG.SAVE_SUCCESS'); }, error => { this.onGoing = false; @@ -159,7 +163,7 @@ export class ConfigurationEmailComponent implements OnChanges { public cancel(): void { let changes = this.getChanges(); if (!isEmpty(changes)) { - this.confirmMessageHandler.confirmUnsavedChanges(changes); + this.conf.confirmUnsavedChanges(changes); } else { // Invalid situation, should not come here console.error('Nothing changed'); diff --git a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html index 052da1de5..56a2ed6e7 100644 --- a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html +++ b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html @@ -1,6 +1,5 @@
- @@ -42,7 +41,7 @@ @@ -73,7 +72,7 @@ {{'CONFIG.ROOT_CERT_LINK' | translate}} - + - + @@ -162,7 +161,7 @@
- + + [disabled]="!currentConfig.notification_enable.editable" /> @@ -188,4 +187,3 @@ [disabled]="(!isValid() || !hasChanges()) && (!hasAllowlistChanged) || inProgress">{{'BUTTON.CANCEL' | translate}} - diff --git a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.spec.ts b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.spec.ts index 2cd8931da..fc9e272ca 100644 --- a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.spec.ts @@ -3,9 +3,10 @@ import { SystemSettingsComponent } from "./system-settings.component"; import { SystemInfoService } from "../../../../shared/services"; import { ErrorHandler } from "../../../../shared/units/error-handler"; import { of } from "rxjs"; -import { StringValueItem } from "../config"; -import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { Configuration, StringValueItem } from "../config"; import { SharedTestingModule } from "../../../../shared/shared.module"; +import { ConfigService } from "../config.service"; +import { AppConfigService } from "../../../../services/app-config.service"; describe('SystemSettingsComponent', () => { let component: SystemSettingsComponent; let fixture: ComponentFixture; @@ -33,13 +34,43 @@ describe('SystemSettingsComponent', () => { return null; } }; + const fakeConfigService = { + config: new Configuration(), + getConfig() { + return this.config; + }, + setConfig(c) { + this.config = c; + }, + getOriginalConfig() { + return new Configuration(); + }, + getLoadingConfigStatus() { + return false; + }, + confirmUnsavedChanges() { + }, + updateConfig() { + }, + resetConfig() { + } + }; + const fakedAppConfigService = { + getConfig() { + return {}; + }, + load() { + return of(null); + } + }; beforeEach(() => { TestBed.configureTestingModule({ imports: [ SharedTestingModule, - BrowserAnimationsModule ], providers: [ + { provide: AppConfigService, useValue: fakedAppConfigService }, + { provide: ConfigService, useValue: fakeConfigService }, { provide: ErrorHandler, useValue: fakedErrorHandler }, { provide: SystemInfoService, useValue: fakedSystemInfoService }, // open auto detect @@ -53,7 +84,7 @@ describe('SystemSettingsComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(SystemSettingsComponent); component = fixture.componentInstance; - component.config.auth_mode = new StringValueItem("db_auth", false ); + component.currentConfig.auth_mode = new StringValueItem("db_auth", false ); fixture.detectChanges(); }); @@ -61,6 +92,7 @@ describe('SystemSettingsComponent', () => { expect(component).toBeTruthy(); }); it('cancel button should works', () => { + const spy: jasmine.Spy = spyOn(fakeConfigService, 'confirmUnsavedChanges').and.returnValue(undefined); component.systemAllowlist.items.push({cve_id: 'CVE-2019-456'}); const readOnly: HTMLElement = fixture.nativeElement.querySelector('#repoReadOnly'); readOnly.click(); @@ -68,7 +100,7 @@ describe('SystemSettingsComponent', () => { const cancel: HTMLButtonElement = fixture.nativeElement.querySelector('#config_system_cancel'); cancel.click(); fixture.detectChanges(); - expect(component.confirmationDlg.opened).toBeTruthy(); + expect(spy.calls.count()).toEqual(1); }); it('save button should works', () => { component.systemAllowlist.items[0].cve_id = 'CVE-2019-789'; diff --git a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.ts b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.ts index f8ad46e5f..917c16a52 100644 --- a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.ts +++ b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.ts @@ -1,28 +1,16 @@ -import { - Component, - Input, - OnInit, - Output, - EventEmitter, - ViewChild, - OnChanges, - SimpleChanges, - ElementRef -} from '@angular/core'; -import {NgForm} from '@angular/forms'; -import {Configuration, StringValueItem} from '../config'; -import { clone, isEmpty, getChanges, compareValue, CURRENT_BASE_HREF } from '../../../../shared/units/utils'; -import {ErrorHandler} from '../../../../shared/units/error-handler'; -import {ConfirmationMessage} from '../../../global-confirmation-dialog/confirmation-message'; -import {ConfirmationDialogComponent} from '../../../../shared/components/confirmation-dialog'; -import {ConfirmationState, ConfirmationTargets} from '../../../../shared/entities/shared.const'; -import {ConfirmationAcknowledgement} from '../../../global-confirmation-dialog/confirmation-state-message'; -import { SystemCVEAllowlist, SystemInfo, SystemInfoService, -} from '../../../../shared/services'; -import {forkJoin} from "rxjs"; +import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { NgForm } from '@angular/forms'; +import { Configuration } from '../config'; +import { clone, compareValue, CURRENT_BASE_HREF, getChanges, isEmpty } from '../../../../shared/units/utils'; +import { ErrorHandler } from '../../../../shared/units/error-handler'; +import { ConfirmationState, ConfirmationTargets } from '../../../../shared/entities/shared.const'; +import { ConfirmationAcknowledgement } from '../../../global-confirmation-dialog/confirmation-state-message'; +import { SystemCVEAllowlist, SystemInfo, SystemInfoService, } from '../../../../shared/services'; +import { forkJoin } from "rxjs"; import { ConfigurationService } from "../../../../services/config.service"; +import { ConfigService } from "../config.service"; +import { AppConfigService } from "../../../../services/app-config.service"; -const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; const ONE_THOUSAND: number = 1000; const CVE_DETAIL_PRE_URL = `https://nvd.nist.gov/vuln/detail/`; const TARGET_BLANK = "_blank"; @@ -32,70 +20,58 @@ const TARGET_BLANK = "_blank"; templateUrl: './system-settings.component.html', styleUrls: ['./system-settings.component.scss'] }) -export class SystemSettingsComponent implements OnChanges, OnInit { - config: Configuration = new Configuration(); +export class SystemSettingsComponent implements OnInit { onGoing = false; - private originalConfig: Configuration; downloadLink: string; - robotTokenExpiration: string; systemAllowlist: SystemCVEAllowlist; systemAllowlistOrigin: SystemCVEAllowlist; cveIds: string; showAddModal: boolean = false; systemInfo: SystemInfo; - @Output() configChange: EventEmitter = new EventEmitter(); - @Output() readOnlyChange: EventEmitter = new EventEmitter(); - @Output() reloadSystemConfig: EventEmitter = new EventEmitter(); - - @Input() - get systemSettings(): Configuration { - return this.config; + get currentConfig(): Configuration { + return this.conf.getConfig(); } - set systemSettings(cfg: Configuration) { - this.config = cfg; - this.configChange.emit(this.config); + set currentConfig(cfg: Configuration) { + this.conf.setConfig(cfg); } - - @Input() showSubTitle: boolean = false; - @Input() hasAdminRole: boolean = false; - @Input() hasCAFile: boolean = false; - @Input() withAdmiral = false; - @ViewChild("systemConfigFrom") systemSettingsForm: NgForm; - @ViewChild("cfgConfirmationDialog") confirmationDlg: ConfirmationDialogComponent; @ViewChild('dateInput') dateInput: ElementRef; get editable(): boolean { - return this.systemSettings && - this.systemSettings.token_expiration && - this.systemSettings.token_expiration.editable; + return this.currentConfig && + this.currentConfig.token_expiration && + this.currentConfig.token_expiration.editable; } get robotExpirationEditable(): boolean { - return this.systemSettings && - this.systemSettings.robot_token_duration && - this.systemSettings.robot_token_duration.editable; + return this.currentConfig && + this.currentConfig.robot_token_duration && + this.currentConfig.robot_token_duration.editable; } get tokenExpirationValue() { - return this.systemSettings.token_expiration.value; + return this.currentConfig.token_expiration.value; } + set tokenExpirationValue(v) { // convert string to number - this.systemSettings.token_expiration.value = +v; + this.currentConfig.token_expiration.value = +v; } + get robotTokenExpirationValue() { - return this.systemSettings.robot_token_duration.value; + return this.currentConfig.robot_token_duration.value; } + set robotTokenExpirationValue(v) { // convert string to number - this.systemSettings.robot_token_duration.value = +v; + this.currentConfig.robot_token_duration.value = +v; } + robotNamePrefixEditable(): boolean { - return this.systemSettings && - this.systemSettings.robot_name_prefix && - this.systemSettings.robot_name_prefix.editable; + return this.currentConfig && + this.currentConfig.robot_name_prefix && + this.currentConfig.robot_name_prefix.editable; } public isValid(): boolean { @@ -107,19 +83,13 @@ export class SystemSettingsComponent implements OnChanges, OnInit { } public getChanges() { - let allChanges = getChanges(this.originalConfig, this.config); + let allChanges = getChanges(this.conf.getOriginalConfig(), this.currentConfig); if (allChanges) { return this.getSystemChanges(allChanges); } return null; } - ngOnChanges(changes: SimpleChanges): void { - if (changes && changes["systemSettings"]) { - this.originalConfig = clone(this.config); - } - } - public getSystemChanges(allChanges: any) { let changes = {}; for (let prop in allChanges) { @@ -132,11 +102,11 @@ export class SystemSettingsComponent implements OnChanges, OnInit { } setRepoReadOnlyValue($event: any) { - this.systemSettings.read_only.value = $event; + this.currentConfig.read_only.value = $event; } setWebhookNotificationEnabledValue($event: any) { - this.systemSettings.notification_enable.value = $event; + this.currentConfig.notification_enable.value = $event; } disabled(prop: any): boolean { @@ -144,7 +114,7 @@ export class SystemSettingsComponent implements OnChanges, OnInit { } get canDownloadCert(): boolean { - return this.hasAdminRole && this.hasCAFile; + return this.appConfigService.getConfig().has_ca_root; } /** @@ -172,12 +142,11 @@ export class SystemSettingsComponent implements OnChanges, OnInit { // To refresh the view, we can clone the original data copy // or force refresh by calling service. // HERE we choose force way - this.retrieveConfig(); - if ('read_only' in changes) { - this.readOnlyChange.emit(changes['read_only']); - } - - this.reloadSystemConfig.emit(); + this.conf.updateConfig(); + // Reload bootstrap option + this.appConfigService.load().subscribe(() => { + } + , error => console.error('Failed to reload bootstrap option with error: ', error)); } if (!compareValue(this.systemAllowlistOrigin, this.systemAllowlist)) { this.systemAllowlistOrigin = clone(this.systemAllowlist); @@ -193,40 +162,10 @@ export class SystemSettingsComponent implements OnChanges, OnInit { } } - retrieveConfig(): void { - this.onGoing = true; - this.configService.getConfiguration() - .subscribe((configurations: Configuration) => { - this.onGoing = false; - // Add two password fields - configurations.email_password = new StringValueItem(fakePass, true); - this.config = configurations; - // Keep the original copy of the data - this.originalConfig = clone(configurations); - }, error => { - this.onGoing = false; - this.errorHandler.error(error); - }); - } - - reset(changes: any): void { - if (!isEmpty(changes)) { - for (let prop in changes) { - if (this.originalConfig[prop]) { - this.config[prop] = clone(this.originalConfig[prop]); - } - } - } else { - // force reset - this.retrieveConfig(); - } - } - confirmCancel(ack: ConfirmationAcknowledgement): void { if (ack && ack.source === ConfirmationTargets.CONFIG && ack.state === ConfirmationState.CONFIRMED) { - let changes = this.getChanges(); - this.reset(changes); + this.conf.resetConfig(); if (!compareValue(this.systemAllowlistOrigin, this.systemAllowlist)) { this.systemAllowlist = clone(this.systemAllowlistOrigin); } @@ -235,7 +174,7 @@ export class SystemSettingsComponent implements OnChanges, OnInit { public get inProgress(): boolean { - return this.onGoing; + return this.onGoing || this.conf.getLoadingConfigStatus(); } /** @@ -247,28 +186,23 @@ export class SystemSettingsComponent implements OnChanges, OnInit { public cancel(): void { let changes = this.getChanges(); if (!isEmpty(changes) || !compareValue(this.systemAllowlistOrigin, this.systemAllowlist)) { - let msg = new ConfirmationMessage( - 'CONFIG.CONFIRM_TITLE', - 'CONFIG.CONFIRM_SUMMARY', - '', - {}, - ConfirmationTargets.CONFIG - ); - this.confirmationDlg.open(msg); + this.conf.confirmUnsavedChanges(changes); } else { // Invalid situation, should not come here console.error('Nothing changed'); } } - constructor( + constructor(private appConfigService: AppConfigService, private configService: ConfigurationService, private errorHandler: ErrorHandler, - private systemInfoService: SystemInfoService) { + private systemInfoService: SystemInfoService, + private conf: ConfigService) { this.downloadLink = CURRENT_BASE_HREF + "/systeminfo/getcert"; } ngOnInit() { + this.conf.resetConfig(); this.getSystemAllowlist(); this.getSystemInfo(); } @@ -278,6 +212,7 @@ export class SystemSettingsComponent implements OnChanges, OnInit { .subscribe(systemInfo => this.systemInfo = systemInfo , error => this.errorHandler.error(error)); } + getSystemAllowlist() { this.onGoing = true; this.systemInfoService.getSystemAllowlist() @@ -298,6 +233,7 @@ export class SystemSettingsComponent implements OnChanges, OnInit { } ); } + deleteItem(index: number) { this.systemAllowlist.items.splice(index, 1); }