mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
Basic tags, correspondents & document type dropdowns
This commit is contained in:
parent
72706a335d
commit
f3fd0fcf72
@ -48,6 +48,7 @@ import { WidgetFrameComponent } from './components/dashboard/widgets/widget-fram
|
||||
import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component';
|
||||
import { YesNoPipe } from './pipes/yes-no.pipe';
|
||||
import { FileSizePipe } from './pipes/file-size.pipe';
|
||||
import { FilterPipe } from './pipes/filter.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -88,7 +89,8 @@ import { FileSizePipe } from './pipes/file-size.pipe';
|
||||
WidgetFrameComponent,
|
||||
WelcomeWidgetComponent,
|
||||
YesNoPipe,
|
||||
FileSizePipe
|
||||
FileSizePipe,
|
||||
FilterPipe
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -1,5 +1,4 @@
|
||||
<app-page-header [title]="getTitle()">
|
||||
|
||||
<div class="btn-group btn-group-toggle" ngbRadioGroup [(ngModel)]="displayMode"
|
||||
(ngModelChange)="saveDisplayMode()">
|
||||
<label ngbButtonLabel class="btn-outline-primary btn-sm">
|
||||
@ -21,6 +20,7 @@
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
@ -42,13 +42,14 @@
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="btn-group ml-2">
|
||||
|
||||
<button type="button" class="btn btn-sm" [ngClass]="isFiltered ? 'btn-primary' : 'btn-outline-primary'" (click)="showFilter=!showFilter">
|
||||
<svg class="toolbaricon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#funnel" />
|
||||
</svg>
|
||||
Filter
|
||||
Advanced Filters
|
||||
</button>
|
||||
|
||||
<div class="btn-group" ngbDropdown role="group">
|
||||
@ -58,18 +59,69 @@
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
</app-page-header>
|
||||
|
||||
<div class="row pb-1 mb-3 align-items-right" >
|
||||
<div class="btn-toolbar col-auto">
|
||||
<div class="btn-group ml-2" ngbDropdown role="group">
|
||||
<button class="btn btn-outline-primary btn-sm" id="dropdownTags" ngbDropdownToggle>Tags</button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu aria-labelledby="dropdownTags">
|
||||
<div class="list-group list-group-flush">
|
||||
<input class="list-group-item form-control" type="text" [(ngModel)]="searchText" placeholder="Filter tags">
|
||||
<ng-container *ngIf="(tags | filter: searchText).length > 0">
|
||||
<button class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" role="menuitem" *ngFor="let tag of tags | filter: searchText; let i = index" (click)="filterByTag(tag.id, true)">
|
||||
{{tag.name}}
|
||||
<span class="badge bg-primary text-light rounded-pill">{{tag.document_count}}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group ml-2" ngbDropdown role="group">
|
||||
<button class="btn btn-outline-primary btn-sm" id="dropdownCorrespondents" ngbDropdownToggle>Correspondents</button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu aria-labelledby="dropdownCorrespondents">
|
||||
<div class="list-group list-group-flush">
|
||||
<input class="list-group-item form-control" type="text" [(ngModel)]="searchText" placeholder="Filter correspondents">
|
||||
<ng-container *ngIf="(correspondents | filter: searchText).length > 0">
|
||||
<button class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" role="menuitem" *ngFor="let correspondent of correspondents | filter: searchText; let i = index" (click)="filterByCorrespondent(correspondent.id, true)">
|
||||
{{correspondent.name}}
|
||||
<span class="badge bg-primary text-light rounded-pill">{{correspondent.document_count}}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group ml-2" ngbDropdown role="group">
|
||||
<button class="btn btn-outline-primary btn-sm" id="dropdownDocumentTypes" ngbDropdownToggle>Document Types</button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu aria-labelledby="dropdownDocumentTypes">
|
||||
<div class="list-group list-group-flush">
|
||||
<input class="list-group-item form-control" type="text" [(ngModel)]="searchText" placeholder="Filter tags">
|
||||
<ng-container *ngIf="(documentTypes | filter: searchText).length > 0">
|
||||
<button class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" role="menuitem" *ngFor="let documentType of documentTypes | filter: searchText; let i = index" (click)="filterByDocumentType(documentType.id, true)">
|
||||
{{documentType.name}}
|
||||
<span class="badge bg-primary text-light rounded-pill">{{documentType.document_count}}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card w-100 mb-3" [hidden]="!showFilter">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter</h5>
|
||||
<h5 class="card-title">Advanced Filters</h5>
|
||||
<app-filter-editor [(filterRules)]="filterRules" (apply)="applyFilterRules()" (clear)="clearFilterRules()"></app-filter-editor>
|
||||
</div>
|
||||
</div>
|
||||
@ -125,5 +177,12 @@
|
||||
|
||||
|
||||
<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>
|
||||
<app-document-card-small [document]="d" *ngFor="let d of list.documents" (clickTag)="filterByTag($event)" (clickCorrespondent)="filterByCorrespondent($event)"></app-document-card-small>
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="customTemplate.html">
|
||||
<a>
|
||||
<img ng-src="http://upload.wikimedia.org/wikipedia/commons/thumb/{{match.model.flag}}" width="16">
|
||||
<span ng-bind-html="match.label | uibTypeaheadHighlight:query"></span>
|
||||
</a>
|
||||
</script>
|
||||
|
@ -11,6 +11,12 @@ import { SavedViewConfigService } from 'src/app/services/saved-view-config.servi
|
||||
import { Toast, ToastService } from 'src/app/services/toast.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
|
||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
|
||||
import { TagService } from 'src/app/services/rest/tag.service';
|
||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service';
|
||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-document-list',
|
||||
@ -25,13 +31,20 @@ export class DocumentListComponent implements OnInit {
|
||||
public route: ActivatedRoute,
|
||||
private toastService: ToastService,
|
||||
public modalService: NgbModal,
|
||||
private titleService: Title) { }
|
||||
private titleService: Title,
|
||||
private tagService: TagService,
|
||||
private correspondentService: CorrespondentService,
|
||||
private documentTypeService: DocumentTypeService) { }
|
||||
|
||||
displayMode = 'smallCards' // largeCards, smallCards, details
|
||||
|
||||
filterRules: FilterRule[] = []
|
||||
showFilter = false
|
||||
|
||||
tags: PaperlessTag[] = []
|
||||
correspondents: PaperlessCorrespondent[] = []
|
||||
documentTypes: PaperlessDocumentType[] = []
|
||||
|
||||
get isFiltered() {
|
||||
return this.list.filterRules?.length > 0
|
||||
}
|
||||
@ -67,6 +80,9 @@ export class DocumentListComponent implements OnInit {
|
||||
this.list.clear()
|
||||
this.list.reload()
|
||||
})
|
||||
this.tagService.listAll().subscribe(result => this.tags = result.results)
|
||||
this.correspondentService.listAll().subscribe(result => this.correspondents = result.results)
|
||||
this.documentTypeService.listAll().subscribe(result => this.documentTypes = result.results)
|
||||
}
|
||||
|
||||
applyFilterRules() {
|
||||
@ -103,8 +119,8 @@ export class DocumentListComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
filterByTag(tag_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
filterByTag(tag_id: number, singleton: boolean = false) {
|
||||
let filterRules = singleton ? [] : this.list.filterRules
|
||||
if (filterRules.find(rule => rule.type.id == FILTER_HAS_TAG && rule.value == tag_id)) {
|
||||
return
|
||||
}
|
||||
@ -114,8 +130,8 @@ export class DocumentListComponent implements OnInit {
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
filterByCorrespondent(correspondent_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
filterByCorrespondent(correspondent_id: number, singleton: boolean = false) {
|
||||
let filterRules = singleton ? [] : this.list.filterRules
|
||||
let existing_rule = filterRules.find(rule => rule.type.id == FILTER_CORRESPONDENT)
|
||||
if (existing_rule && existing_rule.value == correspondent_id) {
|
||||
return
|
||||
@ -128,8 +144,8 @@ export class DocumentListComponent implements OnInit {
|
||||
this.applyFilterRules()
|
||||
}
|
||||
|
||||
filterByDocumentType(document_type_id: number) {
|
||||
let filterRules = this.list.filterRules
|
||||
filterByDocumentType(document_type_id: number, singleton: boolean = false) {
|
||||
let filterRules = singleton ? [] : 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
|
||||
|
17
src-ui/src/app/pipes/filter.pipe.ts
Normal file
17
src-ui/src/app/pipes/filter.pipe.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'filter'
|
||||
})
|
||||
export class FilterPipe implements PipeTransform {
|
||||
transform(items: any[], searchText: string): any[] {
|
||||
if (!items) return [];
|
||||
if (!searchText) return items;
|
||||
|
||||
return items.filter(item => {
|
||||
return Object.keys(item).some(key => {
|
||||
return String(item[key]).toLowerCase().includes(searchText.toLowerCase());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user