mirror of
https://github.com/pandorafms/pandorafms.git
synced 2025-07-27 07:44:35 +02:00
Added visual_console_view
Former-commit-id: a121bb8ee6fe338561fcf7efda289727e1ba7afe
This commit is contained in:
parent
2bcc05806a
commit
db30a8650e
@ -193,4 +193,134 @@ final class Container extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a container data structure from the database using layout id
|
||||||
|
* and returns a valid representation of the model
|
||||||
|
*
|
||||||
|
* @param integer $id_layout
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getItemsFromDB(int $id_layout): array
|
||||||
|
{
|
||||||
|
$layout_items = db_get_all_rows_filter('tlayout_data', ['id_layout' => $id_layout]);
|
||||||
|
if (!empty($layout_items) === true) {
|
||||||
|
$array_items = [];
|
||||||
|
foreach ($layout_items as $key => $value) {
|
||||||
|
switch ($value['type']) {
|
||||||
|
case STATIC_GRAPH:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULE_GRAPH:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIMPLE_VALUE:
|
||||||
|
case SIMPLE_VALUE_MAX:
|
||||||
|
case SIMPLE_VALUE_MIN:
|
||||||
|
case SIMPLE_VALUE_AVG:
|
||||||
|
$value['value'] = visual_map_get_simple_value(
|
||||||
|
$value['type'],
|
||||||
|
$value['id_agente_modulo'],
|
||||||
|
$value['period']
|
||||||
|
);
|
||||||
|
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\SimpleValue::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PERCENTILE_BAR:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LABEL:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\Label::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ICON:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\Icon::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PERCENTILE_BUBBLE:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SERVICE:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GROUP_ITEM:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\Group::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BOX_ITEM:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\Box::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LINE_ITEM:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\Line::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUTO_SLA_GRAPH:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\EventsHistory::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CIRCULAR_PROGRESS_BAR:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CIRCULAR_INTERIOR_PROGRESS_BAR:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DONUT_GRAPH:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BARS_GRAPH:
|
||||||
|
// code...
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLOCK:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\Clock::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COLOR_CLOUD:
|
||||||
|
array_push(
|
||||||
|
$array_items,
|
||||||
|
(string) Items\ColorCloud::fromArray($value)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Models\VisualConsole\Items;
|
namespace Models\VisualConsole\Items;
|
||||||
use Models\VisualConsole\Item;
|
use Models\VisualConsole\Item;
|
||||||
use Models\Model;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of a simple value item of the Visual Console.
|
* Model of a simple value item of the Visual Console.
|
||||||
@ -45,17 +44,9 @@ final class SimpleValue extends Item
|
|||||||
protected function validateData(array $data): void
|
protected function validateData(array $data): void
|
||||||
{
|
{
|
||||||
parent::validateData($data);
|
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) {
|
if (isset($data['value']) === false) {
|
||||||
throw new \InvalidArgumentException(
|
throw new \InvalidArgumentException(
|
||||||
'the value property is required'
|
'the value property is required and should be string'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,18 +86,25 @@ final class SimpleValue extends Item
|
|||||||
*/
|
*/
|
||||||
private function extractProcessValue(array $data): string
|
private function extractProcessValue(array $data): string
|
||||||
{
|
{
|
||||||
$processValue = Model::notEmptyStringOr(
|
$processValue = static::notEmptyStringOr(
|
||||||
Model::issetInArray($data, ['processValue']),
|
static::issetInArray($data, ['processValue']),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($processValue === null) {
|
||||||
|
$processValue = $data['type'];
|
||||||
|
}
|
||||||
|
|
||||||
switch ($processValue) {
|
switch ($processValue) {
|
||||||
|
case SIMPLE_VALUE_AVG:
|
||||||
case 'avg':
|
case 'avg':
|
||||||
return 'avg';
|
return 'avg';
|
||||||
|
|
||||||
|
case SIMPLE_VALUE_MAX:
|
||||||
case 'max':
|
case 'max':
|
||||||
return 'max';
|
return 'max';
|
||||||
|
|
||||||
|
case SIMPLE_VALUE_MIN:
|
||||||
case 'min':
|
case 'min':
|
||||||
return 'min';
|
return 'min';
|
||||||
|
|
||||||
@ -126,8 +124,8 @@ final class SimpleValue extends Item
|
|||||||
*/
|
*/
|
||||||
private function extractPeriod(array $data): int
|
private function extractPeriod(array $data): int
|
||||||
{
|
{
|
||||||
$period = Model::parseIntOr(
|
$period = static::parseIntOr(
|
||||||
Model::issetInArray($data, ['period']),
|
static::issetInArray($data, ['period']),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
if ($period >= 0) {
|
if ($period >= 0) {
|
||||||
@ -148,8 +146,8 @@ final class SimpleValue extends Item
|
|||||||
*/
|
*/
|
||||||
private function extractValueType(array $data): string
|
private function extractValueType(array $data): string
|
||||||
{
|
{
|
||||||
$valueType = Model::notEmptyStringOr(
|
$valueType = static::notEmptyStringOr(
|
||||||
Model::issetInArray($data, ['valueType']),
|
static::issetInArray($data, ['valueType']),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Models\VisualConsole\Items;
|
namespace Models\VisualConsole\Items;
|
||||||
use Models\VisualConsole\Item;
|
use Models\VisualConsole\Item;
|
||||||
use Models\Model;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of a group item of the Visual Console.
|
* Model of a group item of the Visual Console.
|
||||||
@ -84,14 +83,14 @@ final class StaticGraph extends Item
|
|||||||
*/
|
*/
|
||||||
private function extractShowLastValueTooltip(array $data): string
|
private function extractShowLastValueTooltip(array $data): string
|
||||||
{
|
{
|
||||||
$showLastValueTooltip = Model::notEmptyStringOr(
|
$showLastValueTooltip = static::notEmptyStringOr(
|
||||||
Model::issetInArray($data, ['showLastValueTooltip']),
|
static::issetInArray($data, ['showLastValueTooltip']),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($showLastValueTooltip === null) {
|
if ($showLastValueTooltip === null) {
|
||||||
$showLastValueTooltip = Model::parseIntOr(
|
$showLastValueTooltip = static::parseIntOr(
|
||||||
Model::issetInArray($data, ['show_last_value']),
|
static::issetInArray($data, ['show_last_value']),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
switch ($showLastValueTooltip) {
|
switch ($showLastValueTooltip) {
|
||||||
|
@ -169,6 +169,11 @@ $options['view']['active'] = true;
|
|||||||
if (!is_metaconsole()) {
|
if (!is_metaconsole()) {
|
||||||
if (!$config['pure']) {
|
if (!$config['pure']) {
|
||||||
$options['pure']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$refr.'&pure=1">'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).'</a>';
|
$options['pure']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$refr.'&pure=1">'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).'</a>';
|
||||||
|
$options['view2']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/visual_console_view&id='.$id_layout.'&refr='.$view_refresh.'">'.html_print_image(
|
||||||
|
'images/operation.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Beta View')]
|
||||||
|
).'</a>';
|
||||||
ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
|
ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
148
pandora_console/operation/visual_console/visual_console_view.php
Normal file
148
pandora_console/operation/visual_console/visual_console_view.php
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Pandora FMS - http://pandorafms.com
|
||||||
|
// ==================================================
|
||||||
|
// Copyright (c) 2005-2019 Artica Soluciones Tecnologicas
|
||||||
|
// Please see http://pandorafms.org for full contribution list
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation for version 2.
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
// Login check.
|
||||||
|
check_login();
|
||||||
|
|
||||||
|
require_once $config['homedir'].'/vendor/autoload.php';
|
||||||
|
require_once $config['homedir'].'/include/functions_visual_map.php';
|
||||||
|
|
||||||
|
if (!defined('METACONSOLE')) {
|
||||||
|
$id_layout = (int) get_parameter('id');
|
||||||
|
} else {
|
||||||
|
$id_layout = (int) get_parameter('id_visualmap');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get input parameter for layout id.
|
||||||
|
if (!$id_layout) {
|
||||||
|
db_pandora_audit(
|
||||||
|
'ACL Violation',
|
||||||
|
'Trying to access visual console without id layout'
|
||||||
|
);
|
||||||
|
include 'general/noaccess.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$layout = db_get_row('tlayout', 'id', $id_layout);
|
||||||
|
|
||||||
|
if (!$layout) {
|
||||||
|
db_pandora_audit(
|
||||||
|
'ACL Violation',
|
||||||
|
'Trying to access visual console without id layout'
|
||||||
|
);
|
||||||
|
include 'general/noaccess.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id_group = $layout['id_group'];
|
||||||
|
$layout_name = $layout['name'];
|
||||||
|
|
||||||
|
// ACL.
|
||||||
|
$vconsole_read = check_acl($config['id_user'], $id_group, 'VR');
|
||||||
|
$vconsole_write = check_acl($config['id_user'], $id_group, 'VW');
|
||||||
|
$vconsole_manage = check_acl($config['id_user'], $id_group, 'VM');
|
||||||
|
|
||||||
|
if (!$vconsole_read && !$vconsole_write && !$vconsole_manage) {
|
||||||
|
db_pandora_audit(
|
||||||
|
'ACL Violation',
|
||||||
|
'Trying to access visual console without group access'
|
||||||
|
);
|
||||||
|
include 'general/noaccess.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render map.
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
$options['consoles_list']['text'] = '<a href="index.php?sec=network&sec2=godmode/reporting/map_builder&refr='.$refr.'">'.html_print_image(
|
||||||
|
'images/visual_console.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Visual consoles list')]
|
||||||
|
).'</a>';
|
||||||
|
|
||||||
|
if ($vconsole_write || $vconsole_manage) {
|
||||||
|
$url_base = 'index.php?sec=network&sec2=godmode/reporting/visual_console_builder&action=';
|
||||||
|
|
||||||
|
$hash = md5($config['dbpass'].$id_layout.$config['id_user']);
|
||||||
|
|
||||||
|
$options['public_link']['text'] = '<a href="'.ui_get_full_url(
|
||||||
|
'operation/visual_console/public_console.php?hash='.$hash.'&id_layout='.$id_layout.'&id_user='.$config['id_user']
|
||||||
|
).'" target="_blank">'.html_print_image(
|
||||||
|
'images/camera_mc.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Show link to public Visual Console')]
|
||||||
|
).'</a>';
|
||||||
|
$options['public_link']['active'] = false;
|
||||||
|
|
||||||
|
$options['data']['text'] = '<a href="'.$url_base.$action.'&tab=data&id_visual_console='.$id_layout.'">'.html_print_image(
|
||||||
|
'images/op_reporting.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Main data')]
|
||||||
|
).'</a>';
|
||||||
|
$options['list_elements']['text'] = '<a href="'.$url_base.$action.'&tab=list_elements&id_visual_console='.$id_layout.'">'.html_print_image(
|
||||||
|
'images/list.png',
|
||||||
|
true,
|
||||||
|
['title' => __('List elements')]
|
||||||
|
).'</a>';
|
||||||
|
|
||||||
|
if (enterprise_installed()) {
|
||||||
|
$options['wizard_services']['text'] = '<a href="'.$url_base.$action.'&tab=wizard_services&id_visual_console='.$id_layout.'">'.html_print_image(
|
||||||
|
'images/wand_services.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Services wizard')]
|
||||||
|
).'</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['wizard']['text'] = '<a href="'.$url_base.$action.'&tab=wizard&id_visual_console='.$id_layout.'">'.html_print_image(
|
||||||
|
'images/wand.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Wizard')]
|
||||||
|
).'</a>';
|
||||||
|
$options['editor']['text'] = '<a href="'.$url_base.$action.'&tab=editor&id_visual_console='.$id_layout.'">'.html_print_image(
|
||||||
|
'images/builder.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Builder')]
|
||||||
|
).'</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['view']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$view_refresh.'">'.html_print_image('images/operation.png', true, ['title' => __('View')]).'</a>';
|
||||||
|
|
||||||
|
if (!is_metaconsole()) {
|
||||||
|
if (!$config['pure']) {
|
||||||
|
$options['pure']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/render_view&id='.$id_layout.'&refr='.$refr.'&pure=1">'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).'</a>';
|
||||||
|
$options['view2']['text'] = '<a href="index.php?sec=network&sec2=operation/visual_console/visual_console_view&id='.$id_layout.'&refr='.$view_refresh.'">'.html_print_image(
|
||||||
|
'images/operation.png',
|
||||||
|
true,
|
||||||
|
['title' => __('Beta View')]
|
||||||
|
).'</a>';
|
||||||
|
$options['view2']['active'] = true;
|
||||||
|
ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the hidden value for the javascript.
|
||||||
|
html_print_input_hidden('metaconsole', 0);
|
||||||
|
} else {
|
||||||
|
// Set the hidden value for the javascript.
|
||||||
|
html_print_input_hidden('metaconsole', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
use Models\VisualConsole\Container;
|
||||||
|
|
||||||
|
$container = (string) Container::fromArray($layout);
|
||||||
|
$items = Container::getItemsFromDB($id_layout, $config['homedir']);
|
||||||
|
|
||||||
|
hd($config['homedir']);
|
||||||
|
|
||||||
|
hd($items);
|
@ -145,7 +145,7 @@ class ClockTest extends TestCase
|
|||||||
public function testContainerIsRepresentedAsJson(): void
|
public function testContainerIsRepresentedAsJson(): void
|
||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'{"aclGroupId":null,"clockFormat":"time","clockTimezone":"Europe\/Madrid","clockTimezoneOffset":3600,"clockType":"digital","color":"white","height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"showClockTimezone":false,"type":19,"width":0,"x":-666,"y":76}',
|
'{"aclGroupId":null,"clockFormat":"time","clockTimezone":"Europe\/Madrid","clockTimezoneOffset":7200,"clockType":"digital","color":"white","height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"showClockTimezone":false,"type":19,"width":0,"x":-666,"y":76}',
|
||||||
(string) Clock::fromArray(
|
(string) Clock::fromArray(
|
||||||
[
|
[
|
||||||
'id' => 69,
|
'id' => 69,
|
||||||
|
@ -53,84 +53,6 @@ class SimpleValueTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testCannotBeCreatedWithInvalidValueType(): void
|
|
||||||
{
|
|
||||||
$this->expectException(InvalidArgumentException::class);
|
|
||||||
// Invalid valueType.
|
|
||||||
SimpleValue::fromArray(
|
|
||||||
[
|
|
||||||
'id' => 3,
|
|
||||||
'type' => SIMPLE_VALUE,
|
|
||||||
'label' => null,
|
|
||||||
'isLinkEnabled' => true,
|
|
||||||
'isOnTop' => false,
|
|
||||||
'parentId' => null,
|
|
||||||
'width' => '330',
|
|
||||||
'height' => '0',
|
|
||||||
'x' => 511,
|
|
||||||
'y' => 76,
|
|
||||||
'valueType' => '',
|
|
||||||
'value' => 57,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
// Missing valueType.
|
|
||||||
SimpleValue::fromArray(
|
|
||||||
[
|
|
||||||
'id' => 3,
|
|
||||||
'type' => SIMPLE_VALUE,
|
|
||||||
'label' => null,
|
|
||||||
'isLinkEnabled' => true,
|
|
||||||
'isOnTop' => false,
|
|
||||||
'parentId' => null,
|
|
||||||
'width' => '330',
|
|
||||||
'height' => '0',
|
|
||||||
'x' => 511,
|
|
||||||
'y' => 76,
|
|
||||||
'value' => 57,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function testCannotBeCreatedWithInvalidValue(): void
|
|
||||||
{
|
|
||||||
$this->expectException(InvalidArgumentException::class);
|
|
||||||
// Invalid valueType.
|
|
||||||
SimpleValue::fromArray(
|
|
||||||
[
|
|
||||||
'id' => 3,
|
|
||||||
'type' => SIMPLE_VALUE,
|
|
||||||
'label' => null,
|
|
||||||
'isLinkEnabled' => true,
|
|
||||||
'isOnTop' => false,
|
|
||||||
'parentId' => null,
|
|
||||||
'width' => '330',
|
|
||||||
'height' => '0',
|
|
||||||
'x' => 511,
|
|
||||||
'y' => 76,
|
|
||||||
'valueType' => 'string',
|
|
||||||
'value' => 'foo',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
// Missing valueType.
|
|
||||||
SimpleValue::fromArray(
|
|
||||||
[
|
|
||||||
'id' => 3,
|
|
||||||
'type' => SIMPLE_VALUE,
|
|
||||||
'label' => null,
|
|
||||||
'isLinkEnabled' => true,
|
|
||||||
'isOnTop' => false,
|
|
||||||
'parentId' => null,
|
|
||||||
'width' => '330',
|
|
||||||
'height' => '0',
|
|
||||||
'x' => 511,
|
|
||||||
'y' => 76,
|
|
||||||
'valueType' => 'string',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if the model has a valid JSON representation.
|
* Test if the model has a valid JSON representation.
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user