+
Documents
+
+
+ Items per page
+
+
+
+
+
+
+
Document editing
-
+
-
Global search
-
-
-
- Full search links to
-
-
-
+
+
Built-in fields to show:
+ @for (option of documentDetailFieldOptions; track option.id) {
+
+
+
+
+ }
+
Uncheck fields to hide them on the document details page.
-
+
+
-
diff --git a/src-ui/src/app/components/admin/settings/settings.component.spec.ts b/src-ui/src/app/components/admin/settings/settings.component.spec.ts
index 650d6d8ea..62a5aa363 100644
--- a/src-ui/src/app/components/admin/settings/settings.component.spec.ts
+++ b/src-ui/src/app/components/admin/settings/settings.component.spec.ts
@@ -201,9 +201,9 @@ describe('SettingsComponent', () => {
const navigateSpy = jest.spyOn(router, 'navigate')
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
tabButtons[1].nativeElement.dispatchEvent(new MouseEvent('click'))
- expect(navigateSpy).toHaveBeenCalledWith(['settings', 'permissions'])
+ expect(navigateSpy).toHaveBeenCalledWith(['settings', 'documents'])
tabButtons[2].nativeElement.dispatchEvent(new MouseEvent('click'))
- expect(navigateSpy).toHaveBeenCalledWith(['settings', 'notifications'])
+ expect(navigateSpy).toHaveBeenCalledWith(['settings', 'permissions'])
const initSpy = jest.spyOn(component, 'initialize')
component.isDirty = true // mock dirty
@@ -213,8 +213,8 @@ describe('SettingsComponent', () => {
expect(initSpy).not.toHaveBeenCalled()
navigateSpy.mockResolvedValueOnce(true) // nav accepted even though dirty
- tabButtons[1].nativeElement.dispatchEvent(new MouseEvent('click'))
- expect(navigateSpy).toHaveBeenCalledWith(['settings', 'notifications'])
+ tabButtons[2].nativeElement.dispatchEvent(new MouseEvent('click'))
+ expect(navigateSpy).toHaveBeenCalledWith(['settings', 'permissions'])
expect(initSpy).toHaveBeenCalled()
})
@@ -226,7 +226,7 @@ describe('SettingsComponent', () => {
activatedRoute.snapshot.fragment = '#notifications'
const scrollSpy = jest.spyOn(viewportScroller, 'scrollToAnchor')
component.ngOnInit()
- expect(component.activeNavID).toEqual(3) // Notifications
+ expect(component.activeNavID).toEqual(4) // Notifications
component.ngAfterViewInit()
expect(scrollSpy).toHaveBeenCalledWith('#notifications')
})
@@ -251,7 +251,7 @@ describe('SettingsComponent', () => {
expect(toastErrorSpy).toHaveBeenCalled()
expect(storeSpy).toHaveBeenCalled()
expect(appearanceSettingsSpy).not.toHaveBeenCalled()
- expect(setSpy).toHaveBeenCalledTimes(30)
+ expect(setSpy).toHaveBeenCalledTimes(31)
// succeed
storeSpy.mockReturnValueOnce(of(true))
@@ -366,4 +366,22 @@ describe('SettingsComponent', () => {
settingsService.settingsSaved.emit(true)
expect(maybeRefreshSpy).toHaveBeenCalled()
})
+
+ it('should support toggling document detail fields', () => {
+ completeSetup()
+ const field = 'storage_path'
+ expect(
+ component.settingsForm.get('documentDetailsHiddenFields').value.length
+ ).toEqual(0)
+ component.toggleDocumentDetailField(field, false)
+ expect(
+ component.settingsForm.get('documentDetailsHiddenFields').value.length
+ ).toEqual(1)
+ expect(component.isDocumentDetailFieldShown(field)).toBeFalsy()
+ component.toggleDocumentDetailField(field, true)
+ expect(
+ component.settingsForm.get('documentDetailsHiddenFields').value.length
+ ).toEqual(0)
+ expect(component.isDocumentDetailFieldShown(field)).toBeTruthy()
+ })
})
diff --git a/src-ui/src/app/components/admin/settings/settings.component.ts b/src-ui/src/app/components/admin/settings/settings.component.ts
index 614d2fcd0..990944ff6 100644
--- a/src-ui/src/app/components/admin/settings/settings.component.ts
+++ b/src-ui/src/app/components/admin/settings/settings.component.ts
@@ -70,9 +70,9 @@ import { ComponentWithPermissions } from '../../with-permissions/with-permission
enum SettingsNavIDs {
General = 1,
- Permissions = 2,
- Notifications = 3,
- SavedViews = 4,
+ Documents = 2,
+ Permissions = 3,
+ Notifications = 4,
}
const systemLanguage = { code: '', name: $localize`Use system language` }
@@ -81,6 +81,25 @@ const systemDateFormat = {
name: $localize`Use date format of display language`,
}
+export enum DocumentDetailFieldID {
+ ArchiveSerialNumber = 'archive_serial_number',
+ Correspondent = 'correspondent',
+ DocumentType = 'document_type',
+ StoragePath = 'storage_path',
+ Tags = 'tags',
+}
+
+const documentDetailFieldOptions = [
+ {
+ id: DocumentDetailFieldID.ArchiveSerialNumber,
+ label: $localize`Archive serial number`,
+ },
+ { id: DocumentDetailFieldID.Correspondent, label: $localize`Correspondent` },
+ { id: DocumentDetailFieldID.DocumentType, label: $localize`Document type` },
+ { id: DocumentDetailFieldID.StoragePath, label: $localize`Storage path` },
+ { id: DocumentDetailFieldID.Tags, label: $localize`Tags` },
+]
+
@Component({
selector: 'pngx-settings',
templateUrl: './settings.component.html',
@@ -146,6 +165,7 @@ export class SettingsComponent
pdfViewerDefaultZoom: new FormControl(null),
documentEditingRemoveInboxTags: new FormControl(null),
documentEditingOverlayThumbnail: new FormControl(null),
+ documentDetailsHiddenFields: new FormControl([]),
searchDbOnly: new FormControl(null),
searchLink: new FormControl(null),
@@ -176,6 +196,8 @@ export class SettingsComponent
public readonly ZoomSetting = ZoomSetting
+ public readonly documentDetailFieldOptions = documentDetailFieldOptions
+
get systemStatusHasErrors(): boolean {
return (
this.systemStatus.database.status === SystemStatusItemStatus.ERROR ||
@@ -336,6 +358,9 @@ export class SettingsComponent
documentEditingOverlayThumbnail: this.settings.get(
SETTINGS_KEYS.DOCUMENT_EDITING_OVERLAY_THUMBNAIL
),
+ documentDetailsHiddenFields: this.settings.get(
+ SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS
+ ),
searchDbOnly: this.settings.get(SETTINGS_KEYS.SEARCH_DB_ONLY),
searchLink: this.settings.get(SETTINGS_KEYS.SEARCH_FULL_TYPE),
}
@@ -526,6 +551,10 @@ export class SettingsComponent
SETTINGS_KEYS.DOCUMENT_EDITING_OVERLAY_THUMBNAIL,
this.settingsForm.value.documentEditingOverlayThumbnail
)
+ this.settings.set(
+ SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS,
+ this.settingsForm.value.documentDetailsHiddenFields
+ )
this.settings.set(
SETTINGS_KEYS.SEARCH_DB_ONLY,
this.settingsForm.value.searchDbOnly
@@ -587,6 +616,26 @@ export class SettingsComponent
this.settingsForm.get('themeColor').patchValue('')
}
+ isDocumentDetailFieldShown(fieldId: string): boolean {
+ const hiddenFields =
+ this.settingsForm.value.documentDetailsHiddenFields || []
+ return !hiddenFields.includes(fieldId)
+ }
+
+ toggleDocumentDetailField(fieldId: string, checked: boolean) {
+ const hiddenFields = new Set(
+ this.settingsForm.value.documentDetailsHiddenFields || []
+ )
+ if (checked) {
+ hiddenFields.delete(fieldId)
+ } else {
+ hiddenFields.add(fieldId)
+ }
+ this.settingsForm
+ .get('documentDetailsHiddenFields')
+ .setValue(Array.from(hiddenFields))
+ }
+
showSystemStatus() {
const modal: NgbModalRef = this.modalService.open(
SystemStatusDialogComponent,
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.html b/src-ui/src/app/components/document-detail/document-detail.component.html
index 5ca002479..306152cc4 100644
--- a/src-ui/src/app/components/document-detail/document-detail.component.html
+++ b/src-ui/src/app/components/document-detail/document-detail.component.html
@@ -146,16 +146,26 @@
-
+ @if (!isFieldHidden(DocumentDetailFieldID.ArchiveSerialNumber)) {
+
+ }
-
-
-
-
+ @if (!isFieldHidden(DocumentDetailFieldID.Correspondent)) {
+
+ }
+ @if (!isFieldHidden(DocumentDetailFieldID.DocumentType)) {
+
+ }
+ @if (!isFieldHidden(DocumentDetailFieldID.StoragePath)) {
+
+ }
+ @if (!isFieldHidden(DocumentDetailFieldID.Tags)) {
+
+ }
@for (fieldInstance of document?.custom_fields; track fieldInstance.field; let i = $index) {
@switch (getCustomFieldFromInstance(fieldInstance)?.data_type) {
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts
index d1d10c985..809478816 100644
--- a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts
+++ b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts
@@ -48,6 +48,7 @@ import {
} from 'src/app/data/filter-rule-type'
import { StoragePath } from 'src/app/data/storage-path'
import { Tag } from 'src/app/data/tag'
+import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
@@ -1015,7 +1016,7 @@ describe('DocumentDetailComponent', () => {
it('should display built-in pdf viewer if not disabled', () => {
initNormally()
component.document.archived_file_name = 'file.pdf'
- jest.spyOn(settingsService, 'get').mockReturnValue(false)
+ settingsService.set(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, false)
expect(component.useNativePdfViewer).toBeFalsy()
fixture.detectChanges()
expect(fixture.debugElement.query(By.css('pdf-viewer'))).not.toBeNull()
@@ -1024,7 +1025,7 @@ describe('DocumentDetailComponent', () => {
it('should display native pdf viewer if enabled', () => {
initNormally()
component.document.archived_file_name = 'file.pdf'
- jest.spyOn(settingsService, 'get').mockReturnValue(true)
+ settingsService.set(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, true)
expect(component.useNativePdfViewer).toBeTruthy()
fixture.detectChanges()
expect(fixture.debugElement.query(By.css('object'))).not.toBeNull()
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts
index 917597ef6..8c22f53c2 100644
--- a/src-ui/src/app/components/document-detail/document-detail.component.ts
+++ b/src-ui/src/app/components/document-detail/document-detail.component.ts
@@ -84,6 +84,7 @@ import { ToastService } from 'src/app/services/toast.service'
import { getFilenameFromContentDisposition } from 'src/app/utils/http'
import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'
import * as UTIF from 'utif'
+import { DocumentDetailFieldID } from '../admin/settings/settings.component'
import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'
import { PasswordRemovalConfirmDialogComponent } from '../common/confirm-dialog/password-removal-confirm-dialog/password-removal-confirm-dialog.component'
import { CustomFieldsDropdownComponent } from '../common/custom-fields-dropdown/custom-fields-dropdown.component'
@@ -281,6 +282,8 @@ export class DocumentDetailComponent
public readonly DataType = DataType
+ public readonly DocumentDetailFieldID = DocumentDetailFieldID
+
@ViewChild('nav') nav: NgbNav
@ViewChild('pdfPreview') set pdfPreview(element) {
// this gets called when component added or removed from DOM
@@ -327,6 +330,12 @@ export class DocumentDetailComponent
return this.settings.get(SETTINGS_KEYS.DOCUMENT_EDITING_OVERLAY_THUMBNAIL)
}
+ isFieldHidden(fieldId: DocumentDetailFieldID): boolean {
+ return this.settings
+ .get(SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS)
+ .includes(fieldId)
+ }
+
private getRenderType(mimeType: string): ContentRenderType {
if (!mimeType) return ContentRenderType.Unknown
if (mimeType === 'application/pdf') {
diff --git a/src-ui/src/app/data/ui-settings.ts b/src-ui/src/app/data/ui-settings.ts
index e797fe9b3..827a1b82d 100644
--- a/src-ui/src/app/data/ui-settings.ts
+++ b/src-ui/src/app/data/ui-settings.ts
@@ -70,6 +70,8 @@ export const SETTINGS_KEYS = {
'general-settings:document-editing:remove-inbox-tags',
DOCUMENT_EDITING_OVERLAY_THUMBNAIL:
'general-settings:document-editing:overlay-thumbnail',
+ DOCUMENT_DETAILS_HIDDEN_FIELDS:
+ 'general-settings:document-details:hidden-fields',
SEARCH_DB_ONLY: 'general-settings:search:db-only',
SEARCH_FULL_TYPE: 'general-settings:search:more-link',
EMPTY_TRASH_DELAY: 'trash_delay',
@@ -255,6 +257,11 @@ export const SETTINGS: UiSetting[] = [
type: 'boolean',
default: true,
},
+ {
+ key: SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS,
+ type: 'array',
+ default: [],
+ },
{
key: SETTINGS_KEYS.SEARCH_DB_ONLY,
type: 'boolean',