Enhancement: auto-focus default select field in custom field dropdown (#7961)

This commit is contained in:
shamoon 2024-10-18 22:35:57 -07:00 committed by GitHub
parent f0ad073bb2
commit 71e2565386
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 61 additions and 18 deletions

View File

@ -41,7 +41,7 @@
<option value="false" i18n>False</option> <option value="false" i18n>False</option>
</select> </select>
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Select) { } @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Select) {
<ng-select <ng-select #fieldSelects
class="paperless-input-select rounded-end" class="paperless-input-select rounded-end"
[items]="getSelectOptionsForField(atom.field)" [items]="getSelectOptionsForField(atom.field)"
[(ngModel)]="atom.value" [(ngModel)]="atom.value"

View File

@ -1,4 +1,9 @@
import { ComponentFixture, TestBed } from '@angular/core/testing' import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
} from '@angular/core/testing'
import { import {
CustomFieldQueriesModel, CustomFieldQueriesModel,
CustomFieldsQueryDropdownComponent, CustomFieldsQueryDropdownComponent,
@ -20,6 +25,8 @@ import {
CustomFieldQueryAtom, CustomFieldQueryAtom,
CustomFieldQueryElement, CustomFieldQueryElement,
} from 'src/app/utils/custom-field-query-element' } from 'src/app/utils/custom-field-query-element'
import { NgSelectModule } from '@ng-select/ng-select'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
const customFields = [ const customFields = [
{ {
@ -44,7 +51,13 @@ describe('CustomFieldsQueryDropdownComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [CustomFieldsQueryDropdownComponent], declarations: [CustomFieldsQueryDropdownComponent],
imports: [NgbDropdownModule, NgxBootstrapIconsModule.pick(allIcons)], imports: [
NgbDropdownModule,
NgxBootstrapIconsModule.pick(allIcons),
NgSelectModule,
FormsModule,
ReactiveFormsModule,
],
providers: [ providers: [
provideHttpClient(withInterceptorsFromDi()), provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting(), provideHttpClientTesting(),
@ -181,6 +194,15 @@ describe('CustomFieldsQueryDropdownComponent', () => {
expect(component.name).toBe('test_title') expect(component.name).toBe('test_title')
}) })
it('should add a default atom on open and focus the select field', fakeAsync(() => {
expect(component.selectionModel.queries.length).toBe(0)
component.onOpenChange(true)
fixture.detectChanges()
tick()
expect(component.selectionModel.queries.length).toBe(1)
expect(window.document.activeElement.tagName).toBe('INPUT')
}))
describe('CustomFieldQueriesModel', () => { describe('CustomFieldQueriesModel', () => {
let model: CustomFieldQueriesModel let model: CustomFieldQueriesModel

View File

@ -4,9 +4,12 @@ import {
Input, Input,
OnDestroy, OnDestroy,
Output, Output,
QueryList,
ViewChild, ViewChild,
ViewChildren,
} from '@angular/core' } from '@angular/core'
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectComponent } from '@ng-select/ng-select'
import { Subject, first, takeUntil } from 'rxjs' import { Subject, first, takeUntil } from 'rxjs'
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field' import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
import { import {
@ -184,6 +187,8 @@ export class CustomFieldsQueryDropdownComponent implements OnDestroy {
@ViewChild('dropdown') dropdown: NgbDropdown @ViewChild('dropdown') dropdown: NgbDropdown
@ViewChildren(NgSelectComponent) fieldSelects!: QueryList<NgSelectComponent>
private _selectionModel: CustomFieldQueriesModel private _selectionModel: CustomFieldQueriesModel
@Input() @Input()
@ -227,16 +232,32 @@ export class CustomFieldsQueryDropdownComponent implements OnDestroy {
} }
public onOpenChange(open: boolean) { public onOpenChange(open: boolean) {
if (open && this.selectionModel.queries.length === 0) { if (open) {
this.selectionModel.addExpression() if (this.selectionModel.queries.length === 0) {
this.selectionModel.addAtom(
new CustomFieldQueryAtom([
null,
CustomFieldQueryOperator.Exists,
'true',
])
)
}
if (
this.selectionModel.queries.length === 1 &&
(
(this.selectionModel.queries[0] as CustomFieldQueryExpression)
?.value[0] as CustomFieldQueryAtom
)?.field === null
) {
setTimeout(() => {
this.fieldSelects.first?.focus()
}, 0)
}
} }
} }
public get isActive(): boolean { public get isActive(): boolean {
return ( return this.selectionModel.isValid()
(this.selectionModel.queries[0] as CustomFieldQueryExpression)?.value
?.length > 0
)
} }
private getFields() { private getFields() {

View File

@ -101,7 +101,10 @@ import {
CustomFieldQueryLogicalOperator, CustomFieldQueryLogicalOperator,
CustomFieldQueryOperator, CustomFieldQueryOperator,
} from 'src/app/data/custom-field-query' } from 'src/app/data/custom-field-query'
import { CustomFieldQueryAtom } from 'src/app/utils/custom-field-query-element' import {
CustomFieldQueryAtom,
CustomFieldQueryExpression,
} from 'src/app/utils/custom-field-query-element'
const tags: Tag[] = [ const tags: Tag[] = [
{ {
@ -1441,15 +1444,12 @@ describe('FilterEditorComponent', () => {
By.css('button') By.css('button')
) )
customFieldToggleButton.triggerEventHandler('click') customFieldToggleButton.triggerEventHandler('click')
tick()
fixture.detectChanges() fixture.detectChanges()
const customFieldButtons = customFieldsQueryDropdown.queryAll( const expression = component.customFieldQueriesModel
By.css('button') .queries[0] as CustomFieldQueryExpression
) const atom = expression.value[0] as CustomFieldQueryAtom
customFieldButtons[1].triggerEventHandler('click') atom.field = custom_fields[0].id
fixture.detectChanges()
const query = component.customFieldQueriesModel
.queries[0] as CustomFieldQueryAtom
query.field = custom_fields[0].id
const fieldSelect: NgSelectComponent = customFieldsQueryDropdown.queryAll( const fieldSelect: NgSelectComponent = customFieldsQueryDropdown.queryAll(
By.directive(NgSelectComponent) By.directive(NgSelectComponent)
)[0].componentInstance )[0].componentInstance