Crear un widget (tutorial)

Este es un tutorial paso a paso que muestra cómo crear un widget simple para los tableros. Puede descargar todos los archivos de este widget como un archivo ZIP: lesson_gauge_chart.zip.

Lo que construirás

Durante este tutorial, primero crearás un widget básico "¡Hola, mundo!" para luego convertirlo en un widget más avanzado que muestra el valor de un elemento como un gráfico gauge. Así es como se verá el widget terminado:

Parte I - "¡Hola mundo!"

En esta sección, aprenderá cómo crear los elementos mínimos requeridos del widget y agregar un nuevo widget a la interfaz de Zabbix.

Agregar un widget en blanco a la interfaz de Zabbix

  1. Cree un directorio lesson_gauge_chart en el directorio modules de su instalación de la interfaz de Zabbix (por ejemplo, zabbix/ui/modules).

Todos los widgets personalizados se tratan como módulos externos y deben agregarse al directorio modules de su instalación de interfaz de Zabbix (por ejemplo, zabbix/ui/modules). El directorio zabbix/ui/widgets está reservado para los widgets integrados de Zabbix y se actualiza junto con la interfaz de usuario de Zabbix.

  1. Cree un archivo manifest.json con metadatos básicos del widget (consulte la descripción de los parámetros admitidos).

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.0",
           "author": "Zabbix"
       }
  1. En la interfaz de Zabbix, vaya a la sección Administración → General → Módulos y haga clic en el botón Escanear directorio.

  1. Ubique el nuevo módulo Gauge chart en la lista y haga clic en el hipervínculo "Desactivado" para cambiar el estado del módulo de "Desactivado" a "Activado".

  1. Abra un tablero, cámbielo al modo de edición y agregue un nuevo widget. En el campo Tipo, seleccione "Gauge chart".

  1. En este punto, la configuración del widget Gauge chart contiene solo los campos de widget comunes Nombre e Intervalo de actualización. Haga clic en Agregar para agregar el widget al tablero.

  1. Debería aparecer un widget en blanco en el tablero. Haga clic en Guardar cambios en la esquina superior derecha para guardar el tablero.

Agregar una vista de widget

El archivo view del widget debe estar ubicado en el directorio views (para este tutorial, ui/modules/lesson_gauge_chart/views/). Si el archivo tiene el nombre predeterminado widget.view.php, no es necesario registrarlo en el archivo manifest.json. Si el archivo tiene un nombre diferente, especifíquelo en la sección actions/widget.lesson_gauge_chart.view del archivo manifest.json.

  1. Cree un directorio views en el directorio lesson_gauge_chart.

  2. Cree un archivo widget.view.php en el directorio views.

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
       ->addItem(
       new CTag('h1', true, '¡Hola, mundo!')
       )
       ->show();
  1. Actualice el tablero. El widget Gauge chart ahora muestra "¡Hola, mundo!".

Parte II - Gauge chart

Agregar configuraciones a una vista de configuración y usarlas en una vista de widget

En esta sección, aprenderá cómo agregar un campo de configuración del widget y mostrar el valor ingresado en la vista del widget como texto.

La configuración del widget consta de un formulario (Zabbix\Widgets\CWidgetForm) y una vista de formulario de widget (widget.edit.php). Para agregar campos (Zabbix\Widgets\CWidgetField), necesita crear una clase WidgetForm, que extenderá Zabbix\Widgets\CWidgetForm.

El formulario contiene el conjunto de campos (Zabbix\Widgets\CWidgetField) de varios tipos, que se utilizan para validar los valores ingresados por el usuario. El campo de formulario (Zabbix\Widgets\CWidgetField) para cada tipo de elemento de entrada convierte el valor a un formato único para almacenarlo en la base de datos.

