1
0
mirror of https://github.com/bitwarden/desktop.git synced 2024-11-24 11:55:50 +01:00

inital pass at menu bar functions

This commit is contained in:
addison 2021-02-22 13:17:02 -05:00
parent 07e78d75d5
commit 7e03d282df
3 changed files with 154 additions and 79 deletions

View File

@ -2,11 +2,9 @@ import {
BodyOutputType, BodyOutputType,
Toast, Toast,
ToasterConfig, ToasterConfig,
ToasterContainerComponent,
ToasterService, ToasterService,
} from 'angular2-toaster'; } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2'; import { Angulartics2 } from 'angulartics2';
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga';
import { import {
Component, Component,
@ -16,7 +14,6 @@ import {
SecurityContext, SecurityContext,
Type, Type,
ViewChild, ViewChild,
ViewContainerRef,
} from '@angular/core'; } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@ -52,10 +49,16 @@ import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service'; import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { ConstantsService } from 'jslib/services/constants.service'; import { ConstantsService } from 'jslib/services/constants.service';
import { NativeMessagingService } from '../services/nativeMessaging.service';
import { CipherType } from 'jslib/enums/cipherType';
import { ExportComponent } from './vault/export.component';
import { FolderAddEditComponent } from './vault/folder-add-edit.component';
import { PasswordGeneratorComponent } from './vault/password-generator.component';
const BroadcasterSubscriptionId = 'AppComponent'; const BroadcasterSubscriptionId = 'AppComponent';
const IdleTimeout = 60000 * 10; // 10 minutes const IdleTimeout = 60000 * 10; // 10 minutes
const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -65,12 +68,18 @@ const IdleTimeout = 60000 * 10; // 10 minutes
<ng-template #settings></ng-template> <ng-template #settings></ng-template>
<ng-template #premium></ng-template> <ng-template #premium></ng-template>
<ng-template #passwordHistory></ng-template> <ng-template #passwordHistory></ng-template>
<ng-template #appFolderAddEdit></ng-template>
<ng-template #exportVault></ng-template>
<ng-template #appPasswordGenerator></ng-template>
<router-outlet></router-outlet>`, <router-outlet></router-outlet>`,
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
@ViewChild('settings', { read: ViewContainerRef, static: true }) settingsRef: ViewContainerRef; @ViewChild('settings', { read: ViewContainerRef, static: true }) settingsRef: ViewContainerRef;
@ViewChild('premium', { read: ViewContainerRef, static: true }) premiumRef: ViewContainerRef; @ViewChild('premium', { read: ViewContainerRef, static: true }) premiumRef: ViewContainerRef;
@ViewChild('passwordHistory', { read: ViewContainerRef, static: true }) passwordHistoryRef: ViewContainerRef; @ViewChild('passwordHistory', { read: ViewContainerRef, static: true }) passwordHistoryRef: ViewContainerRef;
@ViewChild('exportVault', { read: ViewContainerRef, static: true }) exportVaultModalRef: ViewContainerRef;
@ViewChild('appFolderAddEdit', { read: ViewContainerRef, static: true }) folderAddEditModalRef: ViewContainerRef;
@ViewChild('appPasswordGenerator', { read: ViewContainerRef, static: true }) passwordGeneratorModalRef: ViewContainerRef;
toasterConfig: ToasterConfig = new ToasterConfig({ toasterConfig: ToasterConfig = new ToasterConfig({
showCloseButton: true, showCloseButton: true,
@ -84,8 +93,7 @@ export class AppComponent implements OnInit {
private idleTimer: number = null; private idleTimer: number = null;
private isIdle = false; private isIdle = false;
constructor(private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics, constructor(private broadcasterService: BroadcasterService, private userService: UserService,
private broadcasterService: BroadcasterService, private userService: UserService,
private tokenService: TokenService, private folderService: FolderService, private tokenService: TokenService, private folderService: FolderService,
private settingsService: SettingsService, private syncService: SyncService, private settingsService: SettingsService, private syncService: SyncService,
private passwordGenerationService: PasswordGenerationService, private cipherService: CipherService, private passwordGenerationService: PasswordGenerationService, private cipherService: CipherService,
@ -98,7 +106,7 @@ export class AppComponent implements OnInit {
private searchService: SearchService, private notificationsService: NotificationsService, private searchService: SearchService, private notificationsService: NotificationsService,
private platformUtilsService: PlatformUtilsService, private systemService: SystemService, private platformUtilsService: PlatformUtilsService, private systemService: SystemService,
private stateService: StateService, private eventService: EventService, private stateService: StateService, private eventService: EventService,
private policyService: PolicyService, private nativeMessagingService: NativeMessagingService) { } private policyService: PolicyService) { }
ngOnInit() { ngOnInit() {
this.ngZone.runOutsideAngular(() => { this.ngZone.runOutsideAngular(() => {
@ -173,7 +181,7 @@ export class AppComponent implements OnInit {
this.i18nService.t('fingerprintPhrase'), this.i18nService.t('learnMore'), this.i18nService.t('fingerprintPhrase'), this.i18nService.t('learnMore'),
this.i18nService.t('close')); this.i18nService.t('close'));
if (result) { if (result) {
this.platformUtilsService.launchUri( this.platformUtilsService.launchUri(
'https://help.bitwarden.com/article/fingerprint-phrase/'); 'https://help.bitwarden.com/article/fingerprint-phrase/');
} }
break; break;
@ -205,7 +213,55 @@ export class AppComponent implements OnInit {
this.openModal<PremiumComponent>(PremiumComponent, this.premiumRef); this.openModal<PremiumComponent>(PremiumComponent, this.premiumRef);
} }
break; break;
case 'syncVault':
try {
await this.syncService.fullSync(true, true);
this.toasterService.popAsync('success', null, this.i18nService.t('syncingComplete'));
this.analytics.eventTrack.next({ action: 'Synced Full' });
} catch {
this.toasterService.popAsync('error', null, this.i18nService.t('syncingFailed'));
}
break;
case 'checkSyncVault':
try {
const lastSync = await this.syncService.getLastSync();
let lastSyncAgo = SyncInterval + 1;
if (lastSync != null) {
lastSyncAgo = new Date().getTime() - lastSync.getTime();
}
if (lastSyncAgo >= SyncInterval) {
await this.syncService.fullSync(false);
}
} catch { }
this.messagingService.send('scheduleNextSync');
break;
case 'exportVault':
await this.openExportVault();
break;
case 'newLogin':
this.routeToVault('add', CipherType.Login);
break;
case 'newCard':
this.routeToVault('add', CipherType.Card);
break;
case 'newIdentity':
this.routeToVault('add', CipherType.Identity);
break;
case 'newSecureNote':
this.routeToVault('add', CipherType.SecureNote);
break;
default: default:
break;
case 'newFolder':
await this.addFolder();
break;
case 'openPasswordGenerator':
// openPasswordGenerator has extended functionality if called in the vault
if (!this.router.url.includes('vault')) {
await this.openPasswordGenerator();
}
break;
} }
}); });
}); });
@ -215,6 +271,59 @@ export class AppComponent implements OnInit {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
} }
async openExportVault() {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.exportVaultModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<ExportComponent>(ExportComponent, this.exportVaultModalRef);
childComponent.onSaved.subscribe(() => {
this.modal.close();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
}
async addFolder() {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.folderAddEditModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<FolderAddEditComponent>(
FolderAddEditComponent, this.folderAddEditModalRef, true, comp => comp.folderId = null);
childComponent.onSavedFolder.subscribe(async () => {
this.modal.close();
this.syncService.fullSync(false);
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
}
async openPasswordGenerator() {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.passwordGeneratorModalRef.createComponent(factory).instance;
this.modal.show<PasswordGeneratorComponent>(PasswordGeneratorComponent,
this.passwordGeneratorModalRef, true, comp => comp.showSelect = false);
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
}
private async updateAppMenu() { private async updateAppMenu() {
this.messagingService.send('updateAppMenu', { this.messagingService.send('updateAppMenu', {
isAuthenticated: await this.userService.isAuthenticated(), isAuthenticated: await this.userService.isAuthenticated(),
@ -328,4 +437,16 @@ export class AppComponent implements OnInit {
} }
this.toasterService.popAsync(toast); this.toasterService.popAsync(toast);
} }
private routeToVault(action: string, cipherType: CipherType) {
if (!this.router.url.includes('vault')) {
this.router.navigate(['/vault'], {
queryParams: {
action: action,
addType: cipherType,
},
replaceUrl: true,
});
}
}
} }

View File

@ -38,4 +38,3 @@
<ng-template #share></ng-template> <ng-template #share></ng-template>
<ng-template #folderAddEdit></ng-template> <ng-template #folderAddEdit></ng-template>
<ng-template #passwordHistory></ng-template> <ng-template #passwordHistory></ng-template>
<ng-template #exportVault></ng-template>

View File

@ -49,7 +49,6 @@ import { SyncService } from 'jslib/abstractions/sync.service';
import { TotpService } from 'jslib/abstractions/totp.service'; import { TotpService } from 'jslib/abstractions/totp.service';
import { UserService } from 'jslib/abstractions/user.service'; import { UserService } from 'jslib/abstractions/user.service';
const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours
const BroadcasterSubscriptionId = 'VaultComponent'; const BroadcasterSubscriptionId = 'VaultComponent';
@Component({ @Component({
@ -63,11 +62,10 @@ export class VaultComponent implements OnInit, OnDestroy {
@ViewChild(GroupingsComponent, { static: true }) groupingsComponent: GroupingsComponent; @ViewChild(GroupingsComponent, { static: true }) groupingsComponent: GroupingsComponent;
@ViewChild('passwordGenerator', { read: ViewContainerRef, static: true }) passwordGeneratorModalRef: ViewContainerRef; @ViewChild('passwordGenerator', { read: ViewContainerRef, static: true }) passwordGeneratorModalRef: ViewContainerRef;
@ViewChild('attachments', { read: ViewContainerRef, static: true }) attachmentsModalRef: ViewContainerRef; @ViewChild('attachments', { read: ViewContainerRef, static: true }) attachmentsModalRef: ViewContainerRef;
@ViewChild('folderAddEdit', { read: ViewContainerRef, static: true }) folderAddEditModalRef: ViewContainerRef;
@ViewChild('passwordHistory', { read: ViewContainerRef, static: true }) passwordHistoryModalRef: ViewContainerRef; @ViewChild('passwordHistory', { read: ViewContainerRef, static: true }) passwordHistoryModalRef: ViewContainerRef;
@ViewChild('exportVault', { read: ViewContainerRef, static: true }) exportVaultModalRef: ViewContainerRef;
@ViewChild('share', { read: ViewContainerRef, static: true }) shareModalRef: ViewContainerRef; @ViewChild('share', { read: ViewContainerRef, static: true }) shareModalRef: ViewContainerRef;
@ViewChild('collections', { read: ViewContainerRef, static: true }) collectionsModalRef: ViewContainerRef; @ViewChild('collections', { read: ViewContainerRef, static: true }) collectionsModalRef: ViewContainerRef;
@ViewChild('folderAddEdit', { read: ViewContainerRef, static: true }) folderAddEditModalRef: ViewContainerRef;
action: string; action: string;
cipherId: string = null; cipherId: string = null;
@ -111,9 +109,6 @@ export class VaultComponent implements OnInit, OnDestroy {
case 'newSecureNote': case 'newSecureNote':
await this.addCipher(CipherType.SecureNote); await this.addCipher(CipherType.SecureNote);
break; break;
case 'newFolder':
await this.addFolder();
break;
case 'focusSearch': case 'focusSearch':
(document.querySelector('#search') as HTMLInputElement).select(); (document.querySelector('#search') as HTMLInputElement).select();
detectChanges = false; detectChanges = false;
@ -121,33 +116,6 @@ export class VaultComponent implements OnInit, OnDestroy {
case 'openPasswordGenerator': case 'openPasswordGenerator':
await this.openPasswordGenerator(false); await this.openPasswordGenerator(false);
break; break;
case 'exportVault':
await this.openExportVault();
break;
case 'syncVault':
try {
await this.syncService.fullSync(true, true);
this.toasterService.popAsync('success', null, this.i18nService.t('syncingComplete'));
this.analytics.eventTrack.next({ action: 'Synced Full' });
} catch {
this.toasterService.popAsync('error', null, this.i18nService.t('syncingFailed'));
}
break;
case 'checkSyncVault':
try {
const lastSync = await this.syncService.getLastSync();
let lastSyncAgo = SyncInterval + 1;
if (lastSync != null) {
lastSyncAgo = new Date().getTime() - lastSync.getTime();
}
if (lastSyncAgo >= SyncInterval) {
await this.syncService.fullSync(false);
}
} catch { }
this.messagingService.send('scheduleNextSync');
break;
case 'syncCompleted': case 'syncCompleted':
await this.load(); await this.load();
break; break;
@ -230,7 +198,28 @@ export class VaultComponent implements OnInit, OnDestroy {
await this.viewCipher(cipherView); await this.viewCipher(cipherView);
} }
} else if (params.action === 'add') { } else if (params.action === 'add') {
await this.addCipher(); switch (params.addType) {
case 'Login':
case '1':
this.addType = CipherType.Login;
break;
case 'SecureNote':
case '2':
this.addType = CipherType.SecureNote;
break;
case 'Card':
case '3':
this.addType = CipherType.Card;
break;
case 'Identity':
case '4':
this.addType = CipherType.Identity;
break;
default:
this.addType = CipherType.Login;
break;
}
this.addCipher(this.addType);
} }
if (params.deleted) { if (params.deleted) {
@ -239,7 +228,7 @@ export class VaultComponent implements OnInit, OnDestroy {
} else if (params.favorites) { } else if (params.favorites) {
this.groupingsComponent.selectedFavorites = true; this.groupingsComponent.selectedFavorites = true;
await this.filterFavorites(); await this.filterFavorites();
} else if (params.type) { } else if (params.type && params.action !== 'add') {
const t = parseInt(params.type, null); const t = parseInt(params.type, null);
this.groupingsComponent.selectedType = t; this.groupingsComponent.selectedType = t;
await this.filterCipherType(t); await this.filterCipherType(t);
@ -593,42 +582,8 @@ export class VaultComponent implements OnInit, OnDestroy {
}); });
} }
async openExportVault() {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.exportVaultModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<ExportComponent>(ExportComponent, this.exportVaultModalRef);
childComponent.onSaved.subscribe(() => {
this.modal.close();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
}
async addFolder() { async addFolder() {
if (this.modal != null) { this.messagingService.send('newFolder');
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.folderAddEditModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<FolderAddEditComponent>(
FolderAddEditComponent, this.folderAddEditModalRef, true, comp => comp.folderId = null);
childComponent.onSavedFolder.subscribe(async (folder: FolderView) => {
this.modal.close();
await this.groupingsComponent.loadFolders();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
} }
async editFolder(folderId: string) { async editFolder(folderId: string) {