diff --git a/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.html b/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.html index 3b37baa87..c4d2a1af7 100644 --- a/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.html +++ b/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.html @@ -11,11 +11,6 @@ } @if (!loading() && !error()) { -
-

- Status updates every few seconds while bundles are being prepared. -

-
@if (bundles().length === 0) {

No share link bundles currently exist.

} @@ -149,20 +144,35 @@ - @if (total() > pageSize) { -
- +
+

+ Status updates every few seconds while bundles are being prepared. +

+
+
+ + + per page +
+ @if (total() > pageSize) { + + }
- } +
} }
diff --git a/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.spec.ts b/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.spec.ts index 90e5866d2..618610fc2 100644 --- a/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.spec.ts +++ b/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.spec.ts @@ -7,7 +7,9 @@ import { ShareLinkBundleStatus, ShareLinkBundleSummary, } from 'src/app/data/share-link-bundle' +import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { ShareLinkBundleService } from 'src/app/services/rest/share-link-bundle.service' +import { SettingsService } from 'src/app/services/settings.service' import { ToastService } from 'src/app/services/toast.service' import { environment } from 'src/environments/environment' import { ShareLinkBundleListComponent } from './share-link-bundle-list.component' @@ -121,6 +123,25 @@ describe('ShareLinkBundleListComponent', () => { expect(service.list).toHaveBeenLastCalledWith(2, 25, 'created', true) }) + it('stores a changed page size and reloads from the first page', () => { + fixture.detectChanges() + const settingsService = TestBed.inject(SettingsService) + jest + .spyOn(settingsService, 'get') + .mockReturnValueOnce({ share_link_bundles: 25 }) + const setSpy = jest.spyOn(settingsService, 'set') + jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of({})) + component.page.set(2) + + component.pageSize = 100 + + expect(setSpy).toHaveBeenCalledWith(SETTINGS_KEYS.OBJECT_LIST_SIZES, { + share_link_bundles: 100, + }) + expect(component.page()).toBe(1) + expect(service.list).toHaveBeenLastCalledWith(1, 100, 'created', true) + }) + it('copies bundle links when ready', () => { jest.useFakeTimers() jest.spyOn(clipboard, 'copy').mockReturnValue(true) diff --git a/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.ts b/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.ts index b01206717..2497b2614 100644 --- a/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.ts +++ b/src-ui/src/app/components/manage/share-links/share-link-bundle-list/share-link-bundle-list.component.ts @@ -1,6 +1,7 @@ import { Clipboard } from '@angular/cdk/clipboard' import { CommonModule } from '@angular/common' import { Component, OnDestroy, OnInit, inject, signal } from '@angular/core' +import { FormsModule } from '@angular/forms' import { NgbPaginationModule, NgbPopoverModule, @@ -14,8 +15,10 @@ import { ShareLinkBundleStatus, ShareLinkBundleSummary, } from 'src/app/data/share-link-bundle' +import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { FileSizePipe } from 'src/app/pipes/file-size.pipe' import { ShareLinkBundleService } from 'src/app/services/rest/share-link-bundle.service' +import { SettingsService } from 'src/app/services/settings.service' import { ToastService } from 'src/app/services/toast.service' import { environment } from 'src/environments/environment' import { ConfirmButtonComponent } from 'src/app/components/common/confirm-button/confirm-button.component' @@ -28,6 +31,7 @@ import { LoadingComponentWithPermissions } from 'src/app/components/loading-comp imports: [ ConfirmButtonComponent, CommonModule, + FormsModule, NgbPaginationModule, NgbPopoverModule, NgxBootstrapIconsModule, @@ -39,6 +43,7 @@ export class ShareLinkBundleListComponent implements OnInit, OnDestroy { private readonly shareLinkBundleService = inject(ShareLinkBundleService) + private readonly settingsService = inject(SettingsService) private readonly toastService = inject(ToastService) private readonly clipboard = inject(Clipboard) @@ -47,11 +52,33 @@ export class ShareLinkBundleListComponent readonly copiedSlug = signal(null) readonly total = signal(0) readonly page = signal(1) - readonly pageSize = 25 readonly statuses = ShareLinkBundleStatus readonly fileVersions = FileVersion + get pageSize(): number { + return ( + this.settingsService.get(SETTINGS_KEYS.OBJECT_LIST_SIZES) + ?.share_link_bundles || 25 + ) + } + + set pageSize(pageSize: number) { + this.settingsService.set(SETTINGS_KEYS.OBJECT_LIST_SIZES, { + ...this.settingsService.get(SETTINGS_KEYS.OBJECT_LIST_SIZES), + share_link_bundles: pageSize, + }) + this.settingsService.storeSettings().subscribe({ + next: () => { + this.page.set(1) + this.triggerRefresh(false) + }, + error: (error) => { + this.toastService.showError($localize`Error saving settings`, error) + }, + }) + } + private readonly refresh$ = new Subject() ngOnInit(): void { diff --git a/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.html b/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.html index 3c3b3fe45..87aa0a1be 100644 --- a/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.html +++ b/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.html @@ -85,9 +85,19 @@ - @if (total() > pageSize) { -
+
+
+ + + per page +
+ @if (total() > pageSize) { -
- } + } +
} diff --git a/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.spec.ts b/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.spec.ts index 19dbe4ad0..02de8b43b 100644 --- a/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.spec.ts +++ b/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.spec.ts @@ -4,7 +4,9 @@ import { RouterTestingModule } from '@angular/router/testing' import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' import { of, throwError } from 'rxjs' import { FileVersion, ShareLink } from 'src/app/data/share-link' +import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { ShareLinkService } from 'src/app/services/rest/share-link.service' +import { SettingsService } from 'src/app/services/settings.service' import { ToastService } from 'src/app/services/toast.service' import { ShareLinkListComponent } from './share-link-list.component' @@ -63,7 +65,7 @@ describe('ShareLinkListComponent', () => { expect(service.list).toHaveBeenCalledWith(1, 25, 'created', true) expect(component.links()).toEqual([link]) expect(fixture.nativeElement.textContent).toContain('Test document') - expect(fixture.nativeElement.textContent).toContain('Document #42') + expect(fixture.nativeElement.textContent).toContain('ID: 42') }) it('loads another page', () => { @@ -73,6 +75,23 @@ describe('ShareLinkListComponent', () => { expect(service.list).toHaveBeenLastCalledWith(2, 25, 'created', true) }) + it('stores a changed page size and reloads from the first page', () => { + const settingsService = TestBed.inject(SettingsService) + jest.spyOn(settingsService, 'get').mockReturnValueOnce({ share_links: 25 }) + const setSpy = jest.spyOn(settingsService, 'set') + jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of({})) + const reloadSpy = jest.spyOn(component, 'reload') + component.page.set(2) + + component.pageSize = 50 + + expect(setSpy).toHaveBeenCalledWith(SETTINGS_KEYS.OBJECT_LIST_SIZES, { + share_links: 50, + }) + expect(component.page()).toBe(1) + expect(reloadSpy).toHaveBeenCalled() + }) + it('shows local copy feedback without a toast', () => { jest.useFakeTimers() jest.spyOn(clipboard, 'copy').mockReturnValue(true) diff --git a/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.ts b/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.ts index a78ba929d..36dc6835b 100644 --- a/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.ts +++ b/src-ui/src/app/components/manage/share-links/share-link-list/share-link-list.component.ts @@ -1,6 +1,7 @@ import { Clipboard } from '@angular/cdk/clipboard' import { CommonModule } from '@angular/common' import { Component, OnInit, inject, signal } from '@angular/core' +import { FormsModule } from '@angular/forms' import { RouterModule } from '@angular/router' import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' @@ -9,6 +10,7 @@ import { ConfirmButtonComponent } from 'src/app/components/common/confirm-button import { LoadingComponentWithPermissions } from 'src/app/components/loading-component/loading.component' import { FileVersion, ShareLink } from 'src/app/data/share-link' import { SHARE_LINK_BUNDLE_FILE_VERSION_LABELS } from 'src/app/data/share-link-bundle' +import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' import { @@ -16,6 +18,7 @@ import { PermissionType, } from 'src/app/services/permissions.service' import { ShareLinkService } from 'src/app/services/rest/share-link.service' +import { SettingsService } from 'src/app/services/settings.service' import { ToastService } from 'src/app/services/toast.service' import { environment } from 'src/environments/environment' @@ -26,6 +29,7 @@ import { environment } from 'src/environments/environment' CommonModule, ConfirmButtonComponent, DocumentTitlePipe, + FormsModule, IfPermissionsDirective, NgbPaginationModule, NgxBootstrapIconsModule, @@ -38,6 +42,7 @@ export class ShareLinkListComponent { private readonly clipboard = inject(Clipboard) private readonly shareLinkService = inject(ShareLinkService) + private readonly settingsService = inject(SettingsService) private readonly toastService = inject(ToastService) readonly links = signal([]) @@ -46,10 +51,32 @@ export class ShareLinkListComponent readonly copiedID = signal(null) readonly copiedDocumentID = signal(null) readonly error = signal(null) - readonly pageSize = 25 readonly PermissionAction = PermissionAction readonly PermissionType = PermissionType + get pageSize(): number { + return ( + this.settingsService.get(SETTINGS_KEYS.OBJECT_LIST_SIZES)?.share_links || + 25 + ) + } + + set pageSize(pageSize: number) { + this.settingsService.set(SETTINGS_KEYS.OBJECT_LIST_SIZES, { + ...this.settingsService.get(SETTINGS_KEYS.OBJECT_LIST_SIZES), + share_links: pageSize, + }) + this.settingsService.storeSettings().subscribe({ + next: () => { + this.page.set(1) + this.reload() + }, + error: (error) => { + this.toastService.showError($localize`Error saving settings`, error) + }, + }) + } + ngOnInit(): void { this.reload() } diff --git a/src-ui/src/app/data/ui-settings.ts b/src-ui/src/app/data/ui-settings.ts index 4739051fa..0d6d44b20 100644 --- a/src-ui/src/app/data/ui-settings.ts +++ b/src-ui/src/app/data/ui-settings.ts @@ -228,6 +228,8 @@ export const SETTINGS: UiSetting[] = [ document_types: 25, tags: 25, storage_paths: 25, + share_links: 25, + share_link_bundles: 25, }, }, {