1
1
mirror of https://github.com/Eugeny/tabby.git synced 2025-01-03 08:04:02 +03:00
This commit is contained in:
Eugene Pankov 2017-03-24 23:29:54 +01:00
parent 739750e8f0
commit 384716417a
18 changed files with 148 additions and 40 deletions

View File

@ -1,20 +0,0 @@
export { AppService } from 'services/app'
export { PluginsService } from 'services/plugins'
export { Tab } from 'models/tab'
export interface IPlugin {
}
export interface IToolbarButton {
icon: string
title: string
weight?: number
click: () => void
}
export interface IToolbarButtonProvider {
provide (): IToolbarButton[]
}
export const ToolbarButtonProviderType = 'app:toolbar-button-provider'

6
app/src/api/index.ts Normal file
View File

@ -0,0 +1,6 @@
export { Tab } from './tab'
export { TabRecoveryProviderType, ITabRecoveryProvider } from './tabRecovery'
export { ToolbarButtonProviderType, IToolbarButton, IToolbarButtonProvider } from './toolbarButtonProvider'
export { AppService } from 'services/app'
export { PluginsService } from 'services/plugins'

View File

@ -23,4 +23,8 @@ export class Tab {
getComponentType (): ComponentType<Tab> { getComponentType (): ComponentType<Tab> {
return null return null
} }
getRecoveryToken (): any {
return null
}
} }

View File

@ -0,0 +1,7 @@
import { Tab } from './tab'
export interface ITabRecoveryProvider {
recover (recoveryToken: any): Tab
}
export const TabRecoveryProviderType = 'app:TabRecoveryProviderType'

View File

@ -0,0 +1,12 @@
export interface IToolbarButton {
icon: string
title: string
weight?: number
click: () => void
}
export interface IToolbarButtonProvider {
provide (): IToolbarButton[]
}
export const ToolbarButtonProviderType = 'app:ToolbarButtonProviderType'

View File

