feat(web): add job run timeline and code-block revision diff
Раскрытие строки задачи показывает вертикальный ReUI Timeline: создана (с триггером) -> взята в работу -> результат с текстом ошибки. Diff ревизий переведён с самодельных <pre> на официальный @reui/code-block: единый блок с разметкой добавленных и удалённых строк (знаки +/- и тонировка), нумерацией, копированием и разворотом длинных списков. ResourcePage (filtered-вариант) получил поддержку expandedContent/getRowCanExpand — колонка раскрытия строится так же, как во FrameDataGrid. Точечные упрощения: прогресс BGP-сессий в мониторинге переведён на Progress из кита вместо самодельного бара; удалены @deprecated-константы ui-surface.ts, мёртвый data-grid-defaults.ts и неиспользуемый sparkline-ряд дашборда.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import {
|
||||
Timeline,
|
||||
TimelineContent,
|
||||
TimelineDate,
|
||||
TimelineHeader,
|
||||
TimelineIndicator,
|
||||
TimelineItem,
|
||||
TimelineSeparator,
|
||||
TimelineTitle,
|
||||
} from '@/components/reui/timeline'
|
||||
import { jobStatusRu, jobTriggerRu } from '@/lib/ui-labels'
|
||||
import type { JobRow } from '@/types/api'
|
||||
|
||||
/**
|
||||
* ReUI Timeline в раскрытии строки задач: создана → взята в работу → результат.
|
||||
* Активный шаг выводится из фактических отметок времени задачи.
|
||||
* @see https://reui.io/docs/components/base/timeline
|
||||
*/
|
||||
|
||||
const ruDateTime = (value: string | null | undefined) =>
|
||||
value ? new Date(value).toLocaleString('ru-RU') : undefined
|
||||
|
||||
function resultSubtitle(job: JobRow): string | undefined {
|
||||
if (job.error) return job.error
|
||||
const summary = job.meta?.apply_summary
|
||||
if (summary && typeof summary === 'object') {
|
||||
const message = (summary as Record<string, unknown>).message
|
||||
if (typeof message === 'string' && message !== '') return message
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function JobTimeline({ job }: { job: JobRow }) {
|
||||
const trigger = jobTriggerRu(job.meta?.trigger)
|
||||
const completed = job.finished_at ? 3 : job.started_at ? 2 : 1
|
||||
const failed = ['failed', 'error'].includes(job.status.toLowerCase())
|
||||
const subtitle = resultSubtitle(job)
|
||||
|
||||
return (
|
||||
<div className="py-4 ps-3 pe-2">
|
||||
<Timeline defaultValue={completed}>
|
||||
<TimelineItem step={1}>
|
||||
<TimelineHeader>
|
||||
<TimelineDate>{ruDateTime(job.created_at)}</TimelineDate>
|
||||
<TimelineTitle>Создана{trigger ? ` (${trigger})` : ''}</TimelineTitle>
|
||||
</TimelineHeader>
|
||||
<TimelineIndicator />
|
||||
<TimelineSeparator />
|
||||
<TimelineContent>Идентификатор: {job.job_id}</TimelineContent>
|
||||
</TimelineItem>
|
||||
<TimelineItem step={2}>
|
||||
<TimelineHeader>
|
||||
<TimelineDate>{ruDateTime(job.started_at)}</TimelineDate>
|
||||
<TimelineTitle>Взята в работу</TimelineTitle>
|
||||
</TimelineHeader>
|
||||
<TimelineIndicator />
|
||||
<TimelineSeparator />
|
||||
</TimelineItem>
|
||||
<TimelineItem step={3}>
|
||||
<TimelineHeader>
|
||||
<TimelineDate>{ruDateTime(job.finished_at)}</TimelineDate>
|
||||
<TimelineTitle className={failed ? 'text-destructive' : undefined}>
|
||||
{job.finished_at ? jobStatusRu(job.status) : 'Ещё выполняется'}
|
||||
</TimelineTitle>
|
||||
</TimelineHeader>
|
||||
<TimelineIndicator />
|
||||
<TimelineSeparator />
|
||||
{subtitle ? <TimelineContent>{subtitle}</TimelineContent> : null}
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { Button } from '@evobgp/ui/components/button'
|
||||
import { Badge } from '@/components/reui/badge'
|
||||
import { DataGridMutedCell, DataGridNameCell } from '@/components/data-grid-cell'
|
||||
import { StatusBadge } from '@/components/status-badge'
|
||||
import { JobTimeline } from '@/components/operations/job-timeline'
|
||||
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
|
||||
import type { FilterField, FilterQuery } from '@/components/reui/filters/filters-types'
|
||||
import {
|
||||
@@ -175,6 +176,8 @@ export function OperationsJobsGrid({
|
||||
pinLastColumn
|
||||
virtualization={items.length > 80}
|
||||
emptyState={{ title: 'Нет задач' }}
|
||||
getRowCanExpand={() => true}
|
||||
expandedContent={(row) => <JobTimeline job={row} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user