feat: add StartupLogPanel component for deployment startup logs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
60
ui/src/components/StartupLogPanel.module.css
Normal file
60
ui/src/components/StartupLogPanel.module.css
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
.panel {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerLeft {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 1px 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badgeLive {
|
||||||
|
background: var(--success-muted);
|
||||||
|
color: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badgeStopped {
|
||||||
|
background: var(--error-muted);
|
||||||
|
color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pollingHint {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineCount {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
46
ui/src/components/StartupLogPanel.tsx
Normal file
46
ui/src/components/StartupLogPanel.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { LogViewer } from '@cameleer/design-system';
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StartupLogPanel({ deployment, appSlug, envSlug }: StartupLogPanelProps) {
|
||||||
|
const isStarting = deployment.status === 'STARTING';
|
||||||
|
const isFailed = deployment.status === 'FAILED';
|
||||||
|
|
||||||
|
const { data } = useStartupLogs(appSlug, envSlug, deployment.createdAt, isStarting);
|
||||||
|
|
||||||
|
const entries = data?.data ?? [];
|
||||||
|
|
||||||
|
if (entries.length === 0 && !isStarting) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.panel}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
<div className={styles.headerLeft}>
|
||||||
|
<span className={styles.title}>Startup Logs</span>
|
||||||
|
{isStarting && (
|
||||||
|
<>
|
||||||
|
<span className={`${styles.badge} ${styles.badgeLive}`}>● live</span>
|
||||||
|
<span className={styles.pollingHint}>polling every 3s</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{isFailed && (
|
||||||
|
<span className={`${styles.badge} ${styles.badgeStopped}`}>stopped</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<span className={styles.lineCount}>{entries.length} lines</span>
|
||||||
|
</div>
|
||||||
|
{entries.length > 0 ? (
|
||||||
|
<LogViewer entries={entries} maxHeight={300} />
|
||||||
|
) : (
|
||||||
|
<div className={styles.empty}>Waiting for container output...</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user