From 85113f2f0ac16e01f192eb3641839f2a684eb43b Mon Sep 17 00:00:00 2001
From: Alex <55413326+AlexRubik@users.noreply.github.com>
Date: Thu, 9 Oct 2025 11:22:12 -0400
Subject: [PATCH] [PM-26203] new apps dialog (#16696)
---
apps/web/src/locales/en/messages.json | 21 +++++
.../all-activity.component.ts | 19 ++--
.../new-applications-dialog.component.html | 71 +++++++++++++++
.../new-applications-dialog.component.ts | 86 +++++++++++++++++++
4 files changed, 189 insertions(+), 8 deletions(-)
create mode 100644 bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.html
create mode 100644 bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.ts
diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json
index 691633b3ad..3eab92470a 100644
--- a/apps/web/src/locales/en/messages.json
+++ b/apps/web/src/locales/en/messages.json
@@ -187,6 +187,18 @@
"markAppAsCritical": {
"message": "Mark app as critical"
},
+ "markAsCritical": {
+ "message": "Mark as critical"
+ },
+ "applicationsSelected": {
+ "message": "applications selected"
+ },
+ "selectApplication": {
+ "message": "Select application"
+ },
+ "unselectApplication": {
+ "message": "Unselect application"
+ },
"applicationsMarkedAsCriticalSuccess": {
"message": "Applications marked as critical"
},
@@ -298,6 +310,15 @@
"reviewNow": {
"message": "Review now"
},
+ "prioritizeCriticalApplications": {
+ "message": "Prioritize critical applications"
+ },
+ "atRiskItems": {
+ "message": "At-risk items"
+ },
+ "markAsCriticalPlaceholder": {
+ "message": "Mark as critical functionality will be implemented in a future update"
+ },
"unmarkAsCritical": {
"message": "Unmark as critical"
},
diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-activity.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-activity.component.ts
index 31ab035116..e4942344b0 100644
--- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-activity.component.ts
+++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-activity.component.ts
@@ -13,11 +13,12 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { getById } from "@bitwarden/common/platform/misc";
-import { ToastService } from "@bitwarden/components";
+import { ToastService, DialogService } from "@bitwarden/components";
import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { ActivityCardComponent } from "./activity-card.component";
import { PasswordChangeMetricComponent } from "./activity-cards/password-change-metric.component";
+import { NewApplicationsDialogComponent } from "./new-applications-dialog.component";
import { ApplicationsLoadingComponent } from "./risk-insights-loading.component";
import { RiskInsightsTabType } from "./risk-insights.component";
@@ -37,6 +38,7 @@ export class AllActivityComponent implements OnInit {
totalCriticalAppsCount = 0;
totalCriticalAppsAtRiskCount = 0;
newApplicationsCount = 0;
+ newApplications: string[] = [];
passwordChangeMetricHasProgressBar = false;
destroyRef = inject(DestroyRef);
@@ -57,6 +59,7 @@ export class AllActivityComponent implements OnInit {
this.totalCriticalAppsAtRiskMemberCount = summary.totalCriticalAtRiskMemberCount;
this.totalCriticalAppsCount = summary.totalCriticalApplicationCount;
this.totalCriticalAppsAtRiskCount = summary.totalCriticalAtRiskApplicationCount;
+ this.newApplications = summary.newApplications;
this.newApplicationsCount = summary.newApplications.length;
});
@@ -76,6 +79,7 @@ export class AllActivityComponent implements OnInit {
protected allActivitiesService: AllActivitiesService,
private toastService: ToastService,
private i18nService: I18nService,
+ private dialogService: DialogService,
) {}
get RiskInsightsTabType() {
@@ -89,14 +93,13 @@ export class AllActivityComponent implements OnInit {
/**
* Handles the review new applications button click.
- * Shows a toast notification as a placeholder until the dialog is implemented.
- * TODO: Implement dialog for reviewing new applications (follow-up task)
+ * Opens a dialog showing the list of new applications that can be marked as critical.
*/
- onReviewNewApplications = () => {
- this.toastService.showToast({
- variant: "info",
- title: this.i18nService.t("applicationsNeedingReview"),
- message: this.i18nService.t("newApplicationsWithCount", this.newApplicationsCount.toString()),
+ onReviewNewApplications = async () => {
+ const dialogRef = NewApplicationsDialogComponent.open(this.dialogService, {
+ newApplications: this.newApplications,
});
+
+ await firstValueFrom(dialogRef.closed);
};
}
diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.html
new file mode 100644
index 0000000000..f7a5441030
--- /dev/null
+++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.html
@@ -0,0 +1,71 @@
+
+ {{ "prioritizeCriticalApplications" | i18n }}
+
+
+
+
+
+ |
+
+ {{ "application" | i18n }}
+ |
+
+ {{ "atRiskItems" | i18n }}
+ |
+
+
+
+ @for (app of newApplications; track app) {
+
+ |
+
+ |
+
+
+
+ {{ app }}
+
+ |
+ — |
+
+ }
+
+
+
+
+
+
+
+
+
diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.ts
new file mode 100644
index 0000000000..e06d889c59
--- /dev/null
+++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/new-applications-dialog.component.ts
@@ -0,0 +1,86 @@
+import { CommonModule } from "@angular/common";
+import { Component, inject } from "@angular/core";
+
+import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
+import {
+ ButtonModule,
+ DialogModule,
+ DialogService,
+ ToastService,
+ TypographyModule,
+} from "@bitwarden/components";
+import { I18nPipe } from "@bitwarden/ui-common";
+
+export interface NewApplicationsDialogData {
+ newApplications: string[];
+}
+
+@Component({
+ templateUrl: "./new-applications-dialog.component.html",
+ imports: [CommonModule, ButtonModule, DialogModule, TypographyModule, I18nPipe],
+})
+export class NewApplicationsDialogComponent {
+ protected newApplications: string[] = [];
+ protected selectedApplications: Set = new Set();
+
+ private toastService = inject(ToastService);
+ private i18nService = inject(I18nService);
+
+ /**
+ * Opens the new applications dialog
+ * @param dialogService The dialog service instance
+ * @param data Dialog data containing the list of new applications
+ * @returns Dialog reference
+ */
+ static open(dialogService: DialogService, data: NewApplicationsDialogData) {
+ const ref = dialogService.open(
+ NewApplicationsDialogComponent,
+ {
+ data,
+ },
+ );
+
+ // Set the component's data after opening
+ const instance = ref.componentInstance as NewApplicationsDialogComponent;
+ if (instance) {
+ instance.newApplications = data.newApplications;
+ }
+
+ return ref;
+ }
+
+ /**
+ * Toggles the selection state of an application.
+ * @param applicationName The application to toggle
+ */
+ toggleSelection = (applicationName: string) => {
+ if (this.selectedApplications.has(applicationName)) {
+ this.selectedApplications.delete(applicationName);
+ } else {
+ this.selectedApplications.add(applicationName);
+ }
+ };
+
+ /**
+ * Checks if an application is currently selected.
+ * @param applicationName The application to check
+ * @returns True if selected, false otherwise
+ */
+ isSelected = (applicationName: string): boolean => {
+ return this.selectedApplications.has(applicationName);
+ };
+
+ /**
+ * Placeholder handler for mark as critical functionality.
+ * Shows a toast notification with count of selected applications.
+ * TODO: Implement actual mark as critical functionality (PM-26203 follow-up)
+ */
+ onMarkAsCritical = () => {
+ const selectedCount = this.selectedApplications.size;
+ this.toastService.showToast({
+ variant: "info",
+ title: this.i18nService.t("markAsCritical"),
+ message: `${selectedCount} ${this.i18nService.t("applicationsSelected")}`,
+ });
+ };
+}