El archivo form del widget debe estar ubicado en el directorio includes (para este tutorial, ui/modules/lesson_gauge_chart/includes/). Si el archivo tiene el nombre predeterminado WidgetForm.php, no es necesario registrarlo en el archivo manifest.json. Si el archivo tiene un nombre diferente, especifíquelo en la sección widget/form_class del archivo manifest.json.

  1. Cree un nuevo directorio includes en el directorio lesson_gauge_chart.

  2. Cree un archivo WidgetForm.php en el directorio includes.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Zabbix\Widgets\CWidgetForm;
       
       class WidgetForm extends CWidgetForm {
       }
  1. Agregue un campo Descripción al formulario de configuración del widget. Este es un campo de texto normal, donde un usuario puede ingresar cualquier conjunto de caracteres. Puede utilizar la clase CWidgetFieldTextBox para ello.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Zabbix\Widgets\CWidgetForm;
       
       use Zabbix\Widgets\Fields\CWidgetFieldTextBox;
       
       class WidgetForm extends CWidgetForm {
       
           public function addFields(): self {
           return $this
           ->addField(
           new CWidgetFieldTextBox('description', _('Descripción'))
           );
           }
       }
  1. En el directorio views, cree un archivo de vista de configuración del widget widget.edit.php y agregue una vista para el nuevo campo Descripción. Para la clase de campo CWidgetFieldTextBox, la vista es CWidgetFieldTextBoxView.

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Gauge chart widget form view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetFormView($data))
           ->addField(
           new CWidgetFieldTextBoxView($data['fields']['descripción'])
           )
           ->show();
  1. Vaya al tablero y haga clic en el ícono de ajustes en el widget para abrir el formulario de configuración del widget.

  2. El formulario de configuración del widget ahora contiene un nuevo campo de texto Description. Ingrese cualquier valor, por ejemplo, Descripción del gráfico de indicadores.

  1. Haga clic en Aplicar en el formulario de configuración del widget. Luego haga clic en Guardar cambios en la esquina superior derecha para guardar el panel. Tenga en cuenta que la nueva descripción no es visible en ninguna parte y el widget aún muestra "¡Hola, mundo!".

Para que la nueva descripción aparezca en el widget, el valor del campo Descripción debe recuperarse de la base de datos y pasarse a la vista del widget. Para eso, necesitas crear una clase de acción.

  1. Cree un nuevo directorio actions en el directorio lesson_gauge_chart.

  2. Cree un archivo WidgetView.php en el directorio actions. La clase de acción WidgetView ampliará la clase CControllerDashboardWidgetView.

Los valores de los campos de configuración del widget se almacenan en la propiedad $fields_values de la clase de acción.

ui/modules/lesson_gauge_chart/actions/WidgetView.php

<?php
       
       namespace Modules\LessonGaugeChart\Actions;
       
       use CControllerDashboardWidgetView,
           CControllerResponseData;
       
       class WidgetView extends CControllerDashboardWidgetView {
       
           protected function doAction(): void {
           $this->setResponse(new CControllerResponseData([
           'name' => $this->getInput('name', $this->widget->getName()),
           'description' => $this->fields_values['descripción'],
           'user' => [
           'debug_mode' => $this->getDebugMode()
           ]
           ]));
           }
       }
  1. Abra manifest.json y registre WidgetView como una clase de acción en la sección actions/widget.lesson_gauge_chart.view.

ui/modules/lesson_gauge_chart/manifest.json

{
       "manifest_version": 2.0,
       "id": "lesson_gauge_chart",
       "type": "widget",
       "name": "Gauge chart",
       "namespace": "LessonGaugeChart",
       "version": "1.0",
       "author": "Zabbix",
       "actions": {
       "widget.lesson_gauge_chart.view": {
       "class": "WidgetView"
       }
       }
       }
  1. Ahora puede utilizar el valor del campo de descripción, contenido en $data['description'], en la vista del widget. Abra views/widget.view.php y reemplace el texto estático "¡Hola, mundo!" con $data['description'].

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
       ->addItem(
       new CTag('h1', true, $data['descripción'])
       )
       ->show();
  1. Actualice la página del tablero. Ahora debería ver el texto de descripción del widget en lugar de "¡Hola, mundo!".

Recuperar el valor de una métrica a través de API

El widget debe mostrar el último valor de una métrica elegida por el usuario. Para eso, debe agregar la capacidad de seleccionar métricas en la configuración del widget.

