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