Merge branch 'feature-bulk-edit' into feature-bulk-editor

This commit is contained in:
Michael Shamoon
2020-12-22 00:19:35 -08:00
21 changed files with 271 additions and 124 deletions

View File

@@ -1,7 +1,7 @@
<div class="form-group paperless-input-select">
<label [for]="inputId">{{title}}</label>
<div [class.input-group]="showPlusButton()">
<ng-select name="correspondent" [(ngModel)]="value"
<ng-select name="inputId" [(ngModel)]="value"
[disabled]="disabled"
[style.color]="textColor"
[style.background]="backgroundColor"

View File

@@ -1,4 +1,4 @@
<app-page-header title="Dashboard" subTitle="Welcome to paperless-ng!">
<app-page-header title="Dashboard" [subTitle]="subtitle">
<img src="assets/logo.svg" height="80" class="m-2 d-none d-md-block">
</app-page-header>

View File

@@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { Meta } from '@angular/platform-browser';
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
import { SavedViewService } from 'src/app/services/rest/saved-view.service';
@@ -11,8 +12,29 @@ import { SavedViewService } from 'src/app/services/rest/saved-view.service';
export class DashboardComponent implements OnInit {
constructor(
private savedViewService: SavedViewService) { }
private savedViewService: SavedViewService,
private meta: Meta
) { }
get displayName() {
let tagFullName = this.meta.getTag('name=full_name')
let tagUsername = this.meta.getTag('name=username')
if (tagFullName && tagFullName.content) {
return tagFullName.content
} else if (tagUsername && tagUsername.content) {
return tagUsername.content
} else {
return null
}
}
get subtitle() {
if (this.displayName) {
return `Hello ${this.displayName}, welcome to Paperless-ng!`
} else {
return `Welcome to Paperless-ng!`
}
}
savedViews: PaperlessSavedView[] = []

View File

@@ -23,7 +23,7 @@ export class SavedViewWidgetComponent implements OnInit {
documents: PaperlessDocument[] = []
ngOnInit(): void {
this.documentService.list(1,10,this.savedView.sort_field, this.savedView.sort_reverse, this.savedView.filter_rules).subscribe(result => {
this.documentService.listFiltered(1,10,this.savedView.sort_field, this.savedView.sort_reverse, this.savedView.filter_rules).subscribe(result => {
this.documents = result.results
})
}

View File

@@ -1,7 +1,15 @@
<div class="card mb-3 bg-light shadow-sm">
<div class="card mb-3 bg-light shadow-sm" [class.card-selected]="selected" [class.document-card]="selectable">
<div class="row no-gutters">
<div class="col-md-2 d-none d-lg-block">
<img [src]="getThumbUrl()" class="card-img doc-img border-right">
<div class="col-md-2 d-none d-lg-block doc-img-background" [class.doc-img-background-selected]="selected">
<img [src]="getThumbUrl()" class="card-img doc-img border-right" (click)="selected = selectable ? !selected : false">
<div style="top: 0; left: 0" class="position-absolute border-right border-bottom bg-light p-1" [class.document-card-check]="!selected">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="smallCardCheck{{document.id}}" [checked]="selected" (change)="selected = $event.target.checked">
<label class="custom-control-label" for="smallCardCheck{{document.id}}"></label>
</div>
</div>
</div>
<div class="col">
<div class="card-body">

View File

@@ -1,5 +1,6 @@
@import "/src/theme";
.result-content {
color: darkgray;
overflow-wrap: anywhere;
}
@@ -8,11 +9,31 @@
object-position: top;
height: 100%;
position: absolute;
mix-blend-mode: multiply;
}
.search-score-bar {
width: 100px;
height: 5px;
margin-top: 2px;
}
.document-card-check {
display: none
}
.document-card:hover .document-card-check {
display: block;
}
.card-selected {
border-color: $primary;
}
.doc-img-background {
background-color: white;
}
.doc-img-background-selected {
background-color: $primaryFaded;
}

View File

@@ -12,6 +12,25 @@ export class DocumentCardLargeComponent implements OnInit {
constructor(private documentService: DocumentService, private sanitizer: DomSanitizer) { }
_selected = false
get selected() {
return this._selected
}
@Input()
set selected(value: boolean) {
this._selected = value
this.selectedChange.emit(value)
}
@Output()
selectedChange = new EventEmitter<boolean>()
get selectable() {
return this.selectedChange.observers.length > 0
}
@Input()
moreLikeThis: boolean = false

View File

@@ -10,7 +10,6 @@
</div>
</div>
<div style="top: 0; right: 0; font-size: large" class="text-right position-absolute mr-1">
<div *ngFor="let t of getTagsLimited$() | async">
<app-tag [tag]="t" (click)="clickTag.emit(t.id)" [clickable]="true" linkTitle="Filter by tag"></app-tag>

View File

@@ -100,7 +100,7 @@
</div>
<div *ngIf="displayMode == 'largeCards'">
<app-document-card-large *ngFor="let d of list.documents" [document]="d" [details]="d.content" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)">
<app-document-card-large [selected]="list.isSelected(d)" (selectedChange)="list.setSelected(d, $event)" *ngFor="let d of list.documents; trackBy: trackByDocumentId" [document]="d" [details]="d.content" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)">
</app-document-card-large>
</div>
@@ -115,7 +115,7 @@
<th class="d-none d-xl-table-cell">Added</th>
</thead>
<tbody>
<tr *ngFor="let d of list.documents" [ngClass]="list.isSelected(d) ? 'table-row-selected' : ''">
<tr *ngFor="let d of list.documents; trackBy: trackByDocumentId" [ngClass]="list.isSelected(d) ? 'table-row-selected' : ''">
<td>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="docCheck{{d.id}}" [checked]="list.isSelected(d)" (change)="list.setSelected(d, $event.target.checked)">
@@ -149,7 +149,6 @@
</tbody>
</table>
<div class="m-n2 row m-n2 row row-cols-paperless-cards" *ngIf="displayMode == 'smallCards'">
<app-document-card-small [document]="d" [selected]="list.isSelected(d)" (selectedChange)="list.setSelected(d, $event)" *ngFor="let d of list.documents" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)"></app-document-card-small>
<div class="m-n2 row row-cols-paperless-cards" *ngIf="displayMode == 'smallCards'">
<app-document-card-small [selected]="list.isSelected(d)" (selectedChange)="list.setSelected(d, $event)" [document]="d" *ngFor="let d of list.documents; trackBy: trackByDocumentId" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)"></app-document-card-small>
</div>

