fix(admin-ui): sidebar «Мои черновики» badge — считаем только actionable
Badge в сайдбаре (desktop + mobile) показывал totalElements от /drafts/me и /admin/schema-drafts/me — это сумма ВСЕХ статусов (PENDING + APPROVED + REJECTED + WITHDRAWN). После approve/reject счётчик не уменьшался, юзер видел «висящие» цифры на драфтах которые уже terminal. Tab-бейдж в ReviewsPage давно делает правильно через classifyRecordStatus / classifySchemaStatus. Подтягиваем sidebar к той же логике: - fetch size 50 вместо 1 (нужны .items[] для filter; TanStack дедуплицирует query — на /reviews этот же ключ уже зовётся, лишних запросов нет) - record → 'pending', schema → 'pending'|'wip' - approved schema всё ещё попадает в pending по дизайну (maker должен publish'нуть; см. classifySchemaStatus комментарий)
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
} from '@/api/queries'
|
||||
import { Sheet, SheetContent, SheetTitle } from '@/ui'
|
||||
import { ThemeSwitch } from '@/components/layout/ThemeSwitch'
|
||||
import { classifyRecordStatus, classifySchemaStatus } from '@/components/reviews/MyDraftsPanel'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
/**
|
||||
@@ -86,8 +87,15 @@ export function Sidebar() {
|
||||
// Loaded just for сидбар counter — light request, кэшируется.
|
||||
// Badge "Мои черновики" суммирует record (/drafts/me) + schema
|
||||
// (/admin/schema-drafts/me) — maker не должен помнить разные типы.
|
||||
const myDrafts = useMyDrafts(0, 1)
|
||||
const mySchemaDrafts = useMySchemaDrafts(0, 1)
|
||||
//
|
||||
// page=0 size=50 (не size=1!) — backend /drafts/me возвращает ВСЕ статусы
|
||||
// (PENDING + APPROVED + REJECTED + WITHDRAWN), а totalElements не умеет
|
||||
// filter по статусу. Нужно фильтровать на клиенте: считаем только
|
||||
// pending/WIP-драфты, чтобы approved/rejected не «висели» в badge.
|
||||
// Reuse: на /reviews этот же query (size=50) уже зовётся → TanStack
|
||||
// дедуплицирует по queryKey, лишних запросов нет.
|
||||
const myDrafts = useMyDrafts(0, 50)
|
||||
const mySchemaDrafts = useMySchemaDrafts(0, 50)
|
||||
// Reviews badge — суммирует record-reviews + schema-reviews pending queues
|
||||
// через size=1 paged запросы. Gated на authenticated.
|
||||
const reviews = useReviewsBadgeCount(auth.isAuthenticated)
|
||||
@@ -100,8 +108,17 @@ export function Sidebar() {
|
||||
const webhooks = useWebhookSubscriptions(hasInternal)
|
||||
|
||||
const dictsCount = dictsQuery.data?.length ?? 0
|
||||
const myDraftsCount =
|
||||
(myDrafts.data?.totalElements ?? 0) + (mySchemaDrafts.data?.totalElements ?? 0)
|
||||
// Считаем только actionable-драфты (то же что tab-badge в ReviewsPage):
|
||||
// record → 'pending', schema → 'pending'|'wip'. APPROVED/REJECTED/WITHDRAWN
|
||||
// — терминальны, не считаем.
|
||||
const myRecordPending = (myDrafts.data?.items ?? []).filter(
|
||||
(r) => classifyRecordStatus(r.status) === 'pending',
|
||||
).length
|
||||
const mySchemaPending = (mySchemaDrafts.data?.items ?? []).filter((s) => {
|
||||
const b = classifySchemaStatus(s.status)
|
||||
return b === 'pending' || b === 'wip'
|
||||
}).length
|
||||
const myDraftsCount = myRecordPending + mySchemaPending
|
||||
const reviewsCount = reviews.total
|
||||
// Pending events ждут dispatch. dlq отдельно — alarming, но не блокирует
|
||||
// нормальную работу, можно увидеть на /outbox. Badge показывает только
|
||||
@@ -469,8 +486,10 @@ export function MobileSidebar({ open, onClose }: { open: boolean; onClose: () =>
|
||||
const canReviewRecord = useCanReviewRecord()
|
||||
const isReviewer = canReviewSchema || canReviewRecord
|
||||
const dictsQuery = useDictionaries()
|
||||
const myDrafts = useMyDrafts(0, 1)
|
||||
const mySchemaDrafts = useMySchemaDrafts(0, 1)
|
||||
// size=50 (не size=1): см. desktop Sidebar — нужен .items[] для filter
|
||||
// по статусу (totalElements включает APPROVED/REJECTED).
|
||||
const myDrafts = useMyDrafts(0, 50)
|
||||
const mySchemaDrafts = useMySchemaDrafts(0, 50)
|
||||
const reviews = useReviewsBadgeCount(auth.isAuthenticated)
|
||||
// Same INTERNAL-scope gate as desktop Sidebar (см. line ~92).
|
||||
const hasInternal = useHasInternalScope()
|
||||
@@ -478,8 +497,17 @@ export function MobileSidebar({ open, onClose }: { open: boolean; onClose: () =>
|
||||
const webhooks = useWebhookSubscriptions(hasInternal)
|
||||
|
||||
const dictsCount = dictsQuery.data?.length ?? 0
|
||||
const myDraftsCount =
|
||||
(myDrafts.data?.totalElements ?? 0) + (mySchemaDrafts.data?.totalElements ?? 0)
|
||||
// Считаем только actionable-драфты (то же что tab-badge в ReviewsPage):
|
||||
// record → 'pending', schema → 'pending'|'wip'. APPROVED/REJECTED/WITHDRAWN
|
||||
// — терминальны, не считаем.
|
||||
const myRecordPending = (myDrafts.data?.items ?? []).filter(
|
||||
(r) => classifyRecordStatus(r.status) === 'pending',
|
||||
).length
|
||||
const mySchemaPending = (mySchemaDrafts.data?.items ?? []).filter((s) => {
|
||||
const b = classifySchemaStatus(s.status)
|
||||
return b === 'pending' || b === 'wip'
|
||||
}).length
|
||||
const myDraftsCount = myRecordPending + mySchemaPending
|
||||
const reviewsCount = reviews.total
|
||||
const outboxPending = outboxStats.data?.pending ?? 0
|
||||
const webhooksActive =
|
||||
|
||||
Reference in New Issue
Block a user