mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
PM-20106 Pass indicator data to notification bar cipher items (#14246)
* PM-20106 initial approach whihc preserves exisiting indicator file style * refactored approach to be able to pass any icon when or if needed in the future * address feedback
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
} from "@bitwarden/common/autofill/constants";
|
} from "@bitwarden/common/autofill/constants";
|
||||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
||||||
|
import { ProductTierType } from "@bitwarden/common/billing/enums/product-tier-type.enum";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
@@ -41,7 +42,11 @@ import { SecurityTask } from "@bitwarden/common/vault/tasks/models/security-task
|
|||||||
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window";
|
import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window";
|
||||||
import { NotificationCipherData } from "../content/components/cipher/types";
|
import {
|
||||||
|
OrganizationCategory,
|
||||||
|
OrganizationCategories,
|
||||||
|
NotificationCipherData,
|
||||||
|
} from "../content/components/cipher/types";
|
||||||
import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum";
|
import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum";
|
||||||
import { AutofillService } from "../services/abstractions/autofill.service";
|
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||||
|
|
||||||
@@ -174,8 +179,29 @@ export default class NotificationBackground {
|
|||||||
activeUserId,
|
activeUserId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const organizations = await firstValueFrom(
|
||||||
|
this.organizationService.organizations$(activeUserId),
|
||||||
|
);
|
||||||
|
|
||||||
return decryptedCiphers.map((view) => {
|
return decryptedCiphers.map((view) => {
|
||||||
const { id, name, reprompt, favorite, login } = view;
|
const { id, name, reprompt, favorite, login, organizationId } = view;
|
||||||
|
|
||||||
|
const organizationType = organizationId
|
||||||
|
? organizations.find((org) => org.id === organizationId)?.productTierType
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const organizationCategories: OrganizationCategory[] = [];
|
||||||
|
|
||||||
|
if (
|
||||||
|
[ProductTierType.Teams, ProductTierType.Enterprise, ProductTierType.TeamsStarter].includes(
|
||||||
|
organizationType,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
organizationCategories.push(OrganizationCategories.business);
|
||||||
|
}
|
||||||
|
if ([ProductTierType.Families, ProductTierType.Free].includes(organizationType)) {
|
||||||
|
organizationCategories.push(OrganizationCategories.family);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
@@ -183,6 +209,7 @@ export default class NotificationBackground {
|
|||||||
type: CipherType.Login,
|
type: CipherType.Login,
|
||||||
reprompt,
|
reprompt,
|
||||||
favorite,
|
favorite,
|
||||||
|
...(organizationCategories.length ? { organizationCategories } : {}),
|
||||||
icon: buildCipherIcon(iconsServerUrl, view, showFavicons),
|
icon: buildCipherIcon(iconsServerUrl, view, showFavicons),
|
||||||
login: login && {
|
login: login && {
|
||||||
username: login.username,
|
username: login.username,
|
||||||
|
|||||||
@@ -1,30 +1,35 @@
|
|||||||
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";
|
||||||
|
|
||||||
import { themes } from "../../../content/components/constants/styles";
|
import { themes } from "../../../content/components/constants/styles";
|
||||||
import { Business, Users } from "../../../content/components/icons";
|
import { Business, Users } from "../../../content/components/icons";
|
||||||
|
|
||||||
// @TODO connect data source to icon checks
|
import { OrganizationCategories, OrganizationCategory } from "./types";
|
||||||
// @TODO support other indicator types (attachments, etc)
|
|
||||||
|
const cipherIndicatorIconsMap: Record<
|
||||||
|
OrganizationCategory,
|
||||||
|
(args: { color: string; theme: Theme }) => TemplateResult
|
||||||
|
> = {
|
||||||
|
[OrganizationCategories.business]: Business,
|
||||||
|
[OrganizationCategories.family]: Users,
|
||||||
|
};
|
||||||
|
|
||||||
export function CipherInfoIndicatorIcons({
|
export function CipherInfoIndicatorIcons({
|
||||||
showBusinessIcon,
|
organizationCategories = [],
|
||||||
showFamilyIcon,
|
|
||||||
theme,
|
theme,
|
||||||
}: {
|
}: {
|
||||||
showBusinessIcon?: boolean;
|
organizationCategories?: OrganizationCategory[];
|
||||||
showFamilyIcon?: boolean;
|
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
}) {
|
}) {
|
||||||
const indicatorIcons = [
|
return html`
|
||||||
...(showBusinessIcon ? [Business({ color: themes[theme].text.muted, theme })] : []),
|
<span class=${cipherInfoIndicatorIconsStyles}>
|
||||||
...(showFamilyIcon ? [Users({ color: themes[theme].text.muted, theme })] : []),
|
${organizationCategories.map((name) =>
|
||||||
];
|
cipherIndicatorIconsMap[name]?.({ color: themes[theme].text.muted, theme }),
|
||||||
|
)}
|
||||||
return indicatorIcons.length
|
</span>
|
||||||
? html` <span class=${cipherInfoIndicatorIconsStyles}> ${indicatorIcons} </span> `
|
`;
|
||||||
: null; // @TODO null case should be handled by parent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cipherInfoIndicatorIconsStyles = css`
|
const cipherInfoIndicatorIconsStyles = css`
|
||||||
|
|||||||
@@ -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 } from "@bitwarden/common/platform/enums";
|
import { Theme } from "@bitwarden/common/platform/enums";
|
||||||
|
|
||||||
@@ -8,14 +8,22 @@ import { themes, typography } from "../../../content/components/constants/styles
|
|||||||
import { CipherInfoIndicatorIcons } from "./cipher-indicator-icons";
|
import { CipherInfoIndicatorIcons } from "./cipher-indicator-icons";
|
||||||
import { NotificationCipherData } from "./types";
|
import { NotificationCipherData } from "./types";
|
||||||
|
|
||||||
// @TODO support other cipher types (card, identity, notes, etc)
|
|
||||||
export function CipherInfo({ cipher, theme }: { cipher: NotificationCipherData; theme: Theme }) {
|
export function CipherInfo({ cipher, theme }: { cipher: NotificationCipherData; theme: Theme }) {
|
||||||
const { name, login } = cipher;
|
const { name, login, organizationCategories } = cipher;
|
||||||
|
const hasIndicatorIcons = organizationCategories?.length;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<span class=${cipherInfoPrimaryTextStyles(theme)}>
|
<span class=${cipherInfoPrimaryTextStyles(theme)}>
|
||||||
${[name, CipherInfoIndicatorIcons({ theme })]}
|
${[
|
||||||
|
name,
|
||||||
|
hasIndicatorIcons
|
||||||
|
? CipherInfoIndicatorIcons({
|
||||||
|
theme,
|
||||||
|
organizationCategories,
|
||||||
|
})
|
||||||
|
: nothing,
|
||||||
|
]}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
${login?.username
|
${login?.username
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ export const CipherRepromptTypes = {
|
|||||||
|
|
||||||
type CipherRepromptType = (typeof CipherRepromptTypes)[keyof typeof CipherRepromptTypes];
|
type CipherRepromptType = (typeof CipherRepromptTypes)[keyof typeof CipherRepromptTypes];
|
||||||
|
|
||||||
|
export type OrganizationCategory =
|
||||||
|
(typeof OrganizationCategories)[keyof typeof OrganizationCategories];
|
||||||
|
|
||||||
|
export const OrganizationCategories = {
|
||||||
|
business: "business",
|
||||||
|
family: "family",
|
||||||
|
} as const;
|
||||||
|
|
||||||
export type WebsiteIconData = {
|
export type WebsiteIconData = {
|
||||||
imageEnabled: boolean;
|
imageEnabled: boolean;
|
||||||
image: string;
|
image: string;
|
||||||
@@ -50,4 +58,5 @@ export type NotificationCipherData = BaseCipherData<typeof CipherTypes.Login> &
|
|||||||
login?: {
|
login?: {
|
||||||
username: string;
|
username: string;
|
||||||
};
|
};
|
||||||
|
organizationCategories?: OrganizationCategory[];
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user