1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-27 01:53:23 +00:00

[PM-26378] Auto confirm events (#19025)

* add notification handler for auto confirm

* add missing state check

* fix test

* isolate angular specific code from shared lib code

* clean up

* use autoconfirm method

* add event logging for auto confirm

* update copy
This commit is contained in:
Brandon Treston
2026-02-19 09:57:52 -05:00
committed by GitHub
parent e66a1f37b5
commit c8ba23e28d
8 changed files with 100 additions and 5 deletions

View File

@@ -7,6 +7,8 @@ import { of } from "rxjs";
import { NudgesService, NudgeType } from "@bitwarden/angular/vault";
import { AutoConfirmState, AutomaticUserConfirmationService } from "@bitwarden/auto-confirm";
import { PopOutComponent } from "@bitwarden/browser/platform/popup/components/pop-out.component";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { mockAccountServiceWith } from "@bitwarden/common/spec";
@@ -52,6 +54,8 @@ describe("AdminSettingsComponent", () => {
let autoConfirmService: MockProxy<AutomaticUserConfirmationService>;
let nudgesService: MockProxy<NudgesService>;
let mockDialogService: MockProxy<DialogService>;
let eventCollectionService: MockProxy<EventCollectionService>;
let organizationService: MockProxy<InternalOrganizationServiceAbstraction>;
const userId = "test-user-id" as UserId;
const mockAutoConfirmState: AutoConfirmState = {
@@ -64,10 +68,14 @@ describe("AdminSettingsComponent", () => {
autoConfirmService = mock<AutomaticUserConfirmationService>();
nudgesService = mock<NudgesService>();
mockDialogService = mock<DialogService>();
eventCollectionService = mock<EventCollectionService>();
organizationService = mock<InternalOrganizationServiceAbstraction>();
autoConfirmService.configuration$.mockReturnValue(of(mockAutoConfirmState));
autoConfirmService.upsert.mockResolvedValue(undefined);
nudgesService.showNudgeSpotlight$.mockReturnValue(of(false));
eventCollectionService.collect.mockResolvedValue(undefined);
organizationService.organizations$.mockReturnValue(of([]));
await TestBed.configureTestingModule({
imports: [AdminSettingsComponent],
@@ -77,6 +85,11 @@ describe("AdminSettingsComponent", () => {
{ provide: AutomaticUserConfirmationService, useValue: autoConfirmService },
{ provide: DialogService, useValue: mockDialogService },
{ provide: NudgesService, useValue: nudgesService },
{ provide: EventCollectionService, useValue: eventCollectionService },
{
provide: InternalOrganizationServiceAbstraction,
useValue: organizationService,
},
{ provide: I18nService, useValue: { t: (key: string) => key } },
],
})

View File

@@ -20,8 +20,11 @@ import {
import { PopOutComponent } from "@bitwarden/browser/platform/popup/components/pop-out.component";
import { PopupHeaderComponent } from "@bitwarden/browser/platform/popup/layout/popup-header.component";
import { PopupPageComponent } from "@bitwarden/browser/platform/popup/layout/popup-page.component";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { EventType } from "@bitwarden/common/enums";
import {
BitIconButtonComponent,
CardComponent,
@@ -69,6 +72,8 @@ export class AdminSettingsComponent implements OnInit {
private destroyRef: DestroyRef,
private dialogService: DialogService,
private nudgesService: NudgesService,
private eventCollectionService: EventCollectionService,
private organizationService: InternalOrganizationServiceAbstraction,
) {}
async ngOnInit() {
@@ -88,14 +93,26 @@ export class AdminSettingsComponent implements OnInit {
}
return of(false);
}),
withLatestFrom(this.autoConfirmService.configuration$(userId)),
switchMap(([newValue, existingState]) =>
this.autoConfirmService.upsert(userId, {
withLatestFrom(
this.autoConfirmService.configuration$(userId),
this.organizationService.organizations$(userId),
),
switchMap(async ([newValue, existingState, organizations]) => {
await this.autoConfirmService.upsert(userId, {
...existingState,
enabled: newValue,
showBrowserNotification: false,
}),
),
});
// Auto-confirm users can only belong to one organization
const organization = organizations[0];
if (organization?.id) {
const eventType = newValue
? EventType.Organization_AutoConfirmEnabled_Admin
: EventType.Organization_AutoConfirmDisabled_Admin;
await this.eventCollectionService.collect(eventType, undefined, true, organization.id);
}
}),
takeUntilDestroyed(this.destroyRef),
)
.subscribe();