Enhancement: default to title/content search, allow choosing full search link from global search (#6805)

This commit is contained in:
shamoon
2024-05-22 16:19:46 -07:00
committed by GitHub
parent 8abb0cd75d
commit 719f76060b
8 changed files with 191 additions and 101 deletions

View File

@@ -201,7 +201,23 @@
<div class="row mb-3">
<div class="offset-md-3 col">
<pngx-input-check i18n-title title="Search database only (do not include advanced search results)" formControlName="searchDbOnly"></pngx-input-check>
<pngx-input-check i18n-title title="Do not include advanced search results" formControlName="searchDbOnly"></pngx-input-check>
</div>
</div>
<div class="row mb-3">
<div class="offset-md-3 col">
<div class="row">
<div class="col-md-2 col-form-label pt-0">
<span i18n>Full search links to</span>
</div>
<div class="col">
<select class="form-select" formControlName="searchLink">
<option [ngValue]="GlobalSearchType.TITLE_CONTENT" i18n>Title and content search</option>
<option [ngValue]="GlobalSearchType.ADVANCED" i18n>Advanced search</option>
</select>
</div>
</div>
</div>
</div>

View File

@@ -309,7 +309,7 @@ describe('SettingsComponent', () => {
expect(toastErrorSpy).toHaveBeenCalled()
expect(storeSpy).toHaveBeenCalled()
expect(appearanceSettingsSpy).not.toHaveBeenCalled()
expect(setSpy).toHaveBeenCalledTimes(26)
expect(setSpy).toHaveBeenCalledTimes(27)
// succeed
storeSpy.mockReturnValueOnce(of(true))

View File

@@ -27,7 +27,7 @@ import {
} from 'rxjs'
import { Group } from 'src/app/data/group'
import { SavedView } from 'src/app/data/saved-view'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { GlobalSearchType, SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { User } from 'src/app/data/user'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
import {
@@ -101,6 +101,7 @@ export class SettingsComponent
defaultPermsEditGroups: new FormControl(null),
documentEditingRemoveInboxTags: new FormControl(null),
searchDbOnly: new FormControl(null),
searchLink: new FormControl(null),
notificationsConsumerNewDocument: new FormControl(null),
notificationsConsumerSuccess: new FormControl(null),
@@ -129,6 +130,8 @@ export class SettingsComponent
public systemStatus: SystemStatus
public readonly GlobalSearchType = GlobalSearchType
get systemStatusHasErrors(): boolean {
return (
this.systemStatus.database.status === SystemStatusItemStatus.ERROR ||
@@ -306,6 +309,7 @@ export class SettingsComponent
SETTINGS_KEYS.DOCUMENT_EDITING_REMOVE_INBOX_TAGS
),
searchDbOnly: this.settings.get(SETTINGS_KEYS.SEARCH_DB_ONLY),
searchLink: this.settings.get(SETTINGS_KEYS.SEARCH_FULL_TYPE),
savedViews: {},
}
}
@@ -539,6 +543,10 @@ export class SettingsComponent
SETTINGS_KEYS.SEARCH_DB_ONLY,
this.settingsForm.value.searchDbOnly
)
this.settings.set(
SETTINGS_KEYS.SEARCH_FULL_TYPE,
this.settingsForm.value.searchLink
)
this.settings.setLanguage(this.settingsForm.value.displayLanguage)
this.settings
.storeSettings()

View File

@@ -19,8 +19,12 @@
</div>
</div>
@if (query) {
<button class="btn btn-sm btn-outline-secondary" type="button" (click)="runAdvanedSearch()">
<ng-container i18n>Advanced search</ng-container>
<button class="btn btn-sm btn-outline-secondary" type="button" (click)="runFullSearch()">
@if (useAdvancedForFullSearch) {
<ng-container i18n>Advanced search</ng-container>
} @else {
<ng-container i18n>Search</ng-container>
}
<i-bs width="1em" height="1em" name="arrow-right-short"></i-bs>
</button>
}

View File

@@ -25,6 +25,7 @@ import {
FILTER_HAS_DOCUMENT_TYPE_ANY,
FILTER_HAS_STORAGE_PATH_ANY,
FILTER_HAS_TAGS_ALL,
FILTER_TITLE_CONTENT,
} from 'src/app/data/filter-rule-type'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
import { DocumentService } from 'src/app/services/rest/document.service'
@@ -37,6 +38,8 @@ import { ElementRef } from '@angular/core'
import { ToastService } from 'src/app/services/toast.service'
import { DataType } from 'src/app/data/datatype'
import { queryParamsFromFilterRules } from 'src/app/utils/query-params'
import { SettingsService } from 'src/app/services/settings.service'
import { GlobalSearchType, SETTINGS_KEYS } from 'src/app/data/ui-settings'
const searchResults = {
total: 11,
@@ -130,6 +133,7 @@ describe('GlobalSearchComponent', () => {
let documentService: DocumentService
let documentListViewService: DocumentListViewService
let toastService: ToastService
let settingsService: SettingsService
beforeEach(async () => {
await TestBed.configureTestingModule({
@@ -150,6 +154,7 @@ describe('GlobalSearchComponent', () => {
documentService = TestBed.inject(DocumentService)
documentListViewService = TestBed.inject(DocumentListViewService)
toastService = TestBed.inject(ToastService)
settingsService = TestBed.inject(SettingsService)
fixture = TestBed.createComponent(GlobalSearchComponent)
component = fixture.componentInstance
@@ -262,7 +267,7 @@ describe('GlobalSearchComponent', () => {
component.searchResults = searchResults as any
component.resultsDropdown.open()
component.query = 'test'
const advancedSearchSpy = jest.spyOn(component, 'runAdvanedSearch')
const advancedSearchSpy = jest.spyOn(component, 'runFullSearch')
component.searchInputKeyDown(new KeyboardEvent('keydown', { key: 'Enter' }))
expect(advancedSearchSpy).toHaveBeenCalled()
})
@@ -499,15 +504,6 @@ describe('GlobalSearchComponent', () => {
expect(focusSpy).toHaveBeenCalled()
})
it('should support explicit advanced search', () => {
const qfSpy = jest.spyOn(documentListViewService, 'quickFilter')
component.query = 'test'
component.runAdvanedSearch()
expect(qfSpy).toHaveBeenCalledWith([
{ rule_type: FILTER_FULLTEXT_QUERY, value: 'test' },
])
})
it('should support open in new window', () => {
const openSpy = jest.spyOn(window, 'open')
const event = new Event('click')
@@ -528,4 +524,23 @@ describe('GlobalSearchComponent', () => {
button.dispatchEvent(keyboardEvent)
expect(dispatchSpy).toHaveBeenCalledTimes(2) // once for keydown, second for click
})
it('should support title content search and advanced search', () => {
const qfSpy = jest.spyOn(documentListViewService, 'quickFilter')
component.query = 'test'
component.runFullSearch()
expect(qfSpy).toHaveBeenCalledWith([
{ rule_type: FILTER_TITLE_CONTENT, value: 'test' },
])
settingsService.set(
SETTINGS_KEYS.SEARCH_FULL_TYPE,
GlobalSearchType.ADVANCED
)
component.query = 'test'
component.runFullSearch()
expect(qfSpy).toHaveBeenCalledWith([
{ rule_type: FILTER_FULLTEXT_QUERY, value: 'test' },
])
})
})

View File

@@ -15,6 +15,7 @@ import {
FILTER_HAS_DOCUMENT_TYPE_ANY,
FILTER_HAS_STORAGE_PATH_ANY,
FILTER_HAS_TAGS_ALL,
FILTER_TITLE_CONTENT,
} from 'src/app/data/filter-rule-type'
import { DataType } from 'src/app/data/datatype'
import { ObjectWithId } from 'src/app/data/object-with-id'
@@ -42,6 +43,8 @@ import { UserEditDialogComponent } from '../../common/edit-dialog/user-edit-dial
import { WorkflowEditDialogComponent } from '../../common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component'
import { HotKeyService } from 'src/app/services/hot-key.service'
import { paramsFromViewState } from 'src/app/utils/query-params'
import { SettingsService } from 'src/app/services/settings.service'
import { GlobalSearchType, SETTINGS_KEYS } from 'src/app/data/ui-settings'
@Component({
selector: 'pngx-global-search',
@@ -63,6 +66,13 @@ export class GlobalSearchComponent implements OnInit {
@ViewChildren('primaryButton') primaryButtons: QueryList<ElementRef>
@ViewChildren('secondaryButton') secondaryButtons: QueryList<ElementRef>
get useAdvancedForFullSearch(): boolean {
return (
this.settingsService.get(SETTINGS_KEYS.SEARCH_FULL_TYPE) ===
GlobalSearchType.ADVANCED
)
}
constructor(
public searchService: SearchService,
private router: Router,
@@ -71,7 +81,8 @@ export class GlobalSearchComponent implements OnInit {
private documentListViewService: DocumentListViewService,
private permissionsService: PermissionsService,
private toastService: ToastService,
private hotkeyService: HotKeyService
private hotkeyService: HotKeyService,
private settingsService: SettingsService
) {
this.queryDebounce = new Subject<string>()
@@ -282,7 +293,7 @@ export class GlobalSearchComponent implements OnInit {
this.primaryButtons.first.nativeElement.click()
this.searchInput.nativeElement.blur()
} else if (this.query?.length) {
this.runAdvanedSearch()
this.runFullSearch()
this.reset(true)
}
} else if (event.key === 'Escape' && !this.resultsDropdown.isOpen()) {
@@ -378,9 +389,12 @@ export class GlobalSearchComponent implements OnInit {
)
}
public runAdvanedSearch() {
public runFullSearch() {
const ruleType = this.useAdvancedForFullSearch
? FILTER_FULLTEXT_QUERY
: FILTER_TITLE_CONTENT
this.documentListViewService.quickFilter([
{ rule_type: FILTER_FULLTEXT_QUERY, value: this.query },
{ rule_type: ruleType, value: this.query },
])
this.reset(true)
}

View File

@@ -12,6 +12,11 @@ export interface UiSetting {
default: any
}
export enum GlobalSearchType {
ADVANCED = 'advanced',
TITLE_CONTENT = 'title-content',
}
export const SETTINGS_KEYS = {
LANGUAGE: 'language',
APP_LOGO: 'app_logo',
@@ -57,6 +62,7 @@ export const SETTINGS_KEYS = {
DOCUMENT_EDITING_REMOVE_INBOX_TAGS:
'general-settings:document-editing:remove-inbox-tags',
SEARCH_DB_ONLY: 'general-settings:search:db-only',
SEARCH_FULL_TYPE: 'general-settings:search:more-link',
}
export const SETTINGS: UiSetting[] = [
@@ -225,4 +231,9 @@ export const SETTINGS: UiSetting[] = [
type: 'boolean',
default: false,
},
{
key: SETTINGS_KEYS.SEARCH_FULL_TYPE,
type: 'string',
default: GlobalSearchType.TITLE_CONTENT,
},
]