1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19**/
20
21
22/**
23 * @var CView $this
24 */
25
26// indicator of sort field
27$sort_div = (new CSpan())->addClass(($data['sortorder'] === ZBX_SORT_DOWN) ? ZBX_STYLE_ARROW_DOWN : ZBX_STYLE_ARROW_UP);
28
29$url_details = (new CUrl('tr_events.php'))
30	->setArgument('triggerid', '')
31	->setArgument('eventid', '');
32
33$show_timeline = ($data['sortfield'] === 'clock' && $data['fields']['show_timeline']);
34$show_recovery_data = in_array($data['fields']['show'], [TRIGGERS_OPTION_RECENT_PROBLEM, TRIGGERS_OPTION_ALL]);
35
36$header_time = new CColHeader(($data['sortfield'] === 'clock') ? [_('Time'), $sort_div] : _('Time'));
37
38if ($show_timeline) {
39	$header = [
40		$header_time->addClass(ZBX_STYLE_RIGHT),
41		(new CColHeader())->addClass(ZBX_STYLE_TIMELINE_TH),
42		(new CColHeader())->addClass(ZBX_STYLE_TIMELINE_TH)
43	];
44}
45else {
46	$header = [$header_time];
47}
48
49$show_opdata = $data['fields']['show_opdata'];
50
51$table = (new CTableInfo())
52	->setHeader(array_merge($header, [
53		$show_recovery_data ? _('Recovery time') : null,
54		$show_recovery_data ? _('Status') : null,
55		_('Info'),
56		($data['sortfield'] === 'host') ? [_('Host'), $sort_div] : _('Host'),
57		[
58			($data['sortfield'] === 'name') ? [_('Problem'), $sort_div] : _('Problem'),
59			' &bullet; ',
60			($data['sortfield'] === 'severity') ? [_('Severity'), $sort_div] : _('Severity')
61		],
62		($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) ? _('Operational data') : null,
63		_('Duration'),
64		_('Ack'),
65		_('Actions'),
66		$data['fields']['show_tags'] ? _('Tags') : null
67	]));
68
69$today = strtotime('today');
70$last_clock = 0;
71
72if ($data['data']['problems']) {
73	$triggers_hosts = makeTriggersHostsList($data['data']['triggers_hosts']);
74}
75
76foreach ($data['data']['problems'] as $eventid => $problem) {
77	$trigger = $data['data']['triggers'][$problem['objectid']];
78
79	if ($problem['r_eventid'] != 0) {
80		$value = TRIGGER_VALUE_FALSE;
81		$value_str = _('RESOLVED');
82		$value_clock = $problem['r_clock'];
83	}
84	else {
85		$in_closing = false;
86
87		foreach ($problem['acknowledges'] as $acknowledge) {
88			if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_CLOSE) == ZBX_PROBLEM_UPDATE_CLOSE) {
89				$in_closing = true;
90				break;
91			}
92		}
93
94		$value = $in_closing ? TRIGGER_VALUE_FALSE : TRIGGER_VALUE_TRUE;
95		$value_str = $in_closing ? _('CLOSING') : _('PROBLEM');
96		$value_clock = $in_closing ? time() : $problem['clock'];
97	}
98
99	$url_details
100		->setArgument('triggerid', $problem['objectid'])
101		->setArgument('eventid', $problem['eventid']);
102
103	$cell_clock = ($problem['clock'] >= $today)
104		? zbx_date2str(TIME_FORMAT_SECONDS, $problem['clock'])
105		: zbx_date2str(DATE_TIME_FORMAT_SECONDS, $problem['clock']);
106	$cell_clock = new CCol(new CLink($cell_clock, $url_details));
107
108	$is_acknowledged = ($problem['acknowledged'] == EVENT_ACKNOWLEDGED);
109
110	if ($show_recovery_data) {
111		if ($problem['r_eventid'] != 0) {
112			$cell_r_clock = ($problem['r_clock'] >= $today)
113				? zbx_date2str(TIME_FORMAT_SECONDS, $problem['r_clock'])
114				: zbx_date2str(DATE_TIME_FORMAT_SECONDS, $problem['r_clock']);
115			$cell_r_clock = (new CCol(new CLink($cell_r_clock, $url_details)))
116				->addClass(ZBX_STYLE_NOWRAP)
117				->addClass(ZBX_STYLE_RIGHT);
118		}
119		else {
120			$cell_r_clock = '';
121		}
122
123		$cell_status = new CSpan($value_str);
124
125		// Add colors and blinking to span depending on configuration and trigger parameters.
126		addTriggerValueStyle($cell_status, $value, $value_clock, $is_acknowledged);
127	}
128
129	// Info.
130	$info_icons = [];
131	if ($problem['r_eventid'] != 0) {
132		if ($problem['correlationid'] != 0) {
133			$info_icons[] = makeInformationIcon(
134				array_key_exists($problem['correlationid'], $data['data']['correlations'])
135					? _s('Resolved by correlation rule "%1$s".',
136						$data['data']['correlations'][$problem['correlationid']]['name']
137					)
138					: _('Resolved by correlation rule.')
139			);
140		}
141		elseif ($problem['userid'] != 0) {
142			$info_icons[] = makeInformationIcon(
143				array_key_exists($problem['userid'], $data['data']['users'])
144					? _s('Resolved by user "%1$s".', getUserFullname($data['data']['users'][$problem['userid']]))
145					: _('Resolved by inaccessible user.')
146			);
147		}
148	}
149
150	if (array_key_exists('suppression_data', $problem) && $problem['suppression_data']) {
151		$info_icons[] = makeSuppressedProblemIcon($problem['suppression_data']);
152	}
153
154	$opdata = null;
155	if ($show_opdata != OPERATIONAL_DATA_SHOW_NONE) {
156
157		// operational data
158		if ($trigger['opdata'] === '') {
159			if ($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) {
160				$opdata = (new CCol(CScreenProblem::getLatestValues($trigger['items'])))->addClass('latest-values');
161			}
162		} else {
163			$opdata = CMacrosResolverHelper::resolveTriggerOpdata(
164				[
165					'triggerid' => $trigger['triggerid'],
166					'expression' => $trigger['expression'],
167					'opdata' => $trigger['opdata'],
168					'clock' => ($problem['r_eventid'] != 0) ? $problem['r_clock'] : $problem['clock'],
169					'ns' => ($problem['r_eventid'] != 0) ? $problem['r_ns'] : $problem['ns']
170				],
171				[
172					'events' => true,
173					'html' => true
174				]
175			);
176
177			if ($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) {
178				$opdata = (new CCol($opdata))
179					->addClass('opdata')
180					->addClass(ZBX_STYLE_WORDWRAP);
181			}
182		}
183	}
184
185	$problem_link = [
186		(new CLinkAction($problem['name']))
187			->setAjaxHint(CHintBoxHelper::getEventList($trigger['triggerid'], $eventid, $show_timeline,
188				$data['fields']['show_tags'], $data['fields']['tags'], $data['fields']['tag_name_format'],
189				$data['fields']['tag_priority']
190			))
191			->setAttribute('aria-label', _xs('%1$s, Severity, %2$s', 'screen reader',
192				$problem['name'], getSeverityName($problem['severity'], $data['config'])
193			))
194	];
195
196	if ($show_opdata == OPERATIONAL_DATA_SHOW_WITH_PROBLEM && $opdata) {
197		$problem_link = array_merge($problem_link, [' (', $opdata, ')']);
198	}
199
200	$description = (new CCol($problem_link));
201
202	$description_style = getSeverityStyle($problem['severity']);
203
204	if ($value == TRIGGER_VALUE_TRUE) {
205		$description->addClass($description_style);
206	}
207
208	if (!$show_recovery_data && $data['config'][$is_acknowledged ? 'problem_ack_style' : 'problem_unack_style']) {
209		// blinking
210		$duration = time() - $problem['clock'];
211
212		if ($data['config']['blink_period'] != 0 && $duration < $data['config']['blink_period']) {
213			$description
214				->addClass('blink')
215				->setAttribute('data-time-to-blink', $data['config']['blink_period'] - $duration)
216				->setAttribute('data-toggle-class', ZBX_STYLE_BLINK_HIDDEN);
217		}
218	}
219
220	if ($show_timeline) {
221		if ($last_clock != 0) {
222			CScreenProblem::addTimelineBreakpoint($table, $last_clock, $problem['clock'], $data['sortorder']);
223		}
224		$last_clock = $problem['clock'];
225
226		$row = [
227			$cell_clock->addClass(ZBX_STYLE_TIMELINE_DATE),
228			(new CCol())
229				->addClass(ZBX_STYLE_TIMELINE_AXIS)
230				->addClass(ZBX_STYLE_TIMELINE_DOT),
231			(new CCol())->addClass(ZBX_STYLE_TIMELINE_TD)
232		];
233	}
234	else {
235		$row = [
236			$cell_clock
237				->addClass(ZBX_STYLE_NOWRAP)
238				->addClass(ZBX_STYLE_RIGHT)
239		];
240	}
241
242	// Create acknowledge link.
243	$problem_update_link = (new CLink($is_acknowledged ? _('Yes') : _('No')))
244		->addClass($is_acknowledged ? ZBX_STYLE_GREEN : ZBX_STYLE_RED)
245		->addClass(ZBX_STYLE_LINK_ALT)
246		->onClick('acknowledgePopUp('.json_encode(['eventids' => [$problem['eventid']]]).', this);');
247
248	$table->addRow(array_merge($row, [
249		$show_recovery_data ? $cell_r_clock : null,
250		$show_recovery_data ? $cell_status : null,
251		makeInformationList($info_icons),
252		$triggers_hosts[$trigger['triggerid']],
253		$description,
254		($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY ) ? $opdata : null,
255		(new CCol(zbx_date2age($problem['clock'], ($problem['r_eventid'] != 0) ? $problem['r_clock'] : 0)))
256			->addClass(ZBX_STYLE_NOWRAP),
257		$problem_update_link,
258		makeEventActionsIcons($problem['eventid'], $data['data']['actions'], $data['data']['users'], $data['config']),
259		$data['fields']['show_tags'] ? $data['data']['tags'][$problem['eventid']] : null
260	]));
261}
262
263if ($data['info'] !== '') {
264	$table->setFooter([
265		(new CCol($data['info']))
266			->setColSpan($table->getNumCols())
267			->addClass(ZBX_STYLE_LIST_TABLE_FOOTER)
268	]);
269}
270
271$output = [
272	'aria_label' => _xs('%1$s widget', 'screen reader', $data['name']).', '.$data['info'],
273	'header' => $data['name'],
274	'body' => $table->toString()
275];
276
277if ($data['initial_load']) {
278	$output['script_inline'] =
279		'if (typeof refreshProblemsWidget !== typeof(Function)) {'.
280			'function refreshProblemsWidget(event, response, overlay) {'.
281				'refreshWidgetOnAcknowledgeCreate("problems", response, overlay);'.
282			'}'.
283
284			'$.subscribe("acknowledge.create", refreshProblemsWidget);'.
285		'}';
286}
287
288if (($messages = getMessages()) !== null) {
289	$output['messages'] = $messages->toString();
290}
291
292if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) {
293	CProfiler::getInstance()->stop();
294	$output['debug'] = CProfiler::getInstance()->make()->toString();
295}
296
297echo json_encode($output);
298