mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-29164] Access Intelligence display for only enterprise (#17807)
* Access Intelligence display for only enterprise * modifying the access intelligence routing to properly match. Added documentation. * tasks remove useriskinsights flag * fixing tasks test cases * tasks should only check for enterprise * fixing uncommitted changes * reverting unecessary change from all activites * adding back missing test case
This commit is contained in:
@@ -2,12 +2,15 @@
|
|||||||
<app-side-nav variant="secondary" *ngIf="organization$ | async as organization">
|
<app-side-nav variant="secondary" *ngIf="organization$ | async as organization">
|
||||||
<bit-nav-logo [openIcon]="logo" route="." [label]="'adminConsole' | i18n"></bit-nav-logo>
|
<bit-nav-logo [openIcon]="logo" route="." [label]="'adminConsole' | i18n"></bit-nav-logo>
|
||||||
<org-switcher [filter]="orgFilter" [hideNewButton]="hideNewOrgButton$ | async"></org-switcher>
|
<org-switcher [filter]="orgFilter" [hideNewButton]="hideNewOrgButton$ | async"></org-switcher>
|
||||||
<bit-nav-item
|
|
||||||
icon="bwi-dashboard"
|
@if (canShowAccessIntelligenceTab(organization)) {
|
||||||
*ngIf="organization.canAccessReports"
|
<bit-nav-item
|
||||||
[text]="'accessIntelligence' | i18n"
|
icon="bwi-dashboard"
|
||||||
route="access-intelligence"
|
[text]="'accessIntelligence' | i18n"
|
||||||
></bit-nav-item>
|
route="access-intelligence"
|
||||||
|
></bit-nav-item>
|
||||||
|
}
|
||||||
|
|
||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
icon="bwi-collection-shared"
|
icon="bwi-collection-shared"
|
||||||
[text]="'collections' | i18n"
|
[text]="'collections' | i18n"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { combineLatest, filter, map, Observable, switchMap, withLatestFrom } fro
|
|||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { AdminConsoleLogo } from "@bitwarden/assets/svg";
|
import { AdminConsoleLogo } from "@bitwarden/assets/svg";
|
||||||
import {
|
import {
|
||||||
|
canAccessAccessIntelligence,
|
||||||
canAccessBillingTab,
|
canAccessBillingTab,
|
||||||
canAccessGroupsTab,
|
canAccessGroupsTab,
|
||||||
canAccessMembersTab,
|
canAccessMembersTab,
|
||||||
@@ -172,6 +173,10 @@ export class OrganizationLayoutComponent implements OnInit {
|
|||||||
return canAccessBillingTab(organization);
|
return canAccessBillingTab(organization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canShowAccessIntelligenceTab(organization: Organization): boolean {
|
||||||
|
return canAccessAccessIntelligence(organization);
|
||||||
|
}
|
||||||
|
|
||||||
getReportTabLabel(organization: Organization): string {
|
getReportTabLabel(organization: Organization): string {
|
||||||
return organization.useEvents ? "reporting" : "reports";
|
return organization.useEvents ? "reporting" : "reports";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { NgModule } from "@angular/core";
|
|||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
|
||||||
import { authGuard } from "@bitwarden/angular/auth/guards";
|
import { authGuard } from "@bitwarden/angular/auth/guards";
|
||||||
import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import {
|
||||||
|
canAccessAccessIntelligence,
|
||||||
|
canAccessSettingsTab,
|
||||||
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { isEnterpriseOrgGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/is-enterprise-org.guard";
|
import { isEnterpriseOrgGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/is-enterprise-org.guard";
|
||||||
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
||||||
import { OrganizationLayoutComponent } from "@bitwarden/web-vault/app/admin-console/organizations/layouts/organization-layout.component";
|
import { OrganizationLayoutComponent } from "@bitwarden/web-vault/app/admin-console/organizations/layouts/organization-layout.component";
|
||||||
@@ -79,7 +82,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "access-intelligence",
|
path: "access-intelligence",
|
||||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessReports)],
|
canActivate: [organizationPermissionsGuard(canAccessAccessIntelligence)],
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
import("../../dirt/access-intelligence/access-intelligence.module").then(
|
import("../../dirt/access-intelligence/access-intelligence.module").then(
|
||||||
(m) => m.AccessIntelligenceModule,
|
(m) => m.AccessIntelligenceModule,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
|
||||||
|
import { canAccessAccessIntelligence } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
||||||
|
|
||||||
import { RiskInsightsComponent } from "./risk-insights.component";
|
import { RiskInsightsComponent } from "./risk-insights.component";
|
||||||
@@ -8,7 +9,7 @@ import { RiskInsightsComponent } from "./risk-insights.component";
|
|||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessReports)],
|
canActivate: [organizationPermissionsGuard(canAccessAccessIntelligence)],
|
||||||
component: RiskInsightsComponent,
|
component: RiskInsightsComponent,
|
||||||
data: {
|
data: {
|
||||||
titleId: "accessIntelligence",
|
titleId: "accessIntelligence",
|
||||||
|
|||||||
@@ -41,6 +41,18 @@ export function canAccessBillingTab(org: Organization): boolean {
|
|||||||
return org.isOwner;
|
return org.isOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access Intelligence is only available to:
|
||||||
|
* - Enterprise organizations
|
||||||
|
* - Users in those organizations with report access
|
||||||
|
*
|
||||||
|
* @param org The organization to verify access
|
||||||
|
* @returns If true can access the Access Intelligence feature
|
||||||
|
*/
|
||||||
|
export function canAccessAccessIntelligence(org: Organization): boolean {
|
||||||
|
return org.canUseAccessIntelligence && org.canAccessReports;
|
||||||
|
}
|
||||||
|
|
||||||
export function canAccessOrgAdmin(org: Organization): boolean {
|
export function canAccessOrgAdmin(org: Organization): boolean {
|
||||||
// Admin console can only be accessed by Owners for disabled organizations
|
// Admin console can only be accessed by Owners for disabled organizations
|
||||||
if (!org.enabled && !org.isOwner) {
|
if (!org.enabled && !org.isOwner) {
|
||||||
|
|||||||
@@ -402,4 +402,8 @@ export class Organization {
|
|||||||
this.permissions.accessEventLogs)
|
this.permissions.accessEventLogs)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get canUseAccessIntelligence() {
|
||||||
|
return this.productTierType === ProductTierType.Enterprise;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,10 +51,10 @@ describe("Default task service", () => {
|
|||||||
mockGetAllOrgs$.mockReturnValue(
|
mockGetAllOrgs$.mockReturnValue(
|
||||||
new BehaviorSubject([
|
new BehaviorSubject([
|
||||||
{
|
{
|
||||||
useAccessIntelligence: false,
|
canUseAccessIntelligence: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
useAccessIntelligence: true,
|
canUseAccessIntelligence: true,
|
||||||
},
|
},
|
||||||
] as Organization[]),
|
] as Organization[]),
|
||||||
);
|
);
|
||||||
@@ -70,10 +70,10 @@ describe("Default task service", () => {
|
|||||||
mockGetAllOrgs$.mockReturnValue(
|
mockGetAllOrgs$.mockReturnValue(
|
||||||
new BehaviorSubject([
|
new BehaviorSubject([
|
||||||
{
|
{
|
||||||
useAccessIntelligence: false,
|
canUseAccessIntelligence: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
useAccessIntelligence: false,
|
canUseAccessIntelligence: false,
|
||||||
},
|
},
|
||||||
] as Organization[]),
|
] as Organization[]),
|
||||||
);
|
);
|
||||||
@@ -91,17 +91,17 @@ describe("Default task service", () => {
|
|||||||
mockGetAllOrgs$.mockReturnValue(
|
mockGetAllOrgs$.mockReturnValue(
|
||||||
new BehaviorSubject([
|
new BehaviorSubject([
|
||||||
{
|
{
|
||||||
useAccessIntelligence: true,
|
canUseAccessIntelligence: true,
|
||||||
},
|
},
|
||||||
] as Organization[]),
|
] as Organization[]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return an empty array if tasks are not enabled", async () => {
|
it("should return no tasks if not present and canUserAccessIntelligence is false", async () => {
|
||||||
mockGetAllOrgs$.mockReturnValue(
|
mockGetAllOrgs$.mockReturnValue(
|
||||||
new BehaviorSubject([
|
new BehaviorSubject([
|
||||||
{
|
{
|
||||||
useAccessIntelligence: false,
|
canUseAccessIntelligence: false,
|
||||||
},
|
},
|
||||||
] as Organization[]),
|
] as Organization[]),
|
||||||
);
|
);
|
||||||
@@ -111,7 +111,6 @@ describe("Default task service", () => {
|
|||||||
const result = await firstValueFrom(tasks$("user-id" as UserId));
|
const result = await firstValueFrom(tasks$("user-id" as UserId));
|
||||||
|
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
expect(mockApiSend).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fetch tasks from the API when the state is null", async () => {
|
it("should fetch tasks from the API when the state is null", async () => {
|
||||||
@@ -163,17 +162,17 @@ describe("Default task service", () => {
|
|||||||
mockGetAllOrgs$.mockReturnValue(
|
mockGetAllOrgs$.mockReturnValue(
|
||||||
new BehaviorSubject([
|
new BehaviorSubject([
|
||||||
{
|
{
|
||||||
useAccessIntelligence: true,
|
canUseAccessIntelligence: true,
|
||||||
},
|
},
|
||||||
] as Organization[]),
|
] as Organization[]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return an empty array if tasks are not enabled", async () => {
|
it("should return no tasks if not present and canUserAccessIntelligence is false", async () => {
|
||||||
mockGetAllOrgs$.mockReturnValue(
|
mockGetAllOrgs$.mockReturnValue(
|
||||||
new BehaviorSubject([
|
new BehaviorSubject([
|
||||||
{
|
{
|
||||||
useAccessIntelligence: false,
|
canUseAccessIntelligence: false,
|
||||||
},
|
},
|
||||||
] as Organization[]),
|
] as Organization[]),
|
||||||
);
|
);
|
||||||
@@ -183,7 +182,6 @@ describe("Default task service", () => {
|
|||||||
const result = await firstValueFrom(pendingTasks$("user-id" as UserId));
|
const result = await firstValueFrom(pendingTasks$("user-id" as UserId));
|
||||||
|
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
expect(mockApiSend).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should filter tasks to only pending tasks", async () => {
|
it("should filter tasks to only pending tasks", async () => {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export class DefaultTaskService implements TaskService {
|
|||||||
|
|
||||||
tasksEnabled$ = perUserCache$((userId) => {
|
tasksEnabled$ = perUserCache$((userId) => {
|
||||||
return this.organizationService.organizations$(userId).pipe(
|
return this.organizationService.organizations$(userId).pipe(
|
||||||
map((orgs) => orgs.some((o) => o.useAccessIntelligence)),
|
map((orgs) => orgs.some((o) => o.canUseAccessIntelligence)),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user