logs
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Modal,
|
||||
Button,
|
||||
@ -39,6 +39,40 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
|
||||
const [execution, setExecution] = useState<FunctionExecution | null>(null);
|
||||
const [logs, setLogs] = useState<string[]>([]);
|
||||
const [loadingLogs, setLoadingLogs] = useState(false);
|
||||
const [autoRefreshLogs, setAutoRefreshLogs] = useState(false);
|
||||
const pollIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const logsPollIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const stopLogsAutoRefresh = () => {
|
||||
if (logsPollIntervalRef.current) {
|
||||
clearInterval(logsPollIntervalRef.current);
|
||||
logsPollIntervalRef.current = null;
|
||||
}
|
||||
setAutoRefreshLogs(false);
|
||||
};
|
||||
|
||||
// Cleanup intervals on unmount or when modal closes
|
||||
useEffect(() => {
|
||||
if (!opened) {
|
||||
// Stop auto-refresh when modal closes
|
||||
stopLogsAutoRefresh();
|
||||
if (pollIntervalRef.current) {
|
||||
clearTimeout(pollIntervalRef.current);
|
||||
}
|
||||
}
|
||||
}, [opened]);
|
||||
|
||||
// Cleanup intervals on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (pollIntervalRef.current) {
|
||||
clearTimeout(pollIntervalRef.current);
|
||||
}
|
||||
if (logsPollIntervalRef.current) {
|
||||
clearInterval(logsPollIntervalRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!func) return null;
|
||||
|
||||
@ -69,8 +103,13 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
|
||||
setResult(response.data);
|
||||
|
||||
if (async) {
|
||||
// Poll for execution status
|
||||
// Poll for execution status and start auto-refreshing logs
|
||||
pollExecution(response.data.execution_id);
|
||||
} else {
|
||||
// For synchronous executions, load logs immediately
|
||||
if (response.data.execution_id) {
|
||||
loadLogs(response.data.execution_id);
|
||||
}
|
||||
}
|
||||
|
||||
notifications.show({
|
||||
@ -91,19 +130,24 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
|
||||
};
|
||||
|
||||
const pollExecution = async (executionId: string) => {
|
||||
// Start auto-refreshing logs immediately for async executions
|
||||
startLogsAutoRefresh(executionId);
|
||||
|
||||
const poll = async () => {
|
||||
try {
|
||||
const response = await executionApi.getById(executionId);
|
||||
setExecution(response.data);
|
||||
|
||||
if (response.data.status === 'running' || response.data.status === 'pending') {
|
||||
setTimeout(poll, 2000); // Poll every 2 seconds
|
||||
pollIntervalRef.current = setTimeout(poll, 2000); // Poll every 2 seconds
|
||||
} else {
|
||||
// Execution completed, get logs
|
||||
// Execution completed, stop auto-refresh and load final logs
|
||||
stopLogsAutoRefresh();
|
||||
loadLogs(executionId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error polling execution:', error);
|
||||
stopLogsAutoRefresh();
|
||||
}
|
||||
};
|
||||
|
||||
@ -122,6 +166,28 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const startLogsAutoRefresh = (executionId: string) => {
|
||||
// Clear any existing interval
|
||||
if (logsPollIntervalRef.current) {
|
||||
clearInterval(logsPollIntervalRef.current);
|
||||
}
|
||||
|
||||
setAutoRefreshLogs(true);
|
||||
|
||||
// Load logs immediately
|
||||
loadLogs(executionId);
|
||||
|
||||
// Set up auto-refresh every 2 seconds
|
||||
logsPollIntervalRef.current = setInterval(async () => {
|
||||
try {
|
||||
const response = await executionApi.getLogs(executionId);
|
||||
setLogs(response.data.logs || []);
|
||||
} catch (error) {
|
||||
console.error('Error auto-refreshing logs:', error);
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const handleCancel = async () => {
|
||||
if (result && async) {
|
||||
try {
|
||||
@ -285,35 +351,60 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
|
||||
)}
|
||||
|
||||
{/* Logs */}
|
||||
{async && (
|
||||
<div style={{ marginTop: '1rem' }}>
|
||||
<Group justify="space-between" mb="xs">
|
||||
<div style={{ marginTop: '1rem' }}>
|
||||
<Group justify="space-between" mb="xs">
|
||||
<Group gap="xs">
|
||||
<Text size="sm" fw={500}>Logs:</Text>
|
||||
{autoRefreshLogs && (
|
||||
<Badge size="xs" color="blue" variant="light">
|
||||
Auto-refreshing
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
<Group gap="xs">
|
||||
{result.execution_id && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant={autoRefreshLogs ? "filled" : "light"}
|
||||
color={autoRefreshLogs ? "red" : "blue"}
|
||||
leftSection={<IconRefresh size={12} />}
|
||||
onClick={() => {
|
||||
if (autoRefreshLogs) {
|
||||
stopLogsAutoRefresh();
|
||||
} else {
|
||||
startLogsAutoRefresh(result.execution_id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{autoRefreshLogs ? 'Stop Auto-refresh' : 'Auto-refresh'}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="light"
|
||||
leftSection={<IconRefresh size={12} />}
|
||||
onClick={() => result.execution_id && loadLogs(result.execution_id)}
|
||||
loading={loadingLogs}
|
||||
disabled={autoRefreshLogs}
|
||||
>
|
||||
Refresh
|
||||
Manual Refresh
|
||||
</Button>
|
||||
</Group>
|
||||
<Paper bg="gray.9" p="sm" mah={200} style={{ overflow: 'auto' }}>
|
||||
{loadingLogs ? (
|
||||
<Group justify="center">
|
||||
<Loader size="sm" />
|
||||
</Group>
|
||||
) : logs.length > 0 ? (
|
||||
<Text size="xs" c="white" component="pre">
|
||||
{logs.join('\n')}
|
||||
</Text>
|
||||
) : (
|
||||
<Text size="xs" c="gray.5">No logs available</Text>
|
||||
)}
|
||||
</Paper>
|
||||
</div>
|
||||
)}
|
||||
</Group>
|
||||
<Paper bg="gray.9" p="sm" mah={200} style={{ overflow: 'auto' }}>
|
||||
{loadingLogs ? (
|
||||
<Group justify="center">
|
||||
<Loader size="sm" />
|
||||
</Group>
|
||||
) : (logs.length > 0 || (execution?.logs && execution.logs.length > 0)) ? (
|
||||
<Text size="xs" c="white" component="pre">
|
||||
{(execution?.logs || logs).join('\n')}
|
||||
</Text>
|
||||
) : (
|
||||
<Text size="xs" c="gray.5">No logs available</Text>
|
||||
)}
|
||||
</Paper>
|
||||
</div>
|
||||
</Paper>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -35,6 +35,7 @@ export interface FunctionExecution {
|
||||
error?: string;
|
||||
duration?: number;
|
||||
memory_used?: number;
|
||||
logs?: string[];
|
||||
container_id?: string;
|
||||
executor_id: string;
|
||||
created_at: string;
|
||||
|
||||
Reference in New Issue
Block a user