En esta sección, aprenderá cómo agregar un campo de selección de métricas al formulario del widget y cómo agregar la parte visual de este campo a la vista de configuración. Luego, el controlador del widget podrá recuperar los datos de la métrica y su valor mediante una solicitud API. Una vez recibido, el valor se puede mostrar en la vista del widget.

  1. Abra includes/WidgetForm.php y agregue el campo CWidgetFieldMultiSelectItem. Esto permitirá seleccionar una métrica en el formulario de configuración.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Zabbix\Widgets\{
           CWidgetField,
           CWidgetForm
       };
       
       use Zabbix\Widgets\Fields\{
           CWidgetFieldMultiSelectItem,
           CWidgetFieldTextBox
       };
       
       /**
        * Gauge chart widget form.
        */
       class WidgetForm extends CWidgetForm {
           
           public function addFields(): self {
               return $this
                   ->addField(
                       (new CWidgetFieldMultiSelectItem('itemid', _('Item')))
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                           ->setMultiple(false)
                   )
                   ->addField(
                       new CWidgetFieldTextBox('description', _('Description'))
                   );
           }
       }
  1. Abra views/widget.edit.php y agregue el componente visual de campo a la vista de configuración.

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Gauge chart widget form view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetFormView($data))
           ->addField(
               new CWidgetFieldMultiSelectItemView($data['fields']['itemid'])
           )
           ->addField(
               new CWidgetFieldTextBoxView($data['fields']['description'])
           )
           ->show();
  1. Regrese al tablero y haga clic en el ícono de ajustes en el widget para abrir el formulario de configuración del widget.

  2. El formulario de configuración del widget ahora contiene un nuevo campo de entrada Métrica. Seleccione el equipo "Servidor Zabbix" y la métrica "Promedio de carga (promedio de 1 m)".

  1. Haga clic en Aplicar en el formulario de configuración del widget. Luego haga clic en Guardar cambios en la esquina superior derecha para guardar el tablero.

  2. Abra y modifique actions/WidgetView.php.

De ahora en adelante, el ID de la métrica estará disponible en el controlador del widget en $this->fields_values['itemid']. El método del controlador doAction() recopila los datos de la métrica (nombre, tipo de valor, unidades) usando el método API item.get y el último valor de la métrica usando el Método API history.get.

ui/modules/lesson_gauge_chart/actions/WidgetView.php

<?php
       
       namespace Modules\LessonGaugeChart\Actions;
       
       use API,
           CControllerDashboardWidgetView,
           CControllerResponseData;
       
       class WidgetView extends CControllerDashboardWidgetView {
       
           protected function doAction(): void {
               $db_items = API::Item()->get([
                   'output' => ['itemid', 'value_type', 'name', 'units'],
                   'itemids' => $this->fields_values['itemid'],
                   'webitems' => true,
                   'filter' => [
                       'value_type' => [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT]
                   ]
               ]);
       
               $value = null;
       
               if ($db_items) {
                   $item = $db_items[0];
       
                   $history = API::History()->get([
                       'output' => API_OUTPUT_EXTEND,
                       'itemids' => $item['itemid'],
                       'history' => $item['value_type'],
                       'sortfield' => 'clock',
                       'sortorder' => ZBX_SORT_DOWN,
                       'limit' => 1
                   ]);
       
                   if ($history) {
                       $value = convertUnitsRaw([
                           'value' => $history[0]['value'],
                           'units' => $item['units']
                       ]);
                   }
               }
       
               $this->setResponse(new CControllerResponseData([
                   'name' => $this->getInput('name', $this->widget->getName()),
                   'value' => $value,
                   'description' => $this->fields_values['description'],
                   'user' => [
                       'debug_mode' => $this->getDebugMode()
                   ]
               ]));
           }
       }
  1. Abra views/widget.view.php y agregue el valor de la métrica a la vista del widget.

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
           ->addItem([
               new CTag('h1', true, $data['description']),
               new CDiv($data['value'] !== null ? $data['value']['value'] : _('No data'))
           ])
           ->show();
  1. Actualice la página del tablero. El widget mostrará el último valor de la métrica.

Agregar ajustes de configuración avanzados a una vista de configuración

En esta sección, aprenderá cómo agregar una sección Configuración avanzada expandible/contraíble con parámetros opcionales, como color, valores mínimos y máximos, unidades y el campo Descripción creado anteriormente.

  1. Cree un archivo Widget.php en el directorio principal de widgets lesson_gauge_chart para crear una nueva clase Widget.

