harbor/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.ts

299 lines
9.3 KiB
TypeScript

import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import {
BannerMessage,
BannerMessageI18nMap,
BannerMessageType,
Configuration,
} from '../config';
import {
CURRENT_BASE_HREF,
getChanges,
isEmpty,
} from '../../../../shared/units/utils';
import { ConfigService } from '../config.service';
import { AppConfigService } from '../../../../services/app-config.service';
import { finalize } from 'rxjs/operators';
import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import {
EventService,
HarborEvent,
} from '../../../../services/event-service/event.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'system-settings',
templateUrl: './system-settings.component.html',
styleUrls: ['./system-settings.component.scss'],
})
export class SystemSettingsComponent implements OnInit, OnDestroy {
bannerMessageTypes: string[] = Object.values(BannerMessageType);
onGoing = false;
downloadLink: string;
get currentConfig(): Configuration {
return this.conf.getConfig();
}
set currentConfig(cfg: Configuration) {
this.conf.setConfig(cfg);
}
messageText: string;
messageType: string;
messageClosable: boolean;
messageFromDate: Date;
messageToDate: Date;
// the copy of bannerMessage
messageTextCopy: string;
messageTypeCopy: string;
messageClosableCopy: boolean;
messageFromDateCopy: Date;
messageToDateCopy: Date;
bannerRefreshSub: Subscription;
@ViewChild('systemConfigFrom') systemSettingsForm: NgForm;
constructor(
private appConfigService: AppConfigService,
private errorHandler: MessageHandlerService,
private conf: ConfigService,
private event: EventService
) {
this.downloadLink = CURRENT_BASE_HREF + '/systeminfo/getcert';
}
ngOnInit() {
this.conf.resetConfig();
if (!this.bannerRefreshSub) {
this.bannerRefreshSub = this.event.subscribe(
HarborEvent.REFRESH_BANNER_MESSAGE,
() => {
this.setValueForBannerMessage();
}
);
}
if (this.currentConfig.banner_message) {
this.setValueForBannerMessage();
}
}
ngOnDestroy() {
if (this.bannerRefreshSub) {
this.bannerRefreshSub.unsubscribe();
this.bannerRefreshSub = null;
}
}
setValueForBannerMessage() {
if (this.currentConfig.banner_message.value) {
this.messageText = (
JSON.parse(
this.currentConfig.banner_message.value
) as BannerMessage
).message;
this.messageType = (
JSON.parse(
this.currentConfig.banner_message.value
) as BannerMessage
).type;
this.messageClosable = (
JSON.parse(
this.currentConfig.banner_message.value
) as BannerMessage
).closable;
this.messageFromDate = (
JSON.parse(
this.currentConfig.banner_message.value
) as BannerMessage
).fromDate;
this.messageToDate = (
JSON.parse(
this.currentConfig.banner_message.value
) as BannerMessage
).toDate;
} else {
this.messageText = null;
this.messageType = BannerMessageType.WARNING;
this.messageClosable = false;
}
this.messageTextCopy = this.messageText;
this.messageTypeCopy = this.messageType;
this.messageClosableCopy = this.messageClosable;
this.messageFromDateCopy = this.messageFromDate;
this.messageToDateCopy = this.messageToDate;
}
get editable(): boolean {
return (
this.currentConfig &&
this.currentConfig.token_expiration &&
this.currentConfig.token_expiration.editable
);
}
get robotExpirationEditable(): boolean {
return (
this.currentConfig &&
this.currentConfig.robot_token_duration &&
this.currentConfig.robot_token_duration.editable
);
}
robotNamePrefixEditable(): boolean {
return (
this.currentConfig &&
this.currentConfig.robot_name_prefix &&
this.currentConfig.robot_name_prefix.editable
);
}
public isValid(): boolean {
return this.systemSettingsForm && this.systemSettingsForm.valid;
}
public hasChanges(): boolean {
return !isEmpty(this.getChanges()) || this.hasBannerMessageChanged();
}
hasBannerMessageChanged() {
return (
this.messageTextCopy != this.messageText ||
this.messageTypeCopy != this.messageType ||
this.messageClosableCopy != this.messageClosable ||
this.messageFromDateCopy != this.messageFromDate ||
this.messageToDateCopy != this.messageToDate
);
}
public getChanges() {
let allChanges = getChanges(
this.conf.getOriginalConfig(),
this.currentConfig
);
if (allChanges) {
return this.getSystemChanges(allChanges);
}
return null;
}
public getSystemChanges(allChanges: any) {
let changes = {};
for (let prop in allChanges) {
if (
prop === 'token_expiration' ||
prop === 'read_only' ||
prop === 'project_creation_restriction' ||
prop === 'robot_token_duration' ||
prop === 'notification_enable' ||
prop === 'robot_name_prefix' ||
prop === 'audit_log_forward_endpoint' ||
prop === 'skip_audit_log_database' ||
prop === 'session_timeout' ||
prop === 'scanner_skip_update_pulltime' ||
prop === 'banner_message'
) {
changes[prop] = allChanges[prop];
}
}
return changes;
}
setRepoReadOnlyValue($event: any) {
this.currentConfig.read_only.value = $event;
}
setWebhookNotificationEnabledValue($event: any) {
this.currentConfig.notification_enable.value = $event;
}
disabled(prop: any): boolean {
return !(prop && prop.editable);
}
get canDownloadCert(): boolean {
return this.appConfigService.getConfig().has_ca_root;
}
/**
*
* Save the changed values
*
* @memberOf ConfigurationComponent
*/
public save(): void {
let changes = this.getChanges();
if (this.hasBannerMessageChanged()) {
const bm = new BannerMessage();
bm.message = this.messageText;
bm.type = this.messageType;
bm.closable = this.messageClosable;
bm.fromDate = this.messageFromDate;
bm.toDate = this.messageToDate;
if (bm.message) {
changes['banner_message'] = JSON.stringify(bm);
} else {
changes['banner_message'] = '';
}
}
if (!isEmpty(changes)) {
this.onGoing = true;
this.conf
.saveConfiguration(changes)
.pipe(finalize(() => (this.onGoing = false)))
.subscribe({
next: result => {
// API should return the updated configurations here
// Unfortunately API does not do that
// So we need to call update function again
this.conf.updateConfig();
// Reload bootstrap option
this.appConfigService.load().subscribe(
() => {},
error =>
console.error(
'Failed to reload bootstrap option with error: ',
error
)
);
this.errorHandler.info('CONFIG.SAVE_SUCCESS');
},
error: error => {
this.errorHandler.error(error);
},
});
} else {
// Inprop situation, should not come here
console.error('Save abort because nothing changed');
}
}
public get inProgress(): boolean {
return this.onGoing || this.conf.getLoadingConfigStatus();
}
/**
*
* Discard current changes if have and reset
*
* @memberOf ConfigurationComponent
*/
public cancel(): void {
let changes = this.getChanges();
if (!isEmpty(changes)) {
this.conf.confirmUnsavedChanges(changes);
} else {
// Invalid situation, should not come here
console.error('Nothing changed');
}
}
checkAuditLogForwardEndpoint(e: any) {
if (!e?.target?.value) {
this.currentConfig.skip_audit_log_database.value = false;
}
}
translateMessageType(type: string): string {
return BannerMessageI18nMap[type] || type;
}
}