mirror of
https://github.com/bitwarden/browser
synced 2026-01-21 11:53:34 +00:00
[PM-19079] [PM-28168] add edit desktop migration (#18294)
The goal of this PR is to migrate the Desktop Send-v2 component from the AddEditComponent to now use to shared SendAddEditDialogComponent from @bitwarden/send-ui library --------- Co-authored-by: William Martin <contact@willmartian.com> Co-authored-by: Hinton <hinton@users.noreply.github.com>
This commit is contained in:
@@ -1,21 +1,19 @@
|
||||
<div class="tw-my-4 tw-px-4">
|
||||
<bit-header [title]="resolvedTitle()" [icon]="icon()">
|
||||
<ng-container slot="breadcrumbs">
|
||||
<ng-content select="[slot=breadcrumbs]" />
|
||||
</ng-container>
|
||||
<bit-header [title]="resolvedTitle()" [icon]="icon()">
|
||||
<ng-container slot="breadcrumbs">
|
||||
<ng-content select="[slot=breadcrumbs]" />
|
||||
</ng-container>
|
||||
|
||||
<ng-content />
|
||||
<ng-content />
|
||||
|
||||
<ng-container slot="title-suffix">
|
||||
<ng-content select="[slot=title-suffix]" />
|
||||
</ng-container>
|
||||
<ng-container slot="title-suffix">
|
||||
<ng-content select="[slot=title-suffix]" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container slot="secondary">
|
||||
<ng-content select="[slot=secondary]" />
|
||||
</ng-container>
|
||||
<ng-container slot="secondary">
|
||||
<ng-content select="[slot=secondary]" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container slot="tabs">
|
||||
<ng-content select="[slot=tabs]" />
|
||||
</ng-container>
|
||||
</bit-header>
|
||||
</div>
|
||||
<ng-container slot="tabs">
|
||||
<ng-content select="[slot=tabs]" />
|
||||
</ng-container>
|
||||
</bit-header>
|
||||
|
||||
@@ -1,55 +1,25 @@
|
||||
<div id="sends" class="vault">
|
||||
<div class="send-items-panel tw-w-2/5">
|
||||
<!-- Header with Send title and New button -->
|
||||
<app-header>
|
||||
@if (!disableSend()) {
|
||||
<tools-new-send-dropdown-v2 buttonType="primary" (addSend)="addSend($event)" />
|
||||
}
|
||||
</app-header>
|
||||
<div class="tw-my-4 tw-px-4">
|
||||
<!-- Send List Component -->
|
||||
<tools-send-list
|
||||
[sends]="filteredSends()"
|
||||
[loading]="loading()"
|
||||
[disableSend]="disableSend()"
|
||||
[listState]="listState()"
|
||||
[searchText]="currentSearchText()"
|
||||
(editSend)="onEditSend($event)"
|
||||
(copySend)="onCopySend($event)"
|
||||
(deleteSend)="onDeleteSend($event)"
|
||||
(removePassword)="onRemovePassword($event)"
|
||||
>
|
||||
<tools-new-send-dropdown-v2
|
||||
slot="empty-button"
|
||||
[hideIcon]="true"
|
||||
buttonType="primary"
|
||||
(addSend)="addSend($event)"
|
||||
/>
|
||||
</tools-send-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit/Add panel (right side) -->
|
||||
@if (action() == "add" || action() == "edit") {
|
||||
<app-send-add-edit
|
||||
id="addEdit"
|
||||
class="details"
|
||||
[sendId]="sendId()"
|
||||
[type]="selectedSendType()"
|
||||
(onSavedSend)="savedSend($event)"
|
||||
(onCancelled)="closeEditPanel()"
|
||||
(onDeletedSend)="closeEditPanel()"
|
||||
></app-send-add-edit>
|
||||
<!-- Header with Send title and New button -->
|
||||
<app-header>
|
||||
@if (!disableSend()) {
|
||||
<tools-new-send-dropdown-v2 buttonType="primary" (addSend)="addSend($event)" />
|
||||
}
|
||||
|
||||
<!-- Bitwarden logo (shown when no send is selected) -->
|
||||
@if (!action()) {
|
||||
<div class="logo tw-w-1/2">
|
||||
<div class="content">
|
||||
<div class="inner-content">
|
||||
<img class="logo-image" alt="Bitwarden" aria-hidden="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</app-header>
|
||||
<!-- Send List Component -->
|
||||
<tools-send-list
|
||||
[sends]="filteredSends()"
|
||||
[loading]="loading()"
|
||||
[disableSend]="disableSend()"
|
||||
[listState]="listState()"
|
||||
[searchText]="currentSearchText()"
|
||||
(editSend)="onEditSend($event)"
|
||||
(copySend)="onCopySend($event)"
|
||||
(deleteSend)="onDeleteSend($event)"
|
||||
(removePassword)="onRemovePassword($event)"
|
||||
>
|
||||
<tools-new-send-dropdown-v2
|
||||
slot="empty-button"
|
||||
[hideIcon]="true"
|
||||
buttonType="primary"
|
||||
(addSend)="addSend($event)"
|
||||
/>
|
||||
</tools-send-list>
|
||||
|
||||
@@ -20,11 +20,16 @@ import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { SendType } from "@bitwarden/common/tools/send/types/send-type";
|
||||
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
||||
import { SearchService } from "@bitwarden/common/vault/abstractions/search.service";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { SendItemsService, SendListFiltersService } from "@bitwarden/send-ui";
|
||||
|
||||
import { AddEditComponent } from "../send/add-edit.component";
|
||||
import {
|
||||
SendItemsService,
|
||||
SendListFiltersService,
|
||||
DefaultSendFormConfigService,
|
||||
SendAddEditDialogComponent,
|
||||
SendFormConfig,
|
||||
} from "@bitwarden/send-ui";
|
||||
|
||||
import { SendV2Component } from "./send-v2.component";
|
||||
|
||||
@@ -37,12 +42,34 @@ describe("SendV2Component", () => {
|
||||
let sendItemsService: MockProxy<SendItemsService>;
|
||||
let sendListFiltersService: MockProxy<SendListFiltersService>;
|
||||
let changeDetectorRef: MockProxy<ChangeDetectorRef>;
|
||||
let sendFormConfigService: MockProxy<DefaultSendFormConfigService>;
|
||||
let dialogService: MockProxy<DialogService>;
|
||||
let environmentService: MockProxy<EnvironmentService>;
|
||||
let platformUtilsService: MockProxy<PlatformUtilsService>;
|
||||
let sendApiService: MockProxy<SendApiService>;
|
||||
let toastService: MockProxy<ToastService>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
sendService = mock<SendService>();
|
||||
accountService = mock<AccountService>();
|
||||
policyService = mock<PolicyService>();
|
||||
changeDetectorRef = mock<ChangeDetectorRef>();
|
||||
sendFormConfigService = mock<DefaultSendFormConfigService>();
|
||||
dialogService = mock<DialogService>();
|
||||
environmentService = mock<EnvironmentService>();
|
||||
platformUtilsService = mock<PlatformUtilsService>();
|
||||
sendApiService = mock<SendApiService>();
|
||||
toastService = mock<ToastService>();
|
||||
i18nService = mock<I18nService>();
|
||||
|
||||
// Setup environmentService mock
|
||||
environmentService.getEnvironment.mockResolvedValue({
|
||||
getSendUrl: () => "https://send.bitwarden.com/#/",
|
||||
} as any);
|
||||
|
||||
// Setup i18nService mock
|
||||
i18nService.t.mockImplementation((key: string) => key);
|
||||
|
||||
// Mock SendItemsService with all required observables
|
||||
sendItemsService = mock<SendItemsService>();
|
||||
@@ -71,15 +98,16 @@ describe("SendV2Component", () => {
|
||||
providers: [
|
||||
provideNoopAnimations(),
|
||||
{ provide: SendService, useValue: sendService },
|
||||
{ provide: I18nService, useValue: mock<I18nService>() },
|
||||
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||
{ provide: EnvironmentService, useValue: mock<EnvironmentService>() },
|
||||
{ provide: I18nService, useValue: i18nService },
|
||||
{ provide: PlatformUtilsService, useValue: platformUtilsService },
|
||||
{ provide: EnvironmentService, useValue: environmentService },
|
||||
{ provide: SearchService, useValue: mockSearchService },
|
||||
{ provide: PolicyService, useValue: policyService },
|
||||
{ provide: LogService, useValue: mock<LogService>() },
|
||||
{ provide: SendApiService, useValue: mock<SendApiService>() },
|
||||
{ provide: DialogService, useValue: mock<DialogService>() },
|
||||
{ provide: ToastService, useValue: mock<ToastService>() },
|
||||
{ provide: SendApiService, useValue: sendApiService },
|
||||
{ provide: DialogService, useValue: dialogService },
|
||||
{ provide: DefaultSendFormConfigService, useValue: sendFormConfigService },
|
||||
{ provide: ToastService, useValue: toastService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{ provide: SendItemsService, useValue: sendItemsService },
|
||||
{ provide: SendListFiltersService, useValue: sendListFiltersService },
|
||||
@@ -97,7 +125,16 @@ describe("SendV2Component", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compileComponents();
|
||||
})
|
||||
.overrideComponent(SendV2Component, {
|
||||
set: {
|
||||
providers: [
|
||||
{ provide: DefaultSendFormConfigService, useValue: sendFormConfigService },
|
||||
{ provide: PremiumUpgradePromptService, useValue: mock<PremiumUpgradePromptService>() },
|
||||
],
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SendV2Component);
|
||||
component = fixture.componentInstance;
|
||||
@@ -107,103 +144,83 @@ describe("SendV2Component", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it("initializes with correct default action", () => {
|
||||
expect(component.action()).toBe("");
|
||||
});
|
||||
|
||||
describe("addSend", () => {
|
||||
it("sets action to Add", async () => {
|
||||
await component.addSend(SendType.Text);
|
||||
expect(component.action()).toBe("add");
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("calls resetAndLoad on addEditComponent when component exists", async () => {
|
||||
const mockAddEdit = mock<AddEditComponent>();
|
||||
mockAddEdit.resetAndLoad.mockResolvedValue();
|
||||
jest.spyOn(component as any, "addEditComponent").mockReturnValue(mockAddEdit);
|
||||
it("opens dialog with correct config for Text send", async () => {
|
||||
const mockConfig = { mode: "add", sendType: SendType.Text } as SendFormConfig;
|
||||
const mockDialogRef = { closed: of(true) };
|
||||
|
||||
await component.addSend(SendType.Text);
|
||||
sendFormConfigService.buildConfig.mockResolvedValue(mockConfig);
|
||||
const openDrawerSpy = jest
|
||||
.spyOn(SendAddEditDialogComponent, "openDrawer")
|
||||
.mockReturnValue(mockDialogRef as any);
|
||||
|
||||
expect(mockAddEdit.resetAndLoad).toHaveBeenCalled();
|
||||
await component["addSend"](SendType.Text);
|
||||
|
||||
expect(sendFormConfigService.buildConfig).toHaveBeenCalledWith(
|
||||
"add",
|
||||
undefined,
|
||||
SendType.Text,
|
||||
);
|
||||
expect(openDrawerSpy).toHaveBeenCalled();
|
||||
expect(openDrawerSpy.mock.calls[0][1]).toEqual({
|
||||
formConfig: mockConfig,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not throw when addEditComponent is null", async () => {
|
||||
jest.spyOn(component as any, "addEditComponent").mockReturnValue(undefined);
|
||||
await expect(component.addSend(SendType.Text)).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
it("opens dialog with correct config for File send", async () => {
|
||||
const mockConfig = { mode: "add", sendType: SendType.File } as SendFormConfig;
|
||||
const mockDialogRef = { closed: of(true) };
|
||||
|
||||
describe("closeEditPanel", () => {
|
||||
it("resets action to None", () => {
|
||||
component["action"].set("edit");
|
||||
component["sendId"].set("test-id");
|
||||
sendFormConfigService.buildConfig.mockResolvedValue(mockConfig);
|
||||
const openDrawerSpy = jest
|
||||
.spyOn(SendAddEditDialogComponent, "openDrawer")
|
||||
.mockReturnValue(mockDialogRef as any);
|
||||
|
||||
component["closeEditPanel"]();
|
||||
await component["addSend"](SendType.File);
|
||||
|
||||
expect(component["action"]()).toBe("");
|
||||
expect(component["sendId"]()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("savedSend", () => {
|
||||
it("selects the saved send", async () => {
|
||||
jest.spyOn(component as any, "selectSend").mockResolvedValue();
|
||||
|
||||
const mockSend = new SendView();
|
||||
mockSend.id = "saved-send-id";
|
||||
|
||||
await component["savedSend"](mockSend);
|
||||
|
||||
expect(component["selectSend"]).toHaveBeenCalledWith("saved-send-id");
|
||||
expect(sendFormConfigService.buildConfig).toHaveBeenCalledWith(
|
||||
"add",
|
||||
undefined,
|
||||
SendType.File,
|
||||
);
|
||||
expect(openDrawerSpy).toHaveBeenCalled();
|
||||
expect(openDrawerSpy.mock.calls[0][1]).toEqual({
|
||||
formConfig: mockConfig,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("selectSend", () => {
|
||||
it("sets action to Edit and updates sendId", async () => {
|
||||
await component["selectSend"]("new-send-id");
|
||||
|
||||
expect(component["action"]()).toBe("edit");
|
||||
expect(component["sendId"]()).toBe("new-send-id");
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("updates addEditComponent when it exists", async () => {
|
||||
const mockAddEdit = mock<AddEditComponent>();
|
||||
mockAddEdit.refresh.mockResolvedValue();
|
||||
jest.spyOn(component as any, "addEditComponent").mockReturnValue(mockAddEdit);
|
||||
it("opens dialog with correct config for editing send", async () => {
|
||||
const mockConfig = { mode: "edit", sendId: "test-send-id" } as SendFormConfig;
|
||||
const mockDialogRef = { closed: of(true) };
|
||||
|
||||
sendFormConfigService.buildConfig.mockResolvedValue(mockConfig);
|
||||
const openDrawerSpy = jest
|
||||
.spyOn(SendAddEditDialogComponent, "openDrawer")
|
||||
.mockReturnValue(mockDialogRef as any);
|
||||
|
||||
await component["selectSend"]("test-send-id");
|
||||
|
||||
expect(mockAddEdit.sendId).toBe("test-send-id");
|
||||
expect(mockAddEdit.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not reload if same send is already selected in edit mode", async () => {
|
||||
const mockAddEdit = mock<AddEditComponent>();
|
||||
jest.spyOn(component as any, "addEditComponent").mockReturnValue(mockAddEdit);
|
||||
component["sendId"].set("same-id");
|
||||
component["action"].set("edit");
|
||||
|
||||
await component["selectSend"]("same-id");
|
||||
|
||||
expect(mockAddEdit.refresh).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reloads if selecting different send", async () => {
|
||||
const mockAddEdit = mock<AddEditComponent>();
|
||||
mockAddEdit.refresh.mockResolvedValue();
|
||||
jest.spyOn(component as any, "addEditComponent").mockReturnValue(mockAddEdit);
|
||||
component["sendId"].set("old-id");
|
||||
component["action"].set("edit");
|
||||
|
||||
await component["selectSend"]("new-id");
|
||||
|
||||
expect(mockAddEdit.refresh).toHaveBeenCalled();
|
||||
expect(sendFormConfigService.buildConfig).toHaveBeenCalledWith("edit", "test-send-id");
|
||||
expect(openDrawerSpy).toHaveBeenCalled();
|
||||
expect(openDrawerSpy.mock.calls[0][1]).toEqual({
|
||||
formConfig: mockConfig,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("onEditSend", () => {
|
||||
it("selects the send for editing", async () => {
|
||||
jest.spyOn(component as any, "selectSend").mockResolvedValue();
|
||||
jest.spyOn(component as any, "selectSend").mockResolvedValue(undefined);
|
||||
const mockSend = new SendView();
|
||||
mockSend.id = "edit-send-id";
|
||||
|
||||
@@ -212,4 +229,25 @@ describe("SendV2Component", () => {
|
||||
expect(component["selectSend"]).toHaveBeenCalledWith("edit-send-id");
|
||||
});
|
||||
});
|
||||
|
||||
describe("onCopySend", () => {
|
||||
it("copies send link to clipboard and shows success toast", async () => {
|
||||
const mockSend = {
|
||||
accessId: "test-access-id",
|
||||
urlB64Key: "test-key",
|
||||
} as SendView;
|
||||
|
||||
await component["onCopySend"](mockSend);
|
||||
|
||||
expect(environmentService.getEnvironment).toHaveBeenCalled();
|
||||
expect(platformUtilsService.copyToClipboard).toHaveBeenCalledWith(
|
||||
"https://send.bitwarden.com/#/test-access-id/test-key",
|
||||
);
|
||||
expect(toastService.showToast).toHaveBeenCalledWith({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: expect.any(String),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,14 +4,11 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
inject,
|
||||
signal,
|
||||
viewChild,
|
||||
} from "@angular/core";
|
||||
import { toSignal } from "@angular/core/rxjs-interop";
|
||||
import { combineLatest, map, switchMap } from "rxjs";
|
||||
import { combineLatest, map, switchMap, lastValueFrom } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
@@ -25,6 +22,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendType } from "@bitwarden/common/tools/send/types/send-type";
|
||||
import { SendId } from "@bitwarden/common/types/guid";
|
||||
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
||||
import { ButtonModule, DialogService, ToastService } from "@bitwarden/components";
|
||||
import {
|
||||
@@ -32,34 +30,24 @@ import {
|
||||
SendItemsService,
|
||||
SendListComponent,
|
||||
SendListState,
|
||||
SendAddEditDialogComponent,
|
||||
DefaultSendFormConfigService,
|
||||
} from "@bitwarden/send-ui";
|
||||
|
||||
import { DesktopPremiumUpgradePromptService } from "../../../services/desktop-premium-upgrade-prompt.service";
|
||||
import { DesktopHeaderComponent } from "../../layout/header";
|
||||
import { AddEditComponent } from "../send/add-edit.component";
|
||||
|
||||
const Action = Object.freeze({
|
||||
/** No action is currently active. */
|
||||
None: "",
|
||||
/** The user is adding a new Send. */
|
||||
Add: "add",
|
||||
/** The user is editing an existing Send. */
|
||||
Edit: "edit",
|
||||
} as const);
|
||||
|
||||
type Action = (typeof Action)[keyof typeof Action];
|
||||
|
||||
@Component({
|
||||
selector: "app-send-v2",
|
||||
imports: [
|
||||
JslibModule,
|
||||
ButtonModule,
|
||||
AddEditComponent,
|
||||
SendListComponent,
|
||||
NewSendDropdownV2Component,
|
||||
DesktopHeaderComponent,
|
||||
],
|
||||
providers: [
|
||||
DefaultSendFormConfigService,
|
||||
{
|
||||
provide: PremiumUpgradePromptService,
|
||||
useClass: DesktopPremiumUpgradePromptService,
|
||||
@@ -69,22 +57,17 @@ type Action = (typeof Action)[keyof typeof Action];
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SendV2Component {
|
||||
protected readonly addEditComponent = viewChild(AddEditComponent);
|
||||
|
||||
protected readonly sendId = signal<string | null>(null);
|
||||
protected readonly action = signal<Action>(Action.None);
|
||||
private readonly selectedSendTypeOverride = signal<SendType | undefined>(undefined);
|
||||
|
||||
private sendFormConfigService = inject(DefaultSendFormConfigService);
|
||||
private sendItemsService = inject(SendItemsService);
|
||||
private policyService = inject(PolicyService);
|
||||
private accountService = inject(AccountService);
|
||||
private i18nService = inject(I18nService);
|
||||
private platformUtilsService = inject(PlatformUtilsService);
|
||||
private environmentService = inject(EnvironmentService);
|
||||
private logService = inject(LogService);
|
||||
private sendApiService = inject(SendApiService);
|
||||
private dialogService = inject(DialogService);
|
||||
private toastService = inject(ToastService);
|
||||
private logService = inject(LogService);
|
||||
private cdr = inject(ChangeDetectorRef);
|
||||
|
||||
protected readonly filteredSends = toSignal(this.sendItemsService.filteredAndSortedSends$, {
|
||||
@@ -137,53 +120,27 @@ export class SendV2Component {
|
||||
}
|
||||
|
||||
protected async addSend(type: SendType): Promise<void> {
|
||||
this.action.set(Action.Add);
|
||||
this.sendId.set(null);
|
||||
this.selectedSendTypeOverride.set(type);
|
||||
const formConfig = await this.sendFormConfigService.buildConfig("add", undefined, type);
|
||||
|
||||
const component = this.addEditComponent();
|
||||
if (component) {
|
||||
await component.resetAndLoad();
|
||||
}
|
||||
const dialogRef = SendAddEditDialogComponent.openDrawer(this.dialogService, {
|
||||
formConfig,
|
||||
});
|
||||
|
||||
await lastValueFrom(dialogRef.closed);
|
||||
}
|
||||
|
||||
protected closeEditPanel(): void {
|
||||
this.action.set(Action.None);
|
||||
this.sendId.set(null);
|
||||
this.selectedSendTypeOverride.set(undefined);
|
||||
protected async selectSend(sendId: SendId): Promise<void> {
|
||||
const formConfig = await this.sendFormConfigService.buildConfig("edit", sendId);
|
||||
|
||||
const dialogRef = SendAddEditDialogComponent.openDrawer(this.dialogService, {
|
||||
formConfig,
|
||||
});
|
||||
|
||||
await lastValueFrom(dialogRef.closed);
|
||||
}
|
||||
|
||||
protected async savedSend(send: SendView): Promise<void> {
|
||||
await this.selectSend(send.id);
|
||||
}
|
||||
|
||||
protected async selectSend(sendId: string): Promise<void> {
|
||||
if (sendId === this.sendId() && this.action() === Action.Edit) {
|
||||
return;
|
||||
}
|
||||
this.action.set(Action.Edit);
|
||||
this.sendId.set(sendId);
|
||||
const component = this.addEditComponent();
|
||||
if (component) {
|
||||
component.sendId = sendId;
|
||||
await component.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly selectedSendType = computed(() => {
|
||||
const action = this.action();
|
||||
const typeOverride = this.selectedSendTypeOverride();
|
||||
|
||||
if (action === Action.Add && typeOverride !== undefined) {
|
||||
return typeOverride;
|
||||
}
|
||||
|
||||
const sendId = this.sendId();
|
||||
return this.filteredSends().find((s) => s.id === sendId)?.type;
|
||||
});
|
||||
|
||||
protected async onEditSend(send: SendView): Promise<void> {
|
||||
await this.selectSend(send.id);
|
||||
await this.selectSend(send.id as SendId);
|
||||
}
|
||||
|
||||
protected async onCopySend(send: SendView): Promise<void> {
|
||||
@@ -219,11 +176,6 @@ export class SendV2Component {
|
||||
title: null,
|
||||
message: this.i18nService.t("removedPassword"),
|
||||
});
|
||||
|
||||
if (this.sendId() === send.id) {
|
||||
this.sendId.set(null);
|
||||
await this.selectSend(send.id);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
@@ -247,7 +199,5 @@ export class SendV2Component {
|
||||
title: null,
|
||||
message: this.i18nService.t("deletedSend"),
|
||||
});
|
||||
|
||||
this.closeEditPanel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,70 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"deletionDateDescV2": {
|
||||
"message": "The Send will be permanently deleted on this date.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"fileToShare": {
|
||||
"message": "File to share"
|
||||
},
|
||||
"hideTextByDefault": {
|
||||
"message": "Hide text by default"
|
||||
},
|
||||
"hideYourEmail": {
|
||||
"message": "Hide your email address from viewers."
|
||||
},
|
||||
"limitSendViews": {
|
||||
"message": "Limit views"
|
||||
},
|
||||
"limitSendViewsCount": {
|
||||
"message": "$ACCESSCOUNT$ views left",
|
||||
"description": "Displayed under the limit views field on Send",
|
||||
"placeholders": {
|
||||
"accessCount": {
|
||||
"content": "$1",
|
||||
"example": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"limitSendViewsHint": {
|
||||
"message": "No one can view this Send after the limit is reached.",
|
||||
"description": "Displayed under the limit views field on Send"
|
||||
},
|
||||
"privateNote": {
|
||||
"message": "Private note"
|
||||
},
|
||||
"sendDetails": {
|
||||
"message": "Send details",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"sendPasswordDescV3": {
|
||||
"message": "Add an optional password for recipients to access this Send.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"sendTypeTextToShare": {
|
||||
"message": "Text to share"
|
||||
},
|
||||
"newItemHeaderTextSend": {
|
||||
"message": "New Text Send",
|
||||
"description": "Header for new text send"
|
||||
},
|
||||
"newItemHeaderFileSend": {
|
||||
"message": "New File Send",
|
||||
"description": "Header for new file send"
|
||||
},
|
||||
"editItemHeaderTextSend": {
|
||||
"message": "Edit Text Send",
|
||||
"description": "Header for edit text send"
|
||||
},
|
||||
"editItemHeaderFileSend": {
|
||||
"message": "Edit File Send",
|
||||
"description": "Header for edit file send"
|
||||
},
|
||||
"deleteSendPermanentConfirmation": {
|
||||
"message": "Are you sure you want to permanently delete this Send?",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"new": {
|
||||
"message": "New",
|
||||
"description": "for adding new items"
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Desktop UI Migration
|
||||
*
|
||||
* These are temporary styles during the desktop ui migration.
|
||||
**/
|
||||
|
||||
/**
|
||||
* This removes any padding applied by the bit-layout to content.
|
||||
* This should be revisited once the table is migrated, and again once drawers are migrated.
|
||||
**/
|
||||
bit-layout {
|
||||
#main-content {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Send list panel styling for send-v2 component
|
||||
* Temporary during migration - width handled by tw-w-2/5
|
||||
**/
|
||||
.vault > .send-items-panel {
|
||||
order: 2;
|
||||
min-width: 200px;
|
||||
border-right: 1px solid;
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed("backgroundColor");
|
||||
border-right-color: themed("borderColor");
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,5 @@
|
||||
@import "left-nav.scss";
|
||||
@import "loading.scss";
|
||||
@import "plugins.scss";
|
||||
@import "migration.scss";
|
||||
@import "../../../../libs/angular/src/scss/icons.scss";
|
||||
@import "../../../../libs/components/src/multi-select/scss/bw.theme";
|
||||
|
||||
Reference in New Issue
Block a user