1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-29 22:31:29 +01:00

PM-17392 Slide out drawer (#13096)

This commit is contained in:
Vijay Oommen 2025-01-28 12:27:02 -06:00 committed by GitHub
parent 26a0594056
commit d0018548ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 228 additions and 237 deletions

View File

@ -117,6 +117,11 @@ export type AtRiskApplicationDetail = {
atRiskPasswordCount: number;
};
export type AppAtRiskMembersDialogParams = {
members: MemberDetailsFlat[];
applicationName: string;
};
/**
* Request to drop a password health report application
* Model is expected by the API endpoint
@ -143,4 +148,11 @@ export interface PasswordHealthReportApplicationsRequest {
url: string;
}
export enum DrawerType {
None = 0,
AppAtRiskMembers = 1,
OrgAtRiskMembers = 2,
OrgAtRiskApps = 3,
}
export type PasswordHealthReportApplicationId = Opaque<string, "PasswordHealthReportApplicationId">;

View File

@ -1,10 +1,15 @@
import { BehaviorSubject } from "rxjs";
import { finalize } from "rxjs/operators";
import { ApplicationHealthReportDetail } from "../models/password-health";
import {
AppAtRiskMembersDialogParams,
ApplicationHealthReportDetail,
AtRiskApplicationDetail,
AtRiskMemberDetail,
DrawerType,
} from "../models/password-health";
import { RiskInsightsReportService } from "./risk-insights-report.service";
export class RiskInsightsDataService {
private applicationsSubject = new BehaviorSubject<ApplicationHealthReportDetail[] | null>(null);
@ -22,6 +27,12 @@ export class RiskInsightsDataService {
private dataLastUpdatedSubject = new BehaviorSubject<Date | null>(null);
dataLastUpdated$ = this.dataLastUpdatedSubject.asObservable();
openDrawer = false;
activeDrawerType: DrawerType = DrawerType.None;
atRiskMemberDetails: AtRiskMemberDetail[] = [];
appAtRiskMembers: AppAtRiskMembersDialogParams | null = null;
atRiskAppDetails: AtRiskApplicationDetail[] | null = null;
constructor(private reportService: RiskInsightsReportService) {}
/**
@ -57,4 +68,46 @@ export class RiskInsightsDataService {
refreshApplicationsReport(organizationId: string): void {
this.fetchApplicationsReport(organizationId, true);
}
isActiveDrawerType = (drawerType: DrawerType): boolean => {
return this.activeDrawerType === drawerType;
};
setDrawerForOrgAtRiskMembers = (atRiskMemberDetails: AtRiskMemberDetail[]): void => {
this.resetDrawer(DrawerType.OrgAtRiskMembers);
this.activeDrawerType = DrawerType.OrgAtRiskMembers;
this.atRiskMemberDetails = atRiskMemberDetails;
this.openDrawer = !this.openDrawer;
};
setDrawerForAppAtRiskMembers = (
atRiskMembersDialogParams: AppAtRiskMembersDialogParams,
): void => {
this.resetDrawer(DrawerType.None);
this.activeDrawerType = DrawerType.AppAtRiskMembers;
this.appAtRiskMembers = atRiskMembersDialogParams;
this.openDrawer = !this.openDrawer;
};
setDrawerForOrgAtRiskApps = (atRiskApps: AtRiskApplicationDetail[]): void => {
this.resetDrawer(DrawerType.OrgAtRiskApps);
this.activeDrawerType = DrawerType.OrgAtRiskApps;
this.atRiskAppDetails = atRiskApps;
this.openDrawer = !this.openDrawer;
};
closeDrawer = (): void => {
this.resetDrawer(DrawerType.None);
};
private resetDrawer = (drawerType: DrawerType): void => {
if (this.activeDrawerType !== drawerType) {
this.openDrawer = false;
}
this.activeDrawerType = DrawerType.None;
this.atRiskMemberDetails = [];
this.appAtRiskMembers = null;
this.atRiskAppDetails = null;
};
}

View File

@ -26,7 +26,6 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import {
DialogService,
Icons,
NoItemsModule,
SearchModule,
@ -38,9 +37,6 @@ import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.mod
import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
import { openAppAtRiskMembersDialog } from "./app-at-risk-members-dialog.component";
import { OrgAtRiskAppsDialogComponent } from "./org-at-risk-apps-dialog.component";
import { OrgAtRiskMembersDialogComponent } from "./org-at-risk-members-dialog.component";
import { ApplicationsLoadingComponent } from "./risk-insights-loading.component";
@Component({
@ -131,7 +127,6 @@ export class AllApplicationsComponent implements OnInit {
protected reportService: RiskInsightsReportService,
private accountService: AccountService,
protected criticalAppsService: CriticalAppsService,
protected dialogService: DialogService,
) {
this.searchControl.valueChanges
.pipe(debounceTime(200), takeUntilDestroyed())
@ -176,24 +171,23 @@ export class AllApplicationsComponent implements OnInit {
}
showAppAtRiskMembers = async (applicationName: string) => {
openAppAtRiskMembersDialog(this.dialogService, {
const info = {
members:
this.dataSource.data.find((app) => app.applicationName === applicationName)
?.atRiskMemberDetails ?? [],
applicationName,
});
};
this.dataService.setDrawerForAppAtRiskMembers(info);
};
showOrgAtRiskMembers = async () => {
this.dialogService.open(OrgAtRiskMembersDialogComponent, {
data: this.reportService.generateAtRiskMemberList(this.dataSource.data),
});
const dialogData = this.reportService.generateAtRiskMemberList(this.dataSource.data);
this.dataService.setDrawerForOrgAtRiskMembers(dialogData);
};
showOrgAtRiskApps = async () => {
this.dialogService.open(OrgAtRiskAppsDialogComponent, {
data: this.reportService.generateAtRiskApplicationList(this.dataSource.data),
});
const data = this.reportService.generateAtRiskApplicationList(this.dataSource.data);
this.dataService.setDrawerForOrgAtRiskApps(data);
};
onCheckboxChange(applicationName: string, event: Event) {

View File

@ -1,19 +0,0 @@
<bit-dialog>
<span bitDialogTitle>{{ applicationName }}</span>
<ng-container bitDialogContent>
<div class="tw-flex tw-flex-col tw-gap-2">
<span bitDialogTitle>{{ "atRiskMembersWithCount" | i18n: members.length }} </span>
<span>{{ "atRiskMembersDescriptionWithApp" | i18n: applicationName }}</span>
<div class="tw-mt-1">
<ng-container *ngFor="let member of members">
<div>{{ member.email }}</div>
</ng-container>
</div>
</div>
</ng-container>
<ng-container bitDialogFooter>
<button bitButton bitDialogClose buttonType="secondary" type="button">
{{ "close" | i18n }}
</button>
</ng-container>
</bit-dialog>

View File

@ -1,35 +0,0 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { CommonModule } from "@angular/common";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { MemberDetailsFlat } from "@bitwarden/bit-common/tools/reports/risk-insights/models/password-health";
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
type AppAtRiskMembersDialogParams = {
members: MemberDetailsFlat[];
applicationName: string;
};
export const openAppAtRiskMembersDialog = (
dialogService: DialogService,
dialogConfig: AppAtRiskMembersDialogParams,
) =>
dialogService.open<boolean, AppAtRiskMembersDialogParams>(AppAtRiskMembersDialogComponent, {
data: dialogConfig,
});
@Component({
standalone: true,
templateUrl: "./app-at-risk-members-dialog.component.html",
imports: [ButtonModule, CommonModule, JslibModule, DialogModule],
})
export class AppAtRiskMembersDialogComponent {
protected members: MemberDetailsFlat[];
protected applicationName: string;
constructor(@Inject(DIALOG_DATA) private params: AppAtRiskMembersDialogParams) {
this.members = params.members;
this.applicationName = params.applicationName;
}
}

View File

@ -43,7 +43,7 @@
>
</tools-card>
<tools-card
class="tw-flex-1"
class="tw-flex-1 tw-cursor-pointer"
[title]="'atRiskApplications' | i18n"
[value]="applicationSummary.totalAtRiskApplicationCount"
[maxValue]="applicationSummary.totalApplicationCount"

View File

@ -18,7 +18,6 @@ import {
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { OrganizationId } from "@bitwarden/common/types/guid";
import {
DialogService,
Icons,
NoItemsModule,
SearchModule,
@ -30,9 +29,6 @@ import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.mod
import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
import { openAppAtRiskMembersDialog } from "./app-at-risk-members-dialog.component";
import { OrgAtRiskAppsDialogComponent } from "./org-at-risk-apps-dialog.component";
import { OrgAtRiskMembersDialogComponent } from "./org-at-risk-members-dialog.component";
import { RiskInsightsTabType } from "./risk-insights.component";
@Component({
@ -114,7 +110,6 @@ export class CriticalApplicationsComponent implements OnInit {
protected dataService: RiskInsightsDataService,
protected criticalAppsService: CriticalAppsService,
protected reportService: RiskInsightsReportService,
protected dialogService: DialogService,
protected i18nService: I18nService,
) {
this.searchControl.valueChanges
@ -123,24 +118,23 @@ export class CriticalApplicationsComponent implements OnInit {
}
showAppAtRiskMembers = async (applicationName: string) => {
openAppAtRiskMembersDialog(this.dialogService, {
const data = {
members:
this.dataSource.data.find((app) => app.applicationName === applicationName)
?.atRiskMemberDetails ?? [],
applicationName,
});
};
this.dataService.setDrawerForAppAtRiskMembers(data);
};
showOrgAtRiskMembers = async () => {
this.dialogService.open(OrgAtRiskMembersDialogComponent, {
data: this.reportService.generateAtRiskMemberList(this.dataSource.data),
});
const data = this.reportService.generateAtRiskMemberList(this.dataSource.data);
this.dataService.setDrawerForOrgAtRiskMembers(data);
};
showOrgAtRiskApps = async () => {
this.dialogService.open(OrgAtRiskAppsDialogComponent, {
data: this.reportService.generateAtRiskApplicationList(this.dataSource.data),
});
const data = this.reportService.generateAtRiskApplicationList(this.dataSource.data);
this.dataService.setDrawerForOrgAtRiskApps(data);
};
trackByFunction(_: number, item: ApplicationHealthReportDetailWithCriticalFlag) {

View File

@ -1,25 +0,0 @@
<bit-dialog>
<ng-container bitDialogTitle>
<span bitDialogTitle>{{ "atRiskApplicationsWithCount" | i18n: atRiskApps.length }} </span>
</ng-container>
<ng-container bitDialogContent>
<div class="tw-flex tw-flex-col tw-gap-2">
<span bitTypography="body1">{{ "atRiskApplicationsDescription" | i18n }}</span>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div bitTypography="body2" class="tw-font-bold">{{ "application" | i18n }}</div>
<div bitTypography="body2" class="tw-font-bold">{{ "atRiskPasswords" | i18n }}</div>
</div>
<ng-container *ngFor="let app of atRiskApps">
<div class="tw-flex tw-justify-between tw-mt-2">
<div>{{ app.applicationName }}</div>
<div>{{ app.atRiskPasswordCount }}</div>
</div>
</ng-container>
</div>
</ng-container>
<ng-container bitDialogFooter>
<button bitButton bitDialogClose buttonType="secondary" type="button">
{{ "close" | i18n }}
</button>
</ng-container>
</bit-dialog>

View File

@ -1,24 +0,0 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { CommonModule } from "@angular/common";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AtRiskApplicationDetail } from "@bitwarden/bit-common/tools/reports/risk-insights/models/password-health";
import { ButtonModule, DialogModule, DialogService, TypographyModule } from "@bitwarden/components";
export const openOrgAtRiskMembersDialog = (
dialogService: DialogService,
dialogConfig: AtRiskApplicationDetail[],
) =>
dialogService.open<boolean, AtRiskApplicationDetail[]>(OrgAtRiskAppsDialogComponent, {
data: dialogConfig,
});
@Component({
standalone: true,
templateUrl: "./org-at-risk-apps-dialog.component.html",
imports: [ButtonModule, CommonModule, DialogModule, JslibModule, TypographyModule],
})
export class OrgAtRiskAppsDialogComponent {
constructor(@Inject(DIALOG_DATA) protected atRiskApps: AtRiskApplicationDetail[]) {}
}

View File

@ -1,25 +0,0 @@
<bit-dialog>
<ng-container bitDialogTitle>
<span bitDialogTitle>{{ "atRiskMembersWithCount" | i18n: atRiskMembers.length }} </span>
</ng-container>
<ng-container bitDialogContent>
<div class="tw-flex tw-flex-col tw-gap-2">
<span bitTypography="body1">{{ "atRiskMembersDescription" | i18n }}</span>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div bitTypography="body2" class="tw-font-bold">{{ "email" | i18n }}</div>
<div bitTypography="body2" class="tw-font-bold">{{ "atRiskPasswords" | i18n }}</div>
</div>
<ng-container *ngFor="let member of atRiskMembers">
<div class="tw-flex tw-justify-between tw-mt-2">
<div>{{ member.email }}</div>
<div>{{ member.atRiskPasswordCount }}</div>
</div>
</ng-container>
</div>
</ng-container>
<ng-container bitDialogFooter>
<button bitButton bitDialogClose buttonType="secondary" type="button">
{{ "close" | i18n }}
</button>
</ng-container>
</bit-dialog>

View File

@ -1,24 +0,0 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { CommonModule } from "@angular/common";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AtRiskMemberDetail } from "@bitwarden/bit-common/tools/reports/risk-insights/models/password-health";
import { ButtonModule, DialogModule, DialogService, TypographyModule } from "@bitwarden/components";
export const openOrgAtRiskMembersDialog = (
dialogService: DialogService,
dialogConfig: AtRiskMemberDetail[],
) =>
dialogService.open<boolean, AtRiskMemberDetail[]>(OrgAtRiskMembersDialogComponent, {
data: dialogConfig,
});
@Component({
standalone: true,
templateUrl: "./org-at-risk-members-dialog.component.html",
imports: [ButtonModule, CommonModule, DialogModule, JslibModule, TypographyModule],
})
export class OrgAtRiskMembersDialogComponent {
constructor(@Inject(DIALOG_DATA) protected atRiskMembers: AtRiskMemberDetail[]) {}
}

View File

@ -1,57 +1,126 @@
<ng-container>
<div class="tw-mb-1 text-primary" bitTypography="body1">{{ "accessIntelligence" | i18n }}</div>
<h1 bitTypography="h1">{{ "riskInsights" | i18n }}</h1>
<div class="tw-text-muted tw-max-w-4xl tw-mb-2">
{{ "reviewAtRiskPasswords" | i18n }}
</div>
<div
class="tw-bg-primary-100 tw-rounded-lg tw-w-full tw-px-8 tw-py-4 tw-my-4 tw-flex tw-items-center"
>
<i
class="bwi bwi-exclamation-triangle bwi-lg tw-text-[1.2rem] text-muted"
aria-hidden="true"
></i>
<span class="tw-mx-4">{{
"dataLastUpdated" | i18n: (dataLastUpdated$ | async | date: "MMMM d, y 'at' h:mm a")
}}</span>
<span class="tw-flex tw-justify-center tw-w-16">
<a
*ngIf="!(isRefreshing$ | async)"
bitButton
buttonType="unstyled"
class="tw-border-none !tw-font-normal tw-cursor-pointer !tw-py-0"
[bitAction]="refreshData.bind(this)"
>
{{ "refresh" | i18n }}
</a>
<span>
<i
*ngIf="isRefreshing$ | async"
class="bwi bwi-spinner bwi-spin tw-text-muted tw-text-[1.2rem]"
aria-hidden="true"
></i>
<bit-layout>
<div class="tw-mb-1 text-primary" bitTypography="body1">{{ "accessIntelligence" | i18n }}</div>
<h1 bitTypography="h1">{{ "riskInsights" | i18n }}</h1>
<div class="tw-text-muted tw-max-w-4xl tw-mb-2">
{{ "reviewAtRiskPasswords" | i18n }}
</div>
<div
class="tw-bg-primary-100 tw-rounded-lg tw-w-full tw-px-8 tw-py-4 tw-my-4 tw-flex tw-items-center"
>
<i
class="bwi bwi-exclamation-triangle bwi-lg tw-text-[1.2rem] text-muted"
aria-hidden="true"
></i>
<span class="tw-mx-4">{{
"dataLastUpdated" | i18n: (dataLastUpdated$ | async | date: "MMMM d, y 'at' h:mm a")
}}</span>
<span class="tw-flex tw-justify-center tw-w-16">
<a
*ngIf="!(isRefreshing$ | async)"
bitButton
buttonType="unstyled"
class="tw-border-none !tw-font-normal tw-cursor-pointer !tw-py-0"
[bitAction]="refreshData.bind(this)"
>
{{ "refresh" | i18n }}
</a>
<span>
<i
*ngIf="isRefreshing$ | async"
class="bwi bwi-spinner bwi-spin tw-text-muted tw-text-[1.2rem]"
aria-hidden="true"
></i>
</span>
</span>
</span>
</div>
<bit-tab-group [(selectedIndex)]="tabIndex" (selectedIndexChange)="onTabChange($event)">
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: appsCount }}">
<tools-all-applications></tools-all-applications>
</bit-tab>
<bit-tab *ngIf="isCriticalAppsFeatureEnabled">
<ng-template bitTabLabel>
<i class="bwi bwi-star"></i>
{{ "criticalApplicationsWithCount" | i18n: (criticalApps$ | async)?.length ?? 0 }}
</ng-template>
<tools-critical-applications></tools-critical-applications>
</bit-tab>
<bit-tab *ngIf="showDebugTabs" label="Raw Data">
<tools-password-health></tools-password-health>
</bit-tab>
<bit-tab *ngIf="showDebugTabs" label="Raw Data + members">
<tools-password-health-members></tools-password-health-members>
</bit-tab>
<bit-tab *ngIf="showDebugTabs" label="Raw Data + uri">
<tools-password-health-members-uri></tools-password-health-members-uri>
</bit-tab>
</bit-tab-group>
</div>
<bit-tab-group [(selectedIndex)]="tabIndex" (selectedIndexChange)="onTabChange($event)">
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: appsCount }}">
<tools-all-applications></tools-all-applications>
</bit-tab>
<bit-tab *ngIf="isCriticalAppsFeatureEnabled">
<ng-template bitTabLabel>
<i class="bwi bwi-star"></i>
{{ "criticalApplicationsWithCount" | i18n: (criticalApps$ | async)?.length ?? 0 }}
</ng-template>
<tools-critical-applications></tools-critical-applications>
</bit-tab>
<bit-tab *ngIf="showDebugTabs" label="Raw Data">
<tools-password-health></tools-password-health>
</bit-tab>
<bit-tab *ngIf="showDebugTabs" label="Raw Data + members">
<tools-password-health-members></tools-password-health-members>
</bit-tab>
<bit-tab *ngIf="showDebugTabs" label="Raw Data + uri">
<tools-password-health-members-uri></tools-password-health-members-uri>
</bit-tab>
</bit-tab-group>
<bit-drawer style="width: 30%" [(open)]="dataService.openDrawer">
<ng-container *ngIf="dataService.isActiveDrawerType(drawerTypes.OrgAtRiskMembers)">
<bit-drawer-header
title="{{ 'atRiskMembersWithCount' | i18n: dataService.atRiskMemberDetails.length }}"
>
</bit-drawer-header>
<bit-drawer-body>
<span bitTypography="body1" class="tw-text-muted tw-text-sm">{{
"atRiskMembersDescription" | i18n
}}</span>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div bitTypography="body2" class="tw-font-bold">{{ "email" | i18n }}</div>
<div bitTypography="body2" class="tw-font-bold">{{ "atRiskPasswords" | i18n }}</div>
</div>
<ng-container *ngFor="let member of dataService.atRiskMemberDetails">
<div class="tw-flex tw-justify-between tw-mt-2">
<div>{{ member.email }}</div>
<div>{{ member.atRiskPasswordCount }}</div>
</div>
</ng-container>
</bit-drawer-body>
</ng-container>
<ng-container *ngIf="dataService.isActiveDrawerType(drawerTypes.AppAtRiskMembers)">
<bit-drawer-header title="{{ dataService.appAtRiskMembers.applicationName }}">
</bit-drawer-header>
<bit-drawer-body>
<div bitTypography="body1" class="tw-mb-2">
{{ "atRiskMembersWithCount" | i18n: dataService.appAtRiskMembers.members.length }}
</div>
<div bitTypography="body1" class="tw-text-muted tw-text-sm tw-mb-2">
{{
"atRiskMembersDescriptionWithApp" | i18n: dataService.appAtRiskMembers.applicationName
}}
</div>
<div class="tw-mt-1">
<ng-container *ngFor="let member of dataService.appAtRiskMembers.members">
<div>{{ member.email }}</div>
</ng-container>
</div>
</bit-drawer-body>
</ng-container>
<ng-container *ngIf="dataService.isActiveDrawerType(drawerTypes.OrgAtRiskApps)">
<bit-drawer-header
title="{{ 'atRiskApplicationsWithCount' | i18n: dataService.atRiskAppDetails.length }}"
>
</bit-drawer-header>
<bit-drawer-body>
<span bitTypography="body2" class="tw-text-muted tw-text-sm">{{
"atRiskApplicationsDescription" | i18n
}}</span>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div bitTypography="body2" class="tw-font-bold">{{ "application" | i18n }}</div>
<div bitTypography="body2" class="tw-font-bold">{{ "atRiskPasswords" | i18n }}</div>
</div>
<ng-container *ngFor="let app of dataService.atRiskAppDetails">
<div class="tw-flex tw-justify-between tw-mt-2">
<div>{{ app.applicationName }}</div>
<div>{{ app.atRiskPasswordCount }}</div>
</div>
</ng-container>
</bit-drawer-body>
</ng-container>
</bit-drawer>
</bit-layout>
</ng-container>

View File

@ -12,6 +12,7 @@ import {
} from "@bitwarden/bit-common/tools/reports/risk-insights";
import {
ApplicationHealthReportDetail,
DrawerType,
PasswordHealthReportApplicationsResponse,
} from "@bitwarden/bit-common/tools/reports/risk-insights/models/password-health";
// eslint-disable-next-line no-restricted-imports -- used for dependency injection
@ -19,7 +20,15 @@ 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, TabsModule } from "@bitwarden/components";
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";
@ -51,6 +60,10 @@ export enum RiskInsightsTabType {
PasswordHealthMembersURIComponent,
NotifiedMembersTableComponent,
TabsModule,
DrawerComponent,
DrawerBodyComponent,
DrawerHeaderComponent,
LayoutComponent,
],
})
export class RiskInsightsComponent implements OnInit {
@ -77,7 +90,7 @@ export class RiskInsightsComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private configService: ConfigService,
private dataService: RiskInsightsDataService,
protected dataService: RiskInsightsDataService,
private criticalAppsService: CriticalAppsService,
) {
this.route.queryParams.pipe(takeUntilDestroyed()).subscribe(({ tabIndex }) => {
@ -137,5 +150,13 @@ export class RiskInsightsComponent implements OnInit {
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;
}
}