diff --git a/pandora_console/include/class/Heatmap.class.php b/pandora_console/include/class/Heatmap.class.php
new file mode 100644
index 0000000000..1706d6e700
--- /dev/null
+++ b/pandora_console/include/class/Heatmap.class.php
@@ -0,0 +1,452 @@
+type = $type;
+ $this->filter = $filter;
+ (empty($randomId) === true) ? $this->randomId = uniqid() : $this->randomId = $randomId;
+ $this->refresh = $refresh;
+ }
+
+
+ /**
+ * Show .
+ *
+ * @return void
+ */
+ public function run()
+ {
+ ui_require_css_file('heatmap');
+
+ $settings = [
+ 'type' => 'POST',
+ 'dataType' => 'html',
+ 'url' => ui_get_full_url(
+ 'ajax.php',
+ false,
+ false,
+ false
+ ),
+ 'data' => [
+ 'page' => 'operation/heatmap',
+ 'method' => 'showHeatmap',
+ 'randomId' => $this->randomId,
+ 'type' => $this->type,
+ 'filter' => $this->filter,
+ 'refresh' => $this->refresh,
+ ],
+ ];
+
+ echo '
';
+ ?>
+
+ ';
+ }
+
+
+ /**
+ * Setter for filter
+ *
+ * @param array $filter Filter.
+ *
+ * @return void
+ */
+ public function setFilter(array $filter)
+ {
+ $this->filter = $filter;
+ }
+
+
+ /**
+ * Setter for type
+ *
+ * @param integer $type Type.
+ *
+ * @return void
+ */
+ public function setType(int $type)
+ {
+ $this->type = $type;
+ }
+
+
+ /**
+ * Setter for refresh
+ *
+ * @param integer $refresh Refresh.
+ *
+ * @return void
+ */
+ public function setRefresh(int $refresh)
+ {
+ $this->refresh = $refresh;
+ }
+
+
+ /**
+ * Get all agents
+ *
+ * @return array
+ */
+ protected function getAllAgents()
+ {
+ // All agents.
+ $result = agents_get_agents(
+ [
+ 'disabled' => 0,
+ // 'search_custom' => $search_sql_custom,
+ // 'search' => $search_sql,
+ ],
+ [
+ 'id_agente',
+ 'alias',
+ 'id_grupo',
+ 'normal_count',
+ 'warning_count',
+ 'critical_count',
+ 'unknown_count',
+ 'notinit_count',
+ 'total_count',
+ 'fired_count',
+ ],
+ 'AR',
+ [
+ 'field' => 'id_grupo,id_agente',
+ 'order' => 'ASC',
+ ]
+ );
+
+ $agents = [];
+ // Agent status.
+ foreach ($result as $agent) {
+ if ($agent['total_count'] === 0 || $agent['total_count'] === $agent['notinit_count']) {
+ $status = 'notinit';
+ } else if ($agent['critical_count'] > 0) {
+ $status = 'critical';
+ } else if ($agent['warning_count'] > 0) {
+ $status = 'warning';
+ } else if ($agent['unknown_count'] > 0) {
+ $status = 'unknown';
+ } else {
+ $status = 'normal';
+ }
+
+ $agents[$agent['id_agente']] = $agent;
+ $agents[$agent['id_agente']]['status'] = $status;
+ }
+
+ $status = [
+ 'normal',
+ 'critical',
+ 'warning',
+ 'unknown',
+ 'normal',
+ ];
+
+ // -------------------Agent generator--------------------
+ $a = 1;
+ $agents = [];
+ $total = 1000;
+ while ($a <= $total) {
+ $agents[$a]['id_agente'] = $a;
+ $agents[$a]['status'] = $this->statusColour(rand(4, 0));
+ $agents[$a]['id_grupo'] = ceil($a / 10);
+ $a++;
+ }
+
+ // -------------------------------------------
+ return $agents;
+ }
+
+
+ /**
+ * GetDataJson
+ *
+ * @return json
+ */
+ public function getDataJson()
+ {
+ $return = $this->getAllAgents();
+ echo json_encode($return);
+ return;
+ }
+
+
+ /**
+ * Get colour by status
+ *
+ * @param integer $status Status.
+ *
+ * @return string
+ */
+ protected function statusColour(int $status)
+ {
+ switch ($status) {
+ case AGENT_STATUS_CRITICAL:
+ $return = 'critical';
+ break;
+
+ case AGENT_STATUS_WARNING:
+ $return = 'warning';
+ break;
+
+ case AGENT_STATUS_UNKNOWN:
+ $return = 'unknown';
+ break;
+
+ case AGENT_STATUS_NOT_INIT:
+ $return = 'notinit';
+ break;
+
+ case AGENT_STATUS_NORMAL:
+ default:
+ $return = 'normal';
+ break;
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Get max. number of y-axis
+ *
+ * @param integer $total Total.
+ *
+ * @return integer
+ */
+ protected function getYAxis(int $total)
+ {
+ $yAxis = ceil(sqrt(($total / 2)));
+ return (integer) $yAxis;
+
+ }
+
+
+ /**
+ * Checks if target method is available to be called using AJAX.
+ *
+ * @param string $method Target method.
+ *
+ * @return boolean True allowed, false not.
+ */
+ public function ajaxMethod(string $method):bool
+ {
+ return in_array($method, $this->AJAXMethods);
+ }
+
+
+ /**
+ * ShowHeatmap
+ *
+ * @return void
+ */
+ public function showHeatmap()
+ {
+ switch ($this->type) {
+ case 0:
+ default:
+ $result = $this->getAllAgents();
+ break;
+ }
+
+ $Yaxis = $this->getYAxis(count($result));
+ $Xaxis = ($Yaxis * 2);
+ $viewBox = sprintf(
+ '0 0 %d %d',
+ $Xaxis,
+ $Yaxis
+ );
+
+ echo '
';
+ }
+
+
+}
diff --git a/pandora_console/include/styles/heatmap.css b/pandora_console/include/styles/heatmap.css
new file mode 100644
index 0000000000..c90304885e
--- /dev/null
+++ b/pandora_console/include/styles/heatmap.css
@@ -0,0 +1,37 @@
+.mainDiv {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
+
+.normal {
+ fill: #82b92e;
+}
+
+.critical {
+ fill: #e63c52;
+}
+
+.warning {
+ fill: #f3b200;
+}
+
+.unknown {
+ fill: #b2b2b2;
+}
+
+.notinit {
+ fill: #4a83f3;
+}
+
+.hover:hover {
+ filter: brightness(1.5);
+ stroke-width: 0.009;
+ stroke: black;
+}
+
+.group {
+ fill: none;
+ stroke-width: 0.03;
+ stroke: black;
+}
diff --git a/pandora_console/operation/heatmap.php b/pandora_console/operation/heatmap.php
new file mode 100644
index 0000000000..591865ac40
--- /dev/null
+++ b/pandora_console/operation/heatmap.php
@@ -0,0 +1,108 @@
+ '',
+ 'label' => __('Monitoring'),
+ ],
+ [
+ 'link' => '',
+ 'label' => __('Views'),
+ ],
+ ]
+ );
+}
+
+$type = get_parameter('type', 0);
+$filter = get_parameter('filter', []);
+$randomId = get_parameter('randomId', null);
+$refresh = get_parameter('refresh', 300);
+
+// Control call flow.
+try {
+ // Heatmap construct.
+ $heatmap = new Heatmap($type, $filter, $randomId, $refresh);
+} catch (Exception $e) {
+ if (is_ajax() === true) {
+ echo json_encode(['error' => '[Heatmap]'.$e->getMessage() ]);
+ exit;
+ } else {
+ echo '[Heatmap]'.$e->getMessage();
+ }
+
+ // Stop this execution, but continue 'globally'.
+ return;
+}
+
+// AJAX controller.
+if ($is_ajax === true) {
+ $method = get_parameter('method');
+
+ if (method_exists($heatmap, $method) === true) {
+ if ($heatmap->ajaxMethod($method) === true) {
+ $heatmap->{$method}();
+ } else {
+ echo 'Unavailable method';
+ }
+ } else {
+ echo 'Method not found';
+ }
+
+ // Stop any execution.
+ exit;
+} else {
+ // Run.
+ $heatmap->run();
+}
diff --git a/pandora_console/operation/menu.php b/pandora_console/operation/menu.php
index b417e20b89..299ed19c03 100644
--- a/pandora_console/operation/menu.php
+++ b/pandora_console/operation/menu.php
@@ -63,9 +63,12 @@ if (check_acl($config['id_user'], 0, 'AR')) {
enterprise_hook('tag_view_submenu');
- $sub2['operation/agentes/alerts_status']['text'] = __('Alert detail');
+ $sub2['operation/agentes/alerts_status']['text'] = __('Alert details');
$sub2['operation/agentes/alerts_status']['refr'] = 0;
+ $sub2['operation/heatmap']['text'] = __('Heatmap view');
+ $sub2['operation/heatmap']['refr'] = 0;
+
$sub['view']['sub2'] = $sub2;
enterprise_hook('inventory_menu');