import { useRef, useState } from 'react'; import { LogViewer, Button } from '@cameleer/design-system'; import type { LogEntry } from '@cameleer/design-system'; import { RefreshCw } from 'lucide-react'; import { useStartupLogs } from '../api/queries/logs'; import type { Deployment } from '../api/queries/admin/apps'; import styles from './StartupLogPanel.module.css'; interface StartupLogPanelProps { deployment: Deployment; appSlug: string; envSlug: string; className?: string; } export function StartupLogPanel({ deployment, appSlug, envSlug, className }: StartupLogPanelProps) { const isStarting = deployment.status === 'STARTING'; const isFailed = deployment.status === 'FAILED'; const [sort, setSort] = useState<'asc' | 'desc'>('desc'); const scrollRef = useRef(null); const query = useStartupLogs(appSlug, envSlug, deployment.createdAt, isStarting, sort); const entries = query.data?.data ?? []; const scrollToLatest = () => { const el = scrollRef.current; if (!el || typeof el.scrollTo !== 'function') return; // asc → latest at bottom; desc → latest at top const top = sort === 'asc' ? el.scrollHeight : 0; el.scrollTo({ top, behavior: 'smooth' }); }; const handleRefresh = async () => { await query.refetch?.(); scrollToLatest(); }; if (entries.length === 0 && !isStarting) return null; return (
Startup Logs {isStarting && ( <> ● live polling every 3s )} {isFailed && ( stopped )}
{entries.length} entries
{entries.length > 0 ? ( ) : (
Waiting for container output...
)}
); }