fix dashboard source groups
All checks were successful
CI/CD Pipeline / Manual Action Help (push) Has been skipped
CI/CD Pipeline / Start Dev Containers in Dokploy (push) Has been skipped
CI/CD Pipeline / Cleanup Dev Database (push) Has been skipped
CI/CD Pipeline / Quality Gate (push) Successful in 1m49s
CI/CD Pipeline / Build and Push Images (push) Successful in 2m22s
CI/CD Pipeline / Internal Notify (push) Successful in 1s

This commit is contained in:
2026-04-28 13:01:31 +02:00
parent afa7845fef
commit 6a9e96922c
4 changed files with 43 additions and 9 deletions

View File

@@ -2064,6 +2064,10 @@ class ParserDashboardDataView(APIView):
def get(self, request: Request):
sources = ParserSourceSerializer(PARSER_SOURCES.values(), many=True).data
api_sources = [
source for source in sources if not source["supports_file_upload"]
]
file_sources = [source for source in sources if source["supports_file_upload"]]
jobs = BackgroundJobService.get_user_jobs(user_id=request.user.id, limit=30)
source_counts = dict(
GenericParserRecord.objects.values("source")
@@ -2083,12 +2087,12 @@ class ParserDashboardDataView(APIView):
return api_response(
{
"sources": sources,
"api_sources": [
source for source in sources if not source["supports_file_upload"]
],
"file_sources": [
source for source in sources if source["supports_file_upload"]
],
"api_sources": api_sources,
"file_sources": file_sources,
"groups": {
"api": api_sources,
"uploads": file_sources,
},
"schedules": ParserScheduleSerializer(schedules, many=True).data,
"jobs": BackgroundJobListSerializer(jobs, many=True).data,
"source_counts": source_counts,

View File

@@ -1378,6 +1378,14 @@
return map;
}
function sourceGroups() {
const sources = dashboardData?.sources || [];
return dashboardData?.groups || {
api: dashboardData?.api_sources || sources.filter((source) => !source.supports_file_upload),
uploads: dashboardData?.file_sources || sources.filter((source) => source.supports_file_upload),
};
}
function latestLoadForSource(source) {
return latestLoadsBySource().get(source.source) || null;
}
@@ -1398,7 +1406,7 @@
const other = Math.max(latestLoads.length - success - failed, 0);
const activeSchedules = (dashboardData?.schedules || []).filter((schedule) => schedule.enabled).length;
const runningJobs = (dashboardData?.jobs || []).filter((job) => ["pending", "started", "retry"].includes(job.status)).length;
const uploadCount = (dashboardData?.groups?.uploads || []).length;
const uploadCount = (sourceGroups().uploads || []).length;
$("analyticsKpis").innerHTML = [
["Источников", sources.length],
@@ -1708,14 +1716,15 @@
function renderDashboard(data) {
dashboardData = data.data;
const sources = dashboardData.sources || [];
const groups = sourceGroups();
const options = sources.map((source) => `<option value="${source.key}">${source.title}</option>`).join("");
$("runSource").innerHTML = options;
$("scheduleSource").innerHTML = options;
$("sourceCount").textContent = `${sources.length} источников`;
$("uploadCount").textContent = `${(dashboardData.groups.uploads || []).length} источника`;
$("uploadCount").textContent = `${(groups.uploads || []).length} источника`;
renderAnalytics();
renderSourceCards(sources);
renderUploadSources(dashboardData.groups.uploads || [], "uploadSources");
renderUploadSources(groups.uploads || [], "uploadSources");
$("jobsBody").innerHTML = (dashboardData.jobs || []).map((job) => {
const canRevoke = ["pending", "started", "retry"].includes(job.status);

View File

@@ -21,3 +21,11 @@ class ParserDashboardPageTest(TestCase):
content = response.content.decode()
self.assertIn("refreshRegisters().catch(renderRegistersUnavailable)", content)
self.assertIn("isAuthError(error)", content)
def test_dashboard_has_group_fallback_for_current_api_shape(self):
response = self.client.get("/dashboard")
self.assertEqual(response.status_code, 200)
content = response.content.decode()
self.assertIn("function sourceGroups()", content)
self.assertIn("dashboardData?.file_sources", content)

View File

@@ -120,6 +120,19 @@ class ParsersViewSetTest(APITestCase):
)
self.assertEqual(detail.status_code, status.HTTP_200_OK)
def test_dashboard_data_exposes_source_groups_for_page(self):
self.client.force_authenticate(self.user)
response = self.client.get("/api/v1/parsers/dashboard/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
payload = response.data["data"]
self.assertIn("groups", payload)
self.assertIn("api", payload["groups"])
self.assertIn("uploads", payload["groups"])
self.assertEqual(payload["api_sources"], payload["groups"]["api"])
self.assertEqual(payload["file_sources"], payload["groups"]["uploads"])
def test_financial_reports_list_and_retrieve(self):
report = FinancialReport.objects.create(
external_id=_digits(5),