Merge branch 'ent-10194-nueva-pantalla-tactica-relacionado-con-mejoras-en-la-automonitorizacion' into 'develop'

Ent 10194 Nueva pantalla táctica (relacionado con mejoras en la automonitorización)

See merge request artica/pandorafms!6485
This commit is contained in:
Diego Muñoz-Reja 2023-10-23 07:24:20 +00:00
commit 48c314669a
37 changed files with 5282 additions and 613 deletions

View File

@ -26,6 +26,8 @@
* ============================================================================
*/
use PandoraFMS\TacticalView\GeneralTacticalView;
// Config functions.
require_once 'include/config.php';
@ -43,322 +45,5 @@ if (check_acl($config['id_user'], 0, 'AR') === 0) {
exit;
}
require_once 'include/functions_reporting.php';
require_once 'include/functions_tactical.php';
require_once $config['homedir'].'/include/functions_graph.php';
if (tags_has_user_acl_tags()) {
ui_print_tags_warning();
}
$all_data = tactical_status_modules_agents(
$config['id_user'],
false,
'AR'
);
$data = [];
$data['monitor_not_init'] = (int) $all_data['_monitors_not_init_'];
$data['monitor_unknown'] = (int) $all_data['_monitors_unknown_'];
$data['monitor_ok'] = (int) $all_data['_monitors_ok_'];
$data['monitor_warning'] = (int) $all_data['_monitors_warning_'];
$data['monitor_critical'] = (int) $all_data['_monitors_critical_'];
$data['monitor_not_normal'] = (int) $all_data['_monitor_not_normal_'];
$data['monitor_alerts'] = (int) $all_data['_monitors_alerts_'];
$data['monitor_alerts_fired'] = (int) $all_data['_monitors_alerts_fired_'];
$data['monitor_total'] = (int) $all_data['_monitor_total_'];
$data['total_agents'] = (int) $all_data['_total_agents_'];
$data['monitor_checks'] = (int) $all_data['_monitor_checks_'];
if (!empty($all_data)) {
if ($data['monitor_not_normal'] > 0 && $data['monitor_checks'] > 0) {
$data['monitor_health'] = format_numeric((100 - ($data['monitor_not_normal'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['monitor_health'] = 100;
}
if ($data['monitor_not_init'] > 0 && $data['monitor_checks'] > 0) {
$data['module_sanity'] = format_numeric((100 - ($data['monitor_not_init'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['module_sanity'] = 100;
}
if (isset($data['alerts'])) {
if ($data['monitor_alerts_fired'] > 0 && $data['alerts'] > 0) {
$data['alert_level'] = format_numeric((100 - ($data['monitor_alerts_fired'] / ($data['alerts'] / 100))), 1);
} else {
$data['alert_level'] = 100;
}
} else {
$data['alert_level'] = 100;
$data['alerts'] = 0;
}
$data['monitor_bad'] = ($data['monitor_critical'] + $data['monitor_warning']);
if ($data['monitor_bad'] > 0 && $data['monitor_checks'] > 0) {
$data['global_health'] = format_numeric((100 - ($data['monitor_bad'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['global_health'] = 100;
}
$data['server_sanity'] = format_numeric((100 - $data['module_sanity']), 1);
}
ui_require_css_file('logon');
echo '<div id="welcome_panel">';
//
// Overview Table.
//
$table = new stdClass();
$table->class = 'no-class';
$table->cellpadding = 4;
$table->cellspacing = 4;
$table->head = [];
$table->data = [];
$table->headstyle[0] = 'text-align:center;';
$table->width = '100%';
$table->head_colspan[0] = 4;
// Indicators.
$tdata = [];
$stats = reporting_get_stats_indicators($data, 120, 10, false);
$status = '<table class="status_tactical">';
foreach ($stats as $stat) {
$status .= '<tr><td><b>'.$stat['title'].'</b></td><td>'.$stat['graph'].'</td></tr>';
}
$status .= '</table>';
$table->rowclass = [];
$table->rowclass[0] = 'w100p';
$table->rowclass[1] = 'w100p';
$table->rowclass[2] = 'w100p';
$table->rowclass[3] = 'w100p';
$table->rowclass[4] = 'w100p';
$table->rowclass[5] = 'w100p';
$table->data[0][0] = $status;
$table->data[] = $tdata;
// Alerts.
$tdata = [];
$tdata[0] = reporting_get_stats_alerts($data);
$table->rowclass[] = '';
$table->data[] = $tdata;
// Modules by status.
$tdata = [];
$data_agents = [
__('Critical') => $data['monitor_critical'],
__('Warning') => $data['monitor_warning'],
__('Normal') => $data['monitor_ok'],
__('Unknown') => $data['monitor_unknown'],
__('Not init') => $data['monitor_not_init'],
];
$tdata[0] = reporting_get_stats_modules_status($data, 180, 100, false, $data_agents);
$table->rowclass[] = '';
$table->data[] = $tdata;
// Total agents and modules.
$tdata = [];
$tdata[0] = reporting_get_stats_agents_monitors($data);
$table->rowclass[] = '';
$table->data[] = $tdata;
// Users.
if (users_is_admin() || check_acl($config['id_user'], 0, 'UM')) {
$tdata = [];
$tdata[0] = reporting_get_stats_users($data);
$table->rowclass[] = '';
$table->data[] = $tdata;
}
ui_toggle(
html_print_table($table, true),
__('%s Overview', get_product_name()),
'',
'overview',
false
);
unset($table);
echo '<div id="right">';
// News.
require_once 'general/news_dialog.php';
$options = [];
$options['id_user'] = $config['id_user'];
$options['modal'] = false;
$options['limit'] = 3;
$news = get_news($options);
if (!empty($news)) {
ui_require_css_file('news');
// NEWS BOARD.
if ($config['prominent_time'] == 'timestamp') {
$comparation_suffix = '';
} else {
$comparation_suffix = __('ago');
}
$output_news = '<div id="news_board" class="new">';
foreach ($news as $article) {
$default = false;
if ($article['text'] == '&amp;lt;p&#x20;style=&quot;text-align:&#x20;center;&#x20;font-size:&#x20;13px;&quot;&amp;gt;Hello,&#x20;congratulations,&#x20;if&#x20;you&apos;ve&#x20;arrived&#x20;here&#x20;you&#x20;already&#x20;have&#x20;an&#x20;operational&#x20;monitoring&#x20;console.&#x20;Remember&#x20;that&#x20;our&#x20;forums&#x20;and&#x20;online&#x20;documentation&#x20;are&#x20;available&#x20;24x7&#x20;to&#x20;get&#x20;you&#x20;out&#x20;of&#x20;any&#x20;trouble.&#x20;You&#x20;can&#x20;replace&#x20;this&#x20;message&#x20;with&#x20;a&#x20;personalized&#x20;one&#x20;at&#x20;Admin&#x20;tools&#x20;-&amp;amp;gt;&#x20;Site&#x20;news.&amp;lt;/p&amp;gt;&#x20;') {
$article['subject'] = __('Welcome to Pandora FMS Console');
$default = true;
}
$text_bbdd = io_safe_output($article['text']);
$text = html_entity_decode($text_bbdd);
$output_news .= '<div class="new-board">';
$output_news .= '<div class="new-board-header">';
$output_news .= '<span class="new-board-title">'.$article['subject'].'</span>';
$output_news .= '<span class="new-board-author">'.__('By').' '.$article['author'].' '.ui_print_timestamp($article['timestamp'], true).'</span>';
$output_news .= '</div>';
$output_news .= '<div class="new content">';
if ($default) {
$output_news .= '<div class="default-new">';
$output_news .= '<div class="default-image-new">';
$output_news .= '<img src="./images/welcome_image.svg" alt="img colabora con nosotros - Support">';
$output_news .= '</div><div class="default-text-new">';
$output_news .= '
<p>'.__('Welcome to our monitoring tool so grand,').'
<br>'.__('Where data insights are at your command.').'
<br>'.__('Sales, marketing, operations too,').'
<br>'.__("Customer support, we've got you.").'
</p>
<p>'.__('Our interface is user-friendly,').'
<br>'.__("Customize your dashboard, it's easy.").'
<br>'.__('Set up alerts and gain insights so keen,').'
<br>'.__("Optimize your data, like you've never seen.").'
</p>
<p>'.__('Unleash its power now, and join the pro league,').'
<br>'.__('Unlock the potential of your data to intrigue.').'
<br>'.__('Monitoring made simple, efficient and fun,').'
<br>'.__('Discover a whole new way to get things done.').'
</p>
<p>'.__('And take control of your IT once and for all.').'</p>
<span>'.__('You can replace this message with a personalized one at Admin tools -> Site news.').'</span>
';
$output_news .= '</div></div>';
} else {
$text = str_replace('<script', '&lt;script', $text);
$text = str_replace('</script', '&lt;/script', $text);
$output_news .= nl2br($text);
}
$output_news .= '</div></div>';
}
$output_news .= '</div>';
// News board.
ui_toggle(
$output_news,
__('News board'),
'',
'news',
false
);
// END OF NEWS BOARD.
}
// LAST ACTIVITY.
// Show last activity from this user.
$table = new stdClass();
$table->class = 'no-td-padding info_table';
$table->cellpadding = 0;
$table->cellspacing = 0;
$table->width = '100%';
// Don't specify px.
$table->data = [];
$table->size = [];
$table->headstyle = [];
$table->size[0] = '5%';
$table->size[1] = '15%';
$table->headstyle[1] = 'min-width: 12em;';
$table->size[2] = '5%';
$table->headstyle[2] = 'min-width: 65px;';
$table->size[3] = '10%';
$table->size[4] = '25%';
$table->head = [];
$table->head[0] = __('User');
$table->head[1] = __('Action');
$table->head[2] = __('Date');
$table->head[3] = __('Source IP');
$table->head[4] = __('Comments');
$table->align[4] = 'left';
$sql = sprintf(
'SELECT id_usuario,accion, ip_origen,descripcion,utimestamp
FROM tsesion
WHERE (`utimestamp` > UNIX_TIMESTAMP(NOW()) - '.SECONDS_1WEEK.")
AND `id_usuario` = '%s' ORDER BY `utimestamp` DESC LIMIT 10",
$config['id_user']
);
$sessions = db_get_all_rows_sql($sql);
if ($sessions === false) {
$sessions = [];
}
foreach ($sessions as $session) {
$data = [];
$session_id_usuario = $session['id_usuario'];
$session_ip_origen = $session['ip_origen'];
$data[0] = '<strong>'.$session_id_usuario.'</strong>';
$data[1] = ui_print_session_action_icon($session['accion'], true).' '.$session['accion'];
$data[2] = ui_print_help_tip(
date($config['date_format'], $session['utimestamp']),
true
).human_time_comparation($session['utimestamp'], 'tiny');
$data[3] = $session_ip_origen;
$description = io_safe_output(str_replace([',', ', '], ', ', $session['descripcion']));
if (strlen($description) > 100) {
$data[4] = '<div >'.io_safe_input(substr($description, 0, 150)).'...</div>';
} else {
$data[4] = '<div >'.io_safe_input($description).'</div>';
}
array_push($table->data, $data);
}
$activity = html_print_table($table, true);
unset($table);
ui_toggle(
$activity,
__('Latest activity'),
'',
'activity',
false,
false,
'',
'white-box-content padded'
);
// END OF LAST ACTIVIYY.
// Close right panel.
echo '</div>';
// Close welcome panel.
echo '</div>';
$tacticalView = new GeneralTacticalView();
$tacticalView->render();

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>59DFD8E8-D019-4076-8FED-D5B81BE90197</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1185, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(15, 71)">
<g id="Groups" transform="translate(68, 0)">
<rect id="Rectangle" x="0" y="0" width="5.4" height="5.4" rx="0.5"></rect>
<rect id="Rectangle-Copy-2" x="0" y="21.6" width="5.4" height="5.4" rx="0.5"></rect>
<rect id="Rectangle-Copy" x="21.6" y="0" width="5.4" height="5.4" rx="0.5"></rect>
<rect id="Rectangle-Copy-3" x="21.6" y="21.6" width="5.4" height="5.4" rx="0.5"></rect>
<path d="M24.3,2.7 L24.3,24.3 L2.7,24.3 L2.7,2.7 L24.3,2.7 Z M19.06875,10.8 L17.55,10.8 L17.55,16.36875 C17.55,17.0211364 17.0211364,17.55 16.36875,17.55 L10.8,17.549 L10.8,19.06875 C10.8,19.7211364 11.3288636,20.25 11.98125,20.25 L19.06875,20.25 C19.7211364,20.25 20.25,19.7211364 20.25,19.06875 L20.25,11.98125 C20.25,11.3288636 19.7211364,10.8 19.06875,10.8 Z M15.01875,6.75 L7.93125,6.75 C7.27886364,6.75 6.75,7.27886364 6.75,7.93125 L6.75,15.01875 C6.75,15.6711364 7.27886364,16.2 7.93125,16.2 L15.01875,16.2 C15.6711364,16.2 16.2,15.6711364 16.2,15.01875 L16.2,7.93125 C16.2,7.27886364 15.6711364,6.75 15.01875,6.75 Z" id="Rectangle-2"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>04A64774-B33A-4338-8092-D83F51BBE8C1</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1218, -1942)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(49, 203)">
<g id="Module-template" transform="translate(67, 0)">
<path d="M1,0 L26,0 C26.5522847,-1.01453063e-16 27,0.44771525 27,1 L27,8.45 C27,9.00228475 26.5522847,9.45 26,9.45 L1,9.45 C0.44771525,9.45 6.76353751e-17,9.00228475 0,8.45 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z M11.8,10.8 L26,10.8 C26.5522847,10.8 27,11.2477153 27,11.8 L27,26 C27,26.5522847 26.5522847,27 26,27 L11.8,27 C11.2477153,27 10.8,26.5522847 10.8,26 L10.8,11.8 C10.8,11.2477153 11.2477153,10.8 11.8,10.8 Z" id="Rectangle-2"></path>
<path d="M8.45,10.8 C9.00228475,10.8 9.45,11.2477153 9.45,11.8 L9.45,26 C9.45,26.5522847 9.00228475,27 8.45,27 L1,27 C0.44771525,27 0,26.5522847 0,26 L0,11.8 C0,11.2477153 0.44771525,10.8 1,10.8 L8.45,10.8 Z M7.45,12.8 L2,12.8 L2,25 L7.45,25 L7.45,12.8 Z" id="Rectangle" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CD5F043F-0CA1-4012-8590-20C64D7E7E0D</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1378, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(208, 71)">
<g id="Modules" transform="translate(68, 0)">
<path d="M25.3705078,4.29521484 L14.6865234,0.218847656 C14.3015625,0.0729316406 13.9007813,0 13.5,0 C13.0992187,0 12.6984375,0.0729316406 12.3134766,0.218583984 L1.62896484,4.29521484 C0.648105469,4.66962891 0,5.6109375 0,6.66035156 L0,20.3396484 C0,21.3895898 0.648105469,22.3303711 1.62896484,22.7047852 L12.3129492,26.7811523 C12.6984375,26.9261719 13.0992188,27 13.5,27 C13.9007813,27 14.3031445,26.9270684 14.6849414,26.781416 L25.3689258,22.7050488 C26.3513672,22.3330078 27,21.3890625 27,20.3396484 L27,6.66035156 C27,5.6109375 26.3513672,4.66962891 25.3705078,4.29521484 Z M13.0008122,3 L22,6.5303428 L13.0008122,10 L4,6.5314563 L13.0008122,3 Z M15,23 L15,13.1237485 L23,10 L23,19.8137765 L15,23 Z"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>E1DA8ECF-DB7D-48B5-96B0-3C6199FCC8EB</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1476, -1942)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(306, 203)">
<g id="Not-init-module" transform="translate(68, 0)">
<path d="M1.51937106,7.28411239 C4.95205428,0.667087472 13.0993581,-1.91380755 19.7156094,1.51964932 C20.0173327,1.67592653 20.3097722,1.84226119 20.5937016,2.017106 L18.0128066,3.66652692 L18.009712,3.66575327 L12.8138814,6.98548365 L12.710986,2.70797508 C11.8669343,2.76986705 11.0344873,2.93078616 10.2322127,3.18531688 C7.59329397,4.02163208 5.27234521,5.86523905 3.8960226,8.51730983 C2.52047363,11.1693806 2.34872342,14.1285903 3.18503863,16.767509 C3.79544815,18.6923492 4.94122319,20.4477601 6.54499878,21.7908158 L4.20161418,23.2878278 C-0.0495902992,19.2532452 -1.31528102,12.7468521 1.51937106,7.28411239 Z M22.8349645,3.74853378 C27.0567703,7.78621097 28.3062144,14.2693945 25.4800724,19.7158876 C22.0473892,26.3329125 13.9008591,28.9138076 7.28383414,25.4803507 C6.99990474,25.3333573 6.72371184,25.17708 6.45448178,25.0122927 L6.50167441,24.9821203 L6.47769127,24.980573 L14.2312074,20.0261211 L14.2025824,24.2982141 C15.0760328,24.240964 15.9378784,24.077724 16.7672308,23.8146831 C19.4069232,22.9783679 21.7270983,21.134761 23.1034209,18.4826902 C24.4797435,15.8306194 24.6507201,12.8714097 23.8144049,10.232491 C23.2101845,8.32389744 22.0783352,6.58241222 20.4954481,5.24399843 Z M19.2403271,12.073777 C19.4297542,12.073777 19.5833153,12.227338 19.5833153,12.4167651 L19.5833153,14.5824612 C19.5833153,14.7718883 19.4297542,14.9254494 19.2403271,14.9254494 L7.75834273,14.9254494 C7.5689156,14.9254494 7.41535457,14.7718883 7.41535457,14.5824612 L7.41535457,12.4167651 C7.41535457,12.227338 7.5689156,12.073777 7.75834273,12.073777 L19.2403271,12.073777 Z"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>E2220716-B06D-4CCD-8005-3668217A51C4</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1764, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(594, 71)">
<g id="Plugins" transform="translate(68, 0)">
<path d="M27,18.9 L27,24.3 C27,25.7911688 25.7911688,27 24.3,27 L18.9,27 L18.9,24.3 C18.9,22.8088312 17.6911688,21.6 16.2,21.6 C14.7088312,21.6 13.5,22.8088312 13.5,24.3 L13.5,27 L8.1,27 C6.60883118,27 5.4,25.7911688 5.4,24.3 L5.4,18.9 L2.7,18.9 C1.20883118,18.9 0,17.6911688 0,16.2 C0,14.7088312 1.20883118,13.5 2.7,13.5 L5.4,13.5 L5.4,8.1 C5.4,6.615 6.615,5.4 8.1,5.4 L13.5,5.4 L13.5,2.7 C13.5,1.20883118 14.7088312,0 16.2,0 C17.6911688,0 18.9,1.20883118 18.9,2.7 L18.9,5.4 L24.3,5.4 C25.7911688,5.4 27,6.60883118 27,8.1 L27,13.5 L24.3,13.5 C22.8088312,13.5 21.6,14.7088312 21.6,16.2 C21.6,17.6911688 22.8088312,18.9 24.3,18.9 L27,18.9 Z" id="Path"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="21px" height="27px" viewBox="0 0 21 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>7780B3A6-04AD-41C0-83B2-12DA21E87CFC</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1574, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(401, 71)">
<g id="Policies" transform="translate(71, 0)">
<path d="M18,0 C19.6568542,-3.04359188e-16 21,1.34314575 21,3 L21,24 C21,25.6568542 19.6568542,27 18,27 L3,27 C1.34314575,27 2.02906125e-16,25.6568542 0,24 L0,3 C-2.02906125e-16,1.34314575 1.34314575,3.04359188e-16 3,0 L18,0 Z M15.35625,16.605 C14.83125,16.065 14.04375,16.065 13.51875,16.605 L9.1875,21.06 L7.48125,19.305 C7.021875,18.765 6.16875,18.765 5.64375,19.305 C5.11875,19.845 5.11875,20.655 5.64375,21.195 L8.26875,23.895 C8.53125,24.165 8.859375,24.3 9.1875,24.3 C9.515625,24.3 9.84375,24.165 10.10625,23.895 L15.35625,18.495 C15.88125,17.955 15.88125,17.145 15.35625,16.605 Z M16.0625,9.45 L4.9375,9.45 C4.38521525,9.45 3.9375,9.89771525 3.9375,10.45 L3.9375,11.15 C3.9375,11.7022847 4.38521525,12.15 4.9375,12.15 L16.0625,12.15 C16.6147847,12.15 17.0625,11.7022847 17.0625,11.15 L17.0625,10.45 C17.0625,9.89771525 16.6147847,9.45 16.0625,9.45 Z M16.0625,4.05 L4.9375,4.05 C4.38521525,4.05 3.9375,4.49771525 3.9375,5.05 L3.9375,5.75 C3.9375,6.30228475 4.38521525,6.75 4.9375,6.75 L16.0625,6.75 C16.6147847,6.75 17.0625,6.30228475 17.0625,5.75 L17.0625,5.05 C17.0625,4.49771525 16.6147847,4.05 16.0625,4.05 Z" id="Rectangle-2"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>A8855F06-D8BF-417A-841F-4FBE78913DFF</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1734, -1942)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(564, 203)">
<g id="Unknown-agent" transform="translate(68, 0)">
<path d="M17.4053571,0.0521205975 C18.4487143,-0.201907204 19.5132857,0.496117015 19.7948571,1.67348065 L21.5151429,8.89670596 C21.5252191,8.9391051 21.5342228,8.98182907 21.5421429,9.02482433 C24.8535,9.62786424 27,10.5953788 27,11.6865939 C27,13.5155941 20.9558571,15 13.5,15 C6.04414286,15 0,13.5155941 0,11.6865939 C0,10.5953788 2.1465,9.62786424 5.45785714,9.02482433 L5.48485714,8.89670596 L7.20514286,1.67568959 C7.48671429,0.493908078 8.55128571,-0.201907204 9.59464286,0.0521205975 C10.7787857,0.341491397 12.3042857,0.641906884 13.5,0.641906884 C14.6957143,0.641906884 16.2212143,0.33928246 17.4053571,0.0521205975 Z M7.7625,9.72284855 C7.63511282,9.70805077 7.50781825,9.75189759 7.40868802,9.84471966 C7.30955779,9.93754173 7.24673418,10.0717149 7.23407143,10.2176505 C7.22115184,10.3635566 7.25943347,10.5093566 7.34047424,10.6228979 C7.42151502,10.7364392 7.53865846,10.8083958 7.66607143,10.8228994 C9.4365,11.0283306 11.4152143,11.1431953 13.5,11.1431953 C15.5847857,11.1431953 17.5635,11.0283306 19.3339286,10.8228994 C19.5991436,10.7924003 19.7925566,10.5214212 19.7659286,10.2176505 C19.7393005,9.91387988 19.502715,9.69234949 19.2375,9.72284855 C17.3308445,9.93842752 15.4159177,10.0438538 13.5,10.0387266 C11.4460714,10.0387266 9.49821429,9.92607079 7.7625,9.72284855 Z M1.92582418,20 C1.92582418,19.65 1.98351648,19.312 2.08928571,19 L1.92582418,19 C1.39478115,19 0.964285714,18.5522847 0.964285714,18 C0.964285714,17.4477153 1.39478115,17 1.92582418,17 L8.65659341,17 C10.1098077,17.0001733 11.3359957,18.1245745 11.5181319,19.624 C12.7872537,19.2253356 14.1413177,19.2253356 15.4104396,19.624 C15.5925757,18.1245745 16.8187637,17.0001733 18.271978,17 L25.0027473,17 C25.5337903,17 25.9642857,17.4477153 25.9642857,18 C25.9642857,18.5522847 25.5337903,19 25.0027473,19 L24.8392857,19 C24.9450549,19.312 25.0027473,19.65 25.0027473,20 L25.0027473,22 C25.0027473,24.7614237 22.8502701,27 20.1950549,27 C17.5398398,27 15.3873626,24.7614237 15.3873626,22 L15.3873626,21.72 L14.9835165,21.58 C13.9973271,21.2383946 12.9312443,21.2383946 11.9450549,21.58 L11.5412088,21.72 L11.5412088,22 C11.5412088,24.7614237 9.38873163,27 6.73351648,27 C4.07830134,27 1.92582418,24.7614237 1.92582418,22 L1.92582418,20 L1.92582418,20 Z" id="Shape"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="43px" height="43px" viewBox="0 0 43 43" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>AE320C3A-79E4-4E24-956A-B81125ACFA52@svg</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="100%" y2="100%" id="linearGradient-1">
<stop stop-color="#82B92E" offset="0%"></stop>
<stop stop-color="#2EB9A2" offset="100%"></stop>
</linearGradient>
<path d="M0,31.4018658 L0,11.5981342 C0,3.42952349 9.87916654,0 21.5,0 C33.1208335,0 43,3.42952349 43,11.5981342 L43,31.4018658 C43,39.5704765 33.1208335,43 21.5,43 C9.87916654,43 0,39.5704765 0,31.4018658 Z" id="path-2"></path>
</defs>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-324, -276)">
<g id="General-overview" transform="translate(309, 186)">
<g id="Card-1/8" transform="translate(15, 66)">
<g id="Status-check" transform="translate(0, 24)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<use id="Mask" fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
<path d="M40.3336211,1.77120453 C41.5051939,0.599631653 43.4046889,0.599631653 44.5762617,1.77120453 C45.7009717,2.89591449 45.7459601,4.69147742 44.7112269,5.86985562 L44.5762617,6.01384522 L20.142225,30.447882 C19.017515,31.572592 17.2219521,31.6175804 16.0435739,30.5828472 L15.8995843,30.447882 L10.2105122,24.75881 C9.03893936,23.5872371 9.03893936,21.6877422 10.2105122,20.5161693 C11.3352222,19.3914593 13.1307851,19.3464709 14.3091633,20.3812041 L14.4531529,20.5161693 L18.021,24.084 L40.3336211,1.77120453 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero" mask="url(#mask-3)"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="43px" height="43px" viewBox="0 0 43 43" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CD9D3D2F-E199-427F-BC6C-532C8382EE45@svg</title>
<defs>
<linearGradient x1="100%" y1="5.25852345e-07%" x2="0%" y2="50%" id="linearGradient-1">
<stop stop-color="#F72222" offset="0%"></stop>
<stop stop-color="#E12D81" offset="100%"></stop>
</linearGradient>
<path d="M0,31.4018658 L0,11.5981342 C0,3.42952349 9.87916654,0 21.5,0 C33.1208335,0 43,3.42952349 43,11.5981342 L43,31.4018658 C43,39.5704765 33.1208335,43 21.5,43 C9.87916654,43 0,39.5704765 0,31.4018658 Z" id="path-2"></path>
</defs>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-519, -276)">
<g id="General-overview" transform="translate(309, 186)">
<g id="Card-1/8" transform="translate(210, 66)">
<g id="Path" transform="translate(0, 24)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<use id="Mask" fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
<path d="M17.9773307,13.7437145 L18.1213203,13.8786797 L21.657,17.414 L25.1923882,13.8786797 C26.363961,12.7071068 28.263456,12.7071068 29.4350288,13.8786797 C30.5597388,15.0033896 30.6047272,16.7989525 29.569994,17.9773307 L29.4350288,18.1213203 L25.9,21.657 L29.4350288,25.1923882 C30.6066017,26.363961 30.6066017,28.263456 29.4350288,29.4350288 C28.3103189,30.5597388 26.514756,30.6047272 25.3363778,29.569994 L25.1923882,29.4350288 L21.657,25.9 L18.1213203,29.4350288 C16.9497475,30.6066017 15.0502525,30.6066017 13.8786797,29.4350288 C12.7539697,28.3103189 12.7089813,26.514756 13.7437145,25.3363778 L13.8786797,25.1923882 L17.414,21.657 L13.8786797,18.1213203 C12.7071068,16.9497475 12.7071068,15.0502525 13.8786797,13.8786797 C14.9565267,12.8008326 16.650487,12.7146048 17.8269121,13.6199964 L17.9773307,13.7437145 Z" id="Path-3" fill="#FFFFFF" fill-rule="nonzero" mask="url(#mask-3)"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>F7C0551D-EEAD-4AA0-87B8-DE2D255390BB</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v6" transform="translate(-1764, -1865)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1662)">
<g id="Card-1/8" transform="translate(594, 203)">
<g id="System-event" transform="translate(68, 0)">
<path d="M11.7078546,2.70325912 C11.1257057,3.92992514 10.8,5.30192625 10.8,6.75 C10.8,11.9690909 15.0309091,16.2 20.25,16.2 C21.6996594,16.2 23.0730794,15.8735806 24.3007699,15.2902321 L24.3,20.4457055 C24.3,25.0619204 18.7171222,27 12.15,27 C5.58287783,27 0,25.0619204 0,20.4457055 L0,9.25429447 C0,4.79456141 5.2107929,2.83447266 11.4857292,2.70670994 Z M20.25,0 C23.9779221,0 27,3.02207794 27,6.75 C27,10.4779221 23.9779221,13.5 20.25,13.5 C16.5220779,13.5 13.5,10.4779221 13.5,6.75 C13.5,3.02207794 16.5220779,0 20.25,0 Z M21.6,4.05 L20.4317308,4.05 C20.3365385,4.59915254 19.7394231,5.05677966 18.9,5.06510015 L18.9,5.93875193 L20.2413462,5.93875193 L20.2413462,9.45 L21.6,9.45 L21.6,4.05 Z" id="Mask"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,78 @@
<?php
/**
* Ajax secondary controller for general tactival view.
*
* @category Ajax general tactical view page.
* @package Pandora FMS
* @subpackage Opensource
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2023 Pandora FMS
* Please see https://pandorafms.com/community/ for full contribution list
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
global $config;
// Only logged users have access to this endpoint.
check_login();
if (! check_acl($config['id_user'], 0, 'AR')) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access credential store'
);
if (is_ajax()) {
echo json_encode(['error' => 'noaccess']);
} else {
include 'general/noaccess.php';
}
exit;
}
// AJAX controller.
if (is_ajax()) {
$dir = $config['homedir'].'/include/lib/TacticalView/elements/';
$method = get_parameter('method');
$class = get_parameter('class');
$filepath = realpath($dir.'/'.$class.'.php');
if (is_readable($filepath) === false
|| is_dir($filepath) === true
|| preg_match('/.*\.php$/', $filepath) === false
) {
exit;
}
include_once $filepath;
if (class_exists($class) === true) {
$instance = new $class();
if ($instance->ajaxMethod($method) === true) {
echo $instance->{$method}();
} else {
$instance->error('Unavailable method.');
}
} else {
$class->error('Class not found. ['.$class.']');
}
exit;
}

View File

@ -2763,6 +2763,7 @@ function graph_agent_status(
'height' => $height,
'colors' => array_values($colors),
'legend' => ['display' => false],
'labels' => array_keys($data),
];
if ($donut_narrow_graph == true) {
@ -4624,12 +4625,17 @@ function graph_nodata_image($options)
return base64_encode($dataImg);
}
$widthImage = '200px';
if (isset($options['nodata_image']['width']) === true) {
$widthImage = $options['nodata_image']['width'];
}
return html_print_image(
'images/image_problem_area.png',
true,
[
'title' => __('No data'),
'style' => 'width: 200px;',
'style' => 'width: '.$widthImage.';',
]
);
}

View File

@ -725,6 +725,12 @@ function get_build_setup_charts($type, $options, $data)
$chart->options()->getElements()->center()->setColor($options['elements']['center']['color']);
}
}
if (isset($options['elements']['point']) === true) {
if (isset($options['elements']['point']['radius']) === true) {
$chart->options()->getElements()->point()->setRadius($options['elements']['point']['radius']);
}
}
}
// Set Responsive for responsive charts.
@ -1019,7 +1025,9 @@ function get_build_setup_charts($type, $options, $data)
) {
$scales = $chart->options()->getScales();
if ($options['scales']['x'] !== false) {
if (isset($options['scales']['x']) === true
&& $options['scales']['x'] !== false
) {
// Defaults scalesFont X.
$scalesXFonts = $scales->getX()->ticks()->getFonts();
$scalesXFonts->setFamily((empty($config['fontpath']) === true) ? 'lato' : $config['fontpath']);
@ -1028,7 +1036,9 @@ function get_build_setup_charts($type, $options, $data)
$scalesXFonts->setSize(((int) $config['font_size'] + 2));
}
if ($options['scales']['y'] !== false) {
if (isset($options['scales']['y']) === true
&& $options['scales']['y'] !== false
) {
// Defaults scalesFont Y.
$scalesYFonts = $scales->getY()->ticks()->getFonts();
$scalesYFonts->setFamily((empty($config['fontpath']) === true) ? 'lato' : $config['fontpath']);
@ -1037,7 +1047,9 @@ function get_build_setup_charts($type, $options, $data)
$scalesYFonts->setSize(((int) $config['font_size'] + 2));
}
if ($options['scales']['r'] !== false) {
if (isset($options['scales']['r']) === true
&& $options['scales']['r'] !== false
) {
// Defaults scalesFont R.
$scalesRFonts = $scales->getR()->pointLabels()->getFonts();
$scalesRFonts->setStyle('normal');
@ -1053,6 +1065,10 @@ function get_build_setup_charts($type, $options, $data)
$scales->getX()->setBounds($options['scales']['x']['bounds']);
}
if (isset($options['scales']['x']['display']) === true) {
$scales->getX()->setDisplay($options['scales']['x']['display']);
}
if (isset($options['scales']['x']['grid']) === true
&& empty($options['scales']['x']['grid']) === false
&& is_array($options['scales']['x']['grid']) === true
@ -1098,6 +1114,10 @@ function get_build_setup_charts($type, $options, $data)
$scales->getY()->setBounds($options['scales']['y']['bounds']);
}
if (isset($options['scales']['y']['display']) === true) {
$scales->getY()->setDisplay($options['scales']['y']['display']);
}
if (isset($options['scales']['y']['grid']) === true
&& empty($options['scales']['y']['grid']) === false
&& is_array($options['scales']['y']['grid']) === true
@ -1202,6 +1222,13 @@ function get_build_setup_charts($type, $options, $data)
$borders = array_values($defaultBorder);
}
if (isset($options['borderColors']) === true
&& empty($options['borderColors']) === false
&& is_array($options['borderColors']) === true
) {
$borders = $options['borderColors'];
}
// Set labels.
if (isset($options['labels']) === true
&& empty($options['labels']) === false

View File

@ -0,0 +1,94 @@
/* global $ */
$(document).ready(function() {
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-last-24").html(data);
}
});
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsCriticalityGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-criticality").html(data);
}
});
// Prevent that graphs use same name.
setTimeout(() => {
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsStatusGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-status-validate").html(data);
}
});
}, 100);
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsStatusValidateGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-status-pending-validate").html(data);
}
});
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getStatusHeatMap",
class: "Groups",
width: $("#heatmap-group").width() - 50,
height:
$("#heatmap-group").height() < 280 ? 280 : $("#heatmap-group").height()
},
type: "POST",
success: function(data) {
var title = $(data)[1];
var heatmap = $(data)[0];
$("#heatmap-group").html(heatmap);
$("#heatmap-title").html($(title).html());
}
});
});
function autoRefresh(interval, id, method, php_class) {
setInterval(() => {
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: method,
class: php_class
},
type: "POST",
success: function(data) {
var content = $(data).html();
$("#" + id).html(content);
}
});
}, interval);
}

