Merge branch 'dev' into quick-filters

This commit is contained in:
Michael Shamoon
2020-12-13 11:27:40 -08:00
committed by GitHub
60 changed files with 507 additions and 318 deletions

View File

@@ -132,7 +132,7 @@
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="https://paperless-ng.readthedocs.io/en/latest/">
<a class="nav-link" target="_blank" rel="noopener noreferrer" href="https://paperless-ng.readthedocs.io/en/latest/">
<svg class="sidebaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#question-circle"/>
</svg>
@@ -140,7 +140,7 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/jonaswinkler/paperless-ng">
<a class="nav-link" target="_blank" rel="noopener noreferrer" href="https://github.com/jonaswinkler/paperless-ng">
<svg class="sidebaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#link"/>
</svg>

View File

@@ -5,10 +5,10 @@
</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()">Delete</button>
<button type="button" class="btn" [class]="btnClass" (click)="confirmClicked.emit()">{{btnCaption}}</button>
</div>

View File

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

View File

@@ -0,0 +1,37 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.scss']
})
export class ConfirmDialogComponent implements OnInit {
constructor(public activeModal: NgbActiveModal) { }
@Output()
public confirmClicked = new EventEmitter()
@Input()
title = "Confirmation"
@Input()
messageBold
@Input()
message
@Input()
btnClass = "btn-primary"
@Input()
btnCaption = "Confirm"
ngOnInit(): void {
}
cancelClicked() {
this.activeModal.close()
}
}

View File

@@ -1,31 +0,0 @@
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']
})
export class DeleteDialogComponent implements OnInit {
constructor(public activeModal: NgbActiveModal) { }
@Output()
public deleteClicked = new EventEmitter()
@Input()
title = "Delete confirmation"
@Input()
message = "Do you really want to delete this?"
@Input()
message2
ngOnInit(): void {
}
cancelClicked() {
this.activeModal.close()
}
}

View File

@@ -8,7 +8,7 @@
<div class="input-group-append" ngbDropdown placement="top-right">
<button class="btn btn-outline-secondary" type="button" ngbDropdownToggle></button>
<div ngbDropdownMenu class="scrollable-menu">
<div ngbDropdownMenu class="scrollable-menu shadow">
<button type="button" *ngFor="let tag of tags" ngbDropdownItem (click)="addTag(tag.id)">
<app-tag [tag]="tag"></app-tag>
</button>

View File

@@ -1,4 +1,4 @@
<div class="card mb-3 shadow">
<div class="card mb-3 shadow-sm">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">{{title}}</h5>

View File

@@ -17,7 +17,7 @@
<div class="btn-group" ngbDropdown role="group" *ngIf="metadata?.has_archive_version">
<button class="btn btn-sm btn-outline-primary dropdown-toggle-split" ngbDropdownToggle></button>
<div class="dropdown-menu" ngbDropdownMenu>
<div class="dropdown-menu shadow" ngbDropdownMenu>
<a ngbDropdownItem [href]="downloadOriginalUrl">Download original</a>
</div>
</div>
@@ -35,7 +35,7 @@
<div class="row">
<div class="col-xl">
<div class="col mb-4">
<form [formGroup]='documentForm' (ngSubmit)="save()">
@@ -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>
@@ -171,11 +126,9 @@
</form>
</div>
<div class="col-xl d-none d-xl-block document-preview">
<object [data]="previewUrl | safe" type="application/pdf" width="100%" height="100%">
<p>Your browser does not support PDFs.
<a href="previewUrl">Download the PDF</a>.</p>
</object>
<div class="col-md-6 col-xl-8 mb-3">
<div class="pdf-viewer-container" *ngIf="getContentType() == 'application/pdf'">
<pdf-viewer [src]="previewUrl" [original-size]="false" [show-borders]="true"></pdf-viewer>
</div>
</div>
</div>
</div>

View File

@@ -1,5 +1,6 @@
.document-preview {
height: calc(100vh - 180px);
.pdf-viewer-container {
height: calc(100vh - 160px);
top: 70px;
position: sticky;
}
background-color: gray;
}

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 { 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';
@@ -59,6 +59,10 @@ export class DocumentDetailComponent implements OnInit {
private documentListViewService: DocumentListViewService,
private titleService: Title) { }
getContentType() {
return this.metadata?.has_archive_version ? 'application/pdf' : this.metadata?.original_mime_type
}
ngOnInit(): void {
this.documentForm.valueChanges.subscribe(wow => {
Object.assign(this.document, this.documentForm.value)
@@ -151,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()

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

@@ -12,7 +12,7 @@
<a *ngIf="clickCorrespondent.observers.length ; else nolink" [routerLink]="" title="Filter by correspondent" (click)="clickCorrespondent.emit(document.correspondent)" class="font-weight-bold">{{(document.correspondent$ | async)?.name}}</a>
<ng-template #nolink>{{(document.correspondent$ | async)?.name}}</ng-template>:
</ng-container>
{{document.title}}
{{document.title | documentTitle}}
<app-tag [tag]="t" linkTitle="Filter by tag" *ngFor="let t of document.tags$ | async" class="ml-1" (click)="clickTag.emit(t.id)" [clickable]="clickTag.observers.length"></app-tag>
</h5>
<h5 class="card-title" *ngIf="document.archive_serial_number">#{{document.archive_serial_number}}</h5>

View File

@@ -1,6 +1,6 @@
<div class="col p-2 h-100" style="width: 16rem;">
<div class="card h-100 shadow-sm">
<div class=" border-bottom pr-1">
<div class="border-bottom">
<img class="card-img doc-img" [src]="getThumbUrl()">
<div style="top: 0; right: 0; font-size: large" class="text-right position-absolute mr-1">
<div *ngFor="let t of getTagsLimited$() | async">
@@ -17,7 +17,7 @@
<ng-container *ngIf="document.correspondent">
<a [routerLink]="" title="Filter by correspondent" (click)="clickCorrespondent.emit(document.correspondent)" class="font-weight-bold">{{(document.correspondent$ | async)?.name}}</a>:
</ng-container>
{{document.title}}
{{document.title | documentTitle}}
</p>
</div>
<div class="card-footer">

View File

@@ -24,7 +24,7 @@
<div class="btn-group btn-group-toggle ml-2" ngbRadioGroup [(ngModel)]="list.sortDirection">
<div ngbDropdown class="btn-group">
<button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>Sort by</button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="shadow">
<button *ngFor="let f of getSortFields()" ngbDropdownItem (click)="list.sortField = f.field"
[class.active]="list.sortField == f.field">{{f.name}}</button>
</div>
@@ -79,7 +79,7 @@
</app-document-card-large>
</div>
<table class="table table-sm border shadow" *ngIf="displayMode == 'details'">
<table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'">
<thead>
<th class="d-none d-lg-table-cell">ASN</th>
<th class="d-none d-md-table-cell">Correspondent</th>
@@ -99,7 +99,7 @@
</ng-container>
</td>
<td>
<a routerLink="/documents/{{d.id}}" title="Edit document" style="overflow-wrap: anywhere;">{{d.title}}</a>
<a routerLink="/documents/{{d.id}}" title="Edit document" style="overflow-wrap: anywhere;">{{d.title | documentTitle}}</a>
<app-tag [tag]="t" *ngFor="let t of d.tags$ | async" class="ml-1" clickable="true" linkTitle="Filter by tag" (click)="clickTag(t)"></app-tag>
</td>
<td class="d-none d-xl-table-cell">

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 { 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()