diff --git a/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts b/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts index f19c3f64530..95ae911bbf6 100644 --- a/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts +++ b/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts @@ -37,31 +37,6 @@ export function getNestedCollectionTree( return nodes; } -export function getNestedCollectionTree_vNext( - collections: (CollectionView | CollectionAdminView)[], -): TreeNode[] { - if (!collections) { - return []; - } - - // Collections need to be cloned because ServiceUtils.nestedTraverse actively - // modifies the names of collections. - // These changes risk affecting collections store in StateService. - const clonedCollections = collections - .sort((a, b) => a.name.localeCompare(b.name)) - .map(cloneCollection); - - const nodes: TreeNode[] = []; - clonedCollections.forEach((collection) => { - const parts = - collection.name != null - ? collection.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) - : []; - ServiceUtils.nestedTraverse_vNext(nodes, 0, parts, collection, null, NestingDelimiter); - }); - return nodes; -} - export function getFlatCollectionTree( nodes: TreeNode[], ): CollectionAdminView[]; diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index 8ad0f6cf499..5846209e4c6 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -125,11 +125,7 @@ import { BulkCollectionsDialogResult, } from "./bulk-collections-dialog"; import { CollectionAccessRestrictedComponent } from "./collection-access-restricted.component"; -import { - getNestedCollectionTree, - getFlatCollectionTree, - getNestedCollectionTree_vNext, -} from "./utils"; +import { getNestedCollectionTree, getFlatCollectionTree } from "./utils"; import { VaultFilterModule } from "./vault-filter/vault-filter.module"; import { VaultHeaderComponent } from "./vault-header/vault-header.component"; @@ -423,16 +419,9 @@ export class VaultComponent implements OnInit, OnDestroy { }), ); - const nestedCollections$ = combineLatest([ - allCollections$, - this.configService.getFeatureFlag$(FeatureFlag.OptimizeNestedTraverseTypescript), - ]).pipe( - map( - ([collections, shouldOptimize]) => - (shouldOptimize - ? getNestedCollectionTree_vNext(collections) - : getNestedCollectionTree(collections)) as TreeNode[], - ), + const nestedCollections$ = allCollections$.pipe( + map((collections) => getNestedCollectionTree(collections)), + shareReplay({ refCount: true, bufferSize: 1 }), ); const collections$ = combineLatest([ diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 51d59b54369..52c4bcef01b 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -48,7 +48,6 @@ import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -85,7 +84,6 @@ import { import { getNestedCollectionTree, getFlatCollectionTree, - getNestedCollectionTree_vNext, } from "../../admin-console/organizations/collections"; import { CollectionDialogAction, @@ -331,15 +329,8 @@ export class VaultComponent implements OnInit, OnDestroy { const filter$ = this.routedVaultFilterService.filter$; const allCollections$ = this.collectionService.decryptedCollections$; - const nestedCollections$ = combineLatest([ - allCollections$, - this.configService.getFeatureFlag$(FeatureFlag.OptimizeNestedTraverseTypescript), - ]).pipe( - map(([collections, shouldOptimize]) => - shouldOptimize - ? getNestedCollectionTree_vNext(collections) - : getNestedCollectionTree(collections), - ), + const nestedCollections$ = allCollections$.pipe( + map((collections) => getNestedCollectionTree(collections)), ); this.searchText$ diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 8322dba03c6..55c96c2334c 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -12,7 +12,6 @@ import { ServerConfig } from "../platform/abstractions/config/server-config"; export enum FeatureFlag { /* Admin Console Team */ SeparateCustomRolePermissions = "pm-19917-separate-custom-role-permissions", - OptimizeNestedTraverseTypescript = "pm-21695-optimize-nested-traverse-typescript", CreateDefaultLocation = "pm-19467-create-default-location", /* Auth */ @@ -77,7 +76,6 @@ const FALSE = false as boolean; export const DefaultFeatureFlagValue = { /* Admin Console Team */ [FeatureFlag.SeparateCustomRolePermissions]: FALSE, - [FeatureFlag.OptimizeNestedTraverseTypescript]: FALSE, [FeatureFlag.CreateDefaultLocation]: FALSE, /* Autofill */ diff --git a/libs/common/src/vault/service-utils.spec.ts b/libs/common/src/vault/service-utils.spec.ts index 619d3d72ee6..db414da76d7 100644 --- a/libs/common/src/vault/service-utils.spec.ts +++ b/libs/common/src/vault/service-utils.spec.ts @@ -36,24 +36,6 @@ describe("serviceUtils", () => { }); }); - describe("nestedTraverse_vNext", () => { - it("should traverse a tree and add a node at the correct position given a valid path", () => { - const nodeToBeAdded: FakeObject = { id: "1.2.1", name: "1.2.1" }; - const path = ["1", "1.2", "1.2.1"]; - - ServiceUtils.nestedTraverse_vNext(nodeTree, 0, path, nodeToBeAdded, null, "/"); - expect(nodeTree[0].children[1].children[0].node).toEqual(nodeToBeAdded); - }); - - it("should combine the path for missing nodes and use as the added node name given an invalid path", () => { - const nodeToBeAdded: FakeObject = { id: "blank", name: "blank" }; - const path = ["3", "3.1", "3.1.1"]; - - ServiceUtils.nestedTraverse_vNext(nodeTree, 0, path, nodeToBeAdded, null, "/"); - expect(nodeTree[2].children[0].node.name).toEqual("3.1/3.1.1"); - }); - }); - describe("getTreeNodeObject", () => { it("should return a matching node given a single tree branch and a valid id", () => { const id = "1.1.1"; diff --git a/libs/common/src/vault/service-utils.ts b/libs/common/src/vault/service-utils.ts index 9595434223f..0d863e6ad0b 100644 --- a/libs/common/src/vault/service-utils.ts +++ b/libs/common/src/vault/service-utils.ts @@ -4,64 +4,6 @@ import { ITreeNodeObject, TreeNode } from "./models/domain/tree-node"; export class ServiceUtils { - static nestedTraverse( - nodeTree: TreeNode[], - partIndex: number, - parts: string[], - obj: ITreeNodeObject, - parent: TreeNode | undefined, - delimiter: string, - ) { - if (parts.length <= partIndex) { - return; - } - - const end: boolean = partIndex === parts.length - 1; - const partName: string = parts[partIndex]; - - for (let i = 0; i < nodeTree.length; i++) { - if (nodeTree[i].node.name !== partName) { - continue; - } - if (end && nodeTree[i].node.id !== obj.id) { - // Another node exists with the same name as the node being added - nodeTree.push(new TreeNode(obj, parent, partName)); - return; - } - // Move down the tree to the next level - ServiceUtils.nestedTraverse( - nodeTree[i].children, - partIndex + 1, - parts, - obj, - nodeTree[i], - delimiter, - ); - return; - } - - // If there's no node here with the same name... - if (nodeTree.filter((n) => n.node.name === partName).length === 0) { - // And we're at the end of the path given, add the node - if (end) { - nodeTree.push(new TreeNode(obj, parent, partName)); - return; - } - // And we're not at the end of the path, combine the current name with the next name - // 1, *1.2, 1.2.1 becomes - // 1, *1.2/1.2.1 - const newPartName = partName + delimiter + parts[partIndex + 1]; - ServiceUtils.nestedTraverse( - nodeTree, - 0, - [newPartName, ...parts.slice(partIndex + 2)], - obj, - parent, - delimiter, - ); - } - } - /** * Recursively adds a node to nodeTree * @param {TreeNode[]} nodeTree - An array of TreeNodes that the node will be added to @@ -71,7 +13,7 @@ export class ServiceUtils { * @param {ITreeNodeObject} parent - The parent node of the `obj` node * @param {string} delimiter - The delimiter used to split the path string, will be used to combine the path for missing nodes */ - static nestedTraverse_vNext( + static nestedTraverse( nodeTree: TreeNode[], partIndex: number, parts: string[], @@ -104,7 +46,7 @@ export class ServiceUtils { // 1, *1.2, 1.2.1 becomes // 1, *1.2/1.2.1 const newPartName = partName + delimiter + parts[partIndex + 1]; - ServiceUtils.nestedTraverse_vNext( + ServiceUtils.nestedTraverse( nodeTree, 0, [newPartName, ...parts.slice(partIndex + 2)], @@ -114,7 +56,7 @@ export class ServiceUtils { ); } else { // There is a node here with the same name, descend into it - ServiceUtils.nestedTraverse_vNext( + ServiceUtils.nestedTraverse( matchingNodes[0].children, partIndex + 1, parts,