mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge pull request #1375 from tim-vogel/add_comments
Feature: document comments
This commit is contained in:
@@ -67,6 +67,7 @@ import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'
|
||||
import { ColorSliderModule } from 'ngx-color/slider'
|
||||
import { ColorComponent } from './components/common/input/color/color.component'
|
||||
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
|
||||
import { DocumentCommentsComponent } from './components/document-comments/document-comments.component'
|
||||
import { DirtyDocGuard } from './guards/dirty-doc.guard'
|
||||
|
||||
import localeBe from '@angular/common/locales/be'
|
||||
@@ -173,6 +174,7 @@ function initializeApp(settings: SettingsService) {
|
||||
DateComponent,
|
||||
ColorComponent,
|
||||
DocumentAsnComponent,
|
||||
DocumentCommentsComponent,
|
||||
TasksComponent,
|
||||
],
|
||||
imports: [
|
||||
|
@@ -0,0 +1,27 @@
|
||||
<div *ngIf="comments">
|
||||
<form [formGroup]="commentForm" class="needs-validation mt-3" novalidate>
|
||||
<div class="form-group">
|
||||
<textarea class="form-control form-control-sm" [class.is-invalid]="newCommentError" rows="3" formControlName="newComment" placeholder="Enter comment" i18n-placeholder required></textarea>
|
||||
<div class="invalid-feedback" i18n>
|
||||
Please enter a comment.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mt-2 d-flex justify-content-end">
|
||||
<button type="button" class="btn btn-primary btn-sm" [disabled]="networkActive" (click)="addComment()" i18n>Add comment</button>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div *ngFor="let comment of comments" class="card border mb-3">
|
||||
<div class="card-body text-dark">
|
||||
<p class="card-text">{{comment.comment}}</p>
|
||||
</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)">
|
||||
<svg width="13" height="13" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,9 @@
|
||||
.card-body {
|
||||
max-height: 12rem;
|
||||
overflow: scroll;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.card:hover .fade {
|
||||
opacity: 1;
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
import { Component, Input, OnInit } 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'
|
||||
import { first } from 'rxjs/operators'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-document-comments',
|
||||
templateUrl: './document-comments.component.html',
|
||||
styleUrls: ['./document-comments.component.scss'],
|
||||
})
|
||||
export class DocumentCommentsComponent implements OnInit {
|
||||
commentForm: FormGroup = new FormGroup({
|
||||
newComment: new FormControl(''),
|
||||
})
|
||||
|
||||
networkActive = false
|
||||
comments: PaperlessDocumentComment[] = []
|
||||
newCommentError: boolean = false
|
||||
|
||||
@Input()
|
||||
documentId: number
|
||||
|
||||
constructor(
|
||||
private commentsService: DocumentCommentsService,
|
||||
private toastService: ToastService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.commentsService
|
||||
.getComments(this.documentId)
|
||||
.pipe(first())
|
||||
.subscribe((comments) => (this.comments = comments))
|
||||
}
|
||||
|
||||
addComment() {
|
||||
const comment: string = this.commentForm
|
||||
.get('newComment')
|
||||
.value.toString()
|
||||
.trim()
|
||||
if (comment.length == 0) {
|
||||
this.newCommentError = true
|
||||
return
|
||||
}
|
||||
this.newCommentError = false
|
||||
this.networkActive = true
|
||||
this.commentsService.addComment(this.documentId, comment).subscribe({
|
||||
next: (result) => {
|
||||
this.comments = result
|
||||
this.commentForm.get('newComment').reset()
|
||||
this.networkActive = false
|
||||
},
|
||||
error: (e) => {
|
||||
this.networkActive = false
|
||||
this.toastService.showError(
|
||||
$localize`Error saving comment: ${e.toString()}`
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
deleteComment(commentId: number) {
|
||||
this.commentsService.deleteComment(this.documentId, commentId).subscribe({
|
||||
next: (result) => {
|
||||
this.comments = result
|
||||
this.networkActive = false
|
||||
},
|
||||
error: (e) => {
|
||||
this.networkActive = false
|
||||
this.toastService.showError(
|
||||
$localize`Error deleting comment: ${e.toString()}`
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
displayName(comment: PaperlessDocumentComment): string {
|
||||
if (!comment.user) return ''
|
||||
let nameComponents = []
|
||||
if (comment.user.firstname) nameComponents.unshift(comment.user.firstname)
|
||||
if (comment.user.lastname) nameComponents.unshift(comment.user.lastname)
|
||||
if (comment.user.username) {
|
||||
if (nameComponents.length > 0)
|
||||
nameComponents.push(`(${comment.user.username})`)
|
||||
else nameComponents.push(comment.user.username)
|
||||
}
|
||||
return nameComponents.join(' ')
|
||||
}
|
||||
}
|
@@ -170,6 +170,12 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="5" *ngIf="commentsEnabled">
|
||||
<a ngbNavLink i18n>Comments</a>
|
||||
<ng-template ngbNavContent>
|
||||
<app-document-comments [documentId]="documentId"></app-document-comments>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
|
@@ -551,4 +551,8 @@ export class DocumentDetailComponent
|
||||
this.password = (event.target as HTMLInputElement).value
|
||||
}
|
||||
}
|
||||
|
||||
get commentsEnabled(): boolean {
|
||||
return this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED)
|
||||
}
|
||||
}
|
||||
|
@@ -125,6 +125,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mt-4" i18n>Comments</h4>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="offset-md-3 col">
|
||||
<app-input-check i18n-title title="Enable comments" formControlName="commentsEnabled"></app-input-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
|
@@ -44,6 +44,7 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
notificationsConsumerSuccess: new FormControl(null),
|
||||
notificationsConsumerFailed: new FormControl(null),
|
||||
notificationsConsumerSuppressOnDashboard: new FormControl(null),
|
||||
commentsEnabled: new FormControl(null),
|
||||
})
|
||||
|
||||
savedViews: PaperlessSavedView[]
|
||||
@@ -116,6 +117,7 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
notificationsConsumerSuppressOnDashboard: this.settings.get(
|
||||
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD
|
||||
),
|
||||
commentsEnabled: this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED),
|
||||
}
|
||||
|
||||
for (let view of this.savedViews) {
|
||||
@@ -234,6 +236,10 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD,
|
||||
this.settingsForm.value.notificationsConsumerSuppressOnDashboard
|
||||
)
|
||||
this.settings.set(
|
||||
SETTINGS_KEYS.COMMENTS_ENABLED,
|
||||
this.settingsForm.value.commentsEnabled
|
||||
)
|
||||
this.settings.setLanguage(this.settingsForm.value.displayLanguage)
|
||||
this.settings
|
||||
.storeSettings()
|
||||
|
8
src-ui/src/app/data/paperless-document-comment.ts
Normal file
8
src-ui/src/app/data/paperless-document-comment.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { ObjectWithId } from './object-with-id'
|
||||
import { User } from './user'
|
||||
|
||||
export interface PaperlessDocumentComment extends ObjectWithId {
|
||||
created?: Date
|
||||
comment?: string
|
||||
user?: User
|
||||
}
|
@@ -36,6 +36,7 @@ export const SETTINGS_KEYS = {
|
||||
'general-settings:notifications:consumer-failed',
|
||||
NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD:
|
||||
'general-settings:notifications:consumer-suppress-on-dashboard',
|
||||
COMMENTS_ENABLED: 'general-settings:comments-enabled',
|
||||
}
|
||||
|
||||
export const SETTINGS: PaperlessUiSetting[] = [
|
||||
@@ -114,4 +115,9 @@ export const SETTINGS: PaperlessUiSetting[] = [
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.COMMENTS_ENABLED,
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
]
|
||||
|
7
src-ui/src/app/data/user.ts
Normal file
7
src-ui/src/app/data/user.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ObjectWithId } from './object-with-id'
|
||||
|
||||
export interface User extends ObjectWithId {
|
||||
username: string
|
||||
firstname: string
|
||||
lastname: string
|
||||
}
|
37
src-ui/src/app/services/rest/document-comments.service.ts
Normal file
37
src-ui/src/app/services/rest/document-comments.service.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { PaperlessDocumentComment } from 'src/app/data/paperless-document-comment'
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service'
|
||||
import { Observable } from 'rxjs'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DocumentCommentsService extends AbstractPaperlessService<PaperlessDocumentComment> {
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'documents')
|
||||
}
|
||||
|
||||
getComments(documentId: number): Observable<PaperlessDocumentComment[]> {
|
||||
return this.http.get<PaperlessDocumentComment[]>(
|
||||
this.getResourceUrl(documentId, 'comments')
|
||||
)
|
||||
}
|
||||
|
||||
addComment(id: number, comment): Observable<PaperlessDocumentComment[]> {
|
||||
return this.http.post<PaperlessDocumentComment[]>(
|
||||
this.getResourceUrl(id, 'comments'),
|
||||
{ comment: comment }
|
||||
)
|
||||
}
|
||||
|
||||
deleteComment(
|
||||
documentId: number,
|
||||
commentId: number
|
||||
): Observable<PaperlessDocumentComment[]> {
|
||||
return this.http.delete<PaperlessDocumentComment[]>(
|
||||
this.getResourceUrl(documentId, 'comments'),
|
||||
{ params: new HttpParams({ fromString: `id=${commentId}` }) }
|
||||
)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user