mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 05:43:41 +00:00
[PM-22375] - [Vault] [Clients] Sort My Items collection to the top of Vault collection filters (#15332)
* WIP - default collection sorting * apply filtering to popup list filters service. * add tests. add feature flag checks * finalize my items collection filters * fix type error * re-add service * re-add comment * remove unused code * fix sorting logic * shorten variable name to fit one line * fix error * fix more errors * abstract logic to vault filter service * fix test * export sort as function instead of adding to class * fix more tests * add collator arg * remove ts-ignore. fix type errors * remove optional param * fix vault filter service
This commit is contained in:
@@ -1,17 +1,22 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Injectable } from "@angular/core";
|
||||
import { firstValueFrom, from, map, mergeMap, Observable, switchMap, take } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import {
|
||||
CollectionService,
|
||||
CollectionTypes,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SingleUserState, StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -40,6 +45,8 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
|
||||
protected policyService: PolicyService,
|
||||
protected stateProvider: StateProvider,
|
||||
protected accountService: AccountService,
|
||||
protected configService: ConfigService,
|
||||
protected i18nService: I18nService,
|
||||
) {}
|
||||
|
||||
async storeCollapsedFilterNodes(
|
||||
@@ -103,12 +110,20 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
|
||||
|
||||
async buildCollections(organizationId?: string): Promise<DynamicTreeNode<CollectionView>> {
|
||||
const storedCollections = await this.collectionService.getAllDecrypted();
|
||||
let collections: CollectionView[];
|
||||
if (organizationId != null) {
|
||||
collections = storedCollections.filter((c) => c.organizationId === organizationId);
|
||||
} else {
|
||||
collections = storedCollections;
|
||||
const orgs = await this.buildOrganizations();
|
||||
const defaulCollectionsFlagEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.CreateDefaultLocation,
|
||||
);
|
||||
|
||||
let collections =
|
||||
organizationId == null
|
||||
? storedCollections
|
||||
: storedCollections.filter((c) => c.organizationId === organizationId);
|
||||
|
||||
if (defaulCollectionsFlagEnabled) {
|
||||
collections = sortDefaultCollections(collections, orgs, this.i18nService.collator);
|
||||
}
|
||||
|
||||
const nestedCollections = await this.collectionService.getAllNested(collections);
|
||||
return new DynamicTreeNode<CollectionView>({
|
||||
fullList: collections,
|
||||
@@ -145,7 +160,7 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
|
||||
folderCopy.id = f.id;
|
||||
folderCopy.revisionDate = f.revisionDate;
|
||||
const parts = f.name != null ? f.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : [];
|
||||
ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, null, NestingDelimiter);
|
||||
ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, undefined, NestingDelimiter);
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
@@ -158,3 +173,28 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
|
||||
return ServiceUtils.getTreeNodeObjectFromList(folders, id) as TreeNode<FolderView>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts collections with default user collections at the top, sorted by organization name.
|
||||
* Remaining collections are sorted by name.
|
||||
* @param collections - The list of collections to sort.
|
||||
* @param orgs - The list of organizations to use for sorting default user collections.
|
||||
* @returns Sorted list of collections.
|
||||
*/
|
||||
export function sortDefaultCollections(
|
||||
collections: CollectionView[],
|
||||
orgs: Organization[] = [],
|
||||
collator: Intl.Collator,
|
||||
): CollectionView[] {
|
||||
const sortedDefaultCollectionTypes = collections
|
||||
.filter((c) => c.type === CollectionTypes.DefaultUserCollection)
|
||||
.sort((a, b) => {
|
||||
const aName = orgs.find((o) => o.id === a.organizationId)?.name ?? a.organizationId;
|
||||
const bName = orgs.find((o) => o.id === b.organizationId)?.name ?? b.organizationId;
|
||||
return collator.compare(aName, bName);
|
||||
});
|
||||
return [
|
||||
...sortedDefaultCollectionTypes,
|
||||
...collections.filter((c) => c.type !== CollectionTypes.DefaultUserCollection),
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user