mirror of https://github.com/goharbor/harbor.git
299 lines
9.3 KiB
TypeScript
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;
|
|
}
|
|
}
|