diff --git a/ordinis-admin-ui/src/i18n.ts b/ordinis-admin-ui/src/i18n.ts index f0666d2..b40455c 100644 --- a/ordinis-admin-ui/src/i18n.ts +++ b/ordinis-admin-ui/src/i18n.ts @@ -500,6 +500,10 @@ i18n 'createDraft.toast.updateFailed': 'Не удалось обновить черновик', 'workflow.schemaDraft.actions.edit': 'Редактировать', // === Schema review queue panel === + 'reviews.tab.records': 'Записи', + 'reviews.tab.schemas': 'Схемы', + 'reviews.schema.empty': 'Нет схем на ревью', + 'reviews.schema.emptyDescription': 'Когда maker отправит schema draft на ревью, он появится здесь.', 'reviews.schema.title': 'Изменения схем', 'reviews.schema.label': 'Schema workflow', 'reviews.schema.queueTotal_one': '{{count}} draft ждёт ревью', @@ -1127,6 +1131,10 @@ i18n 'createDraft.toast.updateFailed': 'Failed to update draft', 'workflow.schemaDraft.actions.edit': 'Edit', // === Schema review queue panel === + 'reviews.tab.records': 'Records', + 'reviews.tab.schemas': 'Schemas', + 'reviews.schema.empty': 'No schemas under review', + 'reviews.schema.emptyDescription': 'Once a maker submits a schema draft for review, it will appear here.', 'reviews.schema.title': 'Schema changes', 'reviews.schema.label': 'Schema workflow', 'reviews.schema.queueTotal_one': '{{count}} draft awaiting review', diff --git a/ordinis-admin-ui/src/routes/reviews.tsx b/ordinis-admin-ui/src/routes/reviews.tsx index 171ee20..218c3bc 100644 --- a/ordinis-admin-ui/src/routes/reviews.tsx +++ b/ordinis-admin-ui/src/routes/reviews.tsx @@ -18,6 +18,7 @@ import { TableHead, TableHeaderCell, TableRow, + Tabs, TextArea, TextInput, } from '@/ui' @@ -49,9 +50,25 @@ type BulkResult = { failed: { id: string; bk: string; reason: string }[] } +type ReviewsTab = 'records' | 'schemas' + function ReviewsPage() { const { t } = useTranslation() const queue = useReviewQueue(0, 50) + const schemaQueue = useSchemaReviewQueue(0, 50) + const recordsCount = queue.data?.totalElements ?? 0 + const schemasCount = schemaQueue.data?.total ?? 0 + // Tab дефолтит на records (старее, чаще). Если schema queue не пустой + // а record queue пустой — переключаемся на schemas чтобы reviewer'у не + // пришлось кликать дважды. + const [activeTab, setActiveTab] = useState('records') + // Auto-switch один раз когда queries loaded и records=0/schemas>0. + useMemo(() => { + if (recordsCount === 0 && schemasCount > 0 && activeTab === 'records') { + setActiveTab('schemas') + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [recordsCount, schemasCount]) const [selectedId, setSelectedId] = useState(undefined) /** Phase 4: bulk approve/reject. Set — стабильное id'шник. */ const [selection, setSelection] = useState>(new Set()) @@ -142,17 +159,57 @@ function ReviewsPage() { description={t('reviews.description')} /> - + setActiveTab(v as ReviewsTab)} + items={[ + { + id: 'records', + label: t('reviews.tab.records', { defaultValue: 'Записи' }), + count: + recordsCount > 0 ? ( + {recordsCount} + ) : undefined, + }, + { + id: 'schemas', + label: t('reviews.tab.schemas', { defaultValue: 'Схемы' }), + count: + schemasCount > 0 ? ( + {schemasCount} + ) : undefined, + }, + ]} + /> - {queue.isLoading && } + {activeTab === 'schemas' && ( + <> + {schemaQueue.isLoading && } + + {schemasCount === 0 && !schemaQueue.isLoading && ( + + )} + + )} - {queue.error && ( + {activeTab === 'records' && queue.isLoading && ( + + )} + + {activeTab === 'records' && queue.error && ( {String(queue.error)} )} - {bulkResult && ( + {activeTab === 'records' && bulkResult && ( )} - {queue.data && queue.data.totalElements === 0 && ( + {activeTab === 'records' && queue.data && queue.data.totalElements === 0 && ( )} - {queue.data && queue.data.totalElements > 0 && ( + {activeTab === 'records' && queue.data && queue.data.totalElements > 0 && (