1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-31 00:33:33 +00:00

moved 'collections' outside of 'organizations'

This commit is contained in:
Leslie Xiong
2025-12-16 14:28:18 -05:00
parent 9f5dbb5e43
commit 383cb0663c
4 changed files with 45 additions and 68 deletions

View File

@@ -1,30 +1,13 @@
@if (show()) {
@for (organization of organizations().children ?? []; track organization.node.id) {
@if (getOrgCollections(organization.node.id)?.children?.length > 0) {
<bit-nav-group
[icon]="organization.node.icon"
[class.active]="organization.node.id === activeFilter()?.organizationId"
[text]="organization.node.name"
variant="tree"
[appA11yTitle]="organization.node.name"
(click)="applyFilter(organization)"
>
@if (!hideCollections() && collections() != null) {
@for (c of getOrgCollections(organization.node.id)?.children ?? []; track c.node.id) {
<app-collection-filter [activeFilter]="activeFilter()" [collection]="c" />
}
}
</bit-nav-group>
} @else {
<bit-nav-item
[icon]="organization.node.icon"
[forceActiveStyles]="organization.node.id === activeFilter()?.organizationId"
[text]="organization.node.name"
variant="tree"
[appA11yTitle]="organization.node.name"
(click)="applyFilter(organization)"
/>
}
<bit-nav-item
[icon]="organization.node.icon"
[forceActiveStyles]="organization.node.id === activeFilter()?.organizationId"
[text]="organization.node.name"
variant="tree"
[appA11yTitle]="organization.node.name"
(click)="applyFilter(organization)"
/>
@if (!organization.node.enabled) {
<span class="tw-ml-auto">
<i

View File

@@ -2,32 +2,28 @@ import { Component, computed, input, inject } from "@angular/core";
import { DisplayMode } from "@bitwarden/angular/vault/vault-filter/models/display-mode";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
import { ToastService, NavigationModule, A11yTitleDirective } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { OrganizationFilter, VaultFilter, CollectionFilter } from "@bitwarden/vault";
import { CollectionFilterComponent } from "./collection-filter.component";
import { OrganizationFilter, VaultFilter, VaultFilterServiceAbstraction } from "@bitwarden/vault";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "app-organization-filter",
templateUrl: "organization-filter.component.html",
imports: [A11yTitleDirective, NavigationModule, CollectionFilterComponent, I18nPipe],
imports: [A11yTitleDirective, NavigationModule, I18nPipe],
})
export class OrganizationFilterComponent {
private toastService: ToastService = inject(ToastService);
private i18nService: I18nService = inject(I18nService);
private vaultFilterService: VaultFilterServiceAbstraction = inject(VaultFilterServiceAbstraction);
protected readonly hide = input(false);
protected readonly organizations = input<TreeNode<OrganizationFilter>>();
protected readonly activeFilter = input<VaultFilter>();
protected readonly activeOrganizationDataOwnership = input<boolean>(false);
protected readonly activeSingleOrganizationPolicy = input<boolean>(false);
protected readonly hideCollections = input(false);
protected readonly collections = input<TreeNode<CollectionFilter>>();
protected readonly show = computed(() => {
const hiddenDisplayModes: DisplayMode[] = [
@@ -65,36 +61,11 @@ export class OrganizationFilterComponent {
return;
}
this.vaultFilterService.setOrganizationFilter(organization.node);
const filter = this.activeFilter();
if (filter) {
filter.selectedOrganizationNode = organization;
}
}
private readonly collectionsByOrganization = computed(() => {
const collections = this.collections();
const map = new Map<OrganizationId, TreeNode<CollectionFilter>>();
const orgs = this.organizations()?.children;
if (!collections || !orgs) {
return map;
}
for (const org of orgs) {
const filteredCollections = collections.children.filter(
(node) => node.node.organizationId === org.node.id,
);
const headNode = new TreeNode<CollectionFilter>(collections.node, null);
headNode.children = filteredCollections;
map.set(org.node.id, headNode);
}
return map;
});
protected getOrgCollections(organizationId: OrganizationId): TreeNode<CollectionFilter> {
return this.collectionsByOrganization().get(organizationId) ?? null;
}
}

View File

@@ -5,18 +5,34 @@
} @else {
<bit-nav-group icon="bwi-vault" [text]="'vault' | i18n" route="new-vault">
<app-organization-filter
[activeFilter]="activeFilter"
[activeFilter]="activeFilter()"
[organizations]="organizations$ | async"
[activeOrganizationDataOwnership]="activeOrganizationDataOwnershipPolicy"
[activeSingleOrganizationPolicy]="activeSingleOrganizationPolicy"
[collections]="collections$ | async"
/>
<app-type-filter [activeFilter]="activeFilter" [cipherTypes]="cipherTypes$ | async" />
<app-status-filter [hideArchive]="!showArchiveVaultFilter" [activeFilter]="activeFilter" />
<bit-nav-group icon="bwi-folder" [text]="'folders' | i18n" variant="tree">
<app-type-filter [activeFilter]="activeFilter()" [cipherTypes]="cipherTypes$ | async" />
<app-status-filter [hideArchive]="!showArchiveVaultFilter" [activeFilter]="activeFilter()" />
@if (showCollectionsFilter()) {
<bit-nav-group
icon="bwi-collection"
[text]="'collections' | i18n"
variant="tree"
[appA11yTitle]="'collections' | i18n"
>
@for (collection of (collections$ | async)?.children ?? []; track collection.node.id) {
<app-collection-filter [activeFilter]="activeFilter()" [collection]="collection" />
}
</bit-nav-group>
}
<bit-nav-group
icon="bwi-folder"
[text]="'folders' | i18n"
variant="tree"
[appA11yTitle]="'folders' | i18n"
>
@for (folder of (folders$ | async)?.children ?? []; track folder.node.id) {
<app-folder-filter
[activeFilter]="activeFilter"
[activeFilter]="activeFilter()"
[folder]="folder"
(onEditFolder)="editFolder($event)"
/>

View File

@@ -1,5 +1,5 @@
import { CommonModule } from "@angular/common";
import { Component, inject, OnInit, output } from "@angular/core";
import { Component, inject, OnInit, output, computed, signal } from "@angular/core";
import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
@@ -11,7 +11,7 @@ import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/ciphe
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
import { NavigationModule, DialogService } from "@bitwarden/components";
import { NavigationModule, DialogService, A11yTitleDirective } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import {
OrganizationFilter,
@@ -26,6 +26,7 @@ import {
import { DesktopRoutedVaultFilterBridgeService } from "../../../../app/services/desktop-routed-vault-filter-bridge.service";
import { DesktopPremiumUpgradePromptService } from "../../../../services/desktop-premium-upgrade-prompt.service";
import { CollectionFilterComponent } from "./filters/collection-filter.component";
import { FolderFilterComponent } from "./filters/folder-filter.component";
import { OrganizationFilterComponent } from "./filters/organization-filter.component";
import { StatusFilterComponent } from "./filters/status-filter.component";
@@ -43,7 +44,9 @@ import { TypeFilterComponent } from "./filters/type-filter.component";
OrganizationFilterComponent,
StatusFilterComponent,
TypeFilterComponent,
CollectionFilterComponent,
FolderFilterComponent,
A11yTitleDirective,
],
providers: [
{
@@ -62,7 +65,7 @@ export class VaultFilterComponent implements OnInit {
private dialogService: DialogService = inject(DialogService);
private componentIsDestroyed$ = new Subject<boolean>();
protected activeFilter: VaultFilter;
protected readonly activeFilter = signal<VaultFilter | null>(null);
protected onFilterChange = output<VaultFilter>();
private activeUserId: UserId;
@@ -75,6 +78,10 @@ export class VaultFilterComponent implements OnInit {
protected folders$: Observable<TreeNode<FolderFilter>>;
protected cipherTypes$: Observable<TreeNode<CipherTypeFilter>>;
protected readonly showCollectionsFilter = computed<boolean>(() => {
return this.organizations$ != null && !this.activeFilter()?.isMyVaultSelected;
});
private async setActivePolicies() {
this.activeOrganizationDataOwnershipPolicy = await firstValueFrom(
this.policyService.policyAppliesToUser$(
@@ -108,7 +115,7 @@ export class VaultFilterComponent implements OnInit {
this.routedVaultFilterBridgeService.activeFilter$
.pipe(takeUntil(this.componentIsDestroyed$))
.subscribe((filter) => {
this.activeFilter = filter;
this.activeFilter.set(filter);
});
this.isLoaded = true;