@@ -91,7 +107,7 @@
-@if (!loading) {
+@if (!loading || data.length > 0) {
@if (collectionSize > 0) {
@@ -102,7 +118,7 @@
}
@if (collectionSize > 20) {
-
+
}
}
diff --git a/src-ui/src/app/components/manage/management-list/management-list.component.scss b/src-ui/src/app/components/manage/management-list/management-list.component.scss
index de99b6584..52f8d5812 100644
--- a/src-ui/src/app/components/manage/management-list/management-list.component.scss
+++ b/src-ui/src/app/components/manage/management-list/management-list.component.scss
@@ -24,3 +24,7 @@ td.name-cell {
margin-left: .5rem;
}
}
+
+select.small {
+ font-size: 0.875rem !important; // 14px
+}
diff --git a/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts b/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts
index dca1bb2c9..b2a494425 100644
--- a/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts
+++ b/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts
@@ -31,6 +31,7 @@ import {
MATCH_NONE,
} from 'src/app/data/matching-model'
import { Tag } from 'src/app/data/tag'
+import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SortableDirective } from 'src/app/directives/sortable.directive'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
@@ -41,6 +42,7 @@ import {
} from 'src/app/services/permissions.service'
import { BulkEditObjectOperation } from 'src/app/services/rest/abstract-name-filter-service'
import { TagService } from 'src/app/services/rest/tag.service'
+import { SettingsService } from 'src/app/services/settings.service'
import { ToastService } from 'src/app/services/toast.service'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { EditDialogComponent } from '../../common/edit-dialog/edit-dialog.component'
@@ -79,6 +81,7 @@ describe('ManagementListComponent', () => {
let toastService: ToastService
let documentListViewService: DocumentListViewService
let permissionsService: PermissionsService
+ let settingsService: SettingsService
beforeEach(async () => {
TestBed.configureTestingModule({
@@ -130,6 +133,7 @@ describe('ManagementListComponent', () => {
modalService = TestBed.inject(NgbModal)
toastService = TestBed.inject(ToastService)
documentListViewService = TestBed.inject(DocumentListViewService)
+ settingsService = TestBed.inject(SettingsService)
fixture = TestBed.createComponent(TagListComponent)
component = fixture.componentInstance
fixture.detectChanges()
@@ -447,4 +451,66 @@ describe('ManagementListComponent', () => {
).getSelectableIDs.call({}, [{ id: 1 }, { id: 5 }] as any)
expect(ids).toEqual([1, 5])
})
+
+ it('pageSize getter should return stored page size or default to 25', () => {
+ jest.spyOn(settingsService, 'get').mockReturnValue({ tags: 50 })
+ component.typeNamePlural = 'tags'
+
+ expect(component.pageSize).toBe(50)
+ })
+
+ it('pageSize getter should return 25 when no size is stored', () => {
+ const settingsService = TestBed.inject(SettingsService)
+ jest.spyOn(settingsService, 'get').mockReturnValue({})
+ component.typeNamePlural = 'tags'
+
+ expect(component.pageSize).toBe(25)
+ })
+
+ it('pageSize setter should update settings, reset page and reload data on success', fakeAsync(() => {
+ const reloadSpy = jest.spyOn(component, 'reloadData')
+ const toastErrorSpy = jest.spyOn(toastService, 'showError')
+
+ jest.spyOn(settingsService, 'get').mockReturnValue({ tags: 25 })
+ jest.spyOn(settingsService, 'set').mockImplementation(() => {})
+ jest
+ .spyOn(settingsService, 'storeSettings')
+ .mockReturnValue(of({ success: true }))
+
+ component.typeNamePlural = 'tags'
+ component.page = 2
+ component.pageSize = 100
+
+ tick()
+
+ expect(settingsService.set).toHaveBeenCalledWith(
+ SETTINGS_KEYS.OBJECT_LIST_SIZES,
+ { tags: 100 }
+ )
+ expect(component.page).toBe(1)
+ expect(reloadSpy).toHaveBeenCalled()
+ expect(toastErrorSpy).not.toHaveBeenCalled()
+ }))
+
+ it('pageSize setter should show error toast on settings store failure', fakeAsync(() => {
+ const reloadSpy = jest.spyOn(component, 'reloadData')
+ const toastErrorSpy = jest.spyOn(toastService, 'showError')
+
+ jest.spyOn(settingsService, 'get').mockReturnValue({ tags: 25 })
+ jest.spyOn(settingsService, 'set').mockImplementation(() => {})
+ jest
+ .spyOn(settingsService, 'storeSettings')
+ .mockReturnValue(throwError(() => new Error('error storing settings')))
+
+ component.typeNamePlural = 'tags'
+ component.pageSize = 50
+
+ tick()
+
+ expect(toastErrorSpy).toHaveBeenCalledWith(
+ 'Error saving settings',
+ expect.any(Error)
+ )
+ expect(reloadSpy).not.toHaveBeenCalled()
+ }))
})
diff --git a/src-ui/src/app/components/manage/management-list/management-list.component.ts b/src-ui/src/app/components/manage/management-list/management-list.component.ts
index 2a17f08e6..6f5e9c0dd 100644
--- a/src-ui/src/app/components/manage/management-list/management-list.component.ts
+++ b/src-ui/src/app/components/manage/management-list/management-list.component.ts
@@ -23,6 +23,7 @@ import {
MatchingModel,
} from 'src/app/data/matching-model'
import { ObjectWithPermissions } from 'src/app/data/object-with-permissions'
+import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import {
SortableDirective,
SortEvent,
@@ -37,6 +38,7 @@ import {
AbstractNameFilterService,
BulkEditObjectOperation,
} from 'src/app/services/rest/abstract-name-filter-service'
+import { SettingsService } from 'src/app/services/settings.service'
import { ToastService } from 'src/app/services/toast.service'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
@@ -80,6 +82,8 @@ export abstract class ManagementListComponent
public permissionType: PermissionType
public extraColumns: ManagementListColumn[]
+ private readonly settingsService = inject(SettingsService)
+
@ViewChildren(SortableDirective) headers: QueryList
public data: T[] = []
@@ -160,7 +164,7 @@ export abstract class ManagementListComponent
this.service
.listFiltered(
this.page,
- null,
+ this.pageSize,
this.sortField,
this.sortReverse,
this._nameFilter,
@@ -280,6 +284,30 @@ export abstract class ManagementListComponent
if (event.code == 'Escape') this.nameFilterDebounce.next(null)
}
+ public get pageSize(): number {
+ return (
+ this.settingsService.get(SETTINGS_KEYS.OBJECT_LIST_SIZES)[
+ this.typeNamePlural
+ ] || 25
+ )
+ }
+
+ public set pageSize(newPageSize: number) {
+ this.settingsService.set(SETTINGS_KEYS.OBJECT_LIST_SIZES, {
+ ...this.settingsService.get(SETTINGS_KEYS.OBJECT_LIST_SIZES),
+ [this.typeNamePlural]: newPageSize,
+ })
+ this.settingsService.storeSettings().subscribe({
+ next: () => {
+ this.page = 1
+ this.reloadData()
+ },
+ error: (error) => {
+ this.toastService.showError($localize`Error saving settings`, error)
+ },
+ })
+ }
+
userCanDelete(object: ObjectWithPermissions): boolean {
return this.permissionsService.currentUserOwnsObject(object)
}
diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts b/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts
index 51403379d..a69eacba0 100644
--- a/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts
+++ b/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts
@@ -101,7 +101,7 @@ describe('TagListComponent', () => {
it('should request only parent tags when no name filter is applied', () => {
expect(tagService.listFiltered).toHaveBeenCalledWith(
1,
- null,
+ 25,
undefined,
undefined,
undefined,
@@ -116,7 +116,7 @@ describe('TagListComponent', () => {
component.reloadData()
expect(tagService.listFiltered).toHaveBeenCalledWith(
1,
- null,
+ 25,
undefined,
undefined,
'Tag',
diff --git a/src-ui/src/app/data/ui-settings.ts b/src-ui/src/app/data/ui-settings.ts
index f3c908dc3..f899cffa4 100644
--- a/src-ui/src/app/data/ui-settings.ts
+++ b/src-ui/src/app/data/ui-settings.ts
@@ -63,6 +63,7 @@ export const SETTINGS_KEYS = {
SIDEBAR_VIEWS_SHOW_COUNT:
'general-settings:saved-views:sidebar-views-show-count',
TOUR_COMPLETE: 'general-settings:tour-complete',
+ OBJECT_LIST_SIZES: 'general-settings:object-list-sizes',
DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner',
DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users',
DEFAULT_PERMS_VIEW_GROUPS: 'general-settings:permissions:default-view-groups',
@@ -201,6 +202,16 @@ export const SETTINGS: UiSetting[] = [
type: 'boolean',
default: false,
},
+ {
+ key: SETTINGS_KEYS.OBJECT_LIST_SIZES,
+ type: 'object',
+ default: {
+ correspondents: 25,
+ document_types: 25,
+ tags: 25,
+ storage_paths: 25,
+ },
+ },
{
key: SETTINGS_KEYS.DEFAULT_PERMS_OWNER,
type: 'number',
|