Merge branch 'visual-console-refactor' of https://brutus.artica.lan:8081/artica/pandorafms into visual-console-refactor

Former-commit-id: fb37c8e84e264cd27158a481774c3712650df647
This commit is contained in:
Daniel Maya 2019-04-01 16:11:49 +02:00
commit 92408f2ac1
35 changed files with 5231 additions and 706 deletions

View File

@ -4,37 +4,141 @@ declare(strict_types=1);
namespace Models;
/**
* This class should be extended to add functionalities to
* fetch, validate, transform and represent data entities.
*/
abstract class Model
{
/**
* Internal data of the model.
*
* @var array
*/
private $data;
protected abstract function validateData(array $data): void;
/**
* 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.
*
* @abstract
*/
abstract protected function validateData(array $data): void;
protected abstract function decode(array $data): array;
/**
* Returns a valid representation of the model.
*
* @param array $data Input data.
*
* @return array Data structure representing the model.
*
* @abstract
*/
abstract protected function decode(array $data): array;
/**
* Constructor of the model. It won't be public. The instances
* will be created through factories which start with from*.
*
* @param array $unknownData Input data structure.
*/
protected function __construct(array $unknownData)
{
$this->validateData($unknownData);
$this->data = $this->decode($unknownData);
// Sort alphabetically.
ksort($this->data);
}
/**
* Instance the class with the unknown input data.
*
* @param array $data Unknown data structure.
*
* @return self Instance of the model.
*/
public static function fromArray(array $data)
{
// The reserved word static refers to the invoked class at runtime.
return new static($data);
}
/**
* Obtain a data structure from the database using a filter.
*
* @param array $filter Filter to retrieve the modeled element.
*
* @return array The modeled element data structure stored into the DB.
* @throws \Exception When the data cannot be retrieved from the DB.
*
* @abstract
*/
abstract protected static function fetchDataFromDB(array $filter);
/**
* Obtain a model's instance from the database using a filter.
*
* @param array $filter Filter to retrieve the modeled element.
*
* @return self A modeled element's instance.
*/
public static function fromDB(array $filter): self
{
// The reserved word static refers to the invoked class at runtime.
return static::fromArray(static::fetchDataFromDB($filter));
}
/**
* JSON representation of the model.
*
* @return string
*/
public function toJson(): string
{
return \json_encode($this->data);
}
/**
* Text representation of the model.
*
* @return string
*/
public function __toString(): string
{
return $this->toJson();
}
/*
* -------------
* - UTILITIES -
* -------------
*/
/**
* From a unknown value, it will try to extract a valid boolean value.
*
* @param mixed $value Unknown input.
*
* @return boolean Valid boolean value.
*/
protected static function parseBool($value): bool
{
if (\is_bool($value) === true) {
@ -49,17 +153,48 @@ abstract class Model
}
/**
* Return a not empty string or a default value from a unknown value.
*
* @param mixed $val Input value.
* @param mixed $def Default value.
*
* @return mixed A valid string (not empty) extracted from the input
* or the default value.
*/
protected static function notEmptyStringOr($val, $def)
{
return (\is_string($val) === true && strlen($val) > 0) ? $val : $def;
}
protected static function issetInArray(array $val, array $keys)
/**
* Return a valid integer or a default value from a unknown value.
*
* @param mixed $val Input value.
* @param mixed $def Default value.
*
* @return mixed A valid int extracted from the input or the default value.
*/
protected static function parseIntOr($val, $def)
{
return (is_numeric($val) === true) ? (int) $val : $def;
}
/**
* Get a value from a dictionary from a possible pool of keys.
*
* @param array $dict Input array.
* @param array $keys Possible keys.
*
* @return mixed The first value found with the pool of keys or null.
*/
protected static function issetInArray(array $dict, array $keys)
{
foreach ($keys as $key => $value) {
if (isset($val[$value])) {
return $val[$value];
if (isset($dict[$value]) === true) {
return $dict[$value];
}
}

View File

@ -5,16 +5,26 @@ declare(strict_types=1);
namespace Models\VisualConsole;
use Models\Model;
/**
* Model of a Visual Console.
*/
final class Container extends Model
{
public static function fromArray(array $data): self
{
return new self($data);
}
/**
* 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 Model::validateData.
*/
protected function validateData(array $data): void
{
if (isset($data['id']) === false
@ -56,6 +66,15 @@ final class Container extends Model
}
/**
* Returns a valid representation of the model.
*
* @param array $data Input data.
*
* @return array Data structure representing the model.
*
* @overrides Model::decode.
*/
protected function decode(array $data): array
{
return [
@ -71,53 +90,106 @@ final class Container extends Model
}
/**
* Extract a group Id value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid identifier of a group.
*
* @throws \InvalidArgumentException When a valid group Id can't be found.
*/
private function extractGroupId(array $data): int
{
if (isset($data['id_group']) === true
&& \is_numeric($data['id_group']) === true
&& $data['id_group'] >= 0
) {
return $data['id_group'];
} else if (isset($data['groupId']) === true
&& \is_numeric($data['groupId']) === true
&& $data['groupId'] >= 0
) {
return $data['groupId'];
$groupId = static::parseIntOr(
static::issetInArray($data, ['id_group', 'groupId']),
null
);
if ($groupId === null || $groupId < 0) {
throw new \InvalidArgumentException(
'the group Id property is required and should be integer'
);
}
throw new \InvalidArgumentException(
'the group Id property is required and should be integer'
);
return $groupId;
}
/**
* Extract a image url value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the image url (not empty) or null.
*/
private function extractBackgroundUrl(array $data)
{
$background = Model::notEmptyStringOr(
Model::issetInArray($data, ['background', 'backgroundURL']),
return static::notEmptyStringOr(
static::issetInArray($data, ['background', 'backgroundURL']),
null
);
return $background;
}
/**
* Extract a background color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the color (not empty) or null.
*/
private function extractBackgroundColor(array $data)
{
$backgroundColor = Model::notEmptyStringOr(
Model::issetInArray($data, ['backgroundColor', 'background_color']),
return static::notEmptyStringOr(
static::issetInArray(
$data,
[
'backgroundColor',
'background_color',
]
),
null
);
return $backgroundColor;
}
/**
* Extract the "is favorite" switch value.
*
* @param array $data Unknown input data structure.
*
* @return boolean If the item is favorite or not.
*/
private function extractFavorite(array $data): bool
{
$favorite = Model::parseBool(
Model::issetInArray($data, ['is_favourite', 'isFavorite']),
null
return static::parseBool(
static::issetInArray($data, ['is_favourite', 'isFavorite'])
);
return $favorite;
}
/**
* Obtain a container data structure from the database using a filter.
*
* @param array $filter Filter of the Visual Console.
*
* @return self A Visual Console Container instance.
* @throws \Exception When the data cannot be retrieved from the DB.
*
* @override Model::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter)
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$row = \db_get_row_filter('tlayout', $filter);
if ($row === false) {
throw new \Exception('error fetching the data from the DB');
}
return $row;
}

View File

@ -0,0 +1,728 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole;
use Models\Model;
/**
* Model of a generic Visual Console Item.
*/
class Item extends Model
{
/**
* Used to decide wether to use information about the linked agent or not.
*
* @var boolean
*/
protected static $useLinkedAgent = false;
/**
* Used to decide wether to use information about the linked module or not.
*
* @var boolean
*/
protected static $useLinkedModule = false;
/**
* Used to decide wether to use information about
* the linked visual console or not.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = false;
/**
* 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 Model::validateData.
*/
protected function validateData(array $data): void
{
if (isset($data['id']) === false
|| \is_numeric($data['id']) === false
) {
throw new \InvalidArgumentException(
'the Id property is required and should be integer'
);
}
if (isset($data['type']) === false
|| \is_numeric($data['type']) === false
) {
throw new \InvalidArgumentException(
'the Type property is required and should be integer'
);
}
if (isset($data['width']) === false
|| \is_numeric($data['width']) === false
|| $data['width'] < 0
) {
throw new \InvalidArgumentException(
'the width property is required and should be greater than 0'
);
}
if (isset($data['height']) === false
|| \is_numeric($data['height']) === false
|| $data['height'] < 0
) {
throw new \InvalidArgumentException(
'the height property is required and should be greater than 0'
);
}
// The item has a linked Visual Console.
if (static::$useLinkedVisualConsole === true) {
$linkedLayoutStatusType = static::notEmptyStringOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusType',
'linked_layout_status_type',
]
),
null
);
// The types weight and service require extra data
// which should be validated.
if ($linkedLayoutStatusType === 'weight') {
$weight = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusTypeWeight',
'id_layout_linked_weight',
]
),
null
);
if ($weight === null || $weight < 0) {
throw new \InvalidArgumentException(
'the linked layout status weight property is required and should be greater than 0'
);
}
} else if ($linkedLayoutStatusType === 'service') {
$wThreshold = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusTypeWarningThreshold',
'linked_layout_status_as_service_warning',
]
),
null
);
if ($wThreshold === null || $wThreshold < 0) {
throw new \InvalidArgumentException(
'the linked layout status warning threshold property is required and should be greater than 0'
);
}
$cThreshold = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusTypeCriticalThreshold',
'linked_layout_status_as_service_critical',
]
),
null
);
if ($cThreshold === null || $cThreshold < 0) {
throw new \InvalidArgumentException(
'the linked layout status critical threshold property is required and should be greater than 0'
);
}
}
}
}
/**
* Returns a valid representation of the model.
*
* @param array $data Input data.
*
* @return array Data structure representing the model.
*
* @overrides Model::decode.
*/
protected function decode(array $data): array
{
$decodedData = [
'id' => (int) $data['id'],
'type' => (int) $data['type'],
'label' => $this->extractLabel($data),
'labelPosition' => $this->extractLabelPosition($data),
'isLinkEnabled' => $this->extractIsLinkEnabled($data),
'isOnTop' => $this->extractIsOnTop($data),
'parentId' => $this->extractParentId($data),
'aclGroupId' => $this->extractAclGroupId($data),
'width' => (int) $data['width'],
'height' => (int) $data['height'],
'x' => $this->extractX($data),
'y' => $this->extractY($data),
];
if (static::$useLinkedModule === true) {
$decodedData = array_merge(
$decodedData,
static::extractLinkedModule($data)
);
} else if (static::$useLinkedAgent === true) {
$decodedData = array_merge(
$decodedData,
static::extractLinkedAgent($data)
);
}
if (static::$useLinkedVisualConsole === true) {
$decodedData = array_merge(
$decodedData,
static::extractLinkedVisualConsole($data)
);
}
return $decodedData;
}
/**
* Extract x y axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis position of the item.
*/
private function extractX(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['x', 'pos_x']),
0
);
}
/**
* Extract a y axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis position of the item.
*/
private function extractY(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['y', 'pos_y']),
0
);
}
/**
* Extract a group Id (for ACL) value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid identifier of a group.
*/
private function extractAclGroupId(array $data)
{
return static::parseIntOr(
static::issetInArray($data, ['id_group', 'aclGroupId']),
null
);
}
/**
* Extract a parent Id value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid identifier of the item's parent.
*/
private function extractParentId(array $data)
{
return static::parseIntOr(
static::issetInArray($data, ['parentId', 'parent_item']),
null
);
}
/**
* Extract the "is on top" switch value.
*
* @param array $data Unknown input data structure.
*
* @return boolean If the item is on top or not.
*/
private function extractIsOnTop(array $data): bool
{
return static::parseBool(
static::issetInArray($data, ['isOnTop', 'show_on_top'])
);
}
/**
* Extract the "is link enabled" switch value.
*
* @param array $data Unknown input data structure.
*
* @return boolean If the item has the link enabled or not.
*/
private function extractIsLinkEnabled(array $data): bool
{
return static::parseBool(
static::issetInArray($data, ['isLinkEnabled', 'enable_link'])
);
}
/**
* Extract a label value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the label (not empty) or null.
*/
private function extractLabel(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['label']),
null
);
}
/**
* Extract a label position value.
*
* @param array $data Unknown input data structure.
*
* @return mixed One string of up|right|left|down. down by default.
*/
private function extractLabelPosition(array $data): string
{
$labelPosition = static::notEmptyStringOr(
static::issetInArray($data, ['labelPosition', 'label_position']),
null
);
switch ($labelPosition) {
case 'up':
case 'right':
case 'left':
return $labelPosition;
default:
return 'down';
}
}
/**
* Extract the values of a linked agent.
*
* @param array $data Unknown input data structure.
*
* @return array Data structure of the linked agent info.
*
* @example [
* 'metaconsoleId' => 1,
* 'agentId' => 2,
* 'agentName' => 'Foo',
* ]
* @example [
* 'agentId' => 20,
* 'agentName' => 'Bar',
* ]
* @example [
* 'agentId' => null,
* 'agentName' => null,
* ]
*/
private function extractLinkedAgent(array $data): array
{
$agentData = [];
// We should add the metaconsole Id if we can. If not,
// it doesn't have to be into the structure.
$metaconsoleId = static::issetInArray(
$data,
[
'metaconsoleId',
'id_metaconsole',
]
);
if ($metaconsoleId !== null) {
$metaconsoleId = static::parseIntOr($metaconsoleId, null);
if ($metaconsoleId !== null) {
$agentData['metaconsoleId'] = $metaconsoleId;
}
}
// The agent Id should be a valid int or a null value.
$agentData['agentId'] = static::parseIntOr(
static::issetInArray($data, ['agentId', 'id_agent']),
null
);
// The agent name should be a valid string or a null value.
$agentData['agentName'] = static::notEmptyStringOr(
static::issetInArray($data, ['agentName', 'agent_name']),
null
);
return $agentData;
}
/**
* Extract the values of a linked module.
*
* @param array $data Unknown input data structure.
*
* @return array Data structure of the linked module info.
*
* @example [
* 'metaconsoleId' => 1,
* 'agentId' => 2,
* 'agentName' => 'Foo',
* 'moduleId' => 1,
* 'moduleName' => 'cpu',
* ]
* @example [
* 'agentId' => 4,
* 'agentName' => 'Bar',
* 'moduleId' => null,
* 'moduleName' => null,
* ]
* @example [
* 'agentId' => null,
* 'agentName' => null,
* 'moduleId' => null,
* 'moduleName' => null,
* ]
*/
private function extractLinkedModule(array $data): array
{
// Initialize the data with the agent data and then expand it.
$moduleData = static::extractLinkedAgent($data);
// The module Id should be a valid int or a null value.
$moduleData['moduleId'] = static::parseIntOr(
static::issetInArray($data, ['moduleId', 'id_agente_modulo']),
null
);
// The module name should be a valid string or a null value.
$moduleData['moduleName'] = static::notEmptyStringOr(
static::issetInArray($data, ['moduleName', 'module_name']),
null
);
return $moduleData;
}
/**
* Extract the values of a linked visual console.
*
* @param array $data Unknown input data structure.
*
* @return array Data structure of the linked visual console info.
*
* @example [
* 'metaconsoleId' => 2,
* 'linkedLayoutId' => 12,
* 'linkedLayoutAgentId' => 48,
* 'linkedLayoutStatusType' => 'default',
* ]
* @example [
* 'linkedLayoutId' => 11,
* 'linkedLayoutAgentId' => null,
* 'linkedLayoutStatusType' => 'weight',
* 'linkedLayoutStatusTypeWeight' => 80,
* ]
* @example [
* 'metaconsoleId' => 2,
* 'linkedLayoutId' => 10,
* 'linkedLayoutAgentId' => 48,
* 'linkedLayoutStatusType' => 'service',
* 'linkedLayoutStatusTypeWarningThreshold' => 50,
* 'linkedLayoutStatusTypeCriticalThreshold' => 80,
* ]
*/
private function extractLinkedVisualConsole(array $data): array
{
$vcData = [];
// We should add the metaconsole Id if we can. If not,
// it doesn't have to be into the structure.
$metaconsoleId = static::issetInArray(
$data,
[
'metaconsoleId',
'id_metaconsole',
]
);
if ($metaconsoleId !== null) {
$metaconsoleId = static::parseIntOr($metaconsoleId, null);
if ($metaconsoleId !== null) {
$vcData['metaconsoleId'] = $metaconsoleId;
}
}
// The linked vc Id should be a valid int or a null value.
$vcData['linkedLayoutId'] = static::parseIntOr(
static::issetInArray($data, ['linkedLayoutId', 'id_layout_linked']),
null
);
// The linked vc agent Id should be a valid int or a null value.
$vcData['linkedLayoutAgentId'] = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutAgentId',
'linked_layout_node_id',
]
),
null
);
// The linked vc status type should be a enum value.
$linkedLayoutStatusType = static::notEmptyStringOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusType',
'linked_layout_status_type',
]
),
null
);
// Extract data for the calculation of the linked visual console status.
switch ($linkedLayoutStatusType) {
case 'default':
default:
$vcData['linkedLayoutStatusType'] = 'default';
break;
case 'weight':
$vcData['linkedLayoutStatusType'] = 'weight';
$vcData['linkedLayoutStatusTypeWeight'] = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusTypeWeight',
'id_layout_linked_weight',
]
),
0
);
break;
case 'service':
$vcData['linkedLayoutStatusType'] = 'service';
$vcData['linkedLayoutStatusTypeWarningThreshold'] = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusTypeWarningThreshold',
'linked_layout_status_as_service_warning',
]
),
0
);
$vcData['linkedLayoutStatusTypeCriticalThreshold'] = static::parseIntOr(
static::issetInArray(
$data,
[
'linkedLayoutStatusTypeCriticalThreshold',
'linked_layout_status_as_service_critical',
]
),
0
);
break;
}
return $vcData;
}
/**
* 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 \Exception When the data cannot be retrieved from the DB.
*
* @override Model::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter): array
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$row = \db_get_row_filter('tlayout_data', $filter);
if ($row === false) {
throw new \Exception('error fetching the data from the DB');
}
/*
* Retrieve extra data.
*/
// The linked module includes the agent data.
if (static::$useLinkedModule === true) {
$row = \array_merge($row, static::fetchModuleDataFromDB($row));
} else if (static::$useLinkedAgent === true) {
$row = \array_merge($row, static::fetchAgentDataFromDB($row));
}
return $row;
}
/**
* Fetch a data structure of an agent from the database using the
* vs item's data.
*
* @param array $itemData Visual Console Item's data structure.
*
* @return array The agent data structure stored into the DB.
*
* @throws \InvalidArgumentException When the input agent Id is invalid.
* @throws \Exception When the data cannot be retrieved from the DB.
*/
protected static function fetchAgentDataFromDB(array $itemData): array
{
$agentData = [];
// We should add the metaconsole Id if we can.
$metaconsoleId = static::issetInArray(
$itemData,
[
'metaconsoleId',
'id_metaconsole',
]
);
if ($metaconsoleId !== null) {
$metaconsoleId = static::parseIntOr($metaconsoleId, null);
}
// Can't fetch an agent with a missing Id.
$agentId = static::issetInArray($itemData, ['agentId', 'id_agent']);
if ($agentId === null) {
throw new \InvalidArgumentException('missing agent Id');
}
// Can't fetch an agent with a invalid Id.
$agentId = static::parseIntOr($agentId, null);
if ($agentId === null) {
throw new \InvalidArgumentException('invalid agent Id');
}
// TODO: Should we make a connection to the metaconsole node?
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$agentName = \db_get_value('nombre', 'tagente', 'id_agente', $agentId);
if ($agentName === false) {
throw new \Exception('error fetching the data from the DB');
}
// The agent name should be a valid string or a null value.
$agentData['agentName'] = $agentName;
return $agentData;
}
/**
* Fetch a data structure of an module from the database using the
* vs item's data.
*
* @param array $itemData Visual Console Item's data structure.
*
* @return array The module data structure stored into the DB.
* @throws \InvalidArgumentException When the input module Id is invalid.
* @throws \Exception When the data cannot be retrieved from the DB.
*/
protected static function fetchModuleDataFromDB(
array $itemData
): array {
// Initialize with the agent data.
$moduleData = static::fetchAgentDataFromDB($itemData);
// Can't fetch an module with a missing Id.
$moduleId = static::issetInArray(
$itemData,
[
'moduleId',
'id_agente_modulo',
]
);
if ($moduleId === null) {
throw new \InvalidArgumentException('missing module Id');
}
// Can't fetch an module with a invalid Id.
$moduleId = static::parseIntOr($moduleId, null);
if ($moduleId === null) {
throw new \InvalidArgumentException('invalid module Id');
}
// TODO: Should we make a connection to the metaconsole node?
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$moduleName = \db_get_value(
'nombre',
'tagente_modulo',
'id_agente_modulo',
$moduleId
);
if ($moduleName === false) {
throw new \Exception('error fetching the data from the DB');
}
$moduleData['moduleName'] = $moduleName;
return $moduleData;
}
/**
* Obtain a vc item instance from the database using an identifier.
*
* @param integer $id Identifier of the Visual Console Item.
*
* @return array The Visual Console Item data structure stored into the DB.
* @throws \Exception When the data cannot be retrieved from the DB.
*/
public static function fromDBWithId(int $id): array
{
return static::fromDB(['id' => $id]);
}
}

