width = $width; // Height. $this->height = $height; // Grid Width. $this->gridWidth = $gridWidth; // Cell Id. $this->cellId = $cellId; // Options. $this->values = $this->decoders($this->getOptionsWidget()); // Positions. $this->position = $this->getPositionWidget(); // Page. $this->page = basename(__FILE__); // ClassName. $class = new \ReflectionClass($this); $this->className = $class->getShortName(); // Title. $this->title = __('Color tabs modules'); // Name. if (empty($this->name) === true) { $this->name = 'single_graph'; } // This forces at least a first configuration. $this->configurationRequired = false; if (empty($this->values['moduleGroupedMeterGraphs']) === true) { $this->configurationRequired = true; } $this->overflow_scrollbars = false; } /** * Decoders hack for retrocompability. * * @param array $decoder Values. * * @return array Returns the values ​​with the correct key. */ public function decoders(array $decoder): array { $values = []; // Retrieve global - common inputs. $values = parent::decoders($decoder); $values['agentsGroupedMeterGraphs'] = []; if (isset($decoder['agentsGroupedMeterGraphs']) === true) { if (isset($decoder['agentsGroupedMeterGraphs'][0]) === true && empty($decoder['agentsGroupedMeterGraphs']) === false ) { $values['agentsGroupedMeterGraphs'] = explode( ',', $decoder['agentsGroupedMeterGraphs'][0] ); } } if (isset($decoder['selectionGroupedMeterGraphs']) === true) { $values['selectionGroupedMeterGraphs'] = $decoder['selectionGroupedMeterGraphs']; } $values['moduleGroupedMeterGraphs'] = []; if (isset($decoder['moduleGroupedMeterGraphs']) === true) { if (empty($decoder['moduleGroupedMeterGraphs']) === false) { $values['moduleGroupedMeterGraphs'] = $decoder['moduleGroupedMeterGraphs']; } } if (isset($decoder['formatData']) === true) { $values['formatData'] = $decoder['formatData']; } if (isset($decoder['manualThresholds']) === true) { $values['manualThresholds'] = $decoder['manualThresholds']; } $values['label'] = 'module'; if (isset($decoder['label']) === true) { $values['label'] = $decoder['label']; } $values['min_value'] = null; if (isset($decoder['min_value']) === true) { $values['min_value'] = $decoder['min_value']; } $values['max_value'] = null; if (isset($decoder['max_value']) === true) { $values['max_value'] = $decoder['max_value']; } $values['min_critical'] = null; if (isset($decoder['min_critical']) === true) { $values['min_critical'] = $decoder['min_critical']; } $values['max_critical'] = null; if (isset($decoder['max_critical']) === true) { $values['max_critical'] = $decoder['max_critical']; } $values['min_warning'] = null; if (isset($decoder['min_warning']) === true) { $values['min_warning'] = $decoder['min_warning']; } $values['max_warning'] = null; if (isset($decoder['max_warning']) === true) { $values['max_warning'] = $decoder['max_warning']; } if (isset($decoder['fontColor']) === true) { $values['fontColor'] = $decoder['fontColor']; } return $values; } /** * Generates inputs for form (specific). * * @return array Of inputs. * * @throws Exception On error. */ public function getFormInputs(): array { $values = $this->values; // Retrieve global - common inputs. $inputs = parent::getFormInputs(); $blocks = [ 'row1', 'row2', ]; $inputs['blocks'] = $blocks; foreach ($inputs as $kInput => $vInput) { $inputs['inputs']['row1'][] = $vInput; } if (empty($values['fontColor']) === true) { $values['fontColor'] = '#2c3e50'; } $inputs['inputs']['row1'][] = [ 'label' => __('Font color'), 'arguments' => [ 'wrapper' => 'div', 'name' => 'fontColor', 'type' => 'color', 'value' => $values['fontColor'], 'return' => true, ], ]; // Format Data. $inputs['inputs']['row1'][] = [ 'label' => __('Format Data'), 'arguments' => [ 'name' => 'formatData', 'id' => 'formatData', 'type' => 'switch', 'value' => $values['formatData'], ], ]; $inputs['inputs']['row1'][] = [ 'class' => 'dashboard-input-threshold', 'direct' => 1, 'block_content' => [ [ 'label' => __('Values'), 'arguments' => [], ], [ 'label' => __('Min'), 'arguments' => [ 'name' => 'min_value', 'id' => 'min_value', 'type' => 'number', 'value' => $values['min_value'], ], ], [ 'label' => __('Max'), 'arguments' => [ 'name' => 'max_value', 'id' => 'max_value', 'type' => 'number', 'value' => $values['max_value'], ], ], ], ]; // Format Data. $inputs['inputs']['row1'][] = [ 'label' => __('Manual thresholds'), 'arguments' => [ 'name' => 'manualThresholds', 'id' => 'manualThresholds', 'type' => 'switch', 'value' => $values['manualThresholds'], 'onchange' => 'showManualThresholds(this)', ], ]; $class_invisible = ''; if ((bool) $values['manualThresholds'] !== true) { $class_invisible = 'invisible_important'; } $inputs['inputs']['row1'][] = [ 'class' => 'dashboard-input-threshold dashboard-input-threshold-warning '.$class_invisible, 'direct' => 1, 'block_content' => [ [ 'label' => __('Warning threshold'), 'arguments' => [], ], [ 'label' => __('Min'), 'arguments' => [ 'name' => 'min_warning', 'id' => 'min_warning', 'type' => 'number', 'value' => $values['min_warning'], ], ], [ 'label' => __('Max'), 'arguments' => [ 'name' => 'max_warning', 'id' => 'max_warning', 'type' => 'number', 'value' => $values['max_warning'], ], ], ], ]; $inputs['inputs']['row1'][] = [ 'class' => 'dashboard-input-threshold dashboard-input-threshold-critical '.$class_invisible, 'direct' => 1, 'block_content' => [ [ 'label' => __('Critical threshold'), 'arguments' => [], ], [ 'label' => __('Min'), 'arguments' => [ 'name' => 'min_critical', 'id' => 'min_critical', 'type' => 'number', 'value' => $values['min_critical'], ], ], [ 'label' => __('Max'), 'arguments' => [ 'name' => 'max_critical', 'id' => 'max_critical', 'type' => 'number', 'value' => $values['max_critical'], ], ], ], ]; // Type Label. $fields = [ 'module' => __('Module'), 'agent' => __('Agent'), 'agent_module' => __('Agent / module'), ]; $inputs['inputs']['row2'][] = [ 'label' => __('Label'), 'arguments' => [ 'type' => 'select', 'fields' => $fields, 'name' => 'label', 'selected' => $values['label'], 'return' => true, ], ]; $inputs['inputs']['row2'][] = [ 'arguments' => [ 'type' => 'select_multiple_modules_filtered_select2', 'agent_values' => agents_get_agents_selected(0), 'agent_name' => 'agentsGroupedMeterGraphs[]', 'agent_ids' => $values['agentsGroupedMeterGraphs'], 'selectionModules' => $values['selectionGroupedMeterGraphs'], 'selectionModulesNameId' => 'selectionGroupedMeterGraphs', 'modules_ids' => $values['moduleGroupedMeterGraphs'], 'modules_name' => 'moduleGroupedMeterGraphs[]', 'notStringModules' => true, ], ]; return $inputs; } /** * Get Post for widget. * * @return array */ public function getPost():array { // Retrieve global - common inputs. $values = parent::getPost(); $values['agentsGroupedMeterGraphs'] = \get_parameter( 'agentsGroupedMeterGraphs', [] ); $values['selectionGroupedMeterGraphs'] = \get_parameter( 'selectionGroupedMeterGraphs', 0 ); $values['moduleGroupedMeterGraphs'] = \get_parameter( 'moduleGroupedMeterGraphs' ); $agColor = []; if (isset($values['agentsGroupedMeterGraphs'][0]) === true && empty($values['agentsGroupedMeterGraphs'][0]) === false ) { $agColor = explode(',', $values['agentsGroupedMeterGraphs'][0]); } $agModule = []; if (isset($values['moduleGroupedMeterGraphs'][0]) === true && empty($values['moduleGroupedMeterGraphs'][0]) === false ) { $agModule = explode(',', $values['moduleGroupedMeterGraphs'][0]); } $values['moduleGroupedMeterGraphs'] = get_same_modules_all( $agColor, $agModule ); $values['formatData'] = \get_parameter_switch('formatData', 0); $values['fontColor'] = \get_parameter('fontColor', '#2c3e50'); $values['label'] = \get_parameter('label', 'module'); $values['min_value'] = \get_parameter('min_value', null); $values['max_value'] = \get_parameter('max_value', null); $values['manualThresholds'] = \get_parameter_switch('manualThresholds', 0); $values['min_critical'] = \get_parameter('min_critical', null); $values['max_critical'] = \get_parameter('max_critical', null); $values['min_warning'] = \get_parameter('min_warning', null); $values['max_warning'] = \get_parameter('max_warning', null); return $values; } /** * Draw widget. * * @return string; */ public function load() { $this->size = parent::getSize(); $this->boxNumber = ceil(($this->size['width'] * 0.65) / self::RATIO_WITH_BOX); $output = ''; if (is_metaconsole() === true) { $modules_nodes = array_reduce( $this->values['moduleGroupedMeterGraphs'], function ($carry, $item) { $explode = explode('|', $item); $carry[$explode[0]][] = $explode[1]; return $carry; }, [] ); $modules = []; foreach ($modules_nodes as $n => $mod) { try { $node = new Node((int) $n); $node->connect(); $node_mods = $this->getInfoModules($mod); if (empty($node_mods) === false) { foreach ($node_mods as $value) { $value['id_node'] = $n; $value['server_name'] = $node->toArray()['server_name']; $modules[] = $value; } } $node->disconnect(); } catch (\Exception $e) { // Unexistent agent. $node->disconnect(); } } } else { $modules = $this->getInfoModules( $this->values['moduleGroupedMeterGraphs'] ); } if ($modules !== false && empty($modules) === false && is_array($modules) === true ) { if (count($modules) > self::MAX_MODULES) { $output .= '
'; $output .= \ui_print_info_message( __( 'The maximum number of modules to display is %d, please reconfigure the widget.', self::MAX_MODULES ), '', true ); $output .= '
'; return $output; } $max = null; $min = null; // Dinamic treshold. if ($this->values['min_critical'] !== null || $this->values['max_critical'] !== null || $this->values['min_warning'] !== null || $this->values['max_warning'] !== null ) { if ($this->values['max_value'] === null || $this->values['min_value'] === null) { $tresholdData = [ ($this->values['min_critical'] ?? 0), ($this->values['max_critical'] ?? 0), ($this->values['min_warning'] ?? 0), ($this->values['max_warning'] ?? 0), ]; $moduleData = array_map( function ($module) { return ($module['data'] ?? 0); }, $modules ); } if ($this->values['max_value'] === null) { $max = max( array_merge( $moduleData, $tresholdData ) ); } else { $max = $this->values['max_value']; } // Increases max. if ($this->values['max_critical'] === null && $this->values['max_value'] === null) { $max_increase = ($max * self::MAX_INCREASE); $max = ($max + $max_increase); } if ($this->values['min_value'] === null) { $min = min( array_merge( $moduleData, $tresholdData ) ); } else { $min = $this->values['min_value']; } $tresholds_array = [ 'min_critical' => $this->values['min_critical'], 'max_critical' => $this->values['max_critical'], 'min_warning' => $this->values['min_warning'], 'max_warning' => $this->values['max_warning'], ]; $this->thresholds = $this->calculateThreshold($max, $min, $tresholds_array); } $style = 'color:'.$this->values['fontColor'].';'; $output .= '
'; foreach ($modules as $module) { $output .= $this->drawRowModule( $module, $max, $min ); } $output .= '
'; } else { $output .= '
'; $output .= \ui_print_info_message( __('Not found modules'), '', true ); $output .= '
'; } return $output; } /** * Get info modules. * * @param array $modules Modules. * * @return array Data. */ private function getInfoModules(array $modules): array { $where = sprintf( 'tagente_modulo.id_agente_modulo IN (%s) AND tagente_modulo.delete_pending = 0', implode(',', $modules) ); $sql = sprintf( 'SELECT tagente_modulo.id_agente_modulo AS `id`, tagente_modulo.nombre AS `name`, tagente_modulo.unit AS `unit`, tagente_modulo.min_warning AS w_min, tagente_modulo.max_warning AS w_max, tagente_modulo.str_warning AS w_str, tagente_modulo.min_critical AS c_min, tagente_modulo.max_critical AS c_max, tagente_modulo.str_critical AS c_str, tagente_modulo.id_tipo_modulo AS type_module, tagente_estado.datos AS `data`, tagente_estado.timestamp AS `timestamp`, tagente_estado.estado AS `status`, tagente.alias FROM tagente_modulo LEFT JOIN tagente_estado ON tagente_modulo.id_agente_modulo = tagente_estado.id_agente_modulo LEFT JOIN tagente ON tagente_modulo.id_agente = tagente.id_agente WHERE %s', $where ); $modules = db_get_all_rows_sql($sql); if ($modules === false) { $modules = []; } return $modules; } /** * Draw info module. * * @param array $data Data module. * @param null|float $max Value max. * @param null|float $min Value min. * * @return string */ private function drawRowModule( array $data, ?float $max, ?float $min ):string { global $config; // Dinamic. if ($max === null && $min === null) { $all_values_module = [ ($data['w_min'] ?? 0), ($data['w_max'] ?? 0), ($data['c_min'] ?? 0), ($data['c_max'] ?? 0), ($data['data'] ?? 0), ]; if ($this->values['max_value'] === null) { $max = max($all_values_module); } else { $max = $this->values['max_value']; } // Increases max. if (empty($data['c_max']) === true && $this->values['max_value'] === null ) { $max_increase = ($max * self::MAX_INCREASE); $max = ($max + $max_increase); } $min = 0; if ($this->values['min_value'] !== null) { $min = $this->values['min_value']; } $thresholds_array = [ 'min_critical' => (empty($data['c_min']) === true) ? null : $data['c_min'], 'max_critical' => (empty($data['c_max']) === true) ? null : $data['c_max'], 'min_warning' => (empty($data['w_min']) === true) ? null : $data['w_min'], 'max_warning' => (empty($data['w_max']) === true) ? null : $data['w_max'], ]; $this->thresholds = $this->calculateThreshold( $max, $min, $thresholds_array ); } $module_data = $this->getBoxPercentageMaths($max, $min, (float) $data['data']); $output = ''; $output .= '
'; // Module name. $name = ''; switch ($this->values['label']) { case 'agent': $name = $data['alias']; break; case 'agent_module': $name = $data['alias'].' / '.$data['name']; break; default: case 'module': $name = $data['name']; break; } $output .= '
'; $output .= $name; $output .= '
'; // Graphs. $output .= '
'; for ($i = 0; $i < $this->boxNumber; $i++) { $class = 'meter-graph-'; $class .= $this->getThresholdStatus($i); if ($module_data > $i) { $class .= ' meter-graph-opacity'; } $output .= '
'; $output .= '
'; } $output .= '
'; // Data. $class = 'container-info-module-meter-data'; $class .= ' meter-data-'; $class .= $this->getThresholdStatus($module_data); $result_data = ''; if ($data['data'] !== null && $data['data'] !== '') { if (isset($this->values['formatData']) === true && (bool) $this->values['formatData'] === true ) { $result_data .= format_for_graph( $data['data'], $config['graph_precision'] ); } else { $result_data .= sla_truncate( $data['data'], $config['graph_precision'] ); } $result_data .= ' '.$data['unit']; } else { $result_data .= '--'; } $output .= '
'; $output .= $result_data; $output .= '
'; $output .= '
'; return $output; } /** * Get status. * * @return array */ private static function getStatuses() { return [ self::STATUS_CRITICAL, self::STATUS_WARNING, self::STATUS_NORMAL, ]; } /** * Get tresholds. * * @param float $max Value max. * @param float $min Value min. * @param array $thresholds_array Array thresholds. * * @return array Array threshold. */ private function calculateThreshold(float $max, float $min, array $thresholds_array) { $nMax = null; if ($thresholds_array['min_warning'] !== null) { $nMax = $this->getBoxPercentageMaths($max, $min, $thresholds_array['min_warning']); } $wMin = null; if ($thresholds_array['min_warning'] !== null) { $wMin = $this->getBoxPercentageMaths($max, $min, $thresholds_array['min_warning']); } $wMax = null; if ($thresholds_array['max_warning'] !== null) { $wMax = $this->getBoxPercentageMaths($max, $min, $thresholds_array['max_warning']); } $cMin = null; if ($thresholds_array['min_critical'] !== null) { $cMin = $this->getBoxPercentageMaths($max, $min, $thresholds_array['min_critical']); } $cMax = null; if ($thresholds_array['max_critical'] !== null) { $cMax = $this->getBoxPercentageMaths($max, $min, $thresholds_array['max_critical']); } $thresholds = [ 'normal' => [ 'min' => $this->getBoxPercentageMaths($max, $min, $min), 'max' => $nMax, ], 'warning' => [ 'min' => $wMin, 'max' => $wMax, ], 'critical' => [ 'min' => $cMin, 'max' => $cMax, ], ]; return $thresholds; } /** * Get porcentage. * * @param float $max Maximum. * @param float $min Minimum. * @param float $value Value. * * @return float */ private function getBoxPercentageMaths( float $max, float $min, float $value ):float { if ($min === 0.00 && $max === 0.00) { return 0; } return (((($value - $min) / ($max - $min))) * $this->boxNumber); } /** * Get status compare tresholds. * * @param float $value Value to compare. * * @return string */ private function getThresholdStatus( float $value ) { foreach (self::getStatuses() as $status) { if ($this->thresholds[$status]['min'] === null && $this->thresholds[$status]['max'] === null ) { continue; } if (($this->thresholds[$status]['min'] === null && $this->thresholds[$status]['max'] >= $value) || ($this->thresholds[$status]['max'] === null && $this->thresholds[$status]['min'] <= $value) || ($this->thresholds[$status]['min'] <= $value && $this->thresholds[$status]['max'] >= $value) ) { return $status; } } return self::STATUS_NORMAL; } /** * Get description. * * @return string. */ public static function getDescription() { return __('Grouped meter graphs'); } /** * Get Name. * * @return string. */ public static function getName() { return 'GroupedMeterGraphs'; } /** * Get size Modal Configuration. * * @return array */ public function getSizeModalConfiguration(): array { $size = [ 'width' => (is_metaconsole() === true) ? 1000 : 900, 'height' => 550, ]; return $size; } }