diff --git a/terminus-core/src/api/index.ts b/terminus-core/src/api/index.ts index 75a8a60c..bc1e1f3b 100644 --- a/terminus-core/src/api/index.ts +++ b/terminus-core/src/api/index.ts @@ -25,6 +25,7 @@ export { HomeBaseService } from '../services/homeBase.service' export { HotkeysService } from '../services/hotkeys.service' export { NotificationsService } from '../services/notifications.service' export { ThemesService } from '../services/themes.service' +export { SelectorService } from '../services/selector.service' export { TabsService } from '../services/tabs.service' export { UpdaterService } from '../services/updater.service' export { VaultService, Vault, VaultSecret, VAULT_SECRET_TYPE_FILE } from '../services/vault.service' diff --git a/terminus-core/src/services/app.service.ts b/terminus-core/src/services/app.service.ts index 8f2d2b00..b6486d4a 100644 --- a/terminus-core/src/services/app.service.ts +++ b/terminus-core/src/services/app.service.ts @@ -2,11 +2,9 @@ import { Observable, Subject, AsyncSubject } from 'rxjs' import { takeUntil } from 'rxjs/operators' import { Injectable, Inject } from '@angular/core' -import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { BaseTabComponent } from '../components/baseTab.component' import { SplitTabComponent } from '../components/splitTab.component' -import { SelectorModalComponent } from '../components/selectorModal.component' import { SelectorOption } from '../api/selector' import { RecoveryToken } from '../api/tabRecovery' import { BootstrapData, BOOTSTRAP_DATA } from '../api/mainProcess' @@ -16,6 +14,7 @@ import { HostAppService } from '../api/hostApp' import { ConfigService } from './config.service' import { TabRecoveryService } from './tabRecovery.service' import { TabsService, TabComponentType } from './tabs.service' +import { SelectorService } from './selector.service' class CompletionObserver { get done$ (): Observable { return this.done } @@ -77,7 +76,7 @@ export class AppService { private hostWindow: HostWindowService, private tabRecovery: TabRecoveryService, private tabsService: TabsService, - private ngbModal: NgbModal, + private selector: SelectorService, @Inject(BOOTSTRAP_DATA) private bootstrapData: BootstrapData, ) { this.tabsChanged$.subscribe(() => { @@ -366,11 +365,8 @@ export class AppService { this.completionObservers.delete(tab) } + // Deprecated showSelector (name: string, options: SelectorOption[]): Promise { - const modal = this.ngbModal.open(SelectorModalComponent) - const instance: SelectorModalComponent = modal.componentInstance - instance.name = name - instance.options = options - return modal.result as Promise + return this.selector.show(name, options) } } diff --git a/terminus-core/src/services/fileProviders.service.ts b/terminus-core/src/services/fileProviders.service.ts index 63f4a91f..80fbf00a 100644 --- a/terminus-core/src/services/fileProviders.service.ts +++ b/terminus-core/src/services/fileProviders.service.ts @@ -1,11 +1,11 @@ import { Inject, Injectable } from '@angular/core' -import { AppService, FileProvider, NotificationsService } from '../api' +import { FileProvider, NotificationsService, SelectorService } from '../api' @Injectable({ providedIn: 'root' }) export class FileProvidersService { /** @hidden */ private constructor ( - private app: AppService, + private selector: SelectorService, private notifications: NotificationsService, @Inject(FileProvider) private fileProviders: FileProvider[], ) { } @@ -40,7 +40,7 @@ export class FileProvidersService { if (providers.length === 1) { return providers[0] } - return this.app.showSelector('Select file storage', providers.map(p => ({ + return this.selector.show('Select file storage', providers.map(p => ({ name: p.name, result: p, }))) diff --git a/terminus-core/src/services/selector.service.ts b/terminus-core/src/services/selector.service.ts new file mode 100644 index 00000000..c9cb7153 --- /dev/null +++ b/terminus-core/src/services/selector.service.ts @@ -0,0 +1,22 @@ + +import { Injectable } from '@angular/core' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' + +import { SelectorModalComponent } from '../components/selectorModal.component' +import { SelectorOption } from '../api/selector' + +@Injectable({ providedIn: 'root' }) +export class SelectorService { + /** @hidden */ + private constructor ( + private ngbModal: NgbModal, + ) { } + + show (name: string, options: SelectorOption[]): Promise { + const modal = this.ngbModal.open(SelectorModalComponent) + const instance: SelectorModalComponent = modal.componentInstance + instance.name = name + instance.options = options + return modal.result as Promise + } +} diff --git a/terminus-core/src/services/vault.service.ts b/terminus-core/src/services/vault.service.ts index 99b4f2e1..39fa7fda 100644 --- a/terminus-core/src/services/vault.service.ts +++ b/terminus-core/src/services/vault.service.ts @@ -5,7 +5,8 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { AsyncSubject, Subject, Observable } from 'rxjs' import { wrapPromise } from '../utils' import { UnlockVaultModalComponent } from '../components/unlockVaultModal.component' -import { NotificationsService } from '../services/notifications.service' +import { NotificationsService } from './notifications.service' +import { SelectorService } from './selector.service' import { FileProvider } from '../api/fileProvider' import { PlatformService } from '../api/platform' @@ -226,6 +227,7 @@ export class VaultFileProvider extends FileProvider { constructor ( private vault: VaultService, private platform: PlatformService, + private selector: SelectorService, private zone: NgZone, ) { super() @@ -236,6 +238,32 @@ export class VaultFileProvider extends FileProvider { } async selectAndStoreFile (description: string): Promise { + const vault = await this.vault.load() + if (!vault) { + throw new Error('Vault is locked') + } + const files = vault.secrets.filter(x => x.type === VAULT_SECRET_TYPE_FILE) + if (files.length) { + const result = await this.selector.show('Select file', [ + { + name: 'Add a new file', + icon: 'plus', + result: null, + }, + ...files.map(f => ({ + name: f.key.description, + icon: 'file', + result: f, + })), + ]) + if (result) { + return `${this.prefix}${result.key.id}` + } + } + return this.addNewFile(description) + } + + async addNewFile (description: string): Promise { const transfers = await this.platform.startUpload() if (!transfers.length) { throw new Error('Nothing selected') diff --git a/terminus-local/src/buttonProvider.ts b/terminus-local/src/buttonProvider.ts index dc2ec8fb..654cd922 100644 --- a/terminus-local/src/buttonProvider.ts +++ b/terminus-local/src/buttonProvider.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Injectable } from '@angular/core' -import { ToolbarButtonProvider, ToolbarButton, ConfigService, SelectorOption, AppService } from 'terminus-core' +import { ToolbarButtonProvider, ToolbarButton, ConfigService, SelectorOption, SelectorService } from 'terminus-core' import { ElectronService } from 'terminus-electron' import { TerminalService } from './services/terminal.service' @@ -10,7 +10,7 @@ import { TerminalService } from './services/terminal.service' export class ButtonProvider extends ToolbarButtonProvider { constructor ( electron: ElectronService, - private app: AppService, + private selector: SelectorService, private config: ConfigService, private terminal: TerminalService, ) { @@ -29,7 +29,7 @@ export class ButtonProvider extends ToolbarButtonProvider { }) } - await this.app.showSelector('Select profile', options) + await this.selector.show('Select profile', options) } provide (): ToolbarButton[] { diff --git a/terminus-serial/src/components/serialTab.component.ts b/terminus-serial/src/components/serialTab.component.ts index 4bfd0b2a..5bab8032 100644 --- a/terminus-serial/src/components/serialTab.component.ts +++ b/terminus-serial/src/components/serialTab.component.ts @@ -3,6 +3,7 @@ import colors from 'ansi-colors' import { Spinner } from 'cli-spinner' import { Component, Injector } from '@angular/core' import { first } from 'rxjs/operators' +import { SelectorService } from 'terminus-core' import { BaseTerminalTabComponent } from 'terminus-terminal' import { SerialService } from '../services/serial.service' import { SerialConnection, SerialSession, BAUD_RATES } from '../api' @@ -23,6 +24,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent { // eslint-disable-next-line @typescript-eslint/no-useless-constructor constructor ( injector: Injector, + private selector: SelectorService, ) { super(injector) this.serialService = injector.get(SerialService) @@ -122,7 +124,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent { } async changeBaudRate () { - const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({ + const rate = await this.selector.show('Baud rate', BAUD_RATES.map(x => ({ name: x.toString(), result: x, }))) this.serialPort.update({ baudRate: rate }) diff --git a/terminus-serial/src/services/serial.service.ts b/terminus-serial/src/services/serial.service.ts index aacb1c44..a6537548 100644 --- a/terminus-serial/src/services/serial.service.ts +++ b/terminus-serial/src/services/serial.service.ts @@ -1,6 +1,6 @@ import { Injectable, NgZone } from '@angular/core' import SerialPort from 'serialport' -import { LogService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core' +import { LogService, AppService, SelectorOption, ConfigService, NotificationsService, SelectorService } from 'terminus-core' import { SettingsTabComponent } from 'terminus-settings' import { SerialConnection, SerialSession, SerialPortInfo, BAUD_RATES } from '../api' import { SerialTabComponent } from '../components/serialTab.component' @@ -12,6 +12,7 @@ export class SerialService { private zone: NgZone, private notifications: NotificationsService, private app: AppService, + private selector: SelectorService, private config: ConfigService, ) { } @@ -124,7 +125,7 @@ export class SerialService { }) - await this.app.showSelector('Open a serial port', options) + await this.selector.show('Open a serial port', options) } async connect (connection: SerialConnection): Promise { @@ -170,7 +171,7 @@ export class SerialService { } async connectFoundPort (port: SerialPortInfo): Promise { - const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({ + const rate = await this.selector.show('Baud rate', BAUD_RATES.map(x => ({ name: x.toString(), result: x, }))) return this.quickConnect(`${port.name}@${rate}`) diff --git a/terminus-ssh/src/services/ssh.service.ts b/terminus-ssh/src/services/ssh.service.ts index 97c89f58..4657545d 100644 --- a/terminus-ssh/src/services/ssh.service.ts +++ b/terminus-ssh/src/services/ssh.service.ts @@ -5,7 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { Client } from 'ssh2' import { exec } from 'child_process' import { Subject, Observable } from 'rxjs' -import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService, HostAppService, Platform, PlatformService } from 'terminus-core' +import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService, HostAppService, Platform, PlatformService, SelectorService } from 'terminus-core' import { SettingsTabComponent } from 'terminus-settings' import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api' import { PromptModalComponent } from '../components/promptModal.component' @@ -26,6 +26,7 @@ export class SSHService { private passwordStorage: PasswordStorageService, private notifications: NotificationsService, private app: AppService, + private selector: SelectorService, private config: ConfigService, hostApp: HostAppService, private platform: PlatformService, @@ -230,7 +231,7 @@ export class SSHService { }) - await this.app.showSelector('Open an SSH connection', options) + await this.selector.show('Open an SSH connection', options) } async connect (connection: SSHConnection): Promise {