feat: show build logs alongside pod logs in app detail page
This commit is contained in:
@@ -47,6 +47,7 @@ export default function AppDetailPage() {
|
||||
const queryClient = useQueryClient();
|
||||
const appId = params.id as string;
|
||||
const [showLogs, setShowLogs] = useState(false);
|
||||
const [logTab, setLogTab] = useState<'pod' | 'build'>('pod');
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const logsEndRef = useRef<HTMLPreElement>(null);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
@@ -74,8 +75,15 @@ export default function AppDetailPage() {
|
||||
const { data: logsData } = useQuery<{ logs: string }>({
|
||||
queryKey: ['logs', appId],
|
||||
queryFn: () => api.get(`/deployments/applications/${appId}/logs`).then((r) => r.data),
|
||||
enabled: showLogs,
|
||||
refetchInterval: showLogs ? 3000 : false,
|
||||
enabled: showLogs && logTab === 'pod',
|
||||
refetchInterval: showLogs && logTab === 'pod' ? 3000 : false,
|
||||
});
|
||||
|
||||
const { data: buildLogsData } = useQuery<{ buildLog: string | null; status: string; version: string | null }>({
|
||||
queryKey: ['build-logs', appId],
|
||||
queryFn: () => api.get(`/deployments/applications/${appId}/build-logs`).then((r) => r.data),
|
||||
enabled: showLogs && logTab === 'build',
|
||||
refetchInterval: showLogs && logTab === 'build' ? 5000 : false,
|
||||
});
|
||||
|
||||
const { data: resourceUsage, isLoading: resourcesLoading } = useQuery<ResourceUsage>({
|
||||
@@ -779,17 +787,23 @@ export default function AppDetailPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Pod Logs */}
|
||||
{/* Logs — Pod & Build */}
|
||||
<div className="card">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-lg font-semibold text-gray-900">📋 Pod Logs</h2>
|
||||
<h2 className="text-lg font-semibold text-gray-900">📋 Logs</h2>
|
||||
<div className="flex items-center space-x-3">
|
||||
{showLogs && (
|
||||
{showLogs && logTab === 'pod' && (
|
||||
<span className="text-xs text-gray-400 flex items-center space-x-1">
|
||||
<span className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />
|
||||
<span>Live (every 3s)</span>
|
||||
</span>
|
||||
)}
|
||||
{showLogs && logTab === 'build' && (
|
||||
<span className="text-xs text-gray-400 flex items-center space-x-1">
|
||||
<span className="w-2 h-2 bg-blue-500 rounded-full animate-pulse" />
|
||||
<span>Auto-refresh (every 5s)</span>
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setShowLogs(!showLogs)}
|
||||
className="btn-secondary text-sm"
|
||||
@@ -799,12 +813,66 @@ export default function AppDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
{showLogs && (
|
||||
<pre
|
||||
ref={logsEndRef}
|
||||
className="bg-gray-900 text-green-400 p-4 rounded-lg text-xs font-mono overflow-x-auto max-h-[500px] overflow-y-auto whitespace-pre-wrap break-words"
|
||||
>
|
||||
{logsData?.logs || (isRunning ? 'Loading logs...' : isStopped ? 'Application is stopped. Start it to see logs.' : 'Waiting for pod to be ready...')}
|
||||
</pre>
|
||||
<div className="space-y-3">
|
||||
{/* Tab switcher */}
|
||||
<div className="flex space-x-1 bg-gray-100 rounded-lg p-1">
|
||||
<button
|
||||
onClick={() => setLogTab('pod')}
|
||||
className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||
logTab === 'pod'
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
🖥️ Pod Logs
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLogTab('build')}
|
||||
className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||
logTab === 'build'
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
🔨 Build Logs
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Pod logs */}
|
||||
{logTab === 'pod' && (
|
||||
<pre
|
||||
ref={logsEndRef}
|
||||
className="bg-gray-900 text-green-400 p-4 rounded-lg text-xs font-mono overflow-x-auto max-h-[500px] overflow-y-auto whitespace-pre-wrap break-words"
|
||||
>
|
||||
{logsData?.logs || (isRunning ? 'Loading logs...' : isStopped ? 'Application is stopped. Start it to see logs.' : 'Waiting for pod to be ready...')}
|
||||
</pre>
|
||||
)}
|
||||
|
||||
{/* Build logs */}
|
||||
{logTab === 'build' && (
|
||||
<div>
|
||||
{buildLogsData?.version && (
|
||||
<div className="flex items-center space-x-3 mb-2 text-xs text-gray-500">
|
||||
<span>📌 {buildLogsData.version}</span>
|
||||
<span className={`px-2 py-0.5 rounded-full font-medium ${statusColors[buildLogsData.status] || 'bg-gray-100'}`}>
|
||||
{buildLogsData.status}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<pre className="bg-gray-900 text-blue-300 p-4 rounded-lg text-xs font-mono overflow-x-auto max-h-[500px] overflow-y-auto whitespace-pre-wrap break-words">
|
||||
{buildLogsData?.buildLog || (
|
||||
buildLogsData?.status === 'building'
|
||||
? 'Build in progress... Logs will appear when complete.'
|
||||
: buildLogsData?.status === 'pending'
|
||||
? 'Build is pending...'
|
||||
: buildLogsData?.status === 'no_deployment'
|
||||
? 'No deployments yet. Deploy your app to see build logs.'
|
||||
: 'No build logs available for this deployment.'
|
||||
)}
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user