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

Merge branch 'main' into ps/PM-8297-improve-updater

This commit is contained in:
Daniel García
2025-05-13 14:04:40 +02:00
10 changed files with 69 additions and 53 deletions

View File

@@ -1088,22 +1088,13 @@
}
}
},
"loginSaveConfirmation": {
"message": "$ITEMNAME$ saved to Bitwarden.",
"placeholders": {
"itemName": {
"content": "$1"
}
},
"notificationLoginSaveConfirmation": {
"message": "saved to Bitwarden.",
"description": "Shown to user after item is saved."
},
"loginUpdatedConfirmation": {
"message": "$ITEMNAME$ updated in Bitwarden.",
"placeholders": {
"itemName": {
"content": "$1"
}
},
"notificationLoginUpdatedConfirmation": {
"message": "updated in Bitwarden.",
"description": "Shown to user after item is updated."
},
"saveAsNewLoginAction": {

View File

@@ -107,9 +107,9 @@ export const mockI18n = {
collection: "Collection",
folder: "Folder",
loginSaveSuccess: "Login saved",
loginSaveConfirmation: "$ITEMNAME$ saved to Bitwarden.",
notificationLoginSaveConfirmation: "saved to Bitwarden.",
loginUpdateSuccess: "Login updated",
loginUpdatedConfirmation: "$ITEMNAME$ updated in Bitwarden.",
notificationLoginUpdatedConfirmation: "updated in Bitwarden.",
loginUpdateTaskSuccess:
"Great job! You took the steps to make you and $ORGANIZATION$ more secure.",
loginUpdateTaskSuccessAdditional:

View File

@@ -113,9 +113,14 @@ function getConfirmationMessage(i18n: I18n, type?: NotificationType, error?: str
if (error) {
return i18n.saveFailureDetails;
}
/* @TODO This partial string return and later concatenation with the cipher name is needed
* to handle cipher name overflow cases, but is risky for i18n concerns. Fix concatenation
* with cipher name overflow when a tag replacement solution is available.
*/
return type === NotificationTypes.Add
? i18n.loginSaveConfirmation
: i18n.loginUpdatedConfirmation;
? i18n.notificationLoginSaveConfirmation
: i18n.notificationLoginUpdatedConfirmation;
}
function getHeaderMessage(i18n: I18n, type?: NotificationType, error?: string) {

View File

@@ -28,28 +28,31 @@ export function NotificationConfirmationMessage({
<div class=${containerStyles}>
${message || buttonText
? html`
<span class=${itemNameStyles(theme)} title=${itemName}> ${itemName} </span>
<span
title=${message || buttonText}
class=${notificationConfirmationMessageStyles(theme)}
>
${message || nothing}
${buttonText
? html`
<a
title=${buttonText}
class=${notificationConfirmationButtonTextStyles(theme)}
@click=${handleClick}
@keydown=${(e: KeyboardEvent) => handleButtonKeyDown(e, () => handleClick(e))}
aria-label=${buttonAria}
tabindex="0"
role="button"
>
${buttonText}
</a>
`
: nothing}
</span>
<div class=${singleLineWrapperStyles}>
<span class=${itemNameStyles(theme)} title=${itemName}> ${itemName} </span>
<span
title=${message || buttonText}
class=${notificationConfirmationMessageStyles(theme)}
>
${message || nothing}
${buttonText
? html`
<a
title=${buttonText}
class=${notificationConfirmationButtonTextStyles(theme)}
@click=${handleClick}
@keydown=${(e: KeyboardEvent) =>
handleButtonKeyDown(e, () => handleClick(e))}
aria-label=${buttonAria}
tabindex="0"
role="button"
>
${buttonText}
</a>
`
: nothing}
</span>
</div>
`
: nothing}
${messageDetails
@@ -61,12 +64,17 @@ export function NotificationConfirmationMessage({
const containerStyles = css`
display: flex;
flex-wrap: wrap;
align-items: center;
flex-direction: column;
gap: ${spacing[1]};
width: 100%;
`;
const singleLineWrapperStyles = css`
display: inline;
white-space: normal;
word-break: break-word;
`;
const baseTextStyles = css`
overflow-x: hidden;
text-align: left;
@@ -81,6 +89,9 @@ const notificationConfirmationMessageStyles = (theme: Theme) => css`
color: ${themes[theme].text.main};
font-weight: 400;
white-space: normal;
word-break: break-word;
display: inline;
`;
const itemNameStyles = (theme: Theme) => css`
@@ -90,6 +101,10 @@ const itemNameStyles = (theme: Theme) => css`
font-weight: 400;
white-space: nowrap;
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
vertical-align: bottom;
`;
const notificationConfirmationButtonTextStyles = (theme: Theme) => css`

View File

@@ -94,7 +94,7 @@ const notificationContainerStyles = (theme: Theme) => css`
}
[class*="${notificationBodyClassPrefix}-"] {
margin: ${spacing["3"]} 0 ${spacing["1.5"]} ${spacing["3"]};
margin: ${spacing["3"]} 0 0 ${spacing["3"]};
padding-right: ${spacing["3"]};
}
`;

View File

@@ -8,7 +8,7 @@ import {
NotificationTypes,
} from "../../../notification/abstractions/notification-bar";
import { OrgView, FolderView, I18n, CollectionView } from "../common-types";
import { spacing, themes } from "../constants/styles";
import { spacing } from "../constants/styles";
import { NotificationButtonRow } from "./button-row";
@@ -37,7 +37,7 @@ export function NotificationFooter({
const primaryButtonText = i18n.saveAction;
return html`
<div class=${notificationFooterStyles({ theme })}>
<div class=${notificationFooterStyles({ isChangeNotification })}>
${!isChangeNotification
? NotificationButtonRow({
collections,
@@ -56,13 +56,16 @@ export function NotificationFooter({
`;
}
const notificationFooterStyles = ({ theme }: { theme: Theme }) => css`
const notificationFooterStyles = ({
isChangeNotification,
}: {
isChangeNotification: boolean;
}) => css`
display: flex;
background-color: ${themes[theme].background.alt};
padding: 0 ${spacing[3]} ${spacing[3]} ${spacing[3]};
padding: ${spacing[2]} ${spacing[4]} ${isChangeNotification ? spacing[1] : spacing[4]}
${spacing[4]};
:last-child {
border-radius: 0 0 ${spacing["4"]} ${spacing["4"]};
padding-bottom: ${spacing[4]};
}
`;

View File

@@ -62,7 +62,7 @@ const buttonRowStyles = css`
> button {
max-width: min-content;
flex: 1 1 50%;
flex: 1 1 25%;
}
> div {

View File

@@ -59,9 +59,7 @@ function getI18n() {
collection: chrome.i18n.getMessage("collection"),
folder: chrome.i18n.getMessage("folder"),
loginSaveSuccess: chrome.i18n.getMessage("loginSaveSuccess"),
loginSaveConfirmation: chrome.i18n.getMessage("loginSaveConfirmation"),
loginUpdateSuccess: chrome.i18n.getMessage("loginUpdateSuccess"),
loginUpdatedConfirmation: chrome.i18n.getMessage("loginUpdatedConfirmation"),
loginUpdateTaskSuccess: chrome.i18n.getMessage("loginUpdateTaskSuccess"),
loginUpdateTaskSuccessAdditional: chrome.i18n.getMessage("loginUpdateTaskSuccessAdditional"),
nextSecurityTaskAction: chrome.i18n.getMessage("nextSecurityTaskAction"),
@@ -74,6 +72,10 @@ function getI18n() {
notificationUpdate: chrome.i18n.getMessage("notificationChangeSave"),
notificationEdit: chrome.i18n.getMessage("edit"),
notificationEditTooltip: chrome.i18n.getMessage("notificationEditTooltip"),
notificationLoginSaveConfirmation: chrome.i18n.getMessage("notificationLoginSaveConfirmation"),
notificationLoginUpdatedConfirmation: chrome.i18n.getMessage(
"notificationLoginUpdatedConfirmation",
),
notificationUnlock: chrome.i18n.getMessage("notificationUnlock"),
notificationUnlockDesc: chrome.i18n.getMessage("notificationUnlockDesc"),
notificationViewAria: chrome.i18n.getMessage("notificationViewAria"),

View File

@@ -22,6 +22,7 @@ import { DangerZoneComponent } from "../auth/settings/account/danger-zone.compon
import { DeauthorizeSessionsComponent } from "../auth/settings/account/deauthorize-sessions.component";
import { DeleteAccountDialogComponent } from "../auth/settings/account/delete-account-dialog.component";
import { ProfileComponent } from "../auth/settings/account/profile.component";
import { SelectableAvatarComponent } from "../auth/settings/account/selectable-avatar.component";
import { EmergencyAccessConfirmComponent } from "../auth/settings/emergency-access/confirm/emergency-access-confirm.component";
import { EmergencyAccessAddEditComponent } from "../auth/settings/emergency-access/emergency-access-add-edit.component";
import { EmergencyAccessComponent } from "../auth/settings/emergency-access/emergency-access.component";
@@ -39,7 +40,6 @@ import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.comp
import { SponsoredFamiliesComponent } from "../billing/settings/sponsored-families.component";
import { SponsoringOrgRowComponent } from "../billing/settings/sponsoring-org-row.component";
import { DynamicAvatarComponent } from "../components/dynamic-avatar.component";
import { SelectableAvatarComponent } from "../components/selectable-avatar.component";
import { ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent } from "../dirt/reports/pages/organizations/exposed-passwords-report.component";
import { InactiveTwoFactorReportComponent as OrgInactiveTwoFactorReportComponent } from "../dirt/reports/pages/organizations/inactive-two-factor-report.component";
import { ReusedPasswordsReportComponent as OrgReusedPasswordsReportComponent } from "../dirt/reports/pages/organizations/reused-passwords-report.component";