diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/gui/bastille_manager_gui.php b/gui/bastille_manager_gui.php index 7d1b0e4..9a1738c 100644 --- a/gui/bastille_manager_gui.php +++ b/gui/bastille_manager_gui.php @@ -39,6 +39,41 @@ require_once 'auth.inc'; require_once 'guiconfig.inc'; require_once 'bastille_manager-lib.inc'; +$img_path = [ + 'add' => 'images/add.png', + 'mod' => 'images/edit.png', + 'del' => 'images/delete.png', + 'loc' => 'images/locked.png', + 'unl' => 'images/unlocked.png', + 'mai' => 'images/maintain.png', + 'inf' => 'images/info.png', + 'ena' => 'images/status_enabled.png', + 'dis' => 'images/status_disabled.png', + 'mup' => 'images/up.png', + 'mdn' => 'images/down.png' +]; + +// --- START AUTO-REFRESH LOGIC --- +if (isset($_GET['action']) && $_GET['action'] === 'refresh_table') { + error_reporting(0); + ini_set('display_errors', 0); + ob_start(); + + // Fetch fresh data + $jls_list = []; + if (function_exists('get_jail_infos')) { + $jls_list = get_jail_infos(); + } + + // Return JSON + ob_clean(); + header('Content-Type: application/json'); + header('Cache-Control: no-cache'); + echo json_encode(['success' => true, 'jails' => $jls_list ?: []]); + exit; +} +// --- END AUTO-REFRESH LOGIC --- + function mwexec_parallel($commands) { $processes = []; $results = []; @@ -53,7 +88,6 @@ function mwexec_parallel($commands) { $process = proc_open($command, $descriptors, $pipes); if (is_resource($process)) { - stream_set_blocking($pipes[1], false); stream_set_blocking($pipes[2], false); @@ -71,7 +105,6 @@ function mwexec_parallel($commands) { foreach ($processes as $key => $proc) { $elapsed = time() - $start_time; if ($elapsed < $timeout) { - $stdout = stream_get_contents($proc['pipes'][1]); $stderr = stream_get_contents($proc['pipes'][2]); @@ -102,8 +135,8 @@ function mwexec_parallel($commands) { } function mwexec_background($command) { - $command = $command . ' > /dev/null 2>&1 &'; - exec($command); + $command = $command . ' > /dev/null 2>&1 &'; + exec($command); } $sphere_scriptname = basename(__FILE__); @@ -127,19 +160,6 @@ $gt_selection_start_confirm = gtext('Do you really want to start selected jail(s $gt_selection_stop_confirm = gtext('Do you want to stop the selected jail(s)?'); $gt_selection_restart_confirm = gtext('Do you want to restart the selected jail(s)?'); $gt_selection_autoboot_confirm = gtext('Do you want to set auto-boot on selected jail(s)?'); -$img_path = [ - 'add' => 'images/add.png', - 'mod' => 'images/edit.png', - 'del' => 'images/delete.png', - 'loc' => 'images/locked.png', - 'unl' => 'images/unlocked.png', - 'mai' => 'images/maintain.png', - 'inf' => 'images/info.png', - 'ena' => 'images/status_enabled.png', - 'dis' => 'images/status_disabled.png', - 'mup' => 'images/up.png', - 'mdn' => 'images/down.png' -]; $jls_list = get_jail_infos(); $sphere_array = $jls_list; @@ -184,19 +204,16 @@ if($_POST): if(isset($_POST['start_selected_jail']) && $_POST['start_selected_jail']): $checkbox_member_array = isset($_POST[$checkbox_member_name]) ? $_POST[$checkbox_member_name] : []; $commands = []; - $jail_names = []; foreach($checkbox_member_array as $checkbox_member_record): if(false !== ($index = array_search_ex($checkbox_member_record, $sphere_array, 'jailname'))): if(!isset($sphere_array[$index]['protected'])): $commands[] = "/usr/local/bin/bastille start {$checkbox_member_record}"; - $jail_names[] = $checkbox_member_record; endif; endif; endforeach; if (!empty($commands)): - $results = mwexec_parallel($commands); $success_count = 0; @@ -345,36 +362,116 @@ if($_POST): endif; endif; -$pgtitle = [gtext("Extensions"), gtext('Bastille')]; +$pgtitle = [gtext("Extensions"), gtext('Bastille'), gtext('Manager')]; include 'fbegin.inc'; ?> + + render(); - - - + +
+ + + + - + + + + + + + + + + + + - - - - - - - - - - - render(); endif; endif; ?> + @@ -562,8 +816,9 @@ $document->render();
<?=$gt_record_conf?>
\ No newline at end of file diff --git a/gui/bastille_manager_maintenance.php b/gui/bastille_manager_maintenance.php index f74e28a..67e82a0 100644 --- a/gui/bastille_manager_maintenance.php +++ b/gui/bastille_manager_maintenance.php @@ -306,6 +306,23 @@ $(document).ready(function(){ $('#getinfo_bastille').html(data.bastille); $('#getinfo_ext').html(data.ext); }); + + // --- LOGICA DEL CHECKBOX REFRESH (LocalStorage) --- + var $chk = $("#show_refresh_button"); + + // 1. Leer estado inicial desde LocalStorage + var savedState = localStorage.getItem('bastille_show_refresh_button'); + if (savedState === 'true') { + $chk.prop('checked', true); + } else { + $chk.prop('checked', false); // Por defecto deshabilitado + } + + // 2. Guardar cambios al hacer click + $chk.change(function() { + var isChecked = $(this).is(':checked'); + localStorage.setItem('bastille_show_refresh_button', isChecked); + }); }); //]]> @@ -373,6 +390,9 @@ $(document).ready(function(){ + + +
" value="" onclick="return confirm('')" /> @@ -384,4 +404,4 @@ $(document).ready(function(){ - + \ No newline at end of file diff --git a/gui/css/bastille-header-refresh.css b/gui/css/bastille-header-refresh.css new file mode 100644 index 0000000..91a947f --- /dev/null +++ b/gui/css/bastille-header-refresh.css @@ -0,0 +1,58 @@ +/* bastille_manager.css + Estilo NATIVO (Minimalista) +*/ + +#refresh-controls { + /* Fondo transparente y sin bordes para integrarse con el tema */ + background: transparent; + border: none; + padding: 10px 0; + margin-bottom: 5px; + + /* Alineación a la derecha */ + display: flex; + justify-content: flex-end; + align-items: center; + gap: 15px; + + /* Fuente estándar del sistema */ + font-size: 13px; + color: inherit; +} + +#refresh-status { + /* Color de texto por defecto del tema (negro/gris) */ + color: inherit; + margin-right: 5px; + + /* Coloca el texto a la izquierda de los botones */ + order: -1; +} + +/* Pequeño spinner azul discreto solo cuando actualiza */ +#refresh-status.updating .refresh-spinner { + display: inline-block; + width: 10px; + height: 10px; + border: 2px solid #ccc; + border-top-color: #007bff; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-right: 5px; +} + +/* Animación del spinner */ +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Asegurar que los iconos de la tabla estén centrados verticalmente */ +.area_data_selection tbody td img { + vertical-align: middle; +} + +/* Centrado perfecto para los checkboxes */ +.lcelc { + text-align: center; + vertical-align: middle; +} \ No newline at end of file