Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat#5688: Save As Profile option available for all tabs #8663

Merged
merged 9 commits into from
Jul 11, 2023
12 changes: 11 additions & 1 deletion tabby-core/src/services/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ export class ConfigService {
* Reads config YAML as string
*/
readRaw (): string {
return yaml.dump(this._store)
// Scrub undefined values
const cleanStore = JSON.parse(JSON.stringify(this._store))
return yaml.dump(cleanStore)
}

/**
Expand Down Expand Up @@ -351,6 +353,14 @@ export class ConfigService {
delete window.localStorage.lastSerialConnection
config.version = 3
}
if (config.version < 4) {
for (const p of config.profiles ?? []) {
if (!p.id) {
p.id = `${p.type}:custom:${uuidv4()}`
}
}
config.version = 4
}
}

private async maybeDecryptConfig (store) {
Expand Down
3 changes: 1 addition & 2 deletions tabby-local/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { RecoveryProvider } from './recoveryProvider'
import { ShellSettingsTabProvider } from './settings'
import { TerminalConfigProvider } from './config'
import { LocalTerminalHotkeyProvider } from './hotkeys'
import { NewTabContextMenu, SaveAsProfileContextMenu } from './tabContextMenu'
import { NewTabContextMenu } from './tabContextMenu'

import { AutoOpenTabCLIHandler, OpenPathCLIHandler, TerminalCLIHandler } from './cli'
import { LocalProfilesService } from './profiles'
Expand All @@ -47,7 +47,6 @@ import { LocalProfilesService } from './profiles'
{ provide: ProfileProvider, useClass: LocalProfilesService, multi: true },

{ provide: TabContextMenuItemProvider, useClass: NewTabContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: SaveAsProfileContextMenu, multi: true },

{ provide: CLIHandler, useClass: TerminalCLIHandler, multi: true },
{ provide: CLIHandler, useClass: OpenPathCLIHandler, multi: true },
Expand Down
52 changes: 1 addition & 51 deletions tabby-local/src/tabContextMenu.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,9 @@
import { Inject, Injectable, Optional } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, NotificationsService, MenuItemOptions, ProfilesService, PromptModalComponent, TranslateService } from 'tabby-core'
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, MenuItemOptions, ProfilesService, TranslateService } from 'tabby-core'
import { TerminalTabComponent } from './components/terminalTab.component'
import { TerminalService } from './services/terminal.service'
import { LocalProfile, UACService } from './api'

/** @hidden */
@Injectable()
export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
constructor (
private config: ConfigService,
private ngbModal: NgbModal,
private notifications: NotificationsService,
private translate: TranslateService,
) {
super()
}

async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
if (!(tab instanceof TerminalTabComponent)) {
return []
}
const terminalTab = tab
const items: MenuItemOptions[] = [
{
label: this.translate.instant('Save as profile'),
click: async () => {
const modal = this.ngbModal.open(PromptModalComponent)
modal.componentInstance.prompt = this.translate.instant('New profile name')
const name = (await modal.result)?.value
if (!name) {
return
}
const profile = {
options: {
...terminalTab.profile.options,
cwd: await terminalTab.session?.getWorkingDirectory() ?? terminalTab.profile.options.cwd,
},
name,
type: 'local',
}
this.config.store.profiles = [
...this.config.store.profiles,
profile,
]
this.config.save()
this.notifications.info(this.translate.instant('Saved'))
},
},
]

return items
}
}

/** @hidden */
@Injectable()
export class NewTabContextMenu extends TabContextMenuItemProvider {
Expand Down
3 changes: 2 additions & 1 deletion tabby-terminal/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { PathDropDecorator } from './features/pathDrop'
import { ZModemDecorator } from './features/zmodem'
import { TerminalConfigProvider } from './config'
import { TerminalHotkeyProvider } from './hotkeys'
import { CopyPasteContextMenu, MiscContextMenu, LegacyContextMenu, ReconnectContextMenu } from './tabContextMenu'
import { CopyPasteContextMenu, MiscContextMenu, LegacyContextMenu, ReconnectContextMenu, SaveAsProfileContextMenu } from './tabContextMenu'

import { Frontend } from './frontends/frontend'
import { XTermFrontend, XTermWebGLFrontend } from './frontends/xtermFrontend'
Expand Down Expand Up @@ -60,6 +60,7 @@ import { DefaultColorSchemes } from './colorSchemes'
{ provide: TabContextMenuItemProvider, useClass: MiscContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: LegacyContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: ReconnectContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: SaveAsProfileContextMenu, multi: true },

{ provide: CLIHandler, useClass: TerminalCLIHandler, multi: true },
{ provide: TerminalColorSchemeProvider, useClass: DefaultColorSchemes, multi: true },
Expand Down
68 changes: 67 additions & 1 deletion tabby-terminal/src/tabContextMenu.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Injectable, Optional, Inject } from '@angular/core'
import { BaseTabComponent, TabContextMenuItemProvider, NotificationsService, MenuItemOptions, TranslateService, SplitTabComponent } from 'tabby-core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { BaseTabComponent, TabContextMenuItemProvider, NotificationsService, MenuItemOptions, TranslateService, SplitTabComponent, PromptModalComponent, ConfigService, PartialProfile, Profile } from 'tabby-core'
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
import { TerminalContextMenuItemProvider } from './api/contextMenuProvider'
import { MultifocusService } from './services/multifocus.service'
import { ConnectableTerminalTabComponent } from './api/connectableTerminalTab.component'
import { v4 as uuidv4 } from 'uuid'
import slugify from 'slugify'

/** @hidden */
@Injectable()
Expand Down Expand Up @@ -150,3 +153,66 @@ export class LegacyContextMenu extends TabContextMenuItemProvider {
}

}

/** @hidden */
@Injectable()
export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
constructor (
private config: ConfigService,
private ngbModal: NgbModal,
private notifications: NotificationsService,
private translate: TranslateService,
) {
super()
}

async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
if (tab instanceof BaseTerminalTabComponent) {
return [
{
label: this.translate.instant('Save as profile'),
click: async () => {
const modal = this.ngbModal.open(PromptModalComponent)
modal.componentInstance.prompt = this.translate.instant('New profile name')
modal.componentInstance.value = tab.profile.name
const name = (await modal.result)?.value
if (!name) {
return
}

const options = {
...tab.profile.options,
}

const cwd = await tab.session?.getWorkingDirectory() ?? tab.profile.options.cwd
if (cwd) {
options.cwd = cwd
}

const profile: PartialProfile<Profile> = {
type: tab.profile.type,
name,
options,
}

profile.id = `${profile.type}:custom:${slugify(name)}:${uuidv4()}`
profile.group = tab.profile.group
profile.icon = tab.profile.icon
profile.color = tab.profile.color
profile.disableDynamicTitle = tab.profile.disableDynamicTitle
profile.behaviorOnSessionEnd = tab.profile.behaviorOnSessionEnd

this.config.store.profiles = [
...this.config.store.profiles,
profile,
]
this.config.save()
this.notifications.info(this.translate.instant('Saved'))
},
},
]
}

return []
}
}