Feature: customizable fields display for documents, saved views & dashboard widgets (#6439)

This commit is contained in:
shamoon
2024-04-26 06:41:12 -07:00
committed by GitHub
parent 7a0334f353
commit bd4476d484
50 changed files with 2929 additions and 1018 deletions

View File

@@ -18,6 +18,8 @@ describe('ConsumerStatusService', () => {
let httpTestingController: HttpTestingController
let consumerStatusService: ConsumerStatusService
let documentService: DocumentService
let settingsService: SettingsService
const server = new WS(
`${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/`,
{ jsonProtocol: true }
@@ -25,25 +27,17 @@ describe('ConsumerStatusService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
ConsumerStatusService,
DocumentService,
SettingsService,
{
provide: SettingsService,
useValue: {
currentUser: {
id: 1,
username: 'testuser',
is_superuser: false,
},
},
},
],
providers: [ConsumerStatusService, DocumentService, SettingsService],
imports: [HttpClientTestingModule],
})
httpTestingController = TestBed.inject(HttpTestingController)
settingsService = TestBed.inject(SettingsService)
settingsService.currentUser = {
id: 1,
username: 'testuser',
is_superuser: false,
}
consumerStatusService = TestBed.inject(ConsumerStatusService)
documentService = TestBed.inject(DocumentService)
})

View File

