638e8735a4129c30d2077833a92b44fa644338f8
[racktables] / wwwroot / inc / interface-config.php
1 <?php
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
7 // Find direct sub-pages and dump as a list.
8 function renderConfigMainpage ()
9 {
10 global $pageno, $page;
11 echo '<ul>';
12 foreach ($page as $cpageno => $cpage)
13 if (isset ($cpage['parent']) && $cpage['parent'] == $pageno && permitted ($cpageno))
14 echo '<li>' . mkA (getTitle ($cpageno), $cpageno) . "</li>\n";
15 echo '</ul>';
16 }
17
18 function renderUserList ()
19 {
20 renderCellList ('user', 'User accounts');
21 }
22
23 function renderUserListEditor ()
24 {
25 function printNewItemTR ()
26 {
27 startPortlet ('Add new');
28 printOpFormIntro ('createUser');
29 echo '<table cellspacing=0 cellpadding=5 align=center>';
30 echo '<tr><th>&nbsp;</th><th>&nbsp;</th><th>Tags</th></tr>';
31 echo '<tr><th class=tdright>Username</th><td class=tdleft><input type=text size=64 name=username></td>';
32 echo '<tr><th class=tdright>Real name</th><td class=tdleft><input type=text size=64 name=realname></td></tr>';
33 echo '<tr><th class=tdright>Password</th><td class=tdleft><input type=password size=64 name=password></td></tr>';
34 echo '<tr><th class=tdright>Tags</th><td class=tdleft>';
35 printTagsPicker ();
36 echo '</td></tr>';
37 echo '<tr><td colspan=2>';
38 printImageHREF ('CREATE', 'Add new account', TRUE);
39 echo '</td></tr>';
40 echo '</table></form>';
41 finishPortlet();
42 }
43 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
44 printNewItemTR();
45 $accounts = listCells ('user');
46 startPortlet ('Manage existing (' . count ($accounts) . ')');
47 echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>';
48 echo '<tr><th>Username</th><th>Real name</th><th>New password (use old if blank)</th><th>&nbsp;</th></tr>';
49 foreach ($accounts as $account)
50 {
51 printOpFormIntro ('updateUser', array ('user_id' => $account['user_id']));
52 echo "<tr><td><input type=text name=username value='${account['user_name']}' size=16></td>";
53 echo "<td><input type=text name=realname value='${account['user_realname']}' size=24></td>";
54 echo "<td><input type=password name=password size=40></td><td>";
55 printImageHREF ('save', 'Save changes', TRUE);
56 echo '</td></form></tr>';
57 }
58 echo '</table><br>';
59 finishPortlet();
60 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
61 printNewItemTR();
62 }
63
64 function renderUser ($user_id)
65 {
66 $userinfo = spotEntity ('user', $user_id);
67
68 $summary = array();
69 $summary['Account name'] = $userinfo['user_name'];
70 $summary['Real name'] = $userinfo['user_realname'];
71 $summary['tags'] = '';
72 renderEntitySummary ($userinfo, 'summary', $summary);
73
74 renderFilesPortlet ('user', $user_id);
75 }
76
77 function renderUserProperties ($user_id)
78 {
79 printOpFormIntro ('edit');
80 echo '<table border=0 align=center>';
81 echo "<tr><th class=tdright>Tags:</th><td class=tdleft>";
82 printTagsPicker ();
83 echo "</td></tr>\n";
84 echo "<tr><th class=submit colspan=2>";
85 printImageHREF ('SAVE', 'Save changes', TRUE);
86 echo '</th></tr></table></form>';
87 }
88
89 function renderRackCodeViewer ()
90 {
91 $text = loadScript ('RackCode');
92 echo '<table width="100%" border=0>';
93 $lineno = 1;
94 foreach (explode ("\n", $text) as $line)
95 {
96 echo "<tr><td class=tdright><a name=line${lineno}>${lineno}</a></td>";
97 echo "<td class=tdleft>${line}</td></tr>";
98 $lineno++;
99 }
100 }
101
102 function renderRackCodeEditor ()
103 {
104 addJS ('js/codemirror/codemirror.js');
105 addJS ('js/codemirror/rackcode.js');
106 addCSS ('css/codemirror/codemirror.css');
107 addCSS ('css/codemirror/rackcode.css');
108 addJS (<<<ENDJAVASCRIPT
109 function verify()
110 {
111 $.ajax({
112 type: "POST",
113 url: "index.php",
114 data: {'module': 'ajax', 'ac': 'verifyCode', 'code': $("#RCTA").text()},
115 success: function (data)
116 {
117 arr = data.split("\\n");
118 if (arr[0] == "ACK")
119 {
120 $("#SaveChanges")[0].disabled = "";
121 $("#ShowMessage")[0].innerHTML = "Code verification OK, don't forget to save the code";
122 $("#ShowMessage")[0].className = "msg_success";
123 }
124 else
125 {
126 $("#SaveChanges")[0].disabled = "disabled";
127 $("#ShowMessage")[0].innerHTML = arr[1];
128 $("#ShowMessage")[0].className = "msg_warning";
129 }
130 }
131 });
132 }
133
134 $(document).ready(function() {
135 $("#SaveChanges")[0].disabled = "disabled";
136 $("#ShowMessage")[0].innerHTML = "";
137 $("#ShowMessage")[0].className = "";
138
139 var rackCodeMirror = CodeMirror.fromTextArea(document.getElementById("RCTA"),{
140 mode:'rackcode',
141 lineNumbers:true });
142 rackCodeMirror.on("change",function(cm,cmChangeObject){
143 $("#RCTA").text(cm.getValue());
144 });
145 });
146 ENDJAVASCRIPT
147 , TRUE);
148
149 $text = loadScript ('RackCode');
150 printOpFormIntro ('saveRackCode');
151 echo '<table style="width:100%;border:1px;" border=0 align=center>';
152 echo "<tr><td><textarea rows=40 cols=100 name=rackcode id=RCTA>";
153 echo $text . "</textarea></td></tr>\n";
154 echo "<tr><td align=center>";
155 echo '<div id="ShowMessage"></div>';
156 echo "<input type='button' value='Verify' onclick='verify();'>";
157 echo "<input type='submit' value='Save' disabled='disabled' id='SaveChanges'>";
158 echo "</td></tr>";
159 echo '</table>';
160 echo "</form>";
161 }
162
163 function renderObjectParentCompatViewer()
164 {
165 global $nextorder;
166 $order = 'odd';
167 $last_left_parent_id = NULL;
168 echo '<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>';
169 echo '<tr><th>Parent</th><th>Child</th></tr>';
170 foreach (getObjectParentCompat() as $pair)
171 {
172 if ($last_left_parent_id != $pair['parent_objtype_id'])
173 {
174 $order = $nextorder[$order];
175 $last_left_parent_id = $pair['parent_objtype_id'];
176 }
177 echo "<tr class=row_${order}><td>${pair['parent_name']}</td><td>${pair['child_name']}</td></tr>\n";
178 }
179 echo '</table>';
180 }
181
182 function renderObjectParentCompatEditor()
183 {
184 function printNewitemTR()
185 {
186 printOpFormIntro ('add');
187 echo '<tr><th class=tdleft>';
188 printImageHREF ('add', 'add pair', TRUE);
189 echo '</th><th class=tdleft>';
190 $chapter = readChapter (CHAP_OBJTYPE);
191 // remove rack, row, location
192 unset ($chapter['1560'], $chapter['1561'], $chapter['1562']);
193 printSelect ($chapter, array ('name' => 'parent_objtype_id'));
194 echo '</th><th class=tdleft>';
195 printSelect ($chapter, array ('name' => 'child_objtype_id'));
196 echo "</th></tr></form>\n";
197 }
198
199 global $nextorder;
200 $last_left_parent_id = NULL;
201 $order = 'odd';
202 echo '<br><table class=cooltable align=center border=0 cellpadding=5 cellspacing=0>';
203 echo '<tr><th>&nbsp;</th><th>Parent</th><th>Child</th></tr>';
204 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
205 printNewitemTR();
206 foreach (getObjectParentCompat() as $pair)
207 {
208 if ($last_left_parent_id != $pair['parent_objtype_id'])
209 {
210 $order = $nextorder[$order];
211 $last_left_parent_id = $pair['parent_objtype_id'];
212 }
213 echo "<tr class=row_${order}><td>";
214 if ($pair['count'] > 0)
215 printImageHREF ('nodelete', $pair['count'] . ' relationship(s) stored');
216 else
217 echo getOpLink (array ('op' => 'del', 'parent_objtype_id' => $pair['parent_objtype_id'], 'child_objtype_id' => $pair['child_objtype_id']), '', 'delete', 'remove pair');
218 echo "</td><td class=tdleft>${pair['parent_name']}</td><td class=tdleft>${pair['child_name']}</td></tr>\n";
219 }
220 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
221 printNewitemTR();
222 echo '</table>';
223 }
224
225 function renderOIFCompatViewer()
226 {
227 global $nextorder;
228 $order = 'odd';
229 $last_left_oif_id = NULL;
230 echo '<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>';
231 echo '<tr><th>From interface</th><th>To interface</th></tr>';
232 foreach (getPortOIFCompat() as $pair)
233 {
234 if ($last_left_oif_id != $pair['type1'])
235 {
236 $order = $nextorder[$order];
237 $last_left_oif_id = $pair['type1'];
238 }
239 echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td></tr>";
240 }
241 echo '</table>';
242 }
243
244 function renderOIFCompatEditor()
245 {
246 function printNewitemTR()
247 {
248 printOpFormIntro ('add');
249 echo '<tr><th class=tdleft>';
250 printImageHREF ('add', 'add pair', TRUE);
251 echo '</th><th class=tdleft>';
252 printSelect (getPortOIFOptions(), array ('name' => 'type1'));
253 echo '</th><th class=tdleft>';
254 printSelect (getPortOIFOptions(), array ('name' => 'type2'));
255 echo '</th></tr></form>';
256 }
257
258 global $nextorder, $wdm_packs;
259
260 startPortlet ('WDM wideband receivers');
261 echo '<table border=0 align=center cellspacing=0 cellpadding=5 class=zebra>';
262 echo '<tr><th>&nbsp;</th><th>enable</th><th>disable</th></tr>';
263 foreach ($wdm_packs as $codename => $packinfo)
264 {
265 echo '<tr><td class=tdleft>' . $packinfo['title'] . '</td><td>';
266 echo getOpLink (array ('op' => 'addPack', 'standard' => $codename), '', 'add');
267 echo '</td><td>';
268 echo getOpLink (array ('op' => 'delPack', 'standard' => $codename), '', 'delete');
269 echo '</td></tr>';
270 }
271 echo '</table>';
272 finishPortlet();
273
274 startPortlet ('interface by interface');
275 $last_left_oif_id = NULL;
276 echo '<br><table class=cooltable align=center border=0 cellpadding=5 cellspacing=0>';
277 echo '<tr><th>&nbsp;</th><th>From Interface</th><th>To Interface</th></tr>';
278 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
279 printNewitemTR();
280 $order = 'odd';
281 foreach (getPortOIFCompat() as $pair)
282 {
283 if ($last_left_oif_id != $pair['type1'])
284 {
285 $order = $nextorder[$order];
286 $last_left_oif_id = $pair['type1'];
287 }
288 echo "<tr class=row_${order}><td>";
289 echo getOpLink (array ('op' => 'del', 'type1' => $pair['type1'], 'type2' => $pair['type2']), '', 'delete', 'remove pair');
290 echo "</td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td></tr>";
291 }
292 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
293 printNewitemTR();
294 echo '</table>';
295 finishPortlet();
296 }
297
298 function renderIIFOIFCompat()
299 {
300 echo '<br>';
301 renderTwoColumnCompatTableViewer
302 (
303 getPortInterfaceCompat(),
304 array
305 (
306 'header' => 'Inner interface',
307 'key' => 'iif_id',
308 'value' => 'iif_name',
309 'width' => 16,
310 ),
311 array
312 (
313 'header' => 'Outer interface',
314 'key' => 'oif_id',
315 'value' => 'oif_name',
316 'width' => 48,
317 )
318 );
319 echo '<br>';
320 }
321
322 function renderIIFOIFCompatEditor()
323 {
324 startPortlet ('WDM standard by interface');
325 $iif = getPortIIFOptions();
326 global $nextorder, $wdm_packs;
327 $order = 'odd';
328 echo '<table border=0 align=center cellspacing=0 cellpadding=5>';
329 foreach ($wdm_packs as $codename => $packinfo)
330 {
331 echo "<tr><th>&nbsp;</th><th colspan=2>${packinfo['title']}</th></tr>";
332 foreach ($packinfo['iif_ids'] as $iif_id)
333 {
334 echo "<tr class=row_${order}><th class=tdleft>" . $iif[$iif_id] . '</th><td>';
335 echo getOpLink (array ('op' => 'addPack', 'standard' => $codename, 'iif_id' => $iif_id), '', 'add');
336 echo '</td><td>';
337 echo getOpLink (array ('op' => 'delPack', 'standard' => $codename, 'iif_id' => $iif_id), '', 'delete');
338 echo '</td></tr>';
339 $order = $nextorder[$order];
340 }
341 }
342 echo '</table>';
343 finishPortlet();
344
345 startPortlet ('interface by interface');
346 renderTwoColumnCompatTableEditor
347 (
348 getPortInterfaceCompat(),
349 array
350 (
351 'header' => 'inner interface',
352 'key' => 'iif_id',
353 'value' => 'iif_name',
354 'width' => 16,
355 'options' => getPortIIFOptions(),
356 ),
357 array
358 (
359 'header' => 'outer interface',
360 'key' => 'oif_id',
361 'value' => 'oif_name',
362 'width' => 48,
363 'options' => getPortOIFOptions()
364 )
365 );
366 finishPortlet();
367 }
368
369 function renderPortOIFViewer()
370 {
371 echo '<br><table class="cooltable zebra" align=center border=0 cellpadding=5 cellspacing=0>';
372 echo '<tr><th>Origin</th><th>Key</th><th>Refcnt</th><th>Outer Interface</th></tr>';
373 $refcnt = getPortOIFRefc();
374 foreach (getPortOIFOptions() as $oif_id => $oif_name)
375 {
376 echo '<tr>';
377 echo '<td class=tdleft>' . getImageHREF ($oif_id < 2000 ? 'computer' : 'favorite') . '</td>';
378 echo "<td class=tdright>${oif_id}</td>";
379 echo '<td class=tdright>' . ($refcnt[$oif_id] ? $refcnt[$oif_id] : '&nbsp;') . '</td>';
380 echo '<td class=tdleft>' . stringForTD ($oif_name, 48) . '</td>';
381 echo '</tr>';
382 }
383 echo '</table>';
384 }
385
386 function renderPortOIFEditor()
387 {
388 function printNewitemTR()
389 {
390 printOpFormIntro ('add');
391 echo '<tr>';
392 echo '<td>&nbsp;</td>';
393 echo '<td>&nbsp;</td>';
394 echo '<td>&nbsp;</td>';
395 echo '<td class=tdleft>' . getImageHREF ('create', 'create new', TRUE) . '</td>';
396 echo '<td class=tdleft><input type=text size=48 name=oif_name></td>';
397 echo '<td class=tdleft>' . getImageHREF ('create', 'create new', TRUE) . '</td>';
398 echo '</tr></form>';
399 }
400 echo '<table class=widetable border=0 cellpadding=5 cellspacing=0 align=center>';
401 echo '<tr><th class=tdleft>Origin</th><th>Key</th><th>Refcnt</th><th>&nbsp;</th><th>Outer Interface</th><th>&nbsp;</th></tr>';
402 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
403 printNewitemTR();
404 $refcnt = getPortOIFRefc();
405 foreach (getPortOIFOptions() as $oif_id => $oif_name)
406 {
407 echo '<tr>';
408 if ($oif_id < 2000)
409 {
410 echo '<td class=tdleft>' . getImageHREF ('computer') . '</td>';
411 echo "<td class=tdleft>${oif_id}</td>";
412 echo '<td class=tdright>' . ($refcnt[$oif_id] ? $refcnt[$oif_id] : '&nbsp;') . '</td>';
413 echo '<td>&nbsp;</td>';
414 echo '<td class=tdleft>' . stringForTD ($oif_name, 48) . '</td>';
415 echo '<td>&nbsp;</td>';
416 }
417 else
418 {
419 printOpFormIntro ('upd', array ('id' => $oif_id));
420 echo '<td class=tdleft>' . getImageHREF ('favorite') . '</td>';
421 echo "<td class=tdleft>${oif_id}</td>";
422 if ($refcnt[$oif_id])
423 {
424 echo "<td class=tdright>${refcnt[$oif_id]}</td>";
425 echo '<td class=tdleft>' . getImageHREF ('nodestroy', 'cannot remove') . '</td>';
426 }
427 else
428 {
429 echo '<td>&nbsp;</td>';
430 echo '<td class=tdleft>';
431 echo getOpLink (array ('op' => 'del', 'id' => $oif_id), '', 'destroy', 'remove');
432 echo '</td>';
433 }
434 echo '<td class=tdleft><input type=text size=48 name=oif_name value="' . stringForTextInputValue ($oif_name, 48) . '"></td>';
435 echo '<td>' . getImageHREF ('save', 'Save changes', TRUE) . '</td>';
436 echo '</form>';
437 }
438 echo '</tr>';
439 }
440 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
441 printNewitemTR();
442 echo '</table>';
443 }
444
445 function renderAttributes ()
446 {
447 global $attrtypes;
448 startPortlet ('Optional attributes');
449 echo '<table class="cooltable zebra" border=0 cellpadding=5 cellspacing=0 align=center>';
450 echo "<tr><th class=tdleft>Attribute name</th><th class=tdleft>Attribute type</th><th class=tdleft>Applies to</th></tr>";
451 foreach (getAttrMap() as $attr)
452 {
453 echo '<tr>';
454 echo "<td class=tdleft>${attr['name']}</td>";
455 echo "<td class=tdleft>" . $attrtypes[$attr['type']] . "</td>";
456 echo '<td class=tdleft>';
457 if (count ($attr['application']) == 0)
458 echo '&nbsp;';
459 else
460 foreach ($attr['application'] as $app)
461 if ($attr['type'] == 'dict')
462 echo decodeObjectType ($app['objtype_id']) . " (values from '${app['chapter_name']}')<br>";
463 else
464 echo decodeObjectType ($app['objtype_id']) . '<br>';
465 echo '</td></tr>';
466 }
467 echo "</table><br>\n";
468 finishPortlet();
469 }
470
471 function renderEditAttributesForm ()
472 {
473 function printNewItemTR ()
474 {
475 printOpFormIntro ('add');
476 echo '<tr><td>';
477 printImageHREF ('create', 'Create attribute', TRUE);
478 echo "</td><td><input type=text name=attr_name></td><td>";
479 global $attrtypes;
480 printSelect ($attrtypes, array ('name' => 'attr_type'));
481 echo '</td><td>';
482 printImageHREF ('create', 'Create attribute', TRUE);
483 echo '</td></tr></form>';
484 }
485 startPortlet ('Optional attributes');
486 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
487 echo '<tr><th>&nbsp;</th><th>Name</th><th>Type</th><th>&nbsp;</th></tr>';
488 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
489 printNewItemTR();
490 foreach (getAttrMap() as $attr)
491 {
492 printOpFormIntro ('upd', array ('attr_id' => $attr['id']));
493 echo '<tr><td>';
494 if ($attr['id'] < 10000)
495 printImageHREF ('nodestroy', 'system attribute');
496 elseif (count ($attr['application']))
497 printImageHREF ('nodestroy', count ($attr['application']) . ' reference(s) in attribute map');
498 else
499 echo getOpLink (array('op'=>'del', 'attr_id'=>$attr['id']), '', 'destroy', 'Remove attribute');
500 echo "</td><td><input type=text name=attr_name value='${attr['name']}'></td>";
501 echo "<td class=tdleft>${attr['type']}</td><td>";
502 printImageHREF ('save', 'Save changes', TRUE);
503 echo '</td></tr>';
504 echo '</form>';
505 }
506 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
507 printNewItemTR();
508 echo "</table>\n";
509 finishPortlet();
510 }
511
512 function getAttributeOptions ($attrMap)
513 {
514 $ret = array();
515 $shortType = array
516 (
517 'uint' => 'U',
518 'float' => 'F',
519 'string' => 'S',
520 'dict' => 'D',
521 'date' => 'T',
522 );
523 foreach ($attrMap as $attr)
524 $ret[$attr['id']] = sprintf ('[%s] %s', $shortType[$attr['type']], $attr['name']);
525 return $ret;
526 }
527
528 function renderEditAttrMapForm ()
529 {
530 function printNewItemTR ($aselect)
531 {
532 printOpFormIntro ('add');
533 echo '<tr>';
534 echo "<td colspan=2 class=tdleft>${aselect}</td>";
535 echo '<td class=tdleft>';
536 printImageHREF ('add', '', TRUE);
537 echo ' ';
538 $objtypes = readChapter (CHAP_OBJTYPE, 'o');
539 printNiftySelect (cookOptgroups ($objtypes), array ('name' => 'objtype_id'));
540 $choptions = array (0 => '-- dictionary chapter for [D] attributes --');
541 foreach (getChapterList() as $chapter)
542 if ($chapter['sticky'] != 'yes')
543 $choptions[$chapter['id']] = $chapter['name'];
544 echo ' ' . getSelect ($choptions, array ('name' => 'chapter_no'));
545 echo '</td></tr></form>';
546 }
547 global $attrtypes, $nextorder;
548 $order = 'odd';
549 $attrMap = getAttrMap();
550 $aselect = getSelect (getAttributeOptions ($attrMap), array ('name' => 'attr_id'));
551 startPortlet ('Attribute map');
552 echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>";
553 echo '<tr><th class=tdleft>Attribute name</th><th class=tdleft>Attribute type</th><th class=tdleft>Applies to</th></tr>';
554 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
555 printNewItemTR ($aselect);
556 foreach ($attrMap as $attr)
557 {
558 if (!count ($attr['application']))
559 continue;
560 echo "<tr class=row_${order}><td class=tdleft>${attr['name']}</td>";
561 echo "<td class=tdleft>" . $attrtypes[$attr['type']] . "</td><td colspan=2 class=tdleft>";
562 foreach ($attr['application'] as $app)
563 {
564 if ($app['sticky'] == 'yes')
565 printImageHREF ('nodelete', 'system mapping');
566 elseif ($app['refcnt'])
567 printImageHREF ('nodelete', $app['refcnt'] . ' value(s) stored for objects');
568 else
569 echo getOpLink (array('op'=>'del', 'attr_id'=>$attr['id'], 'objtype_id'=>$app['objtype_id']), '', 'delete', 'Remove mapping');
570 echo ' ';
571 if ($attr['type'] == 'dict')
572 echo decodeObjectType ($app['objtype_id']) . " (values from '${app['chapter_name']}')<br>";
573 else
574 echo decodeObjectType ($app['objtype_id']) . '<br>';
575 }
576 echo "</td></tr>";
577 $order = $nextorder[$order];
578 }
579 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
580 printNewItemTR ($aselect);
581 echo "</table>\n";
582 finishPortlet();
583 }
584
585 function renderDictionary ()
586 {
587 echo '<ul>';
588 foreach (getChapterList() as $chapter_no => $chapter)
589 echo '<li>' . mkA ($chapter['name'], 'chapter', $chapter_no) . " (${chapter['wordc']} records)</li>";
590 echo '</ul>';
591 }
592
593 // We don't allow to rename/delete a sticky chapter and we don't allow
594 // to delete a non-empty chapter.
595 function renderChaptersEditor ()
596 {
597 function printNewItemTR ()
598 {
599 printOpFormIntro ('add');
600 echo '<tr><td>';
601 printImageHREF ('create', 'Add new', TRUE);
602 echo "</td><td><input type=text name=chapter_name></td><td>&nbsp;</td><td>";
603 printImageHREF ('create', 'Add new', TRUE);
604 echo '</td></tr></form>';
605 }
606 $dict = getChapterList();
607 foreach (array_keys ($dict) as $chapter_no)
608 $dict[$chapter_no]['mapped'] = FALSE;
609 foreach (getAttrMap() as $attrinfo)
610 if ($attrinfo['type'] == 'dict')
611 foreach ($attrinfo['application'] as $app)
612 $dict[$app['chapter_no']]['mapped'] = TRUE;
613 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
614 echo '<tr><th>&nbsp;</th><th>Chapter name</th><th>Words</th><th>&nbsp;</th></tr>';
615 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
616 printNewItemTR();
617 foreach ($dict as $chapter_id => $chapter)
618 {
619 $wordcount = $chapter['wordc'];
620 $sticky = $chapter['sticky'] == 'yes';
621 printOpFormIntro ('upd', array ('chapter_no' => $chapter_id));
622 echo '<tr>';
623 echo '<td>';
624 if ($sticky)
625 printImageHREF ('nodestroy', 'system chapter');
626 elseif ($wordcount > 0)
627 printImageHREF ('nodestroy', 'contains ' . $wordcount . ' word(s)');
628 elseif ($chapter['mapped'])
629 printImageHREF ('nodestroy', 'used in attribute map');
630 else
631 echo getOpLink (array('op'=>'del', 'chapter_no'=>$chapter_id), '', 'destroy', 'Remove chapter');
632 echo '</td>';
633 echo "<td><input type=text name=chapter_name value='${chapter['name']}'" . ($sticky ? ' disabled' : '') . "></td>";
634 echo "<td class=tdleft>${wordcount}</td><td>";
635 if ($sticky)
636 echo '&nbsp;';
637 else
638 printImageHREF ('save', 'Save changes', TRUE);
639 echo '</td></tr>';
640 echo '</form>';
641 }
642 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
643 printNewItemTR();
644 echo "</table>\n";
645 }
646
647 function renderChapter ($tgt_chapter_no)
648 {
649 global $nextorder;
650 $words = readChapter ($tgt_chapter_no, 'a');
651 $wc = count ($words);
652 if (!$wc)
653 {
654 echo "<center><h2>(no records)</h2></center>";
655 return;
656 }
657 $refcnt = getChapterRefc ($tgt_chapter_no, array_keys ($words));
658 $attrs = getChapterAttributes($tgt_chapter_no);
659 echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
660 echo "<tr><th colspan=4>${wc} record(s)</th></tr>\n";
661 echo "<tr><th>Origin</th><th>Key</th><th>Refcnt</th><th>Word</th></tr>\n";
662 $order = 'odd';
663 foreach ($words as $key => $value)
664 {
665 echo "<tr class=row_${order}><td>";
666 printImageHREF ($key < 50000 ? 'computer' : 'favorite');
667 echo "</td><td class=tdright>${key}</td><td class=tdright>";
668 if ($refcnt[$key])
669 {
670 // For the ObjectType chapter the extra filter is as simple as "{\$typeid_${key}}" but
671 // the reference counter also includes the relations with AttributeMap.objtype_id hence
672 // it often is not the same as the amount of objects that match the expression. With
673 // this in mind don't display the counter as a link for this specific chapter.
674 if ($tgt_chapter_no == CHAP_OBJTYPE)
675 $cfe = '';
676 else
677 {
678 $tmp = array();
679 foreach ($attrs as $attr_id)
680 $tmp[] = "{\$attr_${attr_id}_${key}}";
681 $cfe = implode (' or ', $tmp);
682 }
683
684 if (! empty($cfe))
685 {
686 $href = makeHref
687 (
688 array
689 (
690 'page'=>'depot',
691 'tab'=>'default',
692 'andor' => 'and',
693 'cfe' => $cfe
694 )
695 );
696 echo '<a href="' . $href . '">' . $refcnt[$key] . '</a>';
697 }
698 else
699 echo $refcnt[$key];
700 }
701 echo "</td><td>${value}</td></tr>\n";
702 $order = $nextorder[$order];
703 }
704 echo "</table>\n<br>";
705 }
706
707 function renderChapterEditor ($tgt_chapter_no)
708 {
709 global $nextorder;
710 function printNewItemTR ()
711 {
712 printOpFormIntro ('add');
713 echo '<tr><td>&nbsp;</td><td>&nbsp;</td><td>';
714 printImageHREF ('add', 'Add new', TRUE);
715 echo "</td>";
716 echo "<td class=tdleft><input type=text name=dict_value size=64></td><td>";
717 printImageHREF ('add', 'Add new', TRUE);
718 echo '</td></tr></form>';
719 }
720 echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
721 $words = readChapter ($tgt_chapter_no, 'r');
722 $refcnt = getChapterRefc ($tgt_chapter_no, array_keys ($words));
723 $order = 'odd';
724 echo "<tr><th>Origin</th><th>Key</th><th>&nbsp;</th><th>Word</th><th>&nbsp;</th></tr>\n";
725 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
726 printNewItemTR();
727 foreach ($words as $key => $value)
728 {
729 echo "<tr class=row_${order}><td>";
730 $order = $nextorder[$order];
731 // Show plain row for stock records, render a form for user's ones.
732 if ($key < 50000)
733 {
734 printImageHREF ('computer');
735 echo "</td><td class=tdright>${key}</td><td>&nbsp;</td><td>${value}</td><td>&nbsp;</td></tr>";
736 continue;
737 }
738 printOpFormIntro ('upd', array ('dict_key' => $key));
739 printImageHREF ('favorite');
740 echo "</td><td class=tdright>${key}</td><td>";
741 // Prevent deleting words currently used somewhere.
742 if ($refcnt[$key])
743 printImageHREF ('nodelete', 'referenced ' . $refcnt[$key] . ' time(s)');
744 else
745 echo getOpLink (array('op'=>'del', 'dict_key'=>$key), '', 'delete', 'Delete word');
746 echo '</td>';
747 echo "<td class=tdleft><input type=text name=dict_value size=64 value='${value}'></td><td>";
748 printImageHREF ('save', 'Save changes', TRUE);
749 echo "</td></tr></form>";
750 }
751 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
752 printNewItemTR();
753 echo "</table>\n<br>";
754 }
755
756 // $v is a $configCache item
757 // prints HTML-formatted varname and description
758 function renderConfigVarName ($v)
759 {
760 echo '<span class="varname">' . $v['varname'] . '</span>';
761 echo '<p class="vardescr">' . $v['description'] . ($v['is_userdefined'] == 'yes' ? '' : ' (system-wide)') . '</p>';
762 }
763
764 function renderUIConfig ()
765 {
766 startPortlet ('Current configuration');
767 echo '<table class="cooltable zebra" border=0 cellpadding=5 cellspacing=0 align=center width="70%">';
768 echo '<tr><th class=tdleft>Option</th><th class=tdleft>Value</th></tr>';
769 foreach (loadConfigCache() as $v)
770 {
771 if ($v['is_hidden'] != 'no')
772 continue;
773 echo '<tr>';
774 echo "<td nowrap valign=top class=tdright>";
775 renderConfigVarName ($v);
776 echo '</td>';
777 echo "<td valign=top class=tdleft>${v['varvalue']}</td></tr>";
778 }
779 echo "</table>\n";
780 finishPortlet();
781 }
782
783 function renderConfigEditor ()
784 {
785 global $pageno;
786 $per_user = ($pageno == 'myaccount');
787 global $configCache;
788 startPortlet ('Current configuration');
789 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='50%'>\n";
790 echo "<tr><th class=tdleft>Option</th>";
791 echo "<th class=tdleft>Value</th></tr>";
792 printOpFormIntro ('upd');
793
794 $i = 0;
795 foreach ($per_user ? $configCache : loadConfigCache() as $v)
796 {
797 if ($v['is_hidden'] != 'no')
798 continue;
799 if ($per_user && $v['is_userdefined'] != 'yes')
800 continue;
801 echo "<input type=hidden name=${i}_varname value='${v['varname']}'>";
802 echo '<tr><td class="tdright">';
803 renderConfigVarName ($v);
804 echo '</td>';
805 echo "<td class=\"tdleft\"><input type=text name=${i}_varvalue value='" . htmlspecialchars ($v['varvalue'], ENT_QUOTES) . "' size=24></td>";
806 echo '<td class="tdleft">';
807 if ($per_user && $v['is_altered'] == 'yes')
808 echo getOpLink (array('op'=>'reset', 'varname'=>$v['varname']), 'reset');
809 echo '</td>';
810 echo "</tr>\n";
811 $i++;
812 }
813 echo "<input type=hidden name=num_vars value=${i}>\n";
814 echo "<tr><td colspan=3>";
815 printImageHREF ('SAVE', 'Save changes', TRUE);
816 echo "</td></tr>";
817 echo "</form>";
818 finishPortlet();
819 }
820
821 function renderUIResetForm()
822 {
823 printOpFormIntro ('go');
824 echo "This button will reset user interface configuration to its defaults (except organization name): ";
825 echo "<input type=submit value='proceed'>";
826 echo "</form>";
827 }
828
829 function serializeTagStats ($taginfo)
830 {
831 $statsdecoder = array
832 (
833 'total' => ' total record(s) linked',
834 'object' => ' object(s)',
835 'rack' => ' rack(s)',
836 'file' => ' file(s)',
837 'user' => ' user account(s)',
838 'ipv6net' => ' IPv6 network(s)',
839 'ipv4net' => ' IPv4 network(s)',
840 'ipv4vs' => ' IPv4 virtual service(s)',
841 'ipv4rspool' => ' IPv4 real server pool(s)',
842 'vst' => ' VLAN switch template(s)',
843 'ipvs' => ' VS group(s)',
844 );
845 $stats = array ("tag ID = ${taginfo['id']}");
846 if ($taginfo['kidc'])
847 $stats[] = "${taginfo['kidc']} sub-tag(s)";
848 if ($taginfo['refcnt']['total'])
849 foreach ($taginfo['refcnt'] as $article => $count)
850 if (array_key_exists ($article, $statsdecoder))
851 $stats[] = $count . $statsdecoder[$article];
852 return implode (', ', $stats);
853 }
854
855 function renderTagRowForViewer ($taginfo, $level = 0)
856 {
857 $self = __FUNCTION__;
858 $trclass = '';
859 if ($level == 0)
860 $trclass .= ' separator';
861 $trclass .= $taginfo['is_assignable'] == 'yes' ? '' : ($taginfo['kidc'] ? ' trnull' : ' trwarning');
862 if (!count ($taginfo['kids']))
863 $level++; // Shift instead of placing a spacer. This won't impact any nested nodes.
864 $refc = $taginfo['refcnt']['total'];
865 echo "<tr class='${trclass}'><td align=left style='padding-left: " . ($level * 16) . "px;'>";
866 if (count ($taginfo['kids']))
867 printImageHREF ('node-expanded-static');
868 echo '<span title="' . serializeTagStats ($taginfo) . '" class="' . getTagClassName ($taginfo['id']) . '">' . $taginfo['tag'];
869 echo ($refc ? " <i>(${refc})</i>" : '') . '</span></td></tr>';
870 foreach ($taginfo['kids'] as $kid)
871 $self ($kid, $level + 1);
872 }
873
874 function renderTagTree ()
875 {
876 echo '<center><table class=tagtree>';
877 foreach (getTagTree() as $taginfo)
878 renderTagRowForViewer ($taginfo);
879 echo '</table></center>';
880 }
881
882 function renderTagRowForEditor ($taginfo, $parent_name = NULL, $level = 0)
883 {
884 $self = __FUNCTION__;
885 if (!count ($taginfo['kids']))
886 $level++; // Idem
887 $trclass = $taginfo['is_assignable'] == 'yes' ? '' : ($taginfo['kidc'] ? ' class=trnull' : ' class=trwarning');
888 echo "<tr${trclass}><td align=left style='padding-left: " . ($level * 16) . "px;'>";
889 if ($taginfo['kidc'])
890 printImageHREF ('node-expanded-static');
891 if ($taginfo['refcnt']['total'] > 0 || $taginfo['kidc'])
892 printImageHREF ('nodestroy', serializeTagStats ($taginfo));
893 else
894 echo getOpLink (array ('op' => 'destroyTag', 'tag_id' => $taginfo['id']), '', 'destroy', 'Delete tag');
895 echo '</td><td>';
896 printOpFormIntro ('updateTag', array ('tag_id' => $taginfo['id']));
897 echo "<input type=text size=48 name=tag_name ";
898 echo "value='${taginfo['tag']}'></td><td class=tdleft>";
899 if ($taginfo['refcnt']['total'])
900 printSelect (array ('yes' => 'yes'), array ('name' => 'is_assignable')); # locked
901 else
902 printSelect (array ('yes' => 'yes', 'no' => 'no'), array ('name' => 'is_assignable'), $taginfo['is_assignable']);
903 echo '</td><td class=tdleft>';
904
905 $poptions = $parent_name === NULL ?
906 array (0 => '-- NONE --') :
907 array ($taginfo['parent_id'] => $parent_name);
908 $sparams = array ('name' => 'parent_id', 'id' => 'nodeid_' . $taginfo['id'], 'class' => 'nodelist-popup');
909 echo getSelect ($poptions, $sparams, $taginfo['parent_id'], FALSE);
910
911 echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . '</form></td></tr>';
912 foreach ($taginfo['kids'] as $kid)
913 $self ($kid, $taginfo['tag'], $level + 1);
914 }
915
916 function addParentNodeOptionsJS ($prefix, $nodetype)
917 {
918 addJS
919 (
920 <<<END
921 function ${prefix}_showselectbox(e) {
922 $(this).load('index.php', {module: 'ajax', ac: 'get-parent-node-options', node_type: '${nodetype}', node_id: this.id});
923 $(this).unbind('mousedown', ${prefix}_showselectbox);
924 }
925 $(document).ready(function () {
926 $('select.nodelist-popup').bind('mousedown', ${prefix}_showselectbox);
927 });
928 END
929 , TRUE
930 );
931 }
932
933 function renderTagTreeEditor ()
934 {
935 function printNewItemTR ($options)
936 {
937 printOpFormIntro ('createTag');
938 echo '<tr>';
939 echo '<td align=left style="padding-left: 16px;">' . getImageHREF ('create', 'Create tag', TRUE) . '</td>';
940 echo '<td><input type=text size=48 name=tag_name></td>';
941 echo '<td class=tdleft>' . getSelect (array ('yes' => 'yes', 'no' => 'no'), array ('name' => 'is_assignable'), 'yes') . '</td>';
942 echo '<td>' . getSelect ($options, array ('name' => 'parent_id')) . '</td>';
943 echo '<td>' . getImageHREF ('create', 'Create tag', TRUE, 120) . '</td>';
944 echo '</tr></form>';
945 }
946 global $taglist;
947 addParentNodeOptionsJS ('tageditor', 'existing tag');
948 $options = getParentNodeOptionsNew ($taglist, 'tag');
949 echo '<br><table cellspacing=0 cellpadding=5 align=center class=widetable>';
950 echo '<tr><th>&nbsp;</th><th>tag name</th><th>assignable</th><th>parent tag</th><th>&nbsp;</th></tr>';
951 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
952 printNewItemTR ($options);
953 foreach (getTagTree() as $taginfo)
954 renderTagRowForEditor ($taginfo);
955 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
956 printNewItemTR ($options);
957 echo '</table>';
958 }
959
960 function renderGraphCycleResolver()
961 {
962 global $pageno;
963 // $fieldmap below does not contain 'parent_id' as it is done by the SELECT.
964 switch ($pageno)
965 {
966 case 'tagtree';
967 global $taglist;
968 $nodelist = $taglist;
969 $textfield = 'tag';
970 $opcode = 'updateTag';
971 $fieldmap = array
972 (
973 'tag_id' => 'id',
974 'tag_name' => 'tag',
975 'is_assignable' => 'is_assignable',
976 );
977 break;
978 default:
979 throw new RackTablesError ('unexpected call to tabhandler function', RackTablesError::INTERNAL);
980 }
981 $invalids = getInvalidNodes ($nodelist);
982 $options = getParentNodeOptionsNew ($nodelist, $textfield);
983 echo '<br><table cellspacing=0 cellpadding=5 align=center class=widetable>';
984 echo '<tr><th>node</th><th>current parent node</th><th>new parent node</th><th>&nbsp;</th></tr>';
985 foreach ($invalids as $node)
986 {
987 $formvalues = array();
988 foreach ($fieldmap as $form_param => $nodefield)
989 $formvalues[$form_param] = $node[$nodefield];
990 printOpFormIntro ($opcode, $formvalues);
991 echo '<tr>';
992 echo '<td class=tdleft>' . stringForLabel ($node[$textfield]) . '</td>';
993 echo '<td class="tdleft trerror">' . stringForLabel ($invalids[$node['parent_id']][$textfield]) . '</td>';
994 echo '<td>' . getSelect ($options, array ('name' => 'parent_id'), $node['parent_id']) . '</td>';
995 echo '<td>' . getImageHREF ('save', 'Save changes', TRUE) . '</td>';
996 echo '</tr></form>';
997 }
998 echo '</table>';
999 }
1000
1001 function renderMyAccount ()
1002 {
1003 global $remote_username, $remote_displayname, $expl_tags, $impl_tags, $auto_tags;
1004
1005 startPortlet ('Current user info');
1006 echo '<div style="text-align: left; display: inline-block;">';
1007 echo "<table>";
1008 echo "<tr><th>Login:</th><td>${remote_username}</td></tr>\n";
1009 echo "<tr><th>Name:</th><td>${remote_displayname}</td></tr>\n";
1010 echo "<tr><th>Explicit tags:</th><td>" . serializeTags (getExplicitTagsOnly ($expl_tags)) . "</td></tr>\n";
1011 echo "<tr><th>Implicit tags:</th><td>" . serializeTags ($impl_tags) . "</td></tr>\n";
1012 echo "<tr><th>Automatic tags:</th><td>" . serializeTags ($auto_tags) . "</td></tr>\n";
1013 echo '</table></div>';
1014 }
1015
1016 function renderMyPasswordEditor ()
1017 {
1018 printOpFormIntro ('changeMyPassword');
1019 echo '<table border=0 align=center>';
1020 echo "<tr><th class=tdright>Current password (*):</th><td><input type=password name=oldpassword></td></tr>";
1021 echo "<tr><th class=tdright>New password (*):</th><td><input type=password name=newpassword1></td></tr>";
1022 echo "<tr><th class=tdright>New password again (*):</th><td><input type=password name=newpassword2></td></tr>";
1023 echo "<tr><td colspan=2 align=center><input type=submit value='Change'></td></tr>";
1024 echo '</table></form>';
1025 }
1026
1027 function renderMyQuickLinks ()
1028 {
1029 global $indexlayout, $page;
1030 startPortlet ('Items to display in page header');
1031 echo '<div style="text-align: left; display: inline-block;">';
1032 printOpFormIntro ('save');
1033 echo '<ul class="qlinks-form">';
1034 $active_items = explode (',', getConfigVar ('QUICK_LINK_PAGES'));
1035 $items = array();
1036 foreach ($indexlayout as $row)
1037 foreach ($row as $ypageno)
1038 {
1039 $items[$ypageno] = getPageName ($ypageno);
1040 if ($ypageno == 'config') // expand
1041 foreach ($page as $subpageno => $subpage)
1042 if (array_fetch ($subpage, 'parent', NULL) == $ypageno)
1043 $items[$subpageno] = $items[$ypageno] . ': ' . getPageName ($subpageno);
1044 }
1045 foreach ($items as $ypageno => $pagename)
1046 {
1047 $checked_state = in_array ($ypageno, $active_items) ? 'checked' : '';
1048 echo "<li><label><input type='checkbox' name='page_list[]' value='$ypageno' $checked_state>" . $pagename . "</label></li>\n";
1049 }
1050 echo '</ul>';
1051 printImageHREF ('SAVE', 'Save changes', TRUE);
1052 echo '</form></div>';
1053 finishPortlet();
1054 }
1055
1056 function renderCactiConfig()
1057 {
1058 $columns = array
1059 (
1060 array ('th_text' => 'base URL', 'row_key' => 'base_url'),
1061 array ('th_text' => 'username', 'row_key' => 'username'),
1062 array ('th_text' => 'graph(s)', 'row_key' => 'num_graphs', 'td_class' => 'tdright'),
1063 );
1064 $servers = getCactiServers();
1065 startPortlet ('Cacti servers (' . count ($servers) . ')');
1066 renderTableViewer ($columns, $servers);
1067 finishPortlet();
1068 }
1069
1070 function renderCactiServersEditor()
1071 {
1072 function printNewItemTR ()
1073 {
1074 printOpFormIntro ('add');
1075 echo '<tr>' .
1076 '<td>' . getImageHREF ('create', 'add a new server', TRUE) . '</td>' .
1077 '<td><input type=text size=48 name=base_url></td>' .
1078 '<td><input type=text size=24 name=username></td>' .
1079 '<td><input type=password size=24 name=password></td>' .
1080 '<td>&nbsp;</td>' .
1081 '<td>' . getImageHREF ('create', 'add a new server', TRUE) . '</td>' .
1082 '</tr></form>';
1083 }
1084 echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>';
1085 echo '<tr>' .
1086 '<th>&nbsp;</th>' .
1087 '<th>base URL</th>' .
1088 '<th>username</th>' .
1089 '<th>password</th>' .
1090 '<th>graph(s)</th>' .
1091 '<th>&nbsp;</th>' .
1092 '</tr>';
1093 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1094 printNewItemTR();
1095 foreach (getCactiServers() as $server)
1096 {
1097 printOpFormIntro ('upd', array ('id' => $server['id']));
1098 echo '<tr><td>';
1099 if ($server['num_graphs'])
1100 printImageHREF ('nodestroy', 'cannot delete, graphs exist');
1101 else
1102 echo getOpLink (array ('op' => 'del', 'id' => $server['id']), '', 'destroy', 'delete this server');
1103 echo '</td>';
1104 echo '<td><input type=text size=48 name=base_url value="' . htmlspecialchars ($server['base_url'], ENT_QUOTES, 'UTF-8') . '"></td>';
1105 echo '<td><input type=text size=24 name=username value="' . htmlspecialchars ($server['username'], ENT_QUOTES, 'UTF-8') . '"></td>';
1106 echo '<td><input type=password size=24 name=password value="' . htmlspecialchars ($server['password'], ENT_QUOTES, 'UTF-8') . '"></td>';
1107 echo "<td class=tdright>${server['num_graphs']}</td>";
1108 echo '<td>' . getImageHREF ('save', 'update this server', TRUE) . '</td>';
1109 echo '</tr></form>';
1110 }
1111 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1112 printNewItemTR();
1113 echo '</table>';
1114 }
1115
1116 function renderMuninConfig()
1117 {
1118 $columns = array
1119 (
1120 array ('th_text' => 'base URL', 'row_key' => 'base_url', 'td_maxlen' => 150),
1121 array ('th_text' => 'graph(s)', 'row_key' => 'num_graphs', 'td_class' => 'tdright'),
1122 );
1123 $servers = getMuninServers();
1124 startPortlet ('Munin servers (' . count ($servers) . ')');
1125 renderTableViewer ($columns, $servers);
1126 finishPortlet();
1127 }
1128
1129 function renderMuninServersEditor()
1130 {
1131 function printNewItemTR()
1132 {
1133 printOpFormIntro ('add');
1134 echo '<tr>' .
1135 '<td>' . getImageHREF ('create', 'add a new server', TRUE) . '</td>' .
1136 '<td><input type=text size=48 name=base_url></td>' .
1137 '<td>&nbsp;</td>' .
1138 '<td>' . getImageHREF ('create', 'add a new server', TRUE) . '</td>' .
1139 '</tr></form>';
1140 }
1141 echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>';
1142 echo '<tr>' .
1143 '<th>&nbsp;</th>' .
1144 '<th>base URL</th>' .
1145 '<th>graph(s)</th>' .
1146 '<th>&nbsp;</th>' .
1147 '</tr>';
1148 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1149 printNewItemTR();
1150 foreach (getMuninServers() as $server)
1151 {
1152 printOpFormIntro ('upd', array ('id' => $server['id']));
1153 echo '<tr><td>';
1154 if ($server['num_graphs'])
1155 printImageHREF ('nodestroy', 'cannot delete, graphs exist');
1156 else
1157 echo getOpLink (array ('op' => 'del', 'id' => $server['id']), '', 'destroy', 'delete this server');
1158 echo '</td>';
1159 echo '<td><input type=text size=48 name=base_url value="' . htmlspecialchars ($server['base_url'], ENT_QUOTES, 'UTF-8') . '"></td>';
1160 echo "<td class=tdright>${server['num_graphs']}</td>";
1161 echo '<td>' . getImageHREF ('save', 'update this server', TRUE) . '</td>';
1162 echo '</tr></form>';
1163 }
1164 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1165 printNewItemTR();
1166 echo '</table>';
1167 }
1168
1169 ?>