Merge branch 'dev' into feature-bulk-edit

This commit is contained in:
jonaswinkler 2020-12-13 15:13:43 +01:00
commit bb9b438aa6
13 changed files with 131 additions and 85 deletions

View File

@ -16,7 +16,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { NotFoundComponent } from './components/not-found/not-found.component'; import { NotFoundComponent } from './components/not-found/not-found.component';
import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.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 { 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 { 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'; 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 { YesNoPipe } from './pipes/yes-no.pipe';
import { FileSizePipe } from './pipes/file-size.pipe'; import { FileSizePipe } from './pipes/file-size.pipe';
import { DocumentTitlePipe } from './pipes/document-title.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'; import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component';
@NgModule({ @NgModule({
@ -64,7 +65,7 @@ import { SelectDialogComponent } from './components/common/select-dialog/select-
SettingsComponent, SettingsComponent,
NotFoundComponent, NotFoundComponent,
CorrespondentEditDialogComponent, CorrespondentEditDialogComponent,
DeleteDialogComponent, ConfirmDialogComponent,
TagEditDialogComponent, TagEditDialogComponent,
DocumentTypeEditDialogComponent, DocumentTypeEditDialogComponent,
TagComponent, TagComponent,
@ -91,6 +92,7 @@ import { SelectDialogComponent } from './components/common/select-dialog/select-
YesNoPipe, YesNoPipe,
FileSizePipe, FileSizePipe,
DocumentTitlePipe, DocumentTitlePipe,
MetadataCollapseComponent,
SelectDialogComponent SelectDialogComponent
], ],
imports: [ imports: [

View File

@ -5,10 +5,13 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p><b>{{message}}</b></p> <p *ngIf="messageBold"><b>{{messageBold}}</b></p>
<p *ngIf="message2">{{message2}}</p> <p *ngIf="message">{{message}}</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancelClicked()">Cancel</button> <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> <button type="button" class="btn" [class]="btnClass" (click)="confirmClicked.emit()" [disabled]="!confirmButtonEnabled">
{{btnCaption}}
<span *ngIf="!confirmButtonEnabled"> ({{seconds}})</span>
</button>
</div> </div>

View File

@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DeleteDialogComponent } from './delete-dialog.component'; import { ConfirmDialogComponent } from './confirm-dialog.component';
describe('DeleteDialogComponent', () => { describe('ConfirmDialogComponent', () => {
let component: DeleteDialogComponent; let component: ConfirmDialogComponent;
let fixture: ComponentFixture<DeleteDialogComponent>; let fixture: ComponentFixture<ConfirmDialogComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ DeleteDialogComponent ] declarations: [ ConfirmDialogComponent ]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(DeleteDialogComponent); fixture = TestBed.createComponent(ConfirmDialogComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@ -2,35 +2,41 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
@Component({ @Component({
selector: 'app-delete-dialog', selector: 'app-confirm-dialog',
templateUrl: './delete-dialog.component.html', templateUrl: './confirm-dialog.component.html',
styleUrls: ['./delete-dialog.component.scss'] styleUrls: ['./confirm-dialog.component.scss']
}) })
export class DeleteDialogComponent implements OnInit { export class ConfirmDialogComponent implements OnInit {
constructor(public activeModal: NgbActiveModal) { } constructor(public activeModal: NgbActiveModal) { }
@Output() @Output()
public deleteClicked = new EventEmitter() public confirmClicked = new EventEmitter()
@Input() @Input()
title = "Delete confirmation" title = "Confirmation"
@Input() @Input()
message = "Do you really want to delete this?" messageBold
@Input() @Input()
message2 message
deleteButtonEnabled = true @Input()
btnClass = "btn-primary"
@Input()
btnCaption = "Confirm"
confirmButtonEnabled = true
seconds = 0 seconds = 0
delayConfirm(seconds: number) { delayConfirm(seconds: number) {
this.deleteButtonEnabled = false this.confirmButtonEnabled = false
this.seconds = seconds this.seconds = seconds
setTimeout(() => { setTimeout(() => {
if (this.seconds <= 1) { if (this.seconds <= 1) {
this.deleteButtonEnabled = true this.confirmButtonEnabled = true
} else { } else {
this.delayConfirm(seconds - 1) this.delayConfirm(seconds - 1)
} }

View File

@ -110,53 +110,8 @@
</tbody> </tbody>
</table> </table>
<h6 *ngIf="metadata?.original_metadata.length > 0"> <app-metadata-collapse title="Original document metadata" [metadata]="metadata.original_metadata" *ngIf="metadata?.original_metadata.length > 0"></app-metadata-collapse>
<button type="button" class="btn btn-outline-secondary btn-sm mr-2" <app-metadata-collapse title="Archived document metadata" [metadata]="metadata.archive_metadata" *ngIf="metadata?.archive_metadata.length > 0"></app-metadata-collapse>
(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>
</ng-template> </ng-template>
</li> </li>

View File

@ -13,7 +13,7 @@ import { CorrespondentService } from 'src/app/services/rest/correspondent.servic
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; import { DocumentTypeService } from 'src/app/services/rest/document-type.service';
import { DocumentService } from 'src/app/services/rest/document.service'; import { DocumentService } from 'src/app/services/rest/document.service';
import { environment } from 'src/environments/environment'; 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 { 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'; 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() { delete() {
let modal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'})
modal.componentInstance.message = `Do you really want to delete document '${this.document.title}'?` modal.componentInstance.title = "Confirm delete"
modal.componentInstance.message2 = `The files for this document will be deleted permanently. This operation cannot be undone.` modal.componentInstance.messageBold = `Do you really want to delete document '${this.document.title}'?`
modal.componentInstance.deleteClicked.subscribe(() => { 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(() => { this.documentsService.delete(this.document).subscribe(() => {
modal.close() modal.close()
this.close() this.close()

View File

@ -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>

View File

@ -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();
});
});

View File

@ -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 {
}
}

View File

@ -15,7 +15,7 @@ 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 { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component';
import { SelectDialogComponent } from '../common/select-dialog/select-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';
@ -238,11 +238,14 @@ export class DocumentListComponent implements OnInit {
} }
bulkDelete() { bulkDelete() {
let modal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'})
modal.componentInstance.delayConfirm(5) modal.componentInstance.delayConfirm(5)
modal.componentInstance.message = `This operation will permanently delete all ${this.list.selected.size} selected document(s).` modal.componentInstance.title = "Delete confirm"
modal.componentInstance.message2 = `This operation cannot be undone.` modal.componentInstance.messageBold = `This operation will permanently delete all ${this.list.selected.size} selected document(s).`
modal.componentInstance.deleteClicked.subscribe(() => { 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( this.executeBulkOperation("delete", {}).subscribe(
response => { response => {
modal.close() modal.close()

View File

@ -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 { ObjectWithId } from 'src/app/data/object-with-id';
import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive'; import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive';
import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'; 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() @Directive()
export abstract class GenericListComponent<T extends ObjectWithId> implements OnInit { 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) { openDeleteDialog(object: T) {
var activeModal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) var activeModal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'})
activeModal.componentInstance.message = `Do you really want to delete ${this.getObjectName(object)}?` activeModal.componentInstance.title = "Confirm delete"
activeModal.componentInstance.message2 = "Associated documents will not be deleted." activeModal.componentInstance.messageBold = `Do you really want to delete ${this.getObjectName(object)}?`
activeModal.componentInstance.deleteClicked.subscribe(() => { 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(_ => { this.service.delete(object).subscribe(_ => {
activeModal.close() activeModal.close()
this.reloadData() this.reloadData()