-
+
@@ -96,6 +95,13 @@
Delete
+ @if (object.document_count > 0) {
+
+
+
+ }
}
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 557d5f388..9aa876da2 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
@@ -49,16 +49,19 @@ const tags: Tag[] = [
name: 'Tag1 Foo',
matching_algorithm: MATCH_LITERAL,
match: 'foo',
+ document_count: 35,
},
{
id: 2,
name: 'Tag2',
matching_algorithm: MATCH_NONE,
+ document_count: 0,
},
{
id: 3,
name: 'Tag3',
matching_algorithm: MATCH_AUTO,
+ document_count: 5,
},
]
@@ -180,7 +183,7 @@ describe('ManagementListComponent', () => {
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
const reloadSpy = jest.spyOn(component, 'reloadData')
- const editButton = fixture.debugElement.queryAll(By.css('button'))[7]
+ const editButton = fixture.debugElement.queryAll(By.css('button'))[6]
editButton.triggerEventHandler('click')
expect(modal).not.toBeUndefined()
@@ -205,7 +208,7 @@ describe('ManagementListComponent', () => {
const deleteSpy = jest.spyOn(tagService, 'delete')
const reloadSpy = jest.spyOn(component, 'reloadData')
- const deleteButton = fixture.debugElement.queryAll(By.css('button'))[8]
+ const deleteButton = fixture.debugElement.queryAll(By.css('button'))[7]
deleteButton.triggerEventHandler('click')
expect(modal).not.toBeUndefined()
@@ -225,7 +228,7 @@ describe('ManagementListComponent', () => {
it('should support quick filter for objects', () => {
const qfSpy = jest.spyOn(documentListViewService, 'quickFilter')
- const filterButton = fixture.debugElement.queryAll(By.css('button'))[6]
+ const filterButton = fixture.debugElement.queryAll(By.css('button'))[8]
filterButton.triggerEventHandler('click')
expect(qfSpy).toHaveBeenCalledWith([
{ rule_type: FILTER_HAS_TAGS_ALL, value: tags[0].id.toString() },
diff --git a/src-ui/src/app/data/custom-field.ts b/src-ui/src/app/data/custom-field.ts
index 7e52d0785..bca77dd51 100644
--- a/src-ui/src/app/data/custom-field.ts
+++ b/src-ui/src/app/data/custom-field.ts
@@ -59,4 +59,5 @@ export interface CustomField extends ObjectWithId {
select_options?: string[]
default_currency?: string
}
+ document_count?: number
}
diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py
index 30f3dd26d..f326b4eee 100644
--- a/src/documents/serialisers.py
+++ b/src/documents/serialisers.py
@@ -494,6 +494,8 @@ class CustomFieldSerializer(serializers.ModelSerializer):
read_only=False,
)
+ document_count = serializers.IntegerField(read_only=True)
+
class Meta:
model = CustomField
fields = [
@@ -501,6 +503,7 @@ class CustomFieldSerializer(serializers.ModelSerializer):
"name",
"data_type",
"extra_data",
+ "document_count",
]
def validate(self, attrs):
diff --git a/src/documents/tests/test_api_custom_fields.py b/src/documents/tests/test_api_custom_fields.py
index 6ffe14681..bfe352d56 100644
--- a/src/documents/tests/test_api_custom_fields.py
+++ b/src/documents/tests/test_api_custom_fields.py
@@ -1,6 +1,7 @@
import json
from datetime import date
+from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.test import APITestCase
@@ -933,3 +934,51 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
results = response.data["results"]
self.assertEqual(len(results), 1)
self.assertEqual(results[0]["name"], custom_field_int.name)
+
+ def test_custom_fields_document_count(self):
+ custom_field_string = CustomField.objects.create(
+ name="Test Custom Field String",
+ data_type=CustomField.FieldDataType.STRING,
+ )
+ doc = Document.objects.create(
+ title="WOW",
+ content="the content",
+ checksum="123",
+ mime_type="application/pdf",
+ owner=self.user,
+ )
+
+ response = self.client.get(
+ f"{self.ENDPOINT}",
+ )
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ results = response.data["results"]
+ self.assertEqual(results[0]["document_count"], 0)
+
+ CustomFieldInstance.objects.create(
+ document=doc,
+ field=custom_field_string,
+ value_text="test value",
+ )
+
+ response = self.client.get(
+ f"{self.ENDPOINT}",
+ )
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ results = response.data["results"]
+ self.assertEqual(results[0]["document_count"], 1)
+
+ # Test as user without access to the document
+ non_superuser = User.objects.create_user(username="non_superuser")
+ non_superuser.user_permissions.add(
+ *Permission.objects.all(),
+ )
+ non_superuser.save()
+ self.client.force_authenticate(user=non_superuser)
+ self.client.force_login(user=non_superuser)
+ response = self.client.get(
+ f"{self.ENDPOINT}",
+ )
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ results = response.data["results"]
+ self.assertEqual(results[0]["document_count"], 0)
diff --git a/src/documents/views.py b/src/documents/views.py
index c870c15b5..94674a83f 100644
--- a/src/documents/views.py
+++ b/src/documents/views.py
@@ -1897,6 +1897,32 @@ class CustomFieldViewSet(ModelViewSet):
queryset = CustomField.objects.all().order_by("-created")
+ def get_queryset(self):
+ filter = (
+ Q(fields__document__deleted_at__isnull=True)
+ if self.request.user is None or self.request.user.is_superuser
+ else (
+ Q(
+ fields__document__deleted_at__isnull=True,
+ fields__document__id__in=get_objects_for_user_owner_aware(
+ self.request.user,
+ "documents.view_document",
+ Document,
+ ).values_list("id", flat=True),
+ )
+ )
+ )
+ return (
+ super()
+ .get_queryset()
+ .annotate(
+ document_count=Count(
+ "fields",
+ filter=filter,
+ ),
+ )
+ )
+
class SystemStatusView(PassUserMixin):
permission_classes = (IsAuthenticated,)