mirror of
https://github.com/bitwarden/browser
synced 2026-02-23 16:13:21 +00:00
PM-27739 per PR comments map ciphers to report data in the components
This commit is contained in:
@@ -92,8 +92,8 @@ export const mockApplicationData: OrganizationReportApplication[] = [
|
||||
];
|
||||
|
||||
export const mockEnrichedReportData: ApplicationHealthReportDetailEnriched[] = [
|
||||
{ ...mockApplication1, isMarkedAsCritical: true, ciphers: [] },
|
||||
{ ...mockApplication2, isMarkedAsCritical: false, ciphers: [] },
|
||||
{ ...mockApplication1, isMarkedAsCritical: true },
|
||||
{ ...mockApplication2, isMarkedAsCritical: false },
|
||||
];
|
||||
|
||||
export const mockCipherViews: CipherView[] = [
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
import {
|
||||
ApplicationHealthReportDetail,
|
||||
OrganizationReportApplication,
|
||||
@@ -8,7 +6,6 @@ import {
|
||||
|
||||
export type ApplicationHealthReportDetailEnriched = ApplicationHealthReportDetail & {
|
||||
isMarkedAsCritical: boolean;
|
||||
ciphers: CipherView[];
|
||||
};
|
||||
export interface RiskInsightsEnrichedData {
|
||||
reportData: ApplicationHealthReportDetailEnriched[];
|
||||
|
||||
@@ -84,6 +84,9 @@ export class RiskInsightsOrchestratorService {
|
||||
// ------------------------- Cipher data -------------------------
|
||||
private _ciphersSubject = new BehaviorSubject<CipherView[] | null>(null);
|
||||
private _ciphers$ = this._ciphersSubject.asObservable();
|
||||
get ciphers$(): Observable<CipherView[]> {
|
||||
return this._ciphers$;
|
||||
}
|
||||
|
||||
private _hasCiphersSubject$ = new BehaviorSubject<boolean | null>(null);
|
||||
hasCiphers$ = this._hasCiphersSubject$.asObservable();
|
||||
@@ -235,7 +238,6 @@ export class RiskInsightsOrchestratorService {
|
||||
application,
|
||||
updatedApplicationData,
|
||||
),
|
||||
ciphers: [], // explicitly ignore ciphers at this stage
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -368,7 +370,6 @@ export class RiskInsightsOrchestratorService {
|
||||
application,
|
||||
updatedApplicationData,
|
||||
),
|
||||
ciphers: [], // explicitly ignore ciphers at this stage
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -504,7 +505,6 @@ export class RiskInsightsOrchestratorService {
|
||||
application,
|
||||
updatedApplicationData,
|
||||
),
|
||||
ciphers: [], // explicitly ignore ciphers at this stage
|
||||
}),
|
||||
);
|
||||
// For now, merge the report with the critical marking flag to make the enriched type
|
||||
@@ -662,7 +662,6 @@ export class RiskInsightsOrchestratorService {
|
||||
application,
|
||||
updatedApplicationData,
|
||||
),
|
||||
ciphers: [], // explicitly ignore ciphers at this stage
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -956,8 +955,8 @@ export class RiskInsightsOrchestratorService {
|
||||
*/
|
||||
private _setupEnrichedReportData() {
|
||||
// Setup the enriched report data pipeline
|
||||
const enrichmentSubscription = combineLatest([this.rawReportData$, this._ciphers$]).pipe(
|
||||
switchMap(([rawReportData, ciphers]) => {
|
||||
const enrichmentSubscription = combineLatest([this.rawReportData$]).pipe(
|
||||
switchMap(([rawReportData]) => {
|
||||
this.logService.debug(
|
||||
"[RiskInsightsOrchestratorService] Enriching report data with ciphers and critical app status",
|
||||
);
|
||||
@@ -968,7 +967,6 @@ export class RiskInsightsOrchestratorService {
|
||||
const enrichedReports: ApplicationHealthReportDetailEnriched[] = rawReports.map((app) => ({
|
||||
...app,
|
||||
isMarkedAsCritical: this.reportService.isCriticalApplication(app, criticalAppsData),
|
||||
ciphers: ciphers?.filter((cipher) => app.cipherIds.includes(cipher.id)) ?? [],
|
||||
}));
|
||||
|
||||
const enrichedData = {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BehaviorSubject, firstValueFrom, Observable, of, Subject } from "rxjs";
|
||||
import { distinctUntilChanged, map } from "rxjs/operators";
|
||||
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
import { getAtRiskApplicationList, getAtRiskMemberList } from "../../helpers";
|
||||
import {
|
||||
@@ -38,6 +39,7 @@ export class RiskInsightsDataService {
|
||||
readonly isGeneratingReport$: Observable<boolean> = of(false);
|
||||
readonly criticalReportResults$: Observable<RiskInsightsEnrichedData | null> = of(null);
|
||||
readonly hasCiphers$: Observable<boolean | null> = of(null);
|
||||
readonly ciphers$: Observable<CipherView[]> = of([]);
|
||||
|
||||
// New applications that need review (reviewedDate === null)
|
||||
readonly newApplications$: Observable<ApplicationHealthReportDetail[]> = of([]);
|
||||
@@ -64,6 +66,7 @@ export class RiskInsightsDataService {
|
||||
this.newApplications$ = this.orchestrator.newApplications$;
|
||||
|
||||
this.hasCiphers$ = this.orchestrator.hasCiphers$.pipe(distinctUntilChanged());
|
||||
this.ciphers$ = this.orchestrator.ciphers$;
|
||||
|
||||
// Expose the loading state
|
||||
this.reportStatus$ = this.reportState$.pipe(
|
||||
|
||||
@@ -215,7 +215,6 @@ export class NewApplicationsDialogComponent {
|
||||
isMarkedAsCritical: updatedStateApplicationData.some(
|
||||
(a) => a.applicationName == application.applicationName && a.isCritical,
|
||||
),
|
||||
ciphers: [], // explicitly ignore ciphers at this stage
|
||||
}),
|
||||
) || [];
|
||||
return from(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, DestroyRef, inject, OnInit } from "@angular/core";
|
||||
import { Component, DestroyRef, inject, OnInit, ChangeDetectionStrategy } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormControl } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { debounceTime } from "rxjs";
|
||||
import { combineLatest, debounceTime, of, switchMap } from "rxjs";
|
||||
|
||||
import { Security } from "@bitwarden/assets/svg";
|
||||
import {
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/report-models";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import {
|
||||
IconButtonModule,
|
||||
NoItemsModule,
|
||||
@@ -31,9 +32,8 @@ import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pip
|
||||
import { AppTableRowScrollableComponent } from "../shared/app-table-row-scrollable.component";
|
||||
import { ApplicationsLoadingComponent } from "../shared/risk-insights-loading.component";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
selector: "dirt-all-applications",
|
||||
templateUrl: "./all-applications.component.html",
|
||||
imports: [
|
||||
@@ -49,7 +49,9 @@ import { ApplicationsLoadingComponent } from "../shared/risk-insights-loading.co
|
||||
],
|
||||
})
|
||||
export class AllApplicationsComponent implements OnInit {
|
||||
protected dataSource = new TableDataSource<ApplicationHealthReportDetailEnriched>();
|
||||
protected dataSource = new TableDataSource<
|
||||
ApplicationHealthReportDetailEnriched & { ciphers: CipherView[] }
|
||||
>();
|
||||
protected selectedUrls: Set<string> = new Set<string>();
|
||||
protected searchControl = new FormControl("", { nonNullable: true });
|
||||
protected organization = new Organization();
|
||||
@@ -74,15 +76,31 @@ export class AllApplicationsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.dataService.enrichedReportData$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
||||
next: (report) => {
|
||||
this.applicationSummary = report?.summaryData ?? createNewSummaryData();
|
||||
this.dataSource.data = report?.reportData ?? [];
|
||||
},
|
||||
error: () => {
|
||||
this.dataSource.data = [];
|
||||
},
|
||||
});
|
||||
combineLatest([this.dataService.enrichedReportData$, this.dataService.ciphers$])
|
||||
.pipe(
|
||||
switchMap(([report, ciphers]) => {
|
||||
if (!report) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Map ciphers to each application
|
||||
const reportWithCiphers = report.reportData.map((app) => ({
|
||||
...app,
|
||||
ciphers: ciphers.filter((cipher) => app.cipherIds.includes(cipher.id)),
|
||||
}));
|
||||
return of({ ...report, reportData: reportWithCiphers });
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe({
|
||||
next: (report) => {
|
||||
this.applicationSummary = report?.summaryData ?? createNewSummaryData();
|
||||
this.dataSource.data = report?.reportData ?? [];
|
||||
},
|
||||
error: () => {
|
||||
this.dataSource.data = [];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
isMarkedAsCriticalItem(applicationName: string) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, DestroyRef, inject, OnInit } from "@angular/core";
|
||||
import { Component, DestroyRef, inject, OnInit, ChangeDetectionStrategy } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormControl } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { debounceTime, EMPTY, map, switchMap } from "rxjs";
|
||||
import { combineLatest, debounceTime, EMPTY, map, switchMap } from "rxjs";
|
||||
|
||||
import { Security } from "@bitwarden/assets/svg";
|
||||
import {
|
||||
@@ -28,9 +28,8 @@ import { RiskInsightsTabType } from "../models/risk-insights.models";
|
||||
import { AppTableRowScrollableComponent } from "../shared/app-table-row-scrollable.component";
|
||||
import { AccessIntelligenceSecurityTasksService } from "../shared/security-tasks.service";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
selector: "dirt-critical-applications",
|
||||
templateUrl: "./critical-applications.component.html",
|
||||
imports: [
|
||||
@@ -72,18 +71,34 @@ export class CriticalApplicationsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.dataService.criticalReportResults$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
||||
next: (criticalReport) => {
|
||||
this.dataSource.data = criticalReport?.reportData ?? [];
|
||||
this.applicationSummary = criticalReport?.summaryData ?? createNewSummaryData();
|
||||
this.enableRequestPasswordChange = criticalReport?.summaryData?.totalAtRiskMemberCount > 0;
|
||||
},
|
||||
error: () => {
|
||||
this.dataSource.data = [];
|
||||
this.applicationSummary = createNewSummaryData();
|
||||
this.enableRequestPasswordChange = false;
|
||||
},
|
||||
});
|
||||
combineLatest([this.dataService.criticalReportResults$, this.dataService.ciphers$])
|
||||
.pipe(
|
||||
map(([report, ciphers]) => {
|
||||
if (!report) {
|
||||
return null;
|
||||
}
|
||||
const reportWithCiphers = (report?.reportData ?? []).map((app) => ({
|
||||
...app,
|
||||
ciphers: ciphers.filter((cipher) => app.cipherIds.includes(cipher.id)),
|
||||
}));
|
||||
return { ...report, reportData: reportWithCiphers };
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe({
|
||||
next: (criticalReport) => {
|
||||
this.dataSource.data = criticalReport?.reportData ?? [];
|
||||
this.applicationSummary = criticalReport?.summaryData ?? createNewSummaryData();
|
||||
this.enableRequestPasswordChange =
|
||||
criticalReport?.summaryData?.totalAtRiskMemberCount > 0;
|
||||
},
|
||||
error: () => {
|
||||
this.dataSource.data = [];
|
||||
this.applicationSummary = createNewSummaryData();
|
||||
this.enableRequestPasswordChange = false;
|
||||
},
|
||||
});
|
||||
|
||||
this.activatedRoute.paramMap
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
|
||||
Reference in New Issue
Block a user