1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00
- Initial structure
- Implement flag where needed
- Apply dynamic styling
This commit is contained in:
Daniel Riera
2025-01-29 11:17:50 -05:00
committed by GitHub
parent e73cb3e3ff
commit d2fec919b3
3 changed files with 111 additions and 28 deletions

View File

@@ -14,6 +14,7 @@ import {
} from "@bitwarden/common/autofill/constants";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
@@ -80,6 +81,7 @@ export default class NotificationBackground {
bgGetExcludedDomains: () => this.getExcludedDomains(),
bgGetActiveUserServerConfig: () => this.getActiveUserServerConfig(),
getWebVaultUrlForNotification: () => this.getWebVaultUrl(),
notificationRefreshFlagValue: () => this.getNotificationFlag(),
};
private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id));
@@ -137,6 +139,15 @@ export default class NotificationBackground {
return await firstValueFrom(this.configService.serverConfig$);
}
/**
* Gets the current value of the notification refresh feature flag
* @returns Promise<boolean> indicating if the feature is enabled
*/
async getNotificationFlag(): Promise<boolean> {
const flagValue = await this.configService.getFeatureFlag(FeatureFlag.NotificationRefresh);
return flagValue;
}
private async getAuthStatus() {
return await firstValueFrom(this.authService.activeAccountStatus$);
}

View File