View File

@ -134,8 +134,9 @@ function render_counter() {
$(".counter-tips img:eq(0)").after(
"<span class='count-round-tip active'></span>"
);
if (totalTips > 1) {
for (let i = 1; i <= totalTips - 1; i++) {
var limitRound = totalTips > 28 ? 28 : totalTips;
if (limitRound > 1) {
for (let i = 1; i <= limitRound - 1; i++) {
$(".count-round-tip:eq(0)").after(
"<span class='count-round-tip'></span>"
);

View File

@ -0,0 +1,211 @@
<?php
/**
* Element class parent for elements
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
namespace PandoraFMS\TacticalView;
/**
* Parent element for general tactical view elements
*/
class Element
{
/**
* Url of controller.
*
* @var string
*/
public $ajaxController;
/**
* List of available ajax methods.
*
* @var array
*/
protected $ajaxMethods = [];
/**
* Title of section
*
* @var string
*/
public $title;
/**
* Interval for refresh element, 0 for not refresh.
*
* @var integer
*/
public $interval;
/**
* Agent of automonitoritation
*
* @var array
*/
protected $monitoringAgent;
/**
* Refresh config for async method.
*
* @var array
*/
public $refreshConfig = [];
/**
* Contructor
*
* @param string $ajax_controller Controller.
*/
public function __construct(
$ajax_controller='include/ajax/general_tactical_view.ajax'
) {
$this->interval = 0;
$this->title = __('Default element');
$this->ajaxController = $ajax_controller;
// Without ACL.
$agent = db_get_row('tagente', 'nombre', 'pandora.internals', '*');
if (is_array($agent) === true) {
$this->monitoringAgent = $agent;
}
/*
// With ACL.
$agent = agents_get_agents(['nombre' => 'pandora.internals']);
if (is_array($agent) === true && count($agent) > 0) {
$this->monitoringAgent = $agent[0];
}
*/
}
/**
* Return error message to target.
*
* @param string $msg Error message.
*
* @return void
*/
public static function error(string $msg)
{
echo json_encode(['error' => $msg]);
}
/**
* Verifies target method is allowed to be called using AJAX call.
*
* @param string $method Method to be invoked via AJAX.
*
* @return boolean Available (true), or not (false).
*/
public function ajaxMethod(string $method):bool
{
return in_array($method, $this->ajaxMethods) === true;
}
/**
* Cut the text to display it on the labels.
*
* @param string $text Text for cut.
* @param integer $length Length max for text cutted.
*
* @return string
*/
protected function controlSizeText(string $text, int $length=14):string
{
if (mb_strlen($text) > $length) {
$newText = mb_substr($text, 0, $length).'...';
return $newText;
} else {
return $text;
}
}
/**
* Return a valur from Module of monitoring.
*
* @param string $moduleName Name of module value.
* @param integer $dateInit Date init for filter.
* @param integer $dateEnd Date end for filter.
*
* @return array Array of module data.
*/
protected function valueMonitoring(string $moduleName, int $dateInit=0, int $dateEnd=0):array
{
if (empty($this->monitoringAgent) === false) {
$module = modules_get_agentmodule_id(io_safe_input($moduleName), $this->monitoringAgent['id_agente']);
if (is_array($module) === true && key_exists('id_agente_modulo', $module) === true) {
if ($dateInit === 0 && $dateEnd === 0) {
$value = modules_get_last_value($module['id_agente_modulo']);
$rawData = [['datos' => $value]];
} else {
$rawData = modules_get_raw_data($module['id_agente_modulo'], $dateInit, $dateEnd);
}
if ($rawData === false || is_array($rawData) === false) {
return [['datos' => 0]];
} else {
return $rawData;
}
} else {
return [['datos' => 0]];
}
return [['datos' => 0]];
} else {
return [['datos' => 0]];
}
}
/**
* Simple image loading for async functions.
*
* @return string
*/
public static function loading():string
{
return html_print_div(
[
'content' => '<span></span>',
'class' => 'spinner-fixed inherit',
],
true
);
}
/**
* Return the name of class
*
* @return string
*/
public static function nameClass():string
{
return static::class;
}
}

View File

@ -0,0 +1,172 @@
<?php
/**
* General tactical view
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
namespace PandoraFMS\TacticalView;
use Exception;
use PandoraFMS\View;
/**
* General tactical view
*/
class GeneralTacticalView
{
/**
* List elements instanced for show in view.
*
* @var array
*/
protected $elements;
/**
* Constructor
*/
public function __construct()
{
ui_require_css_file('general_tactical_view');
ui_require_javascript_file('general_tactical_view');
$this->elements = $this->instanceElements();
}
/**
* Instantiate all the elements that will build the dashboard
*
* @return array
*/
public function instanceElements():array
{
global $config;
$dir = $config['homedir'].'/include/lib/TacticalView/elements/';
$handle = opendir($dir);
if ($handle === false) {
return [];
}
$ignores = [
'.',
'..',
];
$elements = [];
$elements['welcome'] = $this->getWelcomeMessage();
while (false !== ($file = readdir($handle))) {
try {
if (in_array($file, $ignores) === true) {
continue;
}
$filepath = realpath($dir.'/'.$file);
if (is_readable($filepath) === false
|| is_dir($filepath) === true
|| preg_match('/.*\.php$/', $filepath) === false
) {
continue;
}
$className = preg_replace('/.php/', '', $file);
include_once $filepath;
if (class_exists($className) === true) {
$instance = new $className();
$elements[$className] = $instance;
}
} catch (Exception $e) {
}
}
return $elements;
}
/**
* Render funcion for print the html.
*
* @return void
*/
public function render():void
{
$data = [];
$data['javascript'] = $this->javascript();
$data = array_merge($data, $this->elements);
View::render(
'tacticalView/view',
$data
);
}
/**
* Function for print js embedded in html.
*
* @return string
*/
public function javascript():string
{
$js = '<script>';
foreach ($this->elements as $key => $element) {
if ($element->interval > 0) {
foreach ($element->refreshConfig as $key => $conf) {
$js .= 'autoRefresh('.$element->interval.',"'.$conf['id'].'", "'.$conf['method'].'", "'.$element->nameClass().'");';
}
}
}
$js .= '</script>';
return $js;
}
/**
* Return the welcome message.
*
* @return string
*/
private function getWelcomeMessage():string
{
global $config;
$user = users_get_user_by_id($config['id_user']);
if (is_array($user) === true && count($user) > 0) {
$name = $user['fullname'];
} else {
$name = '';
}
if (empty($name) === true) {
$message = __('Welcome back! 👋');
} else {
$message = __('Welcome back %s! 👋', $name);
}
return html_print_div(
[
'content' => $message,
'class' => 'message-welcome',
],
true
);
}
}

View File

@ -0,0 +1,446 @@
<?php
/**
* Agents element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Agents, this class contain all logic for this section.
*/
class Agents extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
include_once $config['homedir'].'/include/graphs/fgraph.php';
include_once $config['homedir'].'/include/functions_graph.php';
$this->title = __('Agents');
$this->ajaxMethods = ['getGroups'];
}
/**
* Get total number of agents.
*
* @return string
*/
public function getTotalAgents():string
{
$agents = agents_get_agents();
if (is_array($agents) === true) {
$total = count($agents);
} else {
$total = 0;
}
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Get total alerts of agents.
*
* @return string
*/
public function getAlerts():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$group_query = ' AND (
t3.id_grupo IN ('.$id_groups.')
OR tasg.id_group IN ('.$id_groups.')
)';
$sql = 'SELECT count(t0.id)
FROM talert_template_modules t0
INNER JOIN talert_templates t1
ON t0.id_alert_template = t1.id
INNER JOIN tagente_modulo t2
ON t0.id_agent_module = t2.id_agente_modulo
INNER JOIN tagente t3
ON t2.id_agente = t3.id_agente
LEFT JOIN tagent_secondary_group tasg
ON tasg.id_agent = t3.id_agente
WHERE last_fired >=UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY) '.$group_query;
$total = db_get_value_sql($sql);
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Get a datatable with the top groups with more agents.
*
* @return string
*/
public function getDataTableGroups():string
{
$columns = [
'nombre',
'total',
];
$columnNames = [
__('Group alias'),
__('Agents'),
];
return ui_print_datatable(
[
'id' => 'list_groups',
'class' => 'info_table',
'style' => 'width: 90%',
'dom_elements' => 'tfp',
'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_url' => $this->ajaxController,
'no_sortable_columns' => [
0,
1,
],
'ajax_data' => [
'method' => 'getGroups',
'class' => static::class,
],
'order' => [
'field' => 'title',
'direction' => 'asc',
],
'default_pagination' => 8,
'search_button_class' => 'sub filter float-right',
'return' => true,
]
);
}
/**
* Return top 20 groups with more agents for ajax datatable.
*
* @return string
*/
public function getGroups():string
{
global $config;
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$pagination = '';
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
try {
ob_start();
if (isset($length) && $length > 0
&& isset($start) && $start >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$length,
$start
);
}
$sql = sprintf(
'SELECT gr.nombre, count(*) +
IFNULL((SELECT count(*) AS total
FROM tagente second_a
LEFT JOIN tagent_secondary_group second_g ON second_g.id_agent = second_a.id_agente
WHERE a.id_grupo = second_g.id_group
GROUP BY second_g.id_group
), 0) AS total
FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
INNER JOIN(
SELECT gr.id_grupo, count(*) AS total
FROM tagente a LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo ORDER BY total DESC LIMIT 20
) top_groups ON top_groups.id_grupo = gr.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo
ORDER BY total DESC
%s',
$pagination
);
$rows = db_process_sql($sql);
$sql_count = 'SELECT gr.nombre,
IFNULL((SELECT count(*) AS total
FROM tagente second_a
LEFT JOIN tagent_secondary_group second_g ON second_g.id_agent = second_a.id_agente
WHERE a.id_grupo = second_g.id_group
GROUP BY second_g.id_group
), 0) AS total
FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
INNER JOIN(
SELECT gr.id_grupo, count(*) AS total
FROM tagente a LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo ORDER BY total DESC LIMIT 20
) top_groups ON top_groups.id_grupo = gr.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo
ORDER BY total DESC';
$total = db_get_num_rows($sql_count);
// Capture output.
$response = ob_get_clean();
return json_encode(
[
'data' => $rows,
'recordsTotal' => $total,
'recordsFiltered' => $total,
]
);
} catch (Exception $e) {
return json_encode(['error' => $e->getMessage()]);
}
return json_decode($response);
if (json_last_error() === JSON_ERROR_NONE) {
return $response;
} else {
return json_encode(
[
'success' => false,
'error' => $response,
]
);
}
}
/**
* Return the html graph of number agents by os.
*
* @return string
*/
public function getOperatingSystemGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT name, count(*) AS total
FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
LEFT JOIN tconfig_os os ON os.id_os = a.id_os
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_os
ORDER BY total DESC';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['name']) === true) {
continue;
}
$labels[] = $this->controlSizeText($row['name']);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the html graph of number agents by status.
*
* @return string
*/
public function getStatusGraph():string
{
$agents = agents_get_agents(
false,
[
'id_agente',
'id_grupo',
'nombre',
'alias',
'id_os',
'ultimo_contacto',
'intervalo',
'comentarios description',
'quiet',
'normal_count',
'warning_count',
'critical_count',
'unknown_count',
'notinit_count',
'total_count',
'fired_count',
'ultimo_contacto_remoto',
'remote',
'agent_version',
]
);
$labels = [
__('No Monitors'),
__('CRITICAL'),
__('WARNING'),
__('UKNOWN'),
__('NORMAL'),
];
$totals = [
'no_monitors' => 0,
'critical' => 0,
'warning' => 0,
'unknown' => 0,
'ok' => 0,
];
$colors = [
COL_NOTINIT,
COL_CRITICAL,
COL_WARNING,
COL_UNKNOWN,
COL_NORMAL,
];
foreach ($agents as $key => $agent) {
if ($agent['total_count'] == 0 || $agent['total_count'] == $agent['notinit_count']) {
$totals['no_monitors']++;
}
if ($agent['critical_count'] > 0) {
$totals['critical']++;
} else if ($agent['warning_count'] > 0) {
$totals['warning']++;
} else if ($agent['unknown_count'] > 0) {
$totals['unknown']++;
} else {
$totals['ok']++;
}
}
foreach ($totals as $key => $total) {
$data[] = $total;
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '80%'],
'colors' => $colors,
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
}

View File

@ -0,0 +1,274 @@
<?php
/**
* Alerts element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Alerts, this class contain all logic for this section.
*/
class Alerts extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Alerts');
$this->ajaxMethods = ['getUsers'];
$this->ajaxMethods = [
'getUsers',
'getCurrentlyTriggered',
'getActiveAlerts',
];
$this->interval = 300000;
$this->refreshConfig = [
'triggered' => [
'id' => 'currently-triggered',
'method' => 'getCurrentlyTriggered',
],
'active-correlation' => [
'id' => 'active-correlation',
'method' => 'getActiveAlerts',
],
];
}
/**
* Returns the html of currently triggered.
*
* @return string
*/
public function getCurrentlyTriggered():string
{
$total = alerts_get_alerts(0, '', 'fired', -1, 'AR', true);
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'id' => 'currently-triggered',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of active correlation.
*
* @return string
*/
public function getActiveAlerts():string
{
$total = alerts_get_alerts(0, '', 'all', -1, 'AR', true);
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'id' => 'active-correlation',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Return a datatable with de users lists.
*
* @return string
*/
public function getDataTableUsers():string
{
$columns = [
'id_user',
'is_admin',
'last_connect',
];
$columnNames = [
__('User'),
__('Role'),
__('Last seen'),
];
return ui_print_datatable(
[
'id' => 'list_users',
'class' => 'info_table',
'style' => 'width: 90%',
'dom_elements' => 'tfp',
'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_url' => $this->ajaxController,
'ajax_data' => [
'method' => 'getUsers',
'class' => static::class,
],
'order' => [
'field' => 'title',
'direction' => 'asc',
],
'default_pagination' => 10,
'search_button_class' => 'sub filter float-right',
'return' => true,
]
);
}
/**
* Return all users for ajax.
*
* @return string
*/
public function getUsers():string
{
global $config;
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$orderDatatable = get_datatable_order(true);
$pagination = '';
$order = '';
try {
ob_start();
if (isset($orderDatatable)) {
$order = sprintf(
' ORDER BY %s %s',
$orderDatatable['field'],
$orderDatatable['direction']
);
}
if (isset($length) && $length > 0
&& isset($start) && $start >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$length,
$start
);
}
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$sql = sprintf(
'SELECT DISTINCT id_user, is_admin ,last_connect
FROM tusuario u
LEFT JOIN tusuario_perfil p ON p.id_usuario = u.id_user
WHERE id_grupo IN ('.$id_groups.')
GROUP BY id_user
%s %s',
$order,
$pagination
);
$rows = db_process_sql($sql);
foreach ($rows as $key => $row) {
$rows[$key]['id_user'] = '<a href="index.php?sec=gusuarios&sec2=godmode/users/configure_user&edit_user=1&pure=0&id_user='.$row['id_user'].'">'.$row['id_user'].'</a>';
if ((bool) $row['is_admin'] === true) {
$rows[$key]['is_admin'] = '<span class="admin">'.__('Admin').'</span>';
} else {
$rows[$key]['is_admin'] = '<span class="user">'.__('User').'</span>';
}
if ($row['last_connect'] > 0) {
$rows[$key]['last_connect'] = ui_print_timestamp($row['last_connect'], true, ['prominent' => 'compact']);
} else {
$rows[$key]['last_connect'] = __('Unknown');
}
}
$sql_count = sprintf(
'SELECT DISTINCT id_user, count(*) as total
FROM tusuario u
LEFT JOIN tusuario_perfil p ON p.id_usuario = u.id_user
WHERE id_grupo IN ('.$id_groups.')
%s',
$order,
);
$total = db_process_sql($sql_count);
// Capture output.
$response = ob_get_clean();
return json_encode(
[
'data' => $rows,
'recordsTotal' => $total[0]['total'],
'recordsFiltered' => $total[0]['total'],
]
);
} catch (Exception $e) {
return json_encode(['error' => $e->getMessage()]);
}
json_decode($response);
if (json_last_error() === JSON_ERROR_NONE) {
return $response;
} else {
return json_encode(
[
'success' => false,
'error' => $response,
]
);
}
}
/**
* Check if user can manager users.
*
* @return boolean
*/
public function checkAclUserList():bool
{
global $config;
$user_m = (bool) check_acl($config['id_user'], 0, 'UM');
return $user_m;
}
}

