mirror of
https://github.com/bitwarden/browser
synced 2025-12-21 10:43:35 +00:00
PM-17212 Invoke notifications API (#13377)
This commit is contained in:
@@ -28,7 +28,14 @@
|
|||||||
<div class="tw-mt-4 tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
|
<div class="tw-mt-4 tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
|
||||||
<div class="tw-flex tw-justify-between tw-mb-4">
|
<div class="tw-flex tw-justify-between tw-mb-4">
|
||||||
<h2 bitTypography="h2">{{ "criticalApplications" | i18n }}</h2>
|
<h2 bitTypography="h2">{{ "criticalApplications" | i18n }}</h2>
|
||||||
<button *ngIf="isNotificationsFeatureEnabled" bitButton buttonType="primary" type="button">
|
<button
|
||||||
|
*ngIf="isNotificationsFeatureEnabled"
|
||||||
|
bitButton
|
||||||
|
buttonType="primary"
|
||||||
|
type="button"
|
||||||
|
[disabled]="!enableRequestPasswordChange"
|
||||||
|
(click)="requestPasswordChange()"
|
||||||
|
>
|
||||||
<i class="bwi bwi-envelope tw-mr-2"></i>
|
<i class="bwi bwi-envelope tw-mr-2"></i>
|
||||||
{{ "requestPasswordChange" | i18n }}
|
{{ "requestPasswordChange" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
import { CipherId, OrganizationId } from "@bitwarden/common/types/guid";
|
||||||
import {
|
import {
|
||||||
Icons,
|
Icons,
|
||||||
NoItemsModule,
|
NoItemsModule,
|
||||||
@@ -27,10 +27,14 @@ import {
|
|||||||
ToastService,
|
ToastService,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { CardComponent } from "@bitwarden/tools-card";
|
import { CardComponent } from "@bitwarden/tools-card";
|
||||||
|
import { SecurityTaskType } from "@bitwarden/vault";
|
||||||
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
|
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
|
||||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||||
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
||||||
|
|
||||||
|
import { CreateTasksRequest } from "../../vault/services/abstractions/admin-task.abstraction";
|
||||||
|
import { DefaultAdminTaskService } from "../../vault/services/default-admin-task.service";
|
||||||
|
|
||||||
import { RiskInsightsTabType } from "./risk-insights.component";
|
import { RiskInsightsTabType } from "./risk-insights.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -38,7 +42,7 @@ import { RiskInsightsTabType } from "./risk-insights.component";
|
|||||||
selector: "tools-critical-applications",
|
selector: "tools-critical-applications",
|
||||||
templateUrl: "./critical-applications.component.html",
|
templateUrl: "./critical-applications.component.html",
|
||||||
imports: [CardComponent, HeaderModule, SearchModule, NoItemsModule, PipesModule, SharedModule],
|
imports: [CardComponent, HeaderModule, SearchModule, NoItemsModule, PipesModule, SharedModule],
|
||||||
providers: [],
|
providers: [DefaultAdminTaskService],
|
||||||
})
|
})
|
||||||
export class CriticalApplicationsComponent implements OnInit {
|
export class CriticalApplicationsComponent implements OnInit {
|
||||||
protected dataSource = new TableDataSource<ApplicationHealthReportDetailWithCriticalFlag>();
|
protected dataSource = new TableDataSource<ApplicationHealthReportDetailWithCriticalFlag>();
|
||||||
@@ -50,6 +54,7 @@ export class CriticalApplicationsComponent implements OnInit {
|
|||||||
protected applicationSummary = {} as ApplicationHealthReportSummary;
|
protected applicationSummary = {} as ApplicationHealthReportSummary;
|
||||||
noItemsIcon = Icons.Security;
|
noItemsIcon = Icons.Security;
|
||||||
isNotificationsFeatureEnabled: boolean = false;
|
isNotificationsFeatureEnabled: boolean = false;
|
||||||
|
enableRequestPasswordChange = false;
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.isNotificationsFeatureEnabled = await this.configService.getFeatureFlag(
|
this.isNotificationsFeatureEnabled = await this.configService.getFeatureFlag(
|
||||||
@@ -75,6 +80,7 @@ export class CriticalApplicationsComponent implements OnInit {
|
|||||||
if (applications) {
|
if (applications) {
|
||||||
this.dataSource.data = applications;
|
this.dataSource.data = applications;
|
||||||
this.applicationSummary = this.reportService.generateApplicationsSummary(applications);
|
this.applicationSummary = this.reportService.generateApplicationsSummary(applications);
|
||||||
|
this.enableRequestPasswordChange = this.applicationSummary.totalAtRiskMemberCount > 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,6 +115,33 @@ export class CriticalApplicationsComponent implements OnInit {
|
|||||||
this.dataSource.data = this.dataSource.data.filter((app) => app.applicationName !== hostname);
|
this.dataSource.data = this.dataSource.data.filter((app) => app.applicationName !== hostname);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async requestPasswordChange() {
|
||||||
|
const apps = this.dataSource.data;
|
||||||
|
const cipherIds = apps
|
||||||
|
.filter((_) => _.atRiskPasswordCount > 0)
|
||||||
|
.flatMap((app) => app.atRiskMemberDetails.map((member) => member.cipherId));
|
||||||
|
const distinctCipherIds = Array.from(new Set(cipherIds));
|
||||||
|
const tasks: CreateTasksRequest[] = distinctCipherIds.map((cipherId) => ({
|
||||||
|
cipherId: cipherId as CipherId,
|
||||||
|
type: SecurityTaskType.UpdateAtRiskCredential,
|
||||||
|
}));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.adminTaskService.bulkCreateTasks(this.organizationId as OrganizationId, tasks);
|
||||||
|
this.toastService.showToast({
|
||||||
|
message: this.i18nService.t("notifiedMembers"),
|
||||||
|
variant: "success",
|
||||||
|
title: this.i18nService.t("success"),
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
this.toastService.showToast({
|
||||||
|
message: this.i18nService.t("unexpectedError"),
|
||||||
|
variant: "error",
|
||||||
|
title: this.i18nService.t("error"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected activatedRoute: ActivatedRoute,
|
protected activatedRoute: ActivatedRoute,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
@@ -118,6 +151,7 @@ export class CriticalApplicationsComponent implements OnInit {
|
|||||||
protected reportService: RiskInsightsReportService,
|
protected reportService: RiskInsightsReportService,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
|
private adminTaskService: DefaultAdminTaskService,
|
||||||
) {
|
) {
|
||||||
this.searchControl.valueChanges
|
this.searchControl.valueChanges
|
||||||
.pipe(debounceTime(200), takeUntilDestroyed())
|
.pipe(debounceTime(200), takeUntilDestroyed())
|
||||||
|
|||||||
Reference in New Issue
Block a user