1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00

Creates notification queue type standard. (#16009)

This commit is contained in:
Miles Blackwood
2025-08-14 18:43:48 -04:00
committed by GitHub
parent ff4952c113
commit 89f797d45f
7 changed files with 114 additions and 84 deletions

View File

@@ -4,11 +4,29 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { CollectionView } from "../../content/components/common-types"; import { CollectionView } from "../../content/components/common-types";
import { NotificationQueueMessageTypes } from "../../enums/notification-queue-message-type.enum"; import { NotificationType, NotificationTypes } from "../../enums/notification-type.enum";
import AutofillPageDetails from "../../models/autofill-page-details"; import AutofillPageDetails from "../../models/autofill-page-details";
/**
* @todo Remove Standard_ label when implemented as standard NotificationQueueMessage.
*/
export interface Standard_NotificationQueueMessage<T, D> {
// universal notification properties
domain: string;
tab: chrome.tabs.Tab;
launchTimestamp: number;
expires: Date;
wasVaultLocked: boolean;
type: T; // NotificationType
data: D; // notification-specific data
}
/**
* @todo Deprecate in favor of Standard_NotificationQueueMessage.
*/
interface NotificationQueueMessage { interface NotificationQueueMessage {
type: NotificationQueueMessageTypes; type: NotificationTypes;
domain: string; domain: string;
tab: chrome.tabs.Tab; tab: chrome.tabs.Tab;
launchTimestamp: number; launchTimestamp: number;
@@ -16,11 +34,15 @@ interface NotificationQueueMessage {
wasVaultLocked: boolean; wasVaultLocked: boolean;
} }
interface AddChangePasswordQueueMessage extends NotificationQueueMessage { type ChangePasswordNotificationData = {
type: "change";
cipherId: CipherView["id"]; cipherId: CipherView["id"];
newPassword: string; newPassword: string;
} };
type AddChangePasswordNotificationQueueMessage = Standard_NotificationQueueMessage<
typeof NotificationType.ChangePassword,
ChangePasswordNotificationData
>;
interface AddLoginQueueMessage extends NotificationQueueMessage { interface AddLoginQueueMessage extends NotificationQueueMessage {
type: "add"; type: "add";
@@ -41,7 +63,7 @@ interface AtRiskPasswordQueueMessage extends NotificationQueueMessage {
type NotificationQueueMessageItem = type NotificationQueueMessageItem =
| AddLoginQueueMessage | AddLoginQueueMessage
| AddChangePasswordQueueMessage | AddChangePasswordNotificationQueueMessage
| AddUnlockVaultQueueMessage | AddUnlockVaultQueueMessage
| AtRiskPasswordQueueMessage; | AtRiskPasswordQueueMessage;
@@ -72,6 +94,11 @@ type UnlockVaultMessageData = {
skipNotification?: boolean; skipNotification?: boolean;
}; };
/**
* @todo Extend generics to this type, see Standard_NotificationQueueMessage
* - use new `data` types as generic
* - eliminate optional status of properties as needed per Notification Type
*/
type NotificationBackgroundExtensionMessage = { type NotificationBackgroundExtensionMessage = {
[key: string]: any; [key: string]: any;
command: string; command: string;
@@ -126,7 +153,7 @@ type NotificationBackgroundExtensionMessageHandlers = {
}; };
export { export {
AddChangePasswordQueueMessage, AddChangePasswordNotificationQueueMessage,
AddLoginQueueMessage, AddLoginQueueMessage,
AddUnlockVaultQueueMessage, AddUnlockVaultQueueMessage,
NotificationQueueMessageItem, NotificationQueueMessageItem,

View File

@@ -26,14 +26,14 @@ import { FolderService } from "@bitwarden/common/vault/services/folder/folder.se
import { TaskService, SecurityTask } from "@bitwarden/common/vault/tasks"; import { TaskService, SecurityTask } from "@bitwarden/common/vault/tasks";
import { BrowserApi } from "../../platform/browser/browser-api"; import { BrowserApi } from "../../platform/browser/browser-api";
import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; import { NotificationType } from "../enums/notification-type.enum";
import { FormData } from "../services/abstractions/autofill.service"; import { FormData } from "../services/abstractions/autofill.service";
import AutofillService from "../services/autofill.service"; import AutofillService from "../services/autofill.service";
import { createAutofillPageDetailsMock, createChromeTabMock } from "../spec/autofill-mocks"; import { createAutofillPageDetailsMock, createChromeTabMock } from "../spec/autofill-mocks";
import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils"; import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils";
import { import {
AddChangePasswordQueueMessage, AddChangePasswordNotificationQueueMessage,
AddLoginQueueMessage, AddLoginQueueMessage,
AddUnlockVaultQueueMessage, AddUnlockVaultQueueMessage,
LockedVaultPendingNotificationsData, LockedVaultPendingNotificationsData,
@@ -761,7 +761,7 @@ describe("NotificationBackground", () => {
notificationBackground["notificationQueue"] = [ notificationBackground["notificationQueue"] = [
mock<AddUnlockVaultQueueMessage>({ mock<AddUnlockVaultQueueMessage>({
tab, tab,
type: NotificationQueueMessageType.UnlockVault, type: NotificationType.UnlockVault,
}), }),
]; ];
@@ -783,7 +783,7 @@ describe("NotificationBackground", () => {
}; };
notificationBackground["notificationQueue"] = [ notificationBackground["notificationQueue"] = [
mock<AddLoginQueueMessage>({ mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "another.com", domain: "another.com",
}), }),
@@ -803,11 +803,11 @@ describe("NotificationBackground", () => {
edit: false, edit: false,
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddChangePasswordQueueMessage>({ const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationQueueMessageType.ChangePassword, type: NotificationType.ChangePassword,
tab, tab,
domain: "example.com", domain: "example.com",
newPassword: "newPassword", data: { newPassword: "newPassword" },
}); });
notificationBackground["notificationQueue"] = [queueMessage]; notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({ const cipherView = mock<CipherView>({
@@ -825,7 +825,7 @@ describe("NotificationBackground", () => {
expect(createWithServerSpy).not.toHaveBeenCalled(); expect(createWithServerSpy).not.toHaveBeenCalled();
expect(updatePasswordSpy).toHaveBeenCalledWith( expect(updatePasswordSpy).toHaveBeenCalledWith(
cipherView, cipherView,
queueMessage.newPassword, queueMessage.data.newPassword,
message.edit, message.edit,
sender.tab, sender.tab,
"testId", "testId",
@@ -851,11 +851,11 @@ describe("NotificationBackground", () => {
edit: false, edit: false,
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddChangePasswordQueueMessage>({ const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationQueueMessageType.ChangePassword, type: NotificationType.ChangePassword,
tab, tab,
domain: "example.com", domain: "example.com",
newPassword: "newPassword", data: { newPassword: "newPassword" },
}); });
notificationBackground["notificationQueue"] = [queueMessage]; notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({ const cipherView = mock<CipherView>({
@@ -874,7 +874,7 @@ describe("NotificationBackground", () => {
expect(createWithServerSpy).not.toHaveBeenCalled(); expect(createWithServerSpy).not.toHaveBeenCalled();
expect(updatePasswordSpy).toHaveBeenCalledWith( expect(updatePasswordSpy).toHaveBeenCalledWith(
cipherView, cipherView,
queueMessage.newPassword, queueMessage.data.newPassword,
message.edit, message.edit,
sender.tab, sender.tab,
"testId", "testId",
@@ -931,11 +931,11 @@ describe("NotificationBackground", () => {
edit: false, edit: false,
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddChangePasswordQueueMessage>({ const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationQueueMessageType.ChangePassword, type: NotificationType.ChangePassword,
tab, tab,
domain: "example.com", domain: "example.com",
newPassword: "newPassword", data: { newPassword: "newPassword" },
}); });
notificationBackground["notificationQueue"] = [queueMessage]; notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({ const cipherView = mock<CipherView>({
@@ -953,7 +953,7 @@ describe("NotificationBackground", () => {
expect(createWithServerSpy).not.toHaveBeenCalled(); expect(createWithServerSpy).not.toHaveBeenCalled();
expect(updatePasswordSpy).toHaveBeenCalledWith( expect(updatePasswordSpy).toHaveBeenCalledWith(
cipherView, cipherView,
queueMessage.newPassword, queueMessage.data.newPassword,
message.edit, message.edit,
sender.tab, sender.tab,
mockCipherId, mockCipherId,
@@ -983,7 +983,7 @@ describe("NotificationBackground", () => {
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddLoginQueueMessage>({ const queueMessage = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "example.com", domain: "example.com",
username: "test", username: "test",
@@ -1018,11 +1018,11 @@ describe("NotificationBackground", () => {
edit: true, edit: true,
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddChangePasswordQueueMessage>({ const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationQueueMessageType.ChangePassword, type: NotificationType.ChangePassword,
tab, tab,
domain: "example.com", domain: "example.com",
newPassword: "newPassword", data: { newPassword: "newPassword" },
}); });
notificationBackground["notificationQueue"] = [queueMessage]; notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>(); const cipherView = mock<CipherView>();
@@ -1035,7 +1035,7 @@ describe("NotificationBackground", () => {
expect(updatePasswordSpy).toHaveBeenCalledWith( expect(updatePasswordSpy).toHaveBeenCalledWith(
cipherView, cipherView,
queueMessage.newPassword, queueMessage.data.newPassword,
message.edit, message.edit,
sender.tab, sender.tab,
"testId", "testId",
@@ -1070,7 +1070,7 @@ describe("NotificationBackground", () => {
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddLoginQueueMessage>({ const queueMessage = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "example.com", domain: "example.com",
username: "test", username: "test",
@@ -1109,7 +1109,7 @@ describe("NotificationBackground", () => {
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddLoginQueueMessage>({ const queueMessage = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "example.com", domain: "example.com",
username: "test", username: "test",
@@ -1162,7 +1162,7 @@ describe("NotificationBackground", () => {
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddLoginQueueMessage>({ const queueMessage = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "example.com", domain: "example.com",
username: "test", username: "test",
@@ -1213,11 +1213,11 @@ describe("NotificationBackground", () => {
edit: false, edit: false,
folder: "folder-id", folder: "folder-id",
}; };
const queueMessage = mock<AddChangePasswordQueueMessage>({ const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationQueueMessageType.ChangePassword, type: NotificationType.ChangePassword,
tab, tab,
domain: "example.com", domain: "example.com",
newPassword: "newPassword", data: { newPassword: "newPassword" },
}); });
notificationBackground["notificationQueue"] = [queueMessage]; notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({ reprompt: CipherRepromptType.None }); const cipherView = mock<CipherView>({ reprompt: CipherRepromptType.None });
@@ -1273,7 +1273,7 @@ describe("NotificationBackground", () => {
const sender = mock<chrome.runtime.MessageSender>({ tab }); const sender = mock<chrome.runtime.MessageSender>({ tab });
const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" }; const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" };
notificationBackground["notificationQueue"] = [ notificationBackground["notificationQueue"] = [
mock<AddUnlockVaultQueueMessage>({ type: NotificationQueueMessageType.UnlockVault, tab }), mock<AddUnlockVaultQueueMessage>({ type: NotificationType.UnlockVault, tab }),
]; ];
sendMockExtensionMessage(message, sender); sendMockExtensionMessage(message, sender);
@@ -1289,7 +1289,7 @@ describe("NotificationBackground", () => {
const sender = mock<chrome.runtime.MessageSender>({ tab: secondaryTab }); const sender = mock<chrome.runtime.MessageSender>({ tab: secondaryTab });
notificationBackground["notificationQueue"] = [ notificationBackground["notificationQueue"] = [
mock<AddLoginQueueMessage>({ mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "another.com", domain: "another.com",
}), }),
@@ -1306,12 +1306,12 @@ describe("NotificationBackground", () => {
const sender = mock<chrome.runtime.MessageSender>({ tab }); const sender = mock<chrome.runtime.MessageSender>({ tab });
const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" }; const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" };
const firstNotification = mock<AddLoginQueueMessage>({ const firstNotification = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab, tab,
domain: "example.com", domain: "example.com",
}); });
const secondNotification = mock<AddLoginQueueMessage>({ const secondNotification = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
tab: createChromeTabMock({ id: 3 }), tab: createChromeTabMock({ id: 3 }),
domain: "another.com", domain: "another.com",
}); });

View File

@@ -60,12 +60,12 @@ import {
NotificationCipherData, NotificationCipherData,
} from "../content/components/cipher/types"; } from "../content/components/cipher/types";
import { CollectionView } from "../content/components/common-types"; import { CollectionView } from "../content/components/common-types";
import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; import { NotificationType } from "../enums/notification-type.enum";
import { AutofillService } from "../services/abstractions/autofill.service"; import { AutofillService } from "../services/abstractions/autofill.service";
import { TemporaryNotificationChangeLoginService } from "../services/notification-change-login-password.service"; import { TemporaryNotificationChangeLoginService } from "../services/notification-change-login-password.service";
import { import {
AddChangePasswordQueueMessage, AddChangePasswordNotificationQueueMessage,
AddLoginQueueMessage, AddLoginQueueMessage,
AddUnlockVaultQueueMessage, AddUnlockVaultQueueMessage,
AddLoginMessageData, AddLoginMessageData,
@@ -208,16 +208,21 @@ export default class NotificationBackground {
organizations.find((org) => org.id === orgId)?.productTierType; organizations.find((org) => org.id === orgId)?.productTierType;
const cipherQueueMessage = this.notificationQueue.find( const cipherQueueMessage = this.notificationQueue.find(
(message): message is AddChangePasswordQueueMessage | AddLoginQueueMessage => (message): message is AddChangePasswordNotificationQueueMessage | AddLoginQueueMessage =>
message.type === NotificationQueueMessageType.ChangePassword || message.type === NotificationType.ChangePassword ||
message.type === NotificationQueueMessageType.AddLogin, message.type === NotificationType.AddLogin,
); );
if (cipherQueueMessage) { if (cipherQueueMessage) {
const cipherView = let cipherView: CipherView;
cipherQueueMessage.type === NotificationQueueMessageType.ChangePassword if (cipherQueueMessage.type === NotificationType.ChangePassword) {
? await this.getDecryptedCipherById(cipherQueueMessage.cipherId, activeUserId) const {
: this.convertAddLoginQueueMessageToCipherView(cipherQueueMessage); data: { cipherId },
} = cipherQueueMessage;
cipherView = await this.getDecryptedCipherById(cipherId, activeUserId);
} else {
cipherView = this.convertAddLoginQueueMessageToCipherView(cipherQueueMessage);
}
const organizationType = getOrganizationType(cipherView.organizationId); const organizationType = getOrganizationType(cipherView.organizationId);
return [ return [
@@ -424,7 +429,7 @@ export default class NotificationBackground {
}; };
switch (notificationType) { switch (notificationType) {
case NotificationQueueMessageType.AddLogin: case NotificationType.AddLogin:
typeData.removeIndividualVault = await this.removeIndividualVault(); typeData.removeIndividualVault = await this.removeIndividualVault();
break; break;
} }
@@ -501,7 +506,7 @@ export default class NotificationBackground {
const queueMessage: NotificationQueueMessageItem = { const queueMessage: NotificationQueueMessageItem = {
domain, domain,
wasVaultLocked, wasVaultLocked,
type: NotificationQueueMessageType.AtRiskPassword, type: NotificationType.AtRiskPassword,
passwordChangeUri, passwordChangeUri,
organizationName: organization.name, organizationName: organization.name,
tab: tab, tab: tab,
@@ -591,7 +596,7 @@ export default class NotificationBackground {
this.removeTabFromNotificationQueue(tab); this.removeTabFromNotificationQueue(tab);
const launchTimestamp = new Date().getTime(); const launchTimestamp = new Date().getTime();
const message: AddLoginQueueMessage = { const message: AddLoginQueueMessage = {
type: NotificationQueueMessageType.AddLogin, type: NotificationType.AddLogin,
username: loginInfo.username, username: loginInfo.username,
password: loginInfo.password, password: loginInfo.password,
domain: loginDomain, domain: loginDomain,
@@ -716,10 +721,9 @@ export default class NotificationBackground {
// remove any old messages for this tab // remove any old messages for this tab
this.removeTabFromNotificationQueue(tab); this.removeTabFromNotificationQueue(tab);
const launchTimestamp = new Date().getTime(); const launchTimestamp = new Date().getTime();
const message: AddChangePasswordQueueMessage = { const message: AddChangePasswordNotificationQueueMessage = {
type: NotificationQueueMessageType.ChangePassword, type: NotificationType.ChangePassword,
cipherId: cipherId, data: { cipherId: cipherId, newPassword: newPassword },
newPassword: newPassword,
domain: loginDomain, domain: loginDomain,
tab: tab, tab: tab,
launchTimestamp, launchTimestamp,
@@ -734,7 +738,7 @@ export default class NotificationBackground {
this.removeTabFromNotificationQueue(tab); this.removeTabFromNotificationQueue(tab);
const launchTimestamp = new Date().getTime(); const launchTimestamp = new Date().getTime();
const message: AddUnlockVaultQueueMessage = { const message: AddUnlockVaultQueueMessage = {
type: NotificationQueueMessageType.UnlockVault, type: NotificationType.UnlockVault,
domain: loginDomain, domain: loginDomain,
tab: tab, tab: tab,
launchTimestamp, launchTimestamp,
@@ -804,8 +808,8 @@ export default class NotificationBackground {
const queueMessage = this.notificationQueue[i]; const queueMessage = this.notificationQueue[i];
if ( if (
queueMessage.tab.id !== tab.id || queueMessage.tab.id !== tab.id ||
(queueMessage.type !== NotificationQueueMessageType.AddLogin && (queueMessage.type !== NotificationType.AddLogin &&
queueMessage.type !== NotificationQueueMessageType.ChangePassword) queueMessage.type !== NotificationType.ChangePassword)
) { ) {
continue; continue;
} }
@@ -818,17 +822,13 @@ export default class NotificationBackground {
this.accountService.activeAccount$.pipe(getOptionalUserId), this.accountService.activeAccount$.pipe(getOptionalUserId),
); );
if (queueMessage.type === NotificationQueueMessageType.ChangePassword) { if (queueMessage.type === NotificationType.ChangePassword) {
const cipherView = await this.getDecryptedCipherById(queueMessage.cipherId, activeUserId); const {
data: { cipherId, newPassword },
} = queueMessage;
const cipherView = await this.getDecryptedCipherById(cipherId, activeUserId);
await this.updatePassword( await this.updatePassword(cipherView, newPassword, edit, tab, activeUserId, skipReprompt);
cipherView,
queueMessage.newPassword,
edit,
tab,
activeUserId,
skipReprompt,
);
return; return;
} }
@@ -993,7 +993,7 @@ export default class NotificationBackground {
const queueItem = this.notificationQueue.find((item) => item.tab.id === senderTab.id); const queueItem = this.notificationQueue.find((item) => item.tab.id === senderTab.id);
if (queueItem?.type === NotificationQueueMessageType.AddLogin) { if (queueItem?.type === NotificationType.AddLogin) {
const cipherView = this.convertAddLoginQueueMessageToCipherView(queueItem); const cipherView = this.convertAddLoginQueueMessageToCipherView(queueItem);
cipherView.organizationId = organizationId; cipherView.organizationId = organizationId;
cipherView.folderId = folder; cipherView.folderId = folder;
@@ -1075,10 +1075,7 @@ export default class NotificationBackground {
private async saveNever(tab: chrome.tabs.Tab) { private async saveNever(tab: chrome.tabs.Tab) {
for (let i = this.notificationQueue.length - 1; i >= 0; i--) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) {
const queueMessage = this.notificationQueue[i]; const queueMessage = this.notificationQueue[i];
if ( if (queueMessage.tab.id !== tab.id || queueMessage.type !== NotificationType.AddLogin) {
queueMessage.tab.id !== tab.id ||
queueMessage.type !== NotificationQueueMessageType.AddLogin
) {
continue; continue;
} }

View File

@@ -1866,7 +1866,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
frameId: this.focusedFieldData.frameId || 0, frameId: this.focusedFieldData.frameId || 0,
}, },
); );
}, 150); }, 300);
} }
/** /**

View File

@@ -1,11 +0,0 @@
const NotificationQueueMessageType = {
AddLogin: "add",
ChangePassword: "change",
UnlockVault: "unlock",
AtRiskPassword: "at-risk-password",
} as const;
type NotificationQueueMessageTypes =
(typeof NotificationQueueMessageType)[keyof typeof NotificationQueueMessageType];
export { NotificationQueueMessageType, NotificationQueueMessageTypes };

View File

@@ -0,0 +1,10 @@
const NotificationType = {
AddLogin: "add",
ChangePassword: "change",
UnlockVault: "unlock",
AtRiskPassword: "at-risk-password",
} as const;
type NotificationTypes = (typeof NotificationType)[keyof typeof NotificationType];
export { NotificationType, NotificationTypes };

View File

@@ -14,6 +14,10 @@ const NotificationTypes = {
AtRiskPassword: "at-risk-password", AtRiskPassword: "at-risk-password",
} as const; } as const;
/**
* @todo Deprecate in favor of apps/browser/src/autofill/enums/notification-type.enum.ts
* - Determine fix or workaround for restricted imports of that file.
*/
type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes]; type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes];
type NotificationTaskInfo = { type NotificationTaskInfo = {
@@ -21,6 +25,9 @@ type NotificationTaskInfo = {
remainingTasksCount: number; remainingTasksCount: number;
}; };
/**
* @todo Use generics to make this type specific to notification types, see Standard_NotificationQueueMessage.
*/
type NotificationBarIframeInitData = { type NotificationBarIframeInitData = {
ciphers?: NotificationCipherData[]; ciphers?: NotificationCipherData[];
folders?: FolderView[]; folders?: FolderView[];