mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	many changes to support server side saved views
This commit is contained in:
		@@ -37,16 +37,16 @@
 | 
				
			|||||||
          </li>
 | 
					          </li>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted" *ngIf='viewConfigService.getSideBarConfigs().length > 0'>
 | 
					        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted" *ngIf='savedViewService.sidebarViews.length > 0'>
 | 
				
			||||||
          <span>Saved views</span>
 | 
					          <span>Saved views</span>
 | 
				
			||||||
        </h6>
 | 
					        </h6>
 | 
				
			||||||
        <ul class="nav flex-column mb-2">
 | 
					        <ul class="nav flex-column mb-2">
 | 
				
			||||||
          <li class="nav-item w-100" *ngFor='let config of viewConfigService.getSideBarConfigs()'>
 | 
					          <li class="nav-item w-100" *ngFor="let view of savedViewService.sidebarViews">
 | 
				
			||||||
            <a class="nav-link text-truncate" routerLink="view/{{config.id}}" routerLinkActive="active" (click)="closeMenu()">
 | 
					            <a class="nav-link text-truncate" routerLink="view/{{view.id}}" routerLinkActive="active" (click)="closeMenu()">
 | 
				
			||||||
              <svg class="sidebaricon" fill="currentColor">
 | 
					              <svg class="sidebaricon" fill="currentColor">
 | 
				
			||||||
                <use xlink:href="assets/bootstrap-icons.svg#funnel"/>
 | 
					                <use xlink:href="assets/bootstrap-icons.svg#funnel"/>
 | 
				
			||||||
              </svg>
 | 
					              </svg>
 | 
				
			||||||
              {{config.title}}
 | 
					              {{view.name}}
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
          </li>
 | 
					          </li>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@ import { from, Observable, Subscription } from 'rxjs';
 | 
				
			|||||||
import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators';
 | 
					import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators';
 | 
				
			||||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
 | 
					import { PaperlessDocument } from 'src/app/data/paperless-document';
 | 
				
			||||||
import { OpenDocumentsService } from 'src/app/services/open-documents.service';
 | 
					import { OpenDocumentsService } from 'src/app/services/open-documents.service';
 | 
				
			||||||
 | 
					import { SavedViewService } from 'src/app/services/rest/saved-view.service';
 | 
				
			||||||
import { SearchService } from 'src/app/services/rest/search.service';
 | 
					import { SearchService } from 'src/app/services/rest/search.service';
 | 
				
			||||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
 | 
					 | 
				
			||||||
import { DocumentDetailComponent } from '../document-detail/document-detail.component';
 | 
					import { DocumentDetailComponent } from '../document-detail/document-detail.component';
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
@@ -21,7 +21,7 @@ export class AppFrameComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    private activatedRoute: ActivatedRoute,
 | 
					    private activatedRoute: ActivatedRoute,
 | 
				
			||||||
    private openDocumentsService: OpenDocumentsService,
 | 
					    private openDocumentsService: OpenDocumentsService,
 | 
				
			||||||
    private searchService: SearchService,
 | 
					    private searchService: SearchService,
 | 
				
			||||||
    public viewConfigService: SavedViewConfigService
 | 
					    public savedViewService: SavedViewService
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import { Component, OnInit } from '@angular/core';
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
import { Title } from '@angular/platform-browser';
 | 
					import { Title } from '@angular/platform-browser';
 | 
				
			||||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
 | 
					import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
 | 
				
			||||||
 | 
					import { SavedViewService } from 'src/app/services/rest/saved-view.service';
 | 
				
			||||||
import { environment } from 'src/environments/environment';
 | 
					import { environment } from 'src/environments/environment';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,14 +13,16 @@ import { environment } from 'src/environments/environment';
 | 
				
			|||||||
export class DashboardComponent implements OnInit {
 | 
					export class DashboardComponent implements OnInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    public savedViewConfigService: SavedViewConfigService,
 | 
					    private savedViewService: SavedViewService,
 | 
				
