From e60a7df9a2586cefb7532a3854503c51d946068e Mon Sep 17 00:00:00 2001 From: Michael Shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 20 May 2022 15:16:17 -0700 Subject: [PATCH] Refactor query params service --- .../app-frame/app-frame.component.ts | 5 +- .../saved-view-widget.component.ts | 6 +- .../document-detail.component.ts | 6 +- .../document-list.component.html | 2 +- .../document-list/document-list.component.ts | 49 ++---- .../correspondent-list.component.ts | 6 +- .../document-type-list.component.ts | 6 +- .../management-list.component.ts | 6 +- .../storage-path-list.component.ts | 5 +- .../manage/tag-list/tag-list.component.ts | 6 +- .../services/document-list-view.service.ts | 98 +++++++---- .../src/app/services/query-params.service.ts | 163 ------------------ .../src/app/services/rest/document.service.ts | 4 +- src-ui/src/app/utils/query-params.ts | 100 +++++++++++ 14 files changed, 205 insertions(+), 257 deletions(-) delete mode 100644 src-ui/src/app/services/query-params.service.ts create mode 100644 src-ui/src/app/utils/query-params.ts diff --git a/src-ui/src/app/components/app-frame/app-frame.component.ts b/src-ui/src/app/components/app-frame/app-frame.component.ts index 675bfc920..0d43f17a2 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.ts +++ b/src-ui/src/app/components/app-frame/app-frame.component.ts @@ -22,7 +22,6 @@ import { RemoteVersionService, AppRemoteVersion, } from 'src/app/services/rest/remote-version.service' -import { QueryParamsService } from 'src/app/services/query-params.service' import { SettingsService } from 'src/app/services/settings.service' @Component({ @@ -38,7 +37,7 @@ export class AppFrameComponent { private searchService: SearchService, public savedViewService: SavedViewService, private remoteVersionService: RemoteVersionService, - private queryParamsService: QueryParamsService, + private list: DocumentListViewService, public settingsService: SettingsService ) { this.remoteVersionService @@ -94,7 +93,7 @@ export class AppFrameComponent { search() { this.closeMenu() - this.queryParamsService.navigateWithFilterRules([ + this.list.quickFilter([ { rule_type: FILTER_FULLTEXT_QUERY, value: (this.searchField.value as string).trim(), diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts index 94e0c4052..17a0d8c89 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts @@ -7,8 +7,8 @@ import { ConsumerStatusService } from 'src/app/services/consumer-status.service' import { DocumentService } from 'src/app/services/rest/document.service' import { PaperlessTag } from 'src/app/data/paperless-tag' import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type' -import { QueryParamsService } from 'src/app/services/query-params.service' import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' @Component({ selector: 'app-saved-view-widget', @@ -21,7 +21,7 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { constructor( private documentService: DocumentService, private router: Router, - private queryParamsService: QueryParamsService, + private list: DocumentListViewService, private consumerStatusService: ConsumerStatusService, public openDocumentsService: OpenDocumentsService ) {} @@ -73,7 +73,7 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { } clickTag(tag: PaperlessTag) { - this.queryParamsService.navigateWithFilterRules([ + this.list.quickFilter([ { rule_type: FILTER_HAS_TAGS_ALL, value: tag.id.toString() }, ]) } diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts index 6728f746d..c4255e9f7 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.ts @@ -32,7 +32,6 @@ import { import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' import { normalizeDateStr } from 'src/app/utils/date' -import { QueryParamsService } from 'src/app/services/query-params.service' import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path' import { StoragePathEditDialogComponent } from '../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component' @@ -120,8 +119,7 @@ export class DocumentDetailComponent private documentTitlePipe: DocumentTitlePipe, private toastService: ToastService, private settings: SettingsService, - private storagePathService: StoragePathService, - private queryParamsService: QueryParamsService + private storagePathService: StoragePathService ) {} titleKeyUp(event) { @@ -494,7 +492,7 @@ export class DocumentDetailComponent } moreLike() { - this.queryParamsService.navigateWithFilterRules([ + this.documentListViewService.quickFilter([ { rule_type: FILTER_FULLTEXT_MORELIKE, value: this.documentId.toString(), diff --git a/src-ui/src/app/components/document-list/document-list.component.html b/src-ui/src/app/components/document-list/document-list.component.html index e8cb78995..f812be217 100644 --- a/src-ui/src/app/components/document-list/document-list.component.html +++ b/src-ui/src/app/components/document-list/document-list.component.html @@ -93,7 +93,7 @@ {list.collectionSize, plural, =1 {One document} other {{{list.collectionSize || 0}} documents}} (filtered)

- diff --git a/src-ui/src/app/components/document-list/document-list.component.ts b/src-ui/src/app/components/document-list/document-list.component.ts index d9355902f..e27f14b14 100644 --- a/src-ui/src/app/components/document-list/document-list.component.ts +++ b/src-ui/src/app/components/document-list/document-list.component.ts @@ -1,5 +1,4 @@ import { - AfterViewInit, Component, OnDestroy, OnInit, @@ -21,7 +20,6 @@ import { import { ConsumerStatusService } from 'src/app/services/consumer-status.service' import { DocumentListViewService } from 'src/app/services/document-list-view.service' import { OpenDocumentsService } from 'src/app/services/open-documents.service' -import { QueryParamsService } from 'src/app/services/query-params.service' import { DOCUMENT_SORT_FIELDS, DOCUMENT_SORT_FIELDS_FULLTEXT, @@ -36,7 +34,7 @@ import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-vi templateUrl: './document-list.component.html', styleUrls: ['./document-list.component.scss'], }) -export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { +export class DocumentListComponent implements OnInit, OnDestroy { constructor( public list: DocumentListViewService, public savedViewService: SavedViewService, @@ -45,7 +43,6 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { private toastService: ToastService, private modalService: NgbModal, private consumerStatusService: ConsumerStatusService, - private queryParamsService: QueryParamsService, public openDocumentsService: OpenDocumentsService ) {} @@ -76,8 +73,6 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { set listSort(reverse: boolean) { this.list.sortReverse = reverse - this.queryParamsService.sortField = this.list.sortField - this.queryParamsService.sortReverse = reverse } get listSort(): boolean { @@ -86,14 +81,14 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { setSortField(field: string) { this.list.sortField = field - this.queryParamsService.sortField = field - this.queryParamsService.sortReverse = this.listSort } onSort(event: SortEvent) { this.list.setSort(event.column, event.reverse) - this.queryParamsService.sortField = event.column - this.queryParamsService.sortReverse = event.reverse + } + + setPage(page: number) { + this.list.currentPage = page } get isBulkEditing(): boolean { @@ -133,7 +128,6 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { } this.list.activateSavedView(view) this.list.reload() - this.queryParamsService.updateFromView(view) this.unmodifiedFilterRules = view.filter_rules }) @@ -148,22 +142,12 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { this.loadViewConfig(parseInt(queryParams.get('view'))) } else { this.list.activateSavedView(null) - this.queryParamsService.parseQueryParams(queryParams) + this.list.loadFromQueryParams(queryParams) this.unmodifiedFilterRules = [] } }) } - ngAfterViewInit(): void { - this.filterEditor.filterRulesChange - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe({ - next: (filterRules) => { - this.queryParamsService.updateFilterRules(filterRules) - }, - }) - } - ngOnDestroy() { // unsubscribes all this.unsubscribeNotifier.next(this) @@ -175,9 +159,8 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { .getCached(viewId) .pipe(first()) .subscribe((view) => { - this.list.loadSavedView(view) + this.list.activateSavedView(view) this.list.reload() - this.queryParamsService.updateFromView(view) }) } @@ -246,34 +229,26 @@ export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { clickTag(tagID: number) { this.list.selectNone() - setTimeout(() => { - this.filterEditor.addTag(tagID) - }) + this.filterEditor.addTag(tagID) } clickCorrespondent(correspondentID: number) { this.list.selectNone() - setTimeout(() => { - this.filterEditor.addCorrespondent(correspondentID) - }) + this.filterEditor.addCorrespondent(correspondentID) } clickDocumentType(documentTypeID: number) { this.list.selectNone() - setTimeout(() => { - this.filterEditor.addDocumentType(documentTypeID) - }) + this.filterEditor.addDocumentType(documentTypeID) } clickStoragePath(storagePathID: number) { this.list.selectNone() - setTimeout(() => { - this.filterEditor.addStoragePath(storagePathID) - }) + this.filterEditor.addStoragePath(storagePathID) } clickMoreLike(documentID: number) { - this.queryParamsService.navigateWithFilterRules([ + this.list.quickFilter([ { rule_type: FILTER_FULLTEXT_MORELIKE, value: documentID.toString() }, ]) } diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts b/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts index 9eb05758c..983c36290 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts +++ b/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts @@ -3,7 +3,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { FILTER_CORRESPONDENT } from 'src/app/data/filter-rule-type' import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' -import { QueryParamsService } from 'src/app/services/query-params.service' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' import { CorrespondentService } from 'src/app/services/rest/correspondent.service' import { ToastService } from 'src/app/services/toast.service' import { CorrespondentEditDialogComponent } from '../../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component' @@ -20,7 +20,7 @@ export class CorrespondentListComponent extends ManagementListComponent private modalService: NgbModal, private editDialogComponent: any, private toastService: ToastService, - private queryParamsService: QueryParamsService, + private documentListViewService: DocumentListViewService, protected filterRuleType: number, public typeName: string, public typeNamePlural: string, @@ -141,7 +141,7 @@ export abstract class ManagementListComponent } filterDocuments(object: ObjectWithId) { - this.queryParamsService.navigateWithFilterRules([ + this.documentListViewService.quickFilter([ { rule_type: this.filterRuleType, value: object.id.toString() }, ]) } diff --git a/src-ui/src/app/components/manage/storage-path-list/storage-path-list.component.ts b/src-ui/src/app/components/manage/storage-path-list/storage-path-list.component.ts index dc363c4d5..1d7b726a0 100644 --- a/src-ui/src/app/components/manage/storage-path-list/storage-path-list.component.ts +++ b/src-ui/src/app/components/manage/storage-path-list/storage-path-list.component.ts @@ -3,7 +3,6 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { FILTER_STORAGE_PATH } from 'src/app/data/filter-rule-type' import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path' import { DocumentListViewService } from 'src/app/services/document-list-view.service' -import { QueryParamsService } from 'src/app/services/query-params.service' import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { ToastService } from 'src/app/services/toast.service' import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component' @@ -19,14 +18,14 @@ export class StoragePathListComponent extends ManagementListComponent { tagService: TagService, modalService: NgbModal, toastService: ToastService, - queryParamsService: QueryParamsService + documentListViewService: DocumentListViewService ) { super( tagService, modalService, TagEditDialogComponent, toastService, - queryParamsService, + documentListViewService, FILTER_HAS_TAGS_ALL, $localize`tag`, $localize`tags`, diff --git a/src-ui/src/app/services/document-list-view.service.ts b/src-ui/src/app/services/document-list-view.service.ts index 471fc7944..52a0de296 100644 --- a/src-ui/src/app/services/document-list-view.service.ts +++ b/src-ui/src/app/services/document-list-view.service.ts @@ -10,13 +10,14 @@ import { PaperlessDocument } from '../data/paperless-document' import { PaperlessSavedView } from '../data/paperless-saved-view' import { SETTINGS_KEYS } from '../data/paperless-uisettings' import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys' +import { generateParams, parseQueryParams } from '../utils/query-params' import { DocumentService, DOCUMENT_SORT_FIELDS } from './rest/document.service' import { SettingsService } from './settings.service' /** * Captures the current state of the list view. */ -interface ListViewState { +export interface ListViewState { /** * Title of the document list view. Either "Documents" (localized) or the name of a saved view. */ @@ -32,7 +33,7 @@ interface ListViewState { /** * Total amount of documents with the current filter rules. Used to calculate the number of pages. */ - collectionSize: number + collectionSize?: number /** * Currently selected sort field. @@ -85,6 +86,32 @@ export class DocumentListViewService { return this.activeListViewState.title } + constructor( + private documentService: DocumentService, + private settings: SettingsService, + private router: Router + ) { + let documentListViewConfigJson = localStorage.getItem( + DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG + ) + if (documentListViewConfigJson) { + try { + let savedState: ListViewState = JSON.parse(documentListViewConfigJson) + // Remove null elements from the restored state + Object.keys(savedState).forEach((k) => { + if (savedState[k] == null) { + delete savedState[k] + } + }) + //only use restored state attributes instead of defaults if they are not null + let newState = Object.assign(this.defaultListViewState(), savedState) + this.listViewStates.set(null, newState) + } catch (e) { + localStorage.removeItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) + } + } + } + private defaultListViewState(): ListViewState { return { title: null, @@ -122,20 +149,36 @@ export class DocumentListViewService { if (closeCurrentView) { this._activeSavedViewId = null } + this.activeListViewState.filterRules = cloneFilterRules(view.filter_rules) this.activeListViewState.sortField = view.sort_field this.activeListViewState.sortReverse = view.sort_reverse if (this._activeSavedViewId) { this.activeListViewState.title = view.name } + this.reduceSelectionToFilter() + + if (!this.router.routerState.snapshot.url.includes('/view/')) { + this.router.navigate([], { + queryParams: { view: view.id }, + }) + } } - reload(onFinish?) { + loadFromQueryParams(queryParams) { + let newState: ListViewState = parseQueryParams(queryParams) + this.activeListViewState.filterRules = newState.filterRules + this.activeListViewState.sortField = newState.sortField + this.activeListViewState.sortReverse = newState.sortReverse + this.activeListViewState.currentPage = newState.currentPage + this.reload(null, false) + } + + reload(onFinish?, updateQueryParams: boolean = true) { this.isReloading = true this.error = null let activeListViewState = this.activeListViewState - this.documentService .listFiltered( activeListViewState.currentPage, @@ -149,6 +192,19 @@ export class DocumentListViewService { this.isReloading = false activeListViewState.collectionSize = result.count activeListViewState.documents = result.results + + if (updateQueryParams && !this._activeSavedViewId) { + let base = ['/documents'] + this.router.navigate(base, { + queryParams: generateParams( + activeListViewState.filterRules, + activeListViewState.sortField, + activeListViewState.sortReverse, + activeListViewState.currentPage + ), + }) + } + if (onFinish) { onFinish() } @@ -191,6 +247,7 @@ export class DocumentListViewService { ) { this.activeListViewState.sortField = 'created' } + this._activeSavedViewId = null this.activeListViewState.filterRules = filterRules this.reload() this.reduceSelectionToFilter() @@ -202,6 +259,7 @@ export class DocumentListViewService { } set sortField(field: string) { + this._activeSavedViewId = null this.activeListViewState.sortField = field this.reload() this.saveDocumentListView() @@ -212,6 +270,7 @@ export class DocumentListViewService { } set sortReverse(reverse: boolean) { + this._activeSavedViewId = null this.activeListViewState.sortReverse = reverse this.reload() this.saveDocumentListView() @@ -237,6 +296,8 @@ export class DocumentListViewService { } set currentPage(page: number) { + if (this.activeListViewState.currentPage == page) return + this._activeSavedViewId = null this.activeListViewState.currentPage = page this.reload() this.saveDocumentListView() @@ -273,6 +334,10 @@ export class DocumentListViewService { } } + quickFilter(filterRules: FilterRule[]) { + this.filterRules = filterRules + } + getLastPage(): number { return Math.ceil(this.collectionSize / this.currentPageSize) } @@ -431,29 +496,4 @@ export class DocumentListViewService { documentIndexInCurrentView(documentID: number): number { return this.documents.map((d) => d.id).indexOf(documentID) } - - constructor( - private documentService: DocumentService, - private settings: SettingsService - ) { - let documentListViewConfigJson = localStorage.getItem( - DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG - ) - if (documentListViewConfigJson) { - try { - let savedState: ListViewState = JSON.parse(documentListViewConfigJson) - // Remove null elements from the restored state - Object.keys(savedState).forEach((k) => { - if (savedState[k] == null) { - delete savedState[k] - } - }) - //only use restored state attributes instead of defaults if they are not null - let newState = Object.assign(this.defaultListViewState(), savedState) - this.listViewStates.set(null, newState) - } catch (e) { - localStorage.removeItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) - } - } - } } diff --git a/src-ui/src/app/services/query-params.service.ts b/src-ui/src/app/services/query-params.service.ts deleted file mode 100644 index 888440aae..000000000 --- a/src-ui/src/app/services/query-params.service.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { Injectable } from '@angular/core' -import { ParamMap, Params, Router } from '@angular/router' -import { FilterRule } from '../data/filter-rule' -import { FilterRuleType, FILTER_RULE_TYPES } from '../data/filter-rule-type' -import { PaperlessSavedView } from '../data/paperless-saved-view' -import { DocumentListViewService } from './document-list-view.service' - -const SORT_FIELD_PARAMETER = 'sort' -const SORT_REVERSE_PARAMETER = 'reverse' - -@Injectable({ - providedIn: 'root', -}) -export class QueryParamsService { - constructor(private router: Router, private list: DocumentListViewService) {} - - private filterParams: Params = {} - private sortParams: Params = {} - - updateFilterRules( - filterRules: FilterRule[], - updateQueryParams: boolean = true - ) { - this.filterParams = filterRulesToQueryParams(filterRules) - if (updateQueryParams) this.updateQueryParams() - } - - set sortField(field: string) { - this.sortParams[SORT_FIELD_PARAMETER] = field - this.updateQueryParams() - } - - set sortReverse(reverse: boolean) { - if (!reverse) this.sortParams[SORT_REVERSE_PARAMETER] = undefined - else this.sortParams[SORT_REVERSE_PARAMETER] = reverse - this.updateQueryParams() - } - - get params(): Params { - return { - ...this.sortParams, - ...this.filterParams, - } - } - - private updateQueryParams() { - // if we were on a saved view we navigate 'away' to /documents - let base = [] - if (this.router.routerState.snapshot.url.includes('/view/')) - base = ['/documents'] - - this.router.navigate(base, { - queryParams: this.params, - }) - } - - public parseQueryParams(queryParams: ParamMap) { - let filterRules = filterRulesFromQueryParams(queryParams) - if ( - filterRules.length || - queryParams.has(SORT_FIELD_PARAMETER) || - queryParams.has(SORT_REVERSE_PARAMETER) - ) { - this.list.filterRules = filterRules - this.list.sortField = queryParams.get(SORT_FIELD_PARAMETER) - this.list.sortReverse = - queryParams.has(SORT_REVERSE_PARAMETER) || - (!queryParams.has(SORT_FIELD_PARAMETER) && - !queryParams.has(SORT_REVERSE_PARAMETER)) - this.list.reload() - } else if ( - filterRules.length == 0 && - !queryParams.has(SORT_FIELD_PARAMETER) - ) { - // this is navigating to /documents so we need to update the params from the list - this.updateFilterRules(this.list.filterRules, false) - this.sortParams[SORT_FIELD_PARAMETER] = this.list.sortField - this.sortParams[SORT_REVERSE_PARAMETER] = this.list.sortReverse - this.router.navigate([], { - queryParams: this.params, - replaceUrl: true, - }) - } - } - - updateFromView(view: PaperlessSavedView) { - if (!this.router.routerState.snapshot.url.includes('/view/')) { - // navigation for /documents?view= - this.router.navigate([], { - queryParams: { view: view.id }, - }) - } - // make sure params are up-to-date - this.updateFilterRules(view.filter_rules, false) - this.sortParams[SORT_FIELD_PARAMETER] = this.list.sortField - this.sortParams[SORT_REVERSE_PARAMETER] = this.list.sortReverse - } - - navigateWithFilterRules(filterRules: FilterRule[]) { - this.updateFilterRules(filterRules) - this.router.navigate(['/documents'], { - queryParams: this.params, - }) - } -} - -export function filterRulesToQueryParams(filterRules: FilterRule[]): Object { - if (filterRules) { - let params = {} - for (let rule of filterRules) { - let ruleType = FILTER_RULE_TYPES.find((t) => t.id == rule.rule_type) - if (ruleType.multi) { - params[ruleType.filtervar] = params[ruleType.filtervar] - ? params[ruleType.filtervar] + ',' + rule.value - : rule.value - } else if (ruleType.isnull_filtervar && rule.value == null) { - params[ruleType.isnull_filtervar] = true - } else { - params[ruleType.filtervar] = rule.value - } - } - return params - } else { - return null - } -} - -export function filterRulesFromQueryParams(queryParams: ParamMap) { - const allFilterRuleQueryParams: string[] = FILTER_RULE_TYPES.map( - (rt) => rt.filtervar - ) - .concat(FILTER_RULE_TYPES.map((rt) => rt.isnull_filtervar)) - .filter((rt) => rt !== undefined) - - // transform query params to filter rules - let filterRulesFromQueryParams: FilterRule[] = [] - allFilterRuleQueryParams - .filter((frqp) => queryParams.has(frqp)) - .forEach((filterQueryParamName) => { - const rule_type: FilterRuleType = FILTER_RULE_TYPES.find( - (rt) => - rt.filtervar == filterQueryParamName || - rt.isnull_filtervar == filterQueryParamName - ) - const isNullRuleType = rule_type.isnull_filtervar == filterQueryParamName - const valueURIComponent: string = queryParams.get(filterQueryParamName) - const filterQueryParamValues: string[] = rule_type.multi - ? valueURIComponent.split(',') - : [valueURIComponent] - - filterRulesFromQueryParams = filterRulesFromQueryParams.concat( - // map all values to filter rules - filterQueryParamValues.map((val) => { - return { - rule_type: rule_type.id, - value: isNullRuleType ? null : val, - } - }) - ) - }) - - return filterRulesFromQueryParams -} diff --git a/src-ui/src/app/services/rest/document.service.ts b/src-ui/src/app/services/rest/document.service.ts index 8d5f80c04..190212084 100644 --- a/src-ui/src/app/services/rest/document.service.ts +++ b/src-ui/src/app/services/rest/document.service.ts @@ -11,7 +11,7 @@ import { CorrespondentService } from './correspondent.service' import { DocumentTypeService } from './document-type.service' import { TagService } from './tag.service' import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' -import { filterRulesToQueryParams } from '../query-params.service' +import { queryParamsFromFilterRules } from '../../utils/query-params' import { StoragePathService } from './storage-path.service' export const DOCUMENT_SORT_FIELDS = [ @@ -91,7 +91,7 @@ export class DocumentService extends AbstractPaperlessService pageSize, sortField, sortReverse, - Object.assign(extraParams, filterRulesToQueryParams(filterRules)) + Object.assign(extraParams, queryParamsFromFilterRules(filterRules)) ).pipe( map((results) => { results.results.forEach((doc) => this.addObservablesToDocument(doc)) diff --git a/src-ui/src/app/utils/query-params.ts b/src-ui/src/app/utils/query-params.ts new file mode 100644 index 000000000..a26093398 --- /dev/null +++ b/src-ui/src/app/utils/query-params.ts @@ -0,0 +1,100 @@ +import { ParamMap, Params } from '@angular/router' +import { FilterRule } from '../data/filter-rule' +import { FilterRuleType, FILTER_RULE_TYPES } from '../data/filter-rule-type' +import { ListViewState } from '../services/document-list-view.service' + +const SORT_FIELD_PARAMETER = 'sort' +const SORT_REVERSE_PARAMETER = 'reverse' +const PAGE_PARAMETER = 'page' + +export function generateParams( + filterRules: FilterRule[], + sortField: string, + sortReverse: boolean, + currentPage: number +): Params { + let params = {} + params[SORT_FIELD_PARAMETER] = sortField + params[SORT_REVERSE_PARAMETER] = sortReverse + params[PAGE_PARAMETER] = isNaN(currentPage) ? 1 : currentPage + return { + ...queryParamsFromFilterRules(filterRules), + ...params, + } +} + +export function parseQueryParams(queryParams: ParamMap): ListViewState { + let filterRules = filterRulesFromQueryParams(queryParams) + let sortField = queryParams.get(SORT_FIELD_PARAMETER) + let sortReverse = + queryParams.has(SORT_REVERSE_PARAMETER) || + (!queryParams.has(SORT_FIELD_PARAMETER) && + !queryParams.has(SORT_REVERSE_PARAMETER)) + let currentPage = queryParams.has(PAGE_PARAMETER) + ? parseInt(queryParams.get(PAGE_PARAMETER)) + : 1 + return { + currentPage: currentPage, + filterRules: filterRules, + sortField: sortField, + sortReverse: sortReverse, + } +} + +export function filterRulesFromQueryParams(queryParams: ParamMap) { + const allFilterRuleQueryParams: string[] = FILTER_RULE_TYPES.map( + (rt) => rt.filtervar + ) + .concat(FILTER_RULE_TYPES.map((rt) => rt.isnull_filtervar)) + .filter((rt) => rt !== undefined) + + // transform query params to filter rules + let filterRulesFromQueryParams: FilterRule[] = [] + allFilterRuleQueryParams + .filter((frqp) => queryParams.has(frqp)) + .forEach((filterQueryParamName) => { + const rule_type: FilterRuleType = FILTER_RULE_TYPES.find( + (rt) => + rt.filtervar == filterQueryParamName || + rt.isnull_filtervar == filterQueryParamName + ) + const isNullRuleType = rule_type.isnull_filtervar == filterQueryParamName + const valueURIComponent: string = queryParams.get(filterQueryParamName) + const filterQueryParamValues: string[] = rule_type.multi + ? valueURIComponent.split(',') + : [valueURIComponent] + + filterRulesFromQueryParams = filterRulesFromQueryParams.concat( + // map all values to filter rules + filterQueryParamValues.map((val) => { + return { + rule_type: rule_type.id, + value: isNullRuleType ? null : val, + } + }) + ) + }) + + return filterRulesFromQueryParams +} + +export function queryParamsFromFilterRules(filterRules: FilterRule[]): Params { + if (filterRules) { + let params = {} + for (let rule of filterRules) { + let ruleType = FILTER_RULE_TYPES.find((t) => t.id == rule.rule_type) + if (ruleType.multi) { + params[ruleType.filtervar] = params[ruleType.filtervar] + ? params[ruleType.filtervar] + ',' + rule.value + : rule.value + } else if (ruleType.isnull_filtervar && rule.value == null) { + params[ruleType.isnull_filtervar] = true + } else { + params[ruleType.filtervar] = rule.value + } + } + return params + } else { + return null + } +}