mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 14:53:33 +00:00
send text details
This commit is contained in:
@@ -2214,6 +2214,10 @@
|
|||||||
"message": "Send",
|
"message": "Send",
|
||||||
"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."
|
||||||
},
|
},
|
||||||
|
"sendDetails": {
|
||||||
|
"message": "Send details",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
"searchSends": {
|
"searchSends": {
|
||||||
"message": "Search Sends",
|
"message": "Search 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."
|
||||||
@@ -2246,14 +2250,14 @@
|
|||||||
"message": "Limit views"
|
"message": "Limit views"
|
||||||
},
|
},
|
||||||
"limitSendViewsHint": {
|
"limitSendViewsHint": {
|
||||||
"message": "No one can view this Send after the limit is reached. $ACCESSCOUNT$ views",
|
"message": "No one can view this Send after the limit is reached.",
|
||||||
"description": "Displayed under the limit views field on Send"
|
"description": "Displayed under the limit views field on Send"
|
||||||
},
|
},
|
||||||
"limitSendViewsHintWithCount": {
|
"limitSendViewsHintWithCount": {
|
||||||
"message": "No one can view this Send after the limit is reached. $ACCESSCOUNT$ views left",
|
"message": "No one can view this Send after the limit is reached. $ACCESSCOUNT$ views left",
|
||||||
"description": "Displayed under the limit views field on Send",
|
"description": "Displayed under the limit views field on Send",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"days": {
|
"accessCount": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
"example": "2"
|
"example": "2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Send>;
|
save: (sendData: [Send, EncArrayBuffer]) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
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";
|
||||||
@@ -137,13 +135,11 @@ 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<Send> {
|
async save(sendData: [Send, EncArrayBuffer]): Promise<void> {
|
||||||
const response = await this.upload(sendData);
|
const response = await this.upload(sendData);
|
||||||
|
|
||||||
const data = new SendData(response);
|
const data = new SendData(response);
|
||||||
const updated = await this.sendService.upsert(data);
|
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> {
|
||||||
|
|||||||
@@ -22,5 +22,5 @@ export abstract class SendFormService {
|
|||||||
send: SendView,
|
send: SendView,
|
||||||
file: File | ArrayBuffer,
|
file: File | ArrayBuffer,
|
||||||
config: SendFormConfig,
|
config: SendFormConfig,
|
||||||
): Promise<SendView>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<bit-label>{{ "limitSendViews" | i18n }}</bit-label>
|
<bit-label>{{ "limitSendViews" | i18n }}</bit-label>
|
||||||
<input bitInput type="number" formControlName="maxAccessCount" min="1" />
|
<input bitInput type="number" formControlName="maxAccessCount" min="1" />
|
||||||
<bit-hint>{{ "limitSendViewsHint" | i18n }}</bit-hint>
|
<bit-hint>{{ "limitSendViewsHint" | i18n }}</bit-hint>
|
||||||
<bit-hint>{{ "limitSendViewsHintWithCount" | i18n }}</bit-hint>
|
<!-- <bit-hint>{{ "limitSendViewsHintWithCount" | i18n: 4 }}</bit-hint> -->
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
<!-- TODO: Add information of current access count as bitHint -->
|
<!-- TODO: Add information of current access count as bitHint -->
|
||||||
<bit-form-field>
|
<bit-form-field>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<bit-section [formGroup]="sendTextDetailsForm">
|
<bit-section [formGroup]="sendTextDetailsForm">
|
||||||
<bit-section-header>
|
<bit-section-header>
|
||||||
<!-- TODO: Add i18n for this header -->
|
<h2 bitTypography="h5">{{ "sendDetails" | i18n }}</h2>
|
||||||
<h2 bitTypography="h5">Send details</h2>
|
|
||||||
</bit-section-header>
|
</bit-section-header>
|
||||||
|
|
||||||
<bit-card>
|
<bit-card>
|
||||||
@@ -28,7 +27,7 @@
|
|||||||
formControlName="selectedDeletionDatePreset"
|
formControlName="selectedDeletionDatePreset"
|
||||||
>
|
>
|
||||||
<bit-option
|
<bit-option
|
||||||
*ngFor="let o of deletionDatePresets"
|
*ngFor="let o of datePresetOptions"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
[label]="o.name"
|
[label]="o.name"
|
||||||
></bit-option>
|
></bit-option>
|
||||||
|
|||||||
@@ -65,25 +65,11 @@ export class SendTextDetailsComponent implements OnInit {
|
|||||||
name: ["", [Validators.required]],
|
name: ["", [Validators.required]],
|
||||||
textToShare: [""],
|
textToShare: [""],
|
||||||
hideTextByDefault: [false],
|
hideTextByDefault: [false],
|
||||||
// sendLink: [null as string],
|
selectedDeletionDatePreset: [DatePreset.SevenDays || "", Validators.required],
|
||||||
selectedDeletionDatePreset: [DatePreset.SevenDays, Validators.required],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
get deletionDatePresets(): DatePresetSelectOption[] {
|
customDeletionDateOption: DatePresetSelectOption | null = null;
|
||||||
const defaultSelections = [
|
datePresetOptions: 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", "14"), value: DatePreset.FourteenDays },
|
|
||||||
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
|
|
||||||
];
|
|
||||||
if (!this.originalSendView.deletionDate) {
|
|
||||||
return defaultSelections;
|
|
||||||
}
|
|
||||||
return [{ name: null, value: this.formattedDeletionDate }, ...defaultSelections];
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private sendFormContainer: SendFormContainer,
|
private sendFormContainer: SendFormContainer,
|
||||||
@@ -95,37 +81,62 @@ export class SendTextDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
this.sendTextDetailsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
this.sendTextDetailsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||||
this.sendFormContainer.patchSend((send) => {
|
this.sendFormContainer.patchSend((send) => {
|
||||||
Object.assign(send, {
|
return Object.assign(send, {
|
||||||
name: value.name,
|
name: value.name,
|
||||||
text: { text: value.textToShare, hidden: value.hideTextByDefault },
|
text: { text: value.textToShare, hidden: value.hideTextByDefault },
|
||||||
deletionDate: new Date(this.formattedDeletionDate),
|
deletionDate: new Date(this.formattedDeletionDate),
|
||||||
expirationDate: new Date(this.formattedDeletionDate),
|
expirationDate: new Date(this.formattedDeletionDate),
|
||||||
} as SendView);
|
} as SendView);
|
||||||
return send;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
this.setupDeletionDatePresets();
|
||||||
|
|
||||||
if (this.originalSendView) {
|
if (this.originalSendView) {
|
||||||
this.sendTextDetailsForm.patchValue({
|
this.sendTextDetailsForm.patchValue({
|
||||||
name: this.originalSendView.name,
|
name: this.originalSendView.name,
|
||||||
textToShare: this.originalSendView.text.text,
|
textToShare: this.originalSendView.text.text,
|
||||||
hideTextByDefault: this.originalSendView.text.hidden,
|
hideTextByDefault: this.originalSendView.text.hidden,
|
||||||
selectedDeletionDatePreset: DatePreset.SevenDays,
|
selectedDeletionDatePreset: this.originalSendView.deletionDate.toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If existing deletion date exists, calculate it once and store it
|
||||||
|
if (this.originalSendView.deletionDate) {
|
||||||
|
this.customDeletionDateOption = {
|
||||||
|
name: this.datePipe.transform(this.originalSendView.deletionDate, "MM/dd/yyyy, hh:mm a"),
|
||||||
|
value: this.originalSendView.deletionDate.toString(),
|
||||||
|
};
|
||||||
|
this.datePresetOptions.unshift(this.customDeletionDateOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupDeletionDatePresets() {
|
||||||
|
const defaultSelections: 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", "14"), value: DatePreset.FourteenDays },
|
||||||
|
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
|
||||||
|
];
|
||||||
|
|
||||||
|
this.datePresetOptions = defaultSelections;
|
||||||
|
}
|
||||||
|
|
||||||
get formattedDeletionDate(): string {
|
get formattedDeletionDate(): string {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const milliseconds = now.setTime(
|
const selectedValue = this.sendTextDetailsForm.controls.selectedDeletionDatePreset.value;
|
||||||
now.getTime() +
|
|
||||||
(this.sendTextDetailsForm.controls.selectedDeletionDatePreset.value as number) *
|
// If existing deletion date is selected, return it as is
|
||||||
60 *
|
if (typeof selectedValue === "string") {
|
||||||
60 *
|
return selectedValue;
|
||||||
1000,
|
}
|
||||||
);
|
|
||||||
|
const milliseconds = now.setTime(now.getTime() + (selectedValue as number) * 60 * 60 * 1000);
|
||||||
return new Date(milliseconds).toString();
|
return new Date(milliseconds).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,8 @@ class TestAddEditFormService implements SendFormService {
|
|||||||
decryptSend(): Promise<SendView> {
|
decryptSend(): Promise<SendView> {
|
||||||
return Promise.resolve(defaultConfig.originalSend as any);
|
return Promise.resolve(defaultConfig.originalSend as any);
|
||||||
}
|
}
|
||||||
async saveSend(send: SendView, file: File | ArrayBuffer): Promise<SendView> {
|
async saveSend(send: SendView, file: File | ArrayBuffer): Promise<void> {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
return send;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,8 @@ export class DefaultSendFormService implements SendFormService {
|
|||||||
return await send.decrypt();
|
return await send.decrypt();
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSend(
|
async saveSend(send: SendView, file: File | ArrayBuffer, config: SendFormConfig) {
|
||||||
send: SendView,
|
|
||||||
file: File | ArrayBuffer,
|
|
||||||
config: SendFormConfig,
|
|
||||||
): Promise<SendView> {
|
|
||||||
const sendData = await this.sendService.encrypt(send, file, send.password, null);
|
const sendData = await this.sendService.encrypt(send, file, send.password, null);
|
||||||
const savedSend = await this.sendApiService.save(sendData);
|
await this.sendApiService.save(sendData);
|
||||||
return await savedSend.decrypt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user