From f642fbc4e6f12e17c818b1750cc8c04f4615c581 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Tue, 23 Sep 2025 08:50:10 -0700 Subject: [PATCH] [PM-24633] - group collections by org in individual vault filters (#16480) * group collections by org in individual vault filters * update vault filter * use OrganizationId * fix tests --- .../services/vault-filter.service.spec.ts | 17 +++++++++++- .../services/vault-filter.service.ts | 26 ++++++++++++------- .../abstractions/collection.service.ts | 7 +++++ .../services/default-collection.service.ts | 4 +-- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts index f2c60651ed9..c05459250c0 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts @@ -247,6 +247,9 @@ describe("vault filter service", () => { createCollectionView("id-3", "Collection 1/Collection 3", "org test id"), ]; collectionViews.next(storedCollections); + collectionService.groupByOrganization.mockReturnValue( + new Map([["org test id" as OrganizationId, storedCollections]]), + ); const result = await firstValueFrom(vaultFilterService.collectionTree$); @@ -260,6 +263,9 @@ describe("vault filter service", () => { createCollectionView("id-3", "Collection 1/Collection 2/Collection 3", "org test id"), ]; collectionViews.next(storedCollections); + collectionService.groupByOrganization.mockReturnValue( + new Map([["org test id" as OrganizationId, storedCollections]]), + ); const result = await firstValueFrom(vaultFilterService.collectionTree$); @@ -276,6 +282,9 @@ describe("vault filter service", () => { createCollectionView("id-4", "Collection 1/Collection 4", "org test id"), ]; collectionViews.next(storedCollections); + collectionService.groupByOrganization.mockReturnValue( + new Map([["org test id" as OrganizationId, storedCollections]]), + ); const result = await firstValueFrom(vaultFilterService.collectionTree$); @@ -294,6 +303,9 @@ describe("vault filter service", () => { createCollectionView("id-3", "Collection 1/Collection 2/Collection 3", "org test id"), ]; collectionViews.next(storedCollections); + collectionService.groupByOrganization.mockReturnValue( + new Map([["org test id" as OrganizationId, storedCollections]]), + ); const result = await firstValueFrom(vaultFilterService.collectionTree$); @@ -302,7 +314,7 @@ describe("vault filter service", () => { expect(c3.parent.node.id).toEqual("id-1"); }); - it.only("calls sortDefaultCollections with the correct args", async () => { + it("calls sortDefaultCollections with the correct args", async () => { const storedOrgs = [ createOrganization("id-defaultOrg1", "org1"), createOrganization("id-defaultOrg2", "org2"), @@ -326,6 +338,9 @@ describe("vault filter service", () => { ), ]; collectionViews.next(storedCollections); + collectionService.groupByOrganization.mockReturnValue( + new Map([["org test id" as OrganizationId, storedCollections]]), + ); await firstValueFrom(vaultFilterService.collectionTree$); diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts index eeecccc87d6..5897ea8c2ce 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts @@ -243,22 +243,28 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { if (!collections) { return headNode; } - const nodes: TreeNode[] = []; + const all: TreeNode[] = []; if (defaultCollectionsFlagEnabled) { collections = sortDefaultCollections(collections, orgs, this.i18nService.collator); } - collections.forEach((c) => { - const collectionCopy = cloneCollection( - new CollectionView({ ...c, name: c.name }), - ) as CollectionFilter; - collectionCopy.icon = "bwi-collection-shared"; - const parts = c.name != null ? c.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; - ServiceUtils.nestedTraverse(nodes, 0, parts, collectionCopy, null, NestingDelimiter); - }); + const groupedByOrg = this.collectionService.groupByOrganization(collections); + + for (const group of groupedByOrg.values()) { + const nodes: TreeNode[] = []; + for (const c of group) { + const collectionCopy = cloneCollection( + new CollectionView({ ...c, name: c.name }), + ) as CollectionFilter; + collectionCopy.icon = "bwi-collection-shared"; + const parts = c.name ? c.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; + ServiceUtils.nestedTraverse(nodes, 0, parts, collectionCopy, undefined, NestingDelimiter); + } + all.push(...nodes); + } - nodes.forEach((n) => { + all.forEach((n) => { n.parent = headNode; headNode.children.push(n); }); diff --git a/libs/admin-console/src/common/collections/abstractions/collection.service.ts b/libs/admin-console/src/common/collections/abstractions/collection.service.ts index dabaf078e16..f879831324d 100644 --- a/libs/admin-console/src/common/collections/abstractions/collection.service.ts +++ b/libs/admin-console/src/common/collections/abstractions/collection.service.ts @@ -28,4 +28,11 @@ export abstract class CollectionService { * Transforms the input CollectionViews into TreeNodes and then returns the Treenode with the specified id */ abstract getNested(collections: CollectionView[], id: string): TreeNode; + + /* + * Groups/keys collections by OrganizationId + */ + abstract groupByOrganization( + collections: CollectionView[], + ): Map; } diff --git a/libs/admin-console/src/common/collections/services/default-collection.service.ts b/libs/admin-console/src/common/collections/services/default-collection.service.ts index d3b4ebe1f34..0511b692b38 100644 --- a/libs/admin-console/src/common/collections/services/default-collection.service.ts +++ b/libs/admin-console/src/common/collections/services/default-collection.service.ts @@ -230,8 +230,8 @@ export class DefaultCollectionService implements CollectionService { return all; } - groupByOrganization(collections: CollectionView[]): Map { - const groupedByOrg = new Map(); + groupByOrganization(collections: CollectionView[]): Map { + const groupedByOrg = new Map(); collections.map((c) => { const key = c.organizationId; (groupedByOrg.get(key) ?? groupedByOrg.set(key, []).get(key)!).push(c);