mirror of
https://github.com/bitwarden/browser
synced 2025-12-29 14:43:31 +00:00
[PM-28181] Open send dialog in drawer instead of popup in refreshed UI (#17666)
* [PM-28181] Open send dialog in drawer instead of popup in refreshed UI * Fix types * [PM-28181] Use drawer to edit sends with refreshed UI * [PM-28181] Address bug where multiple Sends could not be navigated between
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
||||
import { SendAddEditDialogComponent } from "@bitwarden/send-ui";
|
||||
|
||||
import { NewSendDropdownComponent } from "./new-send-dropdown.component";
|
||||
|
||||
describe("NewSendDropdownComponent", () => {
|
||||
let component: NewSendDropdownComponent;
|
||||
let fixture: ComponentFixture<NewSendDropdownComponent>;
|
||||
const mockBillingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
const mockAccountService = mock<AccountService>();
|
||||
const mockConfigService = mock<ConfigService>();
|
||||
const mockI18nService = mock<I18nService>();
|
||||
const mockPolicyService = mock<PolicyService>();
|
||||
const mockSendService = mock<SendService>();
|
||||
const mockPremiumUpgradePromptService = mock<PremiumUpgradePromptService>();
|
||||
const mockSendApiService = mock<SendApiService>();
|
||||
|
||||
beforeAll(() => {
|
||||
mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockImplementation(() =>
|
||||
of(true),
|
||||
);
|
||||
mockAccountService.activeAccount$ = of({ id: "myTestAccount" } as Account);
|
||||
mockPolicyService.policyAppliesToUser$.mockImplementation(() => of(false));
|
||||
mockPremiumUpgradePromptService.promptForPremium.mockImplementation(async () => {});
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [NewSendDropdownComponent],
|
||||
declarations: [],
|
||||
providers: [
|
||||
{
|
||||
provide: BillingAccountProfileStateService,
|
||||
useValue: mockBillingAccountProfileStateService,
|
||||
},
|
||||
{ provide: AccountService, useValue: mockAccountService },
|
||||
{ provide: ConfigService, useValue: mockConfigService },
|
||||
{ provide: I18nService, useValue: mockI18nService },
|
||||
{ provide: PolicyService, useValue: mockPolicyService },
|
||||
{ provide: SendService, useValue: mockSendService },
|
||||
{ provide: PremiumUpgradePromptService, useValue: mockPremiumUpgradePromptService },
|
||||
{ provide: SendApiService, useValue: mockSendApiService },
|
||||
],
|
||||
}).compileComponents();
|
||||
fixture = TestBed.createComponent(NewSendDropdownComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should open send dialog in a popup without feature flag", async () => {
|
||||
const openSpy = jest.spyOn(SendAddEditDialogComponent, "open");
|
||||
const openDrawerSpy = jest.spyOn(SendAddEditDialogComponent, "openDrawer");
|
||||
mockConfigService.getFeatureFlag.mockResolvedValue(false);
|
||||
|
||||
await component.createSend(SendType.Text);
|
||||
|
||||
expect(openSpy).toHaveBeenCalled();
|
||||
expect(openDrawerSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should open send dialog in drawer with feature flag", async () => {
|
||||
const openSpy = jest.spyOn(SendAddEditDialogComponent, "open");
|
||||
const openDrawerSpy = jest.spyOn(SendAddEditDialogComponent, "openDrawer");
|
||||
mockConfigService.getFeatureFlag.mockImplementation(async (key) =>
|
||||
key === FeatureFlag.SendUIRefresh ? true : false,
|
||||
);
|
||||
|
||||
await component.createSend(SendType.Text);
|
||||
|
||||
expect(openSpy).not.toHaveBeenCalled();
|
||||
expect(openDrawerSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,8 @@ import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/pre
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { ButtonModule, DialogService, MenuModule } from "@bitwarden/components";
|
||||
import { DefaultSendFormConfigService, SendAddEditDialogComponent } from "@bitwarden/send-ui";
|
||||
@@ -38,6 +40,7 @@ export class NewSendDropdownComponent {
|
||||
private accountService: AccountService,
|
||||
private dialogService: DialogService,
|
||||
private addEditFormConfigService: DefaultSendFormConfigService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
this.canAccessPremium$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
@@ -60,6 +63,11 @@ export class NewSendDropdownComponent {
|
||||
|
||||
const formConfig = await this.addEditFormConfigService.buildConfig("add", undefined, type);
|
||||
|
||||
SendAddEditDialogComponent.open(this.dialogService, { formConfig });
|
||||
const useRefresh = await this.configService.getFeatureFlag(FeatureFlag.SendUIRefresh);
|
||||
if (useRefresh) {
|
||||
SendAddEditDialogComponent.openDrawer(this.dialogService, { formConfig });
|
||||
} else {
|
||||
SendAddEditDialogComponent.open(this.dialogService, { formConfig });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/sen
|
||||
import { NoSendsIcon } from "@bitwarden/assets/svg";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -77,6 +79,7 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
|
||||
toastService: ToastService,
|
||||
private addEditFormConfigService: DefaultSendFormConfigService,
|
||||
accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
super(
|
||||
sendService,
|
||||
@@ -144,14 +147,21 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
|
||||
* @param formConfig The form configuration.
|
||||
* */
|
||||
async openSendItemDialog(formConfig: SendFormConfig) {
|
||||
// Prevent multiple dialogs from being opened.
|
||||
if (this.sendItemDialogRef) {
|
||||
const useRefresh = await this.configService.getFeatureFlag(FeatureFlag.SendUIRefresh);
|
||||
// Prevent multiple dialogs from being opened but allow drawers since they will prevent multiple being open themselves
|
||||
if (this.sendItemDialogRef && !useRefresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendItemDialogRef = SendAddEditDialogComponent.open(this.dialogService, {
|
||||
formConfig,
|
||||
});
|
||||
if (useRefresh) {
|
||||
this.sendItemDialogRef = SendAddEditDialogComponent.openDrawer(this.dialogService, {
|
||||
formConfig,
|
||||
});
|
||||
} else {
|
||||
this.sendItemDialogRef = SendAddEditDialogComponent.open(this.dialogService, {
|
||||
formConfig,
|
||||
});
|
||||
}
|
||||
|
||||
const result = await lastValueFrom(this.sendItemDialogRef.closed);
|
||||
this.sendItemDialogRef = undefined;
|
||||
|
||||
@@ -50,6 +50,7 @@ export enum FeatureFlag {
|
||||
DesktopSendUIRefresh = "desktop-send-ui-refresh",
|
||||
UseSdkPasswordGenerators = "pm-19976-use-sdk-password-generators",
|
||||
ChromiumImporterWithABE = "pm-25855-chromium-importer-abe",
|
||||
SendUIRefresh = "pm-28175-send-ui-refresh",
|
||||
|
||||
/* DIRT */
|
||||
EventManagementForDataDogAndCrowdStrike = "event-management-for-datadog-and-crowdstrike",
|
||||
@@ -110,6 +111,7 @@ export const DefaultFeatureFlagValue = {
|
||||
[FeatureFlag.DesktopSendUIRefresh]: FALSE,
|
||||
[FeatureFlag.UseSdkPasswordGenerators]: FALSE,
|
||||
[FeatureFlag.ChromiumImporterWithABE]: FALSE,
|
||||
[FeatureFlag.SendUIRefresh]: FALSE,
|
||||
|
||||
/* DIRT */
|
||||
[FeatureFlag.EventManagementForDataDogAndCrowdStrike]: FALSE,
|
||||
|
||||
@@ -174,4 +174,19 @@ export class SendAddEditDialogComponent {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the send add/edit dialog in a drawer
|
||||
* @param dialogService Instance of the DialogService.
|
||||
* @param params The parameters for the drawer.
|
||||
* @returns The drawer result.
|
||||
*/
|
||||
static openDrawer(dialogService: DialogService, params: SendItemDialogParams) {
|
||||
return dialogService.openDrawer<SendItemDialogResult, SendItemDialogParams>(
|
||||
SendAddEditDialogComponent,
|
||||
{
|
||||
data: params,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user