mirror of
https://github.com/Eugeny/tabby.git
synced 2025-10-04 05:54:57 +00:00
new ssh connection selector - fixes #1557
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
export interface SelectorOption<T> {
|
||||
name: string
|
||||
description?: string
|
||||
result: T
|
||||
result?: T
|
||||
icon?: string
|
||||
freeInputPattern?: string
|
||||
callback?: (string?) => void
|
||||
}
|
||||
|
@@ -4,15 +4,15 @@
|
||||
[(ngModel)]='filter',
|
||||
autofocus,
|
||||
[placeholder]='name',
|
||||
(ngModelChange)='onFilterChange()',
|
||||
(keyup.enter)='onFilterEnter()',
|
||||
(keyup.escape)='close()'
|
||||
(ngModelChange)='onFilterChange()'
|
||||
)
|
||||
|
||||
.list-group.mt-3(*ngIf='filteredOptions.length')
|
||||
a.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||
(click)='selectOption(option)',
|
||||
*ngFor='let option of filteredOptions'
|
||||
[class.active]='selectedIndex == i',
|
||||
*ngFor='let option of filteredOptions; let i = index'
|
||||
)
|
||||
.mr-2 {{option.name}}
|
||||
i(class='fa-fw fas mr-1 fa-{{option.icon}}')
|
||||
.mr-2 {{getOptionText(option)}}
|
||||
.text-muted {{option.description}}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { Component, Input, HostListener } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { SelectorOption } from '../api/selector'
|
||||
|
||||
@@ -12,6 +12,7 @@ export class SelectorModalComponent<T> {
|
||||
@Input() filteredOptions: SelectorOption<T>[]
|
||||
@Input() filter = ''
|
||||
@Input() name: string
|
||||
@Input() selectedIndex = 0
|
||||
|
||||
constructor (
|
||||
public modalInstance: NgbActiveModal,
|
||||
@@ -21,23 +22,44 @@ export class SelectorModalComponent<T> {
|
||||
this.onFilterChange()
|
||||
}
|
||||
|
||||
@HostListener('keyup', ['$event']) onKeyUp (event: KeyboardEvent): void {
|
||||
if (event.key === 'ArrowUp') {
|
||||
this.selectedIndex--
|
||||
}
|
||||
if (event.key === 'ArrowDown') {
|
||||
this.selectedIndex++
|
||||
}
|
||||
if (event.key === 'Enter') {
|
||||
this.selectOption(this.filteredOptions[this.selectedIndex])
|
||||
}
|
||||
if (event.key === 'Escape') {
|
||||
this.close()
|
||||
}
|
||||
|
||||
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
|
||||
}
|
||||
|
||||
onFilterChange (): void {
|
||||
const f = this.filter.trim().toLowerCase()
|
||||
if (!f) {
|
||||
this.filteredOptions = this.options
|
||||
this.filteredOptions = this.options.filter(x => !x.freeInputPattern)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
this.filteredOptions = this.options.filter(x => (x.name + (x.description || '')).toLowerCase().includes(f))
|
||||
this.filteredOptions = this.options.filter(x => x.freeInputPattern || (x.name + (x.description || '')).toLowerCase().includes(f))
|
||||
}
|
||||
this.selectedIndex = Math.max(0, this.selectedIndex)
|
||||
this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex)
|
||||
}
|
||||
|
||||
onFilterEnter (): void {
|
||||
if (this.filteredOptions.length === 1) {
|
||||
this.selectOption(this.filteredOptions[0])
|
||||
getOptionText (option: SelectorOption<T>): string {
|
||||
if (option.freeInputPattern) {
|
||||
return option.freeInputPattern.replace('%s', this.filter)
|
||||
}
|
||||
return option.name
|
||||
}
|
||||
|
||||
selectOption (option: SelectorOption<T>): void {
|
||||
option.callback?.(this.filter)
|
||||
this.modalInstance.close(option.result)
|
||||
}
|
||||
|
||||
|
@@ -246,7 +246,7 @@ ngb-tabset .tab-content {
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
transition: 0.25s background;
|
||||
transition: 0.0625s background;
|
||||
|
||||
i + * {
|
||||
margin-left: 10px;
|
||||
|
Reference in New Issue
Block a user