View File

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a Box item of the Visual Console.
*/
final class Box extends Item
{
/**
* 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
{
$boxData = parent::decode($data);
$boxData['type'] = BOX_ITEM;
$boxData['parentId'] = null;
$boxData['aclGroupId'] = null;
$boxData['borderWidth'] = $this->extractBorderWidth($data);
$boxData['borderColor'] = $this->extractBorderColor($data);
$boxData['fillColor'] = $this->extractFillColor($data);
return $boxData;
}
/**
* Extract a border width value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid border width. 0 by default.
*/
private function extractBorderWidth(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['borderWidth', 'border_width']),
0
);
}
/**
* Extract a border color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the border color (not empty) or null.
*/
private function extractBorderColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['borderColor', 'border_color']),
null
);
}
/**
* Extract a fill color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the fill color (not empty) or null.
*/
private function extractFillColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['fillColor', 'fill_color']),
null
);
}
}

View File

@ -0,0 +1,158 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a Clock item of the Visual Console.
*/
final class Clock extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* 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
{
$clockData = parent::decode($data);
$clockData['type'] = CLOCK;
$clockData['clockType'] = $this->extractClockType($data);
$clockData['clockFormat'] = $this->extractClockFormat($data);
$clockData['clockTimezone'] = $this->extractClockTimezone($data);
try {
$timezone = new \DateTimeZone($clockData['clockTimezone']);
$timezoneUTC = new \DateTimeZone('UTC');
$clockData['clockTimezoneOffset'] = $timezone->getOffset(new \DateTime('now', $timezoneUTC));
} catch (Exception $e) {
throw new \InvalidArgumentException($e->getMessage());
}
$clockData['showClockTimezone'] = $this->extractShowClockTimezone($data);
$clockData['color'] = $this->extractColor($data);
return $clockData;
}
/**
* Extract a clock type value.
*
* @param array $data Unknown input data structure.
*
* @return string Digital or analogic. analogic by default.
*/
private function extractClockType(array $data): string
{
$clockType = static::notEmptyStringOr(
static::issetInArray($data, ['clockType', 'clock_animation']),
null
);
switch ($clockType) {
case 'digital':
case 'digital_1':
return 'digital';
default:
return 'analogic';
}
}
/**
* Extract a clock format value.
*
* @param array $data Unknown input data structure.
*
* @return string Time or datetime. datetime by default.
*/
private function extractClockFormat(array $data): string
{
$clockFormat = static::notEmptyStringOr(
static::issetInArray($data, ['clockFormat', 'time_format']),
null
);
switch ($clockFormat) {
case 'time':
return 'time';
default:
return 'datetime';
}
}
/**
* Extract a clock timezone value.
*
* @param array $data Unknown input data structure.
*
* @return string
*/
private function extractClockTimezone(array $data): string
{
$clockTimezone = static::notEmptyStringOr(
static::issetInArray($data, ['clockTimezone', 'timezone']),
null
);
if ($clockTimezone === null) {
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'])
);
}
/**
* Extract the color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed returns a color or null
*/
private function extractColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['color', 'fill_color']),
null
);
}
}

