replace remaining niftyString() occurrences
[racktables] / wwwroot / inc / interface.php
CommitLineData
b325120a 1<?php
cddbb9fd
DO
2
3# This file is a part of RackTables, a datacenter and server room management
4# framework. See accompanying file "COPYING" for the full copyright and
5# licensing information.
6
e673ee24
DO
7/*
8*
9* This file contains frontend functions for RackTables.
10*
11*/
12
e82deb48 13require_once 'ajax-interface.php';
defd92d8 14require_once 'slb-interface.php';
65e557dd 15
9c0b0016
DO
16// Interface function's special.
17$nextorder['odd'] = 'even';
18$nextorder['even'] = 'odd';
19
52c836b1
DO
20// address allocation type
21$aat = array
22(
23 'regular' => 'Connected',
24 'virtual' => 'Loopback',
25 'shared' => 'Shared',
26 'router' => 'Router',
531b1ce3 27 'sharedrouter' => 'Shared router',
2f96a91a 28 'point2point' => 'Point-to-point',
52c836b1 29);
beb9e88a 30// address allocation code, IPv4 addresses and objects view
9d5f6a80 31$aac_right = array
52c836b1
DO
32(
33 'regular' => '',
9d5f6a80
AA
34 'virtual' => '<span class="aac-right" title="' . $aat['virtual'] . '">L</span>',
35 'shared' => '<span class="aac-right" title="' . $aat['shared'] . '">S</span>',
36 'router' => '<span class="aac-right" title="' . $aat['router'] . '">R</span>',
531b1ce3 37 'sharedrouter' => '<span class="aac-right" title="' . $aat['sharedrouter'] . '">R</span>',
2f96a91a 38 'point2point' => '<span class="aac-right" title="' . $aat['point2point'] . '">P</span>',
52c836b1 39);
beb9e88a 40// address allocation code, IPv4 networks view
9d5f6a80 41$aac_left = array
beb9e88a
DO
42(
43 'regular' => '',
9d5f6a80
AA
44 'virtual' => '<span class="aac-left" title="' . $aat['virtual'] . '">L:</span>',
45 'shared' => '<span class="aac-left" title="' . $aat['shared'] . '">S:</span>',
46 'router' => '<span class="aac-left" title="' . $aat['router'] . '">R:</span>',
531b1ce3 47 'sharedrouter' => '<span class="aac-left" title="' . $aat['sharedrouter'] . '">R:</span>',
2f96a91a 48 'point2point' => '<span class="aac-left" title="' . $aat['point2point'] . '">P:</span>',
beb9e88a 49);
52c836b1 50
0dabdc53
DO
51$vtdecoder = array
52(
53 'ondemand' => '',
54b7ced3
DO
54 'compulsory' => 'P',
55# 'alien' => 'NT',
0dabdc53
DO
56);
57
58$vtoptions = array
59(
54b7ced3
DO
60 'ondemand' => 'auto',
61 'compulsory' => 'permanent',
62# 'alien' => 'never touch',
0dabdc53
DO
63);
64
8d4f7d18
DO
65$attrtypes = array
66(
67 'uint' => '[U] unsigned integer',
68 'float' => '[F] floating point',
69 'string' => '[S] string',
86ff26ae
DO
70 'dict' => '[D] dictionary record',
71 'date' => '[T] date'
8d4f7d18
DO
72);
73
5eb81cf8
AD
74function showLogoutURL ()
75{
55eefced 76 $https = (isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 's' : '';
5eb81cf8 77 $port = (! in_array ($_SERVER['SERVER_PORT'], array (80, 443))) ? ':' . $_SERVER['SERVER_PORT'] : '';
73d1e589 78 printf ('http%s://logout@%s%s%s?logout', $https, $_SERVER['SERVER_NAME'], $port, $_SERVER['PHP_SELF']);
5eb81cf8
AD
79}
80
a1d72d2e
AA
81$quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks()
82
83function renderQuickLinks()
84{
85 global $quick_links;
86 if (! isset ($quick_links))
87 $quick_links = getConfiguredQuickLinks();
88 echo '<ul class="qlinks">';
89 foreach ($quick_links as $link)
90 echo '<li><a href="' . $link['href'] . '">' . str_replace (' ', '&nbsp;', $link['title']) . '</a></li>';
91 echo '</ul>';
92}
93
f97df464
DO
94function renderInterfaceHTML ($pageno, $tabno, $payload)
95{
1cfcac1b
DO
96 global $remote_displayname;
97 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
98 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
99 echo '<head><title>' . getTitle ($pageno) . '</title>';
100 printPageHeaders();
101 echo '</head>';
102 echo '<body>';
103 echo '<div class=maintable>';
104 echo '<div class=mainheader>';
105 echo '<div style="float: right" class=greeting>';
106 echo mkA ($remote_displayname, 'myaccount', NULL, 'default');
107 echo ' [ <a href="';
108 showLogoutURL();
109 echo '">logout</a> ]</div>'; // greeting
110 echo getConfigVar ('enterprise') . ' RackTables ';
111 echo '<a href="http://racktables.org" title="Visit RackTables site">' . CODE_VERSION . '</a>';
112 renderQuickLinks();
113 echo '</div>'; // mainheader
114 echo '<div class=menubar>';
115 showPathAndSearch ($pageno, $tabno);
116 echo '</div>';
117 echo '<div class=tabbar>';
118 showTabs ($pageno, $tabno);
119 echo '</div>';
120 echo '<div class=msgbar>';
121 showMessageOrError();
122 echo '</div>';
123 echo "<div class=pagebar>${payload}</div>";
124 echo '</div>'; // maintable
125 echo '</body>';
126 echo '</html>';
f97df464
DO
127}
128
e673ee24 129// Main menu.
f2168c4b
DO
130function renderIndexItem ($ypageno)
131{
132 echo (! permitted ($ypageno)) ? " <td>&nbsp;</td>\n" :
133 " <td>\n" .
134 " <h1><a href='" . makeHref (array ('page' => $ypageno)) . "'>" .
135 getPageName ($ypageno) . "<br>\n" . getImageHREF ($ypageno) .
136 "</a></h1>\n" .
137 " </td>\n";
4b680876
DO
138}
139
e673ee24
DO
140function renderIndex ()
141{
67c5c049 142 global $indexlayout;
1cfcac1b
DO
143 echo '<table border=0 cellpadding=0 cellspacing=0 width="100%">';
144 echo '<tr><td><div style="text-align: center; margin: 10px; ">';
145 echo '<table width="100%" cellspacing=0 cellpadding=20 class=mainmenu border=0>';
146 foreach ($indexlayout as $row)
147 {
148 echo '<tr>';
149 foreach ($row as $column)
150 if ($column === NULL)
151 echo '<td>&nbsp;</td>';
152 else
153 renderIndexItem ($column);
154 echo '</tr>';
155 }
156 echo '</table>';
157 echo '</div></td></tr>';
158 echo '</table>';
e673ee24
DO
159}
160
f3505b35
AA
161function getRenderedAlloc ($object_id, $alloc)
162{
163 $ret = array
164 (
165 'tr_class' => '',
40c9fc94 166 'td_name_suffix' => '',
f3505b35
AA
167 'td_ip' => '',
168 'td_network' => '',
169 'td_routed_by' => '',
170 'td_peers' => '',
171 );
172 $dottedquad = $alloc['addrinfo']['ip'];
4318ced5 173 $ip_bin = $alloc['addrinfo']['ip_bin'];
f3505b35 174
4318ced5
AA
175 $hl_ip_bin = NULL;
176 if (isset ($_REQUEST['hl_ip']))
f3505b35 177 {
4318ced5
AA
178 $hl_ip_bin = ip_parse ($_REQUEST['hl_ip']);
179 addAutoScrollScript ("ip-" . $_REQUEST['hl_ip']);
f3505b35
AA
180 }
181
182 $ret['tr_class'] = $alloc['addrinfo']['class'];
4318ced5 183 if ($hl_ip_bin === $ip_bin)
5c717ce5 184 $ret['tr_class'] .= ' highlight';
dec748f6 185
68c91b9c
AA
186 // render IP change history
187 $ip_title = '';
188 $ip_class = '';
189 if (isset ($alloc['addrinfo']['last_log']))
190 {
191 $log = $alloc['addrinfo']['last_log'];
192 $ip_title = "title='" .
193 htmlspecialchars
194 (
195 $log['user'] . ', ' . formatAge ($log['time']),
196 ENT_QUOTES
197 ) . "'";
198 $ip_class = 'hover-history underline';
199 }
200
f3505b35 201 // render IP address td
9d5f6a80 202 global $aac_right;
4318ced5
AA
203 $netinfo = spotNetworkByIP ($ip_bin);
204 $ret['td_ip'] = "<td class='tdleft'>";
205 if (isset ($netinfo))
206 {
207 $title = $dottedquad;
208 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
209 $title .= '/' . $netinfo['mask'];
68c91b9c 210 $ret['td_ip'] .= "<a name='ip-$dottedquad' class='$ip_class' $ip_title href='" .
f3505b35
AA
211 makeHref (
212 array
213 (
4318ced5 214 'page' => 'ipaddress',
f3505b35
AA
215 'hl_object_id' => $object_id,
216 'ip' => $dottedquad,
217 )
4318ced5
AA
218 ) . "'>$title</a>";
219 }
f3505b35 220 else
68c91b9c 221 $ret['td_ip'] .= "<span class='$ip_class' $ip_title>$dottedquad</span>";
9d5f6a80 222 $ret['td_ip'] .= $aac_right[$alloc['type']];
33973968 223 if ($alloc['addrinfo']['name'] != '')
a0bdf6dc 224 $ret['td_ip'] .= ' (' . stringForLabel ($alloc['addrinfo']['name']) . ')';
f3505b35
AA
225 $ret['td_ip'] .= '</td>';
226
227 // render network and routed_by tds
4318ced5
AA
228 $td_class = 'tdleft';
229 if (! isset ($netinfo))
f3505b35
AA
230 {
231 $ret['td_network'] = "<td class='$td_class sparenetwork'>N/A</td>";
232 $ret['td_routed_by'] = $ret['td_network'];
233 }
234 else
235 {
236 $ret['td_network'] = "<td class='$td_class'>" .
237 getOutputOf ('renderCell', $netinfo) . '</td>';
238
98350e52
AA
239 // render "routed by" td
240 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') == 'none'))
9d5f6a80 241 $ret['td_routed_by'] = '<td>&nbsp;</td>';
f3505b35 242 else
98350e52 243 {
98350e52 244 $other_routers = array();
6063fab7 245 foreach (findNetRouters ($netinfo) as $router)
98350e52
AA
246 if ($router['id'] != $object_id)
247 $other_routers[] = $router;
248 if (count ($other_routers))
249 $ret['td_routed_by'] = getOutputOf ('printRoutersTD', $other_routers, $display_routers);
250 else
251 $ret['td_routed_by'] = "<td class='$td_class'>&nbsp;</td>";
252 }
f3505b35 253 }
dec748f6 254
f3505b35
AA
255 // render peers td
256 $ret['td_peers'] = "<td class='$td_class'>";
257 $prefix = '';
e749a34f 258 $separator = '; ';
f3505b35
AA
259 if ($alloc['addrinfo']['reserved'] == 'yes')
260 {
261 $ret['td_peers'] .= $prefix . '<strong>RESERVED</strong>';
e749a34f 262 $prefix = $separator;
f3505b35
AA
263 }
264 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
2f96a91a
AA
265 if ($allocpeer['object_id'] != $object_id)
266 {
267 $ret['td_peers'] .= $prefix . makeIPAllocLink ($ip_bin, $allocpeer);
268 $prefix = $separator;
269 }
270 elseif ($allocpeer['type'] == 'point2point' && isset ($netinfo))
271 {
272 // show PtP peers in the IP network
6063fab7
AA
273 $addrlist = isset ($netinfo['own_addrlist']) ? $netinfo['own_addrlist'] : getIPAddrList ($netinfo, IPSCAN_DO_ALLOCS);
274 foreach (getPtPNeighbors ($ip_bin, $addrlist) as $p_ip_bin => $p_alloc_list)
2f96a91a
AA
275 foreach ($p_alloc_list as $p_alloc)
276 {
277 $ret['td_peers'] .= $prefix . '&harr;&nbsp;' . makeIPAllocLink ($p_ip_bin, $p_alloc);
278 $prefix = $separator;
279 }
280 }
281
f3505b35
AA
282 $ret['td_peers'] .= '</td>';
283
284 return $ret;
285}
286
e1add254
AD
287function renderLocationFilterPortlet ()
288{
e1add254 289 // Recursive function used to build the location tree
2056822d 290 function renderLocationCheckbox ($subtree, $level = 0)
e1add254
AD
291 {
292 $self = __FUNCTION__;
e1add254 293
2056822d 294 foreach ($subtree as $location_id => $location)
e1add254 295 {
9f68b666 296 echo "<div class=tagbox style='text-align:left; padding-left:" . ($level * 16) . "px;'>";
950dfa1f 297 $checked = (! isset ($_SESSION['locationFilter']) || in_array ($location['id'], $_SESSION['locationFilter'])) ? 'checked' : '';
9c88bba9 298 echo "<label><input type=checkbox name='location_id[]' class=${level} value='${location['id']}'${checked} onClick=checkAll(this)>${location['name']}";
9f68b666 299 echo '</label>';
2056822d 300 if ($location['kidc'])
9f68b666
AD
301 {
302 echo "<a id='lfa" . $location['id'] . "' onclick=\"expand('${location['id']}')\" href\"#\" > - </a>";
303 echo "<div id='lfd" . $location['id'] . "'>";
2056822d 304 $self ($location['kids'], $level + 1);
9f68b666
AD
305 echo '</div>';
306 }
307 echo '</div>';
e1add254
AD
308 }
309 }
310
a6e090f0 311 addJS(<<<'END'
9c88bba9
AD
312function checkAll(bx) {
313 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
4e9e1b7a 314 if (tbls[i].id == "locationFilter") {
9c88bba9
AD
315 var bxs=tbls[i].getElementsByTagName("input");
316 var in_tree = false;
9f68b666 317 for (var j=0; j<bxs.length; j++) {
9c88bba9
AD
318 if(in_tree == false && bxs[j].value == bx.value)
319 in_tree = true;
320 else if(parseInt(bxs[j].className) <= parseInt(bx.className))
321 in_tree = false;
322 if (bxs[j].type=="checkbox" && in_tree == true)
323 bxs[j].checked = bx.checked;
324 }
325 }
326}
9f68b666
AD
327
328function collapseAll(bx) {
329 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
330 if (tbls[i].id == "locationFilter") {
331 var bxs=tbls[i].getElementsByTagName("div");
332 //loop through divs to hide unchecked
333 for (var j=0; j<bxs.length; j++) {
334 var is_checked = -1;
335 var in_div=bxs[j].getElementsByTagName("input");
336 //loop through input to find if any is checked
337 for (var k=0; k<in_div.length; k++) {
338 if(in_div[k].type="checkbox") {
339 if (in_div[k].checked == true) {
340 is_checked = true;
341 break;
342 }
343 else
344 is_checked = false;
345 }
346 }
347 // nothing selected and element id is lfd, collapse it
348 if (is_checked == false && !bxs[j].id.indexOf("lfd"))
349 expand(bxs[j].id.substr(3));
350 }
351 }
352}
353
354function expand(id) {
355 var divid = document.getElementById("lfd" + id);
356 var iconid = document.getElementById("lfa" + id);
357 if (divid.style.display == 'none') {
358 divid.style.display = 'block';
359 iconid.innerHTML = ' - ';
360 } else {
361 divid.style.display = 'none';
362 iconid.innerHTML = ' + ';
363 }
364}
9c88bba9
AD
365END
366 ,TRUE);
e1add254 367 startPortlet ('Location filter');
a6e090f0 368 echo <<<'END'
9c88bba9 369<table border=0 align=center cellspacing=0 class="tagtree" id="locationFilter">
6b816bde 370 <form method=post>
e1add254
AD
371 <input type=hidden name=page value=rackspace>
372 <input type=hidden name=tab value=default>
373 <input type=hidden name=changeLocationFilter value=true>
374END;
2056822d
AA
375
376 $locationlist = listCells ('location');
e1add254
AD
377 if (count ($locationlist))
378 {
9c88bba9
AD
379 echo "<tr><td class=tagbox style='padding-left: 0px'><label>";
380 echo "<input type=checkbox name='location' onClick=checkAll(this)> Toggle all";
1341dc93 381 echo "<img src=?module=chrome&uri=pix/1x1t.gif onLoad=collapseAll(this)>"; // dirty hack to collapse all when page is displayed
9c88bba9 382 echo "</label></td></tr>\n";
9f68b666 383 echo "<tr><td class=tagbox><hr>\n";
d6409c53 384 renderLocationCheckbox (treeFromList (addTraceToNodes ($locationlist)));
9f68b666
AD
385 echo "<hr></td></tr>\n";
386 echo '<tr><td>';
e1add254
AD
387 printImageHREF ('setfilter', 'set filter', TRUE);
388 echo "</td></tr>\n";
389 }
390 else
391 {
392 echo "<tr><td class='tagbox sparenetwork'>(no locations exist)</td></tr>\n";
393 echo "<tr><td>";
394 printImageHREF ('setfilter gray');
395 echo "</td></tr>\n";
396 }
397
398 echo "</form></table>\n";
399 finishPortlet ();
400}
401
d9bad31a
AD
402function rackspaceCmp ($a, $b)
403{
404 $ret = strnatcasecmp ($a['location_tree'], $b['location_tree']);
405 if (!$ret)
406 $ret = strnatcasecmp ($a['row_name'], $b['row_name']);
407 return $ret;
408}
409
150effa7 410function getRackThumbLink ($rack, $scale = 1, $object_id = NULL)
e10d9597
DO
411{
412 if (! is_int ($scale) || $scale <= 0)
413 throw new InvalidArgException ('scale', $scale, 'must be a natural number');
414 $width = getRackImageWidth() * $scale;
415 $height = getRackImageHeight ($rack['height']) * $scale;
416 $title = "${rack['height']} units";
417 $src = '?module=image' .
150effa7
DO
418 ($scale == 1 && $object_id === NULL ? '&img=minirack' : "&img=midirack&scale=${scale}") .
419 "&rack_id=${rack['id']}" .
420 ($object_id === NULL ? '' : "&object_id=${object_id}");
e10d9597 421 $img = "<img border=0 width=${width} height=${height} title='${title}' src='${src}'>";
168c2acb 422 return mkA ($img, 'rack', $rack['id']);
e10d9597
DO
423}
424
e673ee24
DO
425function renderRackspace ()
426{
d4e27fe5 427 global $pageno;
e1add254 428 // Handle the location filter
0a00b344 429 startSession();
e1add254
AD
430 if (isset ($_REQUEST['changeLocationFilter']))
431 unset ($_SESSION['locationFilter']);
432 if (isset ($_REQUEST['location_id']))
433 $_SESSION['locationFilter'] = $_REQUEST['location_id'];
5d6352df 434 session_commit();
e1add254 435
950dfa1f
AA
436 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
437
95857b5c 438 $found_racks = array();
a8efc03e 439 $cellfilter = getCellFilter();
950dfa1f 440 if (! ($cellfilter['is_empty'] && !isset ($_SESSION['locationFilter']) && renderEmptyResults ($cellfilter, 'racks', getEntitiesCount ('rack'))))
e1add254 441 {
950dfa1f
AA
442 $rows = array();
443 $rackCount = 0;
524f8a7b 444 foreach (listCells ('row') as $row_id => $rowInfo)
950dfa1f 445 {
2b16c179 446 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
950dfa1f 447 $found_racks = array_merge ($found_racks, $rackList);
d9bad31a
AD
448 $location_id = $rowInfo['location_id'];
449 $locationIdx = 0;
450 // contains location names in the form of 'grandparent parent child', used for sorting
451 $locationTree = '';
452 // contains location names as well as links
453 $hrefLocationTree = '';
454 while ($location_id)
455 {
456 if ($locationIdx == 20)
457 {
458 showWarning ("Warning: There is likely a circular reference in the location tree. Investigate location ${location_id}.");
459 break;
460 }
461 $parentLocation = spotEntity ('location', $location_id);
462 $locationTree = sprintf ('%s %s', $parentLocation['name'], $locationTree);
463 $hrefLocationTree = "&raquo; <a href='" .
464 makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) .
465 "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " .
466 $hrefLocationTree;
467 $location_id = $parentLocation['parent_id'];
468 $locationIdx++;
469 }
470 $hrefLocationTree = substr ($hrefLocationTree, 8);
950dfa1f
AA
471 $rows[] = array (
472 'location_id' => $rowInfo['location_id'],
d9bad31a
AD
473 'location_tree' => $locationTree,
474 'href_location_tree' => $hrefLocationTree,
950dfa1f
AA
475 'row_id' => $row_id,
476 'row_name' => $rowInfo['name'],
477 'racks' => $rackList
478 );
479 $rackCount += count($rackList);
480 }
1ebbf889 481
d9bad31a
AD
482 // sort by location, then by row
483 usort ($rows, 'rackspaceCmp');
484
950dfa1f 485 if (! renderEmptyResults($cellfilter, 'racks', $rackCount))
1ebbf889 486 {
950dfa1f
AA
487 // generate thumb gallery
488 global $nextorder;
950dfa1f
AA
489 // Zero value effectively disables the limit.
490 $maxPerRow = getConfigVar ('RACKS_PER_ROW');
491 $order = 'odd';
18733c4a
AD
492 if (! count ($rows))
493 echo "<h2>No rows found</h2>\n";
494 else
e1add254 495 {
950dfa1f
AA
496 echo '<table border=0 cellpadding=10 class=cooltable>';
497 echo '<tr><th class=tdleft>Location</th><th class=tdleft>Row</th><th class=tdleft>Racks</th></tr>';
498 foreach ($rows as $row)
c08915c7 499 {
950dfa1f 500 $rackList = $row['racks'];
d1d19f79 501 $location_id = $row['location_id'];
950dfa1f
AA
502
503 if (
55eefced
DO
504 $location_id != '' && isset ($_SESSION['locationFilter']) && ! in_array ($location_id, $_SESSION['locationFilter']) ||
505 empty ($rackList) && ! $cellfilter['is_empty']
950dfa1f
AA
506 )
507 continue;
508 $rackListIdx = 0;
d9bad31a
AD
509 echo "<tr class=row_${order}><th class=tdleft>${row['href_location_tree']}</th>";
510 echo "<th class=tdleft><a href='".makeHref(array('page'=>'row', 'row_id'=>$row['row_id']))."${cellfilter['urlextra']}'>${row['row_name']}</a></th>";
950dfa1f 511 echo "<th class=tdleft><table border=0 cellspacing=5><tr>";
18733c4a
AD
512 if (! count ($rackList))
513 echo '<td>(empty row)</td>';
950dfa1f
AA
514 else
515 foreach ($rackList as $rack)
e1add254 516 {
55eefced 517 if ($rackListIdx > 0 && $maxPerRow > 0 && $rackListIdx % $maxPerRow == 0)
950dfa1f
AA
518 {
519 echo '</tr></table></th></tr>';
d9bad31a 520 echo "<tr class=row_${order}><th class=tdleft></th><th class=tdleft>${row['row_name']} (continued)";
950dfa1f
AA
521 echo "</th><th class=tdleft><table border=0 cellspacing=5><tr>";
522 }
168c2acb
DO
523 echo '<td align=center valign=bottom>' . getRackThumbLink ($rack);
524 echo '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>';
950dfa1f 525 $rackListIdx++;
e1add254 526 }
950dfa1f
AA
527 $order = $nextorder[$order];
528 echo "</tr></table></th></tr>\n";
529 }
530 echo "</table>\n";
e1add254 531 }
1ebbf889 532 }
e673ee24 533 }
d4e27fe5 534 echo "</td><td class='pcright ${pageno}' width='25%'>";
14ad4f4a 535 renderCellFilterPortlet ($cellfilter, 'rack', $found_racks);
e1add254
AD
536 echo "<br>\n";
537 renderLocationFilterPortlet ();
489a7502 538 echo "</td></tr></table>\n";
e673ee24
DO
539}
540
2056822d 541function renderLocationRowForEditor ($subtree, $level = 0)
e1add254
AD
542{
543 $self = __FUNCTION__;
2056822d
AA
544 foreach ($subtree as $locationinfo)
545 {
546 echo "<tr><td align=left style='padding-left: " . ($locationinfo['kidc'] ? $level : ($level + 1) * 16) . "px;'>";
547 if ($locationinfo['kidc'])
548 printImageHREF ('node-expanded-static');
549 if ($locationinfo['refcnt'] > 0 || $locationinfo['kidc'] > 0)
550 printImageHREF ('nodestroy');
551 else
10f5133a 552 echo getOpLink (array ('op' => 'deleteLocation', 'location_id' => $locationinfo['id']), '', 'destroy', 'Delete location');
2056822d
AA
553 echo '</td><td class=tdleft>';
554 printOpFormIntro ('updateLocation', array ('location_id' => $locationinfo['id']));
555 $parent = isset ($locationinfo['parent_id']) ? $locationinfo['parent_id'] : 0;
556 echo getSelect
557 (
558 array ( $parent => $parent ? htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'),
559 array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'),
560 $parent,
561 FALSE
562 );
563 echo "</td><td class=tdleft>";
564 echo "<input type=text size=48 name=name value='${locationinfo['name']}'>";
565 echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . "</form></td></tr>\n";
566 if ($locationinfo['kidc'])
567 $self ($locationinfo['kids'], $level + 1);
568 }
e1add254
AD
569}
570
82fa45a9 571function renderLocationSelectTree ($select_name, $selected_id = NULL)
eda41675 572{
82fa45a9 573 echo "<select name='${select_name}'>";
eda41675 574 echo '<option value=0>-- NONE --</option>';
359ea9f9 575 $locationlist = listCells ('location');
d6409c53 576 foreach (treeFromList (addTraceToNodes ($locationlist)) as $location)
eda41675
AD
577 {
578 echo "<option value=${location['id']} style='font-weight: bold' ";
579 if ($location['id'] == $selected_id )
580 echo ' selected';
581 echo ">${location['name']}</option>";
e3648fa6 582 printLocationChildrenSelectOptions ($location, $selected_id);
eda41675
AD
583 }
584 echo '</select>';
585}
586
e1add254
AD
587function renderRackspaceLocationEditor ()
588{
a6e090f0 589 $js = <<<'JSTXT'
b090b2da
RQ
590 function locationeditor_showselectbox(e) {
591 $(this).load('index.php', {module: 'ajax', ac: 'get-location-select', locationid: this.id});
592 $(this).unbind('mousedown', locationeditor_showselectbox);
593 }
594 $(document).ready(function () {
595 $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox);
596 });
597JSTXT;
598
599 addJS($js, TRUE );
e1add254
AD
600 function printNewItemTR ()
601 {
e1add254 602 printOpFormIntro ('addLocation');
eda41675 603 echo '<tr><td>';
e1add254 604 printImageHREF ('create', 'Add new location', TRUE);
82fa45a9
DO
605 echo '</td><td>';
606 renderLocationSelectTree ('parent_id');
04c61e7e
AB
607 echo '</td><td><input type=text size=48 name=name></td><td>';
608 printImageHREF ('create', 'Add new location', TRUE);
e1add254
AD
609 echo "</td></tr></form>\n";
610 }
e1add254
AD
611
612 startPortlet ('Locations');
613 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
614 echo "<tr><th>&nbsp;</th><th>Parent</th><th>Name</th><th>&nbsp;</th></tr>\n";
615 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
616 printNewItemTR();
2056822d 617
1e0f13f3 618 $locations = listCells ('location');
d6409c53 619 renderLocationRowForEditor (treeFromList (addTraceToNodes ($locations)));
2056822d 620
e1add254
AD
621 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
622 printNewItemTR();
623 echo "</table><br>\n";
624 finishPortlet();
625}
626
345fd640
AD
627function renderRackspaceRowEditor ()
628{
eda41675 629 function printNewItemTR ()
345fd640
AD
630 {
631 printOpFormIntro ('addRow');
eda41675 632 echo '<tr><td>';
7be51fea 633 printImageHREF ('create', 'Add new row', TRUE);
04eee8d2
VS
634 echo '</td><td>&nbsp;';
635 echo '</td><td>&nbsp;';
82fa45a9
DO
636 echo '</td><td>';
637 renderLocationSelectTree ('location_id');
04c61e7e
AB
638 echo '</td><td><input type=text name=name></td><td>';
639 printImageHREF ('create', 'Add new row', TRUE);
aca7e169 640 echo '</td><td>&nbsp;';
34f5d4eb 641 echo '</td><td>&nbsp;</td></tr></form>';
345fd640 642 }
d732e47e 643 startPortlet ('Rows');
345fd640 644 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
34f5d4eb 645 echo "<tr><th>&nbsp;</th><th># Racks</th><th># Devices</th><th>Location</th><th>Name</th><th>&nbsp;</th><th>&nbsp;</th><th>Row link</th></tr>\n";
345fd640 646 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
eda41675 647 printNewItemTR ();
524f8a7b 648 foreach (listCells ('row') as $row_id => $rowInfo)
345fd640 649 {
eda41675 650 echo '<tr><td>';
04eee8d2
VS
651 $rc = $rowInfo['rackc'];
652 $delete_racks_str = $rc ? " and $rc rack(s)" : '';
653 echo getOpLink (array ('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row'.$delete_racks_str, 'need-confirmation');
c40666f5 654 printOpFormIntro ('updateRow', array ('row_id' => $row_id));
34f5d4eb 655 echo '</td><td class=tdright>';
04eee8d2 656 echo $rc;
34f5d4eb 657 echo '</td><td class=tdright>';
04eee8d2
VS
658 echo getRowMountsCount ($row_id);
659 echo '</td><td>';
82fa45a9 660 renderLocationSelectTree ('location_id', $rowInfo['location_id']);
04c61e7e 661 echo "</td><td><input type=text name=name value='${rowInfo['name']}'></td><td>";
7be51fea 662 printImageHREF ('save', 'Save changes', TRUE);
524f8a7b 663 echo "</form></td>";
34f5d4eb
DO
664 echo '<td>&nbsp;</td>';
665 echo '<td class=tdleft>' . mkCellA ($rowInfo) . '</td>';
524f8a7b 666 echo "</tr>\n";
345fd640
AD
667 }
668 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
eda41675 669 printNewItemTR ();
345fd640
AD
670 echo "</table><br>\n";
671 finishPortlet();
672}
673
d10401bf 674function renderRow ($row_id)
e673ee24 675{
e16b666c 676 $rowInfo = getRowInfo ($row_id);
a8efc03e 677 $cellfilter = getCellFilter();
2b16c179 678 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
138655f5
AD
679
680 $summary = array ();
681 $summary['Name'] = $rowInfo['name'];
682 if ($rowInfo['location_id'])
683 $summary['Location'] = mkA ($rowInfo['location'], 'location', $rowInfo['location_id']);
684 $summary['Racks'] = $rowInfo['count'];
685 $summary['Units'] = $rowInfo['sum'];
686 $summary['% used'] = getProgressBar (getRSUforRow ($rackList));
249c78b2 687 foreach (getAttrValuesSorted ($row_id) as $record)
138655f5
AD
688 if
689 (
55eefced 690 $record['value'] != '' &&
138655f5
AD
691 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
692 )
5b908204 693 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record, 1561);
138655f5 694
e673ee24
DO
695 // Main layout starts.
696 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
697
698 // Left portlet with row information.
699 echo "<tr><td class=pcleft>";
138655f5 700 renderEntitySummary ($rowInfo, 'Summary', $summary);
7f297114 701 renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id));
6ccfd4bd 702 renderFilesPortlet ('row',$row_id);
48325652 703 echo "</td><td class=pcright>";
e673ee24 704
4fbb5a00 705 global $nextorder;
f5883ec1
DO
706 // Maximum number of racks per row is proportionally less, but at least 1.
707 $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1);
708 $rackListIdx = 0;
e673ee24
DO
709 $order = 'odd';
710 startPortlet ('Racks');
711 echo "<table border=0 cellspacing=5 align='center'><tr>";
64b95774 712 foreach ($rackList as $rack)
e673ee24 713 {
f5883ec1
DO
714 if ($rackListIdx % $maxPerRow == 0)
715 {
716 if ($rackListIdx > 0)
717 echo '</tr>';
718 echo '<tr>';
719 }
9b8174d7 720 $class = ($rack['has_problems'] == 'yes') ? 'error' : $order;
168c2acb
DO
721 echo "<td align=center valign=bottom class=row_${class}>" .
722 getRackThumbLink ($rack, getConfigVar ('ROW_SCALE')) .
723 '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>';
e673ee24 724 $order = $nextorder[$order];
f5883ec1 725 $rackListIdx++;
e673ee24
DO
726 }
727 echo "</tr></table>\n";
728 finishPortlet();
e673ee24
DO
729 echo "</td></tr></table>";
730}
731
5ff78aff
DO
732function renderEditAttributeTRs ($update_op, $values, $objtype_id, $skip_ids = array())
733{
734 $datehint = ' (' . datetimeFormatHint (getConfigVar ('DATETIME_FORMAT')) . ')';
735 $i = 0;
736 foreach ($values as $record)
737 {
738 $annex = array (array ('tag' => '$attr_' . $record['id']));
739 $can_view = permitted (NULL, NULL, NULL, $annex);
740 if (in_array ($record['id'], $skip_ids) || ! $can_view)
741 continue;
742 $can_update = permitted (NULL, NULL, $update_op, $annex);
743 $can_clear = permitted (NULL, NULL, 'clearSticker', $annex);
744 // Ability to update ultimately includes ability to set to an empty value,
745 // i.e. to clear, but making the check this way in the ophandler is complicated,
746 // so let's keep it consistently imperfect for the time being and maybe
747 // fix it later.
748 $clear_html = ($record['value'] != '' && ($can_clear /* || $can_update*/)) ?
749 getOpLink (array ('op' => 'clearSticker', 'attr_id' => $record['id']), '', 'clear', 'Clear value', 'need-confirmation') :
750 '&nbsp;';
751 echo "<tr><td>${clear_html}</td>";
752 echo '<th class=sticker>' . $record['name'] . ($record['type'] == 'date' ? $datehint : '') . ':</th>';
753 echo '<td class=tdleft>';
754 switch ($record['type'])
755 {
756 case 'uint':
757 case 'float':
758 case 'string':
759 $ro_or_rw = $can_update ? "name=${i}_value" : 'disabled';
760 echo "<input type=text ${ro_or_rw} value='${record['value']}'>";
761 break;
762 case 'date':
763 $ro_or_rw = $can_update ? "name=${i}_value" : 'disabled';
764 $date_value = $record['value'] ? datetimestrFromTimestamp ($record['value']) : '';
765 echo "<input type=text ${ro_or_rw} value='${date_value}'>";
766 break;
767 case 'dict':
768 $ro_or_rw = $can_update ? array ('name' => "${i}_value") : array ('name' => "${i}_value", 'disabled' => 1);
769 $chapter = readChapter ($record['chapter_id'], 'o');
770 $chapter[0] = '-- NOT SET --';
771 $chapter = cookOptgroups ($chapter, $objtype_id, $record['key']);
772 printNiftySelect ($chapter, $ro_or_rw, $record['key']);
773 break;
774 default:
775 throw new InvalidArgException ('record[type]', $record['type']);
776 } // switch
777 if ($can_update)
778 {
779 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
780 $i++;
781 }
782 echo '</td></tr>';
783 } // foreach
784 echo "<input type=hidden name=num_attrs value=${i}>";
785}
786
d10401bf 787function renderEditRowForm ($row_id)
138655f5
AD
788{
789 $row = getRowInfo ($row_id);
790
791 startPortlet ('Attributes');
792 printOpFormIntro ('updateRow');
793 echo '<table border=0 align=center>';
794 echo '<tr><td>&nbsp;</td><th class=tdright>Location:</th><td class=tdleft>';
795 $locations = array ();
796 $locations[0] = '-- NOT SET --';
797 foreach (listCells ('location') as $id => $locationInfo)
798 $locations[$id] = $locationInfo['name'];
799 natcasesort ($locations);
800 printSelect ($locations, array ('name' => 'location_id'), $row['location_id']);
801 echo "</td></tr>\n";
802 echo "<tr><td>&nbsp;</td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${row['name']}'></td></tr>\n";
5ff78aff 803 renderEditAttributeTRs ('updateRow', getAttrValuesSorted ($row_id), 1561);
138655f5
AD
804 if ($row['count'] == 0)
805 {
806 echo '<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>';
807 echo getOpLink (array ('op'=>'deleteRow'), '', 'destroy', 'Delete row', 'need-confirmation');
808 echo "&nbsp;</td></tr>\n";
809 }
810 echo "<tr><td class=submit colspan=3>";
811 printImageHREF ('SAVE', 'Save changes', TRUE);
812 echo "</td></tr>\n";
813 echo '</form></table><br>';
814 finishPortlet();
815
816 startPortlet ('History');
817 renderObjectHistory ($row_id);
818 finishPortlet();
819}
820
0a7feebb 821// Used by renderRack()
84feb87b 822function printObjectDetailsForRenderRack ($object_id, $hl_obj_id = 0)
0a7feebb
AD
823{
824 $objectData = spotEntity ('object', $object_id);
33973968 825 if ($objectData['asset_no'] != '')
0a7feebb
AD
826 $prefix = "<div title='${objectData['asset_no']}";
827 else
828 $prefix = "<div title='no asset tag";
829 // Don't tell about label, if it matches common name.
830 $body = '';
55eefced 831 if ($objectData['name'] != $objectData['label'] && $objectData['label'] != '')
0a7feebb
AD
832 $body = ", visible label is \"${objectData['label']}\"";
833 // Display list of child objects, if any
c17a36f0 834 $objectChildren = getChildren ($objectData, 'object');
5a7bf292 835 $slotRows = $slotCols = $slotInfo = $slotData = $slotTitle = $slotClass = array ();
fe82d92c
DO
836 if (! count ($objectChildren))
837 $suffix = "'>";
838 else
0a7feebb 839 {
c17a36f0 840 foreach ($objectChildren as $childData)
84feb87b 841 {
c17a36f0
AA
842 $childNames[] = $childData['name'];
843 $attrData = getAttrValues ($childData['id']);
be28528c
M
844 $numRows = $numCols = 1;
845 if (isset ($attrData[2])) // HW type
846 {
847 extractLayout ($attrData[2]);
848 if (isset ($attrData[2]['rows']))
849 {
850 $numRows = $attrData[2]['rows'];
851 $numCols = $attrData[2]['cols'];
852 }
853 }
05abd358 854 if (isset ($attrData['28'])) // slot number
84feb87b
AD
855 {
856 $slot = $attrData['28']['value'];
be28528c
M
857 if (preg_match ('/\d+/', $slot, $matches))
858 $slot = $matches[0];
859 $slotRows[$slot] = $numRows;
860 $slotCols[$slot] = $numCols;
c17a36f0
AA
861 $slotInfo[$slot] = $childData['dname'];
862 $slotData[$slot] = $childData['id'];
33973968 863 if ($childData['asset_no'] != '')
84feb87b
AD
864 $slotTitle[$slot] = "<div title='${childData['asset_no']}";
865 else
866 $slotTitle[$slot] = "<div title='no asset tag";
55eefced 867 if ($childData['label'] != '' && $childData['label'] != $childData['dname'])
84feb87b
AD
868 $slotTitle[$slot] .= ", visible label is \"${childData['label']}\"";
869 $slotTitle[$slot] .= "'>";
5a7bf292 870 $slotClass[$slot] = 'state_T';
c17a36f0 871 if ($childData['id'] == $hl_obj_id)
0cdfc55c
DO
872 $slotClass[$slot] .= 'h';
873 if ($childData['has_problems'] == 'yes')
874 $slotClass[$slot] .= 'w';
25526a97
ME
875
876 $child = spotEntity ('object', $childData['id']);
877 setEntityColors ($child);
72b539be
DO
878 $class_context = $childData['id'] == $hl_obj_id ? 'atom_selected' : 'atom_plain';
879 $slotClass[$slot] .= getObjectClass ($child, $class_context);
25526a97 880
84feb87b
AD
881 }
882 }
0a7feebb
AD
883 natsort($childNames);
884 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
885 }
6d8424f8 886 echo "${prefix}${body}${suffix}" . mkCellA ($objectData) . '</div>';
84feb87b
AD
887 if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis
888 {
889 $objAttr = getAttrValues ($objectData['id']);
890 if (isset ($objAttr[2])) // HW type
891 {
892 extractLayout ($objAttr[2]);
893 if (isset ($objAttr[2]['rows']))
894 {
895 $rows = $objAttr[2]['rows'];
896 $cols = $objAttr[2]['cols'];
897 $layout = $objAttr[2]['layout'];
898 echo "<table width='100%' border='1'>";
899 for ($r = 0; $r < $rows; $r++)
900 {
901 echo '<tr>';
902 for ($c = 0; $c < $cols; $c++)
903 {
904 $s = ($r * $cols) + $c + 1;
905 if (isset ($slotData[$s]))
906 {
be28528c 907 if ($slotData[$s] >= 0)
84feb87b 908 {
be28528c
M
909 for ($lr = 0; $lr < $slotRows[$s]; $lr++)
910 for ($lc = 0; $lc < $slotCols[$s]; $lc++)
911 {
912 $skip = ($lr * $cols) + $lc;
913 if ($skip > 0)
914 $slotData[$s + $skip] = -1;
915 }
916 echo '<td';
917 if ($slotRows[$s] > 1)
918 echo " rowspan=$slotRows[$s]";
919 if ($slotCols[$s] > 1)
920 echo " colspan=$slotCols[$s]";
5a7bf292 921 echo " class='${slotClass[$s]}'>${slotTitle[$s]}";
be28528c
M
922 if ($layout == 'V')
923 {
3e393bcc
AY
924 $tmp = mb_substr($slotInfo[$s], 0, 1);
925 for($i = 1; $i < mb_strlen($slotInfo[$s]); $i++)
926 {
927 $tmp .= '<br>' . mb_substr($slotInfo[$s], $i, 1);
928 }
be28528c
M
929 $slotInfo[$s] = $tmp;
930 }
931 echo mkA ($slotInfo[$s], 'object', $slotData[$s]);
932 echo '</div></td>';
84feb87b 933 }
84feb87b
AD
934 }
935 else
936 echo "<td class='state_F'><div title=\"Free slot\">&nbsp;</div></td>";
937 }
938 echo '</tr>';
939 }
940 echo '</table>';
941 }
942 }
943 }
0a7feebb
AD
944}
945
e673ee24 946// This function renders rack as HTML table.
7e1db771 947function renderRack ($rack_id, $hl_obj_id = 0)
e673ee24 948{
61a1d996
DO
949 $rackData = spotEntity ('rack', $rack_id);
950 amplifyCell ($rackData);
e673ee24 951 markAllSpans ($rackData);
25526a97 952 setEntityColors ($rackData);
e673ee24
DO
953 if ($hl_obj_id > 0)
954 highlightObject ($rackData, $hl_obj_id);
736acd8d 955 $neighbors = getRackNeighbors ($rackData['row_id'], $rack_id);
eda8b3ce
DO
956 $prev_id = $neighbors['prev'];
957 $next_id = $neighbors['next'];
d48d8820 958 echo "<center><table border=0><tr valign=middle>";
ad3e5e7e 959 echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>';
e673ee24 960 if ($prev_id != NULL)
ad3e5e7e
DO
961 echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>';
962 echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>';
e673ee24 963 if ($next_id != NULL)
ad3e5e7e 964 echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>';
d48d8820 965 echo "</h2></td></tr></table>\n";
e673ee24 966 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
d08147d6
DO
967 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
968 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
136449ff 969 $reverse = considerConfiguredConstraint ($rackData, 'REVERSED_RACKS_LISTSRC');
e673ee24
DO
970 for ($i = $rackData['height']; $i > 0; $i--)
971 {
136449ff 972 echo '<tr><th>' . inverseRackUnit ($rackData['height'], $i, $reverse) . '</th>';
e673ee24
DO
973 for ($locidx = 0; $locidx < 3; $locidx++)
974 {
975 if (isset ($rackData[$i][$locidx]['skipped']))
976 continue;
977 $state = $rackData[$i][$locidx]['state'];
25526a97
ME
978
979 $class = "atom state_${state}";
980
e673ee24 981 if (isset ($rackData[$i][$locidx]['hl']))
25526a97
ME
982 $class .= $rackData[$i][$locidx]['hl'];
983
984 if($state == 'T')
985 {
986 $objectData = spotEntity ('object', $rackData[$i][$locidx]['object_id']);
987 setEntityColors ($objectData);
72b539be
DO
988 $class_context = $rackData[$i][$locidx]['object_id'] == $hl_obj_id ? 'atom_selected' : 'atom_plain';
989 $class .= getObjectClass ($objectData, $class_context);
25526a97
ME
990 }
991
992 echo "<td class='${class}'";
993
e673ee24
DO
994 if (isset ($rackData[$i][$locidx]['colspan']))
995 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
996 if (isset ($rackData[$i][$locidx]['rowspan']))
997 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
998 echo ">";
999 switch ($state)
1000 {
1001 case 'T':
84feb87b 1002 printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id);
e673ee24
DO
1003 break;
1004 case 'A':
1005 echo '<div title="This rackspace does not exist">&nbsp;</div>';
1006 break;
1007 case 'F':
1008 echo '<div title="Free rackspace">&nbsp;</div>';
1009 break;
1010 case 'U':
1011 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
1012 break;
1013 default:
1014 echo '<div title="No data">&nbsp;</div>';
1015 break;
1016 }
1017 echo '</td>';
1018 }
1019 echo "</tr>\n";
1020 }
0a7feebb
AD
1021 echo "</table>\n";
1022 // Get a list of all of objects Zero-U mounted to this rack
c17a36f0
AA
1023 $zeroUObjects = getChildren ($rackData, 'object');
1024 uasort ($zeroUObjects, 'compare_name');
a20a4e3c
DO
1025 if (count ($zeroUObjects) > 0)
1026 {
0a7feebb
AD
1027 echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n";
1028 echo "<tr><th>Zero-U:</th></tr>\n";
1029 foreach ($zeroUObjects as $zeroUObject)
1030 {
c17a36f0 1031 $state = ($zeroUObject['id'] == $hl_obj_id) ? 'Th' : 'T';
a2037cdd
DO
1032 if ($zeroUObject['has_problems'] == 'yes')
1033 $state .= 'w';
25526a97
ME
1034
1035 $class = "atom state_${state}";
1036 setEntityColors ($zeroUObject);
72b539be
DO
1037 $class_context = $zeroUObject['id'] == $hl_obj_id ? 'atom_selected' : 'atom_plain';
1038 $class .= getObjectClass ($zeroUObject, $class_context);
25526a97
ME
1039
1040 echo "<tr><td class='${class}'>";
1041 printObjectDetailsForRenderRack ($zeroUObject['id']);
0a7feebb
AD
1042 echo "</td></tr>\n";
1043 }
1044 echo "</table>\n";
1045 }
1046 echo "</center>\n";
e673ee24
DO
1047}
1048
d10401bf 1049function renderRackSortForm ($row_id)
42504426 1050{
b090b2da 1051 includeJQueryUI (false);
a6e090f0
DO
1052 // Heredoc, not nowdoc!
1053 $js = <<<"JSTXT"
b090b2da
RQ
1054 $(document).ready(
1055 function () {
1056 $("#sortRacks").sortable({
1057 update : function () {
1058 serial = $('#sortRacks').sortable('serialize');
1059 $.ajax({
824886b2 1060 url: 'index.php?module=ajax&ac=upd-rack-sort-order&row_id=${row_id}',
b090b2da
RQ
1061 type: 'post',
1062 data: serial,
1063 });
1064 }
1065 });
1066 }
42504426 1067 );
b090b2da 1068JSTXT;
1d44a1e1 1069 addJS ($js, TRUE);
42504426
AD
1070
1071 startPortlet ('Racks');
1072 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
1073 echo "<tr><th>Drag to change order</th></tr>\n";
34f5d4eb 1074 echo "<tr><td class=tdleft><ul class='uflist' id='sortRacks'>\n";
42504426
AD
1075 foreach (getRacks($row_id) as $rack_id => $rackInfo)
1076 echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n";
1077 echo "</ul></td></tr></table>\n";
1078 finishPortlet();
1079}
1080
78ba6f56 1081function renderNewRackForm()
e673ee24 1082{
d3e838cd 1083 $default_height = emptyStrIfZero (getConfigVar ('DEFAULT_RACK_HEIGHT'));
50b4ba85 1084 startPortlet ('Add one');
6b552311 1085 printOpFormIntro ('addRack', array ('mode' => 'one'));
e673ee24 1086 echo '<table border=0 align=center>';
04c61e7e
AB
1087 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name></td>";
1088 echo "<tr><th class=tdright>Height in units (required):</th><td class=tdleft><input type=text name=height1 value='${default_height}'></td></tr>\n";
1089 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no></td></tr>\n";
1090 echo "<tr><th class=tdright>Tags:</td><td class=tdleft>";
e7b84015 1091 printTagsPicker ();
72d52730 1092 echo "</td></tr>\n";
f19c75d6
DO
1093 echo "<tr><td class=submit colspan=2>";
1094 printImageHREF ('CREATE', 'Add', TRUE);
1095 echo "</td></tr></table></form>";
406b54bd 1096 finishPortlet();
406b54bd 1097
50b4ba85 1098 startPortlet ('Add many');
6b552311 1099 printOpFormIntro ('addRack', array ('mode' => 'many'));
50b4ba85 1100 echo '<table border=0 align=center>';
9b8174d7 1101 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>";
04c61e7e 1102 echo "<tr><th class=tdright>Assign tags:</td><td class=tdleft>";
e7b84015 1103 printTagsPicker ();
72d52730 1104 echo "</td></tr>\n";
9b8174d7 1105 echo "<tr><th class=tdright>Rack names (required):</th><td class=tdleft><textarea name=names cols=40 rows=25></textarea></td></tr>\n";
f19c75d6
DO
1106 echo "<tr><td class=submit colspan=2>";
1107 printImageHREF ('CREATE', 'Add', TRUE);
e673ee24
DO
1108 echo '</form></table>';
1109 finishPortlet();
1110}
1111
3825c4db 1112function renderEditObjectForm()
e673ee24 1113{
3825c4db 1114 $object_id = getBypassValue();
fb6e2f57 1115 $object = spotEntity ('object', $object_id);
cdd3efe9 1116 startPortlet ();
43fb6eaf 1117 printOpFormIntro ('update');
cdd3efe9
AD
1118
1119 // static attributes
e10f583a
DO
1120 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
1121 echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
3825c4db
DO
1122 echo '<tr><td>&nbsp;</td><th class=tdright>Type:</th><td class=tdleft>';
1123 printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']);
1124 echo '</td></tr>';
22bb04da 1125 // baseline info
e10f583a 1126 echo "<tr><td>&nbsp;</td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
42422859
AD
1127 echo "<tr><td>&nbsp;</td><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
1128 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
e7b84015
AB
1129 echo "<tr><td>&nbsp;</td><th class=tdright>Tags:</th><td class=tdleft>";
1130 printTagsPicker ();
1131 echo "</td></tr>\n";
0682218d 1132 // parent selection
9b8174d7 1133 if (objectTypeMayHaveParent ($object['objtype_id']))
0682218d 1134 {
9563f56f 1135 $parents = getParents ($object, 'object');
af8916e9
AD
1136 // lookup the human-readable object type, sort by it
1137 foreach ($parents as $parent_id => $parent)
1138 $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']);
1139 $grouped_parents = groupBy ($parents, 'object_type');
1140 ksort ($grouped_parents);
1141 foreach ($grouped_parents as $parents_group)
0682218d 1142 {
9563f56f 1143 uasort ($parents_group, 'compare_name');
af8916e9 1144 $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers:' : ' container:');
9563f56f 1145 foreach ($parents_group as $link_id => $parent_cell)
8526b4cc 1146 {
8526b4cc
J
1147 echo "<tr><td>&nbsp;</td>";
1148 echo "<th class=tdright>${label}</th><td class=tdleft>";
9563f56f 1149 echo mkCellA ($parent_cell);
8526b4cc
J
1150 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
1151 echo getOpLink (array('op'=>'unlinkObjects', 'link_id'=>$link_id), '', 'cut', 'Unlink container');
1152 echo "</td></tr>\n";
1153 $label = '&nbsp;';
1154 }
0682218d
AD
1155 }
1156 echo "<tr><td>&nbsp;</td>";
1157 echo "<th class=tdright>Select container:</th><td class=tdleft>";
5d4ca0f3 1158 echo getPopupLink ('objlist', array(), 'findlink', 'attach', 'Select a container');
de55c069 1159 echo "</td></tr>\n";
0682218d 1160 }
5ff78aff 1161 renderEditAttributeTRs ('update', getAttrValuesSorted ($object_id), $object['objtype_id']);
f5b9c21a
DO
1162 echo '<tr><td>&nbsp;</td><th class=tdright><label for=object_has_problems>Has problems:</label></th>';
1163 echo '<td class=tdleft><input type=checkbox name=object_has_problems id=object_has_problems';
e10f583a
DO
1164 if ($object['has_problems'] == 'yes')
1165 echo ' checked';
1166 echo "></td></tr>\n";
dec748f6 1167 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
10f5133a 1168 echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation');
abd1e9ac 1169 echo "&nbsp;";
10f5133a 1170 echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation');
abd1e9ac 1171 echo "</td></tr>\n";
e10f583a 1172 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
cdd3efe9 1173
e10f583a 1174 echo "<tr><th class=submit colspan=3>";
5bbbeaa2 1175 printImageHREF ('SAVE', 'Save changes', TRUE);
cdd3efe9 1176 echo "</form></th></tr></table>\n";
e673ee24 1177 finishPortlet();
e673ee24 1178
cdd3efe9 1179 echo '<table border=0 width=100%><tr><td>';
e673ee24 1180 startPortlet ('history');
9b8174d7 1181 renderObjectHistory ($object_id);
e673ee24 1182 finishPortlet();
cdd3efe9 1183 echo '</td></tr></table>';
e673ee24
DO
1184}
1185
d10401bf 1186function renderEditRackForm ($rack_id)
e673ee24 1187{
61a1d996
DO
1188 $rack = spotEntity ('rack', $rack_id);
1189 amplifyCell ($rack);
e673ee24 1190
9b8174d7 1191 startPortlet ('Attributes');
7056988c 1192 printOpFormIntro ('updateRack');
e673ee24 1193 echo '<table border=0 align=center>';
9b8174d7 1194 echo "<tr><td>&nbsp;</td><th class=tdright>Rack row:</th><td class=tdleft>";
524f8a7b 1195 foreach (listCells ('row') as $row_id => $rowInfo)
64a973a7
AD
1196 {
1197 $trail = getLocationTrail ($rowInfo['location_id'], FALSE);
1198 $rows[$row_id] = empty ($trail) ? $rowInfo['name'] : $rowInfo['name'] . ' [' . $trail . ']';
1199 }
1200 natcasesort ($rows);
e1add254 1201 printSelect ($rows, array ('name' => 'row_id'), $rack['row_id']);
e673ee24 1202 echo "</td></tr>\n";
9b8174d7
AD
1203 echo "<tr><td>&nbsp;</td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${rack['name']}'></td></tr>\n";
1204 echo "<tr><td>&nbsp;</td><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=height value='${rack['height']}'></td></tr>\n";
9b8174d7 1205 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no value='${rack['asset_no']}'></td></tr>\n";
e7b84015
AB
1206 echo "<tr><td>&nbsp;</td><th class=tdright>Tags:</th><td class=tdleft>";
1207 printTagsPicker ();
1208 echo "</td></tr>\n";
5ff78aff 1209 renderEditAttributeTRs ('updateRack', getAttrValuesSorted ($rack_id), 1560, array (27, 29));
f0fe0da7
DO
1210 echo '<tr><td>&nbsp;</td><th class=tdright><label for=has_problems>Has problems:</label></th>';
1211 echo '<td class=tdleft><input type=checkbox name=has_problems id=has_problems';
9b8174d7
AD
1212 if ($rack['has_problems'] == 'yes')
1213 echo ' checked';
1214 echo "></td></tr>\n";
04eee8d2 1215 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
c495997f 1216 if ($rack['isDeletable'])
c8187437 1217 {
10f5133a 1218 echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation');
04eee8d2 1219 echo "&nbsp;";
c8187437 1220 }
04eee8d2
VS
1221 else
1222 {
1223 echo getOpLink (array ('op'=>'cleanRack'), '' ,'clear', 'Reset (cleanup) rack mounts', 'need-confirmation');
1224 echo "&nbsp;";
1225 }
1226 echo "</td></tr>\n";
9b8174d7
AD
1227 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>";
1228 echo "<tr><td class=submit colspan=3>";
7056988c
DO
1229 printImageHREF ('SAVE', 'Save changes', TRUE);
1230 echo "</td></tr>\n";
e673ee24
DO
1231 echo '</form></table><br>';
1232 finishPortlet();
dec748f6 1233
e673ee24 1234 startPortlet ('History');
9b8174d7 1235 renderObjectHistory ($rack_id);
e673ee24
DO
1236 finishPortlet();
1237}
1238
6b9bdb08
AA
1239// populates the $summary array with the sum of power attributes of the objects mounted into the rack
1240function populateRackPower ($rackData, &$summary)
1241{
1242 $power_attrs = array(
1243 7, // 'float','max. current, Ampers'
1244 13, // 'float','max power, Watts'
1245 );
1246 $sum = array();
1247 if (! isset ($rackData['mountedObjects']))
1248 amplifyCell ($rackData);
1249 foreach ($rackData['mountedObjects'] as $object_id)
1250 {
1251 $attrs = getAttrValues ($object_id);
1252 foreach ($power_attrs as $attr_id)
1253 if (isset ($attrs[$attr_id]) && $attrs[$attr_id]['type'] == 'float')
1254 {
1255 if (! isset ($sum[$attr_id]))
1256 {
1257 $sum[$attr_id]['sum'] = 0.0;
1258 $sum[$attr_id]['name'] = $attrs[$attr_id]['name'];
1259 }
1260 $sum[$attr_id]['sum'] += $attrs[$attr_id]['value'];
1261 }
1262 }
1263 foreach ($sum as $attr)
1264 if ($attr['sum'] > 0.0)
1265 $summary[$attr['name']] = $attr['sum'];
1266}
1267
254673dd
DO
1268// used by renderGridForm() and renderRackPage()
1269function renderRackInfoPortlet ($rackData)
1270{
646272be 1271 $summary = array();
67cfe546 1272 $summary['Rack row'] = mkA ($rackData['row_name'], 'row', $rackData['row_id']);
646272be
AA
1273 $summary['Name'] = $rackData['name'];
1274 $summary['Height'] = $rackData['height'];
33973968 1275 if ($rackData['asset_no'] != '')
646272be 1276 $summary['Asset tag'] = $rackData['asset_no'];
9b8174d7 1277 if ($rackData['has_problems'] == 'yes')
646272be 1278 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
6b9bdb08 1279 populateRackPower ($rackData, $summary);
42504426
AD
1280 // Display populated attributes, but skip 'height' since it's already displayed above
1281 // and skip 'sort_order' because it's modified using AJAX
249c78b2 1282 foreach (getAttrValuesSorted ($rackData['id']) as $record)
5b908204
DO
1283 if
1284 (
1285 $record['id'] != 27 && $record['id'] != 29 &&
1286 $record['value'] != '' &&
1287 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1288 )
1289 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record, 1560);
646272be
AA
1290 $summary['% used'] = getProgressBar (getRSUforRack ($rackData));
1291 $summary['Objects'] = count ($rackData['mountedObjects']);
1292 $summary['tags'] = '';
646272be 1293 renderEntitySummary ($rackData, 'summary', $summary);
0602fc27
DO
1294 if ($rackData['comment'] != '')
1295 {
1296 startPortlet ('Comment');
1297 echo '<div class=commentblock>' . string_insert_hrefs ($rackData['comment']) . '</div>';
1298 finishPortlet ();
1299 }
254673dd
DO
1300}
1301
e673ee24 1302// This is a universal editor of rack design/waste.
7e1db771 1303function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
e673ee24 1304{
61a1d996
DO
1305 $rackData = spotEntity ('rack', $rack_id);
1306 amplifyCell ($rackData);
254673dd 1307 $filter ($rackData);
e673ee24 1308
e673ee24
DO
1309 // Render the result whatever it is.
1310 // Main layout.
1311 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1312 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
1313
1314 // Left column with information portlet.
1315 echo "<tr><td class=pcleft height='1%' width='50%'>";
254673dd 1316 renderRackInfoPortlet ($rackData);
e673ee24 1317 echo "</td>\n";
bb09cca0 1318 echo "<td class=pcright>";
e673ee24
DO
1319
1320 // Grid form.
c26d97b6 1321 $is_ro = !rackModificationPermitted ($rackData, 'updateRack');
e673ee24 1322 startPortlet ($header);
e713bb4d 1323 includeJQueryUI (FALSE);
65e557dd 1324 addJS ('js/racktables.js');
e713bb4d
DO
1325 $table_id = 'selectableRack';
1326 addBulkSelectorJS ($table_id);
e673ee24 1327 echo "<center>\n";
c26d97b6
VS
1328 $read_only_text = $is_ro ? '(read-only)' : '&nbsp;';
1329 echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n";
e713bb4d 1330 echo "<table class=rack id={$table_id} border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 1331 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
1332 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1333 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1334 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
4fbb5a00 1335 printOpFormIntro ('updateRack');
e673ee24 1336 markupAtomGrid ($rackData, $state2);
c26d97b6 1337 renderAtomGrid ($rackData, $is_ro);
e673ee24
DO
1338 echo "</table></center>\n";
1339 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
1340 finishPortlet();
bb09cca0 1341 echo "</td></tr></table>\n";
e673ee24
DO
1342}
1343
1344function renderRackDesign ($rack_id)
1345{
bb09cca0 1346 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
e673ee24
DO
1347}
1348
7e1db771 1349function renderRackProblems ($rack_id)
e673ee24 1350{
bb09cca0 1351 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
e673ee24
DO
1352}
1353
21928333
MH
1354function renderObjectPortHeaderRow()
1355{
1356 // Renders the headers for the ports table on the default page
1357
1358 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
1359 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
1360 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
1361 echo '<th class=tdleft>Cable ID</th></tr>';
1362}
1363
40c9fc94
AA
1364function renderObjectPortRow ($port, $is_highlighted)
1365{
acb01e71 1366 // highlight port name with yellow if its name is not canonical
8579b51b
AA
1367 $canon_pn = shortenPortName ($port['name'], $port['object_id']);
1368 $name_class = $canon_pn == $port['name'] ? '' : 'trwarning';
1369
90bf1755
DO
1370 echo '<tr';
1371 if ($is_highlighted)
1372 echo ' class=highlight';
40c9fc94 1373 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
8579b51b 1374 echo "><td class='tdleft $name_class' NOWRAP><a name='port-${port['id']}' class='interactive-portname nolink $a_class'>${port['name']}</a></td>";
40c9fc94 1375 echo "<td class=tdleft>${port['label']}</td>";
bba495fc 1376 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class='tdleft l2address'>${port['l2address']}</td>";
0b09238d 1377 if ($port['remote_object_id'])
90bf1755 1378 {
f4d00faf 1379 $dname = formatObjectDisplayedName ($port['remote_object_name'], $port['remote_object_tid']);
0b09238d 1380 echo "<td class=tdleft>" .
f4d00faf 1381 formatPortLink ($port['remote_object_id'], $dname, $port['remote_id'], NULL) .
0b09238d
DO
1382 "</td>";
1383 echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . "</td>";
1384 $editable = permitted ('object', 'ports', 'editPort')
1385 ? 'editable'
1386 : '';
1387 echo "<td class=tdleft><span class='rsvtext $editable id-${port['id']} op-upd-reservation-cable'>${port['cableid']}</span></td>";
40c9fc94 1388 }
90bf1755
DO
1389 else
1390 echo implode ('', formatPortReservation ($port)) . '<td></td>';
0b09238d 1391 echo "</tr>";
40c9fc94
AA
1392}
1393
d10401bf 1394function renderObject ($object_id)
e673ee24 1395{
8dc2a6c8 1396 global $nextorder, $virtual_obj_types;
fb6e2f57 1397 $info = spotEntity ('object', $object_id);
94fe6370 1398 amplifyCell ($info);
e673ee24
DO
1399 // Main layout starts.
1400 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1401 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
3a243872 1402 // A mandatory left column with varying number of portlets.
e673ee24 1403 echo "<tr><td class=pcleft>";
646272be
AA
1404
1405 // display summary portlet
a11e7938 1406 $summary = array();
33973968 1407 if ($info['name'] != '')
646272be 1408 $summary['Common name'] = $info['name'];
94fe6370 1409 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
646272be
AA
1410 $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>');
1411 $summary['Object type'] = '<a href="' . makeHref (array (
341fd895
DO
1412 'page' => 'depot',
1413 'tab' => 'default',
1414 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
eb11ba46 1415 )) . '">' . decodeObjectType ($info['objtype_id']) . '</a>';
33973968 1416 if ($info['label'] != '')
646272be 1417 $summary['Visible label'] = $info['label'];
33973968 1418 if ($info['asset_no'] != '')
646272be 1419 $summary['Asset tag'] = $info['asset_no'];
d4e8ddeb 1420 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
646272be 1421 $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>');
9563f56f 1422 $parents = getParents ($info, 'object');
af8916e9
AD
1423 // lookup the human-readable object type, sort by it
1424 foreach ($parents as $parent_id => $parent)
1425 $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']);
1426 $grouped_parents = groupBy ($parents, 'object_type');
1427 ksort ($grouped_parents);
1428 foreach ($grouped_parents as $parents_group)
0682218d 1429 {
9563f56f 1430 uasort ($parents_group, 'compare_name');
af8916e9 1431 $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers' : ' container');
9563f56f
AA
1432 $fmt_parents = array();
1433 foreach ($parents_group as $parent)
1434 $fmt_parents[] = mkCellA ($parent);
af8916e9 1435 $summary[$label] = implode ('<br>', $fmt_parents);
0682218d 1436 }
9563f56f
AA
1437 $children = getChildren ($info, 'object');
1438 foreach (groupBy ($children, 'objtype_id') as $objtype_id => $children_group)
42fb3aa2 1439 {
9563f56f
AA
1440 uasort ($children_group, 'compare_name');
1441 $fmt_children = array();
1442 foreach ($children_group as $child)
1443 $fmt_children[] = mkCellA ($child);
c49fddcc 1444 $summary["Contains " . mb_strtolower(decodeObjectType ($objtype_id))] = implode ('<br>', $fmt_children);
42fb3aa2 1445 }
e673ee24 1446 if ($info['has_problems'] == 'yes')
646272be 1447 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
249c78b2 1448 foreach (getAttrValuesSorted ($object_id) as $record)
4969aa31
DO
1449 if
1450 (
55eefced 1451 $record['value'] != '' &&
4969aa31
DO
1452 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1453 )
5b908204 1454 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record, $info['objtype_id']);
a2c597ea
AA
1455 $summary[] = array (getOutputOf ('printTagTRs',
1456 $info,
1457 makeHref
1458 (
1459 array
1460 (
1461 'page'=>'depot',
1462 'tab'=>'default',
1463 'andor' => 'and',
1464 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1465 )
1466 )."&"
1467 ));
0b09238d 1468 renderEntitySummary ($info, 'summary', $summary);
e673ee24 1469
33973968 1470 if ($info['comment'] != '')
e673ee24
DO
1471 {
1472 startPortlet ('Comment');
6cc5d6cd 1473 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
e673ee24
DO
1474 finishPortlet ();
1475 }
1476
b5700329
AA
1477 $logrecords = getLogRecordsForObject ($_REQUEST['object_id']);
1478 if (count ($logrecords))
9a90adc4
DO
1479 {
1480 startPortlet ('log records');
1481 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1482 $order = 'odd';
b5700329 1483 foreach ($logrecords as $row)
9a90adc4
DO
1484 {
1485 echo "<tr class=row_${order} valign=top>";
1486 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
0b8d8309 1487 echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>';
9a90adc4
DO
1488 echo '</tr>';
1489 $order = $nextorder[$order];
1490 }
1491 echo '</table>';
1492 finishPortlet();
1493 }
1494
65e557dd 1495 switchportInfoJS ($object_id); // load JS code to make portnames interactive
e1ae3fb4
AD
1496 renderFilesPortlet ('object', $object_id);
1497
9f75e165 1498 if (count ($info['ports']))
e673ee24 1499 {
0b09238d 1500 startPortlet ('ports and links');
9f75e165
DO
1501 $hl_port_id = 0;
1502 if (isset ($_REQUEST['hl_port_id']))
e673ee24 1503 {
3db0d8ce 1504 genericAssertion ('hl_port_id', 'natural');
9f75e165 1505 $hl_port_id = $_REQUEST['hl_port_id'];
65e557dd 1506 addAutoScrollScript ("port-$hl_port_id");
9f75e165 1507 }
0b09238d 1508 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>";
21928333 1509 callHook ('renderObjectPortHeaderRow');
9f75e165 1510 foreach ($info['ports'] as $port)
40c9fc94 1511 callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id']));
fd5edda8 1512 if (permitted (NULL, 'ports', 'set_reserve_comment'))
a8dc2982 1513 addJS ('js/inplace-edit.js');
9f75e165 1514 echo "</table><br>";
e673ee24
DO
1515 finishPortlet();
1516 }
85970da2 1517
21ee3351 1518 if (count ($info['ipv4']) + count ($info['ipv6']))
e673ee24 1519 {
21ee3351 1520 startPortlet ('IP addresses');
e673ee24 1521 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
e9446e3b 1522 if ('yes' == $ext_ipv4_view = getConfigVar ('EXT_IPV4_VIEW'))
9d5f6a80 1523 echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
83fdf85f 1524 else
9d5f6a80 1525 echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
21ee3351
AA
1526
1527 // group IP allocations by interface name instead of address family
1528 $allocs_by_iface = array();
1529 foreach (array ('ipv4', 'ipv6') as $ip_v)
4318ced5
AA
1530 foreach ($info[$ip_v] as $ip_bin => $alloc)
1531 $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc;
dec748f6 1532
21ee3351
AA
1533 // sort allocs array by portnames
1534 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1535 {
1536 $is_first_row = TRUE;
f3505b35 1537 foreach ($alloclist as $alloc)
b90c3907 1538 {
40c9fc94 1539 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
f3505b35 1540 echo "<tr class='${rendered_alloc['tr_class']}' valign=top>";
21ee3351 1541
f3505b35 1542 // display iface name, same values are grouped into single cell
21ee3351
AA
1543 if ($is_first_row)
1544 {
1545 $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : '';
40c9fc94 1546 echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>";
21ee3351
AA
1547 $is_first_row = FALSE;
1548 }
f3505b35 1549 echo $rendered_alloc['td_ip'];
e9446e3b 1550 if ($ext_ipv4_view == 'yes')
83fdf85f 1551 {
f3505b35
AA
1552 echo $rendered_alloc['td_network'];
1553 echo $rendered_alloc['td_routed_by'];
21ee3351 1554 }
f3505b35
AA
1555 echo $rendered_alloc['td_peers'];
1556
1557 echo "</tr>\n";
b90c3907 1558 }
e673ee24
DO
1559 }
1560 echo "</table><br>\n";
1561 finishPortlet();
1562 }
1563
94fe6370 1564 $forwards = $info['nat4'];
55eefced 1565 if (count ($forwards['in']) || count ($forwards['out']))
e673ee24 1566 {
f28fbe8b 1567 startPortlet('NATv4');
e673ee24
DO
1568
1569 if (count($forwards['out']))
1570 {
1571
f28fbe8b 1572 echo "<h3>locally performed NAT</h3>";
e673ee24 1573
105a3bc8 1574 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1575 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1576
1577 foreach ($forwards['out'] as $pf)
1578 {
2c817354
DO
1579 $class = 'trerror';
1580 $osif = '';
6a3c2dc5
AA
1581 $localip_bin = ip_parse ($pf['localip']);
1582 if (array_key_exists ($localip_bin, $info['ipv4']))
2c817354 1583 {
6a3c2dc5
AA
1584 $class = $info['ipv4'][$localip_bin]['addrinfo']['class'];
1585 $osif = $info['ipv4'][$localip_bin]['osif'] . ': ';
2c817354 1586 }
e673ee24 1587 echo "<tr class='$class'>";
7419401e
AA
1588 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1589 echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
4318ced5 1590 $address = getIPAddress (ip4_parse ($pf['remoteip']));
e673ee24 1591 echo "<td class='description'>";
53ef3908
DO
1592 if (count ($address['allocs']))
1593 foreach($address['allocs'] as $bond)
ad3e5e7e 1594 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
33973968 1595 elseif ($pf['remote_addr_name'] != '')
f28fbe8b 1596 echo '(' . $pf['remote_addr_name'] . ')';
53ef3908 1597 echo "</td><td class='description'>${pf['description']}</td></tr>";
e673ee24
DO
1598 }
1599 echo "</table><br><br>";
1600 }
1601 if (count($forwards['in']))
1602 {
f28fbe8b 1603 echo "<h3>arriving NAT connections</h3>";
105a3bc8 1604 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1605 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1606 foreach ($forwards['in'] as $pf)
1607 {
1608 echo "<tr>";
7419401e 1609 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
ad3e5e7e 1610 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
7419401e 1611 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
e673ee24
DO
1612 echo "<td class='description'>${pf['description']}</td></tr>";
1613 }
e673ee24
DO
1614 echo "</table><br><br>";
1615 }
1616 finishPortlet();
1617 }
1618
eacc0983 1619 renderSLBTriplets2 ($info);
defd92d8 1620 renderSLBTriplets ($info);
e673ee24
DO
1621 echo "</td>\n";
1622
3a243872
DO
1623 // A conditional right column with the rackspace portlet only.
1624 if
1625 (
1626 ! in_array ($info['objtype_id'], $virtual_obj_types) &&
950d4117 1627 count ($rack_ids = getResidentRackIDs ($object_id))
3a243872 1628 )
0682218d 1629 {
3a243872 1630 echo '<td class=pcright>';
0682218d 1631 startPortlet ('rackspace allocation');
3a243872 1632 foreach ($rack_ids as $rack_id)
0682218d
AD
1633 renderRack ($rack_id, $object_id);
1634 echo '<br>';
1635 finishPortlet();
3a243872 1636 echo '</td>';
0682218d 1637 }
3a243872 1638 echo "<tr></table>\n";
e673ee24
DO
1639}
1640
1641function renderRackMultiSelect ($sname, $racks, $selected)
1642{
04571888
DO
1643 // Transform the given flat list into a list of groups, each representing a rack row.
1644 $rdata = array();
e673ee24 1645 foreach ($racks as $rack)
d016010a 1646 {
b956dd24 1647 if ('' != $trail = getLocationTrail ($rack['location_id'], FALSE))
7b6ae79a
AD
1648 $row_name = $trail . ' : ' . $rack['row_name'];
1649 else
1650 $row_name = $rack['row_name'];
d016010a
AD
1651 $rdata[$row_name][$rack['id']] = $rack['name'];
1652 }
4fbb5a00 1653 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
acfc0d89
AA
1654 $row_names = array_keys ($rdata);
1655 natsort ($row_names);
1656 foreach ($row_names as $optgroup)
e673ee24 1657 {
04571888 1658 echo "<optgroup label='${optgroup}'>";
acfc0d89 1659 foreach ($rdata[$optgroup] as $rack_id => $rack_name)
04571888
DO
1660 {
1661 echo "<option value=${rack_id}";
1662 if (!(array_search ($rack_id, $selected) === FALSE))
1663 echo ' selected';
1664 echo">${rack_name}</option>\n";
1665 }
e673ee24
DO
1666 }
1667 echo "</select>\n";
1668}
1669
e673ee24 1670// This function renders a form for port edition.
d10401bf 1671function renderPortsForObject ($object_id)
e673ee24 1672{
3153a326
DO
1673 $prefs = getPortListPrefs();
1674 function printNewItemTR ($prefs)
39b4abd0
DO
1675 {
1676 printOpFormIntro ('addPort');
1677 echo "<tr><td>";
f5ff50f5 1678 printImageHREF ('add', 'add a port', TRUE);
7b30e187 1679 echo "</td><td class='tdleft'><input type=text size=16 name=port_name></td>\n";
04c61e7e 1680 echo "<td><input type=text name=port_label></td><td>";
759b21d2 1681 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']);
97792a8a 1682 echo "<td><input type=text name=port_l2address size=17 maxlength=59></td>\n";
318c48a8 1683 echo "<td colspan=4>&nbsp;</td><td>";
04c61e7e 1684 printImageHREF ('add', 'add a port', TRUE);
9318d2ef 1685 echo "</td></tr></form>";
39b4abd0 1686 }
70c0cb08
DO
1687
1688 function printBulkForm ($prefs)
1689 {
a1fc539a
RF
1690 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1691 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1692 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1693 printOpFormIntro ('addBulkPorts');
1694 echo "<tr><td>";
1695 printImageHREF ('add', 'add ports', TRUE);
04c61e7e
AB
1696 echo "</td><td><input type=text size=8 name=port_name></td>\n";
1697 echo "<td><input type=text name=port_label></td><td>";
759b21d2 1698 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']);
04c61e7e
AB
1699 echo "<td><input type=text name=port_numbering_start size=3 maxlength=3></td>\n";
1700 echo "<td><input type=text name=port_numbering_count size=3 maxlength=3></td>\n";
0b09238d 1701 echo "<td>&nbsp;</td><td>";
04c61e7e 1702 printImageHREF ('add', 'add ports', TRUE);
a1fc539a
RF
1703 echo "</td></tr></form>";
1704 echo "</table><br>\n";
1705 }
dec748f6 1706
70c0cb08
DO
1707 startPortlet ('Ports and interfaces');
1708 $object = spotEntity ('object', $object_id);
1709 amplifyCell ($object);
1710 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar ('ENABLE_BULKPORT_FORM') == 'yes')
1711 printBulkForm ($prefs);
1712
0b09238d 1713 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
0d59a51c 1714 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>L2 address</th>";
0b09238d 1715 echo "<th class=tdcenter colspan=2>Remote object and port</th><th>Cable ID</th><th class=tdcenter>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
39b4abd0 1716 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
3153a326 1717 printNewItemTR ($prefs);
45ff9012 1718
0b09238d
DO
1719 // clear ports link
1720 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation');
1721
8579b51b
AA
1722 // rename ports link
1723 $n_ports_to_rename = 0;
1724 foreach ($object['ports'] as $port)
1725 if ($port['name'] != shortenPortName ($port['name'], $object['id']))
1726 $n_ports_to_rename++;
1727 if ($n_ports_to_rename)
bd2dcd32 1728 echo '<p>' . getOpLink (array ('op'=>'renameAll'), "Auto-rename $n_ports_to_rename port(s)", 'recalc', 'Use RackTables naming convention for this device type') . '</p>';
8579b51b 1729
00276508
AA
1730 if (isset ($_REQUEST['hl_port_id']))
1731 {
3db0d8ce 1732 genericAssertion ('hl_port_id', 'natural');
00276508 1733 $hl_port_id = intval ($_REQUEST['hl_port_id']);
65e557dd 1734 addAutoScrollScript ("port-$hl_port_id");
00276508 1735 }
d10401bf 1736 switchportInfoJS ($object_id); // load JS code to make portnames interactive
9f75e165 1737 foreach ($object['ports'] as $port)
e673ee24 1738 {
acb01e71 1739 // highlight port name with yellow if its name is not canonical
8579b51b
AA
1740 $canon_pn = shortenPortName ($port['name'], $port['object_id']);
1741 $name_class = $canon_pn == $port['name'] ? '' : 'trwarning';
1742
5c717ce5 1743 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : '';
7056988c 1744 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
d0d40671 1745 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
e673ee24
DO
1746 printImageHREF ('delete', 'Unlink and Delete this port');
1747 echo "</a></td>\n";
65e557dd 1748 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
7b30e187 1749 echo "<td class='tdleft $name_class' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=16></td>";
cd3775e9 1750 echo "<td><input type=text name=label value='${port['label']}'></td>";
70c0cb08 1751 echo '<td class=tdleft>';
8e021b86
AA
1752 if ($port['iif_id'] != 1)
1753 echo '<label>' . $port['iif_name'] . ' ';
4f968fa8 1754 $port_type_opts = array();
78b59ab3 1755 if (! $port['linked'])
759b21d2 1756 $port_type_opts = getUnlinkedPortTypeOptions ($port['iif_id']);
78b59ab3 1757 else
4f968fa8
AA
1758 foreach (getExistingPortTypeOptions ($port) as $oif_id => $opt_str)
1759 $port_type_opts[$port['iif_name']][$port['iif_id'] . '-' . $oif_id] = $opt_str;
4f968fa8 1760 printNiftySelect ($port_type_opts, array ('name' => 'port_type_id'), $port['iif_id'] . '-' . $port['oif_id']);
8e021b86
AA
1761 if ($port['iif_id'] != 1)
1762 echo '</label>';
1763 echo '</td>';
1764
97792a8a
DO
1765 // 17 is the full notation length of a MAC address, 23 -- of a WWN address and 59 -- of an IPoIB address.
1766 echo "<td><input type=text name=l2address value='${port['l2address']}' size=17 maxlength=59></td>\n";
0b09238d 1767 if ($port['remote_object_id'])
90bf1755 1768 {
f4d00faf
DO
1769 $dname = formatObjectDisplayedName ($port['remote_object_name'], $port['remote_object_tid']);
1770 echo "<td class=tdleft>" .
1771 formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $dname, $port['remote_id'], NULL)) .
0b09238d 1772 "</td>";
f4d00faf 1773 echo "<td class=tdleft> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') .
0b09238d
DO
1774 "<input type=hidden name=reservation_comment value=''></td>";
1775 echo "<td><input type=text name=cable value='${port['cableid']}'></td>";
1776 echo "<td class=tdcenter>";
1777 echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port');
1778 echo "</td>";
e673ee24 1779 }
33973968 1780 elseif ($port['reservation_comment'] != '')
e673ee24 1781 {
0b09238d 1782 echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
e673ee24 1783 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
318c48a8 1784 echo "<td></td>";
10f5133a
AA
1785 echo "<td class=tdcenter>";
1786 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1787 echo "</td>";
e673ee24
DO
1788 }
1789 else
1790 {
6b1ca530 1791 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
de55c069
AA
1792 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter>";
1793 echo getPopupLink ('portlist', array ('port' => $port['id'], 'in_rack' => ($in_rack == "yes" ? "on" : "")), 'findlink', 'plug', '', 'Link this port');
0b09238d 1794 echo " <input type=text name=reservation_comment></td>\n";
90bf1755 1795 }
0b09238d
DO
1796 echo "<td>";
1797 printImageHREF ('save', 'Save changes', TRUE);
1798 echo "</td></form></tr>\n";
e673ee24 1799 }
39b4abd0 1800 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
3153a326 1801 printNewItemTR ($prefs);
e673ee24 1802 echo "</table><br>\n";
70c0cb08
DO
1803 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar ('ENABLE_BULKPORT_FORM') == 'yes')
1804 printBulkForm ($prefs);
e673ee24 1805 finishPortlet();
70c0cb08
DO
1806
1807 if (getConfigVar ('ENABLE_MULTIPORT_FORM') == 'yes' && permitted (NULL, NULL, 'addMultiPorts'))
1808 {
1809 startPortlet ('Add/update multiple ports');
1810 printOpFormIntro ('addMultiPorts');
1811 $formats = array
1812 (
1813 'ssv1' => 'SSV:<interface name> [<MAC address>]',
1814 );
1815 echo 'Format: ' . getSelect ($formats, array ('name' => 'format'), 'ssv1') . ' ';
1816 echo 'Default port type: ';
1817 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type'), $prefs['selected']);
1818 echo "<input type=submit value='Parse output'><br>\n";
1819 echo "<textarea name=input cols=100 rows=50></textarea><br>\n";
1820 echo '</form>';
1821 finishPortlet();
1822 }
e673ee24
DO
1823}
1824
d10401bf 1825function renderIPForObject ($object_id)
e673ee24 1826{
15e27821 1827 function printNewItemTR ($default_type, $object_id)
21ee3351
AA
1828 {
1829 global $aat;
15e27821 1830
1831 includeJQueryUI (TRUE);
1832
a6e090f0
DO
1833 // Heredoc, not nowdoc!
1834 addJS (<<<"JSEND"
15e27821 1835 $(document).ready( function() {
1836 $('[name="bond_name"]').autocomplete({
1837 source: "?module=ajax&ac=autocomplete&realm=bond_name&object_id=$object_id",
1838 //minLength: 3,
1839 focus: function(event, ui) {
1840 if( ui.item.value == '' )
1841 event.preventDefault();
1842 },
1843 select: function(event, ui) {
1844 if( ui.item.value == '' )
1845 event.preventDefault();
1846 }
1847 });
1848 });
1849JSEND
1850 , TRUE);
4318ced5
AA
1851 printOpFormIntro ('add');
1852 echo "<tr><td>"; // left btn
dec748f6 1853 printImageHREF ('add', 'allocate', TRUE);
21ee3351 1854 echo "</td>";
04c61e7e
AB
1855 echo "<td class=tdleft><input type='text' size='10' name='bond_name'></td>\n"; // if-name
1856 echo "<td class=tdleft><input type=text name='ip'></td>\n"; // IP
4318ced5
AA
1857 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1858 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1859 echo '<td>';
04c61e7e 1860 printSelect ($aat, array ('name' => 'bond_type'), $default_type); // type
4318ced5 1861 echo "</td><td>&nbsp;</td><td>"; // misc
04c61e7e 1862 printImageHREF ('add', 'allocate', TRUE); // right btn
21ee3351
AA
1863 echo "</td></tr></form>";
1864 }
21ee3351 1865 global $aat;
0d5ef6f0 1866
21ee3351 1867 startPortlet ('Allocations');
4318ced5
AA
1868 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1869 echo '<th>&nbsp;</th>';
1870 echo '<th>OS interface</th>';
1871 echo '<th>IP address</th>';
21ee3351 1872 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
4318ced5
AA
1873 {
1874 echo '<th>network</th>';
1875 echo '<th>routed by</th>';
1876 }
1877 echo '<th>type</th>';
1878 echo '<th>misc</th>';
b1b07891 1879 echo '<th>&nbsp;</th>';
4318ced5 1880 echo '</tr>';
21ee3351 1881
710ead7e
AA
1882 $alloc_list = ''; // most of the output is stored here
1883 $used_alloc_types = array();
e9446e3b 1884 $ext_ipv4_view = getConfigVar ('EXT_IPV4_VIEW');
4318ced5 1885 foreach (getObjectIPAllocations ($object_id) as $alloc)
21ee3351 1886 {
710ead7e
AA
1887 if (! isset ($used_alloc_types[$alloc['type']]))
1888 $used_alloc_types[$alloc['type']] = 0;
1889 $used_alloc_types[$alloc['type']]++;
1890
40c9fc94 1891 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
4318ced5 1892 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
710ead7e 1893 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
f3505b35 1894
10f5133a 1895 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
40c9fc94 1896 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
710ead7e 1897 $alloc_list .= $rendered_alloc['td_ip'];
e9446e3b 1898 if ($ext_ipv4_view == 'yes')
21ee3351 1899 {
710ead7e
AA
1900 $alloc_list .= $rendered_alloc['td_network'];
1901 $alloc_list .= $rendered_alloc['td_routed_by'];
21ee3351 1902 }
710ead7e
AA
1903 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1904 $alloc_list .= $rendered_alloc['td_peers'];
1905 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
f3505b35 1906
710ead7e 1907 $alloc_list .= "</form></tr>\n";
21ee3351 1908 }
710ead7e 1909 asort ($used_alloc_types, SORT_NUMERIC);
589c027b 1910 $most_popular_type = ! count ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
710ead7e
AA
1911
1912 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1913 echo $alloc_list;
15e27821 1914 printNewItemTR ($most_popular_type, $object_id);
710ead7e
AA
1915 if (! $list_on_top)
1916 echo $alloc_list;
21ee3351
AA
1917
1918 echo "</table><br>\n";
1919 finishPortlet();
f3505b35
AA
1920}
1921
08408472
AA
1922// This function is deprecated. Do not rely on its internals,
1923// it will probably be removed in the next major relese.
1924// Use new showError, showWarning, showSuccess functions.
dec748f6 1925// Log array is stored in global $log_messages. Its format is simple: plain ordered array
8ab645cf 1926// with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1cb6adf5 1927function showMessageOrError ()
e673ee24 1928{
a2b16202
AA
1929 global $log_messages;
1930
0a00b344 1931 startSession();
a2b16202
AA
1932 if (isset ($_SESSION['log']))
1933 {
1934 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1935 unset ($_SESSION['log']);
1936 }
1937 session_commit();
1938
1939 if (empty ($log_messages))
1cb6adf5 1940 return;
8ab645cf
AA
1941 $msginfo = array
1942 (
dec748f6 1943// records 0~99 with success messages
8ab645cf
AA
1944 0 => array ('code' => 'success', 'format' => '%s'),
1945 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1946 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1947 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1948 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
493e13dd 1949 10 => array ('code' => 'success', 'format' => 'Added %u port(s), updated %u port(s), encountered %u error(s).'),
8ab645cf 1950 21 => array ('code' => 'success', 'format' => 'Generation complete'),
493e13dd
DO
1951 26 => array ('code' => 'success', 'format' => 'updated %u record(s) successfully'),
1952 37 => array ('code' => 'success', 'format' => 'added %u record(s) successfully'),
1953 38 => array ('code' => 'success', 'format' => 'removed %u record(s) successfully'),
8ab645cf 1954 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
493e13dd 1955 44 => array ('code' => 'success', 'format' => '%s failure(s) and %s successfull change(s).'),
8ab645cf
AA
1956 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1957 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1958 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1959 57 => array ('code' => 'success', 'format' => 'Reset complete'),
04eee8d2 1960 58 => array ('code' => 'success', 'format' => '%u device(s) unmounted successfully'),
8ab645cf 1961 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
493e13dd 1962 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u object(s) involved"),
8ab645cf
AA
1963 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1964 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
493e13dd
DO
1965 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u port(s) created, %u failed"),
1966 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d port(s) changed on %d switch(es)'),
8628ae44 1967// records 100~199 with fatal error messages
8ab645cf
AA
1968 100 => array ('code' => 'error', 'format' => '%s'),
1969 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
8ab645cf 1970 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
493e13dd 1971 141 => array ('code' => 'error', 'format' => 'Encountered %u error(s), updated %u record(s)'),
8ab645cf
AA
1972 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1973 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1974 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1975 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1976 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1977 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1978 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
8ab645cf
AA
1979 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1980 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1981 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
8ab645cf 1982 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
f0ff4930 1983
8628ae44 1984// records 200~299 with warnings
8ab645cf
AA
1985 200 => array ('code' => 'warning', 'format' => '%s'),
1986 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
e1add254 1987 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
7587edca 1988 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
57777e4a 1989
24d3182a 1990// records 300~399 with notices
8ab645cf 1991 300 => array ('code' => 'neutral', 'format' => '%s'),
24d3182a 1992
8ab645cf
AA
1993 );
1994 // Handle the arguments. Is there any better way to do it?
a2b16202 1995 foreach ($log_messages as $record)
8ab645cf 1996 {
55eefced 1997 if (! isset ($record['c']) || ! isset ($msginfo[$record['c']]))
8ab645cf 1998 {
41152018
AA
1999 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
2000 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
8ab645cf
AA
2001 continue;
2002 }
2003 if (isset ($record['a']))
2004 switch (count ($record['a']))
baf37d01 2005 {
8ab645cf
AA
2006 case 1:
2007 $msgtext = sprintf
2008 (
2009 $msginfo[$record['c']]['format'],
2010 $record['a'][0]
2011 );
2012 break;
2013 case 2:
2014 $msgtext = sprintf
2015 (
2016 $msginfo[$record['c']]['format'],
2017 $record['a'][0],
2018 $record['a'][1]
2019 );
2020 break;
2021 case 3:
2022 $msgtext = sprintf
2023 (
2024 $msginfo[$record['c']]['format'],
2025 $record['a'][0],
2026 $record['a'][1],
2027 $record['a'][2]
2028 );
2029 break;
2030 case 4:
2031 default:
2032 $msgtext = sprintf
2033 (
2034 $msginfo[$record['c']]['format'],
2035 $record['a'][0],
2036 $record['a'][1],
2037 $record['a'][2],
2038 $record['a'][3]
2039 );
2040 break;
baf37d01 2041 }
8ab645cf
AA
2042 else
2043 $msgtext = $msginfo[$record['c']]['format'];
2044 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
baf37d01 2045 }
a2b16202 2046 $log_messages = array();
e673ee24
DO
2047}
2048
65e557dd 2049// renders two tables: port link status and learned MAC list
d10401bf 2050function renderPortsInfo($object_id)
65e557dd 2051{
2d33a804 2052 $breed = detectDeviceBreed ($object_id);
03522bd8
AA
2053 try
2054 {
2055 if (permitted (NULL, NULL, 'get_link_status'))
2d33a804 2056 {
2057 if (validBreedFunction ($breed, 'getportstatus'))
2058 $linkStatus = queryDevice ($object_id, 'getportstatus');
2059 }
03522bd8
AA
2060 else
2061 showWarning ("You don't have permission to view ports link status");
2062
2063 if (permitted (NULL, NULL, 'get_mac_list'))
2d33a804 2064 {
2065 if (validBreedFunction ($breed, 'getmaclist'))
2066 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
2067 }
03522bd8
AA
2068 else
2069 showWarning ("You don't have permission to view learned MAC list");
2070 }
2071 catch (RTGatewayError $e)
2072 {
2073 showError ($e->getMessage());
2074 return;
2075 }
2076
65e557dd
AA
2077 global $nextorder;
2078 echo "<table width='100%'><tr>";
03522bd8 2079 if (! empty ($linkStatus))
65e557dd 2080 {
03522bd8
AA
2081 echo "<td valign='top' width='50%'>";
2082 startPortlet('Link status');
c51492f5
DO
2083 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'>";
2084 echo '<tr><th>Port</th><th>&nbsp;</th><th>Link status</th><th>Link info</th></tr>';
72c3bebc
DO
2085 $statusmap = array
2086 (
2087 'up' => 'link up',
2088 'down' => 'link down',
2089 'disabled' => 'link disabled',
2090 );
03522bd8
AA
2091 $order = 'even';
2092 foreach ($linkStatus as $pn => $link)
65e557dd 2093 {
03522bd8
AA
2094 echo "<tr class='row_$order'>";
2095 $order = $nextorder[$order];
c51492f5
DO
2096 echo '<td>' . $pn . '</td>';
2097 echo '<td>' . getImageHREF (array_fetch ($statusmap, $link['status'], '16x16t')) . '</td>';
2098 echo '<td>' . $link['status'] . '</td>';
03522bd8
AA
2099 $info = '';
2100 if (isset ($link['speed']))
2101 $info .= $link['speed'];
2102 if (isset ($link['duplex']))
2103 {
cfb42424 2104 if ($info != '')
03522bd8
AA
2105 $info .= ', ';
2106 $info .= $link['duplex'];
65e557dd 2107 }
c51492f5 2108 echo '<td>' . $info . '</td>';
03522bd8 2109 echo '</tr>';
65e557dd 2110 }
03522bd8
AA
2111 echo "</table></td>";
2112 finishPortlet();
65e557dd
AA
2113 }
2114
65e557dd
AA
2115 if (! empty ($macList))
2116 {
2117 echo "<td valign='top' width='50%'>";
2118 $rendered_macs = '';
2119 $mac_count = 0;
c51492f5
DO
2120 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'>";
2121 $rendered_macs .= '<tr><th>MAC address</th><th>VLAN</th><th>Port</th></tr>';
65e557dd
AA
2122 $order = 'even';
2123 foreach ($macList as $pn => $list)
2124 {
2125 $order = $nextorder[$order];
2126 foreach ($list as $item)
2127 {
2128 ++$mac_count;
2129 $rendered_macs .= "<tr class='row_$order'>";
c51492f5
DO
2130 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'] . '</td>';
2131 $rendered_macs .= '<td>' . $item['vid'] . '</td>';
2132 $rendered_macs .= '<td>' . $pn . '</td>';
65e557dd
AA
2133 $rendered_macs .= '</tr>';
2134 }
2135 }
2136 $rendered_macs .= "</table></td>";
dec748f6 2137
65e557dd
AA
2138 startPortlet("Learned MACs ($mac_count)");
2139 echo $rendered_macs;
2140 finishPortlet();
2141 }
2142
2143 echo "</td></tr></table>";
2144}
2145
e713bb4d
DO
2146function addBulkSelectorJS ($element_id)
2147{
2148 // Heredoc, not nowdoc!
2149 addJS (<<<"ENDOFJAVASCRIPT"
2150$(function () {
2151 $("#{$element_id} tbody").selectable({
2152 filter: 'td.atom',
acbc5658 2153 cancel: 'th,a',
e713bb4d
DO
2154 stop: function () {
2155 $(".ui-selected input:enabled", this).each(function () {
2156 this.checked = !this.checked
2157 });
2158 }
2159 });
2160});
2161ENDOFJAVASCRIPT
2162, TRUE);
2163}
2164
d18eac58
DO
2165// An object can be mounted onto free atoms only, that is, if any record for an atom
2166// already exists in RackSpace, it cannot be used for mounting.
d10401bf 2167function renderRackSpaceForObject ($object_id)
e673ee24 2168{
e673ee24
DO
2169 // Always process occupied racks plus racks chosen by user. First get racks with
2170 // already allocated rackspace...
950d4117
DO
2171 $workingRacksData = array();
2172 foreach (getResidentRackIDs ($object_id) as $rack_id)
2173 {
2174 $rackData = spotEntity ('rack', $rack_id);
2175 amplifyCell ($rackData);
2176 $workingRacksData[$rack_id] = $rackData;
2177 }
e673ee24 2178 // ...and then add those chosen by user (if any).
2135fd83 2179 if (isset($_REQUEST['rackmulti']))
e673ee24 2180 foreach ($_REQUEST['rackmulti'] as $cand_id)
e673ee24
DO
2181 if (!isset ($workingRacksData[$cand_id]))
2182 {
0cc24e9a 2183 $rackData = spotEntity ('rack', $cand_id);
61a1d996 2184 amplifyCell ($rackData);
e673ee24
DO
2185 $workingRacksData[$cand_id] = $rackData;
2186 }
51690ad4 2187
c17a36f0
AA
2188 // Get a list of rack ids that are parents of this object.
2189 $object = spotEntity ('object', $object_id);
2190 $parentRacks = reduceSubarraysToColumn (getParents ($object, 'rack'), 'id');
0a7feebb 2191
e673ee24
DO
2192 // Main layout starts.
2193 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
2194
2195 // Left portlet with rack list.
2196 echo "<td class=pcleft height='1%'>";
2197 startPortlet ('Racks');
a8efc03e 2198 $allRacksData = listCells ('rack');
6d42599c
AA
2199
2200 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
55eefced 2201 if (! isset ($_REQUEST['show_all_racks']) && getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
6d42599c
AA
2202 {
2203 $matching_racks = array();
6d42599c
AA
2204 $matched_tags = array();
2205 foreach ($allRacksData as $rack)
01205bb6 2206 {
b51c1007 2207 $tag_chain = array_merge ($rack['etags'], $rack['itags']);
6d42599c 2208 foreach ($object['etags'] as $tag)
01205bb6 2209 if (tagOnChain ($tag, $tag_chain))
6d42599c
AA
2210 {
2211 $matching_racks[$rack['id']] = $rack;
2212 $matched_tags[$tag['id']] = $tag;
2213 break;
2214 }
01205bb6 2215 }
6d42599c
AA
2216 // add current object's racks even if they dont match filter
2217 foreach ($workingRacksData as $rack_id => $rack)
2218 if (! isset ($matching_racks[$rack_id]))
2219 $matching_racks[$rack_id] = $rack;
2220 // if matching racks found, and rack list is reduced, show 'show all' link
55eefced 2221 if (count ($matching_racks) && count ($matching_racks) != count ($allRacksData))
6d42599c 2222 {
1e9266ad 2223 $tmp = array();
6d42599c 2224 foreach ($matched_tags as $tag)
1e9266ad
DO
2225 $tmp[] = '{' . $tag['tag'] . '}';
2226 $filter_text = implode (' or ', $tmp);
6d42599c
AA
2227 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2228 $href_show_all .= htmlspecialchars('&show_all_racks=1');
2229 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
2230 $allRacksData = $matching_racks;
2231 }
2232 }
2233
4b8d413e 2234 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
61a1d996 2235 foreach ($allRacksData as $rack)
51c18782
DO
2236 if (!array_key_exists ($rack['id'], $workingRacksData))
2237 {
2238 amplifyCell ($rack);
2239 $workingRacksData[$rack['id']] = $rack;
2240 }
2241 foreach (array_keys ($workingRacksData) as $rackId)
2242 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
2243 printOpFormIntro ('updateObjectAllocation');
4b8d413e 2244 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
51c18782 2245 echo "<br><br>";
e673ee24
DO
2246 finishPortlet();
2247 echo "</td>";
2248
2249 // Middle portlet with comment and submit.
2250 echo "<td class=pcleft>";
5c8bf2ba 2251 startPortlet ('Comment (for Rackspace History)');
652fc0ef 2252 echo '<textarea name=comment rows=10 cols=40></textarea><br><br>';
e673ee24 2253 echo "<input type=submit value='Save' name=got_atoms>\n";
51c18782 2254 echo "<br><br>";
e673ee24
DO
2255 finishPortlet();
2256 echo "</td>";
2257
d18eac58
DO
2258 // Right portlet with rendered racks. If this form submit is not final,
2259 // the former state of the grid needs to make it to the current form.
e673ee24
DO
2260 echo "<td class=pcright rowspan=2 height='1%'>";
2261 startPortlet ('Working copy');
e8b94513 2262 includeJQueryUI (false);
65e557dd 2263 addJS ('js/racktables.js');
e673ee24
DO
2264 echo '<table border=0 cellspacing=10 align=center><tr>';
2265 foreach ($workingRacksData as $rack_id => $rackData)
2266 {
e713bb4d
DO
2267 $table_id = "selectableRack_{$rack_id}";
2268 addBulkSelectorJS ($table_id);
c26d97b6 2269 $is_ro = !rackModificationPermitted ($rackData, 'updateObjectAllocation');
e673ee24
DO
2270 // Order is important here: only original allocation is highlighted.
2271 highlightObject ($rackData, $object_id);
2272 markupAtomGrid ($rackData, 'T');
d18eac58 2273 // If an HTTP form has been processed, discard user input and show new database
e673ee24 2274 // contents.
c26d97b6 2275 if (!$is_ro && isset ($_REQUEST['rackmulti'][0])) // is an update
e673ee24 2276 mergeGridFormToRack ($rackData);
652fc0ef
DO
2277 echo '<td valign=bottom>';
2278 echo '<center><h2 style="margin:0px">';
2279 echo mkA ($rackData['row_name'], 'row', $rackData['row_id']);
2280 echo ' : ';
2281 echo mkA ($rackData['name'], 'rack', $rackData['id']);
2282 echo '</h2>';
c26d97b6
VS
2283 $read_only_text = $is_ro ? '(read-only)' : '&nbsp;';
2284 echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n";
e713bb4d 2285 echo "<table class=rack id={$table_id} border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 2286 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2287 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2288 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2289 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
c26d97b6 2290 renderAtomGrid ($rackData, $is_ro);
57c69e9c 2291 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2292 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2293 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2294 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
0a7feebb
AD
2295 echo "</table>\n<br>\n";
2296 // Determine zero-u checkbox status.
2297 // If form has been submitted, use form data, otherwise use DB data.
c26d97b6 2298 if (!$is_ro && isset($_REQUEST['op']))
0a7feebb
AD
2299 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
2300 else
2301 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
c26d97b6 2302 $disabled_text = $is_ro ? ' disabled' : '';
51728b4d 2303 echo "<label>Zero-U: <input type=checkbox ${checked} name=zerou_${rack_id}${disabled_text}></label>\n<br><br>\n";
e8c8c99c 2304 echo "<input type='button' onclick='uncheckAllAtoms({$rack_id}, {$rackData['height']});' value='Uncheck all'>\n";
0a7feebb 2305 echo '</center></td>';
e673ee24
DO
2306 }
2307 echo "</tr></table>";
2308 finishPortlet();
2309 echo "</td>\n";
2310
2311 echo "</form>\n";
2312 echo "</tr></table>\n";
2313}
2314
2315function renderMolecule ($mdata, $object_id)
2316{
2317 // sort data out
2318 $rackpack = array();
2319 global $loclist;
64b95774 2320 foreach ($mdata as $rua)
e673ee24
DO
2321 {
2322 $rack_id = $rua['rack_id'];
2323 $unit_no = $rua['unit_no'];
2324 $atom = $rua['atom'];
2325 if (!isset ($rackpack[$rack_id]))
2326 {
61a1d996
DO
2327 $rackData = spotEntity ('rack', $rack_id);
2328 amplifyCell ($rackData);
e673ee24
DO
2329 for ($i = $rackData['height']; $i > 0; $i--)
2330 for ($locidx = 0; $locidx < 3; $locidx++)
2331 $rackData[$i][$locidx]['state'] = 'F';
2332 $rackpack[$rack_id] = $rackData;
2333 }
2334 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2335 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2336 }
d18eac58 2337 // Now there are some racks to render.
64b95774 2338 foreach ($rackpack as $rackData)
e673ee24 2339 {
e673ee24
DO
2340 echo "<table class=molecule cellspacing=0>\n";
2341 echo "<caption>${rackData['name']}</caption>\n";
2342 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
136449ff 2343 $reverse = considerConfiguredConstraint ($rackData, 'REVERSED_RACKS_LISTSRC');
e673ee24
DO
2344 for ($i = $rackData['height']; $i > 0; $i--)
2345 {
136449ff 2346 echo '<tr><th>' . inverseRackUnit ($rackData['height'], $i, $reverse) . '</th>';
e673ee24
DO
2347 for ($locidx = 0; $locidx < 3; $locidx++)
2348 {
2349 $state = $rackData[$i][$locidx]['state'];
65e557dd 2350 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
e673ee24
DO
2351 }
2352 echo "</tr>\n";
2353 }
2354 echo "</table>\n";
2355 }
2356}
2357
23cdc7e9 2358function renderDepot ()
e673ee24 2359{
23cdc7e9 2360 global $pageno, $nextorder;
23cdc7e9 2361 $cellfilter = getCellFilter();
950dfa1f
AA
2362 $objects = array();
2363 $objects_count = getEntitiesCount ('object');
db8255ac 2364 $showobjecttype = (getConfigVar ('SHOW_OBJECTTYPE') == 'yes');
23cdc7e9
DO
2365
2366 echo "<table border=0 class=objectview>\n";
2367 echo "<tr><td class=pcleft>";
2368
950dfa1f
AA
2369 if ($objects_count == 0)
2370 echo '<h2>No objects exist</h2>';
2371 // 1st attempt: do not fetch all objects if cellfilter is empty and rendering empty result is enabled
2372 elseif (! ($cellfilter['is_empty'] && renderEmptyResults ($cellfilter, 'objects', $objects_count)))
e673ee24 2373 {
2b16c179 2374 $objects = applyCellFilter ('object', $cellfilter);
20506de3 2375 // 2nd attempt: do not render all fetched objects if rendering empty result is enabled
950dfa1f 2376 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
1ebbf889 2377 {
4899096d
AD
2378 startPortlet ('Objects (' . count ($objects) . ')');
2379 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
db8255ac
J
2380 echo '<tr><th>Common name</th>';
2381 if ($showobjecttype)
2382 echo '<th>Type</th>';
2383 echo '<th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
4899096d 2384 $order = 'odd';
3f8a25d6
DO
2385 # gather IDs of all objects and fetch rackspace info in one pass
2386 $idlist = array();
2387 foreach ($objects as $obj)
2388 $idlist[] = $obj['id'];
2389 $mountinfo = getMountInfo ($idlist);
cae81598 2390 $containerinfo = getContainerInfo ($idlist);
4899096d
AD
2391 foreach ($objects as $obj)
2392 {
ec788aba 2393 $problem = ($obj['has_problems'] == 'yes') ? 'has_problems' : '';
25526a97
ME
2394
2395 setEntityColors ($obj);
72b539be 2396 $class = getObjectClass ($obj, 'list_plain');
25526a97
ME
2397
2398 echo "<tr class='row_${order} tdleft ${problem}${class}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
4899096d
AD
2399 if (count ($obj['etags']))
2400 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
db8255ac
J
2401 echo '</td>';
2402 if ($showobjecttype)
9563f56f 2403 echo "<td>" . decodeObjectType ($obj['objtype_id']) . "</td>";
8526b4cc 2404 echo "<td>${obj['label']}</td>";
4318ced5 2405 echo "<td>${obj['asset_no']}</td>";
3f8a25d6 2406 $places = array();
cae81598
AD
2407 if (array_key_exists ($obj['id'], $containerinfo))
2408 foreach ($containerinfo[$obj['id']] as $ci)
20506de3 2409 $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']);
cae81598 2410 if (array_key_exists ($obj['id'], $mountinfo))
3f8a25d6
DO
2411 foreach ($mountinfo[$obj['id']] as $mi)
2412 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
cae81598
AD
2413 if (! count ($places))
2414 $places[] = 'Unmounted';
4318ced5 2415 echo "<td>" . implode (', ', $places) . '</td>';
4899096d
AD
2416 echo '</tr>';
2417 $order = $nextorder[$order];
2418 }
2419 echo '</table>';
2420 finishPortlet();
1ebbf889 2421 }
e673ee24 2422 }
23cdc7e9 2423
d4e27fe5 2424 echo "</td><td class='pcright ${pageno}' width='25%'>";
23cdc7e9 2425
95857b5c 2426 renderCellFilterPortlet ($cellfilter, 'object', $objects);
23cdc7e9 2427 echo "</td></tr></table>\n";
e673ee24
DO
2428}
2429
1ebbf889
AA
2430// This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2431// In this case it renders the describing message instead.
2432function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2433{
2434 if (!$cellfilter['is_empty'])
2435 return FALSE;
2436 if (isset ($_REQUEST['show_all_objects']))
2437 return FALSE;
7c91a821 2438 $max = getConfigVar('MAX_UNFILTERED_ENTITIES');
1ebbf889
AA
2439 if (0 == $max || $count <= $max)
2440 return FALSE;
2441
2442 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2443 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2444 $suffix = isset ($count) ? " ($count)" : '';
a6e090f0
DO
2445 // Heredoc, not nowdoc!
2446 echo <<<"END"
1ebbf889
AA
2447<p>Please set a filter to display the corresponging $entities_name.
2448<br><a href="$href_show_all">Show all $entities_name$suffix</a>
2449END;
2450 return TRUE;
2451}
2452
e673ee24 2453// History viewer for history-enabled simple dictionaries.
9b8174d7 2454function renderObjectHistory ($object_id)
e673ee24 2455{
e673ee24
DO
2456 $order = 'odd';
2457 global $nextorder;
9b8174d7
AD
2458 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2459 echo '<tr><th>change time</th><th>author</th><th>name</th><th>visible label</th><th>asset no</th><th>has problems?</th><th>comment</th></tr>';
2460 $result = usePreparedSelectBlade
2461 (
2462 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2463 array ($object_id)
2464 );
e673ee24
DO
2465 while ($row = $result->fetch (PDO::FETCH_NUM))
2466 {
2467 echo "<tr class=row_${order}><td>${row[0]}</td>";
9b8174d7 2468 for ($i = 1; $i <= 6; $i++)
e673ee24
DO
2469 echo "<td>" . $row[$i] . "</td>";
2470 echo "</tr>\n";
2471 $order = $nextorder[$order];
2472 }
2473 echo "</table><br>\n";
2474}
2475
2476function renderRackspaceHistory ()
2477{
4fbb5a00 2478 global $nextorder, $pageno, $tabno;
e673ee24
DO
2479 $order = 'odd';
2480 $history = getRackspaceHistory();
2481 // Show the last operation by default.
2482 if (isset ($_REQUEST['op_id']))
2483 $op_id = $_REQUEST['op_id'];
2484 elseif (isset ($history[0]['mo_id']))
2485 $op_id = $history[0]['mo_id'];
2486 else $op_id = NULL;
dec748f6 2487
e673ee24
DO
2488 $omid = NULL;
2489 $nmid = NULL;
2490 $object_id = 1;
2491 if ($op_id)
2492 list ($omid, $nmid) = getOperationMolecules ($op_id);
2493
2494 // Main layout starts.
2495 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2496
2497 // Left top portlet with old allocation.
2498 echo "<tr><td class=pcleft>";
2499 startPortlet ('Old allocation');
2500 if ($omid)
2501 {
2502 $oldMolecule = getMolecule ($omid);
2503 renderMolecule ($oldMolecule, $object_id);
2504 }
2505 else
2506 echo "nothing";
2507 finishPortlet();
2508
2509 echo '</td><td class=pcright>';
2510
2511 // Right top portlet with new allocation
2512 startPortlet ('New allocation');
2513 if ($nmid)
2514 {
2515 $newMolecule = getMolecule ($nmid);
2516 renderMolecule ($newMolecule, $object_id);
2517 }
2518 else
2519 echo "nothing";
2520 finishPortlet();
737a3f72 2521
e673ee24 2522 echo '</td></tr><tr><td colspan=2>';
737a3f72 2523
e673ee24
DO
2524 // Bottom portlet with list
2525
2526 startPortlet ('Rackspace allocation history');
2527 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
7fa7047a 2528 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
e673ee24
DO
2529 foreach ($history as $row)
2530 {
2531 if ($row['mo_id'] == $op_id)
2532 $class = 'hl';
2533 else
2534 $class = "row_${order}";
4fbb5a00 2535 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
7fa7047a
DO
2536 echo "<td>${row['user_name']}</td><td>";
2537 renderCell (spotEntity ('object', $row['ro_id']));
a0bdf6dc 2538 echo '</td><td>' . stringForTD ($row['comment'], 0) . '</td></tr>';
e673ee24
DO
2539 $order = $nextorder[$order];
2540 }
2541 echo "</table>\n";
2542 finishPortlet();
737a3f72 2543
e673ee24 2544 echo '</td></tr></table>';
e673ee24
DO
2545}
2546
4318ced5 2547function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
d65353ad
DO
2548{
2549 $self = __FUNCTION__;
4318ced5 2550 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
774968ea 2551 $display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none');
00276508
AA
2552
2553 // scroll page to the highlighted item
2554 if ($target && isset ($_REQUEST['hl_net']))
65e557dd 2555 addAutoScrollScript ("net-$target");
00276508 2556
d65353ad
DO
2557 foreach ($tree as $item)
2558 {
0137d53c
DO
2559 if (isset ($item['id']))
2560 {
1f54e1ba 2561 $decor = array ('indent' => $level);
fec0c8da 2562 if ($item['symbol'] == 'node-collapsed')
4318ced5 2563 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
fec0c8da 2564 elseif ($item['symbol'] == 'node-expanded')
4318ced5 2565 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
25526a97
ME
2566
2567 setEntityColors ($item);
72b539be
DO
2568 $class_context = ($target == $item['id'] && isset ($_REQUEST['hl_net'])) ? 'list_selected' : 'list_plain';
2569 $tr_class = getObjectClass ($item, $class_context);
2570 // Use old-style highlighting for colourless networks.
2571 if ($class_context == 'list_selected' && $tr_class == '')
2572 {
2573 $decor['tdclass'] = ' highlight';
2574 $tr_class = $decor['tdclass'];
2575 }
25526a97 2576
4318ced5
AA
2577 echo "<tr valign=top class=\"$tr_class\">";
2578 printIPNetInfoTDs ($item, $decor);
2579
2580 // capacity and usage
2581 echo "<td class=tdcenter>";
2582 echo getRenderedIPNetCapacity ($item);
64347dcf 2583 echo "</td>";
4318ced5
AA
2584
2585 if ($display_routers)
6063fab7 2586 printRoutersTD (findNetRouters ($item), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
0137d53c 2587 echo "</tr>";
55eefced 2588 if ($item['symbol'] == 'node-expanded' || $item['symbol'] == 'node-expanded-static')
4318ced5 2589 $self ($item['kids'], $baseurl, $target, $level + 1);
0137d53c 2590 }
26fc6e7c 2591 elseif (getConfigVar ('IPV4_TREE_SHOW_UNALLOCATED') == 'yes')
0137d53c 2592 {
4318ced5 2593 // non-allocated (spare) IP range
0137d53c 2594 echo "<tr valign=top>";
21ee3351 2595 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
00276508 2596
4318ced5 2597 // capacity and usage
21ee3351 2598 echo "<td class=tdcenter>";
4318ced5 2599 echo getRenderedIPNetCapacity ($item);
21ee3351 2600 echo "</td>";
4318ced5
AA
2601 if ($display_routers)
2602 echo "<td></td>";
21ee3351 2603 echo "</tr>";
21ee3351 2604 }
21ee3351
AA
2605 }
2606}
2607
4318ced5 2608function renderIPSpace()
e673ee24 2609{
4fbb5a00 2610 global $pageno, $tabno;
4318ced5 2611 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
31c941ec 2612 $cellfilter = getCellFilter();
21ee3351 2613
b99b4167
AA
2614 // expand request can take either natural values or "ALL". Zero means no expanding.
2615 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2616
21ee3351
AA
2617 echo "<table border=0 class=objectview>\n";
2618 echo "<tr><td class=pcleft>";
950dfa1f
AA
2619
2620 $netlist = array();
b99b4167 2621 if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm))))
21ee3351 2622 {
950dfa1f
AA
2623 $top = NULL;
2624 foreach (listCells ($realm) as $net)
21ee3351 2625 {
55eefced 2626 if (isset ($top) && IPNetContains ($top, $net))
950dfa1f 2627 ;
55eefced 2628 elseif (! count ($cellfilter['expression']) || judgeCell ($net, $cellfilter['expression']))
950dfa1f
AA
2629 $top = $net;
2630 else
2631 continue;
2632 $netlist[$net['id']] = $net;
2633 }
2634 $netcount = count ($netlist);
950dfa1f
AA
2635 $tree = prepareIPTree ($netlist, $eid);
2636
2637 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
2638 {
2639 startPortlet ("networks (${netcount})");
2640 echo '<h4>';
2641 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2642 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2643 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2644 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2645 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2646 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2647
2648 if ($eid === 0)
2649 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
2650 elseif ($eid === 'ALL')
2651 echo "expanding all ($auto / $none)";
2652 elseif ($eid === 'NONE')
2653 echo "collapsing all ($all / $auto)";
2654 else
2655 {
a0f0c0c7
AA
2656 try
2657 {
2658 $netinfo = spotEntity ($realm, $eid);
2659 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
2660 }
2661 catch (EntityNotFoundException $e)
2662 {
2663 // ignore invalid eid error
2664 }
950dfa1f 2665 }
6edc799c 2666 echo "</h4><table class='widetable zebra' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
950dfa1f
AA
2667 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2668 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
2669 echo "<th>routed by</th>";
2670 echo "</tr>\n";
2671 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2672 renderIPSpaceRecords ($tree, $baseurl, $eid);
2673 echo "</table>\n";
2674 finishPortlet();
21ee3351 2675 }
21ee3351
AA
2676 }
2677
d4e27fe5 2678 echo "</td><td class='pcright ${pageno}'>";
950dfa1f 2679 renderCellFilterPortlet ($cellfilter, $realm, $netlist);
21ee3351
AA
2680 echo "</td></tr></table>\n";
2681}
2682
4318ced5 2683function renderIPSpaceEditor()
21ee3351 2684{
4318ced5
AA
2685 global $pageno;
2686 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
4318ced5 2687 $addrspaceList = listCells ($realm);
93a49e5b
AA
2688 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2689 if (count ($addrspaceList))
21ee3351 2690 {
21ee3351
AA
2691 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2692 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
21ee3351
AA
2693 foreach ($addrspaceList as $netinfo)
2694 {
21ee3351 2695 echo "<tr valign=top><td>";
93a49e5b 2696 if (! isIPNetworkEmpty ($netinfo))
21ee3351
AA
2697 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2698 else
93a49e5b 2699 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
6d8424f8 2700 echo '</td><td class=tdleft>' . mkCellA ($netinfo) . '</td>';
a0bdf6dc 2701 echo '<td class=tdleft>' . stringForTD ($netinfo['name']);
1f54e1ba
DO
2702 if (count ($netinfo['etags']))
2703 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2704 echo '</td><td>';
4318ced5 2705 echo getRenderedIPNetCapacity ($netinfo);
b1e39212 2706 echo '</tr>';
e673ee24 2707 }
04d619d0
DO
2708 echo "</table>";
2709 finishPortlet();
e673ee24 2710 }
93a49e5b
AA
2711}
2712
2713function renderIPNewNetForm ()
2714{
2715 global $pageno;
2716 if ($pageno == 'ipv6space')
2717 {
2718 $realm = 'ipv6net';
3495ec6e 2719 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
93a49e5b
AA
2720 }
2721 else
2722 {
2723 $realm = 'ipv4net';
3495ec6e 2724 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
93a49e5b
AA
2725 }
2726
2727 // IP prefix validator
10f5133a 2728 addJS ('js/live_validation.js');
93a49e5b 2729 $regexp = addslashes ($regexp);
a6e090f0
DO
2730 // Heredoc, not nowdoc!
2731 addJS (<<<"END"
93a49e5b 2732$(document).ready(function () {
b895e6b4 2733 $('form#add input[name="range"]').attr('match', '$regexp');
93a49e5b
AA
2734 Validate.init();
2735});
2736END
2737 , TRUE);
dec748f6 2738
93a49e5b 2739 startPortlet ('Add new');
10f5133a 2740 printOpFormIntro ('add');
e7b84015
AB
2741 echo '<table border=0 cellpadding=5 cellspacing=0 align=center>';
2742
93a49e5b
AA
2743 // inputs column
2744 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
04c61e7e 2745 echo "<th class=tdright>Prefix:</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' value='${prefix_value}'></td>";
e7b84015 2746 echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>';
04c61e7e
AB
2747 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical')) . '</td></tr>';
2748 echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20'></td></tr>";
e7b84015
AB
2749 echo '<tr><th class=tdright>Tags:</th><td class="tdleft">';
2750 printTagsPicker ();
2751 echo '</td></tr>';
38707670
DO
2752 echo '<tr><td class=tdright><input type=checkbox name="is_connected" id="is_connected"></td>';
2753 echo '<th class=tdleft><label for="is_connected">reserve subnet-router anycast address</label></th></tr>';
93a49e5b 2754 echo "<tr><td colspan=2>";
04c61e7e 2755 printImageHREF ('CREATE', 'Add a new network', TRUE);
93a49e5b 2756 echo '</td></tr>';
e7b84015 2757 echo "</table></form><br><br>\n";
93a49e5b 2758 finishPortlet();
e673ee24
DO
2759}
2760
4318ced5 2761function getRenderedIPNetBacktrace ($range)
e673ee24 2762{
4318ced5
AA
2763 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2764 return array();
e673ee24 2765
4318ced5
AA
2766 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2767 $space = "ipv${v}space"; // ipv4space, ipv6space
2768 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
dec748f6 2769
4318ced5
AA
2770 $ret = array();
2771 // Build a backtrace from all parent networks.
2772 $clen = $range['mask'];
2773 $backtrace = array();
2774 $backtrace['&rarr;'] = $range;
2775 $key = '';
2776 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2777 {
2778 $upperinfo = spotEntity ($range['realm'], $upperid);
2779 $clen = $upperinfo['mask'];
2780 $key .= '&uarr;';
2781 $backtrace[$key] = $upperinfo;
2782 }
2783 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2784 {
2785 $link = '<a href="' . makeHref (array (
2786 'page' => $space,
2787 'tab' => 'default',
2788 'clear-cf' => '',
2789 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2790 'hl_net' => 1,
2791 'eid' => $range['id'],
2792 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2793 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2794 }
2795 return $ret;
2796}
2797
d10401bf 2798function renderIPNetwork ($id)
4318ced5
AA
2799{
2800 global $pageno;
2801 $realm = $pageno; // 'ipv4net', 'ipv6net'
d10401bf 2802 $range = spotEntity ($realm, $id);
4318ced5 2803 loadIPAddrList ($range);
25526a97 2804 setEntityColors ($range);
2034d968 2805 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
99ab184f
DO
2806 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2807 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2034d968
DO
2808
2809 echo "<tr><td class=pcleft width='50%'>";
646272be
AA
2810
2811 // render summary portlet
2812 $summary = array();
967bd0b1 2813 $summary['% used'] = getRenderedIPNetCapacity ($range);
2b6b0038 2814 $summary = getRenderedIPNetBacktrace ($range) + $summary;
4318ced5 2815 if ($realm == 'ipv4net')
001e61fa 2816 {
4318ced5
AA
2817 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2818 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2819 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
001e61fa 2820 }
dec748f6 2821
11e3af31
DO
2822 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2823 $domainclass = array();
2824 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2825 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
a5f9d1ca 2826 foreach ($range['8021q'] as $item)
3f642516 2827 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVlanRow ($item['domain_id'] . '-' . $item['vlan_id'])));
55eefced 2828 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' && count ($routers = findNetRouters ($range)))
04d619d0 2829 {
646272be
AA
2830 $summary['Routed by'] = '';
2831 foreach ($routers as $rtr)
4318ced5 2832 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
04d619d0 2833 }
646272be
AA
2834 $summary['tags'] = '';
2835 renderEntitySummary ($range, 'summary', $summary);
e1ae3fb4 2836
33973968 2837 if ($range['comment'] != '')
99ab184f
DO
2838 {
2839 startPortlet ('Comment');
2840 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2841 finishPortlet ();
2842 }
2843
d10401bf 2844 renderFilesPortlet ($realm, $id);
2034d968 2845 echo "</td>\n";
e673ee24 2846
2034d968
DO
2847 echo "<td class=pcright>";
2848 startPortlet ('details');
4318ced5
AA
2849 renderIPNetworkAddresses ($range);
2850 finishPortlet();
2851 echo "</td></tr></table>\n";
2852}
e673ee24 2853
4318ced5
AA
2854// Used solely by renderSeparator
2855function renderEmptyIPv6 ($ip_bin, $hl_ip)
2856{
2857 $class = 'tdleft';
2858 if ($ip_bin === $hl_ip)
5c717ce5 2859 $class .= ' highlight';
4318ced5 2860 $fmt = ip6_format ($ip_bin);
235124a6 2861 echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
0b8d8309
AA
2862 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2863 ? 'editable'
2864 : '';
cc2fa820
AD
2865 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2866 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
4318ced5
AA
2867}
2868
2869// Renders empty table line to shrink empty IPv6 address ranges.
2870// If the range consists of single address, renders the address instead of empty line.
2871// Renders address $hl_ip inside the range.
2872// Used solely by renderIPv6NetworkAddresses
2873function renderSeparator ($first, $last, $hl_ip)
2874{
2875 $self = __FUNCTION__;
2876 if (strcmp ($first, $last) > 0)
2877 return;
2878 if ($first == $last)
2879 renderEmptyIPv6 ($first, $hl_ip);
2880 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2881 { // $hl_ip is inside the range $first - $last
2882 $self ($first, ip_prev ($hl_ip), $hl_ip);
2883 renderEmptyIPv6 ($hl_ip, $hl_ip);
2884 $self (ip_next ($hl_ip), $last, $hl_ip);
2885 }
2886 else
cc2fa820 2887 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
4318ced5
AA
2888}
2889
75e7c0c6 2890// calculates page number that contains given $ip (used by renderIPv6NetworkAddresses)
4318ced5
AA
2891function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2892{
7c91a821 2893 if ($maxperpage <= 0 || count ($list) <= $maxperpage)
4318ced5
AA
2894 return 0;
2895 $keys = array_keys ($list);
2896 for ($i = 1; $i <= count ($keys); $i++)
2897 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2898 return intval ($i / $maxperpage);
2899 return intval (count ($list) / $maxperpage);
2900}
2901
2902function renderIPNetworkAddresses ($range)
2903{
2904 switch (strlen ($range['ip_bin']))
2905 {
2906 case 4: return renderIPv4NetworkAddresses ($range);
2907 case 16: return renderIPv6NetworkAddresses ($range);
2908 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2909 }
2910}
2911
247acd67
KZ
2912function renderIPv4NetworkPageLink ($rangeid, $page, $title)
2913{
2914 global $pageno, $tabno;
2915 return "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $rangeid, 'pg' => $page)) . "' title='".$title."'>".$page."</a> ";
2916}
2917
2918function renderIPv4NetworkPagination ($range, $page, $numpages)
2919{
2920 $rendered_pager = '';
2921 $startip = ip4_bin2int ($range['ip_bin']);
2922 $endip = ip4_bin2int (ip_last ($range));
2923 $rangeid = $range['id'];
2924 // Should make this configurable perhaps
2925 // How many pages before/after current page to show
2926 $prepostpagecount = 8;
2927 // Minimum pages where pagination does not happen
2928 $paginationat = 16; // 16 pages is a /20, 32 is a /19
2929 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2930 if ($numpages <= $paginationat)
2931 {
2932 // create original pagination
2933 for ($i = 0; $i < $numpages; $i++)
2934 if ($i == $page)
2935 $rendered_pager .= "<b>".$i."</b> ";
2936 else
2937 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2938 }
2939 else // number of pages > page range, create ranged pagination
2940 {
2941 // page is within first subset
2942 if ($page - $prepostpagecount <= 1)
2943 {
2944 for ($i = 0; $i < $page; $i++)
2945 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2946 }
2947 // render 0 ... [page - prepostpagecount] [page - prepostpagecount + 1] ... [page - 1]
2948 else
2949 {
2950 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, 0, ip4_format(ip4_int2bin($startip)));
2951 $rendered_pager .= "... ";
2952 for ($i = $page - $prepostpagecount; $i < $page; $i++)
2953 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2954 }
2955 // render current page
2956 $rendered_pager .= "<b>".$page."</b> ";
2957 // page is within last subset
2958 if ($page + $prepostpagecount >= $numpages-2)
2959 {
2960 for ($i = $page+1; $i < $numpages; $i++)
2961 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2962 }
2963 // render [page + 1] [page + 2] ... [page + postpagecount] ... [end page]
2964 else
2965 {
2966 for ($i = $page+1; $i <= $page+$prepostpagecount; $i++)
2967 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2968 $rendered_pager .= "... ";
2969 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, ($numpages-1), ip4_format(ip4_int2bin($endip)));
2970 }
2971 }
2972 return $rendered_pager;
2973}
2974
4318ced5
AA
2975function renderIPv4NetworkAddresses ($range)
2976{
fb7fb30f 2977 global $aac_left;
4318ced5
AA
2978 $startip = ip4_bin2int ($range['ip_bin']);
2979 $endip = ip4_bin2int (ip_last ($range));
2980
2981 if (isset ($_REQUEST['hl_ip']))
00276508 2982 {
4318ced5
AA
2983 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2984 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
00276508
AA
2985 }
2986
79b57b18
AA
2987 // pager
2988 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2989 $address_count = $endip - $startip + 1;
2990 $page = 0;
446c25c3 2991 $rendered_pager = '';
79b57b18
AA
2992 if ($address_count > $maxperpage && $maxperpage > 0)
2993 {
2994 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2995 if ($numpages = ceil ($address_count / $maxperpage))
2996 {
4318ced5 2997 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
247acd67 2998 $rendered_pager = renderIPv4NetworkPagination ($range, $page, $numpages);
79b57b18
AA
2999 }
3000 $startip = $startip + $page * $maxperpage;
3001 $endip = min ($startip + $maxperpage - 1, $endip);
3002 }
3003
446c25c3 3004 echo $rendered_pager;
1ce89bdd 3005 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
5731b2cb
JV
3006
3007 ob_start ();
cc2fa820 3008 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
5731b2cb
JV
3009 $row_html = ob_get_clean ();
3010 $override = callHook ('renderIPv4NetworkAddressesHeaderRow_hook', $row_html);
3011 echo is_string ($override) ? $override : $row_html;
e673ee24 3012
4318ced5
AA
3013 markupIPAddrList ($range['addrlist']);
3014 for ($ip = $startip; $ip <= $endip; $ip++)
3015 {
3016 $ip_bin = ip4_int2bin ($ip);
3017 $dottedquad = ip4_format ($ip_bin);
5c717ce5 3018 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
0cd7c0f6
AA
3019 if (isset ($range['addrlist'][$ip_bin]))
3020 $addr = $range['addrlist'][$ip_bin];
3021 else
e673ee24 3022 {
5731b2cb 3023 ob_start ();
235124a6 3024 echo "<tr class='tdleft $tr_class'><td class=tdleft><a name='ip-$dottedquad' href='" . makeHref(array('page'=>'ipaddress', 'ip' => $dottedquad)) . "'>$dottedquad</a></td>";
0b8d8309
AA
3025 $editable = permitted ('ipaddress', 'properties', 'editAddress')
3026 ? 'editable'
3027 : '';
cc2fa820
AD
3028 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
3029 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
5731b2cb 3030 $row_html = ob_get_clean ();
97d8533e 3031 $override = callHook ('renderIPv4NetworkAddressesRow_hook', $row_html, $ip_bin, null);
5731b2cb 3032 echo is_string ($override) ? $override : $row_html;
b2035dca
DO
3033 continue;
3034 }
68c91b9c
AA
3035 // render IP change history
3036 $title = '';
3037 $history_class = '';
3038 if (isset ($addr['last_log']))
3039 {
3040 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
3041 $history_class = 'hover-history underline';
3042 }
4318ced5 3043 $tr_class .= ' ' . $addr['class'];
5731b2cb 3044 ob_start ();
4318ced5 3045 echo "<tr class='tdleft $tr_class'>";
235124a6 3046 echo "<td><a class='$history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
0b8d8309 3047 $editable =
cc2fa820 3048 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
0b8d8309
AA
3049 && permitted ('ipaddress', 'properties', 'editAddress')
3050 ? 'editable'
3051 : '';
cc2fa820
AD
3052 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
3053 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
0b8d8309 3054 echo "<td>";
b2035dca 3055 $delim = '';
b2035dca
DO
3056 if ( $addr['reserved'] == 'yes')
3057 {
2d318652 3058 echo "<strong>RESERVED</strong> ";
b2035dca
DO
3059 $delim = '; ';
3060 }
212b565a 3061 foreach ($addr['allocs'] as $ref)
b2035dca 3062 {
9d5f6a80 3063 echo $delim . $aac_left[$ref['type']];
e749a34f 3064 echo makeIPAllocLink ($ip_bin, $ref, TRUE);
531b1ce3 3065 $delim = ';<br/>';
b2035dca
DO
3066 }
3067 if ($delim != '')
e0d6e38e 3068 $delim = '<br>';
212b565a
AA
3069 foreach ($addr['vslist'] as $vs_id)
3070 {
3071 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 3072 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
212b565a
AA
3073 $delim = '<br>';
3074 }
eacc0983
AA
3075 foreach ($addr['vsglist'] as $vs_id)
3076 {
3077 $vs = spotEntity ('ipvs', $vs_id);
3078 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
3079 $delim = '<br>';
3080 }
212b565a
AA
3081 foreach ($addr['rsplist'] as $rsp_id)
3082 {
3083 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 3084 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
212b565a
AA
3085 $delim = '<br>';
3086 }
b2035dca 3087 echo "</td></tr>\n";
5731b2cb 3088 $row_html = ob_get_clean ();
97d8533e 3089 $override = callHook ('renderIPv4NetworkAddressesRow_hook', $row_html, $ip_bin, $addr);
5731b2cb 3090 echo is_string ($override) ? $override : $row_html;
4318ced5 3091 }
2727c7df 3092 // end of iteration
a8dc2982
AA
3093 if (permitted (NULL, NULL, 'set_reserve_comment'))
3094 addJS ('js/inplace-edit.js');
e673ee24
DO
3095
3096 echo "</table>";
b956dd24 3097 if ($rendered_pager != '')
446c25c3 3098 echo '<p>' . $rendered_pager . '</p>';
21ee3351
AA
3099}
3100
3101function renderIPv6NetworkAddresses ($netinfo)
3102{
9d5f6a80 3103 global $pageno, $tabno, $aac_left;
1ce89bdd 3104 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
5731b2cb 3105 ob_start ();
cc2fa820 3106 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
5731b2cb
JV
3107 $row_html = ob_get_clean ();
3108 $override = callHook ('renderIPv6NetworkAddressesHeaderRow_hook', $row_html);
3109 echo is_string ($override) ? $override : $row_html;
21ee3351 3110
4318ced5
AA
3111 $hl_ip = NULL;
3112 if (isset ($_REQUEST['hl_ip']))
3113 {
3114 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
3115 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
3116 }