mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 02:35:17 +01:00
refactor configuration
Signed-off-by: Meina Zhou <meinaz@vmware.com>
This commit is contained in:
parent
079059ef0c
commit
e3e15dbc65
@ -38,6 +38,25 @@ export class SystemSettingsComponent {
|
||||
return this.systemSettingsForm && this.systemSettingsForm.valid;
|
||||
}
|
||||
|
||||
public hasUnsavedChanges(allChanges: any): boolean {
|
||||
for (let prop in allChanges) {
|
||||
if (prop === 'token_expiration' || prop === 'read_only') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public getSystemChanges(allChanges: any) {
|
||||
let changes = {};
|
||||
for (let prop in allChanges) {
|
||||
if (prop === 'token_expiration' || prop === 'read_only') {
|
||||
changes[prop] = allChanges[prop];
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
setRepoReadOnlyValue($event: any) {
|
||||
this.systemSettings.read_only.value = $event;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ export * from './harbor-library.module';
|
||||
export * from './service.config';
|
||||
export * from './service/index';
|
||||
export * from './error-handler/index';
|
||||
// export * from './utils';
|
||||
export * from './utils';
|
||||
export * from './log/index';
|
||||
export * from './filter/index';
|
||||
export * from './endpoint/index';
|
||||
|
@ -295,6 +295,10 @@ export function clone(srcObj: any): any {
|
||||
return JSON.parse(JSON.stringify(srcObj));
|
||||
}
|
||||
|
||||
export function isEmpty(obj: any): boolean {
|
||||
return !obj || JSON.stringify(obj) === '{}';
|
||||
}
|
||||
|
||||
export function downloadFile(fileData) {
|
||||
let url = window.URL.createObjectURL(fileData.data);
|
||||
let a = document.createElement("a");
|
||||
@ -306,3 +310,28 @@ export function downloadFile(fileData) {
|
||||
window.URL.revokeObjectURL(url);
|
||||
a.remove();
|
||||
}
|
||||
|
||||
export function getChanges(original: any, afterChange: any): { [key: string]: any | any[] } {
|
||||
let changes: { [key: string]: any | any[] } = {};
|
||||
if (!afterChange || !original) {
|
||||
return changes;
|
||||
}
|
||||
for (let prop of Object.keys(afterChange)) {
|
||||
let field = original[prop];
|
||||
if (field && field.editable) {
|
||||
if (!compareValue(field.value, afterChange[prop].value)) {
|
||||
changes[prop] = afterChange[prop].value;
|
||||
// Number
|
||||
if (typeof field.value === 'number') {
|
||||
changes[prop] = +changes[prop];
|
||||
}
|
||||
|
||||
// Trim string value
|
||||
if (typeof field.value === 'string') {
|
||||
changes[prop] = ('' + changes[prop]).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
@ -214,4 +214,10 @@
|
||||
</clr-checkbox>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</form>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button>
|
||||
<span id="forTestingLDAP" class="spinner spinner-inline" [hidden]="hideLDAPTestingSpinner"></span>
|
||||
</div>
|
@ -11,25 +11,37 @@
|
||||
// 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 } from '@angular/core';
|
||||
import { Component, Input, ViewChild, SimpleChanges, OnChanges} from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { Subscription } from "rxjs";
|
||||
|
||||
import { Configuration } from '@harbor/ui';
|
||||
import { Configuration, clone, isEmpty, getChanges, StringValueItem} from '@harbor/ui';
|
||||
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
|
||||
import { confirmUnsavedChanges} from '../config.msg.utils';
|
||||
import { AppConfigService } from '../../app-config.service';
|
||||
import { ConfigurationService } from '../config.service';
|
||||
const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
|
||||
|
||||
@Component({
|
||||
selector: 'config-auth',
|
||||
templateUrl: 'config-auth.component.html',
|
||||
styleUrls: ['./config-auth.component.scss', '../config.component.scss']
|
||||
})
|
||||
export class ConfigurationAuthComponent {
|
||||
export class ConfigurationAuthComponent implements OnChanges {
|
||||
changeSub: Subscription;
|
||||
testingLDAPOnGoing = false;
|
||||
onGoing = false;
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('allConfig') currentConfig: Configuration = new Configuration();
|
||||
|
||||
private originalConfig: Configuration;
|
||||
@ViewChild('authConfigFrom') authForm: NgForm;
|
||||
|
||||
constructor() { }
|
||||
constructor(
|
||||
private msgHandler: MessageHandlerService,
|
||||
private configService: ConfigurationService,
|
||||
private appConfigService: AppConfigService
|
||||
) {
|
||||
}
|
||||
|
||||
get checkable() {
|
||||
return this.currentConfig &&
|
||||
@ -37,6 +49,12 @@ export class ConfigurationAuthComponent {
|
||||
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 &&
|
||||
@ -59,10 +77,82 @@ export class ConfigurationAuthComponent {
|
||||
return this.authForm && this.authForm.valid;
|
||||
}
|
||||
|
||||
public hasChanges(): boolean {
|
||||
return !isEmpty(this.getChanges());
|
||||
}
|
||||
|
||||
setVerifyCertValue($event: any) {
|
||||
this.currentConfig.ldap_verify_cert.value = $event;
|
||||
}
|
||||
|
||||
public testLDAPServer(): void {
|
||||
if (this.testingLDAPOnGoing) {
|
||||
return; // Should not come here
|
||||
}
|
||||
|
||||
let ldapSettings = {};
|
||||
for (let prop in this.currentConfig) {
|
||||
if (prop.startsWith('ldap_')) {
|
||||
ldapSettings[prop] = this.currentConfig[prop].value;
|
||||
}
|
||||
}
|
||||
|
||||
let allChanges = this.getChanges();
|
||||
let ldapSearchPwd = allChanges['ldap_search_password'];
|
||||
if (ldapSearchPwd) {
|
||||
ldapSettings['ldap_search_password'] = ldapSearchPwd;
|
||||
} else {
|
||||
delete ldapSettings['ldap_search_password'];
|
||||
}
|
||||
|
||||
// Fix: Confirm ldap scope is number
|
||||
ldapSettings['ldap_scope'] = +ldapSettings['ldap_scope'];
|
||||
|
||||
this.testingLDAPOnGoing = true;
|
||||
this.configService.testLDAPServer(ldapSettings)
|
||||
.then(respone => {
|
||||
this.testingLDAPOnGoing = false;
|
||||
this.msgHandler.showSuccess('CONFIG.TEST_LDAP_SUCCESS');
|
||||
})
|
||||
.catch(error => {
|
||||
this.testingLDAPOnGoing = false;
|
||||
let err = error._body;
|
||||
if (!err || !err.trim()) {
|
||||
err = 'UNKNOWN';
|
||||
}
|
||||
this.msgHandler.showError('CONFIG.TEST_LDAP_FAILED', { 'param': err });
|
||||
});
|
||||
}
|
||||
|
||||
public get showLdapServerBtn(): boolean {
|
||||
return this.currentConfig.auth_mode &&
|
||||
this.currentConfig.auth_mode.value === 'ldap_auth';
|
||||
}
|
||||
|
||||
public isLDAPConfigValid(): boolean {
|
||||
return this.isValid() &&
|
||||
!this.testingLDAPOnGoing;
|
||||
}
|
||||
|
||||
public getChanges() {
|
||||
let allChanges = getChanges(this.originalConfig, this.currentConfig);
|
||||
let changes = {};
|
||||
for (let prop in allChanges) {
|
||||
if (prop.startsWith('ldap_')
|
||||
|| prop.startsWith('uaa_')
|
||||
|| prop === 'auth_mode'
|
||||
|| prop === 'project_creattion_restriction'
|
||||
|| prop === 'self_registration') {
|
||||
changes[prop] = allChanges[prop];
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
public get hideLDAPTestingSpinner(): boolean {
|
||||
return !this.testingLDAPOnGoing || !this.showLdapServerBtn;
|
||||
}
|
||||
|
||||
disabled(prop: any): boolean {
|
||||
return !(prop && prop.editable);
|
||||
}
|
||||
@ -77,4 +167,81 @@ export class ConfigurationAuthComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Save the changed values
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public save(): void {
|
||||
let changes = this.getChanges();
|
||||
if (!isEmpty(changes)) {
|
||||
this.onGoing = true;
|
||||
this.configService.saveConfiguration(changes)
|
||||
.then(response => {
|
||||
this.onGoing = false;
|
||||
this.retrieveConfig();
|
||||
// Reload bootstrap option
|
||||
this.appConfigService.load().catch(error => console.error('Failed to reload bootstrap option with error: ', error));
|
||||
this.msgHandler.showSuccess('CONFIG.SAVE_SUCCESS');
|
||||
})
|
||||
.catch(error => {
|
||||
this.onGoing = false;
|
||||
this.msgHandler.handleError(error);
|
||||
});
|
||||
} else {
|
||||
// Inprop situation, should not come here
|
||||
console.error('Save abort because nothing changed');
|
||||
}
|
||||
}
|
||||
|
||||
public hasUnsavedChanges(allChanges: any) {
|
||||
for (let prop in allChanges) {
|
||||
if (prop.startsWith('ldap_')
|
||||
|| prop.startsWith('uaa_')
|
||||
|| prop === 'auth_mode'
|
||||
|| prop === 'project_creattion_restriction'
|
||||
|| prop === 'self_registration') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
retrieveConfig(): void {
|
||||
this.onGoing = true;
|
||||
this.configService.getConfiguration()
|
||||
.then((configurations: Configuration) => {
|
||||
this.onGoing = false;
|
||||
|
||||
// Add two password fields
|
||||
configurations.ldap_search_password = new StringValueItem(fakePass, true);
|
||||
configurations.uaa_client_secret = new StringValueItem(fakePass, true);
|
||||
this.currentConfig = configurations;
|
||||
// Keep the original copy of the data
|
||||
this.originalConfig = clone(configurations);
|
||||
})
|
||||
.catch(error => {
|
||||
this.onGoing = false;
|
||||
this.msgHandler.handleError(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Discard current changes if have and reset
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public cancel(): void {
|
||||
let changes = this.getChanges();
|
||||
if (!isEmpty(changes)) {
|
||||
confirmUnsavedChanges(changes);
|
||||
} else {
|
||||
// Invalid situation, should not come here
|
||||
console.error('Nothing changed');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,22 +4,28 @@
|
||||
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
||||
<ul id="configTabs" class="nav" role="tablist">
|
||||
<li role="presentation" class="nav-item">
|
||||
<button id="config-auth" class="btn btn-link nav-link active" aria-controls="authentication" [class.active]='isCurrentTabLink("config-auth")' type="button" (click)='tabLinkClick("config-auth")'>{{'CONFIG.AUTH' | translate }}</button>
|
||||
<button id="config-auth" class="btn btn-link nav-link active" aria-controls="authentication" [class.active]='isCurrentTabLink("config-auth")'
|
||||
type="button" (click)='tabLinkClick("config-auth")'>{{'CONFIG.AUTH' | translate }}</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button id="config-email" class="btn btn-link nav-link" aria-controls="email" [class.active]='isCurrentTabLink("config-email")' type="button" (click)='tabLinkClick("config-email")'>{{'CONFIG.EMAIL' | translate }}</button>
|
||||
<button id="config-email" class="btn btn-link nav-link" aria-controls="email" [class.active]='isCurrentTabLink("config-email")'
|
||||
type="button" (click)='tabLinkClick("config-email")'>{{'CONFIG.EMAIL' | translate }}</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button id="config-system" class="btn btn-link nav-link" aria-controls="system_settings" [class.active]='isCurrentTabLink("config-system")' type="button" (click)='tabLinkClick("config-system")'>{{'CONFIG.SYSTEM' | translate }}</button>
|
||||
<button id="config-system" class="btn btn-link nav-link" aria-controls="system_settings" [class.active]='isCurrentTabLink("config-system")'
|
||||
type="button" (click)='tabLinkClick("config-system")'>{{'CONFIG.SYSTEM' | translate }}</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item" *ngIf="!withAdmiral">
|
||||
<button id="config-label" class="btn btn-link nav-link" aria-controls="system_label" [class.active]='isCurrentTabLink("config-label")' type="button" (click)='tabLinkClick("config-label")'>{{'CONFIG.LABEL' | translate }}</button>
|
||||
<li role="presentation" class="nav-item" *ngIf="!withAdmiral">
|
||||
<button id="config-label" class="btn btn-link nav-link" aria-controls="system_label" [class.active]='isCurrentTabLink("config-label")'
|
||||
type="button" (click)='tabLinkClick("config-label")'>{{'CONFIG.LABEL' | translate }}</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item" *ngIf="withClair">
|
||||
<button id="config-vulnerability" class="btn btn-link nav-link" aria-controls="vulnerability" [class.active]='isCurrentTabLink("config-vulnerability")' type="button" (click)='tabLinkClick("config-vulnerability")'>{{'CONFIG.VULNERABILITY' | translate}}</button>
|
||||
<button id="config-vulnerability" class="btn btn-link nav-link" aria-controls="vulnerability" [class.active]='isCurrentTabLink("config-vulnerability")'
|
||||
type="button" (click)='tabLinkClick("config-vulnerability")'>{{'CONFIG.VULNERABILITY' | translate}}</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item" *ngIf="hasAdminRole">
|
||||
<button id="config-gc" class="btn btn-link nav-link" aria-controls="gc" [class.active]='isCurrentTabLink("config-gc")' type="button" (click)='tabLinkClick("config-gc")'>{{'CONFIG.GC' | translate}}</button>
|
||||
<button id="config-gc" class="btn btn-link nav-link" aria-controls="gc" [class.active]='isCurrentTabLink("config-gc")' type="button"
|
||||
(click)='tabLinkClick("config-gc")'>{{'CONFIG.GC' | translate}}</button>
|
||||
</li>
|
||||
</ul>
|
||||
<section id="authentication" role="tabpanel" aria-labelledby="config-auth" [hidden]='!isCurrentTabContent("authentication")'>
|
||||
@ -31,7 +37,8 @@
|
||||
<section id="system_settings" role="tabpanel" aria-labelledby="config-system" [hidden]='!isCurrentTabContent("system_settings")'>
|
||||
<system-settings [(systemSettings)]="allConfig" [hasAdminRole]="hasAdminRole" [hasCAFile]="hasCAFile"></system-settings>
|
||||
</section>
|
||||
<section id="system_label" role="tabpanel" aria-labelledby="config-label" *ngIf="!withAdmiral" [hidden]='!isCurrentTabContent("system_label")' style="padding-top: 16px;">
|
||||
<section id="system_label" role="tabpanel" aria-labelledby="config-label" *ngIf="!withAdmiral" [hidden]='!isCurrentTabContent("system_label")'
|
||||
style="padding-top: 16px;">
|
||||
<hbr-label [scope]="'g'"></hbr-label>
|
||||
</section>
|
||||
<section id="vulnerability" *ngIf="withClair" role="tabpanel" aria-labelledby="config-vulnerability" [hidden]='!isCurrentTabContent("vulnerability")'>
|
||||
@ -40,13 +47,10 @@
|
||||
<section id="gc" *ngIf="hasAdminRole" role="tabpanel" aria-labelledby="config-gc" [hidden]='!isCurrentTabContent("gc")'>
|
||||
<gc-config></gc-config>
|
||||
</section>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary" (click)="save()" [hidden]="hideBtn" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()" [hidden]="hideBtn" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="testMailServer()" *ngIf="showTestServerBtn" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button>
|
||||
<span id="forTestingMail" class="spinner spinner-inline" [hidden]="hideMailTestingSpinner"></span>
|
||||
<span id="forTestingLDAP" class="spinner spinner-inline" [hidden]="hideLDAPTestingSpinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary" (click)="save()" [hidden]="hideBtn" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()" [hidden]="hideBtn" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||
|
||||
</div>
|
@ -13,10 +13,12 @@
|
||||
// limitations under the License.
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { Subscription } from "rxjs";
|
||||
import { Configuration, StringValueItem, SystemSettingsComponent, VulnerabilityConfigComponent} from '@harbor/ui';
|
||||
import { Configuration, StringValueItem, SystemSettingsComponent, VulnerabilityConfigComponent,
|
||||
isEmpty, clone, getChanges } from '@harbor/ui';
|
||||
|
||||
import { ConfirmationTargets, ConfirmationState } from '../shared/shared.const';
|
||||
import { SessionService } from '../shared/session.service';
|
||||
import { confirmUnsavedChanges} from './config.msg.utils';
|
||||
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
|
||||
import { ConfirmationMessage } from '../shared/confirmation-dialog/confirmation-message';
|
||||
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
|
||||
@ -24,7 +26,7 @@ import { MessageHandlerService } from '../shared/message-handler/message-handler
|
||||
import { AppConfigService } from '../app-config.service';
|
||||
import { ConfigurationAuthComponent } from './auth/config-auth.component';
|
||||
import { ConfigurationEmailComponent } from './email/config-email.component';
|
||||
import { GcComponent} from './gc/gc.component';
|
||||
import { GcComponent } from './gc/gc.component';
|
||||
import { ConfigurationService } from './config.service';
|
||||
|
||||
|
||||
@ -48,10 +50,8 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
onGoing = false;
|
||||
allConfig: Configuration = new Configuration();
|
||||
currentTabId = 'config-auth'; // default tab
|
||||
originalCopy: Configuration;
|
||||
originalCopy: Configuration = new Configuration();
|
||||
confirmSub: Subscription;
|
||||
testingMailOnGoing = false;
|
||||
testingLDAPOnGoing = false;
|
||||
|
||||
@ViewChild(SystemSettingsComponent) systemSettingsConfig: SystemSettingsComponent;
|
||||
@ViewChild(VulnerabilityConfigComponent) vulnerabilityConfig: VulnerabilityConfigComponent;
|
||||
@ -91,49 +91,31 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
return TabLinkContentMap[this.currentTabId] === contentId;
|
||||
}
|
||||
|
||||
hasUnsavedChangesOfCurrentTab(): any {
|
||||
let allChanges = this.getChanges();
|
||||
if (this.isEmpty(allChanges)) {
|
||||
return null;
|
||||
hasUnsavedChangesOfCurrentTab(allChanges: any): boolean {
|
||||
if (isEmpty(allChanges)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let properties = [];
|
||||
switch (this.currentTabId) {
|
||||
case 'config-auth':
|
||||
for (let prop in allChanges) {
|
||||
if (prop.startsWith('ldap_')) {
|
||||
return allChanges;
|
||||
}
|
||||
}
|
||||
properties = ['auth_mode', 'project_creation_restriction', 'self_registration'];
|
||||
break;
|
||||
return this.authConfig.hasUnsavedChanges(allChanges);
|
||||
case 'config-email':
|
||||
for (let prop in allChanges) {
|
||||
if (prop.startsWith('email_')) {
|
||||
return allChanges;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return this.mailConfig.hasUnsavedChanges(allChanges);
|
||||
case 'config-replication':
|
||||
properties = ['verify_remote_cert'];
|
||||
break;
|
||||
case 'config-system':
|
||||
properties = ['token_expiration'];
|
||||
break;
|
||||
case 'config-vulnerability':
|
||||
properties = ['scan_all_policy'];
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
return this.systemSettingsConfig.hasUnsavedChanges(allChanges);
|
||||
}
|
||||
|
||||
for (let prop in allChanges) {
|
||||
if (properties.indexOf(prop) !== -1) {
|
||||
return allChanges;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -168,68 +150,32 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public isValid(): boolean {
|
||||
return this.systemSettingsConfig &&
|
||||
this.systemSettingsConfig.isValid &&
|
||||
this.mailConfig &&
|
||||
this.mailConfig.isValid() &&
|
||||
this.authConfig &&
|
||||
this.authConfig.isValid() &&
|
||||
this.isVulnerabiltyValid;
|
||||
}
|
||||
|
||||
public get isVulnerabiltyValid(): boolean {
|
||||
return !this.appConfigService.getConfig().with_clair ||
|
||||
(this.vulnerabilityConfig &&
|
||||
this.vulnerabilityConfig.isValid);
|
||||
return this.systemSettingsConfig.isValid;
|
||||
}
|
||||
|
||||
public hasChanges(): boolean {
|
||||
return !this.isEmpty(this.getChanges());
|
||||
return !isEmpty(this.getSystemChanges());
|
||||
}
|
||||
|
||||
public isMailConfigValid(): boolean {
|
||||
return this.mailConfig &&
|
||||
this.mailConfig.isValid() &&
|
||||
!this.testingMailOnGoing;
|
||||
}
|
||||
|
||||
public get showTestServerBtn(): boolean {
|
||||
return this.currentTabId === 'config-email';
|
||||
}
|
||||
|
||||
public get showLdapServerBtn(): boolean {
|
||||
return this.currentTabId === 'config-auth' &&
|
||||
this.allConfig.auth_mode &&
|
||||
this.allConfig.auth_mode.value === 'ldap_auth';
|
||||
}
|
||||
|
||||
public get hideBtn(): boolean {
|
||||
return this.currentTabId === 'config-label' || this.currentTabId === 'config-gc' || this.currentTabId === 'config-vulnerability';
|
||||
}
|
||||
|
||||
public get hideMailTestingSpinner(): boolean {
|
||||
return !this.testingMailOnGoing || !this.showTestServerBtn;
|
||||
}
|
||||
|
||||
public get hideLDAPTestingSpinner(): boolean {
|
||||
return !this.testingLDAPOnGoing || !this.showLdapServerBtn;
|
||||
}
|
||||
|
||||
public isLDAPConfigValid(): boolean {
|
||||
return this.authConfig &&
|
||||
this.authConfig.isValid() &&
|
||||
!this.testingLDAPOnGoing;
|
||||
}
|
||||
|
||||
public tabLinkClick(tabLink: string) {
|
||||
let allChanges = getChanges(this.originalCopy, this.allConfig);
|
||||
// Whether has unsaved changes in current tab
|
||||
let changes = this.hasUnsavedChangesOfCurrentTab();
|
||||
if (!changes) {
|
||||
let hasChanges = this.hasUnsavedChangesOfCurrentTab(allChanges);
|
||||
if (!hasChanges) {
|
||||
this.currentTabId = tabLink;
|
||||
return;
|
||||
}
|
||||
|
||||
this.confirmUnsavedTabChanges(changes, tabLink);
|
||||
this.confirmUnsavedTabChanges(allChanges, tabLink);
|
||||
}
|
||||
|
||||
public getSystemChanges() {
|
||||
let allChanges = getChanges(this.originalCopy, this.allConfig);
|
||||
if (allChanges) {
|
||||
return this.systemSettingsConfig.getSystemChanges(allChanges);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -239,16 +185,8 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public save(): void {
|
||||
let changes = this.getChanges();
|
||||
if (!this.isEmpty(changes)) {
|
||||
// Fix policy parameters issue
|
||||
let scanningAllPolicy = changes['scan_all_policy'];
|
||||
if (scanningAllPolicy &&
|
||||
scanningAllPolicy.type !== 'daily' &&
|
||||
scanningAllPolicy.parameters) {
|
||||
delete (scanningAllPolicy.parameters);
|
||||
}
|
||||
|
||||
let changes = this.getSystemChanges();
|
||||
if (!isEmpty(changes)) {
|
||||
this.onGoing = true;
|
||||
this.configService.saveConfiguration(changes)
|
||||
.then(response => {
|
||||
@ -290,107 +228,17 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public cancel(): void {
|
||||
let changes = this.getChanges();
|
||||
if (!this.isEmpty(changes)) {
|
||||
this.confirmUnsavedChanges(changes);
|
||||
let changes = this.getSystemChanges();
|
||||
if (!isEmpty(changes)) {
|
||||
confirmUnsavedChanges(changes);
|
||||
} else {
|
||||
// Invalid situation, should not come here
|
||||
console.error('Nothing changed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Test the connection of specified mail server
|
||||
*
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public testMailServer(): void {
|
||||
if (this.testingMailOnGoing) {
|
||||
return; // Should not come here
|
||||
}
|
||||
let mailSettings = {};
|
||||
for (let prop in this.allConfig) {
|
||||
if (prop.startsWith('email_')) {
|
||||
mailSettings[prop] = this.allConfig[prop].value;
|
||||
}
|
||||
}
|
||||
// Confirm port is number
|
||||
mailSettings['email_port'] = +mailSettings['email_port'];
|
||||
let allChanges = this.getChanges();
|
||||
let password = allChanges['email_password'];
|
||||
if (password) {
|
||||
mailSettings['email_password'] = password;
|
||||
} else {
|
||||
delete mailSettings['email_password'];
|
||||
}
|
||||
|
||||
this.testingMailOnGoing = true;
|
||||
this.configService.testMailServer(mailSettings)
|
||||
.then(response => {
|
||||
this.testingMailOnGoing = false;
|
||||
this.msgHandler.showSuccess('CONFIG.TEST_MAIL_SUCCESS');
|
||||
})
|
||||
.catch(error => {
|
||||
this.testingMailOnGoing = false;
|
||||
let err = error._body;
|
||||
if (!err) {
|
||||
err = 'UNKNOWN';
|
||||
}
|
||||
this.msgHandler.showError('CONFIG.TEST_MAIL_FAILED', { 'param': err });
|
||||
});
|
||||
}
|
||||
|
||||
public testLDAPServer(): void {
|
||||
if (this.testingLDAPOnGoing) {
|
||||
return; // Should not come here
|
||||
}
|
||||
|
||||
let ldapSettings = {};
|
||||
for (let prop in this.allConfig) {
|
||||
if (prop.startsWith('ldap_')) {
|
||||
ldapSettings[prop] = this.allConfig[prop].value;
|
||||
}
|
||||
}
|
||||
|
||||
let allChanges = this.getChanges();
|
||||
let ldapSearchPwd = allChanges['ldap_search_password'];
|
||||
if (ldapSearchPwd) {
|
||||
ldapSettings['ldap_search_password'] = ldapSearchPwd;
|
||||
} else {
|
||||
delete ldapSettings['ldap_search_password'];
|
||||
}
|
||||
|
||||
// Fix: Confirm ldap scope is number
|
||||
ldapSettings['ldap_scope'] = +ldapSettings['ldap_scope'];
|
||||
|
||||
this.testingLDAPOnGoing = true;
|
||||
this.configService.testLDAPServer(ldapSettings)
|
||||
.then(respone => {
|
||||
this.testingLDAPOnGoing = false;
|
||||
this.msgHandler.showSuccess('CONFIG.TEST_LDAP_SUCCESS');
|
||||
})
|
||||
.catch(error => {
|
||||
this.testingLDAPOnGoing = false;
|
||||
let err = error._body;
|
||||
if (!err || !err.trim()) {
|
||||
err = 'UNKNOWN';
|
||||
}
|
||||
this.msgHandler.showError('CONFIG.TEST_LDAP_FAILED', { 'param': err });
|
||||
});
|
||||
}
|
||||
|
||||
confirmUnsavedChanges(changes: any) {
|
||||
let msg = new ConfirmationMessage(
|
||||
'CONFIG.CONFIRM_TITLE',
|
||||
'CONFIG.CONFIRM_SUMMARY',
|
||||
'',
|
||||
changes,
|
||||
ConfirmationTargets.CONFIG
|
||||
);
|
||||
|
||||
this.confirmService.openComfirmDialog(msg);
|
||||
public get hideBtn(): boolean {
|
||||
return this.currentTabId !== 'config-system';
|
||||
}
|
||||
|
||||
confirmUnsavedTabChanges(changes: any, tabId: string) {
|
||||
@ -420,7 +268,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
configurations.uaa_client_secret = new StringValueItem(fakePass, true);
|
||||
this.allConfig = configurations;
|
||||
// Keep the original copy of the data
|
||||
this.originalCopy = this.clone(configurations);
|
||||
this.originalCopy = clone(configurations);
|
||||
})
|
||||
.catch(error => {
|
||||
this.onGoing = false;
|
||||
@ -428,72 +276,6 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the changed fields and return a map
|
||||
*
|
||||
* @private
|
||||
* returns {*}
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
getChanges(): { [key: string]: any | any[] } {
|
||||
let changes: { [key: string]: any | any[] } = {};
|
||||
if (!this.allConfig || !this.originalCopy) {
|
||||
return changes;
|
||||
}
|
||||
for (let prop of Object.keys(this.allConfig)) {
|
||||
let field = this.originalCopy[prop];
|
||||
if (field && field.editable) {
|
||||
if (!this.compareValue(field.value, this.allConfig[prop].value)) {
|
||||
changes[prop] = this.allConfig[prop].value;
|
||||
// Number
|
||||
if (typeof field.value === 'number') {
|
||||
changes[prop] = +changes[prop];
|
||||
}
|
||||
|
||||
// Trim string value
|
||||
if (typeof field.value === 'string') {
|
||||
changes[prop] = ('' + changes[prop]).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
// private
|
||||
compareValue(a: any, b: any): boolean {
|
||||
if ((a && !b) || (!a && b)) { return false; }
|
||||
if (!a && !b) { return true; }
|
||||
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
}
|
||||
|
||||
// private
|
||||
isEmpty(obj: any): boolean {
|
||||
return !obj || JSON.stringify(obj) === '{}';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Deep clone the configuration object
|
||||
*
|
||||
* @private
|
||||
* ** deprecated param {Configuration} src
|
||||
* returns {Configuration}
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
clone(src: Configuration): Configuration {
|
||||
if (!src) {
|
||||
return new Configuration(); // Empty
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(src));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Reset the configuration form
|
||||
@ -504,10 +286,10 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
reset(changes: any): void {
|
||||
if (!this.isEmpty(changes)) {
|
||||
if (!isEmpty(changes)) {
|
||||
for (let prop in changes) {
|
||||
if (this.originalCopy[prop]) {
|
||||
this.allConfig[prop] = this.clone(this.originalCopy[prop]);
|
||||
this.allConfig[prop] = clone(this.originalCopy[prop]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
17
src/portal/src/app/config/config.msg.utils.ts
Normal file
17
src/portal/src/app/config/config.msg.utils.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
|
||||
import { ConfirmationMessage } from '../shared/confirmation-dialog/confirmation-message';
|
||||
import { ConfirmationTargets } from '../shared/shared.const';
|
||||
|
||||
export function confirmUnsavedChanges(changes: any) {
|
||||
let confirmService = new ConfirmationDialogService();
|
||||
let msg = new ConfirmationMessage(
|
||||
'CONFIG.CONFIRM_TITLE',
|
||||
'CONFIG.CONFIRM_SUMMARY',
|
||||
'',
|
||||
changes,
|
||||
ConfirmationTargets.CONFIG
|
||||
);
|
||||
|
||||
confirmService.openComfirmDialog(msg);
|
||||
}
|
||||
|
@ -2,62 +2,58 @@
|
||||
<section class="form-block">
|
||||
<div class="form-group">
|
||||
<label for="mailServer" class="required">{{'CONFIG.MAIL_SERVER' | translate}}</label>
|
||||
<label for="mailServer" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right" [class.invalid]="mailServerInput.invalid && (mailServerInput.dirty || mailServerInput.touched)">
|
||||
<input name="mailServer" type="text" #mailServerInput="ngModel" [(ngModel)]="currentConfig.email_host.value"
|
||||
required
|
||||
id="mailServer"
|
||||
size="40" [disabled]="disabled(currentConfig.email_host)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
<label for="mailServer" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right"
|
||||
[class.invalid]="mailServerInput.invalid && (mailServerInput.dirty || mailServerInput.touched)">
|
||||
<input name="mailServer" type="text" #mailServerInput="ngModel" [(ngModel)]="currentConfig.email_host.value" required id="mailServer"
|
||||
size="40" [disabled]="disabled(currentConfig.email_host)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="emailPort" class="required">{{'CONFIG.MAIL_SERVER_PORT' | translate}}</label>
|
||||
<label for="emailPort" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right" [class.invalid]="emailPortInput.invalid && (emailPortInput.dirty || emailPortInput.touched)">
|
||||
<input name="emailPort" type="text" #emailPortInput="ngModel" [(ngModel)]="currentConfig.email_port.value"
|
||||
required
|
||||
port
|
||||
id="emailPort"
|
||||
size="40" [disabled]="disabled(currentConfig.email_port)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.PORT_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
<label for="emailPort" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right"
|
||||
[class.invalid]="emailPortInput.invalid && (emailPortInput.dirty || emailPortInput.touched)">
|
||||
<input name="emailPort" type="text" #emailPortInput="ngModel" [(ngModel)]="currentConfig.email_port.value" required port
|
||||
id="emailPort" size="40" [disabled]="disabled(currentConfig.email_port)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.PORT_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="emailUsername">{{'CONFIG.MAIL_USERNAME' | translate}}</label>
|
||||
<label for="emailUsername" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right" [class.invalid]="false">
|
||||
<input name="emailUsername" type="text" #emailUsernameInput="ngModel" [(ngModel)]="currentConfig.email_username.value"
|
||||
id="emailUsername"
|
||||
size="40" [disabled]="disabled(currentConfig.email_username)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
<label for="emailUsername" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right"
|
||||
[class.invalid]="false">
|
||||
<input name="emailUsername" type="text" #emailUsernameInput="ngModel" [(ngModel)]="currentConfig.email_username.value" id="emailUsername"
|
||||
size="40" [disabled]="disabled(currentConfig.email_username)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="emailPassword">{{'CONFIG.MAIL_PASSWORD' | translate}}</label>
|
||||
<label for="emailPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right" [class.invalid]="false">
|
||||
<input name="emailPassword" type="password" #emailPasswordInput="ngModel" [(ngModel)]="currentConfig.email_password.value"
|
||||
id="emailPassword"
|
||||
size="40" [disabled]="disabled(currentConfig.email_password)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
<label for="emailPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right"
|
||||
[class.invalid]="false">
|
||||
<input name="emailPassword" type="password" #emailPasswordInput="ngModel" [(ngModel)]="currentConfig.email_password.value"
|
||||
id="emailPassword" size="40" [disabled]="disabled(currentConfig.email_password)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="emailFrom" class="required">{{'CONFIG.MAIL_FROM' | translate}}</label>
|
||||
<label for="emailFrom" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right" [class.invalid]="emailFromInput.invalid && (emailFromInput.dirty || emailFromInput.touched)">
|
||||
<input name="emailFrom" type="text" #emailFromInput="ngModel" [(ngModel)]="currentConfig.email_from.value"
|
||||
required
|
||||
id="emailFrom"
|
||||
size="40" [disabled]="disabled(currentConfig.email_from)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
<label for="emailFrom" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-right"
|
||||
[class.invalid]="emailFromInput.invalid && (emailFromInput.dirty || emailFromInput.touched)">
|
||||
<input name="emailFrom" type="text" #emailFromInput="ngModel" [(ngModel)]="currentConfig.email_from.value" required id="emailFrom"
|
||||
size="40" [disabled]="disabled(currentConfig.email_from)">
|
||||
<span class="tooltip-content">
|
||||
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="selfReg">{{'CONFIG.MAIL_SSL' | translate}}</label>
|
||||
@ -70,12 +66,19 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="insecure">{{'CONFIG.MAIL_INSECURE' | translate}}</label>
|
||||
<clr-checkbox name="emaiInsecure" id="emailInsecure" [clrChecked]="!currentConfig.email_insecure.value" [clrDisabled]="disabled(currentConfig.email_insecure)" (clrCheckedChange)="setInsecureValue($event)">
|
||||
<clr-checkbox name="emaiInsecure" id="emailInsecure" [clrChecked]="!currentConfig.email_insecure.value" [clrDisabled]="disabled(currentConfig.email_insecure)"
|
||||
(clrCheckedChange)="setInsecureValue($event)">
|
||||
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right" style="top:-7px;">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.INSECURE_TOOLTIP' | translate}}</span>
|
||||
</a>
|
||||
</a>
|
||||
</clr-checkbox>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</form>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="testMailServer()" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL' | translate}}</button>
|
||||
<span id="forTestingMail" class="spinner spinner-inline" [hidden]="hideMailTestingSpinner"></span>
|
||||
</div>
|
@ -11,23 +11,31 @@
|
||||
// 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 } from '@angular/core';
|
||||
import { Component, Input, ViewChild, SimpleChanges, OnChanges } from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
|
||||
import { Configuration } from '@harbor/ui';
|
||||
|
||||
import { Configuration, clone, isEmpty, getChanges, StringValueItem} from '@harbor/ui';
|
||||
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
|
||||
import { confirmUnsavedChanges} from '../config.msg.utils';
|
||||
import { ConfigurationService } from '../config.service';
|
||||
const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
|
||||
@Component({
|
||||
selector: 'config-email',
|
||||
templateUrl: "config-email.component.html",
|
||||
styleUrls: ['./config-email.component.scss', '../config.component.scss']
|
||||
})
|
||||
export class ConfigurationEmailComponent {
|
||||
export class ConfigurationEmailComponent implements OnChanges {
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input("mailConfig") currentConfig: Configuration = new Configuration();
|
||||
|
||||
private originalConfig: Configuration;
|
||||
testingMailOnGoing = false;
|
||||
onGoing = false;
|
||||
@ViewChild("mailConfigFrom") mailForm: NgForm;
|
||||
|
||||
constructor() { }
|
||||
constructor(
|
||||
private msgHandler: MessageHandlerService,
|
||||
private configService: ConfigurationService) {
|
||||
}
|
||||
|
||||
disabled(prop: any): boolean {
|
||||
return !(prop && prop.editable);
|
||||
@ -40,4 +48,146 @@ export class ConfigurationEmailComponent {
|
||||
public isValid(): boolean {
|
||||
return this.mailForm && this.mailForm.valid;
|
||||
}
|
||||
|
||||
public hasChanges(): boolean {
|
||||
return !isEmpty(this.getChanges());
|
||||
}
|
||||
|
||||
public hasUnsavedChanges(allChanges: any) {
|
||||
for (let prop in allChanges) {
|
||||
if (prop.startsWith('email_')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public getChanges() {
|
||||
let allChanges = getChanges(this.originalConfig, this.currentConfig);
|
||||
let changes = {};
|
||||
for (let prop in allChanges) {
|
||||
if (prop.startsWith('email_')) {
|
||||
changes[prop] = allChanges[prop];
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes && changes["currentConfig"]) {
|
||||
this.originalConfig = clone(this.currentConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Test the connection of specified mail server
|
||||
*
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public testMailServer(): void {
|
||||
if (this.testingMailOnGoing) {
|
||||
return; // Should not come here
|
||||
}
|
||||
let mailSettings = {};
|
||||
for (let prop in this.currentConfig) {
|
||||
if (prop.startsWith('email_')) {
|
||||
mailSettings[prop] = this.currentConfig[prop].value;
|
||||
}
|
||||
}
|
||||
// Confirm port is number
|
||||
mailSettings['email_port'] = +mailSettings['email_port'];
|
||||
let allChanges = this.getChanges();
|
||||
let password = allChanges['email_password'];
|
||||
if (password) {
|
||||
mailSettings['email_password'] = password;
|
||||
} else {
|
||||
delete mailSettings['email_password'];
|
||||
}
|
||||
|
||||
this.testingMailOnGoing = true;
|
||||
this.configService.testMailServer(mailSettings)
|
||||
.then(response => {
|
||||
this.testingMailOnGoing = false;
|
||||
this.msgHandler.showSuccess('CONFIG.TEST_MAIL_SUCCESS');
|
||||
})
|
||||
.catch(error => {
|
||||
this.testingMailOnGoing = false;
|
||||
let err = error._body;
|
||||
if (!err) {
|
||||
err = 'UNKNOWN';
|
||||
}
|
||||
this.msgHandler.showError('CONFIG.TEST_MAIL_FAILED', { 'param': err });
|
||||
});
|
||||
}
|
||||
|
||||
public get hideMailTestingSpinner(): boolean {
|
||||
return !this.testingMailOnGoing;
|
||||
}
|
||||
|
||||
public isMailConfigValid(): boolean {
|
||||
return this.isValid() &&
|
||||
!this.testingMailOnGoing;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Save the changed values
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public save(): void {
|
||||
let changes = this.getChanges();
|
||||
if (!isEmpty(changes)) {
|
||||
this.onGoing = true;
|
||||
this.configService.saveConfiguration(changes)
|
||||
.then(response => {
|
||||
this.onGoing = false;
|
||||
this.retrieveConfig();
|
||||
this.msgHandler.showSuccess('CONFIG.SAVE_SUCCESS');
|
||||
})
|
||||
.catch(error => {
|
||||
this.onGoing = false;
|
||||
this.msgHandler.handleError(error);
|
||||
});
|
||||
} else {
|
||||
// Inprop situation, should not come here
|
||||
console.error('Save abort because nothing changed');
|
||||
}
|
||||
}
|
||||
|
||||
retrieveConfig(): void {
|
||||
this.onGoing = true;
|
||||
this.configService.getConfiguration()
|
||||
.then((configurations: Configuration) => {
|
||||
this.onGoing = false;
|
||||
|
||||
// Add two password fields
|
||||
configurations.email_password = new StringValueItem(fakePass, true);
|
||||
this.currentConfig = configurations;
|
||||
// Keep the original copy of the data
|
||||
this.originalConfig = clone(configurations);
|
||||
})
|
||||
.catch(error => {
|
||||
this.onGoing = false;
|
||||
this.msgHandler.handleError(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Discard current changes if have and reset
|
||||
*
|
||||
* @memberOf ConfigurationComponent
|
||||
*/
|
||||
public cancel(): void {
|
||||
let changes = this.getChanges();
|
||||
if (!isEmpty(changes)) {
|
||||
confirmUnsavedChanges(changes);
|
||||
} else {
|
||||
// Invalid situation, should not come here
|
||||
console.error('Nothing changed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user