View File

@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a color cloud item of the Visual Console.
*/
final class ColorCloud extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
*
* @var boolean
*/
protected static $useLinkedModule = true;
/**
* 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
{
$colorCloudData = parent::decode($data);
$colorCloudData['type'] = COLOR_CLOUD;
$colorCloudData['color'] = $this->extractColor($data);
$colorCloudData['colorRanges'] = '';
return $colorCloudData;
}
/**
* Extract a color value.
*
* @param array $data Unknown input data structure.
*
* @return string
*/
private function extractColor(array $data): string
{
$color = static::notEmptyStringOr(
static::issetInArray($data, ['color']),
null
);
if (empty($color) === true) {
$color = static::notEmptyStringOr(
static::issetInArray($data, ['label']),
null
);
$color_decode = \json_decode($color);
if (empty($color) === true || empty($color_decode->default_color) === true) {
throw new \InvalidArgumentException(
'the color property is required and should be string'
);
} else {
return $color_decode->default_color;
}
} else {
return $color;
}
}
/**
* Extract a color ranges value.
*
* @param array $data Unknown input data structure.
*
* @return string
*/
private function extractColorRanges(array $data): array
{
if (isset($data['colorRanges']) && \is_array($data['colorRanges'])) {
foreach ($data['colorRanges'] as $key => $value) {
if ((!isset($data['colorRanges'][$key]['fromValue']) || !\is_float($data['colorRanges'][$key]['fromValue']))
|| (!isset($data['colorRanges'][$key]['toValue']) || !\is_float($data['colorRanges'][$key]['toValue']))
|| (!isset($data['colorRanges'][$key]['color']) | !\is_string($data['colorRanges'][$key]['color']) || strlen($data['colorRanges'][$key]['color']) == 0)
) {
throw new \InvalidArgumentException(
'the color property is required and should be string'
);
}
}
return $data['colorRanges'];
} else if (isset($data['label']) === true) {
$colorRanges_decode = \json_decode($data['label']);
return $colorRanges_decode->color_ranges;
} else {
return [];
}
}
}

