- Added a new function for determining job status badge variants to improve UI consistency. - Refactored imports to utilize the core UI library for better maintainability. - Updated job report and filters components to enhance user experience and streamline functionality. - Improved layout and responsiveness across operations-related components.
121 lines
3.5 KiB
Svelte
121 lines
3.5 KiB
Svelte
<script lang="ts">
|
|
import type { RevisionRow } from '$lib/api/types.js';
|
|
import { Button } from '$lib/ui/core/button/index.js';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle
|
|
} from '$lib/ui/core/card/index.js';
|
|
import AppDataTable from '$lib/ui/patterns/data-table/app-data-table.svelte';
|
|
import { formatDateTime } from '$lib/modules/display.js';
|
|
import RefreshCw from '@lucide/svelte/icons/refresh-cw';
|
|
import Undo from '@lucide/svelte/icons/undo';
|
|
import Eye from '@lucide/svelte/icons/eye';
|
|
import Download from '@lucide/svelte/icons/download';
|
|
|
|
type Props = {
|
|
revisions: RevisionRow[];
|
|
revLoading: boolean;
|
|
onReload: () => void;
|
|
onOpenPreview: (rev: RevisionRow) => void;
|
|
onRollbackRequest: (rev: RevisionRow) => void;
|
|
onDownloadDiagnosticLog: (rev: RevisionRow) => void;
|
|
};
|
|
|
|
let {
|
|
revisions,
|
|
revLoading,
|
|
onReload,
|
|
onOpenPreview,
|
|
onRollbackRequest,
|
|
onDownloadDiagnosticLog
|
|
}: Props = $props();
|
|
|
|
const columns = [
|
|
{
|
|
id: 'id',
|
|
label: 'ID',
|
|
sortable: true,
|
|
sortValue: (rev: RevisionRow) => rev.id
|
|
},
|
|
{
|
|
id: 'created',
|
|
label: 'Создана',
|
|
sortable: true,
|
|
sortValue: (rev: RevisionRow) => rev.created_at ?? ''
|
|
},
|
|
{
|
|
id: 'prefixes',
|
|
label: 'Префиксов',
|
|
sortable: true,
|
|
sortValue: (rev: RevisionRow) => rev.materialized_prefix_count ?? 0
|
|
},
|
|
{ id: 'hash', label: 'Хэш' },
|
|
{ id: 'actions', label: '', class: 'w-32' }
|
|
] as const;
|
|
</script>
|
|
|
|
<Card>
|
|
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
|
<div class="min-w-0 flex-1">
|
|
<CardTitle class="text-base">История ревизий</CardTitle>
|
|
<CardDescription class="max-w-[75ch]">
|
|
Создаются задачей module_refresh (CDN / IP / AS и т.д.); в превью есть полный текст BIRD с
|
|
инклюдами
|
|
</CardDescription>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
class="shrink-0 self-start sm:self-auto"
|
|
onclick={onReload}
|
|
disabled={revLoading}
|
|
>
|
|
<RefreshCw class={revLoading ? 'animate-spin' : ''} />
|
|
</Button>
|
|
</CardHeader>
|
|
<CardContent class="min-w-0 p-4 pt-0">
|
|
<AppDataTable
|
|
columns={[...columns]}
|
|
rows={revisions}
|
|
rowKey={(rev) => rev.id}
|
|
loading={revLoading}
|
|
emptyTitle="Нет ревизий"
|
|
emptyDescription="Ревизии появятся после обновления модулей."
|
|
>
|
|
{#snippet cell({ row: rev, column })}
|
|
{#if column.id === 'id'}
|
|
<span class="font-mono text-xs">{rev.id.slice(0, 8)}…</span>
|
|
{:else if column.id === 'created'}
|
|
<span class="text-sm">{formatDateTime(rev.created_at)}</span>
|
|
{:else if column.id === 'prefixes'}
|
|
{rev.materialized_prefix_count}
|
|
{:else if column.id === 'hash'}
|
|
<span class="font-mono text-xs text-muted-foreground"
|
|
>{rev.content_hash.slice(0, 12)}…</span
|
|
>
|
|
{:else if column.id === 'actions'}
|
|
<div class="flex gap-1">
|
|
<Button variant="ghost" size="icon-sm" onclick={() => onOpenPreview(rev)}>
|
|
<Eye class="size-3.5" />
|
|
</Button>
|
|
<Button variant="ghost" size="icon-sm" onclick={() => onRollbackRequest(rev)}>
|
|
<Undo class="size-3.5" />
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
title="Скачать диагностический лог"
|
|
onclick={() => onDownloadDiagnosticLog(rev)}
|
|
>
|
|
<Download class="size-3.5" />
|
|
</Button>
|
|
</div>
|
|
{/if}
|
|
{/snippet}
|
|
</AppDataTable>
|
|
</CardContent>
|
|
</Card>
|