// ============================================ // GIT PUSHER - MAIN JAVASCRIPT // Version 2.0 avec système de licence par fichier // ============================================ // Configuration const GIT_PUSHER_CONFIG = { serverUrl: window.location.protocol + '//' + window.location.hostname + ':9999', credentialsKey: 'git_pusher_credentials', version: '2.0.0' }; // État global let selectedApps = []; let isProcessing = false; // ============================================ // INITIALISATION // ============================================ require([ 'jquery', 'splunkjs/mvc', 'splunkjs/mvc/searchmanager', 'splunkjs/mvc/simplexml/ready!' ], function($, mvc, SearchManager) { console.log("Git Pusher v2.0 initializing..."); // Initialiser le système de licence if (typeof initializeLicense === 'function') { initializeLicense(); } else { console.warn("License system not loaded"); } // Charger les credentials sauvegardés loadSavedCredentials(); // Récupérer les résultats de recherche pour les apps const searchManager = mvc.Components.get('dsearch'); if (searchManager) { searchManager.on('search:done', function() { const results = searchManager.data('results'); if (results) { results.on('data', function() { const rows = results.data().rows; const fields = results.data().fields; renderAppsList(rows, fields); }); } }); } // Exposer les fonctions globalement window.pushDashboards = pushDashboards; window.resetForm = resetForm; window.toggleSelectAll = toggleSelectAll; }); // Attacher l'événement au bouton après chargement du DOM document.addEventListener('DOMContentLoaded', function() { setTimeout(function() { var pushBtn = document.getElementById('push-btn'); if (pushBtn) { pushBtn.onclick = function() { if (typeof pushDashboards === 'function') { pushDashboards(); } else if (typeof window.pushDashboards === 'function') { window.pushDashboards(); } }; console.log("Push button event attached"); } }, 2000); // Attendre 2 secondes que tout soit chargé }); // ============================================ // RENDU DE LA LISTE DES APPLICATIONS // ============================================ function renderAppsList(rows, fields) { const container = document.getElementById('dashboard-list'); if (!container) return; console.log("Fields:", fields); console.log("First row:", rows[0]); // Trouver les index des colonnes const nameIdx = fields.indexOf('name'); const labelIdx = fields.indexOf('label'); const descIdx = fields.indexOf('description'); console.log("Index - name:", nameIdx, "label:", labelIdx); // Générer le HTML let html = `
${rows.length} apps
`; let validApps = 0; rows.forEach((row, index) => { // Récupérer le nom - essayer plusieurs méthodes let name = ''; if (nameIdx >= 0 && row[nameIdx]) { name = row[nameIdx]; } else if (labelIdx >= 0 && row[labelIdx]) { // Si name est null, utiliser label comme fallback temporaire // On va chercher le vrai nom via l'API name = row[labelIdx]; } else if (row[0]) { name = row[0]; } else if (row[1]) { name = row[1]; // Deuxième élément si premier est null } const label = (labelIdx >= 0 && row[labelIdx]) ? row[labelIdx] : name; console.log(`Row ${index}: name="${name}", label="${label}"`); // Ignorer si pas de nom ou apps système if (!name || name.startsWith('splunk_') || name === 'learned' || name === 'launcher') { return; } validApps++; html += `
`; }); container.innerHTML = html; console.log(`Rendered ${validApps} valid applications out of ${rows.length}`); } // ============================================ // GESTION DE LA SÉLECTION // ============================================ function updateSelectedApps() { const checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app-id]'); selectedApps = []; checkboxes.forEach(cb => { if (cb.checked) { selectedApps.push({ id: cb.getAttribute('data-app-id'), label: cb.getAttribute('data-app-label') }); } }); // Mettre à jour le "Select All" const selectAll = document.getElementById('select-all'); if (selectAll) { const allChecked = Array.from(checkboxes).every(cb => cb.checked); const someChecked = Array.from(checkboxes).some(cb => cb.checked); selectAll.checked = allChecked; selectAll.indeterminate = someChecked && !allChecked; } console.log(`Selected ${selectedApps.length} apps`); } function toggleSelectAll(checked) { const checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app-id]'); checkboxes.forEach(cb => { cb.checked = checked; }); updateSelectedApps(); } // ============================================ // PUSH VERS GIT // ============================================ async function pushDashboards() { console.log("Starting push process..."); // Vérifier si déjà en cours if (isProcessing) { console.log("Push already in progress"); return; } // Récupérer les apps sélectionnées directement depuis le DOM var apps = []; var checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app-id]:checked'); checkboxes.forEach(function(cb) { apps.push({ id: cb.getAttribute('data-app-id'), label: cb.getAttribute('data-app-label') || cb.getAttribute('data-app-id') }); }); console.log("Apps selected from DOM:", apps); // Mettre à jour selectedApps selectedApps = apps; // Vérifier si déjà en cours if (isProcessing) { console.log("Push already in progress"); return; } // Vérifier la licence AVANT tout if (typeof checkLicenseBeforePush === 'function') { const licenseOk = await checkLicenseBeforePush(); if (!licenseOk) { console.log("License check failed"); return; } } // Récupérer les valeurs du formulaire const gitUrl = document.getElementById('git-url')?.value?.trim(); const gitBranch = document.getElementById('git-branch')?.value?.trim() || 'main'; const gitToken = document.getElementById('git-token')?.value?.trim(); const commitMessage = document.getElementById('commit-message')?.value?.trim(); const saveCredentials = document.getElementById('save-credentials')?.checked; // Mettre à jour la liste des apps sélectionnées updateSelectedApps(); // Validation if (!gitUrl) { showMessage('error', 'Please enter a Git repository URL'); return; } if (!gitToken) { showMessage('error', 'Please enter a Git token or password'); return; } if (!commitMessage) { showMessage('error', 'Please enter a commit message'); return; } if (selectedApps.length === 0) { showMessage('error', 'Please select at least one application to deploy'); return; } // Sauvegarder les credentials si demandé if (saveCredentials) { saveCredentialsToStorage(gitUrl, gitBranch, gitToken); } // Démarrer le push isProcessing = true; showLoading(true); hideMessages(); try { // Récupérer l'utilisateur courant const currentUser = await getCurrentUser(); // Construire les paramètres const params = new URLSearchParams({ git_url: gitUrl, git_branch: gitBranch, git_token: gitToken, commit_message: commitMessage, apps: JSON.stringify(selectedApps), user: currentUser }); console.log(`Pushing ${selectedApps.length} apps to ${gitUrl}`); // Appeler le serveur const response = await fetch(`${GIT_PUSHER_CONFIG.serverUrl}/push?${params.toString()}`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const result = await response.json(); console.log("Push result:", result); if (result.status === 'success') { showMessage('success', `✅ Successfully deployed ${result.apps_pushed || selectedApps.length} application(s) to Git!`); // Reset la sélection après succès setTimeout(() => { toggleSelectAll(false); }, 2000); } else if (result.error_code === 'LICENSE_ERROR') { showMessage('error', `🔐 ${result.message}`); // Afficher le modal de licence if (typeof showLicenseModal === 'function') { showLicenseModal(result.message, result.error_code); } } else if (result.error_code === 'APP_LIMIT') { showMessage('error', `📦 ${result.message}`); } else { showMessage('error', result.message || 'Unknown error occurred'); } } catch (error) { console.error("Push error:", error); showMessage('error', `Connection error: ${error.message}. Is the Git Pusher server running?`); } finally { isProcessing = false; showLoading(false); } } // ============================================ // UTILITAIRES UI // ============================================ function showLoading(show) { const loading = document.getElementById('loading'); const pushBtn = document.getElementById('push-btn'); if (loading) { loading.classList.toggle('active', show); } if (pushBtn) { pushBtn.disabled = show; pushBtn.textContent = show ? '⏳ Deploying...' : '✈️ Deploy to Git'; } } function showMessage(type, text) { hideMessages(); const successMsg = document.getElementById('success-msg'); const errorMsg = document.getElementById('error-msg'); const successText = document.getElementById('success-text'); const errorText = document.getElementById('error-text'); if (type === 'success' && successMsg && successText) { successText.textContent = text; successMsg.classList.add('active'); // Auto-hide après 5 secondes setTimeout(() => { successMsg.classList.remove('active'); }, 5000); } else if (type === 'error' && errorMsg && errorText) { errorText.textContent = text; errorMsg.classList.add('active'); } } function hideMessages() { const successMsg = document.getElementById('success-msg'); const errorMsg = document.getElementById('error-msg'); if (successMsg) successMsg.classList.remove('active'); if (errorMsg) errorMsg.classList.remove('active'); } function resetForm(clearCredentials = false) { // Reset les champs const commitMessage = document.getElementById('commit-message'); if (commitMessage) commitMessage.value = ''; if (clearCredentials) { const gitUrl = document.getElementById('git-url'); const gitToken = document.getElementById('git-token'); const saveCredentials = document.getElementById('save-credentials'); if (gitUrl) gitUrl.value = ''; if (gitToken) gitToken.value = ''; if (saveCredentials) saveCredentials.checked = false; // Supprimer les credentials sauvegardés localStorage.removeItem(GIT_PUSHER_CONFIG.credentialsKey); } // Reset la sélection toggleSelectAll(false); // Cacher les messages hideMessages(); console.log("Form reset" + (clearCredentials ? " (with credentials)" : "")); } // ============================================ // GESTION DES CREDENTIALS // ============================================ function saveCredentialsToStorage(gitUrl, gitBranch, gitToken) { try { const credentials = { gitUrl: gitUrl, gitBranch: gitBranch, // Note: En production, envisager une solution plus sécurisée gitToken: btoa(gitToken), // Encodage basique (pas sécurisé, juste pour l'obfuscation) savedAt: new Date().toISOString() }; localStorage.setItem(GIT_PUSHER_CONFIG.credentialsKey, JSON.stringify(credentials)); console.log("Credentials saved"); } catch (error) { console.error("Error saving credentials:", error); } } function loadSavedCredentials() { try { const saved = localStorage.getItem(GIT_PUSHER_CONFIG.credentialsKey); if (!saved) return; const credentials = JSON.parse(saved); const gitUrl = document.getElementById('git-url'); const gitBranch = document.getElementById('git-branch'); const gitToken = document.getElementById('git-token'); const saveCredentials = document.getElementById('save-credentials'); if (gitUrl && credentials.gitUrl) { gitUrl.value = credentials.gitUrl; } if (gitBranch && credentials.gitBranch) { gitBranch.value = credentials.gitBranch; } if (gitToken && credentials.gitToken) { gitToken.value = atob(credentials.gitToken); } if (saveCredentials) { saveCredentials.checked = true; } console.log("Credentials loaded from storage"); } catch (error) { console.error("Error loading credentials:", error); } } // ============================================ // RÉCUPÉRATION DE L'UTILISATEUR SPLUNK // ============================================ async function getCurrentUser() { try { const response = await fetch('/en-US/splunkd/__raw/services/authentication/current-context?output_mode=json'); const data = await response.json(); return data.entry?.[0]?.content?.username || 'unknown'; } catch (error) { console.error("Error getting current user:", error); return 'unknown'; } } // ============================================ // VÉRIFICATION DU SERVEUR // ============================================ async function checkServerHealth() { try { const response = await fetch(`${GIT_PUSHER_CONFIG.serverUrl}/health`, { method: 'GET', timeout: 5000 }); const data = await response.json(); return data.status === 'ok'; } catch (error) { console.error("Server health check failed:", error); return false; } } // Vérifier la santé du serveur au démarrage setTimeout(async () => { const healthy = await checkServerHealth(); if (!healthy) { console.warn("Git Pusher server may not be running"); } else { console.log("Git Pusher server is healthy"); } }, 1000); // ============================================ // EXPORT POUR DEBUG // ============================================ window.GitPusher = { config: GIT_PUSHER_CONFIG, getSelectedApps: () => selectedApps, checkServer: checkServerHealth, version: GIT_PUSHER_CONFIG.version }; // ============================================ // FIX: Attacher les événements aux boutons // ============================================ (function attachButtonEvents() { function tryAttach() { // Bouton Deploy to Git var pushBtn = document.getElementById('push-btn'); if (pushBtn) { pushBtn.addEventListener('click', function(e) { e.preventDefault(); console.log("Push button clicked"); pushDashboards(); }); console.log("✓ Push button event attached"); } // Bouton Reset - chercher par le texte ou la classe var resetBtn = document.querySelector('button.btn-secondary'); if (!resetBtn) { // Chercher par le contenu var allButtons = document.querySelectorAll('button.btn'); allButtons.forEach(function(btn) { if (btn.textContent.includes('Reset') || btn.textContent.includes('🔄')) { resetBtn = btn; } }); } if (resetBtn) { resetBtn.addEventListener('click', function(e) { e.preventDefault(); console.log("Reset button clicked"); resetForm(true); }); console.log("✓ Reset button event attached"); } // Si les boutons ne sont pas encore là, réessayer if (!pushBtn || !resetBtn) { setTimeout(tryAttach, 500); } } // Démarrer après un délai if (document.readyState === 'complete') { setTimeout(tryAttach, 1000); } else { window.addEventListener('load', function() { setTimeout(tryAttach, 1000); }); } })();