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
22require_once dirname(__FILE__).'/include/config.inc.php';
23require_once dirname(__FILE__).'/include/hosts.inc.php';
24require_once dirname(__FILE__).'/include/graphs.inc.php';
25require_once dirname(__FILE__).'/include/forms.inc.php';
26
27$page['title'] = hasRequest('parent_discoveryid') ? _('Configuration of graph prototypes') : _('Configuration of graphs');
28$page['file'] = 'graphs.php';
29$page['scripts'] = ['colorpicker.js', 'multiselect.js'];
30
31require_once dirname(__FILE__).'/include/page_header.php';
32
33// VAR	TYPE	OPTIONAL	FLAGS	VALIDATION	EXCEPTION
34$fields = [
35	'parent_discoveryid' =>	[T_ZBX_INT, O_OPT, P_SYS,		DB_ID,			null],
36	'groupid' =>			[T_ZBX_INT, O_OPT, P_SYS,		DB_ID,			null],
37	'hostid' =>				[T_ZBX_INT, O_OPT, P_SYS,		DB_ID,			null],
38	'copy_type' =>			[T_ZBX_INT, O_OPT, P_SYS,
39								IN([COPY_TYPE_TO_HOST_GROUP, COPY_TYPE_TO_HOST, COPY_TYPE_TO_TEMPLATE]),
40								'isset({copy})'
41							],
42	'copy_mode' =>			[T_ZBX_INT, O_OPT, P_SYS,		IN('0'),		null],
43	'graphid' =>			[T_ZBX_INT, O_OPT, P_SYS,		DB_ID,			'isset({form}) && {form} == "update"'],
44	'name' =>				[T_ZBX_STR, O_OPT, null,		NOT_EMPTY,		'isset({add}) || isset({update})', _('Name')],
45	'width' =>				[T_ZBX_INT, O_OPT, null,		BETWEEN(20, 65535), 'isset({add}) || isset({update})', _('Width')],
46	'height' =>				[T_ZBX_INT, O_OPT, null,		BETWEEN(20, 65535), 'isset({add}) || isset({update})', _('Height')],
47	'graphtype' =>			[T_ZBX_INT, O_OPT, null,		IN('0,1,2,3'),	'isset({add}) || isset({update})'],
48	'show_3d' =>			[T_ZBX_INT, O_OPT, P_NZERO,	IN('0,1'),		null],
49	'show_legend' =>		[T_ZBX_INT, O_OPT, P_NZERO,	IN('0,1'),		null],
50	'ymin_type' =>			[T_ZBX_INT, O_OPT, null,		IN('0,1,2'),	null],
51	'ymax_type' =>			[T_ZBX_INT, O_OPT, null,		IN('0,1,2'),	null],
52	'yaxismin' =>			[T_ZBX_DBL, O_OPT, null,		null,			'(isset({add}) || isset({update})) && isset({graphtype}) && ({graphtype} == '.GRAPH_TYPE_NORMAL.' || {graphtype} == '.GRAPH_TYPE_STACKED.')'],
53	'yaxismax' =>			[T_ZBX_DBL, O_OPT, null,		null,			'(isset({add}) || isset({update})) && isset({graphtype}) && ({graphtype} == '.GRAPH_TYPE_NORMAL.' || {graphtype} == '.GRAPH_TYPE_STACKED.')'],
54	'ymin_itemid' =>		[T_ZBX_INT, O_OPT, null,		DB_ID,			'(isset({add}) || isset({update})) && isset({ymin_type}) && {ymin_type} == '.GRAPH_YAXIS_TYPE_ITEM_VALUE],
55	'ymax_itemid' =>		[T_ZBX_INT, O_OPT, null,		DB_ID,			'(isset({add}) || isset({update})) && isset({ymax_type}) && {ymax_type} == '.GRAPH_YAXIS_TYPE_ITEM_VALUE],
56	'percent_left' =>		[T_ZBX_DBL, O_OPT, null,		BETWEEN(0, 100), null, _('Percentile line (left)')],
57	'percent_right' =>		[T_ZBX_DBL, O_OPT, null,		BETWEEN(0, 100), null, _('Percentile line (right)')],
58	'visible' =>			[T_ZBX_INT, O_OPT, null,		BETWEEN(0, 1),	null],
59	'items' =>				[T_ZBX_STR, O_OPT, null,		null,			null],
60	'show_work_period' =>	[T_ZBX_INT, O_OPT, null,		IN('1'),		null],
61	'show_triggers' =>		[T_ZBX_INT, O_OPT, null,		IN('1'),		null],
62	'group_graphid' =>		[T_ZBX_INT, O_OPT, null,		DB_ID,			null],
63	'copy_targetids' =>		[T_ZBX_INT, O_OPT, null,		DB_ID,			null],
64	// actions
65	'action' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, IN('"graph.masscopyto","graph.massdelete"'),	null],
66	'add' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,			null],
67	'update' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,			null],
68	'clone' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,			null],
69	'copy' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,			null],
70	'delete' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,			null],
71	'cancel' =>				[T_ZBX_STR, O_OPT, P_SYS,		null,			null],
72	'form' =>				[T_ZBX_STR, O_OPT, P_SYS,		null,			null],
73	'form_refresh' =>		[T_ZBX_INT, O_OPT, null,		null,			null],
74	// sort and sortorder
75	'sort' =>				[T_ZBX_STR, O_OPT, P_SYS, IN('"graphtype","name"'),					null],
76	'sortorder' =>			[T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'),	null]
77];
78$percentVisible = getRequest('visible');
79if (!isset($percentVisible['percent_left'])) {
80	unset($_REQUEST['percent_left']);
81}
82if (!isset($percentVisible['percent_right'])) {
83	unset($_REQUEST['percent_right']);
84}
85if (isset($_REQUEST['yaxismin']) && zbx_empty($_REQUEST['yaxismin'])) {
86	unset($_REQUEST['yaxismin']);
87}
88if (isset($_REQUEST['yaxismax']) && zbx_empty($_REQUEST['yaxismax'])) {
89	unset($_REQUEST['yaxismax']);
90}
91check_fields($fields);
92
93$gitems = [];
94foreach (getRequest('items', []) as $gitem) {
95	$gitems[] = json_decode($gitem, true);
96}
97
98$_REQUEST['items'] = $gitems;
99$_REQUEST['show_3d'] = getRequest('show_3d', 0);
100$_REQUEST['show_legend'] = getRequest('show_legend', 0);
101
102/*
103 * Permissions
104 */
105$groupId = getRequest('groupid');
106if ($groupId && !isWritableHostGroups([$groupId])) {
107	access_deny();
108}
109
110$hostId = getRequest('hostid', 0);
111
112if (hasRequest('parent_discoveryid')) {
113	// check whether discovery rule is editable by user
114	$discoveryRule = API::DiscoveryRule()->get([
115		'output' => ['itemid', 'hostid'],
116		'itemids' => getRequest('parent_discoveryid'),
117		'editable' => true
118	]);
119	$discoveryRule = reset($discoveryRule);
120	if (!$discoveryRule) {
121		access_deny();
122	}
123
124	$hostId = $discoveryRule['hostid'];
125
126	// check whether graph prototype is editable by user
127	if (hasRequest('graphid')) {
128		$graphPrototype = (bool) API::GraphPrototype()->get([
129			'output' => [],
130			'graphids' => getRequest('graphid'),
131			'editable' => true
132		]);
133		if (!$graphPrototype) {
134			access_deny();
135		}
136	}
137}
138elseif (hasRequest('graphid')) {
139	// check whether graph is normal and editable by user
140	$graph = (bool) API::Graph()->get([
141		'output' => [],
142		'graphids' => getRequest('graphid'),
143		'editable' => true
144	]);
145	if (!$graph) {
146		access_deny();
147	}
148}
149elseif ($hostId && !isWritableHostTemplates([$hostId])) {
150	access_deny();
151}
152
153/*
154 * Actions
155 */
156if (isset($_REQUEST['clone']) && isset($_REQUEST['graphid'])) {
157	// graph
158	$options = [
159		'graphids' => $_REQUEST['graphid'],
160		'output' => API_OUTPUT_EXTEND
161	];
162	$graph = empty($_REQUEST['parent_discoveryid'])
163		? API::Graph()->get($options)
164		: API::GraphPrototype()->get($options);
165	$graph = reset($graph);
166
167	$graph['items'] = API::GraphItem()->get([
168		'graphids' => $_REQUEST['graphid'],
169		'sortfield' => 'gitemid',
170		'output' => API_OUTPUT_EXTEND
171	]);
172
173	if ($graph['templateid'] || $graph['flags'] == ZBX_FLAG_DISCOVERY_CREATED) {
174		$_REQUEST = array_merge($_REQUEST, $graph);
175	}
176	else {
177		$graph = array_merge($graph, $_REQUEST);
178	}
179
180	unset($_REQUEST['graphid']);
181
182	$_REQUEST['form'] = 'clone';
183}
184elseif (hasRequest('add') || hasRequest('update')) {
185	// remove passing "gitemid" to API if new items added via pop-up
186	foreach ($gitems as &$item) {
187		if (array_key_exists('gitemid', $item) && !$item['gitemid']) {
188			unset($item['gitemid']);
189		}
190	}
191	unset($item);
192
193	$graph = [
194		'name' => getRequest('name'),
195		'width' => getRequest('width'),
196		'height' => getRequest('height'),
197		'ymin_type' => getRequest('ymin_type', 0),
198		'ymax_type' => getRequest('ymax_type', 0),
199		'yaxismin' => getRequest('yaxismin', 0),
200		'yaxismax' => getRequest('yaxismax', 0),
201		'ymin_itemid' => getRequest('ymin_itemid'),
202		'ymax_itemid' => getRequest('ymax_itemid'),
203		'show_work_period' => getRequest('show_work_period', 0),
204		'show_triggers' => getRequest('show_triggers', 0),
205		'graphtype' => getRequest('graphtype'),
206		'show_legend' => getRequest('show_legend', 1),
207		'show_3d' => getRequest('show_3d', 0),
208		'percent_left' => getRequest('percent_left', 0),
209		'percent_right' => getRequest('percent_right', 0),
210		'gitems' => $gitems
211	];
212
213	DBstart();
214
215	// create and update graph prototypes
216	if (hasRequest('parent_discoveryid')) {
217		if (hasRequest('graphid')) {
218			$graph['graphid'] = getRequest('graphid');
219			$result = API::GraphPrototype()->update($graph);
220
221			$messageSuccess = _('Graph prototype updated');
222			$messageFailed = _('Cannot update graph prototype');
223		}
224		else {
225			$result = API::GraphPrototype()->create($graph);
226
227			$messageSuccess = _('Graph prototype added');
228			$messageFailed = _('Cannot add graph prototype');
229		}
230
231		$cookieId = getRequest('parent_discoveryid');
232	}
233	// create and update graphs
234	else {
235		if (hasRequest('graphid')) {
236			$graph['graphid'] = getRequest('graphid');
237			$result = API::Graph()->update($graph);
238
239			$messageSuccess = _('Graph updated');
240			$messageFailed = _('Cannot update graph');
241		}
242		else {
243			$result = API::Graph()->create($graph);
244
245			$messageSuccess = _('Graph added');
246			$messageFailed = _('Cannot add graph');
247		}
248
249		$cookieId = $hostId;
250	}
251
252	if ($result) {
253		if (hasRequest('graphid')) {
254			add_audit(AUDIT_ACTION_UPDATE, AUDIT_RESOURCE_GRAPH,
255				'Graph ID ['.$graph['graphid'].'] Graph ['.getRequest('name').']'
256			);
257		}
258		else {
259			add_audit(AUDIT_ACTION_ADD, AUDIT_RESOURCE_GRAPH, 'Graph ['.getRequest('name').']');
260		}
261
262		unset($_REQUEST['form']);
263	}
264
265	$result = DBend($result);
266
267	if ($result) {
268		uncheckTableRows($cookieId);
269	}
270	show_messages($result, $messageSuccess, $messageFailed);
271}
272elseif (hasRequest('delete') && hasRequest('graphid')) {
273	$graphId = getRequest('graphid');
274
275	if (hasRequest('parent_discoveryid')) {
276		$result = API::GraphPrototype()->delete([$graphId]);
277
278		if ($result) {
279			uncheckTableRows(getRequest('parent_discoveryid'));
280		}
281		show_messages($result, _('Graph prototype deleted'), _('Cannot delete graph prototype'));
282	}
283	else {
284		$result = API::Graph()->delete([$graphId]);
285
286		if ($result) {
287			uncheckTableRows($hostId);
288		}
289		show_messages($result, _('Graph deleted'), _('Cannot delete graph'));
290	}
291
292	if ($result) {
293		unset($_REQUEST['form']);
294	}
295}
296elseif (hasRequest('action') && getRequest('action') === 'graph.massdelete' && hasRequest('group_graphid')) {
297	$graphIds = getRequest('group_graphid');
298
299	if (hasRequest('parent_discoveryid')) {
300		$result = API::GraphPrototype()->delete($graphIds);
301
302		if ($result) {
303			uncheckTableRows(getRequest('parent_discoveryid'));
304		}
305		else {
306			$graphs = API::GraphPrototype()->get([
307				'graphids' => $graphIds,
308				'output' => [],
309				'editable' => true
310			]);
311
312			uncheckTableRows(getRequest('parent_discoveryid'), zbx_objectValues($graphs, 'graphid'));
313		}
314		show_messages($result, _('Graph prototypes deleted'), _('Cannot delete graph prototypes'));
315	}
316	else {
317		$result = API::Graph()->delete($graphIds);
318
319		if ($result) {
320			uncheckTableRows($hostId);
321		}
322		else {
323			$graphs = API::Graph()->get([
324				'graphids' => $graphIds,
325				'output' => [],
326				'editable' => true
327			]);
328
329			uncheckTableRows($hostId, zbx_objectValues($graphs, 'graphid'));
330		}
331		show_messages($result, _('Graphs deleted'), _('Cannot delete graphs'));
332	}
333}
334elseif (hasRequest('action') && getRequest('action') === 'graph.masscopyto' && hasRequest('copy')
335		&& hasRequest('group_graphid')) {
336	if (getRequest('copy_targetids', []) && hasRequest('copy_type')) {
337		$result = true;
338
339		$options = [
340			'output' => ['hostid'],
341			'editable' => true,
342			'templated_hosts' => true
343		];
344
345		// hosts or templates
346		if (getRequest('copy_type') == COPY_TYPE_TO_HOST || getRequest('copy_type') == COPY_TYPE_TO_TEMPLATE) {
347			$options['hostids'] = getRequest('copy_targetids');
348		}
349		// host groups
350		else {
351			$groupids = getRequest('copy_targetids');
352			zbx_value2array($groupids);
353
354			$dbGroups = API::HostGroup()->get([
355				'output' => ['groupid'],
356				'groupids' => $groupids,
357				'editable' => true
358			]);
359			$dbGroups = zbx_toHash($dbGroups, 'groupid');
360
361			foreach ($groupids as $groupid) {
362				if (!isset($dbGroups[$groupid])) {
363					access_deny();
364				}
365			}
366
367			$options['groupids'] = $groupids;
368		}
369
370		$dbHosts = API::Host()->get($options);
371
372		DBstart();
373		foreach (getRequest('group_graphid') as $graphid) {
374			foreach ($dbHosts as $host) {
375				$result &= (bool) copyGraphToHost($graphid, $host['hostid']);
376			}
377		}
378		$result = DBend($result);
379
380		$graphs_count = count(getRequest('group_graphid'));
381
382		if ($result) {
383			uncheckTableRows(
384				(getRequest('parent_discoveryid') == 0) ? $hostId : getRequest('parent_discoveryid')
385			);
386			unset($_REQUEST['group_graphid']);
387		}
388		show_messages($result,
389			_n('Graph copied', 'Graphs copied', $graphs_count),
390			_n('Cannot copy graph', 'Cannot copy graphs', $graphs_count)
391		);
392	}
393	else {
394		error(_('No target selected.'));
395	}
396	show_messages();
397}
398
399/*
400 * Display
401 */
402$pageFilter = new CPageFilter([
403	'groups' => [
404		'with_hosts_and_templates' => true,
405		'editable' => true
406	],
407	'hosts' => [
408		'editable' => true,
409		'templated_hosts' => true
410	],
411	'groupid' => $groupId,
412	'hostid' => $hostId
413]);
414
415if (empty($_REQUEST['parent_discoveryid'])) {
416	$groupId = $pageFilter->groupid;
417	$hostId = $pageFilter->hostid;
418}
419
420if (hasRequest('action') && getRequest('action') === 'graph.masscopyto' && hasRequest('group_graphid')) {
421	$data = getCopyElementsFormData('group_graphid', _('Graphs'));
422	$data['action'] = 'graph.masscopyto';
423
424	// render view
425	$graphView = new CView('configuration.copy.elements', $data);
426	$graphView->render();
427	$graphView->show();
428}
429elseif (isset($_REQUEST['form'])) {
430	$data = [
431		'form' => getRequest('form'),
432		'form_refresh' => getRequest('form_refresh', 0),
433		'graphid' => getRequest('graphid', 0),
434		'parent_discoveryid' => getRequest('parent_discoveryid'),
435		'group_gid' => getRequest('group_gid', []),
436		'hostid' => $hostId,
437		'groupid' => $groupId,
438		'normal_only' => getRequest('normal_only')
439	];
440
441	if (!empty($data['graphid']) && !isset($_REQUEST['form_refresh'])) {
442		$options = [
443			'graphids' => $data['graphid'],
444			'output' => API_OUTPUT_EXTEND,
445			'selectHosts' => ['hostid']
446		];
447
448		if ($data['parent_discoveryid'] === null) {
449			$options['selectDiscoveryRule'] = ['itemid', 'name'];
450			$graph = API::Graph()->get($options);
451		}
452		else {
453			$graph = API::GraphPrototype()->get($options);
454		}
455
456		$graph = reset($graph);
457
458		$data['name'] = $graph['name'];
459		$data['width'] = $graph['width'];
460		$data['height'] = $graph['height'];
461		$data['ymin_type'] = $graph['ymin_type'];
462		$data['ymax_type'] = $graph['ymax_type'];
463		$data['yaxismin'] = $graph['yaxismin'];
464		$data['yaxismax'] = $graph['yaxismax'];
465		$data['ymin_itemid'] = $graph['ymin_itemid'];
466		$data['ymax_itemid'] = $graph['ymax_itemid'];
467		$data['show_work_period'] = $graph['show_work_period'];
468		$data['show_triggers'] = $graph['show_triggers'];
469		$data['graphtype'] = $graph['graphtype'];
470		$data['show_legend'] = $graph['show_legend'];
471		$data['show_3d'] = $graph['show_3d'];
472		$data['percent_left'] = $graph['percent_left'];
473		$data['percent_right'] = $graph['percent_right'];
474		$data['templateid'] = $graph['templateid'];
475		$data['templates'] = [];
476
477		if ($data['parent_discoveryid'] === null) {
478			$data['flags'] = $graph['flags'];
479			$data['discoveryRule'] = $graph['discoveryRule'];
480		}
481
482		// if no host has been selected for the navigation panel, use the first graph host
483		if ($data['hostid'] == 0) {
484			$host = reset($graph['hosts']);
485			$data['hostid'] = $host['hostid'];
486		}
487
488		// templates
489		$flag = ($data['parent_discoveryid'] === null) ? ZBX_FLAG_DISCOVERY_NORMAL : ZBX_FLAG_DISCOVERY_PROTOTYPE;
490		$data['templates'] = makeGraphTemplatesHtml($graph['graphid'], getGraphParentTemplates([$graph], $flag),
491			$flag
492		);
493
494		// items
495		$data['items'] = API::GraphItem()->get([
496			'output' => [
497				'gitemid', 'graphid', 'itemid', 'type', 'drawtype', 'yaxisside', 'calc_fnc', 'color', 'sortorder'
498			],
499			'graphids' => $data['graphid'],
500			'sortfield' => 'gitemid'
501		]);
502	}
503	else {
504		$data['name'] = getRequest('name', '');
505		$data['graphtype'] = getRequest('graphtype', GRAPH_TYPE_NORMAL);
506
507		if ($data['graphtype'] == GRAPH_TYPE_PIE || $data['graphtype'] == GRAPH_TYPE_EXPLODED) {
508			$data['width'] = getRequest('width', 400);
509			$data['height'] = getRequest('height', 300);
510		}
511		else {
512			$data['width'] = getRequest('width', 900);
513			$data['height'] = getRequest('height', 200);
514		}
515
516		$data['ymin_type'] = getRequest('ymin_type', GRAPH_YAXIS_TYPE_CALCULATED);
517		$data['ymax_type'] = getRequest('ymax_type', GRAPH_YAXIS_TYPE_CALCULATED);
518		$data['yaxismin'] = getRequest('yaxismin', 0);
519		$data['yaxismax'] = getRequest('yaxismax', 100);
520		$data['ymin_itemid'] = getRequest('ymin_itemid', 0);
521		$data['ymax_itemid'] = getRequest('ymax_itemid', 0);
522		$data['show_work_period'] = getRequest('show_work_period', 0);
523		$data['show_triggers'] = getRequest('show_triggers', 0);
524		$data['show_legend'] = getRequest('show_legend', 0);
525		$data['show_3d'] = getRequest('show_3d', 0);
526		$data['visible'] = getRequest('visible');
527		$data['percent_left'] = 0;
528		$data['percent_right'] = 0;
529		$data['visible'] = getRequest('visible');
530		$data['items'] = $gitems;
531		$data['templates'] = [];
532
533		if (isset($data['visible']['percent_left'])) {
534			$data['percent_left'] = getRequest('percent_left', 0);
535		}
536		if (isset($data['visible']['percent_right'])) {
537			$data['percent_right'] = getRequest('percent_right', 0);
538		}
539	}
540
541	if (empty($data['graphid']) && !isset($_REQUEST['form_refresh'])) {
542		$data['show_legend'] = $_REQUEST['show_legend'] = 1;
543		$data['show_work_period'] = $_REQUEST['show_work_period'] = 1;
544		$data['show_triggers'] = $_REQUEST['show_triggers'] = 1;
545	}
546
547	// items
548	if ($data['items']) {
549		$items = API::Item()->get([
550			'output' => ['itemid', 'hostid', 'name', 'key_', 'flags'],
551			'selectHosts' => ['hostid', 'name'],
552			'itemids' => zbx_objectValues($data['items'], 'itemid'),
553			'filter' => [
554				'flags' => [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_PROTOTYPE, ZBX_FLAG_DISCOVERY_CREATED]
555			],
556			'webitems' => true,
557			'preservekeys' => true
558		]);
559
560		foreach ($data['items'] as &$item) {
561			$host = reset($items[$item['itemid']]['hosts']);
562
563			$item['host'] = $host['name'];
564			$item['hostid'] = $items[$item['itemid']]['hostid'];
565			$item['name'] = $items[$item['itemid']]['name'];
566			$item['key_'] = $items[$item['itemid']]['key_'];
567			$item['flags'] = $items[$item['itemid']]['flags'];
568		}
569		unset($item);
570
571		$data['items'] = CMacrosResolverHelper::resolveItemNames($data['items']);
572	}
573
574	$data['items'] = array_values($data['items']);
575	$itemCount = count($data['items']);
576	for ($i = 0; $i < $itemCount - 1;) {
577		// check if we delete an item
578		$next = $i + 1;
579		while (!isset($data['items'][$next]) && $next < ($itemCount - 1)) {
580			$next++;
581		}
582
583		if (isset($data['items'][$next]) && $data['items'][$i]['sortorder'] == $data['items'][$next]['sortorder']) {
584			for ($j = $next; $j < $itemCount; $j++) {
585				if ($data['items'][$j - 1]['sortorder'] >= $data['items'][$j]['sortorder']) {
586					$data['items'][$j]['sortorder']++;
587				}
588			}
589		}
590
591		$i = $next;
592	}
593	CArrayHelper::sort($data['items'], ['sortorder']);
594	$data['items'] = array_values($data['items']);
595
596	// is template
597	$data['is_template'] = ($data['hostid'] == 0) ? false : isTemplate($data['hostid']);
598
599	// Read groupid for selected host or template if groupid filter is set to 'All' (is equal 0).
600
601	if ($data['hostid'] && !$data['groupid']) {
602		$db_hostgroup = API::HostGroup()->get([
603			'output' => ['groupid'],
604			'hostids' => $data['hostid'],
605			'templateids' => $data['hostid']
606		]);
607
608		if ($db_hostgroup) {
609			$data['groupid'] = $db_hostgroup[0]['groupid'];
610		}
611	}
612
613	// render view
614	$graphView = new CView('configuration.graph.edit', $data);
615	$graphView->render();
616	$graphView->show();
617}
618else {
619	$sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name'));
620	$sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP));
621
622	CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR);
623	CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR);
624
625	$config = select_config();
626
627	$data = [
628		'pageFilter' => $pageFilter,
629		'hostid' => ($pageFilter->hostid > 0) ? $pageFilter->hostid : $hostId,
630		'parent_discoveryid' => hasRequest('parent_discoveryid') ? $discoveryRule['itemid'] : null,
631		'graphs' => [],
632		'sort' => $sortField,
633		'sortorder' => $sortOrder
634	];
635
636	if ($data['pageFilter']->hostsSelected) {
637		$options = [
638			'output' => ['graphid', 'name', 'graphtype'],
639			'hostids' => ($data['hostid'] == 0) ? null : $data['hostid'],
640			'groupids' => ($data['hostid'] == 0 && $pageFilter->groupid > 0) ? $pageFilter->groupids : null,
641			'discoveryids' => hasRequest('parent_discoveryid') ? $discoveryRule['itemid'] : null,
642			'editable' => true,
643			'limit' => $config['search_limit'] + 1
644		];
645
646		$data['graphs'] = hasRequest('parent_discoveryid')
647			? API::GraphPrototype()->get($options)
648			: API::Graph()->get($options);
649
650		if ($sortField === 'graphtype') {
651			foreach ($data['graphs'] as $gnum => $graph) {
652				$data['graphs'][$gnum]['graphtype'] = graphType($graph['graphtype']);
653			}
654		}
655
656		order_result($data['graphs'], $sortField, $sortOrder);
657	}
658
659	$url = (new CUrl('graphs.php'))
660		->setArgument('groupid', $pageFilter->groupid)
661		->setArgument('hostid', $data['hostid']);
662
663	$data['paging'] = getPagingLine($data['graphs'], $sortOrder, $url);
664
665	if ($data['pageFilter']->hostsSelected) {
666		// Get graphs after paging.
667		$options = [
668			'output' => ['graphid', 'name', 'templateid', 'graphtype', 'width', 'height'],
669			'selectDiscoveryRule' => ['itemid', 'name'],
670			'selectHosts' => ($data['hostid'] == 0) ? ['name'] : null,
671			'selectTemplates' => ($data['hostid'] == 0) ? ['name'] : null,
672			'graphids' => zbx_objectValues($data['graphs'], 'graphid')
673		];
674
675		$data['graphs'] = hasRequest('parent_discoveryid')
676			? API::GraphPrototype()->get($options)
677			: API::Graph()->get($options);
678
679		foreach ($data['graphs'] as $gnum => $graph) {
680			$data['graphs'][$gnum]['graphtype'] = graphType($graph['graphtype']);
681		}
682
683		order_result($data['graphs'], $sortField, $sortOrder);
684	}
685
686	$data['parent_templates'] = getGraphParentTemplates($data['graphs'], ($data['parent_discoveryid'] === null)
687		? ZBX_FLAG_DISCOVERY_NORMAL
688		: ZBX_FLAG_DISCOVERY_PROTOTYPE
689	);
690
691	// render view
692	$graphView = new CView('configuration.graph.list', $data);
693	$graphView->render();
694	$graphView->show();
695}
696
697require_once dirname(__FILE__).'/include/page_footer.php';
698