Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorAlexander Shubin <aleksandrs.subins@zabbix.com>2022-07-12 08:43:22 +0300
committerAlexander Shubin <aleksandrs.subins@zabbix.com>2022-07-12 08:43:22 +0300
commitf5d9f3f7f582f547d0e703a35c91ec88e5b02ff6 (patch)
tree6f370c048cfd4ae7cbe2a313718e19537f533a8a /ui
parentbf2ee5b9cc17afa80f960e2931f3cc4251bbd98a (diff)
parentb3b292fb126dd85d451db9d1555b524c767b25d8 (diff)
.......... [ZBX-20908] updated to latest release/6.0; no conflicts
Diffstat (limited to 'ui')
-rw-r--r--ui/app/controllers/CControllerHostEdit.php5
-rw-r--r--ui/app/controllers/CControllerWidgetGraphView.php53
-rw-r--r--ui/app/partials/configuration.host.edit.html.php1
-rw-r--r--ui/app/partials/monitoring.problem.filter.php1
-rw-r--r--ui/app/views/administration.user.token.edit.php4
-rw-r--r--ui/app/views/js/monitoring.charts.view.js.php28
-rw-r--r--ui/app/views/js/monitoring.problem.view.js.php2
-rw-r--r--ui/app/views/js/monitoring.widget.navtreeitem.edit.js.php48
-rw-r--r--ui/app/views/js/popup.host.edit.js.php8
-rw-r--r--ui/app/views/monitoring.widget.navtreeitem.edit.php26
-rw-r--r--ui/app/views/popup.host.edit.php7
-rw-r--r--ui/assets/styles/blue-theme.css104
-rw-r--r--ui/assets/styles/dark-theme.css104
-rw-r--r--ui/assets/styles/hc-dark.css109
-rw-r--r--ui/assets/styles/hc-light.css109
-rw-r--r--ui/graphs.php8
-rw-r--r--ui/include/classes/graphdraw/CLineGraphDraw.php22
-rw-r--r--ui/include/classes/html/CTabView.php9
-rw-r--r--ui/include/classes/import/CConfigurationImport.php14
-rw-r--r--ui/include/views/configuration.graph.edit.php6
-rw-r--r--ui/include/views/js/configuration.graph.edit.js.php6
-rw-r--r--ui/js/class.tab-indicators.js2
-rw-r--r--ui/js/widgets/class.widget.js4
-rw-r--r--ui/js/widgets/class.widget.navtree.js3
-rw-r--r--ui/tests/integration/IntegrationTests.php2
-rw-r--r--ui/tests/integration/testAlertingForServices.php614
-rw-r--r--ui/tests/selenium/common/testSystemInformation.php6
-rw-r--r--ui/tests/selenium/testFormAdministrationAuthenticationLdap.php42
28 files changed, 985 insertions, 362 deletions
diff --git a/ui/app/controllers/CControllerHostEdit.php b/ui/app/controllers/CControllerHostEdit.php
index 51b2c6e58c0..886545c4a22 100644
--- a/ui/app/controllers/CControllerHostEdit.php
+++ b/ui/app/controllers/CControllerHostEdit.php
@@ -133,7 +133,8 @@ class CControllerHostEdit extends CController {
if ($this->hasInput('full_clone') || $this->hasInput('clone')) {
$clone_hostid = $this->getInput('hostid');
$this->host = ['hostid' => null];
- } else {
+ }
+ else {
$hosts = API::Host()->get([
'output' => ['hostid', 'host', 'name', 'status', 'description', 'proxy_hostid', 'ipmi_authtype',
'ipmi_privilege', 'ipmi_username', 'ipmi_password', 'tls_connect', 'tls_accept', 'tls_issuer',
@@ -352,7 +353,7 @@ class CControllerHostEdit extends CController {
*/
protected function extendDiscoveryRule(?array &$editable_discovery_rule): void {
$editable_discovery_rule = $this->host['discoveryRule']
- ? API::DiscoveryRule([
+ ? API::DiscoveryRule()->get([
'output' => [],
'itemids' => array_column($this->host['discoveryRule'], 'itemid'),
'editable' => true,
diff --git a/ui/app/controllers/CControllerWidgetGraphView.php b/ui/app/controllers/CControllerWidgetGraphView.php
index 82ac42643e9..ea69a05caa7 100644
--- a/ui/app/controllers/CControllerWidgetGraphView.php
+++ b/ui/app/controllers/CControllerWidgetGraphView.php
@@ -92,7 +92,7 @@ class CControllerWidgetGraphView extends CControllerWidget {
$is_dynamic_item = ($is_template_dashboard || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM);
// Replace graph item by particular host item if dynamic items are used.
- if ($is_dynamic_item && $dynamic_hostid && $resourceid) {
+ if ($is_dynamic_item && $dynamic_hostid != 0 && $resourceid) {
// Find same simple-graph item in selected $dynamic_hostid host.
if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) {
$src_items = API::Item()->get([
@@ -218,7 +218,7 @@ class CControllerWidgetGraphView extends CControllerWidget {
// get graph, used below
$graph = API::Graph()->get([
'output' => API_OUTPUT_EXTEND,
- 'selectHosts' => ['name'],
+ 'selectHosts' => ['hostid', 'name'],
'graphids' => $resourceid,
'expandName' => true
]);
@@ -267,7 +267,7 @@ class CControllerWidgetGraphView extends CControllerWidget {
? $graph['hosts'][0]['name'].NAME_DELIMITER.$graph['name']
: $graph['name'];
- if ($is_dynamic_item && $dynamic_hostid && $resourceid) {
+ if ($is_dynamic_item && $dynamic_hostid != 0 && $resourceid) {
if ($graph['graphtype'] == GRAPH_TYPE_PIE || $graph['graphtype'] == GRAPH_TYPE_EXPLODED) {
$graph_src = (new CUrl('chart7.php'))
->setArgument('name', $host['name'].NAME_DELIMITER.$graph['name'])
@@ -341,30 +341,31 @@ class CControllerWidgetGraphView extends CControllerWidget {
}
else {
if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) {
- if ($is_dynamic_item && $dynamic_hostid) {
- $template_graphs = API::Graph()->get([
- 'output' => ['name'],
- 'graphids' => [$resourceid]
- ]);
-
- $resourceid = null;
-
- if ($template_graphs) {
- $host_graphs = API::Graph()->get([
- 'output' => ['graphid'],
- 'hostids' => [$dynamic_hostid],
- 'filter' => [
- 'name' => $template_graphs[0]['name']
- ]
- ]);
-
- if ($host_graphs) {
- $resourceid = $host_graphs[0]['graphid'];
- }
- }
+ $has_host_graph = $is_dynamic_item && $dynamic_hostid != 0
+ ? (bool) API::Graph()->get([
+ 'output' => [],
+ 'hostids' => [$dynamic_hostid],
+ 'filter' => [
+ 'name' => $graph['name']
+ ]
+ ])
+ : true;
+
+ if ($has_host_graph) {
+ $graph_url = $this->checkAccess(CRoleHelper::UI_MONITORING_HOSTS)
+ ? (new CUrl('zabbix.php'))
+ ->setArgument('action', 'charts.view')
+ ->setArgument('filter_hostids', [$graph['hosts'][0]['hostid']])
+ ->setArgument('filter_name', $graph['name'])
+ ->setArgument('filter_show', GRAPH_FILTER_HOST)
+ ->setArgument('filter_set', '1')
+ ->setArgument('from', '')
+ ->setArgument('to', '')
+ : null;
+ }
+ else {
+ $graph_url = null;
}
-
- $graph_url = null;
}
else {
$graph_url = $this->checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA)
diff --git a/ui/app/partials/configuration.host.edit.html.php b/ui/app/partials/configuration.host.edit.html.php
index 19f5cc1b093..735960f80bb 100644
--- a/ui/app/partials/configuration.host.edit.html.php
+++ b/ui/app/partials/configuration.host.edit.html.php
@@ -556,6 +556,5 @@ if (array_key_exists('buttons', $data)) {
}
$host_form
- ->addItem($data['warning'])
->addItem($tabs)
->show();
diff --git a/ui/app/partials/monitoring.problem.filter.php b/ui/app/partials/monitoring.problem.filter.php
index e0627962b8c..24d36d8bf48 100644
--- a/ui/app/partials/monitoring.problem.filter.php
+++ b/ui/app/partials/monitoring.problem.filter.php
@@ -118,7 +118,6 @@ $left_column
->setChecked($data['age_state'] == 1)
->setUncheckedValue(0)
->setId('age_state_#{uniqid}'),
- (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
$filter_age,
(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
_('days')
diff --git a/ui/app/views/administration.user.token.edit.php b/ui/app/views/administration.user.token.edit.php
index 51682ff5314..12f7cbc3c70 100644
--- a/ui/app/views/administration.user.token.edit.php
+++ b/ui/app/views/administration.user.token.edit.php
@@ -64,7 +64,8 @@ $token_from_list = (new CFormList())
(new CDateSelector('expires_at', $data['expires_at']))
->setDateFormat(ZBX_FULL_DATE_TIME)
->setPlaceholder(_('YYYY-MM-DD hh:mm:ss'))
- ->setAriaRequired()
+ ->setAriaRequired(),
+ 'expires-at-row'
)
->addRow(_('Enabled'),
(new CCheckBox('status', ZBX_AUTH_TOKEN_ENABLED))
@@ -72,7 +73,6 @@ $token_from_list = (new CFormList())
->setUncheckedValue(ZBX_AUTH_TOKEN_DISABLED)
);
-
$token_view = (new CTabView())->addTab('token', '', $token_from_list);
$cancel_button = (new CRedirectButton(_('Cancel'), (new CUrl('zabbix.php'))
->setArgument('action', 'user.token.list')
diff --git a/ui/app/views/js/monitoring.charts.view.js.php b/ui/app/views/js/monitoring.charts.view.js.php
index 878143611a6..7e1ec9d4b96 100644
--- a/ui/app/views/js/monitoring.charts.view.js.php
+++ b/ui/app/views/js/monitoring.charts.view.js.php
@@ -61,7 +61,7 @@
this._app = new ChartList( $('#charts'), this._data.timeline, this._data.config, this._container);
this._app.setCharts(this._data.charts);
- this._app.onResize();
+ this._app.refresh();
this._resize_observer = new ResizeObserver(this._app.onResize.bind(this._app));
this._resize_observer.observe(this._container);
@@ -246,27 +246,6 @@
};
/**
- * Start or pause timeout based Chart refresh.
- *
- * @param {number} seconds Seconds to wait before reschedule. Zero seconds will pause schedule.
- * @param {number} delay_loading (optional) Add "loading indicator" only when request exceeds delay.
- */
- Chart.prototype.scheduleRefresh = function(seconds, delay_loading) {
- if (this._timeoutid) {
- clearTimeout(this._timeoutid);
- }
-
- if (!seconds) {
- return;
- }
-
- this.refresh(delay_loading)
- .finally(_ => {
- this._timeoutid = setTimeout(() => this.scheduleRefresh(seconds, 0), seconds * 1000);
- });
- };
-
- /**
* @param {jQuery} $el A container where charts are maintained.
* @param {object} timeline Time control object.
* @param {object} config
@@ -372,10 +351,6 @@
clearTimeout(this._timeoutid);
}
- for (const chart of this.charts) {
- chart.scheduleRefresh(0);
- }
-
this.updateListAndCharts(delay_loading)
.finally(_ => {
if (refresh_interval) {
@@ -430,7 +405,6 @@
if (this._prev_width === undefined) {
this._prev_width = width;
- this.updateCharts();
return;
}
diff --git a/ui/app/views/js/monitoring.problem.view.js.php b/ui/app/views/js/monitoring.problem.view.js.php
index ed6cc5fa9a1..02756407b50 100644
--- a/ui/app/views/js/monitoring.problem.view.js.php
+++ b/ui/app/views/js/monitoring.problem.view.js.php
@@ -157,7 +157,7 @@
refreshResults() {
const url = new Curl();
const screen = window.flickerfreeScreen.screens['problem'];
- const data = $.extend(this.filter_defaults, this.global_timerange, url.getArgumentsObject());
+ const data = Object.assign({}, this.filter_defaults, this.global_timerange, url.getArgumentsObject());
data.inventory = data.inventory
? data.inventory.filter(inventory => 'value' in inventory && inventory.value !== '')
diff --git a/ui/app/views/js/monitoring.widget.navtreeitem.edit.js.php b/ui/app/views/js/monitoring.widget.navtreeitem.edit.js.php
new file mode 100644
index 00000000000..fd68a9c09a0
--- /dev/null
+++ b/ui/app/views/js/monitoring.widget.navtreeitem.edit.js.php
@@ -0,0 +1,48 @@
+<?php declare(strict_types = 0);
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** 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; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+
+/**
+ * @var CView $this
+ */
+?>
+
+window.navtreeitem_edit_popup = new class {
+ init() {
+ jQuery('#sysmapname').on('change', (e) => {
+ const name_input = document.getElementById('name');
+
+ if (name_input.value === '') {
+ name_input.value = e.target.value;
+ }
+ });
+
+ document.getElementById('select').addEventListener('click', () => {
+ return PopUp('popup.generic', {
+ srctbl: 'sysmaps',
+ srcfld1: 'sysmapid',
+ srcfld2: 'name',
+ dstfrm: 'widget_dialogue_form',
+ dstfld1: 'sysmapid',
+ dstfld2: 'sysmapname'
+ }, {dialogue_class: 'modal-popup-generic'});
+ });
+ }
+};
diff --git a/ui/app/views/js/popup.host.edit.js.php b/ui/app/views/js/popup.host.edit.js.php
index 8557d0bf86c..c22ff8ab198 100644
--- a/ui/app/views/js/popup.host.edit.js.php
+++ b/ui/app/views/js/popup.host.edit.js.php
@@ -29,7 +29,7 @@ window.host_edit_popup = {
dialogue: null,
form: null,
- init({popup_url, form_name, host_interfaces, host_is_discovered}) {
+ init({popup_url, form_name, host_interfaces, host_is_discovered, warning}) {
this.overlay = overlays_stack.getById('host_edit');
this.dialogue = this.overlay.$dialogue[0];
this.form = this.overlay.$dialogue.$body[0].querySelector('form');
@@ -39,6 +39,12 @@ window.host_edit_popup = {
history.replaceState({}, '', popup_url);
host_edit.init({form_name, host_interfaces, host_is_discovered});
+
+ if (warning !== null) {
+ const message_box = makeMessageBox('warning', warning, null, true, false)[0];
+
+ this.form.parentNode.insertBefore(message_box, this.form);
+ }
},
addEventListeners() {
diff --git a/ui/app/views/monitoring.widget.navtreeitem.edit.php b/ui/app/views/monitoring.widget.navtreeitem.edit.php
index accedaf91f9..1794d6e1ef1 100644
--- a/ui/app/views/monitoring.widget.navtreeitem.edit.php
+++ b/ui/app/views/monitoring.widget.navtreeitem.edit.php
@@ -39,24 +39,9 @@ $form_list = (new CFormList())
)
->addRow(_('Linked map'), [
new CVar('sysmapid', $data['sysmap']['sysmapid']),
- (new CTextBox('sysmapname', $data['sysmap']['name'], true))
- ->setAttribute('onChange',
- 'javascript: if(jQuery("#'.$form->getName().' input[type=text]:first").val() === ""){'.
- 'jQuery("#widget-dialogue-form input[type=text]:first").val(this.value);}')
- ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH),
+ (new CTextBox('sysmapname', $data['sysmap']['name'], true))->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH),
(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
- (new CButton('select', _('Select')))
- ->addClass(ZBX_STYLE_BTN_GREY)
- ->onClick(
- 'return PopUp("popup.generic", '.json_encode([
- 'srctbl' => 'sysmaps',
- 'srcfld1' => 'sysmapid',
- 'srcfld2' => 'name',
- 'dstfrm' => $form->getName(),
- 'dstfld1' => 'sysmapid',
- 'dstfld2' => 'sysmapname'
- ]).', {dialogue_class: "modal-popup-generic"});'
- )
+ (new CButton('select', _('Select')))->addClass(ZBX_STYLE_BTN_GREY)
]);
if ($data['depth'] >= WIDGET_NAVIGATION_TREE_MAX_DEPTH) {
@@ -69,10 +54,13 @@ else {
]);
}
-$form->addItem($form_list);
+$form
+ ->addItem($form_list)
+ ->addItem((new CScriptTag('navtreeitem_edit_popup.init();'))->setOnDocumentReady());
$output = [
- 'body' => $form->toString()
+ 'body' => $form->toString(),
+ 'script_inline' => $this->readJsFile('monitoring.widget.navtreeitem.edit.js.php')
];
if (($messages = getMessages()) !== null) {
diff --git a/ui/app/views/popup.host.edit.php b/ui/app/views/popup.host.edit.php
index 7923458b968..64ec911da05 100644
--- a/ui/app/views/popup.host.edit.php
+++ b/ui/app/views/popup.host.edit.php
@@ -89,10 +89,6 @@ else {
];
}
-if ($data['warning']) {
- $data['warning'] = makeMessageBox(ZBX_STYLE_MSG_WARNING, [['message' => $data['warning']]]);
-}
-
$output = [
'header' => ($data['hostid'] == 0) ? _('New host') : _('Host'),
'body' => (new CPartial('configuration.host.edit.html', $data))->getOutput(),
@@ -102,7 +98,8 @@ $output = [
'popup_url' => $popup_url->getUrl(),
'form_name' => $data['form_name'],
'host_interfaces' => $data['host']['interfaces'],
- 'host_is_discovered' => ($data['host']['flags'] == ZBX_FLAG_DISCOVERY_CREATED)
+ 'host_is_discovered' => ($data['host']['flags'] == ZBX_FLAG_DISCOVERY_CREATED),
+ 'warning' => $data['warning']
]).');',
'buttons' => $buttons
];
diff --git a/ui/assets/styles/blue-theme.css b/ui/assets/styles/blue-theme.css
index 4c21e63bb6d..82ad95e0dc5 100644
--- a/ui/assets/styles/blue-theme.css
+++ b/ui/assets/styles/blue-theme.css
@@ -2622,8 +2622,9 @@ z-select,
color: #1f2c33;
text-overflow: ellipsis;
word-break: break-word;
- white-space: pre-wrap;
- user-select: none; }
+ user-select: none;
+ white-space: nowrap;
+ overflow: hidden; }
z-select .list li.hover,
.z-select .list li.hover {
background-color: #e8f5ff; }
@@ -2896,7 +2897,6 @@ form.is-loading {
box-shadow: inset 0 -1px 0 0 rgba(31, 44, 51, 0.1);
color: #1f2c33;
height: 22px;
- line-height: 1;
vertical-align: middle;
white-space: nowrap; }
.list-table.compact-view td [class*='icon-'] {
@@ -3639,19 +3639,31 @@ select {
.checkbox-radio {
position: absolute !important;
top: auto !important;
+ z-index: 1;
width: 16px !important;
height: 16px !important;
- opacity: 0;
- z-index: 1; }
+ opacity: 0; }
+ .checkbox-radio + label span {
+ position: relative;
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ margin-right: 4px;
+ vertical-align: text-bottom;
+ background-color: #ffffff;
+ border: 1px solid #acbbc2; }
+ .checkbox-radio + label span:active {
+ border-color: #acbbc2; }
+ .checkbox-radio + label.label-pos-left span {
+ margin-left: 4px;
+ margin-right: 0; }
.checkbox-radio:checked[readonly] + label span {
transition: none; }
.checkbox-radio:checked[readonly] + label span::after {
border-color: #acbbc2 !important; }
- .checkbox-radio[readonly],
- .checkbox-radio[readonly] + label {
+ .checkbox-radio[readonly], .checkbox-radio[readonly] + label {
pointer-events: none; }
- .checkbox-radio[readonly] span,
- .checkbox-radio[readonly] + label span {
+ .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span {
transition: none; }
.checkbox-radio[type="checkbox"] + label span {
border-radius: 2px; }
@@ -3682,20 +3694,6 @@ select {
border-radius: 50%; }
.checkbox-radio[type="radio"]:checked[disabled] + label span::after {
background-color: #acbbc2 !important; }
- .checkbox-radio + label span {
- position: relative;
- display: inline-block;
- width: 14px;
- height: 14px;
- margin: -4px 4px 0 0;
- bottom: -3px;
- border: 1px solid #acbbc2;
- background-color: #ffffff; }
- .checkbox-radio + label span:active {
- border-color: #acbbc2; }
- .checkbox-radio + label.label-pos-left span {
- margin-left: 6px;
- margin-right: 1px; }
.checkbox-radio:focus + label span {
border-color: #02659f; }
.checkbox-radio:checked:focus + label span {
@@ -3707,7 +3705,7 @@ select {
.checkbox-radio[disabled] + label span {
transition: none; }
-input[type="checkbox"], input[type="radio"] {
+input[type="radio"] {
margin: 0;
padding: 0;
border: 0;
@@ -4211,8 +4209,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active {
.radio-list-control input[type="radio"][disabled] + label, z-select[disabled] button,
.z-select[disabled] button, z-select[readonly] button,
-.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span,
-.checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
+.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
color: #acbbc2;
background-color: #ebebeb !important;
border-color: #ccd5d9; }
@@ -5861,10 +5858,7 @@ svg {
.checkbox-list li {
overflow: hidden;
text-overflow: ellipsis;
- line-height: 20px; }
- .checkbox-list li label {
- line-height: 16px;
- vertical-align: bottom; }
+ line-height: 24px; }
.columns-wrapper {
display: flex;
@@ -5926,7 +5920,8 @@ svg {
.preprocessing-list {
display: block;
max-width: 930px;
- min-width: 800px; }
+ min-width: 800px;
+ position: relative; }
.preprocessing-list > li {
display: block;
position: relative; }
@@ -6400,47 +6395,44 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control {
position: relative;
- display: inline-block;
- vertical-align: middle; }
+ display: inline-flex; }
.range-control input[type=range] {
+ width: calc(100% + 10px);
+ height: 20px;
+ margin: 2px -5px;
+ padding: 0;
+ vertical-align: top;
+ opacity: 0;
cursor: pointer;
-webkit-appearance: none;
/* Hides the slider so that custom slider can be made */
-moz-appearance: none;
/* Hides the slider so that custom slider can be made */
- width: calc(100% + 10px);
- opacity: 0;
- vertical-align: middle;
- margin: 0 -5px;
- padding: 0;
- height: 20px;
/* Special styling for WebKit/Blink */ }
.range-control input[type=range]:focus {
outline: none; }
.range-control input[type=range]::-webkit-slider-thumb, .range-control input[type=range]::-moz-range-thumb {
- margin-top: 1px;
- /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
height: 10px;
width: 10px;
+ margin-top: 1px;
+ /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
opacity: 0; }
.range-control input[type=range]::-webkit-slider-runnable-track {
height: 10px;
opacity: 0; }
.range-control input[type=text] {
- width: 31px;
- float: right; }
+ width: 31px; }
.range-control > div {
position: relative;
width: calc(100% - 10px - 31px);
- margin: 2px 10px 0 0;
- float: left; }
+ margin-right: 10px; }
.range-control .range-control-track,
.range-control .range-control-progress {
position: absolute;
top: 50%;
- margin-top: -1px;
left: 0;
height: 2px;
+ margin-top: -1px;
cursor: pointer; }
.range-control .range-control-track {
width: 100%;
@@ -6450,12 +6442,12 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control .range-control-thumb {
position: absolute;
top: 50%;
- margin-top: -5px;
- margin-left: -5px;
width: 10px;
height: 10px;
- border-radius: 50%;
- background: #0275b8; }
+ margin-top: -5px;
+ margin-left: -5px;
+ background: #0275b8;
+ border-radius: 50%; }
.range-control.range-control-focus .range-control-thumb {
margin-top: -6.66667px;
margin-left: -6.66667px;
@@ -6472,15 +6464,15 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
background: #c0c0c0; }
.range-control datalist {
position: absolute;
+ top: 50%;
display: flex;
width: 100%;
- top: 50%;
margin-top: -1px; }
.range-control datalist option {
- padding: 0;
- font-size: 0;
flex: 1 0 0;
height: 2px;
+ padding: 0;
+ font-size: 0;
border-left: 1px solid #ebeef0; }
.graph-legend {
@@ -6980,9 +6972,9 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
background-position: -117px -506px !important; }
.geomap-filter {
- border: 2px solid rgba(223, 228, 231, 0.4);
+ border: 1px solid #ccd5d9;
background-color: #ffffff;
- padding: 10px 30px 5px 10px;
+ padding: 5px 20px 5px 10px;
position: absolute;
margin-right: -2px;
margin-top: 5px;
@@ -6990,7 +6982,7 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
right: 0; }
.geomap-filter.collapsed {
- display: table; }
+ display: block; }
.geomap-filter li {
width: calc(100% + 20px); }
diff --git a/ui/assets/styles/dark-theme.css b/ui/assets/styles/dark-theme.css
index 4763e28b245..bd234e3177e 100644
--- a/ui/assets/styles/dark-theme.css
+++ b/ui/assets/styles/dark-theme.css
@@ -2635,8 +2635,9 @@ z-select,
color: #f2f2f2;
text-overflow: ellipsis;
word-break: break-word;
- white-space: pre-wrap;
- user-select: none; }
+ user-select: none;
+ white-space: nowrap;
+ overflow: hidden; }
z-select .list li.hover,
.z-select .list li.hover {
background-color: #454545; }
@@ -2907,7 +2908,6 @@ form.is-loading {
box-shadow: inset 0 -1px 0 0 rgba(242, 242, 242, 0.1);
color: #f2f2f2;
height: 22px;
- line-height: 1;
vertical-align: middle;
white-space: nowrap; }
.list-table.compact-view td [class*='icon-'] {
@@ -3650,19 +3650,31 @@ select {
.checkbox-radio {
position: absolute !important;
top: auto !important;
+ z-index: 1;
width: 16px !important;
height: 16px !important;
- opacity: 0;
- z-index: 1; }
+ opacity: 0; }
+ .checkbox-radio + label span {
+ position: relative;
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ margin-right: 4px;
+ vertical-align: text-bottom;
+ background-color: #383838;
+ border: 1px solid #4f4f4f; }
+ .checkbox-radio + label span:active {
+ border-color: #4f4f4f; }
+ .checkbox-radio + label.label-pos-left span {
+ margin-left: 4px;
+ margin-right: 0; }
.checkbox-radio:checked[readonly] + label span {
transition: none; }
.checkbox-radio:checked[readonly] + label span::after {
border-color: #4f4f4f !important; }
- .checkbox-radio[readonly],
- .checkbox-radio[readonly] + label {
+ .checkbox-radio[readonly], .checkbox-radio[readonly] + label {
pointer-events: none; }
- .checkbox-radio[readonly] span,
- .checkbox-radio[readonly] + label span {
+ .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span {
transition: none; }
.checkbox-radio[type="checkbox"] + label span {
border-radius: 2px; }
@@ -3693,20 +3705,6 @@ select {
border-radius: 50%; }
.checkbox-radio[type="radio"]:checked[disabled] + label span::after {
background-color: #4f4f4f !important; }
- .checkbox-radio + label span {
- position: relative;
- display: inline-block;
- width: 14px;
- height: 14px;
- margin: -4px 4px 0 0;
- bottom: -3px;
- border: 1px solid #4f4f4f;
- background-color: #383838; }
- .checkbox-radio + label span:active {
- border-color: #4f4f4f; }
- .checkbox-radio + label.label-pos-left span {
- margin-left: 6px;
- margin-right: 1px; }
.checkbox-radio:focus + label span {
border-color: #768d99; }
.checkbox-radio:checked:focus + label span {
@@ -3718,7 +3716,7 @@ select {
.checkbox-radio[disabled] + label span {
transition: none; }
-input[type="checkbox"], input[type="radio"] {
+input[type="radio"] {
margin: 0;
padding: 0;
border: 0;
@@ -4222,8 +4220,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active {
.radio-list-control input[type="radio"][disabled] + label, z-select[disabled] button,
.z-select[disabled] button, z-select[readonly] button,
-.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span,
-.checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
+.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
color: #525252;
background-color: #2b2b2b !important;
border-color: #3d3d3d; }
@@ -5872,10 +5869,7 @@ svg {
.checkbox-list li {
overflow: hidden;
text-overflow: ellipsis;
- line-height: 20px; }
- .checkbox-list li label {
- line-height: 16px;
- vertical-align: bottom; }
+ line-height: 24px; }
.columns-wrapper {
display: flex;
@@ -5937,7 +5931,8 @@ svg {
.preprocessing-list {
display: block;
max-width: 930px;
- min-width: 800px; }
+ min-width: 800px;
+ position: relative; }
.preprocessing-list > li {
display: block;
position: relative; }
@@ -6411,47 +6406,44 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control {
position: relative;
- display: inline-block;
- vertical-align: middle; }
+ display: inline-flex; }
.range-control input[type=range] {
+ width: calc(100% + 10px);
+ height: 20px;
+ margin: 2px -5px;
+ padding: 0;
+ vertical-align: top;
+ opacity: 0;
cursor: pointer;
-webkit-appearance: none;
/* Hides the slider so that custom slider can be made */
-moz-appearance: none;
/* Hides the slider so that custom slider can be made */
- width: calc(100% + 10px);
- opacity: 0;
- vertical-align: middle;
- margin: 0 -5px;
- padding: 0;
- height: 20px;
/* Special styling for WebKit/Blink */ }
.range-control input[type=range]:focus {
outline: none; }
.range-control input[type=range]::-webkit-slider-thumb, .range-control input[type=range]::-moz-range-thumb {
- margin-top: 1px;
- /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
height: 10px;
width: 10px;
+ margin-top: 1px;
+ /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
opacity: 0; }
.range-control input[type=range]::-webkit-slider-runnable-track {
height: 10px;
opacity: 0; }
.range-control input[type=text] {
- width: 31px;
- float: right; }
+ width: 31px; }
.range-control > div {
position: relative;
width: calc(100% - 10px - 31px);
- margin: 2px 10px 0 0;
- float: left; }
+ margin-right: 10px; }
.range-control .range-control-track,
.range-control .range-control-progress {
position: absolute;
top: 50%;
- margin-top: -1px;
left: 0;
height: 2px;
+ margin-top: -1px;
cursor: pointer; }
.range-control .range-control-track {
width: 100%;
@@ -6461,12 +6453,12 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control .range-control-thumb {
position: absolute;
top: 50%;
- margin-top: -5px;
- margin-left: -5px;
width: 10px;
height: 10px;
- border-radius: 50%;
- background: #4796c4; }
+ margin-top: -5px;
+ margin-left: -5px;
+ background: #4796c4;
+ border-radius: 50%; }
.range-control.range-control-focus .range-control-thumb {
margin-top: -6.66667px;
margin-left: -6.66667px;
@@ -6483,15 +6475,15 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
background: #c0c0c0; }
.range-control datalist {
position: absolute;
+ top: 50%;
display: flex;
width: 100%;
- top: 50%;
margin-top: -1px; }
.range-control datalist option {
- padding: 0;
- font-size: 0;
flex: 1 0 0;
height: 2px;
+ padding: 0;
+ font-size: 0;
border-left: 1px solid #0e1012; }
.graph-legend {
@@ -6991,9 +6983,9 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
background-position: -117px -506px !important; }
.geomap-filter {
- border: 2px solid rgba(48, 48, 48, 0.4);
+ border: 1px solid #383838;
background-color: #2b2b2b;
- padding: 10px 30px 5px 10px;
+ padding: 5px 20px 5px 10px;
position: absolute;
margin-right: -2px;
margin-top: 5px;
@@ -7001,7 +6993,7 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
right: 0; }
.geomap-filter.collapsed {
- display: table; }
+ display: block; }
.geomap-filter li {
width: calc(100% + 20px); }
diff --git a/ui/assets/styles/hc-dark.css b/ui/assets/styles/hc-dark.css
index 17e5c4287c2..4633a2344af 100644
--- a/ui/assets/styles/hc-dark.css
+++ b/ui/assets/styles/hc-dark.css
@@ -2611,8 +2611,9 @@ z-select,
color: #ffffff;
text-overflow: ellipsis;
word-break: break-word;
- white-space: pre-wrap;
- user-select: none; }
+ user-select: none;
+ white-space: nowrap;
+ overflow: hidden; }
z-select .list li.hover,
.z-select .list li.hover {
background-color: #454545; }
@@ -2862,7 +2863,6 @@ form.is-loading {
box-shadow: inset 0 -1px 0 0 rgba(255, 255, 255, 0.1);
color: #ffffff;
height: 22px;
- line-height: 1;
vertical-align: middle;
white-space: nowrap; }
.list-table.compact-view td [class*='icon-'] {
@@ -3605,19 +3605,31 @@ select {
.checkbox-radio {
position: absolute !important;
top: auto !important;
+ z-index: 1;
width: 16px !important;
height: 16px !important;
- opacity: 0;
- z-index: 1; }
+ opacity: 0; }
+ .checkbox-radio + label span {
+ position: relative;
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ margin-right: 4px;
+ vertical-align: text-bottom;
+ background-color: #383838;
+ border: 1px solid #666666; }
+ .checkbox-radio + label span:active {
+ border-color: #666666; }
+ .checkbox-radio + label.label-pos-left span {
+ margin-left: 4px;
+ margin-right: 0; }
.checkbox-radio:checked[readonly] + label span {
transition: none; }
.checkbox-radio:checked[readonly] + label span::after {
border-color: #666666 !important; }
- .checkbox-radio[readonly],
- .checkbox-radio[readonly] + label {
+ .checkbox-radio[readonly], .checkbox-radio[readonly] + label {
pointer-events: none; }
- .checkbox-radio[readonly] span,
- .checkbox-radio[readonly] + label span {
+ .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span {
transition: none; }
.checkbox-radio[type="checkbox"] + label span {
border-radius: 2px; }
@@ -3648,20 +3660,6 @@ select {
border-radius: 50%; }
.checkbox-radio[type="radio"]:checked[disabled] + label span::after {
background-color: #666666 !important; }
- .checkbox-radio + label span {
- position: relative;
- display: inline-block;
- width: 14px;
- height: 14px;
- margin: -4px 4px 0 0;
- bottom: -3px;
- border: 1px solid #666666;
- background-color: #383838; }
- .checkbox-radio + label span:active {
- border-color: #666666; }
- .checkbox-radio + label.label-pos-left span {
- margin-left: 6px;
- margin-right: 1px; }
.checkbox-radio:focus + label span {
border-color: #bbbbbb; }
.checkbox-radio:checked:focus + label span {
@@ -3673,7 +3671,7 @@ select {
.checkbox-radio[disabled] + label span {
transition: none; }
-input[type="checkbox"], input[type="radio"] {
+input[type="radio"] {
margin: 0;
padding: 0;
border: 0;
@@ -4177,8 +4175,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active {
.radio-list-control input[type="radio"][disabled] + label, z-select[disabled] button,
.z-select[disabled] button, z-select[readonly] button,
-.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span,
-.checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
+.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
color: #7d7d7d;
background-color: #000000 !important;
border-color: #5a5a5a; }
@@ -5818,10 +5815,7 @@ svg {
.checkbox-list li {
overflow: hidden;
text-overflow: ellipsis;
- line-height: 20px; }
- .checkbox-list li label {
- line-height: 16px;
- vertical-align: bottom; }
+ line-height: 24px; }
.columns-wrapper {
display: flex;
@@ -5883,7 +5877,8 @@ svg {
.preprocessing-list {
display: block;
max-width: 930px;
- min-width: 800px; }
+ min-width: 800px;
+ position: relative; }
.preprocessing-list > li {
display: block;
position: relative; }
@@ -6357,47 +6352,44 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control {
position: relative;
- display: inline-block;
- vertical-align: middle; }
+ display: inline-flex; }
.range-control input[type=range] {
+ width: calc(100% + 10px);
+ height: 20px;
+ margin: 2px -5px;
+ padding: 0;
+ vertical-align: top;
+ opacity: 0;
cursor: pointer;
-webkit-appearance: none;
/* Hides the slider so that custom slider can be made */
-moz-appearance: none;
/* Hides the slider so that custom slider can be made */
- width: calc(100% + 10px);
- opacity: 0;
- vertical-align: middle;
- margin: 0 -5px;
- padding: 0;
- height: 20px;
/* Special styling for WebKit/Blink */ }
.range-control input[type=range]:focus {
outline: none; }
.range-control input[type=range]::-webkit-slider-thumb, .range-control input[type=range]::-moz-range-thumb {
- margin-top: 1px;
- /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
height: 10px;
width: 10px;
+ margin-top: 1px;
+ /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
opacity: 0; }
.range-control input[type=range]::-webkit-slider-runnable-track {
height: 10px;
opacity: 0; }
.range-control input[type=text] {
- width: 31px;
- float: right; }
+ width: 31px; }
.range-control > div {
position: relative;
width: calc(100% - 10px - 31px);
- margin: 2px 10px 0 0;
- float: left; }
+ margin-right: 10px; }
.range-control .range-control-track,
.range-control .range-control-progress {
position: absolute;
top: 50%;
- margin-top: -1px;
left: 0;
height: 2px;
+ margin-top: -1px;
cursor: pointer; }
.range-control .range-control-track {
width: 100%;
@@ -6407,12 +6399,12 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control .range-control-thumb {
position: absolute;
top: 50%;
- margin-top: -5px;
- margin-left: -5px;
width: 10px;
height: 10px;
- border-radius: 50%;
- background: #f8f8f8; }
+ margin-top: -5px;
+ margin-left: -5px;
+ background: #f8f8f8;
+ border-radius: 50%; }
.range-control.range-control-focus .range-control-thumb {
margin-top: -6.66667px;
margin-left: -6.66667px;
@@ -6429,15 +6421,15 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
background: #c0c0c0; }
.range-control datalist {
position: absolute;
+ top: 50%;
display: flex;
width: 100%;
- top: 50%;
margin-top: -1px; }
.range-control datalist option {
- padding: 0;
- font-size: 0;
flex: 1 0 0;
height: 2px;
+ padding: 0;
+ font-size: 0;
border-left: 1px solid #111111; }
.graph-legend {
@@ -6937,9 +6929,9 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
background-position: -117px -506px !important; }
.geomap-filter {
- border: 2px solid rgba(68, 68, 68, 0.4);
+ border: 1px solid #666666;
background-color: #000000;
- padding: 10px 30px 5px 10px;
+ padding: 5px 20px 5px 10px;
position: absolute;
margin-right: -2px;
margin-top: 5px;
@@ -6947,7 +6939,7 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
right: 0; }
.geomap-filter.collapsed {
- display: table; }
+ display: block; }
.geomap-filter li {
width: calc(100% + 20px); }
@@ -7364,6 +7356,11 @@ z-select button.focusable:focus,
.list-table.compact-view td .icon-wizard-action {
background: transparent url("../img/icon-sprite.svg?20211222") no-repeat -318px -624px; }
+.overlay-dialogue .list-table th:first-child {
+ padding-left: 0px; }
+.overlay-dialogue .list-table td:first-child {
+ padding-left: 42px; }
+
.filter-highlight-row-cb {
display: none; }
diff --git a/ui/assets/styles/hc-light.css b/ui/assets/styles/hc-light.css
index efc7f4d8206..502fd43be4d 100644
--- a/ui/assets/styles/hc-light.css
+++ b/ui/assets/styles/hc-light.css
@@ -2611,8 +2611,9 @@ z-select,
color: #000000;
text-overflow: ellipsis;
word-break: break-word;
- white-space: pre-wrap;
- user-select: none; }
+ user-select: none;
+ white-space: nowrap;
+ overflow: hidden; }
z-select .list li.hover,
.z-select .list li.hover {
background-color: #f4f4f4; }
@@ -2862,7 +2863,6 @@ form.is-loading {
box-shadow: inset 0 -1px 0 0 rgba(0, 0, 0, 0.1);
color: #000000;
height: 22px;
- line-height: 1;
vertical-align: middle;
white-space: nowrap; }
.list-table.compact-view td [class*='icon-'] {
@@ -3605,19 +3605,31 @@ select {
.checkbox-radio {
position: absolute !important;
top: auto !important;
+ z-index: 1;
width: 16px !important;
height: 16px !important;
- opacity: 0;
- z-index: 1; }
+ opacity: 0; }
+ .checkbox-radio + label span {
+ position: relative;
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ margin-right: 4px;
+ vertical-align: text-bottom;
+ background-color: #ffffff;
+ border: 1px solid #888888; }
+ .checkbox-radio + label span:active {
+ border-color: #888888; }
+ .checkbox-radio + label.label-pos-left span {
+ margin-left: 4px;
+ margin-right: 0; }
.checkbox-radio:checked[readonly] + label span {
transition: none; }
.checkbox-radio:checked[readonly] + label span::after {
border-color: #888888 !important; }
- .checkbox-radio[readonly],
- .checkbox-radio[readonly] + label {
+ .checkbox-radio[readonly], .checkbox-radio[readonly] + label {
pointer-events: none; }
- .checkbox-radio[readonly] span,
- .checkbox-radio[readonly] + label span {
+ .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span {
transition: none; }
.checkbox-radio[type="checkbox"] + label span {
border-radius: 2px; }
@@ -3648,20 +3660,6 @@ select {
border-radius: 50%; }
.checkbox-radio[type="radio"]:checked[disabled] + label span::after {
background-color: #888888 !important; }
- .checkbox-radio + label span {
- position: relative;
- display: inline-block;
- width: 14px;
- height: 14px;
- margin: -4px 4px 0 0;
- bottom: -3px;
- border: 1px solid #888888;
- background-color: #ffffff; }
- .checkbox-radio + label span:active {
- border-color: #888888; }
- .checkbox-radio + label.label-pos-left span {
- margin-left: 6px;
- margin-right: 1px; }
.checkbox-radio:focus + label span {
border-color: #000000; }
.checkbox-radio:checked:focus + label span {
@@ -3673,7 +3671,7 @@ select {
.checkbox-radio[disabled] + label span {
transition: none; }
-input[type="checkbox"], input[type="radio"] {
+input[type="radio"] {
margin: 0;
padding: 0;
border: 0;
@@ -4177,8 +4175,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active {
.radio-list-control input[type="radio"][disabled] + label, z-select[disabled] button,
.z-select[disabled] button, z-select[readonly] button,
-.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span,
-.checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
+.z-select[readonly] button, .multiselect[aria-disabled], input[disabled], input[readonly], textarea[disabled], textarea[readonly], select option[disabled], select[disabled], select[readonly], .checkbox-radio[readonly] span, .checkbox-radio[readonly] + label span, .checkbox-radio[disabled] + label span, .macro-input-group button.btn-dropdown-toggle:disabled {
color: #9f9f9f;
background-color: #f0f0f0 !important;
border-color: #9f9f9f; }
@@ -5818,10 +5815,7 @@ svg {
.checkbox-list li {
overflow: hidden;
text-overflow: ellipsis;
- line-height: 20px; }
- .checkbox-list li label {
- line-height: 16px;
- vertical-align: bottom; }
+ line-height: 24px; }
.columns-wrapper {
display: flex;
@@ -5883,7 +5877,8 @@ svg {
.preprocessing-list {
display: block;
max-width: 930px;
- min-width: 800px; }
+ min-width: 800px;
+ position: relative; }
.preprocessing-list > li {
display: block;
position: relative; }
@@ -6357,47 +6352,44 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control {
position: relative;
- display: inline-block;
- vertical-align: middle; }
+ display: inline-flex; }
.range-control input[type=range] {
+ width: calc(100% + 10px);
+ height: 20px;
+ margin: 2px -5px;
+ padding: 0;
+ vertical-align: top;
+ opacity: 0;
cursor: pointer;
-webkit-appearance: none;
/* Hides the slider so that custom slider can be made */
-moz-appearance: none;
/* Hides the slider so that custom slider can be made */
- width: calc(100% + 10px);
- opacity: 0;
- vertical-align: middle;
- margin: 0 -5px;
- padding: 0;
- height: 20px;
/* Special styling for WebKit/Blink */ }
.range-control input[type=range]:focus {
outline: none; }
.range-control input[type=range]::-webkit-slider-thumb, .range-control input[type=range]::-moz-range-thumb {
- margin-top: 1px;
- /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
height: 10px;
width: 10px;
+ margin-top: 1px;
+ /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
opacity: 0; }
.range-control input[type=range]::-webkit-slider-runnable-track {
height: 10px;
opacity: 0; }
.range-control input[type=text] {
- width: 31px;
- float: right; }
+ width: 31px; }
.range-control > div {
position: relative;
width: calc(100% - 10px - 31px);
- margin: 2px 10px 0 0;
- float: left; }
+ margin-right: 10px; }
.range-control .range-control-track,
.range-control .range-control-progress {
position: absolute;
top: 50%;
- margin-top: -1px;
left: 0;
height: 2px;
+ margin-top: -1px;
cursor: pointer; }
.range-control .range-control-track {
width: 100%;
@@ -6407,12 +6399,12 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
.range-control .range-control-thumb {
position: absolute;
top: 50%;
- margin-top: -5px;
- margin-left: -5px;
width: 10px;
height: 10px;
- border-radius: 50%;
- background: #555555; }
+ margin-top: -5px;
+ margin-left: -5px;
+ background: #555555;
+ border-radius: 50%; }
.range-control.range-control-focus .range-control-thumb {
margin-top: -6.66667px;
margin-left: -6.66667px;
@@ -6429,15 +6421,15 @@ button.icon-action-command, button.icon-action-close, button.icon-action-msg, bu
background: #c0c0c0; }
.range-control datalist {
position: absolute;
+ top: 50%;
display: flex;
width: 100%;
- top: 50%;
margin-top: -1px; }
.range-control datalist option {
- padding: 0;
- font-size: 0;
flex: 1 0 0;
height: 2px;
+ padding: 0;
+ font-size: 0;
border-left: 1px solid #ffffff; }
.graph-legend {
@@ -6937,9 +6929,9 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
background-position: -117px -506px !important; }
.geomap-filter {
- border: 2px solid rgba(159, 159, 159, 0.4);
+ border: 1px solid #383838;
background-color: #ffffff;
- padding: 10px 30px 5px 10px;
+ padding: 5px 20px 5px 10px;
position: absolute;
margin-right: -2px;
margin-top: 5px;
@@ -6947,7 +6939,7 @@ z-select.z-select-host-interface li[disabled] .description:not(:empty),
right: 0; }
.geomap-filter.collapsed {
- display: table; }
+ display: block; }
.geomap-filter li {
width: calc(100% + 20px); }
@@ -7300,6 +7292,11 @@ z-select button.focusable:focus,
.list-table.compact-view td .icon-wizard-action {
background: transparent url("../img/icon-sprite.svg?20211222") no-repeat -165px -624px; }
+.overlay-dialogue .list-table th:first-child {
+ padding-left: 0px; }
+.overlay-dialogue .list-table td:first-child {
+ padding-left: 42px; }
+
.filter-highlight-row-cb {
display: none; }
diff --git a/ui/graphs.php b/ui/graphs.php
index 9bdc21f9267..79ba750cd8c 100644
--- a/ui/graphs.php
+++ b/ui/graphs.php
@@ -62,6 +62,7 @@ $fields = [
'group_graphid' => [T_ZBX_INT, O_OPT, null, DB_ID, null],
'copy_targetids' => [T_ZBX_INT, O_OPT, null, DB_ID, null],
'context' => [T_ZBX_STR, O_MAND, P_SYS, IN('"host", "template"'), null],
+ 'readonly' => [T_ZBX_INT, O_OPT, null, IN('1'), null],
// actions
'action' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, IN('"graph.masscopyto","graph.massdelete","graph.updatediscover"'), null],
'add' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null],
@@ -502,10 +503,11 @@ elseif (isset($_REQUEST['form'])) {
'group_gid' => getRequest('group_gid', []),
'hostid' => $hostid,
'normal_only' => getRequest('normal_only'),
- 'context' => getRequest('context')
+ 'context' => getRequest('context'),
+ 'readonly' => getRequest('readonly', 0)
];
- if (!empty($data['graphid']) && !isset($_REQUEST['form_refresh'])) {
+ if ($data['graphid'] != 0 && ($data['readonly'] || !$data['form_refresh'])) {
$options = [
'graphids' => $data['graphid'],
'output' => API_OUTPUT_EXTEND,
@@ -612,7 +614,7 @@ elseif (isset($_REQUEST['form'])) {
}
}
- if (empty($data['graphid']) && !isset($_REQUEST['form_refresh'])) {
+ if ($data['graphid'] == 0 && !$data['form_refresh']) {
$data['show_legend'] = $_REQUEST['show_legend'] = 1;
$data['show_work_period'] = $_REQUEST['show_work_period'] = 1;
$data['show_triggers'] = $_REQUEST['show_triggers'] = 1;
diff --git a/ui/include/classes/graphdraw/CLineGraphDraw.php b/ui/include/classes/graphdraw/CLineGraphDraw.php
index a4988b1e782..585fe26262f 100644
--- a/ui/include/classes/graphdraw/CLineGraphDraw.php
+++ b/ui/include/classes/graphdraw/CLineGraphDraw.php
@@ -930,12 +930,14 @@ class CLineGraphDraw extends CGraphDraw {
/**
* Get best matching X-axis interval specification for the preferred sub-interval.
*
- * @param int $pref_sub_interval Preferred sub-interval in seconds.
- * @param float $min_sub_interval Preferred minimal sub-interval in seconds (float). Discarded if no matches.
+ * @param int $pref_sub_interval Preferred sub-interval in seconds.
+ * @param float $min_sub_interval Preferred minimal sub-interval in seconds (float). Discarded if no matches.
+ * @param string $magnitude The highest non-permanent date component (Y, m, d, H, i, s).
*
* @return array
*/
- private function getOptimalDateTimeIntervalSpec(int $pref_sub_interval, float $min_sub_interval): array {
+ private function getOptimalDateTimeIntervalSpec(int $pref_sub_interval, float $min_sub_interval,
+ string $magnitude): array {
// Possible X-axis main and sub-intervals.
$intervals = [
'PT1M' => ['PT1S', 'PT5S', 'PT10S', 'PT30S'],
@@ -962,9 +964,9 @@ class CLineGraphDraw extends CGraphDraw {
$formats = [
'PT1M' => ['main' => TIME_FORMAT, 'sub' => _('H:i:s')],
'PT1H' => ['main' => TIME_FORMAT, 'sub' => TIME_FORMAT],
- 'P1D' => ['main' => _('m-d'), 'sub' => TIME_FORMAT],
- 'P1W' => ['main' => _('m-d'), 'sub' => _('m-d')],
- 'P1M' => ['main' => _('m-d'), 'sub' => _('m-d')],
+ 'P1D' => ['main' => $magnitude === 'Y' ? DATE_FORMAT : _('m-d'), 'sub' => TIME_FORMAT],
+ 'P1W' => ['main' => $magnitude === 'Y' ? DATE_FORMAT : _('m-d'), 'sub' => _('m-d')],
+ 'P1M' => ['main' => $magnitude === 'Y' ? DATE_FORMAT : _('m-d'), 'sub' => _('m-d')],
'P1Y' => ['main' => _x('Y', DATE_FORMAT_CONTEXT), 'sub' => _('M')],
'P10Y' => ['main' => _x('Y', DATE_FORMAT_CONTEXT), 'sub' => _x('Y', DATE_FORMAT_CONTEXT)]
];
@@ -1082,7 +1084,13 @@ class CLineGraphDraw extends CGraphDraw {
$preferred_sub_interval = (int) ($this->period * $this->cell_width / $this->sizeX);
- $optimal = $this->getOptimalDateTimeIntervalSpec($preferred_sub_interval, $label_size);
+ foreach (['Y', 'm', 'd', 'H', 'i', 's'] as $magnitude) {
+ if (date($magnitude, $this->stime) !== date($magnitude, $this->stime + $this->period)) {
+ break;
+ }
+ }
+
+ $optimal = $this->getOptimalDateTimeIntervalSpec($preferred_sub_interval, $label_size, $magnitude);
// Align starting date and time with the interval.
$start = strtotime(date($optimal['aligner']['trim'], $this->stime));
diff --git a/ui/include/classes/html/CTabView.php b/ui/include/classes/html/CTabView.php
index a01c243d1a0..c913c4d3222 100644
--- a/ui/include/classes/html/CTabView.php
+++ b/ui/include/classes/html/CTabView.php
@@ -154,17 +154,18 @@ class CTabView extends CDiv {
}
public function makeJavascript() {
+ $tab_name = ':tab.'.$this->id;
$create_event = '';
if ($this->selectedTab !== null) {
$create_event = 'create: function() {'.
- 'sessionStorage.setItem(ZBX_SESSION_NAME + "_tab", '.json_encode($this->selectedTab).');'.
+ 'sessionStorage.setItem(ZBX_SESSION_NAME + "'.$tab_name.'", '.json_encode($this->selectedTab).');'.
'},';
$active_tab = 'active: '.json_encode($this->selectedTab).',';
}
else {
$active_tab = 'active: function() {'.
- 'return sessionStorage.getItem(ZBX_SESSION_NAME + "_tab") || 0;'.
+ 'return sessionStorage.getItem(ZBX_SESSION_NAME + "'.$tab_name.'") || 0;'.
'}(),';
}
@@ -177,14 +178,14 @@ class CTabView extends CDiv {
$disabled_tabs.
$active_tab.
'activate: function(event, ui) {'.
- 'sessionStorage.setItem(ZBX_SESSION_NAME + "_tab", ui.newTab.index().toString());'.
+ 'sessionStorage.setItem(ZBX_SESSION_NAME + "'.$tab_name.'", ui.newTab.index().toString());'.
'jQuery.cookie("tab", ui.newTab.index().toString());'.
$this->tab_change_js.
'}'.
'})'.
// Prevent changing the cookie value in a different tab.
'.parent().on("submit", function() {'.
- 'jQuery.cookie("tab", sessionStorage.getItem(ZBX_SESSION_NAME + "_tab") || 0);'.
+ 'jQuery.cookie("tab", sessionStorage.getItem(ZBX_SESSION_NAME + "'.$tab_name.'") || 0);'.
'});';
}
}
diff --git a/ui/include/classes/import/CConfigurationImport.php b/ui/include/classes/import/CConfigurationImport.php
index 86a94f43935..653b0230bb0 100644
--- a/ui/include/classes/import/CConfigurationImport.php
+++ b/ui/include/classes/import/CConfigurationImport.php
@@ -2346,15 +2346,11 @@ class CConfigurationImport {
return;
}
- $dashboards = $this->getFormattedTemplateDashboards();
-
- if ($dashboards) {
- $dashboard_importer = new CTemplateDashboardImporter($this->options, $this->referencer,
- $this->importedObjectContainer
- );
+ $dashboard_importer = new CTemplateDashboardImporter($this->options, $this->referencer,
+ $this->importedObjectContainer
+ );
- $dashboard_importer->delete($dashboards);
- }
+ $dashboard_importer->delete($this->getFormattedTemplateDashboards());
}
/**
@@ -2561,7 +2557,7 @@ class CConfigurationImport {
*/
protected function getFormattedTemplateDashboards(): array {
if (!array_key_exists('templateDashboards', $this->formattedData)) {
- $this->formattedData['templateDashboards'] = $this->adapter->getTemplateDashboards();
+ $this->formattedData['templateDashboards'] = $this->adapter->getTemplateDashboards();
}
return $this->formattedData['templateDashboards'];
diff --git a/ui/include/views/configuration.graph.edit.php b/ui/include/views/configuration.graph.edit.php
index a241086e79a..b772e286212 100644
--- a/ui/include/views/configuration.graph.edit.php
+++ b/ui/include/views/configuration.graph.edit.php
@@ -74,6 +74,7 @@ if (array_key_exists('flags', $data) && $data['flags'] == ZBX_FLAG_DISCOVERY_CRE
$readonly = false;
if ($is_templated || $discovered_graph) {
$readonly = true;
+ $graphForm->addItem((new CVar('readonly', 1))->removeId());
}
if ($discovered_graph) {
@@ -431,9 +432,12 @@ if ($data['parent_discoveryid']) {
// Append tabs to form.
$graphTab = (new CTabView())
- ->setSelected(0)
->addTab('graphTab', ($data['parent_discoveryid'] === null) ? _('Graph') : _('Graph prototype'), $graphFormList);
+if (!$data['form_refresh']) {
+ $graphTab->setSelected(0);
+}
+
/*
* Preview tab
*/
diff --git a/ui/include/views/js/configuration.graph.edit.js.php b/ui/include/views/js/configuration.graph.edit.js.php
index 2c883492d2b..8a1a32787ce 100644
--- a/ui/include/views/js/configuration.graph.edit.js.php
+++ b/ui/include/views/js/configuration.graph.edit.js.php
@@ -337,8 +337,10 @@
this.loadItem(item);
});
- $('#tabs').on('tabsactivate', (event, ui) => {
- if (ui.newPanel.attr('id') === 'previewTab') {
+ $('#tabs').on('tabscreate tabsactivate', (event, ui) => {
+ const $panel = (event.type === 'tabscreate') ? ui.panel : ui.newPanel;
+
+ if ($panel.attr('id') === 'previewTab') {
const $preview_chart = $('#previewChart');
const src = new Curl('chart3.php');
diff --git a/ui/js/class.tab-indicators.js b/ui/js/class.tab-indicators.js
index f8cf63a1d59..6ed5bdb8557 100644
--- a/ui/js/class.tab-indicators.js
+++ b/ui/js/class.tab-indicators.js
@@ -537,7 +537,7 @@ class PreprocessingTabIndicatorItem extends TabIndicatorItem {
getValue() {
return document
- .querySelectorAll('#preprocessing .preprocessing-list-item')
+ .querySelectorAll('#preprocessing .preprocessing-list-item:not(.ui-sortable-placeholder)')
.length;
}
diff --git a/ui/js/widgets/class.widget.js b/ui/js/widgets/class.widget.js
index 5640bdc58e4..afddb550969 100644
--- a/ui/js/widgets/class.widget.js
+++ b/ui/js/widgets/class.widget.js
@@ -733,7 +733,9 @@ class CWidget extends CBaseComponent {
this._content_body.insertAdjacentHTML('beforeend', messages);
}
- this._content_body.insertAdjacentHTML('beforeend', body);
+ if (body !== undefined) {
+ this._content_body.insertAdjacentHTML('beforeend', body);
+ }
if (debug !== undefined) {
this._content_body.insertAdjacentHTML('beforeend', debug);
diff --git a/ui/js/widgets/class.widget.navtree.js b/ui/js/widgets/class.widget.navtree.js
index e25c364d996..c424c86c8f8 100644
--- a/ui/js/widgets/class.widget.navtree.js
+++ b/ui/js/widgets/class.widget.navtree.js
@@ -961,7 +961,8 @@ class CWidgetNavTree extends CWidget {
'action': () => {}
}
],
- 'dialogueid': 'navtreeitem'
+ 'dialogueid': 'navtreeitem',
+ 'script_inline': resp.script_inline
}, trigger_elmnt);
}
});
diff --git a/ui/tests/integration/IntegrationTests.php b/ui/tests/integration/IntegrationTests.php
index 88406df41a7..e833788652b 100644
--- a/ui/tests/integration/IntegrationTests.php
+++ b/ui/tests/integration/IntegrationTests.php
@@ -27,6 +27,7 @@ require_once dirname(__FILE__).'/testValuemaps.php';
require_once dirname(__FILE__).'/testTriggerLinking.php';
require_once dirname(__FILE__).'/testGraphLinking.php';
require_once dirname(__FILE__).'/testEscalations.php';
+require_once dirname(__FILE__).'/testAlertingForServices.php';
require_once dirname(__FILE__).'/testComplexServiceStatus.php';
require_once dirname(__FILE__).'/testServiceRoles.php';
require_once dirname(__FILE__).'/testExpressionMacros.php';
@@ -52,6 +53,7 @@ class IntegrationTests {
$suite->addTestSuite('testTriggerLinking');
$suite->addTestSuite('testGraphLinking');
$suite->addTestSuite('testEscalations');
+ $suite->addTestSuite('testAlertingForServices');
$suite->addTestSuite('testComplexServiceStatus');
$suite->addTestSuite('testServiceRoles');
$suite->addTestSuite('testExpressionMacros');
diff --git a/ui/tests/integration/testAlertingForServices.php b/ui/tests/integration/testAlertingForServices.php
new file mode 100644
index 00000000000..5d3fb5bb60a
--- /dev/null
+++ b/ui/tests/integration/testAlertingForServices.php
@@ -0,0 +1,614 @@
+<?php
+/*
+** Zabbix
+** Copyright (C) 2001-2021 Zabbix SIA
+**
+** 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; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+require_once dirname(__FILE__).'/../include/CIntegrationTest.php';
+
+/**
+ * Test suite for alerting for services.
+ *
+ * @required-components server
+ * @configurationDataProvider serverConfigurationProvider
+ * @hosts test_services_alerting
+ * @backup history,items,triggers,alerts,services
+ */
+class testAlertingForServices extends CIntegrationTest {
+ const HOSTNAME = 'test_services_alerting';
+ const TRAPPER_KEY = 'test_trapper';
+ const SERVICENAME = 'Service 1';
+ const TRIGGER_DESC = 'Sample trigger';
+
+ private static $hostid;
+ private static $serviceid;
+ private static $actionid;
+ private static $triggerid;
+ private static $problem_tags;
+
+ private function createServiceWithProblemTags($name, $problem_tags) {
+ $response = $this->call('service.create', [
+ 'name' => $name,
+ 'algorithm' => ZBX_SERVICE_STATUS_CALC_MOST_CRITICAL_ALL,
+ 'sortorder' => 1,
+ 'problem_tags' => $problem_tags
+ ]);
+ $this->assertArrayHasKey('serviceids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['serviceids']);
+
+ return $response['result']['serviceids'][0];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepareData() {
+ // Create host "test_services_alerting"
+ $response = $this->call('host.create', [
+ [
+ 'host' => self::HOSTNAME,
+ 'interfaces' => [
+ 'type' => 1,
+ 'main' => 1,
+ 'useip' => 1,
+ 'ip' => '127.0.0.1',
+ 'dns' => '',
+ 'port' => $this->getConfigurationValue(self::COMPONENT_AGENT, 'ListenPort')
+ ],
+ 'groups' => [['groupid' => 4]],
+ 'status' => HOST_STATUS_MONITORED
+ ]
+ ]);
+
+ $this->assertArrayHasKey('hostids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['hostids']);
+ self::$hostid = $response['result']['hostids'][0];
+
+ // Create trapper item
+ $response = $this->call('item.create', [
+ [
+ 'name' => self::TRAPPER_KEY,
+ 'key_' => self::TRAPPER_KEY,
+ 'type' => ITEM_TYPE_TRAPPER,
+ 'hostid' => self::$hostid,
+ 'value_type' => ITEM_VALUE_TYPE_UINT64
+ ]
+ ]);
+ $this->assertArrayHasKey('itemids', $response['result']);
+ $this->assertEquals(1, count($response['result']['itemids']));
+
+ // Create trigger
+ $response = $this->call('trigger.create', [
+ 'description' => self::TRIGGER_DESC,
+ 'priority' => TRIGGER_SEVERITY_HIGH,
+ 'status' => TRIGGER_STATUS_ENABLED,
+ 'type' => 0,
+ 'recovery_mode' => 0,
+ 'manual_close' => ZBX_TRIGGER_MANUAL_CLOSE_NOT_ALLOWED,
+ 'expression' => 'last(/' . self::HOSTNAME . '/' . self::TRAPPER_KEY . ')=1'
+ ]);
+ $this->assertArrayHasKey('triggerids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['triggerids']);
+ self::$triggerid = $response['result']['triggerids'][0];
+
+ $response = $this->call('trigger.update', [
+ 'triggerid' => self::$triggerid,
+ 'tags' => [
+ [
+ 'tag' => 'ServiceLink',
+ 'value' => self::$triggerid . ':' . self::TRIGGER_DESC
+ ]
+ ]
+ ]);
+ self::$problem_tags = 'ServiceLink:' . self::$triggerid . ':' . self::TRIGGER_DESC;
+
+ // Create service
+ self::$serviceid = $this->createServiceWithProblemTags(self::SERVICENAME, [
+ [
+ 'tag' => 'ServiceLink',
+ 'operator' => 0,
+ 'value' => self::$triggerid . ':' . self::TRIGGER_DESC
+ ]
+ ]);
+
+ // Create action
+ $response = $this->call('action.create', [
+ 'name' => 'Sample service status changed',
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'status' => 0,
+ 'esc_period' => '1h',
+ 'filter' => [
+ 'evaltype' => 0,
+ 'conditions' => [
+ [
+ 'conditiontype' => CONDITION_TYPE_SERVICE,
+ 'operator' => 0,
+ 'value' => self::$serviceid
+ ]
+ ]
+ ],
+ 'operations' => [
+ [
+ 'esc_period' => 0,
+ 'esc_step_from' => 1,
+ 'esc_step_to' => 1,
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Problem',
+ 'subject' => 'Problem'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ],
+ 'recovery_operations' => [
+ [
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Recovery',
+ 'subject' => 'Recovery'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ],
+ 'update_operations' => [
+ [
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Update',
+ 'subject' => 'Update'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ]
+ ]
+ );
+ $this->assertArrayHasKey('actionids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['actionids']);
+ self::$actionid = $response['result']['actionids'][0];
+
+ return true;
+ }
+
+ /**
+ * Component configuration provider for agent related tests.
+ *
+ * @return array
+ */
+ public function serverConfigurationProvider() {
+ return [
+ self::COMPONENT_SERVER => [
+ 'DebugLevel' => 4,
+ 'LogFileSize' => 20
+ ]
+ ];
+ }
+
+ /**
+ * Check alerting based on service action.
+ *
+ * @backup actions,alerts,history_uint,events,problem,service_problem,triggers,escalations
+ */
+ public function testAlertingForServices_checkServiceStatusChange() {
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 1);
+
+ $response = $this->callUntilDataIsPresent('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE
+ ], 25, 2);
+ $this->assertCount(1, $response['result']);
+ $this->assertEquals('Problem', $response['result'][0]['message']);
+ $this->assertEquals('Problem', $response['result'][0]['subject']);
+ $this->assertEquals(0, $response['result'][0]['p_eventid']);
+
+ $response = $this->callUntilDataIsPresent('event.get', [
+ 'objectids' => self::$triggerid
+ ], 25, 2);
+ $this->assertArrayHasKey(0, $response['result']);
+ $eventid = $response['result'][0]['eventid'];
+
+ $response = $this->call('event.acknowledge', [
+ 'eventids' => $eventid,
+ 'action' => ZBX_PROBLEM_UPDATE_SEVERITY,
+ 'message' => 'disaster',
+ 'severity' => TRIGGER_SEVERITY_DISASTER
+ ]);
+ $this->assertArrayHasKey('eventids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['eventids']);
+
+ sleep(12);
+
+ $response = $this->callUntilDataIsPresent('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE
+ ], 25, 2);
+ $this->assertCount(2, $response['result']);
+
+ // Check if new problem event was added
+ $response = $this->call('problem.get', [
+ 'output' => 'extend',
+ 'source' => EVENT_SOURCE_SERVICE,
+ 'object' => EVENT_OBJECT_SERVICE
+ ]
+ );
+ $this->assertArrayHasKey(0, $response['result']);
+ $this->assertEquals(TRIGGER_SEVERITY_HIGH, $response['result'][0]['severity']);
+ $expected_eventname = 'Status of service "' . self::SERVICENAME . '" changed to High';
+ $this->assertEquals($expected_eventname, $response['result'][0]['name']);
+
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 0);
+
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_recover()', true, 120);
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_recover()', true);
+
+ $response = $this->callUntilDataIsPresent('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE,
+ 'sortfield' => 'alertid'
+ ], 25, 3);
+ $this->assertCount(3, $response['result']);
+ $this->assertEquals('Recovery', $response['result'][2]['message']);
+ $this->assertEquals('Recovery', $response['result'][2]['subject']);
+ $this->assertNotEquals(0, $response['result'][2]['p_eventid']);
+
+ // Check recovery event
+ $response = $this->callUntilDataIsPresent('event.get', [
+ 'output' => 'extend',
+ 'source' => EVENT_SOURCE_SERVICE,
+ 'object' => EVENT_OBJECT_SERVICE,
+ 'value' => 0
+ ], 25, 3);
+ $this->assertArrayHasKey(0, $response['result']);
+ $this->assertEquals(ZBX_SEVERITY_OK, $response['result'][0]['severity']);
+ $expected_eventname = 'Status of service "' . self::SERVICENAME . '" changed to OK';
+ $this->assertEquals($expected_eventname, $response['result'][0]['name']);
+
+ return true;
+ }
+
+ /**
+ * Check alerting based on service action (without update operation, but with updated severity).
+ *
+ * @backup actions,alerts,history_uint,events,problem,service_problem,triggers,escalations
+ */
+ public function testAlertingForServices_checkServiceStatusChangeWoUpdate() {
+ $response = $this->call('action.update', [
+ 'actionid' => self::$actionid,
+ 'esc_period' => '1m',
+ 'operations' => [
+ [
+ 'esc_period' => 0,
+ 'esc_step_from' => 1,
+ 'esc_step_to' => 1,
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Problem',
+ 'subject' => 'Problem'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ],
+ 'recovery_operations' => [
+ [
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Recovery',
+ 'subject' => 'Recovery'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ],
+ 'update_operations' => [
+ ]
+ ]);
+ $this->assertArrayHasKey('actionids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['actionids']);
+
+ $this->reloadConfigurationCache();
+
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 1);
+
+ $response = $this->callUntilDataIsPresent('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE
+ ], 25, 2);
+ $this->assertCount(1, $response['result']);
+ $this->assertEquals('Problem', $response['result'][0]['message']);
+ $this->assertEquals('Problem', $response['result'][0]['subject']);
+ $this->assertEquals(0, $response['result'][0]['p_eventid']);
+
+ $response = $this->callUntilDataIsPresent('event.get', [
+ 'objectids' => self::$triggerid
+ ], 25, 2);
+ $this->assertArrayHasKey(0, $response['result']);
+ $eventid = $response['result'][0]['eventid'];
+
+ $response = $this->call('event.acknowledge', [
+ 'eventids' => $eventid,
+ 'action' => ZBX_PROBLEM_UPDATE_SEVERITY,
+ 'message' => 'disaster',
+ 'severity' => TRIGGER_SEVERITY_DISASTER
+ ]);
+ $this->assertArrayHasKey('eventids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['eventids']);
+
+ sleep(10);
+
+ $response = $this->callUntilDataIsPresent('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE
+ ], 25, 2);
+ $this->assertCount(1, $response['result']);
+
+ // Check if new problem event was added
+ $response = $this->call('problem.get', [
+ 'output' => 'extend',
+ 'source' => EVENT_SOURCE_SERVICE,
+ 'object' => EVENT_OBJECT_SERVICE
+ ]
+ );
+ $this->assertArrayHasKey(0, $response['result']);
+ $this->assertEquals(TRIGGER_SEVERITY_HIGH, $response['result'][0]['severity']);
+ $expected_eventname = 'Status of service "' . self::SERVICENAME . '" changed to High';
+ $this->assertEquals($expected_eventname, $response['result'][0]['name']);
+
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 0);
+
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_recover()', true, 120);
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_recover()', true);
+
+ $response = $this->callUntilDataIsPresent('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE,
+ 'sortfield' => 'alertid'
+ ], 25, 3);
+ $this->assertCount(2, $response['result']);
+ $this->assertEquals('Recovery', $response['result'][1]['message']);
+ $this->assertEquals('Recovery', $response['result'][1]['subject']);
+ $this->assertNotEquals(0, $response['result'][1]['p_eventid']);
+
+ // Check recovery event
+ $response = $this->callUntilDataIsPresent('event.get', [
+ 'output' => 'extend',
+ 'source' => EVENT_SOURCE_SERVICE,
+ 'object' => EVENT_OBJECT_SERVICE,
+ 'value' => 0
+ ], 25, 3);
+ $this->assertArrayHasKey(0, $response['result']);
+ $this->assertEquals(ZBX_SEVERITY_OK, $response['result'][0]['severity']);
+ $expected_eventname = 'Status of service "' . self::SERVICENAME . '" changed to OK';
+ $this->assertEquals($expected_eventname, $response['result'][0]['name']);
+
+ return true;
+ }
+
+ /**
+ * Check SERVICE.* macros.
+ *
+ * @backup alerts,history,events,triggers,services
+ */
+ public function testAlertingForServices_checkMacros() {
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 0);
+ $this->reloadConfigurationCache();
+
+ $response = $this->call('action.update', [
+ 'actionid' => self::$actionid,
+ 'esc_period' => '1m',
+ 'operations' => [
+ [
+ 'esc_period' => 0,
+ 'esc_step_from' => 1,
+ 'esc_step_to' => 1,
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => '{SERVICE.NAME}|{SERVICE.TAGS}|{SERVICE.TAGSJSON}|{SERVICE.ROOTCAUSE}',
+ 'subject' => 'Problem'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ]
+ ]);
+ $this->assertArrayHasKey('actionids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['actionids']);
+
+ $this->reloadConfigurationCache();
+
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 1);
+
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 120);
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true);
+
+ $response = $this->call('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE
+ ]);
+ $this->assertArrayHasKey(0, $response['result']);
+
+ $service_macros = explode('|', $response['result'][0]['message']);
+
+ $rootcause = '/Host: "' . self::HOSTNAME . '" Problem name: "' . self::TRIGGER_DESC .'" Severity: "' .
+ 'High" Age: [0-9]+s Problem tags: "' . self::$problem_tags . '"/ ';
+
+ $this->assertEquals(self::SERVICENAME, $service_macros[0]);
+ $this->assertEmpty($service_macros[1]);
+ $this->assertEquals('[]', $service_macros[2]);
+
+ $this->assertEquals(1, preg_match($rootcause, $service_macros[3], $matches));
+ }
+
+ /**
+ * Check escalation steps.
+ *
+ * @backup alerts,history,events,triggers,services
+ */
+ public function testAlertingForServices_checkEscalationSteps() {
+ $response = $this->call('action.update', [
+ 'actionid' => self::$actionid,
+ 'esc_period' => '1m',
+ 'operations' => [
+ [
+ 'esc_period' => 0,
+ 'esc_step_from' => 1,
+ 'esc_step_to' => 1,
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Problem',
+ 'subject' => 'Problem'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ],
+ [
+ 'esc_period' => 0,
+ 'esc_step_from' => 2,
+ 'esc_step_to' => 2,
+ 'operationtype' => OPERATION_TYPE_MESSAGE,
+ 'opmessage' => [
+ 'default_msg' => 0,
+ 'mediatypeid' => 0,
+ 'message' => 'Problem',
+ 'subject' => 'Problem'
+ ],
+ 'opmessage_grp' => [['usrgrpid' => 7]]
+ ]
+ ]
+ ]);
+ $this->assertArrayHasKey('actionids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['actionids']);
+
+ $this->reloadConfigurationCache();
+
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 1);
+
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 120);
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true);
+
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 120);
+ $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true);
+
+ $response = $this->call('alert.get', [
+ 'output' => 'extend',
+ 'actionsids' => self::$actionid,
+ 'eventsource' => EVENT_SOURCE_SERVICE,
+ 'eventobject' => EVENT_OBJECT_SERVICE,
+ 'sortfield' => 'alertid'
+ ]
+ );
+ $this->assertCount(2, $response['result']);
+ $this->assertEquals(1, $response['result'][0]['esc_step']);
+ $this->assertEquals(2, $response['result'][1]['esc_step']);
+
+ return true;
+ }
+
+ /**
+ * Test suite for alerting for services.
+ *
+ * @backup alerts,history,events,triggers,services
+ */
+ public function testAlertingForServices_checkTwoTriggers() {
+ $this->reloadConfigurationCache();
+ // Create trigger
+ $trigger_desc_2 = self::TRIGGER_DESC . '2';
+ $response = $this->call('trigger.create', [
+ 'description' => $trigger_desc_2,
+ 'priority' => TRIGGER_SEVERITY_DISASTER,
+ 'status' => TRIGGER_STATUS_ENABLED,
+ 'type' => 0,
+ 'recovery_mode' => 0,
+ 'manual_close' => ZBX_TRIGGER_MANUAL_CLOSE_NOT_ALLOWED,
+ 'expression' => 'last(/' . self::HOSTNAME . '/' . self::TRAPPER_KEY . ')=1'
+ ]);
+ $this->assertArrayHasKey('triggerids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['triggerids']);
+ $trigger_id_2 = $response['result']['triggerids'][0];
+
+ $response = $this->call('trigger.update', [
+ 'triggerid' => $trigger_id_2,
+ 'tags' => [
+ [
+ 'tag' => 'ServiceLink',
+ 'value' => $trigger_id_2 . ':' . $trigger_desc_2
+ ]
+ ]
+ ]);
+
+ $serviceid_child1 = $this->createServiceWithProblemTags('Child service (disaster)', [[
+ 'tag' => 'ServiceLink',
+ 'operator' => 0,
+ 'value' => $trigger_id_2 . ':' . $trigger_desc_2
+ ]]);
+
+ $serviceid_child2 = $this->createServiceWithProblemTags('Child service (high)', [[
+ 'tag' => 'ServiceLink',
+ 'operator' => 0,
+ 'value' => self::$triggerid . ':' . self::TRIGGER_DESC
+ ]]);
+
+ // Update service
+ $response = $this->call('service.update', [
+ 'serviceid' => self::$serviceid,
+ 'children' => [
+ ['serviceid' => $serviceid_child1],
+ ['serviceid' => $serviceid_child2]
+ ],
+ 'problem_tags' => []
+ ]);
+ $this->assertArrayHasKey('serviceids', $response['result']);
+ $this->assertArrayHasKey(0, $response['result']['serviceids']);
+
+ $this->reloadConfigurationCache();
+
+ $this->sendSenderValue(self::HOSTNAME, self::TRAPPER_KEY, 1);
+
+ $response = $this->callUntilDataIsPresent('service.get', [
+ 'output' => 'extend',
+ 'serviceids' => self::$serviceid
+ ], 25, 3);
+ $this->assertArrayHasKey(0, $response['result']);
+ $this->assertArrayHasKey('status', $response['result'][0]);
+ $this->assertEquals(TRIGGER_SEVERITY_DISASTER, $response['result'][0]['status']);
+
+ return true;
+ }
+}
diff --git a/ui/tests/selenium/common/testSystemInformation.php b/ui/tests/selenium/common/testSystemInformation.php
index f4a966fc7f4..181874c04d4 100644
--- a/ui/tests/selenium/common/testSystemInformation.php
+++ b/ui/tests/selenium/common/testSystemInformation.php
@@ -77,7 +77,7 @@ class testSystemInformation extends CWebTest {
'ha_nodeid' => 'ckvaw9wlf0001tn7psxgh3wfo',
'name' => 'Active node',
'address' => $DB['SERVER'],
- 'port' => $DB['PORT'],
+ 'port' => 0,
'lastaccess' => self::$active_lastaccess,
'status' => 3,
'ha_sessionid' => 'ckvaw9wjo0000td7p8j66e74x'
@@ -174,7 +174,7 @@ class testSystemInformation extends CWebTest {
// Check Zabbix server address and port for each record in the HA cluster nodes table.
if ($name === 'Active node') {
self::$skip_fields[] = $row->getColumn('Address');
- $this->assertEquals($DB['SERVER'].':'.$DB['PORT'], $row->getColumn('Address')->getText());
+ $this->assertEquals($DB['SERVER'].':0', $row->getColumn('Address')->getText());
}
}
@@ -182,7 +182,7 @@ class testSystemInformation extends CWebTest {
* Check and hide the active Zabbix server address in widget that is working in System stats mode or in the part
* of the report that displays the overall system statistics.
*/
- $this->assertEquals($DB['SERVER'].':'.$DB['PORT'], $server_address->getText());
+ $this->assertEquals($DB['SERVER'].':0', $server_address->getText());
self::$skip_fields[] = $server_address;
// Hide the footer of the report as it contains Zabbix version.
diff --git a/ui/tests/selenium/testFormAdministrationAuthenticationLdap.php b/ui/tests/selenium/testFormAdministrationAuthenticationLdap.php
index d9934a19ebc..2ee9a6f8538 100644
--- a/ui/tests/selenium/testFormAdministrationAuthenticationLdap.php
+++ b/ui/tests/selenium/testFormAdministrationAuthenticationLdap.php
@@ -44,7 +44,7 @@ class testFormAdministrationAuthenticationLdap extends CWebTest {
[
'ldap_settings' => [
'Enable LDAP authentication' => true,
- 'LDAP host' => 'ldap.forumsys.com'
+ 'LDAP host' => 'ipa.demo1.freeipa.org'
],
'error' => 'Incorrect value for field "ldap_base_dn": cannot be empty.'
]
@@ -53,8 +53,8 @@ class testFormAdministrationAuthenticationLdap extends CWebTest {
[
'ldap_settings' => [
'Enable LDAP authentication' => true,
- 'LDAP host' => 'ldap.forumsys.com',
- 'Base DN' => 'dc=example,dc=com'
+ 'LDAP host' => 'ipa.demo1.freeipa.org',
+ 'Base DN' => 'cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org'
],
'error' => 'Incorrect value for field "ldap_search_attribute": cannot be empty.'
]
@@ -63,8 +63,8 @@ class testFormAdministrationAuthenticationLdap extends CWebTest {
[
'ldap_settings' => [
'Enable LDAP authentication' => true,
- 'LDAP host' => 'ldap.forumsys.com',
- 'Base DN' => 'dc=example,dc=com',
+ 'LDAP host' => 'ipa.demo1.freeipa.org',
+ 'Base DN' => 'cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
'Search attribute' => 'uid'
],
'error' => 'Login name or password is incorrect.'
@@ -74,10 +74,10 @@ class testFormAdministrationAuthenticationLdap extends CWebTest {
[
'ldap_settings' => [
'Enable LDAP authentication' => true,
- 'LDAP host' => 'ldap.forumsys.com',
- 'Base DN' => 'dc=example,dc=com',
+ 'LDAP host' => 'ipa.demo1.freeipa.org',
+ 'Base DN' => 'cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
'Search attribute' => 'uid',
- 'Login' => 'galieleo'
+ 'Login' => 'admin'
],
'error' => 'Login name or password is incorrect.'
]
@@ -86,10 +86,10 @@ class testFormAdministrationAuthenticationLdap extends CWebTest {
[
'ldap_settings' => [
'Enable LDAP authentication' => true,
- 'LDAP host' => 'ldap.forumsys.com',
- 'Base DN' => 'dc=example,dc=com',
+ 'LDAP host' => 'ipa.demo1.freeipa.org',
+ 'Base DN' => 'cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
'Search attribute' => 'uid',
- 'Bind password' => 'password'
+ 'Bind password' => 'Secret123'
],
'error' => 'Incorrect value for field "ldap_bind_dn": cannot be empty.'
]
@@ -100,23 +100,23 @@ class testFormAdministrationAuthenticationLdap extends CWebTest {
'password' => 'zabbix',
'ldap_settings' => [
'Enable LDAP authentication' => true,
- 'LDAP host' => 'ldap.forumsys.com',
+ 'LDAP host' => 'ipa.demo1.freeipa.org',
'Port' => '389',
- 'Base DN' => 'dc=example,dc=com',
+ 'Base DN' => 'cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
'Search attribute' => 'uid',
- 'Bind DN' => 'cn=read-only-admin,dc=example,dc=com',
+ 'Bind DN' => 'uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
'Case-sensitive login' => true,
- 'Bind password' => 'password',
- 'Login' => 'galieleo',
- 'User password' => 'password'
+ 'Bind password' => 'Secret123',
+ 'Login' => 'admin',
+ 'User password' => 'Secret123'
],
'db_check' => [
'authentication_type' => '1',
- 'ldap_host' => 'ldap.forumsys.com',
+ 'ldap_host' => 'ipa.demo1.freeipa.org',
'ldap_port' => '389',
- 'ldap_base_dn' => 'dc=example,dc=com',
- 'ldap_bind_dn' => 'cn=read-only-admin,dc=example,dc=com',
- 'ldap_bind_password' => 'password',
+ 'ldap_base_dn' => 'cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
+ 'ldap_bind_dn' => 'uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
+ 'ldap_bind_password' => 'Secret123',
'ldap_search_attribute' => 'uid',
'http_auth_enabled' => '0',
'http_login_form' => '0',