View File

@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
use Models\Model;
/**
* Model of a group item of the Visual Console.
*/
final class EventsHistory extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
*
* @var boolean
*/
protected static $useLinkedModule = true;
/**
* 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'] = 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.
*
* @param array $data Unknown input data structure.
*
* @return mixed
*/
private function extractMaxTime(array $data)
{
$maxTime = Model::parseIntOr(
Model::issetInArray($data, ['maxTime', 'period']),
null
);
return $maxTime;
}
/**
* Extract the value of data and
* return an array.
*
* @param array $data Unknown input data structure.
*
* @return array
*/
private function extractData(array $data): array
{
$array = [];
if (isset($data['data']) && \is_array($data['data'])) {
$array = $data['data'];
}
return $array;
}
}

View File

@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a group item of the Visual Console.
*/
final class Group extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* 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'] = GROUP_ITEM;
$return['imageSrc'] = $this->extractImageSrc($data);
$return['groupId'] = $this->extractGroupId($data);
return $return;
}
/**
* Extract a image src value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the image url (not empty) or null.
*
* @throws \InvalidArgumentException When a valid image src can't be found.
*/
private function extractImageSrc(array $data): string
{
$imageSrc = static::notEmptyStringOr(
static::issetInArray($data, ['imageSrc', 'image']),
null
);
if ($imageSrc === null || \strlen($imageSrc) === 0) {
throw new \InvalidArgumentException(
'the image src property is required and should be a non empty string'
);
}
return $imageSrc;
}
/**
* Extract a group Id value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid identifier of a group.
*
* @throws \InvalidArgumentException When a valid group Id can't be found.
*/
private function extractGroupId(array $data): int
{
$groupId = static::parseIntOr(
static::issetInArray($data, ['groupId', 'id_group']),
null
);
if ($groupId === null || $groupId < 0) {
throw new \InvalidArgumentException(
'the group Id property is required and should be integer'
);
}
return $groupId;
}
}

