Tweakhancement: reset to page 1 on reset filters (#12143)

This commit is contained in:
shamoon
2026-02-22 15:17:02 -08:00
committed by GitHub
parent 095ea3cbd3
commit d6cd6d0311
7 changed files with 93 additions and 21 deletions

View File

@@ -117,7 +117,7 @@
</pngx-page-header> </pngx-page-header>
<div class="row sticky-top py-3 mt-n2 mt-md-n3 bg-body"> <div class="row sticky-top py-3 mt-n2 mt-md-n3 bg-body">
<pngx-filter-editor [hidden]="isBulkEditing" [disabled]="isBulkEditing" [(filterRules)]="list.filterRules" [unmodifiedFilterRules]="unmodifiedFilterRules" [selectionData]="list.selectionData" #filterEditor></pngx-filter-editor> <pngx-filter-editor [hidden]="isBulkEditing" [disabled]="isBulkEditing" [filterRules]="list.filterRules" (filterRulesChange)="onFilterRulesChange($event)" (resetFilterRules)="onFilterRulesReset($event)" [unmodifiedFilterRules]="unmodifiedFilterRules" [selectionData]="list.selectionData" #filterEditor></pngx-filter-editor>
<pngx-bulk-editor [hidden]="!isBulkEditing" [disabled]="!isBulkEditing"></pngx-bulk-editor> <pngx-bulk-editor [hidden]="!isBulkEditing" [disabled]="!isBulkEditing"></pngx-bulk-editor>
</div> </div>

View File

@@ -147,21 +147,21 @@ describe('DocumentListComponent', () => {
}) })
it('should show score sort fields on fulltext queries', () => { it('should show score sort fields on fulltext queries', () => {
documentListService.filterRules = [ documentListService.setFilterRules([
{ {
rule_type: FILTER_HAS_TAGS_ANY, rule_type: FILTER_HAS_TAGS_ANY,
value: '10', value: '10',
}, },
] ])
fixture.detectChanges() fixture.detectChanges()
expect(component.getSortFields()).toEqual(documentListService.sortFields) expect(component.getSortFields()).toEqual(documentListService.sortFields)
documentListService.filterRules = [ documentListService.setFilterRules([
{ {
rule_type: FILTER_FULLTEXT_QUERY, rule_type: FILTER_FULLTEXT_QUERY,
value: 'foo', value: 'foo',
}, },
] ])
fixture.detectChanges() fixture.detectChanges()
expect(component.getSortFields()).toEqual( expect(component.getSortFields()).toEqual(
documentListService.sortFieldsFullText documentListService.sortFieldsFullText
@@ -170,12 +170,12 @@ describe('DocumentListComponent', () => {
it('should determine if filtered, support reset', () => { it('should determine if filtered, support reset', () => {
fixture.detectChanges() fixture.detectChanges()
documentListService.filterRules = [ documentListService.setFilterRules([
{ {
rule_type: FILTER_HAS_TAGS_ANY, rule_type: FILTER_HAS_TAGS_ANY,
value: '10', value: '10',
}, },
] ])
documentListService.isReloading = false documentListService.isReloading = false
fixture.detectChanges() fixture.detectChanges()
expect(component.isFiltered).toBeTruthy() expect(component.isFiltered).toBeTruthy()
@@ -185,6 +185,20 @@ describe('DocumentListComponent', () => {
expect(fixture.nativeElement.textContent.match(/Reset/g)).toHaveLength(1) expect(fixture.nativeElement.textContent.match(/Reset/g)).toHaveLength(1)
}) })
it('should apply filter rule changes via list service', () => {
const setFilterRulesSpy = jest.spyOn(documentListService, 'setFilterRules')
const rules = [{ rule_type: FILTER_HAS_TAGS_ANY, value: '10' }]
component.onFilterRulesChange(rules)
expect(setFilterRulesSpy).toHaveBeenCalledWith(rules)
})
it('should reset filter rules to page one via list service', () => {
const setFilterRulesSpy = jest.spyOn(documentListService, 'setFilterRules')
const rules = [{ rule_type: FILTER_HAS_TAGS_ANY, value: '10' }]
component.onFilterRulesReset(rules)
expect(setFilterRulesSpy).toHaveBeenCalledWith(rules, true)
})
it('should load saved view from URL', () => { it('should load saved view from URL', () => {
const view: SavedView = { const view: SavedView = {
id: 10, id: 10,
@@ -217,7 +231,7 @@ describe('DocumentListComponent', () => {
.spyOn(activatedRoute, 'paramMap', 'get') .spyOn(activatedRoute, 'paramMap', 'get')
.mockReturnValue(of(convertToParamMap(queryParams))) .mockReturnValue(of(convertToParamMap(queryParams)))
activatedRoute.snapshot.queryParams = queryParams activatedRoute.snapshot.queryParams = queryParams
fixture.detectChanges() component.ngOnInit()
expect(getSavedViewSpy).toHaveBeenCalledWith(view.id) expect(getSavedViewSpy).toHaveBeenCalledWith(view.id)
expect(activateSavedViewSpy).toHaveBeenCalledWith( expect(activateSavedViewSpy).toHaveBeenCalledWith(
view, view,

View File

@@ -212,6 +212,14 @@ export class DocumentListComponent
this.list.setSort(event.column, event.reverse) this.list.setSort(event.column, event.reverse)
} }
onFilterRulesChange(filterRules: FilterRule[]) {
this.list.setFilterRules(filterRules)
}
onFilterRulesReset(filterRules: FilterRule[]) {
this.list.setFilterRules(filterRules, true)
}
get isBulkEditing(): boolean { get isBulkEditing(): boolean {
return this.list.selected.size > 0 return this.list.selected.size > 0
} }
@@ -300,7 +308,7 @@ export class DocumentListComponent
if (this.list.selected.size > 0) { if (this.list.selected.size > 0) {
this.list.selectNone() this.list.selectNone()
} else if (this.isFiltered) { } else if (this.isFiltered) {
this.filterEditor.resetSelected() this.resetFilters()
} }
}) })

View File

@@ -2107,6 +2107,22 @@ describe('FilterEditorComponent', () => {
expect(component.filterRules).toEqual(rules) expect(component.filterRules).toEqual(rules)
}) })
it('should emit reset filter rules when resetting', () => {
const rules = [{ rule_type: FILTER_HAS_TAGS_ANY, value: '2' }]
component.unmodifiedFilterRules = rules
component.filterRules = [
{ rule_type: FILTER_DOES_NOT_HAVE_TAG, value: '2' },
]
const resetFilterRulesSpy = jest.spyOn(component.resetFilterRules, 'next')
const filterRulesChangeSpy = jest.spyOn(component.filterRulesChange, 'next')
component.resetSelected()
expect(resetFilterRulesSpy).toHaveBeenCalledWith(rules)
expect(filterRulesChangeSpy).not.toHaveBeenCalled()
})
it('should support resetting text field', () => { it('should support resetting text field', () => {
component.textFilter = 'foo' component.textFilter = 'foo'
component.resetTextField() component.resetTextField()

View File

@@ -1101,6 +1101,9 @@ export class FilterEditorComponent
@Output() @Output()
filterRulesChange = new EventEmitter<FilterRule[]>() filterRulesChange = new EventEmitter<FilterRule[]>()
@Output()
resetFilterRules = new EventEmitter<FilterRule[]>()
@Input() @Input()
set selectionData(selectionData: SelectionData) { set selectionData(selectionData: SelectionData) {
this.tagDocumentCounts = selectionData?.selected_tags ?? null this.tagDocumentCounts = selectionData?.selected_tags ?? null
@@ -1244,7 +1247,7 @@ export class FilterEditorComponent
this.textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT this.textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT
this.documentService.searchQuery = '' this.documentService.searchQuery = ''
this.filterRules = this._unmodifiedFilterRules this.filterRules = this._unmodifiedFilterRules
this.updateRules() this.resetFilterRules.next(this.filterRules)
} }
toggleTag(tagId: number) { toggleTag(tagId: number) {

View File

@@ -164,7 +164,7 @@ describe('DocumentListViewService', () => {
value: tags__id__in, value: tags__id__in,
}, },
] ]
documentListViewService.filterRules = filterRulesAny documentListViewService.setFilterRules(filterRulesAny)
let req = httpTestingController.expectOne( let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__in=${tags__id__in}` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__in=${tags__id__in}`
) )
@@ -178,7 +178,7 @@ describe('DocumentListViewService', () => {
) )
expect(req.request.method).toEqual('GET') expect(req.request.method).toEqual('GET')
// reset the list // reset the list
documentListViewService.filterRules = [] documentListViewService.setFilterRules([])
req = httpTestingController.expectOne( req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
) )
@@ -210,7 +210,7 @@ describe('DocumentListViewService', () => {
value: tags__id__in, value: tags__id__in,
}, },
] ]
documentListViewService.filterRules = filterRulesAny documentListViewService.setFilterRules(filterRulesAny)
let req = httpTestingController.expectOne( let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__in=${tags__id__in}` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__in=${tags__id__in}`
) )
@@ -218,7 +218,7 @@ describe('DocumentListViewService', () => {
req.flush('Generic error', { status: 404, statusText: 'Unexpected error' }) req.flush('Generic error', { status: 404, statusText: 'Unexpected error' })
expect(documentListViewService.error).toEqual('Generic error') expect(documentListViewService.error).toEqual('Generic error')
// reset the list // reset the list
documentListViewService.filterRules = [] documentListViewService.setFilterRules([])
req = httpTestingController.expectOne( req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
) )
@@ -295,13 +295,41 @@ describe('DocumentListViewService', () => {
}) })
it('should use filter rules to update query params', () => { it('should use filter rules to update query params', () => {
documentListViewService.filterRules = filterRules documentListViewService.setFilterRules(filterRules)
const req = httpTestingController.expectOne( const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.pageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}` `${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.pageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
) )
expect(req.request.method).toEqual('GET') expect(req.request.method).toEqual('GET')
}) })
it('should support setting filter rules and resetting to page one', () => {
documentListViewService.currentPage = 2
let req = httpTestingController.expectOne((request) =>
request.urlWithParams.startsWith(
`${environment.apiBaseUrl}documents/?page=2&page_size=50&ordering=-created&truncate_content=true`
)
)
expect(req.request.method).toEqual('GET')
req.flush(full_results)
req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/selection_data/`
)
req.flush([])
documentListViewService.setFilterRules(filterRules, true)
const filteredReqs = httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
)
expect(filteredReqs).toHaveLength(1)
filteredReqs[0].flush(full_results)
req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/selection_data/`
)
req.flush([])
expect(documentListViewService.currentPage).toEqual(1)
})
it('should support quick filter', () => { it('should support quick filter', () => {
documentListViewService.quickFilter(filterRules) documentListViewService.quickFilter(filterRules)
const req = httpTestingController.expectOne( const req = httpTestingController.expectOne(
@@ -336,7 +364,7 @@ describe('DocumentListViewService', () => {
req = httpTestingController.expectOne( req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-added&truncate_content=true&tags__id__all=9` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-added&truncate_content=true&tags__id__all=9`
) )
documentListViewService.filterRules = [] documentListViewService.setFilterRules([])
req = httpTestingController.expectOne( req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-added&truncate_content=true` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-added&truncate_content=true`
) )
@@ -348,7 +376,7 @@ describe('DocumentListViewService', () => {
}) })
it('should support navigating next / previous', () => { it('should support navigating next / previous', () => {
documentListViewService.filterRules = [] documentListViewService.setFilterRules([])
let req = httpTestingController.expectOne( let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
) )
@@ -558,7 +586,7 @@ describe('DocumentListViewService', () => {
req.flush(full_results) req.flush(full_results)
expect(documentListViewService.selected.size).toEqual(6) expect(documentListViewService.selected.size).toEqual(6)
documentListViewService.filterRules = filterRules documentListViewService.setFilterRules(filterRules)
httpTestingController.expectOne( httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__all=9` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__all=9`
) )
@@ -592,7 +620,7 @@ describe('DocumentListViewService', () => {
documentListViewService.loadSavedView(view2) documentListViewService.loadSavedView(view2)
expect(documentListViewService.sortField).toEqual('score') expect(documentListViewService.sortField).toEqual('score')
documentListViewService.filterRules = [] documentListViewService.setFilterRules([])
expect(documentListViewService.sortField).toEqual('created') expect(documentListViewService.sortField).toEqual('created')
httpTestingController.expectOne( httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true` `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`

View File

@@ -342,7 +342,7 @@ export class DocumentListViewService {
}) })
} }
set filterRules(filterRules: FilterRule[]) { setFilterRules(filterRules: FilterRule[], resetPage: boolean = false) {
if ( if (
!isFullTextFilterRule(filterRules) && !isFullTextFilterRule(filterRules) &&
this.activeListViewState.sortField == 'score' this.activeListViewState.sortField == 'score'
@@ -350,6 +350,9 @@ export class DocumentListViewService {
this.activeListViewState.sortField = 'created' this.activeListViewState.sortField = 'created'
} }
this.activeListViewState.filterRules = filterRules this.activeListViewState.filterRules = filterRules
if (resetPage) {
this.activeListViewState.currentPage = 1
}
this.reload() this.reload()
this.reduceSelectionToFilter() this.reduceSelectionToFilter()
this.saveDocumentListView() this.saveDocumentListView()
@@ -479,7 +482,7 @@ export class DocumentListViewService {
quickFilter(filterRules: FilterRule[]) { quickFilter(filterRules: FilterRule[]) {
this._activeSavedViewId = null this._activeSavedViewId = null
this.filterRules = filterRules this.setFilterRules(filterRules)
this.router.navigate(['documents']) this.router.navigate(['documents'])
} }