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