feat(web): upgrade lists to ReUI Table v9 and EventCalendar
quality / commitlint (push) Skipped
quality / changes (push) Successful in 9s
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 39s
quality / web (push) Successful in 1m29s
quality / go (push) Successful in 1m3s
quality / bird2 (push) Successful in 15s
CD / quality (push) Successful in 3m43s
CD / publish (push) Failing after 8m29s

Единый kitDataGridTableLayout и ResourcePage/FrameDataGrid на всех списках.
Календарь задач переведён на EventCalendar, lookup — на cascader, у операций появился вид доски.
Удалены settings-7 и самописные DataGridSection/toolbar.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-08-23 01:38:56 +07:00
co-authored by Cursor
parent 927e27640a
commit d56405af7b
157 changed files with 39067 additions and 6110 deletions
@@ -0,0 +1,113 @@
import { useMemo } from 'react'
import { DataGridMutedCell } from '@/components/data-grid-cell'
import { StatusBadge } from '@/components/status-badge'
import {
Kanban,
KanbanBoard,
KanbanColumn,
KanbanColumnContent,
KanbanItem,
} from '@/components/reui/kanban'
import { Frame, FramePanel } from '@/components/reui/frame'
import { jobKindRu } from '@/lib/ui-labels'
import type { JobRow } from '@/types/api'
/**
* Operations jobs board view — ReUI Kanban (read-only columns).
* @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>
<span className="text-muted-foreground text-xs tabular-nums">
{columns[columnId]?.length ?? 0}
</span>
</div>
<KanbanColumnContent value={columnId}>
{(columns[columnId] ?? []).map((job) => (
<KanbanItem
key={job.job_id}
value={job.job_id}
disabled
className="bg-background flex flex-col gap-1 rounded-md border p-3"
>
<p className="text-sm leading-tight font-medium">
{jobKindRu(job.kind)}
</p>
<StatusBadge status={job.status} />
{job.meta?.module_id ? (
<DataGridMutedCell>
{nameById.get(String(job.meta.module_id)) ??
String(job.meta.module_id)}
</DataGridMutedCell>
) : null}
</KanbanItem>
))}
</KanbanColumnContent>
</KanbanColumn>
))}
</KanbanBoard>
</Kanban>
</FramePanel>
</Frame>
)
}