1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-06 03:33:30 +00:00

feat(dirt): add saveApplicationReviewStatus$ to orchestrator

Implement method to save application review status and critical flags.
Updates all applications where reviewedDate === null to set current date,
and marks selected applications as critical.

- Add saveApplicationReviewStatus$() method
- Add _updateReviewStatusAndCriticalFlags() helper
- Uses existing encryption and API update patterns
- Single API call for both review status and critical flags
- Follows same pattern as saveCriticalApplications$()

Related to PM-27284
This commit is contained in:
Claude
2025-10-28 21:17:32 +00:00
parent 9e9d50e7bf
commit 1539e8308a

View File

@@ -350,6 +350,118 @@ export class RiskInsightsOrchestratorService {
);
}
/**
* Saves review status for new applications and optionally marks selected ones as critical.
* This method:
* 1. Sets reviewedDate to current date for all applications where reviewedDate === null
* 2. Sets isCritical = true for applications in the selectedCriticalApps array
*
* @param selectedCriticalApps Array of application names to mark as critical (can be empty)
* @returns Observable of updated ReportState
*/
saveApplicationReviewStatus$(selectedCriticalApps: string[]): Observable<ReportState> {
this.logService.info(
"[RiskInsightsOrchestratorService] Saving application review status",
{
criticalAppsCount: selectedCriticalApps.length,
},
);
return this.rawReportData$.pipe(
take(1),
filter((data) => !data.loading && data.data != null),
withLatestFrom(
this.organizationDetails$.pipe(filter((org) => !!org && !!org.organizationId)),
this._userId$.pipe(filter((userId) => !!userId)),
),
map(([reportState, organizationDetails, userId]) => {
const existingApplicationData = reportState?.data?.applicationData || [];
const updatedApplicationData = this._updateReviewStatusAndCriticalFlags(
existingApplicationData,
selectedCriticalApps,
);
const updatedState = {
...reportState,
data: {
...reportState.data,
applicationData: updatedApplicationData,
},
} as ReportState;
this.logService.debug(
"[RiskInsightsOrchestratorService] Updated review status",
{
totalApps: updatedApplicationData.length,
reviewedApps: updatedApplicationData.filter((app) => app.reviewedDate !== null).length,
criticalApps: updatedApplicationData.filter((app) => app.isCritical).length,
},
);
return { reportState, organizationDetails, updatedState, userId };
}),
switchMap(({ reportState, organizationDetails, updatedState, userId }) => {
return from(
this.riskInsightsEncryptionService.encryptRiskInsightsReport(
{
organizationId: organizationDetails!.organizationId,
userId: userId!,
},
{
reportData: reportState?.data?.reportData ?? [],
summaryData: reportState?.data?.summaryData ?? createNewSummaryData(),
applicationData: updatedState?.data?.applicationData ?? [],
},
reportState?.data?.contentEncryptionKey,
),
).pipe(
map((encryptedData) => ({
reportState,
organizationDetails,
updatedState,
encryptedData,
})),
);
}),
switchMap(({ reportState, organizationDetails, updatedState, encryptedData }) => {
this.logService.debug(
`[RiskInsightsOrchestratorService] Persisting review status - report id: ${reportState?.data?.id}`,
);
if (!reportState?.data?.id || !organizationDetails?.organizationId) {
this.logService.warning(
"[RiskInsightsOrchestratorService] Cannot save review status - missing report id or org id",
);
return of({ ...reportState });
}
return this.reportApiService
.updateRiskInsightsApplicationData$(
reportState.data.id,
organizationDetails.organizationId,
{
data: {
applicationData: encryptedData.encryptedApplicationData.toSdk(),
},
},
)
.pipe(
map(() => updatedState),
tap((finalState) => {
this._markUnmarkUpdatesSubject.next(finalState);
}),
catchError((error: unknown) => {
this.logService.error(
"[RiskInsightsOrchestratorService] Failed to save review status",
error,
);
return of({ ...reportState, error: "Failed to save application review status" });
}),
);
}),
);
}
private _fetchReport$(organizationId: OrganizationId, userId: UserId): Observable<ReportState> {
return this.reportService.getRiskInsightsReport$(organizationId, userId).pipe(
tap(() => this.logService.debug("[RiskInsightsOrchestratorService] Fetching report")),
@@ -501,6 +613,39 @@ export class RiskInsightsOrchestratorService {
return updatedApps;
}
/**
* Updates review status and critical flags for applications.
* Sets reviewedDate for all apps with null reviewedDate.
* Sets isCritical flag for apps in the criticalApplications array.
*
* @param existingApplications Current application data
* @param criticalApplications Array of application names to mark as critical
* @returns Updated application data with review dates and critical flags
*/
private _updateReviewStatusAndCriticalFlags(
existingApplications: OrganizationReportApplication[],
criticalApplications: string[],
): OrganizationReportApplication[] {
const criticalSet = new Set(criticalApplications);
const currentDate = new Date();
return existingApplications.map((app) => {
const shouldMarkCritical = criticalSet.has(app.applicationName);
const needsReviewDate = app.reviewedDate === null;
// Only create new object if changes are needed
if (needsReviewDate || shouldMarkCritical) {
return {
...app,
reviewedDate: needsReviewDate ? currentDate : app.reviewedDate,
isCritical: shouldMarkCritical || app.isCritical,
};
}
return app;
});
}
// Toggles the isCritical flag on applications via criticalApplicationName
private _removeCriticalApplication(
applicationData: OrganizationReportApplication[],