mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-12-15 00:26:23 +00:00
Update AppImage
This commit is contained in:
@@ -262,6 +262,7 @@ export default function Hardware() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
|
script_name: "nvidia_installer",
|
||||||
script_relative_path: "gpu_tpu/nvidia_installer.sh",
|
script_relative_path: "gpu_tpu/nvidia_installer.sh",
|
||||||
params: {
|
params: {
|
||||||
EXECUTION_MODE: "web",
|
EXECUTION_MODE: "web",
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ export function HybridScriptMonitor({
|
|||||||
const [inputValue, setInputValue] = useState("")
|
const [inputValue, setInputValue] = useState("")
|
||||||
const [selectedMenuItem, setSelectedMenuItem] = useState<string>("")
|
const [selectedMenuItem, setSelectedMenuItem] = useState<string>("")
|
||||||
const [isResponding, setIsResponding] = useState(false)
|
const [isResponding, setIsResponding] = useState(false)
|
||||||
|
const [eventSourceState, setEventSourceState] = useState<"connecting" | "open" | "closed" | "error">("connecting")
|
||||||
|
const [lastEventTime, setLastEventTime] = useState<Date | null>(null)
|
||||||
const scrollRef = useRef<HTMLDivElement>(null)
|
const scrollRef = useRef<HTMLDivElement>(null)
|
||||||
const pollingIntervalRef = useRef<NodeJS.Timeout | null>(null)
|
const pollingIntervalRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
const lastLogPositionRef = useRef<number>(0)
|
const lastLogPositionRef = useRef<number>(0)
|
||||||
@@ -67,15 +69,39 @@ export function HybridScriptMonitor({
|
|||||||
if (!sessionId) return
|
if (!sessionId) return
|
||||||
|
|
||||||
console.log("[v0] Setting up EventSource for session:", sessionId)
|
console.log("[v0] Setting up EventSource for session:", sessionId)
|
||||||
const eventSource = new EventSource(`/api/scripts/logs/${sessionId}`)
|
const baseUrl =
|
||||||
|
window.location.protocol === "http:" &&
|
||||||
|
window.location.port &&
|
||||||
|
window.location.port !== "80" &&
|
||||||
|
window.location.port !== "443"
|
||||||
|
? `${window.location.protocol}//${window.location.hostname}:8008`
|
||||||
|
: ""
|
||||||
|
const eventSourceUrl = `${baseUrl}/api/scripts/logs/${sessionId}`
|
||||||
|
console.log("[v0] EventSource URL:", eventSourceUrl)
|
||||||
|
|
||||||
|
const eventSource = new EventSource(eventSourceUrl)
|
||||||
|
|
||||||
|
eventSource.onopen = () => {
|
||||||
|
console.log("[v0] EventSource connection opened")
|
||||||
|
setEventSourceState("open")
|
||||||
|
setLogs((prev) => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
timestamp: new Date().toLocaleTimeString(),
|
||||||
|
message: "Connected to log stream",
|
||||||
|
type: "success",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
eventSource.onmessage = (event) => {
|
eventSource.onmessage = (event) => {
|
||||||
|
setLastEventTime(new Date())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data)
|
const data = JSON.parse(event.data)
|
||||||
console.log("[v0] Received SSE event:", data)
|
console.log("[v0] Received SSE event:", data)
|
||||||
|
|
||||||
if (data.type === "init") {
|
if (data.type === "init") {
|
||||||
// Initial message, add to logs
|
|
||||||
setLogs((prev) => [
|
setLogs((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
@@ -85,10 +111,8 @@ export function HybridScriptMonitor({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
} else if (data.type === "raw") {
|
} else if (data.type === "raw") {
|
||||||
// Raw log line from script
|
|
||||||
const message = data.message
|
const message = data.message
|
||||||
|
|
||||||
// Check if it contains a WEB_INTERACTION
|
|
||||||
if (message.includes("WEB_INTERACTION:")) {
|
if (message.includes("WEB_INTERACTION:")) {
|
||||||
const interactionPart = message.split("WEB_INTERACTION:")[1]
|
const interactionPart = message.split("WEB_INTERACTION:")[1]
|
||||||
|
|
||||||
@@ -111,7 +135,6 @@ export function HybridScriptMonitor({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular log line
|
|
||||||
setLogs((prev) => [
|
setLogs((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
@@ -128,7 +151,6 @@ export function HybridScriptMonitor({
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
} else if (data.type === "error") {
|
} else if (data.type === "error") {
|
||||||
// Error from script_runner
|
|
||||||
setLogs((prev) => [
|
setLogs((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
@@ -138,19 +160,18 @@ export function HybridScriptMonitor({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
// Unknown type, display as-is
|
console.warn("[v0] Unknown SSE event type:", data.type, "Full data:", data)
|
||||||
setLogs((prev) => [
|
setLogs((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
timestamp: new Date().toLocaleTimeString(),
|
timestamp: new Date().toLocaleTimeString(),
|
||||||
message: JSON.stringify(data),
|
message: `[Unknown event type: ${data.type}] ${JSON.stringify(data)}`,
|
||||||
type: "info",
|
type: "warning",
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[v0] Error parsing SSE event:", e, "Raw data:", event.data)
|
console.error("[v0] Error parsing SSE event:", e, "Raw data:", event.data)
|
||||||
// If not JSON, display as plain text
|
|
||||||
setLogs((prev) => [
|
setLogs((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
@@ -164,15 +185,15 @@ export function HybridScriptMonitor({
|
|||||||
|
|
||||||
eventSource.onerror = (error) => {
|
eventSource.onerror = (error) => {
|
||||||
console.error("[v0] EventSource error:", error)
|
console.error("[v0] EventSource error:", error)
|
||||||
|
setEventSourceState("error")
|
||||||
setLogs((prev) => [
|
setLogs((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
timestamp: new Date().toLocaleTimeString(),
|
timestamp: new Date().toLocaleTimeString(),
|
||||||
message: "Connection to log stream lost",
|
message: "Connection to log stream lost. Retrying...",
|
||||||
type: "error",
|
type: "error",
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
eventSource.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pollStatus = async () => {
|
const pollStatus = async () => {
|
||||||
@@ -180,25 +201,41 @@ export function HybridScriptMonitor({
|
|||||||
const statusData = await fetchApi(`/api/scripts/status/${sessionId}`)
|
const statusData = await fetchApi(`/api/scripts/status/${sessionId}`)
|
||||||
console.log("[v0] Status data:", statusData)
|
console.log("[v0] Status data:", statusData)
|
||||||
|
|
||||||
|
if (eventSourceState === "open" && lastEventTime) {
|
||||||
|
const timeSinceLastEvent = Date.now() - lastEventTime.getTime()
|
||||||
|
if (timeSinceLastEvent > 10000) {
|
||||||
|
console.warn("[v0] No logs received for 10 seconds. Flask may not be streaming logs.")
|
||||||
|
setLogs((prev) => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
timestamp: new Date().toLocaleTimeString(),
|
||||||
|
message: "Warning: No new logs received. Check Flask script_runner streaming.",
|
||||||
|
type: "warning",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (statusData.status === "completed" || statusData.exit_code === 0) {
|
if (statusData.status === "completed" || statusData.exit_code === 0) {
|
||||||
console.log("[v0] Script execution completed")
|
console.log("[v0] Script execution completed")
|
||||||
setStatus("completed")
|
setStatus("completed")
|
||||||
eventSource.close()
|
eventSource.close()
|
||||||
|
setEventSourceState("closed")
|
||||||
if (pollingIntervalRef.current) {
|
if (pollingIntervalRef.current) {
|
||||||
clearInterval(pollingIntervalRef.current)
|
clearInterval(pollingIntervalRef.current)
|
||||||
}
|
}
|
||||||
onComplete?.(true)
|
onComplete?.(true)
|
||||||
} else if (statusData.status === "failed" || (statusData.exit_code !== null && statusData.exit_code !== 0)) {
|
} else if (statusData.status === "failed" || (statusData.exit_code !== null && statusData.exit_code !== 0)) {
|
||||||
console.log("[v0] Script execution failed")
|
console.log("[v0] Script execution failed with exit code:", statusData.exit_code)
|
||||||
setStatus("failed")
|
setStatus("failed")
|
||||||
eventSource.close()
|
eventSource.close()
|
||||||
|
setEventSourceState("closed")
|
||||||
if (pollingIntervalRef.current) {
|
if (pollingIntervalRef.current) {
|
||||||
clearInterval(pollingIntervalRef.current)
|
clearInterval(pollingIntervalRef.current)
|
||||||
}
|
}
|
||||||
onComplete?.(false)
|
onComplete?.(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for pending interactions in status
|
|
||||||
if (statusData.pending_interaction) {
|
if (statusData.pending_interaction) {
|
||||||
const parts = statusData.pending_interaction.split(":")
|
const parts = statusData.pending_interaction.split(":")
|
||||||
if (parts.length >= 4) {
|
if (parts.length >= 4) {
|
||||||
@@ -229,7 +266,7 @@ export function HybridScriptMonitor({
|
|||||||
clearInterval(pollingIntervalRef.current)
|
clearInterval(pollingIntervalRef.current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [sessionId, onComplete])
|
}, [sessionId, onComplete, eventSourceState, lastEventTime])
|
||||||
|
|
||||||
const handleInteractionResponse = async (response: string) => {
|
const handleInteractionResponse = async (response: string) => {
|
||||||
if (!interaction || !sessionId) return
|
if (!interaction || !sessionId) return
|
||||||
@@ -411,6 +448,12 @@ export function HybridScriptMonitor({
|
|||||||
<div className="flex items-center gap-2 mb-2">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<AlertCircle className="h-4 w-4" />
|
<AlertCircle className="h-4 w-4" />
|
||||||
<span className="text-sm font-medium">Execution Logs</span>
|
<span className="text-sm font-medium">Execution Logs</span>
|
||||||
|
<span className="text-xs text-muted-foreground ml-auto">
|
||||||
|
Stream: {eventSourceState === "open" && "🟢 Connected"}
|
||||||
|
{eventSourceState === "connecting" && "🟡 Connecting..."}
|
||||||
|
{eventSourceState === "closed" && "⚫ Closed"}
|
||||||
|
{eventSourceState === "error" && "🔴 Error"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<ScrollArea className="h-64" ref={scrollRef}>
|
<ScrollArea className="h-64" ref={scrollRef}>
|
||||||
<div className="space-y-1 font-mono text-xs">
|
<div className="space-y-1 font-mono text-xs">
|
||||||
|
|||||||
Reference in New Issue
Block a user