upgrade design

This commit is contained in:
LathanDevers
2026-06-25 10:50:49 +02:00
parent 323667e835
commit d83b7ad4e7
9 changed files with 226 additions and 442 deletions
+46 -2
View File
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { Folder, ExternalLink, Play, Maximize2, Lock } from 'lucide-react';
import { Folder, ExternalLink, Play, Maximize2, Lock, Copy, Check } from 'lucide-react';
export default function VpsManager({ details, orderId, onRefresh, onAlert }) {
const [showTerminal, setShowTerminal] = useState(false);
@@ -7,11 +7,18 @@ export default function VpsManager({ details, orderId, onRefresh, onAlert }) {
const [newDomain, setNewDomain] = useState(details.domain);
const [isUpdating, setIsUpdating] = useState(false);
const [sslStatus, setSslStatus] = useState(null);
const [copiedField, setCopiedField] = useState(null);
const isInternal = details.domain && details.domain.endsWith('.gise.be');
const fileManagerUrl = isInternal ? `https://file-${details.domain}` : `http://${details.domain}:8080`;
const terminalUrl = isInternal ? `https://terminal-${details.domain}` : `http://${details.domain}:8081`;
const handleCopy = (text, field) => {
navigator.clipboard.writeText(text);
setCopiedField(field);
setTimeout(() => setCopiedField(null), 2000);
};
const handleUpdateDomain = async () => {
if (!newDomain || newDomain === details.domain) return;
setIsUpdating(true);
@@ -62,7 +69,44 @@ export default function VpsManager({ details, orderId, onRefresh, onAlert }) {
</div>
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
{/* ENCART DES IDENTIFIANTS */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div className="bg-black/60 border border-gray-800 rounded p-3">
<span className="text-gray-500 font-bold uppercase tracking-wider block mb-2 text-[10px] flex items-center gap-1">
<Folder className="w-3 h-3" /> Accès Explorateur
</span>
<div className="flex justify-between items-center mb-1">
<span className="text-xs font-mono text-gray-400">User: <strong className="text-cyan-400">root</strong></span>
<button onClick={() => handleCopy('root', 'fileUser')} className="text-gray-500 hover:text-cyan-400 p-1">
{copiedField === 'fileUser' ? <Check className="w-3 h-3 text-cyan-400" /> : <Copy className="w-3 h-3" />}
</button>
</div>
<div className="flex justify-between items-center">
<span className="text-xs font-mono text-gray-400">Pass: <strong className="text-cyan-400">NexusGise2026!</strong></span>
<button onClick={() => handleCopy('NexusGise2026!', 'filePass')} className="text-gray-500 hover:text-cyan-400 p-1">
{copiedField === 'filePass' ? <Check className="w-3 h-3 text-cyan-400" /> : <Copy className="w-3 h-3" />}
</button>
</div>
</div>
<div className="bg-black/60 border border-gray-800 rounded p-3">
<span className="text-gray-500 font-bold uppercase tracking-wider block mb-2 text-[10px] flex items-center gap-1">
<Play className="w-3 h-3" /> Accès Console / SSH
</span>
<div className="flex justify-between items-center mb-1">
<span className="text-xs font-mono text-gray-400">User: <strong className="text-cyan-400">root</strong></span>
<button onClick={() => handleCopy('root', 'sshUser')} className="text-gray-500 hover:text-cyan-400 p-1">
{copiedField === 'sshUser' ? <Check className="w-3 h-3 text-cyan-400" /> : <Copy className="w-3 h-3" />}
</button>
</div>
<div className="flex justify-between items-center">
<span className="text-xs font-mono text-gray-400">Pass: <span className="text-gray-600 italic">Défini à l'installation</span></span>
</div>
</div>
</div>
{/* BOUTONS D'ACTIONS */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-2">
<button onClick={() => window.open(fileManagerUrl, '_blank')} className="bg-gray-950 hover:bg-gray-900 border border-gray-800 hover:border-cyan-500/50 rounded p-3 flex justify-between items-center transition group">
<span className="font-mono text-gray-300 text-sm flex items-center gap-2"><Folder className="w-4 h-4 text-cyan-500" /> Explorateur</span><ExternalLink className="w-4 h-4 text-gray-600 group-hover:text-cyan-400" />
</button>
+63 -11
View File
@@ -1,17 +1,28 @@
import { useState } from 'react';
import { Globe, ExternalLink, Lock, Loader } from 'lucide-react';
import { Globe, ExternalLink, Lock, Loader, Copy, Check } from 'lucide-react';
import { resetHostingPassword } from '../../services/api';
export default function WebManager({ details, orderId, onRefresh, onOpenSso, onAlert }) {
export default function WebManager({ details, orderId, onRefresh, onAlert }) {
const [isEditingDomain, setIsEditingDomain] = useState(false);
const [newDomain, setNewDomain] = useState(details.domain);
const [isUpdating, setIsUpdating] = useState(false);
const [sslStatus, setSslStatus] = useState(null);
// Nouveaux états pour gérer les accès localement
const [isGeneratingSso, setIsGeneratingSso] = useState(false);
const [ssoData, setSsoData] = useState(null);
const [copiedField, setCopiedField] = useState(null);
const isCustomDomain = details.domain && !details.domain.endsWith('.gise.be');
const siteUrl = (isCustomDomain && sslStatus !== 'success') ? `http://${details.domain}` : `https://${details.domain}`;
// Fonction utilitaire pour copier
const handleCopy = (text, field) => {
navigator.clipboard.writeText(text);
setCopiedField(field);
setTimeout(() => setCopiedField(null), 2000);
};
const handleUpdateDomain = async () => {
if (!newDomain || newDomain === details.domain) return;
setIsUpdating(true);
@@ -39,9 +50,12 @@ export default function WebManager({ details, orderId, onRefresh, onOpenSso, onA
const secureHash = Math.random().toString(36).slice(-8) + Math.random().toString(36).slice(-4).toUpperCase();
const rollingPassword = `Nx${secureHash}`;
await resetHostingPassword(orderId, rollingPassword);
onOpenSso({ username: details.username, password: rollingPassword, url: 'https://panel.gise.be/login/' });
} catch (err) { onAlert("Erreur Métal", "Erreur lors de la génération du SSO HestiaCP.", "error"); }
finally { setIsGeneratingSso(false); }
setSsoData({ username: details.username, password: rollingPassword, url: 'https://panel.gise.be/login/' });
} catch (err) {
onAlert("Erreur Métal", "Erreur lors de la génération du SSO HestiaCP.", "error");
} finally {
setIsGeneratingSso(false);
}
};
return (
@@ -50,7 +64,9 @@ export default function WebManager({ details, orderId, onRefresh, onOpenSso, onA
<label className="block text-xs uppercase tracking-widest text-emerald-500 mb-2">Domaine du Site Web</label>
{!isEditingDomain ? (
<div className="flex justify-between items-center">
<span className="font-mono text-xl text-emerald-400 font-bold flex items-center gap-2"><span className="h-3 w-3 rounded-full bg-emerald-500 shadow-[0_0_10px_#10b981]"></span>{details.domain}</span>
<span className="font-mono text-xl text-emerald-400 font-bold flex items-center gap-2">
<span className="h-3 w-3 rounded-full bg-emerald-500 shadow-[0_0_10px_#10b981]"></span>{details.domain}
</span>
<button onClick={() => setIsEditingDomain(true)} className="text-xs border border-gray-700 hover:border-emerald-500 text-gray-400 hover:text-emerald-400 px-3 py-1.5 rounded transition">MODIFIER</button>
</div>
) : (
@@ -60,6 +76,7 @@ export default function WebManager({ details, orderId, onRefresh, onOpenSso, onA
<button onClick={() => setIsEditingDomain(false)} className="bg-gray-800 text-white px-3 py-1.5 rounded text-xs hover:bg-gray-700">ANNULER</button>
</div>
)}
{isCustomDomain && (
<div className="mt-4 border-t border-gray-900 pt-3 flex justify-between items-center">
<p className="text-[11px] text-gray-500">Domaine personnalisé détecté.</p>
@@ -69,13 +86,48 @@ export default function WebManager({ details, orderId, onRefresh, onOpenSso, onA
</div>
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div className="grid grid-cols-1 gap-6 mb-6">
<button onClick={() => window.open(siteUrl, '_blank')} className="bg-gray-950 hover:bg-gray-900 border border-gray-800 hover:border-emerald-500/50 rounded p-3 flex justify-between items-center transition group">
<span className="font-mono text-gray-300 text-sm flex items-center gap-2"><Globe className="w-4 h-4 text-emerald-500" /> Ouvrir Site</span><ExternalLink className="w-4 h-4 text-gray-600 group-hover:text-emerald-400" />
</button>
<button onClick={handleOpenPanel} disabled={isGeneratingSso} className="bg-emerald-900/20 hover:bg-emerald-900/40 border border-emerald-800/50 hover:border-emerald-500 rounded p-3 flex justify-between items-center transition group disabled:opacity-50">
{isGeneratingSso ? <span className="font-mono text-emerald-400 text-sm flex items-center gap-2"><Loader className="w-4 h-4 animate-spin" /> SSO...</span> : <><span className="font-mono text-emerald-400 text-sm flex items-center gap-2"><Lock className="w-4 h-4" /> Panel</span><ExternalLink className="w-4 h-4 text-emerald-600 group-hover:text-emerald-400" /></>}
<span className="font-mono text-gray-300 text-sm flex items-center gap-2"><Globe className="w-4 h-4 text-emerald-500" /> Ouvrir le Site</span><ExternalLink className="w-4 h-4 text-gray-600 group-hover:text-emerald-400" />
</button>
{/* ZONE DES ACCÈS PANEL */}
{!ssoData ? (
<button onClick={handleOpenPanel} disabled={isGeneratingSso} className="bg-emerald-900/20 hover:bg-emerald-900/40 border border-emerald-800/50 hover:border-emerald-500 rounded p-3 flex justify-between items-center transition group disabled:opacity-50">
{isGeneratingSso ? (
<span className="font-mono text-emerald-400 text-sm flex items-center gap-2"><Loader className="w-4 h-4 animate-spin" /> GÉNÉRATION DU MOT DE PASSE...</span>
) : (
<><span className="font-mono text-emerald-400 text-sm flex items-center gap-2"><Lock className="w-4 h-4" /> Obtenir les accès Panel</span><ExternalLink className="w-4 h-4 text-emerald-600 group-hover:text-emerald-400" /></>
)}
</button>
) : (
<div className="bg-emerald-900/10 border border-emerald-500/30 rounded p-4">
<p className="text-[11px] text-emerald-400/80 uppercase tracking-widest mb-3 flex items-center gap-2">
<Lock className="w-3 h-3" /> Accès Panel Généré
</p>
<div className="space-y-2 mb-4">
<div className="flex justify-between items-center bg-black/50 border border-gray-800 rounded p-2">
<span className="text-gray-400 text-xs font-mono">User: <strong className="text-white ml-1">{ssoData.username}</strong></span>
<button onClick={() => handleCopy(ssoData.username, 'webUser')} className="text-emerald-400 hover:text-emerald-300 transition-colors p-1">
{copiedField === 'webUser' ? <Check className="w-4 h-4 text-emerald-500" /> : <Copy className="w-4 h-4" />}
</button>
</div>
<div className="flex justify-between items-center bg-black/50 border border-gray-800 rounded p-2">
<span className="text-gray-400 text-xs font-mono">Pass: <strong className="text-emerald-400 ml-1">{ssoData.password}</strong></span>
<button onClick={() => handleCopy(ssoData.password, 'webPass')} className="text-emerald-400 hover:text-emerald-300 transition-colors p-1">
{copiedField === 'webPass' ? <Check className="w-4 h-4 text-emerald-500" /> : <Copy className="w-4 h-4" />}
</button>
</div>
</div>
<button onClick={() => window.open(ssoData.url, '_blank')} className="w-full bg-emerald-500 hover:bg-emerald-400 text-black font-bold font-mono tracking-widest uppercase py-2.5 rounded transition shadow-[0_0_15px_rgba(16,185,129,0.2)]">
Ouvrir le Panel
</button>
</div>
)}
</div>
</div>
);