mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 23:03:32 +00:00
Temporary local changes not meant to be merged
This commit is contained in:
committed by
jaasen-livefront
parent
89751f46d6
commit
605269813e
@@ -2232,6 +2232,27 @@
|
|||||||
"message": "All Sends",
|
"message": "All Sends",
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
},
|
},
|
||||||
|
"textHiddenByDefault": {
|
||||||
|
"message": "When accessing the Send, hide the text by default",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"limitSendViews": {
|
||||||
|
"message": "Limit views"
|
||||||
|
},
|
||||||
|
"limitSendViewsHint": {
|
||||||
|
"message": "No one can view this Send after the limit is reached. $ACCESSCOUNT$ views",
|
||||||
|
"description": "Displayed under the limit views field on Send"
|
||||||
|
},
|
||||||
|
"limitSendViewsHintWithCount": {
|
||||||
|
"message": "No one can view this Send after the limit is reached. $ACCESSCOUNT$ views left",
|
||||||
|
"description": "Displayed under the limit views field on Send",
|
||||||
|
"placeholders": {
|
||||||
|
"days": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"maxAccessCountReached": {
|
"maxAccessCountReached": {
|
||||||
"message": "Max access count reached",
|
"message": "Max access count reached",
|
||||||
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
|
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function extensionRefreshSwap(
|
|||||||
defaultComponent,
|
defaultComponent,
|
||||||
refreshedComponent,
|
refreshedComponent,
|
||||||
async () => {
|
async () => {
|
||||||
|
return true;
|
||||||
const configService = inject(ConfigService);
|
const configService = inject(ConfigService);
|
||||||
return configService.getFeatureFlag(FeatureFlag.ExtensionRefresh);
|
return configService.getFeatureFlag(FeatureFlag.ExtensionRefresh);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,5 +36,5 @@ export abstract class SendApiService {
|
|||||||
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
|
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
|
||||||
removePassword: (id: string) => Promise<any>;
|
removePassword: (id: string) => Promise<any>;
|
||||||
delete: (id: string) => Promise<any>;
|
delete: (id: string) => Promise<any>;
|
||||||
save: (sendData: [Send, EncArrayBuffer]) => Promise<any>;
|
save: (sendData: [Send, EncArrayBuffer]) => Promise<Send>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { SendId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
import { ApiService } from "../../../abstractions/api.service";
|
import { ApiService } from "../../../abstractions/api.service";
|
||||||
import { ErrorResponse } from "../../../models/response/error.response";
|
import { ErrorResponse } from "../../../models/response/error.response";
|
||||||
import { ListResponse } from "../../../models/response/list.response";
|
import { ListResponse } from "../../../models/response/list.response";
|
||||||
@@ -135,11 +137,13 @@ export class SendApiService implements SendApiServiceAbstraction {
|
|||||||
return this.apiService.send("DELETE", "/sends/" + id, null, true, false);
|
return this.apiService.send("DELETE", "/sends/" + id, null, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(sendData: [Send, EncArrayBuffer]): Promise<any> {
|
async save(sendData: [Send, EncArrayBuffer]): Promise<Send> {
|
||||||
const response = await this.upload(sendData);
|
const response = await this.upload(sendData);
|
||||||
|
|
||||||
const data = new SendData(response);
|
const data = new SendData(response);
|
||||||
await this.sendService.upsert(data);
|
const updated = await this.sendService.upsert(data);
|
||||||
|
// No local data for new Sends
|
||||||
|
return new Send(updated[response.id as SendId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string): Promise<any> {
|
async delete(id: string): Promise<any> {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { UserKeyRotationDataProvider } from "@bitwarden/auth/common";
|
|||||||
|
|
||||||
import { EncArrayBuffer } from "../../../platform/models/domain/enc-array-buffer";
|
import { EncArrayBuffer } from "../../../platform/models/domain/enc-array-buffer";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
import { UserId } from "../../../types/guid";
|
import { SendId, UserId } from "../../../types/guid";
|
||||||
import { UserKey } from "../../../types/key";
|
import { UserKey } from "../../../types/key";
|
||||||
import { SendData } from "../models/data/send.data";
|
import { SendData } from "../models/data/send.data";
|
||||||
import { Send } from "../models/domain/send";
|
import { Send } from "../models/domain/send";
|
||||||
@@ -54,7 +54,7 @@ export abstract class SendService implements UserKeyRotationDataProvider<SendWit
|
|||||||
}
|
}
|
||||||
|
|
||||||
export abstract class InternalSendService extends SendService {
|
export abstract class InternalSendService extends SendService {
|
||||||
upsert: (send: SendData | SendData[]) => Promise<any>;
|
upsert: (send: SendData | SendData[]) => Promise<Record<SendId, SendData>>;
|
||||||
replace: (sends: { [id: string]: SendData }, userId: UserId) => Promise<void>;
|
replace: (sends: { [id: string]: SendData }, userId: UserId) => Promise<void>;
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
delete: (id: string | string[]) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ export class SendService implements InternalSendServiceAbstraction {
|
|||||||
send.disabled = model.disabled;
|
send.disabled = model.disabled;
|
||||||
send.hideEmail = model.hideEmail;
|
send.hideEmail = model.hideEmail;
|
||||||
send.maxAccessCount = model.maxAccessCount;
|
send.maxAccessCount = model.maxAccessCount;
|
||||||
|
send.deletionDate = model.deletionDate;
|
||||||
|
send.expirationDate = model.expirationDate;
|
||||||
if (model.key == null) {
|
if (model.key == null) {
|
||||||
const key = await this.keyGenerationService.createKeyWithPurpose(
|
const key = await this.keyGenerationService.createKeyWithPurpose(
|
||||||
128,
|
128,
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<bit-section [formGroup]="additionalOptionsForm">
|
||||||
|
<bit-section-header>
|
||||||
|
<h2 bitTypography="h5">{{ "additionalOptions" | i18n }}</h2>
|
||||||
|
</bit-section-header>
|
||||||
|
|
||||||
|
<bit-card>
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "limitSendViews" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="number" formControlName="maxAccessCount" min="1" />
|
||||||
|
<bit-hint>{{ "limitSendViewsHint" | i18n }}</bit-hint>
|
||||||
|
<bit-hint>{{ "limitSendViewsHintWithCount" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
<!-- TODO: Add information of current access count as bitHint -->
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "currentAccessCount" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" formControlName="accessCount" readonly />
|
||||||
|
</bit-form-field>
|
||||||
|
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label *ngIf="!hasPassword">{{ "password" | i18n }}</bit-label>
|
||||||
|
<bit-label *ngIf="hasPassword">{{ "newPassword" | i18n }}</bit-label>
|
||||||
|
|
||||||
|
<input bitInput type="password" formControlName="password" />
|
||||||
|
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||||
|
<button type="button" bitIconButton="bwi-refresh" bitSuffix></button>
|
||||||
|
<bit-hint>{{ "sendPasswordDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
|
||||||
|
<bit-form-control>
|
||||||
|
<input bitCheckbox type="checkbox" formControlName="hideEmail" />
|
||||||
|
<bit-label>{{ "hideEmail" | i18n }}</bit-label>
|
||||||
|
</bit-form-control>
|
||||||
|
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "notes" | i18n }}</bit-label>
|
||||||
|
<textarea bitInput formControlName="notes"></textarea>
|
||||||
|
</bit-form-field>
|
||||||
|
</bit-card>
|
||||||
|
</bit-section>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { Component, Input, OnInit } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
||||||
|
|
||||||
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||||
|
import {
|
||||||
|
CardComponent,
|
||||||
|
CheckboxModule,
|
||||||
|
FormFieldModule,
|
||||||
|
IconButtonModule,
|
||||||
|
SectionComponent,
|
||||||
|
SectionHeaderComponent,
|
||||||
|
TypographyModule,
|
||||||
|
} from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { SendFormConfig } from "../../abstractions/send-form-config.service";
|
||||||
|
import { SendFormContainer } from "../../send-form-container";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "tools-send-options-section",
|
||||||
|
templateUrl: "./options-section.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
SectionComponent,
|
||||||
|
SectionHeaderComponent,
|
||||||
|
TypographyModule,
|
||||||
|
JslibModule,
|
||||||
|
CardComponent,
|
||||||
|
FormFieldModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
IconButtonModule,
|
||||||
|
CheckboxModule,
|
||||||
|
CommonModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class AdditionalOptionsSectionComponent implements OnInit {
|
||||||
|
@Input({ required: true })
|
||||||
|
config: SendFormConfig;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
originalSendView: SendView;
|
||||||
|
|
||||||
|
additionalOptionsForm = this.formBuilder.group({
|
||||||
|
maxAccessCount: [null as number],
|
||||||
|
accessCount: [null as number],
|
||||||
|
notes: [null as string],
|
||||||
|
password: [null as string],
|
||||||
|
hideEmail: [false as boolean],
|
||||||
|
});
|
||||||
|
|
||||||
|
get hasPassword(): boolean {
|
||||||
|
return (
|
||||||
|
this.additionalOptionsForm.value.password !== null &&
|
||||||
|
this.additionalOptionsForm.value.password !== ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private sendFormContainer: SendFormContainer,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
) {
|
||||||
|
this.sendFormContainer.registerChildForm("additionalOptions", this.additionalOptionsForm);
|
||||||
|
|
||||||
|
this.additionalOptionsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||||
|
this.sendFormContainer.patchSend((send) => {
|
||||||
|
Object.assign(send, {
|
||||||
|
maxAccessCount: value.maxAccessCount,
|
||||||
|
accessCount: value.accessCount,
|
||||||
|
password: value.password,
|
||||||
|
hideEmail: value.hideEmail,
|
||||||
|
notes: value.notes,
|
||||||
|
});
|
||||||
|
return send;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.sendFormContainer.originalSendView) {
|
||||||
|
this.additionalOptionsForm.patchValue({
|
||||||
|
maxAccessCount: this.sendFormContainer.originalSendView.maxAccessCount,
|
||||||
|
accessCount: this.sendFormContainer.originalSendView.accessCount,
|
||||||
|
password: this.sendFormContainer.originalSendView.password,
|
||||||
|
hideEmail: this.sendFormContainer.originalSendView.hideEmail,
|
||||||
|
notes: this.sendFormContainer.originalSendView.notes,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<bit-section [formGroup]="sendTextDetailsForm">
|
||||||
|
<bit-section-header>
|
||||||
|
<!-- TODO: Add i18n for this header -->
|
||||||
|
<h2 bitTypography="h5">Send details</h2>
|
||||||
|
</bit-section-header>
|
||||||
|
|
||||||
|
<bit-card>
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "name" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" formControlName="name" />
|
||||||
|
</bit-form-field>
|
||||||
|
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "sendTypeText" | i18n }}</bit-label>
|
||||||
|
<textarea bitInput id="text" rows="6" formControlName="textToShare"></textarea>
|
||||||
|
<bit-hint>{{ "sendTextDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
<bit-form-control>
|
||||||
|
<input bitCheckbox type="checkbox" formControlName="hideTextByDefault" />
|
||||||
|
<bit-label>{{ "textHiddenByDefault" | i18n }}</bit-label>
|
||||||
|
</bit-form-control>
|
||||||
|
|
||||||
|
<bit-form-field *ngIf="config.mode === 'edit'">
|
||||||
|
<bit-label>{{ "sendLinkLabel" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" readonly formControlName="sendLink" />
|
||||||
|
<button type="button" bitSuffix bitIconButton="bwi-clone"></button>
|
||||||
|
</bit-form-field>
|
||||||
|
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "deletionDate" | i18n }}</bit-label>
|
||||||
|
<bit-select
|
||||||
|
id="deletionDate"
|
||||||
|
name="SelectedDeletionDatePreset"
|
||||||
|
formControlName="selectedDeletionDatePreset"
|
||||||
|
>
|
||||||
|
<bit-option
|
||||||
|
*ngFor="let o of deletionDatePresets"
|
||||||
|
[value]="o.value"
|
||||||
|
[label]="o.name"
|
||||||
|
></bit-option>
|
||||||
|
</bit-select>
|
||||||
|
<ng-container *ngIf="sendTextDetailsForm.controls['selectedDeletionDatePreset'].value === 0">
|
||||||
|
<input
|
||||||
|
bitInput
|
||||||
|
id="deletionDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="DeletionDate"
|
||||||
|
formControlName="defaultDeletionDateTime"
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
</ng-container>
|
||||||
|
<bit-hint>{{ "deletionDateDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</bit-card>
|
||||||
|
</bit-section>
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import { CommonModule, DatePipe } from "@angular/common";
|
||||||
|
import { Component, Input, OnInit } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
|
||||||
|
|
||||||
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||||
|
import {
|
||||||
|
CardComponent,
|
||||||
|
CheckboxModule,
|
||||||
|
FormFieldModule,
|
||||||
|
IconButtonModule,
|
||||||
|
SectionComponent,
|
||||||
|
SectionHeaderComponent,
|
||||||
|
SelectModule,
|
||||||
|
TypographyModule,
|
||||||
|
} from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { SendFormConfig } from "../../abstractions/send-form-config.service";
|
||||||
|
import { SendFormContainer } from "../../send-form-container";
|
||||||
|
|
||||||
|
// Value = hours
|
||||||
|
enum DatePreset {
|
||||||
|
OneHour = 1,
|
||||||
|
OneDay = 24,
|
||||||
|
TwoDays = 48,
|
||||||
|
ThreeDays = 72,
|
||||||
|
SevenDays = 168,
|
||||||
|
ThirtyDays = 720,
|
||||||
|
Custom = 0,
|
||||||
|
Never = null,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DatePresetSelectOption {
|
||||||
|
name: string;
|
||||||
|
value: DatePreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "tools-send-text-details",
|
||||||
|
templateUrl: "./send-text-details.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
SectionComponent,
|
||||||
|
SectionHeaderComponent,
|
||||||
|
TypographyModule,
|
||||||
|
JslibModule,
|
||||||
|
CardComponent,
|
||||||
|
FormFieldModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
IconButtonModule,
|
||||||
|
CheckboxModule,
|
||||||
|
CommonModule,
|
||||||
|
SelectModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class SendTextDetailsComponent implements OnInit {
|
||||||
|
@Input({ required: true })
|
||||||
|
config: SendFormConfig;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
originalSendView: SendView;
|
||||||
|
|
||||||
|
sendTextDetailsForm = this.formBuilder.group({
|
||||||
|
name: ["", [Validators.required]],
|
||||||
|
textToShare: [""],
|
||||||
|
hideTextByDefault: [false],
|
||||||
|
// sendLink: [null as string],
|
||||||
|
defaultDeletionDateTime: ["", Validators.required],
|
||||||
|
selectedDeletionDatePreset: [DatePreset.SevenDays, Validators.required],
|
||||||
|
});
|
||||||
|
|
||||||
|
deletionDatePresets: DatePresetSelectOption[] = [
|
||||||
|
{ name: this.i18nService.t("oneHour"), value: DatePreset.OneHour },
|
||||||
|
{ name: this.i18nService.t("oneDay"), value: DatePreset.OneDay },
|
||||||
|
{ name: this.i18nService.t("days", "2"), value: DatePreset.TwoDays },
|
||||||
|
{ name: this.i18nService.t("days", "3"), value: DatePreset.ThreeDays },
|
||||||
|
{ name: this.i18nService.t("days", "7"), value: DatePreset.SevenDays },
|
||||||
|
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
|
||||||
|
{ name: this.i18nService.t("custom"), value: DatePreset.Custom },
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private sendFormContainer: SendFormContainer,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
protected datePipe: DatePipe,
|
||||||
|
) {
|
||||||
|
this.sendFormContainer.registerChildForm("sendTextDetailsForm", this.sendTextDetailsForm);
|
||||||
|
|
||||||
|
this.sendTextDetailsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||||
|
this.sendFormContainer.patchSend((send) => {
|
||||||
|
Object.assign(send, {
|
||||||
|
name: value.name,
|
||||||
|
text: { text: value.textToShare, hidden: value.hideTextByDefault },
|
||||||
|
deletionDate: new Date(this.formattedDeletionDate),
|
||||||
|
expirationDate: new Date(this.formattedDeletionDate),
|
||||||
|
} as SendView);
|
||||||
|
return send;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
if (this.originalSendView) {
|
||||||
|
this.sendTextDetailsForm.patchValue({
|
||||||
|
name: this.originalSendView.name,
|
||||||
|
textToShare: this.originalSendView.text.text,
|
||||||
|
hideTextByDefault: this.originalSendView.text.hidden,
|
||||||
|
defaultDeletionDateTime: this.datePipe.transform(
|
||||||
|
new Date(this.originalSendView.deletionDate),
|
||||||
|
"yyyy-MM-ddTHH:mm",
|
||||||
|
),
|
||||||
|
selectedDeletionDatePreset:
|
||||||
|
this.config.mode === "edit" ? DatePreset.Custom : DatePreset.SevenDays,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendTextDetailsForm.controls.selectedDeletionDatePreset.valueChanges
|
||||||
|
.pipe(takeUntilDestroyed())
|
||||||
|
.subscribe((datePreset) => {
|
||||||
|
datePreset === DatePreset.Custom
|
||||||
|
? this.sendTextDetailsForm.controls.defaultDeletionDateTime.enable()
|
||||||
|
: this.sendTextDetailsForm.controls.defaultDeletionDateTime.disable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get formattedDeletionDate(): string {
|
||||||
|
switch (this.sendTextDetailsForm.controls.selectedDeletionDatePreset.value as DatePreset) {
|
||||||
|
case DatePreset.Never:
|
||||||
|
this.sendTextDetailsForm.controls.selectedDeletionDatePreset.patchValue(
|
||||||
|
DatePreset.SevenDays,
|
||||||
|
);
|
||||||
|
return this.formattedDeletionDate;
|
||||||
|
case DatePreset.Custom:
|
||||||
|
return this.sendTextDetailsForm.controls.defaultDeletionDateTime.value;
|
||||||
|
default: {
|
||||||
|
const now = new Date();
|
||||||
|
const milliseconds = now.setTime(
|
||||||
|
now.getTime() +
|
||||||
|
(this.sendTextDetailsForm.controls.selectedDeletionDatePreset.value as number) *
|
||||||
|
60 *
|
||||||
|
60 *
|
||||||
|
1000,
|
||||||
|
);
|
||||||
|
return new Date(milliseconds).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,14 @@
|
|||||||
<form [id]="formId" [formGroup]="sendForm" [bitSubmit]="submit">
|
<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 -->
|
<!-- 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>
|
<ng-container *ngIf="!loading">
|
||||||
|
<tools-send-text-details
|
||||||
|
*ngIf="config.sendType === SendType.Text"
|
||||||
|
[config]="config"
|
||||||
|
[originalSendView]="originalSendView"
|
||||||
|
></tools-send-text-details>
|
||||||
|
<tools-send-options-section
|
||||||
|
[config]="config"
|
||||||
|
[originalSendView]="originalSendView"
|
||||||
|
></tools-send-options-section>
|
||||||
|
</ng-container>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ import { SendFormConfig } from "../abstractions/send-form-config.service";
|
|||||||
import { SendFormService } from "../abstractions/send-form.service";
|
import { SendFormService } from "../abstractions/send-form.service";
|
||||||
import { SendForm, SendFormContainer } from "../send-form-container";
|
import { SendForm, SendFormContainer } from "../send-form-container";
|
||||||
|
|
||||||
|
import { AdditionalOptionsSectionComponent } from "./options/options-section.component";
|
||||||
|
import { SendTextDetailsComponent } from "./send-details/send-text-details.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "tools-send-form",
|
selector: "tools-send-form",
|
||||||
templateUrl: "./send-form.component.html",
|
templateUrl: "./send-form.component.html",
|
||||||
@@ -55,6 +58,8 @@ import { SendForm, SendFormContainer } from "../send-form-container";
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
SelectModule,
|
SelectModule,
|
||||||
NgIf,
|
NgIf,
|
||||||
|
AdditionalOptionsSectionComponent,
|
||||||
|
SendTextDetailsComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, SendFormContainer {
|
export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, SendFormContainer {
|
||||||
@@ -131,12 +136,11 @@ export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, Send
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patches the updated send with the provided partial senbd. Used by child components to update the send
|
* Method to update the sendView with the new values. This method should be called by the child form components
|
||||||
* as their form values change.
|
* @param updateFn - A function that takes the current sendView and returns the updated sendView
|
||||||
* @param send
|
|
||||||
*/
|
*/
|
||||||
patchSend(send: Partial<SendView>): void {
|
patchSend(updateFn: (current: SendView) => SendView): void {
|
||||||
this.updatedSendView = Object.assign(this.updatedSendView, send);
|
this.updatedSendView = updateFn(this.updatedSendView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
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 { AdditionalOptionsSectionComponent } from "./components/options/options-section.component";
|
||||||
|
import { SendTextDetailsComponent } 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.
|
||||||
* TODO: Add additional form sections as they are implemented.
|
* TODO: Add additional form sections as they are implemented.
|
||||||
*/
|
*/
|
||||||
export type SendForm = object;
|
export type SendForm = {
|
||||||
|
sendTextDetailsForm?: SendTextDetailsComponent["sendTextDetailsForm"];
|
||||||
|
additionalOptions?: AdditionalOptionsSectionComponent["additionalOptionsForm"];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container for the {@link SendForm} that allows for registration of child form groups and patching of the send
|
* A container for the {@link SendForm} that allows for registration of child form groups and patching of the send
|
||||||
@@ -32,5 +37,5 @@ export abstract class SendFormContainer {
|
|||||||
group: Exclude<SendForm[K], undefined>,
|
group: Exclude<SendForm[K], undefined>,
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
abstract patchSend(send: Partial<SendView>): void;
|
abstract patchSend(updateFn: (current: SendView) => SendView): void;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user