1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-21 02:33:46 +00:00
Files
browser/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts
Leslie Tilton 5166a9c730 [PM-19716][PM-19714] Move files to Data Insights & Reporting team (DIRT) ownership (#14571)
* Move access-intelligence and reports files from tools to dirt folder for new ownership. Update imports for these files

* Move bit-common/src/reports/risk-insights > dirt

* Update codeowners file for dirt team ownership

* Addressed linting issues by executing `npm run prettier`

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
2025-05-06 10:32:48 +02:00

162 lines
5.4 KiB
TypeScript

import { CommonModule } from "@angular/common";
import { Component, DestroyRef, OnInit, inject } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { ActivatedRoute, Router } from "@angular/router";
import { EMPTY, Observable } from "rxjs";
import { map, switchMap } from "rxjs/operators";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import {
CriticalAppsService,
RiskInsightsDataService,
} from "@bitwarden/bit-common/dirt/reports/risk-insights";
import {
ApplicationHealthReportDetail,
DrawerType,
PasswordHealthReportApplicationsResponse,
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags";
import { OrganizationId } from "@bitwarden/common/types/guid";
import {
AsyncActionsModule,
ButtonModule,
DrawerBodyComponent,
DrawerComponent,
DrawerHeaderComponent,
LayoutComponent,
TabsModule,
} from "@bitwarden/components";
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
import { AllApplicationsComponent } from "./all-applications.component";
import { CriticalApplicationsComponent } from "./critical-applications.component";
import { NotifiedMembersTableComponent } from "./notified-members-table.component";
import { PasswordHealthMembersURIComponent } from "./password-health-members-uri.component";
import { PasswordHealthMembersComponent } from "./password-health-members.component";
import { PasswordHealthComponent } from "./password-health.component";
export enum RiskInsightsTabType {
AllApps = 0,
CriticalApps = 1,
NotifiedMembers = 2,
}
@Component({
standalone: true,
templateUrl: "./risk-insights.component.html",
imports: [
AllApplicationsComponent,
AsyncActionsModule,
ButtonModule,
CommonModule,
CriticalApplicationsComponent,
JslibModule,
HeaderModule,
PasswordHealthComponent,
PasswordHealthMembersComponent,
PasswordHealthMembersURIComponent,
NotifiedMembersTableComponent,
TabsModule,
DrawerComponent,
DrawerBodyComponent,
DrawerHeaderComponent,
LayoutComponent,
],
})
export class RiskInsightsComponent implements OnInit {
tabIndex: RiskInsightsTabType = RiskInsightsTabType.AllApps;
dataLastUpdated: Date = new Date();
isCriticalAppsFeatureEnabled: boolean = false;
criticalApps$: Observable<PasswordHealthReportApplicationsResponse[]> = new Observable();
showDebugTabs: boolean = false;
appsCount: number = 0;
criticalAppsCount: number = 0;
notifiedMembersCount: number = 0;
private organizationId: string | null = null;
private destroyRef = inject(DestroyRef);
isLoading$: Observable<boolean> = new Observable<boolean>();
isRefreshing$: Observable<boolean> = new Observable<boolean>();
dataLastUpdated$: Observable<Date | null> = new Observable<Date | null>();
refetching: boolean = false;
constructor(
private route: ActivatedRoute,
private router: Router,
private configService: ConfigService,
protected dataService: RiskInsightsDataService,
private criticalAppsService: CriticalAppsService,
) {
this.route.queryParams.pipe(takeUntilDestroyed()).subscribe(({ tabIndex }) => {
this.tabIndex = !isNaN(Number(tabIndex)) ? Number(tabIndex) : RiskInsightsTabType.AllApps;
});
const orgId = this.route.snapshot.paramMap.get("organizationId") ?? "";
this.criticalApps$ = this.criticalAppsService.getAppsListForOrg(orgId);
}
async ngOnInit() {
this.isCriticalAppsFeatureEnabled = await this.configService.getFeatureFlag(
FeatureFlag.CriticalApps,
);
this.showDebugTabs = devFlagEnabled("showRiskInsightsDebug");
this.route.paramMap
.pipe(
takeUntilDestroyed(this.destroyRef),
map((params) => params.get("organizationId")),
switchMap((orgId: string | null) => {
if (orgId) {
this.organizationId = orgId;
this.dataService.fetchApplicationsReport(orgId);
this.isLoading$ = this.dataService.isLoading$;
this.isRefreshing$ = this.dataService.isRefreshing$;
this.dataLastUpdated$ = this.dataService.dataLastUpdated$;
return this.dataService.applications$;
} else {
return EMPTY;
}
}),
)
.subscribe({
next: (applications: ApplicationHealthReportDetail[] | null) => {
if (applications) {
this.appsCount = applications.length;
}
this.criticalAppsService.setOrganizationId(this.organizationId as OrganizationId);
},
});
}
/**
* Refreshes the data by re-fetching the applications report.
* This will automatically notify child components subscribed to the RiskInsightsDataService observables.
*/
refreshData(): void {
if (this.organizationId) {
this.dataService.refreshApplicationsReport(this.organizationId);
}
}
async onTabChange(newIndex: number): Promise<void> {
await this.router.navigate([], {
relativeTo: this.route,
queryParams: { tabIndex: newIndex },
queryParamsHandling: "merge",
});
// close drawer when tabs are changed
this.dataService.closeDrawer();
}
// Get a list of drawer types
get drawerTypes(): typeof DrawerType {
return DrawerType;
}
}