1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 01:03:35 +00: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:
aj-rosado
2023-09-07 13:49:13 +01:00
committed by GitHub
parent 86bdfaa7ba
commit 5f78aeaef2
20 changed files with 777 additions and 1388 deletions

View File

@@ -53,7 +53,6 @@ import { ExportComponent } from "./tools/export/export.component";
import { GeneratorComponent } from "./tools/generator.component";
import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.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";
@NgModule({
@@ -87,7 +86,6 @@ import { SendComponent } from "./tools/send/send.component";
SearchComponent,
SendAddEditComponent,
SendComponent,
SendEffluxDatesComponent,
SetPasswordComponent,
SetPinComponent,
SettingsComponent,

View File

@@ -1,4 +1,4 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<form #form [formGroup]="formGroup" (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="content">
<div class="inner-content" *ngIf="send">
<div class="box">
@@ -16,14 +16,7 @@
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="name">{{ "name" | i18n }}</label>
<input
id="name"
type="text"
name="Name"
[(ngModel)]="send.name"
appAutofocus
[readOnly]="disableSend"
/>
<input id="name" type="text" name="Name" formControlName="name" appAutofocus />
</div>
<div class="box-content-row box-content-row-radio" *ngIf="!editMode">
<label class="radio-header">{{ "whatTypeOfSend" | i18n }}</label>
@@ -31,20 +24,16 @@
<input
type="radio"
class="radio"
[(ngModel)]="send.type"
name="Type_{{ o.value }}"
formControlName="type"
id="type_{{ o.value }}"
[value]="o.value"
(change)="typeChanged()"
[checked]="send.type === o.value"
[disabled]="disableSend"
/>
<label class="unstyled" for="type_{{ o.value }}">
{{ o.name }}
</label>
</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>
<input
type="file"
@@ -53,22 +42,20 @@
name="file"
aria-describedby="fileHelp"
required
[disabled]="disableSend"
/>
</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>
<div class="row-main">{{ send.file.fileName }} ({{ send.file.sizeName }})</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>
<textarea
id="text"
name="text"
aria-describedby="textHelp"
[(ngModel)]="send.text.text"
formControlName="text"
rows="6"
[readOnly]="disableSend"
></textarea>
</div>
</div>
@@ -83,13 +70,7 @@
<div class="box-content">
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="hideText">{{ "textHiddenByDefault" | i18n }}</label>
<input
id="hideText"
name="hideText"
type="checkbox"
[(ngModel)]="send.text.hidden"
[disabled]="disableSend"
/>
<input id="hideText" name="hideText" type="checkbox" formControlName="textHidden" />
</div>
</div>
</div>
@@ -112,14 +93,82 @@
</h2>
</div>
<div [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="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="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-content">
<div class="box-content-row" appBoxRow>
@@ -129,8 +178,7 @@
type="number"
name="maxAccessCount"
aria-describedby="maxAccessCountHelp"
[(ngModel)]="send.maxAccessCount"
[readOnly]="disableSend"
formControlName="maxAccessCount"
/>
</div>
</div>
@@ -154,8 +202,7 @@
name="password"
aria-describedby="passwordHelp"
type="{{ showPassword ? 'text' : 'password' }}"
[(ngModel)]="password"
[readOnly]="disableSend"
formControlName="password"
appInputVerbatim
/>
</div>
@@ -167,7 +214,6 @@
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword"
(click)="togglePasswordVisible()"
[disabled]="disableSend"
>
<i
class="bwi bwi-lg"
@@ -192,9 +238,8 @@
id="notes"
name="notes"
aria-describedby="notesHelp"
[(ngModel)]="send.notes"
formControlName="notes"
rows="6"
[readOnly]="disableSend"
></textarea>
</div>
</div>
@@ -206,13 +251,7 @@
<div class="box-content">
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="hideEmail">{{ "hideEmail" | i18n }}</label>
<input
id="hideEmail"
type="checkbox"
name="HideEmail"
[(ngModel)]="send.hideEmail"
[disabled]="(disableHideEmail && !send.hideEmail) || disableSend"
/>
<input id="hideEmail" type="checkbox" name="HideEmail" formControlName="hideEmail" />
</div>
</div>
</div>
@@ -220,13 +259,7 @@
<div class="box-content">
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="disabled">{{ "disableSend" | i18n }}</label>
<input
id="disabled"
type="checkbox"
name="disabled"
[(ngModel)]="send.disabled"
[disabled]="disableSend"
/>
<input id="disabled" type="checkbox" name="disabled" formControlName="disabled" />
</div>
</div>
</div>
@@ -238,17 +271,11 @@
<div class="box-content">
<div class="box-content-row" appBoxRow *ngIf="editMode">
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
<input id="link" name="link" [ngModel]="link" readonly />
<input id="link" name="link" formControlName="link" readonly />
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="copyLink">{{ "copySendLinkOnSave" | i18n }}</label>
<input
id="copyLink"
name="copyLink"
[(ngModel)]="copyLink"
type="checkbox"
[disabled]="disableSend"
/>
<input id="copyLink" name="copyLink" formControlName="copyLink" type="checkbox" />
</div>
</div>
</div>
@@ -259,13 +286,12 @@
type="submit"
class="primary btn-submit"
appA11yTitle="{{ 'save' | i18n }}"
[disabled]="form.loading"
*ngIf="!disableSend"
>
<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>
</button>
<button type="button" (click)="cancel()" [disabled]="form.loading">
<button type="button" (click)="cancel()">
{{ "cancel" | i18n }}
</button>
<div class="right">

View File

@@ -1,5 +1,6 @@
import { DatePipe } from "@angular/common";
import { Component } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
@@ -29,7 +30,8 @@ export class AddEditComponent extends BaseAddEditComponent {
policyService: PolicyService,
logService: LogService,
sendApiService: SendApiService,
dialogService: DialogService
dialogService: DialogService,
formBuilder: FormBuilder
) {
super(
i18nService,
@@ -42,7 +44,8 @@ export class AddEditComponent extends BaseAddEditComponent {
logService,
stateService,
sendApiService,
dialogService
dialogService,
formBuilder
);
}
@@ -50,6 +53,7 @@ export class AddEditComponent extends BaseAddEditComponent {
this.password = null;
const send = await this.loadSend();
this.send = await send.decrypt();
this.updateFormValues();
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"))
);
}
async resetAndLoad() {
this.sendId = null;
this.send = null;
await this.load();
this.updateFormValues();
}
}

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -91,12 +91,10 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
this.searchBarService.setEnabled(false);
}
addSend() {
async addSend() {
this.action = Action.Add;
if (this.addEditComponent != null) {
this.addEditComponent.sendId = null;
this.addEditComponent.send = null;
this.addEditComponent.load();
await this.addEditComponent.resetAndLoad();
}
}