/** * WP Prometheus Admin JavaScript * * @package WP_Prometheus */ (function($) { 'use strict'; var importFileContent = null; $(document).ready(function() { // License tab handlers. initLicenseHandlers(); // Custom metrics tab handlers. initCustomMetricsHandlers(); // Dashboards tab handlers. initDashboardsHandlers(); // Runtime metrics reset handler. initResetRuntimeHandler(); // Storage tab handlers. initStorageHandlers(); }); /** * Initialize license tab handlers. */ function initLicenseHandlers() { // Validate license button. $('#wp-prometheus-validate-license').on('click', function(e) { e.preventDefault(); performLicenseAction('wp_prometheus_validate_license', 'Validating...'); }); // Activate license button. $('#wp-prometheus-activate-license').on('click', function(e) { e.preventDefault(); performLicenseAction('wp_prometheus_activate_license', 'Activating...'); }); // Regenerate token button. $('#wp-prometheus-regenerate-token').on('click', function(e) { e.preventDefault(); if (confirm(wpPrometheus.confirmRegenerateToken)) { var newToken = generateToken(32); $('#wp_prometheus_auth_token').val(newToken); } }); } /** * Initialize custom metrics tab handlers. */ function initCustomMetricsHandlers() { var $formContainer = $('#wp-prometheus-metric-form-container'); var $form = $('#wp-prometheus-metric-form'); var $showFormBtn = $('#show-metric-form'); // Show metric form. $showFormBtn.on('click', function() { resetMetricForm(); $formContainer.slideDown(); $(this).hide(); }); // Cancel metric form. $('#cancel-metric-form').on('click', function() { $formContainer.slideUp(); $showFormBtn.show(); // Remove edit parameter from URL. if (window.location.search.indexOf('edit=') > -1) { window.history.pushState({}, '', window.location.pathname + '?page=wp-prometheus&tab=custom'); } }); // Value type toggle. $('input[name="value_type"]').on('change', function() { var valueType = $(this).val(); if (valueType === 'option') { $('#option-config-row').show(); $('#static-values-row').hide(); } else { $('#option-config-row').hide(); $('#static-values-row').show(); } }); // Add label. $('#add-label').on('click', function() { var $container = $('#metric-labels-container'); var labelCount = $container.find('.metric-label-row').length; if (labelCount >= 5) { alert('Maximum 5 labels allowed per metric.'); return; } var $row = $('
' + '' + '' + '
'); $container.append($row); updateValueRows(); }); // Remove label. $(document).on('click', '.remove-label', function() { $(this).closest('.metric-label-row').remove(); updateValueRows(); }); // Add value row. $('#add-value-row').on('click', function() { var $container = $('#metric-values-container'); var rowCount = $container.find('.metric-value-row').length; var labelCount = getLabelCount(); var $row = $('
'); // Add label value inputs. var labels = getLabels(); for (var i = 0; i < labelCount; i++) { $row.append(''); } // Add metric value input. $row.append(''); $row.append(''); $container.append($row); }); // Remove value row. $(document).on('click', '.remove-value-row', function() { $(this).closest('.metric-value-row').remove(); }); // Submit metric form. $form.on('submit', function(e) { e.preventDefault(); saveCustomMetric(); }); // Delete metric. $(document).on('click', '.delete-metric', function() { var id = $(this).data('id'); if (confirm(wpPrometheus.confirmDelete)) { deleteCustomMetric(id); } }); // Export metrics. $('#export-metrics').on('click', function() { exportMetrics(); }); // Import metrics - trigger file input. $('#import-metrics-btn').on('click', function() { $('#import-metrics-file').click(); }); // Import file selected. $('#import-metrics-file').on('change', function(e) { var file = e.target.files[0]; if (file) { var reader = new FileReader(); reader.onload = function(e) { importFileContent = e.target.result; $('#import-options').slideDown(); }; reader.readAsText(file); } }); // Confirm import. $('#confirm-import').on('click', function() { var mode = $('input[name="import_mode"]:checked').val(); importMetrics(importFileContent, mode); }); // Cancel import. $('#cancel-import').on('click', function() { $('#import-options').slideUp(); $('#import-metrics-file').val(''); importFileContent = null; }); } /** * Initialize dashboards tab handlers. */ function initDashboardsHandlers() { $(document).on('click', '.download-dashboard', function() { var slug = $(this).data('slug'); downloadDashboard(slug); }); } /** * Initialize reset runtime metrics handler. */ function initResetRuntimeHandler() { $('#wp-prometheus-reset-runtime').on('click', function() { if (confirm(wpPrometheus.confirmReset)) { resetRuntimeMetrics(); } }); } /** * Perform a license action via AJAX. * * @param {string} action AJAX action name. * @param {string} message Loading message. */ function performLicenseAction(action, message) { var $spinner = $('#wp-prometheus-license-spinner'); var $message = $('#wp-prometheus-license-message'); $spinner.addClass('is-active'); $message.hide(); $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: { action: action, nonce: wpPrometheus.nonce }, success: function(response) { $spinner.removeClass('is-active'); if (response.success) { $message .removeClass('notice-error') .addClass('notice notice-success') .html('

' + response.data.message + '

') .show(); // Reload page after successful validation/activation. setTimeout(function() { location.reload(); }, 1500); } else { $message .removeClass('notice-success') .addClass('notice notice-error') .html('

' + (response.data.message || 'An error occurred.') + '

') .show(); } }, error: function() { $spinner.removeClass('is-active'); $message .removeClass('notice-success') .addClass('notice notice-error') .html('

Connection error. Please try again.

') .show(); } }); } /** * Save custom metric via AJAX. */ function saveCustomMetric() { var $spinner = $('#wp-prometheus-metric-spinner'); var $message = $('#wp-prometheus-metric-message'); var $form = $('#wp-prometheus-metric-form'); $spinner.addClass('is-active'); $message.hide(); var formData = $form.serialize(); formData += '&action=wp_prometheus_save_custom_metric'; formData += '&nonce=' + wpPrometheus.customMetricNonce; $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: formData, success: function(response) { $spinner.removeClass('is-active'); if (response.success) { $message .removeClass('notice-error') .addClass('notice notice-success') .html('

' + response.data.message + '

') .show(); setTimeout(function() { window.location.href = window.location.pathname + '?page=wp-prometheus&tab=custom'; }, 1000); } else { $message .removeClass('notice-success') .addClass('notice notice-error') .html('

' + (response.data.message || 'An error occurred.') + '

') .show(); } }, error: function() { $spinner.removeClass('is-active'); $message .removeClass('notice-success') .addClass('notice notice-error') .html('

Connection error. Please try again.

') .show(); } }); } /** * Delete custom metric via AJAX. * * @param {string} id Metric ID. */ function deleteCustomMetric(id) { $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: { action: 'wp_prometheus_delete_custom_metric', nonce: wpPrometheus.customMetricNonce, id: id }, success: function(response) { if (response.success) { $('tr[data-metric-id="' + id + '"]').fadeOut(function() { $(this).remove(); // Check if table is empty. if ($('.wp-prometheus-custom-metrics tbody tr').length === 0) { location.reload(); } }); } else { alert(response.data.message || 'An error occurred.'); } }, error: function() { alert('Connection error. Please try again.'); } }); } /** * Export metrics via AJAX. */ function exportMetrics() { $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: { action: 'wp_prometheus_export_metrics', nonce: wpPrometheus.exportNonce }, success: function(response) { if (response.success) { downloadFile(response.data.json, response.data.filename, 'application/json'); } else { alert(response.data.message || 'An error occurred.'); } }, error: function() { alert('Connection error. Please try again.'); } }); } /** * Import metrics via AJAX. * * @param {string} json JSON content. * @param {string} mode Import mode. */ function importMetrics(json, mode) { var $spinner = $('#wp-prometheus-import-spinner'); var $message = $('#wp-prometheus-import-message'); $spinner.addClass('is-active'); $message.hide(); $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: { action: 'wp_prometheus_import_metrics', nonce: wpPrometheus.importNonce, json: json, mode: mode }, success: function(response) { $spinner.removeClass('is-active'); if (response.success) { $message .removeClass('notice-error') .addClass('notice notice-success') .html('

' + response.data.message + '

') .show(); $('#import-options').slideUp(); $('#import-metrics-file').val(''); importFileContent = null; setTimeout(function() { location.reload(); }, 1500); } else { $message .removeClass('notice-success') .addClass('notice notice-error') .html('

' + (response.data.message || 'An error occurred.') + '

') .show(); } }, error: function() { $spinner.removeClass('is-active'); $message .removeClass('notice-success') .addClass('notice notice-error') .html('

Connection error. Please try again.

') .show(); } }); } /** * Download dashboard via AJAX. * * @param {string} slug Dashboard slug. */ function downloadDashboard(slug) { $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: { action: 'wp_prometheus_download_dashboard', nonce: wpPrometheus.dashboardNonce, slug: slug }, success: function(response) { if (response.success) { downloadFile(response.data.json, response.data.filename, 'application/json'); } else { alert(response.data.message || 'An error occurred.'); } }, error: function() { alert('Connection error. Please try again.'); } }); } /** * Reset runtime metrics via AJAX. */ function resetRuntimeMetrics() { var $spinner = $('#wp-prometheus-reset-spinner'); var $message = $('#wp-prometheus-reset-message'); $spinner.addClass('is-active'); $message.hide(); $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: { action: 'wp_prometheus_reset_runtime_metrics', nonce: wpPrometheus.resetRuntimeNonce }, success: function(response) { $spinner.removeClass('is-active'); if (response.success) { $message .removeClass('notice-error') .addClass('notice notice-success') .html('

' + response.data.message + '

') .show(); } else { $message .removeClass('notice-success') .addClass('notice notice-error') .html('

' + (response.data.message || 'An error occurred.') + '

') .show(); } }, error: function() { $spinner.removeClass('is-active'); $message .removeClass('notice-success') .addClass('notice notice-error') .html('

Connection error. Please try again.

') .show(); } }); } /** * Reset the metric form to default state. */ function resetMetricForm() { var $form = $('#wp-prometheus-metric-form'); $form[0].reset(); $('#metric-id').val(''); $('#wp-prometheus-form-title').text('Add New Metric'); $('#option-config-row').hide(); $('#static-values-row').show(); $('#wp-prometheus-metric-message').hide(); // Reset labels to single empty row. $('#metric-labels-container').html( '
' + '' + '' + '
' ); // Reset values to single empty row. $('#metric-values-container').html( '
' + '' + '' + '
' ); } /** * Update value rows when labels change. */ function updateValueRows() { var labels = getLabels(); var labelCount = labels.length; $('#metric-values-container .metric-value-row').each(function(rowIndex) { var $row = $(this); var inputs = $row.find('input').toArray(); var currentValues = inputs.map(function(input) { return input.value; }); // Remove all inputs except the value and button. $row.find('input').remove(); // Re-add label inputs. for (var i = 0; i < labelCount; i++) { var val = currentValues[i] || ''; $row.prepend(''); } // Re-add value input. var metricVal = currentValues[currentValues.length - 1] || ''; $row.find('.remove-value-row').before(''); }); } /** * Get current label names. * * @return {string[]} Array of label names. */ function getLabels() { var labels = []; $('#metric-labels-container input[name="labels[]"]').each(function() { var val = $(this).val().trim(); if (val) { labels.push(val); } }); return labels; } /** * Get current label count. * * @return {number} Number of labels. */ function getLabelCount() { return getLabels().length; } /** * Generate a random token. * * @param {number} length Token length. * @return {string} Generated token. */ function generateToken(length) { var charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; var token = ''; for (var i = 0; i < length; i++) { token += charset.charAt(Math.floor(Math.random() * charset.length)); } return token; } /** * Download a file. * * @param {string} content File content. * @param {string} filename Filename. * @param {string} type MIME type. */ function downloadFile(content, filename, type) { var blob = new Blob([content], { type: type }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } /** * Initialize storage tab handlers. */ function initStorageHandlers() { var $form = $('#wp-prometheus-storage-form'); var $adapterSelect = $('#storage-adapter'); // Show/hide adapter-specific config. $adapterSelect.on('change', function() { var adapter = $(this).val(); $('#redis-config').toggle(adapter === 'redis'); $('#apcu-config').toggle(adapter === 'apcu'); }); // Save storage settings. $form.on('submit', function(e) { e.preventDefault(); saveStorageSettings(); }); // Test storage connection. $('#test-storage').on('click', function() { testStorageConnection(); }); } /** * Save storage settings via AJAX. */ function saveStorageSettings() { var $spinner = $('#wp-prometheus-storage-spinner'); var $message = $('#wp-prometheus-storage-message'); var $form = $('#wp-prometheus-storage-form'); $spinner.addClass('is-active'); $message.hide(); var formData = $form.serialize(); formData += '&action=wp_prometheus_save_storage'; formData += '&nonce=' + wpPrometheus.storageNonce; $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: formData, success: function(response) { $spinner.removeClass('is-active'); if (response.success) { var noticeClass = response.data.warning ? 'notice-warning' : 'notice-success'; $message .removeClass('notice-error notice-success notice-warning') .addClass('notice ' + noticeClass) .html('

' + response.data.message + '

') .show(); if (!response.data.warning) { setTimeout(function() { location.reload(); }, 1500); } } else { $message .removeClass('notice-success notice-warning') .addClass('notice notice-error') .html('

' + (response.data.message || 'An error occurred.') + '

') .show(); } }, error: function() { $spinner.removeClass('is-active'); $message .removeClass('notice-success notice-warning') .addClass('notice notice-error') .html('

Connection error. Please try again.

') .show(); } }); } /** * Test storage connection via AJAX. */ function testStorageConnection() { var $spinner = $('#wp-prometheus-storage-spinner'); var $message = $('#wp-prometheus-storage-message'); var $form = $('#wp-prometheus-storage-form'); $spinner.addClass('is-active'); $message.hide(); var formData = $form.serialize(); formData += '&action=wp_prometheus_test_storage'; formData += '&nonce=' + wpPrometheus.storageNonce; $.ajax({ url: wpPrometheus.ajaxUrl, type: 'POST', data: formData, success: function(response) { $spinner.removeClass('is-active'); if (response.success) { $message .removeClass('notice-error notice-warning') .addClass('notice notice-success') .html('

' + response.data.message + '

') .show(); } else { $message .removeClass('notice-success notice-warning') .addClass('notice notice-error') .html('

' + (response.data.message || 'Connection test failed.') + '

') .show(); } }, error: function() { $spinner.removeClass('is-active'); $message .removeClass('notice-success notice-warning') .addClass('notice notice-error') .html('

Connection error. Please try again.

') .show(); } }); } })(jQuery);