1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-07 11:03:30 +00:00

[AC-2504] Add new members access report card (#9335)

* Added new report card and FeatureFlag for MemberAccessReport

* Add new "isEnterpriseOrgGuard"

* Add member access icon

* Show upgrade organization dialog for enterprise on member access report click

* verify member access featureflag on enterprise org guard

* add comment with TODO information for follow up task

* Improved readability, removed path to wrong component and refactored buildReports to use the productType

* added TODO to remove the feature flag on cleanup

* changing ProductType to ProductTierType on isEnterpriseOrgGuard
This commit is contained in:
aj-rosado
2024-06-18 22:13:55 +01:00
committed by GitHub
parent 08cdecf514
commit 1a37d02556
7 changed files with 134 additions and 8 deletions

View File

@@ -0,0 +1,67 @@
import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { ProductTierType } from "@bitwarden/common/billing/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { DialogService } from "@bitwarden/components";
@Injectable({
providedIn: "root",
})
export class IsEnterpriseOrgGuard implements CanActivate {
constructor(
private router: Router,
private organizationService: OrganizationService,
private dialogService: DialogService,
private configService: ConfigService,
) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const isMemberAccessReportEnabled = await firstValueFrom(
this.configService.getFeatureFlag$(FeatureFlag.MemberAccessReport),
);
// TODO: Remove on "MemberAccessReport" feature flag cleanup
if (!isMemberAccessReportEnabled) {
return this.router.createUrlTree(["/"]);
}
const org = await this.organizationService.get(route.params.organizationId);
if (org == null) {
return this.router.createUrlTree(["/"]);
}
if (org.productTierType != ProductTierType.Enterprise) {
// Users without billing permission can't access billing
if (!org.canEditSubscription) {
await this.dialogService.openSimpleDialog({
title: { key: "upgradeOrganizationEnterprise" },
content: { key: "onlyAvailableForEnterpriseOrganization" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "info",
});
return false;
} else {
const upgradeConfirmed = await this.dialogService.openSimpleDialog({
title: { key: "upgradeOrganizationEnterprise" },
content: { key: "onlyAvailableForEnterpriseOrganization" },
acceptButtonText: { key: "upgradeOrganization" },
type: "info",
icon: "bwi-arrow-circle-up",
});
if (upgradeConfirmed) {
await this.router.navigate(["organizations", org.id, "billing", "subscription"], {
queryParams: { upgrade: true },
});
}
}
}
return org.productTierType == ProductTierType.Enterprise;
}
}

View File

@@ -1,8 +1,11 @@
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, NavigationEnd, Router } from "@angular/router";
import { filter, map, Observable, startWith, concatMap } from "rxjs";
import { filter, map, Observable, startWith, concatMap, firstValueFrom } from "rxjs";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { ProductTierType } from "@bitwarden/common/billing/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { ReportVariant, reports, ReportType, ReportEntry } from "../../../tools/reports";
@@ -14,13 +17,21 @@ export class ReportsHomeComponent implements OnInit {
reports$: Observable<ReportEntry[]>;
homepage$: Observable<boolean>;
private isMemberAccessReportEnabled: boolean;
constructor(
private route: ActivatedRoute,
private organizationService: OrganizationService,
private router: Router,
private configService: ConfigService,
) {}
ngOnInit() {
async ngOnInit() {
// TODO: Remove on "MemberAccessReport" feature flag cleanup
this.isMemberAccessReportEnabled = await firstValueFrom(
this.configService.getFeatureFlag$(FeatureFlag.MemberAccessReport),
);
this.homepage$ = this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map((event) => this.isReportsHomepageRouteUrl((event as NavigationEnd).urlAfterRedirects)),
@@ -29,16 +40,15 @@ export class ReportsHomeComponent implements OnInit {
this.reports$ = this.route.params.pipe(
concatMap((params) => this.organizationService.get$(params.organizationId)),
map((org) => this.buildReports(org.isFreeOrg)),
map((org) => this.buildReports(org.productTierType)),
);
}
private buildReports(upgradeRequired: boolean): ReportEntry[] {
const reportRequiresUpgrade = upgradeRequired
? ReportVariant.RequiresUpgrade
: ReportVariant.Enabled;
private buildReports(productType: ProductTierType): ReportEntry[] {
const reportRequiresUpgrade =
productType == ProductTierType.Free ? ReportVariant.RequiresUpgrade : ReportVariant.Enabled;
return [
const reportsArray = [
{
...reports[ReportType.ExposedPasswords],
variant: reportRequiresUpgrade,
@@ -60,6 +70,18 @@ export class ReportsHomeComponent implements OnInit {
variant: reportRequiresUpgrade,
},
];
if (this.isMemberAccessReportEnabled) {
reportsArray.push({
...reports[ReportType.MemberAccessReport],
variant:
productType == ProductTierType.Enterprise
? ReportVariant.Enabled
: ReportVariant.RequiresEnterprise,
});
}
return reportsArray;
}
private isReportsHomepageRouteUrl(url: string): boolean {