"use client" // Adapted from ReUI PRO sheet-14: event header, facts, tabs and stepping context. // https://reui.io/preview/base/sheet-14 import { useEffect, useState } from "react" import Link from "next/link" import { z } from "zod" import type { LogEntry } from "@mmapp/contracts" import { toast } from "sonner" import { CopyIcon, ExternalLinkIcon } from "lucide-react" import { Sheet, SheetContent, SheetTitle, SheetDescription, SheetHeader } from "@/components/ui/sheet" import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs" import { Button } from "@/components/ui/button" import { Skeleton } from "@/components/ui/skeleton" import { Alert, AlertTitle, AlertDescription } from "@/components/reui/alert" import { getLogContext } from "@/shared/api/logs" import { LevelBadge, formatLogTime } from "./log-presentation" export function LogDetailSheet({ entry, base, onClose, onSelect }: { entry: LogEntry | null; base: string; onClose: () => void; onSelect: (entry: LogEntry) => void }) { return { if (!open) onClose() }}> {entry && } } function LogDetail({ entry, base, onSelect }: { entry: LogEntry; base: string; onSelect: (entry: LogEntry) => void }) { const [context, setContext] = useState> | null>(null), [error, setError] = useState(null), [retry, setRetry] = useState(0) useEffect(() => { const ac = new AbortController() void getLogContext(base, entry.id, ac.signal).then(data => { if (!ac.signal.aborted) { setContext(data); setError(null) } }).catch(e => { if (!ac.signal.aborted) setError(e instanceof z.ZodError ? "Некорректный ответ контекста" : e.message) }) return () => ac.abort() }, [base, entry.id, retry]) const copy = () => { void navigator.clipboard.writeText(JSON.stringify(entry, null, 2)).then(() => toast.success("Событие скопировано"), () => toast.error("Не удалось скопировать событие")) } return <>
{entry.routerId}
Событие RouterOS{entry.serverName} · {entry.host} · {formatLogTime(entry.effectiveAt)}
СобытиеИсходные поляКонтекст

{entry.message}

{[["Topics", entry.topics.join(", ")], ["Время RouterOS", entry.rawTime], ["Получено", formatLogTime(entry.receivedAt)], ["Источник времени", entry.timeKind === "receipt" ? "Время получения: дата или часовой пояс RouterOS неоднозначны" : "Время RouterOS"], ["Поколение буфера", String(entry.generation)]].map(([label, value]) => )}
{JSON.stringify({ ".id": entry.routerId, time: entry.rawTime, topics: entry.topics.join(","), message: entry.message }, null, 2)}

До 10 событий до и после записи на этом MikroTik. Фильтры журнала здесь не применяются.

{error ? Контекст не получен{error} : !context ? : [context.before, [context.entry], context.after].flat().map(row => )}
} function FragmentPair({ label, value }: { label: string; value: string }) { return <>
{label}
{value}
}