mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Merge branch 'dev' into feature-bulk-edit
This commit is contained in:
		| @@ -16,7 +16,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | ||||
| import { DatePipe } from '@angular/common'; | ||||
| import { NotFoundComponent } from './components/not-found/not-found.component'; | ||||
| import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'; | ||||
| import { DeleteDialogComponent } from './components/common/delete-dialog/delete-dialog.component'; | ||||
| import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component'; | ||||
| import { CorrespondentEditDialogComponent } from './components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; | ||||
| import { TagEditDialogComponent } from './components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component'; | ||||
| import { DocumentTypeEditDialogComponent } from './components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; | ||||
| @@ -49,6 +49,7 @@ import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-w | ||||
| import { YesNoPipe } from './pipes/yes-no.pipe'; | ||||
| import { FileSizePipe } from './pipes/file-size.pipe'; | ||||
| import { DocumentTitlePipe } from './pipes/document-title.pipe'; | ||||
| import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component'; | ||||
| import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component'; | ||||
|  | ||||
| @NgModule({ | ||||
| @@ -64,7 +65,7 @@ import { SelectDialogComponent } from './components/common/select-dialog/select- | ||||
|     SettingsComponent, | ||||
|     NotFoundComponent, | ||||
|     CorrespondentEditDialogComponent, | ||||
|     DeleteDialogComponent, | ||||
|     ConfirmDialogComponent, | ||||
|     TagEditDialogComponent, | ||||
|     DocumentTypeEditDialogComponent, | ||||
|     TagComponent, | ||||
| @@ -91,6 +92,7 @@ import { SelectDialogComponent } from './components/common/select-dialog/select- | ||||
|     YesNoPipe, | ||||
|     FileSizePipe, | ||||
|     DocumentTitlePipe, | ||||
|     MetadataCollapseComponent, | ||||
|     SelectDialogComponent | ||||
|   ], | ||||
|   imports: [ | ||||
|   | ||||
| @@ -5,10 +5,13 @@ | ||||
|       </button> | ||||
|     </div> | ||||
|     <div class="modal-body"> | ||||
|       <p><b>{{message}}</b></p> | ||||
|       <p *ngIf="message2">{{message2}}</p> | ||||
|       <p *ngIf="messageBold"><b>{{messageBold}}</b></p> | ||||
|       <p *ngIf="message">{{message}}</p> | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|       <button type="button" class="btn btn-outline-dark" (click)="cancelClicked()">Cancel</button> | ||||
|       <button type="button" class="btn btn-danger" (click)="deleteClicked.emit()" [disabled]="!deleteButtonEnabled">Delete<span *ngIf="!deleteButtonEnabled"> ({{seconds}})</span></button> | ||||
|     </div> | ||||
|       <button type="button" class="btn" [class]="btnClass" (click)="confirmClicked.emit()" [disabled]="!confirmButtonEnabled"> | ||||
|         {{btnCaption}} | ||||
|         <span *ngIf="!confirmButtonEnabled"> ({{seconds}})</span> | ||||
|       </button> | ||||
|     </div> | ||||
| @@ -1,20 +1,20 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { DeleteDialogComponent } from './delete-dialog.component'; | ||||
| import { ConfirmDialogComponent } from './confirm-dialog.component'; | ||||
| 
 | ||||
| describe('DeleteDialogComponent', () => { | ||||
|   let component: DeleteDialogComponent; | ||||
|   let fixture: ComponentFixture<DeleteDialogComponent>; | ||||
| describe('ConfirmDialogComponent', () => { | ||||
|   let component: ConfirmDialogComponent; | ||||
|   let fixture: ComponentFixture<ConfirmDialogComponent>; | ||||
| 
 | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ DeleteDialogComponent ] | ||||
|       declarations: [ ConfirmDialogComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|   }); | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     fixture = TestBed.createComponent(DeleteDialogComponent); | ||||
|     fixture = TestBed.createComponent(ConfirmDialogComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
| @@ -2,35 +2,41 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; | ||||
| import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-delete-dialog', | ||||
|   templateUrl: './delete-dialog.component.html', | ||||
|   styleUrls: ['./delete-dialog.component.scss'] | ||||
|   selector: 'app-confirm-dialog', | ||||
|   templateUrl: './confirm-dialog.component.html', | ||||
|   styleUrls: ['./confirm-dialog.component.scss'] | ||||
| }) | ||||
| export class DeleteDialogComponent implements OnInit { | ||||
| export class ConfirmDialogComponent implements OnInit { | ||||
| 
 | ||||
|   constructor(public activeModal: NgbActiveModal) { } | ||||
| 
 | ||||
|   @Output() | ||||
|   public deleteClicked = new EventEmitter() | ||||
|   public confirmClicked = new EventEmitter() | ||||
| 
 | ||||
|   @Input() | ||||
|   title = "Delete confirmation" | ||||
|   title = "Confirmation" | ||||
| 
 | ||||
|   @Input() | ||||
|   message = "Do you really want to delete this?" | ||||
|   messageBold | ||||
| 
 | ||||
|   @Input() | ||||
|   message2 | ||||
|   message | ||||
| 
 | ||||
|   deleteButtonEnabled = true | ||||
|   @Input() | ||||
|   btnClass = "btn-primary" | ||||
| 
 | ||||
|   @Input() | ||||
|   btnCaption = "Confirm" | ||||
| 
 | ||||
|   confirmButtonEnabled = true | ||||
|   seconds = 0 | ||||
| 
 | ||||
|   delayConfirm(seconds: number) { | ||||
|     this.deleteButtonEnabled = false | ||||
|     this.confirmButtonEnabled = false | ||||
|     this.seconds = seconds | ||||
|     setTimeout(() => { | ||||
|       if (this.seconds <= 1) { | ||||
|         this.deleteButtonEnabled = true | ||||
|         this.confirmButtonEnabled = true | ||||
|       } else { | ||||
|         this.delayConfirm(seconds - 1) | ||||
|       } | ||||
| @@ -110,53 +110,8 @@ | ||||
|                             </tbody> | ||||
|                         </table> | ||||
|  | ||||
|                         <h6 *ngIf="metadata?.original_metadata.length > 0"> | ||||
|                             <button type="button" class="btn btn-outline-secondary btn-sm mr-2" | ||||
|                                 (click)="expandOriginalMetadata = !expandOriginalMetadata" aria-controls="collapseExample"> | ||||
|                                 <svg class="buttonicon" fill="currentColor" *ngIf="!expandOriginalMetadata"> | ||||
|                                     <use xlink:href="assets/bootstrap-icons.svg#caret-down" /> | ||||
|                                 </svg> | ||||
|                                 <svg class="buttonicon" fill="currentColor" *ngIf="expandOriginalMetadata"> | ||||
|                                     <use xlink:href="assets/bootstrap-icons.svg#caret-up" /> | ||||
|                                 </svg> | ||||
|                             </button> | ||||
|                             Original document metadata | ||||
|                         </h6> | ||||
|  | ||||
|                         <div #collapse="ngbCollapse" [(ngbCollapse)]="!expandOriginalMetadata"> | ||||
|                             <table class="table table-borderless"> | ||||
|                                 <tbody> | ||||
|                                     <tr *ngFor="let m of metadata?.original_metadata"> | ||||
|                                         <td>{{m.prefix}}:{{m.key}}</td> | ||||
|                                         <td>{{m.value}}</td> | ||||
|                                     </tr> | ||||
|                                 </tbody> | ||||
|                             </table> | ||||
|                         </div> | ||||
|  | ||||
|                         <h6 *ngIf="metadata?.has_archive_version && metadata?.archive_metadata.length > 0"> | ||||
|                             <button type="button" class="btn btn-outline-secondary btn-sm mr-2" | ||||
|                                 (click)="expandArchivedMetadata = !expandArchivedMetadata" aria-controls="collapseExample"> | ||||
|                                 <svg class="buttonicon" fill="currentColor" *ngIf="!expandArchivedMetadata"> | ||||
|                                     <use xlink:href="assets/bootstrap-icons.svg#caret-down" /> | ||||
|                                 </svg> | ||||
|                                 <svg class="buttonicon" fill="currentColor" *ngIf="expandArchivedMetadata"> | ||||
|                                     <use xlink:href="assets/bootstrap-icons.svg#caret-up" /> | ||||
|                                 </svg> | ||||
|                             </button> | ||||
|                             Archived document metadata | ||||
|                         </h6> | ||||
|  | ||||
|                         <div #collapse="ngbCollapse" [(ngbCollapse)]="!expandArchivedMetadata"> | ||||
|                             <table class="table table-borderless"> | ||||
|                                 <tbody> | ||||
|                                     <tr *ngFor="let m of metadata?.archive_metadata"> | ||||
|                                         <td>{{m.prefix}}:{{m.key}}</td> | ||||
|                                         <td>{{m.value}}</td> | ||||
|                                     </tr> | ||||
|                                 </tbody> | ||||
|                             </table> | ||||
|                         </div> | ||||
|                         <app-metadata-collapse title="Original document metadata" [metadata]="metadata.original_metadata" *ngIf="metadata?.original_metadata.length > 0"></app-metadata-collapse> | ||||
|                         <app-metadata-collapse title="Archived document metadata" [metadata]="metadata.archive_metadata" *ngIf="metadata?.archive_metadata.length > 0"></app-metadata-collapse> | ||||
|  | ||||
|                     </ng-template> | ||||
|                 </li> | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import { CorrespondentService } from 'src/app/services/rest/correspondent.servic | ||||
| import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; | ||||
| import { DocumentService } from 'src/app/services/rest/document.service'; | ||||
| import { environment } from 'src/environments/environment'; | ||||
| import { DeleteDialogComponent } from '../common/delete-dialog/delete-dialog.component'; | ||||
| import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'; | ||||
| import { CorrespondentEditDialogComponent } from '../manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; | ||||
| import { DocumentTypeEditDialogComponent } from '../manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; | ||||
|  | ||||
| @@ -155,10 +155,13 @@ export class DocumentDetailComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   delete() { | ||||
|     let modal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) | ||||
|     modal.componentInstance.message = `Do you really want to delete document '${this.document.title}'?` | ||||
|     modal.componentInstance.message2 = `The files for this document will be deleted permanently. This operation cannot be undone.` | ||||
|     modal.componentInstance.deleteClicked.subscribe(() => { | ||||
|     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||
|     modal.componentInstance.title = "Confirm delete" | ||||
|     modal.componentInstance.messageBold = `Do you really want to delete document '${this.document.title}'?` | ||||
|     modal.componentInstance.message = `The files for this document will be deleted permanently. This operation cannot be undone.` | ||||
|     modal.componentInstance.btnClass = "btn-danger" | ||||
|     modal.componentInstance.btnCaption = "Delete document" | ||||
|     modal.componentInstance.confirmClicked.subscribe(() => { | ||||
|       this.documentsService.delete(this.document).subscribe(() => { | ||||
|         modal.close()   | ||||
|         this.close() | ||||
|   | ||||
| @@ -0,0 +1,23 @@ | ||||
| <h6> | ||||
|   <button type="button" class="btn btn-outline-secondary btn-sm mr-2" | ||||
|       (click)="expand = !expand"> | ||||
|       <svg class="buttonicon" fill="currentColor" *ngIf="!expand"> | ||||
|           <use xlink:href="assets/bootstrap-icons.svg#caret-down" /> | ||||
|       </svg> | ||||
|       <svg class="buttonicon" fill="currentColor" *ngIf="expand"> | ||||
|           <use xlink:href="assets/bootstrap-icons.svg#caret-up" /> | ||||
|       </svg> | ||||
|   </button> | ||||
|   {{title}} | ||||
| </h6> | ||||
|  | ||||
| <div #collapse="ngbCollapse" [(ngbCollapse)]="!expand"> | ||||
|   <table class="table table-borderless"> | ||||
|       <tbody> | ||||
|           <tr *ngFor="let m of metadata"> | ||||
|               <td>{{m.prefix}}:{{m.key}}</td> | ||||
|               <td>{{m.value}}</td> | ||||
|           </tr> | ||||
|       </tbody> | ||||
|   </table> | ||||
| </div> | ||||
| @@ -0,0 +1,25 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
|  | ||||
| import { MetadataCollapseComponent } from './metadata-collapse.component'; | ||||
|  | ||||
| describe('MetadataCollapseComponent', () => { | ||||
|   let component: MetadataCollapseComponent; | ||||
|   let fixture: ComponentFixture<MetadataCollapseComponent>; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ MetadataCollapseComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|   }); | ||||
|  | ||||
|   beforeEach(() => { | ||||
|     fixture = TestBed.createComponent(MetadataCollapseComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
|  | ||||
|   it('should create', () => { | ||||
|     expect(component).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @@ -0,0 +1,23 @@ | ||||
| import { Component, Input, OnInit } from '@angular/core'; | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-metadata-collapse', | ||||
|   templateUrl: './metadata-collapse.component.html', | ||||
|   styleUrls: ['./metadata-collapse.component.scss'] | ||||
| }) | ||||
| export class MetadataCollapseComponent implements OnInit { | ||||
|  | ||||
|   constructor() { } | ||||
|  | ||||
|   expand = false | ||||
|  | ||||
|   @Input() | ||||
|   metadata | ||||
|  | ||||
|   @Input() | ||||
|   title = "Metadata" | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -15,7 +15,7 @@ import { TagService } from 'src/app/services/rest/tag.service'; | ||||
| import { SavedViewConfigService } from 'src/app/services/saved-view-config.service'; | ||||
| import { Toast, ToastService } from 'src/app/services/toast.service'; | ||||
| import { environment } from 'src/environments/environment'; | ||||
| import { DeleteDialogComponent } from '../common/delete-dialog/delete-dialog.component'; | ||||
| import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'; | ||||
| import { SelectDialogComponent } from '../common/select-dialog/select-dialog.component'; | ||||
| import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; | ||||
|  | ||||
| @@ -238,11 +238,14 @@ export class DocumentListComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   bulkDelete() { | ||||
|     let modal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) | ||||
|     let modal = this.modalService.open(ConfirmDialogComponent, {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(() => { | ||||
|     modal.componentInstance.title = "Delete confirm" | ||||
|     modal.componentInstance.messageBold = `This operation will permanently delete all ${this.list.selected.size} selected document(s).` | ||||
|     modal.componentInstance.message = `This operation cannot be undone.` | ||||
|     modal.componentInstance.btnClass = "btn-danger" | ||||
|     modal.componentInstance.btnCaption = "Delete document(s)" | ||||
|     modal.componentInstance.confirmClicked.subscribe(() => { | ||||
|       this.executeBulkOperation("delete", {}).subscribe( | ||||
|         response => { | ||||
|           modal.close() | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import { MatchingModel, MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/mat | ||||
| import { ObjectWithId } from 'src/app/data/object-with-id'; | ||||
| import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive'; | ||||
| import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'; | ||||
| import { DeleteDialogComponent } from '../../common/delete-dialog/delete-dialog.component'; | ||||
| import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'; | ||||
|  | ||||
| @Directive() | ||||
| export abstract class GenericListComponent<T extends ObjectWithId> implements OnInit { | ||||
| @@ -88,10 +88,13 @@ export abstract class GenericListComponent<T extends ObjectWithId> implements On | ||||
|   } | ||||
|  | ||||
|   openDeleteDialog(object: T) { | ||||
|     var activeModal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) | ||||
|     activeModal.componentInstance.message = `Do you really want to delete ${this.getObjectName(object)}?` | ||||
|     activeModal.componentInstance.message2 = "Associated documents will not be deleted." | ||||
|     activeModal.componentInstance.deleteClicked.subscribe(() => { | ||||
|     var activeModal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||
|     activeModal.componentInstance.title = "Confirm delete" | ||||
|     activeModal.componentInstance.messageBold = `Do you really want to delete ${this.getObjectName(object)}?` | ||||
|     activeModal.componentInstance.message = "Associated documents will not be deleted." | ||||
|     activeModal.componentInstance.btnClass = "btn-danger" | ||||
|     activeModal.componentInstance.btnCaption = "Delete" | ||||
|     activeModal.componentInstance.confirmPressed.subscribe(() => { | ||||
|       this.service.delete(object).subscribe(_ => { | ||||
|         activeModal.close() | ||||
|         this.reloadData() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 jonaswinkler
					jonaswinkler