Bulk editor component skeleton

This commit is contained in:
Michael Shamoon 2020-12-18 21:19:49 -08:00
parent 55a6dca373
commit 01d448ecde
5 changed files with 107 additions and 99 deletions

View File

@ -27,6 +27,9 @@ export class FilterableDropdownComponent {
@Output() @Output()
toggle = new EventEmitter() toggle = new EventEmitter()
@Output()
close = new EventEmitter()
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef @ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
@ViewChild('dropdown') dropdown: NgbDropdown @ViewChild('dropdown') dropdown: NgbDropdown
@ -47,6 +50,7 @@ export class FilterableDropdownComponent {
}, 0); }, 0);
} else { } else {
this.filterText = '' this.filterText = ''
this.close.emit(this.itemsSelected)
} }
} }

View File

@ -1,89 +1,34 @@
<div class="card bg-light"> <div class="row">
<div class="card-body small px-2 py-2 d-flex flex-column flex-xl-row justify-content-between justify-content-xl-start"> <div class="col mb-2 mb-xl-0" role="group" aria-label="Select">
<div class="d-flex flex-grow-1 flex-xl-grow-0 mb-2 mb-xl-0 mr-xl-5" role="group" aria-label="Select"> <label class="mr-lg-2">Select:</label>
<label class="d-flex align-self-center my-0 mr-auto mr-lg-2">Select:</label> <div class="btn-group">
<div class="btn-group d-flex"> <button class="btn btn-sm btn-outline-primary" (click)="selectPage.next()">
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="selectPage.next()"> <svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
<svg viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#file-earmark-check" /> <use xlink:href="assets/bootstrap-icons.svg#file-earmark-check" />
</svg> </svg>
<small>Page</small> Page
</button> </button>
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="selectAll.next()"> <button class="btn btn-sm btn-outline-primary" (click)="selectAll.next()">
<svg viewBox="0 0 16 16" fill="currentColor"> <svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#check-all" /> <use xlink:href="assets/bootstrap-icons.svg#check-all" />
</svg> </svg>
<small>All</small> All
</button> </button>
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="selectNone.next()"> <button class="btn btn-sm btn-outline-primary" (click)="selectNone.next()">
<svg viewBox="0 0 16 16" fill="currentColor"> <svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#slash-circle" /> <use xlink:href="assets/bootstrap-icons.svg#slash-circle" />
</svg> </svg>
<small>None</small> None
</button> </button>
</div> </div>
</div> </div>
<div class="d-flex flex-grow-1 flex-xl-grow-0 mb-2 mb-xl-0 mr-xl-5" role="group" aria-label="Tags"> <div class="w-100 d-xl-none"></div>
<label class="d-flex align-self-center my-0 mr-auto mr-lg-2">Tags:</label> <div class="col mb-2 mb-xl-0">
<div class="btn-group d-flex"> <div class="d-flex">
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="addTag.next()"> <label class="ml-auto mt-1 mr-2">Apply:</label>
<ng-container *ngTemplateOutlet="add"></ng-container> <app-filterable-dropdown class="mr-2 mr-md-3" title="Apply Tags" icon="tag-fill" [items]="tags" [itemsSelected]="selectedTags" (close)="applyTags($event)"></app-filterable-dropdown>
</button> <app-filterable-dropdown class="mr-2 mr-md-3" title="Set Correspondent" icon="person-fill" [items]="correspondents" [itemsSelected]="selectedCorrespondents" (close)="applyCorrespondent($event)"></app-filterable-dropdown>
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="removeTag.next()"> <app-filterable-dropdown class="mr-2 mr-md-3" title="Set Document Type" icon="file-earmark-fill" [items]="documentTypes" [itemsSelected]="selectedDocumentTypes" (close)="applyDocumentType($event)"></app-filterable-dropdown>
<ng-container *ngTemplateOutlet="remove"></ng-container>
</button>
</div> </div>
</div> </div>
<div class="d-flex flex-grow-1 flex-xl-grow-0 mb-2 mb-xl-0 mr-xl-5" role="group" aria-label="Correspondent">
<label class="d-flex align-self-center my-0 mr-auto mr-lg-2">Correspondent:</label>
<div class="btn-group d-flex">
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="setCorrespondent.next()">
<ng-container *ngTemplateOutlet="edit"></ng-container>
</button>
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="removeCorrespondent.next()">
<ng-container *ngTemplateOutlet="remove"></ng-container>
</button>
</div>
</div>
<div class="d-flex flex-grow-1 flex-xl-grow-0 mb-2 mb-xl-0 mr-xl-5" role="group" aria-label="Document Type">
<label class="d-flex align-self-center my-0 mr-auto mr-lg-2">Document Type:</label>
<div class="btn-group d-flex">
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="setDocumentType.next()">
<ng-container *ngTemplateOutlet="edit"></ng-container>
</button>
<button class="btn btn-sm btn-outline-primary py-1 px-2" (click)="removeDocumentType.next()">
<ng-container *ngTemplateOutlet="remove"></ng-container>
</button>
</div>
</div>
<div class="d-flex flex-grow-1 flex-xl-grow-0 mb-2 mb-lg-0 ml-auto ml-lg-0 ml-xl-auto" role="group" aria-label="Delete">
<button class="btn btn-sm btn-outline-danger" (click)="delete.next()">
<svg viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg>
<small>Delete</small>
</button>
</div>
</div> </div>
</div>
<ng-template #add>
<svg viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg>
<small>Add</small>
</ng-template>
<ng-template #edit>
<svg viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#pencil" />
</svg>
<small>Edit</small>
</ng-template>
<ng-template #remove>
<svg viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#x-circle" />
</svg>
<small>Remove</small>
</ng-template>

