fix(types): SchemaReviewQueuePage.total → totalElements (match backend)

User reported бэйдж 'Согласований' в sidebar показывал 0 несмотря на 1
pending schema draft. Root cause:

Backend сериализует Spring Page<SchemaDraft> как:
{items, page, size, totalElements, totalPages}

Но TS type SchemaReviewQueuePage объявлял поле как 'total' (mismatch
именования). Consumers читали data?.total → undefined → fallback 0:

- useReviewsBadgeCount (queries.ts:650) — sidebar badge падал на 0
- reviews.tsx:61 — header count в Schemas tab (но fallback на
  items.length скрывал bug в UI)
- reviews.tsx:593-594 — schema queue subtitle 'N drafts ждут ревью'

Fix:
- client.ts SchemaReviewQueuePage: total → totalElements + totalPages
- 3 consumer'а обновлены на .totalElements
- Backend контракт не меняется — это чисто frontend type alignment

После prod deploy v2.16.3 sidebar badge заработает корректно.
This commit is contained in:
Zimin A.N.
2026-05-13 10:58:48 +03:00
parent 894fcea81b
commit aecd65e7d5
3 changed files with 14 additions and 6 deletions
+10 -2
View File
@@ -659,12 +659,20 @@ export type PublishSchemaDraftResult = {
publishedAt: string publishedAt: string
} }
/** Pool queue для /admin/schema-reviews/pending. */ /** Pool queue для /admin/schema-reviews/pending.
*
* <p>Backend сериализует Spring {@code Page<SchemaDraft>} как:
* {@code {items, page, size, totalElements, totalPages}}. Раньше type
* объявлял {@code total} что было mismatched — consumers (`reviews.tsx`,
* `useReviewsBadgeCount`) читали {@code data.total} который === undefined,
* fallback'или на {@code items.length} (или 0 для badge — отсюда баг
* "бэйджа нет"). Type совпадает с фактическим контрактом backend'а. */
export type SchemaReviewQueuePage = { export type SchemaReviewQueuePage = {
items: SchemaDraft[] items: SchemaDraft[]
page: number page: number
size: number size: number
total: number totalElements: number
totalPages: number
} }
export type ChangelogDiff = { export type ChangelogDiff = {
+1 -1
View File
@@ -647,7 +647,7 @@ export const useReviewsBadgeCount = (enabled = true) => {
refetchInterval: 60_000, refetchInterval: 60_000,
}) })
const recordCount = recordQ.data?.totalElements ?? 0 const recordCount = recordQ.data?.totalElements ?? 0
const schemaCount = schemaQ.data?.total ?? 0 const schemaCount = schemaQ.data?.totalElements ?? 0
return { return {
total: recordCount + schemaCount, total: recordCount + schemaCount,
recordCount, recordCount,
+3 -3
View File
@@ -58,7 +58,7 @@ function ReviewsPage() {
const queue = useReviewQueue(0, 50) const queue = useReviewQueue(0, 50)
const schemaQueue = useSchemaReviewQueue(0, 50) const schemaQueue = useSchemaReviewQueue(0, 50)
const recordsCount = queue.data?.totalElements ?? 0 const recordsCount = queue.data?.totalElements ?? 0
const schemasCount = schemaQueue.data?.total ?? 0 const schemasCount = schemaQueue.data?.totalElements ?? 0
// Tab дефолтит на records (старее, чаще). Если schema queue не пустой // Tab дефолтит на records (старее, чаще). Если schema queue не пустой
// а record queue пустой — переключаемся на schemas чтобы reviewer'у не // а record queue пустой — переключаемся на schemas чтобы reviewer'у не
// пришлось кликать дважды. // пришлось кликать дважды.
@@ -590,8 +590,8 @@ function SchemaReviewQueuePanel() {
</h2> </h2>
<p className="text-cell text-mute mt-0.5"> <p className="text-cell text-mute mt-0.5">
{t('reviews.schema.queueTotal', { {t('reviews.schema.queueTotal', {
count: queue.data?.total ?? items.length, count: queue.data?.totalElements ?? items.length,
defaultValue: `${queue.data?.total ?? items.length} draft(s) ждут ревью`, defaultValue: `${queue.data?.totalElements ?? items.length} draft(s) ждут ревью`,
})} })}
</p> </p>
</div> </div>