mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-21 11:35:34 +01:00
[PM-9869] Create SendFormContainer (#10147)
* Move SendV2component into send-v2 subFolder * Create SendFormContainer and related services * Add initial SendFormComponent which uses the SendFormContainer * Remove AdditionalOptionsSectionComponent which will be added with a future PR * Add libs/tools/send to root tsconfig * Register libs/tools/send/send-ui with root jest.config.js * Register libs/tools/send/send-ui with root tailwind.config.js * Fix service injection on DefaultSendFormService --------- Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
parent
beeb0354fd
commit
1320d96cb4
@ -6,6 +6,8 @@ const config: StorybookConfig = {
|
||||
stories: [
|
||||
"../libs/auth/src/**/*.mdx",
|
||||
"../libs/auth/src/**/*.stories.@(js|jsx|ts|tsx)",
|
||||
"../libs/tools/send/send-ui/src/**/*.mdx",
|
||||
"../libs/tools/send/send-ui/src/**/*.stories.@(js|jsx|ts|tsx)",
|
||||
"../libs/vault/src/**/*.mdx",
|
||||
"../libs/vault/src/**/*.stories.@(js|jsx|ts|tsx)",
|
||||
"../libs/components/src/**/*.mdx",
|
||||
|
@ -50,7 +50,7 @@ import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/pass
|
||||
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
||||
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
||||
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
||||
import { SendV2Component } from "../tools/popup/send/send-v2.component";
|
||||
import { SendV2Component } from "../tools/popup/send-v2/send-v2.component";
|
||||
import { AboutPageV2Component } from "../tools/popup/settings/about-page/about-page-v2.component";
|
||||
import { AboutPageComponent } from "../tools/popup/settings/about-page/about-page.component";
|
||||
import { MoreFromBitwardenPageV2Component } from "../tools/popup/settings/about-page/more-from-bitwarden-page-v2.component";
|
||||
|
@ -35,6 +35,7 @@ module.exports = {
|
||||
"<rootDir>/libs/tools/generator/extensions/history/jest.config.js",
|
||||
"<rootDir>/libs/tools/generator/extensions/legacy/jest.config.js",
|
||||
"<rootDir>/libs/tools/generator/extensions/navigation/jest.config.js",
|
||||
"<rootDir>/libs/tools/send/send-ui/jest.config.js",
|
||||
"<rootDir>/libs/importer/jest.config.js",
|
||||
"<rootDir>/libs/platform/jest.config.js",
|
||||
"<rootDir>/libs/node/jest.config.js",
|
||||
|
@ -8,4 +8,5 @@ export type CollectionId = Opaque<string, "CollectionId">;
|
||||
export type ProviderId = Opaque<string, "ProviderId">;
|
||||
export type PolicyId = Opaque<string, "PolicyId">;
|
||||
export type CipherId = Opaque<string, "CipherId">;
|
||||
export type SendId = Opaque<string, "SendId">;
|
||||
export type IndexedEntityId = Opaque<string, "IndexedEntityId">;
|
||||
|
@ -1,2 +1,3 @@
|
||||
export * from "./icons";
|
||||
export * from "./send-form";
|
||||
export { NewSendDropdownComponent } from "./new-send-dropdown/new-send-dropdown.component";
|
||||
|
@ -0,0 +1,93 @@
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
||||
import { SendId } from "@bitwarden/common/types/guid";
|
||||
|
||||
/**
|
||||
* The mode of the add/edit form.
|
||||
* - `add` - The form is creating a new send.
|
||||
* - `edit` - The form is editing an existing send.
|
||||
* - `partial-edit` - The form is editing an existing send, but only the favorite/folder fields
|
||||
*/
|
||||
export type SendFormMode = "add" | "edit" | "partial-edit";
|
||||
|
||||
/**
|
||||
* Base configuration object for the send form. Includes all common fields.
|
||||
*/
|
||||
type BaseSendFormConfig = {
|
||||
/**
|
||||
* The mode of the form.
|
||||
*/
|
||||
mode: SendFormMode;
|
||||
|
||||
/**
|
||||
* The type of send to create/edit.
|
||||
*/
|
||||
sendType: SendType;
|
||||
|
||||
/**
|
||||
* Flag to indicate if the user is allowed to create sends. If false, configuration must
|
||||
* supply a list of organizations that the user can create sends in.
|
||||
*/
|
||||
areSendsAllowed: boolean;
|
||||
|
||||
/**
|
||||
* The original send that is being edited or cloned. This can be undefined when creating a new send.
|
||||
*/
|
||||
originalSend?: Send;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration object for the send form when editing an existing send.
|
||||
*/
|
||||
type ExistingSendConfig = BaseSendFormConfig & {
|
||||
mode: "edit" | "partial-edit";
|
||||
originalSend: Send;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration object for the send form when creating a completely new send.
|
||||
*/
|
||||
type CreateNewSendConfig = BaseSendFormConfig & {
|
||||
mode: "add";
|
||||
};
|
||||
|
||||
type CombinedAddEditConfig = ExistingSendConfig | CreateNewSendConfig;
|
||||
|
||||
/**
|
||||
* Configuration object for the send form when personal ownership is allowed.
|
||||
*/
|
||||
type SendsAllowed = CombinedAddEditConfig & {
|
||||
areSendsAllowed: true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration object for the send form when Sends are not allowed by an organization.
|
||||
* Organizations must be provided.
|
||||
*/
|
||||
type SendsNotAllowed = CombinedAddEditConfig & {
|
||||
areSendsAllowed: false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration object for the send form.
|
||||
* Determines the behavior of the form and the controls that are displayed/enabled.
|
||||
*/
|
||||
export type SendFormConfig = SendsAllowed | SendsNotAllowed;
|
||||
|
||||
/**
|
||||
* Service responsible for building the configuration object for the send form.
|
||||
*/
|
||||
export abstract class SendFormConfigService {
|
||||
/**
|
||||
* Builds the configuration for the send form using the specified mode, sendId, and sendType.
|
||||
* The other configuration fields will be fetched from their respective services.
|
||||
* @param mode
|
||||
* @param sendId
|
||||
* @param sendType
|
||||
*/
|
||||
abstract buildConfig(
|
||||
mode: SendFormMode,
|
||||
sendId?: SendId,
|
||||
sendType?: SendType,
|
||||
): Promise<SendFormConfig>;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
|
||||
import { SendFormConfig } from "./send-form-config.service";
|
||||
|
||||
/**
|
||||
* Service to save the send using the correct endpoint(s) and encapsulating the logic for decrypting the send.
|
||||
*
|
||||
* This service should only be used internally by the SendFormComponent.
|
||||
*/
|
||||
export abstract class SendFormService {
|
||||
/**
|
||||
* Helper to decrypt a send and avoid the need to call the send service directly.
|
||||
* (useful for mocking tests/storybook).
|
||||
*/
|
||||
abstract decryptSend(send: Send): Promise<SendView>;
|
||||
|
||||
/**
|
||||
* Saves the new or modified send with the server.
|
||||
*/
|
||||
abstract saveSend(
|
||||
send: SendView,
|
||||
file: File | ArrayBuffer,
|
||||
config: SendFormConfig,
|
||||
): Promise<SendView>;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<form [id]="formId" [formGroup]="sendForm" [bitSubmit]="submit">
|
||||
<!-- TODO: Should we show a loading spinner here? Or emit a ready event for the container to handle loading state -->
|
||||
<ng-container *ngIf="!loading"> </ng-container>
|
||||
</form>
|
@ -0,0 +1,210 @@
|
||||
import { NgIf } from "@angular/common";
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
DestroyRef,
|
||||
EventEmitter,
|
||||
forwardRef,
|
||||
inject,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
BitSubmitDirective,
|
||||
ButtonComponent,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
ItemModule,
|
||||
SectionComponent,
|
||||
SelectModule,
|
||||
ToastService,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { SendFormConfig } from "../abstractions/send-form-config.service";
|
||||
import { SendFormService } from "../abstractions/send-form.service";
|
||||
import { SendForm, SendFormContainer } from "../send-form-container";
|
||||
|
||||
@Component({
|
||||
selector: "tools-send-form",
|
||||
templateUrl: "./send-form.component.html",
|
||||
standalone: true,
|
||||
providers: [
|
||||
{
|
||||
provide: SendFormContainer,
|
||||
useExisting: forwardRef(() => SendFormComponent),
|
||||
},
|
||||
],
|
||||
imports: [
|
||||
AsyncActionsModule,
|
||||
CardComponent,
|
||||
SectionComponent,
|
||||
TypographyModule,
|
||||
ItemModule,
|
||||
FormFieldModule,
|
||||
ReactiveFormsModule,
|
||||
SelectModule,
|
||||
NgIf,
|
||||
],
|
||||
})
|
||||
export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, SendFormContainer {
|
||||
@ViewChild(BitSubmitDirective)
|
||||
private bitSubmit: BitSubmitDirective;
|
||||
private destroyRef = inject(DestroyRef);
|
||||
private _firstInitialized = false;
|
||||
|
||||
/**
|
||||
* The form ID to use for the form. Used to connect it to a submit button.
|
||||
*/
|
||||
@Input({ required: true }) formId: string;
|
||||
|
||||
/**
|
||||
* The configuration for the add/edit form. Used to determine which controls are shown and what values are available.
|
||||
*/
|
||||
@Input({ required: true }) config: SendFormConfig;
|
||||
|
||||
/**
|
||||
* Optional submit button that will be disabled or marked as loading when the form is submitting.
|
||||
*/
|
||||
@Input()
|
||||
submitBtn?: ButtonComponent;
|
||||
|
||||
/**
|
||||
* Event emitted when the send is saved successfully.
|
||||
*/
|
||||
@Output() sendSaved = new EventEmitter<SendView>();
|
||||
|
||||
/**
|
||||
* The original send being edited or cloned. Null for add mode.
|
||||
*/
|
||||
originalSendView: SendView | null;
|
||||
|
||||
/**
|
||||
* The form group for the send. Starts empty and is populated by child components via the `registerChildForm` method.
|
||||
* @protected
|
||||
*/
|
||||
protected sendForm = this.formBuilder.group<SendForm>({});
|
||||
|
||||
/**
|
||||
* The value of the updated send. Starts as a new send and is updated
|
||||
* by child components via the `patchSend` method.
|
||||
* @protected
|
||||
*/
|
||||
protected updatedSendView: SendView | null;
|
||||
protected loading: boolean = true;
|
||||
|
||||
SendType = SendType;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this.submitBtn) {
|
||||
this.bitSubmit.loading$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((loading) => {
|
||||
this.submitBtn.loading = loading;
|
||||
});
|
||||
|
||||
this.bitSubmit.disabled$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((disabled) => {
|
||||
this.submitBtn.disabled = disabled;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a child form group with the parent form group. Used by child components to add their form groups to
|
||||
* the parent form for validation.
|
||||
* @param name - The name of the form group.
|
||||
* @param group - The form group to add.
|
||||
*/
|
||||
registerChildForm<K extends keyof SendForm>(
|
||||
name: K,
|
||||
group: Exclude<SendForm[K], undefined>,
|
||||
): void {
|
||||
this.sendForm.setControl(name, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches the updated send with the provided partial senbd. Used by child components to update the send
|
||||
* as their form values change.
|
||||
* @param send
|
||||
*/
|
||||
patchSend(send: Partial<SendView>): void {
|
||||
this.updatedSendView = Object.assign(this.updatedSendView, send);
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to re-initialize the form when the config is updated.
|
||||
*/
|
||||
async ngOnChanges() {
|
||||
// Avoid re-initializing the form on the first change detection cycle.
|
||||
if (this._firstInitialized) {
|
||||
await this.init();
|
||||
}
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.init();
|
||||
this._firstInitialized = true;
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.loading = true;
|
||||
this.updatedSendView = new SendView();
|
||||
this.originalSendView = null;
|
||||
this.sendForm.reset();
|
||||
|
||||
if (this.config == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.config.mode !== "add") {
|
||||
if (this.config.originalSend == null) {
|
||||
throw new Error("Original send is required for edit or clone mode");
|
||||
}
|
||||
|
||||
this.originalSendView = await this.addEditFormService.decryptSend(this.config.originalSend);
|
||||
|
||||
this.updatedSendView = Object.assign(this.updatedSendView, this.originalSendView);
|
||||
} else {
|
||||
this.updatedSendView.type = this.config.sendType;
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private addEditFormService: SendFormService,
|
||||
private toastService: ToastService,
|
||||
private i18nService: I18nService,
|
||||
) {}
|
||||
|
||||
submit = async () => {
|
||||
if (this.sendForm.invalid) {
|
||||
this.sendForm.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Add file handling
|
||||
await this.addEditFormService.saveSend(this.updatedSendView, null, this.config);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(
|
||||
this.config.mode === "edit" || this.config.mode === "partial-edit"
|
||||
? "editedItem"
|
||||
: "addedItem",
|
||||
),
|
||||
});
|
||||
|
||||
this.sendSaved.emit(this.updatedSendView);
|
||||
};
|
||||
}
|
7
libs/tools/send/send-ui/src/send-form/index.ts
Normal file
7
libs/tools/send/send-ui/src/send-form/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export { SendFormModule } from "./send-form.module";
|
||||
export {
|
||||
SendFormConfigService,
|
||||
SendFormConfig,
|
||||
SendFormMode,
|
||||
} from "./abstractions/send-form-config.service";
|
||||
export { DefaultSendFormConfigService } from "./services/default-send-form-config.service";
|
36
libs/tools/send/send-ui/src/send-form/send-form-container.ts
Normal file
36
libs/tools/send/send-ui/src/send-form/send-form-container.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
|
||||
import { SendFormConfig } from "./abstractions/send-form-config.service";
|
||||
/**
|
||||
* The complete form for a send. Includes all the sub-forms from their respective section components.
|
||||
* TODO: Add additional form sections as they are implemented.
|
||||
*/
|
||||
export type SendForm = object;
|
||||
|
||||
/**
|
||||
* A container for the {@link SendForm} that allows for registration of child form groups and patching of the send
|
||||
* to be updated/created. Child form components inject this container in order to register themselves with the parent form
|
||||
* and access configuration options.
|
||||
*
|
||||
* This is an alternative to passing the form groups down through the component tree via @Inputs() and form updates via
|
||||
* @Outputs(). It allows child forms to define their own structure and validation rules, while still being able to
|
||||
* update the parent send.
|
||||
*/
|
||||
export abstract class SendFormContainer {
|
||||
/**
|
||||
* The configuration for the send form.
|
||||
*/
|
||||
readonly config: SendFormConfig;
|
||||
|
||||
/**
|
||||
* The original send that is being edited/cloned. Used to pre-populate the form and compare changes.
|
||||
*/
|
||||
readonly originalSendView: SendView | null;
|
||||
|
||||
abstract registerChildForm<K extends keyof SendForm>(
|
||||
name: K,
|
||||
group: Exclude<SendForm[K], undefined>,
|
||||
): void;
|
||||
|
||||
abstract patchSend(send: Partial<SendView>): void;
|
||||
}
|
17
libs/tools/send/send-ui/src/send-form/send-form.mdx
Normal file
17
libs/tools/send/send-ui/src/send-form/send-form.mdx
Normal file
@ -0,0 +1,17 @@
|
||||
import { Controls, Meta, Primary } from "@storybook/addon-docs";
|
||||
|
||||
import * as stories from "./send-form.stories";
|
||||
|
||||
<Meta of={stories} />
|
||||
|
||||
# Send Form
|
||||
|
||||
The send form is a re-usable form component that can be used to create, update, and clone sends. It
|
||||
is configured via a `SendFormConfig` object that is passed to the component as a prop. The
|
||||
`SendFormConfig` object can be created manually, or a `SendFormConfigService` can be used to create
|
||||
it. A default implementation of the `SendFormConfigService` exists in the `@bitwarden/send-ui`
|
||||
library.
|
||||
|
||||
<Primary />
|
||||
|
||||
<Controls include={["config", "submitBtn"]} />
|
17
libs/tools/send/send-ui/src/send-form/send-form.module.ts
Normal file
17
libs/tools/send/send-ui/src/send-form/send-form.module.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { SendFormService } from "./abstractions/send-form.service";
|
||||
import { SendFormComponent } from "./components/send-form.component";
|
||||
import { DefaultSendFormService } from "./services/default-send-form.service";
|
||||
|
||||
@NgModule({
|
||||
imports: [SendFormComponent],
|
||||
providers: [
|
||||
{
|
||||
provide: SendFormService,
|
||||
useClass: DefaultSendFormService,
|
||||
},
|
||||
],
|
||||
exports: [SendFormComponent],
|
||||
})
|
||||
export class SendFormModule {}
|
132
libs/tools/send/send-ui/src/send-form/send-form.stories.ts
Normal file
132
libs/tools/send/send-ui/src/send-form/send-form.stories.ts
Normal file
@ -0,0 +1,132 @@
|
||||
import { importProvidersFrom } from "@angular/core";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import {
|
||||
applicationConfig,
|
||||
componentWrapperDecorator,
|
||||
Meta,
|
||||
moduleMetadata,
|
||||
StoryObj,
|
||||
} from "@storybook/angular";
|
||||
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { AsyncActionsModule, ButtonModule, ToastService } from "@bitwarden/components";
|
||||
import { SendFormConfig } from "@bitwarden/send-ui";
|
||||
import { PreloadedEnglishI18nModule } from "@bitwarden/web-vault/src/app/core/tests";
|
||||
|
||||
import { SendFormService } from "./abstractions/send-form.service";
|
||||
import { SendFormComponent } from "./components/send-form.component";
|
||||
import { SendFormModule } from "./send-form.module";
|
||||
|
||||
const defaultConfig: SendFormConfig = {
|
||||
mode: "add",
|
||||
sendType: SendType.Text,
|
||||
areSendsAllowed: true,
|
||||
originalSend: {
|
||||
id: "123",
|
||||
name: "Test Send",
|
||||
notes: "Example notes",
|
||||
} as unknown as Send,
|
||||
};
|
||||
|
||||
class TestAddEditFormService implements SendFormService {
|
||||
decryptSend(): Promise<SendView> {
|
||||
return Promise.resolve(defaultConfig.originalSend as any);
|
||||
}
|
||||
async saveSend(send: SendView, file: File | ArrayBuffer): Promise<SendView> {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return send;
|
||||
}
|
||||
}
|
||||
|
||||
const actionsData = {
|
||||
onSave: action("onSave"),
|
||||
};
|
||||
|
||||
export default {
|
||||
title: "Tools/Send Form",
|
||||
component: SendFormComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [SendFormModule, AsyncActionsModule, ButtonModule],
|
||||
providers: [
|
||||
{
|
||||
provide: SendFormService,
|
||||
useClass: TestAddEditFormService,
|
||||
},
|
||||
{
|
||||
provide: ToastService,
|
||||
useValue: {
|
||||
showToast: action("showToast"),
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
componentWrapperDecorator(
|
||||
(story) => `<div class="tw-bg-background-alt tw-text-main tw-border">${story}</div>`,
|
||||
),
|
||||
applicationConfig({
|
||||
providers: [importProvidersFrom(PreloadedEnglishI18nModule)],
|
||||
}),
|
||||
],
|
||||
args: {
|
||||
config: defaultConfig,
|
||||
},
|
||||
argTypes: {
|
||||
config: {
|
||||
description: "The configuration object for the form.",
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
type Story = StoryObj<SendFormComponent>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: (args) => {
|
||||
return {
|
||||
props: {
|
||||
onSave: actionsData.onSave,
|
||||
...args,
|
||||
},
|
||||
template: /*html*/ `
|
||||
<tools-send-form [config]="config" (cipherSaved)="onSave($event)" formId="test-form" [submitBtn]="submitBtn"></tools-send-form>
|
||||
<button type="submit" form="test-form" bitButton buttonType="primary" #submitBtn>Submit</button>
|
||||
`,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export const Edit: Story = {
|
||||
...Default,
|
||||
args: {
|
||||
config: {
|
||||
...defaultConfig,
|
||||
mode: "edit",
|
||||
originalSend: defaultConfig.originalSend,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const PartialEdit: Story = {
|
||||
...Default,
|
||||
args: {
|
||||
config: {
|
||||
...defaultConfig,
|
||||
mode: "partial-edit",
|
||||
originalSend: defaultConfig.originalSend,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const SendsHaveBeenDisabledByPolicy: Story = {
|
||||
...Default,
|
||||
args: {
|
||||
config: {
|
||||
...defaultConfig,
|
||||
mode: "add",
|
||||
areSendsAllowed: false,
|
||||
originalSend: defaultConfig.originalSend,
|
||||
},
|
||||
},
|
||||
};
|
@ -0,0 +1,51 @@
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
import { combineLatest, firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { SendId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import {
|
||||
SendFormConfig,
|
||||
SendFormConfigService,
|
||||
SendFormMode,
|
||||
} from "../abstractions/send-form-config.service";
|
||||
|
||||
/**
|
||||
* Default implementation of the `SendFormConfigService`.
|
||||
*/
|
||||
@Injectable()
|
||||
export class DefaultSendFormConfigService implements SendFormConfigService {
|
||||
private policyService: PolicyService = inject(PolicyService);
|
||||
private sendService: SendService = inject(SendService);
|
||||
|
||||
async buildConfig(
|
||||
mode: SendFormMode,
|
||||
sendId?: SendId,
|
||||
sendType?: SendType,
|
||||
): Promise<SendFormConfig> {
|
||||
const [areSendsAllowed, send] = await firstValueFrom(
|
||||
combineLatest([this.areSendsEnabled$, this.getSend(sendId)]),
|
||||
);
|
||||
|
||||
return {
|
||||
mode,
|
||||
sendType: sendType,
|
||||
areSendsAllowed,
|
||||
originalSend: send,
|
||||
};
|
||||
}
|
||||
|
||||
private areSendsEnabled$ = this.policyService
|
||||
.policyAppliesToActiveUser$(PolicyType.DisableSend)
|
||||
.pipe(map((p) => !p));
|
||||
|
||||
private getSend(id?: SendId) {
|
||||
if (id == null) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return this.sendService.get$(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
|
||||
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
||||
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 { SendFormConfig } from "../abstractions/send-form-config.service";
|
||||
import { SendFormService } from "../abstractions/send-form.service";
|
||||
|
||||
@Injectable()
|
||||
export class DefaultSendFormService implements SendFormService {
|
||||
private sendApiService: SendApiService = inject(SendApiService);
|
||||
private sendService = inject(SendService);
|
||||
|
||||
async decryptSend(send: Send): Promise<SendView> {
|
||||
return await send.decrypt();
|
||||
}
|
||||
|
||||
async saveSend(
|
||||
send: SendView,
|
||||
file: File | ArrayBuffer,
|
||||
config: SendFormConfig,
|
||||
): Promise<SendView> {
|
||||
const sendData = await this.sendService.encrypt(send, file, send.password, null);
|
||||
const savedSend = await this.sendApiService.save(sendData);
|
||||
return await savedSend.decrypt();
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ config.content = [
|
||||
"./libs/auth/src/**/*.{html,ts,mdx}",
|
||||
"./libs/billing/src/**/*.{html,ts,mdx}",
|
||||
"./libs/platform/src/**/*.{html,ts,mdx}",
|
||||
"./libs/tools/send/send-ui/src/*.{html,ts,mdx}",
|
||||
"./libs/vault/src/**/*.{html,ts,mdx}",
|
||||
"./apps/web/src/**/*.{html,ts,mdx}",
|
||||
"./bitwarden_license/bit-web/src/**/*.{html,ts,mdx}",
|
||||
|
@ -49,6 +49,7 @@
|
||||
"apps/web/src/**/*",
|
||||
"apps/browser/src/**/*",
|
||||
"libs/*/src/**/*",
|
||||
"libs/tools/send/**/src/**/*",
|
||||
"bitwarden_license/bit-web/src/**/*",
|
||||
"bitwarden_license/bit-common/src/**/*"
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user