View File

@ -0,0 +1,252 @@
<?php
/**
* Configurations element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Configurations, this class contain all logic for this section.
*/
class Configurations extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Configurations');
}
/**
* Get total groups from automonitorization.
*
* @return string
*/
public function getTotalGroups():string
{
$value = $this->valueMonitoring('total_groups');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Groups.svg', true);
$text = '<span class="subtitle">'.__('Groups').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total modules from automonitorization.
*
* @return string
*/
public function getTotalModules():string
{
$value = $this->valueMonitoring('total_modules');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Modules.svg', true);
$text = '<span class="subtitle">'.__('Modules').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total policies from automonitorization.
*
* @return string
*/
public function getTotalPolicies():string
{
$totalPolicies = db_get_value(
'count(*)',
'tpolicies'
);
$image = html_print_image('images/Tactical_Policies.svg', true);
$text = '<span class="subtitle">'.__('Policies').'</span>';
$number = html_print_div(
[
'content' => format_numeric($totalPolicies, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total remote plugins from automonitorization.
*
* @return string
*/
public function getTotalRemotePlugins():string
{
$totalPLugins = db_get_value(
'count(*)',
'tplugin',
'plugin_type',
1,
);
$sql = 'SELECT count(*) AS total FROM tplugin WHERE plugin_type = 1;';
$rows = db_process_sql($sql);
$totalPLugins = 0;
if (is_array($rows) === true && count($rows) > 0) {
$totalPLugins = $rows[0]['total'];
}
$image = html_print_image('images/Tactical_Plugins.svg', true);
$text = '<span class="subtitle">'.__('Remote plugins').'</span>';
$number = html_print_div(
[
'content' => format_numeric($totalPLugins, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total module templates from automonitorization.
*
* @return string
*/
public function getTotalModuleTemplate():string
{
$countModuleTemplates = db_get_value(
'count(*)',
'tnetwork_profile'
);
$image = html_print_image('images/Tactical_Module_template.svg', true);
$text = '<span class="subtitle">'.__('Module templates').'</span>';
$number = html_print_div(
[
'content' => format_numeric($countModuleTemplates, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total not unit modules from automonitorization.
*
* @return string
*/
public function getNotInitModules():string
{
$value = $this->valueMonitoring('total_notinit');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Not_init_module.svg', true);
$text = '<span class="subtitle">'.__('Not-init modules').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total unknow agents from automonitorization.
*
* @return string
*/
public function getTotalUnknowAgents():string
{
$value = $this->valueMonitoring('total_unknown');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Unknown_agent.svg', true);
$text = '<span class="subtitle">'.__('Unknown agents').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Returns the html of total events.
*
* @return string
*/
public function getTotalEvents():string
{
$data = $this->valueMonitoring('last_events_24h');
$total = $data[0]['datos'];
$image = html_print_image('images/system_event.svg', true);
$text = '<span class="subtitle">'.__('Events in last 24 hrs').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
}

View File

@ -0,0 +1,348 @@
<?php
/**
* Database element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Database, this class contain all logic for this section.
*/
class Database extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Database');
$this->ajaxMethods = [
'getStatus',
'getDataRecords',
'getEvents',
'getStringRecords',
'getReadsGraph',
'getWritesGraph',
];
$this->interval = 300000;
$this->refreshConfig = [
'status' => [
'id' => 'status-database',
'method' => 'getStatus',
],
'records' => [
'id' => 'data-records',
'method' => 'getDataRecords',
],
'events' => [
'id' => 'total-events',
'method' => 'getEvents',
],
'totalRecords' => [
'id' => 'total-records',
'method' => 'getStringRecords',
],
'reads' => [
'id' => 'database-reads',
'method' => 'getReadsGraph',
],
'writes' => [
'id' => 'database-writes',
'method' => 'getWritesGraph',
],
];
}
/**
* Returns the html status of database.
*
* @return string
*/
public function getStatus():string
{
// TODO connect to automonitorization.
$status = true;
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Somethings wrong'),
'class' => 'status-text',
],
true
);
}
$output = $image_status.$text;
return html_print_div(
[
'content' => $output,
'class' => 'flex_center margin-top-5',
'id' => 'status-database',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html records data of database.
*
* @return string
*/
public function getDataRecords():string
{
$data = $this->valueMonitoring('mysql_size_of_data');
$value = format_numeric($data[0]['datos'], 2).' MB';
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'id' => 'data-records',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of total events.
*
* @return string
*/
public function getEvents():string
{
$data = $this->valueMonitoring('last_events_24h');
$value = format_numeric($data[0]['datos']);
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'id' => 'total-events',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of total records.
*
* @return string
*/
public function getStringRecords():string
{
$data = $this->valueMonitoring('total_string_data');
$value = format_numeric($data[0]['datos']);
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'id' => 'total-records',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of total reads database in a graph.
*
* @return string
*/
public function getReadsGraph():string
{
$dateInit = (time() - 86400);
$reads = $this->valueMonitoring('mysql_questions_reads', $dateInit, time());
$dates = [];
$string_reads = [];
$total = 0;
foreach ($reads as $key => $read) {
$dates[] = date('d-m-Y H:i:s', $read['utimestamp']);
$string_reads[] = $read['datos'];
$total += $read['datos'];
}
$options = [
'labels' => $dates,
'legend' => [ 'display' => false ],
'tooltips' => [ 'display' => false ],
'scales' => [
'y' => [
'grid' => ['display' => false],
'ticks' => ['display' => false],
'display' => false,
],
'x' => [
'grid' => ['display' => false],
'display' => false,
],
],
'elements' => [ 'point' => [ 'radius' => 0 ] ],
];
$data = [
[
'backgroundColor' => '#EC7176',
'borderColor' => '#EC7176',
'pointBackgroundColor' => '#EC7176',
'pointHoverBorderColor' => '#EC7176',
'data' => $string_reads,
],
];
$graph_area = html_print_div(
[
'content' => line_graph($data, $options),
'class' => 'w100p h100p centered',
'style' => 'max-height: 83px; max-width: 93%; margin-bottom: 10px;',
],
true
);
$total = html_print_div(
[
'content' => format_numeric($total),
'class' => 'text-xl',
],
true
);
$output = html_print_div(
[
'content' => $total.$graph_area,
'id' => 'database-reads',
],
true
);
return $output;
}
/**
* Returns the html of total writes database in a graph.
*
* @return string
*/
public function getWritesGraph():string
{
$dateInit = (time() - 86400);
$writes = $this->valueMonitoring('mysql_questions_writes', $dateInit, time());
$dates = [];
$string_writes = [];
$total = 0;
foreach ($writes as $key => $write) {
$dates[] = date('d-m-Y H:i:s', $write['utimestamp']);
$string_writes[] = $write['datos'];
$total += $write['datos'];
}
$options = [
'labels' => $dates,
'legend' => [ 'display' => false ],
'tooltips' => [ 'display' => false ],
'scales' => [
'y' => [
'grid' => ['display' => false],
'ticks' => ['display' => false],
'display' => false,
],
'x' => [
'grid' => ['display' => false],
'display' => false,
],
],
'elements' => [ 'point' => [ 'radius' => 0 ] ],
];
$data = [
[
'backgroundColor' => '#009D9E',
'borderColor' => '#009D9E',
'pointBackgroundColor' => '#009D9E',
'pointHoverBorderColor' => '#009D9E',
'data' => $string_writes,
],
];
$graph_area = html_print_div(
[
'content' => line_graph($data, $options),
'class' => 'w100p h100p centered',
'style' => 'max-height: 83px; max-width: 93%; margin-bottom: 10px;',
],
true
);
$total = html_print_div(
[
'content' => format_numeric($total),
'class' => 'text-xl',
],
true
);
$output = html_print_div(
[
'content' => $total.$graph_area,
'id' => 'database-writes',
],
true
);
return $output;
}
/**
* Check if user can manage database
*
* @return boolean
*/
public function checkAcl():bool
{
global $config;
$db_m = (bool) check_acl($config['id_user'], 0, 'DM');
return $db_m;
}
}

View File

@ -0,0 +1,485 @@
<?php
/**
* Events element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Events, this class contain all logic for this section.
*/
class Events extends Element
{
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
include_once $config['homedir'].'/include/graphs/fgraph.php';
include_once $config['homedir'].'/include/functions_graph.php';
$this->title = __('Events');
$this->ajaxMethods = [
'getEventsGraph',
'getEventsCriticalityGraph',
'getEventsStatusValidateGraph',
'getEventsStatusGraph',
];
}
/**
* Return the html graph of events in last 24h.
*
* @return string
*/
public function getEventsGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT utimestamp from tevento WHERE utimestamp >= '.$intervalh.' ORDER BY utimestamp DESC;';
$rows = db_process_sql($sql);
$cut_seconds = ($time_events / 24);
$now = (time() - 300);
$cuts_intervals = [];
for ($i = 0; $i < 24; $i++) {
$cuts_intervals[$now] = 0;
$now -= $cut_seconds;
}
foreach ($rows as $key => $row) {
foreach ($cuts_intervals as $time => $count) {
if ($row['utimestamp'] > $time) {
$cuts_intervals[$time]++;
break;
}
}
}
$cuts_intervals = array_reverse($cuts_intervals, true);
$graph_values = [];
$colors = [];
$max_value = 0;
foreach ($cuts_intervals as $utimestamp => $count) {
if ($max_value < $count) {
$max_value = $count;
}
$graph_values[] = [
'y' => $count,
'x' => date('d-m-Y H:i:s', $utimestamp),
];
}
$danger = $max_value;
$ok = ($max_value / 3);
foreach ($graph_values as $key => $value) {
if ($value['y'] >= $danger) {
$colors[] = '#EC7176';
}
if ($value['y'] >= $ok && $value['y'] < $danger) {
$colors[] = '#FCAB10';
}
if ($value['y'] < $ok) {
$colors[] = '#82B92E';
}
}
$options = [
'height' => 237,
'legend' => ['display' => false],
'scales' => [
'x' => [
'bounds' => 'data',
'grid' => ['display' => false],
'display' => false,
],
'y' => [
'grid' => ['display' => false],
],
],
'colors' => $colors,
'borderColors' => ['#ffffff'],
];
$bar = vbar_graph($graph_values, $options);
$output = html_print_div(
[
'content' => $bar,
'class' => 'margin-top-5 w100p relative',
'style' => 'max-height: 250px;',
],
true
);
return $output;
}
/**
* Return the html graph of events in last 8h grouped by criticity.
*
* @return string
*/
public function getEventsCriticalityGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT criticity, count(*) AS total
FROM tevento
WHERE utimestamp >= '.$intervalh.' AND id_grupo IN ('.$id_groups.')
group by criticity';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
$colors = [];
foreach ($rows as $key => $row) {
switch ($row['criticity']) {
case EVENT_CRIT_CRITICAL:
$label = __('CRITICAL');
$colors[] = COL_CRITICAL;
break;
case EVENT_CRIT_MAINTENANCE:
$label = __('MAINTENANCE');
$colors[] = COL_MAINTENANCE;
break;
case EVENT_CRIT_INFORMATIONAL:
$label = __('INFORMATIONAL');
$colors[] = COL_INFORMATIONAL;
break;
case EVENT_CRIT_MAJOR:
$label = __('MAJOR');
$colors[] = COL_MAJOR;
break;
case EVENT_CRIT_MINOR:
$label = __('MINOR');
$colors[] = COL_MINOR;
break;
case EVENT_CRIT_NORMAL:
$label = __('NORMAL');
$colors[] = COL_NORMAL;
break;
case EVENT_CRIT_WARNING:
$label = __('WARNING');
$colors[] = COL_WARNING;
break;
default:
$colors[] = COL_UNKNOWN;
$label = __('UNKNOWN');
break;
}
$labels[] = $this->controlSizeText($label);
$data[] = $row['total'];
}
$options = [
'waterMark' => false,
'labels' => $labels,
'legend' => ['display' => false],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
'colors' => $colors,
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the html graph of events in last 8h grouped by status validate.
*
* @return string
*/
public function getEventsStatusValidateGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT estado, count(*) AS total
FROM tevento
WHERE utimestamp >= '.$intervalh.' AND id_grupo IN ('.$id_groups.')
group by estado';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
switch ($row['estado']) {
case '2':
$label = _('In process');
break;
case '0':
$label = _('New events');
break;
case '3':
$label = _('Not validated');
break;
case '1':
$label = _('Validated events');
break;
default:
$label = __('Unknow');
break;
}
$labels[] = $label;
$data[] = $row['total'];
}
$options = [
'waterMark' => false,
'labels' => $labels,
'legend' => ['display' => false],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the html graph of events in last 8h grouped by status.
*
* @return string
*/
public function getEventsStatusGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT criticity, count(*) AS total
FROM tevento
WHERE utimestamp >= '.$intervalh.' AND id_grupo IN ('.$id_groups.')
group by criticity';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
$colors = [];
foreach ($rows as $key => $row) {
switch ($row['criticity']) {
case EVENT_CRIT_CRITICAL:
$label = __('CRITICAL');
$colors[] = COL_CRITICAL;
break;
case EVENT_CRIT_NORMAL:
$label = __('NORMAL');
$colors[] = COL_NORMAL;
break;
case EVENT_CRIT_WARNING:
$label = __('WARNING');
$colors[] = COL_WARNING;
break;
default:
$colors[] = COL_UNKNOWN;
$label = __('UNKNOWN');
break;
}
$labels[] = $this->controlSizeText($label);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => ['display' => false],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
'colors' => $colors,
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the datatable events in last 8 hours.
*
* @return string
*/
public function getDataTableEvents()
{
$column_names = [
__('S'),
__('Event'),
__('Date'),
];
$fields = [
'mini_severity',
'evento',
'timestamp',
];
return ui_print_datatable(
[
'id' => 'datatable_events',
'class' => 'info_table events',
'style' => 'width: 90%;',
'ajax_url' => 'operation/events/events',
'ajax_data' => [
'get_events' => 1,
'compact_date' => 1,
'external_url' => 1,
],
'order' => [
'field' => 'timestamp',
'direction' => 'desc',
],
'column_names' => $column_names,
'columns' => $fields,
'ajax_return_operation' => 'buffers',
'ajax_return_operation_function' => 'process_buffers',
'return' => true,
'csv' => 0,
'dom_elements' => 'tfp',
'default_pagination' => 8,
]
);
}
/**
* Check permission user for view events section.
*
* @return boolean
*/
public function checkAcl():bool
{
global $config;
$event_a = (bool) check_acl($config['id_user'], 0, 'ER');
return $event_a;
}
}

View File

@ -0,0 +1,563 @@
<?php
/**
* Groups element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Groups, this class contain all logic for this section.
*/
class Groups extends Element
{
/**
* Total groups.
*
* @var integer
*/
public $total;
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
include_once $config['homedir'].'/include/functions_users.php';
include_once $config['homedir'].'/include/functions_groupview.php';
$this->ajaxMethods = ['getStatusHeatMap'];
ui_require_css_file('heatmap');
$this->title = __('Groups');
$this->total = $this->calculateTotalGroups();
}
/**
* Return the total groups.
*
* @return integer
*/
public function calculateTotalGroups():int
{
$total = db_get_value_sql('SELECT count(*) FROM tgrupo');
return $total;
}
/**
* Return the status groups in heat map.
*
* @return string
*/
public function getStatusHeatMap():string
{
global $config;
$groups = users_get_groups($config['id_group'], 'AR', false);
if (is_array($groups) === true && count($groups) >= 10) {
return $this->getStatusHeatMapGroup();
}
$agents = agents_get_agents();
if (is_array($agents) === true && count($agents) >= 10) {
$this->title = __('My monitored agents');
return $this->getStatusHeatMapAgents().'<span id="heatmap-title">'.$this->title.'</span>';
}
$this->title = __('My monitored modules');
return $this->getStatusHeatMapModules().'<span id="heatmap-title">'.$this->title.'</span>';
}
/**
* Return the status modules in heatmap.
*
* @return string
*/
public function getStatusHeatMapModules():string
{
global $config;
$width = get_parameter('width', 350);
$height = get_parameter('height', 275);
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$modules = modules_get_modules_in_group($id_groups);
$total_groups = count($modules);
if ($total_groups === 0) {
return graph_nodata_image(['width' => '400']);
}
$groups = $modules;
// Best square.
$high = (float) max($width, $height);
$low = 0.0;
while (abs($high - $low) > 0.000001) {
$mid = (($high + $low) / 2.0);
$midval = (floor($width / $mid) * floor($height / $mid));
if ($midval >= $total_groups) {
$low = $mid;
} else {
$high = $mid;
}
}
$square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
// Print starmap.
$heatmap = sprintf(
'<svg id="svg" style="width: %spx; height: %spx;">',
$width,
$height
);
$heatmap .= '<g>';
$row = 0;
$column = 0;
$x = 0;
$y = 0;
$cont = 1;
foreach ($groups as $key => $value) {
$module_id = $value['id_agente_modulo'];
$db_status = modules_get_agentmodule_status($module_id);
$module_value = modules_get_last_value($module_id);
$status = '';
$title = '';
modules_get_status($module_id, $db_status, $module_value, $status, $title);
switch ($status) {
case STATUS_MODULE_NO_DATA:
// Not init status.
$status = 'notinit';
break;
case STATUS_MODULE_CRITICAL:
// Critical status.
$status = 'critical';
break;
case STATUS_MODULE_WARNING:
// Warning status.
$status = 'warning';
break;
case STATUS_MODULE_OK:
// Normal status.
$status = 'normal';
break;
case 3:
case -1:
default:
// Unknown status.
$status = 'unknown';
break;
}
$heatmap .= sprintf(
'<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
'rect_'.$cont,
$x,
$y,
$row,
$column,
$square_length,
$square_length,
$status,
random_int(1, 10)
);
$y += $square_length;
$row++;
if ((int) ($y + $square_length) > (int) $height) {
$y = 0;
$x += $square_length;
$row = 0;
$column++;
}
if ((int) ($x + $square_length) > (int) $width) {
$x = 0;
$y += $square_length;
$column = 0;
$row++;
}
$cont++;
}
$heatmap .= '<script type="text/javascript">
$(document).ready(function() {
const total_groups = "'.$total_groups.'";
function getRandomInteger(min, max) {
return Math.floor(Math.random() * max) + min;
}
function oneSquare(solid, time) {
var randomPoint = getRandomInteger(1, total_groups);
let target = $(`#rect_${randomPoint}`);
let class_name = target.attr("class");
class_name = class_name.split("_")[0];
setTimeout(function() {
target.removeClass();
target.addClass(`${class_name}_${solid}`);
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
}, time);
}
let cont = 0;
while (cont < Math.ceil(total_groups / 3)) {
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
cont ++;
}
});
</script>';
$heatmap .= '</g>';
$heatmap .= '</svg>';
return html_print_div(
[
'content' => $heatmap,
'style' => 'margin: 0 auto; width: fit-content; min-height: 285px;',
],
true
);
}
/**
* Return the status agents in heat map.
*
* @return string
*/
public function getStatusHeatMapAgents():string
{
global $config;
$width = get_parameter('width', 350);
$height = get_parameter('height', 275);
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT * FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
WHERE g.id_group IN ('.$id_groups.') OR a.id_grupo IN ('.$id_groups.')';
$all_agents = db_get_all_rows_sql($sql);
if (empty($all_agents)) {
return null;
}
$total_agents = count($all_agents);
// Best square.
$high = (float) max($width, $height);
$low = 0.0;
while (abs($high - $low) > 0.000001) {
$mid = (($high + $low) / 2.0);
$midval = (floor($width / $mid) * floor($height / $mid));
if ($midval >= $total_agents) {
$low = $mid;
} else {
$high = $mid;
}
}
$square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
// Print starmap.
$heatmap = sprintf(
'<svg id="svg" style="width: %spx; height: %spx;">',
$width,
$height
);
$heatmap .= '<g>';
$row = 0;
$column = 0;
$x = 0;
$y = 0;
$cont = 1;
foreach ($all_agents as $key => $value) {
// Colour by status.
$status = agents_get_status_from_counts($value);
switch ($status) {
case 5:
// Not init status.
$status = 'notinit';
break;
case 1:
// Critical status.
$status = 'critical';
break;
case 2:
// Warning status.
$status = 'warning';
break;
case 0:
// Normal status.
$status = 'normal';
break;
case 3:
case -1:
default:
// Unknown status.
$status = 'unknown';
break;
}
$heatmap .= sprintf(
'<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
'rect_'.$cont,
$x,
$y,
$row,
$column,
$square_length,
$square_length,
$status,
random_int(1, 10)
);
$y += $square_length;
$row++;
if ((int) ($y + $square_length) > (int) $height) {
$y = 0;
$x += $square_length;
$row = 0;
$column++;
}
if ((int) ($x + $square_length) > (int) $width) {
$x = 0;
$y += $square_length;
$column = 0;
$row++;
}
$cont++;
}
$heatmap .= '<script type="text/javascript">
$(document).ready(function() {
const total_agents = "'.$total_agents.'";
function getRandomInteger(min, max) {
return Math.floor(Math.random() * max) + min;
}
function oneSquare(solid, time) {
var randomPoint = getRandomInteger(1, total_agents);
let target = $(`#rect_${randomPoint}`);
let class_name = target.attr("class");
class_name = class_name.split("_")[0];
setTimeout(function() {
target.removeClass();
target.addClass(`${class_name}_${solid}`);
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
}, time);
}
let cont = 0;
while (cont < Math.ceil(total_agents / 3)) {
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
cont ++;
}
});
</script>';
$heatmap .= '</g>';
$heatmap .= '</svg>';
return html_print_div(
[
'content' => $heatmap,
'style' => 'margin: 0 auto; width: fit-content; min-height: 285px;',
],
true
);
}
/**
* Return the status groups in heat map.
*
* @return string
*/
public function getStatusHeatMapGroup():string
{
global $config;
$width = get_parameter('width', 350);
$height = get_parameter('height', 275);
// ACL Check.
$agent_a = check_acl($config['id_user'], 0, 'AR');
$agent_w = check_acl($config['id_user'], 0, 'AW');
$groups_list = groupview_get_groups_list(
$config['id_user'],
($agent_a == true) ? 'AR' : (($agent_w == true) ? 'AW' : 'AR'),
true
);
$total_groups = $groups_list['counter'];
$groups = $groups_list['groups'];
// Best square.
$high = (float) max($width, $height);
$low = 0.0;
while (abs($high - $low) > 0.000001) {
$mid = (($high + $low) / 2.0);
$midval = (floor($width / $mid) * floor($height / $mid));
if ($midval >= $total_groups) {
$low = $mid;
} else {
$high = $mid;
}
}
$square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
// Print starmap.
$heatmap = sprintf(
'<svg id="svg" style="width: %spx; height: %spx;">',
$width,
$height
);
$heatmap .= '<g>';
$row = 0;
$column = 0;
$x = 0;
$y = 0;
$cont = 1;
foreach ($groups as $key => $value) {
if ($value['_name_'] === 'All') {
continue;
}
if ($value['_monitors_critical_'] > 0) {
$status = 'critical';
} else if ($value['_monitors_warning_'] > 0) {
$status = 'warning';
} else if (($value['_monitors_unknown_'] > 0) || ($value['_agents_unknown_'] > 0)) {
$status = 'unknown';
} else if ($value['_monitors_ok_'] > 0) {
$status = 'normal';
} else {
$status = 'unknown';
}
$heatmap .= sprintf(
'<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
'rect_'.$cont,
$x,
$y,
$row,
$column,
$square_length,
$square_length,
$status,
random_int(1, 10)
);
$y += $square_length;
$row++;
if ((int) ($y + $square_length) > (int) $height) {
$y = 0;
$x += $square_length;
$row = 0;
$column++;
}
if ((int) ($x + $square_length) > (int) $width) {
$x = 0;
$y += $square_length;
$column = 0;
$row++;
}
$cont++;
}
$heatmap .= '<script type="text/javascript">
$(document).ready(function() {
const total_groups = "'.$total_groups.'";
function getRandomInteger(min, max) {
return Math.floor(Math.random() * max) + min;
}
function oneSquare(solid, time) {
var randomPoint = getRandomInteger(1, total_groups);
let target = $(`#rect_${randomPoint}`);
let class_name = target.attr("class");
class_name = class_name.split("_")[0];
setTimeout(function() {
target.removeClass();
target.addClass(`${class_name}_${solid}`);
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
}, time);
}
let cont = 0;
while (cont < Math.ceil(total_groups / 3)) {
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
cont ++;
}
});
</script>';
$heatmap .= '</g>';
$heatmap .= '</svg>';
return html_print_div(
[
'content' => $heatmap,
'style' => 'margin: 0 auto; width: fit-content; min-height: 285px;',
],
true
);
}
}

View File

@ -0,0 +1,219 @@
<?php
/**
* LogStorage element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* LogStorage, this class contain all logic for this section.
*/
class LogStorage extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Log storage');
$this->ajaxMethods = [
'getStatus',
'getTotalSources',
'getStoredData',
'getAgeOfStoredData',
];
$this->interval = 300000;
$this->refreshConfig = [
'status' => [
'id' => 'status-log-storage',
'method' => 'getStatus',
],
'total-source' => [
'id' => 'total-source-log-storage',
'method' => 'getTotalSources',
],
'total-lines' => [
'id' => 'total-lines-log-storage',
'method' => 'getStoredData',
],
'age' => [
'id' => 'age-of-stored',
'method' => 'getAgeOfStoredData',
],
];
}
/**
* Check if log storage module exist.
*
* @return boolean
*/
public function isEnabled():bool
{
global $config;
if ((bool) $config['log_collector'] === true) {
return true;
} else {
return false;
}
}
/**
* Returns the html status of log storage.
*
* @return string
*/
public function getStatus():string
{
$classDisabled = '';
if ($this->isEnabled() === true) {
$value = $this->valueMonitoring('Log server connection');
$status = ((int) $value[0]['datos'] === 1) ? true : false;
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Somethings wrong'),
'class' => 'status-text',
],
true
);
}
} else {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
$classDisabled = 'alpha50';
}
$output = $image_status.$text;
return html_print_div(
[
'content' => $output,
'class' => 'flex_center margin-top-5 '.$classDisabled,
'style' => 'margin: 0px 10px 10px 10px;',
'id' => 'status-log-storage',
],
true
);
}
/**
* Returns the html of total sources in log storage.
*
* @return string
*/
public function getTotalSources():string
{
if ($this->isEnabled() === true) {
$data = $this->valueMonitoring('Total sources');
$value = format_numeric($data[0]['datos']);
} else {
$value = __('N/A');
}
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'style' => 'margin: 0px 10px 0px 10px;',
'id' => 'total-source-log-storage',
],
true
);
}
/**
* Returns the html of lines in log storage.
*
* @return string
*/
public function getStoredData():string
{
if ($this->isEnabled() === true) {
$data = $this->valueMonitoring('Total lines of data');
$value = format_numeric($data[0]['datos']);
} else {
$value = __('N/A');
}
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'style' => 'margin: 0px 10px 0px 10px;',
'id' => 'total-lines-log-storage',
],
true
);
}
/**
* Returns the html of age of stored data.
*
* @return string
*/
public function getAgeOfStoredData():string
{
$data = $this->valueMonitoring('Longest data archived');
$date = $data[0]['datos'];
if ($date > 0 && $this->isEnabled() === true) {
$interval = (time() - strtotime($date));
$days = format_numeric(($interval / 86400), 0);
} else {
$days = 'N/A';
}
return html_print_div(
[
'content' => $days,
'class' => 'text-l',
'style' => 'margin: 0px 10px 0px 10px;',
'id' => 'age-of-stored',
],
true
);
}
}

View File

@ -0,0 +1,246 @@
<?php
/**
* MonitoringElements element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* MonitoringElements, this class contain all logic for this section.
*/
class MonitoringElements extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
include_once $config['homedir'].'/include/graphs/fgraph.php';
include_once $config['homedir'].'/include/functions_graph.php';
$this->title = __('Monitoring elements');
}
/**
* Returns the html of the tags grouped by modules.
*
* @return string
*/
public function getTagsGraph():string
{
$sql = 'SELECT name, count(*) AS total
FROM ttag_module t
LEFT JOIN ttag ta ON ta.id_tag = t.id_tag
GROUP BY t.id_tag
ORDER BY total DESC
LIMIT 10;';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['name']) === true) {
continue;
}
$labels[] = $this->controlSizeText($row['name']);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Returns the html of the groups grouped by modules.
*
* @return string
*/
public function getModuleGroupGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT name, count(*) AS total
FROM tagente_modulo m
LEFT JOIN tagente a on a.id_agente = m.id_agente
LEFT JOIN tagent_secondary_group gs ON gs.id_agent = a.id_agente
LEFT JOIN tmodule_group g ON g.id_mg = m.id_module_group
WHERE name <> "" AND (a.id_grupo IN ('.$id_groups.') OR gs.id_group IN ('.$id_groups.'))
GROUP BY m.id_module_group
ORDER BY total DESC
LIMIT 10';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['name']) === true) {
continue;
}
$labels[] = $this->controlSizeText($row['name']);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Returns the html of the agent grouped by modules.
*
* @return string
*/
public function getAgentGroupsGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT gr.nombre, count(*) +
IFNULL((SELECT count(*) AS total
FROM tagente second_a
LEFT JOIN tagent_secondary_group second_g ON second_g.id_agent = second_a.id_agente
WHERE a.id_grupo = second_g.id_group AND second_g.id_group IN ('.$id_groups.')
GROUP BY second_g.id_group
), 0) AS total
FROM tagente a
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
WHERE a.id_grupo IN ('.$id_groups.')
GROUP BY a.id_grupo
ORDER BY total DESC
LIMIT 10';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['nombre']) === true) {
continue;
}
$labels[] = $this->controlSizeText(io_safe_output($row['nombre']));
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Returns the html of monitoring by status.
*
* @return string
*/
public function getMonitoringStatusGraph():string
{
$pie = graph_agent_status(false, '', '', true, true, false, true);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
}

View File

@ -0,0 +1,124 @@
<?php
/**
* NewsBoard element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* NewsBoard, this class contain all logic for this section.
*/
class NewsBoard extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
ui_require_css_file('news');
include_once 'general/news_dialog.php';
$this->title = __('News Board');
}
/**
* Returns the html of the latest news.
*
* @return string
*/
public function getNews():string
{
global $config;
$options = [];
$options['id_user'] = $config['id_user'];
$options['modal'] = false;
$options['limit'] = 7;
$news = get_news($options);
if (!empty($news)) {
$output = '<div id="news-board" class="new">';
foreach ($news as $article) {
$default = false;
if ($article['text'] == '&amp;lt;p&#x20;style=&quot;text-align:&#x20;center;&#x20;font-size:&#x20;13px;&quot;&amp;gt;Hello,&#x20;congratulations,&#x20;if&#x20;you&apos;ve&#x20;arrived&#x20;here&#x20;you&#x20;already&#x20;have&#x20;an&#x20;operational&#x20;monitoring&#x20;console.&#x20;Remember&#x20;that&#x20;our&#x20;forums&#x20;and&#x20;online&#x20;documentation&#x20;are&#x20;available&#x20;24x7&#x20;to&#x20;get&#x20;you&#x20;out&#x20;of&#x20;any&#x20;trouble.&#x20;You&#x20;can&#x20;replace&#x20;this&#x20;message&#x20;with&#x20;a&#x20;personalized&#x20;one&#x20;at&#x20;Admin&#x20;tools&#x20;-&amp;amp;gt;&#x20;Site&#x20;news.&amp;lt;/p&amp;gt;&#x20;') {
$article['subject'] = __('Welcome to Pandora FMS Console');
$default = true;
}
$text_bbdd = io_safe_output($article['text']);
$text = html_entity_decode($text_bbdd);
$output .= '<div class="new-board">';
$output .= '<div class="new-board-header">';
$output .= '<span class="new-board-title">'.$article['subject'].'</span>';
$output .= '<span class="new-board-author">'.__('By').' '.$article['author'].' '.ui_print_timestamp($article['timestamp'], true).'</span>';
$output .= '</div>';
$output .= '<div class="new content">';
if ($default) {
$output .= '<div class="default-new">';
$output .= '<div class="default-image-new">';
$output .= '<img src="./images/welcome_image.svg" alt="img colabora con nosotros - Support">';
$output .= '</div><div class="default-text-new">';
$output .= '
<p>'.__('Welcome to our monitoring tool so grand,').'
<br>'.__('Where data insights are at your command.').'
<br>'.__('Sales, marketing, operations too,').'
<br>'.__("Customer support, we've got you.").'
</p>
<p>'.__('Our interface is user-friendly,').'
<br>'.__("Customize your dashboard, it's easy.").'
<br>'.__('Set up alerts and gain insights so keen,').'
<br>'.__("Optimize your data, like you've never seen.").'
</p>
<p>'.__('Unleash its power now, and join the pro league,').'
<br>'.__('Unlock the potential of your data to intrigue.').'
<br>'.__('Monitoring made simple, efficient and fun,').'
<br>'.__('Discover a whole new way to get things done.').'
</p>
<p>'.__('And take control of your IT once and for all.').'</p>
<span>'.__('You can replace this message with a personalized one at Admin tools -> Site news.').'</span>
';
$output .= '</div></div>';
} else {
$text = str_replace('<script', '&lt;script', $text);
$text = str_replace('</script', '&lt;/script', $text);
$output .= nl2br($text);
}
$output .= '</div></div>';
}
$output .= '</div>';
return $output;
}
}
}

View File

@ -0,0 +1,345 @@
<?php
/**
* Overview element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Overview, this class contain all logic for this section.
*/
class Overview extends Element
{
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
if (is_ajax() === true) {
include_once $config['homedir'].'/include/functions_servers.php';
}
$this->title = __('General overview');
$this->ajaxMethods = [
'getLogSizeStatus',
'getServerStatus',
'getCPULoadGraph',
];
$this->interval = 300000;
$this->refreshConfig = [
'logSizeStatus' => [
'id' => 'status-log-size',
'method' => 'getLogSizeStatus',
],
'ServerStatus' => [
'id' => 'status-servers',
'method' => 'getServerStatus',
],
'cpuStatus' => [
'id' => 'status-cpu',
'method' => 'getCPULoadGraph',
],
];
}
/**
* Return the html log size status.
*
* @return string
*/
public function getLogSizeStatus():string
{
$size = $this->valueMonitoring('console_log_size');
$status = ($size[0]['datos'] < 1000) ? true : false;
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Too size log size'),
'class' => 'status-text',
],
true
);
}
$output = $image_status.$text;
return html_print_div(
[
'content' => $output,
'class' => 'margin-top-5 flex_center',
'id' => 'status-log-size',
],
true
);
}
/**
* Return the html Servers status.
*
* @return string
*/
public function getServerStatus():string
{
$status = check_all_servers_up();
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Somethings wrong'),
'class' => 'status-text',
],
true
);
}
$output = '<a href="index.php?sec=gservers&sec2=godmode/servers/modificar_server" class="flex_center">'.$image_status.$text.'</a>';
return html_print_div(
[
'content' => $output,
'class' => 'margin-top-5',
'id' => 'status-servers',
],
true
);
}
/**
* Returns the html of the used licenses.
*
* @return string
*/
public function getLicenseUsageGraph():string
{
if (enterprise_installed() === true) {
$info = license_get_info();
if ($info['limit'] > $info['count']) {
$used = round(($info['count'] / $info['limit']) * 100);
$free = (100 - $used);
} else {
$free = 100;
$used = 0;
}
$data = [
'agents_used' => [
'label' => __('% Agents used'),
'perc' => $used,
'color' => '#1C4E6B',
],
'free_agents' => [
'label' => __('% Free agents'),
'perc' => $free,
'color' => '#5C63A2',
],
];
} else {
$agents = agents_get_agents();
$enabled_agents = agents_get_agents(
false,
false,
'AR',
[
'field' => 'nombre',
'order' => 'ASC',
],
false,
1
);
if (is_array($agents) === true) {
$total = count($agents);
} else {
$total = 0;
}
if ($total > 0 && is_array($enabled_agents) === true) {
$total_disabled_agents = round((($total - count($enabled_agents)) * 100) / $total);
$total_enabled_agents = round((count($enabled_agents) * 100) / $total);
} else {
$total_disabled_agents = 0;
$total_enabled_agents = 100;
}
$data = [
'agents_enabled' => [
'label' => __('% Agents enabled'),
'perc' => $total_enabled_agents,
'color' => '#1C4E6B',
],
'agents_disabled' => [
'label' => __('% Agents disabled'),
'perc' => $total_disabled_agents,
'color' => '#5C63A2',
],
];
}
$bar = $this->printHorizontalBar($data);
$output = html_print_div(
[
'content' => $bar,
'style' => 'margin: 0 auto;',
],
true
);
return $output;
}
/**
* Print horizontal bar divided by percentage.
*
* @param array $data Required [perc, color, label].
*
* @return string
*/
private function printHorizontalBar(array $data):string
{
$output = '<div id="horizontalBar">';
$output .= '<div class="labels">';
foreach ($data as $key => $value) {
$output .= html_print_div(
[
'content' => '<div style="background: '.$value['color'].'"></div><span>'.$value['label'].'</span>',
'class' => 'label',
],
true
);
}
$output .= '</div>';
$output .= '<div class="bar">';
foreach ($data as $key => $value) {
$output .= html_print_div(
[
'content' => $value['perc'].' %',
'style' => 'width: '.$value['perc'].'%; background-color: '.$value['color'].';',
],
true
);
}
$output .= '</div>';
$output .= '
<div class="marks">
<div class="mark"><div class="line mark0"></div><span class="number">0 %</span></div>
<div class="mark"><div class="line mark20"></div><span class="number number20">20 %</span></div>
<div class="mark"><div class="line mark40"></div><span class="number number40">40 %</span></div>
<div class="mark"><div class="line mark60"></div><span class="number number60">60 %</span></div>
<div class="mark"><div class="line mark80"></div><span class="number number80">80 %</span></div>
<div class="mark"><div class="line mark100"></div><span class="number number100">100 %</span></div>
</div>';
$output .= '</div>';
return $output;
}
/**
* Returns the html of a graph with the cpu load.
*
* @return string
*/
public function getCPULoadGraph():string
{
$data_last24h = $this->valueMonitoring('CPU Load', (time() - 86400), time());
$dates = [];
$cpu_load = [];
foreach ($data_last24h as $key => $raw_data) {
$dates[] = date('H:m:s', $raw_data['utimestamp']);
$cpu_load[] = $raw_data['datos'];
}
$options = [
'labels' => $dates,
'legend' => [ 'display' => false ],
'tooltips' => [ 'display' => false ],
'scales' => [
'y' => [
'grid' => ['display' => false],
'ticks' => ['display' => false],
'display' => false,
],
'x' => [
'grid' => ['display' => false],
'display' => false,
],
],
'elements' => [ 'point' => [ 'radius' => 0 ] ],
];
$data = [
[
'backgroundColor' => '#009D9E',
'borderColor' => '#009D9E',
'pointBackgroundColor' => '#009D9E',
'pointHoverBorderColor' => '#009D9E',
'data' => $cpu_load,
],
];
$graph_area = html_print_div(
[
'content' => line_graph($data, $options),
'class' => 'margin-top-5 w100p h100p',
'style' => 'max-height: 50px;',
'id' => 'status-cpu',
],
true
);
$output = $graph_area;
return $output;
}
}