View File

@ -1,10 +0,0 @@
.btn svg {
width: 0.9em;
height: 0.9em;
margin-right: 3px;
margin-top: -1px;
}
.btn-sm {
line-height: 1;
}

View File

@ -1,5 +1,12 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { DocumentListViewService } from 'src/app/services/document-list-view.service'; 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 { PaperlessDocument } from 'src/app/data/paperless-document';
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';
import { DocumentService } from 'src/app/services/rest/document.service';
@Component({ @Component({
selector: 'app-bulk-editor', selector: 'app-bulk-editor',
@ -9,7 +16,10 @@ import { DocumentListViewService } from 'src/app/services/document-list-view.ser
export class BulkEditorComponent { export class BulkEditorComponent {
@Input() @Input()
list: DocumentListViewService documentsSelected: Set<number>
@Input()
allDocuments: PaperlessDocument[]
@Output() @Output()
selectPage = new EventEmitter() selectPage = new EventEmitter()
@ -41,6 +51,65 @@ export class BulkEditorComponent {
@Output() @Output()
delete = new EventEmitter() delete = new EventEmitter()
constructor( ) { } tags: PaperlessTag[]
correspondents: PaperlessCorrespondent[]
documentTypes: PaperlessDocumentType[]
get selectedTags(): PaperlessTag[] {
let selectedTags = []
this.allDocuments.forEach(d => {
if (this.documentsSelected.has(d.id)) {
if (d.tags && !d.tags.every(t => selectedTags.find(st => st.id == t) !== undefined)) d.tags$.subscribe(t => selectedTags = selectedTags.concat(t))
}
})
return selectedTags
}
get selectedCorrespondents(): PaperlessCorrespondent[] {
let selectedCorrespondents = []
this.allDocuments.forEach(d => {
if (this.documentsSelected.has(d.id)) {
if (d.correspondent && selectedCorrespondents.find(sc => sc.id == d.correspondent) == undefined) d.correspondent$.subscribe(c => selectedCorrespondents.push(c))
}
})
return selectedCorrespondents
}
get selectedDocumentTypes(): PaperlessDocumentType[] {
let selectedDocumentTypes = []
this.allDocuments.forEach(d => {
if (this.documentsSelected.has(d.id)) {
if (d.document_type && selectedDocumentTypes.find(sdt => sdt.id == d.document_type) == undefined) d.document_type$.subscribe(dt => selectedDocumentTypes.push(dt))
}
})
return selectedDocumentTypes
}
constructor(
private documentTypeService: DocumentTypeService,
private tagService: TagService,
private correspondentService: CorrespondentService,
private documentService: DocumentService
) { }
ngOnInit() {
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)
}
applyTags(tags) {
console.log(tags);
}
applyCorrespondent(correspondent) {
console.log(correspondent);
}
applyDocumentType(documentType) {
console.log(documentType);
}
} }

View File

@ -78,17 +78,11 @@
</app-page-header> </app-page-header>
<div class="w-100 mb-2 mb-sm-4"> <div class="w-100 mb-2 mb-sm-4">
<app-filter-editor [(filterRules)]="list.filterRules" #filterEditor></app-filter-editor> <app-filter-editor *ngIf="!isBulkEditing" [(filterRules)]="list.filterRules" #filterEditor></app-filter-editor>
</div>
<div class="d-flex justify-content-between align-items-center"> <app-bulk-editor *ngIf="isBulkEditing"
<p><span *ngIf="list.selected.size > 0">Selected {{list.selected.size}} of </span>{{list.collectionSize || 0}} document(s) <span *ngIf="isFiltered">(filtered)</span></p> [allDocuments]="list.documents"
<ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5" [(documentsSelected)]="list.selected"
[rotate]="true" (pageChange)="list.reload()" aria-label="Default pagination"></ngb-pagination>
</div>
<div class="w-100 mb-3" [ngbCollapse]="!isBulkEditing">
<app-bulk-editor
(selectPage)="list.selectPage()" (selectPage)="list.selectPage()"
(selectAll)="list.selectAll()" (selectAll)="list.selectAll()"
(selectNone)="list.selectNone()" (selectNone)="list.selectNone()"
@ -99,7 +93,13 @@
(addTag)="bulkAddTag()" (addTag)="bulkAddTag()"
(removeTag)="bulkRemoveTag()" (removeTag)="bulkRemoveTag()"
(delete)="bulkDelete()"> (delete)="bulkDelete()">
</app-bulk-editor> </app-bulk-editor>
</div>
<div class="d-flex justify-content-between align-items-center">
<p><span *ngIf="list.selected.size > 0">Selected {{list.selected.size}} of </span>{{list.collectionSize || 0}} document(s) <span *ngIf="isFiltered">(filtered)</span></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>
<div *ngIf="displayMode == 'largeCards'"> <div *ngIf="displayMode == 'largeCards'">