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> {
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.app.restoreTabs()
}
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> {
protected model: T

View file

@ -1,5 +1,5 @@
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'
@Component({

View file

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

View file

@ -1,5 +1,8 @@
import { EventEmitter, Injectable } from '@angular/core'
import { Tab } from 'models/tab'
import { Injectable } from '@angular/core'
import { Logger, LogService } from 'services/log'
import { Tab } from 'api/tab'
import { PluginsService } from 'services/plugins'
import { ITabRecoveryProvider, TabRecoveryProviderType } from 'api/tabRecovery'
@Injectable()
@ -7,14 +10,19 @@ export class AppService {
tabs: Tab[] = []
activeTab: Tab
lastTabIndex = 0
logger: Logger
constructor () {
constructor (
private plugins: PluginsService,
log: LogService,
) {
this.logger = log.create('app')
}
openTab (tab: Tab): void {
this.tabs.push(tab)
this.selectTab(tab)
this.saveTabs()
}
selectTab (tab) {
@ -62,5 +70,33 @@ export class AppService {
if (tab == this.activeTab) {
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

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

View file

@ -1,9 +1,8 @@
import { IPlugin } from 'api'
import { Injectable } from '@angular/core'
interface IPluginEntry {
plugin: IPlugin
plugin: any
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]) {
this.plugins[type] = []
}
this.plugins[type].push({ plugin, weight })
}
getAll<T extends IPlugin> (type: string): T[] {
getAll<T> (type: string): T[] {
let plugins = this.plugins[type] || []
plugins = plugins.sort((a: IPluginEntry, b: IPluginEntry) => {
if (a.weight < b.weight) {

View file

@ -9,9 +9,10 @@ import { HotkeyHintComponent } from './components/hotkeyHint'
import { HotkeyInputModalComponent } from './components/hotkeyInputModal'
import { SettingsPaneComponent } from './components/settingsPane'
import { PluginsService, ToolbarButtonProviderType } from 'api'
import { PluginsService, ToolbarButtonProviderType, TabRecoveryProviderType } from 'api'
import { ButtonProvider } from './buttonProvider'
import { RecoveryProvider } from './recoveryProvider'
@NgModule({
@ -22,6 +23,7 @@ import { ButtonProvider } from './buttonProvider'
],
providers: [
ButtonProvider,
RecoveryProvider,
],
entryComponents: [
HotkeyInputModalComponent,
@ -36,8 +38,13 @@ import { ButtonProvider } from './buttonProvider'
],
})
class SettingsModule {
constructor (plugins: PluginsService, buttonProvider: ButtonProvider) {
constructor (
plugins: PluginsService,
buttonProvider: ButtonProvider,
recoveryProvider: RecoveryProvider,
) {
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'
export class SettingsTab extends Tab {
@ -11,4 +11,10 @@ export class SettingsTab extends Tab {
getComponentType (): ComponentType<SettingsTab> {
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 { FormsModule } from '@angular/forms'
import { PluginsService, ToolbarButtonProviderType } from 'api'
import { PluginsService, ToolbarButtonProviderType, TabRecoveryProviderType } from 'api'
import { TerminalTabComponent } from './components/terminalTab'
import { SessionsService } from './services/sessions'
import { ButtonProvider } from './buttonProvider'
import { RecoveryProvider } from './recoveryProvider'
@NgModule({
@ -17,6 +18,7 @@ import { ButtonProvider } from './buttonProvider'
providers: [
ButtonProvider,
SessionsService,
RecoveryProvider,
],
entryComponents: [
TerminalTabComponent,
@ -26,8 +28,13 @@ import { ButtonProvider } from './buttonProvider'
],
})
class TerminalModule {
constructor (plugins: PluginsService, buttonProvider: ButtonProvider) {
constructor (
plugins: PluginsService,
buttonProvider: ButtonProvider,
recoveryProvider: RecoveryProvider,
) {
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 { Session } from './services/sessions'
export class TerminalTab extends Tab {
static recoveryId = 'app:terminal'
constructor (public session: Session) {
super()
}
@ -11,4 +13,11 @@ export class TerminalTab extends Tab {
getComponentType (): ComponentType<TerminalTab> {
return TerminalTabComponent
}
getRecoveryToken (): any {
return {
type: 'app:terminal',
recoveryId: this.session.recoveryId,
}
}
}