mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge branch 'dev' into feature-bulk-edit
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: $primary;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sidebar .nav-link:hover .sidebaricon,
|
||||
|
@@ -90,7 +90,9 @@ export class AppFrameComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.openDocumentsSubscription.unsubscribe()
|
||||
if (this.openDocumentsSubscription) {
|
||||
this.openDocumentsSubscription.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,23 +3,19 @@
|
||||
</app-page-header>
|
||||
|
||||
<div class='row'>
|
||||
<div class="col-lg">
|
||||
<app-widget-frame title="Saved views" *ngIf="savedViews.length == 0">
|
||||
<p class="card-text">This space is reserved to display your saved views. Go to your documents and save a view
|
||||
to have it displayed
|
||||
here!</p>
|
||||
</app-widget-frame>
|
||||
<div class="col-lg-8">
|
||||
<app-welcome-widget *ngIf="savedViews.length == 0"></app-welcome-widget>
|
||||
|
||||
<ng-container *ngFor="let v of savedViews">
|
||||
<app-saved-view-widget [savedView]="v"></app-saved-view-widget>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
<div class="col-lg">
|
||||
<div class="col-lg-4">
|
||||
|
||||
<app-statistics-widget></app-statistics-widget>
|
||||
|
||||
<app-upload-file-widget></app-upload-file-widget>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,6 +1,9 @@
|
||||
<app-widget-frame [title]="savedView.title">
|
||||
|
||||
<table class="table table-sm table-hover table-borderless">
|
||||
<a header-buttons [routerLink]="" (click)="showAll()">Show all</a>
|
||||
|
||||
|
||||
<table content class="table table-sm table-hover table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Created</th>
|
||||
@@ -10,7 +13,7 @@
|
||||
<tbody>
|
||||
<tr *ngFor="let doc of documents" routerLink="/documents/{{doc.id}}">
|
||||
<td>{{doc.created | date}}</td>
|
||||
<td>{{doc.title}}<app-tag [tag]="t" *ngFor="let t of doc.tags" class="ml-1"></app-tag>
|
||||
<td>{{doc.title}}<app-tag [tag]="t" *ngFor="let t of doc.tags$ | async" class="ml-1"></app-tag>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||
import { SavedViewConfig } from 'src/app/data/saved-view-config';
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
||||
import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
|
||||
@Component({
|
||||
@@ -10,7 +12,10 @@ import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
})
|
||||
export class SavedViewWidgetComponent implements OnInit {
|
||||
|
||||
constructor(private documentService: DocumentService) { }
|
||||
constructor(
|
||||
private documentService: DocumentService,
|
||||
private router: Router,
|
||||
private list: DocumentListViewService) { }
|
||||
|
||||
@Input()
|
||||
savedView: SavedViewConfig
|
||||
@@ -23,4 +28,9 @@ export class SavedViewWidgetComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
showAll() {
|
||||
this.list.load(this.savedView)
|
||||
this.router.navigate(["documents"])
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,6 @@
|
||||
<app-widget-frame title="Statistics">
|
||||
<p class="card-text">Documents in inbox: {{statistics.documents_inbox}}</p>
|
||||
<p class="card-text">Total documents: {{statistics.documents_total}}</p>
|
||||
<ng-container content>
|
||||
<p class="card-text">Documents in inbox: {{statistics.documents_inbox}}</p>
|
||||
<p class="card-text">Total documents: {{statistics.documents_total}}</p>
|
||||
</ng-container>
|
||||
</app-widget-frame>
|
@@ -1,6 +1,6 @@
|
||||
<app-widget-frame title="Upload new documents">
|
||||
|
||||
<form>
|
||||
<form content>
|
||||
<ngx-file-drop
|
||||
dropZoneLabel="Drop documents here or" (onFileDrop)="dropped($event)"
|
||||
(onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)"
|
||||
|
@@ -0,0 +1,16 @@
|
||||
<app-widget-frame title="First steps">
|
||||
|
||||
<ng-container content>
|
||||
<img src="assets/save-filter.png" class="float-right">
|
||||
<p>Paperless is running! :)</p>
|
||||
<p>You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list.
|
||||
After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and have them displayed on the dashboard instead of this message.</p>
|
||||
<p>Paperless offers some more features that try to make your life easier, such as:</p>
|
||||
<ul>
|
||||
<li>Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically.</li>
|
||||
<li>You can configure paperless to read your mails and add documents from attached files.</li>
|
||||
</ul>
|
||||
<p>Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general.</p>
|
||||
</ng-container>
|
||||
|
||||
</app-widget-frame>
|
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { WelcomeWidgetComponent } from './welcome-widget.component';
|
||||
|
||||
describe('WelcomeWidgetComponent', () => {
|
||||
let component: WelcomeWidgetComponent;
|
||||
let fixture: ComponentFixture<WelcomeWidgetComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ WelcomeWidgetComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(WelcomeWidgetComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-welcome-widget',
|
||||
templateUrl: './welcome-widget.component.html',
|
||||
styleUrls: ['./welcome-widget.component.scss']
|
||||
})
|
||||
export class WelcomeWidgetComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
@@ -1,8 +1,12 @@
|
||||
<div class="card mb-3 shadow">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">{{title}}</h5>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">{{title}}</h5>
|
||||
<ng-content select ="[header-buttons]"></ng-content>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card-body text-dark">
|
||||
<ng-content></ng-content>
|
||||
<ng-content select ="[content]"></ng-content>
|
||||
</div>
|
||||
</div>
|
@@ -5,12 +5,26 @@
|
||||
</svg>
|
||||
<span class="d-none d-lg-inline"> Delete</span>
|
||||
</button>
|
||||
<a [href]="downloadUrl" class="btn btn-sm btn-outline-primary mr-2">
|
||||
<svg class="buttonicon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#download" />
|
||||
</svg>
|
||||
<span class="d-none d-lg-inline"> Download</span>
|
||||
</a>
|
||||
|
||||
<div class="btn-group mr-2">
|
||||
|
||||
<a [href]="downloadUrl" class="btn btn-sm btn-outline-primary">
|
||||
<svg class="buttonicon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#download" />
|
||||
</svg>
|
||||
<span class="d-none d-lg-inline"> Download</span>
|
||||
</a>
|
||||
|
||||
<div class="btn-group" ngbDropdown role="group" *ngIf="metadata?.paperless__has_archive_version">
|
||||
<button class="btn btn-sm btn-outline-primary dropdown-toggle-split" ngbDropdownToggle></button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu>
|
||||
<a ngbDropdownItem [href]="downloadOriginalUrl">Download original</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" (click)="close()">
|
||||
<svg class="buttonicon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#x" />
|
||||
@@ -39,11 +53,11 @@
|
||||
<textarea class="form-control" id="content" rows="5" formControlName='content'></textarea>
|
||||
</div>
|
||||
|
||||
<app-input-select [items]="correspondents" title="Correspondent" formControlName="correspondent_id" allowNull="true" (createNew)="createCorrespondent()"></app-input-select>
|
||||
<app-input-select [items]="correspondents" title="Correspondent" formControlName="correspondent" allowNull="true" (createNew)="createCorrespondent()"></app-input-select>
|
||||
|
||||
<app-input-select [items]="documentTypes" title="Document type" formControlName="document_type_id" allowNull="true" (createNew)="createDocumentType()"></app-input-select>
|
||||
<app-input-select [items]="documentTypes" title="Document type" formControlName="document_type" allowNull="true" (createNew)="createDocumentType()"></app-input-select>
|
||||
|
||||
<app-input-tags formControlName="tags_id" title="Tags"></app-input-tags>
|
||||
<app-input-tags formControlName="tags" title="Tags"></app-input-tags>
|
||||
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="discard()">Discard</button>
|
||||
<button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()">Save & edit next</button>
|
||||
|
@@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||
import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata';
|
||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
||||
import { OpenDocumentsService } from 'src/app/services/open-documents.service';
|
||||
@@ -23,9 +24,11 @@ export class DocumentDetailComponent implements OnInit {
|
||||
|
||||
documentId: number
|
||||
document: PaperlessDocument
|
||||
metadata: PaperlessDocumentMetadata
|
||||
title: string
|
||||
previewUrl: string
|
||||
downloadUrl: string
|
||||
downloadOriginalUrl: string
|
||||
|
||||
correspondents: PaperlessCorrespondent[]
|
||||
documentTypes: PaperlessDocumentType[]
|
||||
@@ -34,10 +37,10 @@ export class DocumentDetailComponent implements OnInit {
|
||||
title: new FormControl(''),
|
||||
content: new FormControl(''),
|
||||
created: new FormControl(),
|
||||
correspondent_id: new FormControl(),
|
||||
document_type_id: new FormControl(),
|
||||
correspondent: new FormControl(),
|
||||
document_type: new FormControl(),
|
||||
archive_serial_number: new FormControl(),
|
||||
tags_id: new FormControl([])
|
||||
tags: new FormControl([])
|
||||
})
|
||||
|
||||
constructor(
|
||||
@@ -62,6 +65,7 @@ export class DocumentDetailComponent implements OnInit {
|
||||
this.documentId = +paramMap.get('id')
|
||||
this.previewUrl = this.documentsService.getPreviewUrl(this.documentId)
|
||||
this.downloadUrl = this.documentsService.getDownloadUrl(this.documentId)
|
||||
this.downloadOriginalUrl = this.documentsService.getDownloadUrl(this.documentId, true)
|
||||
if (this.openDocumentService.getOpenDocument(this.documentId)) {
|
||||
this.updateComponent(this.openDocumentService.getOpenDocument(this.documentId))
|
||||
} else {
|
||||
@@ -76,6 +80,9 @@ export class DocumentDetailComponent implements OnInit {
|
||||
|
||||
updateComponent(doc: PaperlessDocument) {
|
||||
this.document = doc
|
||||
this.documentsService.getMetadata(doc.id).subscribe(result => {
|
||||
this.metadata = result
|
||||
})
|
||||
this.title = doc.title
|
||||
this.documentForm.patchValue(doc)
|
||||
}
|
||||
@@ -86,7 +93,7 @@ export class DocumentDetailComponent implements OnInit {
|
||||
modal.componentInstance.success.subscribe(newDocumentType => {
|
||||
this.documentTypeService.listAll().subscribe(documentTypes => {
|
||||
this.documentTypes = documentTypes.results
|
||||
this.documentForm.get('document_type_id').setValue(newDocumentType.id)
|
||||
this.documentForm.get('document_type').setValue(newDocumentType.id)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -97,7 +104,7 @@ export class DocumentDetailComponent implements OnInit {
|
||||
modal.componentInstance.success.subscribe(newCorrespondent => {
|
||||
this.correspondentService.listAll().subscribe(correspondents => {
|
||||
this.correspondents = correspondents.results
|
||||
this.documentForm.get('correspondent_id').setValue(newCorrespondent.id)
|
||||
this.documentForm.get('correspondent').setValue(newCorrespondent.id)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@@ -9,9 +9,11 @@
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title">
|
||||
<ng-container *ngIf="document.correspondent">
|
||||
<a [routerLink]="" title="Filter by correspondent" (click)="clickCorrespondent.emit(document.correspondent)" class="font-weight-bold">{{document.correspondent.name}}</a>:
|
||||
<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}}<app-tag [tag]="t" linkTitle="Filter by tag" *ngFor="let t of document.tags" class="ml-1" (click)="clickTag.emit(t)" [clickable]="true"></app-tag>
|
||||
{{document.title}}
|
||||
<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>
|
||||
</div>
|
||||
|
@@ -20,10 +20,10 @@ export class DocumentCardLargeComponent implements OnInit {
|
||||
details: any
|
||||
|
||||
@Output()
|
||||
clickTag = new EventEmitter<PaperlessTag>()
|
||||
clickTag = new EventEmitter<number>()
|
||||
|
||||
@Output()
|
||||
clickCorrespondent = new EventEmitter<PaperlessDocument>()
|
||||
clickCorrespondent = new EventEmitter<number>()
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
<div class="col p-2 h-100" style="width: 16rem;">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class=" border-bottom doc-img pr-1" [ngStyle]="{'background-image': 'url(' + getThumbUrl() + ')'}">
|
||||
<div class="row" *ngFor="let t of document.tags">
|
||||
<app-tag style="font-size: large;" [tag]="t" class="col text-right" (click)="clickTag.emit(t)" [clickable]="true" linkTitle="Filter by tag"></app-tag>
|
||||
<div class="row" *ngFor="let t of document.tags$ | async">
|
||||
<app-tag style="font-size: large;" [tag]="t" class="col text-right" (click)="clickTag.emit(t.id)" [clickable]="true" linkTitle="Filter by tag"></app-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-2">
|
||||
<p class="card-text">
|
||||
<ng-container *ngIf="document.correspondent">
|
||||
<a [routerLink]="" title="Filter by correspondent" (click)="clickCorrespondent.emit(document.correspondent)" class="font-weight-bold">{{document.correspondent.name}}</a>:
|
||||
<a [routerLink]="" title="Filter by correspondent" (click)="clickCorrespondent.emit(document.correspondent)" class="font-weight-bold">{{(document.correspondent$ | async)?.name}}</a>:
|
||||
</ng-container>
|
||||
{{document.title}}
|
||||
</p>
|
||||
|
@@ -16,10 +16,10 @@ export class DocumentCardSmallComponent implements OnInit {
|
||||
document: PaperlessDocument
|
||||
|
||||
@Output()
|
||||
clickTag = new EventEmitter<PaperlessTag>()
|
||||
clickTag = new EventEmitter<number>()
|
||||
|
||||
@Output()
|
||||
clickCorrespondent = new EventEmitter<PaperlessDocument>()
|
||||
clickCorrespondent = new EventEmitter<number>()
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
@@ -96,11 +96,12 @@
|
||||
<div class="card w-100 mb-3" [hidden]="!showFilter">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter</h5>
|
||||
<app-filter-editor [(filterRules)]="filterRules" (apply)="applyFilterRules()"></app-filter-editor>
|
||||
<app-filter-editor [(filterRules)]="filterRules" (apply)="applyFilterRules()" (clear)="clearFilterRules()"></app-filter-editor>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row m-0 justify-content-end">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<p>{{list.collectionSize || 0}} document(s)</p>
|
||||
<ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5"
|
||||
[rotate]="true" (pageChange)="list.reload()" aria-label="Default pagination"></ngb-pagination>
|
||||
</div>
|
||||
@@ -126,16 +127,16 @@
|
||||
</td>
|
||||
<td class="d-none d-md-table-cell">
|
||||
<ng-container *ngIf="d.correspondent">
|
||||
<a [routerLink]="" (click)="filterByCorrespondent(d.correspondent)" title="Filter by correspondent">{{d.correspondent.name}}</a>
|
||||
<a [routerLink]="" (click)="filterByCorrespondent(d.correspondent)" title="Filter by correspondent">{{(d.correspondent$ | async)?.name}}</a>
|
||||
</ng-container>
|
||||
</td>
|
||||
<td>
|
||||
<a routerLink="/documents/{{d.id}}" title="Edit document">{{d.title}}</a>
|
||||
<app-tag [tag]="t" *ngFor="let t of d.tags" class="ml-1" clickable="true" linkTitle="Filter by tag" (click)="filterByTag(t)"></app-tag>
|
||||
<app-tag [tag]="t" *ngFor="let t of d.tags$ | async" class="ml-1" clickable="true" linkTitle="Filter by tag" (click)="filterByTag(t.id)"></app-tag>
|
||||
</td>
|
||||
<td class="d-none d-xl-table-cell">
|
||||
<ng-container *ngIf="d.document_type">
|
||||
<a [routerLink]="" (click)="filterByDocumentType(d.document_type)" title="Filter by document type">{{d.document_type.name}}</a>
|
||||
<a [routerLink]="" (click)="filterByDocumentType(d.document_type)" title="Filter by document type">{{(d.document_type$ | async)?.name}}</a>
|
||||
</ng-container>
|
||||
</td>
|
||||
<td>
|
||||
@@ -152,5 +153,3 @@
|
||||
<div class=" m-n2 row" *ngIf="displayMode == 'smallCards'">
|
||||
<app-document-card-small [document]="d" *ngFor="let d of list.documents" (clickTag)="filterByTag($event)" (clickCorrespondent)="filterByCorrespondent($event)"></app-document-card-small>
|
||||
</div>
|
||||
|
||||
<p *ngIf="list.documents.length == 0" class="mx-auto">No results</p>
|
||||
|
@@ -3,9 +3,6 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
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 { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
|
||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { SavedViewConfig } from 'src/app/data/saved-view-config';
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
||||
import { DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service';
|
||||
@@ -51,13 +48,14 @@ export class DocumentListComponent implements OnInit {
|
||||
this.route.paramMap.subscribe(params => {
|
||||
if (params.has('id')) {
|
||||
this.list.savedView = this.savedViewConfigService.getConfig(params.get('id'))
|
||||
this.filterRules = this.list.filterRules
|
||||
this.showFilter = false
|
||||
} else {
|
||||
this.list.savedView = null
|
||||
this.filterRules = this.list.filterRules
|
||||
this.showFilter = this.filterRules.length > 0
|
||||
}
|
||||
this.filterRules = this.list.filterRules
|
||||
//this.showFilter = this.filterRules.length > 0
|
||||
// prevents temporarily visible results from previous views
|
||||
this.list.documents = []
|
||||
this.list.clear()
|
||||
this.list.reload()
|
||||
})
|
||||
}
|
||||
@@ -66,6 +64,11 @@ export class DocumentListComponent implements OnInit {
|
||||
this.list.filterRules = this.filterRules
|
||||
}
|
||||
|
||||
clearFilterRules() {
|
||||
this.list.filterRules = this.filterRules
|
||||
this.showFilter = false
|
||||
}
|
||||
|
||||
loadViewConfig(config: SavedViewConfig) {
|
||||
this.filterRules = cloneFilterRules(config.filterRules)
|
||||
this.list.load(config)
|
||||
@@ -91,32 +94,42 @@ export class DocumentListComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
filterByTag(t: PaperlessTag) {
|
||||
if (this.filterRules.find(rule => rule.type.id == FILTER_HAS_TAG && rule.value == t.id)) {
|
||||
filterByTag(tag_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
if (filterRules.find(rule => rule.type.id == FILTER_HAS_TAG && rule.value == tag_id)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_HAS_TAG), value: t.id})
|
||||
filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_HAS_TAG), value: tag_id})
|
||||
this.filterRules = filterRules
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
filterByCorrespondent(c: PaperlessCorrespondent) {
|
||||
let existing_rule = this.filterRules.find(rule => rule.type.id == FILTER_CORRESPONDENT)
|
||||
if (existing_rule) {
|
||||
existing_rule.value = c.id
|
||||
filterByCorrespondent(correspondent_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
let existing_rule = filterRules.find(rule => rule.type.id == FILTER_CORRESPONDENT)
|
||||
if (existing_rule && existing_rule.value == correspondent_id) {
|
||||
return
|
||||
} else if (existing_rule) {
|
||||
existing_rule.value = correspondent_id
|
||||
} else {
|
||||
this.filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_CORRESPONDENT), value: c.id})
|
||||
filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_CORRESPONDENT), value: correspondent_id})
|
||||
}
|
||||
this.filterRules = filterRules
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
filterByDocumentType(dt: PaperlessDocumentType) {
|
||||
let existing_rule = this.filterRules.find(rule => rule.type.id == FILTER_DOCUMENT_TYPE)
|
||||
if (existing_rule) {
|
||||
existing_rule.value = dt.id
|
||||
filterByDocumentType(document_type_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
let existing_rule = filterRules.find(rule => rule.type.id == FILTER_DOCUMENT_TYPE)
|
||||
if (existing_rule && existing_rule.value == document_type_id) {
|
||||
return
|
||||
} else if (existing_rule) {
|
||||
existing_rule.value = document_type_id
|
||||
} else {
|
||||
this.filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_DOCUMENT_TYPE), value: dt.id})
|
||||
filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_DOCUMENT_TYPE), value: document_type_id})
|
||||
}
|
||||
this.filterRules = filterRules
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,9 @@ export class FilterEditorComponent implements OnInit {
|
||||
|
||||
constructor(private documentTypeService: DocumentTypeService, private tagService: TagService, private correspondentService: CorrespondentService) { }
|
||||
|
||||
@Output()
|
||||
clear = new EventEmitter()
|
||||
|
||||
@Input()
|
||||
filterRules: FilterRule[] = []
|
||||
|
||||
@@ -48,7 +51,7 @@ export class FilterEditorComponent implements OnInit {
|
||||
|
||||
clearClicked() {
|
||||
this.filterRules.splice(0,this.filterRules.length)
|
||||
this.apply.next()
|
||||
this.clear.next()
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@@ -1,13 +1,21 @@
|
||||
<app-page-header title="Search results">
|
||||
</app-page-header>
|
||||
|
||||
<p>Search string: <i>{{query}}</i></p>
|
||||
<div *ngIf="errorMessage" class="alert alert-danger">Invalid search query: {{errorMessage}}</div>
|
||||
|
||||
<div [class.result-content-searching]="searching" infiniteScroll (scrolled)="onScroll()">
|
||||
<p>
|
||||
Search string: <i>{{query}}</i>
|
||||
<ng-container *ngIf="correctedQuery">
|
||||
- Did you mean "<a [routerLink]="" (click)="searchCorrectedQuery()">{{correctedQuery}}</a>"?
|
||||
</ng-container>
|
||||
|
||||
</p>
|
||||
|
||||
<div *ngIf="!errorMessage" [class.result-content-searching]="searching" infiniteScroll (scrolled)="onScroll()">
|
||||
<p>{{resultCount}} result(s)</p>
|
||||
<app-document-card-large *ngFor="let result of results"
|
||||
[document]="result.document"
|
||||
[details]="result.highlights">
|
||||
|
||||
</app-document-card-large>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SearchHit } from 'src/app/data/search-result';
|
||||
import { SearchService } from 'src/app/services/rest/search.service';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { SearchService } from 'src/app/services/rest/search.service';
|
||||
styleUrls: ['./search.component.scss']
|
||||
})
|
||||
export class SearchComponent implements OnInit {
|
||||
|
||||
|
||||
results: SearchHit[] = []
|
||||
|
||||
query: string = ""
|
||||
@@ -22,7 +22,11 @@ export class SearchComponent implements OnInit {
|
||||
|
||||
resultCount
|
||||
|
||||
constructor(private searchService: SearchService, private route: ActivatedRoute) { }
|
||||
correctedQuery: string = null
|
||||
|
||||
errorMessage: string
|
||||
|
||||
constructor(private searchService: SearchService, private route: ActivatedRoute, private router: Router) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.queryParamMap.subscribe(paramMap => {
|
||||
@@ -31,10 +35,16 @@ export class SearchComponent implements OnInit {
|
||||
this.currentPage = 1
|
||||
this.loadPage()
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
searchCorrectedQuery() {
|
||||
this.router.navigate(["search"], {queryParams: {query: this.correctedQuery}})
|
||||
}
|
||||
|
||||
loadPage(append: boolean = false) {
|
||||
this.errorMessage = null
|
||||
this.correctedQuery = null
|
||||
this.searchService.search(this.query, this.currentPage).subscribe(result => {
|
||||
if (append) {
|
||||
this.results.push(...result.results)
|
||||
@@ -44,12 +54,17 @@ export class SearchComponent implements OnInit {
|
||||
this.pageCount = result.page_count
|
||||
this.searching = false
|
||||
this.resultCount = result.count
|
||||
this.correctedQuery = result.corrected_query
|
||||
}, error => {
|
||||
this.searching = false
|
||||
this.resultCount = 1
|
||||
this.pageCount = 1
|
||||
this.results = []
|
||||
this.errorMessage = error.error
|
||||
})
|
||||
}
|
||||
|
||||
onScroll() {
|
||||
console.log(this.currentPage)
|
||||
console.log(this.pageCount)
|
||||
if (this.currentPage < this.pageCount) {
|
||||
this.currentPage += 1
|
||||
this.loadPage(true)
|
||||
|
Reference in New Issue
Block a user