From 089caf57c2b4864717c3dfb2f285434912e326b2 Mon Sep 17 00:00:00 2001 From: Alex <55413326+AlexRubik@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:11:33 -0500 Subject: [PATCH] [PM-27757] init new apps state (#17200) * feat(dirt): add "needs review" state for applications needing initial review - Add showNeedsReviewState to display warning when all apps lack review dates - Track noAppsHaveReviewDate flag to identify unreviewed applications - Add i18n strings for organization items count and review prompt - Update activity card to show 3 states: all caught up, needs review, new apps - Apply tw-col-span-2 to needs review card for better visibility * refactor: split activity card states into separate @if blocks for readability * fix: set hasLoadedApplicationData when summary data arrives Previously, hasLoadedApplicationData was only set in the enrichedReportData$ subscription, which fired after reportSummary$ and newApplications$. This caused a timing issue where showNeedsReviewState would remain false even when newApplicationsCount === totalApplicationCount because the flag wasn't set yet. Now we set hasLoadedApplicationData=true as soon as reportSummary$ arrives with totalApplicationCount > 0, ensuring proper synchronization. --------- Co-authored-by: Tom --- apps/web/src/locales/en/messages.json | 15 ++++ .../activity/all-activity.component.html | 69 +++++++++++++------ .../activity/all-activity.component.ts | 23 +++++++ 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 761cc2941d..49e29f0074 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -373,6 +373,21 @@ "noNewApplicationsToReviewAtThisTime": { "message": "No new applications to review at this time" }, + "organizationHasItemsSavedForApplications": { + "message": "Your organization has items saved for $COUNT$ applications", + "placeholders": { + "count": { + "content": "$1", + "example": "310" + } + } + }, + "reviewApplicationsToSecureItems": { + "message": "Review applications to secure the items most critical to your organization's security" + }, + "reviewApplications": { + "message": "Review applications" + }, "prioritizeCriticalApplications": { "message": "Prioritize critical applications" }, diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.html index d8ad785ff1..43cf936e1a 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/all-activity.component.html @@ -44,26 +44,53 @@ -
  • - - -
  • + + @if (isAllCaughtUp) { +
  • + + +
  • + } + + @else if (showNeedsReviewState) { +
  • + + +
  • + } + + @else { +
  • + + +
  • + } } 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 06073d93c8..907e8883a4 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 @@ -39,12 +39,14 @@ export class AllActivityComponent implements OnInit { totalCriticalAppsAtRiskMemberCount = 0; totalCriticalAppsCount = 0; totalCriticalAppsAtRiskCount = 0; + totalApplicationCount = 0; newApplicationsCount = 0; newApplications: ApplicationHealthReportDetail[] = []; extendPasswordChangeWidget = false; allAppsHaveReviewDate = false; isAllCaughtUp = false; hasLoadedApplicationData = false; + showNeedsReviewState = false; destroyRef = inject(DestroyRef); @@ -65,6 +67,12 @@ export class AllActivityComponent implements OnInit { this.totalCriticalAppsAtRiskMemberCount = summary.totalCriticalAtRiskMemberCount; this.totalCriticalAppsCount = summary.totalCriticalApplicationCount; this.totalCriticalAppsAtRiskCount = summary.totalCriticalAtRiskApplicationCount; + this.totalApplicationCount = summary.totalApplicationCount; + // If we have application data, mark as loaded + if (summary.totalApplicationCount > 0) { + this.hasLoadedApplicationData = true; + } + this.updateShowNeedsReviewState(); }); this.dataService.newApplications$ @@ -73,6 +81,7 @@ export class AllActivityComponent implements OnInit { this.newApplications = newApps; this.newApplicationsCount = newApps.length; this.updateIsAllCaughtUp(); + this.updateShowNeedsReviewState(); }); this.allActivitiesService.extendPasswordChangeWidget$ @@ -112,6 +121,20 @@ export class AllActivityComponent implements OnInit { this.allAppsHaveReviewDate; } + /** + * Updates the showNeedsReviewState flag based on current state. + * This state is shown when: + * - Data has been loaded + * - There are applications (totalApplicationCount > 0) + * - ALL apps do NOT have a review date (newApplicationsCount === totalApplicationCount) + */ + private updateShowNeedsReviewState(): void { + this.showNeedsReviewState = + this.hasLoadedApplicationData && + this.totalApplicationCount > 0 && + this.newApplicationsCount === this.totalApplicationCount; + } + /** * Handles the review new applications button click. * Opens a dialog showing the list of new applications that can be marked as critical.