From 28b8eeca61fa8fa21149114d8205192e8c28189c Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Thu, 10 Aug 2023 09:13:48 +0200 Subject: [PATCH 01/10] 11423-Graph analytics (WIP) --- .../include/styles/graph_analytics.css | 81 +++++ pandora_console/include/styles/pandora.css | 1 + pandora_console/operation/menu.php | 6 + .../operation/reporting/graph_analytics.php | 299 ++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 pandora_console/include/styles/graph_analytics.css create mode 100644 pandora_console/operation/reporting/graph_analytics.php diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css new file mode 100644 index 0000000000..d2169913f6 --- /dev/null +++ b/pandora_console/include/styles/graph_analytics.css @@ -0,0 +1,81 @@ +/* .options-graph-analytics { + position: sticky; + top: 110px; + width: -webkit-fill-available; + width: -moz-available; + height: 18px; + margin: -25px -25px 25px -25px; + padding: 10px 20px; + z-index: 1; + font-weight: bold; + display: flex; + min-width: fit-content; + background-color: var(--secondary-color); + border: 1px solid #e5e9ed; +} */ + +div#menu_tab ul li, +div#menu_tab ul li span { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + font-size: 14px; + cursor: pointer; +} + +div#menu_tab ul.mn li.nomn.tab_operation img { + margin-right: 3px; +} + +div#menu_tab ul li:hover, +div#menu_tab ul li span:hover { + box-shadow: none; +} + +div.main-div { + display: flex; + flex-direction: row; + flex-wrap: nowrap; +} + +div.padding-div { + margin: 0; + padding: 10px; +} + +div.filters-div { + min-width: 400px; + border-right: 1px solid var(--border-dark-color); +} + +div.graphs-div { + width: 100%; +} + +.handle-graph { + cursor: grab; +} + +#sortable-graphs { + display: flex; + flex-direction: column; + flex-wrap: nowrap; + justify-content: center; +} + +#sortable-graphs .drop-zone-sortable { + background-color: (--primary-color); + width: 100%; + height: 20px; + border: 2px dashed var(--border-dark-color); + border-radius: 6px; +} + +.interval-div { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: center; + margin-bottom: 10px; +} diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index c1d700d749..02797a7deb 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -32,6 +32,7 @@ --secondary-color: #ffffff; --input-border: #c0ccdc; --border-color: #eee; + --border-dark-color: #e1e1e1; --text-color: #333; } diff --git a/pandora_console/operation/menu.php b/pandora_console/operation/menu.php index 19d12e5a03..e64dbe30c7 100644 --- a/pandora_console/operation/menu.php +++ b/pandora_console/operation/menu.php @@ -471,6 +471,12 @@ if ($access_console_node === true) { 'godmode/reporting/graph_builder', ]; + + // Graph analytics. + $sub['operation/reporting/graph_analytics']['text'] = __('Graph analytics'); + $sub['operation/reporting/graph_analytics']['id'] = 'Graph_analytics'; + + if (check_acl($config['id_user'], 0, 'RR') || check_acl($config['id_user'], 0, 'RW') || check_acl($config['id_user'], 0, 'RM') diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php new file mode 100644 index 0000000000..533082c4b3 --- /dev/null +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -0,0 +1,299 @@ + ''.html_print_image( + 'images/change-active.svg', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + +$title_tab = __('New'); +$tab_new = [ + 'text' => ''.html_print_image( + 'images/plus-black.svg', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + +$title_tab = __('Save'); +$tab_save = [ + 'text' => ''.html_print_image( + 'images/save_mc.png', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + +$title_tab = __('Load'); +$tab_load = [ + 'text' => ''.html_print_image( + 'images/logs@svg.svg', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + +$title_tab = __('Share'); +$tab_share = [ + 'text' => ''.html_print_image( + 'images/responses.svg', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + +$title_tab = __('Export to custom graph'); +$tab_export = [ + 'text' => ''.html_print_image( + 'images/module-graph.svg', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + +ui_print_standard_header( + __('Graph analytics'), + 'images/menu/reporting.svg', + false, + '', + false, + [ + $tab_export, + $tab_share, + $tab_load, + $tab_save, + $tab_new, + $tab_start_realtime, + ], + [ + [ + 'link' => '', + 'label' => __('Reporting'), + ], + ] +); + +// Header options. +// $options_content = 'Sample text'; +// html_print_div( +// [ +// 'class' => 'options-graph-analytics', +// 'content' => $options_content, +// ] +// ); +// Content. +$left_content = ''; +$right_content = ''; + +$left_content .= ' +
+
+ 6 + +
+
+ +
+
+ 7 + +
+
+'; + +$intervals = []; +$intervals[SECONDS_1HOUR] = human_time_description_raw(SECONDS_1HOUR, true, 'large'); +$intervals[SECONDS_6HOURS] = human_time_description_raw(SECONDS_6HOURS, true, 'large'); +$intervals[SECONDS_12HOURS] = human_time_description_raw(SECONDS_12HOURS, true, 'large'); +$intervals[SECONDS_1DAY] = human_time_description_raw(SECONDS_1DAY, true, 'large'); +$intervals[SECONDS_2DAY] = human_time_description_raw(SECONDS_2DAY, true, 'large'); +$intervals[SECONDS_1WEEK] = human_time_description_raw(SECONDS_1WEEK, true, 'large'); + +$right_content .= '
'.html_print_select( + $intervals, + 'interval', + SECONDS_12HOURS, + '', + '', + 0, + true, + false, + false, + '' +).'
'; + +$right_content .= ' +
+
+ 1 + +
+
+ 2 + +
+
+ 3 + +
+
+ 4 + +
+
+ 5 + +
+
+'; + +$filters_div = html_print_div( + [ + 'class' => 'padding-div filters-div', + 'content' => $left_content, + ], + true +); + +$graphs_div = html_print_div( + [ + 'class' => 'padding-div graphs-div', + 'content' => $right_content, + ], + true +); + +html_print_div( + [ + 'class' => 'white_box main-div', + 'content' => $filters_div.$graphs_div, + ] +); + + +?> + + \ No newline at end of file From 5ed9206f3684806a4348d4481edb45f8149bcc9e Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Fri, 11 Aug 2023 13:50:32 +0200 Subject: [PATCH 02/10] 11423-Graph analytics. Drag&Drop (WIP) --- .../include/styles/graph_analytics.css | 125 +++++++++- .../operation/reporting/graph_analytics.php | 231 ++++++++++-------- 2 files changed, 242 insertions(+), 114 deletions(-) diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css index d2169913f6..c73b875b2a 100644 --- a/pandora_console/include/styles/graph_analytics.css +++ b/pandora_console/include/styles/graph_analytics.css @@ -44,12 +44,40 @@ div.padding-div { padding: 10px; } -div.filters-div { +div.filters-div-main { min-width: 400px; border-right: 1px solid var(--border-dark-color); } -div.graphs-div { +div.filters-div-main.filters-div-main-collapsed { + width: 20px; + min-width: 20px; +} + +div.filters-div-main.filters-div-main-collapsed + *:not(.filters-div-header):not(.filters-div-header > img) { + display: none; +} + +div.filters-div-main > .filters-div-header { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; +} + +div.filters-div-main > .filters-div-header > img { + width: 20px; + cursor: pointer; +} + +div.filters-div { + display: flex; + flex-direction: column; + flex-wrap: nowrap; +} + +div.graphs-div-main { width: 100%; } @@ -57,21 +85,13 @@ div.graphs-div { cursor: grab; } -#sortable-graphs { +#droppable-graphs { display: flex; flex-direction: column; flex-wrap: nowrap; justify-content: center; } -#sortable-graphs .drop-zone-sortable { - background-color: (--primary-color); - width: 100%; - height: 20px; - border: 2px dashed var(--border-dark-color); - border-radius: 6px; -} - .interval-div { display: flex; flex-direction: row; @@ -79,3 +99,86 @@ div.graphs-div { justify-content: center; margin-bottom: 10px; } + +/* Draggable */ +.draggable.ui-draggable-dragging { + width: 100px; +} + +.draggable { + width: 100px; + height: 20px; + background: red; +} + +.draggable2 { + background: blue; +} + +.draggable3 { + background: green; +} + +.droppable { + width: 100%; + /* height: 20px; */ + margin-bottom: 5px; + display: flex; +} + +#droppable-graphs .droppable-zone { + background-color: #0077ff80; + border: 2px dashed #0077ff; + border-radius: 6px; + width: 100%; + height: 20px; +} + +#droppable-graphs .drops-hover { + background-color: #82b92e80; + border: 2px dashed #82b92e; +} + +#droppable-graphs .droppable.droppable-default-zone:not(.droppable-new) { + height: 70px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + visibility: hidden; +} + +#droppable-graphs .droppable.droppable-default-zone.droppable-new { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +#droppable-graphs + .droppable.droppable-default-zone.droppable-new + > span.drop-here { + display: none; +} + +#droppable-graphs .droppable.droppable-default-zone > span.drop-here { + font-size: 15pt; + font-weight: bold; + color: #0077ff; +} + +#droppable-graphs + .droppable.droppable-default-zone.droppable-new.ui-droppable-active + > span.drop-here { + display: initial; +} + +#droppable-graphs .droppable.droppable-default-zone.ui-droppable-active { + visibility: visible; +} + +#droppable-graphs + .droppable.droppable-default-zone.ui-droppable-active.drops-hover + > span.drop-here { + color: #82b92e; +} diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 533082c4b3..8f90479ee0 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -145,28 +145,24 @@ $left_content = ''; $right_content = ''; $left_content .= ' -
-
- 6 - -
+
+
+
- -
-
- 7 - -
+
+
+
+
'; $intervals = []; -$intervals[SECONDS_1HOUR] = human_time_description_raw(SECONDS_1HOUR, true, 'large'); -$intervals[SECONDS_6HOURS] = human_time_description_raw(SECONDS_6HOURS, true, 'large'); -$intervals[SECONDS_12HOURS] = human_time_description_raw(SECONDS_12HOURS, true, 'large'); -$intervals[SECONDS_1DAY] = human_time_description_raw(SECONDS_1DAY, true, 'large'); -$intervals[SECONDS_2DAY] = human_time_description_raw(SECONDS_2DAY, true, 'large'); -$intervals[SECONDS_1WEEK] = human_time_description_raw(SECONDS_1WEEK, true, 'large'); +$intervals[SECONDS_1HOUR] = _('Last ').human_time_description_raw(SECONDS_1HOUR, true, 'large'); +$intervals[SECONDS_6HOURS] = _('Last ').human_time_description_raw(SECONDS_6HOURS, true, 'large'); +$intervals[SECONDS_12HOURS] = _('Last ').human_time_description_raw(SECONDS_12HOURS, true, 'large'); +$intervals[SECONDS_1DAY] = _('Last ').human_time_description_raw(SECONDS_1DAY, true, 'large'); +$intervals[SECONDS_2DAY] = _('Last ').human_time_description_raw(SECONDS_2DAY, true, 'large'); +$intervals[SECONDS_1WEEK] = _('Last ').human_time_description_raw(SECONDS_1WEEK, true, 'large'); $right_content .= '
'.html_print_select( $intervals, @@ -182,33 +178,16 @@ $right_content .= '
'.html_print_select( ).'
'; $right_content .= ' -
-
- 1 - -
-
- 2 - -
-
- 3 - -
-
- 4 - -
-
- 5 - -
+
+
'.__('Drop here').'
'; - +//
+//
+//
$filters_div = html_print_div( [ - 'class' => 'padding-div filters-div', + 'class' => 'padding-div filters-div-main', 'content' => $left_content, ], true @@ -216,7 +195,7 @@ $filters_div = html_print_div( $graphs_div = html_print_div( [ - 'class' => 'padding-div graphs-div', + 'class' => 'padding-div graphs-div-main', 'content' => $right_content, ], true @@ -233,67 +212,113 @@ html_print_div( ?> \ No newline at end of file From a10b526938ea4a31eaa9187eae6983b86a55ef4a Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Mon, 14 Aug 2023 15:36:19 +0200 Subject: [PATCH 03/10] 11423-Graph analytics. Get filter data (WIP) --- .../include/styles/graph_analytics.css | 59 ++++++- .../operation/reporting/graph_analytics.php | 159 +++++++++++++++++- 2 files changed, 207 insertions(+), 11 deletions(-) diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css index c73b875b2a..13dd23fe69 100644 --- a/pandora_console/include/styles/graph_analytics.css +++ b/pandora_console/include/styles/graph_analytics.css @@ -14,6 +14,23 @@ border: 1px solid #e5e9ed; } */ +div#main { + margin-bottom: 0; +} + +div.box-flat.white_table_graph > div[id^="tgl_div_"] { + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; +} + +div.box-flat.white_table_graph > div[id^="tgl_div_"] > div.white-box-content { + display: flex; + flex-direction: column; + flex-wrap: nowrap; + align-items: flex-start; + justify-content: flex-start; +} + div#menu_tab ul li, div#menu_tab ul li span { display: flex; @@ -37,6 +54,7 @@ div.main-div { display: flex; flex-direction: row; flex-wrap: nowrap; + min-height: calc(100vh - 160px); } div.padding-div { @@ -44,13 +62,20 @@ div.padding-div { padding: 10px; } +div.margin-div { + margin: 10px; + padding: 0; +} + div.filters-div-main { + padding: 0; + margin: 0; min-width: 400px; border-right: 1px solid var(--border-dark-color); } div.filters-div-main.filters-div-main-collapsed { - width: 20px; + width: 35px; min-width: 20px; } @@ -64,6 +89,7 @@ div.filters-div-main > .filters-div-header { flex-direction: row; flex-wrap: nowrap; justify-content: space-between; + margin: 10px; } div.filters-div-main > .filters-div-header > img { @@ -71,10 +97,39 @@ div.filters-div-main > .filters-div-header > img { cursor: pointer; } -div.filters-div { +div.filters-div-submain { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: flex-start; +} + +div.filter-div { display: flex; flex-direction: column; flex-wrap: nowrap; + width: 50%; + height: 100%; + padding: 10px; + border-top: 1px solid var(--border-dark-color); +} + +.filters-left-div { + border-right: 1px solid var(--border-dark-color); +} + +.filters-right-div { +} + +.search-graph-analytics { + background-image: url(../../images/details.svg); + background-position: center right 10px; + background-repeat: no-repeat; + background-size: 17px; + width: 100%; + margin: 10px 0; + padding-right: 30px; } div.graphs-div-main { diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 8f90479ee0..013f496fa3 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -35,7 +35,87 @@ ui_require_css_file('graph_analytics'); require_once 'include/functions_custom_graphs.php'; // Get parameters. -$x = (bool) get_parameter('x'); +$x = get_parameter('x'); + +// Ajax. +if (is_ajax()) { + $search_left = get_parameter('search_left'); + + if (empty($search_left) === false) { + $output = []; + $search = io_safe_input($search_left); + + // Agents. + // Concatenate AW and AD permisions to get all the possible groups where the user can manage. + $user_groupsAW = users_get_groups($config['id_user'], 'AW'); + $user_groupsAD = users_get_groups($config['id_user'], 'AD'); + + $user_groups = ($user_groupsAW + $user_groupsAD); + $user_groups_to_sql = implode(',', array_keys($user_groups)); + + $search_sql = ' AND (nombre LIKE "%%'.$search.'%%" OR alias LIKE "%%'.$search.'%%")'; + + $sql = sprintf( + 'SELECT * + FROM tagente + LEFT JOIN tagent_secondary_group tasg + ON tagente.id_agente = tasg.id_agent + WHERE (tagente.id_grupo IN (%s) OR tasg.id_group IN (%s)) + %s + GROUP BY tagente.id_agente + ORDER BY tagente.nombre', + $user_groups_to_sql, + $user_groups_to_sql, + $search_sql + ); + + $output['agents'] = db_get_all_rows_sql($sql); + + // Groups. + $search_sql = ' AND (nombre LIKE "%%'.$search.'%%" OR description LIKE "%%'.$search.'%%")'; + + $sql = sprintf( + 'SELECT id_grupo, nombre, icon, description + FROM tgrupo + WHERE (id_grupo IN (%s)) + %s + ORDER BY nombre', + $user_groups_to_sql, + $search_sql + ); + + $output['groups'] = db_get_all_rows_sql($sql); + + // Modules. + $result_agents = []; + $sql_result = db_get_all_rows_sql('SELECT id_agente FROM tagente WHERE id_grupo IN ('.$user_groups_to_sql.')'); + + foreach ($sql_result as $result) { + array_push($result_agents, $result['id_agente']); + } + + $id_agents = implode(',', $result_agents); + $search_sql = ' AND (nombre LIKE "%%'.$search.'%%" OR descripcion LIKE "%%'.$search.'%%")'; + + $sql = sprintf( + 'SELECT id_agente_modulo, nombre, descripcion + FROM tagente_modulo + WHERE (id_agente IN (%s)) + %s + ORDER BY nombre', + $id_agents, + $search_sql + ); + + $output['modules'] = db_get_all_rows_sql($sql); + + // Return. + echo json_encode($output); + return; + } + + return; +} // Header & Actions. $title_tab = __('Start realtime'); @@ -144,15 +224,26 @@ ui_print_standard_header( $left_content = ''; $right_content = ''; +// $left_content .= ''; $left_content .= '
-
-
-
-
+
+
+ +
+
+
+
+ '.ui_toggle('code', __('Agents'), 'agents-toggle', 'agents-toggle', true, true).' + '.ui_toggle('code', __('Groups'), 'groups-toggle', 'groups-toggle', true, true).' + '.ui_toggle('code', __('Modules'), 'modules-toggle', 'modules-toggle', true, true).' +
+
+ +
'; @@ -187,7 +278,7 @@ $right_content .= ' //
$filters_div = html_print_div( [ - 'class' => 'padding-div filters-div-main', + 'class' => 'filters-div-main', 'content' => $left_content, ], true @@ -228,7 +319,56 @@ $('div.filters-div-main > .filters-div-header > img').click(function (e) { } }); +// Search left. +$('#search-left').keyup(function (e) { + $.ajax({ + method: "POST", + url: 'ajax.php', + dataType: "json", + data: { + page: 'operation/reporting/graph_analytics', + search_left: e.target.value, + }, + success: function(data) { + if(data.agents || data.groups || data.modules){ + console.log(data); + var agentsToggle = $('#agents-toggle > div[id^=tgl_div_] > div.white-box-content'); + var groupsToggle = $('#groups-toggle > div[id^=tgl_div_] > div.white-box-content'); + var modulesToggle = $('#modules-toggle > div[id^=tgl_div_] > div.white-box-content'); + agentsToggle.empty(); + groupsToggle.empty(); + modulesToggle.empty(); + + data.agents.forEach(agent => { + agentsToggle.append(`
${agent.alias}
`); + }); + + data.groups.forEach(group => { + groupsToggle.append(`
${group.nombre}
`); + }); + + data.modules.forEach(module => { + modulesToggle.append(`
${module.nombre}
`); + }); + + // todo: position: static; div#tgl_div_... + $('.draggable').draggable({ + revert: "invalid", + stack: ".draggable", + helper: "clone", + }); + } else { + console.error('NO DATA FOUND'); + } + }, + error: function(data) { + // console.error("Fatal error in AJAX call", data); + } + }); +}); + $(document).ready(function(){ + // Draggable & Droppable graphs. $('.draggable').draggable({ revert: "invalid", @@ -236,6 +376,7 @@ $(document).ready(function(){ helper: "clone", }); + // Droppable options. var droppableOptions = { accept: ".draggable", hoverClass: "drops-hover", @@ -255,11 +396,10 @@ $(document).ready(function(){ // Ajax. // $.ajax({ // method: "POST", - // url: '', + // url: 'ajax.php', // data: { // page: '', - // method: "updatePriorityNodes", - // order: data + // method: "", // }, // dataType: "json", // success: function(data) { @@ -282,6 +422,7 @@ $(document).ready(function(){ // } // }); + // Create elements. createDroppableZones(droppableOptions, modulesByGraphs); }, }; From 63d37457943206a8fee4f40c7279f2245eff96c7 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Wed, 16 Aug 2023 15:12:31 +0200 Subject: [PATCH 04/10] 11423-Graph analytics. Get filter data (WIP) --- pandora_console/include/functions_ui.php | 10 +- .../include/styles/graph_analytics.css | 19 +- .../operation/reporting/graph_analytics.php | 336 ++++++++++++++++-- 3 files changed, 331 insertions(+), 34 deletions(-) diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index 0ce9201d09..d7cda4422e 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -4515,7 +4515,8 @@ function ui_toggle( $switch_on=null, $switch_name=null, $disableToggle=false, - $id_table=false + $id_table=false, + $position_tgl_div=false ) { // Generate unique Id. $uniqid = uniqid(''); @@ -4634,6 +4635,11 @@ function ui_toggle( } if ($disableToggle === false) { + $position_div = 'relative'; + if ($position_tgl_div !== false) { + $position_div = $position_tgl_div; + } + // JQuery Toggle. $output .= ''; +echo ''; + +if ($config['style'] !== 'pandora_black') { + echo ''; +} + +// Store servers timezone offset to be retrieved from js. +set_js_value('timezone_offset', date('Z', time())); + +extensions_add_operation_menu_option( + __('Realtime graphs'), + 'estado', + null, + 'v1r1', + 'view' +); +extensions_add_main_function('pandora_realtime_graphs'); ?> \ No newline at end of file From ce1c8cdbb7b84afff7a579baa9f847ef73439232 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Tue, 22 Aug 2023 10:04:33 +0200 Subject: [PATCH 05/10] 11423-Graph analytics. Before Share & Export --- pandora_console/extras/mr/66.sql | 12 + pandora_console/include/functions.php | 111 +- pandora_console/include/functions_graph.php | 20 + .../include/graphs/flot/pandora.flot.js | 74 +- .../include/graphs/functions_flot.php | 22 +- .../include/styles/graph_analytics.css | 99 +- .../operation/reporting/graph_analytics.php | 1158 ++++++++++++----- pandora_console/pandoradb.sql | 12 + 8 files changed, 1087 insertions(+), 421 deletions(-) create mode 100644 pandora_console/extras/mr/66.sql diff --git a/pandora_console/extras/mr/66.sql b/pandora_console/extras/mr/66.sql new file mode 100644 index 0000000000..909edd7ca7 --- /dev/null +++ b/pandora_console/extras/mr/66.sql @@ -0,0 +1,12 @@ +START TRANSACTION; + +CREATE TABLE IF NOT EXISTS `tgraph_analytics_filter` ( +`id` INT NOT NULL auto_increment, +`filter_name` VARCHAR(45) NULL, +`user_id` VARCHAR(255) NULL, +`graph_modules` TEXT NULL, +`interval` INT NULL, +PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; + +COMMIT; diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index 4fa87f70cb..0895325ef5 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -270,7 +270,8 @@ function format_for_graph( $dec_point='.', $thousands_sep=',', $divider=1000, - $sufix='' + $sufix='', + $two_lines=false ) { // Exception to exclude modules whose unit is already formatted as KB (satellite modules) if (!empty($sufix) && $sufix == 'KB') { @@ -297,6 +298,10 @@ function format_for_graph( } // This will actually do the rounding and the decimals. + if ($two_lines === true) { + return remove_right_zeros(format_numeric($number, $decimals)).'
'.$shorts[$pos].$sufix; + } + return remove_right_zeros(format_numeric($number, $decimals)).$shorts[$pos].$sufix; } @@ -4046,25 +4051,49 @@ function series_type_graph_array($data, $show_elements_graph) } } else { $name_legend = ''; - if (isset($show_elements_graph['fullscale']) === true - && (int) $show_elements_graph['fullscale'] === 1 - ) { - $name_legend .= 'Tip: '; - } else { - $name_legend .= 'Avg: '; - } - if ($value['unit']) { - $name_legend .= $value['agent_alias']; - $name_legend .= ' / '; - $name_legend .= $value['module_name']; - $name_legend .= ' / '; - $name_legend .= __('Unit ').' '; - $name_legend .= $value['unit'].': '; + if ($show_elements_graph['graph_analytics'] === true) { + $name_legend .= '
'; + $name_legend .= '
'; + $name_legend .= ''; + $name_legend .= format_for_graph( + end(end($value['data'])), + 1, + $config['decimal_separator'], + $config['thousand_separator'], + 1000, + '', + true + ); + $name_legend .= ''; + $name_legend .= ''.$value['unit'].''; + $name_legend .= '
'; + $name_legend .= '
'; + $name_legend .= ''.$value['agent_alias'].''; + $name_legend .= ''.$value['module_name'].''; + $name_legend .= '
'; + $name_legend .= '
'; } else { - $name_legend .= $value['agent_alias']; - $name_legend .= ' / '; - $name_legend .= $value['module_name'].': '; + if (isset($show_elements_graph['fullscale']) === true + && (int) $show_elements_graph['fullscale'] === 1 + ) { + $name_legend .= 'Tip: '; + } else { + $name_legend .= 'Avg: '; + } + + if ($value['unit']) { + $name_legend .= $value['agent_alias']; + $name_legend .= ' / '; + $name_legend .= $value['module_name']; + $name_legend .= ' / '; + $name_legend .= __('Unit ').' '; + $name_legend .= $value['unit'].': '; + } else { + $name_legend .= $value['agent_alias']; + $name_legend .= ' / '; + $name_legend .= $value['module_name'].': '; + } } } } @@ -4085,28 +4114,30 @@ function series_type_graph_array($data, $show_elements_graph) $value['max'] = 0; } - $data_return['legend'][$key] .= ''.__('Min').' '.remove_right_zeros( - number_format( - $value['min'], - $config['graph_precision'], - $config['csv_decimal_separator'], - $config['csv_decimal_separator'] == ',' ? '.' : ',' - ) - ).' '.$value['unit'].' '.__('Max').' '.remove_right_zeros( - number_format( - $value['max'], - $config['graph_precision'], - $config['csv_decimal_separator'], - $config['csv_decimal_separator'] == ',' ? '.' : ',' - ) - ).' '.$value['unit'].' '._('Avg.').' '.remove_right_zeros( - number_format( - $value['avg'], - $config['graph_precision'], - $config['csv_decimal_separator'], - $config['csv_decimal_separator'] == ',' ? '.' : ',' - ) - ).' '.$value['unit'].' '.$str; + if (isset($show_elements_graph['graph_analytics']) === false) { + $data_return['legend'][$key] .= ''.__('Min').' '.remove_right_zeros( + number_format( + $value['min'], + $config['graph_precision'], + $config['csv_decimal_separator'], + $config['csv_decimal_separator'] == ',' ? '.' : ',' + ) + ).' '.$value['unit'].' '.__('Max').' '.remove_right_zeros( + number_format( + $value['max'], + $config['graph_precision'], + $config['csv_decimal_separator'], + $config['csv_decimal_separator'] == ',' ? '.' : ',' + ) + ).' '.$value['unit'].' '._('Avg.').' '.remove_right_zeros( + number_format( + $value['avg'], + $config['graph_precision'], + $config['csv_decimal_separator'], + $config['csv_decimal_separator'] == ',' ? '.' : ',' + ) + ).' '.$value['unit'].' '.$str; + } if ($show_elements_graph['compare'] == 'overlapped' && $key == 'sum2' diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php index 1892b0cd31..6fa1e2a8d5 100644 --- a/pandora_console/include/functions_graph.php +++ b/pandora_console/include/functions_graph.php @@ -5540,3 +5540,23 @@ function graph_events_agent_by_group($id_group, $width=300, $height=200, $noWate $options ); } + + +function graph_analytics_filter_select() +{ + global $config; + + $result = []; + + if (check_acl($config['id_user'], 0, 'RW') === 1 || check_acl($config['id_user'], 0, 'RM') === 1) { + $filters = db_get_all_rows_sql('SELECT id, filter_name FROM tgraph_analytics_filter WHERE user_id = "'.$config['id_user'].'"'); + + if ($filters !== false) { + foreach ($filters as $filter) { + $result[$filter['id']] = $filter['filter_name']; + } + } + } + + return $result; +} diff --git a/pandora_console/include/graphs/flot/pandora.flot.js b/pandora_console/include/graphs/flot/pandora.flot.js index 93c7a9fb06..37162f5a37 100644 --- a/pandora_console/include/graphs/flot/pandora.flot.js +++ b/pandora_console/include/graphs/flot/pandora.flot.js @@ -995,6 +995,9 @@ function pandoraFlotSlicebar( } } +// Set array for realtime graphs +var realtimeGraphs = []; + // eslint-disable-next-line no-unused-vars function pandoraFlotArea( graph_id, @@ -1007,6 +1010,21 @@ function pandoraFlotArea( params, events_array ) { + // Realtime graphs. + if (typeof params.realtime !== "undefined") { + realtimeGraphs.push({ + graph_id, + values, + legend, + series_type, + color, + date_array, + data_module_graph, + params, + events_array + }); + } + //diferents vars var unit = params.unit ? params.unit : ""; var homeurl = params.homeurl; @@ -2462,15 +2480,23 @@ function pandoraFlotArea( if (Object.keys(update_legend).length == 0) { label_aux = legend[series.label]; - $("#legend_" + graph_id + " .legendLabel") - .eq(i) - .html( - label_aux + - " value = " + - number_format(y, 0, "", short_data, divisor) + - " " + - unit - ); + if (params.graph_analytics === true) { + var numberParams = {}; + numberParams.twoLines = true; + $("#legend_" + graph_id + " .legendLabel .square-value") + .eq(i) + .html(number_format(y, 0, "", 1, divisor, numberParams)); + } else { + $("#legend_" + graph_id + " .legendLabel") + .eq(i) + .html( + label_aux + + " value = " + + number_format(y, 0, "", short_data, divisor) + + " " + + unit + ); + } } else { $.each(update_legend, function(index, value) { if (typeof value[x - 1] !== "undefined") { @@ -2844,12 +2870,16 @@ function pandoraFlotArea( // Add bottom margin in the legend // Estimated height of 24 (works fine with this data in all browsers) $("#legend_" + graph_id).css("margin-bottom", "10px"); - parent_height = parseInt( - $("#menu_" + graph_id) - .parent() - .css("height") - .split("px")[0] - ); + + if (typeof params.realtime === "undefined" || params.realtime === false) { + parent_height = parseInt( + $("#menu_" + graph_id) + .parent() + .css("height") + .split("px")[0] + ); + } + adjust_menu(graph_id, plot, parent_height, width, show_legend); } } @@ -2987,7 +3017,14 @@ function check_adaptions(graph_id) { }); } -function number_format(number, force_integer, unit, short_data, divisor) { +function number_format( + number, + force_integer, + unit, + short_data, + divisor, + params +) { divisor = typeof divisor !== "undefined" ? divisor : 1000; var decimals = 2; @@ -3029,6 +3066,11 @@ function number_format(number, force_integer, unit, short_data, divisor) { number = 0; } + if (typeof params !== "undefined") { + if (typeof params.twoLines !== "undefined" && params.twoLines === true); + return number + "
" + shorts[pos] + unit; + } + return number + " " + shorts[pos] + unit; } diff --git a/pandora_console/include/graphs/functions_flot.php b/pandora_console/include/graphs/functions_flot.php index 6b64cae989..84fafbb1ea 100644 --- a/pandora_console/include/graphs/functions_flot.php +++ b/pandora_console/include/graphs/functions_flot.php @@ -262,8 +262,14 @@ function flot_area_graph( (empty($params['line_width']) === true) ? $config['custom_graph_width'] : $params['line_width'], true ); + + $timestamp_top_fixed = ''; + if (isset($params['timestamp_top_fixed']) === true && empty($params['timestamp_top_fixed']) === false) { + $timestamp_top_fixed = $params['timestamp_top_fixed']; + } + $return .= "
"; $legend_top = 10; diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css index 96dd1abc45..c9ae76fe8f 100644 --- a/pandora_console/include/styles/graph_analytics.css +++ b/pandora_console/include/styles/graph_analytics.css @@ -31,6 +31,17 @@ div.box-flat.white_table_graph > div[id^="tgl_div_"] > div.white-box-content { justify-content: flex-start; } +div.box-flat.white_table_graph + > div[id^="tgl_div_"] + > div.white-box-content + > [data-id-agent], +div.box-flat.white_table_graph + > div[id^="tgl_div_"] + > div.white-box-content + > [data-id-group] { + cursor: pointer; +} + div#menu_tab ul li, div#menu_tab ul li span { display: flex; @@ -158,7 +169,7 @@ div.graphs-div-main { /* Draggable */ .draggable.ui-draggable-dragging { - width: 100%; + width: 20%; } .draggable { @@ -166,15 +177,13 @@ div.graphs-div-main { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - width: 100px; - height: 20px; - background: #9efcab; -} -/* !Remove and set width 100% in .draggable */ -#droppable-graphs .draggable { - width: 20px; } +#droppable-graphs * { + cursor: default; +} + +/* Droppable */ .droppable { width: 100%; /* height: 20px; */ @@ -187,7 +196,10 @@ div.graphs-div-main { border: 2px dashed #0077ff; border-radius: 6px; width: 100%; - height: 20px; +} + +#droppable-graphs .droppable-zone > div { + opacity: 0.5; } #droppable-graphs .drops-hover { @@ -238,3 +250,72 @@ div.graphs-div-main { > span.drop-here { color: #82b92e; } + +#droppable-graphs .parent_graph { + padding-top: 40px; +} + +#droppable-graphs .timestamp_graph { + top: 15px; +} + +#droppable-graphs .menu_graph { + left: 85%; + display: flex; + flex-direction: column; + justify-content: center; +} + +div.timestamp-top-fixed { + top: 15px !important; +} + +div.graph-analytics-legend-main { + display: flex; +} + +div.graph-analytics-legend-square { + width: 30px; + height: 30px; + max-width: 30px; + margin-right: 5px; + padding-right: 3px; + display: flex; + flex-direction: column; + align-items: flex-end; + flex-wrap: nowrap; + justify-content: center; +} + +div.graph-analytics-legend-square > span { + text-align: right; + color: #fff; + line-height: 9pt; +} + +div.graph-analytics-legend-square > span.square-unit { + width: 30px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +div.graph-analytics-legend { + display: flex; + flex-direction: column; + flex-wrap: nowrap; +} + +div.graph-analytics-legend > span { + line-height: 12pt; +} + +div.graph-analytics-legend > span:last-child { + font-weight: normal; + font-size: 8pt; + margin-left: 5px; +} + +#droppable-graphs td.legendColorBox { + display: none; +} diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 7e68c92777..1b6751fa1a 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -34,12 +34,15 @@ check_login(); ui_require_css_file('graph_analytics'); require_once 'include/functions_custom_graphs.php'; -// Get parameters. -$x = get_parameter('x'); - // Ajax. if (is_ajax()) { $search_left = get_parameter('search_left'); + $search_right = get_parameter('search_right'); + $get_graphs = get_parameter('get_graphs'); + $save_filter = get_parameter('save_filter'); + $load_filter = get_parameter('load_filter'); + $update_filter = get_parameter('update_filter'); + $get_new_values = get_parameter('get_new_values'); if (empty($search_left) === false) { $output = []; @@ -114,13 +117,367 @@ if (is_ajax()) { return; } + if (empty($search_right) === false) { + $output = []; + $search = io_safe_input(get_parameter('free_search')); + $agent = get_parameter('search_agent'); + $group = get_parameter('search_group'); + + $search_sql = ' AND (tam.nombre LIKE "%%'.$search.'%%" OR tam.descripcion LIKE "%%'.$search.'%%")'; + + // Agent. + if (empty($agent) === false) { + $sql = sprintf( + 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion + FROM tagente_modulo tam + WHERE (tam.id_agente = %s) + %s + ORDER BY tam.nombre', + $agent, + $search_sql + ); + + $output['modules'] = db_get_all_rows_sql($sql); + } + + // Group. + if (empty($group) === false) { + $sql = sprintf( + 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion + FROM tagente_modulo tam + INNER JOIN tagente ta ON ta.id_agente = tam.id_agente + WHERE (ta.id_grupo = %s) + %s + ORDER BY tam.nombre', + $group, + $search_sql + ); + + $output['modules'] = db_get_all_rows_sql($sql); + } + + // Return. + echo json_encode($output); + return; + } + + // Graph. + if (empty($get_graphs) === false) { + $interval = (int) get_parameter('interval'); + $modules = $get_graphs; + + $params = [ + 'period' => $interval, + 'width' => '100%', + 'graph_width' => '85%', + 'height' => 100, + 'date' => time(), + 'percentil' => null, + 'fullscale' => 1, + 'type_graph' => 'line', + 'timestamp_top_fixed' => 'timestamp-top-fixed', + 'graph_analytics' => true, + 'realtime' => true, + ]; + + $params_combined = [ + 'stacked' => 2, + 'labels' => [], + 'modules_series' => $modules, + 'id_graph' => null, + 'return' => 1, + 'graph_analytics' => true, + ]; + + $graph_return = graphic_combined_module( + $modules, + $params, + $params_combined + ); + + $graph_return .= " + + "; + + echo $graph_return; + return; + } + + // Save filter. + if (empty($save_filter) === false) { + $graphs = get_parameter('graphs'); + $interval = (int) get_parameter('interval'); + + if (empty($save_filter) === true) { + echo __('Empty name'); + return; + } + + if (empty($graphs) === true) { + echo __('Empty graphs'); + return; + } + + $id_filter = db_process_sql_insert( + 'tgraph_analytics_filter', + [ + 'filter_name' => $save_filter, + 'user_id' => $config['id_user'], + 'graph_modules' => json_encode($graphs), + 'interval' => $interval, + ] + ); + + if ($id_filter > 0) { + echo 'saved'; + return; + } else { + echo __('Empty graphs'); + return; + } + } + + // Update filter. + if (empty($update_filter) === false) { + $graphs = get_parameter('graphs'); + $interval = (int) get_parameter('interval'); + + if (empty($graphs) === true) { + echo __('Empty graphs'); + return; + } + + $update_filter = db_process_sql_update( + 'tgraph_analytics_filter', + [ + 'graph_modules' => json_encode($graphs), + 'interval' => $interval, + ], + ['id' => $update_filter] + ); + + if ($update_filter > 0) { + echo 'updated'; + return; + } else { + echo __('No updated'); + return; + } + + echo $update_filter; + return; + } + + // Load filter. + if (empty($load_filter) === false) { + $data = []; + $data['graphs'] = json_decode(db_get_value('graph_modules', 'tgraph_analytics_filter', 'id', $load_filter)); + $data['interval'] = db_get_value('tgraph_analytics_filter.interval', 'tgraph_analytics_filter', 'id', $load_filter); + + echo json_encode($data); + return; + } + + // Get new values. + if (empty($get_new_values) === false) { + $data = []; + + $agent_module_id = $get_new_values; + $date_array = get_parameter('date_array'); + $data_module_graph = get_parameter('data_module_graph'); + $params = get_parameter('params'); + $suffix = get_parameter('suffix'); + + // Stract data. + $array_data_module = grafico_modulo_sparse_data( + $agent_module_id, + $date_array, + $data_module_graph, + $params, + $suffix + ); + + echo json_encode($array_data_module); + return; + } + return; } +// Save filter modal. +echo ''; + +// Load filter modal. +$filters = graph_analytics_filter_select(); + +echo ''; + // Header & Actions. $title_tab = __('Start realtime'); $tab_start_realtime = [ - 'text' => ''.html_print_image( + 'text' => ''.html_print_image( 'images/change-active.svg', true, [ @@ -130,9 +487,21 @@ $tab_start_realtime = [ ).$title_tab.'', ]; +$title_tab = __('Pause realtime'); +$tab_pause_realtime = [ + 'text' => ''.html_print_image( + 'images/change-pause.svg', + true, + [ + 'title' => $title_tab, + 'class' => 'invert_filter main_menu_icon', + ] + ).$title_tab.'', +]; + $title_tab = __('New'); $tab_new = [ - 'text' => ''.html_print_image( + 'text' => ''.html_print_image( 'images/plus-black.svg', true, [ @@ -144,7 +513,7 @@ $tab_new = [ $title_tab = __('Save'); $tab_save = [ - 'text' => ''.html_print_image( + 'text' => ''.html_print_image( 'images/save_mc.png', true, [ @@ -156,7 +525,7 @@ $tab_save = [ $title_tab = __('Load'); $tab_load = [ - 'text' => ''.html_print_image( + 'text' => ''.html_print_image( 'images/logs@svg.svg', true, [ @@ -168,7 +537,7 @@ $tab_load = [ $title_tab = __('Share'); $tab_share = [ - 'text' => ''.html_print_image( + 'text' => ''.html_print_image( 'images/responses.svg', true, [ @@ -180,7 +549,7 @@ $tab_share = [ $title_tab = __('Export to custom graph'); $tab_export = [ - 'text' => ''.html_print_image( + 'text' => ''.html_print_image( 'images/module-graph.svg', true, [ @@ -202,6 +571,7 @@ ui_print_standard_header( $tab_load, $tab_save, $tab_new, + $tab_pause_realtime, $tab_start_realtime, ], [ @@ -212,22 +582,10 @@ ui_print_standard_header( ] ); -// Header options. -// $options_content = 'Sample text'; -// html_print_div( -// [ -// 'class' => 'options-graph-analytics', -// 'content' => $options_content, -// ] -// ); // Content. $left_content = ''; $right_content = ''; -// $left_content .= ''; -//
-//
-//
$left_content .= '
@@ -306,7 +664,10 @@ $left_content .= ' ).'
- + + + +
'; @@ -364,217 +725,38 @@ html_print_div( ); -// Realtime graph. -$table = new stdClass(); -$table->width = '100%'; -$table->id = 'table-form'; -$table->class = 'filter-table-adv'; -$table->style = []; -$table->data = []; - -$graph_fields['cpu_load'] = __('%s Server CPU', get_product_name()); -$graph_fields['pending_packets'] = __( - 'Pending packages from %s Server', - get_product_name() -); -$graph_fields['disk_io_wait'] = __( - '%s Server Disk IO Wait', - get_product_name() -); -$graph_fields['apache_load'] = __( - '%s Server Apache load', - get_product_name() -); -$graph_fields['mysql_load'] = __( - '%s Server MySQL load', - get_product_name() -); -$graph_fields['server_load'] = __( - '%s Server load', - get_product_name() -); -$graph_fields['snmp_interface'] = __('SNMP Interface throughput'); - -$graph = get_parameter('graph', 'cpu_load'); -$refresh = get_parameter('refresh', '1000'); - -if ($graph != 'snmp_module') { - $data['graph'] = html_print_label_input_block( - __('Graph'), - html_print_select( - $graph_fields, - 'graph', - $graph, - '', - '', - 0, - true, - false, - true, - '', - false, - 'width: 100%' - ) - ); -} - -$refresh_fields[1000] = human_time_description_raw(1, true, 'large'); -$refresh_fields[5000] = human_time_description_raw(5, true, 'large'); -$refresh_fields[10000] = human_time_description_raw(10, true, 'large'); -$refresh_fields[30000] = human_time_description_raw(30, true, 'large'); - -if ($graph == 'snmp_module') { - $agent_alias = io_safe_output(get_parameter('agent_alias', '')); - $module_name = io_safe_output(get_parameter('module_name', '')); - $module_incremental = get_parameter('incremental', 0); - $data['module_info'] = html_print_label_input_block( - $agent_alias.': '.$module_name, - html_print_input_hidden( - 'incremental', - $module_incremental, - true - ).html_print_select( - ['snmp_module' => '-'], - 'graph', - 'snmp_module', - '', - '', - 0, - true, - false, - true, - '', - false, - 'width: 100%; display: none;' - ) - ); -} - -$data['refresh'] = html_print_label_input_block( - __('Refresh interval'), - html_print_select( - $refresh_fields, - 'refresh', - $refresh, - '', - '', - 0, - true, - false, - true, - '', - false, - 'width: 100%' - ) -); - -if ($graph != 'snmp_module') { - $data['incremental'] = html_print_label_input_block( - __('Incremental'), - html_print_checkbox_switch('incremental', 1, 0, true) - ); -} - -$table->data[] = $data; - -// Print the relative path to AJAX calls. -html_print_input_hidden('rel_path', get_parameter('rel_path', '')); - -// Print the form. -$searchForm = '
'; -$searchForm .= html_print_table($table, true); -$searchForm .= html_print_div( - [ - 'class' => 'action-buttons', - 'content' => html_print_submit_button( - __('Clear graph'), - 'srcbutton', - false, - [ - 'icon' => 'delete', - 'mode' => 'mini', - 'onClick' => 'javascript:realtimeGraphs.clearGraph();', - ], - true - ), - ], - true -); -$searchForm .= '
'; - -// echo $searchForm; -echo ' - - -'; - -// Canvas realtime graph. -$canvas = '
'; -$canvas .= '
'; - -$width = 800; -$height = 300; - -$data_array['realtime']['data'][0][0] = (time() - 10); -$data_array['realtime']['data'][0][1] = 0; -$data_array['realtime']['data'][1][0] = time(); -$data_array['realtime']['data'][1][1] = 0; -$data_array['realtime']['color'] = 'green'; - -$params = [ - 'agent_module_id' => false, - 'period' => 300, - 'width' => $width, - 'height' => $height, - 'only_image' => false, - 'type_graph' => 'area', - 'font' => $config['fontpath'], - 'font-size' => $config['font_size'], - 'array_data_create' => $data_array, - 'show_legend' => false, - 'show_menu' => false, - 'backgroundColor' => 'transparent', -]; - -$canvas .= grafico_modulo_sparse($params); -$canvas .= '
'; -echo $canvas; - -html_print_input_hidden( - 'custom_action', - urlencode( - base64_encode( - ' ' - ) - ), - false -); -html_print_input_hidden('incremental_base', '0'); - -echo ''; -echo ''; - -if ($config['style'] !== 'pandora_black') { - echo ''; -} - -// Store servers timezone offset to be retrieved from js. -set_js_value('timezone_offset', date('Z', time())); - -extensions_add_operation_menu_option( - __('Realtime graphs'), - 'estado', - null, - 'v1r1', - 'view' -); -extensions_add_main_function('pandora_realtime_graphs'); ?> \ No newline at end of file diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index 0056868752..0d7fa28a71 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -4408,3 +4408,15 @@ CREATE TABLE IF NOT EXISTS `tnetwork_explorer_filter` ( `advanced_filter` TEXT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; + +-- --------------------------------------------------------------------- +-- Table `tgraph_analytics_filter` +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tgraph_analytics_filter` ( +`id` INT NOT NULL auto_increment, +`filter_name` VARCHAR(45) NULL, +`user_id` VARCHAR(255) NULL, +`graph_modules` TEXT NULL, +`interval` INT NULL, +PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; \ No newline at end of file From bfa09367d4bbebfea1bc8abbe2c964ddb619a6a9 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Tue, 22 Aug 2023 15:28:05 +0200 Subject: [PATCH 06/10] 11423-Graph analytics. Share function --- pandora_console/include/constants.php | 1 + .../include/javascript/graph_analytics.js | 619 ++++++++++++++++++ .../include/styles/graph_analytics.css | 5 + .../operation/reporting/graph_analytics.php | 618 +++++------------ .../reporting/graph_analytics_public.php | 191 ++++++ 5 files changed, 965 insertions(+), 469 deletions(-) create mode 100644 pandora_console/include/javascript/graph_analytics.js create mode 100644 pandora_console/operation/reporting/graph_analytics_public.php diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index e8d4eb3a4f..889e32f693 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -807,6 +807,7 @@ define('AUDIT_LOG_FILE_MANAGER', 'File manager'); define('AUDIT_LOG_ALERT_MANAGEMENT', 'Alert management'); define('AUDIT_LOG_ALERT_CORRELATION_MANAGEMENT', 'Alert correlation management'); define('AUDIT_LOG_VISUAL_CONSOLE_MANAGEMENT', 'Visual Console Management'); +define('AUDIT_LOG_GRAPH_ANALYTICS_PUBLIC', 'Graph Analytics Public'); define('AUDIT_LOG_TAG_MANAGEMENT', 'Tag management'); define('AUDIT_LOG_SNMP_MANAGEMENT', 'SNMP management'); define('AUDIT_LOG_DASHBOARD_MANAGEMENT', 'Dashboard management'); diff --git a/pandora_console/include/javascript/graph_analytics.js b/pandora_console/include/javascript/graph_analytics.js new file mode 100644 index 0000000000..6afd0d9d38 --- /dev/null +++ b/pandora_console/include/javascript/graph_analytics.js @@ -0,0 +1,619 @@ +// Droppable options. +var droppableOptions = { + accept: ".draggable", + hoverClass: "drops-hover", + activeClass: "droppable-zone", + drop: function(event, ui) { + // Add new module. + $(this) + .data("modules") + .push(ui.draggable.data("id-module")); + + // Create elements. + createDroppableZones(droppableOptions, getModulesByGraphs()); + } +}; + +// Doc ready. +$(document).ready(function() { + // Hide toggles. + $("#agents-toggle").hide(); + $("#groups-toggle").hide(); + $("#modules-toggle").hide(); + $("[data-button=pause-realtime]") + .parent() + .hide(); + + // Set droppable zones. + $(".droppable").droppable(droppableOptions); +}); + +// Interval change. +$("#interval").change(function(e) { + createDroppableZones(droppableOptions, getModulesByGraphs()); +}); + +// Collapse filters. +$("div.filters-div-main > .filters-div-header > img").click(function(e) { + if ($(".filters-div-main").hasClass("filters-div-main-collapsed") === true) { + $(".filters-div-header > img").attr("src", "images/menu/contraer.svg"); + $(".filters-div-main").removeClass("filters-div-main-collapsed"); + } else { + $(".filters-div-header > img").attr("src", "images/menu/expandir.svg"); + $(".filters-div-main").addClass("filters-div-main-collapsed"); + } +}); + +// Search left. +$("#search-left").keyup(function(e) { + if ($(this).val() !== "") { + $.ajax({ + method: "POST", + url: "ajax.php", + dataType: "json", + data: { + page: "operation/reporting/graph_analytics", + search_left: e.target.value + }, + success: function(data) { + if (data.agents || data.groups || data.modules) { + var agentsToggle = $( + "#agents-toggle > div[id^=tgl_div_] > div.white-box-content" + ); + var groupsToggle = $( + "#groups-toggle > div[id^=tgl_div_] > div.white-box-content" + ); + var modulesToggle = $( + "#modules-toggle > div[id^=tgl_div_] > div.white-box-content" + ); + agentsToggle.empty(); + groupsToggle.empty(); + modulesToggle.empty(); + + if (data.agents) { + $("#agents-toggle").show(); + data.agents.forEach(agent => { + agentsToggle.append( + `
${agent.alias}
` + ); + }); + } else { + $("#agents-toggle").hide(); + } + + if (data.groups) { + $("#groups-toggle").show(); + data.groups.forEach(group => { + groupsToggle.append( + `
${group.nombre}
` + ); + }); + } else { + $("#groups-toggle").hide(); + } + + if (data.modules) { + $("#modules-toggle").show(); + data.modules.forEach(module => { + modulesToggle.append( + `
${module.nombre}
` + ); + }); + } else { + $("#modules-toggle").hide(); + } + + // Create draggable elements. + $(".draggable").draggable({ + revert: "invalid", + stack: ".draggable", + helper: "clone" + }); + } else { + console.error("NO DATA FOUND"); + } + } + }); + } +}); + +function clickAgent(e) { + $("#search-agent").val($(e).data("id-agent")); + $("#search-group").val(""); + searchRight($("#search-right").val()); +} + +function clickGroup(e) { + $("#search-group").val($(e).data("id-group")); + $("#search-agent").val(""); + searchRight($("#search-right").val()); +} + +// Search right. +$("#search-right").keyup(function(e) { + if ($("#search-right") !== "") { + searchRight(e.target.value); + } +}); + +function searchRight(freeSearch) { + $.ajax({ + method: "POST", + url: "ajax.php", + dataType: "json", + data: { + page: "operation/reporting/graph_analytics", + search_right: true, + free_search: freeSearch, + search_agent: $("#search-agent").val(), + search_group: $("#search-group").val() + }, + success: function(data) { + var modulesRight = $("#modules-right"); + + if (data.modules) { + modulesRight.empty(); + + data.modules.forEach(module => { + modulesRight.append( + `
${module.nombre}
` + ); + }); + + // Create draggable elements. + $(".draggable").draggable({ + revert: "invalid", + stack: ".draggable", + helper: "clone" + }); + } else { + modulesRight.empty(); + console.error("NO DATA FOUND"); + } + } + }); +} + +function createDroppableZones( + droppableOptions, + modulesByGraphs, + homeurl = "", + getInterval = 0 +) { + var url = "ajax.php"; + var interval = $("#interval").val(); + + if (homeurl !== "") { + url = homeurl + "/ajax.php"; + } + + if (getInterval !== 0) { + interval = getInterval; + } + + // Clear graph area. + $("#droppable-graphs").empty(); + + // Reset realtime data. + realtimeGraphs = []; + + // Graph modules. + modulesByGraphs + .slice() + .reverse() + .forEach(graph => { + // Max modules by graph. + var droppableClass = ""; + if (graph.length < 2) { + droppableClass = "droppable"; + } + + // Create graph div. + var graphDiv = $( + `
` + ); + $("#droppable-graphs").prepend(graphDiv); + + // Print graphs. + $.ajax({ + method: "POST", + url, + dataType: "html", + data: { + page: "operation/reporting/graph_analytics", + get_graphs: graph, + interval + }, + success: function(data) { + if (data) { + graphDiv.append( + $( + `
${data}
` + ) + ); + } + } + }); + + // Create next droppable zone. + graphDiv.after( + $( + `
${dropHere}
` + ) + ); + }); + + // Create first droppable zones and graphs. + $("#droppable-graphs").prepend( + $( + `
${dropHere}
` + ) + ); + + // Set droppable zones. + $(".droppable").droppable(droppableOptions); + + // todo: Create draggable graphs. +} + +function getModulesByGraphs() { + var modulesByGraphs = []; + $("#droppable-graphs > div").each(function(i, v) { + var modulesTmp = $(v).data("modules"); + if (modulesTmp.length > 0) { + modulesByGraphs.push(modulesTmp); + } + }); + + return modulesByGraphs; +} + +function realtimeGraph() { + realtimeGraphsTmp = realtimeGraphs; + realtimeGraphs = []; + + realtimeGraphsTmp.forEach(graph => { + $.each(graph.series_type, function(i, v) { + // Get new values. + $.ajax({ + method: "POST", + url: "ajax.php", + dataType: "json", + data: { + page: "operation/reporting/graph_analytics", + get_new_values: graph.values[i].agent_module_id, + date_array: graph.date_array, + data_module_graph: graph.data_module_graph, + params: graph.params, + suffix: i.slice(-1) + }, + success: function(data) { + if (data) { + // Set new values + graph.values[i].data = data[i].data; + } + } + }); + }); + + // New periods. + var period = $("#interval").val(); + var time = Math.floor(Date.now() / 1000); + + graph.params.date = time; + + var date_array = { + period, + final_date: time, + start_date: time - period + }; + + pandoraFlotArea( + graph.graph_id, + graph.values, + graph.legend, + graph.series_type, + graph.color, + date_array, + graph.data_module_graph, + graph.params, + graph.events_array + ); + }); +} + +// Action buttons. +// Start/Pause Realtime. +var realtimeGraphInterval; +$("[data-button=pause-realtime]") + .parent() + .hide(); + +$("[data-button=start-realtime]").click(function(e) { + $("[data-button=start-realtime]") + .parent() + .hide(); + $("[data-button=pause-realtime]") + .parent() + .show(); + + realtimeGraphInterval = setInterval(realtimeGraph, 5000); +}); + +$("[data-button=pause-realtime]").click(function(e) { + $("[data-button=pause-realtime]") + .parent() + .hide(); + $("[data-button=start-realtime]") + .parent() + .show(); + + clearInterval(realtimeGraphInterval); +}); + +// New graph. +$("[data-button=new]").click(function(e) { + confirmDialog({ + title: titleNew, + message: messageNew, + onAccept: function() { + $("#droppable-graphs").empty(); + + // Create graph div. + $("#droppable-graphs").prepend( + $( + `
${dropHere}
` + ) + ); + $(".droppable").droppable(droppableOptions); + + // Reset realtime button. + $("[data-button=pause-realtime]") + .parent() + .hide(); + $("[data-button=start-realtime]") + .parent() + .show(); + } + }); +}); + +// Save graps modal. +$("[data-button=save]").click(function(e) { + // Filter save mode selector + $("#save_filter_row1").show(); + $("#save_filter_row2").show(); + $("#update_filter_row1").hide(); + $("#radiobtn0002").prop("checked", false); + $("#radiobtn0001").prop("checked", true); + $("#text-id_name").val(""); + + $("[name='filter_mode']").click(function() { + if ($(this).val() == "new") { + $("#save_filter_row1").show(); + $("#save_filter_row2").show(); + $("#submit-save_filter").show(); + $("#update_filter_row1").hide(); + } else { + $("#save_filter_row1").hide(); + $("#save_filter_row2").hide(); + $("#update_filter_row1").show(); + $("#submit-save_filter").hide(); + } + }); + + $("#save-filter-select").dialog({ + resizable: true, + draggable: true, + modal: false, + closeOnEscape: true, + width: 350 + }); +}); + +// Save filter button. +function save_new_filter() { + $.ajax({ + method: "POST", + url: "ajax.php", + dataType: "html", + data: { + page: "operation/reporting/graph_analytics", + save_filter: $("#text-id_name").val(), + graphs: getModulesByGraphs(), + interval: $("#interval").val() + }, + success: function(data) { + if (data == "saved") { + confirmDialog({ + title: titleSave, + message: messageSave, + hideCancelButton: true, + onAccept: function() { + $( + "button.ui-button.ui-corner-all.ui-widget.ui-button-icon-only.ui-dialog-titlebar-close" + ).click(); + } + }); + } else { + var message = messageSaveEmpty; + if (data === "") { + message = messageSaveEmptyName; + } + confirmDialog({ + title: titleError, + message, + hideCancelButton: true + }); + } + } + }); +} + +// Update filter button. +function save_update_filter() { + confirmDialog({ + title: titleUpdate, + message: messageUpdate, + onAccept: function() { + $.ajax({ + method: "POST", + url: "ajax.php", + dataType: "html", + data: { + page: "operation/reporting/graph_analytics", + update_filter: $("#overwrite_filter").val(), + graphs: getModulesByGraphs(), + interval: $("#interval").val() + }, + success: function(data) { + if (data == "updated") { + confirmDialog({ + title: titleUpdateConfirm, + message: messageUpdateConfirm, + hideCancelButton: true, + onAccept: function() { + $( + "button.ui-button.ui-corner-all.ui-widget.ui-button-icon-only.ui-dialog-titlebar-close" + ).click(); + } + }); + } else { + confirmDialog({ + title: titleUpdateError, + message: messageUpdateError, + hideCancelButton: true + }); + } + } + }); + } + }); +} + +// Load graps modal. +$("[data-button=load]").click(function(e) { + $("#load-filter-select").dialog({ + resizable: true, + draggable: true, + modal: false, + closeOnEscape: true, + width: "auto" + }); +}); + +// Load filter button. +function load_filter_values(id = 0, homeurl) { + var url = "ajax.php"; + var filterId = $("#filter_id").val(); + + if (id !== 0) { + filterId = id; + url = homeurl + "/ajax.php"; + } + + if (id === 0) { + confirmDialog({ + title: titleLoad, + message: messageLoad, + onAccept: function() { + loadFilter(url, filterId, homeurl, id); + } + }); + } else { + loadFilter(url, filterId, homeurl, id); + } +} + +function loadFilter(url, filterId, homeurl, id) { + $.ajax({ + method: "POST", + url, + dataType: "json", + data: { + page: "operation/reporting/graph_analytics", + load_filter: filterId + }, + success: function(data) { + if (data) { + createDroppableZones( + droppableOptions, + data.graphs, + homeurl, + data.interval + ); + if (id === 0) { + $("#interval") + .val(data.interval) + .trigger("change"); + } + + $( + "button.ui-button.ui-corner-all.ui-widget.ui-button-icon-only.ui-dialog-titlebar-close" + ).click(); + + // Reset realtime button. + if (id === 0) { + $("[data-button=pause-realtime]") + .parent() + .hide(); + $("[data-button=start-realtime]") + .parent() + .show(); + } + } else { + confirmDialog({ + title: titleLoadConfirm, + message: messageLoadConfirm, + hideCancelButton: true + }); + } + } + }); +} + +// Share button. +$("[data-button=share]").click(function(e) { + $("#share-select").dialog({ + resizable: true, + draggable: true, + modal: false, + closeOnEscape: true, + width: "auto" + }); +}); + +$("#button-share-modal").click(function(e) { + const hash = $("#hash_share").val(); + const idFilter = btoa($("#share-id").val()); + const idUser = $("#id_user").val(); + + const queryParams = "hash=" + hash + "&id=" + idFilter + "&id_user=" + idUser; + + window.open( + configHomeurl + + "/operation/reporting/graph_analytics_public.php?" + + queryParams + ); +}); + +// Export button. +$("[data-button=export]").click(function(e) { + $("#export-select").dialog({ + resizable: true, + draggable: true, + modal: false, + closeOnEscape: true, + width: "auto", + title: titleExport + }); +}); + +$("#button-export-modal").click(function(e) { + const filter = parseInt($("#export-filter-id").val()); + const group = parseInt($("#export-group-id").val()); + + if (filter !== 0 && group !== 0) { + // todo: Ajax save in tgraph & tgraph_source. + } +}); diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css index c9ae76fe8f..a21c532ab7 100644 --- a/pandora_console/include/styles/graph_analytics.css +++ b/pandora_console/include/styles/graph_analytics.css @@ -68,6 +68,10 @@ div.main-div { min-height: calc(100vh - 160px); } +div.main-div.graph-analytics-public { + min-height: calc(100vh - 2px); +} + div.padding-div { margin: 0; padding: 10px; @@ -88,6 +92,7 @@ div.filters-div-main { div.filters-div-main.filters-div-main-collapsed { width: 35px; min-width: 20px; + border-right: 0px; } div.filters-div-main.filters-div-main-collapsed diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 1b6751fa1a..5ce6d97bdf 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -28,8 +28,11 @@ // Begin. global $config; + check_login(); +use PandoraFMS\User; + // Requires. ui_require_css_file('graph_analytics'); require_once 'include/functions_custom_graphs.php'; @@ -474,6 +477,126 @@ $table->rowclass[] = ''; html_print_table($table); echo '
'; +// Share modal. +echo ''; + +// Export graphs. +echo ''; + + // Header & Actions. $title_tab = __('Start realtime'); $tab_start_realtime = [ @@ -535,6 +658,9 @@ $tab_load = [ ).$title_tab.'', ]; +// Hash for auto-auth in public link. +$hash = User::generatePublicHash(); + $title_tab = __('Share'); $tab_share = [ 'text' => ''.html_print_image( @@ -544,7 +670,8 @@ $tab_share = [ 'title' => $title_tab, 'class' => 'invert_filter main_menu_icon', ] - ).$title_tab.'', + ).$title_tab.' + ', ]; $title_tab = __('Export to custom graph'); @@ -698,9 +825,7 @@ $right_content .= '
'.__('Drop here').'
'; -//
-//
-//
+ $filters_div = html_print_div( [ 'class' => 'filters-div-main', @@ -724,482 +849,37 @@ html_print_div( ] ); - +ui_require_javascript_file('graph_analytics', 'include/javascript/', true); ?> \ No newline at end of file diff --git a/pandora_console/operation/reporting/graph_analytics_public.php b/pandora_console/operation/reporting/graph_analytics_public.php new file mode 100644 index 0000000000..434bb89809 --- /dev/null +++ b/pandora_console/operation/reporting/graph_analytics_public.php @@ -0,0 +1,191 @@ + + + + + + + '.get_product_name().$text_subtitle.' +'; + +// CSS. +ui_require_css_file('common', 'include/styles/', true); +ui_require_css_file('pandora', 'include/styles/', true); +ui_require_css_file('discovery', 'include/styles/', true); +ui_require_css_file('register', 'include/styles/', true); +ui_require_css_file('order_interpreter', 'include/styles/', true); +ui_require_css_file('graph_analytics', 'include/styles/', true); +ui_require_css_file('jquery-ui.min', 'include/styles/js/', true); +ui_require_css_file('jquery-ui_custom', 'include/styles/js/', true); +ui_require_css_file('introjs', 'include/styles/js/', true); +ui_require_css_file('events', 'include/styles/', true); + +// JS. +ui_require_javascript_file('jquery.current', 'include/javascript/', true); +ui_require_javascript_file('jquery.pandora', 'include/javascript/', true); +ui_require_javascript_file('jquery-ui.min', 'include/javascript/', true); +ui_require_javascript_file('jquery.countdown', 'include/javascript/', true); +ui_require_javascript_file('pandora', 'include/javascript/', true); +ui_require_javascript_file('pandora_ui', 'include/javascript/', true); +ui_require_javascript_file('pandora_events', 'include/javascript/', true); +ui_require_javascript_file('select2.min', 'include/javascript/', true); +// ui_require_javascript_file('connection_check', 'include/javascript/', true); +ui_require_javascript_file('encode_decode_base64', 'include/javascript/', true); +ui_require_javascript_file('qrcode', 'include/javascript/', true); +ui_require_javascript_file('intro', 'include/javascript/', true); +ui_require_javascript_file('clippy', 'include/javascript/', true); +ui_require_javascript_file('underscore-min', 'include/javascript/', true); + +echo ' + +'; + + + +ui_require_javascript_file('date', 'include/javascript/timezone/src/', true); +ui_require_javascript_file('jquery.flot.min', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.time', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.pie', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.crosshair.min', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.stack.min', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.selection.min', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.resize.min', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.threshold', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.threshold.multiple', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.symbol.min', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.exportdata.pandora', 'include/graphs/flot/', true); +ui_require_javascript_file('jquery.flot.axislabels', 'include/graphs/flot/', true); +ui_require_javascript_file('pandora.flot', 'include/graphs/flot/', true); +ui_require_javascript_file('chart', 'include/graphs/chartjs/', true); +ui_require_javascript_file('chartjs-plugin-datalabels.min', 'include/graphs/chartjs/', true); + + + +ui_require_javascript_file('graph_analytics', 'include/javascript/', true); + + +echo ' + + +'; + +// Content. +$right_content = ''; + +$right_content .= ' +
+
'.__('Drop here').'
+
+'; + +$graphs_div = html_print_div( + [ + 'class' => 'padding-div graphs-div-main', + 'content' => $right_content, + ], + true +); + +html_print_div( + [ + 'class' => 'white_box main-div graph-analytics-public', + 'content' => $graphs_div, + ] +); + +?> + + + + + \ No newline at end of file From c0933e8b15cad4a089657a1cc05311141a493448 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Wed, 23 Aug 2023 11:51:29 +0200 Subject: [PATCH 07/10] 11423-Graph analytics --- pandora_console/images/draggable.svg | 10 +++ .../include/javascript/graph_analytics.js | 43 ++++++++++- .../include/styles/graph_analytics.css | 75 +++++++++++++------ .../operation/reporting/graph_analytics.php | 68 +++++++++++++++-- 4 files changed, 164 insertions(+), 32 deletions(-) create mode 100644 pandora_console/images/draggable.svg diff --git a/pandora_console/images/draggable.svg b/pandora_console/images/draggable.svg new file mode 100644 index 0000000000..3889fef861 --- /dev/null +++ b/pandora_console/images/draggable.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pandora_console/include/javascript/graph_analytics.js b/pandora_console/include/javascript/graph_analytics.js index 6afd0d9d38..77cdab85d7 100644 --- a/pandora_console/include/javascript/graph_analytics.js +++ b/pandora_console/include/javascript/graph_analytics.js @@ -38,9 +38,11 @@ $("div.filters-div-main > .filters-div-header > img").click(function(e) { if ($(".filters-div-main").hasClass("filters-div-main-collapsed") === true) { $(".filters-div-header > img").attr("src", "images/menu/contraer.svg"); $(".filters-div-main").removeClass("filters-div-main-collapsed"); + $("#droppable-graphs").removeClass("droppable-graphs-collapsed"); } else { $(".filters-div-header > img").attr("src", "images/menu/expandir.svg"); $(".filters-div-main").addClass("filters-div-main-collapsed"); + $("#droppable-graphs").addClass("droppable-graphs-collapsed"); } }); @@ -96,7 +98,13 @@ $("#search-left").keyup(function(e) { $("#modules-toggle").show(); data.modules.forEach(module => { modulesToggle.append( - `
${module.nombre}
` + `
+ +
+ ${module.nombre} + ${module.alias} +
+
` ); }); } else { @@ -156,7 +164,13 @@ function searchRight(freeSearch) { data.modules.forEach(module => { modulesRight.append( - `
${module.nombre}
` + `
+ +
+ ${module.nombre} + ${module.alias} +
+
` ); }); @@ -614,6 +628,29 @@ $("#button-export-modal").click(function(e) { const group = parseInt($("#export-group-id").val()); if (filter !== 0 && group !== 0) { - // todo: Ajax save in tgraph & tgraph_source. + $.ajax({ + method: "POST", + url: "ajax.php", + dataType: "html", + data: { + page: "operation/reporting/graph_analytics", + export_filter: filter, + group + }, + success: function(data) { + if (data) { + confirmDialog({ + title: titleExportConfirm, + message: data + " " + messageExportConfirm, + hideCancelButton: true, + onAccept: function() { + $( + "button.ui-button.ui-corner-all.ui-widget.ui-button-icon-only.ui-dialog-titlebar-close" + ).click(); + } + }); + } + } + }); } }); diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css index a21c532ab7..2499a0620e 100644 --- a/pandora_console/include/styles/graph_analytics.css +++ b/pandora_console/include/styles/graph_analytics.css @@ -1,19 +1,3 @@ -/* .options-graph-analytics { - position: sticky; - top: 110px; - width: -webkit-fill-available; - width: -moz-available; - height: 18px; - margin: -25px -25px 25px -25px; - padding: 10px 20px; - z-index: 1; - font-weight: bold; - display: flex; - min-width: fit-content; - background-color: var(--secondary-color); - border: 1px solid #e5e9ed; -} */ - div#main { margin-bottom: 0; } @@ -21,6 +5,7 @@ div#main { div.box-flat.white_table_graph > div[id^="tgl_div_"] { border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; + width: 228px; } div.box-flat.white_table_graph > div[id^="tgl_div_"] > div.white-box-content { @@ -85,7 +70,8 @@ div.margin-div { div.filters-div-main { padding: 0; margin: 0; - min-width: 400px; + width: 500px; + min-width: 500px; border-right: 1px solid var(--border-dark-color); } @@ -100,6 +86,10 @@ div.filters-div-main.filters-div-main-collapsed display: none; } +.droppable-graphs-collapsed { + margin-left: -30px; +} + div.filters-div-main > .filters-div-header { display: flex; flex-direction: row; @@ -126,7 +116,9 @@ div.filter-div { display: flex; flex-direction: column; flex-wrap: nowrap; - width: 50%; + width: 230px; + min-width: 230px; + max-width: 230px; height: 100%; padding: 10px; border-top: 1px solid var(--border-dark-color); @@ -136,7 +128,10 @@ div.filter-div { border-right: 1px solid var(--border-dark-color); } -.filters-right-div { +div.filters-right-div { + width: 230px; + min-width: 230px; + max-width: 230px; } .search-graph-analytics { @@ -184,11 +179,47 @@ div.graphs-div-main { text-overflow: ellipsis; } +.draggable-container { + display: flex; + flex-direction: row; + align-items: center; + margin-left: -10px; + padding-top: 3px; + padding-bottom: 3px; + border-bottom: 1px solid #f0f0f0; +} + +.draggable-container:last-child { + border-bottom: 0px; +} + +.draggable-module { + display: flex; + flex-direction: column; + flex-wrap: nowrap; +} + +.draggable-icon { + height: 25px; +} + +.draggable-module > span { + line-height: 10pt; +} + +.draggable-module > span.draggable-module-name { + font-weight: bold; +} + +.draggable-module > span.draggable-agent-name { + color: #8a96a6; +} + +/* Droppable */ #droppable-graphs * { cursor: default; } -/* Droppable */ .droppable { width: 100%; /* height: 20px; */ @@ -307,7 +338,7 @@ div.graph-analytics-legend-square > span.square-unit { div.graph-analytics-legend { display: flex; - flex-direction: column; + flex-direction: column-reverse; flex-wrap: nowrap; } @@ -315,7 +346,7 @@ div.graph-analytics-legend > span { line-height: 12pt; } -div.graph-analytics-legend > span:last-child { +div.graph-analytics-legend > span:first-child { font-weight: normal; font-size: 8pt; margin-left: 5px; diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 5ce6d97bdf..b3549defe2 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -46,6 +46,7 @@ if (is_ajax()) { $load_filter = get_parameter('load_filter'); $update_filter = get_parameter('update_filter'); $get_new_values = get_parameter('get_new_values'); + $export_filter = get_parameter('export_filter'); if (empty($search_left) === false) { $output = []; @@ -101,14 +102,15 @@ if (is_ajax()) { } $id_agents = implode(',', $result_agents); - $search_sql = ' AND (nombre LIKE "%%'.$search.'%%" OR descripcion LIKE "%%'.$search.'%%")'; + $search_sql = ' AND (tam.nombre LIKE "%%'.$search.'%%" OR tam.descripcion LIKE "%%'.$search.'%%")'; $sql = sprintf( - 'SELECT id_agente_modulo, nombre, descripcion - FROM tagente_modulo - WHERE (id_agente IN (%s)) + 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion, ta.alias + FROM tagente_modulo tam + INNER JOIN tagente ta ON ta.id_agente = tam.id_agente + WHERE (tam.id_agente IN (%s)) %s - ORDER BY nombre', + ORDER BY tam.nombre', $id_agents, $search_sql ); @@ -131,8 +133,9 @@ if (is_ajax()) { // Agent. if (empty($agent) === false) { $sql = sprintf( - 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion + 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion, ta.alias FROM tagente_modulo tam + INNER JOIN tagente ta ON ta.id_agente = tam.id_agente WHERE (tam.id_agente = %s) %s ORDER BY tam.nombre', @@ -146,7 +149,7 @@ if (is_ajax()) { // Group. if (empty($group) === false) { $sql = sprintf( - 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion + 'SELECT tam.id_agente_modulo, tam.nombre, tam.descripcion, ta.alias FROM tagente_modulo tam INNER JOIN tagente ta ON ta.id_agente = tam.id_agente WHERE (ta.id_grupo = %s) @@ -309,6 +312,54 @@ if (is_ajax()) { return; } + // Export graphs. + if (empty($export_filter) === false) { + $counter = 0; + $filter = get_parameter('export_filter'); + $group = get_parameter('group'); + + $filter_name = db_get_value('filter_name', 'tgraph_analytics_filter', 'id', $filter); + $graphs = json_decode(db_get_value('graph_modules', 'tgraph_analytics_filter', 'id', $filter)); + $interval = db_get_value('tgraph_analytics_filter.interval', 'tgraph_analytics_filter', 'id', $filter); + + foreach ($graphs as $graph) { + $id_graph = db_process_sql_insert( + 'tgraph', + [ + 'id_user' => $config['id_user'], + 'id_group' => $group, + 'name' => $filter_name.' ('.__('Graph').' '.($counter + 1).')', + 'description' => __('Created from Graph analytics. Filter:').' '.$filter_name.'. '.__('Graph').' '.($counter + 1), + 'period' => $interval, + 'stacked' => 2, + ] + ); + + if ($id_graph > 0) { + $counter++; + $field_order = 1; + + foreach ($graph as $module) { + $id_graph_source = db_process_sql_insert( + 'tgraph_source', + [ + 'id_graph' => $id_graph, + 'id_server' => 0, + 'id_agent_module' => $module, + 'weight' => 1, + 'label' => '', + 'field_order' => $field_order, + ] + ); + + $field_order++; + } + } + } + + echo $counter; + } + return; } @@ -882,4 +933,7 @@ const titleLoadConfirm = ""; const messageLoadConfirm = ""; const titleExport = ""; + +const titleExportConfirm = ""; +const messageExportConfirm = ""; \ No newline at end of file From 670cf7d9a7f14d989289df1c8c219cb4c479d122 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Thu, 24 Aug 2023 12:27:06 +0200 Subject: [PATCH 08/10] 11423-Graph analytics. Remove graphs & several changes --- .../include/javascript/graph_analytics.js | 63 ++++++++++++++++++- .../include/styles/graph_analytics.css | 14 +++++ .../operation/reporting/graph_analytics.php | 13 ++-- 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/pandora_console/include/javascript/graph_analytics.js b/pandora_console/include/javascript/graph_analytics.js index 77cdab85d7..a6d52be7cc 100644 --- a/pandora_console/include/javascript/graph_analytics.js +++ b/pandora_console/include/javascript/graph_analytics.js @@ -118,10 +118,16 @@ $("#search-left").keyup(function(e) { helper: "clone" }); } else { - console.error("NO DATA FOUND"); + $("#agents-toggle").hide(); + $("#groups-toggle").hide(); + $("#modules-toggle").hide(); } } }); + } else { + $("#agents-toggle").hide(); + $("#groups-toggle").hide(); + $("#modules-toggle").hide(); } }); @@ -245,6 +251,32 @@ function createDroppableZones( `
${data}
` ) ); + + // Create remove button. + if ( + graphDiv + .children() + .children() + .hasClass("parent_graph") === true + ) { + graphDiv + .children() + .children() + .children(":first-child") + .prepend( + $( + '' + ) + ); + } else { + graphDiv + .children() + .append( + $( + '' + ) + ); + } } } }); @@ -266,8 +298,6 @@ function createDroppableZones( // Set droppable zones. $(".droppable").droppable(droppableOptions); - - // todo: Create draggable graphs. } function getModulesByGraphs() { @@ -654,3 +684,30 @@ $("#button-export-modal").click(function(e) { }); } }); + +// Remove graph. +function removeGraph(e) { + confirmDialog({ + title: titleRemoveConfirm, + message: messageRemoveConfirm, + onAccept: function() { + if ( + $(e) + .parent() + .hasClass("menu_graph") === true + ) { + $(e) + .parent() + .parent() + .parent() + .parent() + .remove(); + } else { + $(e) + .parent() + .parent() + .remove(); + } + } + }); +} diff --git a/pandora_console/include/styles/graph_analytics.css b/pandora_console/include/styles/graph_analytics.css index 2499a0620e..3fcb3080ae 100644 --- a/pandora_console/include/styles/graph_analytics.css +++ b/pandora_console/include/styles/graph_analytics.css @@ -287,6 +287,10 @@ div.graphs-div-main { color: #82b92e; } +#droppable-graphs .droppable .draggable.ui-draggable.ui-draggable-handle { + text-align: center; +} + #droppable-graphs .parent_graph { padding-top: 40px; } @@ -355,3 +359,13 @@ div.graph-analytics-legend > span:first-child { #droppable-graphs td.legendColorBox { display: none; } + +#droppable-graphs .remove-graph-analytics { + width: 20px; + opacity: 0; + cursor: pointer; +} + +#droppable-graphs > div:hover .remove-graph-analytics { + opacity: 1; +} diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index b3549defe2..5cd0299c5e 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -225,7 +225,7 @@ if (is_ajax()) { } if (empty($graphs) === true) { - echo __('Empty graphs'); + echo __('It is not possible to create the filter if you have not made any change'); return; } @@ -243,7 +243,7 @@ if (is_ajax()) { echo 'saved'; return; } else { - echo __('Empty graphs'); + echo __('It is not possible to create the filter if you have not made any change'); return; } } @@ -254,7 +254,7 @@ if (is_ajax()) { $interval = (int) get_parameter('interval'); if (empty($graphs) === true) { - echo __('Empty graphs'); + echo __('It is not possible to update the filter if you have not made any change'); return; } @@ -912,7 +912,7 @@ const messageNew = ""; const messageSave = ""; -const messageSaveEmpty = ""; +const messageSaveEmpty = ""; const messageSaveEmptyName = ""; const titleError = ""; @@ -924,7 +924,7 @@ const titleUpdateConfirm = ""; const messageUpdateConfirm = ""; const titleUpdateError = ""; -const messageUpdateError = ""; +const messageUpdateError = ""; const titleLoad = ""; const messageLoad = ""; @@ -936,4 +936,7 @@ const titleExport = ""; const titleExportConfirm = ""; const messageExportConfirm = ""; + +const titleRemoveConfirm = ""; +const messageRemoveConfirm = ""; \ No newline at end of file From 28316e25c3d90ef86dca962b1f14fbfe0a374016 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Fri, 25 Aug 2023 10:33:32 +0200 Subject: [PATCH 09/10] 11423-Graph analytics. Remove Group None from export filter --- pandora_console/include/javascript/graph_analytics.js | 2 +- pandora_console/operation/reporting/graph_analytics.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandora_console/include/javascript/graph_analytics.js b/pandora_console/include/javascript/graph_analytics.js index a6d52be7cc..e63540ae08 100644 --- a/pandora_console/include/javascript/graph_analytics.js +++ b/pandora_console/include/javascript/graph_analytics.js @@ -657,7 +657,7 @@ $("#button-export-modal").click(function(e) { const filter = parseInt($("#export-filter-id").val()); const group = parseInt($("#export-group-id").val()); - if (filter !== 0 && group !== 0) { + if (filter !== 0) { $.ajax({ method: "POST", url: "ajax.php", diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 5cd0299c5e..39162b1c72 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -617,7 +617,7 @@ $data[1] .= html_print_select( 'export-group-id', '', '', - __('None'), + '', 0, true, false, From d8668484811782e26c8116892b2ffbc0b4ca1138 Mon Sep 17 00:00:00 2001 From: Pablo Aragon Date: Fri, 25 Aug 2023 12:38:58 +0200 Subject: [PATCH 10/10] 11423-Graph analytics. Remove Filter None from export and share --- pandora_console/operation/reporting/graph_analytics.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandora_console/operation/reporting/graph_analytics.php b/pandora_console/operation/reporting/graph_analytics.php index 39162b1c72..9b2fa5347d 100644 --- a/pandora_console/operation/reporting/graph_analytics.php +++ b/pandora_console/operation/reporting/graph_analytics.php @@ -549,7 +549,7 @@ $data[0] .= html_print_select( 'share-id', '', '', - __('None'), + '', 0, true, false, @@ -600,7 +600,7 @@ $data[0] .= html_print_select( 'export-filter-id', '', '', - __('None'), + '', 0, true, false,