View File

@ -0,0 +1,270 @@
<?php
/**
* ScheduledDowntime element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* ScheduledDowntime, this class contain all logic for this section.
*/
class ScheduledDowntime extends Element
{
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
ui_require_javascript_file('pandora_planned_downtimes');
include_once $config['homedir'].'/include/functions_reporting.php';
$this->title = __('Scheduled Downtime');
$this->ajaxMethods = ['getScheduleDowntime'];
}
/**
* List all schedule downtime.
*
* @return string
*/
public function list():string
{
$columns = [
'name',
'configuration',
'running',
'affected',
];
$columnNames = [
__('Name #Ag.'),
__('Configuration'),
__('Running'),
__('Affected'),
];
return ui_print_datatable(
[
'id' => 'list_downtime',
'class' => 'info_table',
'style' => 'width: 90%',
'dom_elements' => 'tfp',
'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_url' => $this->ajaxController,
'no_sortable_columns' => [
1,
2,
],
'ajax_data' => [
'method' => 'getScheduleDowntime',
'class' => static::class,
],
'order' => [
'field' => 'name',
'direction' => 'asc',
],
'default_pagination' => 5,
'search_button_class' => 'sub filter float-right',
'return' => true,
]
);
}
/**
* Return the schedule downtime for datatable by ajax.
*
* @return void
*/
public function getScheduleDowntime():void
{
global $config;
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$orderDatatable = get_datatable_order(true);
$pagination = '';
$order = '';
try {
ob_start();
if (isset($orderDatatable)) {
$order = sprintf(
' ORDER BY %s %s',
$orderDatatable['field'],
$orderDatatable['direction']
);
}
if (isset($length) && $length > 0
&& isset($start) && $start >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$length,
$start
);
}
$columns = [
'id',
'name',
'description',
'date_from',
'date_to',
'executed',
'id_group',
'only_alerts',
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday',
'periodically_time_from',
'periodically_time_to',
'periodically_day_from',
'periodically_day_to',
'type_downtime',
'type_execution',
'type_periodicity',
'id_user',
'cron_interval_from',
'cron_interval_to',
];
$columns_str = implode(',', $columns);
$sql = sprintf(
'SELECT %s
FROM tplanned_downtime
%s %s',
$columns_str,
$order,
$pagination,
);
$sql_count = 'SELECT COUNT(id) AS num
FROM tplanned_downtime';
$downtimes = db_get_all_rows_sql($sql);
foreach ($downtimes as $key => $downtime) {
if ((int) $downtime['executed'] === 0) {
$downtimes[$key]['running'] = html_print_div(
[
'content' => '',
'class' => 'square stop',
'title' => 'Not running',
],
true
);
} else {
$downtimes[$key]['running'] = html_print_div(
[
'content' => '',
'class' => 'square running',
'title' => 'Running',
],
true
);
}
$downtimes[$key]['configuration'] = reporting_format_planned_downtime_dates($downtime);
$settings = [
'url' => ui_get_full_url('ajax.php', false, false, false),
'loadingText' => __('Loading, this operation might take several minutes...'),
'title' => __('Elements affected'),
'id' => $downtime['id'],
];
$downtimes[$key]['affected'] = '<a style="margin-left: 22px;" href="javascript:" onclick=\'dialogAgentModulesAffected('.json_encode($settings).')\'>';
$downtimes[$key]['affected'] .= html_print_image(
'images/details.svg',
true,
[
'title' => __('Agents and modules affected'),
'class' => 'main_menu_icon invert_filter',
]
);
$downtimes[$key]['affected'] .= '</a>';
}
$downtimes_number_res = db_get_all_rows_sql($sql_count);
$downtimes_number = ($downtimes_number_res !== false) ? $downtimes_number_res[0]['num'] : 0;
if (empty($downtimes) === true) {
$downtimes = [];
}
echo json_encode(
[
'data' => $downtimes,
'recordsTotal' => $downtimes_number,
'recordsFiltered' => $downtimes_number,
]
);
// Capture output.
$response = ob_get_clean();
} catch (Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
exit;
}
json_decode($response);
if (json_last_error() === JSON_ERROR_NONE) {
echo $response;
} else {
echo json_encode(
[
'success' => false,
'error' => $response,
]
);
}
exit;
}
/**
* Check permission acl for this section.
*
* @return boolean
*/
public function checkAcl():bool
{
global $config;
$read_permisson = (bool) check_acl($config['id_user'], 0, 'AR');
if ($read_permisson === true) {
return true;
} else {
return false;
}
}
}

