paperless-ngx/src-ui/src/app/services/document-list-view.service.ts

340 lines
10 KiB
TypeScript
Raw Normal View History

2020-10-27 01:10:18 +01:00
import { Injectable } from '@angular/core';
2020-12-30 23:34:50 +01:00
import { Router } from '@angular/router';
2020-10-27 01:10:18 +01:00
import { Observable } from 'rxjs';
2020-10-30 23:43:19 +01:00
import { cloneFilterRules, FilterRule } from '../data/filter-rule';
2020-10-27 01:10:18 +01:00
import { PaperlessDocument } from '../data/paperless-document';
import { PaperlessSavedView } from '../data/paperless-saved-view';
2020-12-29 17:09:07 +01:00
import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys';
import { DocumentService } from './rest/document.service';
2020-12-29 17:09:07 +01:00
import { SettingsService, SETTINGS_KEYS } from './settings.service';
2020-10-27 01:10:18 +01:00
interface ListViewState {
title?: string
documents?: PaperlessDocument[]
currentPage: number
collectionSize: number
sortField: string
sortReverse: boolean
filterRules: FilterRule[]
selected?: Set<number>
}
2020-10-30 22:51:16 +01:00
/**
* This service manages the document list which is displayed using the document list view.
*
* This service also serves saved views by transparently switching between the document list
* and saved views on request. See below.
*/
2020-10-27 01:10:18 +01:00
@Injectable({
providedIn: 'root'
})
export class DocumentListViewService {
isReloading: boolean = false
2021-01-15 02:15:26 -08:00
rangeSelectionAnchorIndex: number
lastRangeSelectionToIndex: number
currentPageSize: number = this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)
2020-10-27 01:10:18 +01:00
private listViewStates: Map<number, ListViewState> = new Map()
private _activeSavedViewId: number = null
get activeSavedViewId() {
return this._activeSavedViewId
}
get activeSavedViewTitle() {
return this.activeListViewState.title
}
private defaultListViewState(): ListViewState {
return {
title: null,
documents: [],
currentPage: 1,
collectionSize: null,
sortField: "created",
sortReverse: true,
filterRules: [],
selected: new Set<number>()
}
}
2020-10-30 22:46:43 +01:00
private get activeListViewState() {
if (!this.listViewStates.has(this._activeSavedViewId)) {
this.listViewStates.set(this._activeSavedViewId, this.defaultListViewState())
}
return this.listViewStates.get(this._activeSavedViewId)
}
activateSavedView(view: PaperlessSavedView) {
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null
if (view) {
this._activeSavedViewId = view.id
this.loadSavedView(view)
} else {
this._activeSavedViewId = null
}
}
loadSavedView(view: PaperlessSavedView, closeCurrentView: boolean = false) {
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()
2020-12-03 19:55:42 +01:00
}
reload(onFinish?) {
this.isReloading = true
let activeListViewState = this.activeListViewState
this.documentService.listFiltered(
activeListViewState.currentPage,
2020-11-04 19:28:08 +01:00
this.currentPageSize,
activeListViewState.sortField,
activeListViewState.sortReverse,
activeListViewState.filterRules).subscribe(
2020-10-27 01:10:18 +01:00
result => {
this.isReloading = false
activeListViewState.collectionSize = result.count
activeListViewState.documents = result.results
2020-10-27 01:10:18 +01:00
if (onFinish) {
onFinish()
}
2021-01-15 02:15:26 -08:00
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null
2020-10-27 01:10:18 +01:00
},
error => {
this.isReloading = false
if (activeListViewState.currentPage != 1 && error.status == 404) {
2021-01-04 17:31:35 +01:00
// this happens when applying a filter: the current page might not be available anymore due to the reduced result set.
activeListViewState.currentPage = 1
2020-10-27 01:10:18 +01:00
this.reload()
}
})
}
set filterRules(filterRules: FilterRule[]) {
this.activeListViewState.filterRules = filterRules
this.reload()
2020-12-11 14:48:33 +01:00
this.reduceSelectionToFilter()
this.saveDocumentListView()
}
get filterRules(): FilterRule[] {
return this.activeListViewState.filterRules
}
set sortField(field: string) {
this.activeListViewState.sortField = field
this.reload()
this.saveDocumentListView()
}
get sortField(): string {
return this.activeListViewState.sortField
}
set sortReverse(reverse: boolean) {
this.activeListViewState.sortReverse = reverse
this.reload()
this.saveDocumentListView()
}
get sortReverse(): boolean {
return this.activeListViewState.sortReverse
}
get collectionSize(): number {
return this.activeListViewState.collectionSize
}
get currentPage(): number {
return this.activeListViewState.currentPage
}
set currentPage(page: number) {
this.activeListViewState.currentPage = page
this.reload()
2021-01-04 15:58:04 +01:00
this.saveDocumentListView()
}
get documents(): PaperlessDocument[] {
return this.activeListViewState.documents
}
get selected(): Set<number> {
return this.activeListViewState.selected
}
setSort(field: string, reverse: boolean) {
this.activeListViewState.sortField = field
this.activeListViewState.sortReverse = reverse
2021-01-04 15:58:04 +01:00
this.reload()
this.saveDocumentListView()
2021-01-04 15:58:04 +01:00
}
private saveDocumentListView() {
if (this._activeSavedViewId == null) {
let savedState: ListViewState = {
collectionSize: this.activeListViewState.collectionSize,
currentPage: this.activeListViewState.currentPage,
filterRules: this.activeListViewState.filterRules,
sortField: this.activeListViewState.sortField,
sortReverse: this.activeListViewState.sortReverse
}
2021-04-02 14:46:45 +02:00
localStorage.setItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, JSON.stringify(savedState))
}
2020-10-27 01:10:18 +01:00
}
2020-12-30 23:34:50 +01:00
quickFilter(filterRules: FilterRule[]) {
this._activeSavedViewId = null
this.activeListViewState.filterRules = filterRules
this.activeListViewState.currentPage = 1
2020-12-30 23:34:50 +01:00
this.reduceSelectionToFilter()
this.saveDocumentListView()
this.router.navigate(["documents"])
}
2020-10-27 01:10:18 +01:00
getLastPage(): number {
2020-11-04 19:28:08 +01:00
return Math.ceil(this.collectionSize / this.currentPageSize)
2020-10-27 01:10:18 +01:00
}
hasNext(doc: number) {
if (this.documents) {
let index = this.documents.findIndex(d => d.id == doc)
return index != -1 && (this.currentPage < this.getLastPage() || (index + 1) < this.documents.length)
}
}
getNext(currentDocId: number): Observable<number> {
return new Observable(nextDocId => {
if (this.documents != null) {
let index = this.documents.findIndex(d => d.id == currentDocId)
if (index != -1 && (index + 1) < this.documents.length) {
nextDocId.next(this.documents[index+1].id)
nextDocId.complete()
} else if (index != -1 && this.currentPage < this.getLastPage()) {
this.currentPage += 1
this.reload(() => {
nextDocId.next(this.documents[0].id)
nextDocId.complete()
})
} else {
nextDocId.complete()
}
} else {
nextDocId.complete()
}
})
}
2020-11-04 19:28:08 +01:00
updatePageSize() {
2020-12-29 17:09:07 +01:00
let newPageSize = this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)
2020-11-04 19:28:08 +01:00
if (newPageSize != this.currentPageSize) {
this.currentPageSize = newPageSize
}
}
2020-12-11 14:48:33 +01:00
selectNone() {
this.selected.clear()
2021-01-15 02:15:26 -08:00
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null
2020-12-11 14:48:33 +01:00
}
reduceSelectionToFilter() {
2020-12-11 14:48:33 +01:00
if (this.selected.size > 0) {
this.documentService.listAllFilteredIds(this.filterRules).subscribe(ids => {
for (let id of this.selected) {
if (!ids.includes(id)) {
this.selected.delete(id)
2020-12-11 14:48:33 +01:00
}
}
})
}
}
selectAll() {
this.documentService.listAllFilteredIds(this.filterRules).subscribe(ids => ids.forEach(id => this.selected.add(id)))
}
selectPage() {
this.selected.clear()
this.documents.forEach(doc => {
this.selected.add(doc.id)
})
}
isSelected(d: PaperlessDocument) {
return this.selected.has(d.id)
}
toggleSelected(d: PaperlessDocument): void {
if (this.selected.has(d.id)) this.selected.delete(d.id)
else this.selected.add(d.id)
2021-01-15 02:15:26 -08:00
this.rangeSelectionAnchorIndex = this.documentIndexInCurrentView(d.id)
this.lastRangeSelectionToIndex = null
}
selectRangeTo(d: PaperlessDocument) {
2021-01-15 02:15:26 -08:00
if (this.rangeSelectionAnchorIndex !== null) {
2021-01-15 01:54:33 -08:00
const documentToIndex = this.documentIndexInCurrentView(d.id)
2021-01-15 02:15:26 -08:00
const fromIndex = Math.min(this.rangeSelectionAnchorIndex, documentToIndex)
const toIndex = Math.max(this.rangeSelectionAnchorIndex, documentToIndex)
2021-01-15 01:54:33 -08:00
if (this.lastRangeSelectionToIndex !== null) {
// revert the old selection
2021-01-15 02:15:26 -08:00
this.documents.slice(Math.min(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex), Math.max(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex) + 1).forEach(d => {
this.selected.delete(d.id)
})
2021-01-15 01:54:33 -08:00
}
2021-01-14 14:10:23 -08:00
2021-01-15 01:54:33 -08:00
this.documents.slice(fromIndex, toIndex + 1).forEach(d => {
2021-01-14 14:10:23 -08:00
this.selected.add(d.id)
})
2021-01-15 02:15:26 -08:00
this.lastRangeSelectionToIndex = documentToIndex
} else { // e.g. shift key but was first click
2021-01-15 02:13:21 -08:00
this.toggleSelected(d)
2021-01-14 14:10:23 -08:00
}
}
documentIndexInCurrentView(documentID: number): number {
return this.documents.map(d => d.id).indexOf(documentID)
2020-12-11 14:48:33 +01:00
}
2020-12-30 23:34:50 +01:00
constructor(private documentService: DocumentService, private settings: SettingsService, private router: Router) {
2021-04-02 14:46:45 +02:00
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) {
2021-04-02 14:46:45 +02:00
localStorage.removeItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG)
}
}
}
2020-10-27 01:10:18 +01:00
}