1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-20 02:03:39 +00:00

[PM-14909] Build components for security task completion notification (#14230)

* squash split component work from pm-14909

* fix typing
This commit is contained in:
Jonathan Prusik
2025-04-11 15:16:30 -04:00
committed by GitHub
parent 5006a29546
commit d5b7af75e9
22 changed files with 730 additions and 121 deletions

View File

@@ -1098,6 +1098,31 @@
"message": "Login updated", "message": "Login updated",
"description": "Message displayed when login details are successfully updated." "description": "Message displayed when login details are successfully updated."
}, },
"loginUpdateTaskSuccess": {
"message": "Great job! You took the steps to make you and $ORGANIZATION$ more secure.",
"placeholders": {
"organization": {
"content": "$1"
}
},
"description": "Shown to user after login is updated."
},
"loginUpdateTaskSuccessAdditional": {
"message": "Thank you for making $ORGANIZATION$ more secure. You have $TASK_COUNT$ more passwords to update.",
"placeholders": {
"organization": {
"content": "$1"
},
"task_count": {
"content": "$2"
}
},
"description": "Shown to user after login is updated."
},
"nextSecurityTaskAction": {
"message": "Change next password",
"description": "Message prompting user to undertake completion of another security task."
},
"saveFailure": { "saveFailure": {
"message": "Error saving", "message": "Error saving",
"description": "Error message shown when the system fails to save login details." "description": "Error message shown when the system fails to save login details."

View File

@@ -1,5 +1,5 @@
import { css } from "@emotion/css"; import { css } from "@emotion/css";
import { html } from "lit"; import { html, TemplateResult } from "lit";
import { Theme } from "@bitwarden/common/platform/enums"; import { Theme } from "@bitwarden/common/platform/enums";
@@ -11,7 +11,7 @@ export function ActionButton({
theme, theme,
handleClick, handleClick,
}: { }: {
buttonText: string; buttonText: string | TemplateResult;
disabled?: boolean; disabled?: boolean;
theme: Theme; theme: Theme;
handleClick: (e: Event) => void; handleClick: (e: Event) => void;
@@ -63,4 +63,9 @@ const actionButtonStyles = ({ disabled, theme }: { disabled: boolean; theme: The
color: ${themes[theme].text.contrast}; color: ${themes[theme].text.contrast};
} }
`} `}
svg {
width: fit-content;
height: 16px;
}
`; `;

View File

@@ -0,0 +1,22 @@
import { css } from "@emotion/css";
import { html } from "lit";
import { IconProps } from "../common-types";
import { buildIconColorRule, ruleNames, themes } from "../constants/styles";
export function ExternalLink({ color, disabled, theme }: IconProps) {
const shapeColor = disabled ? themes[theme].secondary["300"] : color || themes[theme].text.main;
return html`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" fill="none">
<path
class=${css(buildIconColorRule(shapeColor, ruleNames.fill))}
d="M1.5 2.75c0-.69.56-1.25 1.25-1.25h3.5a.75.75 0 0 0 0-1.5h-3.5A2.75 2.75 0 0 0 0 2.75v8.5A2.75 2.75 0 0 0 2.75 14h8.5A2.75 2.75 0 0 0 14 11.25v-3.5a.75.75 0 0 0-1.5 0v3.5c0 .69-.56 1.25-1.25 1.25h-8.5c-.69 0-1.25-.56-1.25-1.25v-8.5Z"
/>
<path
class=${css(buildIconColorRule(shapeColor, ruleNames.fill))}
d="M9.75 0a.75.75 0 0 0 0 1.5h1.69L7.22 5.72a.75.75 0 0 0 1.06 1.06l4.22-4.22v1.69a.75.75 0 0 0 1.5 0V.75a.75.75 0 0 0-.75-.75h-3.5Z"
/>
</svg>
`;
}

View File

@@ -4,9 +4,11 @@ export { BrandIconContainer } from "./brand-icon-container";
export { Business } from "./business"; export { Business } from "./business";
export { Close } from "./close"; export { Close } from "./close";
export { ExclamationTriangle } from "./exclamation-triangle"; export { ExclamationTriangle } from "./exclamation-triangle";
export { ExternalLink } from "./external-link";
export { Family } from "./family"; export { Family } from "./family";
export { Folder } from "./folder"; export { Folder } from "./folder";
export { Globe } from "./globe"; export { Globe } from "./globe";
export { Keyhole } from "./keyhole";
export { PartyHorn } from "./party-horn"; export { PartyHorn } from "./party-horn";
export { PencilSquare } from "./pencil-square"; export { PencilSquare } from "./pencil-square";
export { Shield } from "./shield"; export { Shield } from "./shield";

View File

@@ -0,0 +1,222 @@
import { html } from "lit";
import { ThemeTypes } from "@bitwarden/common/platform/enums";
import { IconProps } from "../common-types";
// This icon has static multi-colors for each theme
export function Keyhole({ theme }: IconProps) {
if (theme === ThemeTypes.Dark) {
return html`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" fill="none">
<path
fill="#79A1E9"
fill-rule="evenodd"
d="M64.985 64.083c-.363-1.654.37-3.337 1.72-4.36C74.175 54.063 79 45.095 79 35 79 17.88 65.12 4 48 4 30.88 4 17 17.88 17 35c0 10.095 4.825 19.063 12.295 24.723 1.35 1.023 2.083 2.706 1.72 4.36l-5.947 27.058A4 4 0 0 0 28.975 96h38.05a4 4 0 0 0 3.907-4.859l-5.947-27.058Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M65.497 58.13C72.489 52.83 77 44.441 77 35 77 18.984 64.016 6 48 6S19 18.984 19 35c0 9.443 4.51 17.83 11.503 23.13 1.888 1.43 3.017 3.869 2.465 6.383L27.021 91.57A2 2 0 0 0 28.975 94h38.05a2 2 0 0 0 1.954-2.43l-5.947-27.057c-.552-2.514.577-4.954 2.465-6.384Zm1.208 1.593c-1.35 1.023-2.083 2.706-1.72 4.36l5.947 27.058A4 4 0 0 1 67.025 96h-38.05a4 4 0 0 1-3.907-4.859l5.947-27.058c.363-1.654-.37-3.337-1.72-4.36C21.825 54.063 17 45.095 17 35 17 17.88 30.88 4 48 4c17.12 0 31 13.88 31 31 0 10.095-4.825 19.063-12.295 24.723Z"
clip-rule="evenodd"
/>
<path
fill="#AAC3EF"
fill-rule="evenodd"
d="M20.864 50H46a4 4 0 0 0 4-4V30a4 4 0 0 0-4-4H20c-.647 0-1.258.154-1.8.427C17.42 29.149 17 32.026 17 35a30.86 30.86 0 0 0 3.864 15Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M22.07 48H46a2 2 0 0 0 2-2V30a2 2 0 0 0-2-2H20c-.051 0-.102.002-.151.006A29.072 29.072 0 0 0 19 35c0 4.678 1.106 9.092 3.07 13Zm-1.206 2H46a4 4 0 0 0 4-4V30a4 4 0 0 0-4-4H20c-.647 0-1.258.154-1.8.427C17.42 29.149 17 32.026 17 35a30.86 30.86 0 0 0 3.864 15Z"
clip-rule="evenodd"
/>
<path
fill="#79A1E9"
d="M18 31h30v4H18v-4ZM21 44a1 1 0 0 1 1-1h4a1 1 0 1 1 0 2h-4a1 1 0 0 1-1-1ZM29 44a1 1 0 0 1 1-1h9a1 1 0 1 1 0 2h-9a1 1 0 0 1-1-1Z"
/>
<path
fill="#AAC3EF"
fill-rule="evenodd"
d="M78.954 33.303A3.99 3.99 0 0 0 76 32H50a4 4 0 0 0-4 4v16a4 4 0 0 0 4 4h20.804A30.889 30.889 0 0 0 79 35a31.5 31.5 0 0 0-.046-1.697Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M76.99 34.262A1.987 1.987 0 0 0 76 34H50a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h19.91a28.88 28.88 0 0 0 7.08-19.738Zm1.964-.959A3.99 3.99 0 0 0 76 32H50a4 4 0 0 0-4 4v16a4 4 0 0 0 4 4h20.804A30.889 30.889 0 0 0 79 35a31.5 31.5 0 0 0-.046-1.697Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
d="M66 39a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1ZM66 43a1 1 0 0 1 1-1h3a1 1 0 1 1 0 2h-3a1 1 0 0 1-1-1Z"
/>
<path fill="#F3F6F9" d="M62 40a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z" />
<path
fill="#175DDC"
fill-rule="evenodd"
d="M58 42a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 2a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"
clip-rule="evenodd"
/>
<path
fill="#F3F6F9"
d="M65.391 48.269c.402 1.035.609 1.86.609 2.981a.75.75 0 0 1-.75.75h-14.5a.75.75 0 0 1-.75-.75c0-1.12.207-1.946.609-2.981a8.593 8.593 0 0 1 1.734-2.77 7.987 7.987 0 0 1 2.595-1.85C55.91 43.222 56.95 43 58 43c1.05 0 2.09.22 3.062.65a7.987 7.987 0 0 1 2.595 1.85 8.593 8.593 0 0 1 1.734 2.769Z"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M52.343 45.5a8.593 8.593 0 0 0-1.734 2.769c-.402 1.035-.609 1.86-.609 2.981 0 .414.336.75.75.75h14.5a.75.75 0 0 0 .75-.75c0-1.12-.207-1.946-.609-2.981a8.593 8.593 0 0 0-1.734-2.77 7.987 7.987 0 0 0-2.595-1.85A7.569 7.569 0 0 0 58 43c-1.05 0-2.09.22-3.062.65a7.987 7.987 0 0 0-2.595 1.85ZM63.857 50a8.12 8.12 0 0 0-.33-1.008 6.593 6.593 0 0 0-1.33-2.124l1.414-1.326-1.413 1.325a5.986 5.986 0 0 0-1.945-1.388A5.568 5.568 0 0 0 58 45c-.77 0-1.535.161-2.253.479a5.986 5.986 0 0 0-1.945 1.389 6.593 6.593 0 0 0-1.329 2.124 8.12 8.12 0 0 0-.33 1.008h11.714Z"
clip-rule="evenodd"
/>
<path
fill="#AAC3EF"
fill-rule="evenodd"
d="M67.604 76H48a8 8 0 0 0 0 16h23.027c0-.282-.031-.57-.095-.859L67.604 76Zm-38.769-2H50a8 8 0 1 0 0-16H27.215a31.14 31.14 0 0 0 2.08 1.723c1.35 1.023 2.083 2.706 1.72 4.36L28.835 74Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M29.628 60c1.134 1.034 1.719 2.571 1.387 4.083L28.835 74H50a8 8 0 1 0 0-16H27.215a31.14 31.14 0 0 0 2.08 1.723c.116.088.227.18.333.277Zm2.562 0c.792 1.307 1.134 2.894.778 4.513L31.322 72H50a6 6 0 1 0 0-12H32.19Zm33.806 18H48a6 6 0 0 0 0 12h20.633l-2.637-12Zm1.608-2H48a8 8 0 0 0 0 16h23.027c0-.282-.031-.57-.095-.859L67.604 76Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="m69.06 82.627-1.056.346v-1.4a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.832 1.167a1 1 0 0 0 1.627 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167.883-.29-.431-1.962ZM29.819 69.526a.996.996 0 0 0 .376-.318l.81-1.135.81 1.135a1 1 0 1 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 1 0-.623-1.901l-1.312.43v-1.4a1 1 0 0 0-.95-.999c.08.493.072 1.002-.04 1.51l-1.195 5.442Zm11.186-5.953a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.832 1.167a1 1 0 0 0 1.627 1.162l.81-1.135.81 1.135a1 1 0 1 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 1 0-.623-1.901l-1.312.43v-1.4Zm9 0a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.832 1.167a1 1 0 0 0 1.627 1.162l.81-1.135.81 1.135a1 1 0 1 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 1 0-.623-1.901l-1.312.43v-1.4Zm0 18a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.832 1.167a1 1 0 0 0 1.627 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 1 0-.623-1.901l-1.312.43v-1.4Zm9 0a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.832 1.167a1 1 0 0 0 1.627 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 1 0-.623-1.901l-1.312.43v-1.4Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M65.497 58.13C72.489 52.83 77 44.441 77 35 77 18.984 64.016 6 48 6S19 18.984 19 35c0 9.443 4.51 17.83 11.503 23.13 1.888 1.43 3.017 3.869 2.465 6.383L27.021 91.57A2 2 0 0 0 28.975 94h38.05a2 2 0 0 0 1.954-2.43l-5.947-27.057c-.552-2.514.577-4.954 2.465-6.384Zm1.208 1.593c-1.35 1.023-2.083 2.706-1.72 4.36l5.947 27.058A4 4 0 0 1 67.025 96h-38.05a4 4 0 0 1-3.907-4.859l5.947-27.058c.363-1.654-.37-3.337-1.72-4.36C21.825 54.063 17 45.095 17 35 17 17.88 30.88 4 48 4c17.12 0 31 13.88 31 31 0 10.095-4.825 19.063-12.295 24.723Z"
clip-rule="evenodd"
/>
<path
fill="#FFBF00"
d="M60 12c0 6.627-5.373 12-12 12s-12-5.373-12-12S41.373 0 48 0s12 5.373 12 12Z"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M48 22c5.523 0 10-4.477 10-10S53.523 2 48 2 38 6.477 38 12s4.477 10 10 10Zm0 2c6.627 0 12-5.373 12-12S54.627 0 48 0 36 5.373 36 12s5.373 12 12 12Z"
clip-rule="evenodd"
/>
<path
fill="#175DDC"
fill-rule="evenodd"
d="M53.707 8.293a1 1 0 0 1 0 1.414l-7 7a1 1 0 0 1-1.414 0l-3-3a1 1 0 0 1 1.414-1.414L46 14.586l6.293-6.293a1 1 0 0 1 1.414 0Z"
clip-rule="evenodd"
/>
</svg>
`;
}
return html`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" fill="none">
<path
fill="#99BAF4"
fill-rule="evenodd"
d="M64.985 64.083c-.363-1.654.37-3.337 1.72-4.36C74.175 54.063 79 45.095 79 35 79 17.88 65.12 4 48 4 30.88 4 17 17.88 17 35c0 10.095 4.825 19.063 12.295 24.723 1.35 1.023 2.083 2.706 1.72 4.36l-5.947 27.058A4 4 0 0 0 28.975 96h38.05a4 4 0 0 0 3.907-4.859l-5.947-27.058Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M65.497 58.13C72.489 52.83 77 44.441 77 35 77 18.984 64.016 6 48 6S19 18.984 19 35c0 9.443 4.51 17.83 11.503 23.13 1.888 1.43 3.017 3.869 2.465 6.383L27.021 91.57A2 2 0 0 0 28.975 94h38.05a2 2 0 0 0 1.954-2.43l-5.947-27.057c-.552-2.514.577-4.954 2.465-6.384Zm1.208 1.593c-1.35 1.023-2.083 2.706-1.72 4.36l5.947 27.058A4 4 0 0 1 67.025 96h-38.05a4 4 0 0 1-3.907-4.859l5.947-27.058c.363-1.654-.37-3.337-1.72-4.36C21.825 54.063 17 45.095 17 35 17 17.88 30.88 4 48 4c17.12 0 31 13.88 31 31 0 10.095-4.825 19.063-12.295 24.723Z"
clip-rule="evenodd"
/>
<path
fill="#DBE5F6"
fill-rule="evenodd"
d="M20.864 50H46a4 4 0 0 0 4-4V30a4 4 0 0 0-4-4H20c-.647 0-1.258.154-1.8.427C17.42 29.149 17 32.026 17 35a30.86 30.86 0 0 0 3.864 15Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M22.07 48H46a2 2 0 0 0 2-2V30a2 2 0 0 0-2-2H20c-.051 0-.102.002-.151.006A29.072 29.072 0 0 0 19 35c0 4.678 1.106 9.092 3.07 13Zm-1.206 2H46a4 4 0 0 0 4-4V30a4 4 0 0 0-4-4H20c-.647 0-1.258.154-1.8.427C17.42 29.149 17 32.026 17 35a30.86 30.86 0 0 0 3.864 15Z"
clip-rule="evenodd"
/>
<path
fill="#99BAF4"
d="M18 31h30v4H18v-4ZM21 44a1 1 0 0 1 1-1h4a1 1 0 1 1 0 2h-4a1 1 0 0 1-1-1ZM29 44a1 1 0 0 1 1-1h9a1 1 0 1 1 0 2h-9a1 1 0 0 1-1-1Z"
/>
<path
fill="#DBE5F6"
fill-rule="evenodd"
d="M78.954 33.303A3.99 3.99 0 0 0 76 32H50a4 4 0 0 0-4 4v16a4 4 0 0 0 4 4h20.804A30.889 30.889 0 0 0 79 35a31.5 31.5 0 0 0-.046-1.697Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M76.99 34.262A1.987 1.987 0 0 0 76 34H50a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h19.91a28.88 28.88 0 0 0 7.08-19.738Zm1.964-.959A3.99 3.99 0 0 0 76 32H50a4 4 0 0 0-4 4v16a4 4 0 0 0 4 4h20.804A30.889 30.889 0 0 0 79 35a31.5 31.5 0 0 0-.046-1.697Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
d="M66 39a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1ZM66 43a1 1 0 0 1 1-1h3a1 1 0 1 1 0 2h-3a1 1 0 0 1-1-1Z"
/>
<path fill="#fff" d="M62 40a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z" />
<path
fill="#0E3781"
fill-rule="evenodd"
d="M58 42a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 2a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"
clip-rule="evenodd"
/>
<path
fill="#fff"
d="M65.391 48.269c.402 1.035.609 1.86.609 2.981a.75.75 0 0 1-.75.75h-14.5a.75.75 0 0 1-.75-.75c0-1.12.207-1.946.609-2.981a8.593 8.593 0 0 1 1.734-2.77 7.987 7.987 0 0 1 2.595-1.85C55.91 43.222 56.95 43 58 43c1.05 0 2.09.22 3.062.65a7.987 7.987 0 0 1 2.595 1.85 8.593 8.593 0 0 1 1.734 2.769Z"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M52.343 45.5a8.593 8.593 0 0 0-1.734 2.769c-.402 1.035-.609 1.86-.609 2.981 0 .414.336.75.75.75h14.5a.75.75 0 0 0 .75-.75c0-1.12-.207-1.946-.609-2.981a8.593 8.593 0 0 0-1.734-2.77 7.987 7.987 0 0 0-2.595-1.85A7.569 7.569 0 0 0 58 43c-1.05 0-2.09.22-3.062.65a7.987 7.987 0 0 0-2.595 1.85ZM63.857 50a8.12 8.12 0 0 0-.33-1.008 6.593 6.593 0 0 0-1.33-2.124l1.414-1.326-1.413 1.325a5.986 5.986 0 0 0-1.945-1.388A5.568 5.568 0 0 0 58 45c-.77 0-1.535.161-2.253.479a5.986 5.986 0 0 0-1.945 1.389 6.593 6.593 0 0 0-1.329 2.124 8.12 8.12 0 0 0-.33 1.008h11.714Z"
clip-rule="evenodd"
/>
<path
fill="#DBE5F6"
fill-rule="evenodd"
d="M67.605 76H48a8 8 0 1 0 0 16h23.027c0-.282-.031-.57-.095-.859L67.604 76Zm-38.77-2H50a8 8 0 0 0 0-16H27.215a31.14 31.14 0 0 0 2.08 1.723c1.35 1.023 2.083 2.706 1.72 4.36L28.835 74Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M29.628 60c1.134 1.034 1.72 2.571 1.387 4.083L28.835 74H50a8 8 0 0 0 0-16H27.215a31.117 31.117 0 0 0 2.08 1.723c.116.088.227.18.333.277Zm2.562 0c.792 1.307 1.134 2.894.778 4.513L31.322 72H50a6 6 0 0 0 0-12H32.19Zm33.806 18H48a6 6 0 0 0 0 12h20.634l-2.638-12Zm1.609-2H48a8 8 0 1 0 0 16h23.027c0-.282-.031-.57-.095-.859L67.604 76Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="m69.06 82.627-1.056.346v-1.4a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.832 1.167a1 1 0 1 0 1.627 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167.883-.29-.431-1.962ZM29.819 69.526a.995.995 0 0 0 .376-.318l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 0 0-.623-1.901l-1.312.43v-1.4a1 1 0 0 0-.95-.999c.08.493.072 1.002-.04 1.51l-1.196 5.442Zm11.186-5.953a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.833 1.167a1 1 0 1 0 1.628 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 0 0-.623-1.901l-1.312.43v-1.4Zm9 0a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.833 1.167a1 1 0 1 0 1.628 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 0 0-.623-1.901l-1.312.43v-1.4Zm0 18a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.833 1.167a1 1 0 1 0 1.628 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 0 0-.623-1.901l-1.312.43v-1.4Zm9 0a1 1 0 1 0-2 0v1.4l-1.312-.43a1 1 0 0 0-.623 1.9l1.33.436-.833 1.167a1 1 0 1 0 1.628 1.162l.81-1.135.81 1.135a1 1 0 0 0 1.628-1.162l-.833-1.167 1.33-.435a1 1 0 0 0-.623-1.901l-1.312.43v-1.4Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M65.497 58.13C72.489 52.83 77 44.441 77 35 77 18.984 64.016 6 48 6S19 18.984 19 35c0 9.443 4.51 17.83 11.503 23.13 1.888 1.43 3.017 3.869 2.465 6.383L27.021 91.57A2 2 0 0 0 28.975 94h38.05a2 2 0 0 0 1.954-2.43l-5.947-27.057c-.552-2.514.577-4.954 2.465-6.384Zm1.208 1.593c-1.35 1.023-2.083 2.706-1.72 4.36l5.947 27.058A4 4 0 0 1 67.025 96h-38.05a4 4 0 0 1-3.907-4.859l5.947-27.058c.363-1.654-.37-3.337-1.72-4.36C21.825 54.063 17 45.095 17 35 17 17.88 30.88 4 48 4c17.12 0 31 13.88 31 31 0 10.095-4.825 19.063-12.295 24.723Z"
clip-rule="evenodd"
/>
<path
fill="#FFBF00"
d="M60 12c0 6.627-5.373 12-12 12s-12-5.373-12-12S41.373 0 48 0s12 5.373 12 12Z"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M48 22c5.523 0 10-4.477 10-10S53.523 2 48 2 38 6.477 38 12s4.477 10 10 10Zm0 2c6.627 0 12-5.373 12-12S54.627 0 48 0 36 5.373 36 12s5.373 12 12 12Z"
clip-rule="evenodd"
/>
<path
fill="#0E3781"
fill-rule="evenodd"
d="M53.707 8.293a1 1 0 0 1 0 1.414l-7 7a1 1 0 0 1-1.414 0l-3-3a1 1 0 0 1 1.414-1.414L46 14.586l6.293-6.293a1 1 0 0 1 1.414 0Z"
clip-rule="evenodd"
/>
</svg>
`;
}

View File

@@ -57,9 +57,11 @@ export const BusinessIcon = createIconStory("Business");
export const BrandIcon = createIconStory("BrandIconContainer"); export const BrandIcon = createIconStory("BrandIconContainer");
export const CloseIcon = createIconStory("Close"); export const CloseIcon = createIconStory("Close");
export const ExclamationTriangleIcon = createIconStory("ExclamationTriangle"); export const ExclamationTriangleIcon = createIconStory("ExclamationTriangle");
export const ExternalLinkIcon = createIconStory("ExternalLink");
export const FamilyIcon = createIconStory("Family"); export const FamilyIcon = createIconStory("Family");
export const FolderIcon = createIconStory("Folder"); export const FolderIcon = createIconStory("Folder");
export const GlobeIcon = createIconStory("Globe"); export const GlobeIcon = createIconStory("Globe");
export const KeyholeIcon = createIconStory("Keyhole");
export const PartyHornIcon = createIconStory("PartyHorn"); export const PartyHornIcon = createIconStory("PartyHorn");
export const PencilSquareIcon = createIconStory("PencilSquare"); export const PencilSquareIcon = createIconStory("PencilSquare");
export const ShieldIcon = createIconStory("Shield"); export const ShieldIcon = createIconStory("Shield");

View File

@@ -16,7 +16,7 @@ type Args = {
}; };
export default { export default {
title: "Components/Notifications/Notification Body", title: "Components/Notifications/Body",
argTypes: { argTypes: {
ciphers: { control: "object" }, ciphers: { control: "object" },
theme: { control: "select", options: [...Object.values(ThemeTypes)] }, theme: { control: "select", options: [...Object.values(ThemeTypes)] },

View File

@@ -1,29 +1,26 @@
import { Meta, StoryObj } from "@storybook/web-components"; import { Meta, StoryObj } from "@storybook/web-components";
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums"; import { ThemeTypes } from "@bitwarden/common/platform/enums";
import { NotificationConfirmationBody } from "../../notification/confirmation"; import {
NotificationConfirmationBody,
type Args = { NotificationConfirmationBodyProps,
buttonText: string; } from "../../../notification/confirmation/body";
confirmationMessage: string;
handleOpenVault: () => void;
theme: Theme;
error: string;
};
export default { export default {
title: "Components/Notifications/Notification Confirmation Body", title: "Components/Notifications/Confirmation/Body",
argTypes: { argTypes: {
error: { control: "text" }, error: { control: "text" },
buttonText: { control: "text" }, buttonText: { control: "text" },
confirmationMessage: { control: "text" }, confirmationMessage: { control: "text" },
messageDetails: { control: "text" },
theme: { control: "select", options: [...Object.values(ThemeTypes)] }, theme: { control: "select", options: [...Object.values(ThemeTypes)] },
}, },
args: { args: {
error: "", error: "",
buttonText: "View", buttonText: "View",
confirmationMessage: "[item name] updated in Bitwarden.", confirmationMessage: "[item name] updated in Bitwarden.",
messageDetails: "You can view it in your vault.",
theme: ThemeTypes.Light, theme: ThemeTypes.Light,
}, },
parameters: { parameters: {
@@ -32,10 +29,11 @@ export default {
url: "https://www.figma.com/design/LEhqLAcBPY8uDKRfU99n9W/Autofill-notification-redesign?node-id=485-20160&m=dev", url: "https://www.figma.com/design/LEhqLAcBPY8uDKRfU99n9W/Autofill-notification-redesign?node-id=485-20160&m=dev",
}, },
}, },
} as Meta<Args>; } as Meta<NotificationConfirmationBodyProps>;
const Template = (args: Args) => NotificationConfirmationBody({ ...args }); const Template = (args: NotificationConfirmationBodyProps) =>
NotificationConfirmationBody({ ...args });
export const Default: StoryObj<Args> = { export const Default: StoryObj<NotificationConfirmationBodyProps> = {
render: Template, render: Template,
}; };

View File

@@ -0,0 +1,55 @@
import { Meta, StoryObj } from "@storybook/web-components";
import { ThemeTypes } from "@bitwarden/common/platform/enums";
import { NotificationTypes } from "../../../../../notification/abstractions/notification-bar";
import {
NotificationConfirmationContainer,
NotificationConfirmationContainerProps,
} from "../../../notification/confirmation/container";
export default {
title: "Components/Notifications/Confirmation",
argTypes: {
error: { control: "text" },
theme: { control: "select", options: [...Object.values(ThemeTypes)] },
type: { control: "select", options: [NotificationTypes.Change, NotificationTypes.Add] },
},
args: {
error: "",
task: {
orgName: "Acme, Inc.",
remainingTasksCount: 0,
},
handleCloseNotification: () => alert("Close notification action triggered"),
handleOpenTasks: () => alert("Open tasks action triggered"),
i18n: {
loginSaveSuccess: "Login saved",
loginUpdateSuccess: "Login updated",
loginUpdateTaskSuccessAdditional:
"Thank you for making your organization more secure. You have 3 more passwords to update.",
loginUpdateTaskSuccess:
"Great job! You took the steps to make you and your organization more secure.",
nextSecurityTaskAction: "Change next password",
saveFailure: "Error saving",
saveFailureDetails: "Oh no! We couldn't save this. Try entering the details manually.",
view: "View",
},
type: NotificationTypes.Change,
username: "Acme, Inc. Login",
theme: ThemeTypes.Light,
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/LEhqLAcBPY8uDKRfU99n9W/Autofill-notification-redesign?node-id=485-20160&m=dev",
},
},
} as Meta<NotificationConfirmationContainerProps>;
const Template = (args: NotificationConfirmationContainerProps) =>
NotificationConfirmationContainer({ ...args });
export const Default: StoryObj<NotificationConfirmationContainerProps> = {
render: Template,
};

View File

@@ -0,0 +1,36 @@
import { Meta, StoryObj } from "@storybook/web-components";
import { html } from "lit";
import { ThemeTypes } from "@bitwarden/common/platform/enums/theme-type.enum";
import {
NotificationConfirmationFooter,
NotificationConfirmationFooterProps,
} from "../../../notification/confirmation/footer";
export default {
title: "Components/Notifications/Confirmation/Footer",
argTypes: {
theme: { control: "select", options: [...Object.values(ThemeTypes)] },
},
args: {
handleButtonClick: () => alert("Action button triggered"),
i18n: {
nextSecurityTaskAction: "Change next password",
},
theme: ThemeTypes.Light,
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/LEhqLAcBPY8uDKRfU99n9W/Autofill-notification-redesign?node-id=32-4949&m=dev",
},
},
} as Meta<NotificationConfirmationFooterProps>;
const Template = (args: NotificationConfirmationFooterProps) =>
html`<div style="max-width:400px;">${NotificationConfirmationFooter({ ...args })}</div>`;
export const Default: StoryObj<NotificationConfirmationFooterProps> = {
render: Template,
};

View File

@@ -0,0 +1,37 @@
import { Meta, StoryObj } from "@storybook/web-components";
import { ThemeTypes } from "@bitwarden/common/platform/enums";
import {
NotificationConfirmationMessage,
NotificationConfirmationMessageProps,
} from "../../../notification/confirmation/message";
export default {
title: "Components/Notifications/Confirmation/Message",
argTypes: {
buttonText: { control: "text" },
message: { control: "text" },
messageDetails: { control: "text" },
theme: { control: "select", options: [...Object.values(ThemeTypes)] },
},
args: {
buttonText: "View",
message: "[item name] updated in Bitwarden.",
messageDetails: "It was added to your vault.",
theme: ThemeTypes.Light,
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/LEhqLAcBPY8uDKRfU99n9W/Autofill-notification-redesign?node-id=485-20160&m=dev",
},
},
} as Meta<NotificationConfirmationMessageProps>;
const Template = (args: NotificationConfirmationMessageProps) =>
NotificationConfirmationMessage({ ...args });
export const Default: StoryObj<NotificationConfirmationMessageProps> = {
render: Template,
};

View File

@@ -0,0 +1,61 @@
import { Meta, StoryObj } from "@storybook/web-components";
import { ThemeTypes } from "@bitwarden/common/platform/enums";
import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { NotificationTypes } from "../../../../notification/abstractions/notification-bar";
import { NotificationContainer, NotificationContainerProps } from "../../notification/container";
export default {
title: "Components/Notifications",
argTypes: {
error: { control: "text" },
theme: { control: "select", options: [...Object.values(ThemeTypes)] },
type: { control: "select", options: [...Object.values(NotificationTypes)] },
},
args: {
error: "",
ciphers: [
{
id: "1",
name: "Example Cipher",
type: CipherType.Login,
favorite: false,
reprompt: CipherRepromptType.None,
icon: {
imageEnabled: true,
image: "",
fallbackImage: "https://example.com/fallback.png",
icon: "icon-class",
},
login: { username: "user@example.com" },
},
],
i18n: {
loginSaveSuccess: "Login saved",
loginUpdateSuccess: "Login updated",
saveAction: "Save",
saveAsNewLoginAction: "Save as new login",
saveFailure: "Error saving",
saveFailureDetails: "Oh no! We couldn't save this. Try entering the details manually.",
updateLoginPrompt: "Update existing login?",
view: "View",
},
type: NotificationTypes.Change,
username: "mockUsername",
theme: ThemeTypes.Light,
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/LEhqLAcBPY8uDKRfU99n9W/Autofill-notification-redesign?node-id=485-20160&m=dev",
},
},
} as Meta<NotificationContainerProps>;
const Template = (args: NotificationContainerProps) => NotificationContainer({ ...args });
export const Default: StoryObj<NotificationContainerProps> = {
render: Template,
};

View File

@@ -7,7 +7,7 @@ import { NotificationFooter, NotificationFooterProps } from "../../notification/
import { mockFolderData, mockOrganizationData } from "../mock-data"; import { mockFolderData, mockOrganizationData } from "../mock-data";
export default { export default {
title: "Components/Notifications/Notification Footer", title: "Components/Notifications/Footer",
argTypes: { argTypes: {
notificationType: { notificationType: {
control: "select", control: "select",

View File

@@ -12,7 +12,7 @@ type Args = {
}; };
export default { export default {
title: "Components/Notifications/Notification Header", title: "Components/Notifications/Header",
argTypes: { argTypes: {
message: { control: "text" }, message: { control: "text" },
standalone: { control: "boolean" }, standalone: { control: "boolean" },

View File

@@ -1,53 +0,0 @@
import { css } from "@emotion/css";
import { html } from "lit";
import { Theme } from "@bitwarden/common/platform/enums";
import { themes } from "../constants/styles";
export function NotificationConfirmationMessage({
buttonText,
confirmationMessage,
handleClick,
theme,
}: {
buttonText: string;
confirmationMessage: string;
handleClick: (e: Event) => void;
theme: Theme;
}) {
return html`
<span title=${confirmationMessage} class=${notificationConfirmationMessageStyles(theme)}
>${confirmationMessage}
<a
title=${buttonText}
class=${notificationConfirmationButtonTextStyles(theme)}
@click=${handleClick}
>${buttonText}</a
></span
>
`;
}
const baseTextStyles = css`
flex-grow: 1;
overflow-x: hidden;
text-align: left;
text-overflow: ellipsis;
line-height: 24px;
font-family: "DM Sans", sans-serif;
font-size: 16px;
`;
const notificationConfirmationMessageStyles = (theme: Theme) => css`
${baseTextStyles}
color: ${themes[theme].text.main};
font-weight: 400;
`;
const notificationConfirmationButtonTextStyles = (theme: Theme) => css`
${baseTextStyles}
color: ${themes[theme].primary[600]};
font-weight: 700;
cursor: pointer;
`;

View File

@@ -1,12 +1,12 @@
import createEmotion from "@emotion/css/create-instance"; import createEmotion from "@emotion/css/create-instance";
import { html } from "lit"; import { html, nothing } from "lit";
import { Theme } from "@bitwarden/common/platform/enums"; import { Theme } from "@bitwarden/common/platform/enums";
import { themes } from "../constants/styles"; import { themes } from "../../constants/styles";
import { PartyHorn, Warning } from "../icons"; import { PartyHorn, Keyhole, Warning } from "../../icons";
import { NotificationConfirmationMessage } from "./confirmation-message"; import { NotificationConfirmationMessage } from "./message";
export const componentClassPrefix = "notification-confirmation-body"; export const componentClassPrefix = "notification-confirmation-body";
@@ -14,31 +14,41 @@ const { css } = createEmotion({
key: componentClassPrefix, key: componentClassPrefix,
}); });
export function NotificationConfirmationBody({ export type NotificationConfirmationBodyProps = {
buttonText,
error,
confirmationMessage,
theme,
handleOpenVault,
}: {
error?: string;
buttonText: string; buttonText: string;
confirmationMessage: string; confirmationMessage: string;
error?: string;
messageDetails?: string;
tasksAreComplete?: boolean;
theme: Theme; theme: Theme;
handleOpenVault: (e: Event) => void; handleOpenVault: (e: Event) => void;
}) { };
const IconComponent = !error ? PartyHorn : Warning;
export function NotificationConfirmationBody({
buttonText,
confirmationMessage,
error,
messageDetails,
tasksAreComplete,
theme,
handleOpenVault,
}: NotificationConfirmationBodyProps) {
const IconComponent = tasksAreComplete ? Keyhole : !error ? PartyHorn : Warning;
const showConfirmationMessage = confirmationMessage || buttonText || messageDetails;
return html` return html`
<div class=${notificationConfirmationBodyStyles({ theme })}> <div class=${notificationConfirmationBodyStyles({ theme })}>
<div class=${iconContainerStyles(error)}>${IconComponent({ theme })}</div> <div class=${iconContainerStyles(error)}>${IconComponent({ theme })}</div>
${confirmationMessage && buttonText ${showConfirmationMessage
? NotificationConfirmationMessage({ ? NotificationConfirmationMessage({
handleClick: handleOpenVault,
confirmationMessage,
theme,
buttonText, buttonText,
message: confirmationMessage,
messageDetails,
theme,
handleClick: handleOpenVault,
}) })
: null} : nothing}
</div> </div>
`; `;
} }

View File

@@ -1,42 +1,67 @@
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";
import { import {
NotificationBarIframeInitData, NotificationBarIframeInitData,
NotificationTypes, NotificationTaskInfo,
NotificationType, NotificationType,
} from "../../../notification/abstractions/notification-bar"; NotificationTypes,
import { themes, spacing } from "../constants/styles"; } from "../../../../notification/abstractions/notification-bar";
import { themes, spacing } from "../../constants/styles";
import { NotificationConfirmationBody } from "./confirmation";
import { import {
NotificationHeader, NotificationHeader,
componentClassPrefix as notificationHeaderClassPrefix, componentClassPrefix as notificationHeaderClassPrefix,
} from "./header"; } from "../header";
import { NotificationConfirmationBody } from "./body";
import { NotificationConfirmationFooter } from "./footer";
export type NotificationConfirmationContainerProps = NotificationBarIframeInitData & {
handleCloseNotification: (e: Event) => void;
handleOpenVault: (e: Event) => void;
handleOpenTasks: (e: Event) => void;
} & {
error?: string;
i18n: { [key: string]: string };
task?: NotificationTaskInfo;
type: NotificationType;
username: string;
};
export function NotificationConfirmationContainer({ export function NotificationConfirmationContainer({
error, error,
handleCloseNotification, handleCloseNotification,
handleOpenVault, handleOpenVault,
handleOpenTasks,
i18n, i18n,
task,
theme = ThemeTypes.Light, theme = ThemeTypes.Light,
type, type,
username, username,
}: NotificationBarIframeInitData & { }: NotificationConfirmationContainerProps) {
handleCloseNotification: (e: Event) => void;
handleOpenVault: (e: Event) => void;
} & {
error?: string;
i18n: { [key: string]: string };
type: NotificationType;
username: string;
}) {
const headerMessage = getHeaderMessage(i18n, type, error); const headerMessage = getHeaderMessage(i18n, type, error);
const confirmationMessage = getConfirmationMessage(i18n, username, type, error); const confirmationMessage = getConfirmationMessage(i18n, username, type, error);
const buttonText = error ? i18n.newItem : i18n.view; const buttonText = error ? i18n.newItem : i18n.view;
let messageDetails: string | undefined;
let remainingTasksCount: number | undefined;
let tasksAreComplete: boolean = false;
if (task) {
remainingTasksCount = task.remainingTasksCount || 0;
tasksAreComplete = remainingTasksCount === 0;
messageDetails =
remainingTasksCount > 0
? chrome.i18n.getMessage("loginUpdateTaskSuccessAdditional", [
task.orgName,
`${remainingTasksCount}`,
])
: chrome.i18n.getMessage("loginUpdateTaskSuccess", [task.orgName]);
}
return html` return html`
<div class=${notificationContainerStyles(theme)}> <div class=${notificationContainerStyles(theme)}>
${NotificationHeader({ ${NotificationHeader({
@@ -47,10 +72,18 @@ export function NotificationConfirmationContainer({
${NotificationConfirmationBody({ ${NotificationConfirmationBody({
buttonText, buttonText,
confirmationMessage, confirmationMessage,
error: error, tasksAreComplete,
handleOpenVault, messageDetails,
theme, theme,
handleOpenVault,
})} })}
${remainingTasksCount
? NotificationConfirmationFooter({
i18n,
theme,
handleButtonClick: handleOpenTasks,
})
: nothing}
</div> </div>
`; `;
} }

View File

@@ -0,0 +1,59 @@
import { css } from "@emotion/css";
import { html } from "lit";
import { Theme } from "@bitwarden/common/platform/enums";
import { ActionButton } from "../../buttons/action-button";
import { spacing, themes } from "../../constants/styles";
import { ExternalLink } from "../../icons";
export type NotificationConfirmationFooterProps = {
i18n: { [key: string]: string };
theme: Theme;
handleButtonClick: (event: Event) => void;
};
export function NotificationConfirmationFooter({
i18n,
theme,
handleButtonClick,
}: NotificationConfirmationFooterProps) {
const primaryButtonText = i18n.nextSecurityTaskAction;
return html`
<div class=${notificationConfirmationFooterStyles({ theme })}>
${ActionButton({
handleClick: handleButtonClick,
buttonText: AdditionalTasksButtonContent({ buttonText: primaryButtonText, theme }),
theme,
})}
</div>
`;
}
const notificationConfirmationFooterStyles = ({ theme }: { theme: Theme }) => css`
background-color: ${themes[theme].background.alt};
padding: 0 ${spacing[3]} ${spacing[3]} ${spacing[3]};
max-width: min-content;
:last-child {
border-radius: 0 0 ${spacing["4"]} ${spacing["4"]};
padding-bottom: ${spacing[4]};
}
`;
function AdditionalTasksButtonContent({ buttonText, theme }: { buttonText: string; theme: Theme }) {
return html`
<div class=${additionalTasksButtonContentStyles({ theme })}>
<span>${buttonText}</span>
${ExternalLink({ theme, color: themes[theme].text.contrast })}
</div>
`;
}
const additionalTasksButtonContentStyles = ({ theme }: { theme: Theme }) => css`
gap: ${spacing[2]};
display: flex;
align-items: center;
white-space: nowrap;
`;

View File

@@ -0,0 +1,83 @@
import { css } from "@emotion/css";
import { html, nothing } from "lit";
import { Theme } from "@bitwarden/common/platform/enums";
import { themes, typography } from "../../constants/styles";
export type NotificationConfirmationMessageProps = {
buttonText?: string;
message?: string;
messageDetails?: string;
handleClick: (e: Event) => void;
theme: Theme;
};
export function NotificationConfirmationMessage({
buttonText,
message,
messageDetails,
handleClick,
theme,
}: NotificationConfirmationMessageProps) {
return html`
<div>
${message || buttonText
? html`
<span
title=${message || buttonText}
class=${notificationConfirmationMessageStyles(theme)}
>
${message || nothing}
${buttonText
? html`
<a
title=${buttonText}
class=${notificationConfirmationButtonTextStyles(theme)}
@click=${handleClick}
>
${buttonText}
</a>
`
: nothing}
</span>
`
: nothing}
${messageDetails
? html`<div class=${AdditionalMessageStyles({ theme })}>${messageDetails}</div>`
: nothing}
</div>
`;
}
const baseTextStyles = css`
flex-grow: 1;
overflow-x: hidden;
text-align: left;
text-overflow: ellipsis;
line-height: 24px;
font-family: "DM Sans", sans-serif;
font-size: 16px;
`;
const notificationConfirmationMessageStyles = (theme: Theme) => css`
${baseTextStyles}
color: ${themes[theme].text.main};
font-weight: 400;
`;
const notificationConfirmationButtonTextStyles = (theme: Theme) => css`
${baseTextStyles}
color: ${themes[theme].primary[600]};
font-weight: 700;
cursor: pointer;
`;
const AdditionalMessageStyles = ({ theme }: { theme: Theme }) => css`
${typography.body2}
font-size: 14px;
color: ${themes[theme].text.muted};
`;

View File

@@ -19,6 +19,18 @@ import {
componentClassPrefix as notificationHeaderClassPrefix, componentClassPrefix as notificationHeaderClassPrefix,
} from "./header"; } from "./header";
export type NotificationContainerProps = NotificationBarIframeInitData & {
handleCloseNotification: (e: Event) => void;
handleSaveAction: (e: Event) => void;
handleEditOrUpdateAction: (e: Event) => void;
} & {
ciphers?: NotificationCipherData[];
folders?: FolderView[];
i18n: { [key: string]: string };
organizations?: OrgView[];
type: NotificationType; // @TODO typing override for generic `NotificationBarIframeInitData.type`
};
export function NotificationContainer({ export function NotificationContainer({
handleCloseNotification, handleCloseNotification,
handleEditOrUpdateAction, handleEditOrUpdateAction,
@@ -29,17 +41,7 @@ export function NotificationContainer({
organizations, organizations,
theme = ThemeTypes.Light, theme = ThemeTypes.Light,
type, type,
}: NotificationBarIframeInitData & { }: NotificationContainerProps) {
handleCloseNotification: (e: Event) => void;
handleSaveAction: (e: Event) => void;
handleEditOrUpdateAction: (e: Event) => void;
} & {
ciphers?: NotificationCipherData[];
folders?: FolderView[];
i18n: { [key: string]: string };
organizations?: OrgView[];
type: NotificationType; // @TODO typing override for generic `NotificationBarIframeInitData.type`
}) {
const headerMessage = getHeaderMessage(i18n, type); const headerMessage = getHeaderMessage(i18n, type);
const showBody = true; const showBody = true;

View File

@@ -11,6 +11,11 @@ const NotificationTypes = {
type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes]; type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes];
type NotificationTaskInfo = {
orgName: string;
remainingTasksCount: number;
};
type NotificationBarIframeInitData = { type NotificationBarIframeInitData = {
ciphers?: NotificationCipherData[]; ciphers?: NotificationCipherData[];
folders?: FolderView[]; folders?: FolderView[];
@@ -38,6 +43,7 @@ type NotificationBarWindowMessageHandlers = {
}; };
export { export {
NotificationTaskInfo,
NotificationTypes, NotificationTypes,
NotificationType, NotificationType,
NotificationBarIframeInitData, NotificationBarIframeInitData,

View File

@@ -7,7 +7,7 @@ import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view
import { AdjustNotificationBarMessageData } from "../background/abstractions/notification.background"; import { AdjustNotificationBarMessageData } from "../background/abstractions/notification.background";
import { NotificationCipherData } from "../content/components/cipher/types"; import { NotificationCipherData } from "../content/components/cipher/types";
import { OrgView } from "../content/components/common-types"; import { OrgView } from "../content/components/common-types";
import { NotificationConfirmationContainer } from "../content/components/notification/confirmation-container"; import { NotificationConfirmationContainer } from "../content/components/notification/confirmation/container";
import { NotificationContainer } from "../content/components/notification/container"; import { NotificationContainer } from "../content/components/notification/container";
import { buildSvgDomElement } from "../utils"; import { buildSvgDomElement } from "../utils";
import { circleCheckIcon } from "../utils/svg-icons"; import { circleCheckIcon } from "../utils/svg-icons";
@@ -58,6 +58,9 @@ function getI18n() {
loginSaveSuccessDetails: chrome.i18n.getMessage("loginSaveSuccessDetails"), loginSaveSuccessDetails: chrome.i18n.getMessage("loginSaveSuccessDetails"),
loginUpdateSuccess: chrome.i18n.getMessage("loginUpdateSuccess"), loginUpdateSuccess: chrome.i18n.getMessage("loginUpdateSuccess"),
loginUpdateSuccessDetails: chrome.i18n.getMessage("loginUpdatedSuccessDetails"), loginUpdateSuccessDetails: chrome.i18n.getMessage("loginUpdatedSuccessDetails"),
loginUpdateTaskSuccess: chrome.i18n.getMessage("loginUpdateTaskSuccess"),
loginUpdateTaskSuccessAdditional: chrome.i18n.getMessage("loginUpdateTaskSuccessAdditional"),
nextSecurityTaskAction: chrome.i18n.getMessage("nextSecurityTaskAction"),
newItem: chrome.i18n.getMessage("newItem"), newItem: chrome.i18n.getMessage("newItem"),
never: chrome.i18n.getMessage("never"), never: chrome.i18n.getMessage("never"),
notificationAddDesc: chrome.i18n.getMessage("notificationAddDesc"), notificationAddDesc: chrome.i18n.getMessage("notificationAddDesc"),
@@ -369,6 +372,7 @@ function handleSaveCipherConfirmation(message: NotificationBarWindowMessage) {
error, error,
username: username ?? i18n.typeLogin, username: username ?? i18n.typeLogin,
handleOpenVault: (e) => cipherId && openViewVaultItemPopout(e, cipherId), handleOpenVault: (e) => cipherId && openViewVaultItemPopout(e, cipherId),
handleOpenTasks: () => {},
}), }),
document.body, document.body,
); );