1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00
Files
browser/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.ts
Rui Tomé e3f31ac741 [AC-1081] Merge feature/billing-obfuscation (#5172)
* [AC-431] Add new organization invite process (#4841)

* [AC-431] Added properties 'key' and 'keys' to OrganizationUserAcceptRequest

* [AC-431] On organization accept added check for 'initOrganization' flag and send encrypt keys if true

* [AC-431] Reverted changes on AcceptOrganizationComponent and OrganizationUserAcceptRequest

* [AC-431] Created OrganizationUserAcceptInitRequest

* [AC-431] Added method postOrganizationUserAcceptInit to OrganizationUserService

* [AC-431] Created AcceptInitOrganizationComponent and added routing config. Added 'inviteInitAcceptedDesc' to messages

* [AC-431] Remove blank line

* [AC-431] Remove requirement for logging in again

* [AC-431] Removed accept-init-organization.component.html

* Update libs/common/src/abstractions/organization-user/organization-user.service.ts

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* [AC-431] Sending collection name when initializing an org

* [AC-431] Deleted component accept-init-organization and incorporated logic into accept-organization

* Update libs/common/src/abstractions/organization-user/organization-user.service.ts

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* [AC-431] Returning promise chains

* [AC-431] Moved ReAuth check to org accept only

* [AC-431] Fixed import issues

---------

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* [AC-434] Hide billing screen for reseller clients (#4955)

* [AC-434] Retrieving ProviderType for each Org

* [AC-434] Hide subscription details if user cannot manage billing

* [AC-434] Renamed providerType to provider-type

* [AC-434] Reverted change that showed Billing History and Payment Methods tabs

* [AC-434] Hiding Secrets Manager enroll

* [AC-434] Renamed Billing access variables to be more readable

* Apply suggestions from code review

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* [AC-434] Reduce duplication in permission code

* [AC-434] npm prettier

* [AC-434] Changed selfhost subscription permission

* [AC-434] Added canEditSubscription check for change plan buttons

* [AC-434] Removed message displaying provider name in subscription

* [AC-434] canEditSubscription logic depends on canViewSubscription

* [AC-434] Hiding next charge value for users without billing edit permission

* [AC-434] Changed canViewSubscription and canEditSubscription to be clearer

* [AC-434] Altered BillingSubscriptionItemResponse.amount and BillingSubscriptionUpcomingInvoiceResponse.amount to nullable

* [AC-434] Reverted change on BillingSubscriptionItemResponse.amount

---------

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* Updated IsPaidOrgGuard reference from org.CanManageBilling to canEditSubscription

---------

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2023-04-14 11:14:18 +01:00

194 lines
6.1 KiB
TypeScript

import { Component, EventEmitter, Input, Output } from "@angular/core";
import { Router } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ProductType } from "@bitwarden/common/enums";
import { TreeNode } from "@bitwarden/common/models/domain/tree-node";
import {
DialogService,
SimpleDialogCloseType,
SimpleDialogOptions,
SimpleDialogType,
} from "@bitwarden/components";
import {
CollectionAdminService,
CollectionAdminView,
} from "../../../admin-console/organizations/core";
import { CollectionDialogTabType } from "../../../admin-console/organizations/shared";
import {
All,
RoutedVaultFilterModel,
Unassigned,
} from "../../individual-vault/vault-filter/shared/models/routed-vault-filter.model";
@Component({
selector: "app-org-vault-header",
templateUrl: "./vault-header.component.html",
})
export class VaultHeaderComponent {
protected All = All;
protected Unassigned = Unassigned;
/**
* Boolean to determine the loading state of the header.
* Shows a loading spinner if set to true
*/
@Input() loading: boolean;
/** Current active fitler */
@Input() filter: RoutedVaultFilterModel;
/** The organization currently being viewed */
@Input() organization: Organization;
/** Currently selected collection */
@Input() collection?: TreeNode<CollectionAdminView>;
/** 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 header */
@Output() onAddCollection = new EventEmitter<void>();
/** Emits an event when the edit collection button is clicked in the header */
@Output() onEditCollection = new EventEmitter<{ tab: CollectionDialogTabType }>();
/** Emits an event when the delete collection button is clicked in the header */
@Output() onDeleteCollection = new EventEmitter<void>();
protected CollectionDialogTabType = CollectionDialogTabType;
protected organizations$ = this.organizationService.organizations$;
constructor(
private organizationService: OrganizationService,
private i18nService: I18nService,
private dialogService: DialogService,
private collectionAdminService: CollectionAdminService,
private router: Router
) {}
get title() {
if (this.collection !== undefined) {
return this.collection.node.name;
}
if (this.filter.collectionId === Unassigned) {
return this.i18nService.t("unassigned");
}
return `${this.organization.name} ${this.i18nService.t("vault").toLowerCase()}`;
}
protected get showBreadcrumbs() {
return this.filter.collectionId !== undefined && this.filter.collectionId !== All;
}
/**
* 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);
}
private showFreeOrgUpgradeDialog(): void {
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
title: this.i18nService.t("upgradeOrganization"),
content: this.i18nService.t(
this.organization.canEditSubscription
? "freeOrgMaxCollectionReachedManageBilling"
: "freeOrgMaxCollectionReachedNoManageBilling",
this.organization.maxCollections
),
type: SimpleDialogType.PRIMARY,
};
if (this.organization.canEditSubscription) {
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
} else {
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
orgUpgradeSimpleDialogOpts.cancelButtonText = null; // hide secondary btn
}
const simpleDialog = this.dialogService.openSimpleDialog(orgUpgradeSimpleDialogOpts);
firstValueFrom(simpleDialog.closed).then((result: SimpleDialogCloseType | undefined) => {
if (!result) {
return;
}
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canEditSubscription) {
this.router.navigate(["/organizations", this.organization.id, "billing", "subscription"], {
queryParams: { upgrade: true },
});
}
});
}
get canEditCollection(): boolean {
// Only edit collections if not editing "Unassigned"
if (this.collection === undefined) {
return false;
}
// Otherwise, check if we can edit the specified collection
return (
this.organization.canEditAnyCollection ||
(this.organization.canEditAssignedCollections && this.collection?.node.assigned)
);
}
addCipher() {
this.onAddCipher.emit();
}
async addCollection() {
if (this.organization.planProductType === ProductType.Free) {
const collections = await this.collectionAdminService.getAll(this.organization.id);
if (collections.length === this.organization.maxCollections) {
this.showFreeOrgUpgradeDialog();
return;
}
}
this.onAddCollection.emit();
}
async editCollection(tab: CollectionDialogTabType): Promise<void> {
this.onEditCollection.emit({ tab });
}
get canDeleteCollection(): boolean {
// Only delete collections if not deleting "Unassigned"
if (this.collection === undefined) {
return false;
}
// Otherwise, check if we can delete the specified collection
return (
this.organization?.canDeleteAnyCollection ||
(this.organization?.canDeleteAssignedCollections && this.collection.node.assigned)
);
}
deleteCollection() {
this.onDeleteCollection.emit();
}
}