mirror of
https://github.com/bitwarden/browser
synced 2025-12-24 04:04:24 +00:00
[PM-17487] Load cipher data into new notification experience (#13185)
* PM-17487 - Initial structure - Implement new getNotificationCipherData function in background - Update stories to match new naming - Edit types to be relevant to current functionality * update jsdoc * export types so eslint does not treat them as unused * -Fix types -Promise.all on background * clean comments
This commit is contained in:
@@ -25,6 +25,7 @@ import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-stat
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { buildCipherIcon } from "@bitwarden/common/vault/icon/build-cipher-icon";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
||||
@@ -32,6 +33,7 @@ import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
||||
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window";
|
||||
import { NotificationCipherData } from "../content/components/cipher/types";
|
||||
import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum";
|
||||
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||
|
||||
@@ -82,6 +84,7 @@ export default class NotificationBackground {
|
||||
bgGetActiveUserServerConfig: () => this.getActiveUserServerConfig(),
|
||||
getWebVaultUrlForNotification: () => this.getWebVaultUrl(),
|
||||
notificationRefreshFlagValue: () => this.getNotificationFlag(),
|
||||
bgGetDecryptedCiphers: () => this.getNotificationCipherData(),
|
||||
};
|
||||
|
||||
private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id));
|
||||
@@ -132,6 +135,40 @@ export default class NotificationBackground {
|
||||
return await firstValueFrom(this.domainSettingsService.neverDomains$);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Gets the current active tab and retrieves all decrypted ciphers
|
||||
* for the tab's URL. It constructs and returns an array of `NotificationCipherData` objects.
|
||||
* If no active tab or URL is found, it returns an empty array.
|
||||
*
|
||||
* @returns {Promise<NotificationCipherData[]>}
|
||||
*/
|
||||
|
||||
async getNotificationCipherData(): Promise<NotificationCipherData[]> {
|
||||
const [currentTab, showFavicons, env] = await Promise.all([
|
||||
BrowserApi.getTabFromCurrentWindow(),
|
||||
firstValueFrom(this.domainSettingsService.showFavicons$),
|
||||
firstValueFrom(this.environmentService.environment$),
|
||||
]);
|
||||
const iconsServerUrl = env.getIconsUrl();
|
||||
const decryptedCiphers = await this.cipherService.getAllDecryptedForUrl(currentTab.url);
|
||||
|
||||
return decryptedCiphers.map((view) => {
|
||||
const { id, name, reprompt, favorite, login } = view;
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
type: CipherType.Login,
|
||||
reprompt,
|
||||
favorite,
|
||||
icon: buildCipherIcon(iconsServerUrl, view, showFavicons),
|
||||
login: login && {
|
||||
username: login.username,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the active user server config from the config service.
|
||||
*/
|
||||
|
||||
@@ -6,10 +6,10 @@ import { Theme } from "@bitwarden/common/platform/enums";
|
||||
import { themes, typography } from "../../../content/components/constants/styles";
|
||||
|
||||
import { CipherInfoIndicatorIcons } from "./cipher-indicator-icons";
|
||||
import { CipherData } from "./types";
|
||||
import { NotificationCipherData } from "./types";
|
||||
|
||||
// @TODO support other cipher types (card, identity, notes, etc)
|
||||
export function CipherInfo({ cipher, theme }: { cipher: CipherData; theme: Theme }) {
|
||||
export function CipherInfo({ cipher, theme }: { cipher: NotificationCipherData; theme: Theme }) {
|
||||
const { name, login } = cipher;
|
||||
|
||||
return html`
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { CipherAction } from "./cipher-action";
|
||||
import { CipherIcon } from "./cipher-icon";
|
||||
import { CipherInfo } from "./cipher-info";
|
||||
import { CipherData } from "./types";
|
||||
import { NotificationCipherData } from "./types";
|
||||
|
||||
const cipherIconWidth = "24px";
|
||||
|
||||
@@ -22,7 +22,7 @@ export function CipherItem({
|
||||
notificationType,
|
||||
theme = ThemeTypes.Light,
|
||||
}: {
|
||||
cipher: CipherData;
|
||||
cipher: NotificationCipherData;
|
||||
handleAction?: (e: Event) => void;
|
||||
notificationType?: NotificationType;
|
||||
theme: Theme;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const CipherTypes = {
|
||||
export const CipherTypes = {
|
||||
Login: 1,
|
||||
SecureNote: 2,
|
||||
Card: 3,
|
||||
@@ -9,9 +7,7 @@ const CipherTypes = {
|
||||
|
||||
type CipherType = (typeof CipherTypes)[keyof typeof CipherTypes];
|
||||
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const CipherRepromptTypes = {
|
||||
export const CipherRepromptTypes = {
|
||||
None: 0,
|
||||
Password: 1,
|
||||
} as const;
|
||||
@@ -25,13 +21,16 @@ export type WebsiteIconData = {
|
||||
icon: string;
|
||||
};
|
||||
|
||||
export type CipherData = {
|
||||
type BaseCipherData<CipherTypeValue> = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: CipherType;
|
||||
type: CipherTypeValue;
|
||||
reprompt: CipherRepromptType;
|
||||
favorite: boolean;
|
||||
icon: WebsiteIconData;
|
||||
};
|
||||
|
||||
export type CipherData = BaseCipherData<CipherType> & {
|
||||
accountCreationFieldType?: string;
|
||||
login?: {
|
||||
username: string;
|
||||
@@ -46,3 +45,9 @@ export type CipherData = {
|
||||
username?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type NotificationCipherData = BaseCipherData<typeof CipherTypes.Login> & {
|
||||
login?: {
|
||||
username: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,11 +5,11 @@ import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
|
||||
import { NotificationType } from "../../../../notification/abstractions/notification-bar";
|
||||
import { CipherData } from "../../cipher/types";
|
||||
import { NotificationCipherData } from "../../cipher/types";
|
||||
import { NotificationBody } from "../../notification/body";
|
||||
|
||||
type Args = {
|
||||
ciphers: CipherData[];
|
||||
ciphers: NotificationCipherData[];
|
||||
notificationType: NotificationType;
|
||||
theme: Theme;
|
||||
};
|
||||
@@ -38,7 +38,7 @@ export default {
|
||||
fallbackImage: "https://example.com/fallback.png",
|
||||
icon: "icon-class",
|
||||
},
|
||||
login: { username: "user@example.com", passkey: null },
|
||||
login: { username: "user@example.com" },
|
||||
},
|
||||
],
|
||||
theme: ThemeTypes.Light,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
|
||||
|
||||
import { NotificationType } from "../../../notification/abstractions/notification-bar";
|
||||
import { CipherItem } from "../cipher";
|
||||
import { CipherData } from "../cipher/types";
|
||||
import { NotificationCipherData } from "../cipher/types";
|
||||
import { scrollbarStyles, spacing, themes, typography } from "../constants/styles";
|
||||
import { ItemRow } from "../rows/item-row";
|
||||
|
||||
@@ -20,7 +20,7 @@ export function NotificationBody({
|
||||
notificationType,
|
||||
theme = ThemeTypes.Light,
|
||||
}: {
|
||||
ciphers: CipherData[];
|
||||
ciphers: NotificationCipherData[];
|
||||
customClasses?: string[];
|
||||
notificationType?: NotificationType;
|
||||
theme: Theme;
|
||||
|
||||
@@ -8,8 +8,7 @@ import {
|
||||
NotificationTypes,
|
||||
NotificationType,
|
||||
} from "../../../notification/abstractions/notification-bar";
|
||||
import { createAutofillOverlayCipherDataMock } from "../../../spec/autofill-mocks";
|
||||
import { CipherData } from "../cipher/types";
|
||||
import { NotificationCipherData } from "../cipher/types";
|
||||
import { themes, spacing } from "../constants/styles";
|
||||
|
||||
import { NotificationBody, componentClassPrefix as notificationBodyClassPrefix } from "./body";
|
||||
@@ -24,23 +23,15 @@ export function NotificationContainer({
|
||||
i18n,
|
||||
theme = ThemeTypes.Light,
|
||||
type,
|
||||
ciphers,
|
||||
}: NotificationBarIframeInitData & { handleCloseNotification: (e: Event) => void } & {
|
||||
i18n: { [key: string]: string };
|
||||
type: NotificationType; // @TODO typing override for generic `NotificationBarIframeInitData.type`
|
||||
ciphers: NotificationCipherData[];
|
||||
}) {
|
||||
const headerMessage = getHeaderMessage(i18n, type);
|
||||
const showBody = true;
|
||||
|
||||
// @TODO remove mock ciphers for development
|
||||
const ciphers = [
|
||||
createAutofillOverlayCipherDataMock(1),
|
||||
{ ...createAutofillOverlayCipherDataMock(2), icon: { imageEnabled: false } },
|
||||
{
|
||||
...createAutofillOverlayCipherDataMock(3),
|
||||
icon: { imageEnabled: true, image: "https://localhost:8443/icons/webtests.dev/icon.png" },
|
||||
},
|
||||
] as CipherData[];
|
||||
|
||||
return html`
|
||||
<div class=${notificationContainerStyles(theme)}>
|
||||
${NotificationHeader({
|
||||
|
||||
@@ -84,23 +84,25 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
|
||||
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,
|
||||
);
|
||||
sendPlatformMessage({ command: "bgGetDecryptedCiphers" }, (cipherData) => {
|
||||
// @TODO use context to avoid prop drilling
|
||||
return render(
|
||||
NotificationContainer({
|
||||
...notificationBarIframeInitData,
|
||||
type: notificationBarIframeInitData.type as NotificationType,
|
||||
theme: resolvedTheme,
|
||||
handleCloseNotification,
|
||||
i18n,
|
||||
ciphers: cipherData,
|
||||
}),
|
||||
document.body,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
setNotificationBarTheme();
|
||||
|
||||
Reference in New Issue
Block a user