View File

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
/**
* Model of a group item of the Visual Console.
*/
final class Icon extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* 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'] = ICON;
$return['imageSrc'] = $this->extractImageSrc($data);
return $return;
}
/**
* Extract a image src value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the image url (not empty) or null.
*
* @throws \InvalidArgumentException When a valid image src can't be found.
*/
private function extractImageSrc(array $data)
{
$imageSrc = static::notEmptyStringOr(
static::issetInArray($data, ['imageSrc', 'image']),
null
);
if ($imageSrc === null || \strlen($imageSrc) === 0) {
throw new \InvalidArgumentException(
'the image src property is required and should be a non empty string'
);
}
return $imageSrc;
}
}

View File

@ -0,0 +1,223 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\Model;
final class Line extends Model
{
/**
* 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 Model::validateData.
*/
protected function validateData(array $data): void
{
if (isset($data['id']) === false
|| \is_numeric($data['id']) === false
) {
throw new \InvalidArgumentException(
'the Id property is required and should be integer'
);
}
if (isset($data['type']) === false
|| \is_numeric($data['type']) === false
) {
throw new \InvalidArgumentException(
'the Id property is required and should be integer'
);
}
}
/**
* Returns a valid representation of the model.
*
* @param array $data Input data.
*
* @return array Data structure representing the model.
*
* @overrides Model::decode.
*/
protected function decode(array $data): array
{
return [
'id' => (int) $data['id'],
'type' => LINE_ITEM,
'startX' => $this->extractStartX($data),
'startY' => $this->extractStartY($data),
'endX' => $this->extractEndX($data),
'endY' => $this->extractEndY($data),
'isOnTop' => $this->extractIsOnTope($data),
'borderWidth' => $this->extractBorderWidth($data),
'borderColor' => $this->extractBorderColor($data),
];
}
/**
* Extract the value of startX and
* return a integer.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis start position of the item.
*/
private function extractStartX(array $data): int
{
$startX = Model::parseIntOr(
Model::issetInArray($data, ['startX', 'pos_x']),
0
);
return $startX;
}
/**
* Extract the value of startY and
* return a integer.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis start position of the item.
*/
private function extractStartY(array $data): int
{
$startY = Model::parseIntOr(
Model::issetInArray($data, ['startY', 'pos_y']),
0
);
return $startY;
}
/**
* Extract the value of endX and
* return a integer.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis end position of the item.
*/
private function extractEndX(array $data): int
{
$endX = Model::parseIntOr(
Model::issetInArray($data, ['endX', 'width']),
0
);
return $endX;
}
/**
* Extract the value of endY and
* return a integer.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis end position of the item.
*/
private function extractEndY(array $data): int
{
$endY = Model::parseIntOr(
Model::issetInArray($data, ['endY', 'height']),
0
);
return $endY;
}
/**
* Extract the value of isOnTop and
* return a bool.
*
* @param array $data Unknown input data structure.
*
* @return boolean If the item is on top or not.
*/
private function extractIsOnTope(array $data): bool
{
$isOnTop = Model::parseBool(
Model::issetInArray($data, ['isOnTop', 'show_on_top'])
);
return $isOnTop;
}
/**
* Extract the value of borderWidth and
* return a integer.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid border width. 0 by default.
*/
private function extractBorderWidth(array $data): int
{
$borderWidth = Model::parseIntOr(
Model::issetInArray($data, ['borderWidth', 'border_width']),
0
);
if ($borderWidth >= 0) {
return $borderWidth;
} else {
return 0;
}
}
/**
* Extract the value of borderColor and
* return to not empty string or null.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the border color (not empty) or null.
*/
private function extractBorderColor(array $data)
{
$borderColor = Model::notEmptyStringOr(
Model::issetInArray($data, ['borderColor', 'border_color']),
null
);
return $borderColor;
}
/**
* Obtain 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 line data structure stored into the DB.
* @throws \Exception When the data cannot be retrieved from the DB.
*
* @override Model::fetchDataFromDB.
*/
protected static function fetchDataFromDB(array $filter): array
{
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$row = \db_get_row_filter('tlayout_data', $filter);
if ($row === false) {
throw new \Exception('error fetching the data from the DB');
}
return $row;
}
}

View File

@ -0,0 +1,166 @@
<?php
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.
*/
final class SimpleValue extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
*
* @var boolean
*/
protected static $useLinkedModule = 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 (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'
);
}
}
/**
* 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'] = SIMPLE_VALUE;
$return['processValue'] = $this->extractProcessValue($data);
if ($return['processValue'] !== 'none') {
$return['period'] = $this->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'.
*
* @param array $data Unknown input data structure.
*
* @return string
*/
private function extractProcessValue(array $data): string
{
$processValue = Model::notEmptyStringOr(
Model::issetInArray($data, ['processValue']),
null
);
switch ($processValue) {
case 'avg':
return 'avg';
case 'max':
return 'max';
case 'min':
return 'min';
default:
return 'none';
}
}
/**
* Extract the value of period and
* return a integer.
*
* @param array $data Unknown input data structure.
*
* @return integer
*/
private function extractPeriod(array $data): int
{
$period = Model::parseIntOr(
Model::issetInArray($data, ['period']),
0
);
if ($period >= 0) {
return $period;
} else {
return 0;
}
}
/**
* Extract the value of valueType and
* return 'image' or 'string'.
*
* @param array $data Unknown input data structure.
*
* @return string
*/
private function extractValueType(array $data): string
{
$valueType = Model::notEmptyStringOr(
Model::issetInArray($data, ['valueType']),
null
);
switch ($valueType) {
case 'image':
return 'image';
default:
return 'string';
}
}
}

View File

@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\VisualConsole\Item;
use Models\Model;
/**
* Model of a group item of the Visual Console.
*/
final class StaticGraph extends Item
{
/**
* Used to enable the fetching, validation and extraction of information
* about the linked visual console.
*
* @var boolean
*/
protected static $useLinkedVisualConsole = true;
/**
* Used to enable the fetching, validation and extraction of information
* about the linked module.
*
* @var boolean
*/
protected static $useLinkedModule = true;
/**
* 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'] = STATIC_GRAPH;
$return['imageSrc'] = $this->extractImageSrc($data);
$return['showLastValueTooltip'] = $this->extractShowLastValueTooltip($data);
return $return;
}
/**
* Extract a image src value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the image url (not empty) or null.
*
* @throws \InvalidArgumentException When a valid image src can't be found.
*/
private function extractImageSrc(array $data): string
{
$imageSrc = static::notEmptyStringOr(
static::issetInArray($data, ['imageSrc', 'image']),
null
);
if ($imageSrc === null || \strlen($imageSrc) === 0) {
throw new \InvalidArgumentException(
'the image src property is required and should be a non empty string'
);
}
return $imageSrc;
}
/**
* Extract the value of showLastValueTooltip and
* return 'default', 'enabled' or 'disabled'.
*
* @param array $data Unknown input data structure.
*
* @return string
*/
private function extractShowLastValueTooltip(array $data): string
{
$showLastValueTooltip = Model::notEmptyStringOr(
Model::issetInArray($data, ['showLastValueTooltip']),
null
);
if ($showLastValueTooltip === null) {
$showLastValueTooltip = Model::parseIntOr(
Model::issetInArray($data, ['show_last_value']),
null
);
switch ($showLastValueTooltip) {
case 1:
return 'enabled';
case 2:
return 'disabled';
default:
return 'default';
}
} else {
switch ($showLastValueTooltip) {
case 'enabled':
return 'enabled';
case 'disabled':
return 'disabled';
default:
return 'default';
}
}
}
}

