fix(dashboard): stabilize result tables and fns filters
All checks were successful
CI/CD Pipeline / Quality Gate (push) Successful in 19s
CI/CD Pipeline / Build and Push Images (push) Successful in 6s
CI/CD Pipeline / Internal Notify (push) Successful in 1s
CI/CD Pipeline / Deploy Dev in Dokploy (push) Successful in 1s

This commit is contained in:
2026-04-29 01:14:08 +02:00
parent 9f5bce1e0c
commit 3f2056bac3
3 changed files with 53 additions and 6 deletions

View File

@@ -840,12 +840,24 @@ class FinancialReportViewSet(ReadOnlyModelViewSet):
"ogrn", "ogrn",
"external_id", "external_id",
"status", "status",
"source",
"load_batch", "load_batch",
"registry_organization", "registry_organization",
] ]
search_fields = ["ogrn", "external_id", "file_name"] search_fields = ["ogrn", "external_id", "file_name"]
def get_queryset(self):
queryset = super().get_queryset()
source_value = self.request.query_params.get("source", "").strip()
if not source_value or source_value in {
"fns_reports",
"fns_financial",
"financial-indicators",
}:
return queryset
if source_value in FinancialReport.SourceType.values:
return queryset.filter(source=source_value)
return queryset.none()
def get_serializer_class(self): def get_serializer_class(self):
if self.action == "retrieve": if self.action == "retrieve":
return FinancialReportDetailSerializer return FinancialReportDetailSerializer

View File

@@ -500,11 +500,32 @@
} }
.route-title { display: grid; gap: 3px; } .route-title { display: grid; gap: 3px; }
.record-table tbody tr { cursor: pointer; } .record-table tbody tr { cursor: pointer; }
.record-table {
table-layout: fixed;
min-width: 860px;
}
.record-table th,
.record-table td {
overflow-wrap: anywhere;
}
.record-table th:nth-child(1),
.record-table td:nth-child(1) { width: 72px; }
.record-table th:nth-child(2),
.record-table td:nth-child(2) { width: 38%; }
.record-table th:nth-child(3),
.record-table td:nth-child(3) { width: 24%; }
.record-table th:nth-child(4),
.record-table td:nth-child(4) { width: 150px; }
.record-table th:nth-child(5),
.record-table td:nth-child(5) { width: 150px; }
.record-table td:first-child { .record-table td:first-child {
width: 64px;
color: var(--muted); color: var(--muted);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
} }
#sourceTableView {
min-height: 420px;
overflow-x: auto;
}
.empty-state { .empty-state {
padding: 18px; padding: 18px;
border: 1px dashed var(--line-strong); border: 1px dashed var(--line-strong);
@@ -1799,16 +1820,18 @@
$("routeTitle").textContent = source.title; $("routeTitle").textContent = source.title;
$("routeSubtitle").textContent = `${source.agency} · ${source.source} · ${source.parser_strategy}`; $("routeSubtitle").textContent = `${source.agency} · ${source.source} · ${source.parser_strategy}`;
$("recordsEmpty").classList.add("hidden"); $("recordsEmpty").classList.add("hidden");
$("recordsBody").innerHTML = ""; $("recordsBody").innerHTML = `<tr><td colspan="5"><div class="empty-state">Загрузка данных...</div></td></tr>`;
const listUrl = source.result_list_url || `/api/v1/parsers/records/`; const listUrl = source.result_list_url || `/api/v1/parsers/records/`;
const response = await apiFetch(withQuery(listUrl, { const query = {
source: source.source,
page_size: 100, page_size: 100,
limit: 100, limit: 100,
})); };
if (!source.result_list_url) query.source = source.source;
const response = await apiFetch(withQuery(listUrl, query));
const records = listPayload(response); const records = listPayload(response);
if (!records.length) { if (!records.length) {
$("recordsBody").innerHTML = "";
$("recordsEmpty").textContent = "По этому источнику записей пока нет. Запустите парсер или дождитесь завершения Celery-задачи."; $("recordsEmpty").textContent = "По этому источнику записей пока нет. Запустите парсер или дождитесь завершения Celery-задачи.";
$("recordsEmpty").classList.remove("hidden"); $("recordsEmpty").classList.remove("hidden");
return; return;

View File

@@ -252,6 +252,18 @@ class ParsersViewSetTest(APITestCase):
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["data"][0]["lines_count"], 1) self.assertEqual(response.data["data"][0]["lines_count"], 1)
alias_response = self.client.get(url, {"source": "fns_reports"})
self.assertEqual(alias_response.status_code, status.HTTP_200_OK)
self.assertEqual(alias_response.data["data"][0]["id"], report.id)
source_type_response = self.client.get(
url,
{"source": FinancialReport.SourceType.API},
)
self.assertEqual(source_type_response.status_code, status.HTTP_200_OK)
self.assertEqual(source_type_response.data["data"][0]["id"], report.id)
invalid_source_response = self.client.get(url, {"source": "unknown"})
self.assertEqual(invalid_source_response.status_code, status.HTTP_200_OK)
self.assertEqual(invalid_source_response.data["data"], [])
detail = self.client.get( detail = self.client.get(
reverse("api_v1:fns:fns-reports-detail", args=[report.id]) reverse("api_v1:fns:fns-reports-detail", args=[report.id])
) )