From 2d25400a23c0a9e2b2a6930332deae441ebd8a6e Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Tue, 8 Sep 2026 09:52:46 -0700
Subject: [PATCH] Add column sorting
---
.../share-link-bundle-list.component.html | 6 +++---
.../share-link-bundle-list.component.spec.ts | 10 +++++++++
.../share-link-bundle-list.component.ts | 21 ++++++++++++++++++-
.../share-link-list.component.html | 6 +++---
.../share-link-list.component.spec.ts | 10 +++++++++
.../share-link-list.component.ts | 16 +++++++++++++-
src/documents/tests/test_api_documents.py | 17 +++++++++++++++
src/documents/views.py | 2 +-
8 files changed, 79 insertions(+), 9 deletions(-)
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 62a680964..2ac67b6d9 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
@@ -13,10 +13,10 @@
- | Created |
- Status |
+ Created |
+ Status |
Size |
- Expires |
+ Expires |
Documents |
File version |
Actions |
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 362d99e0a..085ece5c8 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
@@ -123,6 +123,16 @@ describe('ShareLinkBundleListComponent', () => {
expect(service.list).toHaveBeenLastCalledWith(2, 25, 'created', true)
})
+ it('sorts bundles and returns to the first page', () => {
+ fixture.detectChanges()
+ component.page.set(2)
+
+ component.onSort({ column: 'status', reverse: false })
+
+ expect(component.page()).toBe(1)
+ expect(service.list).toHaveBeenLastCalledWith(1, 25, 'status', false)
+ })
+
it('marks expired share link bundles', () => {
service.list.mockReturnValue(
of({
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 a8dc8ed4d..00d04a77e 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
@@ -16,6 +16,10 @@ import {
ShareLinkBundleSummary,
} from 'src/app/data/share-link-bundle'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
+import {
+ SortEvent,
+ SortableDirective,
+} from 'src/app/directives/sortable.directive'
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'
@@ -35,6 +39,7 @@ import { LoadingComponentWithPermissions } from 'src/app/components/loading-comp
NgbPaginationModule,
NgbPopoverModule,
NgxBootstrapIconsModule,
+ SortableDirective,
FileSizePipe,
],
})
@@ -52,6 +57,8 @@ export class ShareLinkBundleListComponent
readonly copiedSlug = signal(null)
readonly total = signal(0)
readonly page = signal(1)
+ readonly sortField = signal('created')
+ readonly sortReverse = signal(true)
readonly statuses = ShareLinkBundleStatus
readonly fileVersions = FileVersion
@@ -90,7 +97,12 @@ export class ShareLinkBundleListComponent
}
this.error.set(null)
return this.shareLinkBundleService
- .list(this.page(), this.pageSize, 'created', true)
+ .list(
+ this.page(),
+ this.pageSize,
+ this.sortField(),
+ this.sortReverse()
+ )
.pipe(
catchError((error) => {
if (!silent) {
@@ -138,6 +150,13 @@ export class ShareLinkBundleListComponent
this.triggerRefresh(false)
}
+ onSort(event: SortEvent): void {
+ this.sortField.set(event.column || 'created')
+ this.sortReverse.set(event.column ? event.reverse : true)
+ this.page.set(1)
+ this.triggerRefresh(false)
+ }
+
copy(bundle: ShareLinkBundleSummary): void {
if (bundle.status !== ShareLinkBundleStatus.Ready) {
return
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 25c90f64c..710db7dc3 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
@@ -12,9 +12,9 @@
- | Document |
- Created |
- Expires |
+ Document |
+ Created |
+ Expires |
File version |
Actions |
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 43a6f7cc0..1946b7e78 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
@@ -75,6 +75,16 @@ describe('ShareLinkListComponent', () => {
expect(service.list).toHaveBeenLastCalledWith(2, 25, 'created', true)
})
+ it('sorts links and returns to the first page', () => {
+ fixture.detectChanges()
+ component.page.set(2)
+
+ component.onSort({ column: 'expiration', reverse: false })
+
+ expect(component.page()).toBe(1)
+ expect(service.list).toHaveBeenLastCalledWith(1, 25, 'expiration', false)
+ })
+
it('marks expired share links', () => {
service.list.mockReturnValue(
of({
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 8c4239256..6f30366f4 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
@@ -12,6 +12,10 @@ 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 {
+ SortEvent,
+ SortableDirective,
+} from 'src/app/directives/sortable.directive'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
import {
PermissionAction,
@@ -34,6 +38,7 @@ import { environment } from 'src/environments/environment'
NgbPaginationModule,
NgxBootstrapIconsModule,
RouterModule,
+ SortableDirective,
],
})
export class ShareLinkListComponent
@@ -48,6 +53,8 @@ export class ShareLinkListComponent
readonly links = signal([])
readonly total = signal(0)
readonly page = signal(1)
+ readonly sortField = signal('created')
+ readonly sortReverse = signal(true)
readonly copiedID = signal(null)
readonly copiedDocumentID = signal(null)
readonly error = signal(null)
@@ -85,7 +92,7 @@ export class ShareLinkListComponent
this.loading.set(true)
this.error.set(null)
this.shareLinkService
- .list(this.page(), this.pageSize, 'created', true)
+ .list(this.page(), this.pageSize, this.sortField(), this.sortReverse())
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe({
next: (results) => {
@@ -109,6 +116,13 @@ export class ShareLinkListComponent
this.reload()
}
+ onSort(event: SortEvent): void {
+ this.sortField.set(event.column || 'created')
+ this.sortReverse.set(event.column ? event.reverse : true)
+ this.page.set(1)
+ this.reload()
+ }
+
getShareUrl(link: ShareLink): string {
const apiURL = new URL(environment.apiBaseUrl)
return `${apiURL.origin}${apiURL.pathname.replace(/\/api\/$/, '/share/')}${
diff --git a/src/documents/tests/test_api_documents.py b/src/documents/tests/test_api_documents.py
index 30ddb4af0..aee461d0f 100644
--- a/src/documents/tests/test_api_documents.py
+++ b/src/documents/tests/test_api_documents.py
@@ -3796,6 +3796,23 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+ def test_order_share_links_by_document_title(self) -> None:
+ document_zulu = Document.objects.create(title="Zulu")
+ document_alpha = Document.objects.create(title="Alpha")
+ ShareLink.objects.create(document=document_zulu, slug="zulu-link")
+ ShareLink.objects.create(document=document_alpha, slug="alpha-link")
+
+ response = self.client.get(
+ "/api/share_links/?ordering=document__title",
+ format="json",
+ )
+
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(
+ [link["document_title"] for link in response.data["results"]],
+ ["Alpha", "Zulu"],
+ )
+
def test_share_links_permissions_aware(self) -> None:
"""
GIVEN:
diff --git a/src/documents/views.py b/src/documents/views.py
index 5f1debbb1..9ae2a4a48 100644
--- a/src/documents/views.py
+++ b/src/documents/views.py
@@ -4571,7 +4571,7 @@ class ShareLinkViewSet(
PermittedObjectsFilter,
)
filterset_class = ShareLinkFilterSet
- ordering_fields = ("created", "expiration", "document")
+ ordering_fields = ("created", "expiration", "document__title")
@extend_schema_view(