mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	bulk edit menu and methods
This commit is contained in:
		@@ -7,22 +7,19 @@
 | 
				
			|||||||
      </svg>
 | 
					      </svg>
 | 
				
			||||||
      Bulk edit
 | 
					      Bulk edit
 | 
				
			||||||
    </button>
 | 
					    </button>
 | 
				
			||||||
    <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
 | 
					    <div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="shadow">
 | 
				
			||||||
      <button ngbDropdownItem>Select page</button>
 | 
					      <button ngbDropdownItem (click)="list.selectPage()">Select page</button>
 | 
				
			||||||
      <button ngbDropdownItem>Select all</button>
 | 
					      <button ngbDropdownItem (click)="list.selectAll()">Select all</button>
 | 
				
			||||||
      <button ngbDropdownItem>Select none</button>
 | 
					      <button ngbDropdownItem (click)="list.selectNone()">Select none</button>
 | 
				
			||||||
      <div class="dropdown-divider"></div>
 | 
					      <div class="dropdown-divider"></div>
 | 
				
			||||||
      <button ngbDropdownItem>Re-create archived document</button>
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkSetCorrespondent()">Set correspondent</button>
 | 
				
			||||||
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkRemoveCorrespondent()">Remove correspondent</button>
 | 
				
			||||||
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkSetDocumentType()">Set document type</button>
 | 
				
			||||||
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkRemoveDocumentType()">Remove document type</button>
 | 
				
			||||||
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkAddTag()">Add tag</button>
 | 
				
			||||||
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkRemoveTag()">Remove tag</button>
 | 
				
			||||||
      <div class="dropdown-divider"></div>
 | 
					      <div class="dropdown-divider"></div>
 | 
				
			||||||
      <button ngbDropdownItem>Set correspondent</button>
 | 
					      <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkDelete()">Delete</button>
 | 
				
			||||||
      <button ngbDropdownItem>Remove correspondent</button>
 | 
					 | 
				
			||||||
      <button ngbDropdownItem>Set document type</button>
 | 
					 | 
				
			||||||
      <button ngbDropdownItem>Remove document type</button>
 | 
					 | 
				
			||||||
      <button ngbDropdownItem>Add tag</button>
 | 
					 | 
				
			||||||
      <button ngbDropdownItem>Remove tag</button>
 | 
					 | 
				
			||||||
      <div class="dropdown-divider"></div>
 | 
					 | 
				
			||||||
      <button ngbDropdownItem>Delete</button>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -101,7 +98,7 @@
 | 
				
			|||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="d-flex justify-content-between align-items-center">
 | 
					<div class="d-flex justify-content-between align-items-center">
 | 
				
			||||||
  <p>{{list.collectionSize || 0}} document(s) <span *ngIf="isFiltered">(filtered)</span></p>
 | 
					  <p><span *ngIf="list.selected.size > 0">Selected {{list.selected.size}} of </span>{{list.collectionSize || 0}} document(s) <span *ngIf="isFiltered">(filtered)</span></p>
 | 
				
			||||||
  <ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5"
 | 
					  <ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5"
 | 
				
			||||||
  [rotate]="true" (pageChange)="list.reload()" aria-label="Default pagination"></ngb-pagination>
 | 
					  [rotate]="true" (pageChange)="list.reload()" aria-label="Default pagination"></ngb-pagination>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@@ -113,6 +110,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'">
 | 
					<table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'">
 | 
				
			||||||
  <thead>
 | 
					  <thead>
 | 
				
			||||||
 | 
					    <th></th>
 | 
				
			||||||
    <th class="d-none d-lg-table-cell">ASN</th>
 | 
					    <th class="d-none d-lg-table-cell">ASN</th>
 | 
				
			||||||
    <th class="d-none d-md-table-cell">Correspondent</th>
 | 
					    <th class="d-none d-md-table-cell">Correspondent</th>
 | 
				
			||||||
    <th>Title</th>
 | 
					    <th>Title</th>
 | 
				
			||||||
