fix(web): align grid columns with reui reference and clean labels

Гриды операций и расписания выровнены по эталону data-grid-filtering-2:
явные размеры колонок (size в columnDef) вместо равномерного деления
при table-layout: fixed — колонка названия доминирует, второстепенные
сжаты по содержимому, пропали обрезанные имена («partner-dom…»,
«Обновлен...»). Убраны фейковые многоточия из JS-срезов: ID ревизии и
варианты выбора в сравнении теперь показываются целиком, а усечение
делает CSS-truncate. Подписи «Ревизия A/B» переведены на Field/FieldLabel
вместо самодельных span, шапка блока diff дополнена заголовком
«ревизия A → ревизия B» (CodeBlockTitle) слева от кнопок.
This commit is contained in:
Denozordec
2026-09-25 22:14:02 +07:00
parent 09580bbcab
commit ecd48642de
4 changed files with 26 additions and 13 deletions
@@ -93,6 +93,7 @@ export function OperationsJobsGrid({
) )
}, },
meta: { headerTitle: 'Вид' }, meta: { headerTitle: 'Вид' },
size: 320,
}, },
{ {
accessorKey: 'status', accessorKey: 'status',
@@ -105,6 +106,7 @@ export function OperationsJobsGrid({
return <StatusBadge status={row.original.status} hint={hint} /> return <StatusBadge status={row.original.status} hint={hint} />
}, },
meta: { headerTitle: 'Статус' }, meta: { headerTitle: 'Статус' },
size: 150,
}, },
{ {
id: 'created_at', id: 'created_at',
@@ -118,6 +120,7 @@ export function OperationsJobsGrid({
</DataGridMutedCell> </DataGridMutedCell>
), ),
meta: { headerTitle: 'Создана' }, meta: { headerTitle: 'Создана' },
size: 190,
}, },
{ {
id: 'finished_at', id: 'finished_at',
@@ -131,6 +134,7 @@ export function OperationsJobsGrid({
</DataGridMutedCell> </DataGridMutedCell>
), ),
meta: { headerTitle: 'Завершена' }, meta: { headerTitle: 'Завершена' },
size: 190,
}, },
{ {
id: 'actions', id: 'actions',
@@ -56,9 +56,10 @@ export function OperationsRevisionsGrid({
accessorFn: (row) => row.id, accessorFn: (row) => row.id,
header: ({ column }) => <DataGridColumnHeader column={column} title="ID" />, header: ({ column }) => <DataGridColumnHeader column={column} title="ID" />,
cell: ({ row }) => ( cell: ({ row }) => (
<DataGridNameCell icon={GitCommitHorizontal} title={`${row.original.id.slice(0, 12)}…`} /> <DataGridNameCell icon={GitCommitHorizontal} title={row.original.id} />
), ),
meta: { headerTitle: 'ID' }, meta: { headerTitle: 'ID' },
size: 340,
}, },
{ {
accessorKey: 'created_at', accessorKey: 'created_at',
@@ -69,6 +70,7 @@ export function OperationsRevisionsGrid({
</DataGridMutedCell> </DataGridMutedCell>
), ),
meta: { headerTitle: 'Создана' }, meta: { headerTitle: 'Создана' },
size: 210,
}, },
{ {
accessorKey: 'materialized_prefix_count', accessorKey: 'materialized_prefix_count',
@@ -79,6 +81,7 @@ export function OperationsRevisionsGrid({
</span> </span>
), ),
meta: { headerTitle: 'Префиксов' }, meta: { headerTitle: 'Префиксов' },
size: 150,
}, },
{ {
id: 'actions', id: 'actions',
@@ -91,7 +94,7 @@ export function OperationsRevisionsGrid({
<RefreshCw className="size-3.5" /> <RefreshCw className="size-3.5" />
</Button> </Button>
} }
title={`Откатиться к ревизии ${row.original.id.slice(0, 8)}…?`} title={`Откатиться к ревизии ${row.original.id}?`}
description="Будет создана новая ревизия на основе выбранной. Требуется роль оператора." description="Будет создана новая ревизия на основе выбранной. Требуется роль оператора."
confirmLabel="Откатить" confirmLabel="Откатить"
destructive destructive
@@ -52,12 +52,14 @@ export function ScheduleModulesGrid({
header: ({ column }) => <DataGridColumnHeader column={column} title="Модуль" />, header: ({ column }) => <DataGridColumnHeader column={column} title="Модуль" />,
cell: ({ row }) => <DataGridNameCell icon={Boxes} title={row.original.name} />, cell: ({ row }) => <DataGridNameCell icon={Boxes} title={row.original.name} />,
meta: { headerTitle: 'Модуль' }, meta: { headerTitle: 'Модуль' },
size: 280,
}, },
{ {
accessorKey: 'type', accessorKey: 'type',
header: ({ column }) => <DataGridColumnHeader column={column} title="Тип" />, header: ({ column }) => <DataGridColumnHeader column={column} title="Тип" />,
cell: ({ row }) => <CategoryBadge>{moduleTypeRu(row.original.type)}</CategoryBadge>, cell: ({ row }) => <CategoryBadge>{moduleTypeRu(row.original.type)}</CategoryBadge>,
meta: { headerTitle: 'Тип' }, meta: { headerTitle: 'Тип' },
size: 150,
}, },
{ {
id: 'schedule', id: 'schedule',
@@ -70,6 +72,7 @@ export function ScheduleModulesGrid({
</DataGridMonoCell> </DataGridMonoCell>
), ),
meta: { headerTitle: 'Расписание' }, meta: { headerTitle: 'Расписание' },
size: 130,
}, },
{ {
id: 'last_refreshed_at', id: 'last_refreshed_at',
@@ -83,6 +86,7 @@ export function ScheduleModulesGrid({
</DataGridMutedCell> </DataGridMutedCell>
), ),
meta: { headerTitle: 'Обновлено' }, meta: { headerTitle: 'Обновлено' },
size: 190,
}, },
{ {
id: 'enabled', id: 'enabled',
@@ -92,6 +96,7 @@ export function ScheduleModulesGrid({
<ModeBadge enabled={row.original.enabled} onLabel="Вкл" offLabel="Выкл" /> <ModeBadge enabled={row.original.enabled} onLabel="Вкл" offLabel="Выкл" />
), ),
meta: { headerTitle: 'Статус' }, meta: { headerTitle: 'Статус' },
size: 110,
}, },
{ {
id: 'actions', id: 'actions',
+12 -11
View File
@@ -5,6 +5,7 @@ import { toast } from 'sonner'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { Button } from '@evobgp/ui/components/button' import { Button } from '@evobgp/ui/components/button'
import { Field, FieldLabel } from '@evobgp/ui/components/field'
import { SegmentedTabs, TabsContent } from '@/components/segmented-tabs' import { SegmentedTabs, TabsContent } from '@/components/segmented-tabs'
import { import {
FrameSection, FrameSection,
@@ -19,6 +20,7 @@ import {
CodeBlockCopyButton, CodeBlockCopyButton,
CodeBlockExpandButton, CodeBlockExpandButton,
CodeBlockHeader, CodeBlockHeader,
CodeBlockTitle,
} from '@/components/reui/code-block/code-block' } from '@/components/reui/code-block/code-block'
import type { CodeBlockDiffSpec } from '@/components/reui/code-block/code-block-highlight' import type { CodeBlockDiffSpec } from '@/components/reui/code-block/code-block-highlight'
import { SelectMenu } from '@/components/select-field' import { SelectMenu } from '@/components/select-field'
@@ -275,35 +277,31 @@ function DiffTab({ revisions }: { revisions: RevisionRow[] }) {
const [b, setB] = useState('') const [b, setB] = useState('')
const diffQ = useQuery(operationsDiffQueryOptions(a, b)) const diffQ = useQuery(operationsDiffQueryOptions(a, b))
const revisionItems = useMemo( const revisionItems = useMemo(
() => () => revisions.map((r) => ({ value: r.id, label: r.id })),
revisions.map((r) => ({
value: r.id,
label: `${r.id.slice(0, 12)}…`,
})),
[revisions], [revisions],
) )
return ( return (
<FrameSection title="Сравнение ревизий" contentClassName="flex flex-col gap-4 py-4"> <FrameSection title="Сравнение ревизий" contentClassName="flex flex-col gap-4 py-4">
<div className="flex flex-wrap items-end gap-3"> <div className="flex flex-wrap items-end gap-3">
<div className="flex w-full max-w-xs flex-col gap-1"> <Field className="w-full max-w-xs">
<span className="text-xs text-muted-foreground">Ревизия A</span> <FieldLabel>Ревизия A</FieldLabel>
<SelectMenu <SelectMenu
items={revisionItems} items={revisionItems}
value={a} value={a}
placeholder="Выберите" placeholder="Выберите"
onValueChange={(v) => v && setA(v)} onValueChange={(v) => v && setA(v)}
/> />
</div> </Field>
<div className="flex w-full max-w-xs flex-col gap-1"> <Field className="w-full max-w-xs">
<span className="text-xs text-muted-foreground">Ревизия B</span> <FieldLabel>Ревизия B</FieldLabel>
<SelectMenu <SelectMenu
items={revisionItems} items={revisionItems}
value={b} value={b}
placeholder="Выберите" placeholder="Выберите"
onValueChange={(v) => v && setB(v)} onValueChange={(v) => v && setB(v)}
/> />
</div> </Field>
<Button onClick={() => diffQ.refetch()} disabled={!a || !b || diffQ.isFetching}> <Button onClick={() => diffQ.refetch()} disabled={!a || !b || diffQ.isFetching}>
Сравнить Сравнить
</Button> </Button>
@@ -363,6 +361,9 @@ function DiffView({ diff }: { diff: import('@/types/api').RevisionDiff }) {
label="Различия ревизий" label="Различия ревизий"
> >
<CodeBlockHeader> <CodeBlockHeader>
<CodeBlockTitle className="flex-1">
{`${diff.revision_a ?? '—'} → ${diff.revision_b ?? '—'}`}
</CodeBlockTitle>
<CodeBlockCopyButton /> <CodeBlockCopyButton />
<CodeBlockExpandButton>Показать всё</CodeBlockExpandButton> <CodeBlockExpandButton>Показать всё</CodeBlockExpandButton>
</CodeBlockHeader> </CodeBlockHeader>