field = $field; } public function getView(): CList { $view = (new CList()) ->setId('data_sets') ->addClass(ZBX_STYLE_SORTABLE_LIST); $values = $this->field->getValue(); if (!$values) { $values[] = CWidgetFieldGraphDataSet::getDefaults(); } // Get item names for single item datasets. $itemids = array_merge(...array_column($values, 'itemids')); $item_names = []; if ($itemids) { $item_names = CWidgetFieldGraphDataSet::getItemNames($itemids); } foreach ($values as $i => $value) { if ($value['dataset_type'] == CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM) { $value['item_names'] = $item_names; } $view->addItem( $this->getGraphDataSetLayout($value, $value['dataset_type'], $i == 0, $i) ); } return $view; } public function getFooterView(): CList { return (new CList()) ->addClass(ZBX_STYLE_BTN_SPLIT) ->addItem( (new CSimpleButton(_('Add new data set'))) ->setId('dataset-add') ->addClass(ZBX_STYLE_BTN_ALT) ->addClass(ZBX_ICON_PLUS_SMALL) ) ->addItem( (new CSimpleButton()) ->setId('dataset-menu') ->addClass(ZBX_STYLE_BTN_ALT) ->addClass(ZBX_ICON_CHEVRON_DOWN_SMALL) ); } public function getTemplates(): array { $value = ['color' => '#{color}'] + CWidgetFieldGraphDataSet::getDefaults(); return [ new CTemplateTag('dataset-pattern-item-tmpl', $this->getGraphDataSetLayout($value, CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM, true) ), new CTemplateTag('dataset-single-item-tmpl', $this->getGraphDataSetLayout($value, CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM, true) ), new CTemplateTag('dataset-item-row-tmpl', $this->getItemRowTemplate()) ]; } private function getGraphDataSetLayout(array $value, int $dataset_type, bool $is_opened, $row_num = '#{rowNum}'): CListItem { $field_name = $this->field->getName(); $dataset_head = [ new CDiv( (new CButtonIcon(ZBX_ICON_CHEVRON_UP))->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_TOGGLE) ), new CVar($field_name.'['.$row_num.'][dataset_type]', $dataset_type, '') ]; if ($dataset_type == CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM) { if ($this->field->isTemplateDashboard()) { $host_pattern_field = null; $item_pattern_field = (new CPatternSelect([ 'name' => $field_name.'['.$row_num.'][items][]', 'object_name' => 'items', 'data' => $value['items'], 'placeholder' => _('item pattern'), 'wildcard_allowed' => 1, 'popup' => [ 'parameters' => [ 'srctbl' => 'items', 'srcfld1' => 'name', 'hostid' => $this->field->getTemplateId(), 'hide_host_filter' => true, 'numeric' => 1, 'dstfrm' => $this->form_name, 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][items][]') ] ], 'add_post_js' => false ]))->addClass('js-items-multiselect'); } else { $host_pattern_field = (new CPatternSelect([ 'name' => $field_name.'['.$row_num.'][hosts][]', 'object_name' => 'hosts', 'data' => $value['hosts'], 'placeholder' => _('host pattern'), 'wildcard_allowed' => 1, 'popup' => [ 'parameters' => [ 'srctbl' => 'hosts', 'srcfld1' => 'host', 'dstfrm' => $this->form_name, 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][hosts][]') ] ], 'add_post_js' => false ]))->addClass('js-hosts-multiselect'); $item_pattern_field = (new CPatternSelect([ 'name' => $field_name.'['.$row_num.'][items][]', 'object_name' => 'items', 'data' => $value['items'], 'placeholder' => _('item pattern'), 'wildcard_allowed' => 1, 'popup' => [ 'parameters' => [ 'srctbl' => 'items', 'srcfld1' => 'name', 'real_hosts' => 1, 'numeric' => 1, 'dstfrm' => $this->form_name, 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][items][]') ], 'filter_preselect' => [ 'id' => $host_pattern_field->getId(), 'submit_as' => 'host_pattern', 'submit_parameters' => [ 'host_pattern_wildcard_allowed' => 1, 'host_pattern_multiple' => 1 ], 'multiple' => true ] ], 'autosuggest' => [ 'filter_preselect' => [ 'id' => $host_pattern_field->getId(), 'submit_as' => 'host_pattern', 'submit_parameters' => [ 'host_pattern_wildcard_allowed' => 1, 'host_pattern_multiple' => 1 ], 'multiple' => true ] ], 'add_post_js' => false ]))->addClass('js-items-multiselect'); } $dataset_head = array_merge($dataset_head, [ (new CColor($field_name.'['.$row_num.'][color]', $value['color'])) ->appendColorPickerJs(false), $host_pattern_field, $item_pattern_field ]); } else { $item_rows = []; foreach ($value['itemids'] as $i => $itemid) { $item_name = array_key_exists($itemid, $value['item_names']) ? $value['item_names'][$itemid] : ''; $item_rows[] = $this->getItemRowTemplate($row_num, ($i + 1), $itemid, $item_name, $value['color'][$i]); } $empty_msg_block = (new CDiv(_('No item selected.')))->addClass('no-items-message'); $items_list = (new CTable()) ->addClass('single-item-table') ->setAttribute('data-set', $row_num) ->setColumns([ (new CTableColumn())->addClass('table-col-handle'), (new CTableColumn())->addClass('table-col-color'), (new CTableColumn())->addClass('table-col-no'), (new CTableColumn(_('Name')))->addClass('table-col-name'), (new CTableColumn(_('Action')))->addClass('table-col-action') ]) ->addItem([ $item_rows, (new CTag('tfoot', true)) ->addItem( (new CCol( (new CList()) ->addClass(ZBX_STYLE_INLINE_FILTER_FOOTER) ->addItem( (new CButtonLink(_('Add')))->addClass('js-add') ) ))->setColSpan(5) ) ]); $dataset_head = array_merge($dataset_head, [ (new CDiv([$empty_msg_block, $items_list]))->addClass('items-list table-forms-separator') ]); } $dataset_head[] = (new CDiv( (new CButtonIcon(ZBX_ICON_REMOVE_SMALLER, _('Delete')))->addClass('js-remove') ))->addClass('list-item-actions'); return (new CListItem([ (new CDiv()) ->addClass(ZBX_STYLE_DRAG_ICON) ->addClass(ZBX_STYLE_SORTABLE_DRAG_HANDLE) ->addClass('js-main-drag-icon'), (new CLabel('')) ->addClass(ZBX_STYLE_SORTABLE_DRAG_HANDLE) ->addClass('js-dataset-label'), (new CDiv()) ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_HEAD) ->addClass('dataset-head') ->addItem($dataset_head), (new CDiv()) ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_BODY) ->addClass('dataset-body') ->addItem([ (new CFormGrid()) ->addItem([ new CLabel(_('Draw')), new CFormField( (new CRadioButtonList($field_name.'['.$row_num.'][type]', (int) $value['type'])) ->addClass('js-type') ->addValue(_('Line'), SVG_GRAPH_TYPE_LINE) ->addValue(_('Points'), SVG_GRAPH_TYPE_POINTS) ->addValue(_('Staircase'), SVG_GRAPH_TYPE_STAIRCASE) ->addValue(_('Bar'), SVG_GRAPH_TYPE_BAR) ->setModern() ) ]) ->addItem([ new CLabel(_('Stacked'), $field_name.'['.$row_num.'][stacked]'), new CFormField([ (new CVar($field_name.'['.$row_num.'][stacked]', '0'))->removeId(), (new CCheckBox($field_name.'['.$row_num.'][stacked]')) ->addClass('js-stacked') ->setChecked((bool) $value['stacked']) ->setEnabled($value['type'] != SVG_GRAPH_TYPE_POINTS) ]) ]) ->addItem([ new CLabel(_('Width')), new CFormField( (new CRangeControl($field_name.'['.$row_num.'][width]', (int) $value['width'])) ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) ->setStep(1) ->setMin(0) ->setMax(10) ) ]) ->addItem([ new CLabel(_('Point size')), new CFormField( (new CRangeControl($field_name.'['.$row_num.'][pointsize]', (int) $value['pointsize'])) ->setEnabled($value['type'] == SVG_GRAPH_TYPE_POINTS) ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) ->setStep(1) ->setMin(1) ->setMax(10) ) ]) ->addItem([ new CLabel(_('Transparency')), new CFormField( (new CRangeControl($field_name.'['.$row_num.'][transparency]', (int) $value['transparency']) ) ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) ->setStep(1) ->setMin(0) ->setMax(10) ) ]) ->addItem([ new CLabel(_('Fill')), new CFormField( (new CRangeControl($field_name.'['.$row_num.'][fill]', (int) $value['fill'])) ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) ->setStep(1) ->setMin(0) ->setMax(10) ) ]) ->addItem([ new CLabel(_('Missing data')), new CFormField( (new CRadioButtonList($field_name.'['.$row_num.'][missingdatafunc]', (int) $value['missingdatafunc']) ) ->addValue(_('None'), SVG_GRAPH_MISSING_DATA_NONE) ->addValue(_x('Connected', 'missing data function'), SVG_GRAPH_MISSING_DATA_CONNECTED ) ->addValue(_x('Treat as 0', 'missing data function'), SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO ) ->addValue(_x('Last known', 'missing data function'), SVG_GRAPH_MISSING_DATA_LAST_KNOWN ) ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) ->setModern() ) ]), (new CFormGrid()) ->addItem([ new CLabel(_('Y-axis')), new CFormField( (new CRadioButtonList($field_name.'['.$row_num.'][axisy]', (int) $value['axisy'])) ->addValue(_('Left'), GRAPH_YAXIS_SIDE_LEFT) ->addValue(_('Right'), GRAPH_YAXIS_SIDE_RIGHT) ->setModern() ) ]) ->addItem([ new CLabel(_('Time shift'), $field_name.'['.$row_num.'][timeshift]'), new CFormField( (new CTextBox($field_name.'['.$row_num.'][timeshift]', $value['timeshift'])) ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) ->setAttribute('placeholder', _('none')) ) ]) ->addItem([ new CLabel(_('Aggregation function'), 'label-'.$field_name.'_'.$row_num.'_aggregate_function' ), new CFormField( (new CSelect($field_name.'['.$row_num.'][aggregate_function]')) ->setId($field_name.'_'.$row_num.'_aggregate_function') ->setFocusableElementId('label-'.$field_name.'_'.$row_num.'_aggregate_function') ->setValue((int) $value['aggregate_function']) ->addOptions(CSelect::createOptionsFromArray([ AGGREGATE_NONE => graph_item_aggr_fnc2str(AGGREGATE_NONE), AGGREGATE_MIN => graph_item_aggr_fnc2str(AGGREGATE_MIN), AGGREGATE_MAX => graph_item_aggr_fnc2str(AGGREGATE_MAX), AGGREGATE_AVG => graph_item_aggr_fnc2str(AGGREGATE_AVG), AGGREGATE_COUNT => graph_item_aggr_fnc2str(AGGREGATE_COUNT), AGGREGATE_SUM => graph_item_aggr_fnc2str(AGGREGATE_SUM), AGGREGATE_FIRST => graph_item_aggr_fnc2str(AGGREGATE_FIRST), AGGREGATE_LAST => graph_item_aggr_fnc2str(AGGREGATE_LAST) ])) ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) ) ]) ->addItem([ new CLabel(_('Aggregation interval'), $field_name.'['.$row_num.'][aggregate_interval]'), new CFormField( (new CTextBox($field_name.'['.$row_num.'][aggregate_interval]', $value['aggregate_interval'] )) ->setEnabled($value['aggregate_function'] != AGGREGATE_NONE) ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) ->setAttribute('placeholder', GRAPH_AGGREGATE_DEFAULT_INTERVAL) ) ]) ->addItem([ new CLabel(_('Aggregate')), new CFormField( (new CRadioButtonList($field_name.'['.$row_num.'][aggregate_grouping]', (int) $value['aggregate_grouping']) ) ->addValue(_('Each item'), GRAPH_AGGREGATE_BY_ITEM) ->addValue(_('Data set'), GRAPH_AGGREGATE_BY_DATASET) ->setEnabled($value['aggregate_function'] != AGGREGATE_NONE) ->setModern() ) ]) ->addItem([ new CLabel(_('Approximation'), 'label-'.$field_name.'_'.$row_num.'_approximation'), new CFormField( (new CSelect($field_name.'['.$row_num.'][approximation]')) ->setId($field_name.'_'.$row_num.'_approximation') ->setFocusableElementId('label-'.$field_name.'_'.$row_num.'_approximation') ->setValue((int) $value['approximation']) ->addOptions(CSelect::createOptionsFromArray([ APPROXIMATION_ALL => [ 'label' => _('all'), 'disabled' => $value['type'] != SVG_GRAPH_TYPE_LINE || $value['stacked'] ], APPROXIMATION_MIN => _('min'), APPROXIMATION_AVG => _('avg'), APPROXIMATION_MAX => _('max') ])) ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) ) ]) ->addItem([ new CLabel([ _('Data set label'), makeHelpIcon(_('Also used as legend label for aggregated data sets.')) ], $field_name.'_'.$row_num.'_data_set_label'), new CFormField( (new CTextBox($field_name.'['.$row_num.'][data_set_label]', $value['data_set_label'])) ->setId($field_name.'_'.$row_num.'_data_set_label') ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) ) ]) ]) ])) ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM) ->addClass(ZBX_STYLE_SORTABLE_ITEM) ->addClass($is_opened ? ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED : ZBX_STYLE_LIST_ACCORDION_ITEM_CLOSED) ->setAttribute('data-set', $row_num) ->setAttribute('data-type', $dataset_type); } private function getItemRowTemplate($ds_num = '#{dsNum}', $row_num = '#{rowNum}', $itemid = '#{itemid}', $name = '#{name}', $color = '#{color}'): CRow { return (new CRow([ (new CCol((new CDiv())->addClass(ZBX_STYLE_DRAG_ICON))) ->addClass('table-col-handle') ->addClass(ZBX_STYLE_TD_DRAG_ICON), (new CCol( (new CColor($this->field->getName().'['.$ds_num.'][color][]', $color, 'items_'.$ds_num.'_'.$row_num.'_color' ))->appendColorPickerJs(false) ))->addClass('table-col-color'), (new CCol(new CSpan($row_num.':')))->addClass('table-col-no'), (new CCol( (new CLink($name)) ->setId('items_'.$ds_num.'_'.$row_num.'_name') ->addClass('js-click-expend') ))->addClass('table-col-name'), (new CCol([ (new CButton('button', _('Remove'))) ->addClass(ZBX_STYLE_BTN_LINK) ->addClass('element-table-remove'), new CVar($this->field->getName().'['.$ds_num.'][itemids][]', $itemid, 'items_'.$ds_num.'_'.$row_num.'_input' ) ])) ->addClass('table-col-action') ->addClass(ZBX_STYLE_NOWRAP) ])) ->addClass(ZBX_STYLE_SORTABLE) ->addClass('single-item-table-row'); } }