@@ -122,6 +120,12 @@
 | 
				
			|||||||
  </thead>
 | 
					  </thead>
 | 
				
			||||||
  <tbody>
 | 
					  <tbody>
 | 
				
			||||||
    <tr *ngFor="let d of list.documents">
 | 
					    <tr *ngFor="let d of list.documents">
 | 
				
			||||||
 | 
					      <td>
 | 
				
			||||||
 | 
					        <div class="custom-control custom-checkbox">
 | 
				
			||||||
 | 
					          <input type="checkbox" class="custom-control-input" id="docCheck{{d.id}}" [checked]="list.isSelected(d)" (change)="list.setSelected(d, $event.target.checked)">
 | 
				
			||||||
 | 
					          <label class="custom-control-label" for="docCheck{{d.id}}"></label>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
      <td class="d-none d-lg-table-cell">
 | 
					      <td class="d-none d-lg-table-cell">
 | 
				
			||||||
        {{d.archive_serial_number}}
 | 
					        {{d.archive_serial_number}}
 | 
				
			||||||
      </td>
 | 
					      </td>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,14 +2,21 @@ import { Component, OnInit } from '@angular/core';
 | 
				
			|||||||
import { Title } from '@angular/platform-browser';
 | 
					import { Title } from '@angular/platform-browser';
 | 
				
			||||||
import { ActivatedRoute } from '@angular/router';
 | 
					import { ActivatedRoute } from '@angular/router';
 | 
				
			||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
 | 
					import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
 | 
				
			||||||
 | 
					import { Observable } from 'rxjs';
 | 
				
			||||||
 | 
					import { map } from 'rxjs/operators';
 | 
				
			||||||
import { cloneFilterRules, FilterRule } from 'src/app/data/filter-rule';
 | 
					import { cloneFilterRules, FilterRule } from 'src/app/data/filter-rule';
 | 
				
			||||||
