mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-16 01:21:48 +01:00
[PM-11903] - add file send component (#11132)
* wip - send file details * wip - file send * send file details * fix click on send list container * remove popup code * remove popup code * finalize send file details * address PR feedback. add base form to send form * revert changes to send list items container * revert changes to send list items container --------- Co-authored-by: Daniel James Smith <2670567+djsmith85@users.noreply.github.com>
This commit is contained in:
parent
2b85392b0f
commit
00f2317a82
@ -1136,6 +1136,9 @@
|
|||||||
"file": {
|
"file": {
|
||||||
"message": "File"
|
"message": "File"
|
||||||
},
|
},
|
||||||
|
"fileToShare": {
|
||||||
|
"message": "File to share"
|
||||||
|
},
|
||||||
"selectFile": {
|
"selectFile": {
|
||||||
"message": "Select a file"
|
"message": "Select a file"
|
||||||
},
|
},
|
||||||
|
@ -117,25 +117,18 @@ export class SendAddEditComponent {
|
|||||||
)
|
)
|
||||||
.subscribe((config) => {
|
.subscribe((config) => {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.headerText = this.getHeaderText(config.mode, config.sendType);
|
this.headerText = this.getHeaderText(config.mode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the header text based on the mode and type.
|
* Gets the header text based on the mode.
|
||||||
* @param mode The mode of the send form.
|
* @param mode The mode of the send form.
|
||||||
* @param type The type of the send form.
|
|
||||||
* @returns The header text.
|
* @returns The header text.
|
||||||
*/
|
*/
|
||||||
private getHeaderText(mode: SendFormMode, type: SendType) {
|
private getHeaderText(mode: SendFormMode) {
|
||||||
const headerKey =
|
return this.i18nService.t(
|
||||||
mode === "edit" || mode === "partial-edit" ? "editItemHeader" : "newItemHeader";
|
mode === "edit" || mode === "partial-edit" ? "editSend" : "createSend",
|
||||||
|
);
|
||||||
switch (type) {
|
|
||||||
case SendType.Text:
|
|
||||||
return this.i18nService.t(headerKey, this.i18nService.t("sendTypeText"));
|
|
||||||
case SendType.File:
|
|
||||||
return this.i18nService.t(headerKey, this.i18nService.t("sendTypeFile"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,8 @@ export class BaseSendDetailsComponent implements OnInit {
|
|||||||
} as SendView);
|
} as SendView);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.sendFormContainer.registerChildForm("sendDetailsForm", this.sendDetailsForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
@ -16,6 +16,13 @@
|
|||||||
[sendDetailsForm]="sendDetailsForm"
|
[sendDetailsForm]="sendDetailsForm"
|
||||||
></tools-send-text-details>
|
></tools-send-text-details>
|
||||||
|
|
||||||
|
<tools-send-file-details
|
||||||
|
*ngIf="config.sendType === FileSendType"
|
||||||
|
[config]="config"
|
||||||
|
[originalSendView]="originalSendView"
|
||||||
|
[sendDetailsForm]="sendDetailsForm"
|
||||||
|
></tools-send-file-details>
|
||||||
|
|
||||||
<bit-form-field>
|
<bit-form-field>
|
||||||
<bit-label>{{ "deletionDate" | i18n }}</bit-label>
|
<bit-label>{{ "deletionDate" | i18n }}</bit-label>
|
||||||
<bit-select
|
<bit-select
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
import { SendFormContainer } from "../../send-form-container";
|
import { SendFormContainer } from "../../send-form-container";
|
||||||
|
|
||||||
import { BaseSendDetailsComponent } from "./base-send-details.component";
|
import { BaseSendDetailsComponent } from "./base-send-details.component";
|
||||||
|
import { SendFileDetailsComponent } from "./send-file-details.component";
|
||||||
import { SendTextDetailsComponent } from "./send-text-details.component";
|
import { SendTextDetailsComponent } from "./send-text-details.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -34,6 +35,7 @@ import { SendTextDetailsComponent } from "./send-text-details.component";
|
|||||||
FormFieldModule,
|
FormFieldModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
SendTextDetailsComponent,
|
SendTextDetailsComponent,
|
||||||
|
SendFileDetailsComponent,
|
||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
CheckboxModule,
|
CheckboxModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<bit-section [formGroup]="sendFileDetailsForm">
|
||||||
|
<div *ngIf="config.mode === 'edit'">
|
||||||
|
<div class="tw-text-muted">{{ "file" | i18n }}</div>
|
||||||
|
<div>{{ originalSendView.file.fileName }}</div>
|
||||||
|
<div class="tw-text-muted">{{ originalSendView.file.sizeName }}</div>
|
||||||
|
</div>
|
||||||
|
<bit-form-field *ngIf="config.mode !== 'edit'">
|
||||||
|
<bit-label for="file">{{ "fileToShare" | i18n }}</bit-label>
|
||||||
|
<button bitButton type="button" buttonType="primary" (click)="fileSelector.click()">
|
||||||
|
{{ "chooseFile" | i18n }}
|
||||||
|
</button>
|
||||||
|
<span
|
||||||
|
class="tw-flex tw-items-center tw-pl-3"
|
||||||
|
[ngClass]="fileName ? 'tw-text-main' : 'tw-text-muted'"
|
||||||
|
>
|
||||||
|
{{ fileName || ("noFileChosen" | i18n) }}</span
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
bitInput
|
||||||
|
#fileSelector
|
||||||
|
type="file"
|
||||||
|
formControlName="file"
|
||||||
|
hidden
|
||||||
|
(change)="onFileSelected($event)"
|
||||||
|
/>
|
||||||
|
<bit-hint>
|
||||||
|
{{ "maxFileSize" | i18n }}
|
||||||
|
</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</bit-section>
|
@ -0,0 +1,92 @@
|
|||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { Component, Input, OnInit } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
import {
|
||||||
|
FormBuilder,
|
||||||
|
FormControl,
|
||||||
|
FormGroup,
|
||||||
|
Validators,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
FormsModule,
|
||||||
|
} from "@angular/forms";
|
||||||
|
|
||||||
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||||
|
import { SendFileView } from "@bitwarden/common/tools/send/models/view/send-file.view";
|
||||||
|
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||||
|
import { ButtonModule, FormFieldModule, SectionComponent } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { SendFormConfig } from "../../abstractions/send-form-config.service";
|
||||||
|
import { SendFormContainer } from "../../send-form-container";
|
||||||
|
|
||||||
|
import { BaseSendDetailsForm } from "./base-send-details.component";
|
||||||
|
|
||||||
|
type BaseSendFileDetailsForm = FormGroup<{
|
||||||
|
file: FormControl<SendFileView | null>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type SendFileDetailsForm = BaseSendFileDetailsForm & BaseSendDetailsForm;
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "tools-send-file-details",
|
||||||
|
templateUrl: "./send-file-details.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
ButtonModule,
|
||||||
|
CommonModule,
|
||||||
|
JslibModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
FormFieldModule,
|
||||||
|
SectionComponent,
|
||||||
|
FormsModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class SendFileDetailsComponent implements OnInit {
|
||||||
|
@Input() config: SendFormConfig;
|
||||||
|
@Input() originalSendView?: SendView;
|
||||||
|
@Input() sendDetailsForm: BaseSendDetailsForm;
|
||||||
|
|
||||||
|
baseSendFileDetailsForm: BaseSendFileDetailsForm;
|
||||||
|
sendFileDetailsForm: SendFileDetailsForm;
|
||||||
|
|
||||||
|
FileSendType = SendType.File;
|
||||||
|
fileName = "";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
protected sendFormContainer: SendFormContainer,
|
||||||
|
) {
|
||||||
|
this.baseSendFileDetailsForm = this.formBuilder.group({
|
||||||
|
file: this.formBuilder.control<SendFileView | null>(null, Validators.required),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.sendFileDetailsForm = Object.assign(this.baseSendFileDetailsForm, this.sendDetailsForm);
|
||||||
|
|
||||||
|
this.sendFormContainer.registerChildForm("sendFileDetailsForm", this.sendFileDetailsForm);
|
||||||
|
|
||||||
|
this.sendFileDetailsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||||
|
this.sendFormContainer.patchSend((send) => {
|
||||||
|
return Object.assign(send, {
|
||||||
|
file: value.file,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onFileSelected = (event: Event): void => {
|
||||||
|
const file = (event.target as HTMLInputElement).files?.[0];
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fileName = file.name;
|
||||||
|
this.sendFormContainer.onFileSelected(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.originalSendView) {
|
||||||
|
this.sendFileDetailsForm.patchValue({
|
||||||
|
file: this.originalSendView.file,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -65,6 +65,7 @@ export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, Send
|
|||||||
private bitSubmit: BitSubmitDirective;
|
private bitSubmit: BitSubmitDirective;
|
||||||
private destroyRef = inject(DestroyRef);
|
private destroyRef = inject(DestroyRef);
|
||||||
private _firstInitialized = false;
|
private _firstInitialized = false;
|
||||||
|
private file: File | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The form ID to use for the form. Used to connect it to a submit button.
|
* The form ID to use for the form. Used to connect it to a submit button.
|
||||||
@ -188,14 +189,17 @@ export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, Send
|
|||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
onFileSelected(file: File): void {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
submit = async () => {
|
submit = async () => {
|
||||||
if (this.sendForm.invalid) {
|
if (this.sendForm.invalid) {
|
||||||
this.sendForm.markAllAsTouched();
|
this.sendForm.markAllAsTouched();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add file handling
|
await this.addEditFormService.saveSend(this.updatedSendView, this.file, this.config);
|
||||||
await this.addEditFormService.saveSend(this.updatedSendView, null, this.config);
|
|
||||||
|
|
||||||
this.toastService.showToast({
|
this.toastService.showToast({
|
||||||
variant: "success",
|
variant: "success",
|
||||||
|
@ -2,6 +2,7 @@ import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
|||||||
|
|
||||||
import { SendFormConfig } from "./abstractions/send-form-config.service";
|
import { SendFormConfig } from "./abstractions/send-form-config.service";
|
||||||
import { SendDetailsComponent } from "./components/send-details/send-details.component";
|
import { SendDetailsComponent } from "./components/send-details/send-details.component";
|
||||||
|
import { SendFileDetailsForm } from "./components/send-details/send-file-details.component";
|
||||||
import { SendTextDetailsForm } from "./components/send-details/send-text-details.component";
|
import { SendTextDetailsForm } from "./components/send-details/send-text-details.component";
|
||||||
/**
|
/**
|
||||||
* The complete form for a send. Includes all the sub-forms from their respective section components.
|
* The complete form for a send. Includes all the sub-forms from their respective section components.
|
||||||
@ -10,6 +11,7 @@ import { SendTextDetailsForm } from "./components/send-details/send-text-details
|
|||||||
export type SendForm = {
|
export type SendForm = {
|
||||||
sendDetailsForm?: SendDetailsComponent["sendDetailsForm"];
|
sendDetailsForm?: SendDetailsComponent["sendDetailsForm"];
|
||||||
sendTextDetailsForm?: SendTextDetailsForm;
|
sendTextDetailsForm?: SendTextDetailsForm;
|
||||||
|
sendFileDetailsForm?: SendFileDetailsForm;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,5 +39,7 @@ export abstract class SendFormContainer {
|
|||||||
group: Exclude<SendForm[K], undefined>,
|
group: Exclude<SendForm[K], undefined>,
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
abstract onFileSelected(file: File): void;
|
||||||
|
|
||||||
abstract patchSend(updateFn: (current: SendView) => SendView): void;
|
abstract patchSend(updateFn: (current: SendView) => SendView): void;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user