mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Refactor query params service
This commit is contained in:
		| @@ -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(), | ||||
|   | ||||
| @@ -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() }, | ||||
|     ]) | ||||
|   } | ||||
|   | ||||
| @@ -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(), | ||||
|   | ||||
| @@ -93,7 +93,7 @@ | ||||
|         <span i18n *ngIf="list.selected.size == 0">{list.collectionSize, plural, =1 {One document} other {{{list.collectionSize || 0}} documents}}</span> <span i18n *ngIf="isFiltered">(filtered)</span> | ||||
|       </ng-container> | ||||
|     </p> | ||||
|     <ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5" | ||||
|     <ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" (pageChange)="setPage($event)" [page]="list.currentPage" [maxSize]="5" | ||||
|     [rotate]="true" aria-label="Default pagination"></ngb-pagination> | ||||
|   </div> | ||||
| </ng-template> | ||||
|   | ||||
| @@ -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() }, | ||||
|     ]) | ||||
|   } | ||||
|   | ||||
| @@ -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<Paperles | ||||
|     correspondentsService: CorrespondentService, | ||||
|     modalService: NgbModal, | ||||
|     toastService: ToastService, | ||||
|     queryParamsService: QueryParamsService, | ||||
|     documentListViewService: DocumentListViewService, | ||||
|     private datePipe: CustomDatePipe | ||||
|   ) { | ||||
|     super( | ||||
| @@ -28,7 +28,7 @@ export class CorrespondentListComponent extends ManagementListComponent<Paperles | ||||
|       modalService, | ||||
|       CorrespondentEditDialogComponent, | ||||
|       toastService, | ||||
|       queryParamsService, | ||||
|       documentListViewService, | ||||
|       FILTER_CORRESPONDENT, | ||||
|       $localize`correspondent`, | ||||
|       $localize`correspondents`, | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { Component } from '@angular/core' | ||||
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { FILTER_DOCUMENT_TYPE } from 'src/app/data/filter-rule-type' | ||||
| import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' | ||||
| import { QueryParamsService } from 'src/app/services/query-params.service' | ||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service' | ||||
| import { DocumentTypeService } from 'src/app/services/rest/document-type.service' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { DocumentTypeEditDialogComponent } from '../../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' | ||||
| @@ -18,14 +18,14 @@ export class DocumentTypeListComponent extends ManagementListComponent<Paperless | ||||
|     documentTypeService: DocumentTypeService, | ||||
|     modalService: NgbModal, | ||||
|     toastService: ToastService, | ||||
|     queryParamsService: QueryParamsService | ||||
|     documentListViewService: DocumentListViewService | ||||
|   ) { | ||||
|     super( | ||||
|       documentTypeService, | ||||
|       modalService, | ||||
|       DocumentTypeEditDialogComponent, | ||||
|       toastService, | ||||
|       queryParamsService, | ||||
|       documentListViewService, | ||||
|       FILTER_DOCUMENT_TYPE, | ||||
|       $localize`document type`, | ||||
|       $localize`document types`, | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import { | ||||
|   SortableDirective, | ||||
|   SortEvent, | ||||
| } from 'src/app/directives/sortable.directive' | ||||
| import { QueryParamsService } from 'src/app/services/query-params.service' | ||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service' | ||||
| import { AbstractNameFilterService } from 'src/app/services/rest/abstract-name-filter-service' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component' | ||||
| @@ -42,7 +42,7 @@ export abstract class ManagementListComponent<T extends ObjectWithId> | ||||
|     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<T extends ObjectWithId> | ||||
|   } | ||||
|  | ||||
|   filterDocuments(object: ObjectWithId) { | ||||
|     this.queryParamsService.navigateWithFilterRules([ | ||||
|     this.documentListViewService.quickFilter([ | ||||
|       { rule_type: this.filterRuleType, value: object.id.toString() }, | ||||
|     ]) | ||||
|   } | ||||
|   | ||||
| @@ -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<PaperlessS | ||||
|     directoryService: StoragePathService, | ||||
|     modalService: NgbModal, | ||||
|     toastService: ToastService, | ||||
|     queryParamsService: QueryParamsService | ||||
|     documentListViewService: DocumentListViewService | ||||
|   ) { | ||||
|     super( | ||||
|       directoryService, | ||||
|       modalService, | ||||
|       StoragePathEditDialogComponent, | ||||
|       toastService, | ||||
|       queryParamsService, | ||||
|       documentListViewService, | ||||
|       FILTER_STORAGE_PATH, | ||||
|       $localize`storage path`, | ||||
|       $localize`storage paths`, | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { Component } from '@angular/core' | ||||
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type' | ||||
| import { PaperlessTag } from 'src/app/data/paperless-tag' | ||||
| import { QueryParamsService } from 'src/app/services/query-params.service' | ||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service' | ||||
| import { TagService } from 'src/app/services/rest/tag.service' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' | ||||
| @@ -18,14 +18,14 @@ export class TagListComponent extends ManagementListComponent<PaperlessTag> { | ||||
|     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`, | ||||
|   | ||||
| @@ -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) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
| @@ -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<PaperlessDocument> | ||||
|       pageSize, | ||||
|       sortField, | ||||
|       sortReverse, | ||||
|       Object.assign(extraParams, filterRulesToQueryParams(filterRules)) | ||||
|       Object.assign(extraParams, queryParamsFromFilterRules(filterRules)) | ||||
|     ).pipe( | ||||
|       map((results) => { | ||||
|         results.results.forEach((doc) => this.addObservablesToDocument(doc)) | ||||
|   | ||||
							
								
								
									
										100
									
								
								src-ui/src/app/utils/query-params.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src-ui/src/app/utils/query-params.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Michael Shamoon
					Michael Shamoon