fix lint errors

This commit is contained in:
Graham Walker
2025-12-05 15:39:33 -06:00
parent 6dc39f3acf
commit 2a3e13b9b3
8 changed files with 57 additions and 33 deletions

View File

@@ -2,12 +2,15 @@
<app-side-nav variant="secondary" *ngIf="organization$ | async as organization">
<bit-nav-logo [openIcon]="logo" route="." [label]="'adminConsole' | i18n"></bit-nav-logo>
<org-switcher [filter]="orgFilter" [hideNewButton]="hideNewOrgButton$ | async"></org-switcher>
<bit-nav-item
icon="bwi-dashboard"
*ngIf="organization.useAccessIntelligence && organization.canAccessReports"
[text]="'accessIntelligence' | i18n"
route="access-intelligence"
></bit-nav-item>
@if (canShowAccessIntelligenceTab(organization)) {
<bit-nav-item
icon="bwi-dashboard"
[text]="'accessIntelligence' | i18n"
route="access-intelligence"
></bit-nav-item>
}
<bit-nav-item
icon="bwi-collection-shared"
[text]="'collections' | i18n"

View File

@@ -1,13 +1,14 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { Component, inject, OnInit } from "@angular/core";
import { ActivatedRoute, RouterModule } from "@angular/router";
import { combineLatest, filter, map, Observable, switchMap, withLatestFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AdminConsoleLogo } from "@bitwarden/assets/svg";
import {
canAccessAccessIntelligence,
canAccessBillingTab,
canAccessGroupsTab,
canAccessMembersTab,
@@ -72,16 +73,14 @@ export class OrganizationLayoutComponent implements OnInit {
protected subscriber$: Observable<NonIndividualSubscriber>;
protected getTaxIdWarning$: () => Observable<TaxIdWarningType | null>;
constructor(
private route: ActivatedRoute,
private organizationService: OrganizationService,
private platformUtilsService: PlatformUtilsService,
private policyService: PolicyService,
private providerService: ProviderService,
private accountService: AccountService,
private freeFamiliesPolicyService: FreeFamiliesPolicyService,
private organizationWarningsService: OrganizationWarningsService,
) {}
private route = inject(ActivatedRoute);
private organizationService = inject(OrganizationService);
private platformUtilsService = inject(PlatformUtilsService);
private policyService = inject(PolicyService);
private providerService = inject(ProviderService);
private accountService = inject(AccountService);
private freeFamiliesPolicyService = inject(FreeFamiliesPolicyService);
private organizationWarningsService = inject(OrganizationWarningsService);
async ngOnInit() {
document.body.classList.remove("layout_frontend");
@@ -172,6 +171,10 @@ export class OrganizationLayoutComponent implements OnInit {
return canAccessBillingTab(organization);
}
canShowAccessIntelligenceTab(organization: Organization): boolean {
return canAccessAccessIntelligence(organization);
}
getReportTabLabel(organization: Organization): string {
return organization.useEvents ? "reporting" : "reports";
}

View File

@@ -2,7 +2,10 @@ import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
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 { 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";
@@ -79,7 +82,7 @@ const routes: Routes = [
},
{
path: "access-intelligence",
canActivate: [organizationPermissionsGuard((org) => org.canAccessReports)],
canActivate: [organizationPermissionsGuard(canAccessAccessIntelligence)],
loadChildren: () =>
import("../../dirt/access-intelligence/access-intelligence.module").then(
(m) => m.AccessIntelligenceModule,

View File

@@ -1,6 +1,7 @@
import { NgModule } from "@angular/core";
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 { RiskInsightsComponent } from "./risk-insights.component";
@@ -8,7 +9,7 @@ import { RiskInsightsComponent } from "./risk-insights.component";
const routes: Routes = [
{
path: "",
canActivate: [organizationPermissionsGuard((org) => org.canAccessReports)],
canActivate: [organizationPermissionsGuard(canAccessAccessIntelligence)],
component: RiskInsightsComponent,
data: {
titleId: "accessIntelligence",

View File

@@ -41,6 +41,18 @@ export function canAccessBillingTab(org: Organization): boolean {
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 {
// Admin console can only be accessed by Owners for disabled organizations
if (!org.enabled && !org.isOwner) {

View File

@@ -400,4 +400,8 @@ export class Organization {
this.permissions.accessEventLogs)
);
}
get canUseAccessIntelligence() {
return this.productTierType === ProductTierType.Enterprise;
}
}

View File

@@ -51,10 +51,10 @@ describe("Default task service", () => {
mockGetAllOrgs$.mockReturnValue(
new BehaviorSubject([
{
useAccessIntelligence: false,
canUseAccessIntelligence: false,
},
{
useAccessIntelligence: true,
canUseAccessIntelligence: true,
},
] as Organization[]),
);
@@ -70,10 +70,10 @@ describe("Default task service", () => {
mockGetAllOrgs$.mockReturnValue(
new BehaviorSubject([
{
useAccessIntelligence: false,
canUseAccessIntelligence: false,
},
{
useAccessIntelligence: false,
canUseAccessIntelligence: false,
},
] as Organization[]),
);
@@ -91,17 +91,17 @@ describe("Default task service", () => {
mockGetAllOrgs$.mockReturnValue(
new BehaviorSubject([
{
useAccessIntelligence: true,
canUseAccessIntelligence: true,
},
] 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(
new BehaviorSubject([
{
useAccessIntelligence: false,
canUseAccessIntelligence: false,
},
] as Organization[]),
);
@@ -111,7 +111,6 @@ describe("Default task service", () => {
const result = await firstValueFrom(tasks$("user-id" as UserId));
expect(result.length).toBe(0);
expect(mockApiSend).not.toHaveBeenCalled();
});
it("should fetch tasks from the API when the state is null", async () => {
@@ -163,17 +162,17 @@ describe("Default task service", () => {
mockGetAllOrgs$.mockReturnValue(
new BehaviorSubject([
{
useAccessIntelligence: true,
canUseAccessIntelligence: true,
},
] 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(
new BehaviorSubject([
{
useAccessIntelligence: false,
canUseAccessIntelligence: false,
},
] as Organization[]),
);
@@ -183,7 +182,6 @@ describe("Default task service", () => {
const result = await firstValueFrom(pendingTasks$("user-id" as UserId));
expect(result.length).toBe(0);
expect(mockApiSend).not.toHaveBeenCalled();
});
it("should filter tasks to only pending tasks", async () => {

View File

@@ -48,7 +48,7 @@ export class DefaultTaskService implements TaskService {
tasksEnabled$ = perUserCache$((userId) => {
return this.organizationService.organizations$(userId).pipe(
map((orgs) => orgs.some((o) => o.useAccessIntelligence)),
map((orgs) => orgs.some((o) => o.canUseAccessIntelligence)),
distinctUntilChanged(),
);
});