Initial frontend global search
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
} from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { NgbDropdown, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subject, debounceTime, distinctUntilChanged, filter } from 'rxjs'
|
||||
import { ObjectWithId } from 'src/app/data/object-with-id'
|
||||
import {
|
||||
GlobalSearchResult,
|
||||
SearchService,
|
||||
} from 'src/app/services/rest/search.service'
|
||||
import { CorrespondentEditDialogComponent } from '../../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component'
|
||||
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
import { DocumentTypeEditDialogComponent } from '../../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component'
|
||||
import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
|
||||
import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
|
||||
import { CustomFieldEditDialogComponent } from '../../common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||
import { GroupEditDialogComponent } from '../../common/edit-dialog/group-edit-dialog/group-edit-dialog.component'
|
||||
import { MailAccountEditDialogComponent } from '../../common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component'
|
||||
import { MailRuleEditDialogComponent } from '../../common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component'
|
||||
import { UserEditDialogComponent } from '../../common/edit-dialog/user-edit-dialog/user-edit-dialog.component'
|
||||
import { WorkflowEditDialogComponent } from '../../common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
import {
|
||||
FILTER_HAS_ANY_TAG,
|
||||
FILTER_HAS_CORRESPONDENT_ANY,
|
||||
FILTER_HAS_DOCUMENT_TYPE_ANY,
|
||||
FILTER_HAS_STORAGE_PATH_ANY,
|
||||
} from 'src/app/data/filter-rule-type'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-global-search',
|
||||
templateUrl: './global-search.component.html',
|
||||
styleUrl: './global-search.component.scss',
|
||||
})
|
||||
export class GlobalSearchComponent {
|
||||
public query: string
|
||||
public queryDebounce: Subject<string>
|
||||
public searchResults: GlobalSearchResult
|
||||
private currentItemIndex: number
|
||||
|
||||
@ViewChild('searchInput') searchInput: ElementRef
|
||||
@ViewChild('resultsDropdown') resultsDropdown: NgbDropdown
|
||||
@ViewChildren('resultItem') resultItems: QueryList<ElementRef>
|
||||
|
||||
@HostListener('document:keydown', ['$event'])
|
||||
handleKeyboardEvent(event: KeyboardEvent) {
|
||||
if (event.key === 'k' && (event.ctrlKey || event.metaKey)) {
|
||||
this.searchInput.nativeElement.focus()
|
||||
}
|
||||
|
||||
if (this.searchResults && this.resultsDropdown.isOpen()) {
|
||||
if (event.key === 'ArrowDown') {
|
||||
if (this.currentItemIndex < this.resultItems.length - 1) {
|
||||
this.currentItemIndex++
|
||||
this.setCurrentItem()
|
||||
event.preventDefault()
|
||||
}
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
if (this.currentItemIndex > 0) {
|
||||
this.currentItemIndex--
|
||||
this.setCurrentItem()
|
||||
event.preventDefault()
|
||||
}
|
||||
} else if (event.key === 'Enter') {
|
||||
this.resultItems.get(this.currentItemIndex).nativeElement.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
private searchService: SearchService,
|
||||
private router: Router,
|
||||
private modalService: NgbModal,
|
||||
private documentService: DocumentService,
|
||||
private documentListViewService: DocumentListViewService
|
||||
) {
|
||||
this.queryDebounce = new Subject<string>()
|
||||
|
||||
this.queryDebounce
|
||||
.pipe(
|
||||
debounceTime(400),
|
||||
distinctUntilChanged(),
|
||||
filter((query) => !query.length || query.length > 2)
|
||||
)
|
||||
.subscribe((text) => {
|
||||
this.query = text
|
||||
this.search(text)
|
||||
})
|
||||
}
|
||||
|
||||
private search(query: string) {
|
||||
this.searchService.globalSearch(query).subscribe((results) => {
|
||||
this.searchResults = results
|
||||
this.resultsDropdown.open()
|
||||
})
|
||||
}
|
||||
|
||||
public primaryAction(type: string, object: ObjectWithId) {
|
||||
this.reset(true)
|
||||
let filterRuleType: number
|
||||
let editDialogComponent: any
|
||||
switch (type) {
|
||||
case 'document':
|
||||
this.router.navigate(['/documents', object.id])
|
||||
return
|
||||
case 'correspondent':
|
||||
filterRuleType = FILTER_HAS_CORRESPONDENT_ANY
|
||||
break
|
||||
case 'documentType':
|
||||
filterRuleType = FILTER_HAS_DOCUMENT_TYPE_ANY
|
||||
break
|
||||
case 'storagePath':
|
||||
filterRuleType = FILTER_HAS_STORAGE_PATH_ANY
|
||||
break
|
||||
case 'tag':
|
||||
filterRuleType = FILTER_HAS_ANY_TAG
|
||||
break
|
||||
case 'user':
|
||||
editDialogComponent = UserEditDialogComponent
|
||||
break
|
||||
case 'group':
|
||||
editDialogComponent = GroupEditDialogComponent
|
||||
break
|
||||
case 'mailAccount':
|
||||
editDialogComponent = MailAccountEditDialogComponent
|
||||
break
|
||||
case 'mailRule':
|
||||
editDialogComponent = MailRuleEditDialogComponent
|
||||
break
|
||||
case 'customField':
|
||||
editDialogComponent = CustomFieldEditDialogComponent
|
||||
break
|
||||
case 'workflow':
|
||||
editDialogComponent = WorkflowEditDialogComponent
|
||||
break
|
||||
}
|
||||
|
||||
if (filterRuleType) {
|
||||
this.documentListViewService.quickFilter([
|
||||
{ rule_type: filterRuleType, value: object.id.toString() },
|
||||
])
|
||||
} else if (editDialogComponent) {
|
||||
const modalRef: NgbModalRef = this.modalService.open(
|
||||
editDialogComponent,
|
||||
{ size: 'lg' }
|
||||
)
|
||||
modalRef.componentInstance.dialogMode = EditDialogMode.EDIT
|
||||
modalRef.componentInstance.object = object
|
||||
}
|
||||
}
|
||||
|
||||
public secondaryAction(type: string, object: ObjectWithId) {
|
||||
this.reset(true)
|
||||
let editDialogComponent: any
|
||||
switch (type) {
|
||||
case 'document':
|
||||
this.router.navigate([this.documentService.getDownloadUrl(object.id)], {
|
||||
skipLocationChange: true,
|
||||
})
|
||||
break
|
||||
case 'correspondent':
|
||||
editDialogComponent = CorrespondentEditDialogComponent
|
||||
break
|
||||
case 'documentType':
|
||||
editDialogComponent = DocumentTypeEditDialogComponent
|
||||
break
|
||||
case 'storagePath':
|
||||
editDialogComponent = StoragePathEditDialogComponent
|
||||
break
|
||||
case 'tag':
|
||||
editDialogComponent = TagEditDialogComponent
|
||||
break
|
||||
}
|
||||
|
||||
if (editDialogComponent) {
|
||||
const modalRef: NgbModalRef = this.modalService.open(
|
||||
editDialogComponent,
|
||||
{ size: 'lg' }
|
||||
)
|
||||
modalRef.componentInstance.dialogMode = EditDialogMode.EDIT
|
||||
modalRef.componentInstance.object = object
|
||||
}
|
||||
}
|
||||
|
||||
private reset(close: boolean = false) {
|
||||
this.queryDebounce.next('')
|
||||
this.searchResults = null
|
||||
this.currentItemIndex = undefined
|
||||
if (close) {
|
||||
this.resultsDropdown.close()
|
||||
}
|
||||
}
|
||||
|
||||
private setCurrentItem() {
|
||||
const item: ElementRef = this.resultItems.get(this.currentItemIndex)
|
||||
item.nativeElement.focus()
|
||||
}
|
||||
|
||||
public searchInputKeyDown(event: KeyboardEvent) {
|
||||
if (
|
||||
event.key === 'ArrowDown' &&
|
||||
this.searchResults &&
|
||||
this.resultsDropdown.isOpen()
|
||||
) {
|
||||
this.currentItemIndex = 0
|
||||
this.setCurrentItem()
|
||||
} else if (
|
||||
event.key === 'Enter' &&
|
||||
this.searchResults?.total === 1 &&
|
||||
this.resultsDropdown.isOpen()
|
||||
) {
|
||||
this.resultItems.first.nativeElement.click()
|
||||
}
|
||||
}
|
||||
|
||||
public onDropdownOpenChange(open: boolean) {
|
||||
if (!open) {
|
||||
this.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user