Merge branch 'visual-console-refactor' into 'ent-3733-Crear-modelos-de-los-distintos-recursos-de-la-Consola-Visual'

# Conflicts:
#   pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php
#   pandora_console/include/rest-api/models/VisualConsole/Items/Label.php
#   pandora_console/tests/Functional/Models/VisualConsole/Items/ColorCloudTest.php
#   pandora_console/tests/Functional/Models/VisualConsole/Items/LabelTest.php

Former-commit-id: 4ef35ceb24d2cde4b3d18f92ea14ea617fcba2cd
This commit is contained in:
Daniel Maya 2019-04-04 10:10:26 +02:00
commit de750bb59f
59 changed files with 2820 additions and 1178 deletions

View File

@ -1,5 +1,5 @@
package: pandorafms-agent-unix
Version: 7.0NG.733-190328
Version: 7.0NG.733-190331
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.733-190328"
pandora_version="7.0NG.733-190331"
echo "Test if you has the tools for to make the packages."
whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null

View File

@ -42,7 +42,7 @@ my $Sem = undef;
my $ThreadSem = undef;
use constant AGENT_VERSION => '7.0NG.733';
use constant AGENT_BUILD => '190328';
use constant AGENT_BUILD => '190331';
# Agent log default file size maximum and instances
use constant DEFAULT_MAX_LOG_SIZE => 600000;

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_agent_unix
%define version 7.0NG.733
%define release 190328
%define release 190331
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_agent_unix
%define version 7.0NG.733
%define release 190328
%define release 190331
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -10,7 +10,7 @@
# **********************************************************************
PI_VERSION="7.0NG.733"
PI_BUILD="190328"
PI_BUILD="190331"
OS_NAME=`uname -s`
FORCE=0

View File

@ -186,7 +186,7 @@ UpgradeApplicationID
{}
Version
{190328}
{190331}
ViewReadme
{Yes}

View File

@ -30,7 +30,7 @@ using namespace Pandora;
using namespace Pandora_Strutils;
#define PATH_SIZE _MAX_PATH+1
#define PANDORA_VERSION ("7.0NG.733(Build 190328)")
#define PANDORA_VERSION ("7.0NG.733(Build 190331)")
string pandora_path;
string pandora_dir;

View File

@ -11,7 +11,7 @@ BEGIN
VALUE "LegalCopyright", "Artica ST"
VALUE "OriginalFilename", "PandoraAgent.exe"
VALUE "ProductName", "Pandora FMS Windows Agent"
VALUE "ProductVersion", "(7.0NG.733(Build 190328))"
VALUE "ProductVersion", "(7.0NG.733(Build 190331))"
VALUE "FileVersion", "1.0.0.0"
END
END

View File

@ -1,5 +1,5 @@
package: pandorafms-console
Version: 7.0NG.733-190328
Version: 7.0NG.733-190331
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.733-190328"
pandora_version="7.0NG.733-190331"
package_pear=0
package_pandora=1

View File

@ -20,7 +20,7 @@
/**
* Pandora build version and version
*/
$build_version = 'PC190328';
$build_version = 'PC190331';
$pandora_version = 'v7.0NG.733';
// Do not overwrite default timezone set if defined.

View File

@ -58,7 +58,7 @@ abstract class Model
$this->validateData($unknownData);
$this->data = $this->decode($unknownData);
// Sort alphabetically.
ksort($this->data);
ksort($this->data, (SORT_NATURAL | SORT_FLAG_CASE));
}

View File

@ -193,4 +193,134 @@ final class Container extends Model
}
/**
* Obtain a container data structure from the database using layout id
* and returns a valid representation of the model
*
* @param integer $id_layout
*
* @return array
*/
public static function getItemsFromDB(int $id_layout): array
{
$layout_items = db_get_all_rows_filter('tlayout_data', ['id_layout' => $id_layout]);
if (!empty($layout_items) === true) {
$array_items = [];
foreach ($layout_items as $key => $value) {
switch ($value['type']) {
case STATIC_GRAPH:
// code...
break;
case MODULE_GRAPH:
// code...
break;
case SIMPLE_VALUE:
case SIMPLE_VALUE_MAX:
case SIMPLE_VALUE_MIN:
case SIMPLE_VALUE_AVG:
$value['value'] = visual_map_get_simple_value(
$value['type'],
$value['id_agente_modulo'],
$value['period']
);
array_push(
$array_items,
(string) Items\SimpleValue::fromArray($value)
);
break;
case PERCENTILE_BAR:
// code...
break;
case LABEL:
array_push(
$array_items,
(string) Items\Label::fromArray($value)
);
break;
case ICON:
array_push(
$array_items,
(string) Items\Icon::fromArray($value)
);
break;
case PERCENTILE_BUBBLE:
// code...
break;
case SERVICE:
// code...
break;
case GROUP_ITEM:
array_push(
$array_items,
(string) Items\Group::fromArray($value)
);
break;
case BOX_ITEM:
array_push(
$array_items,
(string) Items\Box::fromArray($value)
);
break;
case LINE_ITEM:
array_push(
$array_items,
(string) Items\Line::fromArray($value)
);
break;
case AUTO_SLA_GRAPH:
array_push(
$array_items,
(string) Items\EventsHistory::fromArray($value)
);
break;
case CIRCULAR_PROGRESS_BAR:
// code...
break;
case CIRCULAR_INTERIOR_PROGRESS_BAR:
// code...
break;
case DONUT_GRAPH:
// code...
break;
case BARS_GRAPH:
// code...
break;
case CLOCK:
array_push(
$array_items,
(string) Items\Clock::fromArray($value)
);
break;
case COLOR_CLOUD:
array_push(
$array_items,
(string) Items\ColorCloud::fromArray($value)
);
break;
}
}
}
return $array_items;
}
}

View File