@@ -852,10 +852,10 @@ async function loadNotificationBar() {
}
closeBar(false);
openBar(type, notificationBarUrl, notificationBarInitData);
void openBar(type, notificationBarUrl, notificationBarInitData);
}
function openBar(
async function openBar(
type: string,
barPage: string,
notificationBarInitData: NotificationBarIframeInitData,
@@ -865,22 +865,38 @@ async function loadNotificationBar() {
if (document.body == null) {
return;
}
const useComponentBar: boolean = await sendExtensionMessage("notificationRefreshFlagValue");
setupInitNotificationBarMessageListener(notificationBarInitData);
const barPageUrl: string = chrome.runtime.getURL(barPage);
function getIframeStyle(useComponentBar: boolean): string {
return (
(useComponentBar
? "height: calc(276px + 25px); width: 450px; right: 0;"
: "height: 42px; width: 100%;") + " border: 0; min-height: initial;"
);
}
notificationBarIframe = document.createElement("iframe");
notificationBarIframe.style.cssText =
"height: 42px; width: 100%; border: 0; min-height: initial;";
notificationBarIframe.style.cssText = getIframeStyle(useComponentBar);
notificationBarIframe.id = "bit-notification-bar-iframe";
notificationBarIframe.src = barPageUrl;
function getFrameStyle(useComponentBar: boolean): string {
return (
(useComponentBar
? "height: calc(276px + 25px); width: 450px; right: 0;"
: "height: 42px; width: 100%; left: 0;") +
" top: 0; padding: 0; position: fixed;" +
" z-index: 2147483647; visibility: visible;"
);
}
const frameDiv = document.createElement("div");
frameDiv.setAttribute("aria-live", "polite");
frameDiv.id = "bit-notification-bar";
frameDiv.style.cssText =
"height: 42px; width: 100%; top: 0; left: 0; padding: 0; position: fixed; " +
"z-index: 2147483647; visibility: visible;";
frameDiv.style.cssText = getFrameStyle(useComponentBar);
frameDiv.appendChild(notificationBarIframe);
document.body.appendChild(frameDiv);

View File

@@ -1,10 +1,13 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { ThemeTypes } from "@bitwarden/common/platform/enums";
import { render } from "lit";
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { AdjustNotificationBarMessageData } from "../background/abstractions/notification.background";
import { NotificationContainer } from "../content/components/notification/container";
import { buildSvgDomElement } from "../utils";
import { circleCheckIcon } from "../utils/svg-icons";
@@ -12,15 +15,13 @@ import {
NotificationBarWindowMessageHandlers,
NotificationBarWindowMessage,
NotificationBarIframeInitData,
NotificationType,
} from "./abstractions/notification-bar";
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./bar.scss");
const logService = new ConsoleLogService(false);
let notificationBarIframeInitData: NotificationBarIframeInitData = {};
let windowMessageOrigin: string;
let useComponentBar = false;
const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers = {
initNotificationBar: ({ message }) => initNotificationBar(message),
saveCipherAttemptCompleted: ({ message }) => handleSaveCipherAttemptCompletedMessage(message),
@@ -29,6 +30,17 @@ const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers
globalThis.addEventListener("load", load);
function load() {
setupWindowMessageListener();
sendPlatformMessage({ command: "notificationRefreshFlagValue" }, (flagValue) => {
useComponentBar = flagValue;
applyNotificationBarStyle();
});
}
function applyNotificationBarStyle() {
if (!useComponentBar) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./bar.scss");
}
postMessageToParent({ command: "initNotificationBar" });
}
@@ -39,12 +51,7 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
}
notificationBarIframeInitData = initData;
const { isVaultLocked } = notificationBarIframeInitData;
setNotificationBarTheme();
(document.getElementById("logo") as HTMLImageElement).src = isVaultLocked
? chrome.runtime.getURL("images/icon38_locked.png")
: chrome.runtime.getURL("images/icon38.png");
const { isVaultLocked, theme } = notificationBarIframeInitData;
const i18n = {
appName: chrome.i18n.getMessage("appName"),
@@ -58,8 +65,50 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
notificationChangeDesc: chrome.i18n.getMessage("notificationChangeDesc"),
notificationUnlock: chrome.i18n.getMessage("notificationUnlock"),
notificationUnlockDesc: chrome.i18n.getMessage("notificationUnlockDesc"),
// @TODO move values to message catalog
saveAction: "Save",
saveAsNewLoginAction: "Save as new login",
updateLoginAction: "Update login",
saveLoginPrompt: "Save login?",
updateLoginPrompt: "Update existing login?",
loginSaveSuccess: "Login saved",
loginSaveSuccessDetails: "Login saved to Bitwarden.",
loginUpdateSuccess: "Login saved",
loginUpdateSuccessDetails: "Login updated in Bitwarden.",
saveFailure: "Error saving",
saveFailureDetails: "Oh no! We couldn't save this. Try entering the details as a New item",
};
if (useComponentBar) {
document.body.innerHTML = "";
// Current implementations utilize a require for scss files which creates the need to remove the node.
document.head.querySelectorAll('link[rel="stylesheet"]').forEach((node) => node.remove());
const themeType = getTheme(globalThis, theme);
// There are other possible passed theme values, but for now, resolve to dark or light
const resolvedTheme: Theme = themeType === ThemeTypes.Dark ? ThemeTypes.Dark : ThemeTypes.Light;
// @TODO use context to avoid prop drilling
return render(
NotificationContainer({
...notificationBarIframeInitData,
type: notificationBarIframeInitData.type as NotificationType,
theme: resolvedTheme,
handleCloseNotification,
i18n,
}),
document.body,
);
}
setNotificationBarTheme();
(document.getElementById("logo") as HTMLImageElement).src = isVaultLocked
? chrome.runtime.getURL("images/icon38_locked.png")
: chrome.runtime.getURL("images/icon38.png");
setupLogoLink(i18n);
// i18n for "Add" template
@@ -106,7 +155,7 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
closeButton.title = i18n.close;
const notificationType = initData.type;
if (initData.type === "add") {
if (notificationType === "add") {
handleTypeAdd();
} else if (notificationType === "change") {
handleTypeChange();
@@ -114,17 +163,19 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
handleTypeUnlock();
}
closeButton.addEventListener("click", (e) => {
e.preventDefault();
sendPlatformMessage({
command: "bgCloseNotificationBar",
});
});
closeButton.addEventListener("click", handleCloseNotification);
globalThis.addEventListener("resize", adjustHeight);
adjustHeight();
}
function handleCloseNotification(e: Event) {
e.preventDefault();
sendPlatformMessage({
command: "bgCloseNotificationBar",
});
}
function handleTypeAdd() {
setContent(document.getElementById("template-add") as HTMLTemplateElement);
@@ -317,14 +368,19 @@ function setupLogoLink(i18n: Record<string, string>) {
sendPlatformMessage({ command: "getWebVaultUrlForNotification" }, setWebVaultUrlLink);
}
function setNotificationBarTheme() {
let theme = notificationBarIframeInitData.theme;
function getTheme(globalThis: any, theme: NotificationBarIframeInitData["theme"]) {
if (theme === ThemeTypes.System) {
theme = globalThis.matchMedia("(prefers-color-scheme: dark)").matches
return globalThis.matchMedia("(prefers-color-scheme: dark)").matches
? ThemeTypes.Dark
: ThemeTypes.Light;
}
return theme;
}
function setNotificationBarTheme() {
const theme = getTheme(globalThis, notificationBarIframeInitData.theme);
document.documentElement.classList.add(`theme_${theme}`);
if (notificationBarIframeInitData.applyRedesign) {