From 0fdbefa7eecbac24e61d5ffb42391520cd30a334 Mon Sep 17 00:00:00 2001
From: Daniel Cebrian <daniel.cebrian@pandorafms.com>
Date: Mon, 25 Sep 2023 13:52:28 +0200
Subject: [PATCH] #10194 first section drawed

---
 pandora_console/include/functions_graph.php   |   7 +-
 .../include/lib/TacticalView/Element.php      |  19 ++
 .../lib/TacticalView/GeneralTacticalView.php  |  32 ++
 .../lib/TacticalView/elements/Database.php    | 309 ++++++++++++++++++
 .../lib/TacticalView/elements/Groups.php      | 215 ++++++++++++
 .../lib/TacticalView/elements/LogStorage.php  | 141 ++++++++
 .../elements/MonitoringElements.php           | 149 +++++++++
 .../lib/TacticalView/elements/Overview.php    |  18 +-
 .../lib/TacticalView/elements/SnmpTraps.php   |  79 +++++
 .../include/styles/general_tactical_view.css  |  50 ++-
 pandora_console/views/tacticalView/view.php   | 175 ++++++++--
 11 files changed, 1161 insertions(+), 33 deletions(-)
 create mode 100644 pandora_console/include/lib/TacticalView/elements/Database.php
 create mode 100644 pandora_console/include/lib/TacticalView/elements/Groups.php
 create mode 100644 pandora_console/include/lib/TacticalView/elements/LogStorage.php
 create mode 100644 pandora_console/include/lib/TacticalView/elements/SnmpTraps.php

diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php
index bb0fe8fd58..dae91c862c 100644
--- a/pandora_console/include/functions_graph.php
+++ b/pandora_console/include/functions_graph.php
@@ -4842,12 +4842,17 @@ function graph_nodata_image($options)
         return base64_encode($dataImg);
     }
 
+    $widthImage = '200px';
+    if (isset($options['nodata_image']['width']) === true) {
+        $widthImage = $options['nodata_image']['width'];
+    }
+
     return html_print_image(
         'images/image_problem_area.png',
         true,
         [
             'title' => __('No data'),
-            'style' => 'width: 200px;',
+            'style' => 'width: '.$widthImage.';',
         ]
     );
 }
diff --git a/pandora_console/include/lib/TacticalView/Element.php b/pandora_console/include/lib/TacticalView/Element.php
index a97502e0e1..cf0d6b517e 100644
--- a/pandora_console/include/lib/TacticalView/Element.php
+++ b/pandora_console/include/lib/TacticalView/Element.php
@@ -53,4 +53,23 @@ class Element
     }
 
 
+    /**
+     * Cut the text to display it on the labels.
+     *
+     * @param string  $text   Text for cut.
+     * @param integer $length Length max for text cutted.
+     *
+     * @return string
+     */
+    protected function controlSizeText(string $text, int $length=14):string
+    {
+        if (mb_strlen($text) > $length) {
+            $newText = mb_substr($text, 0, $length).'...';
+            return $newText;
+        } else {
+            return $text;
+        }
+    }
+
+
 }
diff --git a/pandora_console/include/lib/TacticalView/GeneralTacticalView.php b/pandora_console/include/lib/TacticalView/GeneralTacticalView.php
index 82b042cf7c..275b82efbd 100644
--- a/pandora_console/include/lib/TacticalView/GeneralTacticalView.php
+++ b/pandora_console/include/lib/TacticalView/GeneralTacticalView.php
@@ -70,6 +70,7 @@ class GeneralTacticalView
         ];
 
         $elements = [];
