diff --git a/decnet_web/src/components/Dashboard.css b/decnet_web/src/components/Dashboard.css index 2b6fe25..773fcd9 100644 --- a/decnet_web/src/components/Dashboard.css +++ b/decnet_web/src/components/Dashboard.css @@ -118,3 +118,12 @@ from { opacity: 0.5; } to { opacity: 1; } } + +.spin { + animation: spin 1.5s linear infinite; +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} diff --git a/decnet_web/src/components/DeckyFleet.tsx b/decnet_web/src/components/DeckyFleet.tsx index c9d7c30..96f7e8a 100644 --- a/decnet_web/src/components/DeckyFleet.tsx +++ b/decnet_web/src/components/DeckyFleet.tsx @@ -18,6 +18,7 @@ interface Decky { const DeckyFleet: React.FC = () => { const [deckies, setDeckies] = useState([]); const [loading, setLoading] = useState(true); + const [mutating, setMutating] = useState(null); const fetchDeckies = async () => { try { @@ -31,12 +32,19 @@ const DeckyFleet: React.FC = () => { }; const handleMutate = async (name: string) => { + setMutating(name); try { await api.post(`/deckies/${name}/mutate`, {}, { timeout: 120000 }); - fetchDeckies(); - } catch (err) { + await fetchDeckies(); + } catch (err: any) { console.error('Failed to mutate', err); - alert('Mutation failed'); + if (err.code === 'ECONNABORTED') { + alert('Mutation is still running in the background but the UI timed out.'); + } else { + alert('Mutation failed'); + } + } finally { + setMutating(null); } }; @@ -102,13 +110,15 @@ const DeckyFleet: React.FC = () => { {decky.last_mutated > 0 && (