import React, { useEffect, useState } from "react"; import axios from "axios"; import { io } from "socket.io-client"; export default function Stacks() { const [stacks, setStacks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [selectedStackIds, setSelectedStackIds] = useState([]); useEffect(() => { const socket = io("/", { path: "/socket.io", transports: ["websocket"] }); console.log("🔌 Socket connected"); socket.on("redeployStatus", async ({ stackId, status }) => { console.log(`🔄 Stack ${stackId} Redeploy Status: ${status ? "running" : "finished"}`); if (!status) { // Status nach Redeploy neu vom Server holen try { const res = await axios.get("/api/stacks"); const sortedStacks = [...res.data].sort((a, b) => a.Name.localeCompare(b.Name)); setStacks(sortedStacks.map(stack => ({ ...stack, redeploying: stack.redeploying || false }))); } catch (err) { console.error("Fehler beim Aktualisieren nach Redeploy:", err); } } else { // UI direkt auf redeploying setzen setStacks(prev => prev.map(stack => stack.Id === stackId ? { ...stack, redeploying: true } : stack ) ); } }); return () => socket.disconnect(); }, []); const fetchStacks = async () => { setLoading(true); try { const res = await axios.get("/api/stacks"); const sortedStacks = [...res.data].sort((a, b) => a.Name.localeCompare(b.Name)); setStacks(sortedStacks.map(stack => ({ ...stack, redeploying: stack.redeploying || false }))); } catch (err) { console.error("❌ Fehler beim Abrufen der Stacks:", err); setError("Fehler beim Laden der Stacks"); } finally { setLoading(false); } }; useEffect(() => { fetchStacks(); }, []); useEffect(() => { setSelectedStackIds(prev => { const filtered = prev.filter(id => { const match = stacks.find(stack => stack.Id === id); return match && match.updateStatus !== '✅'; }); return filtered.length === prev.length ? prev : filtered; }); }, [stacks]); const toggleStackSelection = (stackId, disabled) => { if (disabled) return; setSelectedStackIds(prev => prev.includes(stackId) ? prev.filter(id => id !== stackId) : [...prev, stackId] ); }; const handleRedeploy = async (stackId) => { setSelectedStackIds((prev) => prev.filter((id) => id !== stackId)); setStacks((prev) => prev.map((stack) => stack.Id === stackId ? { ...stack, redeploying: true } : stack ) ); try { await axios.put(`/api/stacks/${stackId}/redeploy`); // Statusupdates kommen über Socket.IO } catch (err) { console.error("❌ Fehler beim Redeploy:", err); setStacks((prev) => prev.map((stack) => stack.Id === stackId ? { ...stack, redeploying: false } : stack ) ); } }; const handleRedeployAll = async () => { const outdatedStacks = stacks.filter((stack) => stack.updateStatus !== '✅'); if (!outdatedStacks.length) return; const outdatedIds = new Set(outdatedStacks.map((stack) => stack.Id)); setStacks(prev => prev.map(stack => outdatedIds.has(stack.Id) ? { ...stack, redeploying: true } : stack ) ); try { await axios.put("/api/stacks/redeploy-all"); setSelectedStackIds((prev) => prev.filter((id) => !outdatedIds.has(id))); // Statusupdates kommen über Socket.IO } catch (err) { console.error("❌ Fehler beim Redeploy ALL:", err); setStacks(prev => prev.map(stack => outdatedIds.has(stack.Id) ? { ...stack, redeploying: false } : stack ) ); } }; const handleRedeploySelection = async () => { if (!selectedStackIds.length) return; const eligibleIds = selectedStackIds.filter((id) => { const stack = stacks.find((entry) => entry.Id === id); return stack && stack.updateStatus !== '✅'; }); if (!eligibleIds.length) { setSelectedStackIds([]); return; } const eligibleSet = new Set(eligibleIds); setStacks(prev => prev.map(stack => eligibleSet.has(stack.Id) ? { ...stack, redeploying: true } : stack ) ); try { await axios.put("/api/stacks/redeploy-selection", { stackIds: eligibleIds }); setSelectedStackIds((prev) => prev.filter((id) => !eligibleSet.has(id))); // Statusupdates kommen über Socket.IO } catch (err) { console.error("❌ Fehler beim Redeploy Auswahl:", err); setStacks(prev => prev.map(stack => eligibleSet.has(stack.Id) ? { ...stack, redeploying: false } : stack ) ); } }; const hasSelection = selectedStackIds.length > 0; const hasOutdatedStacks = stacks.some((stack) => stack.updateStatus !== '✅'); const bulkButtonLabel = hasSelection ? `Redeploy Auswahl (${selectedStackIds.length})` : 'Redeploy All'; const bulkActionDisabled = hasSelection ? selectedStackIds.length === 0 || selectedStackIds.every(id => { const targetStack = stacks.find(stack => stack.Id === id); return !targetStack || targetStack.redeploying || targetStack.updateStatus === '✅'; }) : !hasOutdatedStacks || stacks.every(stack => stack.updateStatus !== '✅' || stack.redeploying); const handleBulkRedeploy = () => { if (hasSelection) { handleRedeploySelection(); } else { handleRedeployAll(); } }; if (loading) return
Lade Stacks...
; if (error) return{error}
; return ({stack.Name}
ID: {stack.Id}
Keine Stacks gefunden.
}