mirror of
https://github.com/bitwarden/browser.git
synced 2025-03-02 03:41:09 +01:00
[PM-7114] Remove legacy Send code from browser extension (#12342)
* Remove Send grouping, type and state * Delete Send list and add-edit --------- Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
parent
4b42092c93
commit
0619ef507f
1
.github/whitelist-capital-letters.txt
vendored
1
.github/whitelist-capital-letters.txt
vendored
@ -37,7 +37,6 @@
|
||||
./apps/browser/store/windows/AppxManifest.xml
|
||||
./apps/browser/src/background/nativeMessaging.background.ts
|
||||
./apps/browser/src/models/browserComponentState.ts
|
||||
./apps/browser/src/models/browserSendComponentState.ts
|
||||
./apps/browser/src/models/browserGroupingsComponentState.ts
|
||||
./apps/browser/src/models/biometricErrors.ts
|
||||
./apps/browser/src/browser/safariApp.ts
|
||||
|
@ -1150,9 +1150,6 @@
|
||||
"moveToOrganization": {
|
||||
"message": "Move to organization"
|
||||
},
|
||||
"share": {
|
||||
"message": "Share"
|
||||
},
|
||||
"movedItemToOrg": {
|
||||
"message": "$ITEMNAME$ moved to $ORGNAME$",
|
||||
"placeholders": {
|
||||
@ -2379,14 +2376,6 @@
|
||||
"message": "Send details",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"searchSends": {
|
||||
"message": "Search Sends",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"addSend": {
|
||||
"message": "Add Send",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"sendTypeText": {
|
||||
"message": "Text"
|
||||
},
|
||||
@ -2403,16 +2392,9 @@
|
||||
"hideTextByDefault": {
|
||||
"message": "Hide text by default"
|
||||
},
|
||||
"maxAccessCountReached": {
|
||||
"message": "Max access count reached",
|
||||
"description": "This text will be displayed after a Send has been accessed the maximum amount of times."
|
||||
},
|
||||
"expired": {
|
||||
"message": "Expired"
|
||||
},
|
||||
"pendingDeletion": {
|
||||
"message": "Pending deletion"
|
||||
},
|
||||
"passwordProtected": {
|
||||
"message": "Password protected"
|
||||
},
|
||||
@ -2462,24 +2444,9 @@
|
||||
"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."
|
||||
},
|
||||
"deletionDateDescV2": {
|
||||
"message": "The Send will be permanently deleted on this date.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
@ -2487,10 +2454,6 @@
|
||||
"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"
|
||||
},
|
||||
@ -2506,43 +2469,10 @@
|
||||
"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."
|
||||
},
|
||||
"sendPasswordDescV3": {
|
||||
"message": "Add an optional password for recipients 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": "Deactivate 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": "New Send",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
@ -2625,18 +2555,6 @@
|
||||
"sendFileCalloutHeader": {
|
||||
"message": "Before you start"
|
||||
},
|
||||
"sendFirefoxCustomDatePopoutMessage1": {
|
||||
"message": "To use a calendar style date picker",
|
||||
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read '**To use a calendar style date picker ** click here to pop out your window.'"
|
||||
},
|
||||
"sendFirefoxCustomDatePopoutMessage2": {
|
||||
"message": "click here",
|
||||
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker **click here** to pop out your window.'"
|
||||
},
|
||||
"sendFirefoxCustomDatePopoutMessage3": {
|
||||
"message": "to pop out your window.",
|
||||
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker click here **to pop out your window.**'"
|
||||
},
|
||||
"expirationDateIsInvalid": {
|
||||
"message": "The expiration date provided is not valid."
|
||||
},
|
||||
@ -2652,15 +2570,9 @@
|
||||
"dateParsingError": {
|
||||
"message": "There was an error saving your deletion and expiration dates."
|
||||
},
|
||||
"hideEmail": {
|
||||
"message": "Hide my email address from recipients."
|
||||
},
|
||||
"hideYourEmail": {
|
||||
"message": "Hide your email address from viewers."
|
||||
},
|
||||
"sendOptionsPolicyInEffect": {
|
||||
"message": "One or more organization policies are affecting your Send options."
|
||||
},
|
||||
"passwordPrompt": {
|
||||
"message": "Master password re-prompt"
|
||||
},
|
||||
|
@ -1,20 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify";
|
||||
|
||||
import { BrowserComponentState } from "./browserComponentState";
|
||||
|
||||
export class BrowserSendComponentState extends BrowserComponentState {
|
||||
sends: SendView[];
|
||||
|
||||
static fromJSON(json: DeepJsonify<BrowserSendComponentState>) {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.assign(new BrowserSendComponentState(), json, {
|
||||
sends: json.sends?.map((s) => SendView.fromJSON(s)),
|
||||
});
|
||||
}
|
||||
}
|
@ -86,9 +86,6 @@ import BrowserPopupUtils from "../platform/popup/browser-popup-utils";
|
||||
import { popupRouterCacheGuard } from "../platform/popup/view-cache/popup-router-cache.service";
|
||||
import { CredentialGeneratorHistoryComponent } from "../tools/popup/generator/credential-generator-history.component";
|
||||
import { CredentialGeneratorComponent } from "../tools/popup/generator/credential-generator.component";
|
||||
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
||||
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
||||
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
||||
import { SendAddEditComponent as SendAddEditV2Component } from "../tools/popup/send-v2/add-edit/send-add-edit.component";
|
||||
import { SendCreatedComponent } from "../tools/popup/send-v2/send-created/send-created.component";
|
||||
import { SendV2Component } from "../tools/popup/send-v2/send-v2.component";
|
||||
@ -415,21 +412,17 @@ const routes: Routes = [
|
||||
data: { elevation: 1 } satisfies RouteDataProperties,
|
||||
}),
|
||||
{
|
||||
path: "send-type",
|
||||
component: SendTypeComponent,
|
||||
path: "add-send",
|
||||
component: SendAddEditV2Component,
|
||||
canActivate: [authGuard],
|
||||
data: { elevation: 1 } satisfies RouteDataProperties,
|
||||
},
|
||||
...extensionRefreshSwap(SendAddEditComponent, SendAddEditV2Component, {
|
||||
path: "add-send",
|
||||
canActivate: [authGuard],
|
||||
data: { elevation: 1 } satisfies RouteDataProperties,
|
||||
}),
|
||||
...extensionRefreshSwap(SendAddEditComponent, SendAddEditV2Component, {
|
||||
{
|
||||
path: "edit-send",
|
||||
component: SendAddEditV2Component,
|
||||
canActivate: [authGuard],
|
||||
data: { elevation: 1 } satisfies RouteDataProperties,
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "send-created",
|
||||
component: SendCreatedComponent,
|
||||
@ -768,11 +761,12 @@ const routes: Routes = [
|
||||
canActivate: [authGuard],
|
||||
data: { elevation: 0 } satisfies RouteDataProperties,
|
||||
},
|
||||
...extensionRefreshSwap(SendGroupingsComponent, SendV2Component, {
|
||||
{
|
||||
path: "send",
|
||||
component: SendV2Component,
|
||||
canActivate: [authGuard],
|
||||
data: { elevation: 0 } satisfies RouteDataProperties,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -26,7 +26,6 @@ import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-
|
||||
import { PopupWidthService } from "../platform/popup/layout/popup-width.service";
|
||||
import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service";
|
||||
import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service";
|
||||
import { BrowserSendStateService } from "../tools/popup/services/browser-send-state.service";
|
||||
import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service";
|
||||
|
||||
import { routerTransition } from "./app-routing.animations";
|
||||
@ -57,7 +56,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
private i18nService: I18nService,
|
||||
private router: Router,
|
||||
private stateService: StateService,
|
||||
private browserSendStateService: BrowserSendStateService,
|
||||
private vaultBrowserStateService: VaultBrowserStateService,
|
||||
private cipherService: CipherService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
@ -243,8 +241,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
await Promise.all([
|
||||
this.vaultBrowserStateService.setBrowserGroupingsComponentState(null),
|
||||
this.vaultBrowserStateService.setBrowserVaultItemsComponentState(null),
|
||||
this.browserSendStateService.setBrowserSendComponentState(null),
|
||||
this.browserSendStateService.setBrowserSendTypeComponentState(null),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -56,10 +56,6 @@ import { PopupHeaderComponent } from "../platform/popup/layout/popup-header.comp
|
||||
import { PopupPageComponent } from "../platform/popup/layout/popup-page.component";
|
||||
import { PopupTabNavigationComponent } from "../platform/popup/layout/popup-tab-navigation.component";
|
||||
import { FilePopoutCalloutComponent } from "../tools/popup/components/file-popout-callout.component";
|
||||
import { SendListComponent } from "../tools/popup/send/components/send-list.component";
|
||||
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
||||
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
||||
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
||||
import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component";
|
||||
import { CipherRowComponent } from "../vault/popup/components/cipher-row.component";
|
||||
import { AddEditCustomFieldsComponent } from "../vault/popup/components/vault/add-edit-custom-fields.component";
|
||||
@ -161,10 +157,6 @@ import "../platform/popup/locales";
|
||||
PasswordHistoryComponent,
|
||||
PremiumComponent,
|
||||
RegisterComponent,
|
||||
SendAddEditComponent,
|
||||
SendGroupingsComponent,
|
||||
SendListComponent,
|
||||
SendTypeComponent,
|
||||
SetPasswordComponent,
|
||||
VaultSettingsComponent,
|
||||
ShareComponent,
|
||||
|
@ -152,7 +152,6 @@ import { ForegroundSyncService } from "../../platform/sync/foreground-sync.servi
|
||||
import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging";
|
||||
import { ExtensionLockComponentService } from "../../services/extension-lock-component.service";
|
||||
import { ForegroundVaultTimeoutService } from "../../services/vault-timeout/foreground-vault-timeout.service";
|
||||
import { BrowserSendStateService } from "../../tools/popup/services/browser-send-state.service";
|
||||
import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service";
|
||||
import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service";
|
||||
import { VaultBrowserStateService } from "../../vault/services/vault-browser-state.service";
|
||||
@ -473,11 +472,6 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: UserNotificationSettingsService,
|
||||
deps: [StateProvider],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: BrowserSendStateService,
|
||||
useClass: BrowserSendStateService,
|
||||
deps: [StateProvider],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: MessageListener,
|
||||
useFactory: (subject: Subject<Message<Record<string, unknown>>>, ngZone: NgZone) =>
|
||||
|
@ -1,98 +0,0 @@
|
||||
<div
|
||||
role="group"
|
||||
*ngFor="let s of sends"
|
||||
appA11yTitle="{{ s.name }}"
|
||||
class="box-content-row box-content-row-flex"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="row-main"
|
||||
(click)="selectSend(s)"
|
||||
appStopClick
|
||||
title="{{ title }} - {{ s.name }}"
|
||||
>
|
||||
<div class="app-vault-icon">
|
||||
<div class="icon" aria-hidden="true">
|
||||
<i class="bwi bwi-fw bwi-lg bwi-file-text" *ngIf="s.type === sendType.Text"></i>
|
||||
<i class="bwi bwi-fw bwi-lg bwi-file" *ngIf="s.type === sendType.File"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-main-content">
|
||||
<span class="text">
|
||||
{{ s.name }}
|
||||
<ng-container *ngIf="s.disabled">
|
||||
<i
|
||||
class="bwi bwi-exclamation-triangle text-muted"
|
||||
title="{{ 'disabled' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "disabled" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.password">
|
||||
<i
|
||||
class="bwi bwi-key text-muted"
|
||||
title="{{ 'passwordProtected' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "passwordProtected" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.maxAccessCountReached">
|
||||
<i
|
||||
class="bwi bwi-ban text-muted"
|
||||
title="{{ 'maxAccessCountReached' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "maxAccessCountReached" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.expired">
|
||||
<i class="bwi bwi-clock text-muted" title="{{ 'expired' | i18n }}" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{ "expired" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="s.pendingDelete">
|
||||
<i
|
||||
class="bwi bwi-trash text-muted"
|
||||
title="{{ 'pendingDeletion' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "pendingDeletion" | i18n }}</span>
|
||||
</ng-container>
|
||||
</span>
|
||||
<span class="detail">{{ s.deletionDate | date: "medium" }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<div class="action-buttons">
|
||||
<button
|
||||
type="button"
|
||||
class="row-btn"
|
||||
appStopClick
|
||||
appStopProp
|
||||
appA11yTitle="{{ 'copySendLink' | i18n }}"
|
||||
(click)="copySendLink(s)"
|
||||
>
|
||||
<i class="bwi bwi-lg bwi-files" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="row-btn"
|
||||
[ngClass]="{ disabled: disabledByPolicy }"
|
||||
[attr.disabled]="disabledByPolicy ? '' : null"
|
||||
appStopClick
|
||||
appStopProp
|
||||
appA11yTitle="{{ 'removePassword' | i18n }}"
|
||||
(click)="removePassword(s)"
|
||||
*ngIf="s.password"
|
||||
>
|
||||
<i class="bwi bwi-lg bwi-undo" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="row-btn"
|
||||
appStopClick
|
||||
appStopProp
|
||||
appA11yTitle="{{ 'delete' | i18n }}"
|
||||
(click)="delete(s)"
|
||||
>
|
||||
<i class="bwi bwi-lg bwi-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
@ -1,38 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
|
||||
@Component({
|
||||
selector: "app-send-list",
|
||||
templateUrl: "send-list.component.html",
|
||||
})
|
||||
export class SendListComponent {
|
||||
@Input() sends: SendView[];
|
||||
@Input() title: string;
|
||||
@Input() disabledByPolicy = false;
|
||||
@Output() onSelected = new EventEmitter<SendView>();
|
||||
@Output() onCopySendLink = new EventEmitter<SendView>();
|
||||
@Output() onRemovePassword = new EventEmitter<SendView>();
|
||||
@Output() onDeleteSend = new EventEmitter<SendView>();
|
||||
|
||||
sendType = SendType;
|
||||
|
||||
selectSend(s: SendView) {
|
||||
this.onSelected.emit(s);
|
||||
}
|
||||
|
||||
copySendLink(s: SendView) {
|
||||
this.onCopySendLink.emit(s);
|
||||
}
|
||||
|
||||
removePassword(s: SendView) {
|
||||
this.onRemovePassword.emit(s);
|
||||
}
|
||||
|
||||
delete(s: SendView) {
|
||||
this.onDeleteSend.emit(s);
|
||||
}
|
||||
}
|
@ -1,411 +0,0 @@
|
||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" [formGroup]="formGroup">
|
||||
<header>
|
||||
<div class="left">
|
||||
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
|
||||
</div>
|
||||
<h1 class="center">
|
||||
<span class="title">{{ title }}</span>
|
||||
</h1>
|
||||
<div class="right">
|
||||
<button type="submit">
|
||||
<span [hidden]="form.loading">{{ "save" | i18n }}</span>
|
||||
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main tabindex="-1" *ngIf="send">
|
||||
<!-- Policy Banner -->
|
||||
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
|
||||
{{ "sendDisabledWarning" | i18n }}
|
||||
</app-callout>
|
||||
<app-callout type="info" *ngIf="disableHideEmail && !disableSend">
|
||||
{{ "sendOptionsPolicyInEffect" | i18n }}
|
||||
</app-callout>
|
||||
<!-- File Warning -->
|
||||
<tools-file-popout-callout *ngIf="type === sendType.File && !disableSend" />
|
||||
<!-- 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"
|
||||
formControlName="name"
|
||||
aria-describedby="nameHelp"
|
||||
[readonly]="disableSend"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nameHelp" 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"
|
||||
formControlName="type"
|
||||
id="type_{{ o.value }}"
|
||||
[value]="o.value"
|
||||
[readonly]="disableSend"
|
||||
/>
|
||||
<label for="type_{{ o.value }}">
|
||||
{{ o.name }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- File -->
|
||||
<div class="box" *ngIf="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"
|
||||
formControlName="file"
|
||||
aria-describedby="fileHelp"
|
||||
[readonly]="disableSend"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="fileHelp" class="box-footer" *ngIf="showFileSelector">
|
||||
{{ "sendFileDesc" | i18n }} {{ "maxFileSize" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Text -->
|
||||
<div class="box" *ngIf="type === sendType.Text">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="text">{{ "sendTypeText" | i18n }}</label>
|
||||
<textarea
|
||||
id="text"
|
||||
formControlName="text"
|
||||
aria-describedby="textHelp"
|
||||
rows="6"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="textHelp" 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" formControlName="textHidden" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Share -->
|
||||
<div class="box">
|
||||
<h2 class="box-header">
|
||||
{{ "share" | i18n }}
|
||||
</h2>
|
||||
<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" formControlName="copyLink" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Options -->
|
||||
<div class="box">
|
||||
<h2>
|
||||
<button
|
||||
type="button"
|
||||
class="box-header-expandable"
|
||||
(click)="showOptions = !showOptions"
|
||||
[attr.aria-expanded]="showOptions"
|
||||
>
|
||||
<i *ngIf="!showOptions" class="bwi bwi-angle-right bwi-sm icon" aria-hidden="true"></i>
|
||||
<i *ngIf="showOptions" class="bwi bwi-angle-down bwi-sm icon" aria-hidden="true"></i>
|
||||
{{ "options" | i18n }}
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div [hidden]="!showOptions">
|
||||
<!-- Deletion Date -->
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<ng-container *ngIf="!editMode">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
||||
<select
|
||||
id="deletionDate"
|
||||
name="DeletionDateSelect"
|
||||
aria-describedby="deletionDateHelp"
|
||||
formControlName="selectedDeletionDatePreset"
|
||||
required
|
||||
>
|
||||
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
class="box-content-row"
|
||||
appBoxRow
|
||||
*ngIf="formGroup.controls['selectedDeletionDatePreset'].value === 0"
|
||||
>
|
||||
<input
|
||||
id="deletionDateCustom"
|
||||
type="datetime-local"
|
||||
name="DeletionDate"
|
||||
aria-describedby="deletionDateHelp"
|
||||
formControlName="defaultDeletionDateTime"
|
||||
required
|
||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||
/>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
||||
<label for="deletionDate">{{ "deletionDate" | i18n }}</label>
|
||||
<input
|
||||
id="deletionDateCustom"
|
||||
type="datetime-local"
|
||||
name="DeletionDate"
|
||||
aria-describedby="deletionDateHelp"
|
||||
formControlName="defaultDeletionDateTime"
|
||||
required
|
||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="deletionDateHelp" class="box-footer">
|
||||
{{ "deletionDateDesc" | i18n }}
|
||||
<ng-container
|
||||
*ngIf="
|
||||
!inPopout &&
|
||||
isFirefox &&
|
||||
(editMode ||
|
||||
(formGroup.controls['selectedDeletionDatePreset'].value === 0 && !editMode))
|
||||
"
|
||||
>
|
||||
<br />{{ "sendFirefoxCustomDatePopoutMessage1" | i18n }}
|
||||
<a (click)="popOutWindow()">{{ "sendFirefoxCustomDatePopoutMessage2" | i18n }}</a>
|
||||
{{ "sendFirefoxCustomDatePopoutMessage3" | i18n }}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Expiration Date -->
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<ng-container *ngIf="!editMode">
|
||||
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
||||
<label for="editExpirationDate">{{ "expirationDate" | i18n }}</label>
|
||||
<select
|
||||
id="expirationDate"
|
||||
name="ExpirationDateSelect"
|
||||
aria-describedby="expirationDateHelp"
|
||||
formControlName="selectedExpirationDatePreset"
|
||||
required
|
||||
>
|
||||
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
class="box-content-row"
|
||||
*ngIf="formGroup.controls['selectedExpirationDatePreset'].value === 0"
|
||||
appBoxRow
|
||||
>
|
||||
<input
|
||||
id="expirationDateCustom"
|
||||
type="datetime-local"
|
||||
name="ExpirationDate"
|
||||
aria-describedby="expirationDateHelp"
|
||||
formControlName="defaultExpirationDateTime"
|
||||
required
|
||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||
[readOnly]="disableSend"
|
||||
/>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="box-content-row" *ngIf="editMode" appBoxRow>
|
||||
<div class="flex-label">
|
||||
<label>{{ "expirationDate" | i18n }}</label>
|
||||
<button type="button" *ngIf="!disableSend" appStopClick (click)="clearExpiration()">
|
||||
{{ "clear" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
id="expirationDateCustom"
|
||||
type="datetime-local"
|
||||
name="ExpirationDate"
|
||||
aria-describedby="expirationDateHelp"
|
||||
formControlName="defaultExpirationDateTime"
|
||||
required
|
||||
placeholder="MM/DD/YYYY HH:MM AM/PM"
|
||||
[readOnly]="disableSend"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="expirationDateHelp" class="box-footer">
|
||||
{{ "expirationDateDesc" | i18n }}
|
||||
<ng-container
|
||||
*ngIf="
|
||||
!inPopout &&
|
||||
isFirefox &&
|
||||
(editMode ||
|
||||
(formGroup.controls['selectedExpirationDatePreset'].value === 0 && !editMode))
|
||||
"
|
||||
>
|
||||
<br />{{ "sendFirefoxCustomDatePopoutMessage1" | i18n }}
|
||||
<a (click)="popOutWindow()">{{ "sendFirefoxCustomDatePopoutMessage2" | i18n }}</a>
|
||||
{{ "sendFirefoxCustomDatePopoutMessage3" | i18n }}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Maximum Access Count -->
|
||||
<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"
|
||||
aria-describedby="maximumAccessCountHelp"
|
||||
formControlName="maxAccessCount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="maximumAccessCountHelp" 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"
|
||||
type="text"
|
||||
name="CurrentAccessCount"
|
||||
formControlName="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"
|
||||
aria-describedby="passwordHelp"
|
||||
class="monospaced"
|
||||
formControlName="password"
|
||||
appInputVerbatim
|
||||
/>
|
||||
</div>
|
||||
<div class="action-buttons" *ngIf="!disableSend">
|
||||
<button
|
||||
type="button"
|
||||
class="row-btn"
|
||||
appStopClick
|
||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||
(click)="togglePasswordVisible()"
|
||||
[attr.aria-pressed]="showPassword"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-lg"
|
||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="passwordHelp" 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"
|
||||
aria-describedby="notesHelp"
|
||||
rows="6"
|
||||
formControlName="notes"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="notesHelp" class="box-footer">
|
||||
{{ "sendNotesDesc" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Hide Email -->
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="hideEmail">{{ "hideEmail" | i18n }}</label>
|
||||
<input id="hideEmail" type="checkbox" name="HideEmail" formControlName="hideEmail" />
|
||||
</div>
|
||||
</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" formControlName="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Delete -->
|
||||
<div class="box list" *ngIf="editMode">
|
||||
<div class="box-content single-line">
|
||||
<button
|
||||
type="button"
|
||||
class="box-content-row"
|
||||
appStopClick
|
||||
(click)="delete()"
|
||||
[appApiAction]="deletePromise"
|
||||
#deleteBtn
|
||||
>
|
||||
<div class="row-main text-danger">
|
||||
<div class="icon text-danger" aria-hidden="true">
|
||||
<i class="bwi bwi-trash bwi-lg bwi-fw" [hidden]="$any(deleteBtn).loading"></i>
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||
[hidden]="!$any(deleteBtn).loading"
|
||||
></i>
|
||||
</div>
|
||||
<span>{{ "deleteSend" | i18n }}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</form>
|
@ -1,140 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { DatePipe, Location } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
|
||||
import { FilePopoutUtilsService } from "../services/file-popout-utils.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-send-add-edit",
|
||||
templateUrl: "send-add-edit.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class SendAddEditComponent extends BaseAddEditComponent implements OnInit {
|
||||
// Options header
|
||||
showOptions = false;
|
||||
// File visibility
|
||||
isFirefox = false;
|
||||
inPopout = false;
|
||||
showFileSelector = false;
|
||||
|
||||
constructor(
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
stateService: StateService,
|
||||
messagingService: MessagingService,
|
||||
policyService: PolicyService,
|
||||
environmentService: EnvironmentService,
|
||||
datePipe: DatePipe,
|
||||
sendService: SendService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private location: Location,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogService,
|
||||
formBuilder: FormBuilder,
|
||||
private filePopoutUtilsService: FilePopoutUtilsService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
accountService: AccountService,
|
||||
toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
environmentService,
|
||||
datePipe,
|
||||
sendService,
|
||||
messagingService,
|
||||
policyService,
|
||||
logService,
|
||||
stateService,
|
||||
sendApiService,
|
||||
dialogService,
|
||||
formBuilder,
|
||||
billingAccountProfileStateService,
|
||||
accountService,
|
||||
toastService,
|
||||
);
|
||||
}
|
||||
|
||||
popOutWindow() {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserPopupUtils.openCurrentPagePopout(window);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
// File visibility
|
||||
this.showFileSelector =
|
||||
!this.editMode && !this.filePopoutUtilsService.showFilePopoutMessage(window);
|
||||
this.inPopout = BrowserPopupUtils.inPopout(window);
|
||||
this.isFirefox = this.platformUtilsService.isFirefox();
|
||||
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
||||
if (params.sendId) {
|
||||
this.sendId = params.sendId;
|
||||
}
|
||||
if (params.type) {
|
||||
const type = parseInt(params.type, null);
|
||||
this.type = type;
|
||||
}
|
||||
await super.ngOnInit();
|
||||
});
|
||||
|
||||
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
|
||||
const isPopup = (window as any)?.previousPopupUrl?.startsWith("/add-send") ?? false;
|
||||
if (!isPopup) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["tabs/send"]);
|
||||
} else {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
<app-header>
|
||||
<div class="left" *ngIf="showLeftHeader">
|
||||
<app-pop-out></app-pop-out>
|
||||
</div>
|
||||
<h1 class="sr-only">{{ "send" | i18n }}</h1>
|
||||
<div class="search center">
|
||||
<input
|
||||
type="search"
|
||||
placeholder="{{ 'searchSends' | i18n }}"
|
||||
id="search"
|
||||
[(ngModel)]="searchText"
|
||||
(input)="search(200)"
|
||||
autocomplete="off"
|
||||
appAutofocus
|
||||
/>
|
||||
<i class="bwi bwi-search"></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button
|
||||
type="button"
|
||||
(click)="addSend()"
|
||||
appA11yTitle="{{ 'addSend' | i18n }}"
|
||||
[disabled]="disableSend"
|
||||
>
|
||||
<i class="bwi bwi-plus bwi-lg bwi-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</app-header>
|
||||
<main tabindex="-1" [ngClass]="{ flex: disableSend, 'tab-page': disableSend }">
|
||||
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
|
||||
{{ "sendDisabledWarning" | i18n }}
|
||||
</app-callout>
|
||||
<div class="no-items" *ngIf="(!sends || !sends.length) && !showSearching() && !disableSend">
|
||||
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded"></i>
|
||||
<ng-container *ngIf="loaded">
|
||||
<img class="no-items-image" aria-hidden="true" />
|
||||
<p>{{ "noItemsInList" | i18n }}</p>
|
||||
<button
|
||||
type="button"
|
||||
(click)="addSend()"
|
||||
class="btn block primary link"
|
||||
[disabled]="disableSend"
|
||||
>
|
||||
{{ "addSend" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ng-container *ngIf="sends && sends.length && !showSearching()">
|
||||
<div class="box list">
|
||||
<h2 class="box-header">
|
||||
{{ "types" | i18n }}
|
||||
</h2>
|
||||
<div class="box-content single-line">
|
||||
<button
|
||||
type="button"
|
||||
class="box-content-row"
|
||||
appStopClick
|
||||
(click)="selectType(sendType.Text)"
|
||||
>
|
||||
<div class="row-main">
|
||||
<div class="icon"><i class="bwi bwi-fw bwi-lg bwi-file-text"></i></div>
|
||||
<span class="text">{{ "sendTypeText" | i18n }}</span>
|
||||
</div>
|
||||
<span class="row-sub-label">{{ getSendCount(sends, sendType.Text) }}</span>
|
||||
<span><i class="bwi bwi-angle-right bwi-lg row-sub-icon"></i></span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="box-content-row"
|
||||
appStopClick
|
||||
(click)="selectType(sendType.File)"
|
||||
>
|
||||
<div class="row-main">
|
||||
<div class="icon"><i class="bwi bwi-fw bwi-lg bwi-file"></i></div>
|
||||
<span class="text">{{ "sendTypeFile" | i18n }}</span>
|
||||
</div>
|
||||
<span class="row-sub-label">{{ getSendCount(sends, sendType.File) }}</span>
|
||||
<span><i class="bwi bwi-angle-right bwi-lg row-sub-icon"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box list">
|
||||
<h2 class="box-header">
|
||||
{{ "allSends" | i18n }}
|
||||
<div class="flex-right">{{ sends.length }}</div>
|
||||
</h2>
|
||||
<div class="box-content">
|
||||
<app-send-list
|
||||
[sends]="sends"
|
||||
title="{{ 'editItem' | i18n }}"
|
||||
[disabledByPolicy]="disableSend"
|
||||
(onSelected)="selectSend($event)"
|
||||
(onCopySendLink)="copy($event)"
|
||||
(onRemovePassword)="removePassword($event)"
|
||||
(onDeleteSend)="delete($event)"
|
||||
></app-send-list>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="showSearching()">
|
||||
<div class="no-items" *ngIf="!filteredSends || !filteredSends.length">
|
||||
<p>{{ "noItemsInList" | i18n }}</p>
|
||||
</div>
|
||||
<div class="box list full-list" *ngIf="filteredSends && filteredSends.length > 0">
|
||||
<div class="box-content">
|
||||
<app-send-list
|
||||
[sends]="filteredSends"
|
||||
title="{{ 'editItem' | i18n }}"
|
||||
[disabledByPolicy]="disableSend"
|
||||
(onSelected)="selectSend($event)"
|
||||
(onCopySendLink)="copy($event)"
|
||||
(onRemovePassword)="removePassword($event)"
|
||||
(onDeleteSend)="delete($event)"
|
||||
>
|
||||
</app-send-list>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</main>
|
@ -1,203 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
||||
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
|
||||
import { BrowserSendStateService } from "../services/browser-send-state.service";
|
||||
|
||||
const ComponentId = "SendComponent";
|
||||
|
||||
@Component({
|
||||
selector: "app-send-groupings",
|
||||
templateUrl: "send-groupings.component.html",
|
||||
})
|
||||
export class SendGroupingsComponent extends BaseSendComponent implements OnInit, OnDestroy {
|
||||
// Header
|
||||
showLeftHeader = true;
|
||||
// State Handling
|
||||
state: BrowserSendComponentState;
|
||||
private loadedTimeout: number;
|
||||
|
||||
constructor(
|
||||
sendService: SendService,
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
environmentService: EnvironmentService,
|
||||
ngZone: NgZone,
|
||||
policyService: PolicyService,
|
||||
searchService: SearchService,
|
||||
private stateService: BrowserSendStateService,
|
||||
private router: Router,
|
||||
private syncService: SyncService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private broadcasterService: BroadcasterService,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogService,
|
||||
toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
sendService,
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
environmentService,
|
||||
ngZone,
|
||||
searchService,
|
||||
policyService,
|
||||
logService,
|
||||
sendApiService,
|
||||
dialogService,
|
||||
toastService,
|
||||
);
|
||||
this.onSuccessfulLoad = async () => {
|
||||
this.selectAll();
|
||||
};
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
// Determine Header details
|
||||
this.showLeftHeader = !(
|
||||
BrowserPopupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
|
||||
);
|
||||
// Clear state of Send Type Component
|
||||
await this.stateService.setBrowserSendTypeComponentState(null);
|
||||
// Let super class finish
|
||||
await super.ngOnInit();
|
||||
// Handle State Restore if necessary
|
||||
const restoredScopeState = await this.restoreState();
|
||||
if (this.state?.searchText != null) {
|
||||
this.searchText = this.state.searchText;
|
||||
}
|
||||
|
||||
if (!this.syncService.syncInProgress) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.load();
|
||||
} else {
|
||||
this.loadedTimeout = window.setTimeout(() => {
|
||||
if (!this.loaded) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.load();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
if (!this.syncService.syncInProgress || restoredScopeState) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserPopupUtils.setContentScrollY(window, this.state?.scrollY);
|
||||
}
|
||||
|
||||
// Load all sends if sync completed in background
|
||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.ngZone.run(async () => {
|
||||
switch (message.command) {
|
||||
case "syncCompleted":
|
||||
window.setTimeout(() => {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.load();
|
||||
}, 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// Remove timeout
|
||||
if (this.loadedTimeout != null) {
|
||||
window.clearTimeout(this.loadedTimeout);
|
||||
}
|
||||
// Save state
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.saveState();
|
||||
// Unsubscribe
|
||||
this.broadcasterService.unsubscribe(ComponentId);
|
||||
}
|
||||
|
||||
async selectType(type: SendType) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/send-type"], { queryParams: { type: type } });
|
||||
}
|
||||
|
||||
async selectSend(s: SendView) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/edit-send"], { queryParams: { sendId: s.id } });
|
||||
}
|
||||
|
||||
async addSend() {
|
||||
if (this.disableSend) {
|
||||
return;
|
||||
}
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/add-send"]);
|
||||
}
|
||||
|
||||
async removePassword(s: SendView): Promise<boolean> {
|
||||
if (this.disableSend) {
|
||||
return;
|
||||
}
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
super.removePassword(s);
|
||||
}
|
||||
|
||||
showSearching() {
|
||||
return this.hasSearched || (!this.searchPending && this.isSearchable);
|
||||
}
|
||||
|
||||
getSendCount(sends: SendView[], type: SendType): number {
|
||||
return sends.filter((s) => s.type === type).length;
|
||||
}
|
||||
|
||||
private async saveState() {
|
||||
this.state = Object.assign(new BrowserSendComponentState(), {
|
||||
scrollY: BrowserPopupUtils.getContentScrollY(window),
|
||||
searchText: this.searchText,
|
||||
sends: this.sends,
|
||||
});
|
||||
await this.stateService.setBrowserSendComponentState(this.state);
|
||||
}
|
||||
|
||||
private async restoreState(): Promise<boolean> {
|
||||
this.state = await this.stateService.getBrowserSendComponentState();
|
||||
if (this.state == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.state.sends != null) {
|
||||
this.sends = this.state.sends;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<header>
|
||||
<div class="left">
|
||||
<button type="button" (click)="back()">
|
||||
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
||||
<span>{{ "back" | i18n }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<h1 class="sr-only">{{ "send" | i18n }}</h1>
|
||||
<div class="search">
|
||||
<input
|
||||
type="search"
|
||||
placeholder="{{ 'searchType' | i18n }}"
|
||||
id="search"
|
||||
[(ngModel)]="searchText"
|
||||
(input)="search(200)"
|
||||
autocomplete="off"
|
||||
appAutofocus
|
||||
/>
|
||||
<i class="bwi bwi-search"></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button
|
||||
type="button"
|
||||
(click)="addSend()"
|
||||
appA11yTitle="{{ 'addSend' | i18n }}"
|
||||
[disabled]="disableSend"
|
||||
>
|
||||
<i class="bwi bwi-plus bwi-lg bwi-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main tabindex="-1" [ngClass]="{ flex: disableSend }">
|
||||
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
|
||||
{{ "sendDisabledWarning" | i18n }}
|
||||
</app-callout>
|
||||
<div class="no-items" *ngIf="!filteredSends.length">
|
||||
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i>
|
||||
<ng-container *ngIf="loaded">
|
||||
<p>{{ "noItemsInList" | i18n }}</p>
|
||||
<button
|
||||
type="button"
|
||||
(click)="addSend()"
|
||||
class="btn block primary link"
|
||||
[disabled]="disableSend"
|
||||
>
|
||||
{{ "addSend" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="box list only-list" *ngIf="filteredSends.length">
|
||||
<h2 class="box-header">
|
||||
{{ groupingTitle }}
|
||||
<span class="flex-right">{{ filteredSends.length }}</span>
|
||||
</h2>
|
||||
<div class="box-content">
|
||||
<app-send-list
|
||||
[sends]="filteredSends"
|
||||
title="{{ 'editItem' | i18n }}"
|
||||
[disabledByPolicy]="disableSend"
|
||||
(onSelected)="selectSend($event)"
|
||||
(onCopySendLink)="copy($event)"
|
||||
(onRemovePassword)="removePassword($event)"
|
||||
(onDeleteSend)="delete($event)"
|
||||
>
|
||||
</app-send-list>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
@ -1,190 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Location } from "@angular/common";
|
||||
import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { BrowserComponentState } from "../../../models/browserComponentState";
|
||||
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
|
||||
import { BrowserSendStateService } from "../services/browser-send-state.service";
|
||||
|
||||
const ComponentId = "SendTypeComponent";
|
||||
|
||||
@Component({
|
||||
selector: "app-send-type",
|
||||
templateUrl: "send-type.component.html",
|
||||
})
|
||||
export class SendTypeComponent extends BaseSendComponent implements OnInit, OnDestroy {
|
||||
groupingTitle: string;
|
||||
// State Handling
|
||||
state: BrowserComponentState;
|
||||
private refreshTimeout: number;
|
||||
private applySavedState = true;
|
||||
|
||||
constructor(
|
||||
sendService: SendService,
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
environmentService: EnvironmentService,
|
||||
ngZone: NgZone,
|
||||
policyService: PolicyService,
|
||||
searchService: SearchService,
|
||||
private stateService: BrowserSendStateService,
|
||||
private route: ActivatedRoute,
|
||||
private location: Location,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private broadcasterService: BroadcasterService,
|
||||
private router: Router,
|
||||
logService: LogService,
|
||||
sendApiService: SendApiService,
|
||||
dialogService: DialogService,
|
||||
toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
sendService,
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
environmentService,
|
||||
ngZone,
|
||||
searchService,
|
||||
policyService,
|
||||
logService,
|
||||
sendApiService,
|
||||
dialogService,
|
||||
toastService,
|
||||
);
|
||||
this.onSuccessfulLoad = async () => {
|
||||
this.selectType(this.type);
|
||||
};
|
||||
this.applySavedState =
|
||||
(window as any).previousPopupUrl != null &&
|
||||
!(window as any).previousPopupUrl.startsWith("/send-type");
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
// Let super class finish
|
||||
await super.ngOnInit();
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
||||
if (this.applySavedState) {
|
||||
this.state = await this.stateService.getBrowserSendTypeComponentState();
|
||||
if (this.state?.searchText != null) {
|
||||
this.searchText = this.state.searchText;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.type != null) {
|
||||
this.type = parseInt(params.type, null);
|
||||
switch (this.type) {
|
||||
case SendType.Text:
|
||||
this.groupingTitle = this.i18nService.t("sendTypeText");
|
||||
break;
|
||||
case SendType.File:
|
||||
this.groupingTitle = this.i18nService.t("sendTypeFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
await this.load((s) => s.type === this.type);
|
||||
}
|
||||
|
||||
// Restore state and remove reference
|
||||
if (this.applySavedState && this.state != null) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserPopupUtils.setContentScrollY(window, this.state?.scrollY);
|
||||
}
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.stateService.setBrowserSendTypeComponentState(null);
|
||||
});
|
||||
|
||||
// Refresh Send list if sync completed in background
|
||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.ngZone.run(async () => {
|
||||
switch (message.command) {
|
||||
case "syncCompleted":
|
||||
if (message.successfully) {
|
||||
this.refreshTimeout = window.setTimeout(() => {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.refresh();
|
||||
}, 500);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// Remove timeout
|
||||
if (this.refreshTimeout != null) {
|
||||
window.clearTimeout(this.refreshTimeout);
|
||||
}
|
||||
// Save state
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.saveState();
|
||||
// Unsubscribe
|
||||
this.broadcasterService.unsubscribe(ComponentId);
|
||||
}
|
||||
|
||||
async selectSend(s: SendView) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/edit-send"], { queryParams: { sendId: s.id } });
|
||||
}
|
||||
|
||||
async addSend() {
|
||||
if (this.disableSend) {
|
||||
return;
|
||||
}
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/add-send"], { queryParams: { type: this.type } });
|
||||
}
|
||||
|
||||
async removePassword(s: SendView): Promise<boolean> {
|
||||
if (this.disableSend) {
|
||||
return;
|
||||
}
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
super.removePassword(s);
|
||||
}
|
||||
|
||||
back() {
|
||||
(window as any).routeDirection = "b";
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
private async saveState() {
|
||||
this.state = {
|
||||
scrollY: BrowserPopupUtils.getContentScrollY(window),
|
||||
searchText: this.searchText,
|
||||
};
|
||||
await this.stateService.setBrowserSendTypeComponentState(this.state);
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
import {
|
||||
FakeAccountService,
|
||||
mockAccountServiceWith,
|
||||
} from "@bitwarden/common/../spec/fake-account-service";
|
||||
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||
import { awaitAsync } from "@bitwarden/common/../spec/utils";
|
||||
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { BrowserComponentState } from "../../../models/browserComponentState";
|
||||
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
||||
|
||||
import { BrowserSendStateService } from "./browser-send-state.service";
|
||||
|
||||
describe("Browser Send State Service", () => {
|
||||
let stateProvider: FakeStateProvider;
|
||||
|
||||
let accountService: FakeAccountService;
|
||||
let stateService: BrowserSendStateService;
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
stateProvider = new FakeStateProvider(accountService);
|
||||
|
||||
stateService = new BrowserSendStateService(stateProvider);
|
||||
});
|
||||
|
||||
describe("getBrowserSendComponentState", () => {
|
||||
it("should return BrowserSendComponentState", async () => {
|
||||
const state = new BrowserSendComponentState();
|
||||
state.scrollY = 0;
|
||||
state.searchText = "test";
|
||||
|
||||
await stateService.setBrowserSendComponentState(state);
|
||||
|
||||
await awaitAsync();
|
||||
|
||||
const actual = await stateService.getBrowserSendComponentState();
|
||||
expect(actual).toStrictEqual(state);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getBrowserSendTypeComponentState", () => {
|
||||
it("should return BrowserComponentState", async () => {
|
||||
const state = new BrowserComponentState();
|
||||
state.scrollY = 0;
|
||||
state.searchText = "test";
|
||||
|
||||
await stateService.setBrowserSendTypeComponentState(state);
|
||||
|
||||
await awaitAsync();
|
||||
|
||||
const actual = await stateService.getBrowserSendTypeComponentState();
|
||||
expect(actual).toStrictEqual(state);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,71 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Observable, firstValueFrom } from "rxjs";
|
||||
|
||||
import { ActiveUserState, StateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
import { BrowserComponentState } from "../../../models/browserComponentState";
|
||||
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
||||
|
||||
import { BROWSER_SEND_COMPONENT, BROWSER_SEND_TYPE_COMPONENT } from "./key-definitions";
|
||||
|
||||
/** Get or set the active user's component state for the Send browser component
|
||||
*/
|
||||
export class BrowserSendStateService {
|
||||
/** Observable that contains the current state for active user Sends including the send data and type counts
|
||||
* along with the search text and scroll position
|
||||
*/
|
||||
browserSendComponentState$: Observable<BrowserSendComponentState>;
|
||||
|
||||
/** Observable that contains the current state for active user Sends that only includes the search text
|
||||
* and scroll position
|
||||
*/
|
||||
browserSendTypeComponentState$: Observable<BrowserComponentState>;
|
||||
|
||||
private activeUserBrowserSendComponentState: ActiveUserState<BrowserSendComponentState>;
|
||||
private activeUserBrowserSendTypeComponentState: ActiveUserState<BrowserComponentState>;
|
||||
|
||||
constructor(protected stateProvider: StateProvider) {
|
||||
this.activeUserBrowserSendComponentState = this.stateProvider.getActive(BROWSER_SEND_COMPONENT);
|
||||
this.browserSendComponentState$ = this.activeUserBrowserSendComponentState.state$;
|
||||
|
||||
this.activeUserBrowserSendTypeComponentState = this.stateProvider.getActive(
|
||||
BROWSER_SEND_TYPE_COMPONENT,
|
||||
);
|
||||
this.browserSendTypeComponentState$ = this.activeUserBrowserSendTypeComponentState.state$;
|
||||
}
|
||||
|
||||
/** Get the active user's browser send component state
|
||||
* @returns { BrowserSendComponentState } contains the sends and type counts along with the scroll position and search text for the
|
||||
* send component on the browser
|
||||
*/
|
||||
async getBrowserSendComponentState(): Promise<BrowserSendComponentState> {
|
||||
return await firstValueFrom(this.browserSendComponentState$);
|
||||
}
|
||||
|
||||
/** Set the active user's browser send component state
|
||||
* @param { BrowserSendComponentState } value sets the sends along with the scroll position and search text for
|
||||
* the send component on the browser
|
||||
*/
|
||||
async setBrowserSendComponentState(value: BrowserSendComponentState): Promise<void> {
|
||||
await this.activeUserBrowserSendComponentState.update(() => value, {
|
||||
shouldUpdate: (current) => !(current == null && value == null),
|
||||
});
|
||||
}
|
||||
|
||||
/** Get the active user's browser component state
|
||||
* @returns { BrowserComponentState } contains the scroll position and search text for the sends menu on the browser
|
||||
*/
|
||||
async getBrowserSendTypeComponentState(): Promise<BrowserComponentState> {
|
||||
return await firstValueFrom(this.browserSendTypeComponentState$);
|
||||
}
|
||||
|
||||
/** Set the active user's browser component state
|
||||
* @param { BrowserComponentState } value set the scroll position and search text for the send component on the browser
|
||||
*/
|
||||
async setBrowserSendTypeComponentState(value: BrowserComponentState): Promise<void> {
|
||||
await this.activeUserBrowserSendTypeComponentState.update(() => value, {
|
||||
shouldUpdate: (current) => !(current == null && value == null),
|
||||
});
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
||||
|
||||
import { BROWSER_SEND_COMPONENT, BROWSER_SEND_TYPE_COMPONENT } from "./key-definitions";
|
||||
|
||||
describe("Key definitions", () => {
|
||||
describe("BROWSER_SEND_COMPONENT", () => {
|
||||
it("should deserialize BrowserSendComponentState", () => {
|
||||
const keyDef = BROWSER_SEND_COMPONENT;
|
||||
|
||||
const expectedState = {
|
||||
scrollY: 0,
|
||||
searchText: "test",
|
||||
};
|
||||
|
||||
const result = keyDef.deserializer(
|
||||
JSON.parse(JSON.stringify(expectedState)) as Jsonify<BrowserSendComponentState>,
|
||||
);
|
||||
|
||||
expect(result).toEqual(expectedState);
|
||||
});
|
||||
});
|
||||
|
||||
describe("BROWSER_SEND_TYPE_COMPONENT", () => {
|
||||
it("should deserialize BrowserComponentState", () => {
|
||||
const keyDef = BROWSER_SEND_TYPE_COMPONENT;
|
||||
|
||||
const expectedState = {
|
||||
scrollY: 0,
|
||||
searchText: "test",
|
||||
};
|
||||
|
||||
const result = keyDef.deserializer(JSON.parse(JSON.stringify(expectedState)));
|
||||
|
||||
expect(result).toEqual(expectedState);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { BROWSER_SEND_MEMORY, UserKeyDefinition } from "@bitwarden/common/platform/state";
|
||||
|
||||
import { BrowserComponentState } from "../../../models/browserComponentState";
|
||||
import { BrowserSendComponentState } from "../../../models/browserSendComponentState";
|
||||
|
||||
export const BROWSER_SEND_COMPONENT = new UserKeyDefinition<BrowserSendComponentState>(
|
||||
BROWSER_SEND_MEMORY,
|
||||
"browser_send_component",
|
||||
{
|
||||
deserializer: (obj: Jsonify<BrowserSendComponentState>) =>
|
||||
BrowserSendComponentState.fromJSON(obj),
|
||||
clearOn: ["logout", "lock"],
|
||||
},
|
||||
);
|
||||
|
||||
export const BROWSER_SEND_TYPE_COMPONENT = new UserKeyDefinition<BrowserComponentState>(
|
||||
BROWSER_SEND_MEMORY,
|
||||
"browser_send_type_component",
|
||||
{
|
||||
deserializer: (obj: Jsonify<BrowserComponentState>) => BrowserComponentState.fromJSON(obj),
|
||||
clearOn: ["logout", "lock"],
|
||||
},
|
||||
);
|
Loading…
Reference in New Issue
Block a user