View File

@ -0,0 +1,129 @@
<?php
/**
* SnmpTraps element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* SnmpTraps, this class contain all logic for this section.
*/
class SnmpTraps extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('SNMP Traps');
$this->ajaxMethods = [
'getQueues',
'getTotalSources',
];
$this->interval = 300000;
$this->refreshConfig = [
'queues' => [
'id' => 'total-queues',
'method' => 'getQueues',
],
'total-snmp' => [
'id' => 'total-snmp',
'method' => 'getTotalSources',
],
];
}
/**
* Check if snmp traps module exist.
*
* @return boolean
*/
public function isEnabled():bool
{
if (empty($this->monitoringAgent) === true) {
return false;
}
$existModule = modules_get_agentmodule_id(io_safe_input('snmp_trap_queue'), $this->monitoringAgent['id_agente']);
if ($existModule === false) {
return false;
} else {
return true;
}
}
/**
* Returns the html of queues traps.
*
* @return string
*/
public function getQueues():string
{
if ($this->isEnabled() === true) {
$value = $this->valueMonitoring('snmp_trap_queue');
$total = round($value[0]['data']);
} else {
$total = __('N/A');
}
return html_print_div(
[
'content' => $total,
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
'id' => 'total-queues',
],
true
);
}
/**
* Returns the html of total sources traps.
*
* @return string
*/
public function getTotalSources():string
{
if ($this->isEnabled() === true) {
$value = $this->valueMonitoring('total_trap');
$total = round($value[0]['data']);
} else {
$total = __('N/A');
}
return html_print_div(
[
'content' => $total,
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
'id' => 'total-snmp',
],
true
);
}
}