+        $elements['welcome'] = $this->getWelcomeMessage();
         while (false !== ($file = readdir($handle))) {
             try {
                 if (in_array($file, $ignores) === true) {
@@ -112,4 +113,35 @@ class GeneralTacticalView
     }
 
 
+    /**
+     * Return the welcome message.
+     *
+     * @return string
+     */
+    private function getWelcomeMessage():string
+    {
+        global $config;
+        $profile = users_get_user_profile($config['id_user']);
+        if (is_array($profile) === true && count($profile) > 0) {
+            $name = $profile[0]['name'];
+        } else {
+            $name = '';
+        }
+
+        if (empty($name) === true) {
+            $message = __('Welcome back! đź‘‹');
+        } else {
+            $message = __('Welcome back %s! đź‘‹', $name);
+        }
+
+        return html_print_div(
+            [
+                'content' => $message,
+                'class'   => 'message-welcome',
+            ],
+            true
+        );
+    }
+
+
 }
diff --git a/pandora_console/include/lib/TacticalView/elements/Database.php b/pandora_console/include/lib/TacticalView/elements/Database.php
new file mode 100644
index 0000000000..b7250fb390
--- /dev/null
+++ b/pandora_console/include/lib/TacticalView/elements/Database.php
@@ -0,0 +1,309 @@
+<?php
+/**
+ * Database element for tactical view.
+ *
+ * @category   General
+ * @package    Pandora FMS
+ * @subpackage TacticalView
+ * @version    1.0.0
+ * @license    See below
+ *
+ *    ______                 ___                    _______ _______ ________
+ *   |   __ \.-----.--.--.--|  |.-----.----.-----. |    ___|   |   |     __|
+ *  |    __/|  _  |     |  _  ||  _  |   _|  _  | |    ___|       |__     |
+ * |___|   |___._|__|__|_____||_____|__| |___._| |___|   |__|_|__|_______|
+ *
+ * ============================================================================
+ * Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
+ * This code is NOT free software. This code is NOT licenced under GPL2 licence
+ * You cannnot redistribute it without written permission of copyright holder.
+ * ============================================================================
+ */
+
+use PandoraFMS\TacticalView\Element;
+
+/**
+ * Database, this class contain all logic for this section.
+ */
+class Database extends Element
+{
+
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->title = __('Database');
+    }
+
+
+    /**
+     * Returns the html status of database.
+     *
+     * @return string
+     */
+    public function getStatus():string
+    {
+        // TODO connect to automonitorization.
+        $status = true;
+
+        if ($status === true) {
+            $image_status = html_print_image('images/status_check@svg.svg', true);
+            $text = html_print_div(
+                [
+                    'content' => __('Everything’s OK!'),
+                    'class'   => 'status-text',
+                ],
+                true
+            );
+        } else {
+            $image_status = html_print_image('images/status_error@svg.svg', true);
+            $text = html_print_div(
+                [
+                    'content' => __('Something’s wrong'),
+                    'class'   => 'status-text',
+                ],
+                true
+            );
+        }
+
+        $output = $image_status.$text;
+
+        return html_print_div(
+            [
+                'content' => $output,
+                'class'   => 'flex_center margin-top-5',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html records data of database.
+     *
+     * @return string
+     */
+    public function getDataRecords():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of total events.
+     *
+     * @return string
+     */
+    public function getEvents():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of total records.
+     *
+     * @return string
+     */
+    public function getStringRecords():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of total reads database in a graph.
+     *
+     * @return string
+     */
+    public function getReadsGraph():string
+    {
+        // TODO connect to automonitorization.
+        $dates = [
+            1,
+            2,
+            3,
+            4,
+            5,
+            6,
+            7,
+            8,
+            9,
+            10,
+        ];
+        $string_reads = [
+            1,
+            0.5,
+            2,
+            1.5,
+            3,
+            2.5,
+            4,
+            3.5,
+            5,
+            4.5,
+            6,
+        ];
+        $total = '9.999.999';
+        $options = [
+            'labels'   => $dates,
+            'legend'   => [ 'display' => false ],
+            'tooltips' => [ 'display' => false ],
+            'scales'   => [
+                'y' => [
+                    'grid'    => ['display' => false],
+                    'ticks'   => ['display' => false],
+                    'display' => false,
+                ],
+                'x' => [
+                    'grid'    => ['display' => false],
+                    'display' => false,
+                ],
+            ],
+        ];
+
+        $data = [
+            [
+                'backgroundColor'       => '#EC7176',
+                'borderColor'           => '#EC7176',
+                'pointBackgroundColor'  => '#EC7176',
+                'pointHoverBorderColor' => '#EC7176',
+                'data'                  => $string_reads,
+            ],
+        ];
+
+        $graph_area = html_print_div(
+            [
+                'content' => line_graph($data, $options),
+                'class'   => 'w100p h100p',
+                'style'   => 'max-height: 100px;',
+            ],
+            true
+        );
+
+        $total = html_print_div(
+            [
+                'content' => $total,
+                'class'   => 'text-xl',
+            ],
+            true
+        );
+
+        $output = $total.$graph_area;
+
+        return $output;
+    }
+
+
+    /**
+     * Returns the html of total writes database in a graph.
+     *
+     * @return string
+     */
+    public function getWritesGraph():string
+    {
+        // TODO connect to automonitorization.
+        $dates = [
+            1,
+            2,
+            3,
+            4,
+            5,
+            6,
+            7,
+            8,
+            9,
+            10,
+        ];
+        $string_writes = [
+            1,
+            0.5,
+            2,
+            1.5,
+            3,
+            2.5,
+            4,
+            3.5,
+            5,
+            4.5,
+            6,
+        ];
+        $total = '9.999.999';
+        $options = [
+            'labels'   => $dates,
+            'legend'   => [ 'display' => false ],
+            'tooltips' => [ 'display' => false ],
+            'scales'   => [
+                'y' => [
+                    'grid'    => ['display' => false],
+                    'ticks'   => ['display' => false],
+                    'display' => false,
+                ],
+                'x' => [
+                    'grid'    => ['display' => false],
+                    'display' => false,
+                ],
+            ],
+        ];
+
+        $data = [
+            [
+                'backgroundColor'       => '#009D9E',
+                'borderColor'           => '#009D9E',
+                'pointBackgroundColor'  => '#009D9E',
+                'pointHoverBorderColor' => '#009D9E',
+                'data'                  => $string_writes,
+            ],
+        ];
+
+        $graph_area = html_print_div(
+            [
+                'content' => line_graph($data, $options),
+                'class'   => 'w100p h100p',
+                'style'   => 'max-height: 100px;',
+            ],
+            true
+        );
+
+        $total = html_print_div(
+            [
+                'content' => $total,
+                'class'   => 'text-xl',
+            ],
+            true
+        );
+
+        $output = $total.$graph_area;
+
+        return $output;
+    }
+
+
+}
diff --git a/pandora_console/include/lib/TacticalView/elements/Groups.php b/pandora_console/include/lib/TacticalView/elements/Groups.php
new file mode 100644
index 0000000000..55bf2a2354
--- /dev/null
+++ b/pandora_console/include/lib/TacticalView/elements/Groups.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Groups element for tactical view.
+ *
+ * @category   General
+ * @package    Pandora FMS
+ * @subpackage TacticalView
+ * @version    1.0.0
+ * @license    See below
+ *
+ *    ______                 ___                    _______ _______ ________
+ *   |   __ \.-----.--.--.--|  |.-----.----.-----. |    ___|   |   |     __|
+ *  |    __/|  _  |     |  _  ||  _  |   _|  _  | |    ___|       |__     |
+ * |___|   |___._|__|__|_____||_____|__| |___._| |___|   |__|_|__|_______|
+ *
+ * ============================================================================
+ * Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
+ * This code is NOT free software. This code is NOT licenced under GPL2 licence
+ * You cannnot redistribute it without written permission of copyright holder.
+ * ============================================================================
+ */
+
+use PandoraFMS\TacticalView\Element;
+
+/**
+ * Groups, this class contain all logic for this section.
+ */
+class Groups extends Element
+{
+
+    /**
+     * Total groups.
+     *
+     * @var integer
+     */
+    public $total;
+
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->title = __('Groups');
+        $this->total = $this->calculateTotalGroups();
+    }
+
+
+    /**
+     * Return the total groups.
+     *
+     * @return integer
+     */
+    public function calculateTotalGroups():int
+    {
+        $total = db_get_num_rows('SELECT * FROM tgrupo;');
+        return $total;
+    }
+
+
+    /**
+     * Return the status groups in heat map.
+     *
+     * @return string
+     */
+    public function getStatusHeatMap():string
+    {
+        ui_require_css_file('heatmap');
+        $width = 350;
+        $height = 335;
+        $sql = 'SELECT * FROM tagente a
+                LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente';
+
+        $all_agents = db_get_all_rows_sql($sql);
+        if (empty($all_agents)) {
+            return null;
+        }
+
+        $total_agents = count($all_agents);
+
+        // Best square.
+        $high = (float) max($width, $height);
+        $low = 0.0;
+
+        while (abs($high - $low) > 0.000001) {
+            $mid = (($high + $low) / 2.0);
+            $midval = (floor($width / $mid) * floor($height / $mid));
+            if ($midval >= $total_agents) {
+                $low = $mid;
+            } else {
+                $high = $mid;
+            }
+        }
+
+        $square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
+        // Print starmap.
+        $heatmap = sprintf(
+            '<svg id="svg" style="width: %spx; height: %spx;">',
+            $width,
+            $height
+        );
+
+        $heatmap .= '<g>';
+        $row = 0;
+        $column = 0;
+        $x = 0;
+        $y = 0;
+        $cont = 1;
+
+        foreach ($all_agents as $key => $value) {
+            // Colour by status.
+            $status = agents_get_status_from_counts($value);
+
+            switch ($status) {
+                case 5:
+                    // Not init status.
+                    $status = 'notinit';
+                break;
+
+                case 1:
+                    // Critical status.
+                    $status = 'critical';
+                break;
+
+                case 2:
+                    // Warning status.
+                    $status = 'warning';
+                break;
+
+                case 0:
+                    // Normal status.
+                    $status = 'normal';
+                break;
+
+                case 3:
+                case -1:
+                default:
+                    // Unknown status.
+                    $status = 'unknown';
+                break;
+            }
+
+            $heatmap .= sprintf(
+                '<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
+                'rect_'.$cont,
+                $x,
+                $y,
+                $row,
+                $column,
+                $square_length,
+                $square_length,
+                $status,
+                random_int(1, 10)
+            );
+
+            $y += $square_length;
+            $row++;
+            if ((int) ($y + $square_length) > (int) $height) {
+                $y = 0;
+                $x += $square_length;
+                $row = 0;
+                $column++;
+            }
+
+            if ((int) ($x + $square_length) > (int) $width) {
+                $x = 0;
+                $y += $square_length;
+                $column = 0;
+                $row++;
+            }
+
+            $cont++;
+        }
+
+        $heatmap .= '<script type="text/javascript">
+                    $(document).ready(function() {
+                        const total_agents = "'.$total_agents.'";
+
+                        function getRandomInteger(min, max) {
+                            return Math.floor(Math.random() * max) + min;
+                        }
+
+                        function oneSquare(solid, time) {
+                            var randomPoint = getRandomInteger(1, total_agents);
+                            let target = $(`#rect_${randomPoint}`);
+                            let class_name = target.attr("class");
+                            class_name = class_name.split("_")[0];
+                            setTimeout(function() {
+                                target.removeClass();
+                                target.addClass(`${class_name}_${solid}`);
+                                oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
+                            }, time);
+                        }
+
+                        let cont = 0;
+                        while (cont < Math.ceil(total_agents / 3)) {
+                            oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
+                            cont ++;
+                        }
+                    });
+                </script>';
+        $heatmap .= '</g>';
+        $heatmap .= '</svg>';
+
+        return html_print_div(
+            [
+                'content' => $heatmap,
+                'style'   => 'margin: 0 auto; width: fit-content;',
+            ],
+            true
+        );
+    }
+
+
+}
diff --git a/pandora_console/include/lib/TacticalView/elements/LogStorage.php b/pandora_console/include/lib/TacticalView/elements/LogStorage.php
new file mode 100644
index 0000000000..fcde21a295
--- /dev/null
+++ b/pandora_console/include/lib/TacticalView/elements/LogStorage.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * LogStorage element for tactical view.
+ *
+ * @category   General
+ * @package    Pandora FMS
+ * @subpackage TacticalView
+ * @version    1.0.0
+ * @license    See below
+ *
+ *    ______                 ___                    _______ _______ ________
+ *   |   __ \.-----.--.--.--|  |.-----.----.-----. |    ___|   |   |     __|
+ *  |    __/|  _  |     |  _  ||  _  |   _|  _  | |    ___|       |__     |
+ * |___|   |___._|__|__|_____||_____|__| |___._| |___|   |__|_|__|_______|
+ *
+ * ============================================================================
+ * Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
+ * This code is NOT free software. This code is NOT licenced under GPL2 licence
+ * You cannnot redistribute it without written permission of copyright holder.
+ * ============================================================================
+ */
+
+use PandoraFMS\TacticalView\Element;
+
+/**
+ * LogStorage, this class contain all logic for this section.
+ */
+class LogStorage extends Element
+{
+
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->title = __('Log storage');
+    }
+
+
+     /**
+      * Returns the html status of log storage.
+      *
+      * @return string
+      */
+    public function getStatus():string
+    {
+        // TODO connect to automonitorization.
+        $status = true;
+
+        if ($status === true) {
+            $image_status = html_print_image('images/status_check@svg.svg', true);
+            $text = html_print_div(
+                [
+                    'content' => __('Everything’s OK!'),
+                    'class'   => 'status-text',
+                ],
+                true
+            );
+        } else {
+            $image_status = html_print_image('images/status_error@svg.svg', true);
+            $text = html_print_div(
+                [
+                    'content' => __('Something’s wrong'),
+                    'class'   => 'status-text',
+                ],
+                true
+            );
+        }
+
+        $output = $image_status.$text;
+
+        return html_print_div(
+            [
+                'content' => $output,
+                'class'   => 'flex_center margin-top-5',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of total sources in log storage.
+     *
+     * @return string
+     */
+    public function getTotalSources():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 0px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of lines in log storage.
+     *
+     * @return string
+     */
+    public function getStoredData():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 0px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of age of stored data.
+     *
+     * @return string
+     */
+    public function getAgeOfStoredData():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 0px 10px;',
+            ],
+            true
+        );
+    }
+
+
+}
diff --git a/pandora_console/include/lib/TacticalView/elements/MonitoringElements.php b/pandora_console/include/lib/TacticalView/elements/MonitoringElements.php
index 4731d54b27..7a91348cf8 100644
--- a/pandora_console/include/lib/TacticalView/elements/MonitoringElements.php
+++ b/pandora_console/include/lib/TacticalView/elements/MonitoringElements.php
@@ -38,4 +38,153 @@ class MonitoringElements extends Element
     }
 
 