La clase Widget ampliará la clase base CWidget para agregar/anular la configuración predeterminada del widget (en este caso, traducciones). JavaScript, que se proporciona a continuación, muestra la cadena "Sin datos" en caso de que falten datos. La cadena "Sin datos" está presente en los archivos de traducción de la interfaz de usuario de Zabbix.

Si hay constantes de widget, se recomienda especificarlas también en la clase Widget.

ui/modules/lesson_gauge_chart/Widget.php

<?php
       
       namespace Modules\LessonGaugeChart;
       
       use Zabbix\Core\CWidget;
       
       class Widget extends CWidget {
       
           public const UNIT_AUTO = 0;
           public const UNIT_STATIC = 1;
       
           public function getTranslationStrings(): array {
               return [
                   'class.widget.js' => [
                       'No data' => _('No data')
                   ]
               ];
           }
       }
  1. Abra includes/WidgetForm.php y agregue los nuevos campos Color (selector de color), Min (campo numérico), Max (campo numérico) y Unidades (seleccione), y defina el paleta de colores predeterminada para el selector de color, de modo que pueda usarse en los siguientes pasos.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Modules\LessonGaugeChart\Widget;
       
       use Zabbix\Widgets\{
           CWidgetField,
           CWidgetForm
       };
       
       use Zabbix\Widgets\Fields\{
           CWidgetFieldColor,
           CWidgetFieldMultiSelectItem,
           CWidgetFieldNumericBox,
           CWidgetFieldSelect,
           CWidgetFieldTextBox
       };
       
       /**
        * Gauge chart widget form.
        */
       class WidgetForm extends CWidgetForm {
       
           public const DEFAULT_COLOR_PALETTE = [
               'FF465C', 'B0AF07', '0EC9AC', '524BBC', 'ED1248', 'D1E754', '2AB5FF', '385CC7', 'EC1594', 'BAE37D',
               '6AC8FF', 'EE2B29', '3CA20D', '6F4BBC', '00A1FF', 'F3601B', '1CAE59', '45CFDB', '894BBC', '6D6D6D'
           ];
       
           public function addFields(): self {
               return $this
                   ->addField(
                       (new CWidgetFieldMultiSelectItem('itemid', _('Item')))
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                           ->setMultiple(false)
                   )
                   ->addField(
                       (new CWidgetFieldColor('chart_color', _('Color')))->setDefault('FF0000')
                   )
                   ->addField(
                       (new CWidgetFieldNumericBox('value_min', _('Min')))
                           ->setDefault(0)
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                   )
                   ->addField(
                       (new CWidgetFieldNumericBox('value_max', _('Max')))
                           ->setDefault(100)
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                   )
                   ->addField(
                       (new CWidgetFieldSelect('value_units', _('Units'), [
                           Widget::UNIT_AUTO => _x('Auto', 'history source selection method'),
                           Widget::UNIT_STATIC => _x('Static', 'history source selection method')
                       ]))->setDefault(Widget::UNIT_AUTO)
                   )
                   ->addField(
                       (new CWidgetFieldTextBox('value_static_units'))
                   )
                   ->addField(
                       new CWidgetFieldTextBox('description', _('Description'))
                   );
           }
       }
  1. Abra views/widget.edit.php y agregue los componentes visuales del campo a la vista de configuración.

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Gauge chart widget form view.
        *
        * @var CView $this
        * @var array $data
        */
       
       $lefty_units = new CWidgetFieldSelectView($data['fields']['value_units']);
       $lefty_static_units = (new CWidgetFieldTextBoxView($data['fields']['value_static_units']))
           ->setPlaceholder(_('value'))
           ->setWidth(ZBX_TEXTAREA_TINY_WIDTH);
       
       (new CWidgetFormView($data))
           ->addField(
               (new CWidgetFieldMultiSelectItemView($data['fields']['itemid']))
                   ->setPopupParameter('numeric', true)
           )
           ->addFieldset(
               (new CWidgetFormFieldsetCollapsibleView(_('Advanced configuration')))
                   ->addField(
                       new CWidgetFieldColorView($data['fields']['chart_color'])
                   )
                   ->addField(
                       new CWidgetFieldNumericBoxView($data['fields']['value_min'])
                   )
                   ->addField(
                       new CWidgetFieldNumericBoxView($data['fields']['value_max'])
                   )
                   ->addItem([
                       $lefty_units->getLabel(),
                       (new CFormField([
                           $lefty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
                           $lefty_static_units->getView()
                       ]))
                   ])
                   ->addField(
                       new CWidgetFieldTextBoxView($data['fields']['description'])
                   )
           )
           ->show();

