From bdcb6cb3f91a0d849bc4e6febf359b492c0e84a6 Mon Sep 17 00:00:00 2001 From: maximus Date: Mon, 22 Jun 2026 13:26:54 +0200 Subject: [PATCH] modification vps et web et add npm rules --- src/pages/app/Services.jsx | 532 ++++++++++++++++++++++--------------- 1 file changed, 317 insertions(+), 215 deletions(-) diff --git a/src/pages/app/Services.jsx b/src/pages/app/Services.jsx index 28dfef1..abc98f2 100644 --- a/src/pages/app/Services.jsx +++ b/src/pages/app/Services.jsx @@ -1,27 +1,24 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { getMyServices, getServiceDetails, getHostingServiceDetails, resetHostingPassword } from '../../services/api'; import { useVPC } from '../../services/useVPC'; -import { Server, Database, Cloud, Globe, Folder, Trash2, ExternalLink, Loader, Plus, Play } from 'lucide-react'; +import { Server, Database, Cloud, Globe, Folder, Trash2, ExternalLink, Loader, Plus, Play, Lock } from 'lucide-react'; // ============================================================================ -// COMPOSANT ISOLÉ : INSTANCE CARD +// COMPOSANT 1 : INSTANCE CARD (Mode PaaS Pur - IP Masquée) // ============================================================================ const 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'); - - // Vérification de l'état d'initialisation pour le VPS + const isWeb = !isVPS && !isCloud && !isDB; + const hasIP = service.hostingDetails?.ip && service.hostingDetails.ip !== '127.0.0.1' && service.hostingDetails.ip !== ''; - - // ------------------------------------------------------------------------ - // DESIGN DES BOUTONS PAR TYPE DE SERVICE - // ------------------------------------------------------------------------ + 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"; @@ -31,9 +28,12 @@ const InstanceCard = ({ service, vpcs, onAssignVpc, onRemoveVpc, onOpenConsole, 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"; - ButtonIcon = ExternalLink; 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"; @@ -48,29 +48,20 @@ const InstanceCard = ({ service, vpcs, onAssignVpc, onRemoveVpc, onOpenConsole, return ; }; - // ------------------------------------------------------------------------ - // NETTOYAGE DU TEXTE (Titre à 2 mots & Extraction de domaine) - // ------------------------------------------------------------------------ - - // 1. Coupe le "pour X" ou "for X" du titre, puis garde les 2 premiers mots const baseTitle = (service.title || '').split(/(?: for | pour )/i)[0].trim(); const shortTitle = baseTitle.split(' ').slice(0, 2).join(' '); - // 2. Extraction du domaine qui se trouve après "pour" ou "for" dans le titre FOSSBilling const titleMatch = (service.title || '').match(/(?: for | pour )(.+)$/i); const domainFromTitle = titleMatch ? titleMatch[1].trim() : null; - // 3. Choix du domaine à afficher (Priorité à la BDD, sinon on prend celui du titre) - let displayDomain = service.hostingDetails?.domain && service.hostingDetails.domain !== '127.0.0.1' - ? service.hostingDetails.domain + 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; - } + if (!displayDomain || displayDomain === '127.0.0.1') displayDomain = null; return ( -
+
@@ -88,17 +79,14 @@ const InstanceCard = ({ service, vpcs, onAssignVpc, onRemoveVpc, onOpenConsole,

{shortTitle}

- - {/* Espace fixe pour le domaine (remplace l'ancien CMD: #id) */} -
+ +
{displayDomain ? ( -

+

{displayDomain}

) : ( -

- Non configuré -

+

En attente de déploiement

)}
@@ -139,7 +127,7 @@ const InstanceCard = ({ service, vpcs, onAssignVpc, onRemoveVpc, onOpenConsole, }; // ============================================================================ -// MODAL : VPS DEPLOYER +// COMPOSANT 2 : VPS DEPLOYER (Instanciation) // ============================================================================ const VpsDeployer = ({ serviceId, onDeploySuccess }) => { const [domain, setDomain] = useState(''); @@ -173,14 +161,14 @@ const VpsDeployer = ({ serviceId, onDeploySuccess }) => { return (
- PHASE D'INITIALISATION REQUISE
+ PHASE D'INITIALISATION REQUISE
La facturation est activée. Veuillez définir un mot de passe Root pour lancer la création de l'instance sur l'hyperviseur.
- +
- setDomain(e.target.value.toLowerCase())} placeholder="Laissez vide pour utiliser l'IP" className="w-full bg-gray-950 border border-gray-800 text-white p-3 rounded font-mono outline-none focus:border-cyan-500 transition-colors" /> + setDomain(e.target.value.toLowerCase())} placeholder="Laissez vide pour le défaut" className="w-full bg-gray-950 border border-gray-800 text-white p-3 rounded font-mono outline-none focus:border-cyan-500 transition-colors" />
@@ -195,111 +183,118 @@ const VpsDeployer = ({ serviceId, onDeploySuccess }) => { }; // ============================================================================ -// MODAL : VPS MANAGER (Modèle PaaS Complet) +// COMPOSANT 3 : VPS MANAGER (Day-2 Operations) // ============================================================================ -const VpsManager = ({ details }) => { +const VpsManager = ({ details, orderId, onRefresh, onClose }) => { const [showTerminal, setShowTerminal] = useState(false); + const [isEditingDomain, setIsEditingDomain] = useState(false); + const [newDomain, setNewDomain] = useState(details.domain); + const [isUpdating, setIsUpdating] = useState(false); + const [sslStatus, setSslStatus] = useState(null); - // Les URLs de tes outils internes - const fileManagerUrl = `https://file.${details.domain}`; - const terminalUrl = `https://terminal.${details.domain}`; + const isInternal = details.domain && details.domain.endsWith('.gise.be'); + const isCustomDomain = details.domain && !isInternal; + + const fileManagerUrl = isInternal ? `https://file-${details.domain}` : `http://${details.domain}:8080`; + const terminalUrl = isInternal ? `https://terminal-${details.domain}` : `http://${details.domain}:8081`; + + const handleUpdateDomain = async () => { + if (!newDomain || newDomain === details.domain) return; + setIsUpdating(true); + try { + const response = await fetch('https://web.gise.be/custom_api/update_service_domain.php', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ order_id: orderId, new_domain: newDomain }) + }); + const data = await response.json(); + if (data.status === 'success') { + setIsEditingDomain(false); + if (onRefresh) onRefresh(); + alert("Domaine VPS mis à jour avec succès sur l'infrastructure !"); + } else alert("Erreur: " + data.error); + } catch (err) { + alert("Erreur de connexion avec l'API."); + } finally { setIsUpdating(false); } + }; + + const handleGenerateSSL = async () => { + setSslStatus('loading'); + try { + const response = await fetch('https://web.gise.be/custom_api/generate_custom_ssl.php', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ domain: details.domain }) + }); + const data = await response.json(); + if (data.status === 'success') { + setSslStatus('success'); + alert("Certificat SSL Let's Encrypt généré et activé avec succès !"); + } else { + setSslStatus('error'); + alert("Échec de la validation DNS. Vérifiez que votre domaine pointe bien vers notre IP."); + } + } catch (e) { setSslStatus('error'); } + }; return (
{!showTerminal ? ( <> -
- {/* BLOC RÉSEAU */} -
-
- -
- +
+ + {!isEditingDomain ? ( +
+ + {details.domain} -
+ +
-
- - {/* BLOC OUTILS MANAGÉS */} -
-
- - -

• Utilisateur: root

-

• Pass: NexusGise2026! (à modifier)

+
-
- - -

• Utilisateur: root

-

• Pass: mot de passe d'initialisation

-
+ )}
- -
- - + +
+
+ + +
+
+ + +
) : ( - /* VUE CONSOLE INTÉGRÉE */ -
+
- - - NEXUS TERMINAL ({details.domain}) - -
- - -
+ NEXUS TERMINAL ({details.domain}) +
- - {/* Le conteneur iFrame qui charge TTYD (xterm.js) */} -
- {/* Message d'aide qui s'affiche brièvement pendant le chargement de l'iframe */} -
- -

Chargement du moteur xterm.js...

-

Identifiant : root

-

Mot de passe : Celui d'initialisation

-
- -