View File

@ -0,0 +1,363 @@
#welcome-message {
margin-bottom: 30px;
}
.message-welcome {
color: #161628;
font-size: 32px;
line-height: 38px;
text-align: left;
font-weight: 700;
}
.subtitle-welcome-message {
color: #8a96a6;
font-size: 15px;
line-height: 20px;
text-align: left;
margin-left: 5px;
}
.row {
display: flex;
width: 100%;
align-items: stretch;
}
.col-12 {
width: 100%;
}
.col-6,
.col-xl-6 {
width: 50%;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
}
.col-7 {
width: 58%;
}
.col-8 {
width: 66.6%;
}
.col-4 {
width: 33%;
}
.col-5 {
width: 42%;
}
.col-3,
.col-md-3 {
width: 25%;
}
.col-9,
.col-md-9 {
width: 75%;
}
.container {
background-color: white;
border: 1px solid #e5e9ed;
border-radius: 10px;
height: 100%;
max-width: 100%;
}
.br-l {
border-left: 1px solid #e5e9ed;
}
.br-t {
border-top: 1px solid #e5e9ed;
}
.br-r {
border-right: 1px solid #e5e9ed;
}
.br-b {
border-bottom: 1px solid #e5e9ed;
}
.title {
font-size: 18px !important;
color: #161628;
text-align: center !important;
font-weight: bold !important;
padding: 15px 0px !important;
}
.subtitle {
font-size: 13px;
color: #161628;
padding-bottom: 5px;
padding-top: 5px;
}
.subtitle.link {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.subtitle.link a {
color: #14524f;
font-size: 13px;
font-weight: 800;
}
.absolute-link::after {
content: "→";
}
.status-text {
color: #6e7079;
font-size: 13px;
margin-left: 6px;
}
.text-xl {
font-size: 40px;
color: #6c7587;
font-weight: bold;
padding-left: 8px;
margin-bottom: 8px;
line-height: initial;
}
.text-l {
font-size: 27px;
color: #6c7587;
font-weight: bold;
margin-bottom: 8px;
line-height: initial;
}
#news-board {
min-width: 530px;
width: 100%;
max-height: 639px;
overflow-y: auto;
}
#database .subtitle,
#logStorage .subtitle,
#SNMPTraps .subtitle,
#Alerts .subtitle,
#Agents .subtitle {
padding: 10px 10px 5px 10px;
}
#Agents > .row {
min-height: 550px;
}
#horizontalBar {
margin: 0px 20px;
position: relative;
}
#horizontalBar .bar {
display: flex;
color: white;
height: 43px;
justify-content: space-between;
}
#horizontalBar .bar div {
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.marks {
display: flex;
margin-top: 20px;
}
.marks .line {
height: 76px;
background: #00000033;
width: 1px;
position: absolute;
top: 24px;
}
.mark {
min-height: 30px;
}
.mark .number {
position: absolute;
}
.mark0 {
left: 0%;
}
.mark20 {
left: 20%;
}
.mark40 {
left: 40%;
}
.mark60 {
left: 60%;
}
.mark80 {
left: 80%;
}
.mark100 {
left: 100%;
}
.number20 {
left: 19%;
}
.number40 {
left: 39%;
}
.number60 {
left: 59%;
}
.number80 {
left: 79%;
}
.number100 {
left: 95%;
}
.mark:nth-child(1) {
text-align: left;
}
.labels {
display: flex;
margin-bottom: 19px;
}
.label {
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.label div {
width: 10px;
height: 10px;
border-radius: 2px;
margin-right: 3px;
}
.indicative-text {
color: #6e7079;
font-size: 12px;
line-height: 13px;
text-align: left;
padding: 0px 10px 10px 10px;
}
.dataTables_paginate a {
background: none !important;
border: 0px;
font-size: 13px;
}
.pandora_pagination.next,
.pandora_pagination.previous {
border-right: 0px !important;
border-left: 0px !important;
}
a.pandora_pagination {
border-radius: 3px;
padding: 6px;
}
.info_table > tbody > tr:nth-child(even) {
background-color: #f9f9f9;
}
.pandora_pagination.current {
background-color: #1d7874 !important;
}
a.pandora_pagination:first-child {
border-left: 0px !important;
}
.info_table {
border: 1px solid #c0ccdc;
border-bottom: 1px solid #c0ccdc !important;
border-collapse: collapse;
}
.info_table td:nth-child(1) {
border-top: 0px;
}
.info_table td {
border-top: 1px solid #c0ccdc !important;
}
.info_table th {
border: 0px !important;
}
.admin {
color: #ec7176;
}
.user {
color: #8a96a6;
}
.mini-criticity {
width: 6px !important;
min-width: auto !important;
max-width: auto !important;
height: 28px !important;
border-radius: 9px !important;
margin-left: 7px !important;
}
#datatable_events .datatables_thead_tr th:nth-child(1) {
width: 10.3333px !important;
padding: 20px 0px 20px 15px !important;
}
.info_table td {
font-size: 13px !important;
}
table.dataTable thead th {
padding: 0px 18px !important;
}
#list_downtime_wrapper {
margin: 28px 0px;
}
.square {
width: 20px;
height: 20px;
margin-left: 20px;
}
.running {
background-color: #82b92e;
}
.stop {
background-color: #ec7176;
}
@media (max-width: 1636px) {
.col-xl-6 {
width: 100%;
}
.col-6 {
width: 49%;
}
.col-3 {
width: 21%;
}
.col-4 {
width: 33%;
}
.row {
flex-wrap: wrap;
}
.col-7 {
width: 56%;
}
.col-5 {
width: 41%;
}
.flex-nowrap {
flex-wrap: nowrap !important;
}
.col-md-9,
.col-md-3 {
width: 100%;
}
}
@media (max-width: 1300px) {
.col-6 {
width: 49%;
}
}

