mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge branch 'dev' into feature-websockets-status
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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,2 +1,2 @@
|
||||
<span *ngIf="!clickable" class="badge" [style.background]="getColour().value" [style.color]="getColour().textColor">{{tag.name}}</span>
|
||||
<a [routerLink]="" *ngIf="clickable" class="badge" [style.background]="getColour().value" [style.color]="getColour().textColor">{{tag.name}}</a>
|
||||
<a [routerLink]="" [title]="linkTitle" *ngIf="clickable" class="badge" [style.background]="getColour().value" [style.color]="getColour().textColor">{{tag.name}}</a>
|
@@ -14,10 +14,10 @@ export class TagComponent implements OnInit {
|
||||
tag: PaperlessTag
|
||||
|
||||
@Input()
|
||||
clickable: boolean = false
|
||||
linkTitle: string = ""
|
||||
|
||||
@Output()
|
||||
click = new EventEmitter()
|
||||
@Input()
|
||||
clickable: boolean = false
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
@@ -3,19 +3,15 @@
|
||||
</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>
|
||||
|
||||
|
@@ -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,7 +1,9 @@
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
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 { ConsumerStatusService } from 'src/app/services/consumer-status.service';
|
||||
import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
|
||||
@@ -12,7 +14,11 @@ import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
})
|
||||
export class SavedViewWidgetComponent implements OnInit {
|
||||
|
||||
constructor(private documentService: DocumentService, private consumerStatusService: ConsumerStatusService) { }
|
||||
constructor(
|
||||
private documentService: DocumentService,
|
||||
private router: Router,
|
||||
private list: DocumentListViewService,
|
||||
private consumerStatusService: ConsumerStatusService) { }
|
||||
|
||||
@Input()
|
||||
savedView: SavedViewConfig
|
||||
@@ -38,4 +44,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)"
|
||||
|
@@ -16,26 +16,31 @@ export class UploadFileWidgetComponent implements OnInit {
|
||||
}
|
||||
|
||||
public fileOver(event){
|
||||
console.log(event);
|
||||
}
|
||||
|
||||
|
||||
public fileLeave(event){
|
||||
console.log(event);
|
||||
}
|
||||
|
||||
|
||||
public dropped(files: NgxFileDropEntry[]) {
|
||||
for (const droppedFile of files) {
|
||||
if (droppedFile.fileEntry.isFile) {
|
||||
const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
|
||||
console.log(fileEntry)
|
||||
fileEntry.file((file: File) => {
|
||||
console.log(file)
|
||||
const formData = new FormData()
|
||||
formData.append('document', file, file.name)
|
||||
this.documentService.uploadDocument(formData).subscribe(result => {
|
||||
this.toastService.showInfo("The document has been uploaded and will be processed by the consumer shortly.")
|
||||
this.toastService.showInfo(The document has been uploaded and will be processed by the consumer shortly.")
|
||||
}, error => {
|
||||
this.toastService.showError("An error has occured while uploading the document. Sorry!")
|
||||
switch (error.status) {
|
||||
case 400: {
|
||||
this.toastService.showError(`There was an error while uploading the document: ${error.error.document}`)
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.toastService.showError("An error has occured while uploading the document. Sorry!")
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
@@ -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>
|
@@ -1,20 +1,20 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ResultHightlightComponent } from './result-hightlight.component';
|
||||
import { WelcomeWidgetComponent } from './welcome-widget.component';
|
||||
|
||||
describe('ResultHightlightComponent', () => {
|
||||
let component: ResultHightlightComponent;
|
||||
let fixture: ComponentFixture<ResultHightlightComponent>;
|
||||
describe('WelcomeWidgetComponent', () => {
|
||||
let component: WelcomeWidgetComponent;
|
||||
let fixture: ComponentFixture<WelcomeWidgetComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ResultHightlightComponent ]
|
||||
declarations: [ WelcomeWidgetComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ResultHightlightComponent);
|
||||
fixture = TestBed.createComponent(WelcomeWidgetComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
@@ -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>
|
||||
|
@@ -1,22 +1,19 @@
|
||||
import { DatePipe, formatDate } from '@angular/common';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
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 { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
||||
import { OpenDocumentsService } from 'src/app/services/open-documents.service';
|
||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service';
|
||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service';
|
||||
import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
import { TagService } from 'src/app/services/rest/tag.service';
|
||||
import { DeleteDialogComponent } from '../common/delete-dialog/delete-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 { TagEditDialogComponent } from '../manage/tag-list/tag-edit-dialog/tag-edit-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-document-detail',
|
||||
@@ -27,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[]
|
||||
@@ -38,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(
|
||||
@@ -66,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 {
|
||||
@@ -80,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)
|
||||
}
|
||||
@@ -90,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)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -101,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)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -133,8 +136,8 @@ export class DocumentDetailComponent implements OnInit {
|
||||
|
||||
close() {
|
||||
this.openDocumentService.closeDocument(this.document)
|
||||
if (this.documentListViewService.viewId) {
|
||||
this.router.navigate(['view', this.documentListViewService.viewId])
|
||||
if (this.documentListViewService.savedViewId) {
|
||||
this.router.navigate(['view', this.documentListViewService.savedViewId])
|
||||
} else {
|
||||
this.router.navigate(['documents'])
|
||||
}
|
||||
|
@@ -7,11 +7,18 @@
|
||||
<div class="card-body">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title">{{document.correspondent ? document.correspondent.name + ': ' : ''}}{{document.title}}<app-tag [tag]="t" *ngFor="let t of document.tags" class="ml-1"></app-tag></h5>
|
||||
<h5 class="card-title">
|
||||
<ng-container *ngIf="document.correspondent">
|
||||
<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$ | 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>
|
||||
<p class="card-text">
|
||||
<app-result-hightlight *ngIf="getDetailsAsHighlight()" class="result-content" [highlights]="getDetailsAsHighlight()"></app-result-hightlight>
|
||||
<app-result-highlight *ngIf="getDetailsAsHighlight()" class="result-content" [highlights]="getDetailsAsHighlight()"></app-result-highlight>
|
||||
<span *ngIf="getDetailsAsString()" class="result-content">{{getDetailsAsString()}}</span>
|
||||
</p>
|
||||
|
||||
@@ -24,6 +31,13 @@
|
||||
</svg>
|
||||
Edit
|
||||
</a>
|
||||
<a type="button" class="btn btn-sm btn-outline-secondary" [href]="getPreviewUrl()">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-search" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M10.442 10.442a1 1 0 0 1 1.415 0l3.85 3.85a1 1 0 0 1-1.414 1.415l-3.85-3.85a1 1 0 0 1 0-1.415z"/>
|
||||
<path fill-rule="evenodd" d="M6.5 12a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM13 6.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z"/>
|
||||
</svg>
|
||||
View
|
||||
</a>
|
||||
<a type="button" class="btn btn-sm btn-outline-secondary" [href]="getDownloadUrl()">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-download" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
|
||||
@Component({
|
||||
@@ -18,6 +19,12 @@ export class DocumentCardLargeComponent implements OnInit {
|
||||
@Input()
|
||||
details: any
|
||||
|
||||
@Output()
|
||||
clickTag = new EventEmitter<number>()
|
||||
|
||||
@Output()
|
||||
clickCorrespondent = new EventEmitter<number>()
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
@@ -41,4 +48,8 @@ export class DocumentCardLargeComponent implements OnInit {
|
||||
getDownloadUrl() {
|
||||
return this.documentService.getDownloadUrl(this.document.id)
|
||||
}
|
||||
|
||||
getPreviewUrl() {
|
||||
return this.documentService.getPreviewUrl(this.document.id)
|
||||
}
|
||||
}
|
||||
|
@@ -1,27 +1,35 @@
|
||||
<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 [tag]="t" class="col text-right"></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">
|
||||
<span class="font-weight-bold">{{document.correspondent? document.correspondent.name + ': ' : ''}}</span> {{document.title}}
|
||||
<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}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center ml-n2">
|
||||
<div class="btn-group">
|
||||
<a routerLink="/documents/{{document.id}}" class="btn btn-sm btn-outline-secondary">
|
||||
<a routerLink="/documents/{{document.id}}" class="btn btn-sm btn-outline-secondary" title="Edit">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-pencil" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5L13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175l-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a [href]="getDownloadUrl()" class="btn btn-sm btn-outline-secondary">
|
||||
<a [href]="getPreviewUrl()" class="btn btn-sm btn-outline-secondary" title="View in browser">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-search" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M10.442 10.442a1 1 0 0 1 1.415 0l3.85 3.85a1 1 0 0 1-1.414 1.415l-3.85-3.85a1 1 0 0 1 0-1.415z"/>
|
||||
<path fill-rule="evenodd" d="M6.5 12a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM13 6.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a [href]="getDownloadUrl()" class="btn btn-sm btn-outline-secondary" title="Download">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-download" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/>
|
||||
<path fill-rule="evenodd" d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { DocumentService } from 'src/app/services/rest/document.service';
|
||||
|
||||
@Component({
|
||||
@@ -14,6 +15,12 @@ export class DocumentCardSmallComponent implements OnInit {
|
||||
@Input()
|
||||
document: PaperlessDocument
|
||||
|
||||
@Output()
|
||||
clickTag = new EventEmitter<number>()
|
||||
|
||||
@Output()
|
||||
clickCorrespondent = new EventEmitter<number>()
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
@@ -24,4 +31,8 @@ export class DocumentCardSmallComponent implements OnInit {
|
||||
getDownloadUrl() {
|
||||
return this.documentService.getDownloadUrl(this.document.id)
|
||||
}
|
||||
|
||||
getPreviewUrl() {
|
||||
return this.documentService.getPreviewUrl(this.document.id)
|
||||
}
|
||||
}
|
||||
|
@@ -21,13 +21,12 @@
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group btn-group-toggle ml-2" ngbRadioGroup [(ngModel)]="docs.sortDirection"
|
||||
*ngIf="!docs.viewId">
|
||||
<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">
|
||||
<button *ngFor="let f of getSortFields()" ngbDropdownItem (click)="setSort(f.field)"
|
||||
[class.active]="docs.sortField == f.field">{{f.name}}</button>
|
||||
<button *ngFor="let f of getSortFields()" ngbDropdownItem (click)="list.sortField = f.field"
|
||||
[class.active]="list.sortField == f.field">{{f.name}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<label ngbButtonLabel class="btn-outline-primary btn-sm">
|
||||
@@ -43,7 +42,7 @@
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group ml-2" *ngIf="!docs.viewId">
|
||||
<div class="btn-group ml-2">
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" (click)="showFilter=!showFilter">
|
||||
<svg class="toolbaricon" fill="currentColor">
|
||||
@@ -55,9 +54,13 @@
|
||||
<div class="btn-group" ngbDropdown role="group">
|
||||
<button class="btn btn-sm btn-outline-primary dropdown-toggle-split" ngbDropdownToggle></button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu>
|
||||
<button ngbDropdownItem *ngFor="let config of savedViewConfigService.getConfigs()" (click)="loadViewConfig(config)">{{config.title}}</button>
|
||||
<div class="dropdown-divider" *ngIf="savedViewConfigService.getConfigs().length > 0"></div>
|
||||
<button ngbDropdownItem (click)="saveViewConfig()">Save current view</button>
|
||||
<ng-container *ngIf="!list.savedViewId" >
|
||||
<button ngbDropdownItem *ngFor="let config of savedViewConfigService.getConfigs()" (click)="loadViewConfig(config)">{{config.title}}</button>
|
||||
<div class="dropdown-divider" *ngIf="savedViewConfigService.getConfigs().length > 0"></div>
|
||||
</ng-container>
|
||||
|
||||
<button ngbDropdownItem (click)="saveViewConfig()" *ngIf="list.savedViewId">Save "{{list.savedViewTitle}}"</button>
|
||||
<button ngbDropdownItem (click)="saveViewConfigAs()">Save as...</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -67,21 +70,22 @@
|
||||
<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">
|
||||
<ngb-pagination [pageSize]="docs.currentPageSize" [collectionSize]="docs.collectionSize" [(page)]="docs.currentPage" [maxSize]="5"
|
||||
[rotate]="true" (pageChange)="reload()" aria-label="Default pagination"></ngb-pagination>
|
||||
<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>
|
||||
|
||||
<div *ngIf="displayMode == 'largeCards'">
|
||||
<app-document-card-large *ngFor="let d of docs.documents" [document]="d" [details]="d.content">
|
||||
<app-document-card-large *ngFor="let d of list.documents" [document]="d" [details]="d.content" (clickTag)="filterByTag($event)" (clickCorrespondent)="filterByCorrespondent($event)">
|
||||
</app-document-card-large>
|
||||
</div>
|
||||
|
||||
<table class="table table-hover table-sm border shadow" *ngIf="displayMode == 'details'">
|
||||
<table class="table table-sm border shadow" *ngIf="displayMode == 'details'">
|
||||
<thead>
|
||||
<th class="d-none d-lg-table-cell">ASN</th>
|
||||
<th class="d-none d-md-table-cell">Correspondent</th>
|
||||
@@ -91,20 +95,35 @@
|
||||
<th class="d-none d-xl-table-cell">Added</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let d of docs.documents" routerLink="/documents/{{d.id}}">
|
||||
<td class="d-none d-lg-table-cell">{{d.archive_serial_number}}</td>
|
||||
<td class="d-none d-md-table-cell">{{d.correspondent ? d.correspondent.name : ''}}</td>
|
||||
<td>{{d.title}}<app-tag [tag]="t" *ngFor="let t of d.tags" class="ml-1"></app-tag></td>
|
||||
<td class="d-none d-xl-table-cell">{{d.document_type ? d.document_type.name : ''}}</td>
|
||||
<td>{{d.created | date}}</td>
|
||||
<td class="d-none d-xl-table-cell">{{d.added | date}}</td>
|
||||
<tr *ngFor="let d of list.documents">
|
||||
<td class="d-none d-lg-table-cell">
|
||||
{{d.archive_serial_number}}
|
||||
</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$ | 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$ | 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$ | async)?.name}}</a>
|
||||
</ng-container>
|
||||
</td>
|
||||
<td>
|
||||
{{d.created | date}}
|
||||
</td>
|
||||
<td class="d-none d-xl-table-cell">
|
||||
{{d.added | date}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<div class=" m-n2 row" *ngIf="displayMode == 'smallCards'">
|
||||
<app-document-card-small [document]="d" *ngFor="let d of docs.documents"></app-document-card-small>
|
||||
<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="docs.documents.length == 0" class="mx-auto">No results</p>
|
@@ -1,11 +1,13 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
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 { 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';
|
||||
import { SavedViewConfigService } from 'src/app/services/saved-view-config.service';
|
||||
import { Toast, ToastService } from 'src/app/services/toast.service';
|
||||
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component';
|
||||
|
||||
@Component({
|
||||
@@ -16,9 +18,10 @@ import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-vi
|
||||
export class DocumentListComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
public docs: DocumentListViewService,
|
||||
public list: DocumentListViewService,
|
||||
public savedViewConfigService: SavedViewConfigService,
|
||||
public route: ActivatedRoute,
|
||||
private toastService: ToastService,
|
||||
public modalService: NgbModal) { }
|
||||
|
||||
displayMode = 'smallCards' // largeCards, smallCards, details
|
||||
@@ -27,17 +30,13 @@ export class DocumentListComponent implements OnInit {
|
||||
showFilter = false
|
||||
|
||||
getTitle() {
|
||||
return this.docs.viewConfigOverride ? this.docs.viewConfigOverride.title : "Documents"
|
||||
return this.list.savedViewTitle || "Documents"
|
||||
}
|
||||
|
||||
getSortFields() {
|
||||
return DOCUMENT_SORT_FIELDS
|
||||
}
|
||||
|
||||
setSort(field: string) {
|
||||
this.docs.sortField = field
|
||||
}
|
||||
|
||||
saveDisplayMode() {
|
||||
localStorage.setItem('document-list:displayMode', this.displayMode)
|
||||
}
|
||||
@@ -48,41 +47,90 @@ export class DocumentListComponent implements OnInit {
|
||||
}
|
||||
this.route.paramMap.subscribe(params => {
|
||||
if (params.has('id')) {
|
||||
this.docs.viewConfigOverride = this.savedViewConfigService.getConfig(params.get('id'))
|
||||
this.list.savedView = this.savedViewConfigService.getConfig(params.get('id'))
|
||||
this.filterRules = this.list.filterRules
|
||||
this.showFilter = false
|
||||
} else {
|
||||
this.filterRules = this.docs.filterRules
|
||||
this.list.savedView = null
|
||||
this.filterRules = this.list.filterRules
|
||||
this.showFilter = this.filterRules.length > 0
|
||||
this.docs.viewConfigOverride = null
|
||||
}
|
||||
this.reload()
|
||||
this.list.clear()
|
||||
this.list.reload()
|
||||
})
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.docs.reload()
|
||||
applyFilterRules() {
|
||||
this.list.filterRules = this.filterRules
|
||||
}
|
||||
|
||||
applyFilterRules() {
|
||||
this.docs.filterRules = this.filterRules
|
||||
clearFilterRules() {
|
||||
this.list.filterRules = this.filterRules
|
||||
this.showFilter = false
|
||||
}
|
||||
|
||||
loadViewConfig(config: SavedViewConfig) {
|
||||
this.filterRules = cloneFilterRules(config.filterRules)
|
||||
this.docs.loadViewConfig(config)
|
||||
this.list.load(config)
|
||||
}
|
||||
|
||||
saveViewConfig() {
|
||||
this.savedViewConfigService.updateConfig(this.list.savedView)
|
||||
this.toastService.showToast(Toast.make("Information", `View "${this.list.savedView.title}" saved successfully.`))
|
||||
}
|
||||
|
||||
saveViewConfigAs() {
|
||||
let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'})
|
||||
modal.componentInstance.saveClicked.subscribe(formValue => {
|
||||
this.savedViewConfigService.saveConfig({
|
||||
this.savedViewConfigService.newConfig({
|
||||
title: formValue.title,
|
||||
showInDashboard: formValue.showInDashboard,
|
||||
showInSideBar: formValue.showInSideBar,
|
||||
filterRules: this.docs.filterRules,
|
||||
sortDirection: this.docs.sortDirection,
|
||||
sortField: this.docs.sortField
|
||||
filterRules: this.list.filterRules,
|
||||
sortDirection: this.list.sortDirection,
|
||||
sortField: this.list.sortField
|
||||
})
|
||||
modal.close()
|
||||
})
|
||||
}
|
||||
|
||||
filterByTag(tag_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
if (filterRules.find(rule => rule.type.id == FILTER_HAS_TAG && rule.value == tag_id)) {
|
||||
return
|
||||
}
|
||||
|
||||
filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_HAS_TAG), value: tag_id})
|
||||
this.filterRules = filterRules
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
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 {
|
||||
filterRules.push({type: FILTER_RULE_TYPES.find(t => t.id == FILTER_CORRESPONDENT), value: correspondent_id})
|
||||
}
|
||||
this.filterRules = filterRules
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
|
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ResultHighlightComponent } from './result-highlight.component';
|
||||
|
||||
describe('ResultHighlightComponent', () => {
|
||||
let component: ResultHighlightComponent;
|
||||
let fixture: ComponentFixture<ResultHighlightComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ResultHighlightComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ResultHighlightComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -2,11 +2,11 @@ import { Component, Input, OnInit } from '@angular/core';
|
||||
import { SearchHitHighlight } from 'src/app/data/search-result';
|
||||
|
||||
@Component({
|
||||
selector: 'app-result-hightlight',
|
||||
templateUrl: './result-hightlight.component.html',
|
||||
styleUrls: ['./result-hightlight.component.scss']
|
||||
selector: 'app-result-highlight',
|
||||
templateUrl: './result-highlight.component.html',
|
||||
styleUrls: ['./result-highlight.component.scss']
|
||||
})
|
||||
export class ResultHightlightComponent implements OnInit {
|
||||
export class ResultHighlightComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
@@ -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>
|
||||
|
@@ -11,5 +11,5 @@
|
||||
}
|
||||
|
||||
.result-content-searching {
|
||||
opacity: 0.2;
|
||||
opacity: 0.3;
|
||||
}
|
@@ -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