1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-21456] Notification bar does not appear when user is adding a new login when vault is locked (#14807)

* WiP if vault is locked, prompt to unlock and save with v3 notification

* add component handling for unlock notification type

* fix header component standalone mode

* fix header copy

* render unlock notification case on save with locked vault
This commit is contained in:
Jonathan Prusik
2025-05-15 17:42:46 -04:00
committed by GitHub
parent ad7c20febc
commit 14ced25561
6 changed files with 43 additions and 10 deletions

View File

@@ -1116,6 +1116,10 @@
"message": "Update login",
"description": "Button text for updating an existing login entry."
},
"unlockToSave": {
"message": "Unlock to save this login",
"description": "User prompt to take action in order to save the login they just entered."
},
"saveLogin": {
"message": "Save login",
"description": "Prompt asking the user if they want to save their login details."

View File

@@ -134,6 +134,7 @@ export const mockI18n = {
saveLogin: "Save login",
selectItemAriaLabel: "Select $ITEMTYPE$, $ITEMNAME$",
typeLogin: "Login",
unlockToSave: "Unlock to save this login",
updateLoginAction: "Update login",
updateLogin: "Update existing login",
vault: "Vault",

View File

@@ -1,5 +1,5 @@
import { css } from "@emotion/css";
import { html } from "lit";
import { html, nothing } from "lit";
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
@@ -47,14 +47,13 @@ export function NotificationContainer({
type,
}: NotificationContainerProps) {
const headerMessage = getHeaderMessage(i18n, type);
const showBody = true;
const showBody = type !== NotificationTypes.Unlock;
return html`
<div class=${notificationContainerStyles(theme)}>
${NotificationHeader({
handleCloseNotification,
message: headerMessage,
standalone: showBody,
theme,
})}
${showBody
@@ -65,7 +64,7 @@ export function NotificationContainer({
theme,
i18n,
})
: null}
: nothing}
${NotificationFooter({
handleSaveAction,
collections,
@@ -106,7 +105,7 @@ function getHeaderMessage(i18n: I18n, type?: NotificationType) {
case NotificationTypes.Change:
return i18n.updateLogin;
case NotificationTypes.Unlock:
return "";
return i18n.unlockToSave;
default:
return undefined;
}

View File

@@ -34,7 +34,13 @@ export function NotificationFooter({
handleSaveAction,
}: NotificationFooterProps) {
const isChangeNotification = notificationType === NotificationTypes.Change;
const primaryButtonText = i18n.saveAction;
const isUnlockNotification = notificationType === NotificationTypes.Unlock;
let primaryButtonText = i18n.saveAction;
if (isUnlockNotification) {
primaryButtonText = i18n.notificationUnlock;
}
return html`
<div class=${notificationFooterStyles({ isChangeNotification })}>

View File

@@ -56,8 +56,8 @@ const notificationHeaderStyles = ({
white-space: nowrap;
${standalone
? css`
? css``
: css`
border-bottom: 0.5px solid ${themes[theme].secondary["300"]};
`
: css``}
`}
`;

View File

@@ -19,6 +19,7 @@ import {
NotificationBarWindowMessage,
NotificationBarIframeInitData,
NotificationType,
NotificationTypes,
} from "./abstractions/notification-bar";
const logService = new ConsoleLogService(false);
@@ -85,6 +86,7 @@ function getI18n() {
saveFailureDetails: chrome.i18n.getMessage("saveFailureDetails"),
saveLogin: chrome.i18n.getMessage("saveLogin"),
typeLogin: chrome.i18n.getMessage("typeLogin"),
unlockToSave: chrome.i18n.getMessage("unlockToSave"),
updateLoginAction: chrome.i18n.getMessage("updateLoginAction"),
updateLogin: chrome.i18n.getMessage("updateLogin"),
vault: chrome.i18n.getMessage("vault"),
@@ -149,6 +151,27 @@ async 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());
if (isVaultLocked) {
return render(
NotificationContainer({
...notificationBarIframeInitData,
type: NotificationTypes.Unlock,
theme: resolvedTheme,
personalVaultIsAllowed: !personalVaultDisallowed,
handleCloseNotification,
handleSaveAction: (e) => {
sendSaveCipherMessage(true);
// @TODO can't close before vault has finished decrypting, but can't leave open during long decrypt because it looks like the experience has failed
},
handleEditOrUpdateAction,
i18n,
}),
document.body,
);
}
const orgId = selectedVaultSignal.get();
await Promise.all([
new Promise<OrgView[]>((resolve) =>