View File

@ -6,12 +6,17 @@ use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Container as VisualConsole;
/**
* Test class
* Test for the Visual Console Container.
*/
class ContainerTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
@ -60,6 +65,11 @@ class ContainerTest extends TestCase
}
/**
* Test if the instance is not created when using a invalid id.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidId(): void
{
$this->expectException(InvalidArgumentException::class);
@ -86,6 +96,11 @@ class ContainerTest extends TestCase
}
/**
* Test if the instance is not created when using a invalid name.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidName(): void
{
$this->expectException(InvalidArgumentException::class);
@ -111,10 +126,15 @@ class ContainerTest extends TestCase
}
/**
* Test if the instance is not created when using a invalid group id.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidGroupId(): void
{
$this->expectException(InvalidArgumentException::class);
// invalid group id.
// Invalid group id.
VisualConsole::fromArray(
[
'id' => 1,
@ -137,10 +157,15 @@ class ContainerTest extends TestCase
}
/**
* Test if the instance is not created when using a invalid width.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidWidth(): void
{
$this->expectException(InvalidArgumentException::class);
// invalid width.
// Invalid width.
VisualConsole::fromArray(
[
'id' => 1,
@ -163,10 +188,15 @@ class ContainerTest extends TestCase
}
/**
* Test if the instance is not created when using a invalid height.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidHeigth(): void
{
$this->expectException(InvalidArgumentException::class);
// invalid height.
// Invalid height.
VisualConsole::fromArray(
[
'id' => 1,
@ -189,11 +219,16 @@ class ContainerTest extends TestCase
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"id":1,"name":"foo","groupId":0,"backgroundURL":null,"backgroundColor":null,"isFavorite":false,"width":1024,"height":768}',
VisualConsole::fromArray(
'{"backgroundColor":null,"backgroundURL":null,"groupId":0,"height":768,"id":1,"isFavorite":false,"name":"foo","width":1024}',
(string) VisualConsole::fromArray(
[
'id' => 1,
'name' => 'foo',

View File

@ -0,0 +1,298 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Item as ItemConsole;
/**
* Test for the Visual Console Item model.
*/
class ItemTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
ItemConsole::class,
ItemConsole::fromArray(
[
'id' => 1,
'type' => 5,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
)
);
$this->assertInstanceOf(
ItemConsole::class,
ItemConsole::fromArray(
[
'id' => 1,
'type' => 5,
'width' => 0,
'height' => 0,
]
)
);
}
/**
* Test if the instance is not created when using a invalid id.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidId(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid id.
ItemConsole::fromArray(
[
'id' => 'foo',
'type' => 5,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
);
// Missing id.
ItemConsole::fromArray(
[
'type' => 5,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
);
}
/**
* Test if the instance is not created when using a invalid type.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidType(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid id.
ItemConsole::fromArray(
[
'id' => 15,
'type' => 'clock',
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
);
// Missing id.
ItemConsole::fromArray(
[
'id' => 6,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
);
}
/**
* Test if the instance is not created when using a invalid width.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidWidth(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid id.
ItemConsole::fromArray(
[
'id' => 15,
'type' => 3,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => -1,
'height' => 600,
'x' => 0,
'y' => 0,
]
);
// Missing id.
ItemConsole::fromArray(
[
'id' => 15,
'type' => 3,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'height' => 600,
'x' => 0,
'y' => 0,
]
);
}
/**
* Test if the instance is not created when using a invalid height.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidHeight(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid id.
ItemConsole::fromArray(
[
'id' => 15,
'type' => 3,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => -1,
'x' => 0,
'y' => 0,
]
);
// Missing id.
ItemConsole::fromArray(
[
'id' => 15,
'type' => 3,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 600,
'x' => 0,
'y' => 0,
]
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testItemIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":12,"height":600,"id":15,"isLinkEnabled":false,"isOnTop":true,"label":"test","labelPosition":"down","parentId":0,"type":3,"width":800,"x":0,"y":0}',
(string) ItemConsole::fromArray(
[
'id' => 15,
'type' => 3,
'label' => 'test',
'labelPosition' => 'down',
'isLinkEnabled' => false,
'isOnTop' => true,
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
)
);
$this->assertEquals(
'{"aclGroupId":12,"height":600,"id":15,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","parentId":0,"type":3,"width":800,"x":0,"y":0}',
(string) ItemConsole::fromArray(
[
'id' => 15,
'type' => 3,
'label' => '',
'labelPosition' => 'test',
'parentId' => 0,
'aclGroupId' => 12,
'width' => 800,
'height' => 600,
'x' => 0,
'y' => 0,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","parentId":null,"type":20,"width":0,"x":-666,"y":76}',
(string) ItemConsole::fromArray(
[
'id' => 69,
'type' => 20,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
)
);
}
}

View File

@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Box;
/**
* Test for the Visual Console Box Item model.
*/
class BoxTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
Box::class,
Box::fromArray(
[
'id' => 69,
'type' => 12,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
)
);
$this->assertInstanceOf(
Box::class,
Box::fromArray(
[
'id' => 1000,
'type' => 8,
'name' => 'test',
'width' => 100,
'height' => 900,
]
)
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"borderColor":null,"borderWidth":0,"fillColor":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","parentId":null,"type":12,"width":0,"x":-666,"y":76}',
(string) Box::fromArray(
[
'id' => 7,
'type' => 10,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
)
);
}
}

View File

