Skip to content

Commit

Permalink
Add costomized banner message UI
Browse files Browse the repository at this point in the history
1.Fixes goharbor#18719
2.Add Banner Message item to configuration
3.Add banner_message property to systeminfo API

Signed-off-by: AllForNothing <[email protected]>
  • Loading branch information
AllForNothing authored and AllForNothing committed Jun 21, 2023
1 parent 46f1fb0 commit ea204db
Show file tree
Hide file tree
Showing 25 changed files with 551 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,4 @@ This project uses open source components which have additional licensing terms.

## Fossa Status

[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgoharbor%2Fharbor.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgoharbor%2Fharbor?ref=badge_large)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgoharbor%2Fharbor.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgoharbor%2Fharbor?ref=badge_large)
14 changes: 14 additions & 0 deletions api/v2.0/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7682,6 +7682,12 @@ definitions:
GeneralInfo:
type: object
properties:
banner_message:
type: string
x-nullable: true
x-omitempty: true
description: The banner message for the UI. It is the stringified result of the banner message object.
example: "{\"closable\":true,\"message\":\"your banner message content\",\"type\":\"warning\",\"fromDate\":\"06/19/2023\",\"toDate\":\"06/21/2023\"}"
current_time:
type: string
format: date-time
Expand Down Expand Up @@ -8820,6 +8826,9 @@ definitions:
session_timeout:
$ref: '#/definitions/IntegerConfigItem'
description: The session timeout in minutes
banner_message:
$ref: '#/definitions/StringConfigItem'
description: The banner message for the UI.It is the stringified result of the banner message object
Configurations:
type: object
properties:
Expand Down Expand Up @@ -9088,6 +9097,11 @@ definitions:
description: Whether or not to skip update pull time for scanner
x-omitempty: true
x-isnullable: true
banner_message:
type: string
description: The banner message for the UI.It is the stringified result of the banner message object
x-omitempty: true
x-isnullable: true
StringConfigItem:
type: object
properties:
Expand Down
3 changes: 3 additions & 0 deletions src/common/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ const (
// SessionTimeout defines the web session timeout
SessionTimeout = "session_timeout"

// Customized banner message
BannerMessage = "banner_message"

// UIMaxLengthLimitedOfNumber is the max length that UI limited for type number
UIMaxLengthLimitedOfNumber = 10
// ExecutionStatusRefreshIntervalSeconds is the interval seconds for refreshing execution status
Expand Down
8 changes: 8 additions & 0 deletions src/controller/systeminfo/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Data struct {
PrimaryAuthMode bool
SelfRegistration bool
HarborVersion string
BannerMessage string
AuthProxySettings *models.HTTPAuthProxy
Protected *protectedData
}
Expand Down Expand Up @@ -90,11 +91,18 @@ func (c *controller) GetInfo(ctx context.Context, opt Options) (*Data, error) {
logger.Errorf("Error occurred getting config: %v", err)
return nil, err
}
mgr := config.GetCfgManager(ctx)
err = mgr.Load(ctx)
if err != nil {
logger.Errorf("Error occurred loading context: %v", err)
return nil, err
}
res := &Data{
AuthMode: utils.SafeCastString(cfg[common.AUTHMode]),
PrimaryAuthMode: utils.SafeCastBool(cfg[common.PrimaryAuthMode]),
SelfRegistration: utils.SafeCastBool(cfg[common.SelfRegistration]),
HarborVersion: fmt.Sprintf("%s-%s", version.ReleaseVersion, version.GitCommit),
BannerMessage: utils.SafeCastString(mgr.Get(ctx, common.BannerMessage).GetString()),
}
if res.AuthMode == common.HTTPAuth {
if s, err := config.HTTPAuthProxySetting(ctx); err == nil {
Expand Down
3 changes: 3 additions & 0 deletions src/controller/systeminfo/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func (s *sysInfoCtlTestSuite) SetupTest() {
common.RegistryStorageProviderName: "filesystem",
common.ReadOnly: false,
common.NotificationEnable: false,
common.BannerMessage: "{\"closable\":false,\"message\":\"Just for test\",\"type\":\" error\"}",
}

config.InitWithSettings(conf)
Expand Down Expand Up @@ -58,6 +59,7 @@ func (s *sysInfoCtlTestSuite) TestGetInfo() {
AuthMode: "db_auth",
HarborVersion: "test-fakeid",
SelfRegistration: true,
BannerMessage: "{\"closable\":false,\"message\":\"Just for test\",\"type\":\" error\"}",
},
},
{
Expand All @@ -66,6 +68,7 @@ func (s *sysInfoCtlTestSuite) TestGetInfo() {
AuthMode: "db_auth",
HarborVersion: "test-fakeid",
SelfRegistration: true,
BannerMessage: "{\"closable\":false,\"message\":\"Just for test\",\"type\":\" error\"}",
Protected: &protectedData{
RegistryURL: "test.goharbor.io",
ExtURL: "https://test.goharbor.io",
Expand Down
2 changes: 2 additions & 0 deletions src/lib/config/metadata/metadatalist.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,5 +189,7 @@ var (
{Name: common.SessionTimeout, Scope: UserScope, Group: BasicGroup, EnvKey: "SESSION_TIMEOUT", DefaultValue: "60", ItemType: &Int64Type{}, Editable: true, Description: `The session timeout in minutes`},

{Name: common.ExecutionStatusRefreshIntervalSeconds, Scope: SystemScope, Group: BasicGroup, EnvKey: "EXECUTION_STATUS_REFRESH_INTERVAL_SECONDS", DefaultValue: "30", ItemType: &Int64Type{}, Editable: false, Description: `The interval seconds to refresh the execution status`},

{Name: common.BannerMessage, Scope: UserScope, Group: BasicGroup, EnvKey: "BANNER_MESSAGE", DefaultValue: "", ItemType: &StringType{}, Editable: true, Description: `The customized banner message for the UI`},
}
)
5 changes: 5 additions & 0 deletions src/lib/config/userconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,8 @@ func ScannerSkipUpdatePullTime(ctx context.Context) bool {
log.Infof("skip_update_pull_time:%v", DefaultMgr().Get(ctx, common.ScannerSkipUpdatePullTime).GetBool())
return DefaultMgr().Get(ctx, common.ScannerSkipUpdatePullTime).GetBool()
}

// BannerMessage returns the customized banner message
func BannerMessage(ctx context.Context) string {
return DefaultMgr().Get(ctx, common.BannerMessage).GetString()
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
<clr-alerts>
<clr-alert
*ngIf="hasValidBannerMessage() && isLogin()"
[clrAlertType]="getBannerMessageType()"
[clrAlertAppLevel]="true"
[clrAlertClosable]="getBannerMessageClosable()">
<clr-alert-item>
<span class="alert-text">{{ getBannerMessage() }}</span>
</clr-alert-item>
</clr-alert>
<clr-alert
*ngIf="showReadOnly && isLogin()"
[clrAlertType]="'warning'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import { MessageService } from '../../../shared/components/global-message/messag
import { Message } from '../../../shared/components/global-message/message';
import { JobServiceDashboardHealthCheckService } from '../../left-side-nav/job-service-dashboard/job-service-dashboard-health-check.service';
import { AppConfigService } from '../../../services/app-config.service';
import {
BannerMessage,
BannerMessageType,
} from '../../left-side-nav/config/config';
const HAS_SHOWED_SCANNER_INFO: string = 'hasShowScannerInfo';
const YES: string = 'yes';
@Component({
Expand Down Expand Up @@ -185,4 +189,79 @@ export class AppLevelAlertsComponent implements OnInit, OnDestroy {
isLogin(): boolean {
return !!this.session.getCurrentUser();
}

hasValidBannerMessage(): boolean {
if (
this.appConfigService.getConfig()?.banner_message &&
this.appConfigService.getConfig()?.current_time
) {
const current = new Date(
this.appConfigService.getConfig()?.current_time
);
const bm = JSON.parse(
this.appConfigService.getConfig()?.banner_message
) as BannerMessage;
if (bm?.fromDate && bm?.toDate) {
return (
new Date(current) <= new Date(bm.toDate) &&
new Date(current) >= new Date(bm.fromDate)
);
}
if (bm?.fromDate && !bm?.toDate) {
return new Date(current) >= new Date(bm.fromDate);
}

if (!bm?.fromDate && bm?.toDate) {
return new Date(current) <= new Date(bm.toDate);
}
}
return false;
}

getBannerMessage() {
if (
this.appConfigService.getConfig()?.banner_message &&
(
JSON.parse(
this.appConfigService.getConfig()?.banner_message
) as BannerMessage
)?.message
) {
return (
JSON.parse(
this.appConfigService.getConfig()?.banner_message
) as BannerMessage
)?.message;
}
return null;
}

getBannerMessageType() {
if (
this.appConfigService.getConfig()?.banner_message &&
(
JSON.parse(
this.appConfigService.getConfig()?.banner_message
) as BannerMessage
)?.type
) {
return (
JSON.parse(
this.appConfigService.getConfig()?.banner_message
) as BannerMessage
)?.type;
}
return BannerMessageType.WARNING;
}

getBannerMessageClosable(): boolean {
if (this.appConfigService.getConfig()?.banner_message) {
return (
JSON.parse(
this.appConfigService.getConfig()?.banner_message
) as BannerMessage
)?.closable;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { clone } from '../../../shared/units/utils';
import { MessageHandlerService } from '../../../shared/services/message-handler.service';
import { finalize } from 'rxjs/operators';
import { Observable, Subscription } from 'rxjs';
import {
EventService,
HarborEvent,
} from '../../../services/event-service/event.service';

const fakePass = 'aWpLOSYkIzJTTU4wMDkx';

Expand All @@ -24,7 +28,8 @@ export class ConfigService {
constructor(
private confirmService: ConfirmationDialogService,
private configureService: ConfigureService,
private msgHandler: MessageHandlerService
private msgHandler: MessageHandlerService,
private event: EventService
) {
this._confirmSub = this.confirmService.confirmationConfirm$.subscribe(
confirmation => {
Expand Down Expand Up @@ -66,6 +71,7 @@ export class ConfigService {
.subscribe(
res => {
this._currentConfig = res as Configuration;
this.event.publish(HarborEvent.REFRESH_BANNER_MESSAGE);
// Add password fields
this._currentConfig.email_password = new StringValueItem(
fakePass,
Expand Down
30 changes: 30 additions & 0 deletions src/portal/src/app/base/left-side-nav/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export class Configuration {
skip_audit_log_database: BoolValueItem;
session_timeout: NumberValueItem;
scanner_skip_update_pulltime: BoolValueItem;
banner_message: StringValueItem;
public constructor() {
this.auth_mode = new StringValueItem('db_auth', true);
this.primary_auth_mode = new BoolValueItem(false, true);
Expand Down Expand Up @@ -190,6 +191,10 @@ export class Configuration {
this.skip_audit_log_database = new BoolValueItem(false, true);
this.session_timeout = new NumberValueItem(60, true);
this.scanner_skip_update_pulltime = new BoolValueItem(false, true);
this.banner_message = new StringValueItem(
JSON.stringify(new BannerMessage()),
true
);
}
}

Expand All @@ -208,3 +213,28 @@ export enum Triggers {
SCHEDULE = 'Schedule',
EVENT = 'Event',
}

export class BannerMessage {
message: string;
closable: boolean;
type: string;
fromDate: Date;
toDate: Date;
constructor() {
this.closable = false;
}
}

export enum BannerMessageType {
SUCCESS = 'success',
INFO = 'info',
WARNING = 'warning',
ERROR = 'danger',
}

export const BannerMessageI18nMap = {
[BannerMessageType.SUCCESS]: 'BANNER_MESSAGE.SUCCESS',
[BannerMessageType.INFO]: 'BANNER_MESSAGE.INFO',
[BannerMessageType.WARNING]: 'BANNER_MESSAGE.WARNING',
[BannerMessageType.ERROR]: 'BANNER_MESSAGE.DANGER',
};
Loading

0 comments on commit ea204db

Please sign in to comment.