mirror of
https://github.com/Eugeny/tabby.git
synced 2025-01-18 14:04:17 +08:00
.
This commit is contained in:
parent
4e451d0598
commit
d7bae654eb
19
app/main.js
19
app/main.js
@ -13,7 +13,7 @@ setupWindowManagement = () => {
|
||||
app.window.on('close', (e) => {
|
||||
windowConfig.set('windowBoundaries', app.window.getBounds())
|
||||
if (!windowCloseable) {
|
||||
app.window.hide()
|
||||
app.window.minimize()
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
@ -31,6 +31,18 @@ setupWindowManagement = () => {
|
||||
app.window.focus()
|
||||
})
|
||||
|
||||
electron.ipcMain.on('window-maximize', () => {
|
||||
if (app.window.isMaximized()) {
|
||||
app.window.unmaximize()
|
||||
} else {
|
||||
app.window.maximize()
|
||||
}
|
||||
})
|
||||
|
||||
electron.ipcMain.on('window-minimize', () => {
|
||||
app.window.minimize()
|
||||
})
|
||||
|
||||
app.on('before-quit', () => windowCloseable = true)
|
||||
}
|
||||
|
||||
@ -82,16 +94,15 @@ start = () => {
|
||||
'web-preferences': {'web-security': false},
|
||||
//- background to avoid the flash of unstyled window
|
||||
backgroundColor: '#1D272D',
|
||||
frame: false,
|
||||
}
|
||||
Object.assign(options, windowConfig.get('windowBoundaries'))
|
||||
|
||||
if (platform == 'darwin') {
|
||||
options.titleBarStyle = 'hidden'
|
||||
} else {
|
||||
options.frame = false
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch('--disable-http-cache')
|
||||
app.commandLine.appendSwitch('disable-http-cache')
|
||||
|
||||
app.window = new electron.BrowserWindow(options)
|
||||
app.window.loadURL(`file://${app.getAppPath()}/assets/webpack/index.html`, {extraHeaders: "pragma: no-cache\n"})
|
||||
|
@ -3,7 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"main": "main.js",
|
||||
"dependencies": {
|
||||
"child-process-promise": "^2.1.3",
|
||||
"child-process-promise": "^2.2.0",
|
||||
"devtron": "^1.4.0",
|
||||
"electron-config": "^0.2.1",
|
||||
"electron-debug": "^1.0.1",
|
||||
|
@ -9,6 +9,7 @@ import { ConfigService } from 'services/config'
|
||||
import { ElectronService } from 'services/electron'
|
||||
import { HostAppService } from 'services/hostApp'
|
||||
import { LogService } from 'services/log'
|
||||
import { HotkeysService } from 'services/hotkeys'
|
||||
import { ModalService } from 'services/modal'
|
||||
import { NotifyService } from 'services/notify'
|
||||
import { QuitterService } from 'services/quitter'
|
||||
@ -33,6 +34,7 @@ import { TerminalComponent } from 'components/terminal'
|
||||
ConfigService,
|
||||
ElectronService,
|
||||
HostAppService,
|
||||
HotkeysService,
|
||||
LogService,
|
||||
ModalService,
|
||||
NotifyService,
|
||||
|
@ -3,20 +3,65 @@
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
width: ~"calc(100vw - 2px)";
|
||||
height: ~"calc(100vh - 2px)";
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
-webkit-user-select: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
cursor: default;
|
||||
background: @body-bg;
|
||||
}
|
||||
|
||||
@titlebar-height: 35px;
|
||||
@tabs-height: 40px;
|
||||
@tab-border-radius: 3px;
|
||||
|
||||
.button-states() {
|
||||
transition: 0.125s all;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background: rgba(255, 255, 255, .033);
|
||||
}
|
||||
|
||||
&:active:not(.active) {
|
||||
background: rgba(0, 0, 0, .1);
|
||||
}
|
||||
}
|
||||
|
||||
.titlebar {
|
||||
height: @titlebar-height;
|
||||
background: #141c23;
|
||||
flex: none;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.title {
|
||||
flex: auto;
|
||||
padding-left: 15px;
|
||||
line-height: @titlebar-height;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.btn-minimize, .btn-maximize, .btn-close {
|
||||
flex: none;
|
||||
line-height: @titlebar-height - 2px;
|
||||
padding: 0 15px;
|
||||
font-size: 8px;
|
||||
|
||||
.button-states();
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
flex: none;
|
||||
height: @tabs-height;
|
||||
background: #141c23;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -41,13 +86,7 @@
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, .1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(0, 0, 0, .1);
|
||||
}
|
||||
.button-states();
|
||||
}
|
||||
|
||||
.tab {
|
||||
@ -55,24 +94,41 @@
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
|
||||
background: @body-bg;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
|
||||
div {
|
||||
&.pre-selected, &:nth-last-child(2) {
|
||||
border-top-right-radius: @tab-border-radius;
|
||||
}
|
||||
|
||||
&.post-selected {
|
||||
border-top-left-radius: @tab-border-radius;
|
||||
}
|
||||
|
||||
div.index {
|
||||
flex: none;
|
||||
padding: 0 0 0 15px;
|
||||
font-weight: bold;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
div.name {
|
||||
flex: auto;
|
||||
padding: 0 15px;
|
||||
margin: 0 15px 0 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: 0.25s all;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background: rgba(255, 255, 255, .05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(0, 0, 0, .1);
|
||||
}
|
||||
.button-states();
|
||||
|
||||
&.active {
|
||||
background: #141c23;
|
||||
|
@ -1,6 +1,22 @@
|
||||
.titlebar
|
||||
.title((dblclick)='hostApp.maximizeWindow()') Term
|
||||
.btn-minimize((click)='hostApp.minimizeWindow()')
|
||||
i.fa.fa-window-minimize
|
||||
.btn-maximize((click)='hostApp.maximizeWindow()')
|
||||
i.fa.fa-window-maximize
|
||||
.btn-close((click)='hostApp.quit()')
|
||||
i.fa.fa-close
|
||||
|
||||
.tabs
|
||||
.tab(*ngFor='let tab of tabs; trackBy: tab?.id', (click)='selectTab(tab)', [class.active]='tab == activeTab')
|
||||
div {{tab.name}}
|
||||
.tab(
|
||||
*ngFor='let tab of tabs; let idx = index; trackBy: tab?.id',
|
||||
(click)='selectTab(tab)',
|
||||
[class.active]='tab == activeTab',
|
||||
[class.pre-selected]='tabs[idx + 1] == activeTab',
|
||||
[class.post-selected]='tabs[idx - 1] == activeTab',
|
||||
)
|
||||
div.index {{idx + 1}}
|
||||
div.name {{tab.name || 'Terminal'}}
|
||||
button((click)='closeTab(tab)') ×
|
||||
.btn-new-tab((click)='newTab()')
|
||||
i.fa.fa-plus
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { Component, ElementRef } from '@angular/core'
|
||||
import { ModalService } from 'services/modal'
|
||||
import { ElectronService } from 'services/electron'
|
||||
import { HostAppService } from 'services/hostApp'
|
||||
import { HotkeysService } from 'services/hotkeys'
|
||||
import { LogService } from 'services/log'
|
||||
import { QuitterService } from 'services/quitter'
|
||||
import { ToasterConfig } from 'angular2-toaster'
|
||||
@ -31,11 +32,13 @@ class Tab {
|
||||
})
|
||||
export class AppComponent {
|
||||
constructor(
|
||||
private hostApp: HostAppService,
|
||||
private modal: ModalService,
|
||||
private electron: ElectronService,
|
||||
private elementRef: ElementRef,
|
||||
private sessions: SessionsService,
|
||||
public hostApp: HostAppService,
|
||||
public hotkeys: HotkeysService,
|
||||
log: LogService,
|
||||
electron: ElectronService,
|
||||
_quitter: QuitterService,
|
||||
) {
|
||||
console.timeStamp('AppComponent ctor')
|
||||
@ -48,6 +51,22 @@ export class AppComponent {
|
||||
preventDuplicates: true,
|
||||
timeout: 4000,
|
||||
})
|
||||
|
||||
this.hotkeys.key.subscribe((key) => {
|
||||
if (key.event == 'keydown') {
|
||||
if (key.alt && key.key >= '1' && key.key <= '9') {
|
||||
let index = key.key.charCodeAt(0) - '0'.charCodeAt(0) - 1
|
||||
if (index < this.tabs.length) {
|
||||
this.selectTab(this.tabs[index])
|
||||
}
|
||||
}
|
||||
if (key.alt && key.key == '0') {
|
||||
if (this.tabs.length >= 10) {
|
||||
this.selectTab(this.tabs[9])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
toasterConfig: ToasterConfig
|
||||
@ -55,23 +74,40 @@ export class AppComponent {
|
||||
activeTab: Tab
|
||||
|
||||
newTab () {
|
||||
const tab = new Tab(this.sessions.createSession({command: 'bash'}))
|
||||
this.addSessionTab(this.sessions.createNewSession({command: 'bash'}))
|
||||
}
|
||||
|
||||
addSessionTab (session) {
|
||||
let tab = new Tab(session)
|
||||
this.tabs.push(tab)
|
||||
this.selectTab(tab)
|
||||
}
|
||||
|
||||
selectTab (tab) {
|
||||
this.activeTab = tab
|
||||
setImmediate(() => {
|
||||
this.elementRef.nativeElement.querySelector(':scope .tab.active iframe').focus()
|
||||
})
|
||||
}
|
||||
|
||||
closeTab (tab) {
|
||||
tab.session.destroy()
|
||||
tab.session.gracefullyDestroy()
|
||||
this.tabs = this.tabs.filter((x) => x != tab)
|
||||
this.selectTab(this.tabs[0])
|
||||
if (tab == this.activeTab) {
|
||||
this.selectTab(this.tabs[0])
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.newTab()
|
||||
this.sessions.recoverAll().then((recoveredSessions) => {
|
||||
if (recoveredSessions.length > 0) {
|
||||
recoveredSessions.forEach((session) => {
|
||||
this.addSessionTab(session)
|
||||
})
|
||||
} else {
|
||||
this.newTab()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
|
@ -2,11 +2,8 @@ import { Component } from '@angular/core'
|
||||
import { ElectronService } from 'services/electron'
|
||||
import { HostAppService, PLATFORM_WINDOWS, PLATFORM_LINUX, PLATFORM_MAC } from 'services/hostApp'
|
||||
import { ConfigService } from 'services/config'
|
||||
import { QuitterService } from 'services/quitter'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
import * as os from 'os'
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'settings-modal',
|
||||
@ -16,10 +13,9 @@ import * as os from 'os'
|
||||
export class SettingsModalComponent {
|
||||
constructor(
|
||||
private modalInstance: NgbActiveModal,
|
||||
private hostApp: HostAppService,
|
||||
private electron: ElectronService,
|
||||
private quitter: QuitterService,
|
||||
public config: ConfigService,
|
||||
hostApp: HostAppService,
|
||||
electron: ElectronService,
|
||||
) {
|
||||
this.isWindows = hostApp.platform == PLATFORM_WINDOWS
|
||||
this.isMac = hostApp.platform == PLATFORM_MAC
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Component, NgZone, Input, Output, EventEmitter, ElementRef } from '@angular/core'
|
||||
import { ElectronService } from 'services/electron'
|
||||
import { ConfigService } from 'services/config'
|
||||
|
||||
import { Session } from 'services/sessions'
|
||||
@ -10,16 +9,25 @@ const hterm = require('hterm-commonjs')
|
||||
hterm.hterm.VT.ESC['k'] = function(parseState) {
|
||||
parseState.resetArguments();
|
||||
|
||||
function parseOSC(parseState) {
|
||||
if (!this.parseUntilStringTerminator_(parseState) || parseState.func == parseOSC) {
|
||||
function parseOSC(ps) {
|
||||
if (!this.parseUntilStringTerminator_(ps) || ps.func == parseOSC) {
|
||||
return
|
||||
}
|
||||
|
||||
this.terminal.setWindowTitle(parseState.args[0])
|
||||
this.terminal.setWindowTitle(ps.args[0])
|
||||
}
|
||||
parseState.func = parseOSC
|
||||
}
|
||||
|
||||
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
|
||||
hterm.hterm.PreferenceManager.defaultPreferences['user-css'] = ``
|
||||
const oldDecorate = hterm.hterm.ScrollPort.prototype.decorate
|
||||
hterm.hterm.ScrollPort.prototype.decorate = function (...args) {
|
||||
oldDecorate.bind(this)(...args)
|
||||
this.screen_.style.cssText += `; padding-right: ${this.screen_.offsetWidth - this.screen_.clientWidth}px;`
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'terminal',
|
||||
template: '',
|
||||
@ -33,7 +41,6 @@ export class TerminalComponent {
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private electron: ElectronService,
|
||||
private elementRef: ElementRef,
|
||||
public config: ConfigService,
|
||||
) {
|
||||
@ -41,7 +48,6 @@ export class TerminalComponent {
|
||||
|
||||
ngOnInit () {
|
||||
let io
|
||||
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
|
||||
this.terminal = new hterm.hterm.Terminal()
|
||||
this.terminal.setWindowTitle = (title) => {
|
||||
this.zone.run(() => {
|
||||
@ -72,5 +78,6 @@ export class TerminalComponent {
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ if (nodeRequire('electron-is-dev')) {
|
||||
}
|
||||
|
||||
console.timeStamp('angular bootstrap started')
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
||||
|
||||
process.emitWarning = function () { console.log(arguments) }
|
||||
(<any>process).emitWarning = function () { console.log(arguments) }
|
||||
|
@ -62,7 +62,15 @@ export class HostAppService {
|
||||
this.electron.ipcRenderer.send('window-focus')
|
||||
}
|
||||
|
||||
quit() {
|
||||
minimizeWindow () {
|
||||
this.electron.ipcRenderer.send('window-minimize')
|
||||
}
|
||||
|
||||
maximizeWindow () {
|
||||
this.electron.ipcRenderer.send('window-maximize')
|
||||
}
|
||||
|
||||
quit () {
|
||||
this.logger.info('Quitting')
|
||||
this.electron.app.quit()
|
||||
}
|
||||
|
60
app/src/services/hotkeys.ts
Normal file
60
app/src/services/hotkeys.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
||||
const hterm = require('hterm-commonjs')
|
||||
|
||||
|
||||
export interface Key {
|
||||
event: string,
|
||||
alt: boolean,
|
||||
ctrl: boolean,
|
||||
cmd: boolean,
|
||||
shift: boolean,
|
||||
key: string
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HotkeysService {
|
||||
key = new EventEmitter<Key>()
|
||||
|
||||
constructor(private zone: NgZone) {
|
||||
let events = [
|
||||
{
|
||||
name: 'keydown',
|
||||
htermHandler: 'onKeyDown_',
|
||||
},
|
||||
{
|
||||
name: 'keypress',
|
||||
htermHandler: 'onKeyPress_',
|
||||
},
|
||||
{
|
||||
name: 'keyup',
|
||||
htermHandler: 'onKeyUp_',
|
||||
},
|
||||
]
|
||||
events.forEach((event) => {
|
||||
document.addEventListener(event.name, (nativeEvent) => {
|
||||
this.emitNativeEvent(event.name, nativeEvent)
|
||||
})
|
||||
|
||||
let oldHandler = hterm.hterm.Keyboard.prototype[event.htermHandler]
|
||||
const __this = this
|
||||
hterm.hterm.Keyboard.prototype[event.htermHandler] = function (nativeEvent) {
|
||||
__this.emitNativeEvent(event.name, nativeEvent)
|
||||
oldHandler.bind(this)(nativeEvent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
emitNativeEvent (name, nativeEvent) {
|
||||
console.debug('Key', nativeEvent)
|
||||
this.zone.run(() => {
|
||||
this.key.emit({
|
||||
event: name,
|
||||
alt: nativeEvent.altKey,
|
||||
shift: nativeEvent.shiftKey,
|
||||
cmd: nativeEvent.metaKey,
|
||||
ctrl: nativeEvent.ctrlKey,
|
||||
key: nativeEvent.key,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
import { Injectable, NgZone } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class ModalService {
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private ngbModal: NgbModal,
|
||||
) {}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ToasterService } from 'angular2-toaster'
|
||||
import { LogService } from 'services/log'
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class NotifyService {
|
||||
constructor(
|
||||
private toaster: ToasterService,
|
||||
private log: LogService,
|
||||
) {}
|
||||
|
||||
pop(options) {
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService } from 'services/hostApp'
|
||||
import { ElectronService } from 'services/electron'
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class QuitterService {
|
||||
constructor(
|
||||
private electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
hostApp.quitRequested.subscribe(() => {
|
||||
|
@ -1,8 +1,52 @@
|
||||
import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
||||
import { Logger, LogService } from 'services/log'
|
||||
const exec = require('child-process-promise').exec
|
||||
import * as crypto from 'crypto'
|
||||
import * as ptyjs from 'pty.js'
|
||||
|
||||
|
||||
export interface SessionRecoveryProvider {
|
||||
list(): Promise<any[]>
|
||||
getRecoveryCommand(item: any): string
|
||||
getNewSessionCommand(command: string): string
|
||||
}
|
||||
|
||||
export class NullSessionRecoveryProvider implements SessionRecoveryProvider {
|
||||
list(): Promise<any[]> {
|
||||
return Promise.resolve([])
|
||||
}
|
||||
|
||||
getRecoveryCommand(_: any): string {
|
||||
return null
|
||||
}
|
||||
|
||||
getNewSessionCommand(command: string) {
|
||||
return command
|
||||
}
|
||||
}
|
||||
|
||||
export class ScreenSessionRecoveryProvider implements SessionRecoveryProvider {
|
||||
list(): Promise<any[]> {
|
||||
return exec('screen -ls').then((result) => {
|
||||
return result.stdout.split('\n')
|
||||
.filter((line) => /\bterm-tab-/.exec(line))
|
||||
.map((line) => line.trim().split('.')[0])
|
||||
}).catch(() => {
|
||||
return []
|
||||
})
|
||||
}
|
||||
|
||||
getRecoveryCommand(item: any): string {
|
||||
return `screen -r ${item}`
|
||||
}
|
||||
|
||||
getNewSessionCommand(command: string): string {
|
||||
const id = crypto.randomBytes(8).toString('hex')
|
||||
return `screen -U -S term-tab-${id} -- ${command}`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface SessionOptions {
|
||||
name?: string,
|
||||
command: string,
|
||||
@ -20,9 +64,10 @@ export class Session {
|
||||
|
||||
constructor (options: SessionOptions) {
|
||||
this.name = options.name
|
||||
console.log('Spawning', options.command)
|
||||
this.pty = ptyjs.spawn('sh', ['-c', options.command], {
|
||||
name: 'xterm-color',
|
||||
//name: 'screen-256color',
|
||||
//name: 'xterm-color',
|
||||
name: 'xterm-256color',
|
||||
cols: 80,
|
||||
rows: 30,
|
||||
cwd: options.cwd || process.env.HOME,
|
||||
@ -62,7 +107,7 @@ export class Session {
|
||||
gracefullyDestroy () {
|
||||
return new Promise((resolve) => {
|
||||
this.sendSignal('SIGTERM')
|
||||
if (!open) {
|
||||
if (!this.open) {
|
||||
resolve()
|
||||
this.destroy()
|
||||
} else {
|
||||
@ -91,11 +136,20 @@ export class SessionsService {
|
||||
sessions: {[id: string]: Session} = {}
|
||||
logger: Logger
|
||||
private lastID = 0
|
||||
recoveryProvider: SessionRecoveryProvider
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
log: LogService,
|
||||
) {
|
||||
this.logger = log.create('sessions')
|
||||
this.recoveryProvider = new ScreenSessionRecoveryProvider()
|
||||
//this.recoveryProvider = new NullSessionRecoveryProvider()
|
||||
}
|
||||
|
||||
createNewSession (options: SessionOptions) : Session {
|
||||
options.command = this.recoveryProvider.getNewSessionCommand(options.command)
|
||||
return this.createSession(options)
|
||||
}
|
||||
|
||||
createSession (options: SessionOptions) : Session {
|
||||
@ -109,4 +163,15 @@ export class SessionsService {
|
||||
this.sessions[session.name] = session
|
||||
return session
|
||||
}
|
||||
|
||||
recoverAll () : Promise<Session[]> {
|
||||
return <Promise<Session[]>>(this.recoveryProvider.list().then((items) => {
|
||||
return this.zone.run(() => {
|
||||
return items.map((item) => {
|
||||
const command = this.recoveryProvider.getRecoveryCommand(item)
|
||||
return this.createSession({command})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
"raw-loader": "^0.5.1",
|
||||
"style-loader": "^0.13.1",
|
||||
"to-string-loader": "^1.1.5",
|
||||
"tslint": "4.0.2",
|
||||
"tslint": "4.2.0",
|
||||
"typescript": "2.1.1",
|
||||
"typings": "2.0.0",
|
||||
"url-loader": "^0.5.7",
|
||||
|
@ -11,17 +11,20 @@
|
||||
"sourceMap": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedParameters": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"compileOnSave": false,
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"platforms",
|
||||
"platforms"
|
||||
],
|
||||
"files": [
|
||||
"app/src/app.d.ts",
|
||||
"app/src/entry.ts",
|
||||
"typings/index.d.ts",
|
||||
"filesGlob" : [
|
||||
"app/src/*.ts",
|
||||
"app/src/**/*.ts",
|
||||
"!node_modules/**",
|
||||
"!app/node_modules/**",
|
||||
"node_modules/rxjs/Rx.d.ts"
|
||||
]
|
||||
}
|
||||
|
@ -5,16 +5,13 @@
|
||||
"semicolon": false,
|
||||
"no-inferrable-types": [true, "ignore-params"],
|
||||
"curly": true,
|
||||
"no-duplicate-key": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": true,
|
||||
"no-eval": true,
|
||||
"no-invalid-this": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-unreachable": true,
|
||||
"no-unused-expression": true,
|
||||
"no-unused-new": true,
|
||||
"no-unused-variable": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"new-parens": true
|
||||
|
@ -67,16 +67,19 @@ module.exports = {
|
||||
]
|
||||
},
|
||||
externals: {
|
||||
'electron': 'require("electron")',
|
||||
'fs': 'require("fs")',
|
||||
'buffer': 'require("buffer")',
|
||||
'system': '{}',
|
||||
'file': '{}',
|
||||
|
||||
'net': 'require("net")',
|
||||
'electron': 'require("electron")',
|
||||
'remote': 'require("remote")',
|
||||
'shell': 'require("shell")',
|
||||
'ipc': 'require("ipc")',
|
||||
'fs': 'require("fs")',
|
||||
'buffer': 'require("buffer")',
|
||||
'crypto': 'require("crypto")',
|
||||
'pty.js': 'require("pty.js")',
|
||||
'system': '{}',
|
||||
'file': '{}'
|
||||
'child-process-promise': 'require("child-process-promise")',
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
|
Loading…
Reference in New Issue
Block a user