Русификация переведена на официальные i18n-слои ReUI: полный русский словарь DataGrid (lib/reui-i18n-ru.ts) подключён через data-grid-i18n во FrameDataGrid и ResourcePage — меню сортировки, «Загрузка…», «Нет данных» и пагинация больше не откатываются к английским дефолтам компонентов. Словарь фильтров дополнен ~30 недостающими ключами, каскадер в мастере проверки переведён целиком. Исправлены некорректные и разъехавшиеся лейблы: accept -> «Принять», API-триггер -> «через API», «арендатор» вместо «Тенант», «Наблюдатель» вместо «Просмотр», «Основной» вместо «Мастер (плоскость)», «AS-префиксы», «DoH-профили», колонка канбана «В очереди».
134 lines
4.1 KiB
TypeScript
134 lines
4.1 KiB
TypeScript
import { useMemo } from 'react'
|
||
|
||
import { DataGridMutedCell } from '@/components/data-grid-cell'
|
||
import { StatusBadge } from '@/components/status-badge'
|
||
import {
|
||
Kanban,
|
||
KanbanBoard,
|
||
KanbanColumn,
|
||
KanbanColumnContent,
|
||
KanbanItem,
|
||
KanbanOverlay,
|
||
} from '@/components/reui/kanban'
|
||
import { Frame, FramePanel } from '@/components/reui/frame'
|
||
import { Badge } from '@/components/reui/badge'
|
||
import {
|
||
Item,
|
||
ItemContent,
|
||
ItemDescription,
|
||
ItemTitle,
|
||
} from '@evobgp/ui/components/item'
|
||
import { jobKindRu } from '@/lib/ui-labels'
|
||
import type { JobRow } from '@/types/api'
|
||
|
||
/**
|
||
* Operations jobs board — ReUI Kanban (read-only columns).
|
||
* @see https://reui.io/preview/base/kanban-board-8
|
||
* @see https://reui.io/docs/components/base/kanban
|
||
* @see https://reui.io/docs/components/base/frame
|
||
*/
|
||
|
||
const COLUMN_ORDER = ['queued', 'running', 'succeeded', 'failed'] as const
|
||
|
||
const COLUMN_LABELS: Record<(typeof COLUMN_ORDER)[number], string> = {
|
||
queued: 'В очереди',
|
||
running: 'Выполняются',
|
||
succeeded: 'Успешные',
|
||
failed: 'Ошибки',
|
||
}
|
||
|
||
function columnForStatus(status: string): (typeof COLUMN_ORDER)[number] {
|
||
const s = status.toLowerCase()
|
||
if (s === 'queued') return 'queued'
|
||
if (s === 'running') return 'running'
|
||
if (s === 'succeeded') return 'succeeded'
|
||
return 'failed'
|
||
}
|
||
|
||
function emptyColumns(): Record<string, JobRow[]> {
|
||
return {
|
||
queued: [],
|
||
running: [],
|
||
succeeded: [],
|
||
failed: [],
|
||
}
|
||
}
|
||
|
||
export function OperationsJobsKanban({
|
||
items,
|
||
nameById,
|
||
}: {
|
||
items: JobRow[]
|
||
nameById: Map<string, string>
|
||
}) {
|
||
const columns = useMemo(() => {
|
||
const next = emptyColumns()
|
||
for (const job of items) {
|
||
next[columnForStatus(job.status)].push(job)
|
||
}
|
||
return next
|
||
}, [items])
|
||
|
||
return (
|
||
<Frame dense spacing="sm" className="w-full min-w-0">
|
||
<FramePanel className="p-4">
|
||
<Kanban
|
||
value={columns}
|
||
onValueChange={() => undefined}
|
||
getItemValue={(job) => job.job_id}
|
||
>
|
||
<KanbanBoard className="grid auto-rows-fr grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
||
{COLUMN_ORDER.map((columnId) => (
|
||
<KanbanColumn
|
||
key={columnId}
|
||
value={columnId}
|
||
disabled
|
||
className="bg-muted/30 flex min-h-40 flex-col gap-3 rounded-lg border p-3"
|
||
>
|
||
<div className="flex items-center justify-between gap-2">
|
||
<p className="text-sm font-medium">{COLUMN_LABELS[columnId]}</p>
|
||
<Badge variant="outline" size="sm">
|
||
{columns[columnId]?.length ?? 0}
|
||
</Badge>
|
||
</div>
|
||
<KanbanColumnContent value={columnId}>
|
||
{(columns[columnId] ?? []).map((job) => (
|
||
<KanbanItem
|
||
key={job.job_id}
|
||
value={job.job_id}
|
||
disabled
|
||
className="p-0"
|
||
>
|
||
<Item variant="outline" size="sm">
|
||
<ItemContent>
|
||
<ItemTitle>{jobKindRu(job.kind)}</ItemTitle>
|
||
<StatusBadge status={job.status} />
|
||
{job.meta?.module_id ? (
|
||
<ItemDescription>
|
||
<DataGridMutedCell>
|
||
{nameById.get(String(job.meta.module_id)) ??
|
||
String(job.meta.module_id)}
|
||
</DataGridMutedCell>
|
||
</ItemDescription>
|
||
) : null}
|
||
</ItemContent>
|
||
</Item>
|
||
</KanbanItem>
|
||
))}
|
||
</KanbanColumnContent>
|
||
</KanbanColumn>
|
||
))}
|
||
</KanbanBoard>
|
||
<KanbanOverlay>
|
||
<Item variant="outline" size="sm">
|
||
<ItemContent>
|
||
<ItemTitle>Задача</ItemTitle>
|
||
</ItemContent>
|
||
</Item>
|
||
</KanbanOverlay>
|
||
</Kanban>
|
||
</FramePanel>
|
||
</Frame>
|
||
)
|
||
}
|