@ -123,6 +123,8 @@ export class AppRootComponent {
} }
this.docking.dock() this.docking.dock()
}) })
this.app.restoreTabs()
} }
getToolbarButtons (aboveZero: boolean): IToolbarButton[] { getToolbarButtons (aboveZero: boolean): IToolbarButton[] {

View File

@ -1,4 +1,4 @@
import { Tab } from 'models/tab' import { Tab } from 'api/tab'
export class BaseTabComponent<T extends Tab> { export class BaseTabComponent<T extends Tab> {
protected model: T protected model: T

View File

@ -1,5 +1,5 @@
import { Component, Input, ViewContainerRef, ViewChild, HostBinding, ComponentFactoryResolver, ComponentRef } from '@angular/core' import { Component, Input, ViewContainerRef, ViewChild, HostBinding, ComponentFactoryResolver, ComponentRef } from '@angular/core'
import { Tab } from 'models/tab' import { Tab } from 'api/tab'
import { BaseTabComponent } from 'components/baseTab' import { BaseTabComponent } from 'components/baseTab'
@Component({ @Component({

View File

@ -1,5 +1,5 @@
import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/core' import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/core'
import { Tab } from 'models/tab' import { Tab } from 'api/tab'
import './tabHeader.scss' import './tabHeader.scss'

View File

@ -1,5 +1,8 @@
import { EventEmitter, Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Tab } from 'models/tab' import { Logger, LogService } from 'services/log'
import { Tab } from 'api/tab'
import { PluginsService } from 'services/plugins'
import { ITabRecoveryProvider, TabRecoveryProviderType } from 'api/tabRecovery'
@Injectable() @Injectable()
@ -7,14 +10,19 @@ export class AppService {
tabs: Tab[] = [] tabs: Tab[] = []
activeTab: Tab activeTab: Tab
lastTabIndex = 0 lastTabIndex = 0
logger: Logger
constructor () { constructor (
private plugins: PluginsService,
log: LogService,
) {
this.logger = log.create('app')
} }
openTab (tab: Tab): void { openTab (tab: Tab): void {
this.tabs.push(tab) this.tabs.push(tab)
this.selectTab(tab) this.selectTab(tab)
this.saveTabs()
} }
selectTab (tab) { selectTab (tab) {
@ -62,5 +70,33 @@ export class AppService {
if (tab == this.activeTab) { if (tab == this.activeTab) {
this.selectTab(this.tabs[newIndex]) this.selectTab(this.tabs[newIndex])
} }
this.saveTabs()
}
saveTabs () {
window.localStorage.tabsRecovery = JSON.stringify(
this.tabs
.map((tab) => tab.getRecoveryToken())
.filter((token) => !!token)
)
}
restoreTabs () {
if (window.localStorage.tabsRecovery) {
let providers = this.plugins.getAll<ITabRecoveryProvider>(TabRecoveryProviderType)
JSON.parse(window.localStorage.tabsRecovery).forEach((token) => {
for (let provider of providers) {
try {
let tab = provider.recover(token)
if (tab) {
this.openTab(tab)
return
}
} catch (_) { }
this.logger.warn('Cannot restore tab from the token:', token)
}
})
this.saveTabs()
}
} }
} }

View File

@ -7,8 +7,7 @@ export class Logger {
) {} ) {}
log (level: string, ...args: any[]) { log (level: string, ...args: any[]) {
args.splice(0, 0, this.name + ':') console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
console[level](...args)
} }
debug(...args: any[]) { this.log('debug', ...args) } debug(...args: any[]) { this.log('debug', ...args) }

View File

@ -1,9 +1,8 @@
import { IPlugin } from 'api'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
interface IPluginEntry { interface IPluginEntry {
plugin: IPlugin plugin: any
weight: number weight: number
} }
@ -15,14 +14,14 @@ export class PluginsService {
) { ) {
} }
register (type: string, plugin: IPlugin, weight = 0): void { register (type: string, plugin: any, weight = 0): void {
if (!this.plugins[type]) { if (!this.plugins[type]) {
this.plugins[type] = [] this.plugins[type] = []
} }
this.plugins[type].push({ plugin, weight }) this.plugins[type].push({ plugin, weight })
} }
getAll<T extends IPlugin> (type: string): T[] { getAll<T> (type: string): T[] {
let plugins = this.plugins[type] || [] let plugins = this.plugins[type] || []
plugins = plugins.sort((a: IPluginEntry, b: IPluginEntry) => { plugins = plugins.sort((a: IPluginEntry, b: IPluginEntry) => {
if (a.weight < b.weight) { if (a.weight < b.weight) {

View File

@ -9,9 +9,10 @@ import { HotkeyHintComponent } from './components/hotkeyHint'
import { HotkeyInputModalComponent } from './components/hotkeyInputModal' import { HotkeyInputModalComponent } from './components/hotkeyInputModal'
import { SettingsPaneComponent } from './components/settingsPane' import { SettingsPaneComponent } from './components/settingsPane'
import { PluginsService, ToolbarButtonProviderType } from 'api' import { PluginsService, ToolbarButtonProviderType, TabRecoveryProviderType } from 'api'
import { ButtonProvider } from './buttonProvider' import { ButtonProvider } from './buttonProvider'
import { RecoveryProvider } from './recoveryProvider'
@NgModule({ @NgModule({
@ -22,6 +23,7 @@ import { ButtonProvider } from './buttonProvider'
], ],
providers: [ providers: [
ButtonProvider, ButtonProvider,
RecoveryProvider,
], ],
entryComponents: [ entryComponents: [
HotkeyInputModalComponent, HotkeyInputModalComponent,
@ -36,8 +38,13 @@ import { ButtonProvider } from './buttonProvider'
], ],
}) })
class SettingsModule { class SettingsModule {
constructor (plugins: PluginsService, buttonProvider: ButtonProvider) { constructor (
plugins: PluginsService,
buttonProvider: ButtonProvider,
recoveryProvider: RecoveryProvider,
) {
plugins.register(ToolbarButtonProviderType, buttonProvider, 1) plugins.register(ToolbarButtonProviderType, buttonProvider, 1)
plugins.register(TabRecoveryProviderType, recoveryProvider)
} }
} }

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core'
import { Tab, ITabRecoveryProvider } from 'api'
import { SettingsTab } from './tab'
@Injectable()
export class RecoveryProvider implements ITabRecoveryProvider {
recover (recoveryToken: any): Tab {
if (recoveryToken.type == 'app:settings') {
return new SettingsTab()
}
return null
}
}

View File

@ -1,4 +1,4 @@
import { Tab, ComponentType } from '../models/tab' import { Tab, ComponentType } from 'api/tab'
import { SettingsPaneComponent } from './components/settingsPane' import { SettingsPaneComponent } from './components/settingsPane'
export class SettingsTab extends Tab { export class SettingsTab extends Tab {
@ -11,4 +11,10 @@ export class SettingsTab extends Tab {
getComponentType (): ComponentType<SettingsTab> { getComponentType (): ComponentType<SettingsTab> {
return SettingsPaneComponent return SettingsPaneComponent
} }
getRecoveryToken (): any {
return {
type: 'app:settings',
}
}
} }

View File

@ -2,11 +2,12 @@ import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { PluginsService, ToolbarButtonProviderType } from 'api' import { PluginsService, ToolbarButtonProviderType, TabRecoveryProviderType } from 'api'
import { TerminalTabComponent } from './components/terminalTab' import { TerminalTabComponent } from './components/terminalTab'
import { SessionsService } from './services/sessions' import { SessionsService } from './services/sessions'
import { ButtonProvider } from './buttonProvider' import { ButtonProvider } from './buttonProvider'
import { RecoveryProvider } from './recoveryProvider'
@NgModule({ @NgModule({
@ -17,6 +18,7 @@ import { ButtonProvider } from './buttonProvider'
providers: [ providers: [
ButtonProvider, ButtonProvider,
SessionsService, SessionsService,
RecoveryProvider,
], ],
entryComponents: [ entryComponents: [
TerminalTabComponent, TerminalTabComponent,
@ -26,8 +28,13 @@ import { ButtonProvider } from './buttonProvider'
], ],
}) })
class TerminalModule { class TerminalModule {
constructor (plugins: PluginsService, buttonProvider: ButtonProvider) { constructor (
plugins: PluginsService,
buttonProvider: ButtonProvider,
recoveryProvider: RecoveryProvider,
) {
plugins.register(ToolbarButtonProviderType, buttonProvider) plugins.register(ToolbarButtonProviderType, buttonProvider)
plugins.register(TabRecoveryProviderType, recoveryProvider)
} }
} }

View File

@ -0,0 +1,20 @@
import { Injectable } from '@angular/core'
import { Tab, ITabRecoveryProvider } from 'api'
import { TerminalTab } from './tab'
import { SessionsService } from './services/sessions'
@Injectable()
export class RecoveryProvider implements ITabRecoveryProvider {
constructor (private sessions: SessionsService) { }
recover (recoveryToken: any): Tab {
if (recoveryToken.type == 'app:terminal') {
const options = this.sessions.recoveryProvider.getRecoverySession(recoveryToken.recoveryId)
let session = this.sessions.createSession(options)
session.recoveryId = recoveryToken.recoveryId
return new TerminalTab(session)
}
return null
}
}

View File

@ -1,9 +1,11 @@
import { Tab, ComponentType } from '../models/tab' import { Tab, ComponentType } from 'api/tab'
import { TerminalTabComponent } from './components/terminalTab' import { TerminalTabComponent } from './components/terminalTab'
import { Session } from './services/sessions' import { Session } from './services/sessions'
export class TerminalTab extends Tab { export class TerminalTab extends Tab {
static recoveryId = 'app:terminal'
constructor (public session: Session) { constructor (public session: Session) {
super() super()
} }
@ -11,4 +13,11 @@ export class TerminalTab extends Tab {
getComponentType (): ComponentType<TerminalTab> { getComponentType (): ComponentType<TerminalTab> {
return TerminalTabComponent return TerminalTabComponent
} }
getRecoveryToken (): any {
return {
type: 'app:terminal',
recoveryId: this.session.recoveryId,
}
}
} }