1
0
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:
Vincent Salucci 2021-02-23 15:37:55 -06:00 committed by GitHub
parent 2ac9f92267
commit 4853fb3e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 582 additions and 12 deletions

2
jslib

@ -1 +1 @@
Subproject commit b0ae1bfa4cb3bc2642e1ecb14c6c1f0eceb06cb6 Subproject commit 42348e2fdc6206157d68d8a9f496eaa70520ab01

View File

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

View File

@ -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),
]); ]);

View File

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

View File

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

View File

@ -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],
}) })

View File

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

View File

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

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

View 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();
}
}
}

View File

@ -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() {

View File

@ -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() {