El método addField() de la clase CWidgetFormView toma una cadena de clase CSS como segundo parámetro.

  1. Regrese al panel, cambie al modo de edición y haga clic en el ícono de ajustes en el widget para abrir el formulario de configuración del widget. El formulario de configuración del widget ahora contiene una nueva sección expandible/contraíble Configuración avanzada.

  1. Expanda la sección Configuración avanzada para ver campos de configuración de widgets adicionales. Tenga en cuenta que el campo Color aún no tiene selector de color. Esto se debe a que el selector de color debe inicializarse con JavaScript, que se agregará en la siguiente sección: Agregar JavaScript al widget.

Agregar JavaScript al widget

En esta sección, aprenderá cómo agregar un gráfico de indicadores, elaborado con JavaScript, que muestra si el último valor es normal o demasiado alto/demasiado bajo.

  1. Cree un archivo widget.edit.js.php en el directorio views.

JavaScript será responsable de inicializar el selector de color en la vista de configuración.

ui/modules/lesson_gauge_chart/views/widget.edit.js.php

<?php
       
       use Modules\LessonGaugeChart\Widget;
       
       ?>
       
       window.widget_lesson_gauge_chart_form = new class {
       
           init({color_palette}) {
               this._unit_select = document.getElementById('value_units');
               this._unit_value = document.getElementById('value_static_units');
       
               this._unit_select.addEventListener('change', () => this.updateForm());
       
               colorPalette.setThemeColors(color_palette);
       
               for (const colorpicker of jQuery('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) {
                   jQuery(colorpicker).colorpicker();
               }
       
               const overlay = overlays_stack.getById('widget_properties');
       
               for (const event of ['overlay.reload', 'overlay.close']) {
                   overlay.$dialogue[0].addEventListener(event, () => { jQuery.colorpicker('hide'); });
               }
       
               this.updateForm();
           }
       
           updateForm() {
               this._unit_value.disabled = this._unit_select.value == <?= Widget::UNIT_AUTO ?>;
           }
       };
  1. Abra views/widget.edit.php y agregue el archivo widget.edit.js.php con JavaScript a la vista de configuración. Para hacer esto, use el método includeJsFile(). Para agregar JavaScript en línea, utilice el método addJavaScript().

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Gauge chart widget form view.
        *
        * @var CView $this
        * @var array $data
        */
       
       use Modules\LessonGaugeChart\Includes\WidgetForm;
       
       $lefty_units = new CWidgetFieldSelectView($data['fields']['value_units']);
       $lefty_static_units = (new CWidgetFieldTextBoxView($data['fields']['value_static_units']))
           ->setPlaceholder(_('value'))
           ->setWidth(ZBX_TEXTAREA_TINY_WIDTH);
       
       (new CWidgetFormView($data))
           ->addField(
               (new CWidgetFieldMultiSelectItemView($data['fields']['itemid']))
                   ->setPopupParameter('numeric', true)
           )
           ->addFieldset(
               (new CWidgetFormFieldsetCollapsibleView(_('Advanced configuration')))
                   ->addField(
                       new CWidgetFieldColorView($data['fields']['chart_color'])
                   )
                   ->addField(
                       new CWidgetFieldNumericBoxView($data['fields']['value_min'])
                   )
                   ->addField(
                       new CWidgetFieldNumericBoxView($data['fields']['value_max'])
                   )
                   ->addItem([
                       $lefty_units->getLabel(),
                       (new CFormField([
                           $lefty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
                           $lefty_static_units->getView()
                       ]))
                   ])
                   ->addField(
                       new CWidgetFieldTextBoxView($data['fields']['description'])
                   )
           )
           ->includeJsFile('widget.edit.js.php')
           ->addJavaScript('widget_lesson_gauge_chart_form.init('.json_encode([
               'color_palette' => WidgetForm::DEFAULT_COLOR_PALETTE
           ], JSON_THROW_ON_ERROR).');')
           ->show();
  1. Regrese al tablero, haga clic en el ícono de ajustes en el widget para abrir el formulario de configuración del widget. Ahora, expanda la sección Configuración avanzada para ver el selector de color inicializado. Complete los campos con valores y seleccione un color para el gráfico de indicadores.

  1. Haga clic en Aplicar en el formulario de configuración del widget. Luego haga clic en Guardar cambios en la esquina superior derecha para guardar el tablero.

  2. Abra actions/WidgetView.php y actualice el controlador.

La propiedad $this->fields_values ahora contiene los valores de todos los campos de Configuración avanzada. Finalice el controlador para permitir pasar la configuración y el valor de la métrica seleccionada a la vista del widget.

ui/modules/lesson_gauge_chart/actions/WidgetView.php

<?php
       
       namespace Modules\LessonGaugeChart\Actions;
       
       use API,
           CControllerDashboardWidgetView,
           CControllerResponseData;
       
       class WidgetView extends CControllerDashboardWidgetView {
       
           protected function doAction(): void {
               $db_items = API::Item()->get([
                   'output' => ['itemid', 'value_type', 'name', 'units'],
                   'itemids' => $this->fields_values['itemid'],
                   'webitems' => true,
                   'filter' => [
                       'value_type' => [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT]
                   ]
               ]);
       
               $history_value = null;
       
               if ($db_items) {
                   $item = $db_items[0];
       
                   $history = API::History()->get([
                       'output' => API_OUTPUT_EXTEND,
                       'itemids' => $item['itemid'],
                       'history' => $item['value_type'],
                       'sortfield' => 'clock',
                       'sortorder' => ZBX_SORT_DOWN,
                       'limit' => 1
                   ]);
       
                   if ($history) {
                       $history_value = convertUnitsRaw([
                           'value' => $history[0]['value'],
                           'units' => $item['units']
                       ]);
                   }
               }
       
               $this->setResponse(new CControllerResponseData([
                   'name' => $this->getInput('name', $this->widget->getName()),
                   'history' => $history_value,
                   'fields_values' => $this->fields_values,
                   'user' => [
                       'debug_mode' => $this->getDebugMode()
                   ]
               ]));
           }
       }
  1. Abra y modifique views/widget.view.php.

Debe crear un contenedor para el gráfico de indicadores, que dibujará en los siguientes pasos, y un contenedor para la descripción.

Para pasar valores a JavaScript como un objeto JSON, utilice el método setVar().

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
           ->addItem([
               (new CDiv())->addClass('chart'),
               $data['fields_values']['description']
                   ? (new CDiv($data['fields_values']['description']))->addClass('description')
                   : null
           ])
           ->setVar('history', $data['history'])
           ->setVar('fields_values', $data['fields_values'])
           ->show();
  1. Cree un nuevo directorio assets en el directorio lesson_gauge_chart. Este directorio se utilizará para almacenar JavaScript, CSS y potencialmente cualquier otro activo, como fuentes o imágenes.

  2. Para la vista de widget JavaScript, cree un directorio js en el directorio assets.

  3. Cree un archivo class.widget.js en el directorio assets/js.

Esta clase de widget de JavaScript ampliará la clase de JavaScript base de todos los widgets del tablero: CWidget.

El tablero se basa en una implementación correcta de un widget y comunica cualquier información relevante al widget mediante la llamada a los respectivos métodos de JavaScript. El tablero también espera que el widget genere eventos cuando se produzca alguna interacción. Por lo tanto, la clase CWidget contiene un conjunto de métodos con la implementación predeterminada del comportamiento del widget, que se puede personalizar extendiendo la clase.

En este caso, es necesaria cierta personalización; por lo tanto, se implementará una lógica personalizada para el siguiente comportamiento del widget:

  • inicialización del widget que es responsable de definir el estado inicial del widget (ver el método onInitialize());
  • mostrar el contenido del widget (es decir, dibujar el gráfico de indicadores) si el proceso de actualización del widget ha sido exitoso y sin errores (consulte el método processUpdateResponse(response) y los métodos relacionados _resizeChart() y _updatedChart())
  • cambiar el tamaño del widget (consulte el método onResize() y el método relacionado _resizeChart())

Para otros aspectos del widget del gráfico de indicadores, se utilizará la implementación predeterminada para el comportamiento del widget. Para obtener más información sobre los métodos JavaScript de la clase CWidget, consulte: JavaScript.

Dado que este JavaScript es necesario para la vista del widget, debe cargarse con la página del tablero. Para habilitar la carga de JavaScript, deberá actualizar los parámetros assets/js y js_class en el archivo manifest.json como se muestra en el paso 10.

ui/modules/lesson_gauge_chart/assets/js/class.widget.js

class WidgetLessonGaugeChart extends CWidget {
       
           static UNIT_AUTO = 0;
           static UNIT_STATIC = 1;
       
           onInitialize() {
               super.onInitialize();
       
               this._refresh_frame = null;
               this._chart_container = null;
               this._canvas = null;
               this._chart_color = null;
               this._min = null;
               this._max = null;
               this._value = null;
               this._last_value = null;
               this._units = '';
           }
       
           processUpdateResponse(response) {
               if (response.history === null) {
                   this._value = null;
                   this._units = '';
               }
               else {
                   this._value = Number(response.history.value);
                   this._units = response.fields_values.value_units == WidgetLessonGaugeChart.UNIT_AUTO
                       ? response.history.units
                       : response.fields_values.value_static_units;
               }
       
               this._chart_color = response.fields_values.chart_color;
               this._min = Number(response.fields_values.value_min);
               this._max = Number(response.fields_values.value_max);
       
               super.processUpdateResponse(response);
           }
       
           setContents(response) {
               if (this._canvas === null) {
                   super.setContents(response);
       
                   this._chart_container = this._body.querySelector('.chart');
                   this._chart_container.style.height =
                       `${this._getContentsSize().height - this._body.querySelector('.description').clientHeight}px`;
                   this._canvas = document.createElement('canvas');
       
                   this._chart_container.appendChild(this._canvas);
       
                   this._resizeChart();
               }
       
               this._updatedChart();
           }
       
           onResize() {
               super.onResize();
       
               if (this._state === WIDGET_STATE_ACTIVE) {
                   this._resizeChart();
               }
           }
       
           _resizeChart() {
               const ctx = this._canvas.getContext('2d');
               const dpr = window.devicePixelRatio;
       
               this._canvas.style.display = 'none';
               const size = Math.min(this._chart_container.offsetWidth, this._chart_container.offsetHeight);
               this._canvas.style.display = '';
       
               this._canvas.width = size * dpr;
               this._canvas.height = size * dpr;
       
               ctx.scale(dpr, dpr);
       
               this._canvas.style.width = `${size}px`;
               this._canvas.style.height = `${size}px`;
       
               this._refresh_frame = null;
       
               this._updatedChart();
           }
       
           _updatedChart() {
               if (this._last_value === null) {
                   this._last_value = this._min;
               }
       
               const start_time = Date.now();
               const end_time = start_time + 400;
       
               const animate = () => {
                   const time = Date.now();
       
                   if (time <= end_time) {
                       const progress = (time - start_time) / (end_time - start_time);
                       const smooth_progress = 0.5 + Math.sin(Math.PI * (progress - 0.5)) / 2;
                       let value = this._value !== null ? this._value : this._min;
                       value = (this._last_value + (value - this._last_value) * smooth_progress - this._min) / (this._max - this._min);
       
                       const ctx = this._canvas.getContext('2d');
                       const size = this._canvas.width;
                       const char_weight = size / 12;
                       const char_shadow = 3;
                       const char_x = size / 2;
                       const char_y = size / 2;
                       const char_radius = (size - char_weight) / 2 - char_shadow;
       
                       const font_ratio = 32 / 100;
       
                       ctx.clearRect(0, 0, size, size);
       
                       ctx.beginPath();
                       ctx.shadowBlur = char_shadow;
                       ctx.shadowColor = '#bbb';
                       ctx.strokeStyle = '#eee';
                       ctx.lineWidth = char_weight;
                       ctx.lineCap = 'round';
                       ctx.arc(char_x, char_y, char_radius, Math.PI * 0.749, Math.PI * 2.251, false);
                       ctx.stroke();
       
                       ctx.beginPath();
                       ctx.strokeStyle = `#${this._chart_color}`;
                       ctx.lineWidth = char_weight - 2;
                       ctx.lineCap = 'round';
                       ctx.arc(char_x, char_y, char_radius, Math.PI * 0.75,
                           Math.PI * (0.75 + (1.5 * Math.min(1, Math.max(0, value)))), false
                           );
                       ctx.stroke();
       
                       ctx.shadowBlur = 2;
                       ctx.fillStyle = '#1f2c33';
                       ctx.font = `${(char_radius * font_ratio)|0}px Arial`;
                       ctx.textAlign = 'center';
                       ctx.textBaseline = 'middle';
                       ctx.fillText(`${this._value !== null ? this._value : t('No data')}${this._units}`,
                           char_x, char_y, size - char_shadow * 4 - char_weight * 2
                       );
       
                       ctx.fillStyle = '#768d99';
                       ctx.font = `${(char_radius * font_ratio * .5)|0}px Arial`;
                       ctx.textBaseline = 'top';
       
                       ctx.textAlign = 'left';
                       ctx.fillText(`${this._min}${this._min != '' ? this._units : ''}`,
                           char_weight * .75, size - char_weight * 1.25, size / 2 - char_weight
                       );
       
                       ctx.textAlign = 'right';
                       ctx.fillText(`${this._max}${this._max != '' ? this._units : ''}`,
                           size - char_weight * .75, size - char_weight * 1.25, size / 2 - char_weight
                       );
       
                       requestAnimationFrame(animate);
                   }
                   else {
                       this._last_value = this._value;
                   }
               };
       
               requestAnimationFrame(animate);
           }
       }
  1. Abra manifest.json y agregue:
  • nombre del archivo (class.widget.js) de la matriz en la sección assets/js;
  • nombre de la clase (WidgetLessonGaugeChart) al parámetro js_class en la sección widget.

La clase WidgetLessonGaugeChart ahora se cargará automáticamente con el tablero.

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.0",
           "author": "Zabbix",
           "actions": {
               "widget.lesson_gauge_chart.view": {
                   "class": "WidgetView"
               }
           },
           "widget": {
               "js_class": "WidgetLessonGaugeChart"
           },
           "assets": {
               "js": ["class.widget.js"]
           }
       }

