mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Show number of comments on cards, tab
This commit is contained in:
@@ -18,10 +18,11 @@
|
||||
</div>
|
||||
<div class="d-flex card-footer small bg-light text-primary justify-content-between align-items-center">
|
||||
<span>{{displayName(comment)}} - {{ comment.created | customDate}}</span>
|
||||
<button type="button" class="btn btn-link btn-sm p-0 fade" (click)="deleteComment(comment.id)" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Comment }">
|
||||
<button type="button" class="btn btn-link btn-sm p-0 fade" title="Delete comment" i18n-title (click)="deleteComment(comment.id)" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Comment }">
|
||||
<svg width="13" height="13" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
||||
</svg>
|
||||
<span class="visually-hidden" i18n>Delete comment</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
||||
import { DocumentCommentsService } from 'src/app/services/rest/document-comments.service'
|
||||
import { PaperlessDocumentComment } from 'src/app/data/paperless-document-comment'
|
||||
import { FormControl, FormGroup } from '@angular/forms'
|
||||
@@ -30,6 +30,9 @@ export class DocumentCommentsComponent extends ComponentWithPermissions {
|
||||
}
|
||||
}
|
||||
|
||||
@Output()
|
||||
updated: EventEmitter<number> = new EventEmitter<number>()
|
||||
|
||||
constructor(
|
||||
private commentsService: DocumentCommentsService,
|
||||
private toastService: ToastService
|
||||
@@ -64,6 +67,7 @@ export class DocumentCommentsComponent extends ComponentWithPermissions {
|
||||
this.comments = result
|
||||
this.commentForm.get('newComment').reset()
|
||||
this.networkActive = false
|
||||
this.updated.emit(this.comments.length)
|
||||
},
|
||||
error: (e) => {
|
||||
this.networkActive = false
|
||||
@@ -79,6 +83,7 @@ export class DocumentCommentsComponent extends ComponentWithPermissions {
|
||||
next: (result) => {
|
||||
this.comments = result
|
||||
this.networkActive = false
|
||||
this.updated.emit(this.comments.length)
|
||||
},
|
||||
error: (e) => {
|
||||
this.networkActive = false
|
||||
|
@@ -172,9 +172,9 @@
|
||||
</li>
|
||||
|
||||
<li [ngbNavItem]="5" *ngIf="commentsEnabled">
|
||||
<a ngbNavLink i18n>Comments</a>
|
||||
<a ngbNavLink i18n>Comments <span *ngIf="document?.n_comments" class="badge text-bg-secondary ms-1">{{document.n_comments}}</span></a>
|
||||
<ng-template ngbNavContent>
|
||||
<app-document-comments [documentId]="documentId"></app-document-comments>
|
||||
<app-document-comments [documentId]="documentId" (updated)="commentsUpdated($event)"></app-document-comments>
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
|
@@ -632,6 +632,11 @@ export class DocumentDetailComponent
|
||||
)
|
||||
}
|
||||
|
||||
commentsUpdated(n_comments: number) {
|
||||
this.document.n_comments = n_comments
|
||||
this.openDocumentService.refreshDocument(this.documentId)
|
||||
}
|
||||
|
||||
get userIsOwner(): boolean {
|
||||
let doc: PaperlessDocument = Object.assign({}, this.document)
|
||||
// dont disable while editing
|
||||
|
@@ -65,24 +65,31 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="list-group list-group-horizontal border-0 card-info ms-md-auto mt-2 mt-md-0">
|
||||
<button *ngIf="document.n_comments" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2" title="View comments" i18n-title>
|
||||
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
|
||||
</svg>
|
||||
<small i18n>{{document.n_comments}} Comments</small>
|
||||
</button>
|
||||
<button *ngIf="document.document_type" type="button" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2" title="Filter by document type" i18n-title
|
||||
(click)="clickDocumentType.emit(document.document_type);$event.stopPropagation()">
|
||||
<svg class="metadata-icon me-2 text-muted bi bi-file-earmark" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5L14 4.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5h-2z"/>
|
||||
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#file-earmark"/>
|
||||
</svg>
|
||||
<small>{{(document.document_type$ | async)?.name}}</small>
|
||||
</button>
|
||||
<button *ngIf="document.storage_path" type="button" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2" title="Filter by storage path" i18n-title
|
||||
(click)="clickStoragePath.emit(document.storage_path);$event.stopPropagation()">
|
||||
<svg class="metadata-icon me-2 text-muted bi bi-folder" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M0 2a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1v7.5a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 1 12.5V5a1 1 0 0 1-1-1V2zm2 3v7.5A1.5 1.5 0 0 0 3.5 14h9a1.5 1.5 0 0 0 1.5-1.5V5H2zm13-3H1v2h14V2zM5 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5z"/>
|
||||
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#archive"/>
|
||||
</svg>
|
||||
<small>{{(document.storage_path$ | async)?.name}}</small>
|
||||
</button>
|
||||
<div *ngIf="document.archive_serial_number" class="list-group-item me-2 bg-light text-dark p-1 border-0">
|
||||
<svg class="metadata-icon me-2 text-muted bi bi-upc-scan" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M1.5 1a.5.5 0 0 0-.5.5v3a.5.5 0 0 1-1 0v-3A1.5 1.5 0 0 1 1.5 0h3a.5.5 0 0 1 0 1h-3zM11 .5a.5.5 0 0 1 .5-.5h3A1.5 1.5 0 0 1 16 1.5v3a.5.5 0 0 1-1 0v-3a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 1-.5-.5zM.5 11a.5.5 0 0 1 .5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 1 0 1h-3A1.5 1.5 0 0 1 0 14.5v-3a.5.5 0 0 1 .5-.5zm15 0a.5.5 0 0 1 .5.5v3a1.5 1.5 0 0 1-1.5 1.5h-3a.5.5 0 0 1 0-1h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 1 .5-.5zM3 4.5a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0v-7zm2 0a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0v-7zm2 0a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0v-7zm2 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-7zm3 0a.5.5 0 0 1 1 0v7a.5.5 0 0 1-1 0v-7z"/>
|
||||
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#upc-scan"/>
|
||||
</svg>
|
||||
<small>#{{document.archive_serial_number}}</small>
|
||||
</div>
|
||||
@@ -94,9 +101,8 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="list-group-item bg-light text-dark p-1 border-0" [ngbTooltip]="dateTooltip">
|
||||
<svg class="metadata-icon me-2 text-muted bi bi-calendar-event" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M11 6.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1z"/>
|
||||
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
|
||||
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#calendar-event"/>
|
||||
</svg>
|
||||
<small>{{document.created_date | customDate:'mediumDate'}}</small>
|
||||
</div>
|
||||
|
@@ -18,6 +18,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="document.n_comments" class="document-card-comments pe-none py-2 px-1">
|
||||
<span class="badge rounded-pill bg-light border text-primary">
|
||||
<svg class="metadata-icon ms-1 me-1" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
|
||||
</svg>
|
||||
{{document.n_comments}}</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-2">
|
||||
<p class="card-text">
|
||||
<ng-container *ngIf="document.correspondent">
|
||||
|
@@ -34,6 +34,12 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.document-card-comments {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 170px;
|
||||
}
|
||||
|
||||
.card-selected {
|
||||
border-color:var(--bs-primary);
|
||||
|
||||
@@ -58,12 +64,12 @@
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.metadata-icon {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
padding: 0.05rem;
|
||||
}
|
||||
.metadata-icon {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
padding: 0.05rem;
|
||||
}
|
||||
|
||||
.card-footer .btn {
|
||||
|
@@ -74,11 +74,12 @@ export class DocumentCardSmallComponent extends ComponentWithPermissions {
|
||||
}
|
||||
|
||||
getTagsLimited$() {
|
||||
const limit = this.document.n_comments > 0 ? 6 : 7
|
||||
return this.document.tags$.pipe(
|
||||
map((tags) => {
|
||||
if (tags.length > 7) {
|
||||
this.moreTags = tags.length - 6
|
||||
return tags.slice(0, 6)
|
||||
if (tags.length > limit) {
|
||||
this.moreTags = tags.length - (limit - 1)
|
||||
return tags.slice(0, limit - 1)
|
||||
} else {
|
||||
return tags
|
||||
}
|
||||
|
@@ -54,5 +54,7 @@ export interface PaperlessDocument extends ObjectWithPermissions {
|
||||
|
||||
archive_serial_number?: number
|
||||
|
||||
n_comments?: number
|
||||
|
||||
__search_hit__?: SearchHit
|
||||
}
|
||||
|
@@ -35,15 +35,16 @@ export class OpenDocumentsService {
|
||||
refreshDocument(id: number) {
|
||||
let index = this.openDocuments.findIndex((doc) => doc.id == id)
|
||||
if (index > -1) {
|
||||
this.documentService.get(id).subscribe(
|
||||
(doc) => {
|
||||
this.documentService.get(id).subscribe({
|
||||
next: (doc) => {
|
||||
this.openDocuments[index] = doc
|
||||
this.save()
|
||||
},
|
||||
(error) => {
|
||||
error: () => {
|
||||
this.openDocuments.splice(index, 1)
|
||||
this.save()
|
||||
}
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,10 +2,8 @@ import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { Observable } from 'rxjs'
|
||||
import { map, publishReplay, refCount } from 'rxjs/operators'
|
||||
import { ObjectWithId } from 'src/app/data/object-with-id'
|
||||
import { PaperlessUser } from 'src/app/data/paperless-user'
|
||||
import { Results } from 'src/app/data/results'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { PermissionAction, PermissionType } from '../permissions.service'
|
||||
|
||||
export abstract class AbstractPaperlessService<T extends ObjectWithId> {
|
||||
protected baseUrl: string = environment.apiBaseUrl
|
||||
|
@@ -133,6 +133,10 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt
|
||||
filter: brightness(.8);
|
||||
}
|
||||
|
||||
.badge.bg-light.border {
|
||||
border-color: rgba(0,0,0,0) !important;
|
||||
}
|
||||
|
||||
.doc-img {
|
||||
mix-blend-mode: normal;
|
||||
border-radius: 0;
|
||||
|
Reference in New Issue
Block a user