sp/src/components/Manager/HetznerList.jsx

214 lines
6.2 KiB
JavaScript

import React, { useState, useEffect } from "react";
import { useToast } from "../ui/toast";
import Loader from "../ui/loader";
import { Button } from "../ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
import Table from "../ui/table"; // Import your custom Table component
import { useIsLoggedIn } from '../../lib/isLoggedIn';
export default function HetznerServicesList() {
const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
const { showToast } = useToast();
const [isLoading, setIsLoading] = useState(true);
const [servers, setServers] = useState([]);
const PUBLIC_HETZNER_API_KEY = import.meta.env.PUBLIC_HETZNER_API_KEY;
// Define fetchServers outside useEffect so it can be reused
const fetchServers = async () => {
try {
const response = await fetch("https://api.hetzner.cloud/v1/servers", {
headers: { "Authorization": `Bearer ${PUBLIC_HETZNER_API_KEY}` }
});
const data = await response.json();
setServers(data.servers || []);
} catch (error) {
showToast({
title: "Error",
description: "Failed to load servers",
variant: "destructive"
});
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchServers();
}, []);
const handlePowerAction = async (serverId, action) => {
try {
setIsLoading(true);
const response = await fetch(`https://api.hetzner.cloud/v1/servers/${serverId}/actions/${action}`, {
method: "POST",
headers: {
"Authorization": `Bearer ${PUBLIC_HETZNER_API_KEY}`,
"Content-Type": "application/json"
}
});
const data = await response.json();
if (data.action) {
showToast({
title: "Success",
description: `Server ${action} action initiated`,
variant: "success"
});
// Refresh server list after a short delay
setTimeout(() => {
fetchServers();
}, 3000);
}
} catch (error) {
showToast({
title: "Error",
description: `Failed to ${action} server`,
variant: "destructive"
});
} finally {
setIsLoading(false);
}
};
const handleDeleteServer = async (serverId) => {
try {
setIsLoading(true);
const response = await fetch(`https://api.hetzner.cloud/v1/servers/${serverId}`, {
method: "DELETE",
headers: {
"Authorization": `Bearer ${PUBLIC_HETZNER_API_KEY}`,
"Content-Type": "application/json"
}
});
if (response.ok) {
showToast({
title: "Success",
description: "Server deleted successfully",
variant: "success"
});
// Remove the server from local state
setServers(prev => prev.filter(server => server.id !== serverId));
}
} catch (error) {
showToast({
title: "Error",
description: "Failed to delete server",
variant: "destructive"
});
} finally {
setIsLoading(false);
}
};
const getStatusBadge = (status) => {
let colorClass = "";
switch (status) {
case "running":
colorClass = "bg-green-100 text-green-800";
break;
case "off":
colorClass = "bg-gray-100 text-gray-800";
break;
case "starting":
case "stopping":
colorClass = "bg-yellow-100 text-yellow-800";
break;
default:
colorClass = "bg-blue-100 text-blue-800";
}
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colorClass}`}>
{status}
</span>
);
};
// Prepare data for your Table component
const tableData = servers.map(server => ({
name: server.name,
status: getStatusBadge(server.status),
type: server.server_type.name,
location: server.datacenter.location.city,
ip: server.public_net.ipv4 ? server.public_net.ipv4.ip : "None",
backups: server.backup_window ? "Enabled" : "Disabled",
actions: (
<div className="flex gap-2">
{server.status === "running" ? (
<>
<Button
variant="outline"
size="sm"
onClick={() => handlePowerAction(server.id, "shutdown")}
disabled={isLoading}
>
Stop
</Button>
<Button
variant="outline"
size="sm"
onClick={() => handlePowerAction(server.id, "reboot")}
disabled={isLoading}
>
Reboot
</Button>
</>
) : (
<Button
className=""
variant="outline"
size="sm"
onClick={() => handlePowerAction(server.id, "poweron")}
disabled={isLoading}
>
Start
</Button>
)}
<Button
className="bg-red-500 hover:bg-red-600 transition duration-500"
size="sm"
onClick={() => handleDeleteServer(server.id)}
disabled={isLoading}
>
Delete
</Button>
</div>
)
}));
const tableHeaders = ["Name", "Status", "Type", "Location", "IPv4", "Backups", "Actions"];
if (loading || (isLoggedIn && sessionData?.user_type === 'admin' && isLoading && servers.length === 0)) {
return <Loader />;
}
if (!isLoggedIn || sessionData?.user_type !== 'admin') {
return <p className="text-center mt-8">You are not authorized to view this page. <a href="/" className="text-[#6d9e37]">Click Here</a> to go to the homepage.</p>;
}
return (
<Card className="container mx-auto my-4">
<CardHeader>
<CardTitle>Your Hetzner Cloud Servers</CardTitle>
</CardHeader>
<CardContent>
{servers.length === 0 ? (
<div className="text-center py-8">
<p className="text-gray-500">No servers found. Create your first server to get started.</p>
</div>
) : (
<Table
headers={tableHeaders}
data={tableData}
striped
hover
caption="A list of your Hetzner Cloud servers"
className="mt-4"
/>
)}
</CardContent>
</Card>
);
}