mirror of
https://github.com/Eugeny/tabby.git
synced 2024-11-22 03:26:09 +03:00
support for providing commands as toolbar buttons
This commit is contained in:
parent
a1825bbbe6
commit
b0600b10cc
@ -2,21 +2,51 @@ import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { MenuItemOptions } from './menu'
|
||||
import { ToolbarButton } from './toolbarButtonProvider'
|
||||
|
||||
export enum CommandLocation {
|
||||
LeftToolbar = 'left-toolbar',
|
||||
RightToolbar = 'right-toolbar',
|
||||
StartPage = 'start-page',
|
||||
}
|
||||
|
||||
export class Command {
|
||||
id?: string
|
||||
label: string
|
||||
sublabel?: string
|
||||
click?: () => void
|
||||
locations?: CommandLocation[]
|
||||
run: () => Promise<void>
|
||||
|
||||
/**
|
||||
* Raw SVG icon code
|
||||
*/
|
||||
icon?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar icon ID
|
||||
*/
|
||||
touchBarNSImage?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar button label
|
||||
*/
|
||||
touchBarTitle?: string
|
||||
|
||||
weight?: number
|
||||
|
||||
static fromToolbarButton (button: ToolbarButton): Command {
|
||||
const command = new Command()
|
||||
command.label = button.commandLabel ?? button.title
|
||||
command.click = button.click
|
||||
command.label = button.title
|
||||
command.run = async () => button.click?.()
|
||||
command.icon = button.icon
|
||||
command.locations = [CommandLocation.StartPage]
|
||||
if ((button.weight ?? 0) <= 0) {
|
||||
command.locations.push(CommandLocation.LeftToolbar)
|
||||
}
|
||||
if ((button.weight ?? 0) > 0) {
|
||||
command.locations.push(CommandLocation.RightToolbar)
|
||||
}
|
||||
command.touchBarNSImage = button.touchBarNSImage
|
||||
command.touchBarTitle = button.touchBarTitle
|
||||
command.weight = button.weight
|
||||
return command
|
||||
}
|
||||
|
||||
@ -24,7 +54,7 @@ export class Command {
|
||||
const command = new Command()
|
||||
command.label = item.commandLabel ?? item.label ?? ''
|
||||
command.sublabel = item.sublabel
|
||||
command.click = item.click
|
||||
command.run = async () => item.click?.()
|
||||
return command
|
||||
}
|
||||
}
|
||||
@ -32,3 +62,10 @@ export class Command {
|
||||
export interface CommandContext {
|
||||
tab?: BaseTabComponent,
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend to add commands
|
||||
*/
|
||||
export abstract class CommandProvider {
|
||||
abstract provide (context: CommandContext): Promise<Command[]>
|
||||
}
|
||||
|
@ -27,13 +27,6 @@ export interface ToolbarButton {
|
||||
|
||||
/** @hidden */
|
||||
submenuItems?: ToolbarButton[]
|
||||
|
||||
showInToolbar?: boolean
|
||||
|
||||
showInStartPage?: boolean
|
||||
|
||||
/** @hidden */
|
||||
commandLabel?: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,26 +2,19 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
|
||||
import { ToolbarButton, ToolbarButtonProvider } from './api/toolbarButtonProvider'
|
||||
import { HostAppService, Platform } from './api/hostApp'
|
||||
import { HotkeysService } from './services/hotkeys.service'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { CommandProvider, Command, CommandLocation } from './api/commands'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ButtonProvider extends ToolbarButtonProvider {
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
hotkeys.hotkey$.subscribe(hotkey => {
|
||||
if (hotkey === 'profile-selector') {
|
||||
this.activate()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async activate () {
|
||||
@ -31,21 +24,22 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
}
|
||||
}
|
||||
|
||||
provide (): ToolbarButton[] {
|
||||
async provide (): Promise<Command[]> {
|
||||
return [
|
||||
{
|
||||
id: 'profile-selector',
|
||||
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage],
|
||||
label: this.translate.instant('Profiles & connections'),
|
||||
icon: this.hostApp.platform === Platform.Web
|
||||
? require('./icons/plus.svg')
|
||||
: require('./icons/profiles.svg'),
|
||||
title: this.translate.instant('Profiles & connections'),
|
||||
click: () => this.activate(),
|
||||
run: async () => this.activate(),
|
||||
},
|
||||
...this.profilesService.getRecentProfiles().map(profile => ({
|
||||
label: profile.name,
|
||||
locations: [CommandLocation.StartPage],
|
||||
icon: require('./icons/history.svg'),
|
||||
title: profile.name,
|
||||
showInToolbar: false,
|
||||
showinStartPage: true,
|
||||
click: async () => {
|
||||
run: async () => {
|
||||
const p = (await this.profilesService.getProfiles()).find(x => x.id === profile.id) ?? profile
|
||||
this.profilesService.launchProfile(p)
|
||||
},
|
@ -38,26 +38,14 @@ title-bar(
|
||||
.btn-group.background
|
||||
.d-flex(
|
||||
*ngFor='let button of leftToolbarButtons',
|
||||
ngbDropdown,
|
||||
(openChange)='generateButtonSubmenu(button)',
|
||||
ngbDropdown
|
||||
)
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
[title]='button.title',
|
||||
(click)='button.click && button.click()',
|
||||
[title]='button.label',
|
||||
(click)='button.run && button.run()',
|
||||
[fastHtmlBind]='button.icon',
|
||||
ngbDropdownToggle,
|
||||
)
|
||||
div(*ngIf='button.submenu', ngbDropdownMenu)
|
||||
button.dropdown-item.d-flex.align-items-center(
|
||||
*ngFor='let item of button.submenuItems',
|
||||
(click)='item.click()',
|
||||
ngbDropdownItem,
|
||||
)
|
||||
.icon-wrapper(
|
||||
*ngIf='hasIcons(button.submenuItems)',
|
||||
[fastHtmlBind]='item.icon'
|
||||
)
|
||||
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
|
||||
|
||||
.d-flex(
|
||||
ngbDropdown,
|
||||
@ -80,26 +68,14 @@ title-bar(
|
||||
.btn-group.background
|
||||
.d-flex(
|
||||
*ngFor='let button of rightToolbarButtons',
|
||||
ngbDropdown,
|
||||
(openChange)='generateButtonSubmenu(button)',
|
||||
ngbDropdown
|
||||
)
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
[title]='button.title',
|
||||
(click)='button.click && button.click()',
|
||||
(click)='button.run && button.run()',
|
||||
[fastHtmlBind]='button.icon',
|
||||
ngbDropdownToggle,
|
||||
)
|
||||
div(*ngIf='button.submenu', ngbDropdownMenu)
|
||||
button.dropdown-item.d-flex.align-items-center(
|
||||
*ngFor='let item of button.submenuItems',
|
||||
(click)='item.click()',
|
||||
ngbDropdownItem,
|
||||
)
|
||||
.icon-wrapper(
|
||||
*ngIf='hasIcons(button.submenuItems)',
|
||||
[fastHtmlBind]='item.icon'
|
||||
)
|
||||
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
|
||||
|
||||
button.btn.btn-secondary.btn-tab-bar.btn-update(
|
||||
*ngIf='updatesAvailable',
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Inject, Input, HostListener, HostBinding, ViewChildren, ViewChild } from '@angular/core'
|
||||
import { Component, Input, HostListener, HostBinding, ViewChildren, ViewChild } from '@angular/core'
|
||||
import { trigger, style, animate, transition, state } from '@angular/animations'
|
||||
import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'
|
||||
@ -10,12 +10,13 @@ import { Logger, LogService } from '../services/log.service'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { ThemesService } from '../services/themes.service'
|
||||
import { UpdaterService } from '../services/updater.service'
|
||||
import { CommandService } from '../services/commands.service'
|
||||
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { SafeModeModalComponent } from './safeModeModal.component'
|
||||
import { TabBodyComponent } from './tabBody.component'
|
||||
import { SplitTabComponent } from './splitTab.component'
|
||||
import { AppService, FileTransfer, HostWindowService, PlatformService, ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
import { AppService, Command, CommandLocation, FileTransfer, HostWindowService, PlatformService } from '../api'
|
||||
|
||||
function makeTabAnimation (dimension: string, size: number) {
|
||||
return [
|
||||
@ -63,8 +64,8 @@ function makeTabAnimation (dimension: string, size: number) {
|
||||
export class AppRootComponent {
|
||||
Platform = Platform
|
||||
@Input() ready = false
|
||||
@Input() leftToolbarButtons: ToolbarButton[]
|
||||
@Input() rightToolbarButtons: ToolbarButton[]
|
||||
@Input() leftToolbarButtons: Command[]
|
||||
@Input() rightToolbarButtons: Command[]
|
||||
@HostBinding('class.platform-win32') platformClassWindows = process.platform === 'win32'
|
||||
@HostBinding('class.platform-darwin') platformClassMacOS = process.platform === 'darwin'
|
||||
@HostBinding('class.platform-linux') platformClassLinux = process.platform === 'linux'
|
||||
@ -79,11 +80,11 @@ export class AppRootComponent {
|
||||
constructor (
|
||||
private hotkeys: HotkeysService,
|
||||
private updater: UpdaterService,
|
||||
private commands: CommandService,
|
||||
public hostWindow: HostWindowService,
|
||||
public hostApp: HostAppService,
|
||||
public config: ConfigService,
|
||||
public app: AppService,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
platform: PlatformService,
|
||||
log: LogService,
|
||||
ngbModal: NgbModal,
|
||||
@ -170,9 +171,9 @@ export class AppRootComponent {
|
||||
this.activeTransfersDropdown.open()
|
||||
})
|
||||
|
||||
config.ready$.toPromise().then(() => {
|
||||
this.leftToolbarButtons = this.getToolbarButtons(false)
|
||||
this.rightToolbarButtons = this.getToolbarButtons(true)
|
||||
config.ready$.toPromise().then(async () => {
|
||||
this.leftToolbarButtons = await this.getToolbarButtons(false)
|
||||
this.rightToolbarButtons = await this.getToolbarButtons(true)
|
||||
|
||||
setInterval(() => {
|
||||
if (this.config.store.enableAutomaticUpdates) {
|
||||
@ -212,16 +213,6 @@ export class AppRootComponent {
|
||||
return this.config.store.appearance.flexTabs ? '*' : '200px'
|
||||
}
|
||||
|
||||
async generateButtonSubmenu (button: ToolbarButton) {
|
||||
if (button.submenu) {
|
||||
button.submenuItems = await button.submenu()
|
||||
}
|
||||
}
|
||||
|
||||
hasIcons (submenuItems: ToolbarButton[]): boolean {
|
||||
return submenuItems.some(x => !!x.icon)
|
||||
}
|
||||
|
||||
onTabsReordered (event: CdkDragDrop<BaseTabComponent[]>) {
|
||||
const tab: BaseTabComponent = event.item.data
|
||||
if (!this.app.tabs.includes(tab)) {
|
||||
@ -244,14 +235,8 @@ export class AppRootComponent {
|
||||
return this.config.store?.appearance.vibrancy
|
||||
}
|
||||
|
||||
private getToolbarButtons (aboveZero: boolean): ToolbarButton[] {
|
||||
let buttons: ToolbarButton[] = []
|
||||
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {
|
||||
buttons = buttons.concat(provider.provide())
|
||||
})
|
||||
return buttons
|
||||
.filter(x => x.showInToolbar ?? true)
|
||||
.filter(button => (button.weight ?? 0) > 0 === aboveZero)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
private async getToolbarButtons (aboveZero: boolean): Promise<Command[]> {
|
||||
return (await this.commands.getCommands({ tab: this.app.activeTab ?? undefined }))
|
||||
.filter(x => x.locations?.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Observable, Subject, distinctUntilChanged, filter, debounceTime } from 'rxjs'
|
||||
import { EmbeddedViewRef, ViewContainerRef, ViewRef } from '@angular/core'
|
||||
import { EmbeddedViewRef, Injector, ViewContainerRef, ViewRef } from '@angular/core'
|
||||
import { RecoveryToken } from '../api/tabRecovery'
|
||||
import { BaseComponent } from './base.component'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
|
||||
/**
|
||||
* Represents an active "process" inside a tab,
|
||||
@ -87,8 +88,11 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
get destroyed$ (): Observable<void> { return this.destroyed }
|
||||
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
|
||||
|
||||
protected constructor () {
|
||||
protected config: ConfigService
|
||||
|
||||
protected constructor (injector: Injector) {
|
||||
super()
|
||||
this.config = injector.get(ConfigService)
|
||||
this.focused$.subscribe(() => {
|
||||
this.hasFocus = true
|
||||
})
|
||||
|
@ -97,8 +97,8 @@ export class SelectorModalComponent<T> {
|
||||
}
|
||||
|
||||
selectOption (option: SelectorOption<T>): void {
|
||||
option.callback?.(this.filter)
|
||||
this.modalInstance.close(option.result)
|
||||
setTimeout(() => option.callback?.(this.filter))
|
||||
}
|
||||
|
||||
canEditSelected (): boolean {
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, AfterViewInit, OnDestroy } from '@angular/core'
|
||||
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, AfterViewInit, OnDestroy, Injector } from '@angular/core'
|
||||
import { BaseTabComponent, BaseTabProcess, GetRecoveryTokenOptions } from './baseTab.component'
|
||||
import { TabRecoveryProvider, RecoveryToken } from '../api/tabRecovery'
|
||||
import { TabsService, NewTabParameters } from '../services/tabs.service'
|
||||
import { HotkeysService } from '../services/hotkeys.service'
|
||||
import { TabRecoveryService } from '../services/tabRecovery.service'
|
||||
import { ConfigService } from '../api'
|
||||
|
||||
export type SplitOrientation = 'v' | 'h'
|
||||
export type SplitDirection = 'r' | 't' | 'b' | 'l'
|
||||
@ -261,9 +260,9 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
private hotkeys: HotkeysService,
|
||||
private tabsService: TabsService,
|
||||
private tabRecovery: TabRecoveryService,
|
||||
private config: ConfigService,
|
||||
injector: Injector,
|
||||
) {
|
||||
super()
|
||||
super(injector)
|
||||
this.root = new SplitContainer()
|
||||
this.setTitle('')
|
||||
|
||||
|
@ -5,11 +5,11 @@ div
|
||||
|
||||
.list-group.mb-4
|
||||
a.list-group-item.list-group-item-action.d-flex(
|
||||
*ngFor='let button of getButtons(); trackBy: buttonsTrackBy',
|
||||
(click)='button.click()',
|
||||
*ngFor='let command of commands; trackBy: buttonsTrackBy',
|
||||
(click)='command.run()',
|
||||
)
|
||||
.d-flex.align-self-center([innerHTML]='sanitizeIcon(button.icon)')
|
||||
span {{button.title}}
|
||||
.d-flex.align-self-center([innerHTML]='sanitizeIcon(command.icon)')
|
||||
span {{command.label}}
|
||||
|
||||
footer.d-flex.align-items-center
|
||||
.btn-group.mr-auto
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Component, Inject } from '@angular/core'
|
||||
import { Component } from '@angular/core'
|
||||
import { DomSanitizer } from '@angular/platform-browser'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { HomeBaseService } from '../services/homeBase.service'
|
||||
import { ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
import { CommandService } from '../services/commands.service'
|
||||
import { Command, CommandLocation } from '../api/commands'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@ -12,29 +12,23 @@ import { ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
})
|
||||
export class StartPageComponent {
|
||||
version: string
|
||||
commands: Command[] = []
|
||||
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
private domSanitizer: DomSanitizer,
|
||||
public homeBase: HomeBaseService,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
commands: CommandService,
|
||||
) {
|
||||
}
|
||||
|
||||
getButtons (): ToolbarButton[] {
|
||||
return this.config.enabledServices(this.toolbarButtonProviders)
|
||||
.map(provider => provider.provide())
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.filter(x => x.showInStartPage ?? true)
|
||||
.filter(x => !!x.click)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
commands.getCommands({}).then(c => {
|
||||
this.commands = c.filter(x => x.locations?.includes(CommandLocation.StartPage))
|
||||
})
|
||||
}
|
||||
|
||||
sanitizeIcon (icon?: string): any {
|
||||
return this.domSanitizer.bypassSecurityTrustHtml(icon ?? '')
|
||||
}
|
||||
|
||||
buttonsTrackBy (btn: ToolbarButton): any {
|
||||
return btn.title + btn.icon
|
||||
buttonsTrackBy (btn: Command): any {
|
||||
return btn.label + btn.icon
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component } from '@angular/core'
|
||||
import { Component, Injector } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
@ -19,8 +19,9 @@ export class WelcomeTabComponent extends BaseTabComponent {
|
||||
public config: ConfigService,
|
||||
public locale: LocaleService,
|
||||
translate: TranslateService,
|
||||
injector: Injector,
|
||||
) {
|
||||
super()
|
||||
super(injector)
|
||||
this.setTitle(translate.instant('Welcome'))
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
|
||||
import { DropZoneDirective } from './directives/dropZone.directive'
|
||||
import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive'
|
||||
|
||||
import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ToolbarButtonProvider, ProfilesService, ProfileProvider, SelectorOption, Profile, SelectorService } from './api'
|
||||
import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
||||
|
||||
import { AppService } from './services/app.service'
|
||||
import { ConfigService } from './services/config.service'
|
||||
@ -51,8 +51,8 @@ import { CoreConfigProvider } from './config'
|
||||
import { AppHotkeyProvider } from './hotkeys'
|
||||
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu'
|
||||
import { LastCLIHandler, ProfileCLIHandler } from './cli'
|
||||
import { ButtonProvider } from './buttonProvider'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { CoreCommandProvider } from './commands'
|
||||
|
||||
import 'perfect-scrollbar/css/perfect-scrollbar.css'
|
||||
|
||||
@ -75,8 +75,8 @@ const PROVIDERS = [
|
||||
{ provide: CLIHandler, useClass: LastCLIHandler, multi: true },
|
||||
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } },
|
||||
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||
{ provide: ProfileProvider, useExisting: SplitLayoutProfilesService, multi: true },
|
||||
{ provide: CommandProvider, useExisting: CoreCommandProvider, multi: true },
|
||||
{
|
||||
provide: LOCALE_ID,
|
||||
deps: [LocaleService],
|
||||
@ -180,7 +180,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
console.error('Unhandled exception:', err)
|
||||
})
|
||||
|
||||
hotkeys.hotkey$.subscribe(async (hotkey) => {
|
||||
hotkeys.hotkey$.subscribe(async hotkey => {
|
||||
if (hotkey.startsWith('profile.')) {
|
||||
const id = hotkey.substring(hotkey.indexOf('.') + 1)
|
||||
const profiles = await profilesService.getProfiles()
|
||||
@ -200,6 +200,10 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
if (hotkey === 'command-selector') {
|
||||
commands.showSelector()
|
||||
}
|
||||
|
||||
if (hotkey === 'profile-selector') {
|
||||
commands.run('profile-selector', {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Inject, Injectable, Optional } from '@angular/core'
|
||||
import { AppService, Command, CommandContext, ConfigService, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider, TranslateService } from '../api'
|
||||
import { AppService, Command, CommandContext, CommandProvider, ConfigService, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider, TranslateService } from '../api'
|
||||
import { SelectorService } from './selector.service'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@ -11,6 +11,7 @@ export class CommandService {
|
||||
private translate: TranslateService,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
@Inject(CommandProvider) private commandProviders: CommandProvider[],
|
||||
) {
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
@ -60,10 +61,20 @@ export class CommandService {
|
||||
}
|
||||
items.forEach(x => flattenItem(x))
|
||||
|
||||
let commands = buttons.map(x => Command.fromToolbarButton(x))
|
||||
commands = commands.concat(flatItems.map(x => Command.fromMenuItem(x)))
|
||||
const commands = buttons.map(x => Command.fromToolbarButton(x))
|
||||
commands.push(...flatItems.map(x => Command.fromMenuItem(x)))
|
||||
|
||||
return commands
|
||||
for (const provider of this.config.enabledServices(this.commandProviders)) {
|
||||
commands.push(...await provider.provide(context))
|
||||
}
|
||||
|
||||
return commands.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
}
|
||||
|
||||
async run (id: string, context: CommandContext): Promise<void> {
|
||||
const commands = await this.getCommands(context)
|
||||
const command = commands.find(x => x.id === id)
|
||||
await command?.run()
|
||||
}
|
||||
|
||||
async showSelector (): Promise<void> {
|
||||
@ -81,7 +92,7 @@ export class CommandService {
|
||||
this.translate.instant('Commands'),
|
||||
commands.map(c => ({
|
||||
name: c.label,
|
||||
callback: c.click,
|
||||
callback: c.run,
|
||||
description: c.sublabel,
|
||||
icon: c.icon,
|
||||
})),
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||
import axios from 'axios'
|
||||
import { marked } from 'marked'
|
||||
import { Component } from '@angular/core'
|
||||
import { Component, Injector } from '@angular/core'
|
||||
import { BaseTabComponent, TranslateService } from 'tabby-core'
|
||||
|
||||
export interface Release {
|
||||
@ -22,8 +22,8 @@ export class ReleaseNotesComponent extends BaseTabComponent {
|
||||
releases: Release[] = []
|
||||
lastPage = 1
|
||||
|
||||
constructor (translate: TranslateService) {
|
||||
super()
|
||||
constructor (translate: TranslateService, injector: Injector) {
|
||||
super(injector)
|
||||
this.setTitle(translate.instant(_('Release notes')))
|
||||
this.loadReleases(1)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { debounce } from 'utils-decorators/dist/esm/debounce/debounce'
|
||||
import { Component, Inject, Input, HostBinding, NgZone } from '@angular/core'
|
||||
import { Component, Inject, Input, HostBinding, NgZone, Injector } from '@angular/core'
|
||||
import {
|
||||
ConfigService,
|
||||
BaseTabComponent,
|
||||
@ -52,8 +52,9 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
private app: AppService,
|
||||
@Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[],
|
||||
translate: TranslateService,
|
||||
injector: Injector,
|
||||
) {
|
||||
super()
|
||||
super(injector)
|
||||
this.setTitle(translate.instant(_('Settings')))
|
||||
this.settingsProviders = config.enabledServices(this.settingsProviders)
|
||||
this.settingsProviders = this.settingsProviders.filter(x => !!x.getComponentType())
|
||||
|
@ -17,6 +17,7 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"ansi-colors": "^4.1.1",
|
||||
"@types/node": "14.14.31"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -6,3 +6,8 @@
|
||||
version "14.14.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
|
||||
integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
|
||||
|
||||
ansi-colors@^4.1.1:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
|
||||
integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
|
||||
|
@ -175,7 +175,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
get sessionChanged$ (): Observable<BaseSession|null> { return this.sessionChanged }
|
||||
|
||||
constructor (protected injector: Injector) {
|
||||
super()
|
||||
super(injector)
|
||||
|
||||
this.config = injector.get(ConfigService)
|
||||
this.element = injector.get(ElementRef)
|
||||
|
Loading…
Reference in New Issue
Block a user