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