Basic shortcuts for filter editor, blur input on esc empty

This commit is contained in:
shamoon 2024-04-05 00:28:12 -07:00
parent 097566e3d1
commit f189da237d
3 changed files with 72 additions and 6 deletions

View File

@ -598,4 +598,29 @@ describe('DocumentListComponent', () => {
{ rule_type: FILTER_FULLTEXT_MORELIKE, value: '99' }, { rule_type: FILTER_FULLTEXT_MORELIKE, value: '99' },
]) ])
}) })
it('should support hotkeys', () => {
fixture.detectChanges()
const resetSpy = jest.spyOn(component['filterEditor'], 'resetSelected')
component.clickTag(1)
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'escape' }))
expect(resetSpy).toHaveBeenCalled()
jest
.spyOn(documentListService, 'selected', 'get')
.mockReturnValue(new Set([1]))
const clearSelectedSpy = jest.spyOn(documentListService, 'selectNone')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'escape' }))
expect(clearSelectedSpy).toHaveBeenCalled()
const selectAllSpy = jest.spyOn(documentListService, 'selectAll')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' }))
expect(selectAllSpy).toHaveBeenCalled()
jest.spyOn(documentListService, 'documents', 'get').mockReturnValue(docs)
fixture.detectChanges()
const detailSpy = jest.spyOn(component, 'openDocumentDetail')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'o' }))
expect(detailSpy).toHaveBeenCalledWith(docs[0])
})
}) })

View File

@ -36,6 +36,7 @@ import { ToastService } from 'src/app/services/toast.service'
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component' import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
import { FilterEditorComponent } from './filter-editor/filter-editor.component' import { FilterEditorComponent } from './filter-editor/filter-editor.component'
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component' import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'
import { HotKeyService } from 'src/app/services/hot-key.service'
@Component({ @Component({
selector: 'pngx-document-list', selector: 'pngx-document-list',
@ -56,6 +57,7 @@ export class DocumentListComponent
private consumerStatusService: ConsumerStatusService, private consumerStatusService: ConsumerStatusService,
public openDocumentsService: OpenDocumentsService, public openDocumentsService: OpenDocumentsService,
private settingsService: SettingsService, private settingsService: SettingsService,
private hotKeyService: HotKeyService,
public permissionService: PermissionsService public permissionService: PermissionsService
) { ) {
super() super()
@ -184,6 +186,33 @@ export class DocumentListComponent
this.unmodifiedFilterRules = [] this.unmodifiedFilterRules = []
} }
}) })
this.hotKeyService
.addShortcut({ keys: 'escape', description: $localize`Clear selection` })
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(() => {
if (this.list.selected.size > 0) {
this.list.selectNone()
} else {
this.filterEditor.resetSelected()
}
})
this.hotKeyService
.addShortcut({ keys: 'a', description: $localize`Select all` })
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(() => {
this.list.selectAll()
})
this.hotKeyService
.addShortcut({ keys: 'o', description: $localize`Open first document` })
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(() => {
if (this.list.documents.length > 0) {
this.openDocumentDetail(this.list.documents[0])
}
})
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -7,12 +7,18 @@ import {
OnDestroy, OnDestroy,
ViewChild, ViewChild,
ElementRef, ElementRef,
AfterViewInit,
} from '@angular/core' } from '@angular/core'
import { Tag } from 'src/app/data/tag' import { Tag } from 'src/app/data/tag'
import { Correspondent } from 'src/app/data/correspondent' import { Correspondent } from 'src/app/data/correspondent'
import { DocumentType } from 'src/app/data/document-type' import { DocumentType } from 'src/app/data/document-type'
import { Subject, Subscription } from 'rxjs' import { Observable, Subject, Subscription } from 'rxjs'
import { debounceTime, distinctUntilChanged, filter } from 'rxjs/operators' import {
debounceTime,
distinctUntilChanged,
filter,
takeUntil,
} from 'rxjs/operators'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service' import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { TagService } from 'src/app/services/rest/tag.service' import { TagService } from 'src/app/services/rest/tag.service'
import { CorrespondentService } from 'src/app/services/rest/correspondent.service' import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
@ -163,7 +169,7 @@ const DEFAULT_TEXT_FILTER_MODIFIER_OPTIONS = [
}) })
export class FilterEditorComponent export class FilterEditorComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy, AfterViewInit
{ {
generateFilterName() { generateFilterName() {
if (this.filterRules.length == 1) { if (this.filterRules.length == 1) {
@ -256,6 +262,8 @@ export class FilterEditorComponent
_moreLikeId: number _moreLikeId: number
_moreLikeDoc: Document _moreLikeDoc: Document
unsubscribeNotifier: Subject<any> = new Subject()
get textFilterTargets() { get textFilterTargets() {
if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) { if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([ return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([
@ -862,7 +870,6 @@ export class FilterEditorComponent
} }
textFilterDebounce: Subject<string> textFilterDebounce: Subject<string>
subscription: Subscription
ngOnInit() { ngOnInit() {
if ( if (
@ -908,8 +915,9 @@ export class FilterEditorComponent
this.textFilterDebounce = new Subject<string>() this.textFilterDebounce = new Subject<string>()
this.subscription = this.textFilterDebounce this.textFilterDebounce
.pipe( .pipe(
takeUntil(this.unsubscribeNotifier),
debounceTime(400), debounceTime(400),
distinctUntilChanged(), distinctUntilChanged(),
filter((query) => !query.length || query.length > 2) filter((query) => !query.length || query.length > 2)
@ -919,8 +927,12 @@ export class FilterEditorComponent
if (this._textFilter) this.documentService.searchQuery = this._textFilter if (this._textFilter) this.documentService.searchQuery = this._textFilter
} }
ngAfterViewInit() {
this.textFilterInput.nativeElement.focus()
}
ngOnDestroy() { ngOnDestroy() {
this.textFilterDebounce.complete() this.unsubscribeNotifier.next(true)
} }
resetSelected() { resetSelected() {