1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-26 05:03:33 +00:00
Files
browser/apps/web/src/app/vault/individual-vault/vault-header/vault-header.component.ts
Robyn MacCallum 683b7fea77 [AC-1120] Implement 'New' button dropdown in Individual Vault (#5235)
* Change 'New' button to dropdown with folders and collections

* Individual vault changes to support adding collections

* Add org selector to CollectionDialogComponent

* Implement CollectionService.upsert() in CollectionAdminService.save()

* Filter collections to ones that users can create collections in

* Filter organizations by ones the user can create a collection in

* CollectionDialog observable updates

* Remove CollectionService.upsert from CollectionAdminService and return collection on save from CollectionDialog.

* Filter out collections that the user does not have access to in collection dialog for Individual Vault.

* Remove add folder action from vault filter

* Remove add button from filters as it is no longer used

* Update comment to reference future ticket

* Change CollectionDialogResult from a class to an interface

* Remove extra call to loadOrg() in the case of opening the modal from the individual vault

* Use async pipe instead of subscribe for organizations
2023-06-27 11:36:48 -04:00

142 lines
3.8 KiB
TypeScript

import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from "@angular/core";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { TreeNode } from "@bitwarden/common/models/domain/tree-node";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
import {
All,
RoutedVaultFilterModel,
Unassigned,
} from "../vault-filter/shared/models/routed-vault-filter.model";
@Component({
selector: "app-vault-header",
templateUrl: "./vault-header.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class VaultHeaderComponent {
protected Unassigned = Unassigned;
protected All = All;
/**
* Boolean to determine the loading state of the header.
* Shows a loading spinner if set to true
*/
@Input() loading: boolean;
/** Current active filter */
@Input() filter: RoutedVaultFilterModel;
/**
* All organizations that can be shown
*/
@Input() organizations: Organization[] = [];
/**
* Currently selected collection
*/
@Input() collection?: TreeNode<CollectionView>;
/**
* Whether 'Collection' option is shown in the 'New' dropdown
*/
@Input() canCreateCollections: boolean;
/**
* Emits an event when the new item button is clicked in the header
*/
@Output() onAddCipher = new EventEmitter<void>();
/**
* Emits an event when the new collection button is clicked in the 'New' dropdown menu
*/
@Output() onAddCollection = new EventEmitter<null>();
/**
* Emits an event when the new folder button is clicked in the 'New' dropdown menu
*/
@Output() onAddFolder = new EventEmitter<null>();
constructor(private i18nService: I18nService) {}
/**
* The id of the organization that is currently being filtered on.
* This can come from a collection filter or organization filter, if applied.
*/
protected get activeOrganizationId() {
if (this.collection != undefined) {
return this.collection.node.organizationId;
}
if (this.filter.organizationId !== undefined) {
return this.filter.organizationId;
}
return undefined;
}
protected get activeOrganization() {
const organizationId = this.activeOrganizationId;
return this.organizations?.find((org) => org.id === organizationId);
}
protected get showBreadcrumbs() {
return this.filter.collectionId !== undefined && this.filter.collectionId !== All;
}
protected get title() {
if (this.filter.collectionId === Unassigned) {
return this.i18nService.t("unassigned");
}
if (this.collection) {
return this.collection.node.name;
}
if (this.filter.organizationId === Unassigned) {
return this.i18nService.t("myVault");
}
const activeOrganization = this.activeOrganization;
if (activeOrganization) {
return `${activeOrganization.name} ${this.i18nService.t("vault").toLowerCase()}`;
}
return this.i18nService.t("allVaults");
}
/**
* A list of collection filters that form a chain from the organization root to currently selected collection.
* Begins from the organization root and excludes the currently selected collection.
*/
protected get collections() {
if (this.collection == undefined) {
return [];
}
const collections = [this.collection];
while (collections[collections.length - 1].parent != undefined) {
collections.push(collections[collections.length - 1].parent);
}
return collections
.slice(1)
.reverse()
.map((treeNode) => treeNode.node);
}
protected addCipher() {
this.onAddCipher.emit();
}
async addFolder(): Promise<void> {
this.onAddFolder.emit();
}
async addCollection(): Promise<void> {
this.onAddCollection.emit();
}
}