mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	many changes to support server side saved views
This commit is contained in:
		| @@ -37,16 +37,16 @@ | ||||
|           </li> | ||||
|         </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> | ||||
|         </h6> | ||||
|         <ul class="nav flex-column mb-2"> | ||||
|           <li class="nav-item w-100" *ngFor='let config of viewConfigService.getSideBarConfigs()'> | ||||
|             <a class="nav-link text-truncate" routerLink="view/{{config.id}}" routerLinkActive="active" (click)="closeMenu()"> | ||||
|           <li class="nav-item w-100" *ngFor="let view of savedViewService.sidebarViews"> | ||||
|             <a class="nav-link text-truncate" routerLink="view/{{view.id}}" routerLinkActive="active" (click)="closeMenu()"> | ||||
|               <svg class="sidebaricon" fill="currentColor"> | ||||
|                 <use xlink:href="assets/bootstrap-icons.svg#funnel"/> | ||||
|               </svg> | ||||
|               {{config.title}} | ||||
|               {{view.name}} | ||||
|             </a> | ||||
|           </li> | ||||
|         </ul> | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import { from, Observable, Subscription } from 'rxjs'; | ||||
| import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators'; | ||||
| import { PaperlessDocument } from 'src/app/data/paperless-document'; | ||||
| 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 { SavedViewConfigService } from 'src/app/services/saved-view-config.service'; | ||||
| import { DocumentDetailComponent } from '../document-detail/document-detail.component'; | ||||
|    | ||||
| @Component({ | ||||
| @@ -21,7 +21,7 @@ export class AppFrameComponent implements OnInit, OnDestroy { | ||||
|     private activatedRoute: ActivatedRoute, | ||||
|     private openDocumentsService: OpenDocumentsService, | ||||
|     private searchService: SearchService, | ||||
|     public viewConfigService: SavedViewConfigService | ||||
|     public savedViewService: SavedViewService | ||||
|     ) { | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| 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'; | ||||
|  | ||||
|  | ||||
| @@ -12,14 +13,16 @@ import { environment } from 'src/environments/environment'; | ||||
| export class DashboardComponent implements OnInit { | ||||
|  | ||||
|   constructor( | ||||
|     public savedViewConfigService: SavedViewConfigService, | ||||
|     private savedViewService: SavedViewService, | ||||
|     private titleService: Title) { } | ||||
|  | ||||
|  | ||||
|   savedViews = [] | ||||
|   savedViews: PaperlessSavedView[] = [] | ||||
|  | ||||
|   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}`) | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { Component, Input, OnInit } from '@angular/core'; | ||||
| import { Router } from '@angular/router'; | ||||
| 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 { DocumentService } from 'src/app/services/rest/document.service'; | ||||
|  | ||||
| @@ -18,18 +18,18 @@ export class SavedViewWidgetComponent implements OnInit { | ||||
|     private list: DocumentListViewService) { } | ||||
|    | ||||
|   @Input() | ||||
|   savedView: SavedViewConfig | ||||
|   savedView: PaperlessSavedView | ||||
|  | ||||
|   documents: PaperlessDocument[] = [] | ||||
|  | ||||
|   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 | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   showAll() { | ||||
|     if (this.savedView.showInSideBar) { | ||||
|     if (this.savedView.show_in_sidebar) { | ||||
|       this.router.navigate(['view', this.savedView.id]) | ||||
|     } else { | ||||
|       this.list.load(this.savedView) | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
|     </label> | ||||
|   </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"> | ||||
|       <button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>Sort by</button> | ||||
|       <div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="shadow"> | ||||
| @@ -30,13 +30,13 @@ | ||||
|       </div> | ||||
|     </div> | ||||
|     <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"> | ||||
|         <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-down" /> | ||||
|       </svg> | ||||
|     </label> | ||||
|     <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"> | ||||
|         <use xlink:href="assets/bootstrap-icons.svg#sort-alpha-up-alt" /> | ||||
|       </svg> | ||||
| @@ -49,8 +49,8 @@ | ||||
|       <button class="btn btn-sm btn-outline-primary dropdown-toggle" ngbDropdownToggle>Views</button> | ||||
|       <div class="dropdown-menu shadow" ngbDropdownMenu> | ||||
|         <ng-container *ngIf="!list.savedViewId"> | ||||
|           <button ngbDropdownItem *ngFor="let config of savedViewConfigService.getConfigs()" (click)="loadViewConfig(config)">{{config.title}}</button> | ||||
|           <div class="dropdown-divider" *ngIf="savedViewConfigService.getConfigs().length > 0"></div> | ||||
|           <button ngbDropdownItem *ngFor="let view of savedViewService.allViews" (click)="loadViewConfig(view)">{{view.name}}</button> | ||||
|           <div class="dropdown-divider" *ngIf="savedViewService.allViews.length > 0"></div> | ||||
|         </ng-container> | ||||
|  | ||||
|         <button ngbDropdownItem (click)="saveViewConfig()" *ngIf="list.savedViewId">Save "{{list.savedViewTitle}}"</button> | ||||
|   | ||||
| @@ -1,15 +1,16 @@ | ||||
| import { Component, OnInit, ViewChild } from '@angular/core'; | ||||
| 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 { 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 { 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 { environment } from 'src/environments/environment'; | ||||
| import { FilterEditorComponent } from '../filter-editor/filter-editor.component'; | ||||
| import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-document-list', | ||||
|   templateUrl: './document-list.component.html', | ||||
| @@ -19,8 +20,9 @@ export class DocumentListComponent implements OnInit { | ||||
|  | ||||
|   constructor( | ||||
|     public list: DocumentListViewService, | ||||
|     public savedViewConfigService: SavedViewConfigService, | ||||
|     public savedViewService: SavedViewService, | ||||
|     public route: ActivatedRoute, | ||||
|     private router: Router, | ||||
|     private toastService: ToastService, | ||||
|     public modalService: NgbModal, | ||||
|     private titleService: Title) { } | ||||
| @@ -51,40 +53,51 @@ export class DocumentListComponent implements OnInit { | ||||
|       this.displayMode = localStorage.getItem('document-list:displayMode') | ||||
|     } | ||||
|     this.route.paramMap.subscribe(params => { | ||||
|       this.list.clear() | ||||
|       if (params.has('id')) { | ||||
|         this.list.savedView = this.savedViewConfigService.getConfig(params.get('id')) | ||||
|         this.titleService.setTitle(`${this.list.savedView.title} - ${environment.appTitle}`) | ||||
|         this.savedViewService.getCached(+params.get('id')).subscribe(view => { | ||||
|           if (!view) { | ||||
|             this.router.navigate(["404"]) | ||||
|             return | ||||
|           } | ||||
|  | ||||
|           this.list.savedView = view | ||||
|           this.titleService.setTitle(`${this.list.savedView.name} - ${environment.appTitle}`) | ||||
|           this.list.reload() | ||||
|         }) | ||||
|       } else { | ||||
|         this.list.savedView = null | ||||
|         this.titleService.setTitle(`Documents - ${environment.appTitle}`) | ||||
|         this.list.reload() | ||||
|       } | ||||
|       this.list.clear() | ||||
|       this.list.reload() | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|  | ||||
|   loadViewConfig(config: SavedViewConfig) { | ||||
|     this.list.load(config) | ||||
|   loadViewConfig(view: PaperlessSavedView) { | ||||
|     this.list.load(view) | ||||
|   } | ||||
|  | ||||
|   saveViewConfig() { | ||||
|     this.savedViewConfigService.updateConfig(this.list.savedView) | ||||
|     this.toastService.showToast(Toast.make("Information", `View "${this.list.savedView.title}" saved successfully.`)) | ||||
|     this.savedViewService.update(this.list.savedView).subscribe(result => { | ||||
|       this.toastService.showToast(Toast.make("Information", `View "${this.list.savedView.name}" saved successfully.`)) | ||||
|     }) | ||||
|  | ||||
|   } | ||||
|  | ||||
|   saveViewConfigAs() { | ||||
|     let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'}) | ||||
|     modal.componentInstance.saveClicked.subscribe(formValue => { | ||||
|       this.savedViewConfigService.newConfig({ | ||||
|         title: formValue.title, | ||||
|         showInDashboard: formValue.showInDashboard, | ||||
|         showInSideBar: formValue.showInSideBar, | ||||
|         filterRules: this.list.filterRules, | ||||
|         sortDirection: this.list.sortDirection, | ||||
|         sortField: this.list.sortField | ||||
|       this.savedViewService.create({ | ||||
|         name: formValue.name, | ||||
|         show_on_dashboard: formValue.showOnDashboard, | ||||
|         show_in_sidebar: formValue.showInSideBar, | ||||
|         filter_rules: this.list.filterRules, | ||||
|         sort_reverse: this.list.sortReverse, | ||||
|         sort_field: this.list.sortField | ||||
|       }).subscribe(() => { | ||||
|         modal.close() | ||||
|       }) | ||||
|       modal.close() | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -6,9 +6,9 @@ | ||||
|     </button> | ||||
|   </div> | ||||
|   <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 dashboard" formControlName="showInDashboard"></app-input-check> | ||||
|     <app-input-check title="Show on dashboard" formControlName="showOnDashboard"></app-input-check> | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <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() | ||||
|  | ||||
|   saveViewConfigForm = new FormGroup({ | ||||
|     title: new FormControl(''), | ||||
|     name: new FormControl(''), | ||||
|     showInSideBar: new FormControl(false), | ||||
|     showInDashboard: new FormControl(false), | ||||
|     showOnDashboard: new FormControl(false), | ||||
|   }) | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|   | ||||
| @@ -39,22 +39,22 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   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)) | ||||
|   } | ||||
|  | ||||
|   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)) | ||||
|   } | ||||
|  | ||||
|   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)) | ||||
|   } | ||||
|  | ||||
|   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 : '' | ||||
|   } | ||||
|  | ||||
| @@ -100,15 +100,15 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|  | ||||
|     let filterRuleType = FILTER_RULE_TYPES.find(t => t.id == filterRuleTypeID) | ||||
|  | ||||
|     let existingRule = this.filterRules.find(rule => rule.type.id == filterRuleTypeID && rule.value == value) | ||||
|     let existingRuleOfSameType = this.filterRules.find(rule => rule.type.id == filterRuleTypeID) | ||||
|     let existingRule = this.filterRules.find(rule => rule.rule_type == filterRuleTypeID && rule.value == value) | ||||
|     let existingRuleOfSameType = this.filterRules.find(rule => rule.rule_type == filterRuleTypeID) | ||||
|      | ||||
|     if (existingRule) { | ||||
|       // if this exact rule already exists, remove it in all cases. | ||||
|       this.filterRules.splice(this.filterRules.indexOf(existingRule), 1) | ||||
|     } else if (filterRuleType.multi || !existingRuleOfSameType) { | ||||
|       // 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 { | ||||
|       // otherwise (i.e., no multi support AND there's already a rule of this type), update the rule. | ||||
|       existingRuleOfSameType.value = value | ||||
| @@ -117,12 +117,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   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) { | ||||
|       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) { | ||||
|       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) { | ||||
|       existingRule.value = title | ||||
|     } | ||||
| @@ -167,7 +167,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   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 ? { | ||||
|       year: createdBeforeRule.value.substring(0,4), | ||||
|       month: createdBeforeRule.value.substring(5,7), | ||||
| @@ -176,7 +176,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   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 ? { | ||||
|       year: createdAfterRule.value.substring(0,4), | ||||
|       month: createdAfterRule.value.substring(5,7), | ||||
| @@ -185,7 +185,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   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 ? { | ||||
|       year: addedBeforeRule.value.substring(0,4), | ||||
|       month: addedBeforeRule.value.substring(5,7), | ||||
| @@ -194,7 +194,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   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 ? { | ||||
|       year: addedAfterRule.value.substring(0,4), | ||||
|       month: addedAfterRule.value.substring(5,7), | ||||
| @@ -224,13 +224,13 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|  | ||||
|   setDateFilter(date: NgbDateStruct, dateRuleTypeID: number) { | ||||
|     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 | ||||
|  | ||||
|     if (existingRule) { | ||||
|       existingRule.value = newValue | ||||
|     } else { | ||||
|       filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == dateRuleTypeID), value: newValue}) | ||||
|       filterRules.push({rule_type: dateRuleTypeID, value: newValue}) | ||||
|     } | ||||
|  | ||||
|     this.filterRules = filterRules | ||||
| @@ -238,7 +238,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|  | ||||
|   clearDateFilter(dateRuleTypeID: number) { | ||||
|     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) | ||||
|     this.filterRules = filterRules | ||||
|   } | ||||
|   | ||||
| @@ -8,9 +8,9 @@ import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dial | ||||
|  | ||||
| @Directive() | ||||
| export abstract class GenericListComponent<T extends ObjectWithId> implements OnInit { | ||||
|    | ||||
|  | ||||
|   constructor( | ||||
|     private service: AbstractPaperlessService<T>,  | ||||
|     private service: AbstractPaperlessService<T>, | ||||
|     private modalService: NgbModal, | ||||
|     private editDialogComponent: any) { | ||||
|     } | ||||
| @@ -60,7 +60,8 @@ export abstract class GenericListComponent<T extends ObjectWithId> implements On | ||||
|   } | ||||
|  | ||||
|   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.collectionSize = c.count | ||||
|     }); | ||||
|   | ||||
| @@ -22,7 +22,7 @@ export class LogsComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   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) { | ||||
| @@ -34,7 +34,7 @@ export class LogsComponent implements OnInit { | ||||
|     if (this.logs.length > 0) { | ||||
|       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) | ||||
|     }) | ||||
|   } | ||||
|   | ||||
| @@ -44,11 +44,11 @@ | ||||
|             </tr> | ||||
|           </thead> | ||||
|           <tbody> | ||||
|             <tr *ngFor="let config of savedViewConfigService.getConfigs()"> | ||||
|               <td>{{ config.title }}</td> | ||||
|               <td>{{ config.showInDashboard | yesno }}</td> | ||||
|               <td>{{ config.showInSideBar | yesno }}</td> | ||||
|               <td><button type="button" class="btn btn-sm btn-outline-danger" (click)="deleteViewConfig(config)">Delete</button></td> | ||||
|             <tr *ngFor="let view of savedViewService.allViews"> | ||||
|               <td>{{ view.name }}</td> | ||||
|               <td>{{ view.show_on_dashboard | yesno }}</td> | ||||
|               <td>{{ view.show_in_sidebar | yesno }}</td> | ||||
|               <td><button type="button" class="btn btn-sm btn-outline-danger" (click)="deleteSavedView(view)">Delete</button></td> | ||||
|             </tr> | ||||
|           </tbody> | ||||
|         </table> | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { FormControl, FormGroup } from '@angular/forms'; | ||||
| 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 { 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'; | ||||
|  | ||||
| @Component({ | ||||
| @@ -19,7 +20,7 @@ export class SettingsComponent implements OnInit { | ||||
|   }) | ||||
|  | ||||
|   constructor( | ||||
|     private savedViewConfigService: SavedViewConfigService, | ||||
|     public savedViewService: SavedViewService, | ||||
|     private documentListViewService: DocumentListViewService, | ||||
|     private titleService: Title | ||||
|   ) { } | ||||
| @@ -28,8 +29,8 @@ export class SettingsComponent implements OnInit { | ||||
|     this.titleService.setTitle(`Settings - ${environment.appTitle}`) | ||||
|   } | ||||
|  | ||||
|   deleteViewConfig(config: SavedViewConfig) { | ||||
|     this.savedViewConfigService.deleteConfig(config) | ||||
|   deleteSavedView(savedView: PaperlessSavedView) { | ||||
|     this.savedViewService.delete(savedView).subscribe(() => {}) | ||||
|   } | ||||
|  | ||||
|   saveSettings() { | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; | ||||
| import { Observable } from 'rxjs'; | ||||
| import { cloneFilterRules, FilterRule } from '../data/filter-rule'; | ||||
| 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 { 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. | ||||
|    */ | ||||
|   private _documentListViewConfig: SavedViewConfig | ||||
|   private _documentListViewConfig: PaperlessSavedView | ||||
|   /** | ||||
|    * 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 | ||||
|   } | ||||
|  | ||||
|   set savedView(value) { | ||||
|   set savedView(value: PaperlessSavedView) { | ||||
|     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) | ||||
| @@ -53,7 +53,7 @@ export class DocumentListViewService { | ||||
|   } | ||||
|  | ||||
|   get savedViewTitle() { | ||||
|     return this.savedView?.title | ||||
|     return this.savedView?.name | ||||
|   } | ||||
|  | ||||
|   get documentListView() { | ||||
| @@ -75,10 +75,11 @@ export class DocumentListViewService { | ||||
|     return this.savedView || this.documentListView | ||||
|   } | ||||
|  | ||||
|   load(config: SavedViewConfig) { | ||||
|     this.view.filterRules = cloneFilterRules(config.filterRules) | ||||
|     this.view.sortDirection = config.sortDirection | ||||
|     this.view.sortField = config.sortField | ||||
|   load(view: PaperlessSavedView) { | ||||
|     this.view.filter_rules = cloneFilterRules(view.filter_rules) | ||||
|     this.view.sort_reverse = view.sort_reverse | ||||
|     this.view.sort_field = view.sort_field | ||||
|     this.saveDocumentListView() | ||||
|     this.reload() | ||||
|   } | ||||
|  | ||||
| @@ -93,9 +94,9 @@ export class DocumentListViewService { | ||||
|     this.documentService.list( | ||||
|       this.currentPage, | ||||
|       this.currentPageSize, | ||||
|       this.view.sortField, | ||||
|       this.view.sortDirection, | ||||
|       this.view.filterRules).subscribe( | ||||
|       this.view.sort_field, | ||||
|       this.view.sort_reverse, | ||||
|       this.view.filter_rules).subscribe( | ||||
|         result => { | ||||
|           this.collectionSize = result.count | ||||
|           this.documents = result.results | ||||
| @@ -116,33 +117,33 @@ export class DocumentListViewService { | ||||
|   set filterRules(filterRules: FilterRule[]) { | ||||
|     //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.view.filter_rules = cloneFilterRules(filterRules) | ||||
|     this.reload() | ||||
|     this.saveDocumentListView() | ||||
|   } | ||||
|  | ||||
|   get filterRules(): FilterRule[] { | ||||
|     return cloneFilterRules(this.view.filterRules) | ||||
|     return cloneFilterRules(this.view.filter_rules) | ||||
|   } | ||||
|  | ||||
|   set sortField(field: string) { | ||||
|     this.view.sortField = field | ||||
|     this.view.sort_field = field | ||||
|     this.saveDocumentListView() | ||||
|     this.reload() | ||||
|   } | ||||
|  | ||||
|   get sortField(): string { | ||||
|     return this.view.sortField | ||||
|     return this.view.sort_field | ||||
|   } | ||||
|  | ||||
|   set sortDirection(direction: string) { | ||||
|     this.view.sortDirection = direction | ||||
|   set sortReverse(reverse: boolean) { | ||||
|     this.view.sort_reverse = reverse | ||||
|     this.saveDocumentListView() | ||||
|     this.reload() | ||||
|   } | ||||
|  | ||||
|   get sortDirection(): string { | ||||
|     return this.view.sortDirection | ||||
|   get sortReverse(): boolean { | ||||
|     return this.view.sort_reverse | ||||
|   } | ||||
|  | ||||
|   private saveDocumentListView() { | ||||
| @@ -204,9 +205,9 @@ export class DocumentListViewService { | ||||
|     } | ||||
|     if (!this.documentListView) { | ||||
|       this.documentListView = { | ||||
|         filterRules: [], | ||||
|         sortDirection: 'des', | ||||
|         sortField: 'created' | ||||
|         filter_rules: [], | ||||
|         sort_reverse: true, | ||||
|         sort_field: 'created' | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -22,17 +22,15 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> { | ||||
|     return url | ||||
|   } | ||||
|  | ||||
|   private getOrderingQueryParam(sortField: string, sortDirection: string) { | ||||
|     if (sortField && sortDirection) { | ||||
|       return (sortDirection == 'des' ? '-' : '') + sortField | ||||
|     } else if (sortField) { | ||||
|       return sortField | ||||
|   private getOrderingQueryParam(sortField: string, sortReverse: boolean) { | ||||
|     if (sortField) { | ||||
|       return (sortReverse ? '-' : '') + sortField | ||||
|     } else { | ||||
|       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() | ||||
|     if (page) { | ||||
|       httpParams = httpParams.set('page', page.toString()) | ||||
| @@ -40,7 +38,7 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> { | ||||
|     if (pageSize) { | ||||
|       httpParams = httpParams.set('page_size', pageSize.toString()) | ||||
|     } | ||||
|     let ordering = this.getOrderingQueryParam(sortField, sortDirection) | ||||
|     let ordering = this.getOrderingQueryParam(sortField, sortReverse) | ||||
|     if (ordering) { | ||||
|       httpParams = httpParams.set('ordering', ordering) | ||||
|     } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import { map } from 'rxjs/operators'; | ||||
| import { CorrespondentService } from './correspondent.service'; | ||||
| import { DocumentTypeService } from './document-type.service'; | ||||
| import { TagService } from './tag.service'; | ||||
|  | ||||
| import { FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type'; | ||||
|  | ||||
| export const DOCUMENT_SORT_FIELDS = [ | ||||
|   { field: "correspondent__name", name: "Correspondent" }, | ||||
| @@ -22,10 +22,6 @@ export const DOCUMENT_SORT_FIELDS = [ | ||||
|   { field: 'modified', name: 'Modified' } | ||||
| ] | ||||
|  | ||||
| export const SORT_DIRECTION_ASCENDING = "asc" | ||||
| export const SORT_DIRECTION_DESCENDING = "des" | ||||
|  | ||||
|  | ||||
| @Injectable({ | ||||
|   providedIn: 'root' | ||||
| }) | ||||
| @@ -39,10 +35,11 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument> | ||||
|     if (filterRules) { | ||||
|       let params = {} | ||||
|       for (let rule of filterRules) { | ||||
|         if (rule.type.multi) { | ||||
|           params[rule.type.filtervar] = params[rule.type.filtervar] ? params[rule.type.filtervar] + "," + rule.value : rule.value | ||||
|         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 { | ||||
|           params[rule.type.filtervar] = rule.value | ||||
|           params[ruleType.filtervar] = rule.value | ||||
|         } | ||||
|       } | ||||
|       return params | ||||
| @@ -64,8 +61,8 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument> | ||||
|     return doc | ||||
|   } | ||||
|  | ||||
|   list(page?: number, pageSize?: number, sortField?: string, sortDirection?: string, filterRules?: FilterRule[]): Observable<Results<PaperlessDocument>> { | ||||
|     return super.list(page, pageSize, sortField, sortDirection, this.filterRulesToQueryParams(filterRules)).pipe( | ||||
|   list(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, filterRules?: FilterRule[]): Observable<Results<PaperlessDocument>> { | ||||
|     return super.list(page, pageSize, sortField, sortReverse, this.filterRulesToQueryParams(filterRules)).pipe( | ||||
|       map(results => { | ||||
|         results.results.forEach(doc => this.addObservablesToDocument(doc)) | ||||
|         return results | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 jonaswinkler
					jonaswinkler