mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-30 04:28:19 +02:00
[PM-2805] Migrate add edit send to Component Library (#6004)
* Converted add-edit send component dialog into a bit-dialog * Updated Send AddEdit text fields to Component Library * Migrated Share and Options fields to ComponentLibrary on SendAddEdit * Migrated footer buttons to ComponentLibrary on SendAddEdit * Updated web's SendAddEdit component file fields * Replaced file upload with component library * Changed SendAddEdit to use Reactive Forms on web * Changed browser SendAddEdit to use ReactiveForms * Update SendAddEdit on desktop to use ReactiveForms * Added AppA11yTitle to button on web SendAddEdit * Initial efflux-dates web change to ComponentLibrary * Corrected delete button to check if it is in EditMode on SendAddEdit * Using BitLink on options button * Corrected typo on send add edit desktop * Replaced efflux-dates with datetime-local input on SendAddEdit web, browser and desktop * Removed efflux dates * Added firefox custom date popout message on DeletionDate to SendAddEdit browser component * moved desktop's new send data reload from send to SendAddEdit component * removing unnecessary attributes and spans from Send AddEdit web * removed redundant try catch from add edit and unnecessary parameter from close * Added type for date select options * Removed unnecessary classes and swapped bootstrap classes by corresponding tailwind classes * Removed unnecessary code * Added file as required field Submit only closes popup on success * Added pre validations at start of submit * PM-3668 removed expiration date from required * PM-3671 not defaulting maximum access count to 0 * PM-3669 Copying the link from link method * Removed required tag from html and added to formgroup * PM-3679 Checking if is not EditMode before validating if FormGroup file value is set * PM-3691 Moved error validation to web component as browser and desktop need to show popup error * PM-3696 - Disabling hide email when it is unset and has policy to not allow hiding * PM-3694 - Properly setting default value for dates on Desktop when changing from an existing send * Disabling hidden required fields * [PM-3800] Clearing password on new send
This commit is contained in:
parent
86bdfaa7ba
commit
5f78aeaef2
@ -33,7 +33,6 @@ import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.
|
|||||||
import { GeneratorComponent } from "../tools/popup/generator/generator.component";
|
import { GeneratorComponent } from "../tools/popup/generator/generator.component";
|
||||||
import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component";
|
import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component";
|
||||||
import { SendListComponent } from "../tools/popup/send/components/send-list.component";
|
import { SendListComponent } from "../tools/popup/send/components/send-list.component";
|
||||||
import { EffluxDatesComponent as SendEffluxDatesComponent } from "../tools/popup/send/efflux-dates.component";
|
|
||||||
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
||||||
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
||||||
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
||||||
@ -133,7 +132,6 @@ import "../platform/popup/locales";
|
|||||||
PrivateModeWarningComponent,
|
PrivateModeWarningComponent,
|
||||||
RegisterComponent,
|
RegisterComponent,
|
||||||
SendAddEditComponent,
|
SendAddEditComponent,
|
||||||
SendEffluxDatesComponent,
|
|
||||||
SendGroupingsComponent,
|
SendGroupingsComponent,
|
||||||
SendListComponent,
|
SendListComponent,
|
||||||
SendTypeComponent,
|
SendTypeComponent,
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
<ng-container [formGroup]="datesForm">
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<ng-container *ngIf="!editMode">
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
|
||||||
<select
|
|
||||||
id="deletionDate"
|
|
||||||
name="DeletionDateSelect"
|
|
||||||
aria-describedby="deletionDateHelp"
|
|
||||||
formControlName="selectedDeletionDatePreset"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">{{ o.name }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" appBoxRow *ngIf="selectedDeletionDatePreset.value === 0">
|
|
||||||
<ng-container *ngTemplateOutlet="deletionDateCustom"></ng-container>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
|
||||||
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
|
||||||
<ng-container *ngTemplateOutlet="deletionDateCustom"></ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="deletionDateHelp" class="box-footer">
|
|
||||||
{{ "deletionDateDesc" | i18n }}
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
!inPopout &&
|
|
||||||
browserPath == 'firefox' &&
|
|
||||||
(editMode || (selectedDeletionDatePreset.value === 0 && !editMode))
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<br />{{ "sendFirefoxCustomDatePopoutMessage1" | i18n }}
|
|
||||||
<a (click)="popOutWindow.emit()">{{ "sendFirefoxCustomDatePopoutMessage2" | i18n }}</a>
|
|
||||||
{{ "sendFirefoxCustomDatePopoutMessage3" | i18n }}
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<ng-container *ngIf="!editMode">
|
|
||||||
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
|
||||||
<label for="editExpirationDate">{{ "expirationDate" | i18n }}</label>
|
|
||||||
<select
|
|
||||||
id="expirationDate"
|
|
||||||
name="ExpirationDateSelect"
|
|
||||||
aria-describedby="expirationDateHelp"
|
|
||||||
formControlName="selectedExpirationDatePreset"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">
|
|
||||||
{{ o.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" *ngIf="selectedExpirationDatePreset.value === 0" appBoxRow>
|
|
||||||
<ng-container *ngTemplateOutlet="expirationDateCustom"></ng-container>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<div class="box-content-row" *ngIf="editMode" appBoxRow>
|
|
||||||
<div class="flex-label">
|
|
||||||
<label>{{ "expirationDate" | i18n }}</label>
|
|
||||||
<button type="button" *ngIf="!disabled" appStopClick (click)="clearExpiration()">
|
|
||||||
{{ "clear" | i18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<ng-container *ngTemplateOutlet="expirationDateCustom"></ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="expirationDateHelp" class="box-footer">
|
|
||||||
{{ "expirationDateDesc" | i18n }}
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
!inPopout &&
|
|
||||||
browserPath == 'firefox' &&
|
|
||||||
(editMode || (selectedExpirationDatePreset.value === 0 && !editMode))
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<br />{{ "sendFirefoxCustomDatePopoutMessage1" | i18n }}
|
|
||||||
<a (click)="popOutWindow.emit()">{{ "sendFirefoxCustomDatePopoutMessage2" | i18n }}</a>
|
|
||||||
{{ "sendFirefoxCustomDatePopoutMessage3" | i18n }}
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ng-template #deletionDateCustom>
|
|
||||||
<ng-container [ngSwitch]="browserPath">
|
|
||||||
<ng-container *ngSwitchCase="'firefox'">
|
|
||||||
<div class="flex flex-grow">
|
|
||||||
<input
|
|
||||||
id="deletionDateCustomFallback"
|
|
||||||
type="date"
|
|
||||||
name="DeletionDateFallback"
|
|
||||||
aria-describedby="deletionDateHelp"
|
|
||||||
formControlName="fallbackDeletionDate"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
id="deletionTimeCustomFallback"
|
|
||||||
type="time"
|
|
||||||
name="DeletionTimeDate"
|
|
||||||
formControlName="fallbackDeletionTime"
|
|
||||||
required
|
|
||||||
placeholder="HH:MM AM/PM"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchCase="'safari'">
|
|
||||||
<div class="flex flex-grow">
|
|
||||||
<input
|
|
||||||
id="deletionDateCustomFallback"
|
|
||||||
type="date"
|
|
||||||
name="DeletionDateFallback"
|
|
||||||
aria-describedby="deletionDateHelp"
|
|
||||||
formControlName="fallbackDeletionDate"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
id="deletionTimeCustomFallback"
|
|
||||||
formControlName="fallbackDeletionTime"
|
|
||||||
name="SafariDeletionTime"
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of safariDeletionTimePresetOptions" [ngValue]="o.twentyFourHour">
|
|
||||||
{{ o.twelveHour }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchDefault>
|
|
||||||
<input
|
|
||||||
id="deletionDateCustom"
|
|
||||||
type="datetime-local"
|
|
||||||
name="DeletionDate"
|
|
||||||
aria-describedby="deletionDateHelp"
|
|
||||||
formControlName="defaultDeletionDateTime"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
|
||||||
/>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template #expirationDateCustom>
|
|
||||||
<ng-container [ngSwitch]="browserPath">
|
|
||||||
<ng-container *ngSwitchCase="'firefox'">
|
|
||||||
<div class="flex flex-grow">
|
|
||||||
<input
|
|
||||||
id="expirationDateCustomFallback"
|
|
||||||
type="date"
|
|
||||||
name="ExpirationDateFallback"
|
|
||||||
aria-describedby="expirationDateHelp"
|
|
||||||
formControlName="fallbackExpirationDate"
|
|
||||||
[required]="!editMode"
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
id="expirationTimeCustomFallback"
|
|
||||||
type="time"
|
|
||||||
name="ExpirationTimeFallback"
|
|
||||||
formControlName="fallbackExpirationTime"
|
|
||||||
[required]="!editMode"
|
|
||||||
placeholder="HH:MM AM/PM"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchCase="'safari'">
|
|
||||||
<div class="flex flex-grow">
|
|
||||||
<input
|
|
||||||
id="expirationDateCustomFallback"
|
|
||||||
type="date"
|
|
||||||
name="ExpirationDateFallback"
|
|
||||||
aria-describedby="expirationDateHelp"
|
|
||||||
formControlName="fallbackExpirationDate"
|
|
||||||
[required]="!editMode"
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
id="expirationTimeCustomFallback"
|
|
||||||
formControlName="fallbackExpirationTime"
|
|
||||||
name="SafariExpirationTime"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
*ngFor="let o of safariExpirationTimePresetOptions"
|
|
||||||
[ngValue]="o.twentyFourHour"
|
|
||||||
>
|
|
||||||
{{ o.twelveHour }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchDefault>
|
|
||||||
<input
|
|
||||||
id="expirationDateCustom"
|
|
||||||
type="datetime-local"
|
|
||||||
name="ExpirationDate"
|
|
||||||
aria-describedby="expirationDateHelp"
|
|
||||||
formControlName="defaultExpirationDateTime"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
/>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
|
||||||
</ng-container>
|
|
@ -1,25 +0,0 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
|
||||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
|
||||||
import { ControlContainer, NgForm } from "@angular/forms";
|
|
||||||
|
|
||||||
import { EffluxDatesComponent as BaseEffluxDatesComponent } from "@bitwarden/angular/tools/send/efflux-dates.component";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-send-efflux-dates",
|
|
||||||
templateUrl: "efflux-dates.component.html",
|
|
||||||
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
|
|
||||||
})
|
|
||||||
export class EffluxDatesComponent extends BaseEffluxDatesComponent {
|
|
||||||
@Input() readonly inPopout: boolean;
|
|
||||||
@Output() popOutWindow = new EventEmitter();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
|
||||||
protected datePipe: DatePipe
|
|
||||||
) {
|
|
||||||
super(i18nService, platformUtilsService, datePipe);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" [formGroup]="formGroup">
|
||||||
<header>
|
<header>
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
|
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<span class="title">{{ title }}</span>
|
<span class="title">{{ title }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button type="submit" [disabled]="form.loading || disableSend">
|
<button type="submit">
|
||||||
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
|
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
|
||||||
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
@ -42,9 +42,8 @@
|
|||||||
<input
|
<input
|
||||||
id="name"
|
id="name"
|
||||||
type="text"
|
type="text"
|
||||||
name="Name"
|
formControlName="name"
|
||||||
aria-describedby="nameHelp"
|
aria-describedby="nameHelp"
|
||||||
[(ngModel)]="send.name"
|
|
||||||
[readonly]="disableSend"
|
[readonly]="disableSend"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -66,12 +65,9 @@
|
|||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
[(ngModel)]="send.type"
|
formControlName="type"
|
||||||
name="Type_{{ o.value }}"
|
|
||||||
id="type_{{ o.value }}"
|
id="type_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="typeChanged()"
|
|
||||||
[checked]="send.type === o.value"
|
|
||||||
[readonly]="disableSend"
|
[readonly]="disableSend"
|
||||||
/>
|
/>
|
||||||
<label for="type_{{ o.value }}">
|
<label for="type_{{ o.value }}">
|
||||||
@ -82,7 +78,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- File -->
|
<!-- File -->
|
||||||
<div class="box" *ngIf="send.type === sendType.File && (editMode || showFileSelector)">
|
<div class="box" *ngIf="type === sendType.File && (editMode || showFileSelector)">
|
||||||
<div class="box-content no-hover">
|
<div class="box-content no-hover">
|
||||||
<div class="box-content-row" *ngIf="editMode">
|
<div class="box-content-row" *ngIf="editMode">
|
||||||
<label for="file">{{ "file" | i18n }}</label>
|
<label for="file">{{ "file" | i18n }}</label>
|
||||||
@ -93,9 +89,8 @@
|
|||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
id="file"
|
id="file"
|
||||||
name="file"
|
formControlName="file"
|
||||||
aria-describedby="fileHelp"
|
aria-describedby="fileHelp"
|
||||||
required
|
|
||||||
[readonly]="disableSend"
|
[readonly]="disableSend"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -105,17 +100,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Text -->
|
<!-- Text -->
|
||||||
<div class="box" *ngIf="send.type === sendType.Text">
|
<div class="box" *ngIf="type === sendType.Text">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="text">{{ "sendTypeText" | i18n }}</label>
|
<label for="text">{{ "sendTypeText" | i18n }}</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="text"
|
id="text"
|
||||||
name="Text"
|
formControlName="text"
|
||||||
aria-describedby="textHelp"
|
aria-describedby="textHelp"
|
||||||
rows="6"
|
rows="6"
|
||||||
[(ngModel)]="send.text.text"
|
|
||||||
[readonly]="disableSend"
|
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -125,13 +118,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="hideText">{{ "sendHideText" | i18n }}</label>
|
<label for="hideText">{{ "sendHideText" | i18n }}</label>
|
||||||
<input
|
<input id="hideText" type="checkbox" name="HideText" formControlName="textHidden" />
|
||||||
id="hideText"
|
|
||||||
type="checkbox"
|
|
||||||
name="HideText"
|
|
||||||
[(ngModel)]="send.text.hidden"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -144,13 +131,7 @@
|
|||||||
<!-- Copy Link on Save -->
|
<!-- Copy Link on Save -->
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="copyOnSave">{{ "sendShareDesc" | i18n }}</label>
|
<label for="copyOnSave">{{ "sendShareDesc" | i18n }}</label>
|
||||||
<input
|
<input id="copyOnSave" type="checkbox" name="CopyOnSave" formControlName="copyLink" />
|
||||||
id="copyOnSave"
|
|
||||||
type="checkbox"
|
|
||||||
name="CopyOnSave"
|
|
||||||
[(ngModel)]="copyLink"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -170,15 +151,140 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div [hidden]="!showOptions">
|
<div [hidden]="!showOptions">
|
||||||
<app-send-efflux-dates
|
<!-- Deletion Date -->
|
||||||
[initialDeletionDate]="send.deletionDate"
|
<div class="box">
|
||||||
[initialExpirationDate]="send.expirationDate"
|
<div class="box-content">
|
||||||
[editMode]="editMode"
|
<ng-container *ngIf="!editMode">
|
||||||
[disabled]="disableSend"
|
<div class="box-content-row" appBoxRow>
|
||||||
(datesChanged)="setDates($event)"
|
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
||||||
(popOutWindow)="popOutWindow()"
|
<select
|
||||||
>
|
id="deletionDate"
|
||||||
</app-send-efflux-dates>
|
name="DeletionDateSelect"
|
||||||
|
aria-describedby="deletionDateHelp"
|
||||||
|
formControlName="selectedDeletionDatePreset"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">
|
||||||
|
{{ o.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box-content-row"
|
||||||
|
appBoxRow
|
||||||
|
*ngIf="formGroup.controls['selectedDeletionDatePreset'].value === 0"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="deletionDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="DeletionDate"
|
||||||
|
aria-describedby="deletionDateHelp"
|
||||||
|
formControlName="defaultDeletionDateTime"
|
||||||
|
required
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
||||||
|
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="deletionDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="DeletionDate"
|
||||||
|
aria-describedby="deletionDateHelp"
|
||||||
|
formControlName="defaultDeletionDateTime"
|
||||||
|
required
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="deletionDateHelp" class="box-footer">
|
||||||
|
{{ "deletionDateDesc" | i18n }}
|
||||||
|
<ng-container
|
||||||
|
*ngIf="
|
||||||
|
!inPopout &&
|
||||||
|
isFirefox &&
|
||||||
|
(editMode ||
|
||||||
|
(formGroup.controls['selectedDeletionDatePreset'].value === 0 && !editMode))
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<br />{{ "sendFirefoxCustomDatePopoutMessage1" | i18n }}
|
||||||
|
<a (click)="popOutWindow()">{{ "sendFirefoxCustomDatePopoutMessage2" | i18n }}</a>
|
||||||
|
{{ "sendFirefoxCustomDatePopoutMessage3" | i18n }}
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Expiration Date -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<ng-container *ngIf="!editMode">
|
||||||
|
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
||||||
|
<label for="editExpirationDate">{{ "expirationDate" | i18n }}</label>
|
||||||
|
<select
|
||||||
|
id="expirationDate"
|
||||||
|
name="ExpirationDateSelect"
|
||||||
|
aria-describedby="expirationDateHelp"
|
||||||
|
formControlName="selectedExpirationDatePreset"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">
|
||||||
|
{{ o.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box-content-row"
|
||||||
|
*ngIf="formGroup.controls['selectedExpirationDatePreset'].value === 0"
|
||||||
|
appBoxRow
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="expirationDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="ExpirationDate"
|
||||||
|
aria-describedby="expirationDateHelp"
|
||||||
|
formControlName="defaultExpirationDateTime"
|
||||||
|
required
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
[readOnly]="disableSend"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<div class="box-content-row" *ngIf="editMode" appBoxRow>
|
||||||
|
<div class="flex-label">
|
||||||
|
<label>{{ "expirationDate" | i18n }}</label>
|
||||||
|
<button type="button" *ngIf="!disableSend" appStopClick (click)="clearExpiration()">
|
||||||
|
{{ "clear" | i18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
id="expirationDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="ExpirationDate"
|
||||||
|
aria-describedby="expirationDateHelp"
|
||||||
|
formControlName="defaultExpirationDateTime"
|
||||||
|
required
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
[readOnly]="disableSend"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="expirationDateHelp" class="box-footer">
|
||||||
|
{{ "expirationDateDesc" | i18n }}
|
||||||
|
<ng-container
|
||||||
|
*ngIf="
|
||||||
|
!inPopout &&
|
||||||
|
isFirefox &&
|
||||||
|
(editMode ||
|
||||||
|
(formGroup.controls['selectedExpirationDatePreset'].value === 0 && !editMode))
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<br />{{ "sendFirefoxCustomDatePopoutMessage1" | i18n }}
|
||||||
|
<a (click)="popOutWindow()">{{ "sendFirefoxCustomDatePopoutMessage2" | i18n }}</a>
|
||||||
|
{{ "sendFirefoxCustomDatePopoutMessage3" | i18n }}
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Maximum Access Count -->
|
<!-- Maximum Access Count -->
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
@ -190,8 +296,7 @@
|
|||||||
type="number"
|
type="number"
|
||||||
name="MaximumAccessCount"
|
name="MaximumAccessCount"
|
||||||
aria-describedby="maximumAccessCountHelp"
|
aria-describedby="maximumAccessCountHelp"
|
||||||
[(ngModel)]="send.maxAccessCount"
|
formControlName="maxAccessCount"
|
||||||
[readonly]="disableSend"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -206,10 +311,9 @@
|
|||||||
<label for="currentAccessCount">{{ "currentAccessCount" | i18n }}</label>
|
<label for="currentAccessCount">{{ "currentAccessCount" | i18n }}</label>
|
||||||
<input
|
<input
|
||||||
id="currentAccessCount"
|
id="currentAccessCount"
|
||||||
readonly
|
|
||||||
type="text"
|
type="text"
|
||||||
name="CurrentAccessCount"
|
name="CurrentAccessCount"
|
||||||
[(ngModel)]="send.accessCount"
|
formControlName="accessCount"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -227,9 +331,8 @@
|
|||||||
name="Password"
|
name="Password"
|
||||||
aria-describedby="passwordHelp"
|
aria-describedby="passwordHelp"
|
||||||
class="monospaced"
|
class="monospaced"
|
||||||
[(ngModel)]="password"
|
formControlName="password"
|
||||||
appInputVerbatim
|
appInputVerbatim
|
||||||
[readonly]="disableSend"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons" *ngIf="!disableSend">
|
<div class="action-buttons" *ngIf="!disableSend">
|
||||||
@ -264,8 +367,7 @@
|
|||||||
name="Notes"
|
name="Notes"
|
||||||
aria-describedby="notesHelp"
|
aria-describedby="notesHelp"
|
||||||
rows="6"
|
rows="6"
|
||||||
[(ngModel)]="send.notes"
|
formControlName="notes"
|
||||||
[readonly]="disableSend"
|
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -278,13 +380,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="hideEmail">{{ "hideEmail" | i18n }}</label>
|
<label for="hideEmail">{{ "hideEmail" | i18n }}</label>
|
||||||
<input
|
<input id="hideEmail" type="checkbox" name="HideEmail" formControlName="hideEmail" />
|
||||||
id="hideEmail"
|
|
||||||
type="checkbox"
|
|
||||||
name="HideEmail"
|
|
||||||
[(ngModel)]="send.hideEmail"
|
|
||||||
[disabled]="(disableHideEmail && !send.hideEmail) || disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -293,13 +389,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="disableSend">{{ "sendDisableDesc" | i18n }}</label>
|
<label for="disableSend">{{ "sendDisableDesc" | i18n }}</label>
|
||||||
<input
|
<input id="disableSend" type="checkbox" name="DisableSend" formControlName="disabled" />
|
||||||
id="disableSend"
|
|
||||||
type="checkbox"
|
|
||||||
name="DisableSend"
|
|
||||||
[(ngModel)]="send.disabled"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { DatePipe, Location } from "@angular/common";
|
import { DatePipe, Location } from "@angular/common";
|
||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
import { FormBuilder } from "@angular/forms";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
@ -47,7 +48,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
|||||||
private popupUtilsService: PopupUtilsService,
|
private popupUtilsService: PopupUtilsService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
sendApiService: SendApiService,
|
sendApiService: SendApiService,
|
||||||
dialogService: DialogService
|
dialogService: DialogService,
|
||||||
|
formBuilder: FormBuilder
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
i18nService,
|
i18nService,
|
||||||
@ -60,7 +62,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
sendApiService,
|
sendApiService,
|
||||||
dialogService
|
dialogService,
|
||||||
|
formBuilder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,6 @@ import { ExportComponent } from "./tools/export/export.component";
|
|||||||
import { GeneratorComponent } from "./tools/generator.component";
|
import { GeneratorComponent } from "./tools/generator.component";
|
||||||
import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component";
|
import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component";
|
||||||
import { AddEditComponent as SendAddEditComponent } from "./tools/send/add-edit.component";
|
import { AddEditComponent as SendAddEditComponent } from "./tools/send/add-edit.component";
|
||||||
import { EffluxDatesComponent as SendEffluxDatesComponent } from "./tools/send/efflux-dates.component";
|
|
||||||
import { SendComponent } from "./tools/send/send.component";
|
import { SendComponent } from "./tools/send/send.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -87,7 +86,6 @@ import { SendComponent } from "./tools/send/send.component";
|
|||||||
SearchComponent,
|
SearchComponent,
|
||||||
SendAddEditComponent,
|
SendAddEditComponent,
|
||||||
SendComponent,
|
SendComponent,
|
||||||
SendEffluxDatesComponent,
|
|
||||||
SetPasswordComponent,
|
SetPasswordComponent,
|
||||||
SetPinComponent,
|
SetPinComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
<form #form [formGroup]="formGroup" (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="inner-content" *ngIf="send">
|
<div class="inner-content" *ngIf="send">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@ -16,14 +16,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="name">{{ "name" | i18n }}</label>
|
<label for="name">{{ "name" | i18n }}</label>
|
||||||
<input
|
<input id="name" type="text" name="Name" formControlName="name" appAutofocus />
|
||||||
id="name"
|
|
||||||
type="text"
|
|
||||||
name="Name"
|
|
||||||
[(ngModel)]="send.name"
|
|
||||||
appAutofocus
|
|
||||||
[readOnly]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-radio" *ngIf="!editMode">
|
<div class="box-content-row box-content-row-radio" *ngIf="!editMode">
|
||||||
<label class="radio-header">{{ "whatTypeOfSend" | i18n }}</label>
|
<label class="radio-header">{{ "whatTypeOfSend" | i18n }}</label>
|
||||||
@ -31,20 +24,16 @@
|
|||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
class="radio"
|
class="radio"
|
||||||
[(ngModel)]="send.type"
|
formControlName="type"
|
||||||
name="Type_{{ o.value }}"
|
|
||||||
id="type_{{ o.value }}"
|
id="type_{{ o.value }}"
|
||||||
[value]="o.value"
|
[value]="o.value"
|
||||||
(change)="typeChanged()"
|
|
||||||
[checked]="send.type === o.value"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
/>
|
||||||
<label class="unstyled" for="type_{{ o.value }}">
|
<label class="unstyled" for="type_{{ o.value }}">
|
||||||
{{ o.name }}
|
{{ o.name }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBowRow *ngIf="!editMode && send.type === sendType.File">
|
<div class="box-content-row" appBoxRow *ngIf="!editMode && type === sendType.File">
|
||||||
<label for="file">{{ "file" | i18n }}</label>
|
<label for="file">{{ "file" | i18n }}</label>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
@ -53,22 +42,20 @@
|
|||||||
name="file"
|
name="file"
|
||||||
aria-describedby="fileHelp"
|
aria-describedby="fileHelp"
|
||||||
required
|
required
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBowRow *ngIf="editMode && send.type === sendType.File">
|
<div class="box-content-row" appBoxRow *ngIf="editMode && type === sendType.File">
|
||||||
<label for="file">{{ "file" | i18n }}</label>
|
<label for="file">{{ "file" | i18n }}</label>
|
||||||
<div class="row-main">{{ send.file.fileName }} ({{ send.file.sizeName }})</div>
|
<div class="row-main">{{ send.file.fileName }} ({{ send.file.sizeName }})</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBoxRow *ngIf="send.type === sendType.Text">
|
<div class="box-content-row" appBoxRow *ngIf="type === sendType.Text">
|
||||||
<label for="text">{{ "text" | i18n }}</label>
|
<label for="text">{{ "text" | i18n }}</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="text"
|
id="text"
|
||||||
name="text"
|
name="text"
|
||||||
aria-describedby="textHelp"
|
aria-describedby="textHelp"
|
||||||
[(ngModel)]="send.text.text"
|
formControlName="text"
|
||||||
rows="6"
|
rows="6"
|
||||||
[readOnly]="disableSend"
|
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -83,13 +70,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="hideText">{{ "textHiddenByDefault" | i18n }}</label>
|
<label for="hideText">{{ "textHiddenByDefault" | i18n }}</label>
|
||||||
<input
|
<input id="hideText" name="hideText" type="checkbox" formControlName="textHidden" />
|
||||||
id="hideText"
|
|
||||||
name="hideText"
|
|
||||||
type="checkbox"
|
|
||||||
[(ngModel)]="send.text.hidden"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -112,14 +93,82 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div [hidden]="!showOptions">
|
<div [hidden]="!showOptions">
|
||||||
<app-send-efflux-dates
|
<div class="box">
|
||||||
[initialDeletionDate]="send.deletionDate"
|
<div class="box-content">
|
||||||
[initialExpirationDate]="send.expirationDate"
|
<div class="box-content-row" appBoxRow *ngIf="!editMode">
|
||||||
[editMode]="editMode"
|
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
||||||
[disabled]="disableSend"
|
<select
|
||||||
(datesChanged)="setDates($event)"
|
id="deletionDate"
|
||||||
>
|
name="DeletionDateSelect"
|
||||||
</app-send-efflux-dates>
|
aria-describedby="deletionDateHelp"
|
||||||
|
formControlName="selectedDeletionDatePreset"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">
|
||||||
|
{{ o.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<small id="deletionDateHelp" class="help-block">{{
|
||||||
|
"deletionDateDesc" | i18n
|
||||||
|
}}</small>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box-content-row"
|
||||||
|
*ngIf="formGroup.controls['selectedDeletionDatePreset'].value === 0 || editMode"
|
||||||
|
>
|
||||||
|
<label *ngIf="editMode" for="deletionDateCustom">{{ "deletionDate" | i18n }}</label>
|
||||||
|
<input
|
||||||
|
id="deletionDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="deletionDate"
|
||||||
|
aria-describedby="deletionDateCustomHelp"
|
||||||
|
formControlName="defaultDeletionDateTime"
|
||||||
|
required
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
<small id="deletionDateCustomHelp" class="help-block" *ngIf="editMode">{{
|
||||||
|
"deletionDateDesc" | i18n
|
||||||
|
}}</small>
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" appBoxRow *ngIf="!editMode">
|
||||||
|
<label for="expirationDate">{{ "expirationDate" | i18n }}</label>
|
||||||
|
<select
|
||||||
|
id="expirationDate"
|
||||||
|
name="expirationDateSelect"
|
||||||
|
aria-describedby="expirationDateHelp"
|
||||||
|
formControlName="selectedExpirationDatePreset"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">
|
||||||
|
{{ o.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<small id="expirationDateHelp" class="help-block">{{
|
||||||
|
"expirationDateDesc" | i18n
|
||||||
|
}}</small>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box-content-row"
|
||||||
|
*ngIf="formGroup.controls['selectedExpirationDatePreset'].value === 0 || editMode"
|
||||||
|
>
|
||||||
|
<label *ngIf="editMode" for="expirationDateCustom">{{
|
||||||
|
"expirationDate" | i18n
|
||||||
|
}}</label>
|
||||||
|
<input
|
||||||
|
id="expirationDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="expirationDate"
|
||||||
|
aria-describedby="expirationDateCustomHelp"
|
||||||
|
formControlName="defaultExpirationDateTime"
|
||||||
|
required
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
<small *ngIf="editMode" id="expirationDateCustomHelp" class="help-block">{{
|
||||||
|
"expirationDateDesc" | i18n
|
||||||
|
}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
@ -129,8 +178,7 @@
|
|||||||
type="number"
|
type="number"
|
||||||
name="maxAccessCount"
|
name="maxAccessCount"
|
||||||
aria-describedby="maxAccessCountHelp"
|
aria-describedby="maxAccessCountHelp"
|
||||||
[(ngModel)]="send.maxAccessCount"
|
formControlName="maxAccessCount"
|
||||||
[readOnly]="disableSend"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -154,8 +202,7 @@
|
|||||||
name="password"
|
name="password"
|
||||||
aria-describedby="passwordHelp"
|
aria-describedby="passwordHelp"
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
type="{{ showPassword ? 'text' : 'password' }}"
|
||||||
[(ngModel)]="password"
|
formControlName="password"
|
||||||
[readOnly]="disableSend"
|
|
||||||
appInputVerbatim
|
appInputVerbatim
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -167,7 +214,6 @@
|
|||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||||
[attr.aria-pressed]="showPassword"
|
[attr.aria-pressed]="showPassword"
|
||||||
(click)="togglePasswordVisible()"
|
(click)="togglePasswordVisible()"
|
||||||
[disabled]="disableSend"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-lg"
|
class="bwi bwi-lg"
|
||||||
@ -192,9 +238,8 @@
|
|||||||
id="notes"
|
id="notes"
|
||||||
name="notes"
|
name="notes"
|
||||||
aria-describedby="notesHelp"
|
aria-describedby="notesHelp"
|
||||||
[(ngModel)]="send.notes"
|
formControlName="notes"
|
||||||
rows="6"
|
rows="6"
|
||||||
[readOnly]="disableSend"
|
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -206,13 +251,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="hideEmail">{{ "hideEmail" | i18n }}</label>
|
<label for="hideEmail">{{ "hideEmail" | i18n }}</label>
|
||||||
<input
|
<input id="hideEmail" type="checkbox" name="HideEmail" formControlName="hideEmail" />
|
||||||
id="hideEmail"
|
|
||||||
type="checkbox"
|
|
||||||
name="HideEmail"
|
|
||||||
[(ngModel)]="send.hideEmail"
|
|
||||||
[disabled]="(disableHideEmail && !send.hideEmail) || disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -220,13 +259,7 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="disabled">{{ "disableSend" | i18n }}</label>
|
<label for="disabled">{{ "disableSend" | i18n }}</label>
|
||||||
<input
|
<input id="disabled" type="checkbox" name="disabled" formControlName="disabled" />
|
||||||
id="disabled"
|
|
||||||
type="checkbox"
|
|
||||||
name="disabled"
|
|
||||||
[(ngModel)]="send.disabled"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -238,17 +271,11 @@
|
|||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
||||||
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
|
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
|
||||||
<input id="link" name="link" [ngModel]="link" readonly />
|
<input id="link" name="link" formControlName="link" readonly />
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
<label for="copyLink">{{ "copySendLinkOnSave" | i18n }}</label>
|
<label for="copyLink">{{ "copySendLinkOnSave" | i18n }}</label>
|
||||||
<input
|
<input id="copyLink" name="copyLink" formControlName="copyLink" type="checkbox" />
|
||||||
id="copyLink"
|
|
||||||
name="copyLink"
|
|
||||||
[(ngModel)]="copyLink"
|
|
||||||
type="checkbox"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -259,13 +286,12 @@
|
|||||||
type="submit"
|
type="submit"
|
||||||
class="primary btn-submit"
|
class="primary btn-submit"
|
||||||
appA11yTitle="{{ 'save' | i18n }}"
|
appA11yTitle="{{ 'save' | i18n }}"
|
||||||
[disabled]="form.loading"
|
|
||||||
*ngIf="!disableSend"
|
*ngIf="!disableSend"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||||
<span><i class="bwi bwi-save-changes bwi-lg bwi-fw" aria-hidden="true"></i></span>
|
<span><i class="bwi bwi-save-changes bwi-lg bwi-fw" aria-hidden="true"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" (click)="cancel()" [disabled]="form.loading">
|
<button type="button" (click)="cancel()">
|
||||||
{{ "cancel" | i18n }}
|
{{ "cancel" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@ -29,7 +30,8 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
sendApiService: SendApiService,
|
sendApiService: SendApiService,
|
||||||
dialogService: DialogService
|
dialogService: DialogService,
|
||||||
|
formBuilder: FormBuilder
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
i18nService,
|
i18nService,
|
||||||
@ -42,7 +44,8 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
sendApiService,
|
sendApiService,
|
||||||
dialogService
|
dialogService,
|
||||||
|
formBuilder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +53,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
this.password = null;
|
this.password = null;
|
||||||
const send = await this.loadSend();
|
const send = await this.loadSend();
|
||||||
this.send = await send.decrypt();
|
this.send = await send.decrypt();
|
||||||
|
this.updateFormValues();
|
||||||
this.hasPassword = this.send.password != null && this.send.password.trim() !== "";
|
this.hasPassword = this.send.password != null && this.send.password.trim() !== "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,4 +69,11 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
this.i18nService.t("valueCopied", this.i18nService.t("sendLink"))
|
this.i18nService.t("valueCopied", this.i18nService.t("sendLink"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async resetAndLoad() {
|
||||||
|
this.sendId = null;
|
||||||
|
this.send = null;
|
||||||
|
await this.load();
|
||||||
|
this.updateFormValues();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
<ng-container [formGroup]="datesForm">
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row" appBoxRow *ngIf="!editMode">
|
|
||||||
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
|
||||||
<select
|
|
||||||
id="deletionDate"
|
|
||||||
name="DeletionDateSelect"
|
|
||||||
aria-describedby="deletionDateHelp"
|
|
||||||
formControlName="selectedDeletionDatePreset"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">{{ o.name }}</option>
|
|
||||||
</select>
|
|
||||||
<small id="deletionDateHelp" class="help-block">{{ "deletionDateDesc" | i18n }}</small>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" *ngIf="selectedDeletionDatePreset.value === 0 || editMode">
|
|
||||||
<label *ngIf="editMode" for="deletionDateCustom">{{ "deletionDate" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="deletionDateCustom"
|
|
||||||
type="datetime-local"
|
|
||||||
name="deletionDate"
|
|
||||||
aria-describedby="deletionDateCustomHelp"
|
|
||||||
formControlName="defaultDeletionDateTime"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
|
||||||
/>
|
|
||||||
<small id="deletionDateCustomHelp" class="help-block" *ngIf="editMode">{{
|
|
||||||
"deletionDateDesc" | i18n
|
|
||||||
}}</small>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" appBoxRow *ngIf="!editMode">
|
|
||||||
<label for="expirationDate">{{ "expirationDate" | i18n }}</label>
|
|
||||||
<select
|
|
||||||
id="expirationDate"
|
|
||||||
name="expirationDateSelect"
|
|
||||||
aria-describedby="expirationDateHelp"
|
|
||||||
formControlName="selectedExpirationDatePreset"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">{{ o.name }}</option>
|
|
||||||
</select>
|
|
||||||
<small id="expirationDateHelp" class="help-block">{{ "expirationDateDesc" | i18n }}</small>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" *ngIf="selectedExpirationDatePreset.value === 0 || editMode">
|
|
||||||
<label *ngIf="editMode" for="expirationDateCustom">{{ "expirationDate" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="expirationDateCustom"
|
|
||||||
type="datetime-local"
|
|
||||||
name="expirationDate"
|
|
||||||
aria-describedby="expirationDateCustomHelp"
|
|
||||||
formControlName="defaultExpirationDateTime"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
|
||||||
/>
|
|
||||||
<small *ngIf="editMode" id="expirationDateCustomHelp" class="help-block">{{
|
|
||||||
"expirationDateDesc" | i18n
|
|
||||||
}}</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
@ -1,38 +0,0 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
|
||||||
import { Component, OnChanges } from "@angular/core";
|
|
||||||
import { ControlContainer, NgForm } from "@angular/forms";
|
|
||||||
|
|
||||||
import { EffluxDatesComponent as BaseEffluxDatesComponent } from "@bitwarden/angular/tools/send/efflux-dates.component";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-send-efflux-dates",
|
|
||||||
templateUrl: "efflux-dates.component.html",
|
|
||||||
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
|
|
||||||
})
|
|
||||||
export class EffluxDatesComponent extends BaseEffluxDatesComponent implements OnChanges {
|
|
||||||
constructor(
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
|
||||||
protected datePipe: DatePipe
|
|
||||||
) {
|
|
||||||
super(i18nService, platformUtilsService, datePipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We reuse the same form on desktop and just swap content, so need to watch these to maintin proper values.
|
|
||||||
ngOnChanges() {
|
|
||||||
this.selectedExpirationDatePreset.setValue(0);
|
|
||||||
this.selectedDeletionDatePreset.setValue(0);
|
|
||||||
this.defaultDeletionDateTime.setValue(
|
|
||||||
this.datePipe.transform(new Date(this.initialDeletionDate), "yyyy-MM-ddTHH:mm")
|
|
||||||
);
|
|
||||||
if (this.initialExpirationDate) {
|
|
||||||
this.defaultExpirationDateTime.setValue(
|
|
||||||
this.datePipe.transform(new Date(this.initialExpirationDate), "yyyy-MM-ddTHH:mm")
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.defaultExpirationDateTime.setValue(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -91,12 +91,10 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
|
|||||||
this.searchBarService.setEnabled(false);
|
this.searchBarService.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSend() {
|
async addSend() {
|
||||||
this.action = Action.Add;
|
this.action = Action.Add;
|
||||||
if (this.addEditComponent != null) {
|
if (this.addEditComponent != null) {
|
||||||
this.addEditComponent.sendId = null;
|
await this.addEditComponent.resetAndLoad();
|
||||||
this.addEditComponent.send = null;
|
|
||||||
this.addEditComponent.load();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,6 @@ import { GeneratorComponent } from "../tools/generator.component";
|
|||||||
import { PasswordGeneratorHistoryComponent } from "../tools/password-generator-history.component";
|
import { PasswordGeneratorHistoryComponent } from "../tools/password-generator-history.component";
|
||||||
import { AccessComponent } from "../tools/send/access.component";
|
import { AccessComponent } from "../tools/send/access.component";
|
||||||
import { AddEditComponent as SendAddEditComponent } from "../tools/send/add-edit.component";
|
import { AddEditComponent as SendAddEditComponent } from "../tools/send/add-edit.component";
|
||||||
import { EffluxDatesComponent as SendEffluxDatesComponent } from "../tools/send/efflux-dates.component";
|
|
||||||
import { ToolsComponent } from "../tools/tools.component";
|
import { ToolsComponent } from "../tools/tools.component";
|
||||||
import { PasswordRepromptComponent } from "../vault/components/password-reprompt.component";
|
import { PasswordRepromptComponent } from "../vault/components/password-reprompt.component";
|
||||||
import { PremiumBadgeComponent } from "../vault/components/premium-badge.component";
|
import { PremiumBadgeComponent } from "../vault/components/premium-badge.component";
|
||||||
@ -198,7 +197,6 @@ import { SharedModule } from "./shared.module";
|
|||||||
SecurityKeysComponent,
|
SecurityKeysComponent,
|
||||||
SelectableAvatarComponent,
|
SelectableAvatarComponent,
|
||||||
SendAddEditComponent,
|
SendAddEditComponent,
|
||||||
SendEffluxDatesComponent,
|
|
||||||
SetPasswordComponent,
|
SetPasswordComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
ShareComponent,
|
ShareComponent,
|
||||||
@ -302,7 +300,6 @@ import { SharedModule } from "./shared.module";
|
|||||||
SecurityKeysComponent,
|
SecurityKeysComponent,
|
||||||
SelectableAvatarComponent,
|
SelectableAvatarComponent,
|
||||||
SendAddEditComponent,
|
SendAddEditComponent,
|
||||||
SendEffluxDatesComponent,
|
|
||||||
SetPasswordComponent,
|
SetPasswordComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
ShareComponent,
|
ShareComponent,
|
||||||
|
@ -1,303 +1,276 @@
|
|||||||
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="sendAddEditTitle">
|
<form
|
||||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
[formGroup]="formGroup"
|
||||||
<form
|
[bitSubmit]="submitAndClose"
|
||||||
class="modal-content"
|
[appApiAction]="formPromise"
|
||||||
#form
|
autocomplete="off"
|
||||||
(ngSubmit)="submit()"
|
>
|
||||||
[appApiAction]="formPromise"
|
<bit-dialog dialogSize="large">
|
||||||
ngNativeValidate
|
<span bitDialogTitle>
|
||||||
autocomplete="off"
|
{{ title }}
|
||||||
>
|
</span>
|
||||||
<div class="modal-header">
|
<span bitDialogContent *ngIf="send">
|
||||||
<h1 class="modal-title" id="sendAddEditTitle">{{ title }}</h1>
|
<bit-callout *ngIf="disableSend">
|
||||||
<button
|
{{ "sendDisabledWarning" | i18n }}
|
||||||
type="button"
|
</bit-callout>
|
||||||
class="close"
|
<bit-callout *ngIf="!disableSend && disableHideEmail">
|
||||||
data-dismiss="modal"
|
{{ "sendOptionsPolicyInEffect" | i18n }}
|
||||||
appA11yTitle="{{ 'close' | i18n }}"
|
<ul class="tw-mb-0">
|
||||||
>
|
<li>{{ "sendDisableHideEmailInEffect" | i18n }}</li>
|
||||||
<span aria-hidden="true">×</span>
|
</ul>
|
||||||
</button>
|
</bit-callout>
|
||||||
|
<bit-form-field class="tw-w-1/2">
|
||||||
|
<bit-label for="name">{{ "name" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" formControlName="name" />
|
||||||
|
<bit-hint>{{ "sendNameDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
<div class="tw-flex" *ngIf="!editMode">
|
||||||
|
<bit-radio-group formControlName="type">
|
||||||
|
<bit-label>{{ "whatTypeOfSend" | i18n }}</bit-label>
|
||||||
|
|
||||||
|
<bit-radio-button
|
||||||
|
*ngFor="let o of typeOptions"
|
||||||
|
id="type_{{ o.value }}"
|
||||||
|
class="tw-block"
|
||||||
|
[value]="o.value"
|
||||||
|
>
|
||||||
|
<bit-label>{{ o.name }}</bit-label>
|
||||||
|
</bit-radio-button>
|
||||||
|
</bit-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" *ngIf="send">
|
<!-- Text -->
|
||||||
<app-callout *ngIf="disableSend">
|
<ng-container *ngIf="type === sendType.Text">
|
||||||
<span>{{ "sendDisabledWarning" | i18n }}</span>
|
<bit-form-field>
|
||||||
</app-callout>
|
<bit-label for="text">{{ "sendTypeText" | i18n }}</bit-label>
|
||||||
<app-callout *ngIf="!disableSend && disableHideEmail">
|
<textarea bitInput id="text" rows="6" formControlName="text"></textarea>
|
||||||
<span>{{ "sendOptionsPolicyInEffect" | i18n }}</span>
|
<bit-hint>{{ "sendTextDesc" | i18n }}</bit-hint>
|
||||||
<ul class="mb-0">
|
</bit-form-field>
|
||||||
<li>{{ "sendDisableHideEmailInEffect" | i18n }}</li>
|
<bit-form-control>
|
||||||
</ul>
|
<input bitCheckbox type="checkbox" formControlName="textHidden" />
|
||||||
</app-callout>
|
<bit-label>{{ "textHiddenByDefault" | i18n }}</bit-label>
|
||||||
<div class="row">
|
</bit-form-control>
|
||||||
<div class="col-6 form-group">
|
</ng-container>
|
||||||
<label for="name">{{ "name" | i18n }}</label>
|
<!-- File -->
|
||||||
<input
|
<ng-container *ngIf="type === sendType.File">
|
||||||
id="name"
|
<div class="tw-flex">
|
||||||
class="form-control"
|
<div *ngIf="editMode">
|
||||||
type="text"
|
<bit-label>{{ "file" | i18n }}</bit-label>
|
||||||
name="Name"
|
<p bitTypography="body1" class="tw-mb-0">
|
||||||
[(ngModel)]="send.name"
|
|
||||||
required
|
|
||||||
[readOnly]="disableSend"
|
|
||||||
/>
|
|
||||||
<small class="form-text text-muted">{{ "sendNameDesc" | i18n }}</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" *ngIf="!editMode">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label>{{ "whatTypeOfSend" | i18n }}</label>
|
|
||||||
<div class="form-check" *ngFor="let o of typeOptions">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="radio"
|
|
||||||
[(ngModel)]="send.type"
|
|
||||||
name="Type_{{ o.value }}"
|
|
||||||
id="type_{{ o.value }}"
|
|
||||||
[value]="o.value"
|
|
||||||
(change)="typeChanged()"
|
|
||||||
[checked]="send.type === o.value"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="type_{{ o.value }}">
|
|
||||||
{{ o.name }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Text -->
|
|
||||||
<ng-container *ngIf="send.type === sendType.Text">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text">{{ "sendTypeText" | i18n }}</label>
|
|
||||||
<textarea
|
|
||||||
id="text"
|
|
||||||
name="Text.Text"
|
|
||||||
rows="6"
|
|
||||||
[(ngModel)]="send.text.text"
|
|
||||||
class="form-control"
|
|
||||||
[readOnly]="disableSend"
|
|
||||||
></textarea>
|
|
||||||
<small class="form-text text-muted">{{ "sendTextDesc" | i18n }}</small>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-check">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
[(ngModel)]="send.text.hidden"
|
|
||||||
id="text-hidden"
|
|
||||||
name="Text.Hidden"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="text-hidden">{{
|
|
||||||
"textHiddenByDefault" | i18n
|
|
||||||
}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<!-- File -->
|
|
||||||
<ng-container *ngIf="send.type === sendType.File">
|
|
||||||
<div class="form-group">
|
|
||||||
<div *ngIf="editMode">
|
|
||||||
<strong class="d-block">{{ "file" | i18n }}</strong>
|
|
||||||
{{ send.file.fileName }} ({{ send.file.sizeName }})
|
{{ send.file.fileName }} ({{ send.file.sizeName }})
|
||||||
</div>
|
</p>
|
||||||
<div *ngIf="!editMode">
|
|
||||||
<label for="file">{{ "file" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
id="file"
|
|
||||||
class="form-control-file"
|
|
||||||
name="file"
|
|
||||||
required
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
<small class="form-text text-muted"
|
|
||||||
>{{ "sendFileDesc" | i18n }} {{ "maxFileSize" | i18n }}</small
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
<bit-form-field *ngIf="!editMode">
|
||||||
<h3 class="mt-5">{{ "share" | i18n }}</h3>
|
<bit-label>{{ "file" | i18n }}</bit-label>
|
||||||
<div class="form-group" *ngIf="link">
|
<div>
|
||||||
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
|
<button bitButton type="button" buttonType="secondary" (click)="fileSelector.click()">
|
||||||
<input type="text" readonly id="link" name="Link" [ngModel]="link" class="form-control" />
|
{{ "chooseFile" | i18n }}
|
||||||
</div>
|
</button>
|
||||||
<div class="form-group">
|
{{ selectedFile?.name ?? ("noFileChosen" | i18n) }}
|
||||||
<div class="form-check">
|
</div>
|
||||||
<input
|
<input
|
||||||
class="form-check-input"
|
bitInput
|
||||||
type="checkbox"
|
#fileSelector
|
||||||
[(ngModel)]="copyLink"
|
hidden
|
||||||
id="copy-link"
|
type="file"
|
||||||
name="CopyLink"
|
id="file"
|
||||||
|
name="file"
|
||||||
|
formControlName="file"
|
||||||
|
(change)="setSelectedFile($event)"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="copy-link">{{
|
<bit-hint>{{ "sendFileDesc" | i18n }} {{ "maxFileSize" | i18n }}</bit-hint>
|
||||||
"copySendLinkOnSave" | i18n
|
</bit-form-field>
|
||||||
}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
</ng-container>
|
||||||
id="options-header"
|
<h4 bitTypography="h4" class="tw-mt-5">{{ "share" | i18n }}</h4>
|
||||||
class="section-header d-flex flex-row align-items-center mt-5"
|
|
||||||
(click)="toggleOptions()"
|
<bit-form-field *ngIf="link">
|
||||||
>
|
<bit-label for="link">{{ "sendLinkLabel" | i18n }}</bit-label>
|
||||||
<h3 class="mb-0 mr-2">
|
<input bitInput type="text" readonly formControlName="link" />
|
||||||
<button type="button" appStopClick class="header-expandable">
|
</bit-form-field>
|
||||||
<i
|
|
||||||
class="bwi"
|
<bit-form-control>
|
||||||
aria-hidden="true"
|
<input bitCheckbox type="checkbox" formControlName="copyLink" />
|
||||||
[ngClass]="{ 'bwi-angle-right': !showOptions, 'bwi-angle-down': showOptions }"
|
<bit-label>{{ "copySendLinkOnSave" | i18n }}</bit-label>
|
||||||
></i>
|
</bit-form-control>
|
||||||
{{ "options" | i18n }}
|
<div class="tw-mt-5 tw-flex" (click)="toggleOptions()">
|
||||||
</button>
|
<h4 bitTypography="h4" class="tw-mb-0 tw-mr-2">
|
||||||
</h3>
|
<button type="button" bitLink appStopClick>
|
||||||
</div>
|
|
||||||
<div id="options" [hidden]="!showOptions">
|
|
||||||
<app-send-efflux-dates
|
|
||||||
[initialDeletionDate]="send.deletionDate"
|
|
||||||
[initialExpirationDate]="send.expirationDate"
|
|
||||||
[editMode]="editMode"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
(datesChanged)="setDates($event)"
|
|
||||||
>
|
|
||||||
</app-send-efflux-dates>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="maxAccessCount">{{ "maxAccessCount" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="maxAccessCount"
|
|
||||||
class="form-control"
|
|
||||||
type="number"
|
|
||||||
name="MaxAccessCount"
|
|
||||||
[(ngModel)]="send.maxAccessCount"
|
|
||||||
min="1"
|
|
||||||
[readOnly]="disableSend"
|
|
||||||
/>
|
|
||||||
<div class="form-text text-muted small">{{ "maxAccessCountDesc" | i18n }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 form-group" *ngIf="editMode">
|
|
||||||
<label for="accessCount">{{ "currentAccessCount" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="accessCount"
|
|
||||||
class="form-control"
|
|
||||||
type="text"
|
|
||||||
name="AccessCount"
|
|
||||||
readonly
|
|
||||||
[(ngModel)]="send.accessCount"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="password" *ngIf="!hasPassword">{{ "password" | i18n }}</label>
|
|
||||||
<label for="password" *ngIf="hasPassword">{{ "newPassword" | i18n }}</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input
|
|
||||||
id="password"
|
|
||||||
class="form-control text-monospace"
|
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
|
||||||
name="Password"
|
|
||||||
[(ngModel)]="password"
|
|
||||||
[readOnly]="disableSend"
|
|
||||||
/>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
|
||||||
(click)="togglePasswordVisible()"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lg"
|
|
||||||
aria-hidden="true"
|
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
|
||||||
></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-text text-muted small">{{ "sendPasswordDesc" | i18n }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="notes">{{ "notes" | i18n }}</label>
|
|
||||||
<textarea
|
|
||||||
id="notes"
|
|
||||||
name="Notes"
|
|
||||||
rows="6"
|
|
||||||
[(ngModel)]="send.notes"
|
|
||||||
class="form-control"
|
|
||||||
[readOnly]="disableSend"
|
|
||||||
></textarea>
|
|
||||||
<div class="form-text text-muted small">{{ "sendNotesDesc" | i18n }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-check">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
[(ngModel)]="send.hideEmail"
|
|
||||||
id="hideEmail"
|
|
||||||
name="HideEmail"
|
|
||||||
[disabled]="(disableHideEmail && !send.hideEmail) || disableSend"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="hideEmail">
|
|
||||||
{{ "hideEmail" | i18n }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-check">
|
|
||||||
<input
|
|
||||||
class="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
[(ngModel)]="send.disabled"
|
|
||||||
id="disabled"
|
|
||||||
name="Disabled"
|
|
||||||
[disabled]="disableSend"
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="disabled">{{ "disableThisSend" | i18n }}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary btn-submit manual"
|
|
||||||
[ngClass]="{ loading: form.loading }"
|
|
||||||
[disabled]="form.loading || disableSend"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
|
||||||
<span>{{ "save" | i18n }}</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
|
||||||
{{ "cancel" | i18n }}
|
|
||||||
</button>
|
|
||||||
<div class="ml-auto" *ngIf="send">
|
|
||||||
<button
|
|
||||||
#deleteBtn
|
|
||||||
type="button"
|
|
||||||
(click)="delete()"
|
|
||||||
class="btn btn-outline-danger"
|
|
||||||
appA11yTitle="{{ 'delete' | i18n }}"
|
|
||||||
*ngIf="editMode"
|
|
||||||
[disabled]="$any(deleteBtn).loading"
|
|
||||||
[appApiAction]="deletePromise"
|
|
||||||
>
|
|
||||||
<i
|
<i
|
||||||
class="bwi bwi-trash bwi-lg bwi-fw"
|
class="bwi"
|
||||||
[hidden]="$any(deleteBtn).loading"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
|
||||||
[hidden]="!$any(deleteBtn).loading"
|
|
||||||
title="{{ 'loading' | i18n }}"
|
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
[ngClass]="{ 'bwi-angle-right': !showOptions, 'bwi-angle-down': showOptions }"
|
||||||
></i>
|
></i>
|
||||||
|
{{ "options" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<div id="options" [hidden]="!showOptions">
|
||||||
</div>
|
<div class="tw-flex">
|
||||||
</div>
|
<div *ngIf="!editMode" class="tw-w-1/2 tw-pr-3">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label for="deletionDate">{{ "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="formGroup.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>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="editMode" class="tw-w-1/2 tw-pr-3">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label for="deletionDate">{{ "deletionDate" | i18n }}</bit-label>
|
||||||
|
<input
|
||||||
|
bitInput
|
||||||
|
id="deletionDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="DeletionDate"
|
||||||
|
formControlName="defaultDeletionDateTime"
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
<bit-hint>{{ "deletionDateDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!editMode" class="tw-w-1/2 tw-pl-3">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label for="expirationDate">
|
||||||
|
{{ "expirationDate" | i18n }}
|
||||||
|
</bit-label>
|
||||||
|
<bit-select
|
||||||
|
bitInput
|
||||||
|
id="expirationDate"
|
||||||
|
name="SelectedExpirationDatePreset"
|
||||||
|
formControlName="selectedExpirationDatePreset"
|
||||||
|
>
|
||||||
|
<bit-option
|
||||||
|
*ngFor="let e of expirationDatePresets"
|
||||||
|
[value]="e.value"
|
||||||
|
[label]="e.name"
|
||||||
|
></bit-option>
|
||||||
|
</bit-select>
|
||||||
|
<ng-container *ngIf="formGroup.controls['selectedExpirationDatePreset'].value === 0">
|
||||||
|
<input
|
||||||
|
bitInput
|
||||||
|
id="expirationDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="ExpirationDate"
|
||||||
|
formControlName="defaultExpirationDateTime"
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
</ng-container>
|
||||||
|
<bit-hint>{{ "expirationDateDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="editMode" class="tw-w-1/2 tw-pl-3">
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label class="tw-flex" for="expirationDate">
|
||||||
|
{{ "expirationDate" | i18n }}
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
bitLink
|
||||||
|
appStopClick
|
||||||
|
(click)="clearExpiration()"
|
||||||
|
*ngIf="!disableSend"
|
||||||
|
class="tw-ml-auto"
|
||||||
|
>
|
||||||
|
{{ "clear" | i18n }}
|
||||||
|
</button>
|
||||||
|
</bit-label>
|
||||||
|
<input
|
||||||
|
bitInput
|
||||||
|
id="expirationDateCustom"
|
||||||
|
type="datetime-local"
|
||||||
|
name="ExpirationDate"
|
||||||
|
formControlName="defaultExpirationDateTime"
|
||||||
|
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||||
|
/>
|
||||||
|
<bit-hint>{{ "expirationDateDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tw-flex">
|
||||||
|
<bit-form-field class="tw-w-1/2 tw-pr-3">
|
||||||
|
<bit-label for="maxAccessCount">{{ "maxAccessCount" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="number" formControlName="maxAccessCount" min="1" />
|
||||||
|
<bit-hint>{{ "maxAccessCountDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
<bit-form-field class="tw-w-1/2 tw-pl-3" *ngIf="editMode">
|
||||||
|
<bit-label for="accessCount">{{ "currentAccessCount" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" formControlName="accessCount" readonly />
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="tw-flex">
|
||||||
|
<bit-form-field class="tw-w-1/2 tw-pr-3">
|
||||||
|
<bit-label for="password" *ngIf="!hasPassword">{{ "password" | i18n }}</bit-label>
|
||||||
|
<bit-label for="password" *ngIf="hasPassword">{{ "newPassword" | i18n }}</bit-label>
|
||||||
|
|
||||||
|
<input bitInput type="password" formControlName="password" />
|
||||||
|
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||||
|
<bit-hint>{{ "sendPasswordDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>{{ "notes" | i18n }}</bit-label>
|
||||||
|
<textarea bitInput formControlName="notes" rows="6"></textarea>
|
||||||
|
<bit-hint>{{ "sendNotesDesc" | 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-control>
|
||||||
|
<input bitCheckbox type="checkbox" formControlName="disabled" />
|
||||||
|
<bit-label>{{ "disableThisSend" | i18n }}</bit-label>
|
||||||
|
</bit-form-control>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<ng-container bitDialogFooter>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
bitButton
|
||||||
|
bitFormButton
|
||||||
|
[appA11yTitle]="'save' | i18n"
|
||||||
|
buttonType="primary"
|
||||||
|
>
|
||||||
|
{{ "save" | i18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
bitButton
|
||||||
|
buttonType="secondary"
|
||||||
|
[appA11yTitle]="'cancel' | i18n"
|
||||||
|
bitDialogClose
|
||||||
|
>
|
||||||
|
{{ "cancel" | i18n }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
*ngIf="editMode"
|
||||||
|
type="button"
|
||||||
|
class="tw-ml-auto"
|
||||||
|
bitIconButton="bwi-trash"
|
||||||
|
buttonType="danger"
|
||||||
|
[appA11yTitle]="'delete' | i18n"
|
||||||
|
[bitAction]="deleteAndClose"
|
||||||
|
></button>
|
||||||
|
</ng-container>
|
||||||
|
</bit-dialog>
|
||||||
|
</form>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog";
|
||||||
import { DatePipe } from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import { Component } from "@angular/core";
|
import { Component, Inject } from "@angular/core";
|
||||||
|
import { FormBuilder } from "@angular/forms";
|
||||||
|
|
||||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@ -19,6 +21,7 @@ import { DialogService } from "@bitwarden/components";
|
|||||||
})
|
})
|
||||||
export class AddEditComponent extends BaseAddEditComponent {
|
export class AddEditComponent extends BaseAddEditComponent {
|
||||||
override componentName = "app-send-add-edit";
|
override componentName = "app-send-add-edit";
|
||||||
|
protected selectedFile: File;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
@ -31,7 +34,10 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
sendApiService: SendApiService,
|
sendApiService: SendApiService,
|
||||||
dialogService: DialogService
|
dialogService: DialogService,
|
||||||
|
formBuilder: FormBuilder,
|
||||||
|
protected dialogRef: DialogRef,
|
||||||
|
@Inject(DIALOG_DATA) params: { sendId: string }
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
i18nService,
|
i18nService,
|
||||||
@ -44,8 +50,11 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService,
|
||||||
sendApiService,
|
sendApiService,
|
||||||
dialogService
|
dialogService,
|
||||||
|
formBuilder
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.sendId = params.sendId;
|
||||||
}
|
}
|
||||||
|
|
||||||
async copyLinkToClipboard(link: string): Promise<void | boolean> {
|
async copyLinkToClipboard(link: string): Promise<void | boolean> {
|
||||||
@ -55,4 +64,29 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
window.setTimeout(() => resolve(super.copyLinkToClipboard(link)), 500);
|
window.setTimeout(() => resolve(super.copyLinkToClipboard(link)), 500);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setSelectedFile(event: Event) {
|
||||||
|
const fileInputEl = <HTMLInputElement>event.target;
|
||||||
|
const file = fileInputEl.files.length > 0 ? fileInputEl.files[0] : null;
|
||||||
|
this.selectedFile = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
submitAndClose = async () => {
|
||||||
|
this.formGroup.markAllAsTouched();
|
||||||
|
if (this.formGroup.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const success = await this.submit();
|
||||||
|
if (success) {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteAndClose = async () => {
|
||||||
|
const success = await this.delete();
|
||||||
|
if (success) {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,188 +0,0 @@
|
|||||||
<div class="row" [formGroup]="datesForm">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
|
||||||
<ng-template #deletionDateCustom>
|
|
||||||
<ng-container [ngSwitch]="browserPath">
|
|
||||||
<ng-container *ngSwitchCase="'firefox'">
|
|
||||||
<div class="d-flex justify-content-around">
|
|
||||||
<input
|
|
||||||
id="deletionDateCustomFallback"
|
|
||||||
class="form-control mt-1"
|
|
||||||
type="date"
|
|
||||||
name="DeletionDateFallback"
|
|
||||||
formControlName="fallbackDeletionDate"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
id="deletionTimeCustomFallback"
|
|
||||||
class="form-control mt-1 ml-1"
|
|
||||||
type="time"
|
|
||||||
name="DeletionTimeDate"
|
|
||||||
formControlName="fallbackDeletionTime"
|
|
||||||
required
|
|
||||||
placeholder="HH:MM AM/PM"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchCase="'safari'">
|
|
||||||
<div class="d-flex justify-content-around">
|
|
||||||
<input
|
|
||||||
id="deletionDateCustomFallback"
|
|
||||||
class="form-control mt-1"
|
|
||||||
type="date"
|
|
||||||
name="DeletionDateFallback"
|
|
||||||
formControlName="fallbackDeletionDate"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
id="deletionTimeCustomFallback"
|
|
||||||
class="form-control mt-1 ml-1"
|
|
||||||
[required]="!editMode"
|
|
||||||
formControlName="fallbackDeletionTime"
|
|
||||||
name="SafariDeletionTime"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
*ngFor="let o of safariDeletionTimePresetOptions"
|
|
||||||
[ngValue]="o.twentyFourHour"
|
|
||||||
>
|
|
||||||
{{ o.twelveHour }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchDefault>
|
|
||||||
<input
|
|
||||||
id="deletionDateCustom"
|
|
||||||
class="form-control mt-1"
|
|
||||||
type="datetime-local"
|
|
||||||
name="DeletionDate"
|
|
||||||
formControlName="defaultDeletionDateTime"
|
|
||||||
required
|
|
||||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
/>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
|
||||||
<div *ngIf="!editMode">
|
|
||||||
<select
|
|
||||||
id="deletionDate"
|
|
||||||
name="SelectedDeletionDatePreset"
|
|
||||||
formControlName="selectedDeletionDatePreset"
|
|
||||||
class="form-control"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">{{ o.name }}</option>
|
|
||||||
</select>
|
|
||||||
<ng-container *ngIf="selectedDeletionDatePreset.value === 0">
|
|
||||||
<ng-container *ngTemplateOutlet="deletionDateCustom"> </ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="editMode">
|
|
||||||
<ng-container *ngTemplateOutlet="deletionDateCustom"> </ng-container>
|
|
||||||
</div>
|
|
||||||
<div class="form-text text-muted small">{{ "deletionDateDesc" | i18n }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<div class="d-flex">
|
|
||||||
<label for="expirationDate">{{ "expirationDate" | i18n }}</label>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
appStopClick
|
|
||||||
(click)="clearExpiration()"
|
|
||||||
class="ml-auto"
|
|
||||||
*ngIf="editMode && !disabled"
|
|
||||||
>
|
|
||||||
{{ "clear" | i18n }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<ng-template #expirationDateCustom>
|
|
||||||
<ng-container [ngSwitch]="browserPath">
|
|
||||||
<div *ngSwitchCase="'firefox'" class="d-flex justify-content-around">
|
|
||||||
<input
|
|
||||||
id="expirationDateCustomFallback"
|
|
||||||
class="form-control mt-1"
|
|
||||||
type="date"
|
|
||||||
name="ExpirationDateFallback"
|
|
||||||
formControlName="fallbackExpirationDate"
|
|
||||||
[required]="!editMode"
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
id="expirationTimeCustomFallback"
|
|
||||||
class="form-control mt-1 ml-1"
|
|
||||||
type="time"
|
|
||||||
name="ExpirationTimeFallback"
|
|
||||||
formControlName="fallbackExpirationTime"
|
|
||||||
[required]="!editMode"
|
|
||||||
placeholder="HH:MM AM/PM"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<!-- non-default cases are not showing up -->
|
|
||||||
<div *ngSwitchCase="'safari'" class="d-flex justify-content-around">
|
|
||||||
<input
|
|
||||||
id="expirationDateCustomFallback"
|
|
||||||
class="form-control mt-1"
|
|
||||||
type="date"
|
|
||||||
name="ExpirationDateFallback"
|
|
||||||
formControlName="fallbackExpirationDate"
|
|
||||||
[required]="!editMode"
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
data-date-format="mm/dd/yyyy"
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
id="expirationTimeCustomFallback"
|
|
||||||
class="form-control mt-1 ml-1"
|
|
||||||
[required]="!editMode"
|
|
||||||
formControlName="fallbackExpirationTime"
|
|
||||||
name="SafariExpirationTime"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
*ngFor="let o of safariExpirationTimePresetOptions"
|
|
||||||
[ngValue]="o.twentyFourHour"
|
|
||||||
>
|
|
||||||
{{ o.twelveHour }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<ng-container *ngSwitchDefault>
|
|
||||||
<input
|
|
||||||
id="expirationDateCustom"
|
|
||||||
class="form-control mt-1"
|
|
||||||
type="datetime-local"
|
|
||||||
name="ExpirationDate"
|
|
||||||
formControlName="defaultExpirationDateTime"
|
|
||||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
|
||||||
[readOnly]="disabled"
|
|
||||||
/>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
|
||||||
<div *ngIf="!editMode">
|
|
||||||
<select
|
|
||||||
id="expirationDate"
|
|
||||||
name="SelectedExpirationDatePreset"
|
|
||||||
formControlName="selectedExpirationDatePreset"
|
|
||||||
class="form-control"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">{{ o.name }}</option>
|
|
||||||
</select>
|
|
||||||
<ng-container *ngIf="selectedExpirationDatePreset.value === 0">
|
|
||||||
<ng-container *ngTemplateOutlet="expirationDateCustom"> </ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="editMode">
|
|
||||||
<ng-container *ngTemplateOutlet="expirationDateCustom"> </ng-container>
|
|
||||||
</div>
|
|
||||||
<div class="form-text text-muted small">{{ "expirationDateDesc" | i18n }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,22 +0,0 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
|
||||||
import { Component } from "@angular/core";
|
|
||||||
import { ControlContainer, NgForm } from "@angular/forms";
|
|
||||||
|
|
||||||
import { EffluxDatesComponent as BaseEffluxDatesComponent } from "@bitwarden/angular/tools/send/efflux-dates.component";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-send-efflux-dates",
|
|
||||||
templateUrl: "efflux-dates.component.html",
|
|
||||||
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
|
|
||||||
})
|
|
||||||
export class EffluxDatesComponent extends BaseEffluxDatesComponent {
|
|
||||||
constructor(
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
|
||||||
protected datePipe: DatePipe
|
|
||||||
) {
|
|
||||||
super(i18nService, platformUtilsService, datePipe);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
import { Component, NgZone, ViewChild, ViewContainerRef } from "@angular/core";
|
import { Component, NgZone, ViewChild, ViewContainerRef } from "@angular/core";
|
||||||
|
import { lastValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||||
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
|
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
|
||||||
@ -98,29 +99,17 @@ export class SendComponent extends BaseSendComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const component = await this.editSend(null);
|
await this.editSend(null);
|
||||||
component.type = this.type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async editSend(send: SendView) {
|
async editSend(send: SendView) {
|
||||||
const [modal, childComponent] = await this.modalService.openViewRef(
|
const dialog = this.dialogService.open(AddEditComponent, {
|
||||||
AddEditComponent,
|
data: {
|
||||||
this.sendAddEditModalRef,
|
sendId: send == null ? null : send.id,
|
||||||
(comp) => {
|
},
|
||||||
comp.sendId = send == null ? null : send.id;
|
});
|
||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
|
||||||
comp.onSavedSend.subscribe(async () => {
|
|
||||||
modal.close();
|
|
||||||
await this.load();
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
|
||||||
comp.onDeletedSend.subscribe(async () => {
|
|
||||||
modal.close();
|
|
||||||
await this.load();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return childComponent;
|
await lastValueFrom(dialog.closed);
|
||||||
|
await this.load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||||
|
import { FormBuilder, Validators } from "@angular/forms";
|
||||||
import { Subject, takeUntil } from "rxjs";
|
import { Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@ -20,6 +21,23 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s
|
|||||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class AddEditComponent implements OnInit, OnDestroy {
|
export class AddEditComponent implements OnInit, OnDestroy {
|
||||||
@Input() sendId: string;
|
@Input() sendId: string;
|
||||||
@ -29,12 +47,25 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
@Output() onDeletedSend = new EventEmitter<SendView>();
|
@Output() onDeletedSend = new EventEmitter<SendView>();
|
||||||
@Output() onCancelled = new EventEmitter<SendView>();
|
@Output() onCancelled = new EventEmitter<SendView>();
|
||||||
|
|
||||||
|
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 },
|
||||||
|
];
|
||||||
|
|
||||||
|
expirationDatePresets: DatePresetSelectOption[] = [
|
||||||
|
{ name: this.i18nService.t("never"), value: DatePreset.Never },
|
||||||
|
...this.deletionDatePresets,
|
||||||
|
];
|
||||||
|
|
||||||
copyLink = false;
|
copyLink = false;
|
||||||
disableSend = false;
|
disableSend = false;
|
||||||
disableHideEmail = false;
|
disableHideEmail = false;
|
||||||
send: SendView;
|
send: SendView;
|
||||||
deletionDate: string;
|
|
||||||
expirationDate: string;
|
|
||||||
hasPassword: boolean;
|
hasPassword: boolean;
|
||||||
password: string;
|
password: string;
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
@ -51,6 +82,27 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
private sendLinkBaseUrl: string;
|
private sendLinkBaseUrl: string;
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
protected formGroup = this.formBuilder.group({
|
||||||
|
name: ["", Validators.required],
|
||||||
|
text: [],
|
||||||
|
textHidden: [false],
|
||||||
|
fileContents: [],
|
||||||
|
file: [null, Validators.required],
|
||||||
|
link: [],
|
||||||
|
copyLink: false,
|
||||||
|
maxAccessCount: [],
|
||||||
|
accessCount: [],
|
||||||
|
password: [],
|
||||||
|
notes: [],
|
||||||
|
hideEmail: false,
|
||||||
|
disabled: false,
|
||||||
|
type: [],
|
||||||
|
defaultExpirationDateTime: [],
|
||||||
|
defaultDeletionDateTime: ["", Validators.required],
|
||||||
|
selectedDeletionDatePreset: [DatePreset.SevenDays, Validators.required],
|
||||||
|
selectedExpirationDatePreset: [],
|
||||||
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
@ -59,10 +111,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
protected sendService: SendService,
|
protected sendService: SendService,
|
||||||
protected messagingService: MessagingService,
|
protected messagingService: MessagingService,
|
||||||
protected policyService: PolicyService,
|
protected policyService: PolicyService,
|
||||||
private logService: LogService,
|
protected logService: LogService,
|
||||||
protected stateService: StateService,
|
protected stateService: StateService,
|
||||||
protected sendApiService: SendApiService,
|
protected sendApiService: SendApiService,
|
||||||
protected dialogService: DialogService
|
protected dialogService: DialogService,
|
||||||
|
protected formBuilder: FormBuilder
|
||||||
) {
|
) {
|
||||||
this.typeOptions = [
|
this.typeOptions = [
|
||||||
{ name: i18nService.t("sendTypeFile"), value: SendType.File },
|
{ name: i18nService.t("sendTypeFile"), value: SendType.File },
|
||||||
@ -72,7 +125,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get link(): string {
|
get link(): string {
|
||||||
if (this.send.id != null && this.send.accessId != null) {
|
if (this.send != null && this.send.id != null && this.send.accessId != null) {
|
||||||
return this.sendLinkBaseUrl + this.send.accessId + "/" + this.send.urlB64Key;
|
return this.sendLinkBaseUrl + this.send.accessId + "/" + this.send.urlB64Key;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -92,13 +145,39 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe((policyAppliesToActiveUser) => {
|
.subscribe((policyAppliesToActiveUser) => {
|
||||||
this.disableSend = policyAppliesToActiveUser;
|
this.disableSend = policyAppliesToActiveUser;
|
||||||
|
if (this.disableSend) {
|
||||||
|
this.formGroup.disable();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.policyService
|
this.policyService
|
||||||
.policyAppliesToActiveUser$(PolicyType.SendOptions, (p) => p.data.disableHideEmail)
|
.policyAppliesToActiveUser$(PolicyType.SendOptions, (p) => p.data.disableHideEmail)
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe((policyAppliesToActiveUser) => {
|
.subscribe((policyAppliesToActiveUser) => {
|
||||||
this.disableHideEmail = policyAppliesToActiveUser;
|
if ((this.disableHideEmail = policyAppliesToActiveUser)) {
|
||||||
|
this.formGroup.controls.hideEmail.disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.formGroup.controls.type.valueChanges.subscribe((val) => {
|
||||||
|
this.type = val;
|
||||||
|
this.typeChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.formGroup.controls.selectedDeletionDatePreset.valueChanges
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((datePreset) => {
|
||||||
|
datePreset === DatePreset.Custom
|
||||||
|
? this.formGroup.controls.defaultDeletionDateTime.enable()
|
||||||
|
: this.formGroup.controls.defaultDeletionDateTime.disable();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.formGroup.controls.hideEmail.valueChanges
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((val) => {
|
||||||
|
if (!val && this.disableHideEmail) {
|
||||||
|
this.formGroup.controls.hideEmail.disable();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.load();
|
await this.load();
|
||||||
@ -117,29 +196,33 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
return this.i18nService.t(this.editMode ? "editSend" : "createSend");
|
return this.i18nService.t(this.editMode ? "editSend" : "createSend");
|
||||||
}
|
}
|
||||||
|
|
||||||
setDates(event: { deletionDate: string; expirationDate: string }) {
|
|
||||||
this.deletionDate = event.deletionDate;
|
|
||||||
this.expirationDate = event.expirationDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.canAccessPremium = await this.stateService.getCanAccessPremium();
|
this.canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||||
this.emailVerified = await this.stateService.getEmailVerified();
|
this.emailVerified = await this.stateService.getEmailVerified();
|
||||||
if (!this.canAccessPremium || !this.emailVerified) {
|
|
||||||
this.type = SendType.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.type = !this.canAccessPremium || !this.emailVerified ? SendType.Text : SendType.File;
|
||||||
if (this.send == null) {
|
if (this.send == null) {
|
||||||
if (this.editMode) {
|
if (this.editMode) {
|
||||||
const send = this.loadSend();
|
const send = this.loadSend();
|
||||||
this.send = await send.decrypt();
|
this.send = await send.decrypt();
|
||||||
|
this.type = this.send.type;
|
||||||
|
this.updateFormValues();
|
||||||
|
if (this.send.hideEmail) {
|
||||||
|
this.formGroup.controls.hideEmail.enable();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.send = new SendView();
|
this.send = new SendView();
|
||||||
this.send.type = this.type == null ? SendType.File : this.type;
|
this.send.type = this.type;
|
||||||
this.send.file = new SendFileView();
|
this.send.file = new SendFileView();
|
||||||
this.send.text = new SendTextView();
|
this.send.text = new SendTextView();
|
||||||
this.send.deletionDate = new Date();
|
this.send.deletionDate = new Date();
|
||||||
this.send.deletionDate.setDate(this.send.deletionDate.getDate() + 7);
|
this.send.deletionDate.setDate(this.send.deletionDate.getDate() + 7);
|
||||||
|
this.formGroup.controls.type.patchValue(this.send.type);
|
||||||
|
|
||||||
|
this.formGroup.patchValue({
|
||||||
|
selectedDeletionDatePreset: DatePreset.SevenDays,
|
||||||
|
selectedExpirationDatePreset: DatePreset.Never,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +230,8 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async submit(): Promise<boolean> {
|
async submit(): Promise<boolean> {
|
||||||
|
this.formGroup.markAllAsTouched();
|
||||||
|
|
||||||
if (this.disableSend) {
|
if (this.disableSend) {
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"error",
|
"error",
|
||||||
@ -156,6 +241,17 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.send.name = this.formGroup.controls.name.value;
|
||||||
|
this.send.text.text = this.formGroup.controls.text.value;
|
||||||
|
this.send.text.hidden = this.formGroup.controls.textHidden.value;
|
||||||
|
this.send.maxAccessCount = this.formGroup.controls.maxAccessCount.value;
|
||||||
|
this.send.accessCount = this.formGroup.controls.accessCount.value;
|
||||||
|
this.send.password = this.formGroup.controls.password.value;
|
||||||
|
this.send.notes = this.formGroup.controls.notes.value;
|
||||||
|
this.send.hideEmail = this.formGroup.controls.hideEmail.value;
|
||||||
|
this.send.disabled = this.formGroup.controls.disabled.value;
|
||||||
|
this.send.type = this.type;
|
||||||
|
|
||||||
if (this.send.name == null || this.send.name === "") {
|
if (this.send.name == null || this.send.name === "") {
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"error",
|
"error",
|
||||||
@ -166,7 +262,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let file: File = null;
|
let file: File = null;
|
||||||
if (this.send.type === SendType.File && !this.editMode) {
|
if (this.type === SendType.File && !this.editMode) {
|
||||||
const fileEl = document.getElementById("file") as HTMLInputElement;
|
const fileEl = document.getElementById("file") as HTMLInputElement;
|
||||||
const files = fileEl.files;
|
const files = fileEl.files;
|
||||||
if (files == null || files.length === 0) {
|
if (files == null || files.length === 0) {
|
||||||
@ -190,7 +286,10 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.password != null && this.password.trim() === "") {
|
if (
|
||||||
|
this.formGroup.controls.password.value != null &&
|
||||||
|
this.formGroup.controls.password.value.trim() === ""
|
||||||
|
) {
|
||||||
this.password = null;
|
this.password = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +303,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
this.send.accessId = encSend[0].accessId;
|
this.send.accessId = encSend[0].accessId;
|
||||||
}
|
}
|
||||||
this.onSavedSend.emit(this.send);
|
this.onSavedSend.emit(this.send);
|
||||||
if (this.copyLink && this.link != null) {
|
if (this.formGroup.controls.copyLink.value && this.link != null) {
|
||||||
await this.handleCopyLinkToClipboard();
|
await this.handleCopyLinkToClipboard();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -227,7 +326,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
return Promise.resolve(this.platformUtilsService.copyToClipboard(link));
|
return Promise.resolve(this.platformUtilsService.copyToClipboard(link));
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(): Promise<boolean> {
|
protected async delete(): Promise<boolean> {
|
||||||
if (this.deletePromise != null) {
|
if (this.deletePromise != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -257,7 +356,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
typeChanged() {
|
typeChanged() {
|
||||||
if (this.send.type === SendType.File && !this.alertShown) {
|
if (this.type === SendType.File && !this.alertShown) {
|
||||||
if (!this.canAccessPremium) {
|
if (!this.canAccessPremium) {
|
||||||
this.alertShown = true;
|
this.alertShown = true;
|
||||||
this.messagingService.send("premiumRequired");
|
this.messagingService.send("premiumRequired");
|
||||||
@ -266,6 +365,9 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
this.messagingService.send("emailVerificationRequired");
|
this.messagingService.send("emailVerificationRequired");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.type === SendType.Text || this.editMode
|
||||||
|
? this.formGroup.controls.file.disable()
|
||||||
|
: this.formGroup.controls.file.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleOptions() {
|
toggleOptions() {
|
||||||
@ -277,17 +379,23 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async encryptSend(file: File): Promise<[Send, EncArrayBuffer]> {
|
protected async encryptSend(file: File): Promise<[Send, EncArrayBuffer]> {
|
||||||
const sendData = await this.sendService.encrypt(this.send, file, this.password, null);
|
const sendData = await this.sendService.encrypt(
|
||||||
|
this.send,
|
||||||
|
file,
|
||||||
|
this.formGroup.controls.password.value,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
// Parse dates
|
// Parse dates
|
||||||
try {
|
try {
|
||||||
sendData[0].deletionDate = this.deletionDate == null ? null : new Date(this.deletionDate);
|
sendData[0].deletionDate =
|
||||||
|
this.formattedDeletionDate == null ? null : new Date(this.formattedDeletionDate);
|
||||||
} catch {
|
} catch {
|
||||||
sendData[0].deletionDate = null;
|
sendData[0].deletionDate = null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
sendData[0].expirationDate =
|
sendData[0].expirationDate =
|
||||||
this.expirationDate == null ? null : new Date(this.expirationDate);
|
this.formattedExpirationDate == null ? null : new Date(this.formattedExpirationDate);
|
||||||
} catch {
|
} catch {
|
||||||
sendData[0].expirationDate = null;
|
sendData[0].expirationDate = null;
|
||||||
}
|
}
|
||||||
@ -299,6 +407,34 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
document.getElementById("password").focus();
|
document.getElementById("password").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFormValues() {
|
||||||
|
this.formGroup.patchValue({
|
||||||
|
name: this.send?.name ?? "",
|
||||||
|
text: this.send?.text?.text ?? "",
|
||||||
|
textHidden: this.send?.text?.hidden ?? false,
|
||||||
|
link: this.link ?? "",
|
||||||
|
maxAccessCount: this.send?.maxAccessCount,
|
||||||
|
accessCount: this.send?.accessCount ?? 0,
|
||||||
|
notes: this.send?.notes ?? "",
|
||||||
|
hideEmail: this.send?.hideEmail ?? false,
|
||||||
|
disabled: this.send?.disabled ?? false,
|
||||||
|
type: this.send.type ?? this.type,
|
||||||
|
password: "",
|
||||||
|
|
||||||
|
selectedDeletionDatePreset: this.editMode ? DatePreset.Custom : DatePreset.SevenDays,
|
||||||
|
selectedExpirationDatePreset: this.editMode ? DatePreset.Custom : DatePreset.Never,
|
||||||
|
defaultExpirationDateTime:
|
||||||
|
this.send.expirationDate != null
|
||||||
|
? this.datePipe.transform(new Date(this.send.expirationDate), "yyyy-MM-ddTHH:mm")
|
||||||
|
: null,
|
||||||
|
defaultDeletionDateTime: this.datePipe.transform(
|
||||||
|
new Date(this.send.deletionDate),
|
||||||
|
"yyyy-MM-ddTHH:mm"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async handleCopyLinkToClipboard() {
|
private async handleCopyLinkToClipboard() {
|
||||||
const copySuccess = await this.copyLinkToClipboard(this.link);
|
const copySuccess = await this.copyLinkToClipboard(this.link);
|
||||||
if (copySuccess ?? true) {
|
if (copySuccess ?? true) {
|
||||||
@ -319,4 +455,46 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
await this.copyLinkToClipboard(this.link);
|
await this.copyLinkToClipboard(this.link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearExpiration() {
|
||||||
|
this.formGroup.controls.defaultExpirationDateTime.patchValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
get formattedExpirationDate(): string {
|
||||||
|
switch (this.formGroup.controls.selectedExpirationDatePreset.value as DatePreset) {
|
||||||
|
case DatePreset.Never:
|
||||||
|
return null;
|
||||||
|
case DatePreset.Custom:
|
||||||
|
if (!this.formGroup.controls.defaultExpirationDateTime.value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.formGroup.controls.defaultExpirationDateTime.value;
|
||||||
|
default: {
|
||||||
|
const now = new Date();
|
||||||
|
const milliseconds = now.setTime(
|
||||||
|
now.getTime() +
|
||||||
|
(this.formGroup.controls.selectedExpirationDatePreset.value as number) * 60 * 60 * 1000
|
||||||
|
);
|
||||||
|
return new Date(milliseconds).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get formattedDeletionDate(): string {
|
||||||
|
switch (this.formGroup.controls.selectedDeletionDatePreset.value as DatePreset) {
|
||||||
|
case DatePreset.Never:
|
||||||
|
this.formGroup.controls.selectedDeletionDatePreset.patchValue(DatePreset.SevenDays);
|
||||||
|
return this.formattedDeletionDate;
|
||||||
|
case DatePreset.Custom:
|
||||||
|
return this.formGroup.controls.defaultDeletionDateTime.value;
|
||||||
|
default: {
|
||||||
|
const now = new Date();
|
||||||
|
const milliseconds = now.setTime(
|
||||||
|
now.getTime() +
|
||||||
|
(this.formGroup.controls.selectedDeletionDatePreset.value as number) * 60 * 60 * 1000
|
||||||
|
);
|
||||||
|
return new Date(milliseconds).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,356 +0,0 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
|
||||||
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
|
||||||
import { UntypedFormControl, UntypedFormGroup } from "@angular/forms";
|
|
||||||
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
|
|
||||||
// Different BrowserPath = different controls.
|
|
||||||
enum BrowserPath {
|
|
||||||
// Native datetime-locale.
|
|
||||||
// We are happy.
|
|
||||||
Default = "default",
|
|
||||||
|
|
||||||
// Native date and time inputs, but no datetime-locale.
|
|
||||||
// We use individual date and time inputs and create a datetime programatically on submit.
|
|
||||||
Firefox = "firefox",
|
|
||||||
|
|
||||||
// No native date, time, or datetime-locale inputs.
|
|
||||||
// We use a polyfill for dates and a dropdown for times.
|
|
||||||
Safari = "safari",
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DateField {
|
|
||||||
DeletionDate = "deletion",
|
|
||||||
ExpirationDate = "expiration",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value = hours
|
|
||||||
enum DatePreset {
|
|
||||||
OneHour = 1,
|
|
||||||
OneDay = 24,
|
|
||||||
TwoDays = 48,
|
|
||||||
ThreeDays = 72,
|
|
||||||
SevenDays = 168,
|
|
||||||
ThirtyDays = 720,
|
|
||||||
Custom = 0,
|
|
||||||
Never = null,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimeOption is used for the dropdown implementation of custom times
|
|
||||||
// twelveHour = displayed time; twentyFourHour = time used in logic
|
|
||||||
interface TimeOption {
|
|
||||||
twelveHour: string;
|
|
||||||
twentyFourHour: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive()
|
|
||||||
export class EffluxDatesComponent implements OnInit {
|
|
||||||
@Input() readonly initialDeletionDate: Date;
|
|
||||||
@Input() readonly initialExpirationDate: Date;
|
|
||||||
@Input() readonly editMode: boolean;
|
|
||||||
@Input() readonly disabled: boolean;
|
|
||||||
|
|
||||||
@Output() datesChanged = new EventEmitter<{ deletionDate: string; expirationDate: string }>();
|
|
||||||
|
|
||||||
get browserPath(): BrowserPath {
|
|
||||||
if (this.platformUtilsService.isFirefox()) {
|
|
||||||
return BrowserPath.Firefox;
|
|
||||||
} else if (this.platformUtilsService.isSafari()) {
|
|
||||||
return BrowserPath.Safari;
|
|
||||||
}
|
|
||||||
return BrowserPath.Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
datesForm = new UntypedFormGroup({
|
|
||||||
selectedDeletionDatePreset: new UntypedFormControl(),
|
|
||||||
selectedExpirationDatePreset: new UntypedFormControl(),
|
|
||||||
defaultDeletionDateTime: new UntypedFormControl(),
|
|
||||||
defaultExpirationDateTime: new UntypedFormControl(),
|
|
||||||
fallbackDeletionDate: new UntypedFormControl(),
|
|
||||||
fallbackDeletionTime: new UntypedFormControl(),
|
|
||||||
fallbackExpirationDate: new UntypedFormControl(),
|
|
||||||
fallbackExpirationTime: new UntypedFormControl(),
|
|
||||||
});
|
|
||||||
|
|
||||||
deletionDatePresets: any[] = [
|
|
||||||
{ 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 },
|
|
||||||
];
|
|
||||||
|
|
||||||
expirationDatePresets: any[] = [
|
|
||||||
{ name: this.i18nService.t("never"), value: DatePreset.Never },
|
|
||||||
].concat([...this.deletionDatePresets]);
|
|
||||||
|
|
||||||
get selectedDeletionDatePreset(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("selectedDeletionDatePreset") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get selectedExpirationDatePreset(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("selectedExpirationDatePreset") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultDeletionDateTime(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("defaultDeletionDateTime") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultExpirationDateTime(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("defaultExpirationDateTime") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fallbackDeletionDate(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("fallbackDeletionDate") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fallbackDeletionTime(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("fallbackDeletionTime") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fallbackExpirationDate(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("fallbackExpirationDate") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fallbackExpirationTime(): UntypedFormControl {
|
|
||||||
return this.datesForm.get("fallbackExpirationTime") as UntypedFormControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be able to call these at any time and compute a submitable value
|
|
||||||
get formattedDeletionDate(): string {
|
|
||||||
switch (this.selectedDeletionDatePreset.value as DatePreset) {
|
|
||||||
case DatePreset.Never:
|
|
||||||
this.selectedDeletionDatePreset.setValue(DatePreset.SevenDays);
|
|
||||||
return this.formattedDeletionDate;
|
|
||||||
case DatePreset.Custom:
|
|
||||||
switch (this.browserPath) {
|
|
||||||
case BrowserPath.Safari:
|
|
||||||
case BrowserPath.Firefox:
|
|
||||||
return this.fallbackDeletionDate.value + "T" + this.fallbackDeletionTime.value;
|
|
||||||
default:
|
|
||||||
return this.defaultDeletionDateTime.value;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
const now = new Date();
|
|
||||||
const milliseconds = now.setTime(
|
|
||||||
now.getTime() + (this.selectedDeletionDatePreset.value as number) * 60 * 60 * 1000
|
|
||||||
);
|
|
||||||
return new Date(milliseconds).toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get formattedExpirationDate(): string {
|
|
||||||
switch (this.selectedExpirationDatePreset.value as DatePreset) {
|
|
||||||
case DatePreset.Never:
|
|
||||||
return null;
|
|
||||||
case DatePreset.Custom:
|
|
||||||
switch (this.browserPath) {
|
|
||||||
case BrowserPath.Safari:
|
|
||||||
case BrowserPath.Firefox:
|
|
||||||
if (
|
|
||||||
(!this.fallbackExpirationDate.value || !this.fallbackExpirationTime.value) &&
|
|
||||||
this.editMode
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.fallbackExpirationDate.value + "T" + this.fallbackExpirationTime.value;
|
|
||||||
default:
|
|
||||||
if (!this.defaultExpirationDateTime.value) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.defaultExpirationDateTime.value;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
const now = new Date();
|
|
||||||
const milliseconds = now.setTime(
|
|
||||||
now.getTime() + (this.selectedExpirationDatePreset.value as number) * 60 * 60 * 1000
|
|
||||||
);
|
|
||||||
return new Date(milliseconds).toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
get safariDeletionTimePresetOptions() {
|
|
||||||
return this.safariTimePresetOptions(DateField.DeletionDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
get safariExpirationTimePresetOptions() {
|
|
||||||
return this.safariTimePresetOptions(DateField.ExpirationDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private get nextWeek(): Date {
|
|
||||||
const nextWeek = new Date();
|
|
||||||
nextWeek.setDate(nextWeek.getDate() + 7);
|
|
||||||
return nextWeek;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
|
||||||
protected datePipe: DatePipe
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.setInitialFormValues();
|
|
||||||
this.emitDates();
|
|
||||||
this.datesForm.valueChanges.subscribe(() => {
|
|
||||||
this.emitDates();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeletionDatePresetSelect(value: DatePreset) {
|
|
||||||
this.selectedDeletionDatePreset.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearExpiration() {
|
|
||||||
switch (this.browserPath) {
|
|
||||||
case BrowserPath.Safari:
|
|
||||||
case BrowserPath.Firefox:
|
|
||||||
this.fallbackExpirationDate.setValue(null);
|
|
||||||
this.fallbackExpirationTime.setValue(null);
|
|
||||||
break;
|
|
||||||
case BrowserPath.Default:
|
|
||||||
this.defaultExpirationDateTime.setValue(null);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected emitDates() {
|
|
||||||
this.datesChanged.emit({
|
|
||||||
deletionDate: this.formattedDeletionDate,
|
|
||||||
expirationDate: this.formattedExpirationDate,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setInitialFormValues() {
|
|
||||||
if (this.editMode) {
|
|
||||||
this.selectedDeletionDatePreset.setValue(DatePreset.Custom);
|
|
||||||
this.selectedExpirationDatePreset.setValue(DatePreset.Custom);
|
|
||||||
switch (this.browserPath) {
|
|
||||||
case BrowserPath.Safari:
|
|
||||||
case BrowserPath.Firefox:
|
|
||||||
this.fallbackDeletionDate.setValue(this.initialDeletionDate.toISOString().slice(0, 10));
|
|
||||||
this.fallbackDeletionTime.setValue(this.initialDeletionDate.toTimeString().slice(0, 5));
|
|
||||||
if (this.initialExpirationDate != null) {
|
|
||||||
this.fallbackExpirationDate.setValue(
|
|
||||||
this.initialExpirationDate.toISOString().slice(0, 10)
|
|
||||||
);
|
|
||||||
this.fallbackExpirationTime.setValue(
|
|
||||||
this.initialExpirationDate.toTimeString().slice(0, 5)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BrowserPath.Default:
|
|
||||||
if (this.initialExpirationDate) {
|
|
||||||
this.defaultExpirationDateTime.setValue(
|
|
||||||
this.datePipe.transform(new Date(this.initialExpirationDate), "yyyy-MM-ddTHH:mm")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.defaultDeletionDateTime.setValue(
|
|
||||||
this.datePipe.transform(new Date(this.initialDeletionDate), "yyyy-MM-ddTHH:mm")
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.selectedDeletionDatePreset.setValue(DatePreset.SevenDays);
|
|
||||||
this.selectedExpirationDatePreset.setValue(DatePreset.Never);
|
|
||||||
|
|
||||||
switch (this.browserPath) {
|
|
||||||
case BrowserPath.Safari:
|
|
||||||
this.fallbackDeletionDate.setValue(this.nextWeek.toISOString().slice(0, 10));
|
|
||||||
this.fallbackDeletionTime.setValue(
|
|
||||||
this.safariTimePresetOptions(DateField.DeletionDate)[1].twentyFourHour
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected safariTimePresetOptions(field: DateField): TimeOption[] {
|
|
||||||
// init individual arrays for major sort groups
|
|
||||||
const noon: TimeOption[] = [];
|
|
||||||
const midnight: TimeOption[] = [];
|
|
||||||
const ams: TimeOption[] = [];
|
|
||||||
const pms: TimeOption[] = [];
|
|
||||||
|
|
||||||
// determine minute skip (5 min, 10 min, 15 min, etc.)
|
|
||||||
const minuteIncrementer = 15;
|
|
||||||
|
|
||||||
// loop through each hour on a 12 hour system
|
|
||||||
for (let h = 1; h <= 12; h++) {
|
|
||||||
// loop through each minute in the hour using the skip to increment
|
|
||||||
for (let m = 0; m < 60; m += minuteIncrementer) {
|
|
||||||
// init the final strings that will be added to the lists
|
|
||||||
let hour = h.toString();
|
|
||||||
let minutes = m.toString();
|
|
||||||
|
|
||||||
// add prepending 0s to single digit hours/minutes
|
|
||||||
if (h < 10) {
|
|
||||||
hour = "0" + hour;
|
|
||||||
}
|
|
||||||
if (m < 10) {
|
|
||||||
minutes = "0" + minutes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build time strings and push to relevant sort groups
|
|
||||||
if (h === 12) {
|
|
||||||
const midnightOption: TimeOption = {
|
|
||||||
twelveHour: `${hour}:${minutes} AM`,
|
|
||||||
twentyFourHour: `00:${minutes}`,
|
|
||||||
};
|
|
||||||
midnight.push(midnightOption);
|
|
||||||
|
|
||||||
const noonOption: TimeOption = {
|
|
||||||
twelveHour: `${hour}:${minutes} PM`,
|
|
||||||
twentyFourHour: `${hour}:${minutes}`,
|
|
||||||
};
|
|
||||||
noon.push(noonOption);
|
|
||||||
} else {
|
|
||||||
const amOption: TimeOption = {
|
|
||||||
twelveHour: `${hour}:${minutes} AM`,
|
|
||||||
twentyFourHour: `${hour}:${minutes}`,
|
|
||||||
};
|
|
||||||
ams.push(amOption);
|
|
||||||
|
|
||||||
const pmOption: TimeOption = {
|
|
||||||
twelveHour: `${hour}:${minutes} PM`,
|
|
||||||
twentyFourHour: `${h + 12}:${minutes}`,
|
|
||||||
};
|
|
||||||
pms.push(pmOption);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bring all the arrays together in the right order
|
|
||||||
const validTimes = [...midnight, ...ams, ...noon, ...pms];
|
|
||||||
|
|
||||||
// determine if an unsupported value already exists on the send & add that to the top of the option list
|
|
||||||
// example: if the Send was created with a different client
|
|
||||||
if (field === DateField.ExpirationDate && this.initialExpirationDate != null && this.editMode) {
|
|
||||||
const previousValue: TimeOption = {
|
|
||||||
twelveHour: this.datePipe.transform(this.initialExpirationDate, "hh:mm a"),
|
|
||||||
twentyFourHour: this.datePipe.transform(this.initialExpirationDate, "HH:mm"),
|
|
||||||
};
|
|
||||||
return [previousValue, { twelveHour: null, twentyFourHour: null }, ...validTimes];
|
|
||||||
} else if (
|
|
||||||
field === DateField.DeletionDate &&
|
|
||||||
this.initialDeletionDate != null &&
|
|
||||||
this.editMode
|
|
||||||
) {
|
|
||||||
const previousValue: TimeOption = {
|
|
||||||
twelveHour: this.datePipe.transform(this.initialDeletionDate, "hh:mm a"),
|
|
||||||
twentyFourHour: this.datePipe.transform(this.initialDeletionDate, "HH:mm"),
|
|
||||||
};
|
|
||||||
return [previousValue, ...validTimes];
|
|
||||||
} else {
|
|
||||||
return [{ twelveHour: null, twentyFourHour: null }, ...validTimes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,9 @@ export type InputTypes =
|
|||||||
| "email"
|
| "email"
|
||||||
| "checkbox"
|
| "checkbox"
|
||||||
| "search"
|
| "search"
|
||||||
| "file";
|
| "file"
|
||||||
|
| "date"
|
||||||
|
| "time";
|
||||||
|
|
||||||
export abstract class BitFormFieldControl {
|
export abstract class BitFormFieldControl {
|
||||||
ariaDescribedBy: string;
|
ariaDescribedBy: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user