Spaces:
Build error
Build error
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Mailix | Déploiement Statique</title> | |
| <link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png"> | |
| <link rel="stylesheet" | |
| href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" /> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| /* -------------------------------------- */ | |
| /* CSS pour la zone de Glisser-Déposer */ | |
| /* -------------------------------------- */ | |
| .dropzone { | |
| border: 3px dashed #007bff; | |
| background-color: #f8f9fa; | |
| padding: 40px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: background-color 0.2s, border-color 0.2s; | |
| border-radius: 12px; | |
| margin-bottom: 20px; | |
| user-select: none; | |
| } | |
| .dropzone.dragover { | |
| background-color: #e2f0ff; | |
| border-color: #0056b3; | |
| } | |
| .dropzone-icon { | |
| font-size: 3rem; | |
| color: #007bff; | |
| margin-bottom: 10px; | |
| } | |
| .dropzone-text { | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| color: #343a40; | |
| } | |
| .dropzone-hint { | |
| font-size: 0.9rem; | |
| color: #6c757d; | |
| margin-top: 5px; | |
| } | |
| /* -------------------------------------- */ | |
| /* Style pour le Responsive (Mobile) */ | |
| /* -------------------------------------- */ | |
| @media (max-width: 576px) { | |
| .dropzone { | |
| padding: 25px; | |
| } | |
| .dropzone-icon { | |
| font-size: 2.5rem; | |
| } | |
| .dropzone-text { | |
| font-size: 1rem; | |
| } | |
| .file-list { | |
| font-size: 0.9rem; | |
| } | |
| } | |
| /* Style pour la liste de fichiers */ | |
| .file-list { | |
| list-style-type: none; | |
| padding: 0; | |
| margin-top: 15px; | |
| text-align: left; | |
| } | |
| .file-list li { | |
| padding: 8px 10px; | |
| border-bottom: 1px solid #eee; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .file-list li:last-child { | |
| border-bottom: none; | |
| } | |
| .file-icon { | |
| margin-right: 8px; | |
| color: #007bff; | |
| } | |
| /* Style pour le bouton de copie */ | |
| #copy-url-button { | |
| width: 50px; /* Fixer la largeur du bouton de copie */ | |
| } | |
| /* Nouveau style pour l'animation de chargement */ | |
| .spinner-border { | |
| display: inline-block; | |
| width: 1rem; | |
| height: 1rem; | |
| vertical-align: middle; | |
| border: .2em solid currentColor; | |
| border-right-color: transparent; | |
| border-radius: 50%; | |
| animation: spinner-border .75s linear infinite; | |
| } | |
| @keyframes spinner-border { | |
| to { transform: rotate(360deg); } | |
| } | |
| /* -------------------------------------- */ | |
| /* Styles du Mode Sombre */ | |
| /* -------------------------------------- */ | |
| /* Le corps principal devient sombre */ | |
| body.dark-mode { | |
| background-color: #1a1a1a; | |
| color: #f1f1f1; | |
| } | |
| /* Conteneurs et cartes (e.g., action-zone, url-container) */ | |
| .dark-mode .bg-white { | |
| background-color: #2c2c2c ; | |
| color: #f1f1f1; | |
| } | |
| /* Zone de Drop */ | |
| .dark-mode .dropzone { | |
| border-color: #00bcd4; /* Cyan pour le contraste */ | |
| background-color: #2c2c2c; | |
| } | |
| .dark-mode .dropzone.dragover { | |
| background-color: #404040; | |
| border-color: #00e5ff; | |
| } | |
| .dark-mode .dropzone-icon, .dark-mode .file-icon { | |
| color: #00bcd4; | |
| } | |
| .dark-mode .dropzone-text { | |
| color: #f1f1f1; | |
| } | |
| .dark-mode .dropzone-hint { | |
| color: #ccc; | |
| } | |
| /* Liste de fichiers */ | |
| .dark-mode .file-list li { | |
| border-bottom: 1px solid #444; | |
| } | |
| /* Statut de téléversement */ | |
| .dark-mode .text-muted { | |
| color: #b0b0b0 ; | |
| } | |
| /* Couleurs des URL (Ajustement pour le fond sombre) */ | |
| .dark-mode #permanent-url-container { | |
| background-color: #0f5132 ; /* Vert foncé */ | |
| border-color: #198754 ; | |
| } | |
| .dark-mode .text-success { | |
| color: #92b8aa ; /* Vert clair */ | |
| } | |
| .dark-mode #temp-url-container { | |
| background-color: #664d03 ; /* Jaune foncé */ | |
| border-color: #ffc107 ; | |
| } | |
| .dark-mode .text-warning { | |
| color: #ffd700 ; /* Jaune clair */ | |
| } | |
| </style> | |
| <div class="d-flex justify-content-end p-3"> | |
| <button id="theme-toggle" class="btn btn-outline-secondary" title="Changer le thème"> | |
| <span id="theme-icon" class="material-symbols-rounded">dark_mode</span> | |
| </button> | |
| </div> | |
| <input type="file" id="file-input" multiple style="display: none;"> | |
| <div class="container my-5 mx-auto px-4 lg:px-0"> | |
| <div class="col-12 col-lg-8 mx-auto"> | |
| <h2 class="text-center mb-4 text-3xl font-bold"> Déploiement Statique Instantané</h2> | |
| <div id="drop-zone" class="dropzone" data-is-dropping="false"> | |
| <span class="material-symbols-rounded dropzone-icon">cloud_upload</span> | |
| <p class="dropzone-text">Glissez et déposez vos fichiers ici (HTML, CSS, JS, Images)</p> | |
| <p class="dropzone-hint">Ou cliquez pour sélectionner des fichiers. Un fichier **index.html** est requis.</p> | |
| <button id="select-files-button" class="btn bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded mt-3">Sélectionner des Fichiers</button> | |
| </div> | |
| <div id="file-upload-status" class="mt-3 text-muted text-center"> | |
| Aucun fichier téléversé. | |
| </div> | |
| <ul id="uploaded-file-list" class="file-list p-3 border rounded shadow-sm bg-white" style="display: none;"> | |
| </ul> | |
| <div id="action-zone" class="mt-4 p-4 border rounded shadow-sm bg-white"> | |
| <div class="flex flex-wrap justify-between items-center space-y-2 md:space-y-0"> | |
| <button id="launch-button" class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded flex items-center" disabled> | |
| <span class="material-symbols-rounded align-middle me-1">open_in_new</span> Lancer l'Aperçu (Temp) | |
| </button> | |
| <button id="deploy-button" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded flex items-center" disabled> | |
| <span class="material-symbols-rounded align-middle me-1">cloud_upload</span> Déployer le Site Web (Permanent) | |
| </button> | |
| <button id="clear-button" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded flex items-center" disabled> | |
| <span class="material-symbols-rounded align-middle me-1">delete_forever</span> Vider | |
| </button> | |
| </div> | |
| </div> | |
| <div id="permanent-url-container" class="mt-4 p-3 bg-success-light border rounded" style="display: none; background-color: #d1e7dd !important; border-color: #badbcc !important;"> | |
| <label class="font-bold d-block text-success" style="color: #0f5132 !important;"> | |
| <span class="material-symbols-rounded align-middle me-1">link</span> Lien Permanent du Site | |
| </label> | |
| <div class="flex mt-2"> | |
| <input type="text" id="permanent-url-display" class="w-full p-2 border rounded-l" readonly value=""> | |
| <button class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-3 rounded-r" type="button" id="copy-permanent-button" title="Copier le lien permanent"> | |
| <span class="material-symbols-rounded">content_copy</span> | |
| </button> | |
| </div> | |
| <small class="mt-1 d-block" style="color: #0f5132 !important;"> ✅ Ce lien est sauvegardé sur Hugging Face et est permanent. </small> | |
| </div> | |
| <div id="temp-url-container" class="mt-4 p-3 bg-light border rounded" style="display: none; background-color: #fff3cd !important; border-color: #ffc107 !important;"> | |
| <label class="font-bold d-block text-warning" style="color: #664d03 !important;"> | |
| <span class="material-symbols-rounded align-middle me-1">share</span> Lien d'Aperçu Temporaire | |
| </label> | |
| <div class="flex mt-2"> | |
| <input type="text" id="temp-url-display" class="w-full p-2 border rounded-l" readonly value="{{ temp_launch_url if temp_launch_url else '' }}"> | |
| <button class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-3 rounded-r" type="button" id="copy-temp-button" title="Copier le lien temporaire"> | |
| <span class="material-symbols-rounded">content_copy</span> | |
| </button> | |
| </div> | |
| <small class="mt-1 d-block"> ⚠️ Ce lien est temporaire. Cliquez sur "**Déployer le Site Web**" pour le rendre permanent. </small> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Récupération des éléments du DOM | |
| const body = document.body; | |
| const themeToggle = document.getElementById('theme-toggle'); | |
| const themeIcon = document.getElementById('theme-icon'); | |
| const dropZone = document.getElementById('drop-zone'); | |
| const fileInput = document.getElementById('file-input'); | |
| const selectFilesButton = document.getElementById('select-files-button'); | |
| const uploadStatus = document.getElementById('file-upload-status'); | |
| const uploadedFileList = document.getElementById('uploaded-file-list'); | |
| const launchButton = document.getElementById('launch-button'); | |
| const clearButton = document.getElementById('clear-button'); | |
| const deployButton = document.getElementById('deploy-button'); | |
| const permanentUrlContainer = document.getElementById('permanent-url-container'); | |
| const permanentUrlInput = document.getElementById('permanent-url-display'); | |
| const copyPermanentButton = document.getElementById('copy-permanent-button'); | |
| const tempUrlContainer = document.getElementById('temp-url-container'); | |
| const tempUrlInput = document.getElementById('temp-url-display'); | |
| const copyTempButton = document.getElementById('copy-temp-button'); | |
| let selectedFiles = []; // Stocke les fichiers à téléverser | |
| // Données injectées par Flask (Assurez-vous que votre route Flask passe ces variables) | |
| let currentTempUrl = '{{ temp_launch_url if temp_launch_url else "" }}'; | |
| let currentPermanentUrl = '{{ permanent_deployment_url if permanent_deployment_url else "" }}'; | |
| let initialIndexFilePresent = {{ 'true' if 'index.html' in files else 'false' }}; | |
| let initialFileCount = {{ files|length }}; | |
| const deployId = '{{ deploy_id }}'; | |
| const initialFiles = JSON.parse('{{ files | tojson | safe }}'); | |
| // État initial de l'interface | |
| let currentIndexFilePresent = initialIndexFilePresent; | |
| // ------------------------------------------------------------- | |
| // --- Fonctions d'Utilitaires et de Mise à Jour de l'Interface --- | |
| // ------------------------------------------------------------- | |
| /** Affiche la liste des fichiers téléversés ou en attente */ | |
| function renderFileList(fileList) { | |
| uploadedFileList.innerHTML = ''; | |
| if (fileList.length === 0) { | |
| uploadedFileList.style.display = 'none'; | |
| return; | |
| } | |
| fileList.forEach(filename => { | |
| const li = document.createElement('li'); | |
| li.innerHTML = `<span class="material-symbols-rounded file-icon">file_present</span> ${filename}`; | |
| uploadedFileList.appendChild(li); | |
| }); | |
| uploadedFileList.style.display = 'block'; | |
| } | |
| /** Met à jour l'état des boutons et des URL */ | |
| function updateUIState() { | |
| clearButton.disabled = initialFileCount === 0 && selectedFiles.length === 0; | |
| if (currentPermanentUrl) { | |
| // État final: URL permanente | |
| permanentUrlInput.value = currentPermanentUrl; | |
| permanentUrlContainer.style.display = 'block'; | |
| tempUrlContainer.style.display = 'none'; | |
| deployButton.disabled = true; | |
| deployButton.innerHTML = '<span class="material-symbols-rounded align-middle me-1">cloud_done</span> Déployé !'; | |
| deployButton.classList.remove('bg-green-500', 'hover:bg-green-600'); | |
| deployButton.classList.add('bg-gray-500', 'cursor-not-allowed'); | |
| launchButton.disabled = false; | |
| uploadStatus.textContent = `Site déployé (${initialFileCount} fichiers).`; | |
| uploadStatus.className = 'mt-3 text-success fw-bold text-center'; | |
| } else if (currentTempUrl && currentIndexFilePresent) { | |
| // État temporaire: prêt à être déployé | |
| tempUrlInput.value = currentTempUrl; | |
| tempUrlContainer.style.display = 'block'; | |
| permanentUrlContainer.style.display = 'none'; | |
| deployButton.disabled = false; | |
| deployButton.innerHTML = '<span class="material-symbols-rounded align-middle me-1">cloud_upload</span> Déployer le Site Web (Permanent)'; | |
| deployButton.classList.remove('bg-gray-500', 'cursor-not-allowed'); | |
| deployButton.classList.add('bg-green-500', 'hover:bg-green-600'); | |
| launchButton.disabled = false; | |
| uploadStatus.textContent = `Fichiers téléversés temporairement (${initialFileCount} fichiers. Index.html: Oui). Cliquez sur "Déployer" pour rendre permanent.`; | |
| uploadStatus.className = 'mt-3 text-info fw-bold text-center'; | |
| } else { | |
| // Aucun fichier ou index.html manquant | |
| tempUrlContainer.style.display = 'none'; | |
| permanentUrlContainer.style.display = 'none'; | |
| deployButton.disabled = true; | |
| deployButton.innerHTML = '<span class="material-symbols-rounded align-middle me-1">cloud_upload</span> Déployer le Site Web (Permanent)'; | |
| deployButton.classList.remove('bg-green-500', 'hover:bg-green-600'); | |
| deployButton.classList.add('bg-gray-500', 'cursor-not-allowed'); | |
| launchButton.disabled = true; | |
| if (selectedFiles.length > 0) { | |
| uploadStatus.textContent = `Prêt à téléverser (${selectedFiles.length} fichiers). Index.html: ${currentIndexFilePresent ? 'Oui' : 'Non'}.`; | |
| uploadStatus.className = 'mt-3 text-muted text-center'; | |
| } else { | |
| uploadStatus.textContent = "Aucun fichier téléversé."; | |
| uploadStatus.className = 'mt-3 text-muted text-center'; | |
| } | |
| } | |
| } | |
| /** Initialise l'état au chargement de la page */ | |
| function updateInitialState() { | |
| renderFileList(initialFiles); | |
| updateUIState(); | |
| loadTheme(); // Appliquer le thème sauvegardé | |
| } | |
| // ------------------------------------------------------------- | |
| // --- Logique du Mode Sombre/Clair --- | |
| // ------------------------------------------------------------- | |
| /** Change l'icône et la classe du corps */ | |
| function toggleTheme() { | |
| const isDarkMode = body.classList.toggle('dark-mode'); | |
| if (isDarkMode) { | |
| themeIcon.textContent = 'light_mode'; | |
| localStorage.setItem('theme', 'dark'); | |
| } else { | |
| themeIcon.textContent = 'dark_mode'; | |
| localStorage.setItem('theme', 'light'); | |
| } | |
| } | |
| /** Charge le thème depuis le localStorage */ | |
| function loadTheme() { | |
| const savedTheme = localStorage.getItem('theme') || 'light'; | |
| if (savedTheme === 'dark') { | |
| body.classList.add('dark-mode'); | |
| themeIcon.textContent = 'light_mode'; | |
| } else { | |
| body.classList.remove('dark-mode'); | |
| themeIcon.textContent = 'dark_mode'; | |
| } | |
| } | |
| themeToggle.addEventListener('click', toggleTheme); | |
| // ------------------------------------------------------------- | |
| // --- Logique de Glisser-Déposer et Sélection de Fichiers --- | |
| // ------------------------------------------------------------- | |
| selectFilesButton.addEventListener('click', () => { | |
| fileInput.click(); | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| handleFiles(e.target.files); | |
| }); | |
| // Prévention du comportement par défaut | |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
| dropZone.addEventListener(eventName, preventDefaults, false); | |
| document.body.addEventListener(eventName, preventDefaults, false); | |
| }); | |
| function preventDefaults (e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| } | |
| // Gestion de l'état 'dragover' | |
| dropZone.addEventListener('dragenter', highlight, false); | |
| dropZone.addEventListener('dragover', highlight, false); | |
| dropZone.addEventListener('dragleave', unhighlight, false); | |
| dropZone.addEventListener('drop', unhighlight, false); | |
| function highlight() { | |
| dropZone.classList.add('dragover'); | |
| } | |
| function unhighlight() { | |
| dropZone.classList.remove('dragover'); | |
| } | |
| dropZone.addEventListener('drop', handleDrop, false); | |
| function handleDrop(e) { | |
| let dt = e.dataTransfer; | |
| let files = dt.files; | |
| handleFiles(files); | |
| } | |
| /** Traite la liste des fichiers sélectionnés ou déposés */ | |
| function handleFiles(files) { | |
| selectedFiles = Array.from(files); | |
| // Vérification de index.html | |
| currentIndexFilePresent = selectedFiles.some(file => file.name.toLowerCase() === 'index.html'); | |
| // Affichage des fichiers en attente | |
| const filenames = selectedFiles.map(file => file.name); | |
| renderFileList(filenames); | |
| // Mise à jour de l'état (prêt à téléverser) | |
| currentTempUrl = ''; | |
| currentPermanentUrl = ''; | |
| initialFileCount = selectedFiles.length; // Pour l'état actuel | |
| updateUIState(); | |
| // Lancer le téléversement temporaire immédiatement | |
| if (selectedFiles.length > 0) { | |
| uploadFilesToTempEndpoint(selectedFiles); | |
| } | |
| } | |
| // ------------------------------------------------------------- | |
| // --- Logique du Téléversement TEMPORAIRE vers /upload-static --- | |
| // ------------------------------------------------------------- | |
| async function uploadFilesToTempEndpoint(filesToUpload) { | |
| if (filesToUpload.length === 0) return; | |
| // 1. Préparer l'animation et l'état | |
| uploadStatus.className = 'mt-3 text-warning fw-bold text-center'; | |
| uploadStatus.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span> Téléversement des fichiers temporaires...'; | |
| launchButton.disabled = true; | |
| deployButton.disabled = true; | |
| const formData = new FormData(); | |
| filesToUpload.forEach(file => { | |
| formData.append('files[]', file); // 'files[]' doit correspondre à la manière dont Flask reçoit les fichiers multiples | |
| }); | |
| try { | |
| const response = await fetch('/upload-static', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await response.json(); | |
| if (data.status === 'success') { | |
| // SUCCÈS du téléversement temporaire | |
| currentTempUrl = data.launch_url; | |
| currentIndexFilePresent = data.index_present; | |
| initialFileCount = data.file_count; | |
| // L'état initial du déploiement est maintenant basé sur les données du backend | |
| initialFiles.length = 0; // Vider la liste affichée pour les fichiers fraichement uploadés | |
| filesToUpload.forEach(file => initialFiles.push(file.name)); | |
| renderFileList(initialFiles); | |
| updateUIState(); // Passer à l'état "Temporaire" | |
| uploadStatus.className = 'mt-3 text-success fw-bold text-center'; | |
| uploadStatus.textContent = data.message; | |
| } else { | |
| // ERREUR | |
| currentTempUrl = ''; | |
| currentIndexFilePresent = false; | |
| updateUIState(); // Revenir à l'état "Aucun fichier" ou "Index manquant" | |
| uploadStatus.className = 'mt-3 text-danger fw-bold text-center'; | |
| uploadStatus.textContent = `Échec du téléversement: ${data.message}`; | |
| } | |
| } catch (error) { | |
| console.error('Erreur réseau/inattendue lors du téléversement temporaire:', error); | |
| currentTempUrl = ''; | |
| currentIndexFilePresent = false; | |
| updateUIState(); | |
| uploadStatus.className = 'mt-3 text-danger fw-bold text-center'; | |
| uploadStatus.textContent = `Erreur réseau ou inattendue lors du téléversement temporaire: ${error.message}`; | |
| } | |
| } | |
| // ------------------------------------------------------------- | |
| // --- Logique du Bouton de Déploiement Permanent (Commit) --- | |
| // ------------------------------------------------------------- | |
| deployButton.addEventListener('click', async () => { | |
| // 1. Préparer l'animation et désactiver le bouton | |
| deployButton.disabled = true; | |
| deployButton.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span> Déploiement en cours...'; | |
| uploadStatus.className = 'mt-3 text-info fw-bold text-center'; | |
| uploadStatus.textContent = 'Persistance des fichiers sur Hugging Face et Baserow en cours... (Cela peut prendre quelques instants)'; | |
| // 2. Appel AJAX à la route de commit | |
| try { | |
| const response = await fetch('/commit_static_deployment', { | |
| method: 'POST', | |
| }); | |
| const data = await response.json(); | |
| // 3. Traiter la réponse | |
| if (data.success) { | |
| // SUCCÈS | |
| currentPermanentUrl = data.url; // Mise à jour de l'URL permanente | |
| currentTempUrl = ''; | |
| updateUIState(); // Passer à l'état "Permanent" | |
| uploadStatus.className = 'mt-3 text-success fw-bold text-center'; | |
| uploadStatus.textContent = data.message; | |
| } else { | |
| // ERREUR | |
| // Rétablir les boutons à l'état "temporaire" (si l'échec n'est pas critique) | |
| uploadStatus.className = 'mt-3 text-danger fw-bold text-center'; | |
| uploadStatus.textContent = `Échec du déploiement: ${data.message}`; | |
| updateUIState(); // Rétablit les boutons en se basant sur currentTempUrl | |
| } | |
| } catch (error) { | |
| console.error('Erreur réseau/inattendue:', error); | |
| uploadStatus.className = 'mt-3 text-danger fw-bold text-center'; | |
| uploadStatus.textContent = `Erreur réseau ou inattendue lors du déploiement: ${error.message}`; | |
| updateUIState(); // Rétablit les boutons | |
| } | |
| }); | |
| // ------------------------------------------------------------- | |
| // --- Logique de Copie d'URL et Lancement --- | |
| // ------------------------------------------------------------- | |
| function setupCopyButton(button, input) { | |
| button.addEventListener('click', () => { | |
| if (input.value) { | |
| input.select(); | |
| input.setSelectionRange(0, 99999); | |
| navigator.clipboard.writeText(input.value) | |
| .then(() => { | |
| button.innerHTML = '<span class="material-symbols-rounded">done</span>'; | |
| button.classList.remove('bg-gray-200'); | |
| button.classList.add('bg-green-500', 'text-white'); | |
| setTimeout(() => { | |
| button.innerHTML = '<span class="material-symbols-rounded">content_copy</span>'; | |
| button.classList.remove('bg-green-500', 'text-white'); | |
| button.classList.add('bg-gray-200'); | |
| }, 2000); | |
| }) | |
| .catch(err => { | |
| console.error('Erreur lors de la copie: ', err); | |
| alert('Erreur lors de la copie du lien.'); | |
| }); | |
| } | |
| }); | |
| } | |
| setupCopyButton(copyTempButton, tempUrlInput); | |
| setupCopyButton(copyPermanentButton, permanentUrlInput); | |
| // Gère l'action du bouton Lancer (Ouvre l'URL temporaire ou permanente) | |
| launchButton.addEventListener('click', () => { | |
| const url = permanentUrlInput.value || tempUrlInput.value; | |
| if (url) { | |
| window.open(url, '_blank'); | |
| } | |
| }); | |
| // Gère le bouton Vider (doit être implémenté au backend pour la suppression du dossier) | |
| clearButton.addEventListener('click', () => { | |
| // Si l'utilisateur clique sur Vider, on reset l'état local. | |
| // NOTE: La suppression du dossier temporaire sur le serveur (route /clear_deployment) doit être implémentée au backend. | |
| // Réinitialisation de l'état de l'interface | |
| selectedFiles = []; | |
| currentTempUrl = ''; | |
| currentPermanentUrl = ''; | |
| initialFileCount = 0; | |
| currentIndexFilePresent = false; | |
| initialFiles.length = 0; | |
| renderFileList(initialFiles); | |
| updateUIState(); | |
| // Optionnel : Ajouter un appel AJAX à une route de nettoyage backend ici | |
| // fetch('/clear_deployment', { method: 'POST' }); | |
| alert("L'état local a été vidé. Pour supprimer le dossier temporaire du serveur, la route '/clear_deployment' doit être implémentée dans Flask."); | |
| }); | |
| // Initialise l'état au chargement de la page | |
| window.onload = updateInitialState; | |
| </script> | |
| </body> | |
| </html> |