mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Completely rewrite change detection, add back remove operations
This commit is contained in:
		| @@ -19,6 +19,12 @@ | |||||||
|           <input class="form-control" type="text" [(ngModel)]="filterText" placeholder="Filter {{title}}" (keyup.enter)="listFilterEnter()" #listFilterTextInput> |           <input class="form-control" type="text" [(ngModel)]="filterText" placeholder="Filter {{title}}" (keyup.enter)="listFilterEnter()" #listFilterTextInput> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|  |       <button *ngIf="showRemoveAll" role="menuitem" class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-left-0 border-right-0 border-bottom" (click)="removeAll.next()"> | ||||||
|  |         <svg class="toolbaricon text-danger" fill="currentColor"> | ||||||
|  |           <use xlink:href="assets/bootstrap-icons.svg#x" /> | ||||||
|  |         </svg> | ||||||
|  |         <small class="my-1">Remove All</small> | ||||||
|  |       </button> | ||||||
|       <div *ngIf="toggleableItems" class="items"> |       <div *ngIf="toggleableItems" class="items"> | ||||||
|         <ng-container *ngFor="let toggleableItem of toggleableItems | filter: filterText"> |         <ng-container *ngFor="let toggleableItem of toggleableItems | filter: filterText"> | ||||||
|           <app-toggleable-dropdown-button [toggleableItem]="toggleableItem" [showCounts]="showCounts" (toggle)="toggleItem($event)"></app-toggleable-dropdown-button> |           <app-toggleable-dropdown-button [toggleableItem]="toggleableItem" [showCounts]="showCounts" (toggle)="toggleItem($event)"></app-toggleable-dropdown-button> | ||||||
|   | |||||||
| @@ -69,12 +69,18 @@ export class FilterableDropdownComponent { | |||||||
|   @Input() |   @Input() | ||||||
|   singular: boolean = false |   singular: boolean = false | ||||||
|  |  | ||||||
|  |   @Input() | ||||||
|  |   showRemoveAll: boolean = false | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   toggle = new EventEmitter() |   toggle = new EventEmitter() | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   open = new EventEmitter() |   open = new EventEmitter() | ||||||
|  |  | ||||||
|  |   @Output() | ||||||
|  |   removeAll = new EventEmitter() | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   editingComplete = new EventEmitter() |   editingComplete = new EventEmitter() | ||||||
|  |  | ||||||
| @@ -110,7 +116,7 @@ export class FilterableDropdownComponent { | |||||||
|       this.open.next() |       this.open.next() | ||||||
|     } else { |     } else { | ||||||
|       this.filterText = '' |       this.filterText = '' | ||||||
|       if (this.type == FilterableDropdownType.Editing) this.editingComplete.emit(this.itemsSelected) |       if (this.type == FilterableDropdownType.Editing) this.editingComplete.emit(this.toggleableItems) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,9 +29,33 @@ | |||||||
|   <div class="col-auto mb-2 mb-xl-0"> |   <div class="col-auto mb-2 mb-xl-0"> | ||||||
|     <div class="d-flex"> |     <div class="d-flex"> | ||||||
|       <label class="ml-auto mt-1 mb-0 mr-2">Edit:</label> |       <label class="ml-auto mt-1 mb-0 mr-2">Edit:</label> | ||||||
|       <app-filterable-dropdown class="mr-2 mr-md-3" title="Tags" icon="tag-fill" [toggleableItems]="tagsToggleableItems" [type]="dropdownTypes.Editing" [showCounts]="!this.selectionSpansPages" (open)="tagsDropdownOpen()" (editingComplete)="applyTags($event)"></app-filterable-dropdown> |       <app-filterable-dropdown class="mr-2 mr-md-3" title="Tags" icon="tag-fill" | ||||||
|       <app-filterable-dropdown class="mr-2 mr-md-3" title="Correspondent" icon="person-fill" [toggleableItems]="correspondentsToggleableItems" [type]="dropdownTypes.Editing" [showCounts]="!this.selectionSpansPages" singular="true" (open)="correspondentsDropdownOpen()" (editingComplete)="applyCorrespondent($event)"></app-filterable-dropdown> |         [toggleableItems]="tagsToggleableItems" | ||||||
|       <app-filterable-dropdown class="mr-2 mr-md-3" title="Document Type" icon="file-earmark-fill" [toggleableItems]="documentTypesToggleableItems" [type]="dropdownTypes.Editing" [showCounts]="!this.selectionSpansPages" singular="true" (open)="documentTypesDropdownOpen()" (editingComplete)="applyDocumentType($event)"></app-filterable-dropdown> |         [type]="dropdownTypes.Editing" | ||||||
|  |         [showCounts]="!this.selectionSpansPages" | ||||||
|  |         [showRemoveAll]="this.selectionSpansPages" | ||||||
|  |         (open)="tagsDropdownOpen()" | ||||||
|  |         (removeAll)="applyTags([], true)" | ||||||
|  |         (editingComplete)="applyTags($event)"> | ||||||
|  |       </app-filterable-dropdown> | ||||||
|  |       <app-filterable-dropdown class="mr-2 mr-md-3" title="Correspondent" icon="person-fill" singular="true" | ||||||
|  |         [toggleableItems]="correspondentsToggleableItems" | ||||||
|  |         [type]="dropdownTypes.Editing" | ||||||
|  |         [showCounts]="!this.selectionSpansPages" | ||||||
|  |         [showRemoveAll]="this.selectionSpansPages" | ||||||
|  |         (open)="correspondentsDropdownOpen()" | ||||||
|  |         (removeAll)="applyCorrespondent([], true)" | ||||||
|  |         (editingComplete)="applyCorrespondent($event)"> | ||||||
|  |       </app-filterable-dropdown> | ||||||
|  |       <app-filterable-dropdown class="mr-2 mr-md-3" title="Document Type" icon="file-earmark-fill" singular="true" | ||||||
|  |         [toggleableItems]="documentTypesToggleableItems" | ||||||
|  |         [type]="dropdownTypes.Editing" | ||||||
|  |         [showCounts]="!this.selectionSpansPages" | ||||||
|  |         [showRemoveAll]="this.selectionSpansPages" | ||||||
|  |         (open)="documentTypesDropdownOpen()" | ||||||
|  |         (removeAll)="applyDocumentType([], true)" | ||||||
|  |         (editingComplete)="applyDocumentType($event)"> | ||||||
|  |       </app-filterable-dropdown> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|   <div class="w-100 d-xl-none"></div> |   <div class="w-100 d-xl-none"></div> | ||||||
|   | |||||||
| @@ -11,6 +11,11 @@ import { DocumentService } from 'src/app/services/rest/document.service'; | |||||||
| import { FilterableDropdownType } from 'src/app/components/common/filterable-dropdown/filterable-dropdown.component'; | import { FilterableDropdownType } from 'src/app/components/common/filterable-dropdown/filterable-dropdown.component'; | ||||||
| import { ToggleableItem, ToggleableItemState } from 'src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; | import { ToggleableItem, ToggleableItemState } from 'src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; | ||||||
|  |  | ||||||
|  | interface ChangedItems { | ||||||
|  |   itemsToAdd: any[], | ||||||
|  |   itemsToRemove: any[] | ||||||
|  | } | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-bulk-editor', |   selector: 'app-bulk-editor', | ||||||
|   templateUrl: './bulk-editor.component.html', |   templateUrl: './bulk-editor.component.html', | ||||||
| @@ -33,6 +38,9 @@ export class BulkEditorComponent { | |||||||
|   @Output() |   @Output() | ||||||
|   selectNone = new EventEmitter() |   selectNone = new EventEmitter() | ||||||
|  |  | ||||||
|  |   @Output() | ||||||
|  |   setTags = new EventEmitter() | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   setCorrespondent = new EventEmitter() |   setCorrespondent = new EventEmitter() | ||||||
|  |  | ||||||
| @@ -40,18 +48,24 @@ export class BulkEditorComponent { | |||||||
|   setDocumentType = new EventEmitter() |   setDocumentType = new EventEmitter() | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   setTags = new EventEmitter() |   delete = new EventEmitter() | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   delete = new EventEmitter() |   removeTags = new EventEmitter() | ||||||
|  |  | ||||||
|  |   @Output() | ||||||
|  |   removeCorrespondents = new EventEmitter() | ||||||
|  |  | ||||||
|  |   @Output() | ||||||
|  |   removeDocumentTypes = new EventEmitter() | ||||||
|  |  | ||||||
|   tags: PaperlessTag[] |   tags: PaperlessTag[] | ||||||
|   correspondents: PaperlessCorrespondent[] |   correspondents: PaperlessCorrespondent[] | ||||||
|   documentTypes: PaperlessDocumentType[] |   documentTypes: PaperlessDocumentType[] | ||||||
|  |  | ||||||
|   private initiallySelectedTagsToggleableItems: ToggleableItem[] |   private initialTagsToggleableItems: ToggleableItem[] | ||||||
|   private initiallySelectedCorrespondentsToggleableItems: ToggleableItem[] |   private initialCorrespondentsToggleableItems: ToggleableItem[] | ||||||
|   private initiallySelectedDocumentTypesToggleableItems: ToggleableItem[] |   private initialDocumentTypesToggleableItems: ToggleableItem[] | ||||||
|  |  | ||||||
|   dropdownTypes = FilterableDropdownType |   dropdownTypes = FilterableDropdownType | ||||||
|  |  | ||||||
| @@ -59,6 +73,7 @@ export class BulkEditorComponent { | |||||||
|     return this.selectedDocuments.size > this.viewDocuments.length || !Array.from(this.selectedDocuments).every(sd => this.viewDocuments.find(d => d.id == sd)) |     return this.selectedDocuments.size > this.viewDocuments.length || !Array.from(this.selectedDocuments).every(sd => this.viewDocuments.find(d => d.id == sd)) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private _tagsToggleableItems: ToggleableItem[] | ||||||
|   get tagsToggleableItems(): ToggleableItem[] { |   get tagsToggleableItems(): ToggleableItem[] { | ||||||
|     let tagsToggleableItems = [] |     let tagsToggleableItems = [] | ||||||
|     let selectedDocuments: PaperlessDocument[] = this.viewDocuments.filter(d => this.selectedDocuments.has(d.id)) |     let selectedDocuments: PaperlessDocument[] = this.viewDocuments.filter(d => this.selectedDocuments.has(d.id)) | ||||||
| @@ -71,9 +86,11 @@ export class BulkEditorComponent { | |||||||
|       else if (selectedDocumentsWithTag.length > 0 && selectedDocumentsWithTag.length < selectedDocuments.length) state = ToggleableItemState.PartiallySelected |       else if (selectedDocumentsWithTag.length > 0 && selectedDocumentsWithTag.length < selectedDocuments.length) state = ToggleableItemState.PartiallySelected | ||||||
|       tagsToggleableItems.push({item: t, state: state, count: selectedDocumentsWithTag.length}) |       tagsToggleableItems.push({item: t, state: state, count: selectedDocumentsWithTag.length}) | ||||||
|     }) |     }) | ||||||
|  |     this._tagsToggleableItems = tagsToggleableItems | ||||||
|     return tagsToggleableItems |     return tagsToggleableItems | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private _correspondentsToggleableItems: ToggleableItem[] | ||||||
|   get correspondentsToggleableItems(): ToggleableItem[] { |   get correspondentsToggleableItems(): ToggleableItem[] { | ||||||
|     let correspondentsToggleableItems = [] |     let correspondentsToggleableItems = [] | ||||||
|     let selectedDocuments: PaperlessDocument[] = this.viewDocuments.filter(d => this.selectedDocuments.has(d.id)) |     let selectedDocuments: PaperlessDocument[] = this.viewDocuments.filter(d => this.selectedDocuments.has(d.id)) | ||||||
| @@ -86,9 +103,11 @@ export class BulkEditorComponent { | |||||||
|       else if (selectedDocumentsWithCorrespondent.length > 0 && selectedDocumentsWithCorrespondent.length < selectedDocuments.length) state = ToggleableItemState.PartiallySelected |       else if (selectedDocumentsWithCorrespondent.length > 0 && selectedDocumentsWithCorrespondent.length < selectedDocuments.length) state = ToggleableItemState.PartiallySelected | ||||||
|       correspondentsToggleableItems.push({item: c, state: state, count: selectedDocumentsWithCorrespondent.length}) |       correspondentsToggleableItems.push({item: c, state: state, count: selectedDocumentsWithCorrespondent.length}) | ||||||
|     }) |     }) | ||||||
|  |     this._correspondentsToggleableItems = correspondentsToggleableItems | ||||||
|     return correspondentsToggleableItems |     return correspondentsToggleableItems | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private _documentTypesToggleableItems: ToggleableItem[] | ||||||
|   get documentTypesToggleableItems(): ToggleableItem[] { |   get documentTypesToggleableItems(): ToggleableItem[] { | ||||||
|     let documentTypesToggleableItems = [] |     let documentTypesToggleableItems = [] | ||||||
|     let selectedDocuments: PaperlessDocument[] = this.viewDocuments.filter(d => this.selectedDocuments.has(d.id)) |     let selectedDocuments: PaperlessDocument[] = this.viewDocuments.filter(d => this.selectedDocuments.has(d.id)) | ||||||
| @@ -101,6 +120,7 @@ export class BulkEditorComponent { | |||||||
|       else if (selectedDocumentsWithDocumentType.length > 0 && selectedDocumentsWithDocumentType.length < selectedDocuments.length) state = ToggleableItemState.PartiallySelected |       else if (selectedDocumentsWithDocumentType.length > 0 && selectedDocumentsWithDocumentType.length < selectedDocuments.length) state = ToggleableItemState.PartiallySelected | ||||||
|       documentTypesToggleableItems.push({item: dt, state: state, count: selectedDocumentsWithDocumentType.length}) |       documentTypesToggleableItems.push({item: dt, state: state, count: selectedDocumentsWithDocumentType.length}) | ||||||
|     }) |     }) | ||||||
|  |     this._documentTypesToggleableItems = documentTypesToggleableItems | ||||||
|     return documentTypesToggleableItems |     return documentTypesToggleableItems | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -118,39 +138,45 @@ export class BulkEditorComponent { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   tagsDropdownOpen() { |   tagsDropdownOpen() { | ||||||
|     this.initiallySelectedTagsToggleableItems = this.tagsToggleableItems.filter(tti => tti.state == ToggleableItemState.Selected) |     this.initialTagsToggleableItems = this._tagsToggleableItems | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   correspondentsDropdownOpen() { |   correspondentsDropdownOpen() { | ||||||
|     this.initiallySelectedCorrespondentsToggleableItems = this.correspondentsToggleableItems.filter(cti => cti.state == ToggleableItemState.Selected) |     this.initialCorrespondentsToggleableItems = this._correspondentsToggleableItems | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   documentTypesDropdownOpen() { |   documentTypesDropdownOpen() { | ||||||
|     this.initiallySelectedDocumentTypesToggleableItems = this.documentTypesToggleableItems.filter(dtti => dtti.state == ToggleableItemState.Selected) |     this.initialDocumentTypesToggleableItems = this._documentTypesToggleableItems | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   applyTags(selectedTags: PaperlessTag[]) { |   applyTags(newTagsToggleableItems: ToggleableItem[], forceApply:boolean = false) { | ||||||
|     let unchanged = this.equateItemsToToggleableItems(selectedTags, this.initiallySelectedTagsToggleableItems) |     let changedTags = this.checkForChangedItems(this.initialTagsToggleableItems, newTagsToggleableItems) | ||||||
|     if (!unchanged) this.setTags.emit(selectedTags) |     if (changedTags.itemsToAdd.length > 0) this.setTags.emit(changedTags.itemsToAdd) | ||||||
|     this.initiallySelectedTagsToggleableItems = [] |     if (changedTags.itemsToRemove.length > 0) this.removeTags.emit(changedTags.itemsToRemove) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   applyCorrespondent(selectedCorrespondents: PaperlessCorrespondent[]) { |   applyCorrespondent(newCorrespondentsToggleableItems: ToggleableItem[], forceApply:boolean = false) { | ||||||
|     let unchanged = this.equateItemsToToggleableItems(selectedCorrespondents, this.initiallySelectedCorrespondentsToggleableItems) |     let changedCorrespondents = this.checkForChangedItems(this.initialCorrespondentsToggleableItems, newCorrespondentsToggleableItems) | ||||||
|     if (!unchanged) this.setCorrespondent.emit(selectedCorrespondents?.length > 0 ? selectedCorrespondents.shift() : null) |     if (changedCorrespondents.itemsToAdd.length > 0) this.setCorrespondent.emit(changedCorrespondents.itemsToAdd) | ||||||
|     this.initiallySelectedCorrespondentsToggleableItems = [] |     else if (changedCorrespondents.itemsToRemove.length > 0) this.removeCorrespondents.emit(changedCorrespondents.itemsToRemove) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   applyDocumentType(selectedDocumentTypes: PaperlessDocumentType[]) { |   applyDocumentType(newDocumentTypesToggleableItems: ToggleableItem[], forceApply:boolean = false) { | ||||||
|     let unchanged = this.equateItemsToToggleableItems(selectedDocumentTypes, this.initiallySelectedDocumentTypesToggleableItems) |     let changedDocumentTypes = this.checkForChangedItems(this.initialDocumentTypesToggleableItems, newDocumentTypesToggleableItems) | ||||||
|     if (!unchanged) this.setDocumentType.emit(selectedDocumentTypes.length > 0 ? selectedDocumentTypes.shift() : null) |     if (changedDocumentTypes.itemsToAdd.length > 0) this.setDocumentType.emit(changedDocumentTypes.itemsToAdd) | ||||||
|     this.initiallySelectedDocumentTypesToggleableItems = [] |     else if (changedDocumentTypes.itemsToRemove.length > 0) this.removeDocumentTypes.emit(changedDocumentTypes.itemsToRemove) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   equateItemsToToggleableItems(items: ObjectWithId[], toggleableItems: ToggleableItem[]): boolean { |   checkForChangedItems(toggleableItemsA: ToggleableItem[], toggleableItemsB: ToggleableItem[]): ChangedItems { | ||||||
|     // either both empty or all items must in toggleableItems and vice-versa |     let itemsToAdd: any[] = [] | ||||||
|     return (toggleableItems.length == 0 && items.length == 0) || |     let itemsToRemove: any[] = [] | ||||||
|            (items.every(i => toggleableItems.find(ti => ti.item.id == i.id) !== undefined) && toggleableItems.every(ti => items.find(i => i.id == ti.item.id) !== undefined)) |     toggleableItemsA.forEach(oldItem => { | ||||||
|  |       let newItem = toggleableItemsB.find(nTTI => nTTI.item.id == oldItem.item.id) | ||||||
|  |  | ||||||
|  |       if (newItem.state == ToggleableItemState.Selected && (oldItem.state == ToggleableItemState.PartiallySelected || oldItem.state == ToggleableItemState.NotSelected)) itemsToAdd.push(newItem.item) | ||||||
|  |       else if (newItem.state == ToggleableItemState.NotSelected && (oldItem.state == ToggleableItemState.Selected || oldItem.state == ToggleableItemState.PartiallySelected)) itemsToRemove.push(newItem.item) | ||||||
|  |     }) | ||||||
|  |     return { itemsToAdd: itemsToAdd, itemsToRemove: itemsToRemove } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   applyDelete() { |   applyDelete() { | ||||||
|   | |||||||
| @@ -87,8 +87,11 @@ | |||||||
|     (selectAll)="list.selectAll()" |     (selectAll)="list.selectAll()" | ||||||
|     (selectNone)="list.selectNone()" |     (selectNone)="list.selectNone()" | ||||||
|     (setTags)="bulkSetTags($event)" |     (setTags)="bulkSetTags($event)" | ||||||
|  |     (removeTags)="bulkRemoveTags($event)" | ||||||
|     (setCorrespondent)="bulkSetCorrespondent($event)" |     (setCorrespondent)="bulkSetCorrespondent($event)" | ||||||
|  |     (removeCorrespondents)="bulkRemoveCorrespondents($event)" | ||||||
|     (setDocumentType)="bulkSetDocumentType($event)" |     (setDocumentType)="bulkSetDocumentType($event)" | ||||||
|  |     (removeDocumentTypes)="bulkRemoveDocumentTypes($event)" | ||||||
|     (delete)="bulkDelete()"> |     (delete)="bulkDelete()"> | ||||||
| </app-bulk-editor> | </app-bulk-editor> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -158,7 +158,7 @@ export class DocumentListComponent implements OnInit { | |||||||
|  |  | ||||||
|   bulkSetCorrespondent(correspondent: PaperlessCorrespondent) { |   bulkSetCorrespondent(correspondent: PaperlessCorrespondent) { | ||||||
|     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|     modal.componentInstance.title = "Confirm correspondent assignment" |     modal.componentInstance.title = "Confirm Correspondent assignment" | ||||||
|     let messageFragment = correspondent ? `assign the correspondent ${correspondent.name} to` : `remove all correspondents from` |     let messageFragment = correspondent ? `assign the correspondent ${correspondent.name} to` : `remove all correspondents from` | ||||||
|     modal.componentInstance.message = `This operation will ${messageFragment} all ${this.list.selected.size} selected document(s).` |     modal.componentInstance.message = `This operation will ${messageFragment} all ${this.list.selected.size} selected document(s).` | ||||||
|     modal.componentInstance.btnClass = "btn-warning" |     modal.componentInstance.btnClass = "btn-warning" | ||||||
| @@ -172,6 +172,22 @@ export class DocumentListComponent implements OnInit { | |||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   bulkRemoveCorrespondents(correspondents: PaperlessCorrespondent[]) { | ||||||
|  |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Confirm Correspondent Removal" | ||||||
|  |     modal.componentInstance.message = `This operation will remove the correspondent(s) ${correspondents.map(t => t.name).join(', ')} from all ${this.list.selected.size} selected document(s).` | ||||||
|  |     modal.componentInstance.btnClass = "btn-warning" | ||||||
|  |     modal.componentInstance.btnCaption = "Confirm" | ||||||
|  |     modal.componentInstance.confirmClicked.subscribe(() => { | ||||||
|  |       // TODO: API endpoint for remove multiple correspondents | ||||||
|  |       this.executeBulkOperation('remove_correspondents', {"correspondents": correspondents.map(t => t.id)}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   bulkSetDocumentType(documentType: PaperlessDocumentType) { |   bulkSetDocumentType(documentType: PaperlessDocumentType) { | ||||||
|     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|     modal.componentInstance.title = "Confirm Document Type assignment" |     modal.componentInstance.title = "Confirm Document Type assignment" | ||||||
| @@ -188,6 +204,22 @@ export class DocumentListComponent implements OnInit { | |||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   bulkRemoveDocumentTypes(documentTypes: PaperlessDocumentType[]) { | ||||||
|  |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Confirm Document Type Removal" | ||||||
|  |     modal.componentInstance.message = `This operation will remove the document type(s) ${documentTypes.map(t => t.name).join(', ')} all ${this.list.selected.size} selected document(s).` | ||||||
|  |     modal.componentInstance.btnClass = "btn-warning" | ||||||
|  |     modal.componentInstance.btnCaption = "Confirm" | ||||||
|  |     modal.componentInstance.confirmClicked.subscribe(() => { | ||||||
|  |       // TODO: API endpoint for remove multiple document types | ||||||
|  |       this.executeBulkOperation('remove_document_types', {"document_types": documentTypes.map(t => t.id)}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   bulkSetTags(tags: PaperlessTag[]) { |   bulkSetTags(tags: PaperlessTag[]) { | ||||||
|     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|     modal.componentInstance.title = "Confirm Tags assignment" |     modal.componentInstance.title = "Confirm Tags assignment" | ||||||
| @@ -197,7 +229,23 @@ export class DocumentListComponent implements OnInit { | |||||||
|     modal.componentInstance.btnCaption = "Confirm" |     modal.componentInstance.btnCaption = "Confirm" | ||||||
|     modal.componentInstance.confirmClicked.subscribe(() => { |     modal.componentInstance.confirmClicked.subscribe(() => { | ||||||
|       // TODO: API endpoint for set multiple tags |       // TODO: API endpoint for set multiple tags | ||||||
|       this.executeBulkOperation('set_tags', {"document_type": tags ? tags.map(t => t.id) : null}).subscribe( |       this.executeBulkOperation('set_tags', {"tags": tags ? tags.map(t => t.id) : null}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkRemoveTags(tags: PaperlessTag[]) { | ||||||
|  |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Confirm Tags Removal" | ||||||
|  |     modal.componentInstance.message = `This operation will remove the tags ${tags.map(t => t.name).join(', ')} from all ${this.list.selected.size} selected document(s).` | ||||||
|  |     modal.componentInstance.btnClass = "btn-warning" | ||||||
|  |     modal.componentInstance.btnCaption = "Confirm" | ||||||
|  |     modal.componentInstance.confirmClicked.subscribe(() => { | ||||||
|  |       // TODO: API endpoint for remove multiple tags | ||||||
|  |       this.executeBulkOperation('remove_tags', {"tags": tags.map(t => t.id)}).subscribe( | ||||||
|         response => { |         response => { | ||||||
|           modal.close() |           modal.close() | ||||||
|         } |         } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Michael Shamoon
					Michael Shamoon