From eaadc3d8d578664555807615b41549766789eec2 Mon Sep 17 00:00:00 2001 From: Andrii Vorobiov Date: Wed, 13 Mar 2024 22:24:31 +0200 Subject: [PATCH 1/3] server: include license info into `uiconfig` endpoint response This change extends response for `uiconfig` endpoint which now contains information about license type and time until license expires. Release note: None --- pkg/server/server_http.go | 3 ++- pkg/server/server_test.go | 6 +++--- pkg/ui/BUILD.bazel | 1 + pkg/ui/ui.go | 13 +++++++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pkg/server/server_http.go b/pkg/server/server_http.go index b1bd3dcb3486..280c12d2b0c8 100644 --- a/pkg/server/server_http.go +++ b/pkg/server/server_http.go @@ -178,7 +178,8 @@ func (s *httpServer) setupRoutes( } return nil }, - Flags: flags, + Flags: flags, + Settings: s.cfg.Settings, }) // The authentication mux used here is created in "allow anonymous" mode so that the UI diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index 39e7fdebb6e0..ba1b2349137d 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -757,7 +757,7 @@ Binary built without web UI. respBytes, err = io.ReadAll(resp.Body) require.NoError(t, err) expected := fmt.Sprintf( - `{"Insecure":true,"LoggedInUser":null,"Tag":"%s","Version":"%s","NodeID":"%d","OIDCAutoLogin":false,"OIDCLoginEnabled":false,"OIDCButtonText":"","FeatureFlags":{"can_view_kv_metric_dashboards":true},"OIDCGenerateJWTAuthTokenEnabled":false}`, + `{"Insecure":true,"LoggedInUser":null,"Tag":"%s","Version":"%s","NodeID":"%d","OIDCAutoLogin":false,"OIDCLoginEnabled":false,"OIDCButtonText":"","FeatureFlags":{"can_view_kv_metric_dashboards":true},"OIDCGenerateJWTAuthTokenEnabled":false,"LicenseType":"OSS","SecondsUntilLicenseExpiry":0}`, build.GetInfo().Tag, build.BinaryVersionPrefix(), 1, @@ -785,7 +785,7 @@ Binary built without web UI. { loggedInClient, fmt.Sprintf( - `{"Insecure":false,"LoggedInUser":"authentic_user","Tag":"%s","Version":"%s","NodeID":"%d","OIDCAutoLogin":false,"OIDCLoginEnabled":false,"OIDCButtonText":"","FeatureFlags":{"can_view_kv_metric_dashboards":true},"OIDCGenerateJWTAuthTokenEnabled":false}`, + `{"Insecure":false,"LoggedInUser":"authentic_user","Tag":"%s","Version":"%s","NodeID":"%d","OIDCAutoLogin":false,"OIDCLoginEnabled":false,"OIDCButtonText":"","FeatureFlags":{"can_view_kv_metric_dashboards":true},"OIDCGenerateJWTAuthTokenEnabled":false,"LicenseType":"OSS","SecondsUntilLicenseExpiry":0}`, build.GetInfo().Tag, build.BinaryVersionPrefix(), 1, @@ -794,7 +794,7 @@ Binary built without web UI. { loggedOutClient, fmt.Sprintf( - `{"Insecure":false,"LoggedInUser":null,"Tag":"%s","Version":"%s","NodeID":"%d","OIDCAutoLogin":false,"OIDCLoginEnabled":false,"OIDCButtonText":"","FeatureFlags":{"can_view_kv_metric_dashboards":true},"OIDCGenerateJWTAuthTokenEnabled":false}`, + `{"Insecure":false,"LoggedInUser":null,"Tag":"%s","Version":"%s","NodeID":"%d","OIDCAutoLogin":false,"OIDCLoginEnabled":false,"OIDCButtonText":"","FeatureFlags":{"can_view_kv_metric_dashboards":true},"OIDCGenerateJWTAuthTokenEnabled":false,"LicenseType":"OSS","SecondsUntilLicenseExpiry":0}`, build.GetInfo().Tag, build.BinaryVersionPrefix(), 1, diff --git a/pkg/ui/BUILD.bazel b/pkg/ui/BUILD.bazel index 5f4438084faf..1d72a85aa200 100644 --- a/pkg/ui/BUILD.bazel +++ b/pkg/ui/BUILD.bazel @@ -20,6 +20,7 @@ go_library( "//pkg/build", "//pkg/server/serverpb", "//pkg/settings", + "//pkg/settings/cluster", "//pkg/util/httputil", "//pkg/util/log", ], diff --git a/pkg/ui/ui.go b/pkg/ui/ui.go index f579a4dbb310..23e0871069ef 100644 --- a/pkg/ui/ui.go +++ b/pkg/ui/ui.go @@ -29,6 +29,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/build" "github.com/cockroachdb/cockroach/pkg/server/serverpb" "github.com/cockroachdb/cockroach/pkg/settings" + "github.com/cockroachdb/cockroach/pkg/settings/cluster" "github.com/cockroachdb/cockroach/pkg/util/httputil" "github.com/cockroachdb/cockroach/pkg/util/log" ) @@ -92,6 +93,9 @@ type indexHTMLArgs struct { FeatureFlags serverpb.FeatureFlags OIDCGenerateJWTAuthTokenEnabled bool + + LicenseType string + SecondsUntilLicenseExpiry int64 } // OIDCUIConf is a variable that stores data required by the @@ -129,6 +133,7 @@ type Config struct { GetUser func(ctx context.Context) *string OIDC OIDCUI Flags serverpb.FeatureFlags + Settings *cluster.Settings } var uiConfigPath = regexp.MustCompile("^/uiconfig$") @@ -158,6 +163,11 @@ func Handler(cfg Config) http.Handler { buildInfo := build.GetInfo() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + licenseType, err := base.LicenseType(cfg.Settings) + if err != nil { + log.Errorf(context.Background(), "unable to get license type: %+v", err) + } + licenseTTL := base.LicenseTTL.Value() oidcConf := cfg.OIDC.GetOIDCConf() args := indexHTMLArgs{ Insecure: cfg.Insecure, @@ -170,6 +180,9 @@ func Handler(cfg Config) http.Handler { FeatureFlags: cfg.Flags, OIDCGenerateJWTAuthTokenEnabled: oidcConf.GenerateJWTAuthTokenEnabled, + + LicenseType: licenseType, + SecondsUntilLicenseExpiry: licenseTTL, } if cfg.NodeID != nil { args.NodeID = cfg.NodeID.String() From 52b0fd89cd736df4cf4c5465e3d773ad2d572e69 Mon Sep 17 00:00:00 2001 From: Andrii Vorobiov Date: Thu, 14 Mar 2024 13:57:49 +0200 Subject: [PATCH 2/3] ui: show license expiration alert in Db Console With this change, new alert message is shown in Db Console when license is expired or less than 15 days left before it will expire. This change doesn't affect clusters that doesn't have any license set. Release note (ui change): show alert message in Db Console when license is expired or less than 15 days left before it expires. --- .../cluster-ui/src/util/dataFromServer.ts | 2 + .../workspaces/db-console/src/redux/alerts.ts | 73 +++++++++++++++++++ .../workspaces/db-console/src/redux/state.ts | 2 + .../db-console/src/util/dataFromServer.ts | 2 + 4 files changed, 79 insertions(+) diff --git a/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts b/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts index 9ab79f896c2c..1ae945a12613 100644 --- a/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts @@ -22,6 +22,8 @@ export interface DataFromServer { OIDCButtonText: string; OIDCGenerateJWTAuthTokenEnabled: boolean; FeatureFlags: FeatureFlags; + LicenseType: string; + SecondsUntilLicenseExpiry: number; } // Tell TypeScript about `window.dataFromServer`, which is set in a script diff --git a/pkg/ui/workspaces/db-console/src/redux/alerts.ts b/pkg/ui/workspaces/db-console/src/redux/alerts.ts index e23dd006cccf..90fb109d3fe3 100644 --- a/pkg/ui/workspaces/db-console/src/redux/alerts.ts +++ b/pkg/ui/workspaces/db-console/src/redux/alerts.ts @@ -684,6 +684,78 @@ export const dataFromServerAlertSelector = createSelector( }, ); +const licenseTypeNames = new Map< + string, + "Trial" | "Enterprise" | "Non-Commercial" | "None" +>([ + ["Evaluation", "Trial"], + ["Enterprise", "Enterprise"], + ["NonCommercial", "Non-Commercial"], + ["OSS", "None"], + ["BSD", "None"], +]); + +// licenseTypeSelector returns user-friendly names of license types. +export const licenseTypeSelector = createSelector( + getDataFromServer, + data => licenseTypeNames.get(data.LicenseType) || "None", +); + +// daysUntilLicenseExpiresSelector returns number of days remaining before license expires. +export const daysUntilLicenseExpiresSelector = createSelector( + getDataFromServer, + data => { + return Math.ceil(data.SecondsUntilLicenseExpiry / 86400); // seconds in 1 day + }, +); + +export const showLicenseTTLLocalSetting = new LocalSetting( + "show_license_ttl", + localSettingsSelector, + { show: true }, +); + +export const showLicenseTTLAlertSelector = createSelector( + showLicenseTTLLocalSetting.selector, + daysUntilLicenseExpiresSelector, + licenseTypeSelector, + (showLicenseTTL, daysUntilLicenseExpired, licenseType): Alert => { + if (!showLicenseTTL.show) { + return; + } + if (licenseType === "None") { + return; + } + const daysToShowAlert = 14; + let title: string; + let level: AlertLevel; + + if (daysUntilLicenseExpired > daysToShowAlert) { + return; + } else if (daysUntilLicenseExpired < 0) { + title = `License expired ${Math.abs(daysUntilLicenseExpired)} days ago`; + level = AlertLevel.CRITICAL; + } else if (daysUntilLicenseExpired === 0) { + title = `License expired`; + level = AlertLevel.CRITICAL; + } else if (daysUntilLicenseExpired <= daysToShowAlert) { + title = `License expires in ${daysUntilLicenseExpired} days`; + level = AlertLevel.WARNING; + } + return { + level: level, + title: title, + showAsAlert: true, + autoClose: false, + closable: true, + dismiss: (dispatch: Dispatch) => { + dispatch(showLicenseTTLLocalSetting.set({ show: false })); + return Promise.resolve(); + }, + }; + }, +); + /** * Selector which returns an array of all active alerts which should be * displayed as a banner, which appears at the top of the page and overlaps @@ -698,6 +770,7 @@ export const bannerAlertsSelector = createSelector( terminateSessionAlertSelector, terminateQueryAlertSelector, dataFromServerAlertSelector, + showLicenseTTLAlertSelector, (...alerts: Alert[]): Alert[] => { return _.without(alerts, null, undefined); }, diff --git a/pkg/ui/workspaces/db-console/src/redux/state.ts b/pkg/ui/workspaces/db-console/src/redux/state.ts index 0dd8c6e680e0..028514d32ff7 100644 --- a/pkg/ui/workspaces/db-console/src/redux/state.ts +++ b/pkg/ui/workspaces/db-console/src/redux/state.ts @@ -66,6 +66,8 @@ const emptyDataFromServer: DataFromServer = { OIDCGenerateJWTAuthTokenEnabled: false, Tag: "", Version: "", + LicenseType: "OSS", + SecondsUntilLicenseExpiry: 0, }; export const featureFlagSelector = createSelector( diff --git a/pkg/ui/workspaces/db-console/src/util/dataFromServer.ts b/pkg/ui/workspaces/db-console/src/util/dataFromServer.ts index e1dac5af337b..d52a8866f378 100644 --- a/pkg/ui/workspaces/db-console/src/util/dataFromServer.ts +++ b/pkg/ui/workspaces/db-console/src/util/dataFromServer.ts @@ -22,6 +22,8 @@ export interface DataFromServer { OIDCButtonText: string; OIDCGenerateJWTAuthTokenEnabled: boolean; FeatureFlags: FeatureFlags; + LicenseType: string; + SecondsUntilLicenseExpiry: number; } // Tell TypeScript about `window.dataFromServer`, which is set in a script // tag in index.html, the contents of which are generated in a Go template From 1e770e1ba0b11eb2fd48dd05c97c9fc04d06fa5f Mon Sep 17 00:00:00 2001 From: David Hartunian Date: Mon, 19 Aug 2024 17:20:19 -0400 Subject: [PATCH 3/3] ui: add license change notification to db console This change adds a dismissable alert to the Overview page of DB Console that informs users about upcoming license changes. This popup is only shown if the cluster does not have an active "Enterprise" license The popup links to this page: "https://www.cockroachlabs.com/enterprise-license-update/" When the popup is dismissed, the dismissal is stored in the DB for this user and they don't see this notification again. Resolves: CRDB-40939 Release note (ui change): DB Console will show a notification alerting customers without an Enterprise license, to upcoming license changes with a link to more information. --- .../db-console/src/redux/alerts.spec.ts | 30 +++++ .../workspaces/db-console/src/redux/alerts.ts | 115 +++++++++++++++--- .../workspaces/db-console/src/redux/uiData.ts | 5 + pkg/ui/workspaces/db-console/src/util/docs.ts | 2 + .../shared/components/alertBox/alertbox.styl | 7 ++ .../shared/components/alertBox/index.tsx | 5 +- .../views/shared/components/icons/index.tsx | 15 ++- 7 files changed, 163 insertions(+), 16 deletions(-) diff --git a/pkg/ui/workspaces/db-console/src/redux/alerts.spec.ts b/pkg/ui/workspaces/db-console/src/redux/alerts.spec.ts index ed8ec55b89b3..f7c0028f0cb1 100644 --- a/pkg/ui/workspaces/db-console/src/redux/alerts.spec.ts +++ b/pkg/ui/workspaces/db-console/src/redux/alerts.spec.ts @@ -15,6 +15,7 @@ import { createHashHistory } from "history"; import * as protos from "src/js/protos"; import { cockroach } from "src/js/protos"; import { API_PREFIX } from "src/util/api"; +import { setDataFromServer } from "src/util/dataFromServer"; import fetchMock from "src/util/fetch-mock"; import { AdminUIState, AppDispatch, createAdminUIStore } from "./state"; @@ -31,11 +32,13 @@ import { emailSubscriptionAlertSelector, clusterPreserveDowngradeOptionDismissedSetting, clusterPreserveDowngradeOptionOvertimeSelector, + licenseUpdateNotificationSelector, } from "./alerts"; import { versionsSelector } from "src/redux/nodes"; import { VERSION_DISMISSED_KEY, INSTRUCTIONS_BOX_COLLAPSED_KEY, + LICENSE_UPDATE_DISMISSED_KEY, setUIDataKey, isInFlight, } from "./uiData"; @@ -47,6 +50,7 @@ import { healthReducerObj, settingsReducerObj, } from "./apiReducers"; + import Long from "long"; import MembershipStatus = cockroach.kv.kvserver.liveness.livenesspb.MembershipStatus; import { loginSuccess } from "./login"; @@ -257,6 +261,31 @@ describe("alerts", function () { }); }); + describe("licence update notification", function () { + it("displays the alert when nothing is done", function () { + dispatch(setUIDataKey(LICENSE_UPDATE_DISMISSED_KEY, null)); + const alert = licenseUpdateNotificationSelector(state()); + expect(typeof alert).toBe("object"); + expect(alert.level).toEqual(AlertLevel.INFORMATION); + expect(alert.text).toEqual( + "Important changes to CockroachDB’s licensing model.", + ); + }); + + it("hides the alert when dismissed timestamp is present", function () { + dispatch(setUIDataKey(LICENSE_UPDATE_DISMISSED_KEY, moment())); + expect(licenseUpdateNotificationSelector(state())).toBeUndefined(); + }); + + it("hides the alert when license is enterprise", function () { + dispatch(setUIDataKey(LICENSE_UPDATE_DISMISSED_KEY, null)); + setDataFromServer({ + LicenseType: "Enterprise", + } as any); + expect(licenseUpdateNotificationSelector(state())).toBeUndefined(); + }); + }); + describe("new version available notification", function () { it("displays nothing when versions have not yet been loaded", function () { dispatch(setUIDataKey(VERSION_DISMISSED_KEY, null)); @@ -630,6 +659,7 @@ describe("alerts", function () { ); dispatch(setUIDataKey(VERSION_DISMISSED_KEY, "blank")); dispatch(setUIDataKey(INSTRUCTIONS_BOX_COLLAPSED_KEY, false)); + dispatch(setUIDataKey(LICENSE_UPDATE_DISMISSED_KEY, moment())); dispatch( versionReducerObj.receiveData({ details: [], diff --git a/pkg/ui/workspaces/db-console/src/redux/alerts.ts b/pkg/ui/workspaces/db-console/src/redux/alerts.ts index 90fb109d3fe3..5f2a5f4b9cc2 100644 --- a/pkg/ui/workspaces/db-console/src/redux/alerts.ts +++ b/pkg/ui/workspaces/db-console/src/redux/alerts.ts @@ -21,6 +21,7 @@ import { ThunkAction } from "redux-thunk"; import { LocalSetting } from "./localsettings"; import { + LICENSE_UPDATE_DISMISSED_KEY, VERSION_DISMISSED_KEY, INSTRUCTIONS_BOX_COLLAPSED_KEY, saveUIData, @@ -55,6 +56,7 @@ export enum AlertLevel { WARNING, CRITICAL, SUCCESS, + INFORMATION, } export interface AlertInfo { @@ -629,20 +631,6 @@ export const upgradeNotFinalizedWarningSelector = createSelector( }, ); -/** - * Selector which returns an array of all active alerts which should be - * displayed in the overview list page, these should be non-critical alerts. - */ - -export const overviewListAlertsSelector = createSelector( - staggeredVersionWarningSelector, - clusterPreserveDowngradeOptionOvertimeSelector, - upgradeNotFinalizedWarningSelector, - (...alerts: Alert[]): Alert[] => { - return _.without(alerts, null, undefined); - }, -); - /** * Selector which returns an array of all active alerts which should be * displayed in the alerts panel, which is embedded within the cluster overview @@ -701,6 +689,104 @@ export const licenseTypeSelector = createSelector( data => licenseTypeNames.get(data.LicenseType) || "None", ); +export const licenseUpdateDismissedLocalSetting = new LocalSetting( + "license_update_dismissed", + localSettingsSelector, + moment(0), +); + +const licenseUpdateDismissedPersistentLoadedSelector = createSelector( + (state: AdminUIState) => state.uiData, + uiData => uiData && Object.hasOwn(uiData, LICENSE_UPDATE_DISMISSED_KEY), +); + +const licenseUpdateDismissedPersistentSelector = createSelector( + (state: AdminUIState) => state.uiData, + uiData => moment(uiData?.[LICENSE_UPDATE_DISMISSED_KEY]?.data ?? 0), +); + +export const licenseUpdateNotificationSelector = createSelector( + licenseTypeSelector, + licenseUpdateDismissedLocalSetting.selector, + licenseUpdateDismissedPersistentSelector, + licenseUpdateDismissedPersistentLoadedSelector, + ( + licenseType, + licenseUpdateDismissed, + licenseUpdateDismissedPersistent, + licenseUpdateDismissedPersistentLoaded, + ): Alert => { + // If customer has Enterprise license they don't need to worry about this. + if (licenseType === "Enterprise") { + return undefined; + } + + // If the notification has been dismissed based on the session storage + // timestamp, don't show it.' + // + // Note: `licenseUpdateDismissed` is wrapped in `moment()` because + // the local storage selector won't convert it back from a string. + // We omit fixing that here since this change is being backported + // to many versions. + if (moment(licenseUpdateDismissed).isAfter(moment(0))) { + return undefined; + } + + // If the notification has been dismissed based on the uiData + // storage in the cluster, don't show it. Note that this is + // different from how version upgrade notifications work, this one + // is dismissed forever and won't return even if you upgrade + // further or time passes. + if ( + licenseUpdateDismissedPersistentLoaded && + licenseUpdateDismissedPersistent && + licenseUpdateDismissedPersistent.isAfter(moment(0)) + ) { + return undefined; + } + + return { + level: AlertLevel.INFORMATION, + title: "Coming November 18, 2024", + text: "Important changes to CockroachDB’s licensing model.", + link: docsURL.enterpriseLicenseUpdate, + dismiss: (dispatch: any) => { + const dismissedAt = moment(); + // Note(davidh): I haven't been able to find historical context + // for why some alerts have both a "local" and a "persistent" + // dismissal. My thinking is that just the persistent dismissal + // should be adequate, but I'm preserving that behavior here to + // match the version upgrade notification. + + // Dismiss locally. + dispatch(licenseUpdateDismissedLocalSetting.set(dismissedAt)); + // Dismiss persistently. + return dispatch( + saveUIData({ + key: LICENSE_UPDATE_DISMISSED_KEY, + value: dismissedAt.valueOf(), + }), + ); + }, + }; + }, +); + +/** + * Selector which returns an array of all active alerts which should be + * displayed in the overview list page, these should be non-critical alerts. + */ + +export const overviewListAlertsSelector = createSelector( + staggeredVersionWarningSelector, + clusterPreserveDowngradeOptionOvertimeSelector, + upgradeNotFinalizedWarningSelector, + licenseUpdateNotificationSelector, + (...alerts: Alert[]): Alert[] => { + return _.without(alerts, null, undefined); + }, +); + // daysUntilLicenseExpiresSelector returns number of days remaining before license expires. export const daysUntilLicenseExpiresSelector = createSelector( getDataFromServer, @@ -817,6 +903,7 @@ export function alertDataSync(store: Store) { const keysToMaybeLoad = [ VERSION_DISMISSED_KEY, INSTRUCTIONS_BOX_COLLAPSED_KEY, + LICENSE_UPDATE_DISMISSED_KEY, ]; const keysToLoad = _.filter(keysToMaybeLoad, key => { return !(_.has(uiData, key) || isInFlight(state, key)); diff --git a/pkg/ui/workspaces/db-console/src/redux/uiData.ts b/pkg/ui/workspaces/db-console/src/redux/uiData.ts index afda71bb7c93..0eb3fc1c4300 100644 --- a/pkg/ui/workspaces/db-console/src/redux/uiData.ts +++ b/pkg/ui/workspaces/db-console/src/redux/uiData.ts @@ -56,6 +56,11 @@ export class OptInAttributes { // was last dismissed. export const VERSION_DISMISSED_KEY = "version_dismissed"; +// LICENSE_UPDATE_DISMISSED_KEY is the uiData key on the server that tracks when the licence +// update banner was last dismissed. This banner notifies the user that we've changed our +// licensing if they're deployed without an active license. +export const LICENSE_UPDATE_DISMISSED_KEY = "license_update_dismissed"; + // INSTRUCTIONS_BOX_COLLAPSED_KEY is the uiData key on the server that tracks whether the // instructions box on the cluster viz has been collapsed or not. export const INSTRUCTIONS_BOX_COLLAPSED_KEY = diff --git a/pkg/ui/workspaces/db-console/src/util/docs.ts b/pkg/ui/workspaces/db-console/src/util/docs.ts index ed10e8a36cf8..c964dab29cf8 100644 --- a/pkg/ui/workspaces/db-console/src/util/docs.ts +++ b/pkg/ui/workspaces/db-console/src/util/docs.ts @@ -62,6 +62,8 @@ export let sessionsTable: string; export let upgradeTroubleshooting: string; // Note that these explicitly don't use the current version, since we want to // link to the most up-to-date documentation available. +export const enterpriseLicenseUpdate = + "https://www.cockroachlabs.com/enterprise-license-update/"; export const upgradeCockroachVersion = "https://www.cockroachlabs.com/docs/stable/upgrade-cockroach-version.html"; export const enterpriseLicensing = diff --git a/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/alertbox.styl b/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/alertbox.styl index 3b80a4e2bd34..d0773a910572 100644 --- a/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/alertbox.styl +++ b/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/alertbox.styl @@ -46,6 +46,13 @@ border-color $notification-info-border-color background-color $notification-info-fill-color + &--information + color $body-color + border-color $notification-info-border-color + background-color $notification-info-fill-color + path + fill $colors--primary-blue-3 + &--warning color $body-color border-color $notification-warning-border-color diff --git a/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/index.tsx b/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/index.tsx index b1e7e600cf5e..5478349ca7cd 100644 --- a/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/index.tsx +++ b/pkg/ui/workspaces/db-console/src/views/shared/components/alertBox/index.tsx @@ -18,6 +18,7 @@ import { warningIcon, notificationIcon, criticalIcon, + informationIcon, } from "src/views/shared/components/icons"; import { trustIcon } from "src/util/trust"; @@ -27,6 +28,8 @@ function alertIcon(level: AlertLevel) { return trustIcon(criticalIcon); case AlertLevel.WARNING: return trustIcon(warningIcon); + case AlertLevel.INFORMATION: + return trustIcon(informationIcon); default: return trustIcon(notificationIcon); } @@ -49,7 +52,7 @@ export class AlertBox extends React.Component { const learnMore = this.props.link && ( - Learn More. + Learn More ); content = ( diff --git a/pkg/ui/workspaces/db-console/src/views/shared/components/icons/index.tsx b/pkg/ui/workspaces/db-console/src/views/shared/components/icons/index.tsx index 35bb1ec73f31..996caf04f651 100644 --- a/pkg/ui/workspaces/db-console/src/views/shared/components/icons/index.tsx +++ b/pkg/ui/workspaces/db-console/src/views/shared/components/icons/index.tsx @@ -98,7 +98,20 @@ export const warningIcon: string = ` + + + + + + + + + +`; + +export const notificationIcon = ` CL Mark