mirror of
https://github.com/bitwarden/web
synced 2025-12-27 13:43:21 +00:00
Apply Prettier (#1347)
This commit is contained in:
@@ -1,92 +1,152 @@
|
||||
<form #form (ngSubmit)="load()" [appApiAction]="formPromise" class="container" ngNativeValidate>
|
||||
<div class="row justify-content-center mt-5">
|
||||
<div class="col-12">
|
||||
<p class="lead text-center mb-4">Bitwarden Send</p>
|
||||
</div>
|
||||
<div class="col-12 text-center" *ngIf="creatorIdentifier != null">
|
||||
<p>{{'sendCreatorIdentifier' | i18n: creatorIdentifier }}</p>
|
||||
</div>
|
||||
<div class="col-8" *ngIf="hideEmail">
|
||||
<app-callout type="warning" title="{{'warning' | i18n}}">
|
||||
{{'viewSendHiddenEmailWarning' | i18n }}
|
||||
<a href="https://bitwarden.com/help/article/receive-send/" target="_blank">{{'learnMore' | i18n}}</a>.
|
||||
</app-callout>
|
||||
</div>
|
||||
<div class="row justify-content-center mt-5">
|
||||
<div class="col-12">
|
||||
<p class="lead text-center mb-4">Bitwarden Send</p>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-5">
|
||||
<div class="card d-block">
|
||||
<div class="card-body" *ngIf="loading" class="text-center">
|
||||
<i class="fa fa-spinner fa-spin fa-2x text-muted" title="{{'loading' | i18n}}"
|
||||
aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'loading' | i18n}}</span>
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && passwordRequired">
|
||||
<p>{{'sendProtectedPassword' | i18n}}</p>
|
||||
<p>{{'sendProtectedPasswordDontKnow' | i18n}}</p>
|
||||
<div class="form-group">
|
||||
<label for="password">{{'password' | i18n}}</label>
|
||||
<input id="password" type="password" name="Password" class="text-monospace form-control"
|
||||
[(ngModel)]="password" required appInputVerbatim appAutofocus>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<button type="submit" class="btn btn-primary btn-block btn-submit" [disabled]="form.loading">
|
||||
<span>
|
||||
<i class="fa fa-sign-in" aria-hidden="true"></i> {{'continue' | i18n}}
|
||||
</span>
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && unavailable">
|
||||
{{'sendAccessUnavailable' | i18n}}
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && error">
|
||||
{{'unexpectedError' | i18n}}
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && !passwordRequired && send">
|
||||
<p class="text-center"><b>{{send.name}}</b></p>
|
||||
<hr>
|
||||
<!-- Text -->
|
||||
<ng-container *ngIf="send.type === sendType.Text">
|
||||
<app-callout *ngIf="send.text.hidden" type="tip">{{'sendHiddenByDefault' | i18n}}</app-callout>
|
||||
<div class="form-group">
|
||||
<textarea id="text" rows="8" name="Text" [(ngModel)]="sendText" class="form-control"
|
||||
readonly></textarea>
|
||||
</div>
|
||||
<button class="btn btn-block btn-link" type="button" (click)="toggleText()"
|
||||
*ngIf="send.text.hidden">
|
||||
<i class="fa fa-lg" aria-hidden="true"
|
||||
[ngClass]="{'fa-eye': !showText, 'fa-eye-slash': showText}"></i>
|
||||
{{'toggleVisibility' | i18n}}
|
||||
</button>
|
||||
<button class="btn btn-block btn-link" type="button" (click)="copyText()">
|
||||
<i class="fa fa-copy" aria-hidden="true"></i> {{'copyValue' | i18n}}
|
||||
</button>
|
||||
</ng-container>
|
||||
<!-- File -->
|
||||
<ng-container *ngIf="send.type === sendType.File">
|
||||
<p>{{send.file.fileName}}</p>
|
||||
<button class="btn btn-primary btn-block" type="button" (click)="download()" *ngIf="!downloading">
|
||||
<i class="fa fa-download" aria-hidden="true"></i>
|
||||
{{'downloadFile' | i18n}} ({{send.file.sizeName}})</button>
|
||||
<button class="btn btn-primary btn-block" type="button" *ngIf="downloading" disabled="true">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
</button>
|
||||
</ng-container>
|
||||
<p *ngIf="expirationDate" class="text-center text-muted">Expires:
|
||||
{{expirationDate | date: 'medium'}}</p>
|
||||
</div>
|
||||
<div class="col-12 text-center" *ngIf="creatorIdentifier != null">
|
||||
<p>{{ "sendCreatorIdentifier" | i18n: creatorIdentifier }}</p>
|
||||
</div>
|
||||
<div class="col-8" *ngIf="hideEmail">
|
||||
<app-callout type="warning" title="{{ 'warning' | i18n }}">
|
||||
{{ "viewSendHiddenEmailWarning" | i18n }}
|
||||
<a href="https://bitwarden.com/help/article/receive-send/" target="_blank">{{
|
||||
"learnMore" | i18n
|
||||
}}</a
|
||||
>.
|
||||
</app-callout>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-5">
|
||||
<div class="card d-block">
|
||||
<div class="card-body" *ngIf="loading" class="text-center">
|
||||
<i
|
||||
class="fa fa-spinner fa-spin fa-2x text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && passwordRequired">
|
||||
<p>{{ "sendProtectedPassword" | i18n }}</p>
|
||||
<p>{{ "sendProtectedPasswordDontKnow" | i18n }}</p>
|
||||
<div class="form-group">
|
||||
<label for="password">{{ "password" | i18n }}</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
name="Password"
|
||||
class="text-monospace form-control"
|
||||
[(ngModel)]="password"
|
||||
required
|
||||
appInputVerbatim
|
||||
appAutofocus
|
||||
/>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block btn-submit"
|
||||
[disabled]="form.loading"
|
||||
>
|
||||
<span>
|
||||
<i class="fa fa-sign-in" aria-hidden="true"></i> {{ "continue" | i18n }}
|
||||
</span>
|
||||
<i
|
||||
class="fa fa-spinner fa-spin"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && unavailable">
|
||||
{{ "sendAccessUnavailable" | i18n }}
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && error">
|
||||
{{ "unexpectedError" | i18n }}
|
||||
</div>
|
||||
<div class="card-body" *ngIf="!loading && !passwordRequired && send">
|
||||
<p class="text-center">
|
||||
<b>{{ send.name }}</b>
|
||||
</p>
|
||||
<hr />
|
||||
<!-- Text -->
|
||||
<ng-container *ngIf="send.type === sendType.Text">
|
||||
<app-callout *ngIf="send.text.hidden" type="tip">{{
|
||||
"sendHiddenByDefault" | i18n
|
||||
}}</app-callout>
|
||||
<div class="form-group">
|
||||
<textarea
|
||||
id="text"
|
||||
rows="8"
|
||||
name="Text"
|
||||
[(ngModel)]="sendText"
|
||||
class="form-control"
|
||||
readonly
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-block btn-link"
|
||||
type="button"
|
||||
(click)="toggleText()"
|
||||
*ngIf="send.text.hidden"
|
||||
>
|
||||
<i
|
||||
class="fa fa-lg"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{ 'fa-eye': !showText, 'fa-eye-slash': showText }"
|
||||
></i>
|
||||
{{ "toggleVisibility" | i18n }}
|
||||
</button>
|
||||
<button class="btn btn-block btn-link" type="button" (click)="copyText()">
|
||||
<i class="fa fa-copy" aria-hidden="true"></i> {{ "copyValue" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
<!-- File -->
|
||||
<ng-container *ngIf="send.type === sendType.File">
|
||||
<p>{{ send.file.fileName }}</p>
|
||||
<button
|
||||
class="btn btn-primary btn-block"
|
||||
type="button"
|
||||
(click)="download()"
|
||||
*ngIf="!downloading"
|
||||
>
|
||||
<i class="fa fa-download" aria-hidden="true"></i>
|
||||
{{ "downloadFile" | i18n }} ({{ send.file.sizeName }})
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary btn-block"
|
||||
type="button"
|
||||
*ngIf="downloading"
|
||||
disabled="true"
|
||||
>
|
||||
<i
|
||||
class="fa fa-spinner fa-spin"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
</ng-container>
|
||||
<p *ngIf="expirationDate" class="text-center text-muted">
|
||||
Expires: {{ expirationDate | date: "medium" }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-12 text-center mt-5 text-muted">
|
||||
<p class="mb-0">{{'sendAccessTaglineProductDesc' | i18n}}<br>
|
||||
{{'sendAccessTaglineLearnMore' | i18n}} <a
|
||||
href="https://www.bitwarden.com/products/send?source=web-vault" target="_blank">Bitwarden Send</a>
|
||||
{{'sendAccessTaglineOr' | i18n}} <a
|
||||
href="https://vault.bitwarden.com/#/register" target="_blank">{{'sendAccessTaglineSignUp' | i18n}}</a>
|
||||
{{'sendAccessTaglineTryToday' | i18n}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 text-center mt-5 text-muted">
|
||||
<p class="mb-0">
|
||||
{{ "sendAccessTaglineProductDesc" | i18n }}<br />
|
||||
{{ "sendAccessTaglineLearnMore" | i18n }}
|
||||
<a href="https://www.bitwarden.com/products/send?source=web-vault" target="_blank"
|
||||
>Bitwarden Send</a
|
||||
>
|
||||
{{ "sendAccessTaglineOr" | i18n }}
|
||||
<a href="https://vault.bitwarden.com/#/register" target="_blank">{{
|
||||
"sendAccessTaglineSignUp" | i18n
|
||||
}}</a>
|
||||
{{ "sendAccessTaglineTryToday" | i18n }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,169 +1,184 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
|
||||
import { SendAccess } from 'jslib-common/models/domain/sendAccess';
|
||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
||||
import { SendAccess } from "jslib-common/models/domain/sendAccess";
|
||||
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||
|
||||
import { SendAccessView } from 'jslib-common/models/view/sendAccessView';
|
||||
import { SendAccessView } from "jslib-common/models/view/sendAccessView";
|
||||
|
||||
import { SendType } from 'jslib-common/enums/sendType';
|
||||
import { SendAccessRequest } from 'jslib-common/models/request/sendAccessRequest';
|
||||
import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
|
||||
import { SendType } from "jslib-common/enums/sendType";
|
||||
import { SendAccessRequest } from "jslib-common/models/request/sendAccessRequest";
|
||||
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
|
||||
|
||||
import { SendAccessResponse } from 'jslib-common/models/response/sendAccessResponse';
|
||||
import { SendAccessResponse } from "jslib-common/models/response/sendAccessResponse";
|
||||
|
||||
@Component({
|
||||
selector: 'app-send-access',
|
||||
templateUrl: 'access.component.html',
|
||||
selector: "app-send-access",
|
||||
templateUrl: "access.component.html",
|
||||
})
|
||||
export class AccessComponent implements OnInit {
|
||||
send: SendAccessView;
|
||||
sendType = SendType;
|
||||
downloading = false;
|
||||
loading = true;
|
||||
passwordRequired = false;
|
||||
formPromise: Promise<SendAccessResponse>;
|
||||
password: string;
|
||||
showText = false;
|
||||
unavailable = false;
|
||||
error = false;
|
||||
hideEmail = false;
|
||||
send: SendAccessView;
|
||||
sendType = SendType;
|
||||
downloading = false;
|
||||
loading = true;
|
||||
passwordRequired = false;
|
||||
formPromise: Promise<SendAccessResponse>;
|
||||
password: string;
|
||||
showText = false;
|
||||
unavailable = false;
|
||||
error = false;
|
||||
hideEmail = false;
|
||||
|
||||
private id: string;
|
||||
private key: string;
|
||||
private decKey: SymmetricCryptoKey;
|
||||
private accessRequest: SendAccessRequest;
|
||||
private id: string;
|
||||
private key: string;
|
||||
private decKey: SymmetricCryptoKey;
|
||||
private accessRequest: SendAccessRequest;
|
||||
|
||||
constructor(private i18nService: I18nService, private cryptoFunctionService: CryptoFunctionService,
|
||||
private apiService: ApiService, private platformUtilsService: PlatformUtilsService,
|
||||
private route: ActivatedRoute, private cryptoService: CryptoService) {
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private apiService: ApiService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private route: ActivatedRoute,
|
||||
private cryptoService: CryptoService
|
||||
) {}
|
||||
|
||||
get sendText() {
|
||||
if (this.send == null || this.send.text == null) {
|
||||
return null;
|
||||
}
|
||||
return this.showText ? this.send.text.text : this.send.text.maskedText;
|
||||
}
|
||||
|
||||
get expirationDate() {
|
||||
if (this.send == null || this.send.expirationDate == null) {
|
||||
return null;
|
||||
}
|
||||
return this.send.expirationDate;
|
||||
}
|
||||
|
||||
get creatorIdentifier() {
|
||||
if (this.send == null || this.send.creatorIdentifier == null) {
|
||||
return null;
|
||||
}
|
||||
return this.send.creatorIdentifier;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe(async (params) => {
|
||||
this.id = params.sendId;
|
||||
this.key = params.key;
|
||||
if (this.key == null || this.id == null) {
|
||||
return;
|
||||
}
|
||||
await this.load();
|
||||
});
|
||||
}
|
||||
|
||||
async download() {
|
||||
if (this.send == null || this.decKey == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
get sendText() {
|
||||
if (this.send == null || this.send.text == null) {
|
||||
return null;
|
||||
}
|
||||
return this.showText ? this.send.text.text : this.send.text.maskedText;
|
||||
if (this.downloading) {
|
||||
return;
|
||||
}
|
||||
|
||||
get expirationDate() {
|
||||
if (this.send == null || this.send.expirationDate == null) {
|
||||
return null;
|
||||
}
|
||||
return this.send.expirationDate;
|
||||
const downloadData = await this.apiService.getSendFileDownloadData(
|
||||
this.send,
|
||||
this.accessRequest
|
||||
);
|
||||
|
||||
if (Utils.isNullOrWhitespace(downloadData.url)) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("missingSendFile"));
|
||||
return;
|
||||
}
|
||||
|
||||
get creatorIdentifier() {
|
||||
if (this.send == null || this.send.creatorIdentifier == null) {
|
||||
return null;
|
||||
}
|
||||
return this.send.creatorIdentifier;
|
||||
this.downloading = true;
|
||||
const response = await fetch(new Request(downloadData.url, { cache: "no-store" }));
|
||||
if (response.status !== 200) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.downloading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe(async params => {
|
||||
this.id = params.sendId;
|
||||
this.key = params.key;
|
||||
if (this.key == null || this.id == null) {
|
||||
return;
|
||||
}
|
||||
await this.load();
|
||||
});
|
||||
try {
|
||||
const buf = await response.arrayBuffer();
|
||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, this.decKey);
|
||||
this.platformUtilsService.saveFile(window, decBuf, null, this.send.file.fileName);
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
}
|
||||
|
||||
async download() {
|
||||
if (this.send == null || this.decKey == null) {
|
||||
return;
|
||||
}
|
||||
this.downloading = false;
|
||||
}
|
||||
|
||||
if (this.downloading) {
|
||||
return;
|
||||
}
|
||||
copyText() {
|
||||
this.platformUtilsService.copyToClipboard(this.send.text.text);
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("valueCopied", this.i18nService.t("sendTypeText"))
|
||||
);
|
||||
}
|
||||
|
||||
toggleText() {
|
||||
this.showText = !this.showText;
|
||||
}
|
||||
|
||||
const downloadData = await this.apiService.getSendFileDownloadData(this.send, this.accessRequest);
|
||||
|
||||
if (Utils.isNullOrWhitespace(downloadData.url)) {
|
||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('missingSendFile'));
|
||||
return;
|
||||
}
|
||||
|
||||
this.downloading = true;
|
||||
const response = await fetch(new Request(downloadData.url, { cache: 'no-store' }));
|
||||
if (response.status !== 200) {
|
||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
|
||||
this.downloading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const buf = await response.arrayBuffer();
|
||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, this.decKey);
|
||||
this.platformUtilsService.saveFile(window, decBuf, null, this.send.file.fileName);
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
|
||||
}
|
||||
|
||||
this.downloading = false;
|
||||
async load() {
|
||||
this.unavailable = false;
|
||||
this.error = false;
|
||||
this.hideEmail = false;
|
||||
const keyArray = Utils.fromUrlB64ToArray(this.key);
|
||||
this.accessRequest = new SendAccessRequest();
|
||||
if (this.password != null) {
|
||||
const passwordHash = await this.cryptoFunctionService.pbkdf2(
|
||||
this.password,
|
||||
keyArray,
|
||||
"sha256",
|
||||
100000
|
||||
);
|
||||
this.accessRequest.password = Utils.fromBufferToB64(passwordHash);
|
||||
}
|
||||
|
||||
copyText() {
|
||||
this.platformUtilsService.copyToClipboard(this.send.text.text);
|
||||
this.platformUtilsService.showToast('success', null,
|
||||
this.i18nService.t('valueCopied', this.i18nService.t('sendTypeText')));
|
||||
}
|
||||
|
||||
toggleText() {
|
||||
this.showText = !this.showText;
|
||||
}
|
||||
|
||||
async load() {
|
||||
this.unavailable = false;
|
||||
this.error = false;
|
||||
this.hideEmail = false;
|
||||
const keyArray = Utils.fromUrlB64ToArray(this.key);
|
||||
this.accessRequest = new SendAccessRequest();
|
||||
if (this.password != null) {
|
||||
const passwordHash = await this.cryptoFunctionService.pbkdf2(this.password, keyArray, 'sha256', 100000);
|
||||
this.accessRequest.password = Utils.fromBufferToB64(passwordHash);
|
||||
try {
|
||||
let sendResponse: SendAccessResponse = null;
|
||||
if (this.loading) {
|
||||
sendResponse = await this.apiService.postSendAccess(this.id, this.accessRequest);
|
||||
} else {
|
||||
this.formPromise = this.apiService.postSendAccess(this.id, this.accessRequest);
|
||||
sendResponse = await this.formPromise;
|
||||
}
|
||||
this.passwordRequired = false;
|
||||
const sendAccess = new SendAccess(sendResponse);
|
||||
this.decKey = await this.cryptoService.makeSendKey(keyArray);
|
||||
this.send = await sendAccess.decrypt(this.decKey);
|
||||
this.showText = this.send.text != null ? !this.send.text.hidden : true;
|
||||
} catch (e) {
|
||||
if (e instanceof ErrorResponse) {
|
||||
if (e.statusCode === 401) {
|
||||
this.passwordRequired = true;
|
||||
} else if (e.statusCode === 404) {
|
||||
this.unavailable = true;
|
||||
} else {
|
||||
this.error = true;
|
||||
}
|
||||
try {
|
||||
let sendResponse: SendAccessResponse = null;
|
||||
if (this.loading) {
|
||||
sendResponse = await this.apiService.postSendAccess(this.id, this.accessRequest);
|
||||
} else {
|
||||
this.formPromise = this.apiService.postSendAccess(this.id, this.accessRequest);
|
||||
sendResponse = await this.formPromise;
|
||||
}
|
||||
this.passwordRequired = false;
|
||||
const sendAccess = new SendAccess(sendResponse);
|
||||
this.decKey = await this.cryptoService.makeSendKey(keyArray);
|
||||
this.send = await sendAccess.decrypt(this.decKey);
|
||||
this.showText = this.send.text != null ? !this.send.text.hidden : true;
|
||||
} catch (e) {
|
||||
if (e instanceof ErrorResponse) {
|
||||
if (e.statusCode === 401) {
|
||||
this.passwordRequired = true;
|
||||
} else if (e.statusCode === 404) {
|
||||
this.unavailable = true;
|
||||
} else {
|
||||
this.error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
this.hideEmail = this.creatorIdentifier == null && !this.passwordRequired && !this.loading && !this.unavailable;
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
this.hideEmail =
|
||||
this.creatorIdentifier == null &&
|
||||
!this.passwordRequired &&
|
||||
!this.loading &&
|
||||
!this.unavailable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,176 +1,308 @@
|
||||
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="sendAddEditTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate
|
||||
autocomplete="off">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="sendAddEditTitle">{{title}}</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<form
|
||||
class="modal-content"
|
||||
#form
|
||||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
ngNativeValidate
|
||||
autocomplete="off"
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="sendAddEditTitle">{{ title }}</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
appA11yTitle="{{ 'close' | i18n }}"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" *ngIf="send">
|
||||
<app-callout *ngIf="disableSend">
|
||||
<span>{{ "sendDisabledWarning" | i18n }}</span>
|
||||
</app-callout>
|
||||
<app-callout *ngIf="!disableSend && disableHideEmail">
|
||||
<span>{{ "sendOptionsPolicyInEffect" | i18n }}</span>
|
||||
<ul class="mb-0">
|
||||
<li>{{ "sendDisableHideEmailInEffect" | i18n }}</li>
|
||||
</ul>
|
||||
</app-callout>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<label for="name">{{ "name" | i18n }}</label>
|
||||
<input
|
||||
id="name"
|
||||
class="form-control"
|
||||
type="text"
|
||||
name="Name"
|
||||
[(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(o)"
|
||||
[checked]="send.type === o.value"
|
||||
/>
|
||||
<label class="form-check-label" for="type_{{ o.value }}">
|
||||
{{ o.name }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-body" *ngIf="send">
|
||||
<app-callout *ngIf="disableSend">
|
||||
<span>{{'sendDisabledWarning' | i18n}}</span>
|
||||
</app-callout>
|
||||
<app-callout *ngIf="!disableSend && disableHideEmail">
|
||||
<span>{{'sendOptionsPolicyInEffect' | i18n}}</span>
|
||||
<ul class="mb-0">
|
||||
<li>{{'sendDisableHideEmailInEffect' | i18n}}</li>
|
||||
</ul>
|
||||
</app-callout>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<label for="name">{{'name' | i18n}}</label>
|
||||
<input id="name" class="form-control" type="text" name="Name" [(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(o)"
|
||||
[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}})
|
||||
</div>
|
||||
<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>
|
||||
</ng-container>
|
||||
<h3 class="mt-5">{{'share' | i18n}}</h3>
|
||||
<div class="form-group" *ngIf="link">
|
||||
<label for="link">{{'sendLinkLabel' | i18n}}</label>
|
||||
<input type="text" readonly id="link" name="Link" [(ngModel)]="link" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" [(ngModel)]="copyLink" id="copy-link"
|
||||
name="CopyLink">
|
||||
<label class="form-check-label" for="copy-link">{{'copySendLinkOnSave' | i18n}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="options-header" class="section-header d-flex flex-row align-items-center mt-5"
|
||||
(click)="toggleOptions()">
|
||||
<h3 class="mb-0 mr-2">{{'options' | i18n}}</h3>
|
||||
<a class="mb-1" href="#" appStopClick role="button">
|
||||
<i class="fa" aria-hidden="true"
|
||||
[ngClass]="{'fa-chevron-down': !showOptions, 'fa-chevron-up': showOptions}"></i>
|
||||
</a>
|
||||
</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="fa fa-lg" aria-hidden="true"
|
||||
[ngClass]="{'fa-eye': !showPassword, 'fa-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>
|
||||
<!-- 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 class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit manual" [ngClass]="{loading:form.loading}"
|
||||
[disabled]="form.loading || disableSend">
|
||||
<i class="fa fa-spinner fa-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]="deleteBtn.loading"
|
||||
[appApiAction]="deletePromise">
|
||||
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading" aria-hidden="true"></i>
|
||||
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading"
|
||||
title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
</button>
|
||||
</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 }})
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<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>
|
||||
</ng-container>
|
||||
<h3 class="mt-5">{{ "share" | i18n }}</h3>
|
||||
<div class="form-group" *ngIf="link">
|
||||
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
id="link"
|
||||
name="Link"
|
||||
[(ngModel)]="link"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
[(ngModel)]="copyLink"
|
||||
id="copy-link"
|
||||
name="CopyLink"
|
||||
/>
|
||||
<label class="form-check-label" for="copy-link">{{
|
||||
"copySendLinkOnSave" | i18n
|
||||
}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="options-header"
|
||||
class="section-header d-flex flex-row align-items-center mt-5"
|
||||
(click)="toggleOptions()"
|
||||
>
|
||||
<h3 class="mb-0 mr-2">{{ "options" | i18n }}</h3>
|
||||
<a class="mb-1" href="#" appStopClick role="button">
|
||||
<i
|
||||
class="fa"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{ 'fa-chevron-down': !showOptions, 'fa-chevron-up': showOptions }"
|
||||
></i>
|
||||
</a>
|
||||
</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="fa fa-lg"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{ 'fa-eye': !showPassword, 'fa-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="fa fa-spinner fa-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]="deleteBtn.loading"
|
||||
[appApiAction]="deletePromise"
|
||||
>
|
||||
<i
|
||||
class="fa fa-trash-o fa-lg fa-fw"
|
||||
[hidden]="deleteBtn.loading"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<i
|
||||
class="fa fa-spinner fa-spin fa-lg fa-fw"
|
||||
[hidden]="!deleteBtn.loading"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,37 +1,52 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { DatePipe } from "@angular/common";
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { SendService } from 'jslib-common/abstractions/send.service';
|
||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||
import { SendService } from "jslib-common/abstractions/send.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from 'jslib-angular/components/send/add-edit.component';
|
||||
import { AddEditComponent as BaseAddEditComponent } from "jslib-angular/components/send/add-edit.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-send-add-edit',
|
||||
templateUrl: 'add-edit.component.html',
|
||||
selector: "app-send-add-edit",
|
||||
templateUrl: "add-edit.component.html",
|
||||
})
|
||||
export class AddEditComponent extends BaseAddEditComponent {
|
||||
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
|
||||
environmentService: EnvironmentService, datePipe: DatePipe,
|
||||
sendService: SendService, stateService: StateService,
|
||||
messagingService: MessagingService, policyService: PolicyService,
|
||||
logService: LogService) {
|
||||
super(i18nService, platformUtilsService, environmentService, datePipe, sendService,
|
||||
messagingService, policyService, logService, stateService);
|
||||
}
|
||||
constructor(
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
environmentService: EnvironmentService,
|
||||
datePipe: DatePipe,
|
||||
sendService: SendService,
|
||||
stateService: StateService,
|
||||
messagingService: MessagingService,
|
||||
policyService: PolicyService,
|
||||
logService: LogService
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
environmentService,
|
||||
datePipe,
|
||||
sendService,
|
||||
messagingService,
|
||||
policyService,
|
||||
logService,
|
||||
stateService
|
||||
);
|
||||
}
|
||||
|
||||
async copyLinkToClipboard(link: string): Promise<void | boolean> {
|
||||
// Copy function on web depends on the modal being open or not. Since this event occurs during a transition
|
||||
// of the modal closing we need to add a small delay to make sure state of the DOM is consistent.
|
||||
return new Promise(resolve => {
|
||||
window.setTimeout(() => resolve(super.copyLinkToClipboard(link)), 500);
|
||||
});
|
||||
}
|
||||
async copyLinkToClipboard(link: string): Promise<void | boolean> {
|
||||
// Copy function on web depends on the modal being open or not. Since this event occurs during a transition
|
||||
// of the modal closing we need to add a small delay to make sure state of the DOM is consistent.
|
||||
return new Promise((resolve) => {
|
||||
window.setTimeout(() => resolve(super.copyLinkToClipboard(link)), 500);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +1,191 @@
|
||||
<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" [readOnly]="disableSend" 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" [readOnly]="disableSend">
|
||||
</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" [readOnly]="disableSend" 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>
|
||||
<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"
|
||||
[readOnly]="disableSend"
|
||||
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"
|
||||
[readOnly]="disableSend"
|
||||
/>
|
||||
</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"
|
||||
[readOnly]="disableSend"
|
||||
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>
|
||||
<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>
|
||||
</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 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 *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 +1,25 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { DatePipe } from "@angular/common";
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { ControlContainer, NgForm } from '@angular/forms';
|
||||
import { ControlContainer, NgForm } from "@angular/forms";
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
|
||||
import { EffluxDatesComponent as BaseEffluxDatesComponent } from 'jslib-angular/components/send/efflux-dates.component';
|
||||
import { EffluxDatesComponent as BaseEffluxDatesComponent } from "jslib-angular/components/send/efflux-dates.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-send-efflux-dates',
|
||||
templateUrl: 'efflux-dates.component.html',
|
||||
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
|
||||
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);
|
||||
}
|
||||
constructor(
|
||||
protected i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected datePipe: DatePipe
|
||||
) {
|
||||
super(i18nService, platformUtilsService, datePipe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,137 +1,188 @@
|
||||
<div class="container page-content">
|
||||
<app-callout type="warning" title="{{'sendDisabled' | i18n}}" *ngIf="disableSend">
|
||||
<span>{{'sendDisabledWarning' | i18n}}</span>
|
||||
</app-callout>
|
||||
<div class="row">
|
||||
<div class="col-3 groupings">
|
||||
<div class="card vault-filters">
|
||||
<div class="card-header d-flex">
|
||||
{{'filters' | i18n}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<input type="search" placeholder="{{searchPlaceholder || ('searchSends' | i18n)}}" id="search"
|
||||
class="form-control" [(ngModel)]="searchText" (input)="searchTextChanged()" autocomplete="off"
|
||||
appAutofocus>
|
||||
<ul class="fa-ul card-ul">
|
||||
<li [ngClass]="{active: selectedAll}">
|
||||
<a href="#" appStopClick (click)="selectAll()">
|
||||
<i class="fa-li fa fa-fw fa-th"></i>{{'allSends' | i18n}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{'types' | i18n}}</h3>
|
||||
<ul class="fa-ul card-ul">
|
||||
<li [ngClass]="{active: selectedType === sendType.Text}">
|
||||
<a href="#" appStopClick (click)="selectType(sendType.Text)">
|
||||
<i class="fa-li fa fa-fw fa-file-text-o"></i>{{'sendTypeText' | i18n}}
|
||||
</a>
|
||||
</li>
|
||||
<li [ngClass]="{active: selectedType === sendType.File}">
|
||||
<a href="#" appStopClick (click)="selectType(sendType.File)">
|
||||
<i class="fa-li fa fa-fw fa-file-o"></i>{{'sendTypeFile' | i18n}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
|
||||
<span>{{ "sendDisabledWarning" | i18n }}</span>
|
||||
</app-callout>
|
||||
<div class="row">
|
||||
<div class="col-3 groupings">
|
||||
<div class="card vault-filters">
|
||||
<div class="card-header d-flex">
|
||||
{{ "filters" | i18n }}
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="page-header d-flex">
|
||||
<h1>
|
||||
{{'send' | i18n}}
|
||||
<small #actionSpinner [appApiAction]="actionPromise">
|
||||
<ng-container *ngIf="actionSpinner.loading">
|
||||
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}"
|
||||
aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'loading' | i18n}}</span>
|
||||
</ng-container>
|
||||
</small>
|
||||
</h1>
|
||||
<div class="ml-auto d-flex">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" (click)="addSend()"
|
||||
[disabled]="disableSend">
|
||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>{{'createSend' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--Listing Table-->
|
||||
<table class="table table-hover table-list" *ngIf="filteredSends && filteredSends.length">
|
||||
<tbody>
|
||||
<tr *ngFor="let s of filteredSends">
|
||||
<td class="table-list-icon">
|
||||
<div class="icon" aria-hidden="true">
|
||||
<i class="fa fa-fw fa-lg fa-file-o" *ngIf="s.type == sendType.File"></i>
|
||||
<i class="fa fa-fw fa-lg fa-file-text-o" *ngIf="s.type == sendType.Text"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="reduced-lh wrap">
|
||||
<a href="#" appStopClick appStopProp (click)="editSend(s)">{{s.name}}</a>
|
||||
<ng-container *ngIf="s.disabled">
|
||||
<i class="fa fa-warning" appStopProp title="{{'disabled' | i18n}}"
|
||||
aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'disabled' | i18n}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.password">
|
||||
<i class="fa fa-key" appStopProp title="{{'password' | i18n}}" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'password' | i18n}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.maxAccessCountReached">
|
||||
<i class="fa fa-ban" appStopProp title="{{'maxAccessCountReached' | i18n}}"
|
||||
aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'maxAccessCountReached' | i18n}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.expired">
|
||||
<i class="fa fa-clock-o" appStopProp title="{{'expired' | i18n}}"
|
||||
aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'expired' | i18n}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.pendingDelete">
|
||||
<i class="fa fa-trash" appStopProp title="{{'pendingDeletion' | i18n}}"
|
||||
aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'pendingDeletion' | i18n}}</span>
|
||||
</ng-container>
|
||||
<br>
|
||||
<small appStopProp>{{s.deletionDate | date:'medium'}}</small>
|
||||
</td>
|
||||
<td class="table-list-options">
|
||||
<div class="dropdown" appListDropdown>
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button"
|
||||
id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="false" appA11yTitle="{{'options' | i18n}}">
|
||||
<i class="fa fa-cog fa-lg" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
|
||||
<a class="dropdown-item" href="#" appStopClick (click)="copy(s)">
|
||||
<i class="fa fa-fw fa-copy" aria-hidden="true"></i>
|
||||
{{'copySendLink' | i18n}}
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" appStopClick (click)="removePassword(s)"
|
||||
*ngIf="s.password && !disableSend">
|
||||
<i class="fa fa-fw fa-undo" aria-hidden="true"></i>
|
||||
{{'removePassword' | i18n}}
|
||||
</a>
|
||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="delete(s)">
|
||||
<i class="fa fa-fw fa-trash-o" aria-hidden="true"></i>
|
||||
{{'delete' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="no-items" *ngIf="filteredSends && !filteredSends.length">
|
||||
<ng-container *ngIf="!loaded">
|
||||
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{'loading' | i18n}}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="loaded">
|
||||
<p>{{'noSendsInList' | i18n}}</p>
|
||||
<button (click)="addSend()" class="btn btn-outline-primary" [disabled]="disableSend">
|
||||
<i class="fa fa-plus fa-fw"></i>{{'createSend' | i18n}}</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<input
|
||||
type="search"
|
||||
placeholder="{{ searchPlaceholder || ('searchSends' | i18n) }}"
|
||||
id="search"
|
||||
class="form-control"
|
||||
[(ngModel)]="searchText"
|
||||
(input)="searchTextChanged()"
|
||||
autocomplete="off"
|
||||
appAutofocus
|
||||
/>
|
||||
<ul class="fa-ul card-ul">
|
||||
<li [ngClass]="{ active: selectedAll }">
|
||||
<a href="#" appStopClick (click)="selectAll()">
|
||||
<i class="fa-li fa fa-fw fa-th"></i>{{ "allSends" | i18n }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ "types" | i18n }}</h3>
|
||||
<ul class="fa-ul card-ul">
|
||||
<li [ngClass]="{ active: selectedType === sendType.Text }">
|
||||
<a href="#" appStopClick (click)="selectType(sendType.Text)">
|
||||
<i class="fa-li fa fa-fw fa-file-text-o"></i>{{ "sendTypeText" | i18n }}
|
||||
</a>
|
||||
</li>
|
||||
<li [ngClass]="{ active: selectedType === sendType.File }">
|
||||
<a href="#" appStopClick (click)="selectType(sendType.File)">
|
||||
<i class="fa-li fa fa-fw fa-file-o"></i>{{ "sendTypeFile" | i18n }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="page-header d-flex">
|
||||
<h1>
|
||||
{{ "send" | i18n }}
|
||||
<small #actionSpinner [appApiAction]="actionPromise">
|
||||
<ng-container *ngIf="actionSpinner.loading">
|
||||
<i
|
||||
class="fa fa-spinner fa-spin text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
</ng-container>
|
||||
</small>
|
||||
</h1>
|
||||
<div class="ml-auto d-flex">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
(click)="addSend()"
|
||||
[disabled]="disableSend"
|
||||
>
|
||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>{{ "createSend" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--Listing Table-->
|
||||
<table class="table table-hover table-list" *ngIf="filteredSends && filteredSends.length">
|
||||
<tbody>
|
||||
<tr *ngFor="let s of filteredSends">
|
||||
<td class="table-list-icon">
|
||||
<div class="icon" aria-hidden="true">
|
||||
<i class="fa fa-fw fa-lg fa-file-o" *ngIf="s.type == sendType.File"></i>
|
||||
<i class="fa fa-fw fa-lg fa-file-text-o" *ngIf="s.type == sendType.Text"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="reduced-lh wrap">
|
||||
<a href="#" appStopClick appStopProp (click)="editSend(s)">{{ s.name }}</a>
|
||||
<ng-container *ngIf="s.disabled">
|
||||
<i
|
||||
class="fa fa-warning"
|
||||
appStopProp
|
||||
title="{{ 'disabled' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "disabled" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.password">
|
||||
<i
|
||||
class="fa fa-key"
|
||||
appStopProp
|
||||
title="{{ 'password' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "password" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.maxAccessCountReached">
|
||||
<i
|
||||
class="fa fa-ban"
|
||||
appStopProp
|
||||
title="{{ 'maxAccessCountReached' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "maxAccessCountReached" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.expired">
|
||||
<i
|
||||
class="fa fa-clock-o"
|
||||
appStopProp
|
||||
title="{{ 'expired' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "expired" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.pendingDelete">
|
||||
<i
|
||||
class="fa fa-trash"
|
||||
appStopProp
|
||||
title="{{ 'pendingDeletion' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "pendingDeletion" | i18n }}</span>
|
||||
</ng-container>
|
||||
<br />
|
||||
<small appStopProp>{{ s.deletionDate | date: "medium" }}</small>
|
||||
</td>
|
||||
<td class="table-list-options">
|
||||
<div class="dropdown" appListDropdown>
|
||||
<button
|
||||
class="btn btn-outline-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
appA11yTitle="{{ 'options' | i18n }}"
|
||||
>
|
||||
<i class="fa fa-cog fa-lg" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
|
||||
<a class="dropdown-item" href="#" appStopClick (click)="copy(s)">
|
||||
<i class="fa fa-fw fa-copy" aria-hidden="true"></i>
|
||||
{{ "copySendLink" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
appStopClick
|
||||
(click)="removePassword(s)"
|
||||
*ngIf="s.password && !disableSend"
|
||||
>
|
||||
<i class="fa fa-fw fa-undo" aria-hidden="true"></i>
|
||||
{{ "removePassword" | i18n }}
|
||||
</a>
|
||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="delete(s)">
|
||||
<i class="fa fa-fw fa-trash-o" aria-hidden="true"></i>
|
||||
{{ "delete" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="no-items" *ngIf="filteredSends && !filteredSends.length">
|
||||
<ng-container *ngIf="!loaded">
|
||||
<i
|
||||
class="fa fa-spinner fa-spin text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="loaded">
|
||||
<p>{{ "noSendsInList" | i18n }}</p>
|
||||
<button (click)="addSend()" class="btn btn-outline-primary" [disabled]="disableSend">
|
||||
<i class="fa fa-plus fa-fw"></i>{{ "createSend" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ng-template #sendAddEdit></ng-template>
|
||||
|
||||
@@ -1,89 +1,104 @@
|
||||
import {
|
||||
Component,
|
||||
NgZone,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
import { Component, NgZone, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
|
||||
import { SendView } from 'jslib-common/models/view/sendView';
|
||||
import { SendView } from "jslib-common/models/view/sendView";
|
||||
|
||||
import { SendComponent as BaseSendComponent } from 'jslib-angular/components/send/send.component';
|
||||
import { SendComponent as BaseSendComponent } from "jslib-angular/components/send/send.component";
|
||||
|
||||
import { AddEditComponent } from './add-edit.component';
|
||||
import { AddEditComponent } from "./add-edit.component";
|
||||
|
||||
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
|
||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
||||
import { SearchService } from 'jslib-common/abstractions/search.service';
|
||||
import { SendService } from 'jslib-common/abstractions/send.service';
|
||||
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||
import { SendService } from "jslib-common/abstractions/send.service";
|
||||
|
||||
import { ModalService } from 'jslib-angular/services/modal.service';
|
||||
import { ModalService } from "jslib-angular/services/modal.service";
|
||||
|
||||
const BroadcasterSubscriptionId = 'SendComponent';
|
||||
const BroadcasterSubscriptionId = "SendComponent";
|
||||
|
||||
@Component({
|
||||
selector: 'app-send',
|
||||
templateUrl: 'send.component.html',
|
||||
selector: "app-send",
|
||||
templateUrl: "send.component.html",
|
||||
})
|
||||
export class SendComponent extends BaseSendComponent {
|
||||
@ViewChild('sendAddEdit', { read: ViewContainerRef, static: true }) sendAddEditModalRef: ViewContainerRef;
|
||||
@ViewChild("sendAddEdit", { read: ViewContainerRef, static: true })
|
||||
sendAddEditModalRef: ViewContainerRef;
|
||||
|
||||
constructor(sendService: SendService, i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService,
|
||||
ngZone: NgZone, searchService: SearchService,
|
||||
policyService: PolicyService, private modalService: ModalService,
|
||||
private broadcasterService: BroadcasterService, logService: LogService) {
|
||||
super(sendService, i18nService, platformUtilsService, environmentService, ngZone, searchService,
|
||||
policyService, logService);
|
||||
}
|
||||
constructor(
|
||||
sendService: SendService,
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
environmentService: EnvironmentService,
|
||||
ngZone: NgZone,
|
||||
searchService: SearchService,
|
||||
policyService: PolicyService,
|
||||
private modalService: ModalService,
|
||||
private broadcasterService: BroadcasterService,
|
||||
logService: LogService
|
||||
) {
|
||||
super(
|
||||
sendService,
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
environmentService,
|
||||
ngZone,
|
||||
searchService,
|
||||
policyService,
|
||||
logService
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await super.ngOnInit();
|
||||
await this.load();
|
||||
async ngOnInit() {
|
||||
await super.ngOnInit();
|
||||
await this.load();
|
||||
|
||||
// Broadcaster subscription - load if sync completes in the background
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
this.ngZone.run(async () => {
|
||||
switch (message.command) {
|
||||
case 'syncCompleted':
|
||||
if (message.successfully) {
|
||||
await this.load();
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
||||
}
|
||||
|
||||
async addSend() {
|
||||
if (this.disableSend) {
|
||||
return;
|
||||
// Broadcaster subscription - load if sync completes in the background
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
this.ngZone.run(async () => {
|
||||
switch (message.command) {
|
||||
case "syncCompleted":
|
||||
if (message.successfully) {
|
||||
await this.load();
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const component = await this.editSend(null);
|
||||
component.type = this.type;
|
||||
ngOnDestroy() {
|
||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
||||
}
|
||||
|
||||
async addSend() {
|
||||
if (this.disableSend) {
|
||||
return;
|
||||
}
|
||||
|
||||
async editSend(send: SendView) {
|
||||
const [modal, childComponent] = await this.modalService.openViewRef(AddEditComponent, this.sendAddEditModalRef, comp => {
|
||||
comp.sendId = send == null ? null : send.id;
|
||||
comp.onSavedSend.subscribe(async (s: SendView) => {
|
||||
modal.close();
|
||||
await this.load();
|
||||
});
|
||||
comp.onDeletedSend.subscribe(async (s: SendView) => {
|
||||
modal.close();
|
||||
await this.load();
|
||||
});
|
||||
const component = await this.editSend(null);
|
||||
component.type = this.type;
|
||||
}
|
||||
|
||||
async editSend(send: SendView) {
|
||||
const [modal, childComponent] = await this.modalService.openViewRef(
|
||||
AddEditComponent,
|
||||
this.sendAddEditModalRef,
|
||||
(comp) => {
|
||||
comp.sendId = send == null ? null : send.id;
|
||||
comp.onSavedSend.subscribe(async (s: SendView) => {
|
||||
modal.close();
|
||||
await this.load();
|
||||
});
|
||||
comp.onDeletedSend.subscribe(async (s: SendView) => {
|
||||
modal.close();
|
||||
await this.load();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return childComponent;
|
||||
}
|
||||
return childComponent;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user