@@ -19,6 +19,11 @@ import { routes } from 'src/app/app-routing.module'
import { PermissionsGuard } from '../guards/permissions.guard'
import { SettingsService } from './settings.service'
import { SETTINGS_KEYS } from '../data/ui-settings'
import {
DisplayMode,
DisplayField,
DEFAULT_DISPLAY_FIELDS,
} from '../data/document'
const documents = [
{
@@ -213,7 +218,7 @@ describe('DocumentListViewService', () => {
documentListViewService.loadFromQueryParams(convertToParamMap(params))
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=${page}&page_size=${
documentListViewService.currentPageSize
documentListViewService.pageSize
}&ordering=${reverse ? '-' : ''}${sort}&truncate_content=true`
)
expect(req.request.method).toEqual('GET')
@@ -231,7 +236,7 @@ describe('DocumentListViewService', () => {
}
documentListViewService.loadFromQueryParams(convertToParamMap(params))
let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.currentPageSize}&ordering=-added&truncate_content=true&tags__id__all=${tags__id__all}`
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.pageSize}&ordering=-added&truncate_content=true&tags__id__all=${tags__id__all}`
)
expect(req.request.method).toEqual('GET')
expect(documentListViewService.filterRules).toEqual([
@@ -249,7 +254,7 @@ describe('DocumentListViewService', () => {
it('should use filter rules to update query params', () => {
documentListViewService.filterRules = filterRules
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.currentPageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.pageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
)
expect(req.request.method).toEqual('GET')
})
@@ -257,7 +262,7 @@ describe('DocumentListViewService', () => {
it('should support quick filter', () => {
documentListViewService.quickFilter(filterRules)
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.currentPageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.pageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
)
expect(req.request.method).toEqual('GET')
})
@@ -280,7 +285,7 @@ describe('DocumentListViewService', () => {
convertToParamMap(params)
)
let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=${page}&page_size=${documentListViewService.currentPageSize}&ordering=-added&truncate_content=true&tags__id__all=${tags__id__all}`
`${environment.apiBaseUrl}documents/?page=${page}&page_size=${documentListViewService.pageSize}&ordering=-added&truncate_content=true&tags__id__all=${tags__id__all}`
)
expect(req.request.method).toEqual('GET')
// reset the list
@@ -305,8 +310,7 @@ describe('DocumentListViewService', () => {
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
)
expect(documentListViewService.currentPage).toEqual(1)
documentListViewService.currentPageSize = 3
documentListViewService.reload()
documentListViewService.pageSize = 3
req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=3&ordering=-created&truncate_content=true`
)
@@ -362,7 +366,10 @@ describe('DocumentListViewService', () => {
.spyOn(documentListViewService, 'documents', 'get')
.mockReturnValue(documents)
expect(documentListViewService.currentPage).toEqual(1)
documentListViewService.currentPageSize = 3
documentListViewService.pageSize = 3
httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=1&page_size=3&ordering=-created&truncate_content=true`
)
jest
.spyOn(documentListViewService, 'getLastPage')
.mockReturnValue(Math.ceil(documents.length / 3))
@@ -410,7 +417,13 @@ describe('DocumentListViewService', () => {
.spyOn(documentListViewService, 'documents', 'get')
.mockReturnValue(documents)
documentListViewService.currentPage = 2
documentListViewService.currentPageSize = 3
httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=2&page_size=50&ordering=-created&truncate_content=true`
)
documentListViewService.pageSize = 3
httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=2&page_size=3&ordering=-created&truncate_content=true`
)
const reloadSpy = jest.spyOn(documentListViewService, 'reload')
documentListViewService.getPrevious(1).subscribe({
next: () => {},
@@ -426,8 +439,7 @@ describe('DocumentListViewService', () => {
it('should update page size from settings', () => {
settingsService.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, 10)
documentListViewService.updatePageSize()
expect(documentListViewService.currentPageSize).toEqual(10)
expect(documentListViewService.pageSize).toEqual(10)
})
it('should support select a document', () => {
@@ -459,8 +471,7 @@ describe('DocumentListViewService', () => {
})
it('should support select page', () => {
documentListViewService.currentPageSize = 3
documentListViewService.reload()
documentListViewService.pageSize = 3
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/?page=1&page_size=3&ordering=-created&truncate_content=true`
)
@@ -544,4 +555,40 @@ describe('DocumentListViewService', () => {
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
)
})
it('should update default view state when display mode changes', () => {
const localStorageSpy = jest.spyOn(localStorage, 'setItem')
expect(documentListViewService.displayMode).toEqual(DisplayMode.SMALL_CARDS)
documentListViewService.displayMode = DisplayMode.LARGE_CARDS
expect(documentListViewService.displayMode).toEqual(DisplayMode.LARGE_CARDS)
documentListViewService.displayMode = 'details' as any // legacy
expect(documentListViewService.displayMode).toEqual(DisplayMode.TABLE)
expect(localStorageSpy).toHaveBeenCalledTimes(2)
})
it('should update default view state when display fields change', () => {
const localStorageSpy = jest.spyOn(localStorage, 'setItem')
documentListViewService.displayFields = [
DisplayField.ADDED,
DisplayField.TITLE,
]
expect(documentListViewService.displayFields).toEqual([
DisplayField.ADDED,
DisplayField.TITLE,
])
expect(localStorageSpy).toHaveBeenCalled()
// reload triggered
httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
)
documentListViewService.displayFields = null
httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
)
expect(documentListViewService.displayFields).toEqual(
DEFAULT_DISPLAY_FIELDS.filter((f) => f.id !== DisplayField.ADDED).map(
(f) => f.id
)
)
})
})

View File

@@ -7,16 +7,17 @@ import {
cloneFilterRules,
isFullTextFilterRule,
} from '../utils/filter-rules'
import { Document } from '../data/document'
import {
DEFAULT_DISPLAY_FIELDS,
DisplayField,
DisplayMode,
Document,
} from '../data/document'
import { SavedView } from '../data/saved-view'
import { SETTINGS_KEYS } from '../data/ui-settings'
import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys'
import { paramsFromViewState, paramsToViewState } from '../utils/query-params'
import {
DocumentService,
DOCUMENT_SORT_FIELDS,
SelectionData,
} from './rest/document.service'
import { DocumentService, SelectionData } from './rest/document.service'
import { SettingsService } from './settings.service'
/**
@@ -59,6 +60,21 @@ export interface ListViewState {
* Contains the IDs of all selected documents.
*/
selected?: Set<number>
/**
* The page size of the list view.
*/
pageSize?: number
/**
* Display mode of the list view.
*/
displayMode?: DisplayMode
/**
* The fields to display in the document list.
*/
displayFields?: DisplayField[]
}
/**
@@ -80,8 +96,6 @@ export class DocumentListViewService {
selectionData?: SelectionData
currentPageSize: number = this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)
private unsubscribeNotifier: Subject<any> = new Subject()
private listViewStates: Map<number, ListViewState> = new Map()
@@ -113,7 +127,7 @@ export class DocumentListViewService {
delete savedState[k]
}
})
//only use restored state attributes instead of defaults if they are not null
// only use restored state attributes instead of defaults if they are not null
let newState = Object.assign(this.defaultListViewState(), savedState)
this.listViewStates.set(null, newState)
} catch (e) {
@@ -176,6 +190,9 @@ export class DocumentListViewService {
if (this._activeSavedViewId) {
this.activeListViewState.title = view.name
}
this.activeListViewState.displayMode = view.display_mode
this.activeListViewState.pageSize = view.page_size
this.activeListViewState.displayFields = view.display_fields
this.reduceSelectionToFilter()
@@ -220,7 +237,7 @@ export class DocumentListViewService {
this.documentService
.listFiltered(
activeListViewState.currentPage,
this.currentPageSize,
activeListViewState.pageSize ?? this.pageSize,
activeListViewState.sortField,
activeListViewState.sortReverse,
activeListViewState.filterRules,
@@ -281,9 +298,8 @@ export class DocumentListViewService {
errorMessage = Object.keys(error.error)
.map((fieldName) => {
const fieldError: Array<string> = error.error[fieldName]
return `${DOCUMENT_SORT_FIELDS.find(
(f) => f.field == fieldName
)?.name}: ${fieldError[0]}`
return `${this.sortFields.find((f) => f.field == fieldName)
?.name}: ${fieldError[0]}`
})
.join(', ')
} else {
@@ -312,6 +328,14 @@ export class DocumentListViewService {
return this.activeListViewState.filterRules
}
get sortFields(): any[] {
return this.documentService.sortFields
}
get sortFieldsFullText(): any[] {
return this.documentService.sortFieldsFullText
}
set sortField(field: string) {
this.activeListViewState.sortField = field
this.reload()
@@ -362,6 +386,51 @@ export class DocumentListViewService {
this.saveDocumentListView()
}
set displayMode(mode: DisplayMode) {
this.activeListViewState.displayMode = mode
this.saveDocumentListView()
}
get displayMode(): DisplayMode {
const mode = this.activeListViewState.displayMode ?? DisplayMode.SMALL_CARDS
if (mode === ('details' as any)) {
// legacy
return DisplayMode.TABLE
}
return mode
}
set pageSize(size: number) {
this.activeListViewState.pageSize = size
this.reload()
this.saveDocumentListView()
}
get pageSize(): number {
return (
this.activeListViewState.pageSize ??
this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)
)
}
get displayFields(): DisplayField[] {
let fields =
this.activeListViewState.displayFields ??
DEFAULT_DISPLAY_FIELDS.map((f) => f.id)
if (!this.activeListViewState.displayFields) {
fields = fields.filter((f) => f !== DisplayField.ADDED)
}
return fields.filter(
(field) =>
this.settings.allDisplayFields.find((f) => f.id === field) !== undefined
)
}
set displayFields(fields: DisplayField[]) {
this.activeListViewState.displayFields = fields
this.saveDocumentListView()
}
private saveDocumentListView() {
if (this._activeSavedViewId == null) {
let savedState: ListViewState = {
@@ -370,6 +439,8 @@ export class DocumentListViewService {
filterRules: this.activeListViewState.filterRules,
sortField: this.activeListViewState.sortField,
sortReverse: this.activeListViewState.sortReverse,
displayMode: this.activeListViewState.displayMode,
displayFields: this.activeListViewState.displayFields,
}
localStorage.setItem(
DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG,
@@ -385,7 +456,7 @@ export class DocumentListViewService {
}
getLastPage(): number {
return Math.ceil(this.collectionSize / this.currentPageSize)
return Math.ceil(this.collectionSize / this.pageSize)
}
hasNext(doc: number) {
@@ -452,13 +523,6 @@ export class DocumentListViewService {
})
}
updatePageSize() {
let newPageSize = this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)
if (newPageSize != this.currentPageSize) {
this.currentPageSize = newPageSize
}
}
selectNone() {
this.selected.clear()
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null

View File

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

View File

@@ -9,11 +9,17 @@ import { DocumentService } from './document.service'
import { FILTER_TITLE } from 'src/app/data/filter-rule-type'
import { SettingsService } from '../settings.service'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import {
DOCUMENT_SORT_FIELDS,
DOCUMENT_SORT_FIELDS_FULLTEXT,
} from 'src/app/data/document'
import { PermissionsService } from '../permissions.service'
let httpTestingController: HttpTestingController
let service: DocumentService
let subscription: Subscription
let settingsService: SettingsService
const endpoint = 'documents'
const documents = [
{
@@ -275,6 +281,31 @@ describe(`DocumentService`, () => {
})
})
it('should construct sort fields respecting permissions', () => {
expect(
service.sortFields.find((f) => f.field === 'correspondent__name')
).toBeUndefined()
expect(
service.sortFields.find((f) => f.field === 'document_type__name')
).toBeUndefined()
const permissionsService: PermissionsService =
TestBed.inject(PermissionsService)
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
service['setupSortFields']()
expect(service.sortFields).toEqual(DOCUMENT_SORT_FIELDS)
expect(service.sortFieldsFullText).toEqual([
...DOCUMENT_SORT_FIELDS,
...DOCUMENT_SORT_FIELDS_FULLTEXT,
])
settingsService.set(SETTINGS_KEYS.NOTES_ENABLED, false)
service['setupSortFields']()
expect(
service.sortFields.find((f) => f.field === 'num_notes')
).toBeUndefined()
})
afterEach(() => {
subscription?.unsubscribe()
httpTestingController.verify()

View File

@@ -1,5 +1,9 @@
import { Injectable } from '@angular/core'
import { Document } from 'src/app/data/document'
import {
DOCUMENT_SORT_FIELDS,
DOCUMENT_SORT_FIELDS_FULLTEXT,
Document,
} from 'src/app/data/document'
import { DocumentMetadata } from 'src/app/data/document-metadata'
import { AbstractPaperlessService } from './abstract-paperless-service'
import { HttpClient } from '@angular/common/http'
@@ -22,26 +26,6 @@ import { SettingsService } from '../settings.service'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { AuditLogEntry } from 'src/app/data/auditlog-entry'
export const DOCUMENT_SORT_FIELDS = [
{ field: 'archive_serial_number', name: $localize`ASN` },
{ field: 'correspondent__name', name: $localize`Correspondent` },
{ field: 'title', name: $localize`Title` },
{ field: 'document_type__name', name: $localize`Document type` },
{ field: 'created', name: $localize`Created` },
{ field: 'added', name: $localize`Added` },
{ field: 'modified', name: $localize`Modified` },
{ field: 'num_notes', name: $localize`Notes` },
{ field: 'owner', name: $localize`Owner` },
]
export const DOCUMENT_SORT_FIELDS_FULLTEXT = [
...DOCUMENT_SORT_FIELDS,
{
field: 'score',
name: $localize`:Score is a value returned by the full text search engine and specifies how well a result matches the given query:Search score`,
},
]
export interface SelectionDataItem {
id: number
document_count: number
@@ -60,6 +44,16 @@ export interface SelectionData {
export class DocumentService extends AbstractPaperlessService<Document> {
private _searchQuery: string
private _sortFields
get sortFields() {
return this._sortFields
}
private _sortFieldsFullText
get sortFieldsFullText() {
return this._sortFieldsFullText
}
constructor(
http: HttpClient,
private correspondentService: CorrespondentService,
@@ -70,6 +64,46 @@ export class DocumentService extends AbstractPaperlessService<Document> {
private settingsService: SettingsService
) {
super(http, 'documents')
this.setupSortFields()
}
private setupSortFields() {
this._sortFields = [...DOCUMENT_SORT_FIELDS]
let excludes = []
if (
!this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.Correspondent
)
) {
excludes.push('correspondent__name')
}
if (
!this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.DocumentType
)
) {
excludes.push('document_type__name')
}
if (
!this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.User
)
) {
excludes.push('owner')
}
if (!this.settingsService.get(SETTINGS_KEYS.NOTES_ENABLED)) {
excludes.push('num_notes')
}
this._sortFields = this._sortFields.filter(
(field) => !excludes.includes(field.field)
)
this._sortFieldsFullText = [
...this._sortFields,
...DOCUMENT_SORT_FIELDS_FULLTEXT,
]
}
addObservablesToDocument(doc: Document) {

View File

@@ -7,17 +7,38 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterTestingModule } from '@angular/router/testing'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { CookieService } from 'ngx-cookie-service'
import { Subscription } from 'rxjs'
import { Subscription, of } from 'rxjs'
import { environment } from 'src/environments/environment'
import { AppModule } from '../app.module'
import { UiSettings, SETTINGS_KEYS } from '../data/ui-settings'
import { SettingsService } from './settings.service'
import { SavedView } from '../data/saved-view'
import { CustomFieldsService } from './rest/custom-fields.service'
import { CustomFieldDataType } from '../data/custom-field'
import { PermissionsService } from './permissions.service'
import { DEFAULT_DISPLAY_FIELDS, DisplayField } from '../data/document'
const customFields = [
{
id: 1,
name: 'Field 1',
created: new Date(),
data_type: CustomFieldDataType.Monetary,
},
{
id: 2,
name: 'Field 2',
created: new Date(),
data_type: CustomFieldDataType.String,
},
]
describe('SettingsService', () => {
let httpTestingController: HttpTestingController
let settingsService: SettingsService
let cookieService: CookieService
let customFieldsService: CustomFieldsService
let permissionService: PermissionsService
let subscription: Subscription
const ui_settings: UiSettings = {
@@ -76,12 +97,14 @@ describe('SettingsService', () => {
httpTestingController = TestBed.inject(HttpTestingController)
cookieService = TestBed.inject(CookieService)
customFieldsService = TestBed.inject(CustomFieldsService)
permissionService = TestBed.inject(PermissionsService)
settingsService = TestBed.inject(SettingsService)
})
afterEach(() => {
subscription?.unsubscribe()
httpTestingController.verify()
// httpTestingController.verify()
})
it('calls ui_settings api endpoint on initialize', () => {
@@ -314,4 +337,51 @@ describe('SettingsService', () => {
// post for migrate
httpTestingController.expectOne(`${environment.apiBaseUrl}ui_settings/`)
})
it('should hide fields if no perms or disabled', () => {
jest.spyOn(permissionService, 'currentUserCan').mockReturnValue(false)
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}ui_settings/`
)
req.flush(ui_settings)
settingsService.initializeDisplayFields()
expect(
settingsService.allDisplayFields.includes(DEFAULT_DISPLAY_FIELDS[0])
).toBeTruthy() // title
expect(
settingsService.allDisplayFields.includes(DEFAULT_DISPLAY_FIELDS[4])
).toBeFalsy() // correspondent
settingsService.set(SETTINGS_KEYS.NOTES_ENABLED, false)
settingsService.initializeDisplayFields()
expect(
settingsService.allDisplayFields.includes(DEFAULT_DISPLAY_FIELDS[8])
).toBeFalsy() // notes
jest.spyOn(permissionService, 'currentUserCan').mockReturnValue(true)
settingsService.initializeDisplayFields()
expect(
settingsService.allDisplayFields.includes(DEFAULT_DISPLAY_FIELDS[4])
).toBeTruthy() // correspondent
})
it('should dynamically create display fields options including custom fields', () => {
jest.spyOn(permissionService, 'currentUserCan').mockReturnValue(true)
jest.spyOn(customFieldsService, 'listAll').mockReturnValue(
of({
all: customFields.map((f) => f.id),
count: customFields.length,
results: customFields.concat([]),
})
)
settingsService.initializeDisplayFields()
expect(
settingsService.allDisplayFields.includes(DEFAULT_DISPLAY_FIELDS[0])
).toBeTruthy()
expect(
settingsService.allDisplayFields.find(
(f) => f.id === `${DisplayField.CUSTOM_FIELD}${customFields[0].id}`
).name
).toEqual(customFields[0].name)
})
})

View File

@@ -19,9 +19,15 @@ import {
import { environment } from 'src/environments/environment'
import { UiSettings, SETTINGS, SETTINGS_KEYS } from '../data/ui-settings'
import { User } from '../data/user'
import { PermissionsService } from './permissions.service'
import {
PermissionAction,
PermissionType,
PermissionsService,
} from './permissions.service'
import { ToastService } from './toast.service'
import { SavedView } from '../data/saved-view'
import { CustomFieldsService } from './rest/custom-fields.service'
import { DEFAULT_DISPLAY_FIELDS, DisplayField } from '../data/document'
export interface LanguageOption {
code: string
@@ -257,6 +263,12 @@ export class SettingsService {
public globalDropzoneActive: boolean = false
public organizingSidebarSavedViews: boolean = false
private _allDisplayFields: Array<{ id: DisplayField; name: string }> =
DEFAULT_DISPLAY_FIELDS
public get allDisplayFields(): Array<{ id: DisplayField; name: string }> {
return this._allDisplayFields
}
constructor(
rendererFactory: RendererFactory2,
@Inject(DOCUMENT) private document,
@@ -265,7 +277,8 @@ export class SettingsService {
@Inject(LOCALE_ID) private localeId: string,
protected http: HttpClient,
private toastService: ToastService,
private permissionsService: PermissionsService
private permissionsService: PermissionsService,
private customFieldsService: CustomFieldsService
) {
this._renderer = rendererFactory.createRenderer(null, null)
}
@@ -288,10 +301,70 @@ export class SettingsService {
uisettings.permissions,
this.currentUser
)
this.initializeDisplayFields()
})
)
}
public initializeDisplayFields() {
this._allDisplayFields = DEFAULT_DISPLAY_FIELDS
this._allDisplayFields = this._allDisplayFields
?.map((field) => {
if (
field.id === DisplayField.NOTES &&
!this.get(SETTINGS_KEYS.NOTES_ENABLED)
) {
return null
}
if (
[
DisplayField.TITLE,
DisplayField.CREATED,
DisplayField.ADDED,
DisplayField.ASN,
DisplayField.SHARED,
].includes(field.id)
) {
return field
}
let type: PermissionType = Object.values(PermissionType).find((t) =>
t.includes(field.id)
)
if (field.id === DisplayField.OWNER) {
type = PermissionType.User
}
return this.permissionsService.currentUserCan(
PermissionAction.View,
type
)
? field
: null
})
.filter((f) => f)
if (
this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.CustomField
)
) {
this.customFieldsService.listAll().subscribe((r) => {
this._allDisplayFields = this._allDisplayFields.concat(
r.results.map((field) => {
return {
id: `${DisplayField.CUSTOM_FIELD}${field.id}` as any,
name: field.name,
}
})
)
})
}
}
get displayName(): string {
return (
this.currentUser.first_name ??