From db43381f0db05741baf0f9cf8718aab42562ea2c Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Mon, 23 Mar 2020 01:12:46 +0100 Subject: [PATCH] use new selector in serial plugin --- .../components/selectorModal.component.pug | 1 + .../components/selectorModal.component.scss | 4 + .../src/components/selectorModal.component.ts | 11 +- terminus-serial/src/buttonProvider.ts | 9 +- .../src/components/serialModal.component.pug | 32 ----- .../src/components/serialModal.component.scss | 5 - .../src/components/serialModal.component.ts | 102 ---------------- .../src/components/serialTab.component.ts | 10 +- terminus-serial/src/index.ts | 3 - .../src/services/serial.service.ts | 113 +++++++++++++++++- 10 files changed, 130 insertions(+), 160 deletions(-) create mode 100644 terminus-core/src/components/selectorModal.component.scss delete mode 100644 terminus-serial/src/components/serialModal.component.pug delete mode 100644 terminus-serial/src/components/serialModal.component.scss delete mode 100644 terminus-serial/src/components/serialModal.component.ts diff --git a/terminus-core/src/components/selectorModal.component.pug b/terminus-core/src/components/selectorModal.component.pug index 94b47381..a0854b76 100644 --- a/terminus-core/src/components/selectorModal.component.pug +++ b/terminus-core/src/components/selectorModal.component.pug @@ -9,6 +9,7 @@ .list-group.mt-3(*ngIf='filteredOptions.length') a.list-group-item.list-group-item-action.d-flex.align-items-center( + #item, (click)='selectOption(option)', [class.active]='selectedIndex == i', *ngFor='let option of filteredOptions; let i = index' diff --git a/terminus-core/src/components/selectorModal.component.scss b/terminus-core/src/components/selectorModal.component.scss new file mode 100644 index 00000000..2066a9ce --- /dev/null +++ b/terminus-core/src/components/selectorModal.component.scss @@ -0,0 +1,4 @@ +.list-group { + max-height: 70vh; + overflow: auto; +} diff --git a/terminus-core/src/components/selectorModal.component.ts b/terminus-core/src/components/selectorModal.component.ts index 2ddad7a6..5c0636d6 100644 --- a/terminus-core/src/components/selectorModal.component.ts +++ b/terminus-core/src/components/selectorModal.component.ts @@ -1,11 +1,11 @@ -import { Component, Input, HostListener } from '@angular/core' +import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { SelectorOption } from '../api/selector' /** @hidden */ @Component({ template: require('./selectorModal.component.pug'), - // styles: [require('./selectorModal.component.scss')], + styles: [require('./selectorModal.component.scss')], }) export class SelectorModalComponent { @Input() options: SelectorOption[] @@ -13,6 +13,7 @@ export class SelectorModalComponent { @Input() filter = '' @Input() name: string @Input() selectedIndex = 0 + @ViewChildren('item') itemChildren: QueryList constructor ( public modalInstance: NgbActiveModal, @@ -22,7 +23,7 @@ export class SelectorModalComponent { this.onFilterChange() } - @HostListener('keyup', ['$event']) onKeyUp (event: KeyboardEvent): void { + @HostListener('keypress', ['$event']) onKeyUp (event: KeyboardEvent): void { if (event.key === 'ArrowUp') { this.selectedIndex-- } @@ -37,6 +38,10 @@ export class SelectorModalComponent { } this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length + Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }) } onFilterChange (): void { diff --git a/terminus-serial/src/buttonProvider.ts b/terminus-serial/src/buttonProvider.ts index 303a8503..1f232654 100644 --- a/terminus-serial/src/buttonProvider.ts +++ b/terminus-serial/src/buttonProvider.ts @@ -1,14 +1,13 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { Injectable } from '@angular/core' -import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { Injectable, Injector } from '@angular/core' import { HotkeysService, ToolbarButtonProvider, ToolbarButton } from 'terminus-core' -import { SerialModalComponent } from './components/serialModal.component' +import { SerialService } from './services/serial.service' /** @hidden */ @Injectable() export class ButtonProvider extends ToolbarButtonProvider { constructor ( - private ngbModal: NgbModal, + private injector: Injector, hotkeys: HotkeysService, ) { super() @@ -20,7 +19,7 @@ export class ButtonProvider extends ToolbarButtonProvider { } activate () { - this.ngbModal.open(SerialModalComponent) + this.injector.get(SerialService).showConnectionSelector() } provide (): ToolbarButton[] { diff --git a/terminus-serial/src/components/serialModal.component.pug b/terminus-serial/src/components/serialModal.component.pug deleted file mode 100644 index 24fe524e..00000000 --- a/terminus-serial/src/components/serialModal.component.pug +++ /dev/null @@ -1,32 +0,0 @@ -.modal-body - input.form-control( - type='text', - [(ngModel)]='quickTarget', - autofocus, - placeholder='Quick connect: path@baudrate', - (ngModelChange)='refresh()', - (keyup.enter)='quickConnect()' - ) - - .list-group.mt-3(*ngIf='lastConnection') - a.list-group-item.list-group-item-action.d-flex.align-items-center((click)='connect(lastConnection)') - i.fas.fa-fw.fa-history - .mr-auto {{lastConnection.name}} - button.btn.btn-outline-danger.btn-sm((click)='clearLastConnection(); $event.stopPropagation()') - i.fas.fa-trash - - .list-group.mt-3.connections-list(*ngIf='connections.length') - a.list-group-item.list-group-item-action.d-flex.align-items-center( - *ngFor='let connection of connections', - (click)='connect(connection)' - ) - .mr-2 {{connection.name}} - .text-muted {{connection.port}} - - .list-group.mt-3(*ngIf='foundPorts.length') - a.list-group-item.list-group-item-action.d-flex.align-items-center( - (click)='connectFoundPort(port)', - *ngFor='let port of foundPorts' - ) - .mr-2 {{port.name}} - .text-muted {{port.description}} diff --git a/terminus-serial/src/components/serialModal.component.scss b/terminus-serial/src/components/serialModal.component.scss deleted file mode 100644 index eae336fa..00000000 --- a/terminus-serial/src/components/serialModal.component.scss +++ /dev/null @@ -1,5 +0,0 @@ -.list-group.connections-list { - display: block; - max-height: 70vh; - overflow-y: auto; -} diff --git a/terminus-serial/src/components/serialModal.component.ts b/terminus-serial/src/components/serialModal.component.ts deleted file mode 100644 index ad46c4b2..00000000 --- a/terminus-serial/src/components/serialModal.component.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { Component, NgZone } from '@angular/core' -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' -import { ToastrService } from 'ngx-toastr' -import { ConfigService, AppService } from 'terminus-core' -import { SettingsTabComponent } from 'terminus-settings' -import { SerialService } from '../services/serial.service' -import { SerialConnection, SerialPortInfo, BAUD_RATES } from '../api' -import { SerialTabComponent } from './serialTab.component' - -/** @hidden */ -@Component({ - template: require('./serialModal.component.pug'), - styles: [require('./serialModal.component.scss')], -}) -export class SerialModalComponent { - connections: SerialConnection[] - quickTarget: string - lastConnection: SerialConnection|null = null - foundPorts: SerialPortInfo[] = [] - - constructor ( - public modalInstance: NgbActiveModal, - private config: ConfigService, - private serial: SerialService, - private app: AppService, - private zone: NgZone, - private toastr: ToastrService, - ) { } - - async ngOnInit () { - this.connections = this.config.store.serial.connections - if (window.localStorage.lastSerialConnection) { - this.lastConnection = JSON.parse(window.localStorage.lastSerialConnection) - } - this.foundPorts = await this.serial.listPorts() - } - - quickConnect () { - let path = this.quickTarget - let baudrate = 115200 - if (this.quickTarget.includes('@')) { - baudrate = parseInt(path.split('@')[1]) - path = path.split('@')[0] - } - const connection: SerialConnection = { - name: this.quickTarget, - port: path, - baudrate: baudrate, - databits: 8, - parity: 'none', - rtscts: false, - stopbits: 1, - xany: false, - xoff: false, - xon: false, - } - window.localStorage.lastSerialConnection = JSON.stringify(connection) - this.connect(connection) - } - - clearLastConnection () { - window.localStorage.lastSerialConnection = null - this.lastConnection = null - } - - async connect (connection: SerialConnection) { - this.close() - - try { - const tab = this.zone.run(() => this.app.openNewTab( - SerialTabComponent, - { connection } - ) as SerialTabComponent) - if (connection.color) { - (this.app.getParentTab(tab) || tab).color = connection.color - } - setTimeout(() => { - this.app.activeTab.emitFocused() - }) - } catch (error) { - this.toastr.error(`Could not connect: ${error}`) - } - } - - manageConnections () { - this.close() - this.app.openNewTab(SettingsTabComponent, { activeTab: 'serial' }) - } - - close () { - this.modalInstance.close() - } - - async connectFoundPort (port: SerialPortInfo) { - const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({ - name: x.toString(), result: x, - }))) - this.quickTarget = `${port.name}@${rate}` - this.quickConnect() - } -} diff --git a/terminus-serial/src/components/serialTab.component.ts b/terminus-serial/src/components/serialTab.component.ts index 105ec98b..6ea7ef6d 100644 --- a/terminus-serial/src/components/serialTab.component.ts +++ b/terminus-serial/src/components/serialTab.component.ts @@ -21,9 +21,9 @@ export class SerialTabComponent extends BaseTerminalTabComponent { serialPort: any private homeEndSubscription: Subscription + // eslint-disable-next-line @typescript-eslint/no-useless-constructor constructor ( injector: Injector, - private serial: SerialService, ) { super(injector) } @@ -62,7 +62,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent { return } - this.session = this.serial.createSession(this.connection) + this.session = this.injector.get(SerialService).createSession(this.connection) this.session.serviceMessage$.subscribe(msg => { this.write('\r\n' + colors.black.bgWhite(' serial ') + ' ' + msg + '\r\n') this.session.resize(this.size.columns, this.size.rows) @@ -80,11 +80,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent { spinner.start() try { - this.serialPort = await this.serial.connectSession(this.session, (message: string) => { - spinner.stop(true) - this.write(message + '\r\n') - spinner.start() - }) + this.serialPort = await this.injector.get(SerialService).connectSession(this.session) spinner.stop(true) } catch (e) { spinner.stop(true) diff --git a/terminus-serial/src/index.ts b/terminus-serial/src/index.ts index c3b68949..0ecba627 100644 --- a/terminus-serial/src/index.ts +++ b/terminus-serial/src/index.ts @@ -8,7 +8,6 @@ import { SettingsTabProvider } from 'terminus-settings' import TerminusTerminalModule from 'terminus-terminal' import { EditConnectionModalComponent } from './components/editConnectionModal.component' -import { SerialModalComponent } from './components/serialModal.component' import { SerialSettingsTabComponent } from './components/serialSettingsTab.component' import { SerialTabComponent } from './components/serialTab.component' @@ -37,13 +36,11 @@ import { SerialHotkeyProvider } from './hotkeys' ], entryComponents: [ EditConnectionModalComponent, - SerialModalComponent, SerialSettingsTabComponent, SerialTabComponent, ], declarations: [ EditConnectionModalComponent, - SerialModalComponent, SerialSettingsTabComponent, SerialTabComponent, ], diff --git a/terminus-serial/src/services/serial.service.ts b/terminus-serial/src/services/serial.service.ts index 1a22258f..f1fb9088 100644 --- a/terminus-serial/src/services/serial.service.ts +++ b/terminus-serial/src/services/serial.service.ts @@ -1,8 +1,10 @@ import { Injectable, NgZone } from '@angular/core' import SerialPort from 'serialport' import { ToastrService } from 'ngx-toastr' -import { LogService } from 'terminus-core' -import { SerialConnection, SerialSession, SerialPortInfo } from '../api' +import { LogService, AppService, SelectorOption, ConfigService } from 'terminus-core' +import { SettingsTabComponent } from 'terminus-settings' +import { SerialConnection, SerialSession, SerialPortInfo, BAUD_RATES } from '../api' +import { SerialTabComponent } from '../components/serialTab.component' @Injectable({ providedIn: 'root' }) export class SerialService { @@ -10,6 +12,8 @@ export class SerialService { private log: LogService, private zone: NgZone, private toastr: ToastrService, + private app: AppService, + private config: ConfigService, ) { } async listPorts (): Promise { @@ -25,7 +29,7 @@ export class SerialService { return session } - async connectSession (session: SerialSession, _?: (s: any) => void): Promise { + async connectSession (session: SerialSession): Promise { const serial = new SerialPort(session.connection.port, { autoOpen: false, baudRate: session.connection.baudrate, dataBits: session.connection.databits, stopBits: session.connection.stopbits, parity: session.connection.parity, rtscts: session.connection.rtscts, xon: session.connection.xon, xoff: session.connection.xoff, @@ -57,4 +61,107 @@ export class SerialService { }) return serial } + + async showConnectionSelector (): Promise { + const options: SelectorOption[] = [] + const lastConnection = JSON.parse(window.localStorage.lastSerialConnection) + const foundPorts = await this.listPorts() + + if (lastConnection) { + options.push({ + name: lastConnection.name, + icon: 'history', + callback: () => this.connect(lastConnection), + }) + options.push({ + name: 'Clear last connection', + icon: 'eraser', + callback: () => { + window.localStorage.lastSerialConnection = null + }, + }) + } + + for (const port of foundPorts) { + options.push({ + name: port.name, + description: port.description, + icon: 'arrow-right', + callback: () => this.connectFoundPort(port), + }) + } + + for (const connection of this.config.store.serial.connections) { + options.push({ + name: connection.name, + description: connection.port, + callback: () => this.connect(connection), + }) + } + + options.push({ + name: 'Manage connections', + icon: 'cog', + callback: () => this.app.openNewTab(SettingsTabComponent, { activeTab: 'serial' }), + }) + + options.push({ + name: 'Quick connect', + freeInputPattern: 'Open device: %s...', + icon: 'arrow-right', + callback: query => this.quickConnect(query), + }) + + + await this.app.showSelector('Open a serial port', options) + } + + async connect (connection: SerialConnection): Promise { + try { + const tab = this.app.openNewTab( + SerialTabComponent, + { connection } + ) as SerialTabComponent + if (connection.color) { + (this.app.getParentTab(tab) || tab).color = connection.color + } + setTimeout(() => { + this.app.activeTab.emitFocused() + }) + return tab + } catch (error) { + this.toastr.error(`Could not connect: ${error}`) + throw error + } + } + + quickConnect (query: string): Promise { + let path = query + let baudrate = 115200 + if (query.includes('@')) { + baudrate = parseInt(path.split('@')[1]) + path = path.split('@')[0] + } + const connection: SerialConnection = { + name: query, + port: path, + baudrate: baudrate, + databits: 8, + parity: 'none', + rtscts: false, + stopbits: 1, + xany: false, + xoff: false, + xon: false, + } + window.localStorage.lastSerialConnection = JSON.stringify(connection) + return this.connect(connection) + } + + async connectFoundPort (port: SerialPortInfo): Promise { + const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({ + name: x.toString(), result: x, + }))) + return this.quickConnect(`${port.name}@${rate}`) + } }