@for (column of savedView.dashboard_view_table_columns; track column; let i = $index) {
- @if (columnIsVisible(column)) {
+ @if (visibleColumns.includes(column)) {
1 }">
@switch (column) {
@case (DashboardViewTableColumn.ADDED) {
@@ -64,6 +64,31 @@
}
}
}
+ @if (column.startsWith(DashboardViewTableColumn.CUSTOM_FIELD)) {
+ @switch(getCustomFieldDataType(column)) {
+ @case (CustomFieldDataType.Monetary) {
+ {{ getMonetaryCustomFieldValue(doc, column)[0] | currency: getMonetaryCustomFieldValue(doc, column)[1] }}
+ }
+ @case (CustomFieldDataType.Date) {
+ {{ getCustomFieldValue(doc, column) | customDate }}
+ }
+ @case (CustomFieldDataType.Url) {
+ {{ getCustomFieldValue(doc, column) }}
+ }
+ @case (CustomFieldDataType.DocumentLink) {
+
+ }
+ @default {
+ {{ getCustomFieldValue(doc, column) }}
+ }
+ }
+ }
@if (i === savedView.dashboard_view_table_columns.length - 1) {
{
},
CustomDatePipe,
DatePipe,
+ {
+ provide: CustomFieldsService,
+ useValue: {
+ listAll: () =>
+ of({
+ all: [3, 11, 15],
+ count: 3,
+ results: [
+ {
+ id: 3,
+ name: 'Custom field 3',
+ data_type: CustomFieldDataType.Monetary,
+ },
+ {
+ id: 11,
+ name: 'Custom Field 11',
+ data_type: CustomFieldDataType.String,
+ },
+ {
+ id: 15,
+ name: 'Custom Field 15',
+ data_type: CustomFieldDataType.DocumentLink,
+ },
+ ],
+ }),
+ },
+ },
],
imports: [
HttpClientTestingModule,
@@ -289,52 +346,97 @@ describe('SavedViewWidgetComponent', () => {
it('should check if column is visible including permissions', () => {
expect(
- component.columnIsVisible(DashboardViewTableColumn.TITLE)
+ component.visibleColumns.includes(DashboardViewTableColumn.TITLE)
).toBeTruthy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.CREATED)
+ component.visibleColumns.includes(DashboardViewTableColumn.CREATED)
).toBeTruthy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.ADDED)
+ component.visibleColumns.includes(DashboardViewTableColumn.ADDED)
).toBeTruthy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.TAGS)
+ component.visibleColumns.includes(DashboardViewTableColumn.TAGS)
).toBeTruthy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.CORRESPONDENT)
+ component.visibleColumns.includes(DashboardViewTableColumn.CORRESPONDENT)
).toBeTruthy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.DOCUMENT_TYPE)
+ component.visibleColumns.includes(DashboardViewTableColumn.DOCUMENT_TYPE)
).toBeTruthy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.STORAGE_PATH)
+ component.visibleColumns.includes(DashboardViewTableColumn.STORAGE_PATH)
+ ).toBeTruthy()
+ expect(
+ component.visibleColumns.includes(
+ `${DashboardViewTableColumn.CUSTOM_FIELD}11` as any
+ )
).toBeTruthy()
+ component.visibleColumns = []
jest
.spyOn(component.permissionsService, 'currentUserCan')
.mockReturnValue(false)
+ component.ngOnInit()
expect(
- component.columnIsVisible(DashboardViewTableColumn.TITLE)
- ).toBeTruthy()
- expect(
- component.columnIsVisible(DashboardViewTableColumn.CREATED)
- ).toBeTruthy()
- expect(
- component.columnIsVisible(DashboardViewTableColumn.ADDED)
- ).toBeTruthy()
- expect(component.columnIsVisible(DashboardViewTableColumn.TAGS)).toBeFalsy()
- expect(
- component.columnIsVisible(DashboardViewTableColumn.CORRESPONDENT)
+ component.visibleColumns.includes(DashboardViewTableColumn.TAGS)
).toBeFalsy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.DOCUMENT_TYPE)
+ component.visibleColumns.includes(DashboardViewTableColumn.CORRESPONDENT)
).toBeFalsy()
expect(
- component.columnIsVisible(DashboardViewTableColumn.STORAGE_PATH)
+ component.visibleColumns.includes(DashboardViewTableColumn.DOCUMENT_TYPE)
).toBeFalsy()
+ expect(
+ component.visibleColumns.includes(DashboardViewTableColumn.STORAGE_PATH)
+ ).toBeFalsy()
+ expect(
+ component.visibleColumns.includes(
+ `${DashboardViewTableColumn.CUSTOM_FIELD}11` as any
+ )
+ ).toBeFalsy()
+ })
+ it('should display monetary custom field value', () => {
expect(
- component.columnIsVisible('unknown' as DashboardViewTableColumn)
- ).toBeFalsy() // coverage
+ component.getMonetaryCustomFieldValue(
+ documentResults[2],
+ `${DashboardViewTableColumn.CUSTOM_FIELD}3`
+ )
+ ).toEqual([123, 'EUR'])
+ expect(
+ component.getMonetaryCustomFieldValue(
+ documentResults[0],
+ `${DashboardViewTableColumn.CUSTOM_FIELD}999`
+ )
+ ).toEqual([null, null])
+ })
+
+ it('should retrieve documents for document link columns', () => {
+ const listAllSpy = jest.spyOn(documentService, 'listAll')
+ listAllSpy.mockReturnValue(
+ of({
+ all: [123, 456, 789],
+ count: 3,
+ results: [
+ { id: 123, title: 'doc123' },
+ { id: 456, title: 'doc456' },
+ { id: 789, title: 'doc789' },
+ ],
+ })
+ )
+ jest.spyOn(documentService, 'listFiltered').mockReturnValue(
+ of({
+ all: [4, 5],
+ count: 2,
+ results: [documentResults[2], documentResults[3]],
+ })
+ )
+ component.ngOnInit()
+ expect(listAllSpy).toHaveBeenCalledWith(null, false, {
+ id__in: '123,456,789',
+ })
+ fixture.detectChanges()
+ expect(fixture.debugElement.nativeElement.textContent).toContain('doc123')
+ component.maybeGetDocuments() // coverage
})
})
diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts
index 6496698dd..8fc14f1d5 100644
--- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts
+++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts
@@ -32,6 +32,9 @@ import {
PermissionType,
PermissionsService,
} from 'src/app/services/permissions.service'
+import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
+import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
+import { Results } from 'src/app/data/results'
@Component({
selector: 'pngx-saved-view-widget',
@@ -44,9 +47,12 @@ export class SavedViewWidgetComponent
{
public DashboardViewMode = DashboardViewMode
public DashboardViewTableColumn = DashboardViewTableColumn
+ public CustomFieldDataType = CustomFieldDataType
loading: boolean = true
+ private customFields: CustomField[] = []
+
constructor(
private documentService: DocumentService,
private router: Router,
@@ -54,7 +60,8 @@ export class SavedViewWidgetComponent
private consumerStatusService: ConsumerStatusService,
public openDocumentsService: OpenDocumentsService,
public documentListViewService: DocumentListViewService,
- public permissionsService: PermissionsService
+ public permissionsService: PermissionsService,
+ private customFieldService: CustomFieldsService
) {
super()
}
@@ -72,6 +79,14 @@ export class SavedViewWidgetComponent
mouseOnPreview = false
popoverHidden = true
+ visibleColumns: DashboardViewTableColumn[] = [
+ DashboardViewTableColumn.TITLE,
+ DashboardViewTableColumn.CREATED,
+ DashboardViewTableColumn.ADDED,
+ ]
+
+ docLinkDocuments: Document[] = []
+
ngOnInit(): void {
this.reload()
this.consumerStatusService
@@ -80,6 +95,35 @@ export class SavedViewWidgetComponent
.subscribe(() => {
this.reload()
})
+
+ if (
+ this.permissionsService.currentUserCan(
+ PermissionAction.View,
+ PermissionType.CustomField
+ )
+ ) {
+ this.customFieldService
+ .listAll()
+ .pipe(takeUntil(this.unsubscribeNotifier))
+ .subscribe((customFields) => {
+ this.customFields = customFields.results
+ this.maybeGetDocuments()
+ })
+ }
+
+ this.savedView.dashboard_view_table_columns?.forEach((column) => {
+ let type: PermissionType = Object.values(PermissionType).find((t) =>
+ t.includes(column)
+ )
+ if (column.startsWith(DashboardViewTableColumn.CUSTOM_FIELD)) {
+ type = PermissionType.CustomField
+ }
+ if (
+ type &&
+ this.permissionsService.currentUserCan(PermissionAction.View, type)
+ )
+ this.visibleColumns.push(column)
+ })
}
ngOnDestroy(): void {
@@ -102,6 +146,7 @@ export class SavedViewWidgetComponent
.subscribe((result) => {
this.loading = false
this.documents = result.results
+ this.maybeGetDocuments()
})
}
@@ -204,26 +249,73 @@ export class SavedViewWidgetComponent
}, 300)
}
- public columnIsVisible(column: DashboardViewTableColumn): boolean {
- if (
- [
- DashboardViewTableColumn.TITLE,
- DashboardViewTableColumn.CREATED,
- DashboardViewTableColumn.ADDED,
- ].includes(column)
- ) {
- return true
- } else {
- const type: PermissionType = Object.values(PermissionType).find((t) =>
- t.includes(column)
+ public getColumnTitle(column: DashboardViewTableColumn): string {
+ if (column.startsWith(DashboardViewTableColumn.CUSTOM_FIELD)) {
+ const id = column.split('_')[2]
+ return this.customFields.find((c) => c.id === parseInt(id))?.name
+ }
+ return DASHBOARD_VIEW_TABLE_COLUMNS.find((c) => c.id === column)?.name
+ }
+
+ public getCustomFieldDataType(column_id: string): string {
+ const customFieldId = parseInt(column_id.split('_')[2])
+ return this.customFields.find((cf) => cf.id === customFieldId)?.data_type
+ }
+
+ public getCustomFieldValue(document: Document, column_id: string): any {
+ const customFieldId = parseInt(column_id.split('_')[2])
+ return document.custom_fields.find((cf) => cf.field === customFieldId)
+ ?.value
+ }
+
+ public getMonetaryCustomFieldValue(
+ document: Document,
+ column_id: string
+ ): Array {
+ const value = this.getCustomFieldValue(document, column_id)
+ if (!value) return [null, null]
+ const currencyCode = value.match(/[A-Z]{3}/)?.[0]
+ const amount = parseFloat(value.replace(currencyCode, ''))
+ return [amount, currencyCode]
+ }
+
+ maybeGetDocuments() {
+ // retrieve documents for document link columns
+ if (this.docLinkDocuments.length) return
+ let docIds = []
+ let docLinkColumns = []
+ this.savedView.dashboard_view_table_columns
+ ?.filter((column) =>
+ column.startsWith(DashboardViewTableColumn.CUSTOM_FIELD)
)
- return type
- ? this.permissionsService.currentUserCan(PermissionAction.View, type)
- : false
+ .forEach((column) => {
+ if (
+ this.getCustomFieldDataType(column) ===
+ CustomFieldDataType.DocumentLink
+ ) {
+ docLinkColumns.push(column)
+ }
+ })
+ this.documents.forEach((doc) => {
+ docLinkColumns.forEach((column) => {
+ const docs: number[] = this.getCustomFieldValue(doc, column)
+ if (docs) {
+ docIds = docIds.concat(docs)
+ }
+ })
+ })
+
+ if (docIds.length) {
+ this.documentService
+ .listAll(null, false, { id__in: docIds.join(',') })
+ .pipe(takeUntil(this.unsubscribeNotifier))
+ .subscribe((result: Results) => {
+ this.docLinkDocuments = result.results
+ })
}
}
- public getColumnTitle(column: DashboardViewTableColumn): string {
- return DASHBOARD_VIEW_TABLE_COLUMNS.find((c) => c.id === column)?.name
+ public getDocumentTitle(documentId: number): string {
+ return this.docLinkDocuments.find((doc) => doc.id === documentId)?.title
}
}
diff --git a/src-ui/src/app/data/saved-view.ts b/src-ui/src/app/data/saved-view.ts
index 605b2d934..b2f7f6b25 100644
--- a/src-ui/src/app/data/saved-view.ts
+++ b/src-ui/src/app/data/saved-view.ts
@@ -14,6 +14,7 @@ export enum DashboardViewTableColumn {
CORRESPONDENT = 'correspondent',
DOCUMENT_TYPE = 'documenttype',
STORAGE_PATH = 'storagepath',
+ CUSTOM_FIELD = 'custom_field_',
}
export const DASHBOARD_VIEW_TABLE_COLUMNS = [
diff --git a/src-ui/src/app/services/rest/custom-fields.service.ts b/src-ui/src/app/services/rest/custom-fields.service.ts
index e951e68b0..e4be128aa 100644
--- a/src-ui/src/app/services/rest/custom-fields.service.ts
+++ b/src-ui/src/app/services/rest/custom-fields.service.ts
@@ -1,9 +1,7 @@
import { Injectable } from '@angular/core'
-import { HttpClient, HttpParams } from '@angular/common/http'
+import { HttpClient } from '@angular/common/http'
import { AbstractPaperlessService } from './abstract-paperless-service'
-import { Observable } from 'rxjs'
import { CustomField } from 'src/app/data/custom-field'
-import { CustomFieldInstance } from 'src/app/data/custom-field-instance'
@Injectable({
providedIn: 'root',
|