@ -33,6 +33,13 @@ class Item extends Model
*/
protected static $useLinkedVisualConsole = false;
/**
* Used to decide wether to validate, extract and encode HTML output or not.
*
* @var boolean
*/
protected static $useHtmlOutput = false;
/**
* Validate the received data structure to ensure if we can extract the
@ -70,7 +77,7 @@ class Item extends Model
|| $data['width'] < 0
) {
throw new \InvalidArgumentException(
'the width property is required and should be greater than 0'
'the width property is required and should be equal or greater than 0'
);
}
@ -79,7 +86,7 @@ class Item extends Model
|| $data['height'] < 0
) {
throw new \InvalidArgumentException(
'the height property is required and should be greater than 0'
'the height property is required and should be equal or greater than 0'
);
}
@ -148,6 +155,17 @@ class Item extends Model
}
}
}
// The item uses HTML output.
if (static::$useHtmlOutput === true) {
if (static::notEmptyStringOr($data['encodedHtml'], null) === null
&& static::notEmptyStringOr($data['html'], null) === null
) {
throw new \InvalidArgumentException(
'the html property is required and should be a not empty string'
);
}
}
}
@ -196,6 +214,10 @@ class Item extends Model
);
}
if (static::$useHtmlOutput === true) {
$decodedData['encodedHtml'] = static::extractEncodedHtml($data);
}
return $decodedData;
}
@ -357,7 +379,7 @@ class Item extends Model
* 'agentName' => null,
* ]
*/
private function extractLinkedAgent(array $data): array
protected static function extractLinkedAgent(array $data): array
{
$agentData = [];
@ -420,7 +442,7 @@ class Item extends Model
* 'moduleName' => null,
* ]
*/
private function extractLinkedModule(array $data): array
protected static function extractLinkedModule(array $data): array
{
// Initialize the data with the agent data and then expand it.
$moduleData = static::extractLinkedAgent($data);
@ -569,6 +591,25 @@ class Item extends Model
}
/**
* Extract a encoded HTML representation of the item.
*
* @param array $data Unknown input data structure.
*
* @return string The HTML representation in base64 encoding.
*/
private static function extractEncodedHtml(array $data): string
{
if (isset($data['encodedHtml']) === true) {
return $data['encodedHtml'];
} else if (isset($data['html']) === true) {
return \base64_encode($data['html']);
}
return '';
}
/**
* Fetch a vc item data structure from the database using a filter.
*

View File

@ -6,7 +6,7 @@ namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a Clock item of the Visual Console.
* Model of a clock item of the Visual Console.
*/
final class Clock extends Item
{
@ -26,6 +26,8 @@ final class Clock extends Item
* @param array $data Input data.
*
* @return array Data structure representing the model.
* @throws \InvalidArgumentException When there is a problem with
* the time management.
*
* @overrides Item::decode.
*/
@ -33,20 +35,25 @@ final class Clock extends Item
{
$clockData = parent::decode($data);
$clockData['type'] = CLOCK;
$clockData['clockType'] = $this->extractClockType($data);
$clockData['clockFormat'] = $this->extractClockFormat($data);
$clockData['clockTimezone'] = $this->extractClockTimezone($data);
$clockData['clockType'] = static::extractClockType($data);
$clockData['clockFormat'] = static::extractClockFormat($data);
$clockData['clockTimezone'] = static::extractClockTimezone($data);
try {
$timezone = new \DateTimeZone($clockData['clockTimezone']);
$timezoneUTC = new \DateTimeZone('UTC');
$clockData['clockTimezoneOffset'] = $timezone->getOffset(new \DateTime('now', $timezoneUTC));
} catch (Exception $e) {
$dateTimeUtc = new \DateTime('now', $timezoneUTC);
$clockData['clockTimezoneOffset'] = $timezone->getOffset(
$dateTimeUtc
);
} catch (\Exception $e) {
throw new \InvalidArgumentException($e->getMessage());
}
$clockData['showClockTimezone'] = $this->extractShowClockTimezone($data);
$clockData['color'] = $this->extractColor($data);
$clockData['showClockTimezone'] = static::parseBool(
$data['showClockTimezone']
);
$clockData['color'] = static::extractColor($data);
return $clockData;
}
@ -56,9 +63,9 @@ final class Clock extends Item
*
* @param array $data Unknown input data structure.
*
* @return string Digital or analogic. analogic by default.
* @return string One of 'digital' or 'analogic'. 'analogic' by default.
*/
private function extractClockType(array $data): string
private static function extractClockType(array $data): string
{
$clockType = static::notEmptyStringOr(
static::issetInArray($data, ['clockType', 'clock_animation']),
@ -81,9 +88,9 @@ final class Clock extends Item
*
* @param array $data Unknown input data structure.
*
* @return string Time or datetime. datetime by default.
* @return string One of 'time' or 'datetime'. 'datetime' by default.
*/
private function extractClockFormat(array $data): string
private static function extractClockFormat(array $data): string
{
$clockFormat = static::notEmptyStringOr(
static::issetInArray($data, ['clockFormat', 'time_format']),
@ -106,8 +113,10 @@ final class Clock extends Item
* @param array $data Unknown input data structure.
*
* @return string
* @throws \InvalidArgumentException When a valid clock timezone cannot be
* extracted.
*/
private function extractClockTimezone(array $data): string
private static function extractClockTimezone(array $data): string
{
$clockTimezone = static::notEmptyStringOr(
static::issetInArray($data, ['clockTimezone', 'timezone']),
@ -118,24 +127,9 @@ final class Clock extends Item
throw new \InvalidArgumentException(
'the clockTimezone property is required and should be string'
);
} else {
return $clockTimezone;
}
}
/**
* Extract a clock timezone value.
*
* @param array $data Unknown input data structure.
*
* @return boolean
*/
private function extractShowClockTimezone(array $data): bool
{
return static::parseBool(
static::issetInArray($data, ['showClockTimezone'])
);
return $clockTimezone;
}
@ -144,9 +138,9 @@ final class Clock extends Item
*
* @param array $data Unknown input data structure.
*
* @return mixed returns a color or null
* @return mixed returns a color or null.
*/
private function extractColor(array $data)
private static function extractColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['color', 'fill_color']),

View File

@ -35,100 +35,242 @@ final class ColorCloud extends Item
*
* @return array Data structure representing the model.
*
* @overrides Item::decode.
* @overrides Item->decode.
*/
protected function decode(array $data): array
{
$colorCloudData = parent::decode($data);
$colorCloudData['type'] = COLOR_CLOUD;
$colorCloudData['color'] = $this->extractColor($data);
$colorCloudData['colorRanges'] = $this->extractColorRanges($data);
$colorCloudData['label'] = null;
return $colorCloudData;
$decodedData = parent::decode($data);
$decodedData['type'] = COLOR_CLOUD;
$decodedData['label'] = null;
$decodedData['defaultColor'] = static::extractDefaultColor($data);
$decodedData['colorRanges'] = static::extractColorRanges($data);
$decodedData['color'] = static::notEmptyStringOr($data['color'], null);
return $decodedData;
}
/**
* Extract a color value.
* Extract the default color value.
*
* @param array $data Unknown input data structure.
*
* @return string
* @return string Default color.
* @throws \InvalidArgumentException If the default color cannot be
* extracted.
*/
private function extractColor(array $data): string
private static function extractDefaultColor(array $data): string
{
$color = static::notEmptyStringOr(
static::issetInArray($data, ['color']),
null
);
if (empty($color) === true) {
$color = static::notEmptyStringOr(
static::issetInArray($data, ['label']),
if (isset($data['defaultColor'])) {
$defaultColor = static::notEmptyStringOr(
$data['defaultColor'],
null
);
if (empty($color) === true) {
if ($defaultColor === null) {
throw new \InvalidArgumentException(
'the color property is required and should be string'
'the default color property is required and should be a not empty string'
);
} else {
$color_decode = \json_decode($color);
if (empty($color_decode->default_color) === true) {
throw new \InvalidArgumentException(
'the color property is required and should be string'
);
}
return $color_decode->default_color;
}
return $defaultColor;
} else {
return $color;
$dynamicData = static::extractDynamicData($data);
return $dynamicData['defaultColor'];
}
}
/**
* Extract a color ranges value.
* Extract a list of color ranges.
*
* @param array $data Unknown input data structure.
*
* @return string
* @return array Color ranges list.
* @throws \InvalidArgumentException If any of the color ranges is invalid.
*/
private function extractColorRanges(array $data): array
private static function extractColorRanges(array $data): array
{
if (isset($data['colorRanges']) && \is_array($data['colorRanges'])) {
foreach ($data['colorRanges'] as $key => $value) {
if ((!isset($value['fromValue']) || !\is_numeric($value['fromValue']))
|| (!isset($value['toValue']) || !\is_numeric($value['toValue']))
|| (!isset($value['color']) || !\is_string($value['color'])
|| \strlen($value['color']) == 0)
// Validate the color ranges.
foreach ($data['colorRanges'] as $colorRange) {
if (\is_numeric($colorRange['fromValue']) === false
|| \is_numeric($colorRange['toValue']) === false
|| static::notEmptyStringOr($colorRange['color'], null) === null
) {
throw new \InvalidArgumentException(
'the fromValue, toValue and color properties is required'
);
throw new \InvalidArgumentException('invalid color range');
}
}
return $data['colorRanges'];
} else if (isset($data['label']) === true) {
$colorRanges_decode = \json_decode($data['label']);
$array_out = [];
if (!empty($colorRanges_decode->color_ranges)) {
foreach ($colorRanges_decode->color_ranges as $key => $value) {
$array_aux = [];
$array_aux['fromValue'] = $value->from_value;
$array_aux['toValue'] = $value->to_value;
$array_aux['color'] = $value->color;
array_push($array_out, $array_aux);
}
}
return $array_out;
$dynamicData = static::extractDynamicData($data);
return $dynamicData['colorRanges'];
} else {
return [];
}
}
/**
* Extract a dynamic data structure from the 'label' field.
*
* @param array $data Unknown input data structure.
*
* @return array Dynamic data structure.
* @throws \InvalidArgumentException If the structure cannot be built.
*
* @example [
* 'defaultColor' => '#FFF',
* 'colorRanges' => [
* [
* 'fromValue' => 50.0,
* 'toValue' => 150.5,
* 'color' => '#000',
* ],
* [
* 'fromValue' => 200.0,
* 'toValue' => 300.5,
* 'color' => '#F0F0F0',
* ],
* ]
* ]
*/
private static function extractDynamicData(array $data): array
{
$dynamicDataEncoded = static::notEmptyStringOr($data['label'], null);
if ($dynamicDataEncoded === null) {
throw new \InvalidArgumentException('dynamic data not found');
}
$result = [];
try {
$dynamicData = \json_decode(
\base64_decode($dynamicDataEncoded),
true
);
$result['defaultColor'] = $dynamicData['default_color'];
$result['colorRanges'] = [];
if (\is_array($dynamicData['color_ranges']) === true) {
foreach ($dynamicData['color_ranges'] as $colorRange) {
if (\is_numeric($colorRange['from_value']) === true
&& \is_numeric($colorRange['to_value']) === true
&& static::notEmptyStringOr(
$colorRange['color'],
null
) !== null
) {
$result['colorRanges'][] = [
'color' => $colorRange['color'],
'fromValue' => (float) $colorRange['from_value'],
'toValue' => (float) $colorRange['to_value'],
];
}
}
}
} catch (\Exception $e) {
throw new \InvalidArgumentException('invalid dynamic data');
}
return $result;
}
/**
* Fetch a vc item data structure from the database using a filter.
*
* @param array $filter Filter of the Visual Console Item.
*
* @return array The Visual Console Item data structure stored into the DB.
* @throws \InvalidArgumentException When an agent Id cannot be found.
*
* @override Item::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter): array
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$data = parent::fetchDataFromDB($filter);
/*
* Retrieve extra data.
*/
// Load side libraries.
global $config;
include_once $config['homedir'].'/include/functions_graph.php';
include_once $config['homedir'].'/include/functions_modules.php';
// Get the linked module Id.
$linkedModule = static::extractLinkedModule($data);
$moduleId = static::parseIntOr($linkedModule['moduleId'], null);
$metaconsoleId = static::parseIntOr(
$linkedModule['metaconsoleId'],
null
);
if ($moduleId === null) {
throw new \InvalidArgumentException('missing module Id');
}
$dynamicData = static::extractDynamicData($data);
// Set the initial color.
$data['color'] = $dynamicData['defaultColor'];
// Search for a matching color range.
if (empty($dynamicData['colorRanges']) === false) {
// Connect to node.
$nodeConnected = false;
if (is_metaconsole() === true && $metaconsoleId !== null) {
$nodeConnected = metaconsole_connect(
null,
$metaconsoleId
) === NOERR;
}
// Fetch module value.
$value = false;
if ($metaconsoleId === null
|| ($metaconsoleId !== null && $nodeConnected)
) {
$value = modules_get_last_value($moduleId);
}
// Restore connection.
if ($nodeConnected === true) {
metaconsole_restore_db();
}
// Value found.
if ($value !== false) {
/*
* TODO: It would be ok to give support to string values in the
* future?
*
* It can be done by matching the range value with the value
* if it is a string. I think the function to retrieve the value
* only supports numeric values.
*/
$value = (float) $value;
foreach ($dynamicData['colorRanges'] as $colorRange) {
if ($colorRange['fromValue'] <= $value
&& $colorRange['toValue'] >= $value
) {
// Range matched. Use the range color.
$data['color'] = $colorRange['color'];
break;
}
}
}
}
return $data;
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
use Models\Model;
/**
* Model of a events history item of the Visual Console.
@ -12,6 +11,14 @@ use Models\Model;
final class EventsHistory extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
*
* @var boolean
*/
protected static $useLinkedModule = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
@ -21,12 +28,11 @@ final class EventsHistory extends Item
protected static $useLinkedVisualConsole = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
* Used to enable validation, extraction and encodeing of the HTML output.
*
* @var boolean
*/
protected static $useLinkedModule = true;
protected static $useHtmlOutput = true;
/**
@ -43,45 +49,75 @@ final class EventsHistory extends Item
$return = parent::decode($data);
$return['type'] = AUTO_SLA_GRAPH;
$return['maxTime'] = $this->extractMaxTime($data);
$return['data'] = $this->extractData($data);
return $return;
}
/**
* Extract the value of maxTime and
* return a integer or null.
* Extract a graph period value.
*
* @param array $data Unknown input data structure.
*
* @return mixed
* @return mixed The time in seconds of the graph period or null.
*/
private function extractMaxTime(array $data)
private static function extractMaxTime(array $data)
{
$maxTime = Model::parseIntOr(
Model::issetInArray($data, ['maxTime', 'period']),
return static::parseIntOr(
static::issetInArray($data, ['maxTime', 'period']),
null
);
return $maxTime;
}
/**
* Extract the value of data and
* return an array.
* Fetch a vc item data structure from the database using a filter.
*
* @param array $data Unknown input data structure.
* @param array $filter Filter of the Visual Console Item.
*
* @return array
* @return array The Visual Console Item data structure stored into the DB.
* @throws \InvalidArgumentException When an agent Id cannot be found.
*
* @override Item::fetchDataFromDB.
*/
private function extractData(array $data): array
protected static function fetchDataFromDB(array $filter): array
{
$array = [];
if (isset($data['data']) && \is_array($data['data'])) {
$array = $data['data'];
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$data = parent::fetchDataFromDB($filter);
/*
* Retrieve extra data.
*/
// Load side libraries.
global $config;
include_once $config['homedir'].'/include/functions_graph.php';
// Get the linked agent and module Ids.
$linkedModule = static::extractLinkedModule($data);
$agentId = static::parseIntOr($linkedModule['agentId'], null);
$moduleId = static::parseIntOr($linkedModule['moduleId'], null);
if ($agentId === null) {
throw new \InvalidArgumentException('missing agent Id');
}
return $array;
// Use the same HTML output as the old VC.
$html = '<div style="width:500px;">';
$html .= \graph_graphic_moduleevents(
$agentId,
$moduleId,
(int) $data['width'],
(int) $data['height'],
static::extractMaxTime($data),
'',
true
);
$html .= '</div>';
$data['html'] = $html;
return $data;
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
use Models\Model;
/**
* Model of a label item of the Visual Console.
@ -32,14 +31,14 @@ final class Label extends Item
* @throws \InvalidArgumentException If any input value is considered
* invalid.
*
* @overrides Item::validateData.
* @overrides Item->validateData.
*/
protected function validateData(array $data): void
{
parent::validateData($data);
if (empty($data['label']) === true) {
if (static::notEmptyStringOr($data['label'], null) === null) {
throw new \InvalidArgumentException(
'the label property is required and should be string and not null'
'the label property is required and should be a not empty string'
);
}
}
@ -52,7 +51,7 @@ final class Label extends Item
*
* @return array Data structure representing the model.
*
* @overrides Item::decode.
* @overrides Item->decode.
*/
protected function decode(array $data): array
{

View File

@ -5,6 +5,9 @@ declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\Model;
/**
* Model of a line item of the Visual Console.
*/
final class Line extends Model
{
@ -16,11 +19,10 @@ final class Line extends Model
* @param array $data Input data.
*
* @return void
*
* @throws \InvalidArgumentException If any input value is considered
* invalid.
*
* @overrides Model::validateData.
* @overrides Model->validateData.
*/
protected function validateData(array $data): void
{
@ -49,7 +51,7 @@ final class Line extends Model
*
* @return array Data structure representing the model.
*
* @overrides Model::decode.
* @overrides Model->decode.
*/
protected function decode(array $data): array
{
@ -60,7 +62,7 @@ final class Line extends Model
'startY' => $this->extractStartY($data),
'endX' => $this->extractEndX($data),
'endY' => $this->extractEndY($data),
'isOnTop' => $this->extractIsOnTope($data),
'isOnTop' => $this->extractIsOnTop($data),
'borderWidth' => $this->extractBorderWidth($data),
'borderColor' => $this->extractBorderColor($data),
];
@ -68,119 +70,104 @@ final class Line extends Model
/**
* Extract the value of startX and
* return a integer.
* Extract a x axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis start position of the item.
* @return integer Valid x axis of the start position of the line.
*/
private function extractStartX(array $data): int
{
$startX = Model::parseIntOr(
Model::issetInArray($data, ['startX', 'pos_x']),
return static::parseIntOr(
static::issetInArray($data, ['startX', 'pos_x']),
0
);
return $startX;
}
/**
* Extract the value of startY and
* return a integer.
* Extract a y axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis start position of the item.
* @return integer Valid y axis of the start position of the line.
*/
private function extractStartY(array $data): int
{
$startY = Model::parseIntOr(
Model::issetInArray($data, ['startY', 'pos_y']),
return static::parseIntOr(
static::issetInArray($data, ['startY', 'pos_y']),
0
);
return $startY;
}
/**
* Extract the value of endX and
* return a integer.
* Extract a x axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis end position of the item.
* @return integer Valid x axis of the end position of the line.
*/
private function extractEndX(array $data): int
{
$endX = Model::parseIntOr(
Model::issetInArray($data, ['endX', 'width']),
return static::parseIntOr(
static::issetInArray($data, ['endX', 'width']),
0
);
return $endX;
}
/**
* Extract the value of endY and
* return a integer.
* Extract a y axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis end position of the item.
* @return integer Valid y axis of the end position of the line.
*/
private function extractEndY(array $data): int
{
$endY = Model::parseIntOr(
Model::issetInArray($data, ['endY', 'height']),
return static::parseIntOr(
static::issetInArray($data, ['endY', 'height']),
0
);
return $endY;
}
/**
* Extract the value of isOnTop and
* return a bool.
* Extract a conditional value which tells if the item has visual priority.
*
* @param array $data Unknown input data structure.
*
* @return boolean If the item is on top or not.
*/
private function extractIsOnTope(array $data): bool
private function extractIsOnTop(array $data): bool
{
$isOnTop = Model::parseBool(
Model::issetInArray($data, ['isOnTop', 'show_on_top'])
return static::parseBool(
static::issetInArray($data, ['isOnTop', 'show_on_top'])
);
return $isOnTop;
}
/**
* Extract the value of borderWidth and
* return a integer.
* Extract a border width value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid border width. 0 by default.
* @return integer Valid border width. 0 by default and minimum value.
*/
private function extractBorderWidth(array $data): int
{
$borderWidth = Model::parseIntOr(
Model::issetInArray($data, ['borderWidth', 'border_width']),
$borderWidth = static::parseIntOr(
static::issetInArray($data, ['borderWidth', 'border_width']),
0
);
if ($borderWidth >= 0) {
return $borderWidth;
} else {
return 0;
}
return ($borderWidth >= 0) ? $borderWidth : 0;
}
/**
* Extract the value of borderColor and
* return to not empty string or null.
* Extract a border color value.
*
* @param array $data Unknown input data structure.
*
@ -188,11 +175,10 @@ final class Line extends Model
*/
private function extractBorderColor(array $data)
{
$borderColor = Model::notEmptyStringOr(
Model::issetInArray($data, ['borderColor', 'border_color']),
return static::notEmptyStringOr(
static::issetInArray($data, ['borderColor', 'border_color']),
null
);
return $borderColor;
}

View File

@ -0,0 +1,223 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a percentile item of the Visual Console.
*/
final class Percentile extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
*
* @var boolean
*/
protected static $useLinkedModule = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* Used to enable validation, extraction and encodeing of the HTML output.
*
* @var boolean
*/
protected static $useHtmlOutput = true;
/**
* Validate the received data structure to ensure if we can extract the
* values required to build the model.
*
* @param array $data Input data.
*
* @return void
*
* @throws \InvalidArgumentException If any input value is considered
* invalid.
*
* @overrides Item::validateData.
*/
protected function validateData(array $data): void
{
parent::validateData($data);
if (static::notEmptyStringOr($data['encodedHtml'], null) === null
&& static::notEmptyStringOr($data['html'], null) === null
) {
throw new \InvalidArgumentException(
'the html property is required and should be string'
);
}
}
/**
* Returns a valid representation of the model.
*
* @param array $data Input data.
*
* @return array Data structure representing the model.
*
* @overrides Item::decode.
*/
protected function decode(array $data): array
{
$return = parent::decode($data);
$return['type'] = PERCENTILE_BAR;
$return['percentileType'] = static::extractPercentileType($data);
$return['valueType'] = static::extractValueType($data);
$return['value'] = static::notEmptyStringOr($data['value'], null);
$return['color'] = static::extractColor($data);
$return['labelColor'] = static::extractLabelColor($data);
return $return;
}
/**
* Extract a percentile type value.
*
* @param array $data Unknown input data structure.
*
* @return string 'progress-bar', 'bubble', 'circular-progress-bar'
* or 'circular-progress-bar-alt'. 'progress-bar' by default.
*/
private static function extractPercentileType(array $data): string
{
if (isset($data['percentileType']) === true) {
switch ($data['percentileType']) {
case 'progress-bar':
case 'bubble':
case 'circular-progress-bar':
case 'circular-progress-bar-alt':
return $data['percentileType'];
default:
return 'progress-bar';
}
}
switch ($data['type']) {
case PERCENTILE_BUBBLE:
return 'bubble';
case CIRCULAR_PROGRESS_BAR:
return 'circular-progress-bar';
case CIRCULAR_INTERIOR_PROGRESS_BAR:
return 'circular-progress-bar-alt';
default:
case PERCENTILE_BAR:
return 'progress-bar';
}
}
/**
* Extract a value type value.
*
* @param array $data Unknown input data structure.
*
* @return string 'percent' or 'value'. 'percent' by default.
*/
private static function extractValueType(array $data): string
{
$rawValueType = static::issetInArray($data, ['valueType', 'image']);
switch ($rawValueType) {
case 'percent':
case 'value':
return $rawValueType;
default:
return 'percent';
}
}
/**
* Extract a color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed The color or null.
*/
private static function extractColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['color', 'border_color']),
null
);
}
/**
* Extract a label color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed The label color or null.
*/
private static function extractLabelColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['labelColor', 'fill_color']),
null
);
}
/**
* Fetch a vc item data structure from the database using a filter.
*
* @param array $filter Filter of the Visual Console Item.
*
* @return array The Visual Console Item data structure stored into the DB.
* @throws \InvalidArgumentException When an agent Id cannot be found.
*
* @override Item::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter): array
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$data = parent::fetchDataFromDB($filter);
/*
* Retrieve extra data.
*/
// Load side libraries.
global $config;
include_once $config['homedir'].'/include/functions_graph.php';
// Get the linked agent and module Ids.
$linkedModule = static::extractLinkedModule($data);
$agentId = static::parseIntOr($linkedModule['agentId'], null);
$moduleId = static::parseIntOr($linkedModule['moduleId'], null);
if ($agentId === null) {
throw new \InvalidArgumentException('missing agent Id');
}
// TODO: Use the same HTML output as the old VC.
$html = '';
$data['html'] = $html;
return $data;
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
use Models\Model;
/**
* Model of a simple value item of the Visual Console.
@ -40,22 +39,14 @@ final class SimpleValue extends Item
* @throws \InvalidArgumentException If any input value is considered
* invalid.
*
* @overrides Item::validateData.
* @overrides Item->validateData.
*/
protected function validateData(array $data): void
{
parent::validateData($data);
if (isset($data['valueType']) === false
|| \is_string($data['valueType']) === false
) {
throw new \InvalidArgumentException(
'the valueType property is required and should be string'
);
}
if (isset($data['value']) === false) {
throw new \InvalidArgumentException(
'the value property is required'
'the value property is required and should be string'
);
}
}
@ -68,47 +59,39 @@ final class SimpleValue extends Item
*
* @return array Data structure representing the model.
*
* @overrides Item::decode.
* @overrides Item->decode.
*/
protected function decode(array $data): array
{
$return = parent::decode($data);
$return['type'] = SIMPLE_VALUE;
$return['processValue'] = $this->extractProcessValue($data);
$return['processValue'] = static::extractProcessValue($data);
$return['valueType'] = static::extractValueType($data);
$return['value'] = $data['value'];
if ($return['processValue'] !== 'none') {
$return['period'] = $this->extractPeriod($data);
$return['period'] = static::extractPeriod($data);
}
$return['valueType'] = $this->extractValueType($data);
$return['value'] = $data['value'];
return $return;
}
/**
* Extract the value of processValue and
* return 'avg', 'max', 'min' or 'none'.
* Extract a process value.
*
* @param array $data Unknown input data structure.
*
* @return string
* @return string One of 'none', 'avg', 'max' or 'min'. 'none' by default.
*/
private function extractProcessValue(array $data): string
private static function extractProcessValue(array $data): string
{
$processValue = Model::notEmptyStringOr(
Model::issetInArray($data, ['processValue']),
null
);
switch ($processValue) {
switch ($data['processValue']) {
case 'none':
case 'avg':
return 'avg';
case 'max':
return 'max';
case 'min':
return 'min';
return $data['processValue'];
default:
return 'none';
@ -117,45 +100,32 @@ final class SimpleValue extends Item
/**
* Extract the value of period and
* return a integer.
* Extract the value of period.
*
* @param array $data Unknown input data structure.
*
* @return integer
* @return integer The period in seconds. 0 is the minimum value.
*/
private function extractPeriod(array $data): int
private static function extractPeriod(array $data): int
{
$period = Model::parseIntOr(
Model::issetInArray($data, ['period']),
0
);
if ($period >= 0) {
return $period;
} else {
return 0;
}
$period = static::parseIntOr($data['period'], 0);
return ($period >= 0) ? $period : 0;
}
/**
* Extract the value of valueType and
* return 'image' or 'string'.
* Extract a value type.
*
* @param array $data Unknown input data structure.
*
* @return string
* @return string One of 'string' or 'image'. 'string' by default.
*/
private function extractValueType(array $data): string
private static function extractValueType(array $data): string
{
$valueType = Model::notEmptyStringOr(
Model::issetInArray($data, ['valueType']),
null
);
switch ($valueType) {
switch ($data['valueType']) {
case 'string':
case 'image':
return 'image';
return $data['valueType'];
default:
return 'string';
@ -163,4 +133,57 @@ final class SimpleValue extends Item
}
/**
* Fetch a vc item data structure from the database using a filter.
*
* @param array $filter Filter of the Visual Console Item.
*
* @return array The Visual Console Item data structure stored into the DB.
* @throws \InvalidArgumentException When a module Id cannot be found.
*
* @override Item::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter): array
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$data = parent::fetchDataFromDB($filter);
/*
* Retrieve extra data.
*/
// Load side libraries.
global $config;
include_once $config['homedir'].'/include/functions_graph.php';
// Get the linked agent and module Ids.
$linkedModule = static::extractLinkedModule($data);
$moduleId = static::parseIntOr($linkedModule['moduleId'], null);
if ($moduleId === null) {
throw new \InvalidArgumentException('missing module Id');
}
// Get the formatted value.
$value = \visual_map_get_simple_value(
$data['type'],
$moduleId,
static::extractPeriod($data)
);
// Some modules are image based. Extract the base64 image if needed.
$matches = [];
if (\preg_match('/src=\"(data:image.*)"/', $value, $matches) === 1) {
$data['valueType'] = 'image';
$data['value'] = $matches[1];
} else {
$data['valueType'] = 'string';
$data['value'] = $value;
}
return $data;
}
}

View File

@ -4,10 +4,9 @@ declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
use Models\Model;
/**
* Model of a group item of the Visual Console.
* Model of a static graph item of the Visual Console.
*/
final class StaticGraph extends Item
{
@ -36,7 +35,7 @@ final class StaticGraph extends Item
*
* @return array Data structure representing the model.
*
* @overrides Item::decode.
* @overrides Item->decode.
*/
protected function decode(array $data): array
{
@ -44,6 +43,11 @@ final class StaticGraph extends Item
$return['type'] = STATIC_GRAPH;
$return['imageSrc'] = $this->extractImageSrc($data);
$return['showLastValueTooltip'] = $this->extractShowLastValueTooltip($data);
$return['statusImageSrc'] = static::notEmptyStringOr(
$data['statusImageSrc'],
null
);
return $return;
}
@ -64,7 +68,7 @@ final class StaticGraph extends Item
null
);
if ($imageSrc === null || \strlen($imageSrc) === 0) {
if ($imageSrc === null) {
throw new \InvalidArgumentException(
'the image src property is required and should be a non empty string'
);
@ -84,14 +88,14 @@ final class StaticGraph extends Item
*/
private function extractShowLastValueTooltip(array $data): string
{
$showLastValueTooltip = Model::notEmptyStringOr(
Model::issetInArray($data, ['showLastValueTooltip']),
$showLastValueTooltip = static::notEmptyStringOr(
static::issetInArray($data, ['showLastValueTooltip']),
null
);
if ($showLastValueTooltip === null) {
$showLastValueTooltip = Model::parseIntOr(
Model::issetInArray($data, ['show_last_value']),
$showLastValueTooltip = static::parseIntOr(
static::issetInArray($data, ['show_last_value']),
null
);
switch ($showLastValueTooltip) {
@ -119,4 +123,35 @@ final class StaticGraph extends Item
}
/**
* Fetch a vc item data structure from the database using a filter.
*
* @param array $filter Filter of the Visual Console Item.
*
* @return array The Visual Console Item data structure stored into the DB.
* @throws \InvalidArgumentException When an agent Id cannot be found.
*
* @override Item::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter): array
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$data = parent::fetchDataFromDB($filter);
/*
* Retrieve extra data.
*/
// Load side libraries.
global $config;
include_once $config['homedir'].'/include/functions_visual_map.php';
// Get the img src.
$data['statusImageSrc'] = \visual_map_get_image_status_element($data);
return $data;
}
}

View File

@ -129,7 +129,7 @@
<div style='height: 10px'>
<?php
$version = '7.0NG.733';
$build = '190328';
$build = '190331';
$banner = "v$version Build $build";
error_reporting(0);

View File

@ -169,6 +169,11 @@ $options['view']['active'] = true;
if (!is_metaconsole()) {
if (!$config['pure']) {
$options['pure']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$refr.'&pure=1">'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).'</a>';
$options['view2']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/visual_console_view&id='.$id_layout.'&refr='.$view_refresh.'">'.html_print_image(
'images/operation.png',
true,
['title' => __('Beta View')]
).'</a>';
ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
}

View File

@ -0,0 +1,148 @@
<?php
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2019 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation for version 2.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
global $config;
// Login check.
check_login();
require_once $config['homedir'].'/vendor/autoload.php';
require_once $config['homedir'].'/include/functions_visual_map.php';
if (!defined('METACONSOLE')) {
$id_layout = (int) get_parameter('id');
} else {
$id_layout = (int) get_parameter('id_visualmap');
}
// Get input parameter for layout id.
if (!$id_layout) {
db_pandora_audit(
'ACL Violation',
'Trying to access visual console without id layout'
);
include 'general/noaccess.php';
exit;
}
$layout = db_get_row('tlayout', 'id', $id_layout);
if (!$layout) {
db_pandora_audit(
'ACL Violation',
'Trying to access visual console without id layout'
);
include 'general/noaccess.php';
exit;
}
$id_group = $layout['id_group'];
$layout_name = $layout['name'];
// ACL.
$vconsole_read = check_acl($config['id_user'], $id_group, 'VR');
$vconsole_write = check_acl($config['id_user'], $id_group, 'VW');
$vconsole_manage = check_acl($config['id_user'], $id_group, 'VM');
if (!$vconsole_read && !$vconsole_write && !$vconsole_manage) {
db_pandora_audit(
'ACL Violation',
'Trying to access visual console without group access'
);
include 'general/noaccess.php';
exit;
}
// Render map.
$options = [];
$options['consoles_list']['text'] = '<a href="index.php?sec=network&sec2=godmode/reporting/map_builder&refr='.$refr.'">'.html_print_image(
'images/visual_console.png',
true,
['title' => __('Visual consoles list')]
).'</a>';
if ($vconsole_write || $vconsole_manage) {
$url_base = 'index.php?sec=network&sec2=godmode/reporting/visual_console_builder&action=';
$hash = md5($config['dbpass'].$id_layout.$config['id_user']);
$options['public_link']['text'] = '<a href="'.ui_get_full_url(
'operation/visual_console/public_console.php?hash='.$hash.'&id_layout='.$id_layout.'&id_user='.$config['id_user']
).'" target="_blank">'.html_print_image(
'images/camera_mc.png',
true,
['title' => __('Show link to public Visual Console')]
).'</a>';
$options['public_link']['active'] = false;
$options['data']['text'] = '<a href="'.$url_base.$action.'&tab=data&id_visual_console='.$id_layout.'">'.html_print_image(
'images/op_reporting.png',
true,
['title' => __('Main data')]
).'</a>';
$options['list_elements']['text'] = '<a href="'.$url_base.$action.'&tab=list_elements&id_visual_console='.$id_layout.'">'.html_print_image(
'images/list.png',
true,
['title' => __('List elements')]
).'</a>';
if (enterprise_installed()) {
$options['wizard_services']['text'] = '<a href="'.$url_base.$action.'&tab=wizard_services&id_visual_console='.$id_layout.'">'.html_print_image(
'images/wand_services.png',
true,
['title' => __('Services wizard')]
).'</a>';
}
$options['wizard']['text'] = '<a href="'.$url_base.$action.'&tab=wizard&id_visual_console='.$id_layout.'">'.html_print_image(
'images/wand.png',
true,
['title' => __('Wizard')]
).'</a>';
$options['editor']['text'] = '<a href="'.$url_base.$action.'&tab=editor&id_visual_console='.$id_layout.'">'.html_print_image(
'images/builder.png',
true,
['title' => __('Builder')]
).'</a>';
}
$options['view']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$view_refresh.'">'.html_print_image('images/operation.png', true, ['title' => __('View')]).'</a>';
if (!is_metaconsole()) {
if (!$config['pure']) {
$options['pure']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$refr.'&pure=1">'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).'</a>';
$options['view2']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/visual_console_view&id='.$id_layout.'&refr='.$view_refresh.'">'.html_print_image(
'images/operation.png',
true,
['title' => __('Beta View')]
).'</a>';
$options['view2']['active'] = true;
ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
}
// Set the hidden value for the javascript.
html_print_input_hidden('metaconsole', 0);
} else {
// Set the hidden value for the javascript.
html_print_input_hidden('metaconsole', 1);
}
use Models\VisualConsole\Container;
$container = (string) Container::fromArray($layout);
$items = Container::getItemsFromDB($id_layout, $config['homedir']);
hd($config['homedir']);
hd($items);

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.733
%define release 190328
%define release 190331
# User and Group under which Apache is running
%define httpd_name httpd

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.733
%define release 190328
%define release 190331
%define httpd_name httpd
# User and Group under which Apache is running
%define httpd_name apache2

View File

@ -145,7 +145,7 @@ class ClockTest extends TestCase
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"clockFormat":"time","clockTimezone":"Europe\/Madrid","clockTimezoneOffset":3600,"clockType":"digital","color":"white","height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"showClockTimezone":false,"type":19,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"clockFormat":"time","clockTimezone":"Europe\/Madrid","clockTimezoneOffset":7200,"clockType":"digital","color":"white","height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"showClockTimezone":false,"type":19,"width":0,"x":-666,"y":76}',
(string) Clock::fromArray(
[
'id' => 69,

View File

@ -6,27 +6,26 @@ use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\ColorCloud;
/**
* Test for the Visual Console color cloud Item model.
* Test for the Visual Console color cloud item model.
*/
class ColorCloudTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
ColorCloud::class,
ColorCloud::fromArray(
[
'id' => 69,
'id' => 345,
'type' => COLOR_CLOUD,
'label' => '{"default_color":"#47b042","color_ranges":[{"from_value":20,"to_value":60,"color":"#d0da27"},{"from_value":61,"to_value":100,"color":"#ec1f1f"}]}',
'labelPosition' => 'up',
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
@ -34,6 +33,8 @@ class ColorCloudTest extends TestCase
'height' => '0',
'x' => -666,
'y' => 76,
'defaultColor' => '#FFF',
'colorRanges' => [],
]
)
);
@ -46,82 +47,30 @@ class ColorCloudTest extends TestCase
'type' => COLOR_CLOUD,
'width' => 100,
'height' => 900,
'color' => '#47b042',
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
'colorRanges' => [
[
'fromValue' => 50,
'toValue' => 90,
'color' => '#d0da27',
],
[
'fromValue' => 910,
'toValue' => 100,
'color' => '#ec1f1f',
'color' => '#000',
'fromValue' => 10.05,
'toValue' => 100.0,
],
],
'color' => '#000',
]
)
);
}
/**
* Test if the instance is not created when using a invalid color.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidColor(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid color.
ColorCloud::fromArray(
[
'id' => 69,
'type' => COLOR_CLOUD,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'color' => '',
]
);
// Invalid color.
ColorCloud::fromArray(
[
'id' => 69,
'type' => COLOR_CLOUD,
'label' => '{"default_col":"#47b042","color_ranges":[]}',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
);
// Missing color.
ColorCloud::fromArray(
[
'id' => 69,
'type' => COLOR_CLOUD,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
$this->assertInstanceOf(
ColorCloud::class,
ColorCloud::fromArray(
[
'id' => 1000,
'type' => COLOR_CLOUD,
'width' => 100,
'height' => 900,
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
]
)
);
}
@ -134,12 +83,12 @@ class ColorCloudTest extends TestCase
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#47b042","colorRanges":[{"fromValue":20,"toValue":60,"color":"#d0da27"},{"fromValue":61,"toValue":100,"color":"#ec1f1f"}],"height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
(string) ColorCloud::fromArray(
[
'id' => 69,
'id' => 7,
'type' => COLOR_CLOUD,
'label' => '{"default_color":"#47b042","color_ranges":[{"from_value":20,"to_value":60,"color":"#d0da27"},{"from_value":61,"to_value":100,"color":"#ec1f1f"}]}',
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
@ -148,35 +97,157 @@ class ColorCloudTest extends TestCase
'height' => '0',
'x' => -666,
'y' => 76,
'defaultColor' => '#FFF',
'colorRanges' => [
[
'color' => '#000',
'fromValue' => 10.05,
'toValue' => 100.0,
],
],
'color' => '#000',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#47b042","colorRanges":[{"fromValue":50,"toValue":90,"color":"#d0da27"},{"fromValue":910,"toValue":100,"color":"#ec1f1f"}],"height":900,"id":1000,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":100,"x":0,"y":0}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"colorRanges":[],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
(string) ColorCloud::fromArray(
[
'id' => 1000,
'type' => COLOR_CLOUD,
'width' => 100,
'height' => 900,
'color' => '#47b042',
'colorRanges' => [
'id' => 7,
'type' => COLOR_CLOUD,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'defaultColor' => '#FFF',
'colorRanges' => [],
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
(string) ColorCloud::fromArray(
[
'id' => 7,
'type' => COLOR_CLOUD,
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'color' => '#000',
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
(string) ColorCloud::fromArray(
[
'id' => 7,
'type' => COLOR_CLOUD,
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'defaultColor' => '#FFF',
'color' => '#000',
'id_layout_linked' => 1,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
(string) ColorCloud::fromArray(
[
'id' => 7,
'type' => COLOR_CLOUD,
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'colorRanges' => [
[
'fromValue' => 50,
'toValue' => 90,
'color' => '#d0da27',
],
[
'fromValue' => 910,
'toValue' => 100,
'color' => '#ec1f1f',
'color' => '#000',
'fromValue' => 10.05,
'toValue' => 100.0,
],
],
'color' => '#000',
'linkedLayoutId' => 2,
'linked_layout_status_type' => 'service',
'linkedLayoutStatusTypeWarningThreshold' => 50,
'linked_layout_status_as_service_critical' => 80,
]
)
);
}
/**
* Test if the instance is not created when using a invalid dynamic data.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidDynamicData(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid dynamic data.
ColorCloud::fromArray(
[
'id' => 3,
'type' => COLOR_CLOUD,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
]
);
// Missing dynamic data.
ColorCloud::fromArray(
[
'id' => 3,
'type' => COLOR_CLOUD,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
]
);
}
}

View File

@ -28,7 +28,7 @@ class EventsHistoryTest extends TestCase
'width' => '600',
'height' => '500',
'maxTime' => null,
'data' => [],
'html' => '<h1>Foo</h1>',
]
)
);
@ -37,15 +37,12 @@ class EventsHistoryTest extends TestCase
EventsHistory::class,
EventsHistory::fromArray(
[
'id' => 14,
'type' => AUTO_SLA_GRAPH,
'width' => '600',
'height' => '500',
'maxTime' => 12800,
'data' => [
'data' => '5',
'time' => 23456788,
],
'id' => 14,
'type' => AUTO_SLA_GRAPH,
'width' => '600',
'height' => '500',
'maxTime' => 12800,
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
]
)
);
@ -60,7 +57,7 @@ class EventsHistoryTest extends TestCase
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"data":[],"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxTime":null,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxTime":null,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
(string) EventsHistory::fromArray(
[
'id' => 7,
@ -75,13 +72,13 @@ class EventsHistoryTest extends TestCase
'x' => -666,
'y' => 76,
'maxTime' => null,
'data' => [],
'html' => '<h1>Foo</h1>',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"data":{"time":23456789,"data":15},"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxTime":12800,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxTime":12800,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
(string) EventsHistory::fromArray(
[
'id' => 7,
@ -96,16 +93,13 @@ class EventsHistoryTest extends TestCase
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'data' => [
'time' => 23456789,
'data' => 15,
],
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"data":[],"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","maxTime":null,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","maxTime":null,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
(string) EventsHistory::fromArray(
[
'id' => 7,
@ -120,14 +114,14 @@ class EventsHistoryTest extends TestCase
'x' => -666,
'y' => 76,
'maxTime' => null,
'data' => [],
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
'id_layout_linked' => 1,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"data":{"time":23456789,"data":15},"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","maxTime":12800,"metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","maxTime":12800,"metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
(string) EventsHistory::fromArray(
[
'id' => 7,
@ -142,10 +136,7 @@ class EventsHistoryTest extends TestCase
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'data' => [
'time' => 23456789,
'data' => 15,
],
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
@ -154,7 +145,7 @@ class EventsHistoryTest extends TestCase
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":21,"agentName":null,"data":{"time":23456789,"data":15},"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":15,"linkedLayoutId":3,"linkedLayoutStatusType":"default","maxTime":12800,"metaconsoleId":2,"moduleId":385,"moduleName":"module_test","parentId":null,"type":14,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":21,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":15,"linkedLayoutId":3,"linkedLayoutStatusType":"default","maxTime":12800,"metaconsoleId":2,"moduleId":385,"moduleName":"module_test","parentId":null,"type":14,"width":0,"x":-666,"y":76}',
(string) EventsHistory::fromArray(
[
'id' => 7,
@ -169,10 +160,7 @@ class EventsHistoryTest extends TestCase
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'data' => [
'time' => 23456789,
'data' => 15,
],
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
'id_metaconsole' => 2,
'linked_layout_node_id' => 15,
'linkedLayoutId' => 3,

View File

@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Label;
/**
* Test for the Visual Console label Item model.
* Test for the Visual Console Label Item model.
*/
class LabelTest extends TestCase
{
@ -23,11 +23,11 @@ class LabelTest extends TestCase
Label::class,
Label::fromArray(
[
'id' => 3,
'id' => 69,
'type' => LABEL,
'width' => '600',
'height' => '500',
'label' => 'test',
'width' => '0',
'height' => '0',
'label' => 'Label',
]
)
);
@ -42,23 +42,35 @@ class LabelTest extends TestCase
public function testCannotBeCreatedWithInvalidLabel(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid id.
// Missing label.
Label::fromArray(
[
'id' => 3,
'type' => LABEL,
'width' => '600',
'height' => '500',
'label' => null,
'id' => 7,
'type' => LABEL,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
);
// Missing id.
// Empty label.
Label::fromArray(
[
'id' => 3,
'type' => LABEL,
'width' => '600',
'height' => '500',
'id' => 7,
'type' => LABEL,
'label' => '',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
);
}
@ -72,12 +84,12 @@ class LabelTest extends TestCase
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"test","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"type":4,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"Label","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"type":4,"width":0,"x":-666,"y":76}',
(string) Label::fromArray(
[
'id' => 7,
'type' => LABEL,
'label' => 'test',
'label' => 'Label',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
@ -90,13 +102,14 @@ class LabelTest extends TestCase
)
);
// With a linked layout.
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"test_pandora","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"type":4,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"Label","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"type":4,"width":0,"x":-666,"y":76}',
(string) Label::fromArray(
[
'id' => 7,
'type' => LABEL,
'label' => 'test_pandora',
'label' => 'Label',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
@ -110,27 +123,6 @@ class LabelTest extends TestCase
)
);
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"test_pandora","labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"parentId":null,"type":4,"width":0,"x":-666,"y":76}',
(string) Label::fromArray(
[
'id' => 7,
'type' => LABEL,
'label' => 'test_pandora',
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
}

View File

@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Percentile;
/**
* Test for the Visual Console Percentile Item model.
*/
class PercentileTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
Percentile::class,
Percentile::fromArray(
[
'id' => 3,
'type' => PERCENTILE_BAR,
'width' => '600',
'height' => '500',
'maxTime' => null,
'valueType' => 'value',
'value' => '123ms',
'html' => '<h1>Foo</h1>',
]
)
);
$this->assertInstanceOf(
Percentile::class,
Percentile::fromArray(
[
'id' => 14,
'type' => PERCENTILE_BUBBLE,
'width' => '600',
'height' => '500',
'maxTime' => 12800,
'valueType' => 'image',
'value' => 'data:image;asdasoih==',
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
]
)
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"percentileType":"progress-bar","type":3,"value":null,"valueType":"percent","width":0,"x":-666,"y":76}',
(string) Percentile::fromArray(
[
'id' => 7,
'type' => PERCENTILE_BAR,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => null,
'html' => '<h1>Foo</h1>',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"percentileType":"bubble","type":3,"value":null,"valueType":"percent","width":0,"x":-666,"y":76}',
(string) Percentile::fromArray(
[
'id' => 7,
'type' => PERCENTILE_BUBBLE,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"percentileType":"circular-progress-bar","type":3,"value":"1","valueType":"value","width":0,"x":-666,"y":76}',
(string) Percentile::fromArray(
[
'id' => 7,
'type' => CIRCULAR_PROGRESS_BAR,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
'valueType' => 'value',
'value' => '1',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#FFF","encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":"#000","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"percentileType":"circular-progress-bar","type":3,"value":"80","valueType":"percent","width":0,"x":-666,"y":76}',
(string) Percentile::fromArray(
[
'id' => 7,
'type' => CIRCULAR_PROGRESS_BAR,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'encodedHtml' => 'PGgxPkZvbzwvaDE+',
'valueType' => 'percent',
'value' => '80',
'color' => '#FFF',
'labelColor' => '#000',
]
)
);
}
}

View File

@ -53,84 +53,6 @@ class SimpleValueTest extends TestCase
}
public function testCannotBeCreatedWithInvalidValueType(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid valueType.
SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
'valueType' => '',
'value' => 57,
]
);
// Missing valueType.
SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
'value' => 57,
]
);
}
public function testCannotBeCreatedWithInvalidValue(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid valueType.
SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
'valueType' => 'string',
'value' => 'foo',
]
);
// Missing valueType.
SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
'valueType' => 'string',
]
);
}
/**
* Test if the model has a valid JSON representation.
*

View File

@ -6,12 +6,17 @@ use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\StaticGraph;
/**
* Test class
* Test for the Visual Console static graph Item model.
*/
class StaticGrahpTest extends TestCase
class StaticGraphTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
@ -19,7 +24,7 @@ class StaticGrahpTest extends TestCase
StaticGraph::fromArray(
[
'id' => 345,
'type' => 1,
'type' => STATIC_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
@ -40,7 +45,7 @@ class StaticGrahpTest extends TestCase
StaticGraph::fromArray(
[
'id' => 1000,
'type' => 0,
'type' => STATIC_GRAPH,
'width' => 100,
'height' => 900,
'image' => 'test.jpg',
@ -59,7 +64,7 @@ class StaticGrahpTest extends TestCase
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","type":0,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":null,"type":0,"width":0,"x":-666,"y":76}',
(string) StaticGraph::fromArray(
[
'id' => 7,
@ -79,7 +84,7 @@ class StaticGrahpTest extends TestCase
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"disabled","type":0,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"disabled","statusImageSrc":null,"type":0,"width":0,"x":-666,"y":76}',
(string) StaticGraph::fromArray(
[
'id' => 7,
@ -100,7 +105,7 @@ class StaticGrahpTest extends TestCase
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","type":0,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":"image.bad.jpg","type":0,"width":0,"x":-666,"y":76}',
(string) StaticGraph::fromArray(
[
'id' => 7,
@ -118,12 +123,13 @@ class StaticGrahpTest extends TestCase
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
'statusImageSrc' => 'image.bad.jpg',
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","type":0,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":null,"type":0,"width":0,"x":-666,"y":76}',
(string) StaticGraph::fromArray(
[
'id' => 7,
@ -144,7 +150,7 @@ class StaticGrahpTest extends TestCase
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","type":0,"width":0,"x":-666,"y":76}',
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":"image.bad.jpg","type":0,"width":0,"x":-666,"y":76}',
(string) StaticGraph::fromArray(
[
'id' => 7,
@ -163,12 +169,18 @@ class StaticGrahpTest extends TestCase
'linked_layout_status_type' => 'service',
'linkedLayoutStatusTypeWarningThreshold' => 50,
'linked_layout_status_as_service_critical' => 80,
'statusImageSrc' => 'image.bad.jpg',
]
)
);
}
/**
* Test if the instance is not created when using a invalid image src.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidImageSrc(): void
{
$this->expectException(InvalidArgumentException::class);
@ -176,7 +188,7 @@ class StaticGrahpTest extends TestCase
StaticGraph::fromArray(
[
'id' => 3,
'type' => 0,
'type' => STATIC_GRAPH,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
@ -189,11 +201,12 @@ class StaticGrahpTest extends TestCase
'showLastValueTooltip' => 'disabled',
]
);
// Missing imageSrc.
StaticGraph::fromArray(
[
'id' => 3,
'type' => 0,
'type' => STATIC_GRAPH,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,

View File

@ -1,5 +1,5 @@
package: pandorafms-server
Version: 7.0NG.733-190328
Version: 7.0NG.733-190331
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.733-190328"
pandora_version="7.0NG.733-190331"
package_cpan=0
package_pandora=1

View File

@ -45,7 +45,7 @@ our @EXPORT = qw(
# version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.733";
my $pandora_build = "190328";
my $pandora_build = "190331";
our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash

View File

@ -32,7 +32,7 @@ our @ISA = qw(Exporter);
# version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.733";
my $pandora_build = "190328";
my $pandora_build = "190331";
our $VERSION = $pandora_version." ".$pandora_build;
our %EXPORT_TAGS = ( 'all' => [ qw() ] );

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_server
%define version 7.0NG.733
%define release 190328
%define release 190331
Summary: Pandora FMS Server
Name: %{name}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_server
%define version 7.0NG.733
%define release 190328
%define release 190331
Summary: Pandora FMS Server
Name: %{name}

View File

@ -9,7 +9,7 @@
# **********************************************************************
PI_VERSION="7.0NG.733"
PI_BUILD="190328"
PI_BUILD="190331"
MODE=$1
if [ $# -gt 1 ]; then

View File

@ -34,7 +34,7 @@ use PandoraFMS::Config;
use PandoraFMS::DB;
# version: define current version
my $version = "7.0NG.733 PS190328";
my $version = "7.0NG.733 PS190331";
# Pandora server configuration
my %conf;

View File

@ -36,7 +36,7 @@ use Encode::Locale;
Encode::Locale::decode_argv;
# version: define current version
my $version = "7.0NG.733 PS190328";
my $version = "7.0NG.733 PS190331";
# save program name for logging
my $progname = basename($0);

File diff suppressed because it is too large Load Diff

View File

@ -24,25 +24,25 @@
},
"homepage": "https://github.com/pandorafms/pandorafms#readme",
"dependencies": {
"@types/jest": "^24.0.9",
"@typescript-eslint/eslint-plugin": "^1.4.2",
"@typescript-eslint/parser": "^1.4.2",
"@types/jest": "^24.0.11",
"@typescript-eslint/eslint-plugin": "^1.5.0",
"@typescript-eslint/parser": "^1.5.0",
"awesome-typescript-loader": "^5.2.1",
"clean-webpack-plugin": "^2.0.0",
"css-loader": "^2.1.0",
"eslint": "^5.14.1",
"eslint-config-prettier": "^4.0.0",
"clean-webpack-plugin": "^2.0.1",
"css-loader": "^2.1.1",
"eslint": "^5.16.0",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-prettier": "^3.0.1",
"file-loader": "^3.0.1",
"jest": "^24.1.0",
"jest": "^24.5.0",
"mini-css-extract-plugin": "^0.5.0",
"postcss-loader": "^3.0.0",
"prettier": "^1.16.1",
"ts-jest": "^24.0.0",
"typescript": "^3.3.3333",
"ts-jest": "^24.0.1",
"typescript": "^3.4.1",
"url-loader": "^1.1.2",
"webpack": "^4.29.5",
"webpack-cli": "^3.2.3",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
}

View File

@ -7,6 +7,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" media="screen" href="vc.main.css" />
</head>
<style>
body {
margin: 0;
}
</style>
<body>
<div id="visual-console-container"></div>
</body>
@ -19,8 +24,8 @@
id: 1,
groupId: 0,
name: "Test Visual Console",
width: 800,
height: 300,
width: 1000,
height: 400,
backgroundURL: null,
backgroundColor: "rgb(86, 86, 86)",
isFavorite: false
@ -131,7 +136,8 @@
// Generic props.
id: 5,
type: 19, // Clock = 19
label: null,
label: "<h1>Analogic clock</h1>",
labelPosition: "up",
isLinkEnabled: false,
isOnTop: false,
parentId: null,
@ -185,6 +191,44 @@
color: "white"
};
var labelRawProps = {
// Generic props.
id: 8,
type: 4, // Label = 4
label: '<h1 style="color: #FDFD96;">I\'m a label</h1>',
isLinkEnabled: false,
isOnTop: false,
parentId: null,
aclGroupId: null,
// Position props.
x: 410,
y: 0,
// Size props.
width: 200,
height: 200
};
var simpleValueRawProps = {
// Generic props.
id: 9,
type: 2, // Simple value = 2
label: '<h3 style="color: #FDFD96;">Simple Value: 10</h3>',
isLinkEnabled: false,
isOnTop: false,
parentId: null,
aclGroupId: null,
// Position props.
x: 10,
y: 10,
// Size props.
width: 50,
height: 50,
// Custom props.
valueType: "string",
value: "10",
processValue: "none"
};
var items = [
staticGraphRawProps,
colorCloudRawProps,
@ -192,7 +236,9 @@
digitalClockRawProps2,
analogicClockRawProps,
boxRawProps,
lineRawProps
lineRawProps,
labelRawProps,
simpleValueRawProps
];
try {

View File

@ -82,7 +82,6 @@ export function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {
if (data.id == null || isNaN(parseInt(data.id))) {
throw new TypeError("invalid id.");
}
// TODO: Check for valid types.
if (data.type == null || isNaN(parseInt(data.type))) {
throw new TypeError("invalid type.");
}
@ -101,11 +100,15 @@ export function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {
};
}
/**
* Base class of the visual console items. Should be extended to use its capabilities.
*/
abstract class VisualConsoleItem<Props extends ItemProps> {
// Properties of the item.
private itemProps: Props;
// Reference to the DOM element which will contain the item.
public readonly elementRef: HTMLElement;
private readonly labelElementRef: HTMLElement;
// Reference to the DOM element which will contain the view of the item which extends this class.
protected readonly childElementRef: HTMLElement;
// Event manager for click events.
@ -129,6 +132,8 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
* when hovered, etc.
*/
this.elementRef = this.createContainerDomElement();
this.labelElementRef = document.createElement("div");
this.labelElementRef.className = "visual-console-item-label";
/*
* Get a HTMLElement which represents the custom view
@ -137,9 +142,18 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
*/
this.childElementRef = this.createDomElement();
// Add the label if it exists.
if (this.props.label && this.props.label.length) {
this.labelElementRef.innerHTML = this.props.label;
}
// Insert the elements into the container.
// Visual Console Item Container > Custom Item View.
this.elementRef.append(this.childElementRef);
this.elementRef.append(this.childElementRef, this.labelElementRef);
// Resize element.
this.resizeElement(props.width, props.height);
// Set label position.
this.changeLabelPosition(props.labelPosition);
}
/**
@ -149,12 +163,12 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
private createContainerDomElement(): HTMLElement {
const box: HTMLDivElement = document.createElement("div");
box.className = "visual-console-item";
box.style.width = `${this.props.width}px`;
box.style.height = `${this.props.height}px`;
// box.style.width = `${this.props.width}px`;
// box.style.height = `${this.props.height}px`;
box.style.left = `${this.props.x}px`;
box.style.top = `${this.props.y}px`;
box.onclick = () => this.clickEventManager.emit({ data: this.props });
// TODO: Add label.
return box;
}
@ -204,6 +218,8 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
* @param prevProps If exists it will be used to only perform DOM updates instead of a full replace.
*/
public render(prevProps: Props | null = null): void {
this.childElementRef.innerHTML = this.createDomElement().innerHTML;
// Move box.
if (!prevProps || this.positionChanged(prevProps, this.props)) {
this.moveElement(this.props.x, this.props.y);
@ -212,8 +228,15 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
if (!prevProps || this.sizeChanged(prevProps, this.props)) {
this.resizeElement(this.props.width, this.props.height);
}
this.childElementRef.innerHTML = this.createDomElement().innerHTML;
// Change label.
if (!prevProps || prevProps.label !== this.props.label) {
this.labelElementRef.innerHTML =
this.props.label != null ? this.props.label : "";
}
// Change label position.
if (!prevProps || prevProps.labelPosition !== this.props.labelPosition) {
this.changeLabelPosition(this.props.labelPosition);
}
}
/**
@ -222,8 +245,6 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
public remove(): void {
// Event listeners.
this.disposables.forEach(_ => _.dispose());
// VisualConsoleItem extension DOM element.
this.childElementRef.remove();
// VisualConsoleItem DOM element.
this.elementRef.remove();
}
@ -242,6 +263,28 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
return prevPosition.x !== newPosition.x || prevPosition.y !== newPosition.y;
}
/**
* Move the label around the item content.
* @param position Label position.
*/
protected changeLabelPosition(position: Props["labelPosition"]): void {
switch (position) {
case "up":
this.elementRef.style.flexDirection = "column-reverse";
break;
case "left":
this.elementRef.style.flexDirection = "row-reverse";
break;
case "right":
this.elementRef.style.flexDirection = "row";
break;
case "down":
default:
this.elementRef.style.flexDirection = "column";
break;
}
}
/**
* Move the DOM container.
* @param x Horizontal axis position.
@ -280,13 +323,14 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
}
/**
* Resize the DOM container.
* Resize the DOM content container.
* @param width
* @param height
*/
protected resizeElement(width: number, height: number): void {
this.elementRef.style.width = `${width}px`;
this.elementRef.style.height = `${height}px`;
// The most valuable size is the content size.
this.childElementRef.style.width = `${width}px`;
this.childElementRef.style.height = `${height}px`;
}
/**

View File

@ -13,6 +13,12 @@ import Group, { groupPropsDecoder } from "./items/Group";
import Clock, { clockPropsDecoder } from "./items/Clock";
import Box, { boxPropsDecoder } from "./items/Box";
import Line, { linePropsDecoder } from "./items/Line";
import Label, { labelPropsDecoder } from "./items/Label";
import SimpleValue, { simpleValuePropsDecoder } from "./items/SimpleValue";
import EventsHistory, {
eventsHistoryPropsDecoder
} from "./items/EventsHistory";
import Percentile, { percentilePropsDecoder } from "./items/Percentile";
// Base properties.
export interface VisualConsoleProps extends Size {
@ -79,21 +85,19 @@ function itemInstanceFrom(data: UnknownObject) {
case ItemType.MODULE_GRAPH:
throw new TypeError("item not found");
case ItemType.SIMPLE_VALUE:
throw new TypeError("item not found");
case ItemType.SIMPLE_VALUE_MAX:
case ItemType.SIMPLE_VALUE_MIN:
case ItemType.SIMPLE_VALUE_AVG:
return new SimpleValue(simpleValuePropsDecoder(data));
case ItemType.PERCENTILE_BAR:
throw new TypeError("item not found");
case ItemType.PERCENTILE_BUBBLE:
case ItemType.CIRCULAR_PROGRESS_BAR:
case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
return new Percentile(percentilePropsDecoder(data));
case ItemType.LABEL:
throw new TypeError("item not found");
return new Label(labelPropsDecoder(data));
case ItemType.ICON:
return new Icon(iconPropsDecoder(data));
case ItemType.SIMPLE_VALUE_MAX:
throw new TypeError("item not found");
case ItemType.SIMPLE_VALUE_MIN:
throw new TypeError("item not found");
case ItemType.SIMPLE_VALUE_AVG:
throw new TypeError("item not found");
case ItemType.PERCENTILE_BUBBLE:
throw new TypeError("item not found");
case ItemType.SERVICE:
throw new TypeError("item not found");
case ItemType.GROUP_ITEM:
@ -103,13 +107,8 @@ function itemInstanceFrom(data: UnknownObject) {
case ItemType.LINE_ITEM:
return new Line(linePropsDecoder(data));
case ItemType.AUTO_SLA_GRAPH:
throw new TypeError("item not found");
case ItemType.CIRCULAR_PROGRESS_BAR:
throw new TypeError("item not found");
case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
throw new TypeError("item not found");
return new EventsHistory(eventsHistoryPropsDecoder(data));
case ItemType.DONUT_GRAPH:
throw new TypeError("item not found");
case ItemType.BARS_GRAPH:
throw new TypeError("item not found");
case ItemType.CLOCK:
@ -252,6 +251,7 @@ export default class VisualConsole {
public remove(): void {
this.elements.forEach(e => e.remove()); // Arrow function.
this.elements = [];
// TODO: Clean container.
// Clean container.
this.containerRef.innerHTML = "";
}
}

View File

@ -172,8 +172,8 @@ export default class Clock extends Item<ClockProps> {
*/
public resize(width: number, height: number): void {
super.resize(width, height);
// this.childElementRef.style.width = `${width}px`;
// this.childElementRef.style.height = `${height}px`;
this.childElementRef.style.width = `${width}px`;
this.childElementRef.style.height = `${height}px`;
// Re-render the item to force it calculate a new font size.
if (this.props.clockType === "digital") this.render();
}
@ -212,6 +212,8 @@ export default class Clock extends Item<ClockProps> {
const div = document.createElement("div");
div.className = "analogic-clock";
div.style.width = `${this.props.width}px`;
div.style.height = `${this.props.height}px`;
// SVG container.
const svg = document.createElementNS(svgNS, "svg");

View File

@ -0,0 +1,58 @@
import {
LinkedVisualConsoleProps,
UnknownObject,
WithModuleProps
} from "../types";
import {
linkedVCPropsDecoder,
modulePropsDecoder,
parseIntOr,
decodeBase64,
stringIsEmpty
} from "../lib";
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
export type EventsHistoryProps = {
type: ItemType.AUTO_SLA_GRAPH;
maxTime: number | null;
html: string;
} & ItemProps &
WithModuleProps &
LinkedVisualConsoleProps;
/**
* Build a valid typed object from a raw object.
* This will allow us to ensure the type safety.
*
* @param data Raw object.
* @return An object representing the events history props.
* @throws Will throw a TypeError if some property
* is missing from the raw object or have an invalid type.
*/
export function eventsHistoryPropsDecoder(
data: UnknownObject
): EventsHistoryProps | never {
if (stringIsEmpty(data.html) || stringIsEmpty(data.encodedHtml)) {
throw new TypeError("missing html content.");
}
return {
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
type: ItemType.AUTO_SLA_GRAPH,
maxTime: parseIntOr(data.maxTime, null),
html: !stringIsEmpty(data.html)
? data.html
: decodeBase64(data.encodedHtml),
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
};
}
export default class EventsHistory extends Item<EventsHistoryProps> {
public createDomElement(): HTMLElement {
const element = document.createElement("div");
element.innerHTML = this.props.html;
return element;
}
}

View File

@ -41,13 +41,4 @@ describe("Group item", () => {
groupInstance.elementRef.getElementsByClassName("group").length
).toBeGreaterThan(0);
});
it("should have the required size", () => {
expect(groupInstance.elementRef.style.width).toBe(
`${sizeRawProps.width}px`
);
expect(groupInstance.elementRef.style.height).toBe(
`${sizeRawProps.height}px`
);
});
});

View File

@ -0,0 +1,49 @@
import { LinkedVisualConsoleProps, UnknownObject } from "../types";
import { linkedVCPropsDecoder } from "../lib";
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
export type LabelProps = {
type: ItemType.LABEL;
} & ItemProps &
LinkedVisualConsoleProps;
/**
* Build a valid typed object from a raw object.
* This will allow us to ensure the type safety.
*
* @param data Raw object.
* @return An object representing the label props.
* @throws Will throw a TypeError if some property
* is missing from the raw object or have an invalid type.
*/
export function labelPropsDecoder(data: UnknownObject): LabelProps | never {
return {
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
type: ItemType.LABEL,
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
};
}
export default class Label extends Item<LabelProps> {
public createDomElement(): HTMLElement {
const element = document.createElement("div");
element.className = "label";
// Size to 0, as the item content is managed using the label.
element.style.width = "0";
element.style.height = "0";
// The content of this item is already shown into the label container.
// element.innerHTML = this.props.label || "";
return element;
}
/**
* @override Item.resize
* To resize the item.
*/
public resizeElement(): void {
// Size to 0, as the item content is managed using the label.
this.childElementRef.style.width = `0`;
this.childElementRef.style.height = `0`;
}
}

View File

@ -0,0 +1,109 @@
import {
LinkedVisualConsoleProps,
UnknownObject,
WithModuleProps
} from "../types";
import {
linkedVCPropsDecoder,
modulePropsDecoder,
decodeBase64,
stringIsEmpty,
notEmptyStringOr
} from "../lib";
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
export type PercentileProps = {
type: ItemType.PERCENTILE_BAR;
percentileType:
| "progress-bar"
| "bubble"
| "circular-progress-bar"
| "circular-progress-bar-alt";
valueType: "percent" | "value";
value: string | null;
color: string | null;
labelColor: string | null;
html: string;
} & ItemProps &
WithModuleProps &
LinkedVisualConsoleProps;
/**
* Extract a valid enum value from a raw type value.
* @param type Raw value.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function extractPercentileType(type: any): PercentileProps["percentileType"] {
switch (type) {
case "progress-bar":
case "bubble":
case "circular-progress-bar":
case "circular-progress-bar-alt":
return type;
default:
case ItemType.PERCENTILE_BAR:
return "progress-bar";
case ItemType.PERCENTILE_BUBBLE:
return "bubble";
case ItemType.CIRCULAR_PROGRESS_BAR:
return "circular-progress-bar";
case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
return "circular-progress-bar-alt";
}
}
/**
* Extract a valid enum value from a raw value type value.
* @param type Raw value.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function extractValueType(valueType: any): PercentileProps["valueType"] {
switch (valueType) {
case "percent":
case "value":
return valueType;
default:
return "percent";
}
}
/**
* Build a valid typed object from a raw object.
* This will allow us to ensure the type safety.
*
* @param data Raw object.
* @return An object representing the percentile props.
* @throws Will throw a TypeError if some property
* is missing from the raw object or have an invalid type.
*/
export function percentilePropsDecoder(
data: UnknownObject
): PercentileProps | never {
if (stringIsEmpty(data.html) || stringIsEmpty(data.encodedHtml)) {
throw new TypeError("missing html content.");
}
return {
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
type: ItemType.PERCENTILE_BAR,
percentileType: extractPercentileType(data.type),
valueType: extractValueType(data.valueType),
value: notEmptyStringOr(data.value, null),
color: notEmptyStringOr(data.color, null),
labelColor: notEmptyStringOr(data.labelColor, null),
html: !stringIsEmpty(data.html)
? data.html
: decodeBase64(data.encodedHtml),
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
};
}
export default class Percentile extends Item<PercentileProps> {
public createDomElement(): HTMLElement {
const element = document.createElement("div");
element.innerHTML = this.props.html;
return element;
}
}

View File

@ -0,0 +1,119 @@
import {
LinkedVisualConsoleProps,
UnknownObject,
WithModuleProps
} from "../types";
import { linkedVCPropsDecoder, parseIntOr, modulePropsDecoder } from "../lib";
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
export type SimpleValueProps = {
type: ItemType.SIMPLE_VALUE;
valueType: "string" | "image";
value: string;
} & (
| {
processValue: "none";
}
| {
processValue: "avg" | "max" | "min";
period: number;
}) &
ItemProps &
WithModuleProps &
LinkedVisualConsoleProps;
/**
* Extract a valid enum value from a raw value type.
* @param valueType Raw value.
*/
const parseValueType = (
valueType: any // eslint-disable-line @typescript-eslint/no-explicit-any
): SimpleValueProps["valueType"] => {
switch (valueType) {
case "string":
case "image":
return valueType;
default:
return "string";
}
};
/**
* Extract a valid enum value from a raw process value.
* @param processValue Raw value.
*/
const parseProcessValue = (
processValue: any // eslint-disable-line @typescript-eslint/no-explicit-any
): SimpleValueProps["processValue"] => {
switch (processValue) {
case "none":
case "avg":
case "max":
case "min":
return processValue;
default:
return "none";
}
};
/**
* Build a valid typed object from a raw object.
* This will allow us to ensure the type safety.
*
* @param data Raw object.
* @return An object representing the simple value props.
* @throws Will throw a TypeError if some property
* is missing from the raw object or have an invalid type.
*/
export function simpleValuePropsDecoder(
data: UnknownObject
): SimpleValueProps | never {
if (typeof data.value !== "string" || data.value.length === 0) {
throw new TypeError("invalid value");
}
const processValue = parseProcessValue(data.processValue);
return {
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
type: ItemType.SIMPLE_VALUE,
valueType: parseValueType(data.valueType),
value: data.value,
...(processValue === "none"
? { processValue }
: { processValue, period: parseIntOr(data.period, 0) }), // Object spread. It will merge the properties of the two objects.
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
};
}
export default class SimpleValue extends Item<SimpleValueProps> {
public createDomElement(): HTMLElement {
const element = document.createElement("div");
element.className = "simple-value";
if (this.props.valueType === "image") {
const img = document.createElement("img");
img.src = this.props.value;
element.append(img);
} else {
// Size to 0, as the item content is managed using the label.
element.style.width = "0";
element.style.height = "0";
// The content of this item is already shown into the label container.
// element.innerHTML = this.props.label || "";
}
return element;
}
/**
* @override Item.resize
* To resize the item.
*/
public resizeElement(): void {
// Size to 0, as the item content is managed using the label.
this.childElementRef.style.width = `0`;
this.childElementRef.style.height = `0`;
}
}

View File

@ -4,13 +4,18 @@ import {
UnknownObject
} from "../types";
import { modulePropsDecoder, linkedVCPropsDecoder } from "../lib";
import {
modulePropsDecoder,
linkedVCPropsDecoder,
notEmptyStringOr
} from "../lib";
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
export type StaticGraphProps = {
type: ItemType.STATIC_GRAPH;
imageSrc: string; // URL?
showLastValueTooltip: "default" | "enabled" | "disabled";
statusImageSrc: string | null; // URL?
} & ItemProps &
(WithModuleProps | LinkedVisualConsoleProps);
@ -52,6 +57,7 @@ export function staticGraphPropsDecoder(
type: ItemType.STATIC_GRAPH,
imageSrc: data.imageSrc,
showLastValueTooltip: parseShowLastValueTooltip(data.showLastValueTooltip),
statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
};
@ -61,7 +67,7 @@ export default class StaticGraph extends Item<StaticGraphProps> {
public createDomElement(): HTMLElement {
const img: HTMLImageElement = document.createElement("img");
img.className = "static-graph";
img.src = this.props.imageSrc;
img.src = this.props.statusImageSrc || this.props.imageSrc;
// TODO: Show last value in a tooltip.

View File

@ -1,4 +1,11 @@
import { parseIntOr, notEmptyStringOr, padLeft, prefixedCssRules } from "./lib";
import {
parseIntOr,
stringIsEmpty,
notEmptyStringOr,
padLeft,
prefixedCssRules,
decodeBase64
} from "./lib";
describe("function parseIntOr", () => {
it("should retrieve valid int or a default value", () => {
@ -12,6 +19,15 @@ describe("function parseIntOr", () => {
});
});
describe("function stringIsEmpty", () => {
it("should check properly if a string is empry or not", () => {
expect(stringIsEmpty()).toBe(true);
expect(stringIsEmpty("")).toBe(true);
expect(stringIsEmpty("foo")).toBe(false);
expect(stringIsEmpty("bar")).toBe(false);
});
});
describe("function notEmptyStringOr", () => {
it("should retrieve not empty string or a default value", () => {
expect(notEmptyStringOr("", null)).toBe(null);
@ -50,3 +66,16 @@ describe("function prefixedCssRules", () => {
expect(rules).toHaveLength(5);
});
});
describe("function decodeBase64", () => {
it("should decode the base64 without errors", () => {
expect(decodeBase64("SGkgSSdtIGRlY29kZWQ=")).toEqual("Hi I'm decoded");
expect(decodeBase64("Rk9PQkFSQkFa")).toEqual("FOOBARBAZ");
expect(decodeBase64("eyJpZCI6MSwibmFtZSI6ImZvbyJ9")).toEqual(
'{"id":1,"name":"foo"}'
);
expect(
decodeBase64("PGRpdj5Cb3ggPHA+UGFyYWdyYXBoPC9wPjxociAvPjwvZGl2Pg==")
).toEqual("<div>Box <p>Paragraph</p><hr /></div>");
});
});

View File

@ -22,6 +22,15 @@ export function parseIntOr<T>(value: any, defaultValue: T): number | T {
else return defaultValue;
}
/**
* Check if a string exists and it's not empty.
* @param value Value to check.
* @return The check result.
*/
export function stringIsEmpty(value?: string | null): boolean {
return value == null || value.length === 0;
}
/**
* Return a not empty string or a default value from a raw value.
* @param value Raw value from which we will try to extract a non empty string.
@ -241,3 +250,12 @@ export function prefixedCssRules(
`${rule}`
];
}
/**
* Decode a base64 string.
* @param input Data encoded using base64.
* @return Decoded data.
*/
export function decodeBase64(input: string): string {
return decodeURIComponent(escape(window.atob(input)));
}

View File

@ -1,8 +1,11 @@
.visual-console-item {
position: absolute;
.visual-console-container {
position: relative;
}
.visual-console-item > * {
width: inherit;
height: inherit;
.visual-console-item {
position: absolute;
display: flex;
flex-direction: initial;
justify-items: center;
align-items: center;
}