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// indicator of sort field
23$sort_div = (new CSpan())->addClass(($data['sortorder'] === ZBX_SORT_DOWN) ? ZBX_STYLE_ARROW_DOWN : ZBX_STYLE_ARROW_UP);
24
25$backurl = (new CUrl('zabbix.php'))
26	->setArgument('action', 'dashboard.view')
27	->getUrl();
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$table = (new CTableInfo())
50	->setHeader(array_merge($header, [
51		$show_recovery_data ? _('Recovery time') : null,
52		$show_recovery_data ? _('Status') : null,
53		_('Info'),
54		($data['sortfield'] === 'host') ? [_('Host'), $sort_div] : _('Host'),
55		[
56			($data['sortfield'] === 'name') ? [_('Problem'), $sort_div] : _('Problem'),
57			' &bullet; ',
58			($data['sortfield'] === 'severity') ? [_('Severity'), $sort_div] : _('Severity')
59		],
60		$data['fields']['show_latest_values'] ? _('Latest values') : null,
61		_('Duration'),
62		_('Ack'),
63		_('Actions'),
64		$data['fields']['show_tags'] ? _('Tags') : null
65	]));
66
67$today = strtotime('today');
68$last_clock = 0;
69
70if ($data['data']['problems']) {
71	$triggers_hosts = makeTriggersHostsList($data['data']['triggers_hosts']);
72}
73
74foreach ($data['data']['problems'] as $eventid => $problem) {
75	$trigger = $data['data']['triggers'][$problem['objectid']];
76
77	if ($problem['r_eventid'] != 0) {
78		$value = TRIGGER_VALUE_FALSE;
79		$value_str = _('RESOLVED');
80		$value_clock = $problem['r_clock'];
81	}
82	else {
83		$in_closing = false;
84
85		foreach ($problem['acknowledges'] as $acknowledge) {
86			if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_CLOSE) == ZBX_PROBLEM_UPDATE_CLOSE) {
87				$in_closing = true;
88				break;
89			}
90		}
91
92		$value = $in_closing ? TRIGGER_VALUE_FALSE : TRIGGER_VALUE_TRUE;
93		$value_str = $in_closing ? _('CLOSING') : _('PROBLEM');
94		$value_clock = $in_closing ? time() : $problem['clock'];
95	}
96
97	$url_details
98		->setArgument('triggerid', $problem['objectid'])
99		->setArgument('eventid', $problem['eventid']);
100
101	$cell_clock = ($problem['clock'] >= $today)
102		? zbx_date2str(TIME_FORMAT_SECONDS, $problem['clock'])
103		: zbx_date2str(DATE_TIME_FORMAT_SECONDS, $problem['clock']);
104	$cell_clock = new CCol(new CLink($cell_clock, $url_details));
105
106	$is_acknowledged = $problem['acknowledged'] == EVENT_ACKNOWLEDGED;
107
108	if ($show_recovery_data) {
109		if ($problem['r_eventid'] != 0) {
110			$cell_r_clock = ($problem['r_clock'] >= $today)
111				? zbx_date2str(TIME_FORMAT_SECONDS, $problem['r_clock'])
112				: zbx_date2str(DATE_TIME_FORMAT_SECONDS, $problem['r_clock']);
113			$cell_r_clock = (new CCol(new CLink($cell_r_clock, $url_details)))
114				->addClass(ZBX_STYLE_NOWRAP)
115				->addClass(ZBX_STYLE_RIGHT);
116		}
117		else {
118			$cell_r_clock = '';
119		}
120
121		$cell_status = new CSpan($value_str);
122
123		// Add colors and blinking to span depending on configuration and trigger parameters.
124		addTriggerValueStyle($cell_status, $value, $value_clock, $is_acknowledged);
125	}
126
127	// Info.
128	$info_icons = [];
129	if ($problem['r_eventid'] != 0) {
130		if ($problem['correlationid'] != 0) {
131			$info_icons[] = makeInformationIcon(
132				array_key_exists($problem['correlationid'], $data['data']['correlations'])
133					? _s('Resolved by correlation rule "%1$s".',
134						$data['data']['correlations'][$problem['correlationid']]['name']
135					)
136					: _('Resolved by correlation rule.')
137			);
138		}
139		elseif ($problem['userid'] != 0) {
140			$info_icons[] = makeInformationIcon(
141				array_key_exists($problem['userid'], $data['data']['users'])
142					? _s('Resolved by user "%1$s".', getUserFullname($data['data']['users'][$problem['userid']]))
143					: _('Resolved by inaccessible user.')
144			);
145		}
146	}
147
148	if (array_key_exists('suppression_data', $problem) && $problem['suppression_data']) {
149		$info_icons[] = makeSuppressedProblemIcon($problem['suppression_data']);
150	}
151
152	$description = (new CCol([
153		(new CLinkAction($problem['name']))
154			->setAjaxHint(CHintBoxHelper::getEventList($trigger['triggerid'], $eventid, $backurl, $show_timeline,
155				$data['fields']['show_tags'], $data['fields']['tags'], $data['fields']['tag_name_format'],
156				$data['fields']['tag_priority']
157			))
158			->setAttribute('aria-label', _xs('%1$s, Severity, %2$s', 'screen reader',
159				$problem['name'], getSeverityName($problem['severity'], $data['config'])
160			))
161	]));
162
163	$description_style = getSeverityStyle($problem['severity']);
164
165	if ($value == TRIGGER_VALUE_TRUE) {
166		$description->addClass($description_style);
167	}
168
169	if (!$show_recovery_data && $data['config'][$is_acknowledged ? 'problem_ack_style' : 'problem_unack_style']) {
170		// blinking
171		$duration = time() - $problem['clock'];
172
173		if ($data['config']['blink_period'] != 0 && $duration < $data['config']['blink_period']) {
174			$description
175				->addClass('blink')
176				->setAttribute('data-time-to-blink', $data['config']['blink_period'] - $duration)
177				->setAttribute('data-toggle-class', ZBX_STYLE_BLINK_HIDDEN);
178		}
179	}
180
181	if ($show_timeline) {
182		if ($last_clock != 0) {
183			CScreenProblem::addTimelineBreakpoint($table, $last_clock, $problem['clock'], $data['sortorder']);
184		}
185		$last_clock = $problem['clock'];
186
187		$row = [
188			$cell_clock->addClass(ZBX_STYLE_TIMELINE_DATE),
189			(new CCol())
190				->addClass(ZBX_STYLE_TIMELINE_AXIS)
191				->addClass(ZBX_STYLE_TIMELINE_DOT),
192			(new CCol())->addClass(ZBX_STYLE_TIMELINE_TD)
193		];
194	}
195	else {
196		$row = [
197			$cell_clock
198				->addClass(ZBX_STYLE_NOWRAP)
199				->addClass(ZBX_STYLE_RIGHT)
200		];
201	}
202
203	// Create acknowledge url.
204	$problem_update_url = (new CUrl('zabbix.php'))
205		->setArgument('action', 'acknowledge.edit')
206		->setArgument('eventids', [$problem['eventid']])
207		->setArgument('backurl', $backurl)
208		->getUrl();
209
210	$table->addRow(array_merge($row, [
211		$show_recovery_data ? $cell_r_clock : null,
212		$show_recovery_data ? $cell_status : null,
213		makeInformationList($info_icons),
214		$triggers_hosts[$trigger['triggerid']],
215		$description,
216		$data['fields']['show_latest_values'] ? CScreenProblem::getLatestValues($trigger['items']) : null,
217		(new CCol(zbx_date2age($problem['clock'], ($problem['r_eventid'] != 0) ? $problem['r_clock'] : 0)))
218			->addClass(ZBX_STYLE_NOWRAP),
219		(new CLink($problem['acknowledged'] == EVENT_ACKNOWLEDGED ? _('Yes') : _('No'), $problem_update_url))
220			->addClass($problem['acknowledged'] == EVENT_ACKNOWLEDGED ? ZBX_STYLE_GREEN : ZBX_STYLE_RED)
221			->addClass(ZBX_STYLE_LINK_ALT),
222		makeEventActionsIcons($problem['eventid'], $data['data']['actions'], $data['data']['mediatypes'],
223			$data['data']['users'], $data['config']
224		),
225		$data['fields']['show_tags'] ? $data['data']['tags'][$problem['eventid']] : null
226	]));
227}
228
229if ($data['info'] !== '') {
230	$table->setFooter([
231		(new CCol($data['info']))
232			->setColSpan($table->getNumCols())
233			->addClass(ZBX_STYLE_LIST_TABLE_FOOTER)
234	]);
235}
236
237$output = [
238	'aria_label' => _xs('%1$s widget', 'screen reader', $data['name']).', '.$data['info'],
239	'header' => $data['name'],
240	'body' => $table->toString()
241];
242
243if (($messages = getMessages()) !== null) {
244	$output['messages'] = $messages->toString();
245}
246
247if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) {
248	CProfiler::getInstance()->stop();
249	$output['debug'] = CProfiler::getInstance()->make()->toString();
250}
251
252echo (new CJson())->encode($output);
253