diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index 78449cac7d..b2136a6b38 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.773.3-231024 +Version: 7.0NG.773.3-231030 Architecture: all Priority: optional Section: admin diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index e2fb7b5786..b7d9a12761 100644 --- a/pandora_agents/unix/DEBIAN/make_deb_package.sh +++ b/pandora_agents/unix/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.773.3-231024" +pandora_version="7.0NG.773.3-231030" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index d35d45fd9d..5dff06e9c4 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -1031,7 +1031,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.773.3'; -use constant AGENT_BUILD => '231024'; +use constant AGENT_BUILD => '231030'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index 47241efe72..05e1abdda7 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -4,7 +4,7 @@ %global __os_install_post %{nil} %define name pandorafms_agent_linux %define version 7.0NG.773.3 -%define release 231024 +%define release 231030 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.redhat_bin.spec b/pandora_agents/unix/pandora_agent.redhat_bin.spec index 1d083c4790..3e3f3a4882 100644 --- a/pandora_agents/unix/pandora_agent.redhat_bin.spec +++ b/pandora_agents/unix/pandora_agent.redhat_bin.spec @@ -5,7 +5,7 @@ %define name pandorafms_agent_linux_bin %define source_name pandorafms_agent_linux %define version 7.0NG.773.3 -%define release 231024 +%define release 231030 Summary: Pandora FMS Linux agent, binary version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index 1f76bd9650..fe363dd7d4 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -4,7 +4,7 @@ %global __os_install_post %{nil} %define name pandorafms_agent_linux %define version 7.0NG.773.3 -%define release 231024 +%define release 231030 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index 0cbc4f92d3..35551e23df 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.773.3" -PI_BUILD="231024" +PI_BUILD="231030" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index 3dc24116ab..7961a3028d 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{231024} +{231030} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 57fc6ca3c3..1623d31492 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -30,7 +30,7 @@ using namespace Pandora; using namespace Pandora_Strutils; #define PATH_SIZE _MAX_PATH+1 -#define PANDORA_VERSION ("7.0NG.773.3 Build 231024") +#define PANDORA_VERSION ("7.0NG.773.3 Build 231030") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index 4f0d19d6be..67f7830d3b 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -11,7 +11,7 @@ BEGIN VALUE "LegalCopyright", "Pandora FMS" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.773.3(Build 231024))" + VALUE "ProductVersion", "(7.0NG.773.3(Build 231030))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 1f2b9abcf9..9594583b12 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.773.3-231024 +Version: 7.0NG.773.3-231030 Architecture: all Priority: optional Section: admin diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index 32ddad8f60..1701342a8b 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.773.3-231024" +pandora_version="7.0NG.773.3-231030" package_pear=0 package_pandora=1 diff --git a/pandora_console/extras/discovery/DiscoveryApplicationsMigrateCodes.ini b/pandora_console/extras/discovery/DiscoveryApplicationsMigrateCodes.ini index 2dc698cb74..6323aec140 100644 --- a/pandora_console/extras/discovery/DiscoveryApplicationsMigrateCodes.ini +++ b/pandora_console/extras/discovery/DiscoveryApplicationsMigrateCodes.ini @@ -1,4 +1,4 @@ -pandorafms.vmware=459175dce8ab811e874ce2e7216f0db4 +pandorafms.vmware=9959cc3e5cc6bfcfadd6d05b56d4a11b pandorafms.mysql=fadb4750d18285c0eca34f47c6aa3cfe pandorafms.mssql=1cc215409741d19080269ffba112810e pandorafms.oracle=2d9320a514d1e48a0b2804e1653c31c6 diff --git a/pandora_console/extras/mr/66.sql b/pandora_console/extras/mr/66.sql index 60423984e0..8925d79506 100644 --- a/pandora_console/extras/mr/66.sql +++ b/pandora_console/extras/mr/66.sql @@ -160,6 +160,9 @@ UPDATE tagente_modulo SET `tcp_send` = '2c' WHERE `tcp_send` = '2'; UPDATE tpolicy_modules SET `tcp_send` = '2c' WHERE `tcp_send` = '2'; UPDATE tnetwork_component SET `tcp_send` = '2c' WHERE `tcp_send` = '2'; +ALTER TABLE tagente_modulo ADD COLUMN `made_enabled` TINYINT UNSIGNED DEFAULT 0; +ALTER TABLE tpolicy_modules ADD COLUMN `made_enabled` TINYINT UNSIGNED DEFAULT 0; + ALTER TABLE talert_templates ADD COLUMN `time_window` ENUM ('thirty_days','this_month','seven_days','this_week','one_day','today'), ADD COLUMN `math_function` ENUM ('avg', 'min', 'max', 'sum'), @@ -359,7 +362,13 @@ SET @id_os = 9; INSERT INTO tmodule_inventory (`id_os`, `name`, `description`, `interpreter`, `data_format`, `code`, `block_mode`,`script_mode`) SELECT * FROM (SELECT @id_os id_os, @tmodule_name name, @tmodule_description description, '' interpreter, 'ID:STATUS' data_format, '' code, '0' block_mode, 2 script_mode) AS tmp WHERE NOT EXISTS (SELECT name, description FROM tmodule_inventory WHERE name = @tmodule_name and description = @tmodule_description and id_os = @id_os); +INSERT INTO tmodule_group (name) SELECT ('Security') WHERE NOT EXISTS (SELECT name FROM tmodule_group WHERE LOWER(name) = 'security'); + +ALTER TABLE tagente_modulo ADD COLUMN `last_compact` TIMESTAMP NOT NULL DEFAULT 0; UPDATE `tevent_alert` ea INNER JOIN `tevent_rule` er ON ea.id = er.id_event_alert SET disabled=1 WHERE er.log_agent IS NOT NULL OR er.log_content IS NOT NULL OR er.log_source IS NOT NULL; +ALTER TABLE `tnetwork_explorer_filter` +MODIFY COLUMN `id` INT NOT NULL AUTO_INCREMENT; + COMMIT; diff --git a/pandora_console/extras/mr/67.sql b/pandora_console/extras/mr/67.sql index aa44ceea56..d15e49cf38 100644 --- a/pandora_console/extras/mr/67.sql +++ b/pandora_console/extras/mr/67.sql @@ -1,7 +1,7 @@ START TRANSACTION; ALTER TABLE `tncm_queue` -ADD COLUMN `id_agent_data` INT NOT NULL DEFAULT 0 AFTER `id_script`; +ADD COLUMN `id_agent_data` bigint unsigned AFTER `id_script`, +ADD CONSTRAINT `fk_tncm_queue_tncm_agent_data` FOREIGN KEY (`id_agent_data`) REFERENCES `tncm_agent_data`(`id`) ON UPDATE CASCADE ON DELETE SET NULL; - -COMMIT; \ No newline at end of file +COMMIT; diff --git a/pandora_console/godmode/agentes/configurar_agente.php b/pandora_console/godmode/agentes/configurar_agente.php index b78b98f3c7..88d4b0e4ed 100644 --- a/pandora_console/godmode/agentes/configurar_agente.php +++ b/pandora_console/godmode/agentes/configurar_agente.php @@ -1326,6 +1326,12 @@ if ($update_module === true || $create_module === true) { */ $post_process = (string) get_parameter('post_process', 0.0); + if (modules_made_compatible($id_module_type) === true) { + $made_enabled = (bool) get_parameter_checkbox('made_enabled', 0); + } else { + $made_enabled = false; + } + $prediction_module = (int) get_parameter('prediction_module'); $max_timeout = (int) get_parameter('max_timeout'); $max_retries = (int) get_parameter('max_retries'); @@ -1348,6 +1354,14 @@ if ($update_module === true || $create_module === true) { } $configuration_data = (string) get_parameter('configuration_data'); + $array_configuration_data = explode(PHP_EOL, io_safe_output($configuration_data)); + $configuration_data = ''; + foreach ($array_configuration_data as $value) { + $configuration_data .= trim($value).PHP_EOL; + } + + $configuration_data = io_safe_input($configuration_data); + $old_configuration_data = (string) get_parameter('old_configuration_data'); $new_configuration_data = ''; @@ -1488,6 +1502,14 @@ if ($update_module === true || $create_module === true) { } $plugin_parameter = (string) get_parameter('plugin_parameter'); + + $array_plugin_parameter = explode(PHP_EOL, io_safe_output($plugin_parameter)); + $plugin_parameter = ''; + foreach ($array_plugin_parameter as $value) { + $plugin_parameter .= trim($value).PHP_EOL; + } + + $plugin_parameter = io_safe_input($plugin_parameter); } $parent_module_id = (int) get_parameter('parent_module_id'); @@ -1704,6 +1726,7 @@ if ($update_module) { 'plugin_parameter' => $plugin_parameter, 'id_plugin' => $id_plugin, 'post_process' => $post_process, + 'made_enabled' => $made_enabled, 'prediction_module' => $prediction_module, 'max_timeout' => $max_timeout, 'max_retries' => $max_retries, @@ -1902,6 +1925,7 @@ if ($create_module) { 'plugin_parameter' => $plugin_parameter, 'id_plugin' => $id_plugin, 'post_process' => $post_process, + 'made_enabled' => $made_enabled, 'prediction_module' => $prediction_module, 'max_timeout' => $max_timeout, 'max_retries' => $max_retries, diff --git a/pandora_console/godmode/agentes/module_manager_editor.php b/pandora_console/godmode/agentes/module_manager_editor.php index 452d2a498a..a52813fbf3 100644 --- a/pandora_console/godmode/agentes/module_manager_editor.php +++ b/pandora_console/godmode/agentes/module_manager_editor.php @@ -294,6 +294,7 @@ if ($id_agent_module) { $plugin_parameter = $module['plugin_parameter']; $id_plugin = $module['id_plugin']; $post_process = $module['post_process']; + $made_enabled = $module['made_enabled']; $prediction_module = $module['prediction_module']; $custom_integer_1 = $module['custom_integer_1']; $custom_integer_2 = $module['custom_integer_2']; @@ -408,6 +409,7 @@ if ($id_agent_module) { $id_module_group = 1; $id_module_type = 1; $post_process = ''; + $made_enabled = false; $max_timeout = 0; $max_retries = 0; $min = ''; diff --git a/pandora_console/godmode/agentes/module_manager_editor_common.php b/pandora_console/godmode/agentes/module_manager_editor_common.php index d9a0d3ba22..ca74b7d171 100644 --- a/pandora_console/godmode/agentes/module_manager_editor_common.php +++ b/pandora_console/godmode/agentes/module_manager_editor_common.php @@ -1,4 +1,5 @@ data['switch_warning_threshold'][0] .= html_print_switch_ html_print_radio_button_extended('warning_thresholds_checks', 'warning_inverse', __('Inverse interval'), ($warning_inverse) ? 'warning_inverse' : false, $disabledBecauseInPolicy, '', '', true, false, '', 'radius-warning_inverse'), html_print_radio_button_extended('warning_thresholds_checks', 'percentage_warning', __('Percentage'), ($percentage_warning) ? 'percentage_warning' : false, $disabledBecauseInPolicy, '', '', true, false, '', 'radius-percentage_warning'), ], - [ 'class' => 'margin-top-10' ], + ['class' => 'margin-top-10'], true ); @@ -565,7 +566,7 @@ $tableBasicThresholds->data['switch_critical_threshold'][0] .= html_print_switch html_print_radio_button_extended('critical_thresholds_checks', 'critical_inverse', __('Inverse interval'), ($critical_inverse) ? 'critical_inverse' : false, $disabledBecauseInPolicy, '', '', true, false, '', 'radius-critical_inverse'), html_print_radio_button_extended('critical_thresholds_checks', 'percentage_critical', __('Percentage'), ($percentage_critical) ? 'percentage_critical' : false, $disabledBecauseInPolicy, '', '', true, false, '', 'radius-percentage_critical'), ], - [ 'class' => 'margin-top-10' ], + ['class' => 'margin-top-10'], true ); @@ -722,14 +723,14 @@ if ($cps_module > 0) { ob_start(); ?> data['ff_main_thresholds'][0] = html_print_switch_radio_butto html_print_radio_button_extended('each_ff', 0, __('All state changing'), $each_ff, false, 'ffStateChange(0)', '', true, false, '', 'ff_all_state'), html_print_radio_button_extended('each_ff', 1, __('Each state changing'), $each_ff, false, 'ffStateChange(1)', '', true, false, '', 'ff_each_state'), ], - [ 'add_content' => $ffThresholdsScript ], + ['add_content' => $ffThresholdsScript], true ); @@ -1376,6 +1377,24 @@ $table_advanced->data['process_unit'][1] = html_print_extended_select_for_post_p $disabledBecauseInPolicy ); +$table_advanced->rowclass['caption_made_enabled'] = 'w50p'; +$table_advanced->rowclass['made_enabled'] = 'w50p'; +$table_advanced->data['caption_made_enabled'][0] = __('MADE enabled').ui_print_help_tip( + __('By activating this option, the module data will be processed by the MADE engine (if active), and events will be generated automatically by the IA engine'), + true +); +$table_advanced->data['made_enabled'][0] = html_print_checkbox_switch( + 'made_enabled', + 1, + (bool) $made_enabled, + false, + false, + '', + false, + false, + 'wp100 static' +); + $table_advanced->data['title_5'] = html_print_subtitle_table(__('Notifications and alerts')); $table_advanced->data['caption_export_target'][0] = __('Export target'); @@ -1666,47 +1685,48 @@ ui_require_jquery_file('json'); ?> + /* ]]> */ + \ No newline at end of file diff --git a/pandora_console/godmode/agentes/module_manager_editor_web.php b/pandora_console/godmode/agentes/module_manager_editor_web.php index 727e16d5bf..6089a932ee 100644 --- a/pandora_console/godmode/agentes/module_manager_editor_web.php +++ b/pandora_console/godmode/agentes/module_manager_editor_web.php @@ -318,7 +318,7 @@ foreach ($texts as $code => $text) { return; } - $(plugin_parameter).val('task_begin\ncookie 0\nresource 0\ntask_end'); + $(plugin_parameter).val('task_begin\nget https://demoweb.com/page/\ncheck_string text string or HTML code to search (regexp)\ntask_end\n'); $('#button-btn_loadbasic').attr('disabled', 'disabled'); diff --git a/pandora_console/godmode/massive/massive_edit_modules.php b/pandora_console/godmode/massive/massive_edit_modules.php index fbb63c49d3..156ca507d8 100755 --- a/pandora_console/godmode/massive/massive_edit_modules.php +++ b/pandora_console/godmode/massive/massive_edit_modules.php @@ -916,7 +916,24 @@ $table->data[17][0] = html_print_label_input_block( ) ); -$table->data[17][1] = html_print_label_input_block( +$table->data['made_enabled'][1] = html_print_label_input_block( + __('MADE enabled').ui_print_help_tip( + __('By activating this option, the module data will be processed by the MADE engine (if active), and events will be generated automatically by the IA engine'), + true + ), + html_print_checkbox_switch( + 'made_enabled', + 1, + false, + true, + false, + '', + false, + 'wp100 static' + ) +); + +$table->data[17][2] = html_print_label_input_block( __('SNMP community'), html_print_input_text( 'snmp_community', @@ -1653,7 +1670,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").hide(); var params = { @@ -1728,7 +1746,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").show (); switch($('#module_type').val()) { @@ -1838,7 +1857,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").hide (); $('input[type=checkbox]').attr('checked', false); $('input[type=checkbox]').attr('disabled', true); @@ -1877,7 +1897,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").show(); } else { @@ -1908,7 +1929,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").hide(); } } @@ -1932,6 +1954,9 @@ $(document).ready (function () { else if (this.id == "checkbox-dynamic_two_tailed") { return; //Do none } + else if (this.id == "checkbox-made_enabled") { + return; //Do none + } else { if (this.id == "checkbox-force_group") { $("#checkbox-recursion").prop("checked", false); @@ -1964,7 +1989,7 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + "tr#delete_table-40").show (); } else { @@ -1995,7 +2020,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").hide(); } } @@ -2085,7 +2111,8 @@ $(document).ready (function () { "tr#delete_table-36, " + "tr#delete_table-37, " + "tr#delete_table-38, " + - "tr#delete_table-39, " + + "tr#delete_table-39, " + + "tr#delete_table-made_enabled, " + "tr#delete_table-40").hide(); jQuery.post ("ajax.php", @@ -2315,6 +2342,7 @@ function process_manage_edit($module_name, $agents_select=null, $module_status=' 'module_interval', 'disabled', 'post_process', + 'made_enabled', 'unit_select', 'snmp_community', 'snmp_oid', @@ -2626,6 +2654,10 @@ function process_manage_edit($module_name, $agents_select=null, $module_status=' $values['macros'] = json_encode($module_macros); } + if (modules_made_compatible($module['id_tipo_modulo']) === false) { + $values['made_enabled'] = 0; + } + $result = modules_update_agent_module( $module['id_agente_modulo'], $values, diff --git a/pandora_console/godmode/servers/modificar_server.php b/pandora_console/godmode/servers/modificar_server.php index 4b3f26606a..c51c0476d3 100644 --- a/pandora_console/godmode/servers/modificar_server.php +++ b/pandora_console/godmode/servers/modificar_server.php @@ -151,6 +151,10 @@ if (isset($_GET['server']) === true) { $title .= __('Netflow server').' ID: '.$id_server; break; + case SERVER_TYPE_MADE: + $title .= __('MADE server').' ID: '.$id_server; + break; + default: $title = __('Update server').' ID: '.$id_server; break; diff --git a/pandora_console/images/Anomaly-detection.png b/pandora_console/images/Anomaly-detection.png new file mode 100644 index 0000000000..cf3c346138 Binary files /dev/null and b/pandora_console/images/Anomaly-detection.png differ diff --git a/pandora_console/images/Anomaly-detection@2x.png b/pandora_console/images/Anomaly-detection@2x.png new file mode 100644 index 0000000000..ba2352fbf1 Binary files /dev/null and b/pandora_console/images/Anomaly-detection@2x.png differ diff --git a/pandora_console/images/Anomaly-detection@svg.svg b/pandora_console/images/Anomaly-detection@svg.svg new file mode 100644 index 0000000000..45abb1db7a --- /dev/null +++ b/pandora_console/images/Anomaly-detection@svg.svg @@ -0,0 +1,14 @@ + + + Anomaly detection@svg + + + + + + + + + + + \ No newline at end of file diff --git a/pandora_console/include/ajax/module.php b/pandora_console/include/ajax/module.php index 92ab21b1bc..3d77c7ba30 100755 --- a/pandora_console/include/ajax/module.php +++ b/pandora_console/include/ajax/module.php @@ -483,6 +483,13 @@ if (check_login()) { 'tagente_modulo', ['id_agente_modulo' => $module_id] ); + + $made_enabled = db_get_value_filter( + 'made_enabled', + 'tagente_modulo', + ['id_agente_modulo' => $module_id] + ); + $unit = db_get_value_filter( 'unit', 'tagente_modulo', diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index 650ef9d473..1cddf36ca1 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC231024'; +$build_version = 'PC231030'; $pandora_version = 'v7.0NG.773.3'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index 2dba4790e3..4f020e61de 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -442,6 +442,7 @@ define('SERVER_TYPE_CORRELATION', 22); define('SERVER_TYPE_NCM', 23); define('SERVER_TYPE_NETFLOW', 24); define('SERVER_TYPE_LOG', 25); +define('SERVER_TYPE_MADE', 26); // REPORTS. define('REPORT_TOP_N_MAX', 1); diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 5481152ac6..888531e915 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -5409,7 +5409,7 @@ function html_print_link_with_params($text, $params=[], $type='text', $style='', $formStyle = ' style="'.$formStyle.'"'; } - $html = '
'; + $html = ''; switch ($type) { case 'image': $html .= html_print_input_image($text, $text, $text, $style, true); diff --git a/pandora_console/include/functions_modules.php b/pandora_console/include/functions_modules.php index e82fca400b..de618605c8 100755 --- a/pandora_console/include/functions_modules.php +++ b/pandora_console/include/functions_modules.php @@ -4762,3 +4762,31 @@ function export_agents_module_csv($filters) return $result; } + + +/** + * Check if modules are compatible with MADE server. + * + * @param integer $id_tipo_modulo + * @retur boolean True if compatible, false otherwise. + */ +function modules_made_compatible($id_tipo_modulo) +{ + $compatible_types = [ + 1, + 4, + 5, + 8, + 15, + 16, + 22, + 30, + 34, + ]; + + if (array_search($id_tipo_modulo, $compatible_types) === false) { + return false; + } else { + return true; + } +} diff --git a/pandora_console/include/functions_servers.php b/pandora_console/include/functions_servers.php index 845a57a77b..75e034ce3c 100644 --- a/pandora_console/include/functions_servers.php +++ b/pandora_console/include/functions_servers.php @@ -992,6 +992,19 @@ function servers_get_info($id_server=-1, $sql_limit=-1) $id_modulo = 0; break; + case SERVER_TYPE_MADE: + $server['img'] = html_print_image( + 'images/Anomaly-detection@svg.svg', + true, + [ + 'title' => __('MADE server'), + 'class' => 'main_menu_icon invert_filter', + ] + ); + $server['type'] = 'made'; + $id_modulo = 0; + break; + default: $server['img'] = ''; $server['type'] = 'unknown'; diff --git a/pandora_console/include/graphs/flot/jquery.flot.min.js b/pandora_console/include/graphs/flot/jquery.flot.min.js index abf73f210b..59d81c4c9e 100644 --- a/pandora_console/include/graphs/flot/jquery.flot.min.js +++ b/pandora_console/include/graphs/flot/jquery.flot.min.js @@ -13,6 +13,6 @@ Licensed under the MIT license. if (yrange.from == null) yrange.from = yrange.axis.min; if (yrange.to == null) yrange.to = yrange.axis.max; if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) continue; xrange.from = Math.max(xrange.from, xrange.axis.min); xrange.to = Math.min(xrange.to, xrange.axis.max); yrange.from = Math.max(yrange.from, yrange.axis.min); yrange.to = Math.min(yrange.to, yrange.axis.max); var xequal = xrange.from === xrange.to, yequal = yrange.from === yrange.to; if (xequal && yequal) { continue } xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); if (xequal || yequal) { var lineWidth = m.lineWidth || options.grid.markingsLineWidth, subPixel = lineWidth % 2 ? .5 : 0; ctx.beginPath(); ctx.strokeStyle = m.color || options.grid.markingsColor; ctx.lineWidth = lineWidth; if (xequal) { ctx.moveTo(xrange.to + subPixel, yrange.from); ctx.lineTo(xrange.to + subPixel, yrange.to) } else { ctx.moveTo(xrange.from, yrange.to + subPixel); ctx.lineTo(xrange.to, yrange.to + subPixel) } ctx.stroke() } else { ctx.fillStyle = m.color || options.grid.markingsColor; ctx.fillRect(xrange.from, yrange.to, xrange.to - xrange.from, yrange.from - yrange.to) } } } axes = allAxes(); bw = options.grid.borderWidth; for (var j = 0; j < axes.length; ++j) { var axis = axes[j], box = axis.box, t = axis.tickLength, x, y, xoff, yoff; if (!axis.show || axis.ticks.length == 0) continue; ctx.lineWidth = 1; if (axis.direction == "x") { x = 0; if (t == "full") y = axis.position == "top" ? 0 : plotHeight; else y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0) } else { y = 0; if (t == "full") x = axis.position == "left" ? 0 : plotWidth; else x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0) } if (!axis.innermost) { ctx.strokeStyle = axis.options.color; ctx.beginPath(); xoff = yoff = 0; if (axis.direction == "x") xoff = plotWidth + 1; else yoff = plotHeight + 1; if (ctx.lineWidth == 1) { if (axis.direction == "x") { y = Math.floor(y) + .5 } else { x = Math.floor(x) + .5 } } ctx.moveTo(x, y); ctx.lineTo(x + xoff, y + yoff); ctx.stroke() } ctx.strokeStyle = axis.options.tickColor; ctx.beginPath(); for (i = 0; i < axis.ticks.length; ++i) { var v = axis.ticks[i].v; xoff = yoff = 0; if (isNaN(v) || v < axis.min || v > axis.max || t == "full" && (typeof bw == "object" && bw[axis.position] > 0 || bw > 0) && (v == axis.min || v == axis.max)) continue; if (axis.direction == "x") { x = axis.p2c(v); yoff = t == "full" ? -plotHeight : t; if (axis.position == "top") yoff = -yoff } else { y = axis.p2c(v); xoff = t == "full" ? -plotWidth : t; if (axis.position == "left") xoff = -xoff } if (ctx.lineWidth == 1) { if (axis.direction == "x") x = Math.floor(x) + .5; else y = Math.floor(y) + .5 } ctx.moveTo(x, y); ctx.lineTo(x + xoff, y + yoff) } ctx.stroke() } if (bw) { bc = options.grid.borderColor; if (typeof bw == "object" || typeof bc == "object") { if (typeof bw !== "object") { bw = { top: bw, right: bw, bottom: bw, left: bw } } if (typeof bc !== "object") { bc = { top: bc, right: bc, bottom: bc, left: bc } } if (bw.top > 0) { ctx.strokeStyle = bc.top; ctx.lineWidth = bw.top; ctx.beginPath(); ctx.moveTo(0 - bw.left, 0 - bw.top / 2); ctx.lineTo(plotWidth, 0 - bw.top / 2); ctx.stroke() } if (bw.right > 0) { ctx.strokeStyle = bc.right; ctx.lineWidth = bw.right; ctx.beginPath(); ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); ctx.lineTo(plotWidth + bw.right / 2, plotHeight); ctx.stroke() } if (bw.bottom > 0) { ctx.strokeStyle = bc.bottom; ctx.lineWidth = bw.bottom; ctx.beginPath(); ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); ctx.lineTo(0, plotHeight + bw.bottom / 2); ctx.stroke() } if (bw.left > 0) { ctx.strokeStyle = bc.left; ctx.lineWidth = bw.left; ctx.beginPath(); ctx.moveTo(0 - bw.left / 2, plotHeight + bw.bottom); ctx.lineTo(0 - bw.left / 2, 0); ctx.stroke() } } else { ctx.lineWidth = bw; ctx.strokeStyle = options.grid.borderColor; ctx.strokeRect(-bw / 2, -bw / 2, plotWidth + bw, plotHeight + bw) } } ctx.restore() - } function drawAxisLabels() { $.each(allAxes(), function (_, axis) { var box = axis.box, legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, font = axis.options.font || "flot-tick-label tickLabel", tick, x, y, halign, valign; surface.removeText(layer); if (!axis.show || axis.ticks.length == 0) return; for (var i = 0; i < axis.ticks.length; ++i) { tick = axis.ticks[i]; if (!tick.label || tick.v < axis.min || tick.v > axis.max) continue; if (axis.direction == "x") { halign = "center"; x = plotOffset.left + axis.p2c(tick.v); if (axis.position == "bottom") { y = box.top + box.padding } else { y = box.top + box.height - box.padding; valign = "bottom" } } else { valign = "middle"; y = plotOffset.top + axis.p2c(tick.v); if (axis.position == "left") { x = box.left + box.width - box.padding; halign = "right" } else { x = box.left + box.padding } } surface.addText(layer, x, y, tick.label, font, null, null, halign, valign) } }) } function drawSeries(series) { if (series.lines.show) drawSeriesLines(series); if (series.bars.show) drawSeriesBars(series); if (series.points.show) drawSeriesPoints(series) } function drawSeriesLines(series) { function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize, prevx = null, prevy = null; ctx.beginPath(); for (var i = ps; i < points.length; i += ps) { var x1 = points[i - ps], y1 = points[i - ps + 1], x2 = points[i], y2 = points[i + 1]; if (x1 == null || x2 == null) continue; if (y1 <= y2 && y1 < axisy.min) { if (y2 < axisy.min) continue; x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.min } else if (y2 <= y1 && y2 < axisy.min) { if (y1 < axisy.min) continue; x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.min } if (y1 >= y2 && y1 > axisy.max) { if (y2 > axisy.max) continue; x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.max } else if (y2 >= y1 && y2 > axisy.max) { if (y1 > axisy.max) continue; x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.max } if (x1 <= x2 && x1 < axisx.min) { if (x2 < axisx.min) continue; y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.min } else if (x2 <= x1 && x2 < axisx.min) { if (x1 < axisx.min) continue; y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.min } if (x1 >= x2 && x1 > axisx.max) { if (x2 > axisx.max) continue; y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.max } else if (x2 >= x1 && x2 > axisx.max) { if (x1 > axisx.max) continue; y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.max } if (x1 != prevx || y1 != prevy) ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); prevx = x2; prevy = y2; ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset) } ctx.stroke() } function plotLineArea(datapoints, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize, bottom = Math.min(Math.max(0, axisy.min), axisy.max), i = 0, top, areaOpen = false, ypos = 1, segmentStart = 0, segmentEnd = 0; while (true) { if (ps > 0 && i > points.length + ps) break; i += ps; var x1 = points[i - ps], y1 = points[i - ps + ypos], x2 = points[i], y2 = points[i + ypos]; if (areaOpen) { if (ps > 0 && x1 != null && x2 == null) { segmentEnd = i; ps = -ps; ypos = 2; continue } if (ps < 0 && i == segmentStart + ps) { ctx.fill(); areaOpen = false; ps = -ps; ypos = 1; i = segmentStart = segmentEnd + ps; continue } } if (x1 == null || x2 == null) continue; if (x1 <= x2 && x1 < axisx.min) { if (x2 < axisx.min) continue; y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.min } else if (x2 <= x1 && x2 < axisx.min) { if (x1 < axisx.min) continue; y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.min } if (x1 >= x2 && x1 > axisx.max) { if (x2 > axisx.max) continue; y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.max } else if (x2 >= x1 && x2 > axisx.max) { if (x1 > axisx.max) continue; y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.max } if (!areaOpen) { ctx.beginPath(); ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); areaOpen = true } if (y1 >= axisy.max && y2 >= axisy.max) { ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); continue } else if (y1 <= axisy.min && y2 <= axisy.min) { ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); continue } var x1old = x1, x2old = x2; if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.min } else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.min } if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.max } else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.max } if (x1 != x1old) { ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)) } ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); if (x2 != x2old) { ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)) } } } ctx.save(); ctx.translate(plotOffset.left, plotOffset.top); ctx.lineJoin = "round"; var lw = series.lines.lineWidth, sw = series.shadowSize; if (lw > 0 && sw > 0) { ctx.lineWidth = sw; ctx.strokeStyle = "rgba(0,0,0,0.1)"; var angle = Math.PI / 18; plotLine(series.datapoints, Math.sin(angle) * (lw / 2 + sw / 2), Math.cos(angle) * (lw / 2 + sw / 2), series.xaxis, series.yaxis); ctx.lineWidth = sw / 2; plotLine(series.datapoints, Math.sin(angle) * (lw / 2 + sw / 4), Math.cos(angle) * (lw / 2 + sw / 4), series.xaxis, series.yaxis) } ctx.lineWidth = lw; ctx.strokeStyle = series.color; var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); if (fillStyle) { ctx.fillStyle = fillStyle; plotLineArea(series.datapoints, series.xaxis, series.yaxis) } if (lw > 0) plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); ctx.restore() } function drawSeriesPoints(series) { function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { var points = datapoints.points, ps = datapoints.pointsize; for (var i = 0; i < points.length; i += ps) { var x = points[i], y = points[i + 1]; if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) continue; ctx.beginPath(); x = axisx.p2c(x); y = axisy.p2c(y) + offset; if (symbol == "circle") ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); else symbol(ctx, x, y, radius, shadow); ctx.closePath(); if (fillStyle) { ctx.fillStyle = fillStyle; ctx.fill() } ctx.stroke() } } ctx.save(); ctx.translate(plotOffset.left, plotOffset.top); var lw = series.points.lineWidth, sw = series.shadowSize, radius = series.points.radius, symbol = series.points.symbol; if (lw == 0) lw = 1e-4; if (lw > 0 && sw > 0) { var w = sw / 2; ctx.lineWidth = w; ctx.strokeStyle = "rgba(0,0,0,0.1)"; plotPoints(series.datapoints, radius, null, w + w / 2, true, series.xaxis, series.yaxis, symbol); ctx.strokeStyle = "rgba(0,0,0,0.2)"; plotPoints(series.datapoints, radius, null, w / 2, true, series.xaxis, series.yaxis, symbol) } ctx.lineWidth = lw; ctx.strokeStyle = series.color; plotPoints(series.datapoints, radius, getFillStyle(series.points, series.color), 0, false, series.xaxis, series.yaxis, symbol); ctx.restore() } function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { var left, right, bottom, top, drawLeft, drawRight, drawTop, drawBottom, tmp; if (horizontal) { drawBottom = drawRight = drawTop = true; drawLeft = false; left = b; right = x; top = y + barLeft; bottom = y + barRight; if (right < left) { tmp = right; right = left; left = tmp; drawLeft = true; drawRight = false } } else { drawLeft = drawRight = drawTop = true; drawBottom = false; left = x + barLeft; right = x + barRight; bottom = b; top = y; if (top < bottom) { tmp = top; top = bottom; bottom = tmp; drawBottom = true; drawTop = false } } if (right < axisx.min || left > axisx.max || top < axisy.min || bottom > axisy.max) return; if (left < axisx.min) { left = axisx.min; drawLeft = false } if (right > axisx.max) { right = axisx.max; drawRight = false } if (bottom < axisy.min) { bottom = axisy.min; drawBottom = false } if (top > axisy.max) { top = axisy.max; drawTop = false } left = axisx.p2c(left); bottom = axisy.p2c(bottom); right = axisx.p2c(right); top = axisy.p2c(top); if (fillStyleCallback) { c.fillStyle = fillStyleCallback(bottom, top); c.fillRect(left, top, right - left, bottom - top) } if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { c.beginPath(); c.moveTo(left, bottom); if (drawLeft) c.lineTo(left, top); else c.moveTo(left, top); if (drawTop) c.lineTo(right, top); else c.moveTo(right, top); if (drawRight) c.lineTo(right, bottom); else c.moveTo(right, bottom); if (drawBottom) c.lineTo(left, bottom); else c.moveTo(left, bottom); c.stroke() } } function drawSeriesBars(series) { function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize; for (var i = 0; i < points.length; i += ps) { if (points[i] == null) continue; drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth) } } ctx.save(); ctx.translate(plotOffset.left, plotOffset.top); ctx.lineWidth = series.bars.lineWidth; ctx.strokeStyle = series.color; var barLeft; switch (series.bars.align) { case "left": barLeft = 0; break; case "right": barLeft = -series.bars.barWidth; break; default: barLeft = -series.bars.barWidth / 2 }var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top) } : null; plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); ctx.restore() } function getFillStyle(filloptions, seriesColor, bottom, top) { var fill = filloptions.fill; if (!fill) return null; if (filloptions.fillColor) return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); var c = $.color.parse(seriesColor); c.a = typeof fill == "number" ? fill : .4; c.normalize(); return c.toString() } function insertLegend() { if (options.legend.container != null) { $(options.legend.container).html("") } else { placeholder.find(".legend").remove() } if (!options.legend.show) { return } var fragments = [], entries = [], rowStarted = false, lf = options.legend.labelFormatter, s, label; for (var i = 0; i < series.length; ++i) { s = series[i]; if (s.label) { label = lf ? lf(s.label, s) : s.label; if (label) { entries.push({ label: label, color: s.color }) } } } if (options.legend.sorted) { if ($.isFunction(options.legend.sorted)) { entries.sort(options.legend.sorted) } else if (options.legend.sorted == "reverse") { entries.reverse() } else { var ascending = options.legend.sorted != "descending"; entries.sort(function (a, b) { return a.label == b.label ? 0 : a.label < b.label != ascending ? 1 : -1 }) } } for (var i = 0; i < entries.length; ++i) { var entry = entries[i]; if (i % options.legend.noColumns == 0) { if (rowStarted) fragments.push(""); fragments.push(""); rowStarted = true } fragments.push('
' + '' + entry.label + "") } if (rowStarted) fragments.push(""); if (fragments.length == 0) return; var table = '' + fragments.join("") + "
"; if (options.legend.container != null) $(options.legend.container).html(table); else { var pos = "", p = options.legend.position, m = options.legend.margin; if (m[0] == null) m = [m, m]; if (p.charAt(0) == "n") pos += "top:" + (m[1] + plotOffset.top) + "px;"; else if (p.charAt(0) == "s") pos += "bottom:" + (m[1] + plotOffset.bottom) + "px;"; if (p.charAt(1) == "e") pos += "right:" + (m[0] + plotOffset.right) + "px;"; else if (p.charAt(1) == "w") pos += "left:" + (m[0] + plotOffset.left) + "px;"; var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos + ";") + "
").appendTo(placeholder); if (options.legend.backgroundOpacity != 0) { var c = options.legend.backgroundColor; if (c == null) { c = options.grid.backgroundColor; if (c && typeof c == "string") c = $.color.parse(c); else c = $.color.extract(legend, "background-color"); c.a = 1; c = c.toString() } var div = legend.children(); $('
').prependTo(legend).css("opacity", options.legend.backgroundOpacity) } } } var highlights = [], redrawTimeout = null; function findNearbyItem(mouseX, mouseY, seriesFilter) { var maxDistance = options.grid.mouseActiveRadius, smallestDistance = maxDistance * maxDistance + 1, item = null, foundPoint = false, i, j, ps; for (i = series.length - 1; i >= 0; --i) { if (!seriesFilter(series[i])) continue; var s = series[i], axisx = s.xaxis, axisy = s.yaxis, points = s.datapoints.points, mx = axisx.c2p(mouseX), my = axisy.c2p(mouseY), maxx = maxDistance / axisx.scale, maxy = maxDistance / axisy.scale; ps = s.datapoints.pointsize; if (axisx.options.inverseTransform) maxx = Number.MAX_VALUE; if (axisy.options.inverseTransform) maxy = Number.MAX_VALUE; if (s.lines.show || s.points.show) { for (j = 0; j < points.length; j += ps) { var x = points[j], y = points[j + 1]; if (x == null) continue; if (x - mx > maxx || x - mx < -maxx || y - my > maxy || y - my < -maxy) continue; var dx = Math.abs(axisx.p2c(x) - mouseX), dy = Math.abs(axisy.p2c(y) - mouseY), dist = dx * dx + dy * dy; if (dist < smallestDistance) { smallestDistance = dist; item = [i, j / ps] } } } if (s.bars.show && !item) { var barLeft, barRight; switch (s.bars.align) { case "left": barLeft = 0; break; case "right": barLeft = -s.bars.barWidth; break; default: barLeft = -s.bars.barWidth / 2 }barRight = barLeft + s.bars.barWidth; for (j = 0; j < points.length; j += ps) { var x = points[j], y = points[j + 1], b = points[j + 2]; if (x == null) continue; if (series[i].bars.horizontal ? mx <= Math.max(b, x) && mx >= Math.min(b, x) && my >= y + barLeft && my <= y + barRight : mx >= x + barLeft && mx <= x + barRight && my >= Math.min(b, y) && my <= Math.max(b, y)) item = [i, j / ps] } } } if (item) { i = item[0]; j = item[1]; ps = series[i].datapoints.pointsize; return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), dataIndex: j, series: series[i], seriesIndex: i } } return null } function onMouseMove(e) { if (options.grid.hoverable) triggerClickHoverEvent("plothover", e, function (s) { return s["hoverable"] != false }) } function onMouseLeave(e) { if (options.grid.hoverable) triggerClickHoverEvent("plothover", e, function (s) { return false }) } function onClick(e) { triggerClickHoverEvent("plotclick", e, function (s) { return s["clickable"] != false }) } function triggerClickHoverEvent(eventname, event, seriesFilter) { var offset = eventHolder.offset(), canvasX = event.pageX - offset.left - plotOffset.left, canvasY = event.pageY - offset.top - plotOffset.top, pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); pos.pageX = event.pageX; pos.pageY = event.pageY; var item = findNearbyItem(canvasX, canvasY, seriesFilter); if (item) { item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10) } if (options.grid.autoHighlight) { for (var i = 0; i < highlights.length; ++i) { var h = highlights[i]; if (h.auto == eventname && !(item && h.series == item.series && h.point[0] == item.datapoint[0] && h.point[1] == item.datapoint[1])) unhighlight(h.series, h.point) } if (item) highlight(item.series, item.datapoint, eventname) } placeholder.trigger(eventname, [pos, item]) } function triggerRedrawOverlay() { var t = options.interaction.redrawOverlayInterval; if (t == -1) { drawOverlay(); return } if (!redrawTimeout) redrawTimeout = setTimeout(drawOverlay, t) } function drawOverlay() { redrawTimeout = null; octx.save(); overlay.clear(); octx.translate(plotOffset.left, plotOffset.top); var i, hi; for (i = 0; i < highlights.length; ++i) { hi = highlights[i]; if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point); else drawPointHighlight(hi.series, hi.point) } octx.restore(); executeHooks(hooks.drawOverlay, [octx]) } function highlight(s, point, auto) { if (typeof s == "number") s = series[s]; if (typeof point == "number") { var ps = s.datapoints.pointsize; point = s.datapoints.points.slice(ps * point, ps * (point + 1)) } var i = indexOfHighlight(s, point); if (i == -1) { highlights.push({ series: s, point: point, auto: auto }); triggerRedrawOverlay() } else if (!auto) highlights[i].auto = false } function unhighlight(s, point) { if (s == null && point == null) { highlights = []; triggerRedrawOverlay(); return } if (typeof s == "number") s = series[s]; if (typeof point == "number") { var ps = s.datapoints.pointsize; point = s.datapoints.points.slice(ps * point, ps * (point + 1)) } var i = indexOfHighlight(s, point); if (i != -1) { highlights.splice(i, 1); triggerRedrawOverlay() } } function indexOfHighlight(s, p) { for (var i = 0; i < highlights.length; ++i) { var h = highlights[i]; if (h.series == s && h.point[0] == p[0] && h.point[1] == p[1]) return i } return -1 } function drawPointHighlight(series, point) { var x = point[0], y = point[1], axisx = series.xaxis, axisy = series.yaxis, highlightColor = typeof series.highlightColor === "string" ? series.highlightColor : $.color.parse(series.color).scale("a", .5).toString(); if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) return; var pointRadius = series.points.radius + series.points.lineWidth / 2; octx.lineWidth = pointRadius; octx.strokeStyle = highlightColor; var radius = 1.5 * pointRadius; x = axisx.p2c(x); y = axisy.p2c(y); octx.beginPath(); if (series.points.symbol == "circle") octx.arc(x, y, radius, 0, 2 * Math.PI, false); else series.points.symbol(octx, x, y, radius, false); octx.closePath(); octx.stroke() } function drawBarHighlight(series, point) { var highlightColor = typeof series.highlightColor === "string" ? series.highlightColor : $.color.parse(series.color).scale("a", .5).toString(), fillStyle = highlightColor, barLeft; switch (series.bars.align) { case "left": barLeft = 0; break; case "right": barLeft = -series.bars.barWidth; break; default: barLeft = -series.bars.barWidth / 2 }octx.lineWidth = series.bars.lineWidth; octx.strokeStyle = highlightColor; drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, function () { return fillStyle }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth) } function getColorOrGradient(spec, bottom, top, defaultColor) { if (typeof spec == "string") return spec; else { var gradient = ctx.createLinearGradient(0, top, 0, bottom); for (var i = 0, l = spec.colors.length; i < l; ++i) { var c = spec.colors[i]; if (typeof c != "string") { var co = $.color.parse(defaultColor); if (c.brightness != null) co = co.scale("rgb", c.brightness); if (c.opacity != null) co.a *= c.opacity; c = co.toString() } gradient.addColorStop(i / (l - 1), c) } return gradient } } + } function drawAxisLabels() { $.each(allAxes(), function (_, axis) { var box = axis.box, legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, font = axis.options.font || "flot-tick-label tickLabel", tick, x, y, halign, valign; surface.removeText(layer); if (!axis.show || axis.ticks.length == 0) return; for (var i = 0; i < axis.ticks.length; ++i) { tick = axis.ticks[i]; if (!tick.label || tick.v < axis.min || tick.v > axis.max) continue; if (axis.direction == "x") { halign = "center"; x = plotOffset.left + axis.p2c(tick.v); if (axis.position == "bottom") { y = box.top + box.padding } else { y = box.top + box.height - box.padding; valign = "bottom" } } else { valign = "middle"; y = plotOffset.top + axis.p2c(tick.v); if (axis.position == "left") { x = box.left + box.width - box.padding; halign = "right" } else { x = box.left + box.padding } } surface.addText(layer, x, y, tick.label, font, null, null, halign, valign) } }) } function drawSeries(series) { if (series.lines.show) drawSeriesLines(series); if (series.bars.show) drawSeriesBars(series); if (series.points.show) drawSeriesPoints(series) } function drawSeriesLines(series) { function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize, prevx = null, prevy = null; ctx.beginPath(); for (var i = ps; i < points.length; i += ps) { var x1 = points[i - ps], y1 = points[i - ps + 1], x2 = points[i], y2 = points[i + 1]; if (x1 == null || x2 == null) continue; if (y1 <= y2 && y1 < axisy.min) { if (y2 < axisy.min) continue; x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.min } else if (y2 <= y1 && y2 < axisy.min) { if (y1 < axisy.min) continue; x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.min } if (y1 >= y2 && y1 > axisy.max) { if (y2 > axisy.max) continue; x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.max } else if (y2 >= y1 && y2 > axisy.max) { if (y1 > axisy.max) continue; x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.max } if (x1 <= x2 && x1 < axisx.min) { if (x2 < axisx.min) continue; y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.min } else if (x2 <= x1 && x2 < axisx.min) { if (x1 < axisx.min) continue; y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.min } if (x1 >= x2 && x1 > axisx.max) { if (x2 > axisx.max) continue; y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.max } else if (x2 >= x1 && x2 > axisx.max) { if (x1 > axisx.max) continue; y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.max } if (x1 != prevx || y1 != prevy) ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); prevx = x2; prevy = y2; ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset) } ctx.stroke() } function plotLineArea(datapoints, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize, bottom = Math.min(Math.max(0, axisy.min), axisy.max), i = 0, top, areaOpen = false, ypos = 1, segmentStart = 0, segmentEnd = 0; while (true) { if (ps > 0 && i > points.length + ps) break; i += ps; var x1 = points[i - ps], y1 = points[i - ps + ypos], x2 = points[i], y2 = points[i + ypos]; if (areaOpen) { if (ps > 0 && x1 != null && x2 == null) { segmentEnd = i; ps = -ps; ypos = 2; continue } if (ps < 0 && i == segmentStart + ps) { ctx.fill(); areaOpen = false; ps = -ps; ypos = 1; i = segmentStart = segmentEnd + ps; continue } } if (x1 == null || x2 == null) continue; if (x1 <= x2 && x1 < axisx.min) { if (x2 < axisx.min) continue; y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.min } else if (x2 <= x1 && x2 < axisx.min) { if (x1 < axisx.min) continue; y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.min } if (x1 >= x2 && x1 > axisx.max) { if (x2 > axisx.max) continue; y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x1 = axisx.max } else if (x2 >= x1 && x2 > axisx.max) { if (x1 > axisx.max) continue; y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; x2 = axisx.max } if (!areaOpen) { ctx.beginPath(); ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); areaOpen = true } if (y1 >= axisy.max && y2 >= axisy.max) { ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); continue } else if (y1 <= axisy.min && y2 <= axisy.min) { ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); continue } var x1old = x1, x2old = x2; if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.min } else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.min } if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y1 = axisy.max } else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; y2 = axisy.max } if (x1 != x1old) { ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)) } ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); if (x2 != x2old) { ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)) } } } ctx.save(); ctx.translate(plotOffset.left, plotOffset.top); ctx.lineJoin = "round"; var lw = series.lines.lineWidth, sw = series.shadowSize; if (lw > 0 && sw > 0) { ctx.lineWidth = sw; ctx.strokeStyle = "rgba(0,0,0,0.1)"; var angle = Math.PI / 18; plotLine(series.datapoints, Math.sin(angle) * (lw / 2 + sw / 2), Math.cos(angle) * (lw / 2 + sw / 2), series.xaxis, series.yaxis); ctx.lineWidth = sw / 2; plotLine(series.datapoints, Math.sin(angle) * (lw / 2 + sw / 4), Math.cos(angle) * (lw / 2 + sw / 4), series.xaxis, series.yaxis) } ctx.lineWidth = lw; ctx.strokeStyle = series.color; var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); if (fillStyle) { ctx.fillStyle = fillStyle; plotLineArea(series.datapoints, series.xaxis, series.yaxis) } if (lw > 0) plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); ctx.restore() } function drawSeriesPoints(series) { function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { var points = datapoints.points, ps = datapoints.pointsize; for (var i = 0; i < points.length; i += ps) { var x = points[i], y = points[i + 1]; if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) continue; ctx.beginPath(); x = axisx.p2c(x); y = axisy.p2c(y) + offset; if (symbol == "circle") ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); else symbol(ctx, x, y, radius, shadow); ctx.closePath(); if (fillStyle) { ctx.fillStyle = fillStyle; ctx.fill() } ctx.stroke() } } ctx.save(); ctx.translate(plotOffset.left, plotOffset.top); var lw = series.points.lineWidth, sw = series.shadowSize, radius = series.points.radius, symbol = series.points.symbol; if (lw == 0) lw = 1e-4; if (lw > 0 && sw > 0) { var w = sw / 2; ctx.lineWidth = w; ctx.strokeStyle = "rgba(0,0,0,0.1)"; plotPoints(series.datapoints, radius, null, w + w / 2, true, series.xaxis, series.yaxis, symbol); ctx.strokeStyle = "rgba(0,0,0,0.2)"; plotPoints(series.datapoints, radius, null, w / 2, true, series.xaxis, series.yaxis, symbol) } ctx.lineWidth = lw; ctx.strokeStyle = series.color; plotPoints(series.datapoints, radius, getFillStyle(series.points, series.color), 0, false, series.xaxis, series.yaxis, symbol); ctx.restore() } function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { var left, right, bottom, top, drawLeft, drawRight, drawTop, drawBottom, tmp; if (horizontal) { drawBottom = drawRight = drawTop = true; drawLeft = false; left = b; right = x; top = y + barLeft; bottom = y + barRight; if (right < left) { tmp = right; right = left; left = tmp; drawLeft = true; drawRight = false } } else { drawLeft = drawRight = drawTop = true; drawBottom = false; left = x + barLeft; right = x + barRight; bottom = b; top = y; if (top < bottom) { tmp = top; top = bottom; bottom = tmp; drawBottom = true; drawTop = false } } if (right < axisx.min || left > axisx.max || top < axisy.min || bottom > axisy.max) return; if (left < axisx.min) { left = axisx.min; drawLeft = false } if (right > axisx.max) { right = axisx.max; drawRight = false } if (bottom < axisy.min) { bottom = axisy.min; drawBottom = false } if (top > axisy.max) { top = axisy.max; drawTop = false } left = axisx.p2c(left); bottom = axisy.p2c(bottom); right = axisx.p2c(right); top = axisy.p2c(top); if (fillStyleCallback) { c.fillStyle = fillStyleCallback(bottom, top); c.fillRect(left, top, right - left, bottom - top) } if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { c.beginPath(); c.moveTo(left, bottom); if (drawLeft) c.lineTo(left, top); else c.moveTo(left, top); if (drawTop) c.lineTo(right, top); else c.moveTo(right, top); if (drawRight) c.lineTo(right, bottom); else c.moveTo(right, bottom); if (drawBottom) c.lineTo(left, bottom); else c.moveTo(left, bottom); c.stroke() } } function drawSeriesBars(series) { function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { var points = datapoints.points, ps = datapoints.pointsize; for (var i = 0; i < points.length; i += ps) { if (points[i] == null) continue; drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth) } } ctx.save(); ctx.translate(plotOffset.left, plotOffset.top); ctx.lineWidth = series.bars.lineWidth; ctx.strokeStyle = series.color; var barLeft; switch (series.bars.align) { case "left": barLeft = 0; break; case "right": barLeft = -series.bars.barWidth; break; default: barLeft = -series.bars.barWidth / 2 }var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top) } : null; plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); ctx.restore() } function getFillStyle(filloptions, seriesColor, bottom, top) { var fill = filloptions.fill; if (!fill) return null; if (filloptions.fillColor) return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); var c = $.color.parse(seriesColor); c.a = typeof fill == "number" ? fill : .4; c.normalize(); return c.toString() } function insertLegend() { if (options.legend.container != null) { $(options.legend.container).html("") } else { placeholder.find(".legend").remove() } if (!options.legend.show) { return } var fragments = [], entries = [], rowStarted = false, lf = options.legend.labelFormatter, s, label; for (var i = 0; i < series.length; ++i) { s = series[i]; if (s.label) { label = lf ? lf(s.label, s) : s.label; if (label) { entries.push({ label: label, color: s.color }) } } } if (options.legend.sorted) { if ($.isFunction(options.legend.sorted)) { entries.sort(options.legend.sorted) } else if (options.legend.sorted == "reverse") { entries.reverse() } else { var ascending = options.legend.sorted != "descending"; entries.sort(function (a, b) { return a.label == b.label ? 0 : a.label < b.label != ascending ? 1 : -1 }) } } for (var i = 0; i < entries.length; ++i) { var entry = entries[i]; if (i % options.legend.noColumns == 0) { if (rowStarted) fragments.push(""); fragments.push(""); rowStarted = true } fragments.push('
' + '' + entry.label.replace("font-size: 9pt;", "") + "") } if (rowStarted) fragments.push(""); if (fragments.length == 0) return; var table = '' + fragments.join("") + "
"; if (options.legend.container != null) $(options.legend.container).html(table); else { var pos = "", p = options.legend.position, m = options.legend.margin; if (m[0] == null) m = [m, m]; if (p.charAt(0) == "n") pos += "top:" + (m[1] + plotOffset.top) + "px;"; else if (p.charAt(0) == "s") pos += "bottom:" + (m[1] + plotOffset.bottom) + "px;"; if (p.charAt(1) == "e") pos += "right:" + (m[0] + plotOffset.right) + "px;"; else if (p.charAt(1) == "w") pos += "left:" + (m[0] + plotOffset.left) + "px;"; var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos + ";") + "
").appendTo(placeholder); if (options.legend.backgroundOpacity != 0) { var c = options.legend.backgroundColor; if (c == null) { c = options.grid.backgroundColor; if (c && typeof c == "string") c = $.color.parse(c); else c = $.color.extract(legend, "background-color"); c.a = 1; c = c.toString() } var div = legend.children(); $('
').prependTo(legend).css("opacity", options.legend.backgroundOpacity) } } } var highlights = [], redrawTimeout = null; function findNearbyItem(mouseX, mouseY, seriesFilter) { var maxDistance = options.grid.mouseActiveRadius, smallestDistance = maxDistance * maxDistance + 1, item = null, foundPoint = false, i, j, ps; for (i = series.length - 1; i >= 0; --i) { if (!seriesFilter(series[i])) continue; var s = series[i], axisx = s.xaxis, axisy = s.yaxis, points = s.datapoints.points, mx = axisx.c2p(mouseX), my = axisy.c2p(mouseY), maxx = maxDistance / axisx.scale, maxy = maxDistance / axisy.scale; ps = s.datapoints.pointsize; if (axisx.options.inverseTransform) maxx = Number.MAX_VALUE; if (axisy.options.inverseTransform) maxy = Number.MAX_VALUE; if (s.lines.show || s.points.show) { for (j = 0; j < points.length; j += ps) { var x = points[j], y = points[j + 1]; if (x == null) continue; if (x - mx > maxx || x - mx < -maxx || y - my > maxy || y - my < -maxy) continue; var dx = Math.abs(axisx.p2c(x) - mouseX), dy = Math.abs(axisy.p2c(y) - mouseY), dist = dx * dx + dy * dy; if (dist < smallestDistance) { smallestDistance = dist; item = [i, j / ps] } } } if (s.bars.show && !item) { var barLeft, barRight; switch (s.bars.align) { case "left": barLeft = 0; break; case "right": barLeft = -s.bars.barWidth; break; default: barLeft = -s.bars.barWidth / 2 }barRight = barLeft + s.bars.barWidth; for (j = 0; j < points.length; j += ps) { var x = points[j], y = points[j + 1], b = points[j + 2]; if (x == null) continue; if (series[i].bars.horizontal ? mx <= Math.max(b, x) && mx >= Math.min(b, x) && my >= y + barLeft && my <= y + barRight : mx >= x + barLeft && mx <= x + barRight && my >= Math.min(b, y) && my <= Math.max(b, y)) item = [i, j / ps] } } } if (item) { i = item[0]; j = item[1]; ps = series[i].datapoints.pointsize; return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), dataIndex: j, series: series[i], seriesIndex: i } } return null } function onMouseMove(e) { if (options.grid.hoverable) triggerClickHoverEvent("plothover", e, function (s) { return s["hoverable"] != false }) } function onMouseLeave(e) { if (options.grid.hoverable) triggerClickHoverEvent("plothover", e, function (s) { return false }) } function onClick(e) { triggerClickHoverEvent("plotclick", e, function (s) { return s["clickable"] != false }) } function triggerClickHoverEvent(eventname, event, seriesFilter) { var offset = eventHolder.offset(), canvasX = event.pageX - offset.left - plotOffset.left, canvasY = event.pageY - offset.top - plotOffset.top, pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); pos.pageX = event.pageX; pos.pageY = event.pageY; var item = findNearbyItem(canvasX, canvasY, seriesFilter); if (item) { item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10) } if (options.grid.autoHighlight) { for (var i = 0; i < highlights.length; ++i) { var h = highlights[i]; if (h.auto == eventname && !(item && h.series == item.series && h.point[0] == item.datapoint[0] && h.point[1] == item.datapoint[1])) unhighlight(h.series, h.point) } if (item) highlight(item.series, item.datapoint, eventname) } placeholder.trigger(eventname, [pos, item]) } function triggerRedrawOverlay() { var t = options.interaction.redrawOverlayInterval; if (t == -1) { drawOverlay(); return } if (!redrawTimeout) redrawTimeout = setTimeout(drawOverlay, t) } function drawOverlay() { redrawTimeout = null; octx.save(); overlay.clear(); octx.translate(plotOffset.left, plotOffset.top); var i, hi; for (i = 0; i < highlights.length; ++i) { hi = highlights[i]; if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point); else drawPointHighlight(hi.series, hi.point) } octx.restore(); executeHooks(hooks.drawOverlay, [octx]) } function highlight(s, point, auto) { if (typeof s == "number") s = series[s]; if (typeof point == "number") { var ps = s.datapoints.pointsize; point = s.datapoints.points.slice(ps * point, ps * (point + 1)) } var i = indexOfHighlight(s, point); if (i == -1) { highlights.push({ series: s, point: point, auto: auto }); triggerRedrawOverlay() } else if (!auto) highlights[i].auto = false } function unhighlight(s, point) { if (s == null && point == null) { highlights = []; triggerRedrawOverlay(); return } if (typeof s == "number") s = series[s]; if (typeof point == "number") { var ps = s.datapoints.pointsize; point = s.datapoints.points.slice(ps * point, ps * (point + 1)) } var i = indexOfHighlight(s, point); if (i != -1) { highlights.splice(i, 1); triggerRedrawOverlay() } } function indexOfHighlight(s, p) { for (var i = 0; i < highlights.length; ++i) { var h = highlights[i]; if (h.series == s && h.point[0] == p[0] && h.point[1] == p[1]) return i } return -1 } function drawPointHighlight(series, point) { var x = point[0], y = point[1], axisx = series.xaxis, axisy = series.yaxis, highlightColor = typeof series.highlightColor === "string" ? series.highlightColor : $.color.parse(series.color).scale("a", .5).toString(); if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) return; var pointRadius = series.points.radius + series.points.lineWidth / 2; octx.lineWidth = pointRadius; octx.strokeStyle = highlightColor; var radius = 1.5 * pointRadius; x = axisx.p2c(x); y = axisy.p2c(y); octx.beginPath(); if (series.points.symbol == "circle") octx.arc(x, y, radius, 0, 2 * Math.PI, false); else series.points.symbol(octx, x, y, radius, false); octx.closePath(); octx.stroke() } function drawBarHighlight(series, point) { var highlightColor = typeof series.highlightColor === "string" ? series.highlightColor : $.color.parse(series.color).scale("a", .5).toString(), fillStyle = highlightColor, barLeft; switch (series.bars.align) { case "left": barLeft = 0; break; case "right": barLeft = -series.bars.barWidth; break; default: barLeft = -series.bars.barWidth / 2 }octx.lineWidth = series.bars.lineWidth; octx.strokeStyle = highlightColor; drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, function () { return fillStyle }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth) } function getColorOrGradient(spec, bottom, top, defaultColor) { if (typeof spec == "string") return spec; else { var gradient = ctx.createLinearGradient(0, top, 0, bottom); for (var i = 0, l = spec.colors.length; i < l; ++i) { var c = spec.colors[i]; if (typeof c != "string") { var co = $.color.parse(defaultColor); if (c.brightness != null) co = co.scale("rgb", c.brightness); if (c.opacity != null) co.a *= c.opacity; c = co.toString() } gradient.addColorStop(i / (l - 1), c) } return gradient } } } $.plot = function (placeholder, data, options) { var plot = new Plot($(placeholder), data, options, $.plot.plugins); return plot }; $.plot.version = "0.8.3"; $.plot.plugins = []; $.fn.plot = function (data, options) { return this.each(function () { $.plot(this, data, options) }) }; function floorInBase(n, base) { return base * Math.floor(n / base) } })(jQuery); \ No newline at end of file diff --git a/pandora_console/include/lib/Dashboard/Widgets/inventory.php b/pandora_console/include/lib/Dashboard/Widgets/inventory.php index fe0d5fe308..1bcacf4da8 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/inventory.php +++ b/pandora_console/include/lib/Dashboard/Widgets/inventory.php @@ -30,6 +30,8 @@ namespace PandoraFMS\Dashboard; global $config; +require_once $config['homedir'].'/include/functions_inventory.php'; + /** * Inventory Widget. */ @@ -608,7 +610,7 @@ class InventoryWidget extends Widget } } - $id_table = 'id_'.$row['id_module_inventory'].'_'.$nodo['server_uid']; + $id_table = 'id_'.$row['id_module_inventory'].'_'.uniqid().'_'.$nodo['server_uid']; $table = ui_print_datatable( [ 'id' => $id_table, @@ -619,7 +621,7 @@ class InventoryWidget extends Widget 'no_sortable_columns' => [], 'data_element' => $data, 'searching' => true, - 'dom_elements' => 'frtilp', + 'dom_elements' => 'rtilp', 'order' => [ 'field' => $columns[0], 'direction' => 'asc', @@ -727,7 +729,7 @@ class InventoryWidget extends Widget } } - $id_table = 'id_'.$row['id_module_inventory'].'_'.$nodo['server_uid']; + $id_table = 'id_'.$row['id_module_inventory'].'_'.uniqid().'_'.$nodo['server_uid']; $table = ui_print_datatable( [ @@ -739,7 +741,7 @@ class InventoryWidget extends Widget 'no_sortable_columns' => [], 'data_element' => $data, 'searching' => true, - 'dom_elements' => 'frtilp', + 'dom_elements' => 'rtilp', 'order' => [ 'field' => $columns[0], 'direction' => 'asc', @@ -893,7 +895,7 @@ class InventoryWidget extends Widget } } - $id_table = 'id_'.$key_row.'_'.$row['id_module_inventory'].'_'.$row['id_agente']; + $id_table = 'id_'.$key_row.'_'.$row['id_module_inventory'].'_'.uniqid().'_'.$row['id_agente']; $table = ui_print_datatable( [ @@ -905,7 +907,7 @@ class InventoryWidget extends Widget 'no_sortable_columns' => [], 'data_element' => $data, 'searching' => true, - 'dom_elements' => 'frtilp', + 'dom_elements' => 'rtilp', 'order' => [ 'field' => $columns[0], 'direction' => 'asc', @@ -985,7 +987,7 @@ class InventoryWidget extends Widget array_push($data, $data_tmp); } - $id_table = 'id_'.$row['id_module_inventory']; + $id_table = 'id_'.$row['id_module_inventory'].'_'.uniqid(); } if ($count_rows > 1) { @@ -999,7 +1001,7 @@ class InventoryWidget extends Widget 'no_sortable_columns' => [], 'data_element' => $data, 'searching' => true, - 'dom_elements' => 'frtilp', + 'dom_elements' => 'rtilp', 'order' => [ 'field' => $columns[0], 'direction' => 'asc', @@ -1035,7 +1037,7 @@ class InventoryWidget extends Widget 'no_sortable_columns' => [], 'data_element' => $data, 'searching' => true, - 'dom_elements' => 'frtilp', + 'dom_elements' => 'rtilp', 'order' => [ 'field' => $columns[0], 'direction' => 'asc', @@ -1098,7 +1100,7 @@ class InventoryWidget extends Widget 'columns' => $columns, 'column_names' => $columns_names, 'ordering' => $ordering, - 'dom_elements' => 'frtilp', + 'dom_elements' => 'rtilp', 'searching' => $searching, 'order' => [ 'field' => $columns[0], diff --git a/pandora_console/include/lib/Dashboard/Widgets/single_graph.php b/pandora_console/include/lib/Dashboard/Widgets/single_graph.php index 957159824c..dd8cb160a7 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/single_graph.php +++ b/pandora_console/include/lib/Dashboard/Widgets/single_graph.php @@ -300,6 +300,10 @@ class SingleGraphWidget extends Widget $values['period'] = SECONDS_1DAY; } + if (isset($values['period_projection']) === false) { + $values['period_projection'] = SECONDS_1DAY; + } + if (isset($values['showLegend']) === false) { $values['showLegend'] = 1; } @@ -439,7 +443,7 @@ class SingleGraphWidget extends Widget $trickHight = 0; if ($this->values['showLegend'] === 1) { // Needed for legend. - $trickHight = 40; + $trickHight = 60; } $output = '
'; @@ -448,10 +452,16 @@ class SingleGraphWidget extends Widget 'period' => $this->values['period'], 'date' => strtotime(date('Y-m-d H:i:s')), 'only_image' => false, - 'homeurl' => ui_get_full_url(false, false, false, false).'/', 'height' => ((int) $size['height'] - $trickHight), 'landscape' => $content['landscape'], 'return_img_base_64' => true, + 'show_legend' => $this->values['showLegend'], + 'width' => '100%', + 'height' => ((int) $size['height'] - $trickHight), + 'title' => $module_name, + 'unit' => $units_name, + 'homeurl' => $config['homeurl'], + 'menu' => false, ]; $params_combined = [ diff --git a/pandora_console/include/styles/dashboards.css b/pandora_console/include/styles/dashboards.css index 2cda2de6f4..818e523316 100644 --- a/pandora_console/include/styles/dashboards.css +++ b/pandora_console/include/styles/dashboards.css @@ -949,3 +949,7 @@ input.resize_button { bottom: 3%; right: 6%; } + +.parent_graph > .graph { + margin-left: 10px; +} diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 26df195090..63179618b1 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -1292,6 +1292,11 @@ p.center { margin: 0 5px; } +.loading-text { + font-size: 19px; + text-align: center; +} + /* Legacy spinner */ #loading { position: fixed; diff --git a/pandora_console/install.php b/pandora_console/install.php index bd099564eb..1b461bc6ee 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -131,7 +131,7 @@
'container_netflow', 'class' => $netflowContainerClass, 'content' => netflow_draw_item( $date_from, @@ -677,6 +679,22 @@ if (empty($draw) === false) { ), ] ); + $spinner = html_print_div( + [ + 'content' => '', + 'class' => 'spinner-fixed inherit', + 'style' => 'position: initial;', + ], + true + ); + html_print_div( + [ + 'id' => 'spinner', + 'content' => '

'.__('Loading netflow data, please wait...').'

'.$spinner, + 'class' => 'invisible', + 'style' => 'position: initial;', + ] + ); } } else { ui_print_info_message(__('No data to show')); @@ -934,6 +952,11 @@ ui_include_time_picker(); $('#filter_group_color').css('color', '#000000'); } }); + + $("#button-draw_button").on('click', function(){ + $("#container_netflow").remove(); + $("#spinner").removeClass("invisible"); + }); }); $("#text-time, #text-time_lower").timepicker({ diff --git a/pandora_console/operation/network/network_report.php b/pandora_console/operation/network/network_report.php index d3f736c13d..66847f4c1b 100644 --- a/pandora_console/operation/network/network_report.php +++ b/pandora_console/operation/network/network_report.php @@ -135,11 +135,53 @@ if ($advanced_filter !== '') { $filter['advanced_filter'] = $advanced_filter; } +$filter_name = get_parameter('filter_name'); + $order_by = get_parameter('order_by', 'bytes'); if (!in_array($order_by, ['bytes', 'pkts', 'flows'])) { $order_by = 'bytes'; } + +$save = get_parameter('save_button', ''); +$update = get_parameter('update_button', ''); + +// Save user defined filter. +if ($save != '' && check_acl($config['id_user'], 0, 'AW')) { + // Save filter args. + $data['filter_name'] = $filter_name; + $data['top'] = $top; + $data['action'] = $action; + $data['advanced_filter'] = $advanced_filter; + + + $filter_id = db_process_sql_insert('tnetwork_explorer_filter', $data); + if ($filter_id === false) { + $filter_id = 0; + ui_print_error_message(__('Error creating filter')); + } else { + ui_print_success_message(__('Filter created successfully')); + } +} else if ($update != '' && check_acl($config['id_user'], 0, 'AW')) { + // Update current filter. + // Do not update the filter name and group. + $data['top'] = $top; + $data['action'] = $action; + $data['advanced_filter'] = $advanced_filter; + + $result = db_process_sql_update( + 'tnetwork_explorer_filter', + $data, + ['id' => $filter_id] + ); + ui_print_result_message( + $result, + __('Filter updated successfully'), + __('Error updating filter') + ); +} + + // Build the table. $filterTable = new stdClass(); $filterTable->id = ''; @@ -176,6 +218,59 @@ $filterTable->data[0][1] = html_print_label_input_block( html_print_select_date_range('date', true) ); +$filterTable->data[1][0] = html_print_label_input_block( + __('Data to show'), + html_print_select( + network_get_report_actions(), + 'action', + $action, + '', + '', + 0, + true + ) +); + +$advanced_toggle = new stdClass(); +$advanced_toggle->class = 'filter-table-adv'; +$advanced_toggle->size = []; +$advanced_toggle->size[0] = '50%'; +$advanced_toggle->size[1] = '50%'; +$advanced_toggle->width = '100%'; +$user_groups = users_get_groups($config['id_user'], 'AR', $own_info['is_admin'], true); +$user_groups[0] = 0; +// Add all groups. +$sql = 'SELECT * FROM tnetwork_explorer_filter'; +$advanced_toggle->data[0][0] = html_print_label_input_block( + __('Load Filter'), + html_print_select_from_sql($sql, 'filter_id', $filter_id, '', __('Select a filter'), 0, true, false, true, false, 'width:100%;') +); +$advanced_toggle->data[0][1] = html_print_label_input_block( + __('Filter name'), + html_print_input_text('filter_name', $filter_name, false, 40, 45, true, false, false, '', 'w100p') +); +$advanced_toggle->colspan[1][0] = 2; +$advanced_toggle->data[1][0] = html_print_label_input_block( + __('Filter').ui_print_help_icon('pcap_filter', true), + html_print_textarea('advanced_filter', 4, 10, $advanced_filter, 'style="width:100%"', true) +); +$filterTable->colspan[2][0] = 3; +$filterTable->data[2][0] = html_print_label_input_block( + '', + ui_toggle( + html_print_table($advanced_toggle, true), + __('Advanced'), + '', + '', + true, + true, + '', + 'white-box-content', + 'box-flat white_table_graph' + ) +); + + $filterInputTable = ''; $filterInputTable .= html_print_input_hidden('order_by', $order_by); $filterInputTable .= html_print_table($filterTable, true); @@ -262,12 +357,16 @@ $data = netflow_get_top_summary( // Get the params to return the builder. $hidden_main_link = [ - 'time_greater' => $time_greater, - 'date_greater' => $date_greater, - 'time_lower' => $time_lower, - 'date_lower' => $date_lower, - 'top' => $top, - 'action' => $action, + 'custom_date' => get_parameter('custom_date', '0'), + 'date' => get_parameter('date', SECONDS_1DAY), + 'date_init' => get_parameter('date_init'), + 'time_init' => get_parameter('time_init'), + 'date_end' => get_parameter('date_end'), + 'time_end' => get_parameter('time_end'), + 'date_text' => get_parameter('date_text'), + 'date_units' => get_parameter('date_units'), + 'top' => $top, + 'action' => $action, ]; unset($table); @@ -449,6 +548,7 @@ if (empty($data)) { // Print results. html_print_div( [ + 'id' => 'content-netflow', 'style' => 'max-width: -webkit-fill-available; display: flex', 'class' => '', 'content' => $resultsTable.$pieGraph, @@ -456,11 +556,25 @@ if (empty($data)) { ); } +$spinner = html_print_div( + [ + 'content' => '', + 'class' => 'spinner-fixed inherit', + 'style' => 'position: initial;', + ], + true +); +html_print_div( + [ + 'id' => 'spinner', + 'content' => '

'.__('Loading netflow data, please wait...').'

'.$spinner, + 'class' => 'invisible', + 'style' => 'position: initial;', + ] +); ?>