mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[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 <ttalty@bitwarden.com>
This commit is contained in:
@@ -373,6 +373,21 @@
|
|||||||
"noNewApplicationsToReviewAtThisTime": {
|
"noNewApplicationsToReviewAtThisTime": {
|
||||||
"message": "No new applications to review at this time"
|
"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": {
|
"prioritizeCriticalApplications": {
|
||||||
"message": "Prioritize critical applications"
|
"message": "Prioritize critical applications"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,26 +44,53 @@
|
|||||||
</dirt-activity-card>
|
</dirt-activity-card>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="tw-col-span-1">
|
<!-- All Caught Up State -->
|
||||||
<dirt-activity-card
|
@if (isAllCaughtUp) {
|
||||||
[title]="'newApplicationsCardTitle' | i18n"
|
<li class="tw-col-span-1">
|
||||||
[cardMetrics]="
|
<dirt-activity-card
|
||||||
isAllCaughtUp
|
[title]="'applicationsNeedingReview' | i18n"
|
||||||
? ('allCaughtUp' | i18n)
|
[cardMetrics]="'allCaughtUp' | i18n"
|
||||||
: ('newApplicationsWithCount' | i18n: newApplicationsCount)
|
[metricDescription]="'noNewApplicationsToReviewAtThisTime' | i18n"
|
||||||
"
|
[iconClass]="'bwi-check-circle'"
|
||||||
[metricDescription]="
|
[iconColorClass]="'tw-text-success'"
|
||||||
isAllCaughtUp
|
[buttonText]="''"
|
||||||
? ('noNewApplicationsToReviewAtThisTime' | i18n)
|
[buttonType]="'primary'"
|
||||||
: ('newApplicationsDescription' | i18n)
|
(buttonClick)="onReviewNewApplications()"
|
||||||
"
|
>
|
||||||
[iconClass]="isAllCaughtUp ? 'bwi-check-circle' : 'bwi-exclamation-triangle'"
|
</dirt-activity-card>
|
||||||
[iconColorClass]="isAllCaughtUp ? 'tw-text-success' : 'tw-text-warning'"
|
</li>
|
||||||
[buttonText]="isAllCaughtUp ? '' : ('reviewNow' | i18n)"
|
}
|
||||||
[buttonType]="'primary'"
|
<!-- Needs Review State (No apps have been reviewed) -->
|
||||||
(buttonClick)="onReviewNewApplications()"
|
@else if (showNeedsReviewState) {
|
||||||
>
|
<li class="tw-col-span-2">
|
||||||
</dirt-activity-card>
|
<dirt-activity-card
|
||||||
</li>
|
[title]="'applicationsNeedingReview' | i18n"
|
||||||
|
[cardMetrics]="'organizationHasItemsSavedForApplications' | i18n: totalApplicationCount"
|
||||||
|
[metricDescription]="'reviewApplicationsToSecureItems' | i18n"
|
||||||
|
[iconClass]="'bwi-exclamation-triangle'"
|
||||||
|
[iconColorClass]="'tw-text-warning'"
|
||||||
|
[buttonText]="'reviewApplications' | i18n"
|
||||||
|
[buttonType]="'primary'"
|
||||||
|
(buttonClick)="onReviewNewApplications()"
|
||||||
|
>
|
||||||
|
</dirt-activity-card>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
<!-- Default State (New applications to review) -->
|
||||||
|
@else {
|
||||||
|
<li class="tw-col-span-1">
|
||||||
|
<dirt-activity-card
|
||||||
|
[title]="'applicationsNeedingReview' | i18n"
|
||||||
|
[cardMetrics]="'newApplicationsWithCount' | i18n: newApplicationsCount"
|
||||||
|
[metricDescription]="'newApplicationsDescription' | i18n"
|
||||||
|
[iconClass]="'bwi-exclamation-triangle'"
|
||||||
|
[iconColorClass]="'tw-text-muted'"
|
||||||
|
[buttonText]="'reviewNow' | i18n"
|
||||||
|
[buttonType]="'primary'"
|
||||||
|
(buttonClick)="onReviewNewApplications()"
|
||||||
|
>
|
||||||
|
</dirt-activity-card>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,12 +39,14 @@ export class AllActivityComponent implements OnInit {
|
|||||||
totalCriticalAppsAtRiskMemberCount = 0;
|
totalCriticalAppsAtRiskMemberCount = 0;
|
||||||
totalCriticalAppsCount = 0;
|
totalCriticalAppsCount = 0;
|
||||||
totalCriticalAppsAtRiskCount = 0;
|
totalCriticalAppsAtRiskCount = 0;
|
||||||
|
totalApplicationCount = 0;
|
||||||
newApplicationsCount = 0;
|
newApplicationsCount = 0;
|
||||||
newApplications: ApplicationHealthReportDetail[] = [];
|
newApplications: ApplicationHealthReportDetail[] = [];
|
||||||
extendPasswordChangeWidget = false;
|
extendPasswordChangeWidget = false;
|
||||||
allAppsHaveReviewDate = false;
|
allAppsHaveReviewDate = false;
|
||||||
isAllCaughtUp = false;
|
isAllCaughtUp = false;
|
||||||
hasLoadedApplicationData = false;
|
hasLoadedApplicationData = false;
|
||||||
|
showNeedsReviewState = false;
|
||||||
|
|
||||||
destroyRef = inject(DestroyRef);
|
destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
@@ -65,6 +67,12 @@ export class AllActivityComponent implements OnInit {
|
|||||||
this.totalCriticalAppsAtRiskMemberCount = summary.totalCriticalAtRiskMemberCount;
|
this.totalCriticalAppsAtRiskMemberCount = summary.totalCriticalAtRiskMemberCount;
|
||||||
this.totalCriticalAppsCount = summary.totalCriticalApplicationCount;
|
this.totalCriticalAppsCount = summary.totalCriticalApplicationCount;
|
||||||
this.totalCriticalAppsAtRiskCount = summary.totalCriticalAtRiskApplicationCount;
|
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$
|
this.dataService.newApplications$
|
||||||
@@ -73,6 +81,7 @@ export class AllActivityComponent implements OnInit {
|
|||||||
this.newApplications = newApps;
|
this.newApplications = newApps;
|
||||||
this.newApplicationsCount = newApps.length;
|
this.newApplicationsCount = newApps.length;
|
||||||
this.updateIsAllCaughtUp();
|
this.updateIsAllCaughtUp();
|
||||||
|
this.updateShowNeedsReviewState();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.allActivitiesService.extendPasswordChangeWidget$
|
this.allActivitiesService.extendPasswordChangeWidget$
|
||||||
@@ -112,6 +121,20 @@ export class AllActivityComponent implements OnInit {
|
|||||||
this.allAppsHaveReviewDate;
|
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.
|
* Handles the review new applications button click.
|
||||||
* Opens a dialog showing the list of new applications that can be marked as critical.
|
* Opens a dialog showing the list of new applications that can be marked as critical.
|
||||||
|
|||||||
Reference in New Issue
Block a user