separate components

This commit is contained in:
LathanDevers
2026-06-25 09:16:47 +02:00
parent cb89b521ef
commit 323667e835
25 changed files with 921 additions and 1572 deletions
+68
View File
@@ -0,0 +1,68 @@
import { Server, Database, Cloud, Globe, ExternalLink, Play, Loader } from 'lucide-react';
export default function InstanceCard({ service, vpcs, onAssignVpc, onRemoveVpc, onOpenConsole, isConnecting }) {
const titleLower = (service.title || '').toLowerCase();
const isVPS = titleLower.includes('vps') || titleLower.includes('compute');
const isCloud = titleLower.includes('cloud') || titleLower.includes('nextcloud');
const isDB = titleLower.includes('db') || titleLower.includes('base') || titleLower.includes('sql');
const isWeb = !isVPS && !isCloud && !isDB;
const hasIP = service.hostingDetails?.ip && service.hostingDetails.ip !== '127.0.0.1' && service.hostingDetails.ip !== '';
let buttonText = "CONSOLE D'ADMINISTRATION";
let ButtonIcon = ExternalLink;
let buttonStyle = "bg-cyan-400/10 hover:bg-cyan-400 text-cyan-400 hover:text-gray-900 border-cyan-400";
if (isVPS) {
if (hasIP) { buttonText = "GÉRER L'INSTANCE"; ButtonIcon = ExternalLink; }
else { buttonText = "INITIALISATION"; ButtonIcon = Play; buttonStyle = "bg-yellow-500/10 text-yellow-500 hover:bg-yellow-500 hover:text-gray-900 border-yellow-500/50"; }
} else if (isWeb) { buttonText = "GÉRER L'HÉBERGEMENT"; ButtonIcon = Globe; buttonStyle = "bg-emerald-400/10 hover:bg-emerald-400 text-emerald-400 hover:text-gray-900 border-emerald-400"; }
else if (isCloud) { buttonText = "ACCÉDER AU CLOUD"; buttonStyle = "bg-blue-400/10 hover:bg-blue-400 text-blue-400 hover:text-gray-900 border-blue-400"; }
else if (isDB) { buttonText = "PHPMYADMIN / CLUSTER"; ButtonIcon = Database; buttonStyle = "bg-purple-400/10 hover:bg-purple-400 text-purple-400 hover:text-gray-900 border-purple-400"; }
const getServiceIcon = () => {
if (isVPS) return <Server className="w-8 h-8 text-cyan-400" />;
if (isCloud) return <Cloud className="w-8 h-8 text-blue-400" />;
if (isDB) return <Database className="w-8 h-8 text-purple-400" />;
return <Globe className="w-8 h-8 text-emerald-400" />;
};
const baseTitle = (service.title || '').split(/(?: for | pour )/i)[0].trim();
const shortTitle = baseTitle.split(' ').slice(0, 2).join(' ');
const titleMatch = (service.title || '').match(/(?: for | pour )(.+)$/i);
const domainFromTitle = titleMatch ? titleMatch[1].trim() : null;
let displayDomain = service.hostingDetails?.domain && service.hostingDetails.domain !== '127.0.0.1' ? service.hostingDetails.domain : domainFromTitle || service.domain;
if (!displayDomain || displayDomain === '127.0.0.1') displayDomain = null;
return (
<div className="bg-gray-900 border border-gray-800 rounded-xl p-5 flex flex-col justify-between hover:border-gray-700 transition-all shadow-lg">
<div>
<div className="flex justify-between items-start mb-4">
<div className="p-2 bg-black/40 rounded-lg">{getServiceIcon()}</div>
{service.status === 'active' ? (
<span className="bg-emerald-500/10 text-emerald-400 px-2 py-1 rounded text-xs border border-emerald-500/20 font-bold tracking-widest">
{isVPS && !hasIP ? 'AWAITING INIT' : 'ONLINE'}
</span>
) : (
<span className="bg-orange-500/10 text-orange-400 px-2 py-1 rounded text-xs border border-orange-500/20 animate-pulse">DEPLOYING</span>
)}
</div>
<h3 className="font-bold text-white text-lg truncate" title={baseTitle}>{shortTitle}</h3>
<div className="flex flex-col gap-1 mt-2 mb-4 h-8 justify-center">
{displayDomain ? ( <p className={`${isVPS ? 'text-cyan-400' : 'text-emerald-400'} text-xs font-mono truncate`} title={displayDomain}>{displayDomain}</p> ) : ( <p className="text-gray-600 text-xs font-mono italic">En attente de déploiement</p> )}
</div>
</div>
<div className="mt-auto space-y-3">
<div className="flex items-center justify-between text-sm border-t border-gray-800 pt-3">
<span className="text-gray-500 text-xs">Projet VPC:</span>
<select onChange={(e) => { const val = e.target.value; if (val === "free") onRemoveVpc(service.id); else if (val) onAssignVpc(service.id, val); }} className="bg-black border border-gray-700 text-gray-300 rounded px-2 py-1 outline-none focus:border-cyan-400 text-xs w-[130px]" defaultValue={vpcs.find(v => v.services.includes(service.id))?.id || "free"}>
<option value="free">-- Libre --</option>
{vpcs.map(vpc => ( <option key={vpc.id} value={vpc.id}>{vpc.name}</option> ))}
</select>
</div>
<button onClick={() => onOpenConsole(service)} disabled={isConnecting === service.id || service.status !== 'active'} className={`w-full flex items-center justify-center space-x-2 py-2.5 rounded-lg font-bold text-sm tracking-wide transition-all disabled:opacity-50 border ${buttonStyle}`}>
{isConnecting === service.id ? ( <><Loader className="w-4 h-4 animate-spin" /><span>CONNEXION...</span></> ) : ( <><ButtonIcon className="w-4 h-4" /><span>{buttonText}</span></> )}
</button>
</div>
</div>
);
}