mirror of
https://github.com/myronblair/kino-app
synced 2026-07-28 21:44:14 -05:00
70 lines
2.1 KiB
React
70 lines
2.1 KiB
React
import { useEffect, useState, useCallback } from "react";
|
|
import api from "../lib/api";
|
|
import { toast } from "sonner";
|
|
import { RotateCw } from "lucide-react";
|
|
|
|
export default function ServiceStatus() {
|
|
const [services, setServices] = useState([]);
|
|
const [restarting, setRestarting] = useState(null);
|
|
|
|
const load = useCallback(async () => {
|
|
try {
|
|
const { data } = await api.get("/services");
|
|
setServices(data);
|
|
} catch {
|
|
setServices([]);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
load();
|
|
const t = setInterval(load, 15000);
|
|
return () => clearInterval(t);
|
|
}, [load]);
|
|
|
|
const restart = async (key, label) => {
|
|
setRestarting(key);
|
|
try {
|
|
await api.post(`/services/${key}/restart`);
|
|
toast.success(`${label} restarting…`);
|
|
setTimeout(load, 4000);
|
|
} catch (err) {
|
|
toast.error(err.response?.data?.detail || `Could not restart ${label}`);
|
|
} finally {
|
|
setRestarting(null);
|
|
}
|
|
};
|
|
|
|
if (!services.length) return null;
|
|
|
|
return (
|
|
<div className="px-6 md:px-12 pt-6" data-testid="service-status">
|
|
<div className="flex flex-wrap gap-2">
|
|
{services.map((s) => (
|
|
<div
|
|
key={s.key}
|
|
className="flex items-center gap-2 bg-[#0F0F0F] border border-[#222] px-3 py-1.5 text-xs"
|
|
data-testid={`service-${s.key}`}
|
|
>
|
|
<span
|
|
className={`inline-block w-2 h-2 rounded-full ${s.running ? "bg-[#86efac]" : "bg-[#fca5a5]"}`}
|
|
/>
|
|
<span className="text-[#8A8A8A]">{s.label}</span>
|
|
{!s.running && (
|
|
<button
|
|
onClick={() => restart(s.key, s.label)}
|
|
disabled={restarting === s.key}
|
|
className="ml-1 flex items-center gap-1 text-[#D9381E] hover:text-[#ED4B32] disabled:opacity-50"
|
|
data-testid={`service-restart-${s.key}`}
|
|
>
|
|
<RotateCw size={12} className={restarting === s.key ? "animate-spin" : ""} />
|
|
Restart
|
|
</button>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|