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 }} +
+
+ + + + + + + + + + @for (app of newApplications; track app) { + + + + + + } + +
+ {{ "application" | i18n }} + + {{ "atRiskItems" | i18n }} +
+ + +
+ + {{ 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")}`, + }); + }; +}