diff --git a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/view/all-activities.service.ts b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/view/all-activities.service.ts index 7de8ab223de..65a9e9e4ad0 100644 --- a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/view/all-activities.service.ts +++ b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/view/all-activities.service.ts @@ -1,4 +1,5 @@ -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, Subject } from "rxjs"; +import { takeUntil } from "rxjs/operators"; import { ApplicationHealthReportDetailEnriched } from "../../models"; import { OrganizationReportSummary } from "../../models/report-models"; @@ -11,6 +12,8 @@ export class AllActivitiesService { /// Going forward, this class can be simplified by using the RiskInsightsDataService /// as it contains the application summary data. + private _destroy$ = new Subject(); + private reportSummarySubject$ = new BehaviorSubject({ totalMemberCount: 0, totalCriticalMemberCount: 0, @@ -40,7 +43,7 @@ export class AllActivitiesService { constructor(private dataService: RiskInsightsDataService) { // All application summary changes - this.dataService.enrichedReportData$.subscribe((report) => { + this.dataService.enrichedReportData$.pipe(takeUntil(this._destroy$)).subscribe((report) => { if (report) { this.setAllAppsReportSummary(report.summaryData); this.setAllAppsReportDetails(report.reportData); @@ -48,14 +51,14 @@ export class AllActivitiesService { }); // Critical application summary changes - this.dataService.criticalReportResults$.subscribe((report) => { + this.dataService.criticalReportResults$.pipe(takeUntil(this._destroy$)).subscribe((report) => { if (report) { this.setCriticalAppsReportSummary(report.summaryData); } }); // New applications changes (from orchestrator's reactive pipeline) - this.dataService.newApplications$.subscribe((newApps) => { + this.dataService.newApplications$.pipe(takeUntil(this._destroy$)).subscribe((newApps) => { this.setNewApplications(newApps); }); } @@ -108,4 +111,13 @@ export class AllActivitiesService { newApplications: newApps, }); } + + /** + * Cleanup method to unsubscribe from all observables. + * Should be called when the service is destroyed to prevent memory leaks. + */ + destroy(): void { + this._destroy$.next(); + this._destroy$.complete(); + } } diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.ts index 07559a4abdc..7563bd2bbc0 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.ts @@ -2,7 +2,6 @@ import { Component, DestroyRef, inject, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { ActivatedRoute } from "@angular/router"; import { firstValueFrom } from "rxjs"; -import { finalize } from "rxjs/operators"; import { AllActivitiesService, @@ -99,15 +98,7 @@ export class AllActivityComponent implements OnInit { if (result?.saved) { // User clicked Continue - save review status and critical flags - let isSaving = true; - - firstValueFrom( - this.dataService.saveApplicationReviewStatus(result.selectedApplications).pipe( - finalize(() => { - isSaving = false; - }), - ), - ) + firstValueFrom(this.dataService.saveApplicationReviewStatus(result.selectedApplications)) .then(() => { // Success - data will update automatically through reactive pipeline if (result.selectedApplications.length > 0) { @@ -127,7 +118,8 @@ export class AllActivityComponent implements OnInit { }); } }) - .catch((error) => { + .catch(() => { + // Error already logged by orchestrator service this.toastService.showToast({ variant: "error", title: this.i18nService.t("error"),