mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +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:
@@ -1116,6 +1116,10 @@
|
|||||||
"message": "Update login",
|
"message": "Update login",
|
||||||
"description": "Button text for updating an existing login entry."
|
"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": {
|
"saveLogin": {
|
||||||
"message": "Save login",
|
"message": "Save login",
|
||||||
"description": "Prompt asking the user if they want to save their login details."
|
"description": "Prompt asking the user if they want to save their login details."
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export const mockI18n = {
|
|||||||
saveLogin: "Save login",
|
saveLogin: "Save login",
|
||||||
selectItemAriaLabel: "Select $ITEMTYPE$, $ITEMNAME$",
|
selectItemAriaLabel: "Select $ITEMTYPE$, $ITEMNAME$",
|
||||||
typeLogin: "Login",
|
typeLogin: "Login",
|
||||||
|
unlockToSave: "Unlock to save this login",
|
||||||
updateLoginAction: "Update login",
|
updateLoginAction: "Update login",
|
||||||
updateLogin: "Update existing login",
|
updateLogin: "Update existing login",
|
||||||
vault: "Vault",
|
vault: "Vault",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { css } from "@emotion/css";
|
import { css } from "@emotion/css";
|
||||||
import { html } from "lit";
|
import { html, nothing } from "lit";
|
||||||
|
|
||||||
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
|
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
|
||||||
|
|
||||||
@@ -47,14 +47,13 @@ export function NotificationContainer({
|
|||||||
type,
|
type,
|
||||||
}: NotificationContainerProps) {
|
}: NotificationContainerProps) {
|
||||||
const headerMessage = getHeaderMessage(i18n, type);
|
const headerMessage = getHeaderMessage(i18n, type);
|
||||||
const showBody = true;
|
const showBody = type !== NotificationTypes.Unlock;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class=${notificationContainerStyles(theme)}>
|
<div class=${notificationContainerStyles(theme)}>
|
||||||
${NotificationHeader({
|
${NotificationHeader({
|
||||||
handleCloseNotification,
|
handleCloseNotification,
|
||||||
message: headerMessage,
|
message: headerMessage,
|
||||||
standalone: showBody,
|
|
||||||
theme,
|
theme,
|
||||||
})}
|
})}
|
||||||
${showBody
|
${showBody
|
||||||
@@ -65,7 +64,7 @@ export function NotificationContainer({
|
|||||||
theme,
|
theme,
|
||||||
i18n,
|
i18n,
|
||||||
})
|
})
|
||||||
: null}
|
: nothing}
|
||||||
${NotificationFooter({
|
${NotificationFooter({
|
||||||
handleSaveAction,
|
handleSaveAction,
|
||||||
collections,
|
collections,
|
||||||
@@ -106,7 +105,7 @@ function getHeaderMessage(i18n: I18n, type?: NotificationType) {
|
|||||||
case NotificationTypes.Change:
|
case NotificationTypes.Change:
|
||||||
return i18n.updateLogin;
|
return i18n.updateLogin;
|
||||||
case NotificationTypes.Unlock:
|
case NotificationTypes.Unlock:
|
||||||
return "";
|
return i18n.unlockToSave;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,13 @@ export function NotificationFooter({
|
|||||||
handleSaveAction,
|
handleSaveAction,
|
||||||
}: NotificationFooterProps) {
|
}: NotificationFooterProps) {
|
||||||
const isChangeNotification = notificationType === NotificationTypes.Change;
|
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`
|
return html`
|
||||||
<div class=${notificationFooterStyles({ isChangeNotification })}>
|
<div class=${notificationFooterStyles({ isChangeNotification })}>
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ const notificationHeaderStyles = ({
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
${standalone
|
${standalone
|
||||||
? css`
|
? css``
|
||||||
|
: css`
|
||||||
border-bottom: 0.5px solid ${themes[theme].secondary["300"]};
|
border-bottom: 0.5px solid ${themes[theme].secondary["300"]};
|
||||||
`
|
`}
|
||||||
: css``}
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
NotificationBarWindowMessage,
|
NotificationBarWindowMessage,
|
||||||
NotificationBarIframeInitData,
|
NotificationBarIframeInitData,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
|
NotificationTypes,
|
||||||
} from "./abstractions/notification-bar";
|
} from "./abstractions/notification-bar";
|
||||||
|
|
||||||
const logService = new ConsoleLogService(false);
|
const logService = new ConsoleLogService(false);
|
||||||
@@ -85,6 +86,7 @@ function getI18n() {
|
|||||||
saveFailureDetails: chrome.i18n.getMessage("saveFailureDetails"),
|
saveFailureDetails: chrome.i18n.getMessage("saveFailureDetails"),
|
||||||
saveLogin: chrome.i18n.getMessage("saveLogin"),
|
saveLogin: chrome.i18n.getMessage("saveLogin"),
|
||||||
typeLogin: chrome.i18n.getMessage("typeLogin"),
|
typeLogin: chrome.i18n.getMessage("typeLogin"),
|
||||||
|
unlockToSave: chrome.i18n.getMessage("unlockToSave"),
|
||||||
updateLoginAction: chrome.i18n.getMessage("updateLoginAction"),
|
updateLoginAction: chrome.i18n.getMessage("updateLoginAction"),
|
||||||
updateLogin: chrome.i18n.getMessage("updateLogin"),
|
updateLogin: chrome.i18n.getMessage("updateLogin"),
|
||||||
vault: chrome.i18n.getMessage("vault"),
|
vault: chrome.i18n.getMessage("vault"),
|
||||||
@@ -149,6 +151,27 @@ async function initNotificationBar(message: NotificationBarWindowMessage) {
|
|||||||
document.body.innerHTML = "";
|
document.body.innerHTML = "";
|
||||||
// Current implementations utilize a require for scss files which creates the need to remove the node.
|
// 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());
|
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();
|
const orgId = selectedVaultSignal.get();
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
new Promise<OrgView[]>((resolve) =>
|
new Promise<OrgView[]>((resolve) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user