mirror of
https://github.com/bitwarden/browser
synced 2025-12-26 05:03:33 +00:00
* 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
142 lines
3.8 KiB
TypeScript
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();
|
|
}
|
|
}
|