diff options
author | Andrejs Verza <andrejs.verza@zabbix.com> | 2020-10-11 11:10:21 +0300 |
---|---|---|
committer | Andrejs Verza <andrejs.verza@zabbix.com> | 2020-10-11 11:10:21 +0300 |
commit | 9e7ea552f0dc6af69881656c1c4995d9320ed41b (patch) | |
tree | 00e1ce11a4985847b070d138139802e10d35e9f0 /ui/app | |
parent | 617c51a6641d9d792b4f2f340ed428a3f4877c42 (diff) | |
parent | 5d4bbbeb417f13ac4e8d6e5bc64efaab0c14f6b3 (diff) |
.......... [ZBXNEXT-6001] updated to the latest master branch (conflicts solved)
Diffstat (limited to 'ui/app')
30 files changed, 2588 insertions, 1081 deletions
diff --git a/ui/app/controllers/CControllerHost.php b/ui/app/controllers/CControllerHost.php index 171d8985d69..c9ad329f56e 100644 --- a/ui/app/controllers/CControllerHost.php +++ b/ui/app/controllers/CControllerHost.php @@ -25,8 +25,29 @@ */ abstract class CControllerHost extends CController { + // Filter idx prefix. + const FILTER_IDX = 'web.monitoring.hosts'; + + // Filter fields default values. + const FILTER_FIELDS_DEFAULT = [ + 'name' => '', + 'groupids' => [], + 'ip' => '', + 'dns' => '', + 'port' => '', + 'status' => -1, + 'evaltype' => TAG_EVAL_TYPE_AND_OR, + 'tags' => [], + 'severities' => [], + 'show_suppressed' => ZBX_PROBLEM_SUPPRESSED_FALSE, + 'maintenance_status' => HOST_MAINTENANCE_STATUS_ON, + 'page' => null, + 'sort' => 'name', + 'sortorder' => ZBX_SORT_UP + ]; + /** - * Prepares the host list based on the given filter and sorting options. + * Get host list results count for passed filter. * * @param array $filter Filter options. * @param string $filter['name'] Filter hosts by name. @@ -40,51 +61,61 @@ abstract class CControllerHost extends CController { * @param string $filter['severities'] Filter problems on hosts by severities. * @param string $filter['show_suppressed'] Filter suppressed problems. * @param int $filter['maintenance_status'] Filter hosts by maintenance. - * @param int $filter['page'] Page number. - * @param string $sort Sorting field. - * @param string $sortorder Sorting order. * - * @return array + * @return int */ - protected function prepareData(array $filter, string $sort, string $sortorder): array { - $child_groups = []; - - // Multiselect host groups. - $multiselect_hostgroup_data = []; - - if ($filter['groupids']) { - $groups = API::HostGroup()->get([ - 'output' => ['groupid', 'name'], - 'groupids' => $filter['groupids'], - 'preservekeys' => true - ]); + protected function getCount(array $filter): int { + $groupids = $filter['groupids'] ? getSubGroups($filter['groupids']) : null; - if ($groups) { - $subgroup_names = []; - - foreach ($groups as $group) { - $subgroup_names[] = $group['name'].'/'; - - $multiselect_hostgroup_data[] = [ - 'id' => $group['groupid'], - 'name' => $group['name'] - ]; - } - - $groups += API::HostGroup()->get([ - 'output' => ['groupid'], - 'search' => ['name' => $subgroup_names], - 'startSearch' => true, - 'searchByAny' => true, - 'preservekeys' => true - ]); - } + return (int) API::Host()->get([ + 'countOutput' => true, + 'evaltype' => $filter['evaltype'], + 'tags' => $filter['tags'], + 'inheritedTags' => true, + 'groupids' => $groupids ? $groupids : null, + 'severities' => $filter['severities'] ? $filter['severities'] : null, + 'withProblemsSuppressed' => $filter['severities'] + ? (($filter['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) ? null : false) + : null, + 'search' => [ + 'name' => ($filter['name'] === '') ? null : $filter['name'], + 'ip' => ($filter['ip'] === '') ? null : $filter['ip'], + 'dns' => ($filter['dns'] === '') ? null : $filter['dns'] + ], + 'filter' => [ + 'status' => ($filter['status'] == -1) ? null : $filter['status'], + 'port' => ($filter['port'] === '') ? null : $filter['port'], + 'maintenance_status' => ($filter['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) + ? null + : HOST_MAINTENANCE_STATUS_OFF + ], + 'limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1 + ]); + } - $groupids = array_keys($groups); - } - else { - $groupids = null; - } + /** + * Prepares the host list based on the given filter and sorting options. + * + * @param array $filter Filter options. + * @param string $filter['name'] Filter hosts by name. + * @param array $filter['groupids'] Filter hosts by host groups. + * @param string $filter['ip'] Filter hosts by IP. + * @param string $filter['dns'] Filter hosts by DNS. + * @param string $filter['port'] Filter hosts by port. + * @param string $filter['status'] Filter hosts by status. + * @param string $filter['evaltype'] Filter hosts by tags. + * @param string $filter['tags'] Filter hosts by tag names and values. + * @param string $filter['severities'] Filter problems on hosts by severities. + * @param string $filter['show_suppressed'] Filter supressed problems. + * @param int $filter['maintenance_status'] Filter hosts by maintenance. + * @param int $filter['page'] Page number. + * @param string $filter['sort'] Sorting field. + * @param string $filter['sortorder'] Sorting order. + * + * @return array + */ + protected function getData(array $filter): array { + $groupids = $filter['groupids'] ? getSubGroups($filter['groupids'], $filter_groups) : null; $limit = CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1; $hosts = API::Host()->get([ @@ -92,7 +123,7 @@ abstract class CControllerHost extends CController { 'evaltype' => $filter['evaltype'], 'tags' => $filter['tags'], 'inheritedTags' => true, - 'groupids' => $groupids, + 'groupids' => $groupids ? $groupids : null, 'severities' => $filter['severities'] ? $filter['severities'] : null, 'withProblemsSuppressed' => $filter['severities'] ? (($filter['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) ? null : false) @@ -115,14 +146,14 @@ abstract class CControllerHost extends CController { ]); // Sort for paging so we know which IDs go to which page. - CArrayHelper::sort($hosts, [['field' => $sort, 'order' => $sortorder]]); + CArrayHelper::sort($hosts, [['field' => $filter['sort'], 'order' => $filter['sortorder']]]); - $view_curl = (new CUrl('zabbix.php'))->setArgument('action', 'host.view'); + $view_curl = (new CUrl())->setArgument('action', 'host.view'); // Split result array and create paging. - $paging = CPagerHelper::paginate($filter['page'], $hosts, $sortorder, $view_curl); + $paging = CPagerHelper::paginate($filter['page'], $hosts, $filter['sortorder'], $view_curl); - // Get additional data to limited host amount. + // Get additonal data to limited host amount. $hosts = API::Host()->get([ 'output' => ['hostid', 'name', 'status', 'maintenance_status', 'maintenanceid', 'maintenance_type', 'available', 'snmp_available', 'jmx_available', 'ipmi_available', 'error', 'ipmi_error', 'snmp_error', @@ -137,7 +168,7 @@ abstract class CControllerHost extends CController { 'preservekeys' => true ]); // Re-sort the results again. - CArrayHelper::sort($hosts, [['field' => $sort, 'order' => $sortorder]]); + CArrayHelper::sort($hosts, [['field' => $filter['sort'], 'order' => $filter['sortorder']]]); $maintenanceids = []; @@ -234,11 +265,46 @@ abstract class CControllerHost extends CController { return [ 'paging' => $paging, - 'view_curl' => $view_curl, 'hosts' => $hosts, - 'maintenances' => $maintenances, - 'multiselect_hostgroup_data' => $multiselect_hostgroup_data, - 'filter' => $filter + 'maintenances' => $maintenances ]; } + + /** + * Get additional data for filters. Selected groups for multiselect, etc. + * + * @param array $filter Filter fields values array. + * + * @return array + */ + protected function getAdditionalData($filter): array { + $data = []; + + if ($filter['groupids']) { + $groups= API::HostGroup()->get([ + 'output' => ['groupid', 'name'], + 'groupids' => $filter['groupids'] + ]); + $data['groups_multiselect'] = CArrayHelper::renameObjectsKeys(array_values($groups), ['groupid' => 'id']); + } + + return $data; + } + + /** + * Clean passed filter fields in input from default values required for HTML presentation. Convert field + * + * @param array $input Filter fields values. + * + * @return array + */ + protected function cleanInput(array $input): array { + if (array_key_exists('tags', $input) && $input['tags']) { + $input['tags'] = array_filter($input['tags'], function($tag) { + return !($tag['tag'] === '' && $tag['value'] === ''); + }); + } + + return $input; + } } diff --git a/ui/app/controllers/CControllerHostView.php b/ui/app/controllers/CControllerHostView.php index 83a8ae673c3..8d7eb96df5c 100644 --- a/ui/app/controllers/CControllerHostView.php +++ b/ui/app/controllers/CControllerHostView.php @@ -28,29 +28,32 @@ class CControllerHostView extends CControllerHost { protected function checkInput(): bool { $fields = [ - 'sort' => 'in name,status', - 'sortorder' => 'in '.ZBX_SORT_UP.','.ZBX_SORT_DOWN, - 'page' => 'ge 1', - 'filter_set' => 'in 1', - 'filter_rst' => 'in 1', - 'filter_name' => 'string', - 'filter_groupids' => 'array_id', - 'filter_ip' => 'string', - 'filter_dns' => 'string', - 'filter_port' => 'string', - 'filter_status' => 'in -1,'.HOST_STATUS_MONITORED.','.HOST_STATUS_NOT_MONITORED, - 'filter_evaltype' => 'in '.TAG_EVAL_TYPE_AND_OR.','.TAG_EVAL_TYPE_OR, - 'filter_tags' => 'array', - 'filter_severities' => 'array', - 'filter_show_suppressed' => 'in '.ZBX_PROBLEM_SUPPRESSED_FALSE.','.ZBX_PROBLEM_SUPPRESSED_TRUE, - 'filter_maintenance_status' => 'in '.HOST_MAINTENANCE_STATUS_OFF.','.HOST_MAINTENANCE_STATUS_ON + 'name' => 'string', + 'groupids' => 'array_id', + 'ip' => 'string', + 'dns' => 'string', + 'port' => 'string', + 'status' => 'in -1,'.HOST_STATUS_MONITORED.','.HOST_STATUS_NOT_MONITORED, + 'evaltype' => 'in '.TAG_EVAL_TYPE_AND_OR.','.TAG_EVAL_TYPE_OR, + 'tags' => 'array', + 'severities' => 'array', + 'show_suppressed' => 'in '.ZBX_PROBLEM_SUPPRESSED_FALSE.','.ZBX_PROBLEM_SUPPRESSED_TRUE, + 'maintenance_status' => 'in '.HOST_MAINTENANCE_STATUS_OFF.','.HOST_MAINTENANCE_STATUS_ON, + 'sort' => 'in name,status', + 'sortorder' => 'in '.ZBX_SORT_UP.','.ZBX_SORT_DOWN, + 'page' => 'ge 1', + 'filter_name' => 'string', + 'filter_custom_time' => 'in 1,0', + 'filter_show_counter' => 'in 1,0', + 'filter_counters' => 'in 1', + 'counter_index' => 'ge 0' ]; $ret = $this->validateInput($fields); // Validate tags filter. - if ($ret && $this->hasInput('filter_tags')) { - foreach ($this->getInput('filter_tags') as $filter_tag) { + if ($ret && $this->hasInput('tags')) { + foreach ($this->getInput('tags') as $filter_tag) { if (count($filter_tag) != 3 || !array_key_exists('tag', $filter_tag) || !is_string($filter_tag['tag']) || !array_key_exists('value', $filter_tag) || !is_string($filter_tag['value']) @@ -62,13 +65,10 @@ class CControllerHostView extends CControllerHost { } // Validate severity checkbox filter. - if ($ret && $this->hasInput('filter_severities')) { - foreach ($this->getInput('filter_severities') as $severity) { - if (!in_array($severity, range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1))) { - $ret = false; - break; - } - } + if ($ret && $this->hasInput('severities')) { + $ret = !array_diff($this->getInput('severities'), + range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1) + ); } if (!$ret) { @@ -83,118 +83,34 @@ class CControllerHostView extends CControllerHost { } protected function doAction(): void { - $sort = $this->getInput('sort', CProfile::get('web.hostsmon.sort', 'name')); - $sortorder = $this->getInput('sortorder', CProfile::get('web.hostsmon.sortorder', ZBX_SORT_UP)); - $active_tab = CProfile::get('web.hostsmon.filter.active', 1); - CProfile::update('web.hostsmon.filter.active', $active_tab, PROFILE_TYPE_INT); - CProfile::update('web.hostsmon.sort', $sort, PROFILE_TYPE_STR); - CProfile::update('web.hostsmon.sortorder', $sortorder, PROFILE_TYPE_STR); - - // filter - if ($this->hasInput('filter_set')) { - CProfile::update('web.hostsmon.filter.name', $this->getInput('filter_name', ''), PROFILE_TYPE_STR); - CProfile::updateArray('web.hostsmon.filter.groupids', $this->getInput('filter_groupids', []), - PROFILE_TYPE_ID - ); - CProfile::update('web.hostsmon.filter.ip', $this->getInput('filter_ip', ''), PROFILE_TYPE_STR); - CProfile::update('web.hostsmon.filter.dns', $this->getInput('filter_dns', ''), PROFILE_TYPE_STR); - CProfile::update('web.hostsmon.filter.port', $this->getInput('filter_port', ''), PROFILE_TYPE_STR); - $severities = $this->getInput('filter_severities', []); - CProfile::updateArray('web.hostsmon.filter.severities', $severities, PROFILE_TYPE_INT); - CProfile::update('web.hostsmon.filter.status', getRequest('filter_status', -1), PROFILE_TYPE_INT); - - $filter_tags = ['tags' => [], 'values' => [], 'operators' => []]; - foreach ($this->getInput('filter_tags', []) as $filter_tag) { - if ($filter_tag['tag'] === '' && $filter_tag['value'] === '') { - continue; - } - - $filter_tags['tags'][] = $filter_tag['tag']; - $filter_tags['values'][] = $filter_tag['value']; - $filter_tags['operators'][] = $filter_tag['operator']; - } - - CProfile::update('web.hostsmon.filter.evaltype', $this->getInput('filter_evaltype', TAG_EVAL_TYPE_AND_OR), - PROFILE_TYPE_INT - ); - CProfile::updateArray('web.hostsmon.filter.tags.tag', $filter_tags['tags'], PROFILE_TYPE_STR); - CProfile::updateArray('web.hostsmon.filter.tags.value', $filter_tags['values'], PROFILE_TYPE_STR); - CProfile::updateArray('web.hostsmon.filter.tags.operator', $filter_tags['operators'], PROFILE_TYPE_INT); - CProfile::update('web.hostsmon.filter.show_suppressed', - $this->getInput('filter_show_suppressed', ZBX_PROBLEM_SUPPRESSED_FALSE), PROFILE_TYPE_INT - ); - CProfile::update('web.hostsmon.filter.maintenance_status', - $this->getInput('filter_maintenance_status', HOST_MAINTENANCE_STATUS_ON), PROFILE_TYPE_INT - ); - } - elseif ($this->hasInput('filter_rst')) { - CProfile::delete('web.hostsmon.filter.name'); - CProfile::deleteIdx('web.hostsmon.filter.groupids'); - CProfile::delete('web.hostsmon.filter.ip'); - CProfile::delete('web.hostsmon.filter.dns'); - CProfile::delete('web.hostsmon.filter.port'); - CProfile::deleteIdx('web.hostsmon.filter.severities'); - CProfile::delete('web.hostsmon.filter.status'); - CProfile::delete('web.hostsmon.filter.show_suppressed'); - CProfile::delete('web.hostsmon.filter.maintenance_status'); - CProfile::delete('web.hostsmon.filter.evaltype'); - CProfile::deleteIdx('web.hostsmon.filter.tags.tag'); - CProfile::deleteIdx('web.hostsmon.filter.tags.value'); - CProfile::deleteIdx('web.hostsmon.filter.tags.operator'); - } + $filter_tabs = []; + $profile = (new CTabFilterProfile(static::FILTER_IDX, static::FILTER_FIELDS_DEFAULT)) + ->read() + ->setInput($this->cleanInput($this->getInputAll())); - $filter_tags = []; - foreach (CProfile::getArray('web.hostsmon.filter.tags.tag', []) as $i => $tag) { - $filter_tags[] = [ - 'tag' => $tag, - 'value' => CProfile::get('web.hostsmon.filter.tags.value', null, $i), - 'operator' => CProfile::get('web.hostsmon.filter.tags.operator', null, $i) - ]; + foreach ($profile->getTabsWithDefaults() as $filter_tab) { + $filter_tabs[] = $filter_tab + ['filter_view_data' => $this->getAdditionalData($filter_tab)]; } - CArrayHelper::sort($filter_tags, ['tag', 'value', 'operator']); - - $filter = [ - 'name' => CProfile::get('web.hostsmon.filter.name', ''), - 'groupids' => CProfile::getArray('web.hostsmon.filter.groupids', []), - 'ip' => CProfile::get('web.hostsmon.filter.ip', ''), - 'dns' => CProfile::get('web.hostsmon.filter.dns', ''), - 'port' => CProfile::get('web.hostsmon.filter.port', ''), - 'status' => CProfile::get('web.hostsmon.filter.status', -1), - 'evaltype' => CProfile::get('web.hostsmon.filter.evaltype', TAG_EVAL_TYPE_AND_OR), - 'tags' => $filter_tags, - 'severities' => CProfile::getArray('web.hostsmon.filter.severities', []), - 'show_suppressed' => CProfile::get('web.hostsmon.filter.show_suppressed', ZBX_PROBLEM_SUPPRESSED_FALSE), - 'maintenance_status' => CProfile::get('web.hostsmon.filter.maintenance_status', HOST_MAINTENANCE_STATUS_ON), - 'page' => $this->hasInput('page') ? $this->getInput('page') : null - ]; - $refresh_curl = (new CUrl('zabbix.php')) - ->setArgument('action', 'host.view.refresh') - ->setArgument('filter_name', $filter['name']) - ->setArgument('filter_groupids', $filter['groupids']) - ->setArgument('filter_ip', $filter['ip']) - ->setArgument('filter_dns', $filter['dns']) - ->setArgument('filter_port', $filter['port']) - ->setArgument('filter_status', $filter['status']) - ->setArgument('filter_evaltype', $filter['evaltype']) - ->setArgument('filter_tags', $filter['tags']) - ->setArgument('filter_severities', $filter['severities']) - ->setArgument('filter_show_suppressed', $filter['show_suppressed']) - ->setArgument('filter_maintenance_status', $filter['maintenance_status']) - ->setArgument('sort', $sort) - ->setArgument('sortorder', $sortorder) - ->setArgument('page', $filter['page']); - - $prepared_data = $this->prepareData($filter, $sort, $sortorder); + $filter = $profile->getTabFilter($profile->selected); + $refresh_curl = new CUrl('zabbix.php'); + $filter['action'] = 'host.view.refresh'; + array_map([$refresh_curl, 'setArgument'], array_keys($filter), $filter); $data = [ - 'filter' => $filter, - 'sort' => $sort, - 'sortorder' => $sortorder, 'refresh_url' => $refresh_curl->getUrl(), 'refresh_interval' => CWebUser::getRefresh() * 1000, - 'active_tab' => $active_tab - ] + $prepared_data; + 'filter_view' => 'monitoring.host.filter', + 'filter_defaults' => $profile->filter_defaults, + 'filter_tabs' => $filter_tabs, + 'tabfilter_options' => [ + 'idx' => static::FILTER_IDX, + 'selected' => $profile->selected, + 'support_custom_time' => 0, + 'expanded' => $profile->expanded, + 'page' => $filter['page'] + ], + ] + $this->getData($filter); $response = new CControllerResponseData($data); $response->setTitle(_('Hosts')); diff --git a/ui/app/controllers/CControllerHostViewRefresh.php b/ui/app/controllers/CControllerHostViewRefresh.php index ae7cfdae677..6ea392e1ea7 100644 --- a/ui/app/controllers/CControllerHostViewRefresh.php +++ b/ui/app/controllers/CControllerHostViewRefresh.php @@ -23,99 +23,46 @@ /** * Controller for the "Host->Monitoring" asynchronous refresh page. */ -class CControllerHostViewRefresh extends CControllerHost { +class CControllerHostViewRefresh extends CControllerHostView { - protected function init(): void { - $this->disableSIDValidation(); - } - - protected function checkInput(): bool { - $fields = [ - 'sort' => 'in name,status', - 'sortorder' => 'in '.ZBX_SORT_UP.','.ZBX_SORT_DOWN, - 'page' => 'ge 1', - 'filter_set' => 'in 1', - 'filter_rst' => 'in 1', - 'filter_name' => 'string', - 'filter_groupids' => 'array_id', - 'filter_ip' => 'string', - 'filter_dns' => 'string', - 'filter_port' => 'string', - 'filter_status' => 'in -1,'.HOST_STATUS_MONITORED.','.HOST_STATUS_NOT_MONITORED, - 'filter_evaltype' => 'in '.TAG_EVAL_TYPE_AND_OR.','.TAG_EVAL_TYPE_OR, - 'filter_tags' => 'array', - 'filter_severities' => 'array', - 'filter_show_suppressed' => 'in '.ZBX_PROBLEM_SUPPRESSED_FALSE.','.ZBX_PROBLEM_SUPPRESSED_TRUE, - 'filter_maintenance_status' => 'in '.HOST_MAINTENANCE_STATUS_OFF.','.HOST_MAINTENANCE_STATUS_ON - ]; + protected function doAction(): void { + $filter = static::FILTER_FIELDS_DEFAULT; - $ret = $this->validateInput($fields); + if ($this->getInput('filter_counters', 0)) { + $profile = (new CTabFilterProfile(static::FILTER_IDX, static::FILTER_FIELDS_DEFAULT))->read(); + $filters = $this->hasInput('counter_index') + ? [$profile->getTabFilter($this->getInput('counter_index'))] + : $profile->getTabsWithDefaults(); + $filter_counters = []; - // Validate tags filter. - if ($ret && $this->hasInput('filter_tags')) { - foreach ($this->getInput('filter_tags') as $filter_tag) { - if (count($filter_tag) != 3 - || !array_key_exists('tag', $filter_tag) || !is_string($filter_tag['tag']) - || !array_key_exists('value', $filter_tag) || !is_string($filter_tag['value']) - || !array_key_exists('operator', $filter_tag) || !is_string($filter_tag['operator'])) { - $ret = false; - break; - } + foreach ($filters as $index => $tabfilter) { + $filter_counters[$index] = $tabfilter['filter_show_counter'] ? $this->getCount($tabfilter) : 0; } - } - // Validate severity checkbox filter. - if ($ret && $this->hasInput('filter_severities')) { - foreach ($this->getInput('filter_severities') as $severity) { - if (!in_array($severity, range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1))) { - $ret = false; - break; - } - } + $this->setResponse( + (new CControllerResponseData([ + 'main_block' => json_encode(['filter_counters' => $filter_counters]) + ]))->disableView() + ); } - - if (!$ret) { - $this->setResponse(new CControllerResponseFatal()); + else { + $this->getInputs($filter, array_keys($filter)); + $filter = $this->cleanInput($filter); + $prepared_data = $this->getData($filter); + + $view_url = (new CUrl()) + ->setArgument('action', 'host.view') + ->removeArgument('page'); + + $data = [ + 'filter' => $filter, + 'view_curl' => $view_url, + 'sort' => $filter['sort'], + 'sortorder' => $filter['sortorder'] + ] + $prepared_data; + + $response = new CControllerResponseData($data); + $this->setResponse($response); } - - return $ret; - } - - protected function checkPermissions(): bool { - return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); - } - - protected function doAction(): void { - $filter = [ - 'name' => $this->getInput('filter_name', ''), - 'groupids' => $this->hasInput('filter_groupids') ? $this->getInput('filter_groupids') : null, - 'ip' => $this->getInput('filter_ip', ''), - 'dns' => $this->getInput('filter_dns', ''), - 'port' => $this->getInput('filter_port', ''), - 'status' => $this->getInput('filter_status', -1), - 'evaltype' => $this->getInput('filter_evaltype', TAG_EVAL_TYPE_AND_OR), - 'tags' => $this->getInput('filter_tags', []), - 'severities' => $this->getInput('filter_severities', []), - 'show_suppressed' => $this->getInput('filter_show_suppressed', ZBX_PROBLEM_SUPPRESSED_FALSE), - 'maintenance_status' => $this->getInput('filter_maintenance_status', HOST_MAINTENANCE_STATUS_ON), - 'page' => $this->hasInput('page') ? $this->getInput('page') : null - ]; - - $sort = $this->getInput('sort', 'name'); - $sortorder = $this->getInput('sortorder', ZBX_SORT_UP); - - $view_curl = (new CUrl('zabbix.php'))->setArgument('action', 'host.view'); - - $prepared_data = $this->prepareData($filter, $sort, $sortorder); - - $data = [ - 'filter' => $filter, - 'sort' => $sort, - 'sortorder' => $sortorder, - 'view_curl' => $view_curl - ] + $prepared_data; - - $response = new CControllerResponseData($data); - $this->setResponse($response); } } diff --git a/ui/app/controllers/CControllerNotificationsGet.php b/ui/app/controllers/CControllerNotificationsGet.php index 1e772334edc..d3700e64a65 100644 --- a/ui/app/controllers/CControllerNotificationsGet.php +++ b/ui/app/controllers/CControllerNotificationsGet.php @@ -166,14 +166,14 @@ class CControllerNotificationsGet extends CController { $url_problems = (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_hostids[]', $trigger['hosts'][0]['hostid']) - ->setArgument('filter_set', '1') + ->setArgument('filter_name', '') + ->setArgument('hostids[]', $trigger['hosts'][0]['hostid']) ->getUrl(); $url_events = (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_triggerids[]', $triggerid) - ->setArgument('filter_set', '1') + ->setArgument('filter_name', '') + ->setArgument('triggerids[]', $triggerid) ->getUrl(); $url_trigger_events_pt = (new CUrl('tr_events.php'))->setArgument('triggerid', $triggerid); diff --git a/ui/app/controllers/CControllerPopupTabFilterDelete.php b/ui/app/controllers/CControllerPopupTabFilterDelete.php new file mode 100644 index 00000000000..7b7d2ae9ed4 --- /dev/null +++ b/ui/app/controllers/CControllerPopupTabFilterDelete.php @@ -0,0 +1,68 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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. +**/ + + +/** + * Controller to delete tab filter by idx and idx2. + */ +class CControllerPopupTabFilterDelete extends CController { + + protected function init() { + $this->disableSIDValidation(); + } + + protected function checkInput() { + $rules = [ + 'idx' => 'string|required', + 'idx2' => 'int32|required' + ]; + + $ret = $this->validateInput($rules); + + if (!$ret) { + $output = []; + + if (($messages = getMessages()) !== null) { + $output['errors'] = $messages->toString(); + } + + $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output)])); + } + + return $ret; + } + + protected function checkPermissions() { + return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); + } + + protected function doAction() { + $idx = $this->getInput('idx'); + $idx2 = $this->getInput('idx2'); + + (new CTabFilterProfile($idx, [])) + ->read() + ->deleteTab((int) $idx2) + ->update(); + + $this->setResponse(new CControllerResponseData(['main_block' => json_encode([])])); + + } +} diff --git a/ui/app/controllers/CControllerPopupTabFilterEdit.php b/ui/app/controllers/CControllerPopupTabFilterEdit.php new file mode 100644 index 00000000000..f78c488f77e --- /dev/null +++ b/ui/app/controllers/CControllerPopupTabFilterEdit.php @@ -0,0 +1,126 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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. +**/ + + +/** + * Controller to load tab filter properties dialog. + */ +class CControllerPopupTabFilterEdit extends CController { + + protected function init() { + $this->disableSIDValidation(); + } + + protected function checkInput() { + $rules = [ + 'idx' => 'string|required', + 'idx2' => 'int32|required', + 'filter_name' => 'string', + 'filter_show_counter' => 'in 0,1', + 'filter_custom_time' => 'in 0,1', + 'tabfilter_from' => 'string', + 'tabfilter_to' => 'string', + 'support_custom_time' => 'in 0,1', + 'create' => 'in 0,1' + ]; + + $ret = $this->validateInput($rules) && $this->customValidation(); + + if (!$ret) { + $output = []; + + if (($messages = getMessages()) !== null) { + $output['errors'] = $messages->toString(); + } + + $this->setResponse( + (new CControllerResponseData(['main_block' => json_encode($output)]))->disableView() + ); + } + + return $ret; + } + + protected function customValidation(): bool { + if (!$this->getInput('support_custom_time', 0) || $this->getInput('filter_custom_time', 0)) { + return true; + } + + $rules = [ + 'tabfilter_from' => 'range_time|required', + 'tabfilter_to' => 'range_time|required', + ]; + + $validator = new CNewValidator($this->getInputAll(), $rules); + $ret = !$validator->isError() && !$validator->isErrorFatal(); + + foreach ($validator->getAllErrors() as $error) { + info($error); + } + + if ($ret) { + $this->input += [ + 'from' => $this->input['tabfilter_from'], + 'to' => $this->input['tabfilter_to'] + ]; + $ret = $this->validateTimeSelectorPeriod(); + } + + return $ret; + } + + protected function checkPermissions() { + return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); + } + + protected function doAction() { + $data = [ + 'form_action' => '', + 'idx' => '', + 'idx2' => '', + 'filter_name' => _('Untitled'), + 'filter_show_counter' => 0, + 'filter_custom_time' => 0, + 'tabfilter_from' => '', + 'tabfilter_to' => '', + 'support_custom_time' => 0, + 'create' => 0 + ]; + $this->getInputs($data, array_keys($data)); + + if (!$data['support_custom_time'] || !$data['filter_custom_time']) { + $data = [ + 'filter_custom_time' => 0, + 'tabfilter_from' => 'now-1h', + 'tabfilter_to' => 'now' + ] + $data; + } + + $data += [ + 'title' => _('Filter properties'), + 'errors' => hasErrorMesssages() ? getMessages() : null, + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ] + ]; + + $this->setResponse(new CControllerResponseData($data)); + } +} diff --git a/ui/app/controllers/CControllerPopupTabFilterUpdate.php b/ui/app/controllers/CControllerPopupTabFilterUpdate.php new file mode 100644 index 00000000000..d6d863c7c72 --- /dev/null +++ b/ui/app/controllers/CControllerPopupTabFilterUpdate.php @@ -0,0 +1,123 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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. +**/ + + +/** + * Controller to update tab filter. + */ +class CControllerPopupTabFilterUpdate extends CController { + + protected function init() { + $this->disableSIDValidation(); + } + + protected function checkInput() { + $rules = [ + 'idx' => 'string|required', + 'idx2' => 'int32|required', + 'filter_name' => 'string|not_empty', + 'filter_show_counter' => 'in 0,1', + 'filter_custom_time' => 'in 0,1', + 'tabfilter_from' => 'string', + 'tabfilter_to' => 'string', + 'support_custom_time' => 'in 0,1', + 'create' => 'in 0,1' + ]; + + $ret = $this->validateInput($rules) && $this->customValidation(); + + if (!$ret) { + $output = []; + + if (($messages = getMessages()) !== null) { + $output['errors'] = $messages->toString(); + } + + $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output)])); + } + + return $ret; + } + + protected function customValidation(): bool { + if (!$this->getInput('support_custom_time', 0) || !$this->getInput('filter_custom_time', 0)) { + return true; + } + + $rules = [ + 'tabfilter_from' => 'range_time|required', + 'tabfilter_to' => 'range_time|required', + ]; + + $validator = new CNewValidator($this->getInputAll(), $rules); + $ret = !$validator->isError() && !$validator->isErrorFatal(); + + foreach ($validator->getAllErrors() as $error) { + info($error); + } + + if ($ret) { + $this->input += [ + 'from' => $this->input['tabfilter_from'], + 'to' => $this->input['tabfilter_to'] + ]; + $ret = $this->validateTimeSelectorPeriod(); + } + + return $ret; + } + + protected function checkPermissions() { + return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); + } + + protected function doAction() { + $idx = $this->getInput('idx', ''); + $idx2 = $this->getInput('idx2', ''); + $create = (int) $this->getInput('create', 0); + + $properties = [ + 'filter_name' => $this->getInput('filter_name'), + 'filter_show_counter' => (int) $this->getInput('filter_show_counter', 0), + 'filter_custom_time' => (int) $this->getInput('filter_custom_time', 0) + ]; + + if ($this->getInput('support_custom_time', 0) && $properties['filter_custom_time']) { + $properties['from'] = $this->getInput('tabfilter_from', ''); + $properties['to'] = $this->getInput('tabfilter_to', ''); + } + + $filter = (new CTabFilterProfile($idx, []))->read(); + + if (array_key_exists($idx2, $filter->tabfilters)) { + $properties = $properties + $filter->tabfilters[$idx2]; + } + else { + $idx2 = count($filter->tabfilters); + } + + $filter->tabfilters[$idx2] = $properties; + $filter->update(); + + $this->setResponse(new CControllerResponseData([ + 'main_block' => json_encode($properties + ['idx2' => $idx2, 'create' => $create]) + ])); + } +} diff --git a/ui/app/controllers/CControllerPopupTriggerExpr.php b/ui/app/controllers/CControllerPopupTriggerExpr.php index 65de11fcc28..d0a89985e53 100644 --- a/ui/app/controllers/CControllerPopupTriggerExpr.php +++ b/ui/app/controllers/CControllerPopupTriggerExpr.php @@ -22,6 +22,7 @@ class CControllerPopupTriggerExpr extends CController { private $metrics = []; private $param1SecCount = []; + private $param1Period = []; private $param1Sec = []; private $param1Str = []; private $param2SecCount = []; @@ -67,6 +68,19 @@ class CControllerPopupTriggerExpr extends CController { ] ]; + $this->param1Period = [ + 'last' => [ + 'C' => _('Last of').' (T)', + 'T' => T_ZBX_INT, + 'A' => true + ], + 'period_shift' => [ + 'C' => _('Period shift'), + 'T' => T_ZBX_INT, + 'A' => true + ] + ]; + $this->param1Sec = [ 'last' => [ 'C' => _('Last of').' (T)', @@ -416,6 +430,42 @@ class CControllerPopupTriggerExpr extends CController { 'params' => $this->paramTimeleft, 'allowed_types' => $this->allowedTypesNumeric, 'operators' => ['=', '<>', '>', '<', '>=', '<='] + ], + 'trendavg' => [ + 'description' => _('trendavg() - Average value of a period T with exact period shift'), + 'params' => $this->param1Period, + 'allowed_types' => $this->allowedTypesNumeric, + 'operators' => ['=', '<>', '>', '<', '>=', '<='] + ], + 'trendcount' => [ + 'description' => _('trendcount() - Number of successfully retrieved values V (which fulfill operator O) for period T with exact period shift'), + 'params' => $this->param1Period, + 'allowed_types' => $this->allowedTypesAny, + 'operators' => ['=', '<>', '>', '<', '>=', '<='] + ], + 'trenddelta' => [ + 'description' => _('trenddelta() - Difference between MAX and MIN value of a period T with exact period shift'), + 'params' => $this->param1Period, + 'allowed_types' => $this->allowedTypesNumeric, + 'operators' => ['=', '<>', '>', '<', '>=', '<='] + ], + 'trendmax' => [ + 'description' => _('trendmax() - Maximum value for period T with exact period shift'), + 'params' => $this->param1Period, + 'allowed_types' => $this->allowedTypesNumeric, + 'operators' => ['=', '<>', '>', '<', '>=', '<='] + ], + 'trendmin' => [ + 'description' => _('trendmin() - Minimum value for period T with exact period shift'), + 'params' => $this->param1Period, + 'allowed_types' => $this->allowedTypesNumeric, + 'operators' => ['=', '<>', '>', '<', '>=', '<='] + ], + 'trendsum' => [ + 'description' => _('trendsum() - Sum of values of a period T with exact period shift'), + 'params' => $this->param1Period, + 'allowed_types' => $this->allowedTypesNumeric, + 'operators' => ['=', '<>', '>', '<', '>=', '<='] ] ]; diff --git a/ui/app/controllers/CControllerPopupTriggerWizard.php b/ui/app/controllers/CControllerPopupTriggerWizard.php index b9634a1a110..820aa3d59fb 100644 --- a/ui/app/controllers/CControllerPopupTriggerWizard.php +++ b/ui/app/controllers/CControllerPopupTriggerWizard.php @@ -29,6 +29,7 @@ class CControllerPopupTriggerWizard extends CController { protected function checkInput() { $fields = [ 'description' => 'string', + 'event_name' => 'db triggers.event_name', 'itemid' => 'required|db items.itemid', 'triggerid' => 'db triggers.triggerid', 'type' => 'in 0,1', @@ -89,6 +90,7 @@ class CControllerPopupTriggerWizard extends CController { protected function doAction() { $page_options = [ 'description' => $this->getInput('description', ''), + 'event_name' => $this->getInput('event_name', ''), 'opdata' => $this->getInput('opdata', ''), 'itemid' => $this->getInput('itemid', 0), 'type' => $this->getInput('type', 0), @@ -164,6 +166,7 @@ class CControllerPopupTriggerWizard extends CController { 'triggerid' => $triggerid, 'expression' => $expression, 'description' => $description, + 'event_name' => $page_options['event_name'], 'opdata' => $opdata, 'type' => TRIGGER_MULT_EVENT_ENABLED, 'priority' => $page_options['priority'], @@ -176,6 +179,7 @@ class CControllerPopupTriggerWizard extends CController { $trigger = [ 'expression' => $expression, 'description' => $page_options['description'], + 'event_name' => $page_options['event_name'], 'opdata' => $page_options['opdata'], 'type' => TRIGGER_MULT_EVENT_ENABLED, 'priority' => $page_options['priority'], @@ -245,7 +249,8 @@ class CControllerPopupTriggerWizard extends CController { // Select requested trigger. if (array_key_exists('triggerid', $page_options)) { $result = DBselect( - 'SELECT t.expression,t.description,t.priority,t.comments,t.url,t.status,t.type,t.opdata'. + 'SELECT t.expression,t.description,t.priority,t.comments,t.url,t.status,t.type,t.opdata,'. + 't.event_name'. ' FROM triggers t'. ' WHERE t.triggerid='.zbx_dbstr($page_options['triggerid']). ' AND EXISTS ('. @@ -262,6 +267,7 @@ class CControllerPopupTriggerWizard extends CController { if ($row = DBfetch($result)) { $expression = CMacrosResolverHelper::resolveTriggerExpression($row['expression']); $page_options['description'] = $row['description']; + $page_options['event_name'] = $row['event_name']; $page_options['opdata'] = $row['opdata']; $page_options['type'] = $row['type']; $page_options['priority'] = $row['priority']; diff --git a/ui/app/controllers/CControllerProblem.php b/ui/app/controllers/CControllerProblem.php new file mode 100644 index 00000000000..8b2e0923034 --- /dev/null +++ b/ui/app/controllers/CControllerProblem.php @@ -0,0 +1,173 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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. +**/ + + +/** + * Base controller for the "Monitoring->Problems" page. + */ +abstract class CControllerProblem extends CController { + + // Filter idx prefix. + const FILTER_IDX = 'web.monitoring.problem'; + + // Filter fields default values. + const FILTER_FIELDS_DEFAULT = [ + 'show' => TRIGGERS_OPTION_RECENT_PROBLEM, + 'groupids' => [], + 'hostids' => [], + 'application' => '', + 'triggerids' => [], + 'name' => '', + 'severities' => [], + 'age_state' => 0, + 'age' => 14, + 'inventory' => [], + 'evaltype' => TAG_EVAL_TYPE_AND_OR, + 'tags' => [], + 'show_tags' => PROBLEMS_SHOW_TAGS_3, + 'show_suppressed' => 0, + 'unacknowledged' => 0, + 'compact_view' => 0, + 'show_timeline' => 1, + 'details' => 0, + 'highlight_row' => 0, + 'show_opdata' => OPERATIONAL_DATA_SHOW_NONE, + 'tag_name_format' => PROBLEMS_TAG_NAME_FULL, + 'tag_priority' => '', + 'page' => null, + 'sort' => 'clock', + 'sortorder' => ZBX_SORT_DOWN, + 'from' => '', + 'to' => '' + ]; + + /** + * Get count of resulting rows for specified filter. + * + * @param array $filter Filter fields values. + * + * @return int + */ + protected function getCount(array $filter): int { + $range_time_parser = new CRangeTimeParser(); + $range_time_parser->parse($filter['from']); + $filter['from'] = $range_time_parser->getDateTime(true)->getTimestamp(); + $range_time_parser->parse($filter['to']); + $filter['to'] = $range_time_parser->getDateTime(false)->getTimestamp(); + + $data = CScreenProblem::getData($filter, [ + 'search_limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + ]); + + return count($data['problems']); + } + + /** + * Get resulting rows for specified filter. + * + * @param array $filter Filter fields values. + * + * @return array + */ + protected function getData(array $filter): array { + // getData is handled by jsrpc.php 'screen.get' action. + return []; + } + + /** + * Get additional data required for render filter as HTML. + * + * @param array $filter Filter fileds values. + * + * @return array + */ + protected function getAdditionalData(array $filter): array { + $data = [ + 'groups' => [], + 'hosts' => [], + 'triggers' => [] + ]; + + // Host groups multiselect. + if ($filter['groupids']) { + $host_groups = API::HostGroup()->get([ + 'output' => ['groupid', 'name'], + 'groupids' => $filter['groupids'], + 'preservekeys' => true + ]); + $data['groups'] = CArrayHelper::renameObjectsKeys($host_groups, ['groupid' => 'id']); + } + + // Triggers multiselect. + if ($filter['triggerids']) { + $triggers = CArrayHelper::renameObjectsKeys(API::Trigger()->get([ + 'output' => ['triggerid', 'description'], + 'selectHosts' => ['name'], + 'expandDescription' => true, + 'triggerids' => $filter['triggerids'], + 'monitored' => true + ]), ['triggerid' => 'id', 'description' => 'name']); + + CArrayHelper::sort($triggers, [ + ['field' => 'name', 'order' => ZBX_SORT_UP] + ]); + + foreach ($triggers as &$trigger) { + $trigger['prefix'] = $trigger['hosts'][0]['name'].NAME_DELIMITER; + unset($trigger['hosts']); + } + + $data['triggers'] = $triggers; + } + + // Hosts multiselect. + if ($filter['hostids']) { + $data['hosts'] = CArrayHelper::renameObjectsKeys(API::Host()->get([ + 'output' => ['hostid', 'name'], + 'hostids' => $filter['hostids'] + ]), ['hostid' => 'id']); + } + + return $data; + } + + /** + * Clean passed filter fields in input from default values required for HTML presentation. Convert field + * + * @param array $input Filter fields values. + * + * @return array + */ + protected function cleanInput(array $input): array { + if (array_key_exists('tags', $input) && $input['tags']) { + $input['tags'] = array_filter($input['tags'], function($tag) { + return !($tag['tag'] === '' && $tag['value'] === ''); + }); + } + + if (array_key_exists('inventory', $input) && $input['inventory']) { + $input['inventory'] = array_filter($input['inventory'], function($inventory) { + return $inventory['value'] !== ''; + }); + } + + return $input; + } +} diff --git a/ui/app/controllers/CControllerProblemView.php b/ui/app/controllers/CControllerProblemView.php index 3036ea8dbd5..c5826783e03 100644 --- a/ui/app/controllers/CControllerProblemView.php +++ b/ui/app/controllers/CControllerProblemView.php @@ -19,7 +19,7 @@ **/ -class CControllerProblemView extends CController { +class CControllerProblemView extends CControllerProblem { protected function init() { $this->disableSIDValidation(); @@ -27,43 +27,46 @@ class CControllerProblemView extends CController { protected function checkInput() { $fields = [ - 'action' => 'string', + 'show' => 'in '.TRIGGERS_OPTION_RECENT_PROBLEM.','.TRIGGERS_OPTION_IN_PROBLEM.','.TRIGGERS_OPTION_ALL, + 'groupids' => 'array_id', + 'hostids' => 'array_id', + 'application' => 'string', + 'triggerids' => 'array_id', + 'name' => 'string', + 'severities' => 'array', + 'age_state' => 'in 0,1', + 'age' => 'int32', + 'inventory' => 'array', + 'evaltype' => 'in '.TAG_EVAL_TYPE_AND_OR.','.TAG_EVAL_TYPE_OR, + 'tags' => 'array', + 'show_tags' => 'in '.PROBLEMS_SHOW_TAGS_NONE.','.PROBLEMS_SHOW_TAGS_1.','.PROBLEMS_SHOW_TAGS_2.','.PROBLEMS_SHOW_TAGS_3, + 'show_suppressed' => 'in 0,1', + 'unacknowledged' => 'in 0,1', + 'compact_view' => 'in 0,1', + 'show_timeline' => 'in 0,1', + 'details' => 'in 0,1', + 'highlight_row' => 'in 0,1', + 'show_opdata' => 'in '.OPERATIONAL_DATA_SHOW_NONE.','.OPERATIONAL_DATA_SHOW_SEPARATELY.','.OPERATIONAL_DATA_SHOW_WITH_PROBLEM, + 'tag_name_format' => 'in '.PROBLEMS_TAG_NAME_FULL.','.PROBLEMS_TAG_NAME_SHORTENED.','.PROBLEMS_TAG_NAME_NONE, + 'tag_priority' => 'string', + 'from' => 'range_time', + 'to' => 'range_time', 'sort' => 'in clock,host,severity,name', 'sortorder' => 'in '.ZBX_SORT_DOWN.','.ZBX_SORT_UP, - 'uncheck' => 'in 1', 'page' => 'ge 1', - 'filter_set' => 'in 1', - 'filter_rst' => 'in 1', - 'filter_show' => 'in '.TRIGGERS_OPTION_RECENT_PROBLEM.','.TRIGGERS_OPTION_IN_PROBLEM.','.TRIGGERS_OPTION_ALL, - 'filter_groupids' => 'array_id', - 'filter_hostids' => 'array_id', - 'filter_application' => 'string', - 'filter_triggerids' => 'array_id', + 'uncheck' => 'in 1', 'filter_name' => 'string', - 'filter_severities' => 'array', - 'filter_age_state' => 'in 1', - 'filter_age' => 'int32', - 'filter_inventory' => 'array', - 'filter_evaltype' => 'in '.TAG_EVAL_TYPE_AND_OR.','.TAG_EVAL_TYPE_OR, - 'filter_tags' => 'array', - 'filter_show_tags' => 'in '.PROBLEMS_SHOW_TAGS_NONE.','.PROBLEMS_SHOW_TAGS_1.','.PROBLEMS_SHOW_TAGS_2.','.PROBLEMS_SHOW_TAGS_3, - 'filter_show_suppressed' => 'in 1', - 'filter_unacknowledged' => 'in 1', - 'filter_compact_view' => 'in 1', - 'filter_show_timeline' => 'in 1', - 'filter_details' => 'in 1', - 'filter_highlight_row' => 'in 1', - 'filter_show_opdata' => 'in '.OPERATIONAL_DATA_SHOW_NONE.','.OPERATIONAL_DATA_SHOW_SEPARATELY.','.OPERATIONAL_DATA_SHOW_WITH_PROBLEM, - 'filter_tag_name_format' => 'in '.PROBLEMS_TAG_NAME_FULL.','.PROBLEMS_TAG_NAME_SHORTENED.','.PROBLEMS_TAG_NAME_NONE, - 'filter_tag_priority' => 'string', - 'from' => 'range_time', - 'to' => 'range_time' + 'filter_custom_time' => 'in 1,0', + 'filter_show_counter' => 'in 1,0', + 'filter_counters' => 'in 1', + 'filter_reset' => 'in 1', + 'counter_index' => 'ge 0' ]; $ret = $this->validateInput($fields) && $this->validateTimeSelectorPeriod(); - if ($ret && $this->hasInput('filter_inventory')) { - foreach ($this->getInput('filter_inventory') as $filter_inventory) { + if ($ret && $this->hasInput('inventory')) { + foreach ($this->getInput('inventory') as $filter_inventory) { if (count($filter_inventory) != 2 || !array_key_exists('field', $filter_inventory) || !is_string($filter_inventory['field']) || !array_key_exists('value', $filter_inventory) || !is_string($filter_inventory['value'])) { @@ -73,8 +76,8 @@ class CControllerProblemView extends CController { } } - if ($ret && $this->hasInput('filter_tags')) { - foreach ($this->getInput('filter_tags') as $filter_tag) { + if ($ret && $this->hasInput('tags')) { + foreach ($this->getInput('tags') as $filter_tag) { if (count($filter_tag) != 3 || !array_key_exists('tag', $filter_tag) || !is_string($filter_tag['tag']) || !array_key_exists('value', $filter_tag) || !is_string($filter_tag['value']) @@ -97,245 +100,55 @@ class CControllerProblemView extends CController { } protected function doAction() { - $sortField = $this->getInput('sort', CProfile::get('web.problem.sort', 'clock')); - $sortOrder = $this->getInput('sortorder', CProfile::get('web.problem.sortorder', ZBX_SORT_DOWN)); - $active_tab = CProfile::get('web.problem.filter.active', 1); - - CProfile::update('web.problem.sort', $sortField, PROFILE_TYPE_STR); - CProfile::update('web.problem.sortorder', $sortOrder, PROFILE_TYPE_STR); - - // filter - if ($this->hasInput('filter_set')) { - $show_db_type = CProfile::get('web.problem.filter.show', TRIGGERS_OPTION_RECENT_PROBLEM); - $show_type = $this->getInput('filter_show', TRIGGERS_OPTION_RECENT_PROBLEM); - - if ($show_db_type != $show_type) { - CProfile::update('web.problem.filter.show', $show_type, PROFILE_TYPE_INT); - - if ($show_type == TRIGGERS_OPTION_ALL && $active_tab == 1) { - $active_tab = 2; - CProfile::update('web.problem.filter.active', $active_tab, PROFILE_TYPE_INT); - } - } - - CProfile::updateArray('web.problem.filter.groupids', $this->getInput('filter_groupids', []), - PROFILE_TYPE_ID - ); - CProfile::updateArray('web.problem.filter.hostids', $this->getInput('filter_hostids', []), PROFILE_TYPE_ID); - CProfile::update('web.problem.filter.application', $this->getInput('filter_application', ''), - PROFILE_TYPE_STR - ); - CProfile::updateArray('web.problem.filter.triggerids', $this->getInput('filter_triggerids', []), - PROFILE_TYPE_ID - ); - CProfile::update('web.problem.filter.name', $this->getInput('filter_name', ''), PROFILE_TYPE_STR); - CProfile::updateArray('web.problem.filter.severities', $this->getInput('filter_severities', []), - PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.age_state', $this->getInput('filter_age_state', 0), PROFILE_TYPE_INT); - CProfile::update('web.problem.filter.age', $this->getInput('filter_age', 14), PROFILE_TYPE_INT); - - $filter_inventory = ['fields' => [], 'values' => []]; - foreach ($this->getInput('filter_inventory', []) as $field) { - if ($field['value'] === '') { - continue; - } - - $filter_inventory['fields'][] = $field['field']; - $filter_inventory['values'][] = $field['value']; - } - CProfile::updateArray('web.problem.filter.inventory.field', $filter_inventory['fields'], PROFILE_TYPE_STR); - CProfile::updateArray('web.problem.filter.inventory.value', $filter_inventory['values'], PROFILE_TYPE_STR); - - CProfile::update('web.problem.filter.evaltype', $this->getInput('filter_evaltype', TAG_EVAL_TYPE_AND_OR), - PROFILE_TYPE_INT - ); - - $filter_tags = ['tags' => [], 'values' => [], 'operators' => []]; - foreach ($this->getInput('filter_tags', []) as $filter_tag) { - if ($filter_tag['tag'] === '' && $filter_tag['value'] === '') { - continue; - } - - $filter_tags['tags'][] = $filter_tag['tag']; - $filter_tags['values'][] = $filter_tag['value']; - $filter_tags['operators'][] = $filter_tag['operator']; + $filter_tabs = []; + $profile = (new CTabFilterProfile(static::FILTER_IDX, static::FILTER_FIELDS_DEFAULT)) + ->read() + ->setInput($this->cleanInput($this->getInputAll())); + + foreach ($profile->getTabsWithDefaults() as $filter_tab) { + if ($filter_tab['show'] != TRIGGERS_OPTION_ALL) { + $filter_tab['filter_custom_time'] = 0; } - CProfile::updateArray('web.problem.filter.tags.tag', $filter_tags['tags'], PROFILE_TYPE_STR); - CProfile::updateArray('web.problem.filter.tags.value', $filter_tags['values'], PROFILE_TYPE_STR); - CProfile::updateArray('web.problem.filter.tags.operator', $filter_tags['operators'], PROFILE_TYPE_INT); - - CProfile::update('web.problem.filter.show_tags', $this->getInput('filter_show_tags', PROBLEMS_SHOW_TAGS_3), - PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.tag_name_format', $this->getInput('filter_tag_name_format', - PROBLEMS_TAG_NAME_FULL), PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.tag_priority', $this->getInput('filter_tag_priority', ''), - PROFILE_TYPE_STR - ); - CProfile::update('web.problem.filter.show_suppressed', - $this->getInput('filter_show_suppressed', ZBX_PROBLEM_SUPPRESSED_FALSE), PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.unacknowledged', $this->getInput('filter_unacknowledged', 0), - PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.compact_view', $this->getInput('filter_compact_view', 0), - PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.show_timeline', $this->getInput('filter_show_timeline', 0), - PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.details', $this->getInput('filter_details', 0), PROFILE_TYPE_INT); - CProfile::update('web.problem.filter.highlight_row', $this->getInput('filter_highlight_row', 0), - PROFILE_TYPE_INT - ); - CProfile::update('web.problem.filter.show_opdata', $this->getInput('filter_show_opdata', 0), - PROFILE_TYPE_INT - ); - } - elseif ($this->hasInput('filter_rst')) { - CProfile::delete('web.problem.filter.show'); - CProfile::deleteIdx('web.problem.filter.groupids'); - CProfile::deleteIdx('web.problem.filter.hostids'); - CProfile::delete('web.problem.filter.application'); - CProfile::deleteIdx('web.problem.filter.triggerids'); - CProfile::delete('web.problem.filter.name'); - CProfile::deleteIdx('web.problem.filter.severities'); - CProfile::delete('web.problem.filter.age_state'); - CProfile::delete('web.problem.filter.age'); - CProfile::deleteIdx('web.problem.filter.inventory.field'); - CProfile::deleteIdx('web.problem.filter.inventory.value'); - CProfile::delete('web.problem.filter.evaltype'); - CProfile::deleteIdx('web.problem.filter.tags.tag'); - CProfile::deleteIdx('web.problem.filter.tags.value'); - CProfile::deleteIdx('web.problem.filter.tags.operator'); - CProfile::delete('web.problem.filter.show_tags'); - CProfile::delete('web.problem.filter.tag_name_format'); - CProfile::delete('web.problem.filter.tag_priority'); - CProfile::delete('web.problem.filter.show_suppressed'); - CProfile::delete('web.problem.filter.unacknowledged'); - CProfile::delete('web.problem.filter.compact_view'); - CProfile::delete('web.problem.filter.show_timeline'); - CProfile::delete('web.problem.filter.details'); - CProfile::delete('web.problem.filter.highlight_row'); - CProfile::delete('web.problem.filter.show_opdata'); - } - - $filter_groupids = CProfile::getArray('web.problem.filter.groupids', []); - $filter_hostids = CProfile::getArray('web.problem.filter.hostids', []); - $filter_triggerids = CProfile::getArray('web.problem.filter.triggerids', []); - - $groups = []; - - if ($filter_groupids) { - $filter_groupids = getSubGroups($filter_groupids, $groups); - } - - $filter_triggers = $filter_triggerids - ? CArrayHelper::renameObjectsKeys(API::Trigger()->get([ - 'output' => ['triggerid', 'description'], - 'selectHosts' => ['name'], - 'expandDescription' => true, - 'triggerids' => $filter_triggerids, - 'monitored' => true - ]), ['triggerid' => 'id', 'description' => 'name']) - : []; - - CArrayHelper::sort($filter_triggers, [ - ['field' => 'name', 'order' => ZBX_SORT_UP] - ]); - - foreach ($filter_triggers as &$filter_trigger) { - $filter_trigger['prefix'] = $filter_trigger['hosts'][0]['name'].NAME_DELIMITER; - unset($filter_trigger['hosts']); - } - unset($filter_trigger); - $inventories = []; - foreach (getHostInventories() as $inventory) { - $inventories[$inventory['db_field']] = $inventory['title']; + $filter_tabs[] = $filter_tab + ['filter_view_data' => $this->getAdditionalData($filter_tab)]; } - $filter_inventory = []; - foreach (CProfile::getArray('web.problem.filter.inventory.field', []) as $i => $field) { - $filter_inventory[] = [ - 'field' => $field, - 'value' => CProfile::get('web.problem.filter.inventory.value', null, $i) - ]; - } - - $filter_tags = []; - foreach (CProfile::getArray('web.problem.filter.tags.tag', []) as $i => $tag) { - $filter_tags[] = [ - 'tag' => $tag, - 'value' => CProfile::get('web.problem.filter.tags.value', null, $i), - 'operator' => CProfile::get('web.problem.filter.tags.operator', null, $i) - ]; - } + $filter = $profile->getTabFilter($profile->selected); + $refresh_curl = (new CUrl('zabbix.php')); + $filter['action'] = 'problem.view.refresh'; + array_map([$refresh_curl, 'setArgument'], array_keys($filter), $filter); - /* - * Display - */ $data = [ - 'action' => $this->getInput('action'), - 'sort' => $sortField, - 'sortorder' => $sortOrder, - 'uncheck' => $this->hasInput('uncheck'), - 'page' => $this->getInput('page', 1), - 'filter' => [ - 'show' => CProfile::get('web.problem.filter.show', TRIGGERS_OPTION_RECENT_PROBLEM), - 'groupids' => $filter_groupids, - 'groups' => $groups, - 'hostids' => $filter_hostids, - 'hosts' => $filter_hostids - ? CArrayHelper::renameObjectsKeys(API::Host()->get([ - 'output' => ['hostid', 'name'], - 'hostids' => $filter_hostids - ]), ['hostid' => 'id']) - : [], - 'application' => CProfile::get('web.problem.filter.application', ''), - 'triggerids' => $filter_triggerids, - 'triggers' => $filter_triggers, - 'name' => CProfile::get('web.problem.filter.name', ''), - 'severities' => CProfile::getArray('web.problem.filter.severities', []), - 'age_state' => CProfile::get('web.problem.filter.age_state', 0), - 'age' => CProfile::get('web.problem.filter.age', 14), - 'inventories' => $inventories, - 'inventory' => $filter_inventory, - 'evaltype' => CProfile::get('web.problem.filter.evaltype', TAG_EVAL_TYPE_AND_OR), - 'tags' => $filter_tags, - 'show_tags' => CProfile::get('web.problem.filter.show_tags', PROBLEMS_SHOW_TAGS_3), - 'tag_name_format' => CProfile::get('web.problem.filter.tag_name_format', PROBLEMS_TAG_NAME_FULL), - 'tag_priority' => CProfile::get('web.problem.filter.tag_priority', ''), - 'show_suppressed' => CProfile::get('web.problem.filter.show_suppressed', 0), - 'unacknowledged' => CProfile::get('web.problem.filter.unacknowledged', 0), - 'compact_view' => CProfile::get('web.problem.filter.compact_view', 0), - 'show_timeline' => CProfile::get('web.problem.filter.show_timeline', 1), - 'details' => CProfile::get('web.problem.filter.details', 0), - 'highlight_row' => CProfile::get('web.problem.filter.highlight_row', 0), - 'show_opdata' => CProfile::get('web.problem.filter.show_opdata', 0) + 'action' => $this->getAction(), + 'tabfilter_idx' => static::FILTER_IDX, + 'filter' => $filter, + 'filter_view' => 'monitoring.problem.filter', + 'filter_defaults' => $profile->filter_defaults, + 'tabfilter_options' => [ + 'idx' => static::FILTER_IDX, + 'selected' => $profile->selected, + 'support_custom_time' => 1, + 'expanded' => $profile->expanded, + 'page' => $filter['page'], + 'timeselector' => [ + 'from' => $profile->from, + 'to' => $profile->to, + 'disabled' => ($filter['show'] != TRIGGERS_OPTION_ALL || $filter['filter_custom_time']) + ] + getTimeselectorActions($profile->from, $profile->to) ], - 'active_tab' => $active_tab + 'filter_tabs' => $filter_tabs, + 'refresh_url' => $refresh_curl->getUrl(), + 'refresh_interval' => CWebUser::getRefresh() * 1000, + 'inventories' => array_column(getHostInventories(), 'title', 'db_field'), + 'sort' => $filter['sort'], + 'sortorder' => $filter['sortorder'], + 'uncheck' => $this->hasInput('filter_reset'), + 'page' => $this->getInput('page', 1), ]; - if ($data['filter']['show'] == TRIGGERS_OPTION_ALL) { - $timeselector_options = [ - 'profileIdx' => 'web.problem.filter', - 'profileIdx2' => 0, - 'from' => $this->hasInput('from') ? $this->getInput('from') : null, - 'to' => $this->hasInput('to') ? $this->getInput('to') : null - ]; - updateTimeSelectorPeriod($timeselector_options); - - $data += $timeselector_options; - } - else { - $data['profileIdx'] = 'web.problem.filter'; - } - $response = new CControllerResponseData($data); $response->setTitle(_('Problems')); + if ($data['action'] === 'problem.view.csv') { $response->setFileName('zbx_problems_export.csv'); } diff --git a/ui/app/controllers/CControllerProblemViewRefresh.php b/ui/app/controllers/CControllerProblemViewRefresh.php new file mode 100644 index 00000000000..e160cfcf036 --- /dev/null +++ b/ui/app/controllers/CControllerProblemViewRefresh.php @@ -0,0 +1,52 @@ +<?php +/* +** Zabbix +** Copyright (C) 2001-2020 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. +**/ + + +class CControllerProblemViewRefresh extends CControllerProblemView { + + protected function doAction() { + $data = []; + + if ($this->getInput('filter_counters', 0)) { + $profile = (new CTabFilterProfile(static::FILTER_IDX, static::FILTER_FIELDS_DEFAULT))->read(); + $filters = $this->hasInput('counter_index') + ? [$profile->getTabFilter($this->getInput('counter_index'))] + : $profile->getTabsWithDefaults(); + $data['filter_counters'] = []; + + foreach ($filters as $index => $tabfilter) { + if (!$tabfilter['filter_custom_time']) { + $tabfilter = [ + 'from' => $profile->from, + 'to' => $profile->to + ] + $tabfilter; + } + + $data['filter_counters'][$index] = $tabfilter['filter_show_counter'] ? $this->getCount($tabfilter) : 0; + } + } + + if (($messages = getMessages()) !== null) { + $data['messages'] = $messages->toString(); + } + + $this->setResponse(new CControllerResponseData(['main_block' => json_encode($data)])); + } +} diff --git a/ui/app/controllers/CControllerTabFilterProfileUpdate.php b/ui/app/controllers/CControllerTabFilterProfileUpdate.php new file mode 100644 index 00000000000..1c6a5e9a9a5 --- /dev/null +++ b/ui/app/controllers/CControllerTabFilterProfileUpdate.php @@ -0,0 +1,171 @@ +<?php declare(strict_types=1); +/* +** Zabbix +** Copyright (C) 2001-2020 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. +**/ + + +/** + * Controller to update tab filter. Handles following events: + * - select tab; + * - expand/collapse active tab; + * - update filter properties; + * - save tab order. + */ +class CControllerTabFilterProfileUpdate extends CController { + + public static $namespaces = [ + CControllerHost::FILTER_IDX => CControllerHost::FILTER_FIELDS_DEFAULT, + CControllerProblem::FILTER_IDX => CControllerProblem::FILTER_FIELDS_DEFAULT + ]; + + public function init() { + $this->disableSIDvalidation(); + } + + protected function checkPermissions() { + return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); + } + + protected function checkInput() { + $fields = [ + 'idx' => 'required|string', + 'value_int' => 'int32', + 'value_str' => 'string', + 'idx2' => 'id' + ]; + + $ret = $this->validateInput($fields); + + if ($ret) { + $idx_cunks = explode('.', $this->getInput('idx')); + $property = array_pop($idx_cunks); + $idx = implode('.', $idx_cunks); + $supported = ['selected', 'expanded', 'properties', 'taborder']; + + $ret = (in_array($property, $supported) && array_key_exists($idx, static::$namespaces)); + + if ($property === 'selected' || $property === 'expanded') { + $ret = ($ret && $this->hasInput('value_int')); + } + else if ($property === 'properties' || $property === 'taborder') { + $ret = ($ret && $this->hasInput('value_str')); + } + } + + if (!$ret) { + $this->setResponse(new CControllerResponseData(['main_block' => ''])); + } + + return $ret; + } + + protected function doAction() { + $data = $this->getInputAll() + [ + 'value_int' => 0, + 'value_str' => '', + 'idx2' => 0 + ]; + $idx_cunks = explode('.', $this->getInput('idx')); + $property = array_pop($idx_cunks); + $idx = implode('.', $idx_cunks); + $defaults = static::$namespaces[$idx]; + + if (array_key_exists('from', $defaults) || array_key_exists('to', $defaults)) { + $defaults += [ + 'from' => 'now-'.CSettingsHelper::get(CSettingsHelper::PERIOD_DEFAULT), + 'to' => 'now' + ]; + } + + $filter = (new CTabFilterProfile($idx, $defaults))->read(); + + switch ($property) { + case 'selected': + $dynamictabs = count($filter->tabfilters); + + if ($data['value_int'] >= 0 && $data['value_int'] < $dynamictabs) { + $filter->selected = (int) $data['value_int']; + } + + break; + + case 'properties': + $properties = []; + parse_str($this->getInput('value_str'), $properties); + $filter->setTabFilter($this->getInput('idx2'), $this->cleanProperties($properties)); + + break; + + case 'taborder': + $filter->sort($this->getInput('value_str')); + + break; + + case 'expanded': + $filter->expanded = ($data['value_int'] > 0); + + break; + } + + $filter->update(); + + $data += [ + 'property' => $property, + 'idx' => $idx + ]; + $response = new CControllerResponseData($data); + $this->setResponse($response); + } + + /** + * Clean fields data removing empty initial elements. + * + * @param array $properties Array of submitted fields data. + * + * @return array + */ + protected function cleanProperties(array $properties): array { + if (array_key_exists('tags', $properties)) { + $tags = array_filter($properties['tags'], function ($tag) { + return !($tag['tag'] === '' && $tag['value'] === ''); + }); + + if ($tags) { + $properties['tags'] = array_values($tags); + } + else { + unset($properties['tags']); + } + } + + if (array_key_exists('inventory', $properties)) { + $inventory = array_filter($properties['inventory'], function ($field) { + return ($field['value'] !== ''); + }); + + if ($inventory) { + $properties['inventory'] = array_values($inventory); + } + else { + unset($properties['inventory']); + } + } + + return $properties; + } +} diff --git a/ui/app/controllers/CControllerTimeSelectorUpdate.php b/ui/app/controllers/CControllerTimeSelectorUpdate.php index 3b7de8f2658..ef0ed19c835 100644 --- a/ui/app/controllers/CControllerTimeSelectorUpdate.php +++ b/ui/app/controllers/CControllerTimeSelectorUpdate.php @@ -24,6 +24,12 @@ */ class CControllerTimeSelectorUpdate extends CController { + public static $profiles = ['web.dashbrd.filter', 'web.screens.filter', 'web.charts.filter', 'web.httpdetails.filter', + 'web.problem.filter', 'web.auditlog.filter', 'web.slides.filter', 'web.auditacts.filter', + 'web.item.graph.filter', 'web.toptriggers.filter', 'web.avail_report.filter', CControllerHost::FILTER_IDX, + CControllerProblem::FILTER_IDX + ]; + /** * @var CRangeTimeParser */ @@ -38,14 +44,9 @@ class CControllerTimeSelectorUpdate extends CController { } protected function checkInput() { - $profiles = ['web.auditacts.filter', 'web.auditlog.filter', 'web.avail_report.filter', 'web.charts.filter', - 'web.dashbrd.filter', 'web.item.graph.filter', 'web.httpdetails.filter', 'web.problem.filter', - 'web.screens.filter', 'web.slides.filter', 'web.toptriggers.filter' - ]; - $fields = [ 'method' => 'required|in increment,zoomout,decrement,rangechange,rangeoffset', - 'idx' => 'required|in '.implode(',', $profiles), + 'idx' => 'required|in '.implode(',', static::$profiles), 'idx2' => 'required|id', 'from' => 'required|string', 'to' => 'required|string', @@ -201,10 +202,7 @@ class CControllerTimeSelectorUpdate extends CController { 'to' => $value['to'], 'to_ts' => $ts['to'], 'to_date' => $date->setTimestamp($ts['to'])->format(ZBX_FULL_DATE_TIME), - 'can_zoomout' => ($ts['to'] - $ts['from'] + 1 < $max_period), - 'can_decrement' => ($ts['from'] > 0), - 'can_increment' => ($ts['to'] < $ts['now'] - ZBX_MIN_PERIOD) - ])])); + ] + getTimeselectorActions($value['from'], $value['to']))])); } /** diff --git a/ui/app/partials/monitoring.host.filter.php b/ui/app/partials/monitoring.host.filter.php new file mode 100644 index 00000000000..61c8bcc2cc5 --- /dev/null +++ b/ui/app/partials/monitoring.host.filter.php @@ -0,0 +1,315 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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 CPartial $this + */ + +$filter_tags_table = (new CTable()) + ->setId('tags_#{uniqid}') + ->addRow( + (new CCol( + (new CRadioButtonList('evaltype', (int) $data['evaltype'])) + ->setId('evaltype_#{uniqid}') + ->addValue(_('And/Or'), TAG_EVAL_TYPE_AND_OR, 'evaltype_0#{uniqid}') + ->addValue(_('Or'), TAG_EVAL_TYPE_OR, 'evaltype_2#{uniqid}') + ->setModern(true) + ))->setColSpan(4) +); + +foreach (array_values($data['tags']) as $i => $tag) { + $filter_tags_table->addRow([ + (new CTextBox('tags['.$i.'][tag]', $tag['tag'])) + ->setAttribute('placeholder', _('tag')) + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) + ->removeId(), + (new CRadioButtonList('tags['.$i.'][operator]', (int) $tag['operator'])) + ->addValue(_('Contains'), TAG_OPERATOR_LIKE, 'tags_0'.$i.'_#{uniqid}') + ->addValue(_('Equals'), TAG_OPERATOR_EQUAL, 'tags_1'.$i.'_#{uniqid}') + ->setId('tags_'.$i.'_#{uniqid}') + ->setModern(true), + (new CTextBox('tags['.$i.'][value]', $tag['value'])) + ->setAttribute('placeholder', _('value')) + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) + ->removeId(), + (new CCol( + (new CButton('tags['.$i.'][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ->removeId() + ))->addClass(ZBX_STYLE_NOWRAP) + ], 'form_row'); +} +$filter_tags_table->addRow( + (new CCol( + (new CButton('tags_add', _('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-add') + ->removeId() + ))->setColSpan(3) +); + +$left_column = (new CFormList()) + ->addRow(_('Name'), + (new CTextBox('name', $data['name'])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('name_#{uniqid}') + ) + ->addRow((new CLabel(_('Host groups'), 'groupids_#{uniqid}_ms')), + (new CMultiSelect([ + 'name' => 'groupids[]', + 'object_name' => 'hostGroup', + 'data' => array_key_exists('groups_multiselect', $data) ? $data['groups_multiselect'] : [], + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'host_groups', + 'srcfld1' => 'groupid', + 'dstfrm' => 'zbx_filter', + 'dstfld1' => 'groupids_', + 'real_hosts' => true, + 'enrich_parent_groups' => true + ] + ], + 'add_post_js' => false + ])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('groupids_#{uniqid}') + ) + ->addRow(_('IP'), + (new CTextBox('ip', $data['ip'])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('ip_#{uniqid}') + ) + ->addRow(_('DNS'), + (new CTextBox('dns', $data['dns'])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('dns_#{uniqid}') + ) + ->addRow(_('Port'), + (new CTextBox('port', $data['port'])) + ->setWidth(ZBX_TEXTAREA_INTERFACE_PORT_WIDTH) + ->setId('port_#{uniqid}') + ) + ->addRow(_('Severity'), + (new CSeverityCheckBoxList('severities')) + ->setChecked($data['severities']) + ->setUniqid('#{uniqid}') + ); + +$right_column = (new CFormList()) + ->addRow(_('Status'), + (new CRadioButtonList('status', (int) $data['status'])) + ->addValue(_('Any'), -1, 'status_1#{uniqid}') + ->addValue(_('Enabled'), HOST_STATUS_MONITORED, 'status_2#{uniqid}') + ->addValue(_('Disabled'), HOST_STATUS_NOT_MONITORED, 'status_3#{uniqid}') + ->setId('status_#{uniqid}') + ->setModern(true) + ) + ->addRow(_('Tags'), $filter_tags_table) + ->addRow(_('Show hosts in maintenance'), [ + (new CCheckBox('maintenance_status')) + ->setChecked($data['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) + ->setId('maintenance_status_#{uniqid}') + ->setUncheckedValue(HOST_MAINTENANCE_STATUS_OFF), + (new CDiv([ + (new CLabel(_('Show suppressed problems'), 'show_suppressed_#{uniqid}')) + ->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), + (new CCheckBox('show_suppressed')) + ->setId('show_suppressed_#{uniqid}') + ->setChecked($data['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) + ->setUncheckedValue(ZBX_PROBLEM_SUPPRESSED_FALSE) + ->setEnabled($data['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON), + ]))->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) + ]); + +$template = (new CDiv()) + ->addClass(ZBX_STYLE_TABLE) + ->addClass(ZBX_STYLE_FILTER_FORMS) + ->addItem([ + (new CDiv($left_column))->addClass(ZBX_STYLE_CELL), + (new CDiv($right_column))->addClass(ZBX_STYLE_CELL) + ]); +$template = (new CForm('get')) + ->cleanItems() + ->setName('zbx_filter') + ->addItem([ + $template, + (new CSubmitButton(null))->addClass(ZBX_STYLE_DISPLAY_NONE), + (new CVar('filter_name', '#{filter_name}'))->removeId(), + (new CVar('filter_show_counter', '#{filter_show_counter}'))->removeId(), + (new CVar('filter_custom_time', '#{filter_custom_time}'))->removeId(), + (new CVar('sort', '#{sort}'))->removeId(), + (new CVar('sortorder', '#{sortorder}'))->removeId() + ]); + +if (array_key_exists('render_html', $data)) { + /** + * Render HTML to prevent filter flickering after initial page load. PHP created content will be replaced by + * javascript with additional event handling (dynamic rows, etc.) when page will be fully loaded and javascript + * executed. + */ + $template->show(); + + return; +} + +(new CScriptTemplate('filter-monitoring-hosts')) + ->setAttribute('data-template', 'monitoring.host.filter') + ->addItem($template) + ->show(); + +(new CScriptTemplate('filter-tag-row-tmpl')) + ->addItem( + (new CRow([ + (new CTextBox('tags[#{rowNum}][tag]', '#{tag}')) + ->setAttribute('placeholder', _('tag')) + ->removeId() + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CRadioButtonList('tags[#{rowNum}][operator]', TAG_OPERATOR_LIKE)) + ->addValue(_('Contains'), TAG_OPERATOR_LIKE, 'tags_0#{rowNum}#{uniqid}') + ->addValue(_('Equals'), TAG_OPERATOR_EQUAL, 'tags_1#{rowNum}#{uniqid}') + ->setModern(true) + ->setId('tags_#{rowNum}#{uniqid}'), + (new CTextBox('tags[#{rowNum}][value]', '#{value}')) + ->setAttribute('placeholder', _('value')) + ->removeId() + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CCol( + (new CButton('tags[#{rowNum}][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ->removeId() + ))->addClass(ZBX_STYLE_NOWRAP) + ])) + ->addClass('form_row')) + ->show(); +?> +<script type="text/javascript"> + let template = document.querySelector('[data-template="monitoring.host.filter"]'); + + function render(data, container) { + // "Save as" can contain only home tab, also home tab cannot contain "Update" button. + $('[name="filter_new"],[name="filter_update"]').hide() + .filter(data.filter_configurable ? '[name="filter_update"]' : '[name="filter_new"]').show(); + + // Host groups multiselect. + $('#groupids_' + data.uniqid, container).multiSelectHelper({ + id: 'groupids_' + data.uniqid, + object_name: 'hostGroup', + name: 'groupids[]', + data: data.filter_view_data.groups_multiselect || [], + objectOptions: { + real_hosts: 1, + enrich_parent_groups: 1 + }, + popup: { + parameters: { + multiselect: '1', + noempty: '1', + srctbl: 'host_groups', + srcfld1: 'groupid', + dstfrm: 'zbx_filter', + dstfld1: 'groupids_' + data.uniqid, + real_hosts: 1, + enrich_parent_groups: 1 + } + } + }); + + // Show hosts in maintenance events. + let maintenance_checkbox = $('[name="maintenance_status"]', container).click(function () { + $('[name="show_suppressed"]', container).prop('disabled', !this.checked); + }); + + if (maintenance_checkbox.attr('unchecked-value') === data['maintenance_status']) { + maintenance_checkbox.removeAttr('checked'); + $('[name="show_suppressed"]', container).prop('disabled', true); + } + + // Tags table + if (data.tags.length == 0) { + data.tags.push({'tag': '', 'value': '', 'operator': <?= TAG_OPERATOR_LIKE ?>, uniqid: data.uniqid}); + } + + $('#tags_' + data.uniqid, container).dynamicRows({ + template: '#filter-tag-row-tmpl', + rows: data.tags, + counter: 0, + dataCallback: (tag) => { + tag.uniqid = data.uniqid; + return tag; + } + }); + + // Input, radio and single checkboxes. + ['name', 'ip', 'dns', 'port', 'status', 'evaltype', 'show_suppressed'].forEach((key) => { + var elm = $('[name="' + key + '"]', container); + + if (elm.is(':radio,:checkbox')) { + elm.filter('[value="' + data[key] + '"]').attr('checked', true); + } + else { + elm.val(data[key]); + } + }); + + // Severities checkboxes. + for (const value in data.severities) { + $('[name="severities[' + value + ']"]', container).attr('checked', true); + } + + // Initialize src_url. + this.resetUnsavedState(); + this.on(TABFILTERITEM_EVENT_ACTION, update.bind(this)); + } + + function expand(data, container) { + // "Save as" can contain only home tab, also home tab cannot contain "Update" button. + $('[name="filter_new"],[name="filter_update"]').hide() + .filter(data.filter_configurable ? '[name="filter_update"]' : '[name="filter_new"]').show(); + } + + /** + * On filter apply or update buttons press update disabled UI fields. + * + * @param {CustomEvent} ev CustomEvent object. + */ + function update(ev) { + let action = ev.detail.action, + container = this._content_container; + + if (action !== 'filter_apply' && action !== 'filter_update') { + return; + } + + $('[name="show_suppressed"]', container) + .filter(':disabled') + .prop('checked', false); + } + + // Tab filter item events handlers. + template.addEventListener(TABFILTERITEM_EVENT_RENDER, function (ev) { + render.call(ev.detail, ev.detail._data, ev.detail._content_container); + }); + template.addEventListener(TABFILTERITEM_EVENT_EXPAND, function (ev) { + expand.call(ev.detail, ev.detail._data, ev.detail._content_container); + }); +</script> diff --git a/ui/app/partials/monitoring.host.view.html.php b/ui/app/partials/monitoring.host.view.html.php index c6ee51bedc9..4ecef5d6d39 100644 --- a/ui/app/partials/monitoring.host.view.html.php +++ b/ui/app/partials/monitoring.host.view.html.php @@ -21,10 +21,6 @@ $form = (new CForm())->setName('host_view'); -$url = (new CUrl('zabbix.php')) - ->setArgument('action', 'host.view') - ->getUrl(); - $table = (new CTableInfo()); $view_url = $data['view_curl']->getUrl(); @@ -122,9 +118,9 @@ foreach ($data['hosts'] as $hostid => $host) { new CLink(_('Problems'), (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_set', '1') - ->setArgument('filter_severities', $data['filter']['severities']) - ->setArgument('filter_hostids', [$host['hostid']]) + ->setArgument('filter_name', '') + ->setArgument('severities', $data['filter']['severities']) + ->setArgument('hostids', [$host['hostid']]) ), CViewHelper::showNum($total_problem_count) ], diff --git a/ui/app/partials/monitoring.problem.filter.php b/ui/app/partials/monitoring.problem.filter.php new file mode 100644 index 00000000000..fa5985f6464 --- /dev/null +++ b/ui/app/partials/monitoring.problem.filter.php @@ -0,0 +1,641 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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 CPartial $this + */ + +$left_column = (new CFormList()) + ->addRow(_('Show'), + (new CRadioButtonList('show', (int) $data['show'])) + ->addValue(_('Recent problems'), TRIGGERS_OPTION_RECENT_PROBLEM, 'show_1#{uniqid}') + ->addValue(_('Problems'), TRIGGERS_OPTION_IN_PROBLEM, 'show_3#{uniqid}') + ->addValue(_('History'), TRIGGERS_OPTION_ALL, 'show_2#{uniqid}') + ->setId('show_#{uniqid}') + ->setModern(true) + ) + ->addRow((new CLabel(_('Host groups'), 'groupids_#{uniqid}_ms')), + (new CMultiSelect([ + 'name' => 'groupids[]', + 'object_name' => 'hostGroup', + 'data' => array_key_exists('groups', $data) ? $data['groups'] : [], + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'host_groups', + 'srcfld1' => 'groupid', + 'dstfrm' => 'zbx_filter', + 'dstfld1' => 'groupids_', + 'real_hosts' => true, + 'enrich_parent_groups' => true + ] + ] + ])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('groupids_#{uniqid}') + ) + ->addRow((new CLabel(_('Hosts'), 'hostids_#{uniqid}_ms')), + (new CMultiSelect([ + 'name' => 'hostids[]', + 'object_name' => 'hosts', + 'data' => array_key_exists('hosts', $data) ? $data['hosts'] : [], + 'popup' => [ + 'filter_preselect_fields' => [ + 'hostgroups' => 'groupids_' + ], + 'parameters' => [ + 'srctbl' => 'hosts', + 'srcfld1' => 'hostid', + 'dstfrm' => 'zbx_filter', + 'dstfld1' => 'hostids_' + ] + ] + ])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('hostids_#{uniqid}') + ) + ->addRow(_('Application'), [ + (new CTextBox('application', $data['application'])) + ->setId('application_#{uniqid}') + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH), + (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), + (new CButton('application_select', _('Select'))) + ->setId('application_select_#{uniqid}') + ->addClass(ZBX_STYLE_BTN_GREY) + ]) + ->addRow((new CLabel(_('Triggers'), 'triggerids_#{uniqid}_ms')), + (new CMultiSelect([ + 'name' => 'triggerids[]', + 'object_name' => 'triggers', + 'data' => array_key_exists('triggers', $data) ? $data['triggers'] : [], + 'popup' => [ + 'filter_preselect_fields' => [ + 'hosts' => 'hostids_' + ], + 'parameters' => [ + 'srctbl' => 'triggers', + 'srcfld1' => 'triggerid', + 'dstfrm' => 'zbx_filter', + 'dstfld1' => 'triggerids_', + 'monitored_hosts' => true, + 'with_monitored_triggers' => true, + 'noempty' => true + ] + ] + ])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('triggerids_#{uniqid}') + ) + ->addRow(_('Problem'), + (new CTextBox('name', $data['name'])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setId('name_#{uniqid}') + ) + ->addRow(_('Severity'), + (new CSeverityCheckBoxList('severities')) + ->setChecked($data['severities']) + ->setUniqid('#{uniqid}') + ); + +$filter_age = (new CNumericBox('age', $data['age'], 3, false, false, false)) + ->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH) + ->removeId(); +if ($data['age_state'] == 0) { + $filter_age->setAttribute('disabled', 'disabled'); +} + +$left_column + ->addRow(_('Age less than'), [ + (new CCheckBox('age_state')) + ->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') + ]); + +$filter_inventory_table = new CTable(); +$filter_inventory_table->setId('filter-inventory_#{uniqid}'); +$inventories = array_column(getHostInventories(), 'title', 'db_field'); +$i = 0; +foreach ($data['inventory'] as $field) { + $filter_inventory_table->addRow([ + new CComboBox('inventory['.$i.'][field]', $field['field'], null, $inventories), + (new CTextBox('inventory['.$i.'][value]', $field['value']))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CCol( + (new CButton('inventory['.$i.'][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ))->addClass(ZBX_STYLE_NOWRAP) + ], 'form_row'); + + $i++; +} +$filter_inventory_table->addRow( + (new CCol( + (new CButton('inventory_add', _('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-add') + ->removeId() + ))->setColSpan(3) +); + +$filter_tags_table = new CTable(); +$filter_tags_table->setId('filter-tags_#{uniqid}'); + +$filter_tags_table->addRow( + (new CCol( + (new CRadioButtonList('evaltype', (int) $data['evaltype'])) + ->addValue(_('And/Or'), TAG_EVAL_TYPE_AND_OR, 'evaltype_0#{uniqid}') + ->addValue(_('Or'), TAG_EVAL_TYPE_OR, 'evaltype_2#{uniqid}') + ->setModern(true) + ->setId('evaltype_#{uniqid}') + ))->setColSpan(4) +); + +$i = 0; +foreach ($data['tags'] as $tag) { + $filter_tags_table->addRow([ + (new CTextBox('tags['.$i.'][tag]', $tag['tag'])) + ->setAttribute('placeholder', _('tag')) + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CRadioButtonList('tags['.$i.'][operator]', (int) $tag['operator'])) + ->addValue(_('Contains'), TAG_OPERATOR_LIKE) + ->addValue(_('Equals'), TAG_OPERATOR_EQUAL) + ->setModern(true), + (new CTextBox('tags['.$i.'][value]', $tag['value'])) + ->setAttribute('placeholder', _('value')) + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CCol( + (new CButton('tags['.$i.'][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ->removeId() + ))->addClass(ZBX_STYLE_NOWRAP) + ], 'form_row'); + + $i++; +} +$filter_tags_table->addRow( + (new CCol( + (new CButton('tags_add', _('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-add') + ->removeId() + ))->setColSpan(3) +); + +$tag_format_line = (new CHorList()) + ->addItem((new CRadioButtonList('show_tags', (int) $data['show_tags'])) + ->addValue(_('None'), PROBLEMS_SHOW_TAGS_NONE, 'show_tags_0#{uniqid}') + ->addValue(PROBLEMS_SHOW_TAGS_1, PROBLEMS_SHOW_TAGS_1, 'show_tags_1#{uniqid}') + ->addValue(PROBLEMS_SHOW_TAGS_2, PROBLEMS_SHOW_TAGS_2, 'show_tags_2#{uniqid}') + ->addValue(PROBLEMS_SHOW_TAGS_3, PROBLEMS_SHOW_TAGS_3, 'show_tags_3#{uniqid}') + ->setModern(true) + ->setId('show_tags_#{uniqid}') + ) + ->addItem((new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN)) + ->addItem(new CLabel(_('Tag name'))) + ->addItem((new CRadioButtonList('tag_name_format', (int) $data['tag_name_format'])) + ->addValue(_('Full'), PROBLEMS_TAG_NAME_FULL, 'tag_name_format_0#{uniqid}') + ->addValue(_('Shortened'), PROBLEMS_TAG_NAME_SHORTENED, 'tag_name_format_1#{uniqid}') + ->addValue(_('None'), PROBLEMS_TAG_NAME_NONE, 'tag_name_format_2#{uniqid}') + ->setModern(true) + ->setEnabled((int) $data['show_tags'] !== PROBLEMS_SHOW_TAGS_NONE) + ->setId('tag_name_format_#{uniqid}') + ); + +$right_column = (new CFormList()) + ->addRow(_('Host inventory'), $filter_inventory_table) + ->addRow(_('Tags'), $filter_tags_table) + ->addRow(_('Show tags'), $tag_format_line) + ->addRow(_('Tag display priority'), + (new CTextBox('tag_priority', $data['tag_priority'])) + ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) + ->setAttribute('placeholder', _('comma-separated list')) + ->setEnabled((int) $data['show_tags'] !== PROBLEMS_SHOW_TAGS_NONE) + ->setId('tag_priority_#{uniqid}') + ) + ->addRow(_('Show operational data'), [ + (new CRadioButtonList('show_opdata', (int) $data['show_opdata'])) + ->addValue(_('None'), OPERATIONAL_DATA_SHOW_NONE, 'show_opdata_0_#{uniqid}') + ->addValue(_('Separately'), OPERATIONAL_DATA_SHOW_SEPARATELY, 'show_opdata_1_#{uniqid}') + ->addValue(_('With problem name'), OPERATIONAL_DATA_SHOW_WITH_PROBLEM, 'show_opdata_2_#{uniqid}') + ->setModern(true) + ->setEnabled($data['compact_view'] == 0) + ->removeId() + ]) + ->addRow(_('Show suppressed problems'), [ + (new CCheckBox('show_suppressed')) + ->setChecked($data['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) + ->setUncheckedValue(0) + ->setId('show_suppressed_#{uniqid}'), + (new CDiv([ + (new CLabel(_('Show unacknowledged only'), 'unacknowledged_#{uniqid}')) + ->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), + (new CCheckBox('unacknowledged')) + ->setChecked($data['unacknowledged'] == 1) + ->setUncheckedValue(0) + ->setId('unacknowledged_#{uniqid}') + ]))->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) + ]) + ->addRow(_('Compact view'), [ + (new CCheckBox('compact_view')) + ->setChecked($data['compact_view'] == 1) + ->setUncheckedValue(0) + ->setId('compact_view_#{uniqid}'), + (new CDiv([ + (new CLabel(_('Show timeline'), 'show_timeline_#{uniqid}'))->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), + (new CCheckBox('show_timeline')) + ->setChecked($data['show_timeline'] == 1) + ->setEnabled($data['compact_view'] == 0) + ->setUncheckedValue(0) + ->setId('show_timeline_#{uniqid}'), + ]))->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) + ]) + ->addRow(_('Show details'), [ + (new CCheckBox('details')) + ->setChecked($data['details'] == 1) + ->setEnabled($data['compact_view'] == 0) + ->setUncheckedValue(0) + ->setId('details_#{uniqid}'), + (new CDiv([ + (new CLabel(_('Highlight whole row'), 'highlight_row'))->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), + (new CCheckBox('highlight_row')) + ->setChecked($data['highlight_row'] == 1) + ->setEnabled($data['compact_view'] == 1) + ->setUncheckedValue(0) + ->setId('highlight_row_#{uniqid}') + ])) + ->addClass(ZBX_STYLE_FILTER_HIGHLIGHT_ROW_CB) + ->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) + ]); + +$template = (new CDiv()) + ->addClass(ZBX_STYLE_TABLE) + ->addClass(ZBX_STYLE_FILTER_FORMS) + ->addItem([ + (new CDiv($left_column))->addClass(ZBX_STYLE_CELL), + (new CDiv($right_column))->addClass(ZBX_STYLE_CELL) + ]); +$template = (new CForm('get')) + ->cleanItems() + ->setName('zbx_filter') + ->addItem([ + $template, + (new CSubmitButton(null))->addClass(ZBX_STYLE_DISPLAY_NONE), + (new CVar('filter_name', '#{filter_name}'))->removeId(), + (new CVar('filter_show_counter', '#{filter_show_counter}'))->removeId(), + (new CVar('filter_custom_time', '#{filter_custom_time}'))->removeId(), + (new CVar('sort', '#{sort}'))->removeId(), + (new CVar('sortorder', '#{sortorder}'))->removeId() + ]); + +if (array_key_exists('render_html', $data)) { + /** + * Render HTML to prevent filter flickering after initial page load. PHP created content will be replaced by + * javascript with additional event handling (dynamic rows, etc.) when page will be fully loaded and javascript + * executed. + */ + $template->show(); + + return; +} + +(new CScriptTemplate('filter-monitoring-problem')) + ->setAttribute('data-template', 'monitoring.problem.filter') + ->addItem($template) + ->show(); + +(new CScriptTemplate('filter-inventory-row')) + ->addItem( + (new CRow([ + (new CComboBox('inventory[#{rowNum}][field]', null, null, $inventories))->removeId(), + (new CTextBox('inventory[#{rowNum}][value]', '#{value}')) + ->removeId() + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CCol( + (new CButton('inventory[#{rowNum}][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ->removeId() + ))->addClass(ZBX_STYLE_NOWRAP) + ]))->addClass('form_row') + ) + ->show(); + +(new CScriptTemplate('filter-tag-row-tmpl')) + ->addItem( + (new CRow([ + (new CTextBox('tags[#{rowNum}][tag]', '#{tag}')) + ->setAttribute('placeholder', _('tag')) + ->removeId() + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CRadioButtonList('tags[#{rowNum}][operator]', TAG_OPERATOR_LIKE)) + ->addValue(_('Contains'), TAG_OPERATOR_LIKE, 'tags_0#{rowNum}#{uniqid}') + ->addValue(_('Equals'), TAG_OPERATOR_EQUAL, 'tags_1#{rowNum}#{uniqid}') + ->setModern(true) + ->setId('tags_#{rowNum}#{uniqid}'), + (new CTextBox('tags[#{rowNum}][value]', '#{value}')) + ->setAttribute('placeholder', _('value')) + ->removeId() + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), + (new CCol( + (new CButton('tags[#{rowNum}][remove]', _('Remove'))) + ->removeId() + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ->removeId() + ))->addClass(ZBX_STYLE_NOWRAP) + ]))->addClass('form_row') + ) + ->show(); + +?> +<script type="text/javascript"> + let template = document.querySelector('[data-template="monitoring.problem.filter"]'); + + function render(data, container) { + // "Save as" can contain only home tab, also home tab cannot contain "Update" button. + $('[name="filter_new"],[name="filter_update"]').hide() + .filter(data.filter_configurable ? '[name="filter_update"]' : '[name="filter_new"]').show(); + + let fields = ['show', 'application', 'name', 'tag_priority', 'show_opdata', 'show_suppressed', 'show_tags', + 'unacknowledged', 'compact_view', 'show_timeline', 'details', 'highlight_row', 'age_state', 'age', + 'tag_name_format', 'evaltype' + ], + eventHandler = { + show: () => { + // Dynamically disable hidden input elements to allow correct detection of unsaved changes. + var filter_show = ($('input[name="show"]:checked', container).val() != <?= TRIGGERS_OPTION_ALL ?>), + disabled = (!filter_show || !$('[name="age_state"]:checked', container).length); + + $('[name="age"]', container).attr('disabled', disabled).closest('li').toggle(filter_show); + $('[name="age_state"]', container).attr('disabled', !filter_show); + + if (filter_show) { + this._data.filter_custom_time = 0; + } + + if (this._parent) { + this._parent.updateTimeselector(this, filter_show); + } + }, + age_state: (ev) => { + $('[name="age"]', container).prop('disabled', !$('[name="age_state"]', container).is(':checked')); + }, + compact_view: () => { + let checked = $('[name="compact_view"]', container).is(':checked'); + + $('[name="show_timeline"]', container).prop('disabled', checked); + $('[name="details"]', container).prop('disabled', checked); + $('[name="show_opdata"]', container).prop('disabled', checked); + $('[name="highlight_row"]', container).prop('disabled', !checked); + }, + show_tags: () => { + let disabled = ($('[name="show_tags"]:checked', container).val() == <?= PROBLEMS_SHOW_TAGS_NONE ?>); + + $('[name="tag_priority"]', container).prop('disabled', disabled); + $('[name="tag_name_format"]', container).prop('disabled', disabled); + } + }; + + // Input, radio and single checkboxes. + fields.forEach((key) => { + var elm = $('[name="' + key + '"]', container); + + if (elm.is(':radio,:checkbox')) { + elm.filter('[value="' + data[key] + '"]').attr('checked', true); + } + else { + elm.val(data[key]); + } + }); + + // Show timeline default value is checked and it will be rendered in template therefore initalize if unchecked. + $('[name="show_timeline"][unchecked-value="' + data['show_timeline'] + '"]', container).removeAttr('checked'); + + // Severities checkboxes. + for (const value in data.severities) { + $('[name="severities[' + value + ']"]', container).attr('checked', true); + } + + // Inventory table. + if (data.inventory.length == 0) { + data.inventory.push({'field': '', 'value': ''}); + } + $('#filter-inventory_' + data.uniqid, container).dynamicRows({ + template: '#filter-inventory-row', + rows: data.inventory, + counter: 0 + }); + + // Tags table. + if (data.tags.length == 0) { + data.tags.push({'tag': '', 'value': '', 'operator': <?= TAG_OPERATOR_LIKE ?>}); + } + + $('#filter-tags_' + data.uniqid, container).dynamicRows({ + template: '#filter-tag-row-tmpl', + rows: data.tags, + counter: 0, + dataCallback: (tag) => { + tag.uniqid = data.uniqid + return tag; + } + }); + + // Host groups multiselect. + $('#groupids_' + data.uniqid, container).multiSelectHelper({ + id: 'groupids_' + data.uniqid, + object_name: 'hostGroup', + name: 'groupids[]', + data: data.filter_view_data.groups || [], + objectOptions: { + real_hosts: 1, + enrich_parent_groups: 1 + }, + popup: { + parameters: { + srctbl: 'host_groups', + srcfld1: 'groupid', + dstfrm: 'zbx_filter', + dstfld1: 'groupids_' + data.uniqid, + multiselect: 1, + noempty: 1, + real_hosts: 1, + enrich_parent_groups: 1 + } + } + }); + + // Hosts multiselect. + $('#hostids_' + data.uniqid, container).multiSelectHelper({ + id: 'hostids_' + data.uniqid, + object_name: 'hosts', + name: 'hostids[]', + data: data.filter_view_data.hosts || [], + popup: { + filter_preselect_fields: { + hostgroups: 'groupids_' + data.uniqid + }, + parameters: { + multiselect: 1, + srctbl: 'hosts', + srcfld1: 'hostid', + dstfrm: 'zbx_filter', + dstfld1: 'hostids_' + data.uniqid, + } + } + }); + + // Application + $('#application_select_' + data.uniqid).on('click', function() { + let options = { + srctbl: 'applications', + srcfld1: 'name', + dstfrm: 'zbx_filter', + dstfld1: 'application_' + data.uniqid, + with_applications: '1', + real_hosts: '1' + }; + + PopUp('popup.generic', $.extend(options, getFirstMultiselectValue('hostids_' + data.uniqid)), null, this); + }); + + // Triggers multiselect. + $('#triggerids_' + data.uniqid, container).multiSelectHelper({ + id: 'triggerids_' + data.uniqid, + object_name: 'triggers', + name: 'triggerids[]', + data: data.filter_view_data.triggers || [], + popup: { + filter_preselect_fields: { + hosts: 'hostids_' + data.uniqid + }, + parameters: { + srctbl: 'triggers', + srcfld1: 'triggerid', + dstfrm: 'zbx_filter', + dstfld1: 'triggerids_' + data.uniqid, + multiselect: 1, + noempty: 1, + monitored_hosts: 1, + with_monitored_triggers: 1 + } + } + }); + + $('#show_' + data.uniqid, container).change(eventHandler.show).trigger('change'); + $('[name="age_state"]').change(eventHandler.age_state).trigger('change'); + $('[name="compact_view"]', container).change(eventHandler.compact_view).trigger('change'); + $('[name="show_tags"]', container).change(eventHandler.show_tags).trigger('change'); + + // Initialize src_url. + this.resetUnsavedState(); + this.on(TABFILTERITEM_EVENT_ACTION, update.bind(this)); + + if (this._parent) { + this._parent.on(TABFILTER_EVENT_UPDATE, (ev) => { + let form = this.getForm(), + tabfilter = ev.detail.target; + + if (tabfilter._active_item !== this) { + return; + } + + if ($(form).find('[name="filter_custom_time"]').val() == 1) { + $('[name="show"][value="<?= TRIGGERS_OPTION_ALL ?>"]', form).prop('checked', true); + $('#show_' + this._data.uniqid, form).trigger('change'); + this.updateUnsavedState(); + this.setBrowserLocationToApplyUrl(); + } + }); + + this._parent.on(TABFILTER_EVENT_NEWITEM, () => { + let form = this.getForm(); + + if ($(form).find('[name="filter_custom_time"]').val() == 1) { + $('[name="show"][value="<?= TRIGGERS_OPTION_ALL ?>"]', form).prop('checked', true); + } + }); + } + } + + function expand(data, container) { + // "Save as" can contain only home tab, also home tab cannot contain "Update" button. + $('[name="filter_new"],[name="filter_update"]').hide() + .filter(data.filter_configurable ? '[name="filter_update"]' : '[name="filter_new"]').show(); + + // Trigger change to update timeselector ui disabled state. + $('#show_' + data.uniqid, container).trigger('change'); + } + + function select(data, container) { + if (this._template_rendered) { + // Template rendered, use element events, trigger change to update timeselector ui disabled state. + $('#show_' + data.uniqid, container).trigger('change'); + } + else if (this._parent) { + // Template is not rendered, use input data. + this._parent.updateTimeselector(this, (data.show != <?= TRIGGERS_OPTION_ALL ?>)); + } + } + + /** + * On filter apply or update buttons press update disabled UI fields. + * + * @param {CustomEvent} ev CustomEvent object. + */ + function update(ev) { + let action = ev.detail.action, + container = this._content_container; + + if (action !== 'filter_apply' && action !== 'filter_update') { + return; + } + + $('[name="highlight_row"],[name="details"],[name="show_timeline"]', container) + .filter(':disabled') + .prop('checked', false); + + $('[name="show_opdata"]:disabled', container) + .prop('checked', false) + .filter('[value="' + <?= CControllerProblem::FILTER_FIELDS_DEFAULT['show_opdata'] ?> +'"]') + .prop('checked', true); + + if ($('[name="age_state"]', container).not(':checked').length) { + $('[name="age"]').val(<?= CControllerProblem::FILTER_FIELDS_DEFAULT['age'] ?>); + } + } + + // Tab filter item events handlers. + template.addEventListener(TABFILTERITEM_EVENT_RENDER, function(ev) { + render.call(ev.detail, ev.detail._data, ev.detail._content_container); + }); + template.addEventListener(TABFILTERITEM_EVENT_EXPAND, function(ev) { + expand.call(ev.detail, ev.detail._data, ev.detail._content_container); + }); + template.addEventListener(TABFILTERITEM_EVENT_SELECT, function(ev) { + select.call(ev.detail, ev.detail._data, ev.detail._content_container); + }); +</script> diff --git a/ui/app/partials/timeselector.filter.php b/ui/app/partials/timeselector.filter.php new file mode 100644 index 00000000000..3d7d1f78088 --- /dev/null +++ b/ui/app/partials/timeselector.filter.php @@ -0,0 +1,111 @@ +<?php declare(strict_types = 1); +/* +** Zabbix +** Copyright (C) 2001-2020 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 CPartial $this + */ + +$time_ranges = [ + [ + ['now-2d', 'now'], + ['now-7d', 'now'], + ['now-30d', 'now'], + ['now-3M', 'now'], + ['now-6M', 'now'], + ['now-1y', 'now'], + ['now-2y', 'now'] + ], + [ + ['now-1d/d', 'now-1d/d'], + ['now-2d/d', 'now-2d/d'], + ['now-1w/d', 'now-1w/d'], + ['now-1w/w', 'now-1w/w'], + ['now-1M/M', 'now-1M/M'], + ['now-1y/y', 'now-1y/y'] + ], + [ + ['now/d', 'now/d'], + ['now/d', 'now'], + ['now/w', 'now/w'], + ['now/w', 'now'], + ['now/M', 'now/M'], + ['now/M', 'now'], + ['now/y', 'now/y'], + ['now/y', 'now'] + ], + [ + ['now-5m', 'now'], + ['now-15m', 'now'], + ['now-30m', 'now'], + ['now-1h', 'now'], + ['now-3h', 'now'], + ['now-6h', 'now'], + ['now-12h', 'now'], + ['now-24h', 'now'] + ] +]; +$predefined_ranges = []; + +foreach ($time_ranges as $column_ranges) { + $column = (new CList())->addClass(ZBX_STYLE_TIME_QUICK); + + foreach ($column_ranges as $range) { + $label = relativeDateToText($range[0], $range[1]); + $is_selected = ($data['label'] === $label); + + $column->addItem((new CLink($label)) + ->setAttribute('data-from', $range[0]) + ->setAttribute('data-to', $range[1]) + ->setAttribute('data-label', $label) + ->addClass($is_selected ? ZBX_STYLE_SELECTED : null) + ); + } + + $predefined_ranges[] = (new CDiv($column))->addClass(ZBX_STYLE_CELL); +} + +(new CDiv([ + (new CDiv([ + new CList([ + new CLabel(_('From'), 'from'), + (new CDateSelector('from', $data['from']))->setDateFormat($data['format']) + ]), + (new CList([(new CListItem(''))->addClass(ZBX_STYLE_RED)])) + ->setAttribute('data-error-for', 'from') + ->addClass(ZBX_STYLE_TIME_INPUT_ERROR) + ->addStyle('display: none'), + new CList([ + new CLabel(_('To'), 'to'), + (new CDateSelector('to', $data['to']))->setDateFormat($data['format']) + ]), + (new CList([(new CListItem(''))->addClass(ZBX_STYLE_RED)])) + ->setAttribute('data-error-for', 'to') + ->addClass(ZBX_STYLE_TIME_INPUT_ERROR) + ->addStyle('display: none'), + new CList([ + new CButton('apply', _('Apply')) + ]) + ]))->addClass(ZBX_STYLE_TIME_INPUT), + (new CDiv($predefined_ranges))->addClass(ZBX_STYLE_TIME_QUICK_RANGE) +])) + ->addClass(ZBX_STYLE_FILTER_CONTAINER) + ->addClass(ZBX_STYLE_TIME_SELECTION_CONTAINER) + ->show(); diff --git a/ui/app/views/js/monitoring.host.view.js.php b/ui/app/views/js/monitoring.host.view.js.php index 76c8189ff60..23f5ba2195e 100644 --- a/ui/app/views/js/monitoring.host.view.js.php +++ b/ui/app/views/js/monitoring.host.view.js.php @@ -22,45 +22,71 @@ /** * @var CView $this */ + ?> -<script type="text/x-jquery-tmpl" id="filter-tag-row-tmpl"> - <?= (new CRow([ - (new CTextBox('filter_tags[#{rowNum}][tag]')) - ->setAttribute('placeholder', _('tag')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CRadioButtonList('filter_tags[#{rowNum}][operator]', TAG_OPERATOR_LIKE)) - ->addValue(_('Contains'), TAG_OPERATOR_LIKE) - ->addValue(_('Equals'), TAG_OPERATOR_EQUAL) - ->setModern(true), - (new CTextBox('filter_tags[#{rowNum}][value]')) - ->setAttribute('placeholder', _('value')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CCol( - (new CButton('filter_tags[#{rowNum}][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ])) - ->addClass('form_row') - ->toString() - ?> -</script> <script type="text/javascript"> jQuery(function($) { - $('#filter-tags').dynamicRows({template: '#filter-tag-row-tmpl'}); - - $('#filter_maintenance_status').on('change', function() { - $('#filter_show_suppressed').prop('disabled', !this.checked); - }); - function hostPage() { + let filter_options = <?= json_encode($data['filter_options']) ?>; + this.refresh_url = '<?= $data['refresh_url'] ?>'; this.refresh_interval = <?= $data['refresh_interval'] ?>; this.running = false; this.timeout = null; + this.deferred = null; + + if (filter_options) { + this.refresh_counters = this.createCountersRefresh(1); + this.filter = new CTabFilter($('#monitoring_hosts_filter')[0], filter_options); + this.filter.on(TABFILTER_EVENT_URLSET, (ev) => { + let url = new Curl('', false); + + url.setArgument('action', 'host.view.refresh'); + this.refresh_url = url.getUrl(); + this.unscheduleRefresh(); + this.refresh(); + }); + this.filter.on(TABFILTER_EVENT_UPDATE, (ev) => { + if (!this.filter._active_item.hasCounter() || ev.detail.filter_property !== 'properties') { + return; + } + + var filter_item = this.filter._active_item; + + $.post('zabbix.php', { + action: 'host.view.refresh', + filter_counters: 1, + counter_index: filter_item._index + }).done((json) => { + if (json.filter_counters) { + filter_item.updateCounter(json.filter_counters.pop()); + } + }); + }); + } } hostPage.prototype = { + createCountersRefresh: function(timeout) { + if (this.refresh_counters) { + clearTimeout(this.refresh_counters); + this.refresh_counters = null; + } + + return setTimeout(() => this.getFiltersCounters(), timeout); + }, + getFiltersCounters: function() { + return $.post('zabbix.php', { + action: 'host.view.refresh', + filter_counters: 1 + }).done((json) => { + if (json.filter_counters) { + this.filter.updateCounters(json.filter_counters); + } + }).always(() => { + this.refresh_counters = this.createCountersRefresh(this.refresh_interval); + }); + }, getCurrentForm: function() { return $('form[name=host_view]'); }, @@ -73,9 +99,9 @@ refresh: function() { this.setLoading(); - var deferred = $.getJSON(this.refresh_url); + this.deferred = $.getJSON(this.refresh_url); - return this.bindDataEvents(deferred); + return this.bindDataEvents(this.deferred); }, setLoading: function() { this.getCurrentForm().addClass('is-loading is-loading-fadein delayed-15s'); @@ -128,6 +154,7 @@ }, onDataAlways: function() { if (this.running) { + this.deferred = null; this.scheduleRefresh(); } }, @@ -143,19 +170,20 @@ clearTimeout(this.timeout); this.timeout = null; } + + if (this.deferred) { + this.deferred.abort(); + } }, start: function() { if (this.refresh_interval != 0) { this.running = true; - this.scheduleRefresh(); + this.refresh(); } - }, - stop: function() { - this.running = false; - this.unscheduleRefresh(); } }; window.host_page = new hostPage(); + window.host_page.start(); }); </script> diff --git a/ui/app/views/js/monitoring.problem.view.js.php b/ui/app/views/js/monitoring.problem.view.js.php index a47fc1b22ae..778a0e17a8f 100644 --- a/ui/app/views/js/monitoring.problem.view.js.php +++ b/ui/app/views/js/monitoring.problem.view.js.php @@ -22,81 +22,154 @@ /** * @var CView $this */ -?> - -<script type="text/x-jquery-tmpl" id="filter-inventory-row"> - <?= (new CRow([ - new CComboBox('filter_inventory[#{rowNum}][field]', null, null, $data['filter']['inventories']), - (new CTextBox('filter_inventory[#{rowNum}][value]'))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CCol( - (new CButton('filter_inventory[#{rowNum}][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ])) - ->addClass('form_row') - ->toString() - ?> -</script> -<script type="text/x-jquery-tmpl" id="filter-tag-row-tmpl"> - <?= (new CRow([ - (new CTextBox('filter_tags[#{rowNum}][tag]')) - ->setAttribute('placeholder', _('tag')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CRadioButtonList('filter_tags[#{rowNum}][operator]', TAG_OPERATOR_LIKE)) - ->addValue(_('Contains'), TAG_OPERATOR_LIKE) - ->addValue(_('Equals'), TAG_OPERATOR_EQUAL) - ->setModern(true), - (new CTextBox('filter_tags[#{rowNum}][value]')) - ->setAttribute('placeholder', _('value')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CCol( - (new CButton('filter_tags[#{rowNum}][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ])) - ->addClass('form_row') - ->toString() - ?> -</script> - -<script type="text/javascript"> - jQuery(function($) { - $(function() { - $('#filter-inventory').dynamicRows({template: '#filter-inventory-row'}); - $('#filter-tags').dynamicRows({template: '#filter-tag-row-tmpl'}); +if (array_key_exists('filter_options', $data)) { ?> + <script type="text/javascript"> + $(function() { + var options = <?= json_encode($data['filter_options']) ?>, + filter = new CTabFilter($('#monitoring_problem_filter')[0], options), + refresh_interval = <?= $data['refresh_interval'] ?>, + refresh_url = '<?= $data['refresh_url'] ?>', + refresh_timer, + filter_item, + filter_counter_fetch, + active_filter = filter._active_item, + global_timerange = { + from: options.timeselector.from, + to: options.timeselector.to + }; + + /** + * Update on filter changes. + */ + filter.on(TABFILTER_EVENT_URLSET, () => { + let url = new Curl(); + + url.setArgument('action', 'problem.view.csv'); + $('#export_csv').attr('data-url', url.getUrl()); + refreshResults(); + + if (active_filter !== filter._active_item) { + active_filter = filter._active_item; + chkbxRange.checkObjectAll(chkbxRange.pageGoName, false); + chkbxRange.clearSelectedOnFilterChange(); + } }); - $('#filter_show').change(function() { - var filter_show = jQuery('input[name=filter_show]:checked').val(); + /** + * Update filter item counter when filter settings updated. + */ + filter.on(TABFILTER_EVENT_UPDATE, (ev) => { + if (!filter._active_item.hasCounter() || ev.detail.filter_property !== 'properties') { + return; + } - $('#filter_age').closest('li').toggle(filter_show == <?= TRIGGERS_OPTION_RECENT_PROBLEM ?> - || filter_show == <?= TRIGGERS_OPTION_IN_PROBLEM ?>); + if (filter_counter_fetch) { + filter_counter_fetch.abort(); + } + + filter_counter_fetch = new AbortController(); + filter_item = filter._active_item; + + fetch(refresh_url, { + method: 'POST', + signal: filter_counter_fetch.signal, + body: new URLSearchParams({filter_counters: 1, counter_index: filter_item._index}) + }) + .then(response => response.json()) + .then(response => { + filter_item.updateCounter(response.filter_counters.pop()); + }); }); - $('#filter_show').trigger('change'); + /** + * Refresh results table via window.flickerfreeScreen.refresh call. + */ + function refreshResults() { + let url = new Curl(), + screen = window.flickerfreeScreen.screens['problem'], + data = $.extend(<?= json_encode($data['filter_defaults']) ?>, + global_timerange, url.getArgumentsObject() + ); + + data.inventory = data.inventory + ? data.inventory.filter(inventory => 'value' in inventory && inventory.value !== '') + : data.inventory; + data.tags = data.tags + ? data.tags.filter(tag => !(tag.tag === '' && tag.value === '')) + : data.tags; + data.severities = data.severities + ? data.severities.filter((value, key) => value == key) + : data.severities; + + // Modify filter data of flickerfreeScreen object with id 'problem'. + if (data.page === null) { + delete data.page; + } - $('#filter_compact_view').change(function() { - if ($(this).is(':checked')) { - $('#filter_show_timeline, #filter_details').prop('disabled', true); - $('input[name=filter_show_opdata]').prop('disabled', true); - $('#filter_highlight_row').prop('disabled', false); + if (data.filter_custom_time) { + screen.timeline.from = data.from; + screen.timeline.to = data.to; } else { - $('#filter_show_timeline, #filter_details').prop('disabled', false); - $('input[name=filter_show_opdata]').prop('disabled', false); - $('#filter_highlight_row').prop('disabled', true); + screen.timeline.from = global_timerange.from; + screen.timeline.to = global_timerange.to; } - }); - $('#filter_show_tags').change(function() { - var disabled = $(this).find('[value = "<?= PROBLEMS_SHOW_TAGS_NONE ?>"]').is(':checked'); - $('#filter_tag_priority').prop('disabled', disabled); - $('#filter_tag_name_format input').prop('disabled', disabled); - }); + screen.data.filter = data; + screen.data.sort = data.sort; + screen.data.sortorder = data.sortorder; + // Close all opened hint boxes otherwise flicker free screen will not refresh it content. + for (var i = overlays_stack.length - 1; i >= 0; i--) { + let hintbox = overlays_stack.getById(overlays_stack.stack[i]); + + if (hintbox.type === 'hintbox') { + hintBox.hideHint(hintbox.element, true); + removeFromOverlaysStack(overlays_stack.stack[i]); + } + } + + window.flickerfreeScreen.refresh(screen.id); + } + + function refreshCounters() { + clearTimeout(refresh_timer); + + fetch(refresh_url, { + method: 'POST', + body: new URLSearchParams({filter_counters: 1}) + }) + .then(response => response.json()) + .then(response => { + if (response.filter_counters) { + filter.updateCounters(response.filter_counters); + } + + refresh_timer = setTimeout(refreshCounters, refresh_interval); + }) + .catch(() => { + // On error restart refresh timer. + refresh_timer = setTimeout(refreshCounters, refresh_interval); + }); + } + + refreshCounters(); + + // Keep timeselector changes in global_timerange. + $.subscribe('timeselector.rangeupdate', (e, data) => { + if (data.idx === '<?= CControllerProblem::FILTER_IDX ?>') { + global_timerange.from = data.from; + global_timerange.to = data.to; + } + }); + }); + </script> +<?php +} +?> +<script type="text/javascript"> + jQuery(function($) { $(document).on({ mouseenter: function() { if ($(this)[0].scrollWidth > $(this)[0].offsetWidth) { diff --git a/ui/app/views/js/popup.tabfilter.edit.js.php b/ui/app/views/js/popup.tabfilter.edit.js.php new file mode 100644 index 00000000000..948e3b68cfe --- /dev/null +++ b/ui/app/views/js/popup.tabfilter.edit.js.php @@ -0,0 +1,84 @@ +<?php +/* +** Zabbix +** Copyright (C) 2001-2020 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 + */ +?> + +$('.overlay-dialogue-body #filter_custom_time').on('change', function() { + let $calendars = $(this).closest('form').find('.calendar-control'); + + $('input,button', $calendars).prop('disabled', !$(this).is(':checked')); +}); + +function tabFilterDelete(overlay) { + var $form = overlay.$dialogue.find('form'), + url = new Curl($form.attr('action')), + form_data = $form.serializeJSON(); + + url.setArgument('action', 'popup.tabfilter.delete'); + url.setArgument('idx', form_data['idx']); + url.setArgument('idx2', form_data['idx2']); + + overlay.setLoading(); + overlay.xhr = $.post(url.getUrl(), null, 'json') + .done((response) => { + overlay.$dialogue.find('.<?= ZBX_STYLE_MSG_BAD ?>').remove(); + + if ('errors' in response) { + $(response.errors).insertBefore($form); + } + else { + overlayDialogueDestroy(overlay.dialogueid); + overlay.element.dispatchEvent(new CustomEvent(TABFILTERITEM_EVENT_DELETE, {bubbles: true})); + } + }) + .always(() => { + overlay.unsetLoading(); + }); +} + +function tabFilterUpdate(overlay) { + var $form = overlay.$dialogue.find('form'), + url = new Curl($form.attr('action')), + form_data = $form.serializeJSON(); + + form_data.filter_name = form_data.filter_name.trim(); + + overlay.setLoading(); + overlay.xhr = $.post(url.getUrl(), form_data, 'json') + .done((response) => { + overlay.$dialogue.find('.<?= ZBX_STYLE_MSG_BAD ?>').remove(); + + if ('errors' in response) { + $(response.errors).insertBefore($form); + } + else { + overlayDialogueDestroy(overlay.dialogueid); + const properties = {detail: response, bubbles: true}; + overlay.element.dispatchEvent(new CustomEvent(TABFILTERITEM_EVENT_UPDATE, properties)); + } + }) + .always(() => { + overlay.unsetLoading(); + }); +} diff --git a/ui/app/views/js/popup.triggerwizard.js.php b/ui/app/views/js/popup.triggerwizard.js.php index 72f51f627e3..f01b29205d5 100644 --- a/ui/app/views/js/popup.triggerwizard.js.php +++ b/ui/app/views/js/popup.triggerwizard.js.php @@ -142,6 +142,12 @@ $expr_input.val(''); } + + $('#event_name') + .textareaFlexible() + .on('input keydown paste', function() { + overlays_stack.end().centerDialog(); + }); })(jQuery); /** diff --git a/ui/app/views/monitoring.host.view.php b/ui/app/views/monitoring.host.view.php index ed9a5376baf..ba502131a93 100644 --- a/ui/app/views/monitoring.host.view.php +++ b/ui/app/views/monitoring.host.view.php @@ -25,8 +25,11 @@ $this->addJsFile('multiselect.js'); $this->addJsFile('layout.mode.js'); - -$this->includeJsFile('monitoring.host.view.js.php'); +$this->addJsFile('menupopup.js'); +$this->addJsFile('gtlc.js'); +$this->addJsFile('class.calendar.js'); +$this->addJsFile('class.tabfilter.js'); +$this->addJsFile('class.tabfilteritem.js'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); @@ -39,133 +42,28 @@ $widget = (new CWidget()) ->setAttribute('aria-label', _('Content controls')) ); -$filter_tags = $data['filter']['tags']; -if (!$filter_tags) { - $filter_tags = [['tag' => '', 'value' => '', 'operator' => TAG_OPERATOR_LIKE]]; -} - -$filter_tags_table = (new CTable()) - ->setId('filter-tags') - ->addRow( - (new CCol( - (new CRadioButtonList('filter_evaltype', (int) $data['filter']['evaltype'])) - ->addValue(_('And/Or'), TAG_EVAL_TYPE_AND_OR) - ->addValue(_('Or'), TAG_EVAL_TYPE_OR) - ->setModern(true) - ))->setColSpan(4) -); - -$i = 0; -foreach ($filter_tags as $tag) { - $filter_tags_table->addRow([ - (new CTextBox('filter_tags['.$i.'][tag]', $tag['tag'])) - ->setAttribute('placeholder', _('tag')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CRadioButtonList('filter_tags['.$i.'][operator]', (int) $tag['operator'])) - ->addValue(_('Contains'), TAG_OPERATOR_LIKE) - ->addValue(_('Equals'), TAG_OPERATOR_EQUAL) - ->setModern(true), - (new CTextBox('filter_tags['.$i.'][value]', $tag['value'])) - ->setAttribute('placeholder', _('value')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CCol( - (new CButton('filter_tags['.$i.'][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ], 'form_row'); +if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { + $filter = (new CTabFilter()) + ->setId('monitoring_hosts_filter') + ->setOptions($data['tabfilter_options']) + ->addTemplate(new CPartial($data['filter_view'], $data['filter_defaults'])); - $i++; -} -$filter_tags_table->addRow( - (new CCol( - (new CButton('filter_tags_add', _('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-add') - ))->setColSpan(3) -); + foreach ($data['filter_tabs'] as $tab) { + $tab['tab_view'] = $data['filter_view']; + $filter->addTemplatedTab($tab['filter_name'], $tab); + } -$severities = []; -foreach (range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1) as $severity) { - $severities[] = [ - 'name' => getSeverityName($severity), - 'value' => $severity - ]; + // Set javascript options for tab filter initialization in monitoring.host.view.js.php file. + $data['filter_options'] = $filter->options; + $widget->addItem($filter); } - -if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { - $widget->addItem((new CFilter((new CUrl('zabbix.php'))->setArgument('action', 'host.view'))) - ->setProfile('web.hostsmon.filter') - ->setActiveTab($data['active_tab']) - ->addFormItem((new CVar('action', 'host.view'))->removeId()) - ->addFilterTab(_('Filter'), [ - (new CFormList()) - ->addRow(_('Name'), - (new CTextBox('filter_name', $data['filter']['name']))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow((new CLabel(_('Host groups'), 'filter_groupids__ms')), - (new CMultiSelect([ - 'name' => 'filter_groupids[]', - 'object_name' => 'hostGroup', - 'data' => $data['multiselect_hostgroup_data'], - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'host_groups', - 'srcfld1' => 'groupid', - 'dstfrm' => 'zbx_filter', - 'dstfld1' => 'filter_groupids_', - 'real_hosts' => true, - 'enrich_parent_groups' => true - ] - ] - ]))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow(_('IP'), - (new CTextBox('filter_ip', $data['filter']['ip'])) - ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow(_('DNS'), - (new CTextBox('filter_dns', $data['filter']['dns'])) - ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow(_('Port'), - (new CTextBox('filter_port', $data['filter']['port'])) - ->setWidth(ZBX_TEXTAREA_INTERFACE_PORT_WIDTH) - ) - ->addRow(_('Severity'), - (new CSeverityCheckBoxList('filter_severities'))->setChecked($data['filter']['severities']) - ), - (new CFormList()) - ->addRow(_('Status'), - (new CRadioButtonList('filter_status', (int) $data['filter']['status'])) - ->addValue(_('Any'), -1) - ->addValue(_('Enabled'), HOST_STATUS_MONITORED) - ->addValue(_('Disabled'), HOST_STATUS_NOT_MONITORED) - ->setModern(true) - ) - ->addRow(_('Tags'), $filter_tags_table) - ->addRow(_('Show hosts in maintenance'), [ - (new CCheckBox('filter_maintenance_status')) - ->setChecked($data['filter']['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) - ->setUncheckedValue(HOST_MAINTENANCE_STATUS_OFF), - (new CDiv([ - (new CLabel(_('Show suppressed problems'), 'filter_show_suppressed')) - ->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), - (new CCheckBox('filter_show_suppressed')) - ->setChecked($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) - ->setUncheckedValue(ZBX_PROBLEM_SUPPRESSED_FALSE) - ->setEnabled($data['filter']['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON), - ]))->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) - ]) - ]) - ); +else { + $data['filter_options'] = null; } -$widget->addItem(new CPartial('monitoring.host.view.html', array_intersect_key($data, array_flip([ - 'filter', 'sort', 'sortorder', 'view_curl', 'hosts', 'maintenances', 'paging' -])))); - +$widget->addItem((new CForm())->setName('host_view')->addClass('is-loading')); $widget->show(); +$this->includeJsFile('monitoring.host.view.js.php', $data); (new CScriptTag('host_page.start();')) ->setOnDocumentReady() diff --git a/ui/app/views/monitoring.problem.view.php b/ui/app/views/monitoring.problem.view.php index 13c235c6b12..1f17d605e5c 100644 --- a/ui/app/views/monitoring.problem.view.php +++ b/ui/app/views/monitoring.problem.view.php @@ -65,25 +65,23 @@ switch ($data['filter']['show']) { break; case TRIGGERS_OPTION_ALL: - $options['profileIdx'] = $data['profileIdx']; - $options['profileIdx2'] = $data['profileIdx2']; - $options['from'] = $data['from']; - $options['to'] = $data['to']; + $options['profileIdx'] = $data['tabfilter_idx']; + $options['profileIdx2'] = 0; + $options['from'] = $data['filter']['from']; + $options['to'] = $data['filter']['to']; break; } $screen = CScreenBuilder::getScreen($options); if ($data['action'] === 'problem.view') { - if ($data['filter']['show'] == TRIGGERS_OPTION_ALL) { - $this->addJsFile('class.calendar.js'); - } + $this->addJsFile('class.calendar.js'); $this->addJsFile('gtlc.js'); $this->addJsFile('flickerfreescreen.js'); $this->addJsFile('multiselect.js'); $this->addJsFile('layout.mode.js'); - - $this->includeJsFile('monitoring.problem.view.js.php'); + $this->addJsFile('class.tabfilter.js'); + $this->addJsFile('class.tabfilteritem.js'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); @@ -92,267 +90,6 @@ if ($data['action'] === 'problem.view') { uncheckTableRows('problem'); } - $filter_column1 = (new CFormList()) - ->addRow(_('Show'), - (new CRadioButtonList('filter_show', (int) $data['filter']['show'])) - ->addValue(_('Recent problems'), TRIGGERS_OPTION_RECENT_PROBLEM) - ->addValue(_('Problems'), TRIGGERS_OPTION_IN_PROBLEM) - ->addValue(_('History'), TRIGGERS_OPTION_ALL) - ->setModern(true) - ) - ->addRow((new CLabel(_('Host groups'), 'filter_groupids__ms')), - (new CMultiSelect([ - 'name' => 'filter_groupids[]', - 'object_name' => 'hostGroup', - 'data' => $data['filter']['groups'], - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'host_groups', - 'srcfld1' => 'groupid', - 'dstfrm' => 'zbx_filter', - 'dstfld1' => 'filter_groupids_', - 'real_hosts' => true, - 'enrich_parent_groups' => true - ] - ] - ]))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow((new CLabel(_('Hosts'), 'filter_hostids__ms')), - (new CMultiSelect([ - 'name' => 'filter_hostids[]', - 'object_name' => 'hosts', - 'data' => $data['filter']['hosts'], - 'popup' => [ - 'filter_preselect_fields' => [ - 'hostgroups' => 'filter_groupids_' - ], - 'parameters' => [ - 'srctbl' => 'hosts', - 'srcfld1' => 'hostid', - 'dstfrm' => 'zbx_filter', - 'dstfld1' => 'filter_hostids_' - ] - ] - ]))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow(_('Application'), [ - (new CTextBox('filter_application', $data['filter']['application'])) - ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH), - (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - (new CButton('filter_application_select', _('Select'))) - ->onClick('return PopUp("popup.generic", jQuery.extend('. - json_encode([ - 'srctbl' => 'applications', - 'srcfld1' => 'name', - 'dstfrm' => 'zbx_filter', - 'dstfld1' => 'filter_application', - 'with_applications' => '1', - 'real_hosts' => '1' - ]).', getFirstMultiselectValue("filter_hostids_")), null, this);' - ) - ->addClass(ZBX_STYLE_BTN_GREY) - ]) - ->addRow((new CLabel(_('Triggers'), 'filter_triggerids__ms')), - (new CMultiSelect([ - 'name' => 'filter_triggerids[]', - 'object_name' => 'triggers', - 'data' => $data['filter']['triggers'], - 'popup' => [ - 'filter_preselect_fields' => [ - 'hosts' => 'filter_hostids_' - ], - 'parameters' => [ - 'srctbl' => 'triggers', - 'srcfld1' => 'triggerid', - 'dstfrm' => 'zbx_filter', - 'dstfld1' => 'filter_triggerids_', - 'monitored_hosts' => true, - 'with_monitored_triggers' => true, - 'noempty' => true - ] - ] - ]))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow(_('Problem'), - (new CTextBox('filter_name', $data['filter']['name']))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ) - ->addRow(_('Severity'), - (new CSeverityCheckBoxList('filter_severities'))->setChecked($data['filter']['severities']) - ); - - $filter_age = (new CNumericBox('filter_age', $data['filter']['age'], 3, false, false, false)) - ->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH); - if ($data['filter']['age_state'] == 0) { - $filter_age->setAttribute('disabled', 'disabled'); - } - - $filter_column1 - ->addRow(_('Age less than'), [ - (new CCheckBox('filter_age_state')) - ->setChecked($data['filter']['age_state'] == 1) - ->onClick('javascript: jQuery("#filter_age").prop("disabled", !this.checked)'), - (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - $filter_age, - (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - _('days') - ]); - - $filter_inventory = $data['filter']['inventory']; - if (!$filter_inventory) { - $filter_inventory = [['field' => '', 'value' => '']]; - } - - $filter_inventory_table = new CTable(); - $filter_inventory_table->setId('filter-inventory'); - $i = 0; - foreach ($filter_inventory as $field) { - $filter_inventory_table->addRow([ - new CComboBox('filter_inventory['.$i.'][field]', $field['field'], null, $data['filter']['inventories']), - (new CTextBox('filter_inventory['.$i.'][value]', $field['value']))->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CCol( - (new CButton('filter_inventory['.$i.'][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ], 'form_row'); - - $i++; - } - $filter_inventory_table->addRow( - (new CCol( - (new CButton('filter_inventory_add', _('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-add') - ))->setColSpan(3) - ); - - $filter_tags = $data['filter']['tags']; - if (!$filter_tags) { - $filter_tags = [['tag' => '', 'value' => '', 'operator' => TAG_OPERATOR_LIKE]]; - } - - $filter_tags_table = new CTable(); - $filter_tags_table->setId('filter-tags'); - - $filter_tags_table->addRow( - (new CCol( - (new CRadioButtonList('filter_evaltype', (int) $data['filter']['evaltype'])) - ->addValue(_('And/Or'), TAG_EVAL_TYPE_AND_OR) - ->addValue(_('Or'), TAG_EVAL_TYPE_OR) - ->setModern(true) - ))->setColSpan(4) - ); - - $i = 0; - foreach ($filter_tags as $tag) { - $filter_tags_table->addRow([ - (new CTextBox('filter_tags['.$i.'][tag]', $tag['tag'])) - ->setAttribute('placeholder', _('tag')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CRadioButtonList('filter_tags['.$i.'][operator]', (int) $tag['operator'])) - ->addValue(_('Contains'), TAG_OPERATOR_LIKE) - ->addValue(_('Equals'), TAG_OPERATOR_EQUAL) - ->setModern(true), - (new CTextBox('filter_tags['.$i.'][value]', $tag['value'])) - ->setAttribute('placeholder', _('value')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH), - (new CCol( - (new CButton('filter_tags['.$i.'][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ], 'form_row'); - - $i++; - } - $filter_tags_table->addRow( - (new CCol( - (new CButton('filter_tags_add', _('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-add') - ))->setColSpan(3) - ); - - $tag_format_line = (new CHorList()) - ->addItem((new CRadioButtonList('filter_show_tags', (int) $data['filter']['show_tags'])) - ->addValue(_('None'), PROBLEMS_SHOW_TAGS_NONE) - ->addValue(PROBLEMS_SHOW_TAGS_1, PROBLEMS_SHOW_TAGS_1) - ->addValue(PROBLEMS_SHOW_TAGS_2, PROBLEMS_SHOW_TAGS_2) - ->addValue(PROBLEMS_SHOW_TAGS_3, PROBLEMS_SHOW_TAGS_3) - ->setModern(true) - ) - ->addItem((new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN)) - ->addItem(new CLabel(_('Tag name'))) - ->addItem((new CRadioButtonList('filter_tag_name_format', (int) $data['filter']['tag_name_format'])) - ->addValue(_('Full'), PROBLEMS_TAG_NAME_FULL) - ->addValue(_('Shortened'), PROBLEMS_TAG_NAME_SHORTENED) - ->addValue(_('None'), PROBLEMS_TAG_NAME_NONE) - ->setModern(true) - ->setEnabled((int) $data['filter']['show_tags'] !== PROBLEMS_SHOW_TAGS_NONE) - ); - - $filter_column2 = (new CFormList()) - ->addRow(_('Host inventory'), $filter_inventory_table) - ->addRow(_('Tags'), $filter_tags_table) - ->addRow(_('Show tags'), $tag_format_line) - ->addRow(_('Tag display priority'), - (new CTextBox('filter_tag_priority', $data['filter']['tag_priority'])) - ->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) - ->setAttribute('placeholder', _('comma-separated list')) - ->setEnabled((int) $data['filter']['show_tags'] !== PROBLEMS_SHOW_TAGS_NONE) - ) - ->addRow(_('Show operational data'), [ - (new CRadioButtonList('filter_show_opdata', (int) $data['filter']['show_opdata'])) - ->addValue(_('None'), OPERATIONAL_DATA_SHOW_NONE) - ->addValue(_('Separately'), OPERATIONAL_DATA_SHOW_SEPARATELY) - ->addValue(_('With problem name'), OPERATIONAL_DATA_SHOW_WITH_PROBLEM) - ->setModern(true) - ->setEnabled($data['filter']['compact_view'] == 0) - ]) - ->addRow(_('Show suppressed problems'), [ - (new CCheckBox('filter_show_suppressed')) - ->setChecked($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE), - (new CDiv([ - (new CLabel(_('Show unacknowledged only'), 'filter_unacknowledged')) - ->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), - (new CCheckBox('filter_unacknowledged')) - ->setChecked($data['filter']['unacknowledged'] == 1) - ]))->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) - ]) - ->addRow(_('Compact view'), [ - (new CCheckBox('filter_compact_view'))->setChecked($data['filter']['compact_view'] == 1), - (new CDiv([ - (new CLabel(_('Show timeline'), 'filter_show_timeline'))->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), - (new CCheckBox('filter_show_timeline')) - ->setChecked($data['filter']['show_timeline'] == 1) - ->setEnabled($data['filter']['compact_view'] == 0), - ]))->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) - ]) - ->addRow(_('Show details'), [ - (new CCheckBox('filter_details')) - ->setChecked($data['filter']['details'] == 1) - ->setEnabled($data['filter']['compact_view'] == 0), - (new CDiv([ - (new CLabel(_('Highlight whole row'), 'filter_highlight_row'))->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), - (new CCheckBox('filter_highlight_row')) - ->setChecked($data['filter']['highlight_row'] == 1) - ->setEnabled($data['filter']['compact_view'] == 1) - ])) - ->addClass(ZBX_STYLE_FILTER_HIGHLIGHT_ROW_CB) - ->addClass(ZBX_STYLE_TABLE_FORMS_SECOND_COLUMN) - ]); - - $filter = (new CFilter((new CUrl('zabbix.php'))->setArgument('action', 'problem.view'))) - ->setProfile($data['profileIdx']) - ->setActiveTab($data['active_tab']) - ->addFormItem((new CVar('action', 'problem.view'))->removeId()); - - if ($data['filter']['show'] == TRIGGERS_OPTION_ALL) { - $filter->addTimeSelector($screen->timeline['from'], $screen->timeline['to']); - } - - $filter->addFilterTab(_('Filter'), [$filter_column1, $filter_column2]); - $widget = (new CWidget()) ->setTitle(_('Problems')) ->setWebLayoutMode($web_layout_mode) @@ -360,14 +97,35 @@ if ($data['action'] === 'problem.view') { (new CTag('nav', true, (new CList()) ->addItem(new CRedirectButton(_('Export to CSV'), - (new CUrl('zabbix.php'))->setArgument('action', 'problem.view.csv') + (new CUrl())->setArgument('action', 'problem.view.csv') )) ->addItem(get_icon('kioskmode', ['mode' => $web_layout_mode])) ))->setAttribute('aria-label', _('Content controls')) ); if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { + $defaults = [ + 'tags' => [['tag' => '', 'value' => '', 'operator' => TAG_OPERATOR_LIKE]], + 'inventory' => [['field' => 'type', 'value' => '']] + ]; + $filter = (new CTabFilter()) + ->setId('monitoring_problem_filter') + ->setIdx($data['tabfilter_idx']) + ->setSelected((int) $data['tab_selected']) + ->setExpanded((bool) $data['tab_expanded']) + ->addTemplate(new CPartial($data['filter_view'], $data['filter_defaults'] + $defaults)); + + foreach ($data['filter_tabs'] as $tab) { + $tab['tab_view'] = $data['filter_view']; + $filter->addTemplatedTab($tab['filter_name'], $tab); + } + + $filter->addTimeselector($data['timerange']); + // Set javascript options for tab filter initialization in monitoring.problem.view.js.php file. + $data['filter_options'] = $filter->options; $widget->addItem($filter); + + $this->includeJsFile('monitoring.problem.view.js.php', $data); } $widget @@ -376,20 +134,6 @@ if ($data['action'] === 'problem.view') { // Activate blinking. (new CScriptTag('jqBlink.blink();'))->show(); - - if ($data['filter']['show'] == TRIGGERS_OPTION_ALL) { - $objData = [ - 'id' => 'timeline_1', - 'loadSBox' => 0, - 'loadImage' => 0, - 'dynamic' => 0 - ]; - - (new CScriptTag( - 'timeControl.addObject("scroll_events_id", '.zbx_jsvalue($screen->timeline).', '.zbx_jsvalue($objData).');'. - 'timeControl.processObjects();' - ))->show(); - } } else { echo $screen->get(); diff --git a/ui/app/views/monitoring.widget.problemhosts.view.php b/ui/app/views/monitoring.widget.problemhosts.view.php index cac7cc7994d..8cb2600727f 100644 --- a/ui/app/views/monitoring.widget.problemhosts.view.php +++ b/ui/app/views/monitoring.widget.problemhosts.view.php @@ -37,23 +37,20 @@ $table = (new CTableInfo()) $url_group = (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_set', 1) - ->setArgument('filter_show', TRIGGERS_OPTION_RECENT_PROBLEM) - ->setArgument('filter_groupids', null) - ->setArgument('filter_hostids', $data['filter']['hostids']) - ->setArgument('filter_name', $data['filter']['problem']) - ->setArgument('filter_show_suppressed', ($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) + ->setArgument('filter_name', '') + ->setArgument('show', TRIGGERS_OPTION_RECENT_PROBLEM) + ->setArgument('hostids', $data['filter']['hostids']) + ->setArgument('name', $data['filter']['problem']) + ->setArgument('show_suppressed', ($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) ? ZBX_PROBLEM_SUPPRESSED_TRUE : null ); $url_host = (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_set', 1) - ->setArgument('filter_show', TRIGGERS_OPTION_RECENT_PROBLEM) - ->setArgument('filter_groupids', null) - ->setArgument('filter_hostids', null) - ->setArgument('filter_name', $data['filter']['problem']) - ->setArgument('filter_show_suppressed', ($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) + ->setArgument('filter_name', '') + ->setArgument('show', TRIGGERS_OPTION_RECENT_PROBLEM) + ->setArgument('name', $data['filter']['problem']) + ->setArgument('show_suppressed', ($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) ? ZBX_PROBLEM_SUPPRESSED_TRUE : null ); @@ -67,8 +64,8 @@ foreach ($data['groups'] as $group) { continue; } - $url_group->setArgument('filter_groupids', [$group['groupid']]); - $url_host->setArgument('filter_groupids', [$group['groupid']]); + $url_group->setArgument('groupids', [$group['groupid']]); + $url_host->setArgument('groupids', [$group['groupid']]); $group_row = [new CLink($group['name'], $url_group->getUrl())]; diff --git a/ui/app/views/monitoring.widget.problemsbysv.view.php b/ui/app/views/monitoring.widget.problemsbysv.view.php index 9611ade1653..74ace70b452 100644 --- a/ui/app/views/monitoring.widget.problemsbysv.view.php +++ b/ui/app/views/monitoring.widget.problemsbysv.view.php @@ -51,14 +51,13 @@ else { $groupurl = (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_set', 1) - ->setArgument('filter_show', TRIGGERS_OPTION_RECENT_PROBLEM) - ->setArgument('filter_groupids', null) - ->setArgument('filter_hostids', + ->setArgument('filter_name', '') + ->setArgument('show', TRIGGERS_OPTION_RECENT_PROBLEM) + ->setArgument('hostids', array_key_exists('hostids', $data['filter']) ? $data['filter']['hostids'] : null ) - ->setArgument('filter_name', array_key_exists('problem', $data['filter']) ? $data['filter']['problem'] : null) - ->setArgument('filter_show_suppressed', + ->setArgument('name', array_key_exists('problem', $data['filter']) ? $data['filter']['problem'] : null) + ->setArgument('show_suppressed', (array_key_exists('show_suppressed', $data['filter']) && $data['filter']['show_suppressed'] == 1) ? 1 : null ); diff --git a/ui/app/views/popup.tabfilter.edit.php b/ui/app/views/popup.tabfilter.edit.php new file mode 100644 index 00000000000..ea94348545c --- /dev/null +++ b/ui/app/views/popup.tabfilter.edit.php @@ -0,0 +1,93 @@ +<?php +/* +** Zabbix +** Copyright (C) 2001-2020 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 + */ + +$form_list = (new CFormList()) + ->addVar('idx', $data['idx']) + ->addVar('idx2', $data['idx2']) + ->addVar('create', $data['create']) + ->addVar('support_custom_time', $data['support_custom_time']) + ->addRow((new CLabel(_('Name'), 'filter_name'))->setAsteriskMark(), + (new CTextBox('filter_name', $data['filter_name']))->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ) + ->addRow(_('Show number of records'), + (new CCheckBox('filter_show_counter', 1))->setChecked($data['filter_show_counter']) + ); + +if ($data['support_custom_time']) { + $form_list + ->addRow(_('Set custom time period'), + (new CCheckBox('filter_custom_time', 1)) + ->setChecked($data['filter_custom_time']) + ) + ->addRow(new CLabel(_('From'), 'tabfilter_from'), + (new CDateSelector('tabfilter_from', $data['tabfilter_from'])) + ->setDateFormat(ZBX_DATE_TIME) + ->setEnabled((bool) $data['filter_custom_time']) + ) + ->addRow(new CLabel(_('To'), 'tabfilter_to'), + (new CDateSelector('tabfilter_to', $data['tabfilter_to'])) + ->setDateFormat(ZBX_DATE_TIME) + ->setEnabled((bool) $data['filter_custom_time']) + ); +} + +$form = (new CForm()) + ->cleanItems() + ->setName('tabfilter_form') + ->addVar('action', 'popup.tabfilter.update') + ->addItem([ + $form_list, + (new CInput('submit', 'submit'))->addStyle('display: none;') + ]); + +$output = [ + 'header' => $data['title'], + 'script_inline' => $this->readJsFile('popup.tabfilter.edit.js.php'), + 'body' => (new CDiv([$data['errors'], $form]))->toString(), + 'buttons' => [ + [ + 'title' => _('Delete'), + 'isSubmit' => true, + 'keepOpen' => true, + 'enabled' => !$data['create'], + 'class' => 'float-left', + 'confirmation' => _('Are you sure you want to delete this filter?'), + 'action' => 'return tabFilterDelete(overlay)' + ], + [ + 'title' => _('Save'), + 'keepOpen' => true, + 'isSubmit' => true, + 'action' => 'return tabFilterUpdate(overlay)' + ] + ] +]; + +if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { + CProfiler::getInstance()->stop(); + $output['debug'] = CProfiler::getInstance()->make()->toString(); +} + +echo json_encode($output); diff --git a/ui/app/views/popup.triggerexpr.php b/ui/app/views/popup.triggerexpr.php index 674e952eaae..91f445070ef 100644 --- a/ui/app/views/popup.triggerexpr.php +++ b/ui/app/views/popup.triggerexpr.php @@ -139,9 +139,16 @@ if (array_key_exists('params', $data['functions'][$data['selectedFunction']])) { elseif (in_array($param_name, ['shift'])) { $param_type_element = _('Time'); } + elseif (in_array($param_name, ['period_shift'])) { + $param_type_element = _('Period'); + } $param_field = (new CTextBox('params['.$param_name.']', $param_value))->setWidth(ZBX_TEXTAREA_SMALL_WIDTH); + if ($param_name === 'period_shift') { + $param_field->setAttribute('placeholder', 'now/h'); + } + $expression_form_list->addRow($label, [ $param_field, (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), diff --git a/ui/app/views/popup.triggerwizard.php b/ui/app/views/popup.triggerwizard.php index abcd67251db..de5a0bfe3ac 100644 --- a/ui/app/views/popup.triggerwizard.php +++ b/ui/app/views/popup.triggerwizard.php @@ -83,6 +83,12 @@ $form->addItem( ->setAriaRequired() ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ) + ->addRow( + new CLabel(_('Event name'), 'event_name'), + (new CTextAreaFlexible('event_name', $options['event_name'])) + ->setMaxlength(DB::getFieldLength('triggers', 'event_name')) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ) ->addRow((new CLabel(_('Item'), 'itemid'))->setAsteriskMark(), $ms_itemid) ->addRow(_('Severity'), new CSeverity([ 'name' => 'priority', diff --git a/ui/app/views/search.php b/ui/app/views/search.php index 394b04539f9..a0decb08f49 100644 --- a/ui/app/views/search.php +++ b/ui/app/views/search.php @@ -123,8 +123,8 @@ foreach ($data['hosts'] as $hostid => $host) { new CLink(_('Problems'), (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_hostids[]', $hostid) - ->setArgument('filter_set', '1') + ->setArgument('filter_name', '') + ->setArgument('hostids', [$hostid]) ), new CLink(_('Graphs'), (new CUrl('zabbix.php')) @@ -208,8 +208,8 @@ foreach ($data['groups'] as $groupid => $group) { new CLink(_('Problems'), (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_groupids[]', $groupid) - ->setArgument('filter_set', '1') + ->setArgument('filter_name', '') + ->setArgument('groupids', [$groupid]) ), new CLink(_('Web'), (new CUrl('zabbix.php')) |