			||||||
    private titleService: Title) { }
 | 
					    private titleService: Title) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  savedViews = []
 | 
					  savedViews: PaperlessSavedView[] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
    this.savedViews = this.savedViewConfigService.getDashboardConfigs()
 | 
					    this.savedViewService.listAll().subscribe(results => {
 | 
				
			||||||
 | 
					      this.savedViews = results.results.filter(savedView => savedView.show_on_dashboard)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
    this.titleService.setTitle(`Dashboard - ${environment.appTitle}`)
 | 
					    this.titleService.setTitle(`Dashboard - ${environment.appTitle}`)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
<app-widget-frame [title]="savedView.title">
 | 
					<app-widget-frame [title]="savedView.name">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <a header-buttons [routerLink]="" (click)="showAll()">Show all</a>
 | 
					  <a header-buttons [routerLink]="" (click)="showAll()">Show all</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import { Component, Input, OnInit } from '@angular/core';
 | 
					import { Component, Input, OnInit } from '@angular/core';
 | 
				
			||||||
import { Router } from '@angular/router';
 | 
					import { Router } from '@angular/router';
 | 
				
			||||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
 | 
					import { PaperlessDocument } from 'src/app/data/paperless-document';
 | 
				
			||||||
import { SavedViewConfig } from 'src/app/data/saved-view-config';
 | 
					import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
 | 
				
			||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
 | 
					import { DocumentListViewService } from 'src/app/services/document-list-view.service';
 | 
				
			||||||
import { DocumentService } from 'src/app/services/rest/document.service';
 | 
					import { DocumentService } from 'src/app/services/rest/document.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,18 +18,18 @@ export class SavedViewWidgetComponent implements OnInit {
 | 
				
			|||||||
    private list: DocumentListViewService) { }
 | 
					    private list: DocumentListViewService) { }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  @Input()
 | 
					  @Input()
 | 
				
			||||||
  savedView: SavedViewConfig
 | 
					  savedView: PaperlessSavedView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  documents: PaperlessDocument[] = []
 | 
					  documents: PaperlessDocument[] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
    this.documentService.list(1,10,this.savedView.sortField,this.savedView.sortDirection,this.savedView.filterRules).subscribe(result => {
 | 
					    this.documentService.list(1,10,this.savedView.sort_field, this.savedView.sort_reverse, this.savedView.filter_rules).subscribe(result => {
 | 
				
			||||||
      this.documents = result.results
 | 
					      this.documents = result.results
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  showAll() {
 | 
					  showAll() {
 | 
				
			||||||
    if (this.savedView.showInSideBar) {
 | 
					    if (this.savedView.show_in_sidebar) {
 | 
				
			||||||
      this.router.navigate(['view', this.savedView.id])
 | 
					      this.router.navigate(['view', this.savedView.id])
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.list.load(this.savedView)
 | 
					      this.list.load(this.savedView)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@
 | 
				
			|||||||
    </label>
 | 
					    </label>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="btn-group btn-group-toggle ml-2" ngbRadioGroup [(ngModel)]="list.sortDirection">
 | 
					  <div class="btn-group btn-group-toggle ml-2" ngbRadioGroup [(ngModel)]="list.sortReverse">
 | 
				
			||||||
    <div ngbDropdown class="btn-group">
 | 
					    <div ngbDropdown class="btn-group">
 | 
				
			||||||
      <button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>Sort by</button>
 | 
					      <button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>Sort by</button>
 | 
				
			||||||
      <div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="shadow">
 | 
					      <div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="shadow">
 | 
				
			||||||
@@ -30,13 +30,13 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
					    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
				
			||||||
      <input ngbButton type="radio" class="btn btn-sm" value="asc">
 | 
					      <input ngbButton type="radio" class="btn btn-sm" [value]="false">
 | 
				
			||||||
      <svg class="toolbaricon" fill="currentColor">
 | 
					      <svg class="toolbaricon" fill="currentColor">
 | 
				
			||||||
        <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-down" />
 | 
					        <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-down" />
 | 
				
			||||||
      </svg>
 | 
					      </svg>
 | 
				
			||||||
    </label>
 | 
					    </label>
 | 
				
			||||||
    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
					    <label ngbButtonLabel class="btn-outline-primary btn-sm">
 | 
				
			||||||
      <input ngbButton type="radio" class="btn btn-sm" value="des">
 | 
					      <input ngbButton type="radio" class="btn btn-sm" [value]="true">
 | 
				
			||||||
      <svg class="toolbaricon" fill="currentColor">
 | 
					      <svg class="toolbaricon" fill="currentColor">
 | 
				
			||||||
        <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-up-alt" />
 | 
					        <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-up-alt" />
 | 
				
			||||||
      </svg>
 | 
					      </svg>
 | 
				
			||||||
@@ -49,8 +49,8 @@
 | 
				
			|||||||
      <button class="btn btn-sm btn-outline-primary dropdown-toggle" ngbDropdownToggle>Views</button>
 | 
					      <button class="btn btn-sm btn-outline-primary dropdown-toggle" ngbDropdownToggle>Views</button>
 | 
				
			||||||
      <div class="dropdown-menu shadow" ngbDropdownMenu>
 | 
					      <div class="dropdown-menu shadow" ngbDropdownMenu>
 | 
				
			||||||
        <ng-container *ngIf="!list.savedViewId">
 | 
					        <ng-container *ngIf="!list.savedViewId">
 | 
				
			||||||
          <button ngbDropdownItem *ngFor="let config of savedViewConfigService.getConfigs()" (click)="loadViewConfig(config)">{{config.title}}</button>
 | 
					          <button ngbDropdownItem *ngFor="let view of savedViewService.allViews" (click)="loadViewConfig(view)">{{view.name}}</button>
 | 
				
			||||||
          <div class="dropdown-divider" *ngIf="savedViewConfigService.getConfigs().length > 0"></div>
 | 
					          <div class="dropdown-divider" *ngIf="savedViewService.allViews.length > 0"></div>
 | 
				
			||||||
        </ng-container>
 | 
					        </ng-container>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <button ngbDropdownItem (click)="saveViewConfig()" *ngIf="list.savedViewId">Save "{{list.savedViewTitle}}"</button>
 | 
					        <button ngbDropdownItem (click)="saveViewConfig()" *ngIf="list.savedViewId">Save "{{list.savedViewTitle}}"</button>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,16 @@
 | 
				
			|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
 | 
					import { Component, OnInit, ViewChild } from '@angular/core';
 | 
				
			||||||
import { Title } from '@angular/platform-browser';
 | 
					import { Title } from '@angular/platform-browser';
 | 
				
			||||||
import { ActivatedRoute } from '@angular/router';
 | 
					import { ActivatedRoute, Router } from '@angular/router';
 | 
				
			||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
 | 
					import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
 | 
				
			||||||
import { SavedViewConfig } from 'src/app/data/saved-view-config';
 | 
					import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
 | 
				
			||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
 | 
					import { DocumentListViewService } from 'src/app/services/document-list-view.service';
 | 
				
			||||||
import { DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service';
 | 
					import { DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service';
 | 
				
			||||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
 | 
					import { SavedViewService } from 'src/app/services/rest/saved-view.service';
 | 
				
			||||||
import { Toast, ToastService } from 'src/app/services/toast.service';
 | 
					import { Toast, ToastService } from 'src/app/services/toast.service';
 | 
				
			||||||
import { environment } from 'src/environments/environment';
 | 
					import { environment } from 'src/environments/environment';
 | 
				
			||||||
import { FilterEditorComponent } from '../filter-editor/filter-editor.component';
 | 
					import { FilterEditorComponent } from '../filter-editor/filter-editor.component';
 | 
				
			||||||
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component';
 | 
					import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-document-list',
 | 
					  selector: 'app-document-list',
 | 
				
			||||||
  templateUrl: './document-list.component.html',
 | 
					  templateUrl: './document-list.component.html',
 | 
				
			||||||
@@ -19,8 +20,9 @@ export class DocumentListComponent implements OnInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    public list: DocumentListViewService,
 | 
					    public list: DocumentListViewService,
 | 
				
			||||||
    public savedViewConfigService: SavedViewConfigService,
 | 
					    public savedViewService: SavedViewService,
 | 
				
			||||||
    public route: ActivatedRoute,
 | 
					    public route: ActivatedRoute,
 | 
				
			||||||
 | 
					    private router: Router,
 | 
				
			||||||
    private toastService: ToastService,
 | 
					    private toastService: ToastService,
 | 
				
			||||||
    public modalService: NgbModal,
 | 
					    public modalService: NgbModal,
 | 
				
			||||||
    private titleService: Title) { }
 | 
					    private titleService: Title) { }
 | 
				
			||||||
@@ -51,41 +53,52 @@ export class DocumentListComponent implements OnInit {
 | 
				
			|||||||
      this.displayMode = localStorage.getItem('document-list:displayMode')
 | 
					      this.displayMode = localStorage.getItem('document-list:displayMode')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.route.paramMap.subscribe(params => {
 | 
					    this.route.paramMap.subscribe(params => {
 | 
				
			||||||
 | 
					      this.list.clear()
 | 
				
			||||||
      if (params.has('id')) {
 | 
					      if (params.has('id')) {
 | 
				
			||||||
        this.list.savedView = this.savedViewConfigService.getConfig(params.get('id'))
 | 
					        this.savedViewService.getCached(+params.get('id')).subscribe(view => {
 | 
				
			||||||
        this.titleService.setTitle(`${this.list.savedView.title} - ${environment.appTitle}`)
 | 
					          if (!view) {
 | 
				
			||||||
 | 
					            this.router.navigate(["404"])
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          this.list.savedView = view
 | 
				
			||||||
 | 
					          this.titleService.setTitle(`${this.list.savedView.name} - ${environment.appTitle}`)
 | 
				
			||||||
 | 
					          this.list.reload()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        this.list.savedView = null
 | 
					        this.list.savedView = null
 | 
				
			||||||
        this.titleService.setTitle(`Documents - ${environment.appTitle}`)
 | 
					        this.titleService.setTitle(`Documents - ${environment.appTitle}`)
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      this.list.clear()
 | 
					 | 
				
			||||||
        this.list.reload()
 | 
					        this.list.reload()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loadViewConfig(config: SavedViewConfig) {
 | 
					  loadViewConfig(view: PaperlessSavedView) {
 | 
				
			||||||
    this.list.load(config)
 | 
					    this.list.load(view)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  saveViewConfig() {
 | 
					  saveViewConfig() {
 | 
				
			||||||
    this.savedViewConfigService.updateConfig(this.list.savedView)
 | 
					    this.savedViewService.update(this.list.savedView).subscribe(result => {
 | 
				
			||||||
    this.toastService.showToast(Toast.make("Information", `View "${this.list.savedView.title}" saved successfully.`))
 | 
					      this.toastService.showToast(Toast.make("Information", `View "${this.list.savedView.name}" saved successfully.`))
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  saveViewConfigAs() {
 | 
					  saveViewConfigAs() {
 | 
				
			||||||
    let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'})
 | 
					    let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
    modal.componentInstance.saveClicked.subscribe(formValue => {
 | 
					    modal.componentInstance.saveClicked.subscribe(formValue => {
 | 
				
			||||||
      this.savedViewConfigService.newConfig({
 | 
					      this.savedViewService.create({
 | 
				
			||||||
        title: formValue.title,
 | 
					        name: formValue.name,
 | 
				
			||||||
        showInDashboard: formValue.showInDashboard,
 | 
					        show_on_dashboard: formValue.showOnDashboard,
 | 
				
			||||||
        showInSideBar: formValue.showInSideBar,
 | 
					        show_in_sidebar: formValue.showInSideBar,
 | 
				
			||||||
        filterRules: this.list.filterRules,
 | 
					        filter_rules: this.list.filterRules,
 | 
				
			||||||
        sortDirection: this.list.sortDirection,
 | 
					        sort_reverse: this.list.sortReverse,
 | 
				
			||||||
        sortField: this.list.sortField
 | 
					        sort_field: this.list.sortField
 | 
				
			||||||
      })
 | 
					      }).subscribe(() => {
 | 
				
			||||||
        modal.close()
 | 
					        modal.close()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  clickTag(tagID: number) {
 | 
					  clickTag(tagID: number) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,9 @@
 | 
				
			|||||||
    </button>
 | 
					    </button>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="modal-body">
 | 
					  <div class="modal-body">
 | 
				
			||||||
    <app-input-text title="Title" formControlName="title"></app-input-text>
 | 
					    <app-input-text title="Name" formControlName="name"></app-input-text>
 | 
				
			||||||
    <app-input-check title="Show in side bar" formControlName="showInSideBar"></app-input-check>
 | 
					    <app-input-check title="Show in side bar" formControlName="showInSideBar"></app-input-check>
 | 
				
			||||||
    <app-input-check title="Show in dashboard" formControlName="showInDashboard"></app-input-check>
 | 
					    <app-input-check title="Show on dashboard" formControlName="showOnDashboard"></app-input-check>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="modal-footer">
 | 
					  <div class="modal-footer">
 | 
				
			||||||
    <button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button>
 | 
					    <button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,9 +15,9 @@ export class SaveViewConfigDialogComponent implements OnInit {
 | 
				
			|||||||
  public saveClicked = new EventEmitter()
 | 
					  public saveClicked = new EventEmitter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  saveViewConfigForm = new FormGroup({
 | 
					  saveViewConfigForm = new FormGroup({
 | 
				
			||||||
    title: new FormControl(''),
 | 
					    name: new FormControl(''),
 | 
				
			||||||
    showInSideBar: new FormControl(false),
 | 
					    showInSideBar: new FormControl(false),
 | 
				
			||||||
    showInDashboard: new FormControl(false),
 | 
					    showOnDashboard: new FormControl(false),
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,22 +39,22 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get selectedTags(): PaperlessTag[] {
 | 
					  get selectedTags(): PaperlessTag[] {
 | 
				
			||||||
    let tagRules: FilterRule[] = this.filterRules.filter(fr => fr.type.id == FILTER_HAS_TAG)
 | 
					    let tagRules: FilterRule[] = this.filterRules.filter(fr => fr.rule_type == FILTER_HAS_TAG)
 | 
				
			||||||
    return this.tags?.filter(t => tagRules.find(tr => tr.value == t.id))
 | 
					    return this.tags?.filter(t => tagRules.find(tr => tr.value == t.id))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get selectedCorrespondents(): PaperlessCorrespondent[] {
 | 
					  get selectedCorrespondents(): PaperlessCorrespondent[] {
 | 
				
			||||||
    let correspondentRules: FilterRule[] = this.filterRules.filter(fr => fr.type.id == FILTER_CORRESPONDENT)
 | 
					    let correspondentRules: FilterRule[] = this.filterRules.filter(fr => fr.rule_type == FILTER_CORRESPONDENT)
 | 
				
			||||||
    return this.correspondents?.filter(c => correspondentRules.find(cr => cr.value == c.id))
 | 
					    return this.correspondents?.filter(c => correspondentRules.find(cr => cr.value == c.id))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get selectedDocumentTypes(): PaperlessDocumentType[] {
 | 
					  get selectedDocumentTypes(): PaperlessDocumentType[] {
 | 
				
			||||||
    let documentTypeRules: FilterRule[] = this.filterRules.filter(fr => fr.type.id == FILTER_DOCUMENT_TYPE)
 | 
					    let documentTypeRules: FilterRule[] = this.filterRules.filter(fr => fr.rule_type == FILTER_DOCUMENT_TYPE)
 | 
				
			||||||
    return this.documentTypes?.filter(dt => documentTypeRules.find(dtr => dtr.value == dt.id))
 | 
					    return this.documentTypes?.filter(dt => documentTypeRules.find(dtr => dtr.value == dt.id))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get titleFilter() {
 | 
					  get titleFilter() {
 | 
				
			||||||
    let existingRule = this.filterRules.find(rule => rule.type.id == FILTER_TITLE)
 | 
					    let existingRule = this.filterRules.find(rule => rule.rule_type == FILTER_TITLE)
 | 
				
			||||||
    return existingRule ? existingRule.value : ''
 | 
					    return existingRule ? existingRule.value : ''
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,15 +100,15 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let filterRuleType = FILTER_RULE_TYPES.find(t => t.id == filterRuleTypeID)
 | 
					    let filterRuleType = FILTER_RULE_TYPES.find(t => t.id == filterRuleTypeID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let existingRule = this.filterRules.find(rule => rule.type.id == filterRuleTypeID && rule.value == value)
 | 
					    let existingRule = this.filterRules.find(rule => rule.rule_type == filterRuleTypeID && rule.value == value)
 | 
				
			||||||
    let existingRuleOfSameType = this.filterRules.find(rule => rule.type.id == filterRuleTypeID)
 | 
					    let existingRuleOfSameType = this.filterRules.find(rule => rule.rule_type == filterRuleTypeID)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (existingRule) {
 | 
					    if (existingRule) {
 | 
				
			||||||
      // if this exact rule already exists, remove it in all cases.
 | 
					      // if this exact rule already exists, remove it in all cases.
 | 
				
			||||||
      this.filterRules.splice(this.filterRules.indexOf(existingRule), 1)
 | 
					      this.filterRules.splice(this.filterRules.indexOf(existingRule), 1)
 | 
				
			||||||
    } else if (filterRuleType.multi || !existingRuleOfSameType) {
 | 
					    } else if (filterRuleType.multi || !existingRuleOfSameType) {
 | 
				
			||||||
      // if we allow multiple rules per type, or no rule of this type already exists, push a new rule.
 | 
					      // if we allow multiple rules per type, or no rule of this type already exists, push a new rule.
 | 
				
			||||||
      this.filterRules.push({type: filterRuleType, value: value})
 | 
					      this.filterRules.push({rule_type: filterRuleTypeID, value: value})
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // otherwise (i.e., no multi support AND there's already a rule of this type), update the rule.
 | 
					      // otherwise (i.e., no multi support AND there's already a rule of this type), update the rule.
 | 
				
			||||||
      existingRuleOfSameType.value = value
 | 
					      existingRuleOfSameType.value = value
 | 
				
			||||||
@@ -117,12 +117,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private setTitleRule(title: string) {
 | 
					  private setTitleRule(title: string) {
 | 
				
			||||||
    let existingRule = this.filterRules.find(rule => rule.type.id == FILTER_TITLE)
 | 
					    let existingRule = this.filterRules.find(rule => rule.rule_type == FILTER_TITLE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!existingRule && title) {
 | 
					    if (!existingRule && title) {
 | 
				
			||||||
      this.filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_TITLE), value: title})
 | 
					      this.filterRules.push({rule_type: FILTER_TITLE, value: title})
 | 
				
			||||||
    } else if (existingRule && !title) {
 | 
					    } else if (existingRule && !title) {
 | 
				
			||||||
      this.filterRules.splice(this.filterRules.findIndex(rule => rule.type.id == FILTER_TITLE), 1)
 | 
					      this.filterRules.splice(this.filterRules.findIndex(rule => rule.rule_type == FILTER_TITLE), 1)
 | 
				
			||||||
    } else if (existingRule && title) {
 | 
					    } else if (existingRule && title) {
 | 
				
			||||||
      existingRule.value = title
 | 
					      existingRule.value = title
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -167,7 +167,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get dateCreatedBefore(): NgbDateStruct {
 | 
					  get dateCreatedBefore(): NgbDateStruct {
 | 
				
			||||||
    let createdBeforeRule: FilterRule = this.filterRules.find(fr => fr.type.id == FILTER_CREATED_BEFORE)
 | 
					    let createdBeforeRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_CREATED_BEFORE)
 | 
				
			||||||
    return createdBeforeRule ? {
 | 
					    return createdBeforeRule ? {
 | 
				
			||||||
      year: createdBeforeRule.value.substring(0,4),
 | 
					      year: createdBeforeRule.value.substring(0,4),
 | 
				
			||||||
      month: createdBeforeRule.value.substring(5,7),
 | 
					      month: createdBeforeRule.value.substring(5,7),
 | 
				
			||||||
@@ -176,7 +176,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get dateCreatedAfter(): NgbDateStruct {
 | 
					  get dateCreatedAfter(): NgbDateStruct {
 | 
				
			||||||
    let createdAfterRule: FilterRule = this.filterRules.find(fr => fr.type.id == FILTER_CREATED_AFTER)
 | 
					    let createdAfterRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_CREATED_AFTER)
 | 
				
			||||||
    return createdAfterRule ? {
 | 
					    return createdAfterRule ? {
 | 
				
			||||||
      year: createdAfterRule.value.substring(0,4),
 | 
					      year: createdAfterRule.value.substring(0,4),
 | 
				
			||||||
      month: createdAfterRule.value.substring(5,7),
 | 
					      month: createdAfterRule.value.substring(5,7),
 | 
				
			||||||
@@ -185,7 +185,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get dateAddedBefore(): NgbDateStruct {
 | 
					  get dateAddedBefore(): NgbDateStruct {
 | 
				
			||||||
    let addedBeforeRule: FilterRule = this.filterRules.find(fr => fr.type.id == FILTER_ADDED_BEFORE)
 | 
					    let addedBeforeRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_ADDED_BEFORE)
 | 
				
			||||||
    return addedBeforeRule ? {
 | 
					    return addedBeforeRule ? {
 | 
				
			||||||
      year: addedBeforeRule.value.substring(0,4),
 | 
					      year: addedBeforeRule.value.substring(0,4),
 | 
				
			||||||
      month: addedBeforeRule.value.substring(5,7),
 | 
					      month: addedBeforeRule.value.substring(5,7),
 | 
				
			||||||
@@ -194,7 +194,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get dateAddedAfter(): NgbDateStruct {
 | 
					  get dateAddedAfter(): NgbDateStruct {
 | 
				
			||||||
    let addedAfterRule: FilterRule = this.filterRules.find(fr => fr.type.id == FILTER_ADDED_AFTER)
 | 
					    let addedAfterRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_ADDED_AFTER)
 | 
				
			||||||
    return addedAfterRule ? {
 | 
					    return addedAfterRule ? {
 | 
				
			||||||
      year: addedAfterRule.value.substring(0,4),
 | 
					      year: addedAfterRule.value.substring(0,4),
 | 
				
			||||||
      month: addedAfterRule.value.substring(5,7),
 | 
					      month: addedAfterRule.value.substring(5,7),
 | 
				
			||||||
@@ -224,13 +224,13 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  setDateFilter(date: NgbDateStruct, dateRuleTypeID: number) {
 | 
					  setDateFilter(date: NgbDateStruct, dateRuleTypeID: number) {
 | 
				
			||||||
    let filterRules = this.filterRules
 | 
					    let filterRules = this.filterRules
 | 
				
			||||||
    let existingRule = filterRules.find(rule => rule.type.id == dateRuleTypeID)
 | 
					    let existingRule = filterRules.find(rule => rule.rule_type == dateRuleTypeID)
 | 
				
			||||||
    let newValue = `${date.year}-${date.month.toString().padStart(2,'0')}-${date.day.toString().padStart(2,'0')}` // YYYY-MM-DD
 | 
					    let newValue = `${date.year}-${date.month.toString().padStart(2,'0')}-${date.day.toString().padStart(2,'0')}` // YYYY-MM-DD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (existingRule) {
 | 
					    if (existingRule) {
 | 
				
			||||||
      existingRule.value = newValue
 | 
					      existingRule.value = newValue
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == dateRuleTypeID), value: newValue})
 | 
					      filterRules.push({rule_type: dateRuleTypeID, value: newValue})
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.filterRules = filterRules
 | 
					    this.filterRules = filterRules
 | 
				
			||||||
@@ -238,7 +238,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  clearDateFilter(dateRuleTypeID: number) {
 | 
					  clearDateFilter(dateRuleTypeID: number) {
 | 
				
			||||||
    let filterRules = this.filterRules
 | 
					    let filterRules = this.filterRules
 | 
				
			||||||
    let existingRule = filterRules.find(rule => rule.type.id == dateRuleTypeID)
 | 
					    let existingRule = filterRules.find(rule => rule.rule_type == dateRuleTypeID)
 | 
				
			||||||
    filterRules.splice(filterRules.indexOf(existingRule), 1)
 | 
					    filterRules.splice(filterRules.indexOf(existingRule), 1)
 | 
				
			||||||
    this.filterRules = filterRules
 | 
					    this.filterRules = filterRules
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,7 +60,8 @@ export abstract class GenericListComponent<T extends ObjectWithId> implements On
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reloadData() {
 | 
					  reloadData() {
 | 
				
			||||||
    this.service.list(this.page, null, this.sortField, this.sortDirection).subscribe(c => {
 | 
					    // TODO: this is a hack
 | 
				
			||||||
 | 
					    this.service.list(this.page, null, this.sortField, this.sortDirection == 'des').subscribe(c => {
 | 
				
			||||||
      this.data = c.results
 | 
					      this.data = c.results
 | 
				
			||||||
      this.collectionSize = c.count
 | 
					      this.collectionSize = c.count
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ export class LogsComponent implements OnInit {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reload() {
 | 
					  reload() {
 | 
				
			||||||
    this.logService.list(1, 50, 'created', 'des', {'level__gte': this.level}).subscribe(result => this.logs = result.results)
 | 
					    this.logService.list(1, 50, 'created', true, {'level__gte': this.level}).subscribe(result => this.logs = result.results)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getLevelText(level: number) {
 | 
					  getLevelText(level: number) {
 | 
				
			||||||
@@ -34,7 +34,7 @@ export class LogsComponent implements OnInit {
 | 
				
			|||||||
    if (this.logs.length > 0) {
 | 
					    if (this.logs.length > 0) {
 | 
				
			||||||
      lastCreated = new Date(this.logs[this.logs.length-1].created).toISOString()
 | 
					      lastCreated = new Date(this.logs[this.logs.length-1].created).toISOString()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.logService.list(1, 25, 'created', 'des', {'created__lt': lastCreated, 'level__gte': this.level}).subscribe(result => {
 | 
					    this.logService.list(1, 25, 'created', true, {'created__lt': lastCreated, 'level__gte': this.level}).subscribe(result => {
 | 
				
			||||||
      this.logs.push(...result.results)
 | 
					      this.logs.push(...result.results)
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,11 +44,11 @@
 | 
				
			|||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
          </thead>
 | 
					          </thead>
 | 
				
			||||||
          <tbody>
 | 
					          <tbody>
 | 
				
			||||||
            <tr *ngFor="let config of savedViewConfigService.getConfigs()">
 | 
					            <tr *ngFor="let view of savedViewService.allViews">
 | 
				
			||||||
              <td>{{ config.title }}</td>
 | 
					              <td>{{ view.name }}</td>
 | 
				
			||||||
              <td>{{ config.showInDashboard | yesno }}</td>
 | 
					              <td>{{ view.show_on_dashboard | yesno }}</td>
 | 
				
			||||||
              <td>{{ config.showInSideBar | yesno }}</td>
 | 
					              <td>{{ view.show_in_sidebar | yesno }}</td>
 | 
				
			||||||
              <td><button type="button" class="btn btn-sm btn-outline-danger" (click)="deleteViewConfig(config)">Delete</button></td>
 | 
					              <td><button type="button" class="btn btn-sm btn-outline-danger" (click)="deleteSavedView(view)">Delete</button></td>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
          </tbody>
 | 
					          </tbody>
 | 
				
			||||||
        </table>
 | 
					        </table>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
import { Component, OnInit } from '@angular/core';
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
import { FormControl, FormGroup } from '@angular/forms';
 | 
					import { FormControl, FormGroup } from '@angular/forms';
 | 
				
			||||||
import { Title } from '@angular/platform-browser';
 | 
					import { Title } from '@angular/platform-browser';
 | 
				
			||||||
import { SavedViewConfig } from 'src/app/data/saved-view-config';
 | 
					import { map, tap } from 'rxjs/operators';
 | 
				
			||||||
 | 
					import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
 | 
				
			||||||
import { GENERAL_SETTINGS } from 'src/app/data/storage-keys';
 | 
					import { GENERAL_SETTINGS } from 'src/app/data/storage-keys';
 | 
				
			||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
 | 
					import { DocumentListViewService } from 'src/app/services/document-list-view.service';
 | 
				
			||||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
 | 
					import { SavedViewService } from 'src/app/services/rest/saved-view.service';
 | 
				
			||||||
import { environment } from 'src/environments/environment';
 | 
					import { environment } from 'src/environments/environment';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
@@ -19,7 +20,7 @@ export class SettingsComponent implements OnInit {
 | 
				
			|||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    private savedViewConfigService: SavedViewConfigService,
 | 
					    public savedViewService: SavedViewService,
 | 
				
			||||||
    private documentListViewService: DocumentListViewService,
 | 
					    private documentListViewService: DocumentListViewService,
 | 
				
			||||||
    private titleService: Title
 | 
					    private titleService: Title
 | 
				
			||||||
  ) { }
 | 
					  ) { }
 | 
				
			||||||
@@ -28,8 +29,8 @@ export class SettingsComponent implements OnInit {
 | 
				
			|||||||
    this.titleService.setTitle(`Settings - ${environment.appTitle}`)
 | 
					    this.titleService.setTitle(`Settings - ${environment.appTitle}`)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deleteViewConfig(config: SavedViewConfig) {
 | 
					  deleteSavedView(savedView: PaperlessSavedView) {
 | 
				
			||||||
    this.savedViewConfigService.deleteConfig(config)
 | 
					    this.savedViewService.delete(savedView).subscribe(() => {})
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  saveSettings() {
 | 
					  saveSettings() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
 | 
				
			|||||||
import { Observable } from 'rxjs';
 | 
					import { Observable } from 'rxjs';
 | 
				
			||||||
import { cloneFilterRules, FilterRule } from '../data/filter-rule';
 | 
					import { cloneFilterRules, FilterRule } from '../data/filter-rule';
 | 
				
			||||||
import { PaperlessDocument } from '../data/paperless-document';
 | 
					import { PaperlessDocument } from '../data/paperless-document';
 | 
				
			||||||
import { SavedViewConfig } from '../data/saved-view-config';
 | 
					import { PaperlessSavedView } from '../data/paperless-saved-view';
 | 
				
			||||||
import { DOCUMENT_LIST_SERVICE, GENERAL_SETTINGS } from '../data/storage-keys';
 | 
					import { DOCUMENT_LIST_SERVICE, GENERAL_SETTINGS } from '../data/storage-keys';
 | 
				
			||||||
import { DocumentService } from './rest/document.service';
 | 
					import { DocumentService } from './rest/document.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,17 +29,17 @@ export class DocumentListViewService {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * This is the current config for the document list. The service will always remember the last settings used for the document list.
 | 
					   * 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
 | 
					  private _documentListViewConfig: PaperlessSavedView
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Optionally, this is the currently selected saved view, which might be null.
 | 
					   * Optionally, this is the currently selected saved view, which might be null.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  private _savedViewConfig: SavedViewConfig
 | 
					  private _savedViewConfig: PaperlessSavedView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get savedView() {
 | 
					  get savedView(): PaperlessSavedView {
 | 
				
			||||||
    return this._savedViewConfig
 | 
					    return this._savedViewConfig
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  set savedView(value) {
 | 
					  set savedView(value: PaperlessSavedView) {
 | 
				
			||||||
    if (value) {
 | 
					    if (value) {
 | 
				
			||||||
      //this is here so that we don't modify value, which might be the actual instance of the saved view.
 | 
					      //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)
 | 
					      this._savedViewConfig = Object.assign({}, value)
 | 
				
			||||||
@@ -53,7 +53,7 @@ export class DocumentListViewService {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get savedViewTitle() {
 | 
					  get savedViewTitle() {
 | 
				
			||||||
    return this.savedView?.title
 | 
					    return this.savedView?.name
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get documentListView() {
 | 
					  get documentListView() {
 | 
				
			||||||
@@ -75,10 +75,11 @@ export class DocumentListViewService {
 | 
				
			|||||||
    return this.savedView || this.documentListView
 | 
					    return this.savedView || this.documentListView
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  load(config: SavedViewConfig) {
 | 
					  load(view: PaperlessSavedView) {
 | 
				
			||||||
    this.view.filterRules = cloneFilterRules(config.filterRules)
 | 
					    this.view.filter_rules = cloneFilterRules(view.filter_rules)
 | 
				
			||||||
    this.view.sortDirection = config.sortDirection
 | 
					    this.view.sort_reverse = view.sort_reverse
 | 
				
			||||||
    this.view.sortField = config.sortField
 | 
					    this.view.sort_field = view.sort_field
 | 
				
			||||||
 | 
					    this.saveDocumentListView()
 | 
				
			||||||
    this.reload()
 | 
					    this.reload()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,9 +94,9 @@ export class DocumentListViewService {
 | 
				
			|||||||
    this.documentService.list(
 | 
					    this.documentService.list(
 | 
				
			||||||
      this.currentPage,
 | 
					      this.currentPage,
 | 
				
			||||||
      this.currentPageSize,
 | 
					      this.currentPageSize,
 | 
				
			||||||
      this.view.sortField,
 | 
					      this.view.sort_field,
 | 
				
			||||||
      this.view.sortDirection,
 | 
					      this.view.sort_reverse,
 | 
				
			||||||
      this.view.filterRules).subscribe(
 | 
					      this.view.filter_rules).subscribe(
 | 
				
			||||||
        result => {
 | 
					        result => {
 | 
				
			||||||
          this.collectionSize = result.count
 | 
					          this.collectionSize = result.count
 | 
				
			||||||
          this.documents = result.results
 | 
					          this.documents = result.results
 | 
				
			||||||
@@ -116,33 +117,33 @@ export class DocumentListViewService {
 | 
				
			|||||||
  set filterRules(filterRules: FilterRule[]) {
 | 
					  set filterRules(filterRules: FilterRule[]) {
 | 
				
			||||||
    //we're going to clone the filterRules object, since we don't
 | 
					    //we're going to clone the filterRules object, since we don't
 | 
				
			||||||
    //want changes in the filter editor to propagate into here right away.
 | 
					    //want changes in the filter editor to propagate into here right away.
 | 
				
			||||||
    this.view.filterRules = cloneFilterRules(filterRules)
 | 
					    this.view.filter_rules = cloneFilterRules(filterRules)
 | 
				
			||||||
    this.reload()
 | 
					    this.reload()
 | 
				
			||||||
    this.saveDocumentListView()
 | 
					    this.saveDocumentListView()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get filterRules(): FilterRule[] {
 | 
					  get filterRules(): FilterRule[] {
 | 
				
			||||||
    return cloneFilterRules(this.view.filterRules)
 | 
					    return cloneFilterRules(this.view.filter_rules)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  set sortField(field: string) {
 | 
					  set sortField(field: string) {
 | 
				
			||||||
    this.view.sortField = field
 | 
					    this.view.sort_field = field
 | 
				
			||||||
    this.saveDocumentListView()
 | 
					    this.saveDocumentListView()
 | 
				
			||||||
    this.reload()
 | 
					    this.reload()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get sortField(): string {
 | 
					  get sortField(): string {
 | 
				
			||||||
    return this.view.sortField
 | 
					    return this.view.sort_field
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  set sortDirection(direction: string) {
 | 
					  set sortReverse(reverse: boolean) {
 | 
				
			||||||
    this.view.sortDirection = direction
 | 
					    this.view.sort_reverse = reverse
 | 
				
			||||||
    this.saveDocumentListView()
 | 
					    this.saveDocumentListView()
 | 
				
			||||||
    this.reload()
 | 
					    this.reload()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get sortDirection(): string {
 | 
					  get sortReverse(): boolean {
 | 
				
			||||||
    return this.view.sortDirection
 | 
					    return this.view.sort_reverse
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private saveDocumentListView() {
 | 
					  private saveDocumentListView() {
 | 
				
			||||||
@@ -204,9 +205,9 @@ export class DocumentListViewService {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!this.documentListView) {
 | 
					    if (!this.documentListView) {
 | 
				
			||||||
      this.documentListView = {
 | 
					      this.documentListView = {
 | 
				
			||||||
        filterRules: [],
 | 
					        filter_rules: [],
 | 
				
			||||||
        sortDirection: 'des',
 | 
					        sort_reverse: true,
 | 
				
			||||||
        sortField: 'created'
 | 
					        sort_field: 'created'
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,17 +22,15 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> {
 | 
				
			|||||||
    return url
 | 
					    return url
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private getOrderingQueryParam(sortField: string, sortDirection: string) {
 | 
					  private getOrderingQueryParam(sortField: string, sortReverse: boolean) {
 | 
				
			||||||
    if (sortField && sortDirection) {
 | 
					    if (sortField) {
 | 
				
			||||||
      return (sortDirection == 'des' ? '-' : '') + sortField
 | 
					      return (sortReverse ? '-' : '') + sortField
 | 
				
			||||||
    } else if (sortField) {
 | 
					 | 
				
			||||||
      return sortField
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      return null
 | 
					      return null
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  list(page?: number, pageSize?: number, sortField?: string, sortDirection?: string, extraParams?): Observable<Results<T>> {
 | 
					  list(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, extraParams?): Observable<Results<T>> {
 | 
				
			||||||
    let httpParams = new HttpParams()
 | 
					    let httpParams = new HttpParams()
 | 
				
			||||||
    if (page) {
 | 
					    if (page) {
 | 
				
			||||||
      httpParams = httpParams.set('page', page.toString())
 | 
					      httpParams = httpParams.set('page', page.toString())
 | 
				
			||||||
@@ -40,7 +38,7 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> {
 | 
				
			|||||||
    if (pageSize) {
 | 
					    if (pageSize) {
 | 
				
			||||||
      httpParams = httpParams.set('page_size', pageSize.toString())
 | 
					      httpParams = httpParams.set('page_size', pageSize.toString())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let ordering = this.getOrderingQueryParam(sortField, sortDirection)
 | 
					    let ordering = this.getOrderingQueryParam(sortField, sortReverse)
 | 
				
			||||||
    if (ordering) {
 | 
					    if (ordering) {
 | 
				
			||||||
      httpParams = httpParams.set('ordering', ordering)
 | 
					      httpParams = httpParams.set('ordering', ordering)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import { map } from 'rxjs/operators';
 | 
				
			|||||||
import { CorrespondentService } from './correspondent.service';
 | 
					import { CorrespondentService } from './correspondent.service';
 | 
				
			||||||
import { DocumentTypeService } from './document-type.service';
 | 
					import { DocumentTypeService } from './document-type.service';
 | 
				
			||||||
import { TagService } from './tag.service';
 | 
					import { TagService } from './tag.service';
 | 
				
			||||||
 | 
					import { FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DOCUMENT_SORT_FIELDS = [
 | 
					export const DOCUMENT_SORT_FIELDS = [
 | 
				
			||||||
  { field: "correspondent__name", name: "Correspondent" },
 | 
					  { field: "correspondent__name", name: "Correspondent" },
 | 
				
			||||||
@@ -22,10 +22,6 @@ export const DOCUMENT_SORT_FIELDS = [
 | 
				
			|||||||
  { field: 'modified', name: 'Modified' }
 | 
					  { field: 'modified', name: 'Modified' }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SORT_DIRECTION_ASCENDING = "asc"
 | 
					 | 
				
			||||||
export const SORT_DIRECTION_DESCENDING = "des"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Injectable({
 | 
					@Injectable({
 | 
				
			||||||
  providedIn: 'root'
 | 
					  providedIn: 'root'
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
@@ -39,10 +35,11 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument>
 | 
				
			|||||||
    if (filterRules) {
 | 
					    if (filterRules) {
 | 
				
			||||||
      let params = {}
 | 
					      let params = {}
 | 
				
			||||||
      for (let rule of filterRules) {
 | 
					      for (let rule of filterRules) {
 | 
				
			||||||
        if (rule.type.multi) {
 | 
					        let ruleType = FILTER_RULE_TYPES.find(t => t.id == rule.rule_type)
 | 
				
			||||||
          params[rule.type.filtervar] = params[rule.type.filtervar] ? params[rule.type.filtervar] + "," + rule.value : rule.value
 | 
					        if (ruleType.multi) {
 | 
				
			||||||
 | 
					          params[ruleType.filtervar] = params[ruleType.filtervar] ? params[ruleType.filtervar] + "," + rule.value : rule.value
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          params[rule.type.filtervar] = rule.value
 | 
					          params[ruleType.filtervar] = rule.value
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return params
 | 
					      return params
 | 
				
			||||||
@@ -64,8 +61,8 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument>
 | 
				
			|||||||
    return doc
 | 
					    return doc
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  list(page?: number, pageSize?: number, sortField?: string, sortDirection?: string, filterRules?: FilterRule[]): Observable<Results<PaperlessDocument>> {
 | 
					  list(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, filterRules?: FilterRule[]): Observable<Results<PaperlessDocument>> {
 | 
				
			||||||
    return super.list(page, pageSize, sortField, sortDirection, this.filterRulesToQueryParams(filterRules)).pipe(
 | 
					    return super.list(page, pageSize, sortField, sortReverse, this.filterRulesToQueryParams(filterRules)).pipe(
 | 
				
			||||||
      map(results => {
 | 
					      map(results => {
 | 
				
			||||||
        results.results.forEach(doc => this.addObservablesToDocument(doc))
 | 
					        results.results.forEach(doc => this.addObservablesToDocument(doc))
 | 
				
			||||||
        return results
 | 
					        return results
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user