View File

@@ -3,6 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { PaperlessDocument } from 'src/app/data/paperless-document';
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view';
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
import { CorrespondentService } from 'src/app/services/rest/correspondent.service';
@@ -139,6 +140,10 @@ export class DocumentListComponent implements OnInit {
})
}
trackByDocumentId(index, item: PaperlessDocument) {
return item.id
}
private executeBulkOperation(method: string, args): Observable<any> {
return this.documentService.bulkEdit(Array.from(this.list.selected), method, args).pipe(
map(r => {

View File

@@ -8,10 +8,9 @@
<div class="modal-body">
<app-input-text title="Name" formControlName="name"></app-input-text>
<app-input-text title="Match" formControlName="match"></app-input-text>
<app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select>
<app-input-check title="Case insensitive" formControlName="is_insensitive"></app-input-check>
<app-input-text title="Match" formControlName="match" hint="Auto matching does not require you to fill in this field."></app-input-text>
<app-input-check title="Case insensitive" formControlName="is_insensitive" hint="Auto matching ignores this option."></app-input-check>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button>

View File

@@ -8,9 +8,9 @@
<div class="modal-body">
<app-input-text title="Name" formControlName="name"></app-input-text>
<app-input-text title="Match" formControlName="match"></app-input-text>
<app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select>
<app-input-check title="Case insensitive" formControlName="is_insensitive"></app-input-check>
<app-input-text title="Match" formControlName="match" hint="Auto matching does not require you to fill in this field."></app-input-text>
<app-input-check title="Case insensitive" formControlName="is_insensitive" hint="Auto matching ignores this option."></app-input-check>
</div>
<div class="modal-footer">

View File

@@ -7,11 +7,21 @@
</div>
<div class="modal-body">
<app-input-text title="Name" formControlName="name"></app-input-text>
<app-input-select title="Colour" [items]="getColours()" formControlName="colour" [textColor]="getColor(objectForm.value.colour).textColor" [backgroundColor]="getColor(objectForm.value.colour).value"></app-input-select>
<div class="form-group paperless-input-select">
<label for="colour">Colour</label>
<ng-select name="colour" formControlName="colour" [items]="getColours()" bindValue="id" bindLabel="name" [clearable]="false">
<ng-template ng-option-tmp ng-label-tmp let-item="item">
<span class="badge" [style.background]="item.value" [style.color]="item.textColor">{{item.name}}</span>
</ng-template>
</ng-select>
</div>
<app-input-check title="Inbox tag" formControlName="is_inbox_tag" hint="Inbox tags are automatically assigned to all consumed documents."></app-input-check>
<app-input-text title="Match" formControlName="match"></app-input-text>
<app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select>
<app-input-check title="Case insensitive" formControlName="is_insensitive"></app-input-check>
<app-input-text title="Match" formControlName="match" hint="Auto matching does not require you to fill in this field."></app-input-text>
<app-input-check title="Case insensitive" formControlName="is_insensitive" hint="Auto matching ignores this option."></app-input-check>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button>