+    /**
+     * Returns the html of the tags grouped by modules.
+     *
+     * @return string
+     */
+    public function getTagsGraph():string
+    {
+        $sql = 'SELECT name, count(*) AS total
+                FROM ttag_module t
+                LEFT JOIN ttag ta ON ta.id_tag = t.id_tag
+                GROUP BY t.id_tag';
+        $rows = db_process_sql($sql);
+
+        $labels = [];
+        $data = [];
+        foreach ($rows as $key => $row) {
+            $labels[] = $this->controlSizeText($row['name']);
+            $data[] = $row['total'];
+        }
+
+        $options = [
+            'labels'       => $labels,
+            'legend'       => [
+                'position' => 'bottom',
+                'align'    => 'right',
+            ],
+            'cutout'       => 80,
+            'nodata_image' => ['width' => '100%'],
+        ];
+        $pie = ring_graph($data, $options);
+        $output = html_print_div(
+            [
+                'content' => $pie,
+                'style'   => 'margin: 0 auto; max-width: 60%; max-height: 220px;',
+            ],
+            true
+        );
+
+        return $output;
+    }
+
+
+    /**
+     * Returns the html of the groups grouped by modules.
+     *
+     * @return string
+     */
+    public function getModuleGroupGraph():string
+    {
+        $sql = 'SELECT name, count(*) AS total
+                FROM tagente_modulo m
+                LEFT JOIN tmodule_group g ON g.id_mg = m.id_module_group
+                WHERE name <> ""
+                GROUP BY m.id_module_group';
+        $rows = db_process_sql($sql);
+
+        $labels = [];
+        $data = [];
+        foreach ($rows as $key => $row) {
+            $labels[] = $this->controlSizeText($row['name']);
+            $data[] = $row['total'];
+        }
+
+        $options = [
+            'labels'       => $labels,
+            'legend'       => [
+                'position' => 'bottom',
+                'align'    => 'right',
+            ],
+            'cutout'       => 80,
+            'nodata_image' => ['width' => '100%'],
+        ];
+        $pie = ring_graph($data, $options);
+        $output = html_print_div(
+            [
+                'content' => $pie,
+                'style'   => 'margin: 0 auto; max-width: 60%; max-height: 220px;',
+            ],
+            true
+        );
+
+        return $output;
+    }
+
+
+    /**
+     * Returns the html of the agent grouped by modules.
+     *
+     * @return string
+     */
+    public function getAgentGroupsGraph():string
+    {
+        $sql = 'SELECT gr.nombre, count(*) AS total
+                FROM tagente a
+                LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
+                LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
+                GROUP BY a.id_grupo';
+        $rows = db_process_sql($sql);
+
+        $labels = [];
+        $data = [];
+        foreach ($rows as $key => $row) {
+            $labels[] = $this->controlSizeText($row['nombre']);
+            $data[] = $row['total'];
+        }
+
+        $options = [
+            'labels'       => $labels,
+            'legend'       => [
+                'position' => 'bottom',
+                'align'    => 'right',
+            ],
+            'cutout'       => 80,
+            'nodata_image' => ['width' => '100%'],
+        ];
+        $pie = ring_graph($data, $options);
+        $output = html_print_div(
+            [
+                'content' => $pie,
+                'style'   => 'margin: 0 auto; max-width: 60%; max-height: 220px;',
+            ],
+            true
+        );
+
+        return $output;
+    }
+
+
+    /**
+     * Returns the html of monitoring by status.
+     *
+     * @return string
+     */
+    public function getMonitoringStatusGraph():string
+    {
+        // TODO add labels.
+        $pie = graph_agent_status(false, '', '', true, true, false, true);
+        $output = html_print_div(
+            [
+                'content' => $pie,
+                'style'   => 'margin: 0 auto; max-width: 60%; max-height: 220px;',
+            ],
+            true
+        );
+
+        return $output;
+    }
+
+
 }