@ -0,0 +1,173 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Clock;
/**
* Test for the Visual Console Clock Item model.
*/
class ClockTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
Clock::class,
Clock::fromArray(
[
'id' => 69,
'type' => CLOCK,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'clockType' => 'digital',
'clockFormat' => 'time',
'clockTimezone' => 'Europe/Madrid',
'showClockTimezone' => false,
'color' => 'white',
]
)
);
$this->assertInstanceOf(
Clock::class,
Clock::fromArray(
[
'id' => 1000,
'type' => CLOCK,
'width' => 100,
'height' => 900,
'clockType' => 'analogic',
'clockFormat' => 'datetime',
'clockTimezone' => 'Asia/Tokyo',
'showClockTimezone' => true,
'color' => 'red',
]
)
);
}
/**
* Test if the instance is not created when using a invalid clockTimezone.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidImageSrc(): void
{
$this->expectException(Exception::class);
// Invalid clockTimezone.
Clock::fromArray(
[
'id' => 69,
'type' => CLOCK,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'clockType' => 'digital',
'clockFormat' => 'time',
'clockTimezone' => 'Europe/Tokyo',
'showClockTimezone' => false,
'color' => 'white',
]
);
// Invalid clockTimezone.
Clock::fromArray(
[
'id' => 69,
'type' => CLOCK,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'clockType' => 'digital',
'clockFormat' => 'time',
'clockTimezone' => 'Europe/Tokyo',
'showClockTimezone' => false,
'color' => 'white',
]
);
// Missing clockTimezone.
Clock::fromArray(
[
'id' => 69,
'type' => CLOCK,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'clockType' => 'digital',
'clockFormat' => 'time',
'showClockTimezone' => false,
'color' => 'white',
]
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
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}',
(string) Clock::fromArray(
[
'id' => 69,
'type' => CLOCK,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'clockType' => 'digital',
'clockFormat' => 'time',
'clockTimezone' => 'Europe/Madrid',
'showClockTimezone' => false,
'color' => 'white',
]
)
);
}
}

View File

@ -0,0 +1,188 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\EventsHistory;
/**
* Test for the Visual Console events history Item model.
*/
class EventsHistoryTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
EventsHistory::class,
EventsHistory::fromArray(
[
'id' => 3,
'type' => AUTO_SLA_GRAPH,
'width' => '600',
'height' => '500',
'maxTime' => null,
'data' => [],
]
)
);
$this->assertInstanceOf(
EventsHistory::class,
EventsHistory::fromArray(
[
'id' => 14,
'type' => AUTO_SLA_GRAPH,
'width' => '600',
'height' => '500',
'maxTime' => 12800,
'data' => [
'data' => '5',
'time' => 23456788,
],
]
)
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
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}',
(string) EventsHistory::fromArray(
[
'id' => 7,
'type' => AUTO_SLA_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => null,
'data' => [],
]
)
);
$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}',
(string) EventsHistory::fromArray(
[
'id' => 7,
'type' => AUTO_SLA_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'data' => [
'time' => 23456789,
'data' => 15,
],
]
)
);
$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}',
(string) EventsHistory::fromArray(
[
'id' => 7,
'type' => AUTO_SLA_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => null,
'data' => [],
'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}',
(string) EventsHistory::fromArray(
[
'id' => 7,
'type' => AUTO_SLA_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'data' => [
'time' => 23456789,
'data' => 15,
],
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
$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}',
(string) EventsHistory::fromArray(
[
'id' => 7,
'type' => AUTO_SLA_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'maxTime' => 12800,
'data' => [
'time' => 23456789,
'data' => 15,
],
'id_metaconsole' => 2,
'linked_layout_node_id' => 15,
'linkedLayoutId' => 3,
'agentId' => 21,
'moduleId' => 385,
'moduleName' => 'module_test',
]
)
);
}
}

View File

@ -0,0 +1,270 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Group;
/**
* Test for the Visual Console Box Group Item model.
*/
class GroupTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
Group::class,
Group::fromArray(
[
'id' => 13,
'type' => GROUP_ITEM,
'width' => '600',
'height' => '500',
'imageSrc' => 'image.jpg',
'groupId' => 12,
]
)
);
$this->assertInstanceOf(
Group::class,
Group::fromArray(
[
'id' => 1004,
'type' => GROUP_ITEM,
'width' => '600',
'height' => '500',
'image' => 'test_image.png',
'id_group' => 0,
]
)
);
}
/**
* Test if the instance is not created when using a invalid image src.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidImageSrc(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid imageSrc.
Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => '',
'groupId' => 0,
]
);
// Missing imageSrc.
Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'id_group' => 11,
]
);
}
/**
* Test if the instance is not created when using a invalid group Id.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidGroupId(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid groupId.
Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'test.jpg',
'groupId' => 'bar',
]
);
// Missing groupId.
Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'test.jpg',
]
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"type":11,"width":0,"x":-666,"y":76}',
(string) Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'groupId' => 12,
]
)
);
// With a linked layout.
$this->assertEquals(
'{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"type":11,"width":0,"x":-666,"y":76}',
(string) Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'groupId' => 12,
'id_layout_linked' => 1,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"parentId":null,"type":11,"width":0,"x":-666,"y":76}',
(string) Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'groupId' => 12,
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"weight","linkedLayoutStatusTypeWeight":80,"metaconsoleId":5,"parentId":null,"type":11,"width":0,"x":-666,"y":76}',
(string) Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'groupId' => 12,
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
'linkedLayoutStatusType' => 'weight',
'linkedLayoutStatusTypeWeight' => 80,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"groupId":12,"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,"parentId":null,"type":11,"width":0,"x":-666,"y":76}',
(string) Group::fromArray(
[
'id' => 7,
'type' => GROUP_ITEM,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'groupId' => 12,
'linkedLayoutId' => 2,
'linked_layout_status_type' => 'service',
'linkedLayoutStatusTypeWarningThreshold' => 50,
'linked_layout_status_as_service_critical' => 80,
]
)
);
}
}

View File

@ -0,0 +1,207 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Icon;
/**
* Test for the Visual Console Box Icon Item model.
*/
class IconTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
Icon::class,
Icon::fromArray(
[
'id' => 69,
'type' => ICON,
'width' => '0',
'height' => '0',
'imageSrc' => 'image.jpg',
]
)
);
}
/**
* Test if the instance is not created when using a invalid image src.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidImageSrc(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid imageSrc.
Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => '',
]
);
// Missing imageSrc.
Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
]
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"type":5,"width":0,"x":-666,"y":76}',
(string) Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
]
)
);
// With a linked layout.
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"type":5,"width":0,"x":-666,"y":76}',
(string) Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'id_layout_linked' => 1,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"parentId":null,"type":5,"width":0,"x":-666,"y":76}',
(string) Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"weight","linkedLayoutStatusTypeWeight":80,"metaconsoleId":5,"parentId":null,"type":5,"width":0,"x":-666,"y":76}',
(string) Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
'linkedLayoutStatusType' => 'weight',
'linkedLayoutStatusTypeWeight' => 80,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"metaconsoleId":5,"parentId":null,"type":5,"width":0,"x":-666,"y":76}',
(string) Icon::fromArray(
[
'id' => 7,
'type' => ICON,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
'linked_layout_status_type' => 'service',
'linkedLayoutStatusTypeWarningThreshold' => 50,
'linked_layout_status_as_service_critical' => 80,
]
)
);
}
}

View File

@ -0,0 +1,156 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\Line;
/**
* Test for the Visual Console Box Icon Item model.
*/
class LineTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
Line::class,
Line::fromArray(
[
'id' => 10,
'type' => LINE_ITEM,
'startX' => 50,
'startY' => 100,
'endX' => 0,
'endY' => 10,
'isOnTop' => false,
'borderWidth' => 0,
'borderColor' => 'white',
]
)
);
$this->assertInstanceOf(
Line::class,
Line::fromArray(
[
'id' => 10,
'type' => LINE_ITEM,
'startX' => 50,
'endY' => 10,
'borderColor' => 'black',
]
)
);
}
/**
* Test if the instance is not created when using a invalid Id.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidId(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid id.
Line::fromArray(
[
'id' => 'foo',
'type' => LINE_ITEM,
'startX' => 50,
'startY' => 100,
'endX' => 0,
'endY' => 10,
'isOnTop' => false,
'borderWidth' => 0,
'borderColor' => 'white',
]
);
// Missing id.
Line::fromArray(
[
'type' => LINE_ITEM,
'startX' => 50,
'startY' => 100,
'endX' => 0,
'endY' => 10,
'isOnTop' => false,
'borderWidth' => 0,
'borderColor' => 'white',
]
);
}
/**
* Test if the instance is not created when using a invalid type.
*
* @return void
*/
public function testCannotBeCreatedWithInvalidtype(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid type.
Line::fromArray(
[
'id' => 13,
'type' => 'test',
'startX' => 50,
'startY' => 100,
'endX' => 0,
'endY' => 10,
'isOnTop' => false,
'borderWidth' => 0,
'borderColor' => 'white',
]
);
// Missing type.
Line::fromArray(
[
'id' => 13,
'startX' => 50,
'startY' => 100,
'endX' => 0,
'endY' => 10,
'isOnTop' => true,
'borderWidth' => 0,
'borderColor' => 'white',
]
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"borderColor":"white","borderWidth":0,"endX":0,"endY":10,"id":1,"isOnTop":false,"startX":50,"startY":100,"type":13}',
(string) Line::fromArray(
[
'id' => 1,
'type' => LINE_ITEM,
'startX' => 50,
'startY' => 100,
'endX' => 0,
'endY' => 10,
'isOnTop' => false,
'borderWidth' => 0,
'borderColor' => 'white',
]
)
);
}
}

