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 00b840b48..aa4922bb0 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 @@ -1,4 +1,3 @@ -import { DatePipe, formatDate } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; @@ -6,17 +5,14 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; import { PaperlessDocument } from 'src/app/data/paperless-document'; import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag'; import { DocumentListViewService } from 'src/app/services/document-list-view.service'; import { OpenDocumentsService } from 'src/app/services/open-documents.service'; import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; import { DocumentService } from 'src/app/services/rest/document.service'; -import { TagService } from 'src/app/services/rest/tag.service'; import { DeleteDialogComponent } from '../common/delete-dialog/delete-dialog.component'; import { CorrespondentEditDialogComponent } from '../manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; import { DocumentTypeEditDialogComponent } from '../manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; -import { TagEditDialogComponent } from '../manage/tag-list/tag-edit-dialog/tag-edit-dialog.component'; @Component({ selector: 'app-document-detail', @@ -133,8 +129,8 @@ export class DocumentDetailComponent implements OnInit { close() { this.openDocumentService.closeDocument(this.document) - if (this.documentListViewService.viewId) { - this.router.navigate(['view', this.documentListViewService.viewId]) + if (this.documentListViewService.savedViewId) { + this.router.navigate(['view', this.documentListViewService.savedViewId]) } else { this.router.navigate(['documents']) } 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 7c0abebc8..8bd5b1a55 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 @@ -21,13 +21,12 @@ -
No results
\ No newline at end of file +No results
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 2b155c34f..8cc5ed863 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,11 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { cloneFilterRules, FilterRule } from 'src/app/data/filter-rule'; import { SavedViewConfig } from 'src/app/data/saved-view-config'; import { DocumentListViewService } from 'src/app/services/document-list-view.service'; import { DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service'; import { SavedViewConfigService } from 'src/app/services/saved-view-config.service'; +import { Toast, ToastService } from 'src/app/services/toast.service'; import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; @Component({ @@ -16,9 +17,10 @@ import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-vi export class DocumentListComponent implements OnInit { constructor( - public docs: DocumentListViewService, + public list: DocumentListViewService, public savedViewConfigService: SavedViewConfigService, public route: ActivatedRoute, + private toastService: ToastService, public modalService: NgbModal) { } displayMode = 'smallCards' // largeCards, smallCards, details @@ -27,17 +29,13 @@ export class DocumentListComponent implements OnInit { showFilter = false getTitle() { - return this.docs.viewConfigOverride ? this.docs.viewConfigOverride.title : "Documents" + return this.list.savedViewTitle || "Documents" } getSortFields() { return DOCUMENT_SORT_FIELDS } - setSort(field: string) { - this.docs.sortField = field - } - saveDisplayMode() { localStorage.setItem('document-list:displayMode', this.displayMode) } @@ -48,39 +46,42 @@ export class DocumentListComponent implements OnInit { } this.route.paramMap.subscribe(params => { if (params.has('id')) { - this.docs.viewConfigOverride = this.savedViewConfigService.getConfig(params.get('id')) + this.list.savedView = this.savedViewConfigService.getConfig(params.get('id')) } else { - this.filterRules = this.docs.filterRules - this.showFilter = this.filterRules.length > 0 - this.docs.viewConfigOverride = null + this.list.savedView = null } - this.reload() + this.filterRules = this.list.filterRules + //this.showFilter = this.filterRules.length > 0 + // prevents temporarily visible results from previous views + this.list.documents = [] + this.list.reload() }) } - reload() { - this.docs.reload() - } - applyFilterRules() { - this.docs.filterRules = this.filterRules + this.list.filterRules = this.filterRules } loadViewConfig(config: SavedViewConfig) { this.filterRules = cloneFilterRules(config.filterRules) - this.docs.loadViewConfig(config) + this.list.load(config) } saveViewConfig() { + this.savedViewConfigService.updateConfig(this.list.savedView) + this.toastService.showToast(Toast.make("Information", `View "${this.list.savedView.title}" saved successfully.`)) + } + + saveViewConfigAs() { let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'}) modal.componentInstance.saveClicked.subscribe(formValue => { - this.savedViewConfigService.saveConfig({ + this.savedViewConfigService.newConfig({ title: formValue.title, showInDashboard: formValue.showInDashboard, showInSideBar: formValue.showInSideBar, - filterRules: this.docs.filterRules, - sortDirection: this.docs.sortDirection, - sortField: this.docs.sortField + filterRules: this.list.filterRules, + sortDirection: this.list.sortDirection, + sortField: this.list.sortField }) modal.close() }) 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 39a8661b9..9c7e244f4 100644 --- a/src-ui/src/app/services/document-list-view.service.ts +++ b/src-ui/src/app/services/document-list-view.service.ts @@ -7,6 +7,12 @@ import { DOCUMENT_LIST_SERVICE, GENERAL_SETTINGS } from '../data/storage-keys'; import { DocumentService } from './rest/document.service'; +/** + * 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. + */ @Injectable({ providedIn: 'root' }) @@ -14,80 +20,127 @@ export class DocumentListViewService { static DEFAULT_SORT_FIELD = 'created' + isReloading: boolean = false documents: PaperlessDocument[] = [] currentPage = 1 currentPageSize: number = +localStorage.getItem(GENERAL_SETTINGS.DOCUMENT_LIST_SIZE) || GENERAL_SETTINGS.DOCUMENT_LIST_SIZE_DEFAULT collectionSize: number - private currentViewConfig: SavedViewConfig - //TODO: make private - viewConfigOverride: SavedViewConfig + /** + * This is the current config for the document list. The service will always remember the last settings used for the document list. + */ + private _documentListViewConfig: SavedViewConfig + /** + * Optionally, this is the currently selected saved view, which might be null. + */ + private _savedViewConfig: SavedViewConfig - get viewId() { - return this.viewConfigOverride?.id + get savedView() { + return this._savedViewConfig + } + + set savedView(value) { + if (value) { + //this is here so that we don't modify value, which might be the actual instance of the saved view. + this._savedViewConfig = Object.assign({}, value) + } else { + this._savedViewConfig = null + } + } + + get savedViewId() { + return this.savedView?.id + } + + get savedViewTitle() { + return this.savedView?.title + } + + get documentListView() { + return this._documentListViewConfig + } + + set documentListView(value) { + if (value) { + this._documentListViewConfig = Object.assign({}, value) + this.saveDocumentListView() + } + } + + /** + * This is what switches between the saved views and the document list view. Everything on the document list uses + * this property to determine the settings for the currently displayed document list. + */ + get view() { + return this.savedView || this.documentListView + } + + load(config: SavedViewConfig) { + this.view.filterRules = cloneFilterRules(config.filterRules) + this.view.sortDirection = config.sortDirection + this.view.sortField = config.sortField + this.reload() } reload(onFinish?) { - let viewConfig = this.viewConfigOverride || this.currentViewConfig - + this.isReloading = true this.documentService.list( this.currentPage, this.currentPageSize, - viewConfig.sortField, - viewConfig.sortDirection, - viewConfig.filterRules).subscribe( + this.view.sortField, + this.view.sortDirection, + this.view.filterRules).subscribe( result => { this.collectionSize = result.count this.documents = result.results if (onFinish) { onFinish() } + this.isReloading = false }, error => { if (error.error['detail'] == 'Invalid page.') { this.currentPage = 1 this.reload() } + this.isReloading = false }) } set filterRules(filterRules: FilterRule[]) { - this.currentViewConfig.filterRules = cloneFilterRules(filterRules) - this.saveCurrentViewConfig() + //we're going to clone the filterRules object, since we don't + //want changes in the filter editor to propagate into here right away. + this.view.filterRules = cloneFilterRules(filterRules) this.reload() + this.saveDocumentListView() } get filterRules(): FilterRule[] { - return cloneFilterRules(this.currentViewConfig.filterRules) + return cloneFilterRules(this.view.filterRules) } set sortField(field: string) { - this.currentViewConfig.sortField = field - this.saveCurrentViewConfig() + this.view.sortField = field + this.saveDocumentListView() this.reload() } get sortField(): string { - return this.currentViewConfig.sortField + return this.view.sortField } set sortDirection(direction: string) { - this.currentViewConfig.sortDirection = direction - this.saveCurrentViewConfig() + this.view.sortDirection = direction + this.saveDocumentListView() this.reload() } get sortDirection(): string { - return this.currentViewConfig.sortDirection + return this.view.sortDirection } - loadViewConfig(config: SavedViewConfig) { - Object.assign(this.currentViewConfig, config) - this.reload() - } - - private saveCurrentViewConfig() { - sessionStorage.setItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, JSON.stringify(this.currentViewConfig)) + private saveDocumentListView() { + sessionStorage.setItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, JSON.stringify(this.documentListView)) } getLastPage(): number { @@ -134,21 +187,21 @@ export class DocumentListViewService { } constructor(private documentService: DocumentService) { - let currentViewConfigJson = sessionStorage.getItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) - if (currentViewConfigJson) { + let documentListViewConfigJson = sessionStorage.getItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) + if (documentListViewConfigJson) { try { - this.currentViewConfig = JSON.parse(currentViewConfigJson) + this.documentListView = JSON.parse(documentListViewConfigJson) } catch (e) { sessionStorage.removeItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) - this.currentViewConfig = null + this.documentListView = null } } - if (!this.currentViewConfig) { - this.currentViewConfig = { + if (!this.documentListView) { + this.documentListView = { filterRules: [], sortDirection: 'des', sortField: 'created' } - } + } } } diff --git a/src-ui/src/app/services/saved-view-config.service.ts b/src-ui/src/app/services/saved-view-config.service.ts index d69791209..41c28216b 100644 --- a/src-ui/src/app/services/saved-view-config.service.ts +++ b/src-ui/src/app/services/saved-view-config.service.ts @@ -36,13 +36,21 @@ export class SavedViewConfigService { return this.configs.find(sf => sf.id == id) } - saveConfig(config: SavedViewConfig) { + newConfig(config: SavedViewConfig) { config.id = uuidv4() this.configs.push(config) this.save() } + updateConfig(config: SavedViewConfig) { + let savedConfig = this.configs.find(c => c.id == config.id) + if (savedConfig) { + Object.assign(savedConfig, config) + this.save() + } + } + private save() { localStorage.setItem('saved-view-config-service:savedConfigs', JSON.stringify(this.configs)) }