1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-25869] add a new tab called Activity in risk insights (#16454)

This commit is contained in:
Vijay Oommen
2025-09-18 08:00:17 -05:00
committed by GitHub
parent fb2fe703a2
commit 8d4d38d334
5 changed files with 88 additions and 3 deletions

View File

@@ -0,0 +1,17 @@
<div *ngIf="isLoading$ | async">
<tools-risk-insights-loading></tools-risk-insights-loading>
</div>
<div class="tw-mt-4" *ngIf="!(isLoading$ | async) && !atRiskAppDetails?.length">
<bit-no-items class="tw-text-main">
<ng-container slot="title">
<h2 class="tw-font-semibold tw-mt-4">
{{ organization.name }}
</h2>
</ng-container>
<ng-container slot="description">
<div class="tw-flex tw-flex-col tw-mb-2">
<a class="tw-text-primary-600" routerLink="/login">{{ "learnMore" | i18n }}</a>
</div>
</ng-container>
</bit-no-items>
</div>

View File

@@ -0,0 +1,46 @@
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { firstValueFrom, Observable } from "rxjs";
import { RiskInsightsDataService } from "@bitwarden/bit-common/dirt/reports/risk-insights";
import { AtRiskApplicationDetail } from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { getById } from "@bitwarden/common/platform/misc";
import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { ApplicationsLoadingComponent } from "./risk-insights-loading.component";
@Component({
selector: "tools-all-activity",
imports: [ApplicationsLoadingComponent, SharedModule],
templateUrl: "./all-activity.component.html",
})
export class AllActivityComponent implements OnInit {
isLoading$: Observable<boolean> = this.dataService.isLoading$;
atRiskAppDetails: AtRiskApplicationDetail[] = [];
organization: Organization | null = null;
async ngOnInit(): Promise<void> {
const organizationId = this.activatedRoute.snapshot.paramMap.get("organizationId");
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
if (organizationId) {
this.organization =
(await firstValueFrom(
this.organizationService.organizations$(userId).pipe(getById(organizationId)),
)) ?? null;
this.atRiskAppDetails = this.dataService.atRiskAppDetails ?? [];
}
}
constructor(
protected activatedRoute: ActivatedRoute,
private accountService: AccountService,
protected organizationService: OrganizationService,
protected dataService: RiskInsightsDataService,
) {}
}

View File

@@ -34,6 +34,11 @@
</span>
</div>
<bit-tab-group [(selectedIndex)]="tabIndex" (selectedIndexChange)="onTabChange($event)">
@if (isRiskInsightsActivityTabFeatureEnabled) {
<bit-tab label="{{ 'activity' | i18n }}">
<tools-all-activity></tools-all-activity>
</bit-tab>
}
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: appsCount }}">
<tools-all-applications></tools-all-applications>
</bit-tab>

View File

@@ -17,6 +17,7 @@ import {
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { OrganizationId } from "@bitwarden/common/types/guid";
import {
@@ -29,15 +30,17 @@ import {
} from "@bitwarden/components";
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
import { AllActivityComponent } from "./all-activity.component";
import { AllApplicationsComponent } from "./all-applications.component";
import { CriticalApplicationsComponent } from "./critical-applications.component";
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum RiskInsightsTabType {
AllApps = 0,
CriticalApps = 1,
NotifiedMembers = 2,
AllActivity = 0,
AllApps = 1,
CriticalApps = 2,
NotifiedMembers = 3,
}
@Component({
@@ -54,10 +57,12 @@ export enum RiskInsightsTabType {
DrawerComponent,
DrawerBodyComponent,
DrawerHeaderComponent,
AllActivityComponent,
],
})
export class RiskInsightsComponent implements OnInit {
tabIndex: RiskInsightsTabType = RiskInsightsTabType.AllApps;
isRiskInsightsActivityTabFeatureEnabled: boolean = false;
dataLastUpdated: Date = new Date();
@@ -69,6 +74,7 @@ export class RiskInsightsComponent implements OnInit {
private organizationId: OrganizationId = "" as OrganizationId;
private destroyRef = inject(DestroyRef);
isLoading$: Observable<boolean> = new Observable<boolean>();
isRefreshing$: Observable<boolean> = new Observable<boolean>();
dataLastUpdated$: Observable<Date | null> = new Observable<Date | null>();
@@ -85,6 +91,14 @@ export class RiskInsightsComponent implements OnInit {
this.route.queryParams.pipe(takeUntilDestroyed()).subscribe(({ tabIndex }) => {
this.tabIndex = !isNaN(Number(tabIndex)) ? Number(tabIndex) : RiskInsightsTabType.AllApps;
});
this.configService
.getFeatureFlag$(FeatureFlag.PM22887_RiskInsightsActivityTab)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((isEnabled) => {
this.isRiskInsightsActivityTabFeatureEnabled = isEnabled;
this.tabIndex = 0; // default to first tab
});
}
async ngOnInit() {