mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-28 12:45:45 +01:00
[Send] Add/Edit functionality (#1622)
* Update jslib (0951424
->1968dbf
) * [Send] Browser integration initial commit * Update jslib (1968dbf
->8a3b551
) * Cleaned up integration * added radio button style support // updated warning UI/UX * Update jslib (8a3b551
->42348e2)
This commit is contained in:
parent
2ac9f92267
commit
4853fb3e29
2
jslib
2
jslib
@ -1 +1 @@
|
|||||||
Subproject commit b0ae1bfa4cb3bc2642e1ecb14c6c1f0eceb06cb6
|
Subproject commit 42348e2fdc6206157d68d8a9f496eaa70520ab01
|
@ -1506,7 +1506,7 @@
|
|||||||
"message": "Password protected"
|
"message": "Password protected"
|
||||||
},
|
},
|
||||||
"copySendLink": {
|
"copySendLink": {
|
||||||
"message": "Copy Send Link",
|
"message": "Copy Send link",
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
},
|
},
|
||||||
"removePassword": {
|
"removePassword": {
|
||||||
@ -1523,7 +1523,7 @@
|
|||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
},
|
},
|
||||||
"sendLink": {
|
"sendLink": {
|
||||||
"message": "Send Link",
|
"message": "Send link",
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
},
|
},
|
||||||
"disabled": {
|
"disabled": {
|
||||||
@ -1539,5 +1539,110 @@
|
|||||||
"deleteSendConfirmation": {
|
"deleteSendConfirmation": {
|
||||||
"message": "Are you sure you want to delete this Send?",
|
"message": "Are you sure you want to delete this Send?",
|
||||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"editSend": {
|
||||||
|
"message": "Edit Send",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendTypeHeader": {
|
||||||
|
"message": "What type of Send is this?",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendNameDesc": {
|
||||||
|
"message": "A friendly name to describe this Send.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendFileDesc": {
|
||||||
|
"message": "The file you want to send."
|
||||||
|
},
|
||||||
|
"deletionDate": {
|
||||||
|
"message": "Deletion Date"
|
||||||
|
},
|
||||||
|
"deletionDateDesc": {
|
||||||
|
"message": "The Send will be permanently deleted on the specified date and time.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"expirationDate": {
|
||||||
|
"message": "Expiration Date"
|
||||||
|
},
|
||||||
|
"expirationDateDesc": {
|
||||||
|
"message": "If set, access to this Send will expire on the specified date and time.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"oneDay": {
|
||||||
|
"message": "1 day"
|
||||||
|
},
|
||||||
|
"days": {
|
||||||
|
"message": "$DAYS$ days",
|
||||||
|
"placeholders": {
|
||||||
|
"days": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"message": "Custom"
|
||||||
|
},
|
||||||
|
"maximumAccessCount": {
|
||||||
|
"message": "Maximum Access Count"
|
||||||
|
},
|
||||||
|
"maximumAccessCountDesc": {
|
||||||
|
"message": "If set, users will no longer be able to access this Send once the maximum access count is reached.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendPasswordDesc": {
|
||||||
|
"message": "Optionally require a password for users to access this Send.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendNotesDesc": {
|
||||||
|
"message": "Private notes about this Send.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendDisableDesc": {
|
||||||
|
"message": "Disable this Send so that no one can access it.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendShareDesc": {
|
||||||
|
"message": "Copy this Send's link to clipboard upon save.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendTextDesc": {
|
||||||
|
"message": "The text you want to send."
|
||||||
|
},
|
||||||
|
"sendHideText": {
|
||||||
|
"message": "Hide this Send's text by default.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"currentAccessCount": {
|
||||||
|
"message": "Current Access Count"
|
||||||
|
},
|
||||||
|
"createSend": {
|
||||||
|
"message": "Create New Send",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"newPassword": {
|
||||||
|
"message": "New Password"
|
||||||
|
},
|
||||||
|
"sendDisabledWarning": {
|
||||||
|
"message": "Due to an enterprise policy, you are only able to delete an existing Send.",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"createdSend": {
|
||||||
|
"message": "Created Send",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"editedSend": {
|
||||||
|
"message": "Edited Send",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
|
},
|
||||||
|
"sendFirefoxFileWarning": {
|
||||||
|
"message": "In order to choose a file using Firefox, open the extension in the sidebar or pop out to a new window by clicking this banner."
|
||||||
|
},
|
||||||
|
"sendSafariFileWarning": {
|
||||||
|
"message": "In order to choose a file using Safari, pop out to a new window by clicking this banner."
|
||||||
|
},
|
||||||
|
"sendFileCalloutHeader": {
|
||||||
|
"message": "Before you start"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,4 +190,10 @@ export const routerTransition = trigger('routerTransition', [
|
|||||||
|
|
||||||
transition('tabs => send-type', inSlideLeft),
|
transition('tabs => send-type', inSlideLeft),
|
||||||
transition('send-type => tabs', outSlideRight),
|
transition('send-type => tabs', outSlideRight),
|
||||||
|
|
||||||
|
transition('tabs => add-send, send-type => add-send', inSlideUp),
|
||||||
|
transition('add-send => tabs, add-send => send-type', outSlideDown),
|
||||||
|
|
||||||
|
transition('tabs => edit-send, send-type => edit-send', inSlideUp),
|
||||||
|
transition('edit-send => tabs, edit-send => send-type', outSlideDown),
|
||||||
]);
|
]);
|
||||||
|
@ -46,6 +46,7 @@ import { PasswordHistoryComponent } from './vault/password-history.component';
|
|||||||
import { ShareComponent } from './vault/share.component';
|
import { ShareComponent } from './vault/share.component';
|
||||||
import { ViewComponent } from './vault/view.component';
|
import { ViewComponent } from './vault/view.component';
|
||||||
|
|
||||||
|
import { SendAddEditComponent } from './send/send-add-edit.component';
|
||||||
import { SendGroupingsComponent } from './send/send-groupings.component';
|
import { SendGroupingsComponent } from './send/send-groupings.component';
|
||||||
import { SendTypeComponent } from './send/send-type.component';
|
import { SendTypeComponent } from './send/send-type.component';
|
||||||
|
|
||||||
@ -243,6 +244,18 @@ const routes: Routes = [
|
|||||||
canActivate: [AuthGuardService],
|
canActivate: [AuthGuardService],
|
||||||
data: { state: 'send-type' },
|
data: { state: 'send-type' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'add-send',
|
||||||
|
component: SendAddEditComponent,
|
||||||
|
canActivate: [AuthGuardService],
|
||||||
|
data: { state: 'add-send' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'edit-send',
|
||||||
|
component: SendAddEditComponent,
|
||||||
|
canActivate: [AuthGuardService],
|
||||||
|
data: { state: 'edit-send' },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'tabs',
|
path: 'tabs',
|
||||||
component: TabsComponent,
|
component: TabsComponent,
|
||||||
|
@ -145,6 +145,7 @@ export class AppComponent implements OnInit {
|
|||||||
if (url.startsWith('/tabs/') && (window as any).previousPopupUrl != null &&
|
if (url.startsWith('/tabs/') && (window as any).previousPopupUrl != null &&
|
||||||
(window as any).previousPopupUrl.startsWith('/tabs/')) {
|
(window as any).previousPopupUrl.startsWith('/tabs/')) {
|
||||||
this.stateService.remove('GroupingsComponent');
|
this.stateService.remove('GroupingsComponent');
|
||||||
|
this.stateService.remove('GroupingsComponentScope');
|
||||||
this.stateService.remove('CiphersComponent');
|
this.stateService.remove('CiphersComponent');
|
||||||
this.stateService.remove('SendGroupingsComponent');
|
this.stateService.remove('SendGroupingsComponent');
|
||||||
this.stateService.remove('SendGroupingsComponentScope');
|
this.stateService.remove('SendGroupingsComponentScope');
|
||||||
@ -152,7 +153,6 @@ export class AppComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
if (url.startsWith('/tabs/')) {
|
if (url.startsWith('/tabs/')) {
|
||||||
this.stateService.remove('addEditCipherInfo');
|
this.stateService.remove('addEditCipherInfo');
|
||||||
// TODO Remove any Send add/edit state information (?)
|
|
||||||
}
|
}
|
||||||
(window as any).previousPopupUrl = url;
|
(window as any).previousPopupUrl = url;
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ import { PasswordHistoryComponent } from './vault/password-history.component';
|
|||||||
import { ShareComponent } from './vault/share.component';
|
import { ShareComponent } from './vault/share.component';
|
||||||
import { ViewComponent } from './vault/view.component';
|
import { ViewComponent } from './vault/view.component';
|
||||||
|
|
||||||
|
import { SendAddEditComponent } from './send/send-add-edit.component';
|
||||||
import { SendGroupingsComponent } from './send/send-groupings.component';
|
import { SendGroupingsComponent } from './send/send-groupings.component';
|
||||||
import { SendTypeComponent } from './send/send-type.component';
|
import { SendTypeComponent } from './send/send-type.component';
|
||||||
|
|
||||||
@ -81,6 +82,7 @@ import { IconComponent } from 'jslib/angular/components/icon.component';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CurrencyPipe,
|
CurrencyPipe,
|
||||||
|
DatePipe,
|
||||||
registerLocaleData,
|
registerLocaleData,
|
||||||
} from '@angular/common';
|
} from '@angular/common';
|
||||||
import localeBe from '@angular/common/locales/be';
|
import localeBe from '@angular/common/locales/be';
|
||||||
@ -213,6 +215,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||||||
RegisterComponent,
|
RegisterComponent,
|
||||||
SearchCiphersPipe,
|
SearchCiphersPipe,
|
||||||
SelectCopyDirective,
|
SelectCopyDirective,
|
||||||
|
SendAddEditComponent,
|
||||||
SendGroupingsComponent,
|
SendGroupingsComponent,
|
||||||
SendListComponent,
|
SendListComponent,
|
||||||
SendTypeComponent,
|
SendTypeComponent,
|
||||||
@ -232,6 +235,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||||||
entryComponents: [],
|
entryComponents: [],
|
||||||
providers: [
|
providers: [
|
||||||
CurrencyPipe,
|
CurrencyPipe,
|
||||||
|
DatePipe,
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
})
|
})
|
||||||
|
@ -19,6 +19,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box-header-expandable {
|
||||||
|
margin: 0 10px 5px 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed('headingColor');
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover, &:focus, &.active {
|
||||||
|
@include themify($themes) {
|
||||||
|
background-color: themed('boxBackgroundHoverColor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed('headingColor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.box-content {
|
.box-content {
|
||||||
border-top: 1px solid #000000;
|
border-top: 1px solid #000000;
|
||||||
border-bottom: 1px solid #000000;
|
border-bottom: 1px solid #000000;
|
||||||
@ -202,6 +228,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-label {
|
||||||
|
font-size: $font-size-small;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed('mutedColor');
|
||||||
|
}
|
||||||
|
|
||||||
|
> a {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.text, .detail {
|
.text, .detail {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
@ -329,7 +370,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input:not([type="checkbox"]), textarea {
|
input:not([type="checkbox"]):not([type="radio"]), textarea {
|
||||||
border: none;
|
border: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
@ -546,4 +587,27 @@
|
|||||||
background-color: $brand-primary;
|
background-color: $brand-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.radio-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed('textColor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,6 +302,14 @@ app-vault-icon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.clickable {
|
||||||
|
&:hover, &:focus, &.active {
|
||||||
|
@include themify($themes) {
|
||||||
|
background-color: themed('boxBackgroundHoverColor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="password"]::-ms-reveal {
|
input[type="password"]::-ms-reveal {
|
||||||
|
246
src/popup/send/send-add-edit.component.html
Normal file
246
src/popup/send/send-add-edit.component.html
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
|
<header>
|
||||||
|
<div class="left">
|
||||||
|
<button type="button" appBlurClick (click)="cancel()">{{'cancel' | i18n}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="center">
|
||||||
|
<span class="title">{{title}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<button type="submit" appBlurClick [disabled]="form.loading">
|
||||||
|
<span [hidden]="form.loading">{{'save' | i18n}}</span>
|
||||||
|
<i class="fa fa-spinner fa-lg fa-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<content *ngIf="send">
|
||||||
|
<!-- File Warning -->
|
||||||
|
<app-callout type="warning" icon="fa fa-external-link fa-rotate-270 fa-fw" [clickable]="true"
|
||||||
|
title="{{'sendFileCalloutHeader' | i18n}}" *ngIf="showFilePopoutMessage && send.type === sendType.File"
|
||||||
|
(click)="popOutWindow()">
|
||||||
|
<div *ngIf="showFirefoxFileWarning">{{'sendFirefoxFileWarning' | i18n}}</div>
|
||||||
|
<div *ngIf="showSafariFileWarning">{{'sendSafariFileWarning' | i18n}}</div>
|
||||||
|
</app-callout>
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="box">
|
||||||
|
<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">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'sendNameDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Type Options -->
|
||||||
|
<div class="box" *ngIf="!editMode">
|
||||||
|
<div class="box-content no-hover">
|
||||||
|
<div class="box-content-row">
|
||||||
|
<label for="sendTypeOptions">{{'sendTypeHeader' | i18n}}</label>
|
||||||
|
<div class="radio-group text-default" appBoxRow name="SendTypeOptions"
|
||||||
|
*ngFor="let o of typeOptions">
|
||||||
|
<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 for="type_{{o.value}}">
|
||||||
|
{{o.name}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- File -->
|
||||||
|
<div class="box" *ngIf="send.type === sendType.File && (editMode || showFileSelector)">
|
||||||
|
<div class="box-content no-hover">
|
||||||
|
<div class="box-content-row" *ngIf="editMode">
|
||||||
|
<label for="file">{{'file' | i18n}}</label>
|
||||||
|
<div class="row-main">{{send.file.fileName}} ({{send.file.sizeName}})</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" *ngIf="showFileSelector">
|
||||||
|
<label for="file">{{'file' | i18n}}</label>
|
||||||
|
<input type="file" id="file" name="file" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer" *ngIf="showFileSelector">
|
||||||
|
{{'sendFileDesc' | i18n}} {{'maxFileSize' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Text -->
|
||||||
|
<div class="box" *ngIf="send.type === sendType.Text">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="text">{{'sendTypeText' | i18n}}</label>
|
||||||
|
<textarea id="text" name="Text" rows="6" [(ngModel)]="send.text.text"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'sendTextDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
<label for="hideText">{{'sendHideText' | i18n}}</label>
|
||||||
|
<input id="hideText" type="checkbox" name="HideText" [(ngModel)]="send.text.hidden">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Share -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header">
|
||||||
|
{{'share' | i18n}}
|
||||||
|
</div>
|
||||||
|
<div class="box-content">
|
||||||
|
<!-- Copy Link on Save -->
|
||||||
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
<label for="copyOnSave">{{'sendShareDesc' | i18n}}</label>
|
||||||
|
<input id="copyOnSave" type="checkbox" name="CopyOnSave" [(ngModel)]="copyLink">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Options -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header-expandable" (click)="showOptions = !showOptions">
|
||||||
|
{{'options' | i18n}}
|
||||||
|
<i *ngIf="!showOptions" class="fa fa-chevron-down fa-sm icon"></i>
|
||||||
|
<i *ngIf="showOptions" class="fa fa-chevron-up fa-sm icon"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngIf="showOptions">
|
||||||
|
<!-- Deletion Date -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row" *ngIf="!editMode">
|
||||||
|
<label for="deletionDate">{{'deletionDate' | i18n}}</label>
|
||||||
|
<select id="deletionDate" name="DeletionDateSelect" [(ngModel)]="deletionDateSelect" required>
|
||||||
|
<option *ngFor="let o of deletionDateOptions" [ngValue]="o.value">{{o.name}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" *ngIf="deletionDateSelect === 0 && !editMode">
|
||||||
|
<input id="deletionDateCustom" type="datetime-local" name="DeletionDate"
|
||||||
|
[(ngModel)]="deletionDate" required placeholder="MM/DD/YYYY HH:MM AM/PM">
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" *ngIf="editMode" appBoxRow>
|
||||||
|
<label for="editDeletionDate">{{'deletionDate' | i18n}}</label>
|
||||||
|
<input id="editDeletionDate" type="datetime-local" name="EditDeletionDate"
|
||||||
|
[(ngModel)]="deletionDate" required placeholder="MM/DD/YYYY HH:MM AM/PM">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'deletionDateDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Expiration Date -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row" *ngIf="!editMode">
|
||||||
|
<label for="expirationDate">{{'expirationDate' | i18n}}</label>
|
||||||
|
<select id="expirationDate" name="ExpirationDateSelect" [(ngModel)]="expirationDateSelect"
|
||||||
|
required>
|
||||||
|
<option *ngFor="let o of expirationDateOptions" [ngValue]="o.value">{{o.name}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" *ngIf="expirationDateSelect === 0 && !editMode">
|
||||||
|
<input id="expirationDateCustom" type="datetime-local" name="ExpirationDate"
|
||||||
|
[(ngModel)]="expirationDate" required placeholder="MM/DD/YYYY HH:MM AM/PM">
|
||||||
|
</div>
|
||||||
|
<div class="box-content-row" *ngIf="editMode" appBoxRow>
|
||||||
|
<div class="flex-label">
|
||||||
|
<label for="editExpirationDate">{{'expirationDate' | i18n}}</label>
|
||||||
|
<a href="#" appStopClick (click)="clearExpiration()">
|
||||||
|
{{'clear' | i18n}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<input id="editExpirationDate" type="datetime-local" name="EditExpirationDate"
|
||||||
|
[(ngModel)]="expirationDate" placeholder="MM/DD/YYYY HH:MM AM/PM">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'expirationDateDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Maximum Access Count -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="maximumAccessCount">{{'maximumAccessCount' | i18n}}</label>
|
||||||
|
<input id="maximumAccessCount" min="1" type="number" name="MaximumAccessCount"
|
||||||
|
[(ngModel)]="send.maxAccessCount">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'maximumAccessCountDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Current Access Count -->
|
||||||
|
<div class="box" *ngIf="editMode">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="currentAccessCount">{{'currentAccessCount' | i18n}}</label>
|
||||||
|
<input id="currentAccessCount" readonly type="number" name="CurrentAccessCount"
|
||||||
|
[(ngModel)]="send.accessCount">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Password -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row box-content-row-flex" appBoxRow>
|
||||||
|
<div class="row-main">
|
||||||
|
<label for="password" *ngIf="hasPassword">{{'newPassword' | i18n}}</label>
|
||||||
|
<label for="password" *ngIf="!hasPassword">{{'password' | i18n}}</label>
|
||||||
|
<input id="password" type="{{showPassword ? 'text' : 'password'}}" name="Password"
|
||||||
|
class="monospaced" [(ngModel)]="password" appInputVerbatim>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<a class="row-btn" href="#" appStopClick appBlurClick
|
||||||
|
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePasswordVisible()">
|
||||||
|
<i class="fa fa-lg" [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"
|
||||||
|
aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'sendPasswordDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Notes -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row" appBoxRow>
|
||||||
|
<label for="notes">{{'notes' | i18n}}</label>
|
||||||
|
<textarea id="notes" name="Notes" rows="6" [(ngModel)]="send.notes"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'sendNotesDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Disable Send -->
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||||
|
<label for="disableSend">{{'sendDisableDesc' | i18n}}</label>
|
||||||
|
<input id="disableSend" type="checkbox" name="DisableSend" [(ngModel)]="send.disabled">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Delete -->
|
||||||
|
<div class="box list" *ngIf="editMode">
|
||||||
|
<div class="box-content single-line">
|
||||||
|
<a class="box-content-row" href="#" appStopClick appBlurClick (click)="delete()"
|
||||||
|
[appApiAction]="deletePromise" #deleteBtn>
|
||||||
|
<div class="row-main text-danger">
|
||||||
|
<div class="icon text-danger" aria-hidden="true">
|
||||||
|
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading"></i>
|
||||||
|
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading"></i>
|
||||||
|
</div>
|
||||||
|
<span>{{'deleteSend' | i18n}}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</content>
|
||||||
|
</form>
|
124
src/popup/send/send-add-edit.component.ts
Normal file
124
src/popup/send/send-add-edit.component.ts
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import {
|
||||||
|
DatePipe,
|
||||||
|
Location,
|
||||||
|
} from '@angular/common';
|
||||||
|
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActivatedRoute,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||||
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||||
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { PolicyService } from 'jslib/abstractions/policy.service';
|
||||||
|
import { SendService } from 'jslib/abstractions/send.service';
|
||||||
|
import { UserService } from 'jslib/abstractions/user.service';
|
||||||
|
|
||||||
|
import { PopupUtilsService } from '../services/popup-utils.service';
|
||||||
|
|
||||||
|
import { AddEditComponent as BaseAddEditComponent } from 'jslib/angular/components/send/add-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-send-add-edit',
|
||||||
|
templateUrl: 'send-add-edit.component.html',
|
||||||
|
})
|
||||||
|
export class SendAddEditComponent extends BaseAddEditComponent {
|
||||||
|
// Options header
|
||||||
|
showOptions = false;
|
||||||
|
// File visibility
|
||||||
|
isFirefox = false;
|
||||||
|
isSafari = false;
|
||||||
|
inPopout = false;
|
||||||
|
inSidebar = false;
|
||||||
|
|
||||||
|
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
|
||||||
|
userService: UserService, messagingService: MessagingService, policyService: PolicyService,
|
||||||
|
environmentService: EnvironmentService, datePipe: DatePipe, sendService: SendService,
|
||||||
|
private route: ActivatedRoute, private router: Router, private location: Location,
|
||||||
|
private popupUtilsService: PopupUtilsService) {
|
||||||
|
super(i18nService, platformUtilsService, environmentService, datePipe, sendService, userService,
|
||||||
|
messagingService, policyService);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showFileSelector(): boolean {
|
||||||
|
return !this.editMode && (!this.isFirefox && !this.isSafari) ||
|
||||||
|
(this.isFirefox && (this.inSidebar || this.inPopout)) ||
|
||||||
|
(this.isSafari && this.inPopout);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showFilePopoutMessage(): boolean {
|
||||||
|
return !this.editMode && (this.showFirefoxFileWarning || this.showSafariFileWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showFirefoxFileWarning(): boolean {
|
||||||
|
return this.isFirefox && !(this.inSidebar || this.inPopout);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showSafariFileWarning(): boolean {
|
||||||
|
return this.isSafari && !this.inPopout;
|
||||||
|
}
|
||||||
|
|
||||||
|
popOutWindow() {
|
||||||
|
this.popupUtilsService.popOut(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
// File visilibity
|
||||||
|
this.isFirefox = this.platformUtilsService.isFirefox();
|
||||||
|
this.isSafari = this.platformUtilsService.isSafari();
|
||||||
|
this.inPopout = this.popupUtilsService.inPopout(window);
|
||||||
|
this.inSidebar = this.popupUtilsService.inSidebar(window);
|
||||||
|
|
||||||
|
const queryParamsSub = this.route.queryParams.subscribe(async (params) => {
|
||||||
|
if (params.sendId) {
|
||||||
|
this.sendId = params.sendId;
|
||||||
|
}
|
||||||
|
if (params.type) {
|
||||||
|
const type = parseInt(params.type, null);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
await this.load();
|
||||||
|
|
||||||
|
if (queryParamsSub != null) {
|
||||||
|
queryParamsSub.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.setTimeout(() => {
|
||||||
|
if (!this.editMode) {
|
||||||
|
document.getElementById('name').focus();
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
async submit(): Promise<boolean> {
|
||||||
|
if (await super.submit()) {
|
||||||
|
this.cancel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(): Promise<boolean> {
|
||||||
|
if (await super.delete()) {
|
||||||
|
this.cancel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
// If true, the window was pop'd out on the add-send page. location.back will not work
|
||||||
|
if ((window as any).previousPopupUrl.startsWith('/add-send')) {
|
||||||
|
this.router.navigate(['tabs/send']);
|
||||||
|
} else {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActivatedRoute,
|
|
||||||
Router,
|
Router,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ export class SendGroupingsComponent extends BaseSendComponent {
|
|||||||
platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService, ngZone: NgZone,
|
platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService, ngZone: NgZone,
|
||||||
policyService: PolicyService, userService: UserService, searchService: SearchService,
|
policyService: PolicyService, userService: UserService, searchService: SearchService,
|
||||||
private popupUtils: PopupUtilsService, private stateService: StateService,
|
private popupUtils: PopupUtilsService, private stateService: StateService,
|
||||||
private route: ActivatedRoute, private router: Router, private syncService: SyncService,
|
private router: Router, private syncService: SyncService,
|
||||||
private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService) {
|
private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService) {
|
||||||
super(sendService, i18nService, platformUtilsService, environmentService, ngZone, searchService,
|
super(sendService, i18nService, platformUtilsService, environmentService, ngZone, searchService,
|
||||||
policyService, userService);
|
policyService, userService);
|
||||||
@ -122,11 +121,11 @@ export class SendGroupingsComponent extends BaseSendComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async selectSend(s: SendView) {
|
async selectSend(s: SendView) {
|
||||||
// TODO -> Route to edit send
|
this.router.navigate(['/edit-send'], { queryParams: { sendId: s.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
async addSend() {
|
async addSend() {
|
||||||
// TODO -> Route to create send
|
this.router.navigate(['/add-send']);
|
||||||
}
|
}
|
||||||
|
|
||||||
showSearching() {
|
showSearching() {
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ActivatedRoute,
|
ActivatedRoute,
|
||||||
|
Router,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
@ -47,7 +48,7 @@ export class SendTypeComponent extends BaseSendComponent {
|
|||||||
policyService: PolicyService, userService: UserService, searchService: SearchService,
|
policyService: PolicyService, userService: UserService, searchService: SearchService,
|
||||||
private popupUtils: PopupUtilsService, private stateService: StateService,
|
private popupUtils: PopupUtilsService, private stateService: StateService,
|
||||||
private route: ActivatedRoute, private location: Location, private changeDetectorRef: ChangeDetectorRef,
|
private route: ActivatedRoute, private location: Location, private changeDetectorRef: ChangeDetectorRef,
|
||||||
private broadcasterService: BroadcasterService) {
|
private broadcasterService: BroadcasterService, private router: Router) {
|
||||||
super(sendService, i18nService, platformUtilsService, environmentService, ngZone, searchService,
|
super(sendService, i18nService, platformUtilsService, environmentService, ngZone, searchService,
|
||||||
policyService, userService);
|
policyService, userService);
|
||||||
super.onSuccessfulLoad = async () => {
|
super.onSuccessfulLoad = async () => {
|
||||||
@ -127,11 +128,11 @@ export class SendTypeComponent extends BaseSendComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async selectSend(s: SendView) {
|
async selectSend(s: SendView) {
|
||||||
// TODO -> Route to edit send
|
this.router.navigate(['/edit-send'], { queryParams: { sendId: s.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
async addSend() {
|
async addSend() {
|
||||||
// TODO -> Route to create send
|
this.router.navigate(['/add-send'], { queryParams: { type: this.type } });
|
||||||
}
|
}
|
||||||
|
|
||||||
back() {
|
back() {
|
||||||
|
Loading…
Reference in New Issue
Block a user