84a4de4ceb
Phase 2 admin UI на скелете Phase 0/1 (e438c4c,2020af9). Делает workflow end-to-end usable: reviewer'ы могут approve/reject через UI; admins включают approval_required per-dict через checkbox. API surface (admin-ui): - types: DraftStatus, DraftOperation, DraftResponse, SubmitDraftRequest, ReviewQueuePage. + DictionaryDefinition: approvalRequired, approvalMinRole. - queries (react-query): * useReviewQueue (page, size) — global queue, refetch 30s. * useDraft(id) — single draft for diff drawer. * useLiveRecord(dict, bk) — current live record for side-by-side comparison. - mutations: * useSubmitDraft(dict) — POST /dictionaries/{n}/records/drafts * useApproveDraft() — POST /drafts/{id}/approve * useRejectDraft() — POST /drafts/{id}/reject (reason required) * useWithdrawDraft() — DELETE /drafts/{id} New /reviews route: - Table queue: dict, business_key, operation badge, maker, submitted_at. - Click "Просмотр" → side-by-side drawer: * left: current live (если есть; для CREATE — placeholder). * right: proposed (или CLOSE notice). * maker comment chip если есть. * Reviewer comment input + Approve / Reject buttons. * Reject disabled пока comment пустой (mirror's backend 400). - Auto-invalidates на success — queue refresh, list updates. - Nav link "Согласования" в header. DictionaryEditorDialog Metadata tab: - New checkbox "Требовать approval (maker-checker)" — orbit/8 styled (отделимо от Redis projection card visually). - При checked → shown approval_min_role TextInput (e.g. "ordinis:internal"). - payload sends approvalRequired + approvalMinRole. i18n RU/EN: - nav.reviews, reviews.{title,description,empty,queueTotal_*,col.*, action.*, drawer.*} - schema.approvalRequired.{label,hint}, schema.approvalMinRole.{label,hint} - Plurals для RU queueTotal (one/few/many/other). Verify: - pnpm tsc --noEmit: clean. - pnpm test (vitest): 89/89 PASS. - pnpm build: clean. - routeTree.gen.ts auto-regenerated с /reviews. Phase 3 (next session): - e2e tests: full flow maker submit → checker approve → record live + outbox event. - e2e: reject keeps draft, doesn't publish. - e2e: self-approve blocked (no_self_approve constraint). - e2e: two pending drafts на one business_key blocked (one_pending_per_key). - Per-dict opt-in soak: 1-2 dicts (например ground_station) с approval_required=true в staging.
290 lines
8.3 KiB
TypeScript
290 lines
8.3 KiB
TypeScript
/* eslint-disable */
|
|
|
|
// @ts-nocheck
|
|
|
|
// noinspection JSUnusedGlobalSymbols
|
|
|
|
// This file was automatically generated by TanStack Router.
|
|
// You should NOT make any changes in this file as it will be overwritten.
|
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
|
|
import { Route as rootRouteImport } from './routes/__root'
|
|
import { Route as WebhooksRouteImport } from './routes/webhooks'
|
|
import { Route as SearchRouteImport } from './routes/search'
|
|
import { Route as ReviewsRouteImport } from './routes/reviews'
|
|
import { Route as OutboxRouteImport } from './routes/outbox'
|
|
import { Route as DictionariesRouteImport } from './routes/dictionaries'
|
|
import { Route as AuditRouteImport } from './routes/audit'
|
|
import { Route as IndexRouteImport } from './routes/index'
|
|
import { Route as WebhooksIndexRouteImport } from './routes/webhooks.index'
|
|
import { Route as DictionariesIndexRouteImport } from './routes/dictionaries.index'
|
|
import { Route as WebhooksIdRouteImport } from './routes/webhooks.$id'
|
|
import { Route as DictionariesNameRouteImport } from './routes/dictionaries.$name'
|
|
|
|
const WebhooksRoute = WebhooksRouteImport.update({
|
|
id: '/webhooks',
|
|
path: '/webhooks',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const SearchRoute = SearchRouteImport.update({
|
|
id: '/search',
|
|
path: '/search',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const ReviewsRoute = ReviewsRouteImport.update({
|
|
id: '/reviews',
|
|
path: '/reviews',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const OutboxRoute = OutboxRouteImport.update({
|
|
id: '/outbox',
|
|
path: '/outbox',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const DictionariesRoute = DictionariesRouteImport.update({
|
|
id: '/dictionaries',
|
|
path: '/dictionaries',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const AuditRoute = AuditRouteImport.update({
|
|
id: '/audit',
|
|
path: '/audit',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const IndexRoute = IndexRouteImport.update({
|
|
id: '/',
|
|
path: '/',
|
|
getParentRoute: () => rootRouteImport,
|
|
} as any)
|
|
const WebhooksIndexRoute = WebhooksIndexRouteImport.update({
|
|
id: '/',
|
|
path: '/',
|
|
getParentRoute: () => WebhooksRoute,
|
|
} as any)
|
|
const DictionariesIndexRoute = DictionariesIndexRouteImport.update({
|
|
id: '/',
|
|
path: '/',
|
|
getParentRoute: () => DictionariesRoute,
|
|
} as any)
|
|
const WebhooksIdRoute = WebhooksIdRouteImport.update({
|
|
id: '/$id',
|
|
path: '/$id',
|
|
getParentRoute: () => WebhooksRoute,
|
|
} as any)
|
|
const DictionariesNameRoute = DictionariesNameRouteImport.update({
|
|
id: '/$name',
|
|
path: '/$name',
|
|
getParentRoute: () => DictionariesRoute,
|
|
} as any)
|
|
|
|
export interface FileRoutesByFullPath {
|
|
'/': typeof IndexRoute
|
|
'/audit': typeof AuditRoute
|
|
'/dictionaries': typeof DictionariesRouteWithChildren
|
|
'/outbox': typeof OutboxRoute
|
|
'/reviews': typeof ReviewsRoute
|
|
'/search': typeof SearchRoute
|
|
'/webhooks': typeof WebhooksRouteWithChildren
|
|
'/dictionaries/$name': typeof DictionariesNameRoute
|
|
'/webhooks/$id': typeof WebhooksIdRoute
|
|
'/dictionaries/': typeof DictionariesIndexRoute
|
|
'/webhooks/': typeof WebhooksIndexRoute
|
|
}
|
|
export interface FileRoutesByTo {
|
|
'/': typeof IndexRoute
|
|
'/audit': typeof AuditRoute
|
|
'/outbox': typeof OutboxRoute
|
|
'/reviews': typeof ReviewsRoute
|
|
'/search': typeof SearchRoute
|
|
'/dictionaries/$name': typeof DictionariesNameRoute
|
|
'/webhooks/$id': typeof WebhooksIdRoute
|
|
'/dictionaries': typeof DictionariesIndexRoute
|
|
'/webhooks': typeof WebhooksIndexRoute
|
|
}
|
|
export interface FileRoutesById {
|
|
__root__: typeof rootRouteImport
|
|
'/': typeof IndexRoute
|
|
'/audit': typeof AuditRoute
|
|
'/dictionaries': typeof DictionariesRouteWithChildren
|
|
'/outbox': typeof OutboxRoute
|
|
'/reviews': typeof ReviewsRoute
|
|
'/search': typeof SearchRoute
|
|
'/webhooks': typeof WebhooksRouteWithChildren
|
|
'/dictionaries/$name': typeof DictionariesNameRoute
|
|
'/webhooks/$id': typeof WebhooksIdRoute
|
|
'/dictionaries/': typeof DictionariesIndexRoute
|
|
'/webhooks/': typeof WebhooksIndexRoute
|
|
}
|
|
export interface FileRouteTypes {
|
|
fileRoutesByFullPath: FileRoutesByFullPath
|
|
fullPaths:
|
|
| '/'
|
|
| '/audit'
|
|
| '/dictionaries'
|
|
| '/outbox'
|
|
| '/reviews'
|
|
| '/search'
|
|
| '/webhooks'
|
|
| '/dictionaries/$name'
|
|
| '/webhooks/$id'
|
|
| '/dictionaries/'
|
|
| '/webhooks/'
|
|
fileRoutesByTo: FileRoutesByTo
|
|
to:
|
|
| '/'
|
|
| '/audit'
|
|
| '/outbox'
|
|
| '/reviews'
|
|
| '/search'
|
|
| '/dictionaries/$name'
|
|
| '/webhooks/$id'
|
|
| '/dictionaries'
|
|
| '/webhooks'
|
|
id:
|
|
| '__root__'
|
|
| '/'
|
|
| '/audit'
|
|
| '/dictionaries'
|
|
| '/outbox'
|
|
| '/reviews'
|
|
| '/search'
|
|
| '/webhooks'
|
|
| '/dictionaries/$name'
|
|
| '/webhooks/$id'
|
|
| '/dictionaries/'
|
|
| '/webhooks/'
|
|
fileRoutesById: FileRoutesById
|
|
}
|
|
export interface RootRouteChildren {
|
|
IndexRoute: typeof IndexRoute
|
|
AuditRoute: typeof AuditRoute
|
|
DictionariesRoute: typeof DictionariesRouteWithChildren
|
|
OutboxRoute: typeof OutboxRoute
|
|
ReviewsRoute: typeof ReviewsRoute
|
|
SearchRoute: typeof SearchRoute
|
|
WebhooksRoute: typeof WebhooksRouteWithChildren
|
|
}
|
|
|
|
declare module '@tanstack/react-router' {
|
|
interface FileRoutesByPath {
|
|
'/webhooks': {
|
|
id: '/webhooks'
|
|
path: '/webhooks'
|
|
fullPath: '/webhooks'
|
|
preLoaderRoute: typeof WebhooksRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/search': {
|
|
id: '/search'
|
|
path: '/search'
|
|
fullPath: '/search'
|
|
preLoaderRoute: typeof SearchRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/reviews': {
|
|
id: '/reviews'
|
|
path: '/reviews'
|
|
fullPath: '/reviews'
|
|
preLoaderRoute: typeof ReviewsRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/outbox': {
|
|
id: '/outbox'
|
|
path: '/outbox'
|
|
fullPath: '/outbox'
|
|
preLoaderRoute: typeof OutboxRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/dictionaries': {
|
|
id: '/dictionaries'
|
|
path: '/dictionaries'
|
|
fullPath: '/dictionaries'
|
|
preLoaderRoute: typeof DictionariesRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/audit': {
|
|
id: '/audit'
|
|
path: '/audit'
|
|
fullPath: '/audit'
|
|
preLoaderRoute: typeof AuditRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/': {
|
|
id: '/'
|
|
path: '/'
|
|
fullPath: '/'
|
|
preLoaderRoute: typeof IndexRouteImport
|
|
parentRoute: typeof rootRouteImport
|
|
}
|
|
'/webhooks/': {
|
|
id: '/webhooks/'
|
|
path: '/'
|
|
fullPath: '/webhooks/'
|
|
preLoaderRoute: typeof WebhooksIndexRouteImport
|
|
parentRoute: typeof WebhooksRoute
|
|
}
|
|
'/dictionaries/': {
|
|
id: '/dictionaries/'
|
|
path: '/'
|
|
fullPath: '/dictionaries/'
|
|
preLoaderRoute: typeof DictionariesIndexRouteImport
|
|
parentRoute: typeof DictionariesRoute
|
|
}
|
|
'/webhooks/$id': {
|
|
id: '/webhooks/$id'
|
|
path: '/$id'
|
|
fullPath: '/webhooks/$id'
|
|
preLoaderRoute: typeof WebhooksIdRouteImport
|
|
parentRoute: typeof WebhooksRoute
|
|
}
|
|
'/dictionaries/$name': {
|
|
id: '/dictionaries/$name'
|
|
path: '/$name'
|
|
fullPath: '/dictionaries/$name'
|
|
preLoaderRoute: typeof DictionariesNameRouteImport
|
|
parentRoute: typeof DictionariesRoute
|
|
}
|
|
}
|
|
}
|
|
|
|
interface DictionariesRouteChildren {
|
|
DictionariesNameRoute: typeof DictionariesNameRoute
|
|
DictionariesIndexRoute: typeof DictionariesIndexRoute
|
|
}
|
|
|
|
const DictionariesRouteChildren: DictionariesRouteChildren = {
|
|
DictionariesNameRoute: DictionariesNameRoute,
|
|
DictionariesIndexRoute: DictionariesIndexRoute,
|
|
}
|
|
|
|
const DictionariesRouteWithChildren = DictionariesRoute._addFileChildren(
|
|
DictionariesRouteChildren,
|
|
)
|
|
|
|
interface WebhooksRouteChildren {
|
|
WebhooksIdRoute: typeof WebhooksIdRoute
|
|
WebhooksIndexRoute: typeof WebhooksIndexRoute
|
|
}
|
|
|
|
const WebhooksRouteChildren: WebhooksRouteChildren = {
|
|
WebhooksIdRoute: WebhooksIdRoute,
|
|
WebhooksIndexRoute: WebhooksIndexRoute,
|
|
}
|
|
|
|
const WebhooksRouteWithChildren = WebhooksRoute._addFileChildren(
|
|
WebhooksRouteChildren,
|
|
)
|
|
|
|
const rootRouteChildren: RootRouteChildren = {
|
|
IndexRoute: IndexRoute,
|
|
AuditRoute: AuditRoute,
|
|
DictionariesRoute: DictionariesRouteWithChildren,
|
|
OutboxRoute: OutboxRoute,
|
|
ReviewsRoute: ReviewsRoute,
|
|
SearchRoute: SearchRoute,
|
|
WebhooksRoute: WebhooksRouteWithChildren,
|
|
}
|
|
export const routeTree = rootRouteImport
|
|
._addFileChildren(rootRouteChildren)
|
|
._addFileTypes<FileRouteTypes>()
|