View File

@ -1,7 +1,7 @@
.new-board {
background-color: #ffffff;
border: 1px solid #e5e9ed;
border-radius: 4px;
border-top: 1px solid #e5e9ed;
border-bottom: 1px solid #e5e9ed;
margin-bottom: 15px;
}
@ -36,12 +36,12 @@
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
align-items: flex-start;
}
.default-new > div > img {
width: 100%;
max-width: 430px;
max-width: 268px;
height: auto;
}

View File

@ -12090,6 +12090,10 @@ span.help_icon_15px > img {
border-radius: 50%;
}
.spinner-fixed.inherit {
position: inherit;
}
@keyframes animate {
0% {
transform: rotate(0deg);

View File

@ -1858,3 +1858,16 @@ a.pandora_pagination,
#modal_help::before {
border-bottom: 8px solid #222222;
}
#general-tactical-view .message-welcome,
#general-tactical-view .subtitle,
#general-tactical-view .text-l,
#general-tactical-view .text-xl,
#general-tactical-view .status-text {
color: white !important;
}
#general-tactical-view .marks .line {
background-color: #ffffff33;
}
#general-tactical-view #horizontalBar .labels .label span {
color: black;
}

View File

@ -27,14 +27,9 @@
*/
// Begin.
use PandoraFMS\TacticalView\GeneralTacticalView;
global $config;
require_once 'include/functions_events.php';
require_once 'include/functions_servers.php';
require_once 'include/functions_reporting.php';
require_once 'include/functions_tactical.php';
require_once $config['homedir'].'/include/functions_graph.php';
check_login();
if (! check_acl($config['id_user'], 0, 'AR') && ! check_acl($config['id_user'], 0, 'AW')) {
@ -46,267 +41,5 @@ if (! check_acl($config['id_user'], 0, 'AR') && ! check_acl($config['id_user'],
return;
}
ui_require_css_file('tactical');
$is_admin = check_acl($config['id_user'], 0, 'PM');
$user_strict = (bool) db_get_value('strict_acl', 'tusuario', 'id_user', $config['id_user']);
$force_refresh = get_parameter('force_refresh', '');
$refresh = get_parameter('refr', 0);
if ($force_refresh == 1) {
db_process_sql('UPDATE tgroup_stat SET utimestamp = 0');
}
$updated_time = '';
if ($config['realtimestats'] == 0) {
$updated_time = "<a href='index.php?sec=estado&sec2=operation/agentes/tactical&force_refresh=1'>";
$updated_time .= __('Last update').' : '.ui_print_timestamp(db_get_sql('SELECT min(utimestamp) FROM tgroup_stat'), true);
$updated_time .= '</a>';
} else {
// $updated_info = __("Updated at realtime");
$updated_info = '';
}
// Header.
ui_print_standard_header(
__('Tactical view'),
'',
false,
'',
false,
(array) $updated_time,
[
[
'link' => '',
'label' => __('Monitoring'),
],
[
'link' => '',
'label' => __('Views'),
],
]
);
// Currently this function makes loading this page is impossible. Change
// and create new function.
$all_data = tactical_status_modules_agents($config['id_user'], false, 'AR');
$data = [];
$data['monitor_not_init'] = (int) $all_data['_monitors_not_init_'];
$data['monitor_unknown'] = (int) $all_data['_monitors_unknown_'];
$data['monitor_ok'] = (int) $all_data['_monitors_ok_'];
$data['monitor_warning'] = (int) $all_data['_monitors_warning_'];
$data['monitor_critical'] = (int) $all_data['_monitors_critical_'];
$data['monitor_not_normal'] = (int) $all_data['_monitor_not_normal_'];
$data['monitor_alerts'] = (int) $all_data['_monitors_alerts_'];
$data['monitor_alerts_fired'] = (int) $all_data['_monitors_alerts_fired_'];
$data['monitor_total'] = (int) $all_data['_monitor_total_'];
$data['total_agents'] = (int) $all_data['_total_agents_'];
$data['monitor_checks'] = (int) $all_data['_monitor_checks_'];
// Percentages
if (!empty($all_data)) {
if ($data['monitor_not_normal'] > 0 && $data['monitor_checks'] > 0) {
$data['monitor_health'] = format_numeric((100 - ($data['monitor_not_normal'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['monitor_health'] = 100;
}
if ($data['monitor_not_init'] > 0 && $data['monitor_checks'] > 0) {
$data['module_sanity'] = format_numeric((100 - ($data['monitor_not_init'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['module_sanity'] = 100;
}
if (isset($data['alerts'])) {
if ($data['monitor_alerts_fired'] > 0 && $data['alerts'] > 0) {
$data['alert_level'] = format_numeric((100 - ($data['monitor_alerts_fired'] / ($data['alerts'] / 100))), 1);
} else {
$data['alert_level'] = 100;
}
} else {
$data['alert_level'] = 100;
$data['alerts'] = 0;
}
$data['monitor_bad'] = ($data['monitor_critical'] + $data['monitor_warning']);
if ($data['monitor_bad'] > 0 && $data['monitor_checks'] > 0) {
$data['global_health'] = format_numeric((100 - ($data['monitor_bad'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['global_health'] = 100;
}
$data['server_sanity'] = format_numeric((100 - $data['module_sanity']), 1);
}
echo '<table border=0 class="w100p"><tr>';
echo '<td class="tactical_left_column" id="leftcolumn">';
// ---------------------------------------------------------------------
// The status horizontal bars (Global health, Monitor sanity...
// ---------------------------------------------------------------------
$bg_color = 'background-color: #222';
if ($config['style'] !== 'pandora_black' && !is_metaconsole()) {
$bg_color = 'background-color: #fff';
}
$table = new stdClass();
$table->width = '100%';
$table->class = 'info_table no-td-borders';
$table->cellpadding = 2;
$table->cellspacing = 2;
$table->border = 0;
$table->head = [];
$table->data = [];
$table->style = [$bg_color];
$stats = reporting_get_stats_indicators($data, 120, 10, false);
$statusTacticalTable = new stdClass();
$statusTacticalTable->width = '100%';
$statusTacticalTable->id = 'statusTacticalTable';
$statusTacticalTable->class = 'status_tactical tactical_table bg_white';
$statusTacticalTable->data = [];
foreach ($stats as $key => $stat) {
$statusTacticalTable->cellstyle['line_'.$key][0] = 'width: 40%;';
$statusTacticalTable->style['line_'.$key][1] = 'width: 60%;';
$statusTacticalTable->data['line_'.$key][0] = '<span>'.$stat['title'].'</span>';
$statusTacticalTable->data['line_'.$key][1] = $stat['graph'];
}
$status = html_print_table($statusTacticalTable, true);
$table->rowclass = [];
$table->rowclass[0] = 'w100p';
$table->rowclass[1] = 'w100p';
$table->rowclass[2] = 'w100p';
$table->rowclass[3] = 'w100p';
$table->rowclass[4] = 'w100p';
$table->data[0][0] = $status;
// ---------------------------------------------------------------------
// Monitor checks
// ---------------------------------------------------------------------
$data_agents = [
__('Critical') => $data['monitor_critical'],
__('Warning') => $data['monitor_warning'],
__('Normal') => $data['monitor_ok'],
__('Unknown') => $data['monitor_unknown'],
__('Not init') => $data['monitor_not_init'],
];
$table->data[1][0] = reporting_get_stats_alerts($data);
$table->rowclass[1] = 'w100p';
$table->data[2][0] = reporting_get_stats_modules_status($data, 180, 100, false, $data_agents);
$table->data[3][0] = reporting_get_stats_agents_monitors($data);
$table->rowclass[] = '';
// ---------------------------------------------------------------------
// Server performance
// ---------------------------------------------------------------------
if ($is_admin) {
$table->data[4][0] = reporting_get_stats_servers();
$table->rowclass[] = '';
}
ui_toggle(
html_print_table($table, true),
__('Report of State'),
'',
'',
false
);
echo '</td>';
// Left column
echo '<td class="w75p pdd_t_0px" id="rightcolumn">';
// ---------------------------------------------------------------------
// Last events information
// ---------------------------------------------------------------------
if (check_acl($config['id_user'], 0, 'ER')) {
$tags_condition = tags_get_acl_tags(false, 0, 'ER', 'event_condition');
$event_filter = 'estado<>1';
if (!empty($tags_condition)) {
$event_filter .= " AND ($tags_condition)";
}
if ($config['event_view_hr']) {
$event_filter .= ' AND utimestamp > (UNIX_TIMESTAMP(NOW()) - '.($config['event_view_hr'] * SECONDS_1HOUR).')';
}
$events = events_print_event_table($event_filter, 10, '100%', true, 0, true);
ui_toggle(
$events,
__('Latest events'),
'',
'',
false
);
}
// ---------------------------------------------------------------------
// Server information
// ---------------------------------------------------------------------
if ($is_admin) {
$tiny = true;
include $config['homedir'].'/godmode/servers/servers.build_table.php';
}
$out = '<table cellpadding=0 cellspacing=0 class="databox pies" width=100%><tr><td style="width:50%;">';
$out .= '<fieldset class="databox tactical_set" id="total_event_graph">';
$out .= '<legend>'.__('Event graph').'</legend>';
$out .= html_print_image('images/spinner.gif', true, ['id' => 'spinner_total_event_graph']);
$out .= '</fieldset>';
$out .= '</td><td style="width:50%;">';
$out .= '<fieldset class="databox tactical_set" id="graphic_event_group">
<legend>'.__('Event graph by agent').'</legend>'.html_print_image('images/spinner.gif', true, ['id' => 'spinner_graphic_event_group']).'</fieldset>';
$out .= '</td></tr></table>';
ui_toggle(
$out,
__('Event graphs'),
'',
'',
false
);
echo '</td>';
echo '</tr></table>';
?>
<script type="text/javascript">
$(document).ready(function () {
var parameters = {};
parameters["page"] = "include/ajax/events";
parameters["total_event_graph"] = 1;
$.ajax({type: "GET",url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",data: parameters,
success: function(data) {
$("#spinner_total_event_graph").hide();
$("#total_event_graph").append(data);
}
});
delete parameters["total_event_graph"];
parameters["graphic_event_group"] = 1;
$.ajax({type: "GET",url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",data: parameters,
success: function(data) {
$("#spinner_graphic_event_group").hide();
$("#graphic_event_group").append(data);
}
});
});
$('.tactical_table .alert_module_background_state').replaceWith(function(){
return $("<div />").addClass($(this).attr('class')).data($(this).data());
});
</script>
$tacticalView = new GeneralTacticalView();
$tacticalView->render();

View File

@ -338,8 +338,10 @@ if (is_metaconsole() === true
// Ajax responses.
if (is_ajax() === true) {
$get_events = (int) get_parameter('get_events', 0);
$external_url = (bool) get_parameter('external_url', 0);
$table_id = get_parameter('table_id', '');
$groupRecursion = (bool) get_parameter('groupRecursion', false);
$compact_date = (int) get_parameter('compact_date', 0);
// Datatables offset, limit.
$start = (int) get_parameter('start', 0);
@ -469,7 +471,7 @@ if (is_ajax() === true) {
$data = array_reduce(
$events,
function ($carry, $item) use ($table_id, &$redirection_form_id, $filter) {
function ($carry, $item) use ($table_id, &$redirection_form_id, $filter, $compact_date, $external_url) {
global $config;
$tmp = (object) $item;
@ -610,6 +612,12 @@ if (is_ajax() === true) {
);
$user_timezone = users_get_user_by_id($_SESSION['id_usuario'])['timezone'];
if ($compact_date === 1) {
$options = ['prominent' => 'compact'];
} else {
$options = [];
}
if (empty($user_timezone) === true) {
if (date_default_timezone_get() !== $config['timezone']) {
$timezone = timezone_open(date_default_timezone_get());
@ -624,16 +632,16 @@ if (is_ajax() === true) {
$total_sec = strtotime($tmp->timestamp);
$total_sec += $dif;
$last_contact = date($config['date_format'], $total_sec);
$last_contact_value = ui_print_timestamp($last_contact, true);
$last_contact_value = ui_print_timestamp($last_contact, true, $options);
} else {
$title = date($config['date_format'], strtotime($tmp->timestamp));
$value = ui_print_timestamp(strtotime($tmp->timestamp), true);
$value = ui_print_timestamp(strtotime($tmp->timestamp), true, $options);
$last_contact_value = '<span title="'.$title.'">'.$value.'</span>';
}
} else {
date_default_timezone_set($user_timezone);
$title = date($config['date_format'], strtotime($tmp->timestamp));
$value = ui_print_timestamp(strtotime($tmp->timestamp), true);
$value = ui_print_timestamp(strtotime($tmp->timestamp), true, $options);
$last_contact_value = '<span title="'.$title.'">'.$value.'</span>';
}
@ -734,8 +742,13 @@ if (is_ajax() === true) {
$criticity .= $color.'" data-title="'.$text.'" data-use_title_for_force_title="1">'.$text.'</div>';
$tmp->criticity = $criticity;
if (isset($external_url) === true && $external_url === true) {
$url = ui_get_full_url('index.php?sec=eventos&sec2=operation/events/events');
$evn = '<a href="'.$url.'&show_event_dialog='.$tmp->b64.'">';
} else {
// Add event severity to end of text.
$evn = '<a href="javascript:" onclick="show_event_dialog(\''.$tmp->b64.'\')">';
}
// Grouped events.
if ((int) $filter['group_rep'] === EVENT_GROUP_REP_EXTRAIDS) {
@ -3562,7 +3575,7 @@ function show_event_dialo(event, dialog_page) {
// History mode flag
var history = $("#hidden-history").val();
console.log(event);
jQuery.post(
ajax_file,
{
@ -3580,7 +3593,7 @@ function show_event_dialo(event, dialog_page) {
.empty()
.append(data)
.dialog({
title: event.evento,
title: event.event_title,
resizable: true,
draggable: true,
modal: true,

View File

@ -0,0 +1,391 @@
<?php global $config; ?>
<div id="general-tactical-view">
<div id="welcome-message">
<?php echo $welcome; ?>
<span class="subtitle-welcome-message"><?php echo __('This is the latest data in your tactical view'); ?></span>
</div>
<div class="row">
<div class="col-xl-6">
<div id="general-overview" class="pdd_5px">
<div class="container">
<div class="title">
<?php echo $Overview->title; ?>
</div>
<div class="content br-t">
<div class="row">
<div class="col-12">
<div class="row">
<div class="col-4">
<div class="padding10">
<span class="subtitle">
<?php echo __('Pandora FMS log size'); ?>
</span>
<?php echo $Overview->getLogSizeStatus(); ?>
</div>
</div>
<div class="col-4 br-l">
<div class="padding10">
<span class="subtitle">
<?php echo __('Server status'); ?>
</span>
<?php echo $Overview->getServerStatus(); ?>
</div>
</div>
<div class="col-4 br-l">
<div class="padding10">
<span class="subtitle">
<?php echo __('System CPU Load'); ?>
</span>
<?php echo $Overview->getCPULoadGraph(); ?>
</div>
</div>
</div>
<div class="br-t">
<div class="padding10">
<span class="subtitle">
<?php echo __('License usage'); ?>
</span>
<?php echo $Overview->getLicenseUsageGraph(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row flex-nowrap">
<div class="col-7 pdd_5px">
<div class="container">
<div class="title">
<?php echo $MonitoringElements->title; ?>
</div>
<div class="content br-t">
<div class="row">
<div class="col-6 br-r br-b">
<div class="subtitle link padding10 padding2">
<?php echo __('Top-10 Tags'); ?> <a href="index.php?sec=gusuarios&sec2=godmode/tag/tag"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getTagsGraph(); ?>
</div>
<div class="col-6 br-b">
<div class="subtitle link padding10 padding2">
<?php echo __('Top-10 module groups'); ?> <a href="index.php?sec=view&sec2=extensions/module_groups"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getModuleGroupGraph(); ?>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="subtitle link padding10 padding2">
<?php echo __('Status'); ?> <a href="index.php?sec=view&sec2=operation/agentes/estado_agente"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getMonitoringStatusGraph(); ?>
</div>
<div class="col-6 br-l">
<div class="subtitle link padding10 padding2">
<?php echo __('Top-10 Groups'); ?> <a href="index.php?sec=view&sec2=operation/agentes/group_view"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getAgentGroupsGraph(); ?>
</div>
</div>
</div>
</div>
</div>
<div class="col-5 pdd_5px">
<div class="container" id="database">
<div class="title">
<?php echo $Database->title; ?>
</div>
<div class="content br-t">
<div class="row">
<div class="col-6 br-r br-b">
<div class="subtitle">
<?php echo __('Database status'); ?>
</div>
<?php echo $Database->getStatus(); ?>
</div>
<div class="col-6 br-b">
<div class="subtitle">
<?php echo __('Data records'); ?>
</div>
<?php echo $Database->getDataRecords(); ?>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="subtitle">
<?php echo __('String records'); ?>
</div>
<?php echo $Database->getStringRecords(); ?>
</div>
<div class="col-6 br-l">
<div class="subtitle">
<?php echo __('Events'); ?>
</div>
<?php echo $Database->getEvents(); ?>
</div>
</div>
<div class="br-t">
<div class="subtitle padding10 padding2">
<?php echo __('Reads (last 24 hrs)'); ?>
</div>
<?php echo $Database->getReadsGraph(); ?>
</div>
<div class="br-t">
<div class="subtitle padding10 padding2">
<?php echo __('Writes (last 24 hrs)'); ?>
</div>
<?php echo $Database->getWritesGraph(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-6">
<div class="container mrgn_5px">
<div class="title">
<?php echo $NewsBoard->title; ?>
</div>
<?php echo $NewsBoard->getNews(); ?>
</div>
<div class="row">
<div class="col-6 pdd_5px">
<div class="container">
<div class="title br-b" id="heatmap-title">
<?php echo $Groups->title; ?>
</div>
<div class="subtitle link padding10 padding2">
<?php echo __('Status'); ?> <a href="index.php?sec=view&sec2=operation/agentes/group_view"><?php echo __('Info'); ?></a>
</div>
<div id="heatmap-group">
<?php echo $Groups->loading(); ?>
</div>
</div>
</div>
<div class="col-6">
<div class="container mrgn_5px" id="logStorage">
<div class="title br-b">
<?php echo $LogStorage->title; ?>
</div>
<div class="row">
<div class="col-6 br-r br-b">
<div class="subtitle">
<?php echo __('Log storage status'); ?>
</div>
<?php echo $LogStorage->getStatus(); ?>
</div>
<div class="col-6 br-b">
<div class="subtitle">
<?php echo __('Total sources'); ?>
</div>
<?php echo $LogStorage->getTotalSources(); ?>
</div>
</div>
<div class="row">
<div class="col-6 br-r">
<div class="subtitle">
<?php echo __('Stored data'); ?>
</div>
<?php echo $LogStorage->getStoredData(); ?>
<span class="indicative-text"><?php echo __('Lines'); ?></span>
</div>
<div class="col-6">
<div class="subtitle">
<?php echo __('Age of stored data'); ?>
</div>
<?php echo $LogStorage->getAgeOfStoredData(); ?>
<span class="indicative-text"><?php echo __('Days'); ?></span>
</div>
</div>
</div>
<div class="container mrgn_5px" id="SNMPTraps">
<div class="title br-b">
<?php echo $SnmpTraps->title; ?>
</div>
<div class="row">
<div class="col-6 br-r">
<div class="subtitle">
<?php echo __('Trap queues'); ?>
</div>
<?php echo $SnmpTraps->getQueues(); ?>
</div>
<div class="col-6">
<div class="subtitle">
<?php echo __('Total sources'); ?>
</div>
<?php echo $SnmpTraps->getTotalSources(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="<?php echo (($Events->checkAcl() === true)) ? 'col-md-3 pdd_5px' : 'col-12 pdd_5px'; ?>">
<div class="container" id="Alerts">
<div class="title br-b">
<?php echo $Alerts->title; ?>
</div>
<div class="row br-b">
<div class="col-6">
<div class="subtitle">
<?php echo __('Currently triggered'); ?>
</div>
<?php echo $Alerts->getCurrentlyTriggered(); ?>
</div>
<div class="col-6 br-l">
<div class="subtitle">
<?php echo __('Active alerts'); ?>
</div>
<?php echo $Alerts->getActiveAlerts(); ?>
</div>
</div>
<?php if ($Alerts->checkAclUserList() === true) : ?>
<div id="list-users">
<div class="subtitle link padding10 padding2">
<b><?php echo __('Logged in users (24 hrs)'); ?></b> <a href="index.php?sec=gusuarios&sec2=godmode/users/user_list"><?php echo __('More details'); ?></a>
</div>
<?php echo $Alerts->getDataTableUsers(); ?>
</div>
<?php endif; ?>
</div>
</div>
<?php if ($Events->checkAcl() === true) : ?>
<div class="col-md-9 pdd_5px">
<div class="container overflow_hidden" id="Events">
<div class="title br-b">
<?php echo $Events->title; ?>
</div>
<div class="row">
<div class="col-8 br-r">
<div class="subtitle link padding10 padding2">
<?php echo __('Number of events per hour ('.$config['event_view_hr'].' hrs)'); ?></b> <a href="index.php?sec=eventos&sec2=operation/events/events&filter[event_view_hr]=24&filter[tag_with]=WyIwIl0=&filter[tag_without]=WyIwIl0="><?php echo __('Info'); ?></a>
</div>
<div id="events-last-24"><?php echo $Events->loading(); ?></div>
<div class="row br-t h100p">
<div class="col-4 br-r">
<div class="subtitle padding10 padding2">
<?php echo __('Criticality'); ?></b>
</div>
<div id="events-criticality"><?php echo $Events->loading(); ?></div>
</div>
<div class="col-4 br-r">
<div class="subtitle padding10 padding2">
<?php echo __('Status'); ?></b>
</div>
<div id="events-status-validate"><?php echo $Events->loading(); ?></div>
</div>
<div class="col-4">
<div class="subtitle padding10 padding2">
<?php echo __('Pending validation'); ?></b>
</div>
<div id="events-status-pending-validate"><?php echo $Events->loading(); ?></div>
</div>
</div>
</div>
<div class="col-4">
<div class="subtitle link padding10 padding2">
<?php echo __('Active events ('.$config['event_view_hr'].' hrs)'); ?></b> <a href="index.php?sec=eventos&sec2=operation/events/events"><?php echo __('Info'); ?></a>
</div>
<?php echo $Events->getDataTableEvents(); ?>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
<div class="row">
<div class="col-xl-6 pdd_5px">
<div class="container" id="Agents">
<div class="title br-b">
<?php echo $Agents->title; ?>
</div>
<div class="row">
<div class="col-6 br-r">
<div class="row br-b">
<div class="col-6 br-r">
<div class="subtitle">
<?php echo __('Total agents'); ?>
</div>
<?php echo $Agents->getTotalAgents(); ?>
</div>
<div class="col-6">
<div class="subtitle">
<?php echo __('Alerts (24hrs)'); ?>
</div>
<?php echo $Agents->getAlerts(); ?>
</div>
</div>
<div class="subtitle link padding10 padding2">
<?php echo __('Top 20 groups'); ?></b> <a href="index.php?sec=view&sec2=operation/agentes/estado_agente"><?php echo __('More details'); ?></a>
</div>
<?php echo $Agents->getDataTableGroups(); ?>
</div>
<div class="col-6">
<div class="subtitle padding10 padding2">
<?php echo __('Operating system'); ?></b>
</div>
<?php echo $Agents->getOperatingSystemGraph(); ?>
<div class="subtitle padding10 padding2 br-t">
<?php echo __('Status'); ?></b>
</div>
<?php echo $Agents->getStatusGraph(); ?>
</div>
</div>
</div>
</div>
<div class="col-xl-6">
<div class="container mrgn_5px">
<div class="title br-b">
<?php echo $Configurations->title; ?>
</div>
<div class="row br-b flex-nowrap">
<a href="index.php?sec=view&sec2=operation/agentes/group_view" class="col-3 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalGroups(); ?>
</a>
<a href="index.php?sec=view&sec2=extensions/agents_modules" class="col-3 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalModules(); ?>
</a>
<?php if (enterprise_installed() === true) : ?>
<a href="index.php?sec=gmodules&sec2=enterprise/godmode/policies/policies" class="col-3 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalPolicies(); ?>
</a>
<?php endif; ?>
<a href="index.php?sec=gservers&sec2=godmode/servers/plugin" class="col-3 flex flex-column center pdd_20px">
<?php echo $Configurations->getTotalRemotePlugins(); ?>
</a>
</div>
<div class="row flex-nowrap br-b">
<a href="index.php?sec=templates&sec2=godmode/modules/manage_module_templates" class="col-4 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalModuleTemplate(); ?>
</a>
<a href="index.php?sec=view&sec2=operation/agentes/estado_agente&status=5" class="col-4 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getNotInitModules(); ?>
</a>
<a href="index.php?sec=view&sec2=operation/agentes/estado_agente&status=3" class="col-4 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalUnknowAgents(); ?>
</a>
<a href="index.php?sec=eventos&sec2=operation/events/events" class="col-4 flex flex-column center pdd_20px">
<?php echo $Configurations->getTotalEvents(); ?>
</a>
</div>
</div>
<?php if ($ScheduledDowntime->checkAcl() === true) : ?>
<div class="container mrgn_5px">
<div class="title br-b">
<?php echo $ScheduledDowntime->title; ?>
</div>
<?php echo $ScheduledDowntime->list(); ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php
echo $javascript;