View File

@ -0,0 +1,226 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\SimpleValue;
/**
* Test for the Visual Console Simple Value Item model.
*/
class SimpleValueTest extends TestCase
{
/**
* Test if the instance is created using a valid data structure.
*
* @return void
*/
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
SimpleValue::class,
SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'string',
'value' => 57,
'processValue' => 'avg',
'period' => 12800,
]
)
);
$this->assertInstanceOf(
SimpleValue::class,
SimpleValue::fromArray(
[
'id' => 14,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'image',
'value' => 3598,
'processValue' => 'max',
'period' => 9000,
]
)
);
}
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.
*
* @return void
*/
public function testContainerIsRepresentedAsJson(): void
{
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"period":12800,"processValue":"avg","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
(string) SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'string',
'value' => 57,
'processValue' => 'avg',
'period' => 12800,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
(string) SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'string',
'value' => 57,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
(string) SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'string',
'value' => 57,
'id_layout_linked' => 1,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
(string) SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'string',
'value' => 57,
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
$this->assertEquals(
'{"aclGroupId":null,"agentId":21,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":15,"linkedLayoutId":3,"linkedLayoutStatusType":"default","metaconsoleId":2,"moduleId":385,"moduleName":"module_test","parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
(string) SimpleValue::fromArray(
[
'id' => 3,
'type' => SIMPLE_VALUE,
'width' => '600',
'height' => '500',
'valueType' => 'string',
'value' => 57,
'id_metaconsole' => 2,
'linked_layout_node_id' => 15,
'linkedLayoutId' => 3,
'agentId' => 21,
'moduleId' => 385,
'moduleName' => 'module_test',
]
)
);
}
}

View File

@ -0,0 +1,211 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Models\VisualConsole\Items\StaticGraph;
/**
* Test class
*/
class StaticGrahpTest extends TestCase
{
public function testCanBeCreatedFromValidUserStructure(): void
{
$this->assertInstanceOf(
StaticGraph::class,
StaticGraph::fromArray(
[
'id' => 345,
'type' => 1,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'aaaaa',
'showLastValueTooltip' => 'enabled',
]
)
);
$this->assertInstanceOf(
StaticGraph::class,
StaticGraph::fromArray(
[
'id' => 1000,
'type' => 0,
'width' => 100,
'height' => 900,
'image' => 'test.jpg',
'show_last_value' => 2,
]
)
);
}
/**
* Test if the model has a valid JSON representation.
*
* @return void
*/
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}',
(string) StaticGraph::fromArray(
[
'id' => 7,
'type' => STATIC_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.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":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"disabled","type":0,"width":0,"x":-666,"y":76}',
(string) StaticGraph::fromArray(
[
'id' => 7,
'type' => STATIC_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'image' => 'image.jpg',
'showLastValueTooltip' => 'disabled',
]
)
);
$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}',
(string) StaticGraph::fromArray(
[
'id' => 7,
'type' => STATIC_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'imageSrc' => 'image.jpg',
'id_metaconsole' => 5,
'linked_layout_node_id' => 3,
'linkedLayoutId' => 2,
]
)
);
$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}',
(string) StaticGraph::fromArray(
[
'id' => 7,
'type' => STATIC_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'image' => 'image.jpg',
'id_layout_linked' => 1,
]
)
);
$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}',
(string) StaticGraph::fromArray(
[
'id' => 7,
'type' => STATIC_GRAPH,
'label' => null,
'labelPosition' => 'up',
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '0',
'height' => '0',
'x' => -666,
'y' => 76,
'image' => 'image.jpg',
'linkedLayoutId' => 2,
'linked_layout_status_type' => 'service',
'linkedLayoutStatusTypeWarningThreshold' => 50,
'linked_layout_status_as_service_critical' => 80,
]
)
);
}
public function testCannotBeCreatedWithInvalidImageSrc(): void
{
$this->expectException(InvalidArgumentException::class);
// Invalid imageSrc.
StaticGraph::fromArray(
[
'id' => 3,
'type' => 0,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
'imageSrc' => 45,
'showLastValueTooltip' => 'disabled',
]
);
// Missing imageSrc.
StaticGraph::fromArray(
[
'id' => 3,
'type' => 0,
'label' => null,
'isLinkEnabled' => true,
'isOnTop' => false,
'parentId' => null,
'width' => '330',
'height' => '0',
'x' => 511,
'y' => 76,
'showLastValueTooltip' => 'enabled',
]
);
}
}

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,11 @@ 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";
// Base properties.
export interface VisualConsoleProps extends Size {
@ -79,21 +84,17 @@ 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.PERCENTILE_BAR:
throw new TypeError("item not found");
case ItemType.LABEL:
throw new TypeError("item not found");
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");
return new SimpleValue(simpleValuePropsDecoder(data));
case ItemType.PERCENTILE_BAR:
case ItemType.PERCENTILE_BUBBLE:
throw new TypeError("item not found");
case ItemType.LABEL:
return new Label(labelPropsDecoder(data));
case ItemType.ICON:
return new Icon(iconPropsDecoder(data));
case ItemType.SERVICE:
throw new TypeError("item not found");
case ItemType.GROUP_ITEM:
@ -103,13 +104,10 @@ function itemInstanceFrom(data: UnknownObject) {
case ItemType.LINE_ITEM:
return new Line(linePropsDecoder(data));
case ItemType.AUTO_SLA_GRAPH:
throw new TypeError("item not found");
return new EventsHistory(eventsHistoryPropsDecoder(data));
case ItemType.CIRCULAR_PROGRESS_BAR:
throw new TypeError("item not found");
case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
throw new TypeError("item not found");
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 +250,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 simple value 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,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

@ -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;
}