Merge pull request #1375 from tim-vogel/add_comments

Feature: document comments
This commit is contained in:
shamoon
2022-08-25 11:48:31 -07:00
committed by GitHub
23 changed files with 686 additions and 34 deletions

View File

@@ -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: [

View File

@@ -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>

View File

@@ -0,0 +1,9 @@
.card-body {
max-height: 12rem;
overflow: scroll;
white-space: pre-wrap;
}
.card:hover .fade {
opacity: 1;
}

View File

@@ -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(' ')
}
}

View File

@@ -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>

View File

@@ -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)
}
}

View File

@@ -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>

View File

@@ -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()

View 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
}

View File

@@ -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,
},
]

View File

@@ -0,0 +1,7 @@
import { ObjectWithId } from './object-with-id'
export interface User extends ObjectWithId {
username: string
firstname: string
lastname: string
}

View 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}` }) }
)
}
}