Agregar estilos CSS al widget

En esta sección aprenderá cómo agregar estilos CSS personalizados para que el widget sea más atractivo.

  1. Para estilos de widgets, cree un nuevo directorio css en el directorio assets.

  2. Cree un archivo widget.css en el directorio assets/css. Para aplicar estilo a los elementos del widget, utilice el selector div.dashboard-widget-{widget id}. Para configurar CSS para todo el widget, use el selector form.dashboard-widget-{widget id}

ui/modules/lesson_gauge_chart/assets/css/widget.css

div.dashboard-widget-lesson_gauge_chart {
           display: grid;
           grid-template-rows: 1fr;
           padding: 0;
       }
       
       div.dashboard-widget-lesson_gauge_chart .chart {
           display: grid;
           align-items: center;
           justify-items: center;
       }
       
       div.dashboard-widget-lesson_gauge_chart .chart canvas {
           background: white;
       }
       
       div.dashboard-widget-lesson_gauge_chart .description {
           padding-bottom: 8px;
           font-size: 1.750em;
           line-height: 1.2;
           text-align: center;
       }
       
       .dashboard-grid-widget-hidden-header div.dashboard-widget-lesson_gauge_chart .chart {
           margin-top: 8px;
       }
  1. Abra manifest.json y agregue el nombre del archivo CSS (widget.css) a la matriz en la sección assets/css. Esto permitirá que los estilos CSS definidos en widget.css se carguen con la página del tablero.

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.0",
           "author": "Zabbix",
           "actions": {
               "widget.lesson_gauge_chart.view": {
                   "class": "WidgetView"
               }
           },
           "widget": {
               "js_class": "WidgetLessonGaugeChart"
           },
           "assets": {
               "css": ["widget.css"],
               "js": ["class.widget.js"]
           }
       }
  1. Actualice la página del tablero para ver la versión finalizada del widget.