浏览代码

SFTP filter bar (#10590)

Eugene 2 月之前
父节点
当前提交
56ee368b63

+ 22 - 2
tabby-ssh/src/components/sftpPanel.component.pug

@@ -17,6 +17,10 @@
 
     .breadcrumb-spacer.flex-grow-1.h-100((dblclick)='editPath()')
 
+    button.btn.btn-link.btn-sm.flex-shrink-0.d-flex(*ngIf='!showFilter', (click)='showFilter = true')
+        i.fas.fa-filter.me-1
+        div(translate) Filter
+
     button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='openCreateDirectoryModal()')
         i.fas.fa-plus.me-1
         div(translate) Create directory
@@ -31,6 +35,19 @@
 
     button.btn.btn-link.text-decoration-none((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')}
 
+.filter-bar.px-3.py-2.border-bottom(*ngIf='showFilter')
+    .input-group
+        input.form-control(
+            type='text',
+            placeholder='Filter...',
+            autofocus,
+            [(ngModel)]='filterText',
+            (input)='onFilterChange()',
+            (keydown.escape)='clearFilter()'
+        )
+        button.btn.btn-secondary((click)='clearFilter()')
+            i.fas.fa-times
+
 .body(dropZone, (transfer)='uploadOneFolder($event)')
     a.alert.alert-info.d-flex.align-items-center(
         *ngIf='shouldShowCWDTip && !cwdDetectionAvailable',
@@ -47,13 +64,13 @@
         div(*ngIf='fileList === null', translate) Loading
         .list-group.list-group-light(*ngIf='fileList !== null')
             .list-group-item.list-group-item-action.d-flex.align-items-center(
-                *ngIf='path !== "/"',
+                *ngIf='path !== "/" && (!showFilter || filterText.trim() === "")',
                 (click)='goUp()'
             )
                 i.fas.fa-fw.fa-level-up-alt
                 div(translate) Go up
             .list-group-item.list-group-item-action.d-flex.align-items-center(
-                *ngFor='let item of fileList',
+                *ngFor='let item of filteredFileList',
                 (contextmenu)='showContextMenu(item, $event)',
                 (click)='open(item)'
             )
@@ -63,3 +80,6 @@
                 .size(*ngIf='!item.isDirectory') {{item.size|filesize}}
                 .date {{item.modified|tabbyDate}}
                 .mode {{getModeString(item)}}
+        .alert.alert-info.text-center.mt-3(*ngIf='fileList !== null && filteredFileList.length === 0 && showFilter && filterText.trim() !== ""')
+            i.fas.fa-search.me-2
+            span(translate) No files match the filter "{{filterText}}"

+ 4 - 0
tabby-ssh/src/components/sftpPanel.component.scss

@@ -9,6 +9,10 @@
         flex: none;
     }
 
+    > .filter-bar {
+        flex: none;
+    }
+
     > .body {
         padding: 10px 20px;
         flex: 1 1 0;

+ 33 - 0
tabby-ssh/src/components/sftpPanel.component.ts

@@ -23,11 +23,14 @@ export class SFTPPanelComponent {
     @Output() closed = new EventEmitter<void>()
     sftp: SFTPSession
     fileList: SFTPFile[]|null = null
+    filteredFileList: SFTPFile[] = []
     @Input() path = '/'
     @Output() pathChange = new EventEmitter<string>()
     pathSegments: PathSegment[] = []
     @Input() cwdDetectionAvailable = false
     editingPath: string|null = null
+    showFilter = false
+    filterText = ''
 
     constructor (
         private ngbModal: NgbModal,
@@ -54,6 +57,8 @@ export class SFTPPanelComponent {
         this.path = newPath
         this.pathChange.next(this.path)
 
+        this.clearFilter()
+
         let p = newPath
         this.pathSegments = []
         while (p !== '/') {
@@ -65,6 +70,7 @@ export class SFTPPanelComponent {
         }
 
         this.fileList = null
+        this.filteredFileList = []
         try {
             this.fileList = await this.sftp.readdir(this.path)
         } catch (error) {
@@ -79,6 +85,8 @@ export class SFTPPanelComponent {
         this.fileList.sort((a, b) =>
             dirKey(b) - dirKey(a) ||
             a.name.localeCompare(b.name))
+
+        this.updateFilteredList()
     }
 
     getFileType (fileExtension: string): string {
@@ -336,4 +344,29 @@ export class SFTPPanelComponent {
         this.closed.emit()
     }
 
+    clearFilter (): void {
+        this.showFilter = false
+        this.filterText = ''
+        this.updateFilteredList()
+    }
+
+    onFilterChange (): void {
+        this.updateFilteredList()
+    }
+
+    private updateFilteredList (): void {
+        if (!this.fileList) {
+            this.filteredFileList = []
+            return
+        }
+
+        if (!this.showFilter || this.filterText.trim() === '') {
+            this.filteredFileList = this.fileList
+            return
+        }
+
+        this.filteredFileList = this.fileList.filter(item =>
+            item.name.toLowerCase().includes(this.filterText.toLowerCase()),
+        )
+    }
 }