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:
parent
07e78d75d5
commit
7e03d282df
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user