import { FILTER_CORRESPONDENT, FILTER_DOCUMENT_TYPE, FILTER_HAS_TAG, FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type';
 | 
					import { FILTER_CORRESPONDENT, FILTER_DOCUMENT_TYPE, FILTER_HAS_TAG, FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type';
 | 
				
			||||||
import { SavedViewConfig } from 'src/app/data/saved-view-config';
 | 
					import { SavedViewConfig } from 'src/app/data/saved-view-config';
 | 
				
			||||||
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 { CorrespondentService } from 'src/app/services/rest/correspondent.service';
 | 
				
			||||||
 | 
					import { DocumentTypeService } from 'src/app/services/rest/document-type.service';
 | 
				
			||||||
 | 
					import { DocumentService, DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service';
 | 
				
			||||||
 | 
					import { TagService } from 'src/app/services/rest/tag.service';
 | 
				
			||||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
 | 
					import { SavedViewConfigService } from 'src/app/services/saved-view-config.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 { DeleteDialogComponent } from '../common/delete-dialog/delete-dialog.component';
 | 
				
			||||||
 | 
					import { SelectDialogComponent } from '../common/select-dialog/select-dialog.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({
 | 
				
			||||||
@@ -25,7 +32,11 @@ export class DocumentListComponent implements OnInit {
 | 
				
			|||||||
    public route: ActivatedRoute,
 | 
					    public route: ActivatedRoute,
 | 
				
			||||||
    private toastService: ToastService,
 | 
					    private toastService: ToastService,
 | 
				
			||||||
    public modalService: NgbModal,
 | 
					    public modalService: NgbModal,
 | 
				
			||||||
    private titleService: Title) { }
 | 
					    private titleService: Title,
 | 
				
			||||||
 | 
					    private correspondentService: CorrespondentService,
 | 
				
			||||||
 | 
					    private documentTypeService: DocumentTypeService,
 | 
				
			||||||
 | 
					    private tagService: TagService,
 | 
				
			||||||
 | 
					    private documentService: DocumentService) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  displayMode = 'smallCards' // largeCards, smallCards, details
 | 
					  displayMode = 'smallCards' // largeCards, smallCards, details
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,4 +153,101 @@ export class DocumentListComponent implements OnInit {
 | 
				
			|||||||
    this.applyFilterRules()
 | 
					    this.applyFilterRules()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private executeBulkOperation(method: string, args): Observable<any> {
 | 
				
			||||||
 | 
					    return this.documentService.bulkEdit(Array.from(this.list.selected), method, args).pipe(
 | 
				
			||||||
 | 
					      map(r => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.list.reload()
 | 
				
			||||||
 | 
					        this.list.selectNone()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkSetCorrespondent() {
 | 
				
			||||||
 | 
					    let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
 | 
					    modal.componentInstance.title = "Select correspondent"
 | 
				
			||||||
 | 
					    modal.componentInstance.message = `Select the correspondent you wish to assign to ${this.list.selected.size} selected document(s):`
 | 
				
			||||||
 | 
					    this.correspondentService.listAll().subscribe(response => {
 | 
				
			||||||
 | 
					      modal.componentInstance.objects = response.results
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    modal.componentInstance.selectClicked.subscribe(selectedId => {
 | 
				
			||||||
 | 
					      this.executeBulkOperation('set_correspondent', {"correspondent": selectedId}).subscribe(
 | 
				
			||||||
 | 
					        response => {
 | 
				
			||||||
 | 
					          modal.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkRemoveCorrespondent() {
 | 
				
			||||||
 | 
					    this.executeBulkOperation('set_correspondent', {"correspondent": null}).subscribe(r => {})
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkSetDocumentType() {
 | 
				
			||||||
 | 
					    let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
 | 
					    modal.componentInstance.title = "Select document type"
 | 
				
			||||||
 | 
					    modal.componentInstance.message = `Select the document type you wish to assign to ${this.list.selected.size} selected document(s):`
 | 
				
			||||||
 | 
					    this.documentTypeService.listAll().subscribe(response => {
 | 
				
			||||||
 | 
					      modal.componentInstance.objects = response.results
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    modal.componentInstance.selectClicked.subscribe(selectedId => {
 | 
				
			||||||
 | 
					      this.executeBulkOperation('set_document_type', {"document_type": selectedId}).subscribe(
 | 
				
			||||||
 | 
					        response => {
 | 
				
			||||||
 | 
					          modal.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkRemoveDocumentType() {
 | 
				
			||||||
 | 
					    this.executeBulkOperation('set_document_type', {"document_type": null}).subscribe(r => {})
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkAddTag() {
 | 
				
			||||||
 | 
					    let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
 | 
					    modal.componentInstance.title = "Select tag"
 | 
				
			||||||
 | 
					    modal.componentInstance.message = `Select the tag you wish to assign to ${this.list.selected.size} selected document(s):`
 | 
				
			||||||
 | 
					    this.tagService.listAll().subscribe(response => {
 | 
				
			||||||
 | 
					      modal.componentInstance.objects = response.results
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    modal.componentInstance.selectClicked.subscribe(selectedId => {
 | 
				
			||||||
 | 
					      this.executeBulkOperation('add_tag', {"tag": selectedId}).subscribe(
 | 
				
			||||||
 | 
					        response => {
 | 
				
			||||||
 | 
					          modal.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkRemoveTag() {
 | 
				
			||||||
 | 
					    let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
 | 
					    modal.componentInstance.title = "Select tag"
 | 
				
			||||||
 | 
					    modal.componentInstance.message = `Select the tag you wish to remove from ${this.list.selected.size} selected document(s):`
 | 
				
			||||||
 | 
					    this.tagService.listAll().subscribe(response => {
 | 
				
			||||||
 | 
					      modal.componentInstance.objects = response.results
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    modal.componentInstance.selectClicked.subscribe(selectedId => {
 | 
				
			||||||
 | 
					      this.executeBulkOperation('remove_tag', {"tag": selectedId}).subscribe(
 | 
				
			||||||
 | 
					        response => {
 | 
				
			||||||
 | 
					          modal.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bulkDelete() {
 | 
				
			||||||
 | 
					    let modal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
 | 
					    modal.componentInstance.delayConfirm(5)
 | 
				
			||||||
 | 
					    modal.componentInstance.message = `This operation will permanently delete all ${this.list.selected.size} selected document(s).`
 | 
				
			||||||
 | 
					    modal.componentInstance.message2 = `This operation cannot be undone.`
 | 
				
			||||||
 | 
					    modal.componentInstance.deleteClicked.subscribe(() => {
 | 
				
			||||||
 | 
					      this.executeBulkOperation("delete", {}).subscribe(
 | 
				
			||||||
 | 
					        response => {
 | 
				
			||||||
 | 
					          modal.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    })    
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user