From fd2947c6b351ed29e7f6b01fdf2d64ef466f4ede Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Mon, 22 Jan 2024 15:01:15 -0500 Subject: [PATCH] AC-1965 collections navigation highlight (#7574) * keep collections in filters highlighted when featureflag is on and user navigates to a specific collection * apply flexible collections logic to the bitcrumbs and filters in org view --- .../abstractions/vault-filter.service.ts | 1 + .../services/vault-filter.service.spec.ts | 7 ++++++ .../services/vault-filter.service.ts | 4 +++ .../vault-filter-section.component.ts | 25 +++++++++++++++---- .../vault-filter/vault-filter.component.ts | 12 ++++++--- .../vault-header/vault-header.component.html | 8 +++++- 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts index 3b94be2438..72be67f7a0 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts @@ -24,6 +24,7 @@ export abstract class VaultFilterService { getCollectionNodeFromTree: (id: string) => Promise>; setCollapsedFilterNodes: (collapsedFilterNodes: Set) => Promise; expandOrgFilter: () => Promise; + getOrganizationFilter: () => Observable; setOrganizationFilter: (organization: Organization) => void; buildTypeTree: ( head: CipherTypeFilter, 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 3ab230a9f1..912626beac 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 @@ -144,6 +144,13 @@ describe("vault filter service", () => { createFolderView("folder test id", "test"), ]); }); + + it("returns current organization", () => { + vaultFilterService.getOrganizationFilter().subscribe((org) => { + expect(org.id).toEqual("org test id"); + expect(org.identifier).toEqual("Test Org"); + }); + }); }); describe("folder tree", () => { 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 36cbcbed87..bfd8130691 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 @@ -106,6 +106,10 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { return nodes; } + getOrganizationFilter() { + return this._organizationFilter; + } + setOrganizationFilter(organization: Organization) { if (organization?.id != "AllVaults") { this._organizationFilter.next(organization); diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.ts index 430353e760..305212b77c 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.ts @@ -15,6 +15,7 @@ import { VaultFilter } from "../models/vault-filter.model"; }) export class VaultFilterSectionComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); + protected flexibleCollectionsEnabled: boolean; @Input() activeFilter: VaultFilter; @Input() section: VaultFilterSection; @@ -35,10 +36,16 @@ export class VaultFilterSectionComponent implements OnInit, OnDestroy { }); } - ngOnInit() { + async ngOnInit() { this.section?.data$?.pipe(takeUntil(this.destroy$)).subscribe((data) => { this.data = data; }); + this.vaultFilterService + .getOrganizationFilter() + .pipe(takeUntil(this.destroy$)) + .subscribe((org) => { + this.flexibleCollectionsEnabled = org != null ? org.flexibleCollections : false; + }); } ngOnDestroy() { @@ -67,11 +74,19 @@ export class VaultFilterSectionComponent implements OnInit, OnDestroy { } isNodeSelected(filterNode: TreeNode) { + const { organizationId, cipherTypeId, folderId, collectionId, isCollectionSelected } = + this.activeFilter; + + const collectionStatus = this.flexibleCollectionsEnabled + ? filterNode?.node.id === "AllCollections" && + (isCollectionSelected || collectionId === "AllCollections") + : collectionId === filterNode?.node.id; + return ( - this.activeFilter.organizationId === filterNode?.node.id || - this.activeFilter.cipherTypeId === filterNode?.node.id || - this.activeFilter.folderId === filterNode?.node.id || - this.activeFilter.collectionId === filterNode?.node.id + organizationId === filterNode?.node.id || + cipherTypeId === filterNode?.node.id || + folderId === filterNode?.node.id || + collectionStatus ); } diff --git a/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts b/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts index e45c1eef20..819281738e 100644 --- a/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts +++ b/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.component.ts @@ -1,9 +1,8 @@ -import { Component, Input, OnDestroy, OnInit } from "@angular/core"; +import { Component, Input, OnDestroy, OnInit, SimpleChanges } from "@angular/core"; import { firstValueFrom, Subject } from "rxjs"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; @@ -36,7 +35,6 @@ export class VaultFilterComponent extends BaseVaultFilterComponent implements On protected policyService: PolicyService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, - protected configService: ConfigServiceAbstraction, ) { super(vaultFilterService, policyService, i18nService, platformUtilsService); } @@ -51,6 +49,12 @@ export class VaultFilterComponent extends BaseVaultFilterComponent implements On this.isLoaded = true; } + async ngOnChanges(changes: SimpleChanges) { + if (changes.organization) { + this.filters = await this.buildAllFilters(); + } + } + ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); @@ -97,7 +101,7 @@ export class VaultFilterComponent extends BaseVaultFilterComponent implements On async buildAllFilters(): Promise { const builderFilter = {} as VaultFilterList; builderFilter.typeFilter = await this.addTypeFilter(["favorites"]); - if (this.organization?.flexibleCollections) { + if (this._organization?.flexibleCollections) { builderFilter.collectionFilter = await this.addCollectionFilter(); } else { builderFilter.collectionFilter = await super.addCollectionFilter(); diff --git a/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.html b/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.html index 7855acec38..08dd28dc60 100644 --- a/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.html +++ b/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.html @@ -6,7 +6,13 @@ [queryParams]="{ organizationId: organization.id, collectionId: null }" queryParamsHandling="merge" > - {{ organization.name }} {{ "vault" | i18n | lowercase }} + {{ organization.name }} + + {{ "vault" | i18n | lowercase }} + + + {{ "collections" | i18n | lowercase }} +