mirror of
https://github.com/bitwarden/browser
synced 2026-01-04 09:33:27 +00:00
[PM-12048] Wire up vNextCollectionService (#14871)
* remove derived state, add cache in service. Fix ts strict errors
* cleanup
* promote vNextCollectionService
* wip
* replace callers in web WIP
* refactor tests for web
* update callers to use vNextCollectionServcie methods in CLI
* WIP make decryptMany public again, fix callers, imports
* wip cli
* wip desktop
* update callers in browser, fix tests
* remove in service cache
* cleanup
* fix test
* clean up
* address cr feedback
* remove duplicate userId
* clean up
* remove unused import
* fix vault-settings-import-nudge.service
* fix caching issue
* clean up
* refactor decryption, cleanup, update callers
* clean up
* Use in-memory statedefinition
* Ac/pm 12048 v next collection service pairing (#15239)
* Draft from pairing with Gibson
* Add todos
* Add comment
* wip
* refactor upsert
---------
Co-authored-by: Brandon <btreston@bitwarden.com>
* clean up
* fix state definitions
* fix linter error
* cleanup
* add test, fix shareReplay
* fix item-more-options component
* fix desktop build
* refactor state to account for null as an initial value, remove caching
* add proper cache, add unit test, update callers
* clean up
* fix routing when deleting collections
* cleanup
* use combineLatest
* fix ts-strict errors, fix error handling
* refactor Collection and CollectionView properties for ts-strict
* Revert "refactor Collection and CollectionView properties for ts-strict"
This reverts commit a5c63aab76.
---------
Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
This commit is contained in:
@@ -1030,18 +1030,23 @@ export default class NotificationBackground {
|
||||
private async getCollectionData(
|
||||
message: NotificationBackgroundExtensionMessage,
|
||||
): Promise<CollectionView[]> {
|
||||
const collections = (await this.collectionService.getAllDecrypted()).reduce<CollectionView[]>(
|
||||
(acc, collection) => {
|
||||
if (collection.organizationId === message?.orgId) {
|
||||
acc.push({
|
||||
id: collection.id,
|
||||
name: collection.name,
|
||||
organizationId: collection.organizationId,
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
const collections = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.collectionService.decryptedCollections$(userId)),
|
||||
map((collections) =>
|
||||
collections.reduce<CollectionView[]>((acc, collection) => {
|
||||
if (collection.organizationId === message?.orgId) {
|
||||
acc.push({
|
||||
id: collection.id,
|
||||
name: collection.name,
|
||||
organizationId: collection.organizationId,
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []),
|
||||
),
|
||||
),
|
||||
);
|
||||
return collections;
|
||||
}
|
||||
|
||||
@@ -1620,7 +1620,6 @@ export default class MainBackground {
|
||||
this.keyService.clearKeys(userBeingLoggedOut),
|
||||
this.cipherService.clear(userBeingLoggedOut),
|
||||
this.folderService.clear(userBeingLoggedOut),
|
||||
this.collectionService.clear(userBeingLoggedOut),
|
||||
this.vaultTimeoutSettingsService.clear(userBeingLoggedOut),
|
||||
this.vaultFilterService.clear(),
|
||||
this.biometricStateService.logout(userBeingLoggedOut),
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Observable, combineLatest, filter, first, map, switchMap } from "rxjs";
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
@@ -70,7 +71,12 @@ export class AssignCollections {
|
||||
),
|
||||
);
|
||||
|
||||
combineLatest([cipher$, this.collectionService.decryptedCollections$])
|
||||
const decryptedCollection$ = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.collectionService.decryptedCollections$(userId)),
|
||||
);
|
||||
|
||||
combineLatest([cipher$, decryptedCollection$])
|
||||
.pipe(takeUntilDestroyed(), first())
|
||||
.subscribe(([cipherView, collections]) => {
|
||||
let availableCollections = collections;
|
||||
|
||||
@@ -93,7 +93,7 @@ export class ItemMoreOptionsComponent {
|
||||
switchMap((userId) => {
|
||||
return combineLatest([
|
||||
this.organizationService.hasOrganizations(userId),
|
||||
this.collectionService.decryptedCollections$,
|
||||
this.collectionService.decryptedCollections$(userId),
|
||||
]).pipe(
|
||||
map(([hasOrgs, collections]) => {
|
||||
const canEditCollections = collections.some((c) => !c.readOnly);
|
||||
|
||||
@@ -139,7 +139,7 @@ describe("VaultPopupItemsService", () => {
|
||||
];
|
||||
|
||||
organizationServiceMock.organizations$.mockReturnValue(new BehaviorSubject([mockOrg]));
|
||||
collectionService.decryptedCollections$ = new BehaviorSubject(mockCollections);
|
||||
collectionService.decryptedCollections$.mockReturnValue(new BehaviorSubject(mockCollections));
|
||||
|
||||
activeUserLastSync$ = new BehaviorSubject(new Date());
|
||||
syncServiceMock.activeUserLastSync$.mockReturnValue(activeUserLastSync$);
|
||||
|
||||
@@ -72,6 +72,11 @@ export class VaultPopupItemsService {
|
||||
private organizations$ = this.activeUserId$.pipe(
|
||||
switchMap((userId) => this.organizationService.organizations$(userId)),
|
||||
);
|
||||
|
||||
private decryptedCollections$ = this.activeUserId$.pipe(
|
||||
switchMap((userId) => this.collectionService.decryptedCollections$(userId)),
|
||||
);
|
||||
|
||||
/**
|
||||
* Observable that contains the list of other cipher types that should be shown
|
||||
* in the autofill section of the Vault tab. Depends on vault settings.
|
||||
@@ -130,7 +135,7 @@ export class VaultPopupItemsService {
|
||||
|
||||
private _activeCipherList$: Observable<PopupCipherViewLike[]> = this._allDecryptedCiphers$.pipe(
|
||||
switchMap((ciphers) =>
|
||||
combineLatest([this.organizations$, this.collectionService.decryptedCollections$]).pipe(
|
||||
combineLatest([this.organizations$, this.decryptedCollections$]).pipe(
|
||||
map(([organizations, collections]) => {
|
||||
const orgMap = Object.fromEntries(organizations.map((org) => [org.id, org]));
|
||||
const collectionMap = Object.fromEntries(collections.map((col) => [col.id, col]));
|
||||
@@ -291,7 +296,7 @@ export class VaultPopupItemsService {
|
||||
*/
|
||||
deletedCiphers$: Observable<PopupCipherViewLike[]> = this._allDecryptedCiphers$.pipe(
|
||||
switchMap((ciphers) =>
|
||||
combineLatest([this.organizations$, this.collectionService.decryptedCollections$]).pipe(
|
||||
combineLatest([this.organizations$, this.decryptedCollections$]).pipe(
|
||||
map(([organizations, collections]) => {
|
||||
const orgMap = Object.fromEntries(organizations.map((org) => [org.id, org]));
|
||||
const collectionMap = Object.fromEntries(collections.map((col) => [col.id, col]));
|
||||
|
||||
@@ -20,6 +20,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import {
|
||||
@@ -58,7 +59,7 @@ describe("VaultPopupListFiltersService", () => {
|
||||
};
|
||||
|
||||
const collectionService = {
|
||||
decryptedCollections$,
|
||||
decryptedCollections$: () => decryptedCollections$,
|
||||
getAllNested: () => Promise.resolve([]),
|
||||
} as unknown as CollectionService;
|
||||
|
||||
@@ -106,7 +107,7 @@ describe("VaultPopupListFiltersService", () => {
|
||||
signal: jest.fn(() => mockCachedSignal),
|
||||
};
|
||||
|
||||
collectionService.getAllNested = () => Promise.resolve([]);
|
||||
collectionService.getAllNested = () => [];
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{
|
||||
@@ -382,14 +383,7 @@ describe("VaultPopupListFiltersService", () => {
|
||||
beforeEach(() => {
|
||||
decryptedCollections$.next(testCollections);
|
||||
|
||||
collectionService.getAllNested = () =>
|
||||
Promise.resolve(
|
||||
testCollections.map((c) => ({
|
||||
children: [],
|
||||
node: c,
|
||||
parent: null,
|
||||
})),
|
||||
);
|
||||
collectionService.getAllNested = () => testCollections.map((c) => new TreeNode(c, null));
|
||||
});
|
||||
|
||||
it("returns all collections", (done) => {
|
||||
@@ -755,15 +749,13 @@ function createSeededVaultPopupListFiltersService(
|
||||
} as any;
|
||||
|
||||
const collectionServiceMock = {
|
||||
decryptedCollections$: seededCollections$,
|
||||
decryptedCollections$: () => seededCollections$,
|
||||
getAllNested: () =>
|
||||
Promise.resolve(
|
||||
seededCollections$.value.map((c) => ({
|
||||
children: [],
|
||||
node: c,
|
||||
parent: null,
|
||||
})),
|
||||
),
|
||||
seededCollections$.value.map((c) => ({
|
||||
children: [],
|
||||
node: c,
|
||||
parent: null,
|
||||
})),
|
||||
} as any;
|
||||
|
||||
const folderServiceMock = {
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
from,
|
||||
map,
|
||||
Observable,
|
||||
shareReplay,
|
||||
@@ -446,7 +445,7 @@ export class VaultPopupListFiltersService {
|
||||
this.filters$.pipe(
|
||||
distinctUntilChanged((prev, curr) => prev.organization?.id === curr.organization?.id),
|
||||
),
|
||||
this.collectionService.decryptedCollections$,
|
||||
this.collectionService.decryptedCollections$(userId),
|
||||
this.organizationService.memberOrganizations$(userId),
|
||||
this.configService.getFeatureFlag$(FeatureFlag.CreateDefaultLocation),
|
||||
]),
|
||||
@@ -463,16 +462,11 @@ export class VaultPopupListFiltersService {
|
||||
}
|
||||
return sortDefaultCollections(filtered, orgs, this.i18nService.collator);
|
||||
}),
|
||||
switchMap((collections) => {
|
||||
return from(this.collectionService.getAllNested(collections)).pipe(
|
||||
map(
|
||||
(nested) =>
|
||||
new DynamicTreeNode<CollectionView>({
|
||||
fullList: collections,
|
||||
nestedList: nested,
|
||||
}),
|
||||
),
|
||||
);
|
||||
map((fullList) => {
|
||||
return new DynamicTreeNode<CollectionView>({
|
||||
fullList,
|
||||
nestedList: this.collectionService.getAllNested(fullList),
|
||||
});
|
||||
}),
|
||||
map((tree) =>
|
||||
tree.nestedList.map((c) => this.convertToChipSelectOption(c, "bwi-collection-shared")),
|
||||
|
||||
Reference in New Issue
Block a user