diff --git a/pandora_console/include/lib/TacticalView/elements/Overview.php b/pandora_console/include/lib/TacticalView/elements/Overview.php
index ba82e00a60..8ab35336a9 100644
--- a/pandora_console/include/lib/TacticalView/elements/Overview.php
+++ b/pandora_console/include/lib/TacticalView/elements/Overview.php
@@ -129,7 +129,7 @@ class Overview extends Element
      *
      * @return string
      */
-    public function getLicenseUsage():string
+    public function getLicenseUsageGraph():string
     {
         // TODO connect to automonitorization.
         $options = [
@@ -167,7 +167,7 @@ class Overview extends Element
      *
      * @return string
      */
-    public function getXmlProcessed():string
+    public function getXmlProcessedGraph():string
     {
         $sql = 'SELECT
                 utimestamp,
@@ -184,9 +184,9 @@ class Overview extends Element
         $xml_proccessed = [];
         $total = 0;
         foreach ($rows as $key => $raw_data) {
-            $dates[] = date('H:i:s', $raw_data['utimestamp']);
-            $xml_proccessed[] = $raw_data['xml_proccessed'];
+            $dates[] = date('H:00:00', $raw_data['utimestamp']);
             $total += $raw_data['xml_proccessed'];
+            $xml_proccessed[] = $raw_data['xml_proccessed'];
         }
 
         $options = [
@@ -205,7 +205,15 @@ class Overview extends Element
             ],
         ];
 
-        $data = [['data' => $xml_proccessed]];
+        $data = [
+            [
+                'backgroundColor'       => '#009D9E',
+                'borderColor'           => '#009D9E',
+                'pointBackgroundColor'  => '#009D9E',
+                'pointHoverBorderColor' => '#009D9E',
+                'data'                  => $xml_proccessed,
+            ],
+        ];
 
         $graph_area = html_print_div(
             [
diff --git a/pandora_console/include/lib/TacticalView/elements/SnmpTraps.php b/pandora_console/include/lib/TacticalView/elements/SnmpTraps.php
new file mode 100644
index 0000000000..4068531c2d
--- /dev/null
+++ b/pandora_console/include/lib/TacticalView/elements/SnmpTraps.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * SnmpTraps element for tactical view.
+ *
+ * @category   General
+ * @package    Pandora FMS
+ * @subpackage TacticalView
+ * @version    1.0.0
+ * @license    See below
+ *
+ *    ______                 ___                    _______ _______ ________
+ *   |   __ \.-----.--.--.--|  |.-----.----.-----. |    ___|   |   |     __|
+ *  |    __/|  _  |     |  _  ||  _  |   _|  _  | |    ___|       |__     |
+ * |___|   |___._|__|__|_____||_____|__| |___._| |___|   |__|_|__|_______|
+ *
+ * ============================================================================
+ * Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
+ * This code is NOT free software. This code is NOT licenced under GPL2 licence
+ * You cannnot redistribute it without written permission of copyright holder.
+ * ============================================================================
+ */
+
+use PandoraFMS\TacticalView\Element;
+
+/**
+ * SnmpTraps, this class contain all logic for this section.
+ */
+class SnmpTraps extends Element
+{
+
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->title = __('SNMP Traps');
+    }
+
+
+    /**
+     * Returns the html of queues traps.
+     *
+     * @return string
+     */
+    public function getQueues():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+    /**
+     * Returns the html of total sources traps.
+     *
+     * @return string
+     */
+    public function getTotalSources():string
+    {
+        // TODO connect to automonitorization.
+        return html_print_div(
+            [
+                'content' => '9.999.999',
+                'class'   => 'text-l',
+                'style'   => 'margin: 0px 10px 10px 10px;',
+            ],
+            true
+        );
+    }
+
+
+}
diff --git a/pandora_console/include/styles/general_tactical_view.css b/pandora_console/include/styles/general_tactical_view.css
index 27c8482cd3..427667455e 100644
--- a/pandora_console/include/styles/general_tactical_view.css
+++ b/pandora_console/include/styles/general_tactical_view.css
@@ -1,3 +1,22 @@
+#welcome-message {
+  margin-bottom: 30px;
+}
+
+.message-welcome {
+  color: #161628;
+  font-size: 32px;
+  line-height: 38px;
+  text-align: left;
+  font-weight: 700;
+}
+
+.subtitle-welcome-message {
+  color: #8a96a6;
+  font-size: 15px;
+  line-height: 20px;
+  text-align: left;
+  margin-left: 5px;
+}
 .row {
   display: flex;
   width: 100%;
@@ -19,6 +38,7 @@
   border: 1px solid #e5e9ed;
   border-radius: 10px;
   margin: 5px;
+  max-width: 100%;
 }
 .br-l {
   border-left: 1px solid #e5e9ed;
@@ -33,11 +53,11 @@
   border-bottom: 1px solid #e5e9ed;
 }
 .title {
-  font-size: 18px;
+  font-size: 18px !important;
   color: #161628;
-  text-align: center;
-  font-weight: bold;
-  padding: 15px 0px;
+  text-align: center !important;
+  font-weight: bold !important;
+  padding: 15px 0px !important;
 }
 .subtitle {
   font-size: 13px;
@@ -52,6 +72,7 @@
 .subtitle.link a {
   color: #14524f;
   font-size: 13px;
+  font-weight: 800;
 }
 .absolute-link::after {
   content: "→";
@@ -69,9 +90,30 @@
   margin-bottom: 8px;
   line-height: initial;
 }
+.text-l {
+  font-size: 27px;
+  color: #6c7587;
+  font-weight: bold;
+  margin-bottom: 8px;
+  line-height: initial;
+}
 #news-board {
   min-width: 530px;
   width: 100%;
   max-height: 805px;
   overflow-y: auto;
 }
+
+#database .subtitle,
+#logStorage .subtitle,
+#SNMPTraps .subtitle {
+  padding: 10px 10px 5px 10px;
+}
+
+.indicative-text {
+  color: #6e7079;
+  font-size: 12px;
+  line-height: 13px;
+  text-align: left;
+  padding: 0px 10px 10px 10px;
+}
diff --git a/pandora_console/views/tacticalView/view.php b/pandora_console/views/tacticalView/view.php
index 63c59c2790..92a4d54f79 100644
--- a/pandora_console/views/tacticalView/view.php
+++ b/pandora_console/views/tacticalView/view.php
@@ -1,3 +1,8 @@
+<div id="welcome-message">
+    <?php echo $welcome; ?>
+    <span class="subtitle-welcome-message"><?php echo __('This is the latest data in your tactical view'); ?></span>
+</div>
+
 <div class="row">
     <div class="col-6">
         <div id="general-overview">
@@ -31,7 +36,7 @@
                                     <span class="subtitle link">
                                         <?php echo __('License usage'); ?> <a href=""><?php echo __('Info'); ?></a>
                                     </span>
-                                    <?php echo $Overview->getLicenseUsage(); ?>
+                                    <?php echo $Overview->getLicenseUsageGraph(); ?>
                                 </div>
                             </div>
                         </div>
@@ -39,7 +44,7 @@
                             <div class="subtitle link padding10 padding2">
                                 <?php echo __('XML packets processed (last 24 hrs)'); ?> <a href=""><?php echo __('Info'); ?></a>
                             </div>
-                            <?php echo $Overview->getXmlProcessed(); ?>
+                            <?php echo $Overview->getXmlProcessedGraph(); ?>
                         </div>
                     </div>
                 </div>
@@ -51,27 +56,33 @@
                     <div class="title">
                         <?php echo $MonitoringElements->title; ?>
                     </div>
-                    <div class="row">
-                        <div class="col-6">
-                            <div class="subtitle link padding10 padding2">
-                                <?php echo __('Tags'); ?> <a href=""><?php echo __('Info'); ?></a>
+                    <div class="content br-t">
+                        <div class="row">
+                            <div class="col-6 br-r br-b">
+                                <div class="subtitle link padding10 padding2">
+                                    <?php echo __('Tags'); ?> <a href=""><?php echo __('Info'); ?></a>
+                                </div>
+                                <?php echo $MonitoringElements->getTagsGraph(); ?>
+                            </div>
+                            <div class="col-6 br-b">
+                                <div class="subtitle link padding10 padding2">
+                                    <?php echo __('By modules groups'); ?> <a href=""><?php echo __('Info'); ?></a>
+                                </div>
+                                <?php echo $MonitoringElements->getModuleGroupGraph(); ?>
                             </div>
                         </div>
-                        <div class="col-6">
-                            <div class="subtitle link padding10 padding2">
-                                <?php echo __('By modules groups'); ?> <a href=""><?php echo __('Info'); ?></a>
+                        <div class="row">
+                            <div class="col-6">
+                                <div class="subtitle link padding10 padding2">
+                                    <?php echo __('Status'); ?> <a href=""><?php echo __('Info'); ?></a>
+                                </div>
+                                <?php echo $MonitoringElements->getMonitoringStatusGraph(); ?>
                             </div>
-                        </div>
-                    </div>
-                    <div class="row">
-                        <div class="col-6">
-                            <div class="subtitle link padding10 padding2">
-                                <?php echo __('Status'); ?> <a href=""><?php echo __('Info'); ?></a>
-                            </div>
-                        </div>
-                        <div class="col-6">
-                            <div class="subtitle link padding10 padding2">
-                                <?php echo __('Groups'); ?> <a href=""><?php echo __('Info'); ?></a>
+                            <div class="col-6 br-l">
+                                <div class="subtitle link padding10 padding2">
+                                    <?php echo __('Groups'); ?> <a href=""><?php echo __('Info'); ?></a>
+                                </div>
+                                <?php echo $MonitoringElements->getAgentGroupsGraph(); ?>
                             </div>
                         </div>
                     </div>
@@ -79,16 +90,134 @@
 
             </div>
             <div class="col-5">
+                <div class="container" id="database">
+                    <div class="title">
+                        <?php echo $Database->title; ?>
+                    </div>
+                    <div class="content br-t">
+                        <div class="row">
+                            <div class="col-6 br-r br-b">
+                                <div class="subtitle">
+                                    <?php echo __('Database status'); ?>
+                                </div>
+                                <?php echo $Database->getStatus(); ?>
+                            </div>
+                            <div class="col-6 br-b">
+                                <div class="subtitle">
+                                    <?php echo __('Data records'); ?>
+                                </div>
+                                <?php echo $Database->getDataRecords(); ?>
+                            </div>
+                        </div>
+                        <div class="row">
+                            <div class="col-6">
+                                <div class="subtitle">
+                                    <?php echo __('String records'); ?>
+                                </div>
+                                <?php echo $Database->getStringRecords(); ?>
+                            </div>
+                            <div class="col-6 br-l">
+                                <div class="subtitle">
+                                    <?php echo __('Events'); ?>
+                                </div>
+                                <?php echo $Database->getEvents(); ?>
+                            </div>
+                        </div>
+                        <div class="br-t">
+                            <div class="subtitle link padding10 padding2">
+                                <?php echo __('Reads (last 24 hrs)'); ?> <a href=""><?php echo __('Info'); ?></a>
+                            </div>
+                            <?php echo $Database->getReadsGraph(); ?>
+                        </div>
+                        <div class="br-t">
+                            <div class="subtitle link padding10 padding2">
+                                <?php echo __('Reads (last 24 hrs)'); ?> <a href=""><?php echo __('Info'); ?></a>
+                            </div>
+                            <?php echo $Database->getWritesGraph(); ?>
+                        </div>
+                    </div>
+                </div>
 
             </div>
         </div>
     </div>
     <div class="col-6">
         <div class="container">
-                <div class="title">
-                    <?php echo $NewsBoard->title; ?>
+            <div class="title">
+                <?php echo $NewsBoard->title; ?>
+            </div>
+            <?php echo $NewsBoard->getNews(); ?>
+        </div>
+        <div class="row">
+            <?php if ($Groups->total < 200) : ?>
+                <div class="col-6">
+                    <div class="container">
+                        <div class="title br-b">
+                            <?php echo $Groups->title; ?>
+                        </div>
+                        <div class="subtitle link padding10 padding2">
+                            <?php echo __('Status'); ?> <a href=""><?php echo __('Info'); ?></a>
+                        </div>
+                        <?php echo $Groups->getStatusHeatMap(); ?>
+                    </div>
                 </div>
-                <?php echo $NewsBoard->getNews(); ?>
+            <?php endif; ?>
+            <div class="col-6">
+                <div class="container" id="logStorage">
+                    <div class="title br-b">
+                        <?php echo $LogStorage->title; ?>
+                    </div>
+                    <div class="row">
+                        <div class="col-6 br-r br-b">
+                            <div class="subtitle">
+                                <?php echo __('Log storage status'); ?>
+                            </div>
+                            <?php echo $LogStorage->getStatus(); ?>
+                        </div>
+                        <div class="col-6 br-b">
+                            <div class="subtitle">
+                                <?php echo __('Total sources'); ?>
+                            </div>
+                            <?php echo $LogStorage->getTotalSources(); ?>
+                        </div>
+                    </div>
+                    <div class="row">
+                        <div class="col-6 br-r">
+                            <div class="subtitle">
+                                <?php echo __('Stored data'); ?>
+                            </div>
+                            <?php echo $LogStorage->getStoredData(); ?>
+                            <span class="indicative-text"><?php echo __('Lines'); ?></span>
+                        </div>
+                        <div class="col-6">
+                            <div class="subtitle">
+                                <?php echo __('Age of stored data'); ?>
+                            </div>
+                            <?php echo $LogStorage->getAgeOfStoredData(); ?>
+                            <span class="indicative-text"><?php echo __('Days'); ?></span>
+                        </div>
+                    </div>
+                </div>
+                <div class="container" id="SNMPTraps">
+                    <div class="title br-b">
+                        <?php echo $SnmpTraps->title; ?>
+                    </div>
+                    <div class="row">
+                        <div class="col-6 br-r">
+                            <div class="subtitle">
+                                <?php echo __('Trap queues'); ?>
+                            </div>
+                            <?php echo $SnmpTraps->getQueues(); ?>
+                        </div>
+                        <div class="col-6">
+                            <div class="subtitle">
+                                <?php echo __('Total sources'); ?>
+                            </div>
+                            <?php echo $SnmpTraps->getTotalSources(); ?>
+                        </div>
+                    </div>
+                </div>
+            </div>
         </div>
     </div>
 </div>