Enhancement: show small task summary in system status (#12634)

This commit is contained in:
shamoon
2026-04-24 09:11:42 -07:00
committed by GitHub
parent 2ca9e6764a
commit 5bb9241e9a
5 changed files with 110 additions and 0 deletions
@@ -142,6 +142,31 @@
}
</ng-template>
</dd>
<dt i18n>Recent Task Activity <span class="small text-muted fw-light">({{status.tasks.summary.days}} days)</span></dt>
<dd class="mb-0">
@if (status.tasks.summary.total_count > 0) {
<ul class="list-group border-light mt-2">
<li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<span class="small"><ng-container i18n>Total</ng-container>:</span>
<span class="badge bg-light rounded-pill">{{status.tasks.summary.total_count}}</span>
</li>
<li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<span class="small"><ng-container i18n>Successful</ng-container>:</span>
<span class="badge bg-primary rounded-pill">{{status.tasks.summary.success_count}}</span>
</li>
<li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<span class="small"><ng-container i18n>Failed</ng-container>:</span>
<span class="badge bg-danger rounded-pill">{{status.tasks.summary.failure_count}}</span>
</li>
<li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<span class="small"><ng-container i18n>Pending</ng-container>:</span>
<span class="badge bg-warning rounded-pill">{{status.tasks.summary.pending_count}}</span>
</li>
</ul>
} @else {
<span class="small text-muted" i18n>No recent tasks</span>
}
</dd>
</dl>
</div>
</div>
@@ -71,6 +71,13 @@ const status: SystemStatus = {
llmindex_status: SystemStatusItemStatus.OK,
llmindex_last_modified: new Date().toISOString(),
llmindex_error: null,
summary: {
days: 30,
total_count: 12,
pending_count: 1,
success_count: 10,
failure_count: 1,
},
},
}
+7
View File
@@ -47,6 +47,13 @@ export interface SystemStatus {
llmindex_status: SystemStatusItemStatus
llmindex_last_modified: string // ISO date string
llmindex_error: string
summary: {
days: number
total_count: number
pending_count: number
success_count: number
failure_count: number
}
}
websocket_connected?: SystemStatusItemStatus // added client-side
}
+36
View File
@@ -1,12 +1,14 @@
import os
import shutil
import tempfile
from datetime import timedelta
from pathlib import Path
from unittest import mock
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from django.utils import timezone
from rest_framework import status
from rest_framework.test import APITestCase
@@ -76,6 +78,11 @@ class TestSystemStatus(APITestCase):
self.assertEqual(response.data["tasks"]["redis_url"], "redis://localhost:6379")
self.assertEqual(response.data["tasks"]["redis_status"], "ERROR")
self.assertIsNotNone(response.data["tasks"]["redis_error"])
self.assertEqual(response.data["tasks"]["summary"]["days"], 30)
self.assertEqual(response.data["tasks"]["summary"]["total_count"], 0)
self.assertEqual(response.data["tasks"]["summary"]["success_count"], 0)
self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 0)
self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 0)
def test_system_status_insufficient_permissions(self) -> None:
"""
@@ -436,3 +443,32 @@ class TestSystemStatus(APITestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["llmindex_status"], "ERROR")
self.assertIsNotNone(response.data["tasks"]["llmindex_error"])
def test_system_status_includes_recent_task_summary(self) -> None:
PaperlessTaskFactory(
task_type=PaperlessTask.TaskType.CONSUME_FILE,
status=PaperlessTask.Status.SUCCESS,
)
PaperlessTaskFactory(
task_type=PaperlessTask.TaskType.CONSUME_FILE,
status=PaperlessTask.Status.FAILURE,
)
PaperlessTaskFactory(
task_type=PaperlessTask.TaskType.SANITY_CHECK,
status=PaperlessTask.Status.PENDING,
)
PaperlessTaskFactory(
task_type=PaperlessTask.TaskType.MAIL_FETCH,
status=PaperlessTask.Status.SUCCESS,
date_created=timezone.now() - timedelta(days=45),
)
self.client.force_login(self.user)
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["summary"]["days"], 30)
self.assertEqual(response.data["tasks"]["summary"]["total_count"], 3)
self.assertEqual(response.data["tasks"]["summary"]["success_count"], 1)
self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 1)
self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 1)
+35
View File
@@ -4597,6 +4597,16 @@ class CustomFieldViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Custom
"redis_status": serializers.CharField(),
"redis_error": serializers.CharField(),
"celery_status": serializers.CharField(),
"summary": inline_serializer(
name="TasksSummaryOverview",
fields={
"days": serializers.IntegerField(),
"total_count": serializers.IntegerField(),
"pending_count": serializers.IntegerField(),
"success_count": serializers.IntegerField(),
"failure_count": serializers.IntegerField(),
},
),
},
),
"index": inline_serializer(
@@ -4630,6 +4640,7 @@ class CustomFieldViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Custom
)
class SystemStatusView(PassUserMixin):
permission_classes = (IsAuthenticated,)
TASK_SUMMARY_DAYS = 30
def get(self, request, format=None):
if not has_system_status_permission(request.user):
@@ -4796,6 +4807,29 @@ class SystemStatusView(PassUserMixin):
last_llmindex_update.date_done if last_llmindex_update else None
)
summary_cutoff = timezone.now() - timedelta(days=self.TASK_SUMMARY_DAYS)
task_summary_agg = PaperlessTask.objects.filter(
date_created__gte=summary_cutoff,
).aggregate(
total_count=Count("id"),
pending_count=Count(
"id",
filter=Q(status=PaperlessTask.Status.PENDING),
),
success_count=Count(
"id",
filter=Q(status=PaperlessTask.Status.SUCCESS),
),
failure_count=Count(
"id",
filter=Q(status=PaperlessTask.Status.FAILURE),
),
)
task_summary = {
"days": self.TASK_SUMMARY_DAYS,
**task_summary_agg,
}
return Response(
{
"pngx_version": current_version,
@@ -4836,6 +4870,7 @@ class SystemStatusView(PassUserMixin):
"llmindex_status": llmindex_status,
"llmindex_last_modified": llmindex_last_modified,
"llmindex_error": llmindex_error,
"summary": task_summary,
},
},
)