View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
550 | RackTables | default | public | 2012-04-12 11:46 | 2015-06-11 03:59 |
Reporter | Assigned To | infrastation | |||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | assigned | Resolution | open | ||
Summary | 550: tracking cable types | ||||
Description | Hi, I've discussed this idea with infrastation a while ago. My colleagues want to track which cable types are used for certain connections. I'm willing to write that code, but first I'd like to have a few opinions on my plan: Changes in Database: - Add a field `cable_type_id` UNSIGNED INTEGER to PortCompat which hold a ref to a chapter from which possible cable types for this kind of connection can be selected. ( This can be NULL if you don't want to use this feature for a certain connection ) - Add a field to `cable_type_key` UNSIGNED INTEGER to Link which points to a dictionary entry. ( This is NULL if the cable is not known. ) Changes in Interface: - Extend the Port compatibility config page according to the database changes. - Extend the Object -> Ports tab to show the cable type for connected ports. - Extend the Link-to popup with a drop-down showing the available cable types. Changes to functions: - fetchPortList ( fetch the cable type ) - linkPorts ( optional additional argument ) - commitUpdatePortLink ( idem ) - handlePopupPortLink Still to be considered: - Track cable changes in PortLog? - Interface if you just want to change the cable type but not the linked port. Kind regards Hannes | ||||
Tags | No tags attached. | ||||
Attached Files | track_cable_type.patch (31,600 bytes)
diff -rupN '--exclude=.git' '--exclude=secret.php' racktables2/wwwroot/inc/database.php racktables/wwwroot/inc/database.php --- racktables2/wwwroot/inc/database.php 2012-04-19 12:29:26.749825940 +0200 +++ racktables/wwwroot/inc/database.php 2012-04-19 12:20:06.809828661 +0200 @@ -728,6 +728,7 @@ SELECT (SELECT PortInnerInterface.iif_name FROM PortInnerInterface WHERE PortInnerInterface.id = Port.iif_id) AS iif_name, (SELECT Dictionary.dict_value FROM Dictionary WHERE Dictionary.dict_key = Port.type) AS oif_name, IF(la.porta, la.cable, lb.cable) AS cableid, + IF(la.porta, la.cable_dict_key, lb.cable_dict_key) AS cable_dict_key, IF(la.porta, pa.id, pb.id) AS remote_id, IF(la.porta, pa.name, pb.name) AS remote_name, IF(la.porta, pa.object_id, pb.object_id) AS remote_object_id, @@ -1452,19 +1453,44 @@ function getAllIPv4Allocations () return $ret; } -function linkPorts ($porta, $portb, $cable = NULL) +function linkPorts ($porta, $portb, $cable = NULL, $cable_type = NULL, $update = false) { if ($porta == $portb) throw new InvalidArgException ('porta/portb', $porta, "Ports can't be the same"); global $dbxlink; - $dbxlink->exec ('LOCK TABLES Link WRITE'); + # the many locks are necessary. otherwise commitUnlinkPort could not access these tables: + $dbxlink->exec ('LOCK TABLES Link WRITE, Port AS pa WRITE, Port AS pb WRITE , Object WRITE, RackObject WRITE, PortLog WRITE'); $result = usePreparedSelectBlade ( - 'SELECT COUNT(*) FROM Link WHERE porta IN (?,?) OR portb IN (?,?)', + 'SELECT * FROM Link WHERE porta IN (?,?) OR portb IN (?,?)', array ($porta, $portb, $porta, $portb) ); - if ($result->fetchColumn () != 0) + if ( $update ) + { + $a = $result->fetch(); + if( $a ){ + if( ($a['porta'] == $porta && $a['portb'] == $portb) || ($a['portb'] == $porta && $a['porta'] == $portb) ) + { + // update! + $dbxlink->exec ('UNLOCK TABLES'); + usePreparedUpdateBlade( + 'Link', + array ( + 'cable' => ( mb_strlen ($cable) ? $cable : NULL ) , + 'cable_dict_key' => ( mb_strlen ($cable_type) ? intval($cable_type) : NULL ) + ), + array( 'porta' => $a['porta'], 'portb' => $a['portb'] ) + ); + + return ; + }else{ + commitUnlinkPort($porta); + commitUnlinkPort($portb); + } + } + } + else if ($result->fetch ()) { $dbxlink->exec ('UNLOCK TABLES'); return "Port ${porta} or ${portb} is already linked"; @@ -1483,7 +1509,8 @@ function linkPorts ($porta, $portb, $cab ( 'porta' => $porta, 'portb' => $portb, - 'cable' => mb_strlen ($cable) ? $cable : NULL + 'cable' => mb_strlen ($cable) ? $cable : NULL, + 'cable_dict_key' => mb_strlen ($cable_type) ? intval($cable_type) : NULL ) ); $dbxlink->exec ('UNLOCK TABLES'); @@ -2812,9 +2839,10 @@ function commitUpdateUserAccount ($id, $ function getPortOIFCompat () { $query = - "select type1, type2, d1.dict_value as type1name, d2.dict_value as type2name from " . + "select type1, type2, d1.dict_value as type1name, d2.dict_value as type2name, cable_chapter_id , c.name as cable_chapter_name from " . "PortCompat as pc inner join Dictionary as d1 on pc.type1 = d1.dict_key " . "inner join Dictionary as d2 on pc.type2 = d2.dict_key " . + "left join Chapter as c on pc.cable_chapter_id = c.id ". 'ORDER BY type1name, type2name'; $result = usePreparedSelectBlade ($query); return $result->fetchAll (PDO::FETCH_ASSOC); diff -rupN '--exclude=.git' '--exclude=secret.php' racktables2/wwwroot/inc/interface.php racktables/wwwroot/inc/interface.php --- racktables2/wwwroot/inc/interface.php 2012-04-16 09:51:40.040216558 +0200 +++ racktables/wwwroot/inc/interface.php 2012-04-19 12:20:06.813828661 +0200 @@ -1246,7 +1246,24 @@ function renderPortsForObject ($object_i 'object_id'=>$object_id)). "'>"; printImageHREF ('cut', 'Unlink this port'); - echo "</a></td>"; + echo "</a>"; + echo "<span"; + $helper_args = array + ( + 'port' => $port['id'], + ); + $popup_args = 'height=700, width=400, location=no, menubar=no, '. + 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no'; + echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args); + echo "\",\"findlink\",\"${popup_args}\");'"; + // end of onclick= + echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args); + echo "\",\"findlink\",\"${popup_args}\");'"; + // end of onclick= + echo '>'; + // end of <a> + printImageHREF ('plug', 'Link this port'); + echo "</span></td>"; } elseif (strlen ($port['reservation_comment'])) { @@ -3418,7 +3435,7 @@ function renderOIFCompatViewer() $order = 'odd'; $last_left_oif_id = NULL; echo '<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>'; - echo '<tr><th>From interface</th><th>To interface</th></tr>'; + echo '<tr><th>From interface</th><th>To interface</th><th>Cable</th></tr>'; foreach (getPortOIFCompat() as $pair) { if ($last_left_oif_id != $pair['type1']) @@ -3426,14 +3443,20 @@ function renderOIFCompatViewer() $order = $nextorder[$order]; $last_left_oif_id = $pair['type1']; } - echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td></tr>"; + echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td><td>${pair['cable_chapter_name']}</td></tr>"; } echo '</table>'; } function renderOIFCompatEditor() { - function printNewitemTR() + $raw_chaplist = getChapterList(); + $chaplist = array(); + $chaplist[0]=''; + foreach( $raw_chaplist as $chapter ){ + $chaplist[$chapter['id']]= htmlspecialchars( $chapter['name'] ); + } + function printNewitemTR($chaplist_local) { printOpFormIntro ('add'); echo '<tr><th class=tdleft>'; @@ -3442,6 +3465,10 @@ function renderOIFCompatEditor() printSelect (readChapter (CHAP_PORTTYPE), array ('name' => 'type1')); echo '</th><th class=tdleft>'; printSelect (readChapter (CHAP_PORTTYPE), array ('name' => 'type2')); + echo '</th><th class=tdleft>'; + printSelect( $chaplist_local, array( 'name' => 'cable_chapter_id' ) ); + echo '</th><th>'; + printImageHREF ('add', 'add pair', TRUE); echo '</th></tr></form>'; } @@ -3466,9 +3493,9 @@ function renderOIFCompatEditor() startPortlet ('interface by interface'); $last_left_oif_id = NULL; echo '<br><table class=cooltable align=center border=0 cellpadding=5 cellspacing=0>'; - echo '<tr><th> </th><th>From Interface</th><th>To Interface</th></tr>'; + echo '<tr><th> </th><th>From Interface</th><th>To Interface</th><th>Cable</th><th></th></tr>'; if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') - printNewitemTR(); + printNewitemTR($chaplist); foreach (getPortOIFCompat() as $pair) { if ($last_left_oif_id != $pair['type1']) @@ -3476,13 +3503,19 @@ function renderOIFCompatEditor() $order = $nextorder[$order]; $last_left_oif_id = $pair['type1']; } + printOpFormIntro('upd',array('type1'=>$pair['type1'], 'type2' => $pair['type2']) ); echo "<tr class=row_${order}><td>"; echo '<a href="' . makeHrefProcess (array ('op' => 'del', 'type1' => $pair['type1'], 'type2' => $pair['type2'])) . '">'; printImageHREF ('delete', 'remove pair'); - echo "</a></td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td></tr>"; + echo "</a></td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td>"; + echo '<td>'; + printSelect($chaplist, array('name'=>'cable_chapter_id'), $pair['cable_chapter_id']); + echo '</td><td>'; + printImageHREF ('save', 'Save changes', TRUE); + echo "</td></tr></form>"; } if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') - printNewitemTR(); + printNewitemTR($chaplist); echo '</table>'; finishPortlet(); } diff -rupN '--exclude=.git' '--exclude=secret.php' racktables2/wwwroot/inc/navigation.php racktables/wwwroot/inc/navigation.php --- racktables2/wwwroot/inc/navigation.php 2012-04-16 09:51:40.044216558 +0200 +++ racktables/wwwroot/inc/navigation.php 2012-04-19 12:20:06.813828661 +0200 @@ -435,6 +435,7 @@ $tabhandler['portmap']['default'] = 'ren $tabhandler['portmap']['edit'] = 'renderOIFCompatEditor'; $ophandler['portmap']['edit']['add'] = 'tableHandler'; $ophandler['portmap']['edit']['del'] = 'tableHandler'; +$ophandler['portmap']['edit']['upd'] = 'tableHandler'; $ophandler['portmap']['edit']['addPack'] = 'addOIFCompatPack'; $ophandler['portmap']['edit']['delPack'] = 'delOIFCompatPack'; diff -rupN '--exclude=.git' '--exclude=secret.php' racktables2/wwwroot/inc/ophandlers.php racktables/wwwroot/inc/ophandlers.php --- racktables2/wwwroot/inc/ophandlers.php 2012-04-19 12:29:26.757825940 +0200 +++ racktables/wwwroot/inc/ophandlers.php 2012-04-19 12:20:06.813828661 +0200 @@ -262,6 +262,21 @@ $opspec_list['portmap-edit-add'] = array ( array ('url_argname' => 'type1', 'assertion' => 'uint'), array ('url_argname' => 'type2', 'assertion' => 'uint'), + array ('url_argname' => 'cable_chapter_id', 'assertion' => 'uint0', 'if_empty' => 'NULL' ) + ), +); +$opspec_list['portmap-edit-upd'] = array +( + 'table' => 'PortCompat', + 'action' => 'UPDATE', + 'set_arglist' => array + ( + array ('url_argname' => 'cable_chapter_id', 'assertion' => 'uint0', 'if_empty' => 'NULL'), + ), + 'where_arglist' => array + ( + array ('url_argname' => 'type1', 'assertion' => 'uint'), + array ('url_argname' => 'type2', 'assertion' => 'uint') ), ); $opspec_list['portmap-edit-del'] = array diff -rupN '--exclude=.git' '--exclude=secret.php' racktables2/wwwroot/inc/popup.php racktables/wwwroot/inc/popup.php --- racktables2/wwwroot/inc/popup.php 2012-04-16 09:51:40.044216558 +0200 +++ racktables/wwwroot/inc/popup.php 2012-04-19 12:39:08.649823113 +0200 @@ -34,7 +34,7 @@ function getProximateRacks ($rack_id, $p return $ret; } -function findSparePorts ($port_info, $filter) +function getSparePorts($port_info, $filter) { $qparams = array (); $query = " @@ -45,37 +45,34 @@ SELECT p.iif_id, p.type as oif_id, pii.iif_name, - d.dict_value as oif_name, p.object_id, o.name as object_name FROM Port p INNER JOIN Object o ON o.id = p.object_id INNER JOIN PortInnerInterface pii ON p.iif_id = pii.id -INNER JOIN Dictionary d ON d.dict_key = p.type "; // porttype filter (non-strict match) $query .= " INNER JOIN ( - SELECT Port.id FROM Port + SELECT p2.id FROM Port p2 INNER JOIN ( - SELECT DISTINCT pic2.iif_id + SELECT DISTINCT pic2.iif_id, pic2.oif_id FROM PortInterfaceCompat pic2 INNER JOIN PortCompat pc ON pc.type2 = pic2.oif_id "; if ($port_info['iif_id'] != 1) { - $query .= " INNER JOIN PortInterfaceCompat pic ON pic.oif_id = pc.type1 WHERE pic.iif_id = ? AND "; + $query .= " INNER JOIN PortInterfaceCompat pic ON pic.oif_id = pc.type1 WHERE pic.iif_id = ? "; $qparams[] = $port_info['iif_id']; } else { - $query .= " WHERE pc.type1 = ? AND "; + $query .= " WHERE pc.type1 = ? "; $qparams[] = $port_info['oif_id']; } $query .= " - pic2.iif_id <> 1 - ) AS sub1 USING (iif_id) + ) AS sub1 ON p2.iif_id = sub1.iif_id AND ( p2.iif_id <> 1 OR p2.type = sub1.oif_id ) UNION SELECT Port.id FROM Port @@ -113,42 +110,104 @@ INNER JOIN ( // ordering $query .= ' ORDER BY o.name'; - $ret = array(); - $result = usePreparedSelectBlade ($query, $qparams); - - $rows_by_pn = array(); - $prev_object_id = NULL; + return usePreparedSelectBlade ($query, $qparams); +} + +function getLinkPortJavascript($port_info, $ports) +{ + $required_oif = array(); + $required_iif = array(); + $required_chapter = array(); + if( count($ports) == 0 ){ + return ''; + } + $jsports = array(); + $compat = array(); + $buffer = array('$(function($){'); + $buffer[]='var PORT = { id:'.$port_info['id'].', name:"'.addslashes($port_info['name']).'",'; + $buffer[]=' object_name:"'.addslashes($port_info['object_name']).'",'; + $buffer[]=' oif_id:'.($port_info['oif_id'] ? $port_info['oif_id'] : 'null').', '; + $buffer[]=' iif_id:'.$port_info['iif_id'].', '; + $buffer[]=' cable:"'.addslashes($port_info['cableid']).'", '; + $buffer[]=' cable_dict_key:'.($port_info['cable_dict_key'] ? $port_info['cable_dict_key'] : 'null' ).', '; + $buffer[]=' remote_id:'.($port_info['remote_id'] ? $port_info['remote_id'] : 'null').'};'; + $buffer[]='var PORTS = ['; - // fetch port rows from the DB - while (TRUE) + $required_iif[$port_info['iif_id']]=true; + if( $port_info['oif_id'] ) $required_oif[$port_info['oif_id']]=true; + foreach( $ports as $port ){ + $required_iif[ $port['iif_id'] ]=true; + if( $port['oif_id'] ) $required_oif[$port['oif_id']]=true; + $buffer[]=' { id:'.$port['id'].', name:"'.addslashes($port['name']).'", object_name:"'.addslashes($port['object_name']).'", oif_id:'.($port['oif_id'] ? $port['oif_id'] : 'null').', iif_id:'.$port['iif_id'].', reservation:"'.addslashes($port['reservation_comment']).'"},'; + } + $buffer[]='];'; + + $incom = usePreparedSelectBlade('SELECT * FROM PortInterfaceCompat WHERE iif_id IN ('.questionMarks(count($required_iif)).') ORDER BY iif_id ', array_keys($required_iif)); + $buffer[]='var INNER_OUTER_COMPATIBILITY = {'; + $last_iif_id = null; + foreach( $incom as $in ) { - $row = $result->fetch (PDO::FETCH_ASSOC); - if (isset ($prev_object_id) and (! $row or $row['object_id'] != $prev_object_id)) + if( $in['iif_id'] != $last_iif_id ) { - // handle sorted object's portlist - foreach (sortPortList ($rows_by_pn) as $ports_subarray) - foreach ($ports_subarray as $port_row) - { - $port_description = $port_row['object_name'] . ' -- ' . $port_row['name']; - if (count ($ports_subarray) > 1) - { - $if_type = $port_row['iif_id'] == 1 ? $port_row['oif_name'] : $port_row['iif_name']; - $port_description .= " ($if_type)"; - } - if (! empty ($port_row['reservation_comment'])) - $port_description .= ' -- ' . $port_row['reservation_comment']; - $ret[$port_row['id']] = $port_description; - } - $rows_by_pn = array(); + if( $last_iif_id != null ) + { + $buffer[]=' ],'; + } + $buffer[]=' '.$in['iif_id'].': ['; + $last_iif_id = $in['iif_id']; } - $prev_object_id = $row['object_id']; - if ($row) - $rows_by_pn[$row['name']][] = $row; - else - break; + $required_oif[$in['oif_id']]=true; + $buffer[]=' '.$in['oif_id'].','; } + if( $last_iif_id != null ) + { + $buffer[]=' ]'; + } + $buffer[]='};'; - return $ret; + $query ='SELECT * FROM PortCompat pc'. + ' WHERE type1 IN ('.questionMarks(count($required_oif)).') AND type2 IN ('.questionMarks(count($required_oif)).');'; + $types = usePreparedSelectBlade($query, array_merge( array_keys($required_oif), array_keys($required_oif) ) ); + foreach( $types as $type ){ + @$compat[ $type['type1'] ][ $type['type2'] ] = array( 'cable_chapter_id'=> ($type['cable_chapter_id'] ? intval($type['cable_chapter_id']) : 'null') ); + if( $type['cable_chapter_id'] ) $required_chapter[intval($type['cable_chapter_id'])] = true; + } + $buffer[]='var OUTER_COMPATIBILITY = {'; + foreach( $compat as $a => $sub ){ + $buffer[]=' '.$a.': { '; + foreach( $sub as $b => $info ){ + $buffer[]=' '.$b.': {cable_chapter_id:'.$info['cable_chapter_id'].'},'; + } + $buffer[]=' },'; + } + $buffer[]='};'; + if( $required_chapter ){ + $buffer[]='var CABLES = {'; + $last_chapter_id = -1; + foreach( array_keys($required_chapter) as $chapter_id ){ + $chapter = cookOptgroups( readChapter( $chapter_id, 'o' ) ); + $buffer[]= $chapter_id.': ['; + foreach( $chapter as $group => $entries ){ + $buffer[]= ' {name: "'.addslashes($group).'", values:['; + foreach( $entries as $key => $value ){ + $buffer[]= ' {key: '.$key.', value: "'.addslashes($value).'"},'; + } + $buffer[]=' ]},'; + } + $buffer[]='],'; + } + $buffer[]='};'; + }else{ + $buffer[]='var CABLES = {};'; + } + $oifs = usePreparedSelectBlade('SELECT dict_key,dict_value FROM Dictionary WHERE chapter_id = 2 AND dict_key IN ('.questionMarks(count($required_oif)).');', array_keys($required_oif)); + $buffer[]='var OIF = {};'; + foreach( $oifs as $oif ){ + $buffer[]='OIF['.$oif['dict_key'].']= "'.addslashes($oif['dict_value']).'";'; + } + $buffer[]=' initializeLinkportForm( PORT, PORTS, INNER_OUTER_COMPATIBILITY, OUTER_COMPATIBILITY, CABLES, OIF )'; + $buffer[]='});'; + return join("\n",$buffer); } // Return a list of all objects which are possible parents @@ -221,131 +280,66 @@ function renderPopupObjectSelector() function handlePopupPortLink() { + global $dbxlink; assertUIntArg ('port'); assertUIntArg ('remote_port'); assertStringArg ('cable', TRUE); $port_info = getPortInfo ($_REQUEST['port']); $remote_port_info = getPortInfo ($_REQUEST['remote_port']); - $POIFC = getPortOIFCompat(); - if (isset ($_REQUEST['port_type']) and isset ($_REQUEST['remote_port_type'])) - { - $type_local = $_REQUEST['port_type']; - $type_remote = $_REQUEST['remote_port_type']; - } - else - { - $type_local = $port_info['oif_id']; - $type_remote = $remote_port_info['oif_id']; - } - $matches = FALSE; - $js_table = ''; - foreach ($POIFC as $pair) - if ($pair['type1'] == $type_local && $pair['type2'] == $type_remote) - { - $matches = TRUE; - break; + $dbxlink->beginTransaction(); + try{ + + if( $port_info['iif_id'] != 1 ){ + // updateable + assertUIntArg ('local_oif'); + if( $_POST['local_oif'] != $port_info['oif_id'] ){ + commitUpdatePortOIF( $port_info['id'], $_POST['local_oif']); + $port_info['oif_id'] = intval($_POST['local_oif']); + } } - else - $js_table .= "POIFC['${pair['type1']}-${pair['type2']}'] = 1;\n"; - - if ($matches) - { - if ($port_info['oif_id'] != $type_local) - commitUpdatePortOIF ($port_info['id'], $type_local); - if ($remote_port_info['oif_id'] != $type_remote) - commitUpdatePortOIF ($remote_port_info['id'], $type_remote); - linkPorts ($port_info['id'], $remote_port_info['id'], $_REQUEST['cable']); - showOneLiner - ( - 8, - array + if( $remote_port_info['iif_id'] != 1 ){ + // updateable + assertUIntArg ('remote_oif'); + if( $_POST['remote_oif'] != $remote_port_info['oif_id'] ){ + commitUpdatePortOIF( $remote_port_info['id'], $_POST['remote_oif']); + $remote_port_info['oif_id'] = intval($_POST['remote_oif']); + } + } + // now check compat + $compat = usePreparedSelectBlade('SELECT * FROM PortCompat WHERE ( type1 = ? AND type2 = ? ) OR ( type2 = ? AND type1= ? ) ', + array( $port_info['oif_id'],$remote_port_info['oif_id'],$port_info['oif_id'],$remote_port_info['oif_id']) )->fetchAll(); + if( !$compat ){ + throw new InvalidRequestArgException('oif_id', '', 'Ports are not compatible'); + }else{ + // :) + $cable_type = null; + if( $compat[0]['cable_chapter_id'] && $_POST['cable_type'] ){ + assertUIntArg('cable_type',true); + $cable_type = $_POST['cable_type']; + } + linkPorts( $port_info['id'], $remote_port_info['id'], $_POST['cable'], $cable_type, true ); + $dbxlink->commit(); + showOneLiner ( - formatPortLink ($port_info['id'], $port_info['name'], NULL, NULL), - formatPort ($remote_port_info), - ) - ); - addJS (<<<END -window.opener.location.reload(true); -window.close(); + 8, + array + ( + formatPortLink ($port_info['id'], $port_info['name'], NULL, NULL), + formatPort ($remote_port_info), + ) + ); + addJS (<<<END + window.opener.location.reload(true); + window.close(); END - , TRUE); - } - else - { - // JS code to display port compatibility hint - addJS (<<<END -POIFC = {}; -$js_table -$(document).ready(function () { - $('select.porttype').change(onPortTypeChange); - onPortTypeChange(); -}); -function onPortTypeChange() { - var key = $('*[name=port_type]')[0].value + '-' + $('*[name=remote_port_type]')[0].value; - if (POIFC[key] == 1) - { - $('#hint-not-compat').hide(); - $('#hint-compat').show(); - } - else - { - $('#hint-compat').hide(); - $('#hint-not-compat').show(); - } -} -END - , TRUE); - addCSS (<<<END -.compat-hint { - display: none; - font-size: 125%; -} -.compat-hint#hint-compat { - color: green; -} -.compat-hint#hint-not-compat { - color: #804040; -} -END - , TRUE); - // render port type editor form - echo '<form method=GET>'; - echo '<input type=hidden name="module" value="popup">'; - echo '<input type=hidden name="helper" value="portlist">'; - echo '<input type=hidden name="port" value="' . $port_info['id'] . '">'; - echo '<input type=hidden name="remote_port" value="' . $remote_port_info['id'] . '">'; - echo '<input type=hidden name="cable" value="' . htmlspecialchars ($_REQUEST['cable'], ENT_QUOTES) . '">'; - echo '<p>The ports you have selected are not compatible. Please select a compatible transceiver pair.'; - echo '<p>'; - echo formatPort ($port_info) . ' '; - if ($port_info['iif_id'] == 1) - { - echo formatPortIIFOIF ($port_info); - echo '<input type=hidden name="port_type" value="' . $port_info['oif_id'] . '">'; - } - else - { - echo '<label>' . $port_info['iif_name'] . ' '; - printSelect (getExistingPortTypeOptions ($port_info['id']), array ('class' => 'porttype', 'name' => 'port_type'), $type_local); - echo '</label>'; + , true); + return; } - echo ' — '; - if ($remote_port_info['iif_id'] == 1) - { - echo formatPortIIFOIF ($remote_port_info); - echo '<input type=hidden name="remote_port_type" value="' . $remote_port_info['oif_id'] . '">'; - } - else - { - echo '<label>' . $remote_port_info['iif_name'] . ' '; - printSelect (getExistingPortTypeOptions ($remote_port_info['id']), array ('class' => 'porttype', 'name' => 'remote_port_type'), $type_remote); - echo '</label>'; - } - echo ' ' . formatPort ($remote_port_info); - echo '<p class="compat-hint" id="hint-not-compat">✕ Not compatible port types</p>'; - echo '<p class="compat-hint" id="hint-compat">✔ Compatible port types</p>'; - echo '<p><input type=submit name="do_link" value="Link">'; + }catch( Exception $e ){ + $dbxlink->rollBack(); + throw $e; } + return renderPopupPortSelector(); } function renderPopupPortSelector() @@ -353,6 +347,7 @@ function renderPopupPortSelector() assertUIntArg ('port'); $port_id = $_REQUEST['port']; $port_info = getPortInfo ($port_id); + $in_rack = isset ($_REQUEST['in_rack']); // fill port filter structure @@ -379,11 +374,27 @@ function renderPopupPortSelector() ! empty ($filter['objects']) || ! empty ($filter['ports']) ) - $spare_ports = findSparePorts ($port_info, $filter); - + $ports_with_current = $ports = getSparePorts($port_info, $filter)->fetchAll(); + if( $port_info['remote_id'] ){ + $current = $ports_with_current[]= getPortInfo($port_info['remote_id']); + } + addJS('js/link_port_form.js'); + addJS(getLinkPortJavascript($port_info, $ports_with_current),true); + addCSS (<<<'END' +.reserved { + text-decoration: line-through; +} +.compatible { + background: #afa; +} +.incompatible { + background: #faa; +} +END + , TRUE); // display search form echo 'Link ' . formatPort ($port_info) . ' to...'; - echo '<form method=GET>'; + echo '<form method="POST">'; startPortlet ('Port list filter'); echo '<input type=hidden name="module" value="popup">'; echo '<input type=hidden name="helper" value="portlist">'; @@ -391,23 +402,59 @@ function renderPopupPortSelector() echo '<table align="center" valign="bottom"><tr>'; echo '<td class="tdleft"><label>Object name:<br><input type=text size=8 name="filter-obj" value="' . htmlspecialchars ($filter['objects'], ENT_QUOTES) . '"></label></td>'; echo '<td class="tdleft"><label>Port name:<br><input type=text size=6 name="filter-port" value="' . htmlspecialchars ($filter['ports'], ENT_QUOTES) . '"></label></td>'; + echo '</tr><tr>'; echo '<td class="tdleft" valign="bottom"><label><input type=checkbox name="in_rack"' . ($in_rack ? ' checked' : '') . '>Nearest racks</label></td>'; echo '<td valign="bottom"><input type=submit value="show ports"></td>'; echo '</tr></table>'; finishPortlet(); // display results - startPortlet ('Compatible spare ports'); - if (empty ($spare_ports)) - echo '(nothing found)'; - else - { - echo getSelect ($spare_ports, array ('name' => 'remote_port', 'size' => getConfigVar ('MAXSELSIZE')), NULL, FALSE); - echo "<p>Cable ID: <input type=text id=cable name=cable>"; - echo "<p><input type='submit' value='Link' name='do_link'>"; + startPortlet ('Link port'); + if( $ports_with_current ){ + echo '<div style="float: left;width:40%">'; + echo '<select name="remote_port" id="remote_port" size="',getConfigVar ('MAXSELSIZE'),'" style="width:100%">'; + if( $current ){ + echo '<optgroup label="current">'; + echo '<optgroup label=" ', htmlspecialchars($current['object_name']), '">'; + echo '<option value="',$current['id'],'" selected="selected">', htmlspecialchars($current['name'] ),'</option>'; + echo '</optgroup>'; + } + echo '<optgroup label="search result">'; + if( !$ports ){ + echo '<option disabled="disabled" value="">nothing found</option>'; + }else{ + $ports_by_object = array(); + foreach( $ports as $port ){ + if( !isset($ports_by_object[$port['object_name']]) ) $ports_by_object[$port['object_name']] = array(); + $ports_by_object[$port['object_name']][] = $port; + } + ksort( $ports_by_object ); + foreach( $ports_by_object as $name => $object_ports ){ + echo '<optgroup label=" ', htmlspecialchars($name), '">'; + foreach( sortPortList($object_ports, true) as $port ){ + echo '<option value="', $port['id'],'"',($port['reservation_comment'] ? ' class="reserved"':''),'>', htmlspecialchars($port['name']), '</option>'; + } + echo '</optgroup>'; + } + } + echo '</optgroup>'; + echo '</select>'; + echo '</div>'; + echo '<div style="margin-left: 41%">'; + echo '<p style="display:none">This port is reserved: <span id="reservation"></span></p>'; + echo '<p style="display:none"><label for="cable_type">Local Transceiver</label></br><select name="local_oif" id="local_oif" style="width:100%"></select></p>'; + echo '<p style="display:none"><label for="remote_oif">Remote Transceiver</label></br><select name="remote_oif" id="remote_oif" style="width:100%"></select></p>'; + echo '<p style="display:none"><label for="cable_type">Cable type</label></br><select name="cable_type" id="cable_type" style="width:100%"></select></p>'; + echo '<p><label for="cable">Cable ID: </label><br /><input type="text" id="cable" name="cable" style="width:100%" value="',htmlspecialchars($port_info['cableid']) ,'"/></p>'; + echo '<p><input type="submit" value="Link" name="do_link" id="submit"></p>'; + echo '<br style="clear:both" /></div>'; + }else{ + echo 'nothing found'; } + finishPortlet(); echo '</form>'; + echo '<br style="clear:both" />'; } function renderPopupIPv4Selector() diff -rupN '--exclude=.git' '--exclude=secret.php' racktables2/wwwroot/js/link_port_form.js racktables/wwwroot/js/link_port_form.js --- racktables2/wwwroot/js/link_port_form.js 1970-01-01 01:00:00.000000000 +0100 +++ racktables/wwwroot/js/link_port_form.js 2012-04-19 12:20:06.813828661 +0200 @@ -0,0 +1,147 @@ +function initializeLinkportForm( PORT, PORTS, INNER_OUTER_COMPATIBILITY, OUTER_COMPATIBILITY, CABLES, OIF ){ + var $remote_port = $('#remote_port'),$remote_oif = $('#remote_oif'),$local_oif = $('#local_oif'),$cable_type = $('#cable_type'), $submit = $('#submit'), $reservation = $('#reservation'); + var compatClass = function(a,b){ + if( !a || !b ){ + return ''; + }else if( !OUTER_COMPATIBILITY[a] || !OUTER_COMPATIBILITY[a][b] ){ + return 'incompatible'; + }else{ + return 'compatible'; + } + } + var updateSelects = function(){ + var rp = $remote_port.val(), ro = $remote_oif.val(), lo = $local_oif.val(), ct = $cable_type.val(); + if( ro ) ro = parseInt(ro); + if( !lo ){ + lo = PORT.oif_id; + }else{ + lo = parseInt(lo); + } + if( !rp ){ + rp = PORT.remote_id; + } + if( !ct ){ + ct = PORT.cable_dict_key; + } + //remote_oif + $remote_oif.empty(); + var remote_port; + if( rp ){ + remote_port = $.grep(PORTS,function(p){ return p.id == rp })[0]; + if( !ro || remote_port.iif_id == 1 || INNER_OUTER_COMPATIBILITY[ remote_port.iif_id ].indexOf(ro) == -1 ){ + ro = remote_port.oif_id; + } + if( remote_port.reservation == "" ){ + $reservation.closest('p').hide(); + }else{ + $reservation.text( remote_port.reservation ); + $reservation.closest('p').show(); + } + if( remote_port.iif_id != 1 ){ + $remote_oif.closest('p').show(); + $remote_oif.attr('disabled',false); + }else{ + $remote_oif.closest('p').hide(); + $remote_oif.attr('disabled',true); + } + var rps = INNER_OUTER_COMPATIBILITY[ remote_port.iif_id ]; + rps.sort(function(a,b){ + return OIF[a].localeCompare(OIF[b]); + }).forEach( function(oif){ + $('<option>').val(oif).text( OIF[oif] ).addClass( compatClass( oif, lo ) ).appendTo($remote_oif); + }); + $remote_oif.val(ro); + }else{ + $remote_oif.closest('p').hide(); + $remote_oif.attr('disabled',true); + } + //local_oif + $local_oif.empty(); + if( PORT.iif_id != 1 ){ + $local_oif.closest('p').show(); + $local_oif.attr('disabled',false); + }else{ + $local_oif.closest('p').hide(); + $local_oif.attr('disabled',true); + } + var lps = INNER_OUTER_COMPATIBILITY[ PORT.iif_id ]; + lps.sort(function(a,b){ + return OIF[a].localeCompare(OIF[b]); + }).forEach( function(oif){ + $('<option>').val(oif).text( OIF[oif] ).addClass( compatClass( oif, ro ) ).appendTo($local_oif); + }); + $local_oif.val(lo); + if( rp && lo && ro ){ + // cables and compat! + var comb = OUTER_COMPATIBILITY[ ro ] ? OUTER_COMPATIBILITY[ ro ][ lo ] : null; + if( !comb ){ + $submit.attr('disabled',true); + $submit.val('Incompatible transceiver'); + $cable_type.closest('p').hide(); + }else{ + if( comb.cable_chapter_id ){ + $cable_type.empty(); + var cables = CABLES[comb.cable_chapter_id]; + if( cables ){ + var other; + $.each(cables,function(i,group){ + if( group.name == 'other' ){ + other = group; + return ; + } + var g = $('<optgroup>').attr('label',group.name).appendTo($cable_type); + $.each(group.values, function(j, opt){ + $('<option>').val(opt.key).text(opt.value).appendTo(g); + }); + }); + if( other ){ + $.each(other.values, function(j, opt){ + $('<option>').val(opt.key).text(opt.value).appendTo($cable_type); + }); + } + } + $('<option>').val('').text('').appendTo($cable_type); + $cable_type.val(ct); + $cable_type.closest('p').show(); + }else{ + // compatible but no cables + $cable_type.closest('p').hide(); + } + $submit.attr('disabled',false); + $submit.val('Link'); + } + }else{ + if( !rp ){ + $submit.attr('disabled',true); + $submit.val('Select a port'); + } + $cable_type.closest('p').hide(); + } + } + updateSelects(); + $remote_port.change(updateSelects); + var changeTransceiver = function( $a, $b ){ + var av = $a.val(); + var bv = $b.val(); + if( !OUTER_COMPATIBILITY[av] ){ + return ; + } + if( OUTER_COMPATIBILITY[av][bv] ){ + return; + } + $b.children('option').each(function(i,o ){ + if( OUTER_COMPATIBILITY[ av ][ $(o).val() ] ){ + $b.val( $(o).val() ); + return false; + } + }); + } + $local_oif.change(function(){ + changeTransceiver($local_oif,$remote_oif); + updateSelects(); + }); + $remote_oif.change(function(){ + changeTransceiver($remote_oif,$local_oif); + updateSelects(); + }); +} track_cable_type_0.19.13.diff (31,959 bytes)
diff --git a/wwwroot/inc/database.php b/wwwroot/inc/database.php index d9f8e2c..1b9dd82 100644 --- a/wwwroot/inc/database.php +++ b/wwwroot/inc/database.php @@ -580,9 +580,10 @@ function getObjectPortsAndLinks ($object_id) { $portid = $ret[$tmpkey]['id']; $remote_id = NULL; - $query = "select porta, portb, cable from Link where porta = ? or portb = ?"; + $query = "select porta, portb, cable, cable_dict_key from Link where porta = ? or portb = ?"; $result = usePreparedSelectBlade ($query, array ($portid, $portid)); $cable = "CableID n/a"; + $cable_dict_key = null; if ($row = $result->fetch (PDO::FETCH_ASSOC)) { if ($portid != $row['porta']) @@ -590,6 +591,7 @@ function getObjectPortsAndLinks ($object_id) elseif ($portid != $row['portb']) $remote_id = $row['portb']; $cable = $row['cable']; + $cable_dict_key = $row['cable_dict_key']; } unset ($result); if ($remote_id) // there's a remote end here @@ -601,6 +603,7 @@ function getObjectPortsAndLinks ($object_id) $ret[$tmpkey]['remote_name'] = $row['name']; $ret[$tmpkey]['remote_object_id'] = $row['object_id']; $ret[$tmpkey]['cableid'] = $cable; + $ret[$tmpkey]['cable_dict_key'] = $cable_dict_key; } $ret[$tmpkey]['remote_id'] = $remote_id; unset ($result); @@ -1232,19 +1235,44 @@ function getAllIPv4Allocations () return $ret; } -function linkPorts ($porta, $portb, $cable = NULL) +function linkPorts ($porta, $portb, $cable = NULL, $cable_type = NULL, $update = false) { if ($porta == $portb) throw new InvalidArgException ('porta/portb', $porta, "Ports can't be the same"); global $dbxlink; - $dbxlink->exec ('LOCK TABLES Link WRITE'); + # the many locks are necessary. otherwise commitUnlinkPort could not access these tables: + $dbxlink->exec ('LOCK TABLES Link WRITE, Port AS pa WRITE, Port AS pb WRITE , RackObject WRITE'); $result = usePreparedSelectBlade ( - 'SELECT COUNT(*) FROM Link WHERE porta IN (?,?) OR portb IN (?,?)', + 'SELECT * FROM Link WHERE porta IN (?,?) OR portb IN (?,?)', array ($porta, $portb, $porta, $portb) ); - if ($result->fetchColumn () != 0) + if ( $update ) + { + $a = $result->fetch(); + if( $a ){ + if( ($a['porta'] == $porta && $a['portb'] == $portb) || ($a['portb'] == $porta && $a['porta'] == $portb) ) + { + // update! + $dbxlink->exec ('UNLOCK TABLES'); + usePreparedUpdateBlade( + 'Link', + array ( + 'cable' => ( mb_strlen ($cable) ? $cable : NULL ) , + 'cable_dict_key' => ( mb_strlen ($cable_type) ? intval($cable_type) : NULL ) + ), + array( 'porta' => $a['porta'], 'portb' => $a['portb'] ) + ); + + return ; + }else{ + commitUnlinkPort($porta); + commitUnlinkPort($portb); + } + } + } + else if ($result->fetch ()) { $dbxlink->exec ('UNLOCK TABLES'); return "Port ${porta} or ${portb} is already linked"; @@ -1263,7 +1291,8 @@ function linkPorts ($porta, $portb, $cable = NULL) ( 'porta' => $porta, 'portb' => $portb, - 'cable' => mb_strlen ($cable) ? $cable : NULL + 'cable' => mb_strlen ($cable) ? $cable : NULL, + 'cable_dict_key' => mb_strlen ($cable_type) ? intval($cable_type) : NULL ) ); $dbxlink->exec ('UNLOCK TABLES'); @@ -2311,9 +2340,10 @@ function commitUpdateUserAccount ($id, $new_username, $new_realname, $new_passwo function getPortOIFCompat () { $query = - "select type1, type2, d1.dict_value as type1name, d2.dict_value as type2name from " . + "select type1, type2, d1.dict_value as type1name, d2.dict_value as type2name, cable_chapter_id , c.name as cable_chapter_name from " . "PortCompat as pc inner join Dictionary as d1 on pc.type1 = d1.dict_key " . "inner join Dictionary as d2 on pc.type2 = d2.dict_key " . + "left join Chapter as c on pc.cable_chapter_id = c.id ". 'ORDER BY type1name, type2name'; $result = usePreparedSelectBlade ($query); return $result->fetchAll (PDO::FETCH_ASSOC); diff --git a/wwwroot/inc/interface.php b/wwwroot/inc/interface.php index 3e54e38..85fb28d 100644 --- a/wwwroot/inc/interface.php +++ b/wwwroot/inc/interface.php @@ -1164,7 +1164,24 @@ function renderPortsForObject ($object_id) 'object_id'=>$object_id)). "'>"; printImageHREF ('cut', 'Unlink this port'); - echo "</a></td>"; + echo "</a>"; + echo "<span"; + $helper_args = array + ( + 'port' => $port['id'], + ); + $popup_args = 'height=700, width=400, location=no, menubar=no, '. + 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no'; + echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args); + echo "\",\"findlink\",\"${popup_args}\");'"; + // end of onclick= + echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args); + echo "\",\"findlink\",\"${popup_args}\");'"; + // end of onclick= + echo '>'; + // end of <a> + printImageHREF ('plug', 'Link this port'); + echo "</span></td>"; } elseif (strlen ($port['reservation_comment'])) { @@ -3928,7 +3945,7 @@ function renderPortOIFCompatViewer() $order = 'odd'; $last_left_oif_id = NULL; echo '<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>'; - echo '<tr><th>From interface</th><th>To interface</th></tr>'; + echo '<tr><th>From interface</th><th>To interface</th><th>Cable</th></tr>'; foreach (getPortOIFCompat() as $pair) { if ($last_left_oif_id != $pair['type1']) @@ -3936,14 +3953,20 @@ function renderPortOIFCompatViewer() $order = $nextorder[$order]; $last_left_oif_id = $pair['type1']; } - echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td></tr>"; + echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td><td>${pair['cable_chapter_name']}</td></tr>"; } echo '</table>'; } function renderPortOIFCompatEditor() { - function printNewitemTR() + $raw_chaplist = getChapterList(); + $chaplist = array(); + $chaplist[0]=''; + foreach( $raw_chaplist as $chapter ){ + $chaplist[$chapter['id']]= htmlspecialchars( $chapter['name'] ); + } + function printNewitemTR($chaplist_local) { printOpFormIntro ('add'); echo '<tr><th class=tdleft>'; @@ -3952,6 +3975,10 @@ function renderPortOIFCompatEditor() printSelect (readChapter (CHAP_PORTTYPE), array ('name' => 'type1')); echo '</th><th class=tdleft>'; printSelect (readChapter (CHAP_PORTTYPE), array ('name' => 'type2')); + echo '</th><th class=tdleft>'; + printSelect( $chaplist_local, array( 'name' => 'cable_chapter_id' ) ); + echo '</th><th>'; + printImageHREF ('add', 'add pair', TRUE); echo '</th></tr></form>'; } @@ -3959,9 +3986,9 @@ function renderPortOIFCompatEditor() $last_left_oif_id = NULL; $order = 'odd'; echo '<br><table class=cooltable align=center border=0 cellpadding=5 cellspacing=0>'; - echo '<tr><th> </th><th>From Interface</th><th>To Interface</th></tr>'; + echo '<tr><th> </th><th>From Interface</th><th>To Interface</th><th>Cable</th><th></th></tr>'; if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') - printNewitemTR(); + printNewitemTR($chaplist); foreach (getPortOIFCompat() as $pair) { if ($last_left_oif_id != $pair['type1']) @@ -3969,13 +3996,19 @@ function renderPortOIFCompatEditor() $order = $nextorder[$order]; $last_left_oif_id = $pair['type1']; } + printOpFormIntro('upd',array('type1'=>$pair['type1'], 'type2' => $pair['type2']) ); echo "<tr class=row_${order}><td>"; echo '<a href="' . makeHrefProcess (array ('op' => 'del', 'type1' => $pair['type1'], 'type2' => $pair['type2'])) . '">'; printImageHREF ('delete', 'remove pair'); - echo "</a></td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td></tr>"; + echo "</a></td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td>"; + echo '<td>'; + printSelect($chaplist, array('name'=>'cable_chapter_id'), $pair['cable_chapter_id']); + echo '</td><td>'; + printImageHREF ('save', 'Save changes', TRUE); + echo "</td></tr></form>"; } if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') - printNewitemTR(); + printNewitemTR($chaplist); echo '</table>'; } diff --git a/wwwroot/inc/navigation.php b/wwwroot/inc/navigation.php index 7e25ec3..f32fdfc 100644 --- a/wwwroot/inc/navigation.php +++ b/wwwroot/inc/navigation.php @@ -453,6 +453,9 @@ $tabhandler['portmap']['default'] = 'renderPortOIFCompatViewer'; $tabhandler['portmap']['edit'] = 'renderPortOIFCompatEditor'; $ophandler['portmap']['edit']['add'] = 'tableHandler'; $ophandler['portmap']['edit']['del'] = 'tableHandler'; +$ophandler['portmap']['edit']['upd'] = 'tableHandler'; +$ophandler['portmap']['edit']['addPack'] = 'addOIFCompatPack'; +$ophandler['portmap']['edit']['delPack'] = 'delOIFCompatPack'; $page['portifcompat']['title'] = 'Enabled port types'; $page['portifcompat']['parent'] = 'config'; diff --git a/wwwroot/inc/ophandlers.php b/wwwroot/inc/ophandlers.php index 2fad512..3fc2e15 100644 --- a/wwwroot/inc/ophandlers.php +++ b/wwwroot/inc/ophandlers.php @@ -272,6 +272,21 @@ $opspec_list['portmap-edit-add'] = array ( array ('url_argname' => 'type1', 'assertion' => 'uint'), array ('url_argname' => 'type2', 'assertion' => 'uint'), + array ('url_argname' => 'cable_chapter_id', 'assertion' => 'uint0', 'if_empty' => 'NULL' ) + ), +); +$opspec_list['portmap-edit-upd'] = array +( + 'table' => 'PortCompat', + 'action' => 'UPDATE', + 'set_arglist' => array + ( + array ('url_argname' => 'cable_chapter_id', 'assertion' => 'uint0', 'if_empty' => 'NULL'), + ), + 'where_arglist' => array + ( + array ('url_argname' => 'type1', 'assertion' => 'uint'), + array ('url_argname' => 'type2', 'assertion' => 'uint') ), ); $opspec_list['portmap-edit-del'] = array diff --git a/wwwroot/inc/popup.php b/wwwroot/inc/popup.php index 15244cb..d9bb8a8 100644 --- a/wwwroot/inc/popup.php +++ b/wwwroot/inc/popup.php @@ -34,7 +34,7 @@ function getProximateRacks ($rack_id, $proximity = 0) return $ret; } -function findSparePorts ($port_info, $filter) +function getSparePorts($port_info, $filter) { $qparams = array (); $query = " @@ -45,37 +45,34 @@ SELECT p.iif_id, p.type as oif_id, pii.iif_name, - d.dict_value as oif_name, p.object_id, o.name as object_name FROM Port p INNER JOIN RackObject o ON o.id = p.object_id INNER JOIN PortInnerInterface pii ON p.iif_id = pii.id -INNER JOIN Dictionary d ON d.dict_key = p.type "; // porttype filter (non-strict match) $query .= " INNER JOIN ( - SELECT Port.id FROM Port + SELECT p2.id FROM Port p2 INNER JOIN ( - SELECT DISTINCT pic2.iif_id + SELECT DISTINCT pic2.iif_id, pic2.oif_id FROM PortInterfaceCompat pic2 INNER JOIN PortCompat pc ON pc.type2 = pic2.oif_id "; if ($port_info['iif_id'] != 1) { - $query .= " INNER JOIN PortInterfaceCompat pic ON pic.oif_id = pc.type1 WHERE pic.iif_id = ? AND "; + $query .= " INNER JOIN PortInterfaceCompat pic ON pic.oif_id = pc.type1 WHERE pic.iif_id = ? "; $qparams[] = $port_info['iif_id']; } else { - $query .= " WHERE pc.type1 = ? AND "; + $query .= " WHERE pc.type1 = ? "; $qparams[] = $port_info['oif_id']; } $query .= " - pic2.iif_id <> 1 - ) AS sub1 USING (iif_id) + ) AS sub1 ON p2.iif_id = sub1.iif_id AND ( p2.iif_id <> 1 OR p2.type = sub1.oif_id ) UNION SELECT Port.id FROM Port @@ -113,42 +110,104 @@ INNER JOIN ( // ordering $query .= ' ORDER BY o.name'; - $ret = array(); - $result = usePreparedSelectBlade ($query, $qparams); - - $rows_by_pn = array(); - $prev_object_id = NULL; + return usePreparedSelectBlade ($query, $qparams); +} + +function getLinkPortJavascript($port_info, $ports) +{ + $required_oif = array(); + $required_iif = array(); + $required_chapter = array(); + if( count($ports) == 0 ){ + return ''; + } + $jsports = array(); + $compat = array(); + $buffer = array('$(function($){'); + $buffer[]='var PORT = { id:'.$port_info['id'].', name:"'.addslashes($port_info['name']).'",'; + $buffer[]=' object_name:"'.addslashes($port_info['object_name']).'",'; + $buffer[]=' oif_id:'.($port_info['oif_id'] ? $port_info['oif_id'] : 'null').', '; + $buffer[]=' iif_id:'.$port_info['iif_id'].', '; + $buffer[]=' cable:"'.addslashes($port_info['cableid']).'", '; + $buffer[]=' cable_dict_key:'.($port_info['cable_dict_key'] ? $port_info['cable_dict_key'] : 'null' ).', '; + $buffer[]=' remote_id:'.($port_info['remote_id'] ? $port_info['remote_id'] : 'null').'};'; + $buffer[]='var PORTS = ['; - // fetch port rows from the DB - while (TRUE) + $required_iif[$port_info['iif_id']]=true; + if( $port_info['oif_id'] ) $required_oif[$port_info['oif_id']]=true; + foreach( $ports as $port ){ + $required_iif[ $port['iif_id'] ]=true; + if( $port['oif_id'] ) $required_oif[$port['oif_id']]=true; + $buffer[]=' { id:'.$port['id'].', name:"'.addslashes($port['name']).'", object_name:"'.addslashes($port['object_name']).'", oif_id:'.($port['oif_id'] ? $port['oif_id'] : 'null').', iif_id:'.$port['iif_id'].', reservation:"'.addslashes($port['reservation_comment']).'"},'; + } + $buffer[]='];'; + + $incom = usePreparedSelectBlade('SELECT * FROM PortInterfaceCompat WHERE iif_id IN ('.questionMarks(count($required_iif)).') ORDER BY iif_id ', array_keys($required_iif)); + $buffer[]='var INNER_OUTER_COMPATIBILITY = {'; + $last_iif_id = null; + foreach( $incom as $in ) { - $row = $result->fetch (PDO::FETCH_ASSOC); - if (isset ($prev_object_id) and (! $row or $row['object_id'] != $prev_object_id)) + if( $in['iif_id'] != $last_iif_id ) { - // handle sorted object's portlist - foreach (sortPortList ($rows_by_pn) as $ports_subarray) - foreach ($ports_subarray as $port_row) - { - $port_description = $port_row['object_name'] . ' -- ' . $port_row['name']; - if (count ($ports_subarray) > 1) - { - $if_type = $port_row['iif_id'] == 1 ? $port_row['oif_name'] : $port_row['iif_name']; - $port_description .= " ($if_type)"; - } - if (! empty ($port_row['reservation_comment'])) - $port_description .= ' -- ' . $port_row['reservation_comment']; - $ret[$port_row['id']] = $port_description; - } - $rows_by_pn = array(); + if( $last_iif_id != null ) + { + $buffer[]=' ],'; + } + $buffer[]=' '.$in['iif_id'].': ['; + $last_iif_id = $in['iif_id']; } - $prev_object_id = $row['object_id']; - if ($row) - $rows_by_pn[$row['name']][] = $row; - else - break; + $required_oif[$in['oif_id']]=true; + $buffer[]=' '.$in['oif_id'].','; } + if( $last_iif_id != null ) + { + $buffer[]=' ]'; + } + $buffer[]='};'; - return $ret; + $query ='SELECT * FROM PortCompat pc'. + ' WHERE type1 IN ('.questionMarks(count($required_oif)).') AND type2 IN ('.questionMarks(count($required_oif)).');'; + $types = usePreparedSelectBlade($query, array_merge( array_keys($required_oif), array_keys($required_oif) ) ); + foreach( $types as $type ){ + @$compat[ $type['type1'] ][ $type['type2'] ] = array( 'cable_chapter_id'=> ($type['cable_chapter_id'] ? intval($type['cable_chapter_id']) : 'null') ); + if( $type['cable_chapter_id'] ) $required_chapter[intval($type['cable_chapter_id'])] = true; + } + $buffer[]='var OUTER_COMPATIBILITY = {'; + foreach( $compat as $a => $sub ){ + $buffer[]=' '.$a.': { '; + foreach( $sub as $b => $info ){ + $buffer[]=' '.$b.': {cable_chapter_id:'.$info['cable_chapter_id'].'},'; + } + $buffer[]=' },'; + } + $buffer[]='};'; + if( $required_chapter ){ + $buffer[]='var CABLES = {'; + $last_chapter_id = -1; + foreach( array_keys($required_chapter) as $chapter_id ){ + $chapter = cookOptgroups( readChapter( $chapter_id, 'o' ) ); + $buffer[]= $chapter_id.': ['; + foreach( $chapter as $group => $entries ){ + $buffer[]= ' {name: "'.addslashes($group).'", values:['; + foreach( $entries as $key => $value ){ + $buffer[]= ' {key: '.$key.', value: "'.addslashes($value).'"},'; + } + $buffer[]=' ]},'; + } + $buffer[]='],'; + } + $buffer[]='};'; + }else{ + $buffer[]='var CABLES = {};'; + } + $oifs = usePreparedSelectBlade('SELECT dict_key,dict_value FROM Dictionary WHERE chapter_id = 2 AND dict_key IN ('.questionMarks(count($required_oif)).');', array_keys($required_oif)); + $buffer[]='var OIF = {};'; + foreach( $oifs as $oif ){ + $buffer[]='OIF['.$oif['dict_key'].']= "'.addslashes($oif['dict_value']).'";'; + } + $buffer[]=' initializeLinkportForm( PORT, PORTS, INNER_OUTER_COMPATIBILITY, OUTER_COMPATIBILITY, CABLES, OIF )'; + $buffer[]='});'; + return join("\n",$buffer); } // Return a list of all objects which are possible parents @@ -221,131 +280,66 @@ function renderPopupObjectSelector() function handlePopupPortLink() { + global $dbxlink; assertUIntArg ('port'); assertUIntArg ('remote_port'); assertStringArg ('cable', TRUE); $port_info = getPortInfo ($_REQUEST['port']); $remote_port_info = getPortInfo ($_REQUEST['remote_port']); - $POIFC = getPortOIFCompat(); - if (isset ($_REQUEST['port_type']) and isset ($_REQUEST['remote_port_type'])) - { - $type_local = $_REQUEST['port_type']; - $type_remote = $_REQUEST['remote_port_type']; - } - else - { - $type_local = $port_info['oif_id']; - $type_remote = $remote_port_info['oif_id']; - } - $matches = FALSE; - $js_table = ''; - foreach ($POIFC as $pair) - if ($pair['type1'] == $type_local && $pair['type2'] == $type_remote) - { - $matches = TRUE; - break; + $dbxlink->beginTransaction(); + try{ + + if( $port_info['iif_id'] != 1 ){ + // updateable + assertUIntArg ('local_oif'); + if( $_POST['local_oif'] != $port_info['oif_id'] ){ + commitUpdatePortOIF( $port_info['id'], $_POST['local_oif']); + $port_info['oif_id'] = intval($_POST['local_oif']); + } } - else - $js_table .= "POIFC['${pair['type1']}-${pair['type2']}'] = 1;\n"; - - if ($matches) - { - if ($port_info['oif_id'] != $type_local) - commitUpdatePortOIF ($port_info['id'], $type_local); - if ($remote_port_info['oif_id'] != $type_remote) - commitUpdatePortOIF ($remote_port_info['id'], $type_remote); - linkPorts ($port_info['id'], $remote_port_info['id'], $_REQUEST['cable']); - showSuccess - ( - sprintf + if( $remote_port_info['iif_id'] != 1 ){ + // updateable + assertUIntArg ('remote_oif'); + if( $_POST['remote_oif'] != $remote_port_info['oif_id'] ){ + commitUpdatePortOIF( $remote_port_info['id'], $_POST['remote_oif']); + $remote_port_info['oif_id'] = intval($_POST['remote_oif']); + } + } + // now check compat + $compat = usePreparedSelectBlade('SELECT * FROM PortCompat WHERE ( type1 = ? AND type2 = ? ) OR ( type2 = ? AND type1= ? ) ', + array( $port_info['oif_id'],$remote_port_info['oif_id'],$port_info['oif_id'],$remote_port_info['oif_id']) )->fetchAll(); + if( !$compat ){ + throw new InvalidRequestArgException('oif_id', '', 'Ports are not compatible'); + }else{ + // :) + $cable_type = null; + if( $compat[0]['cable_chapter_id'] && $_POST['cable_type'] ){ + assertUIntArg('cable_type',true); + $cable_type = $_POST['cable_type']; + } + linkPorts( $port_info['id'], $remote_port_info['id'], $_POST['cable'], $cable_type, true ); + $dbxlink->commit(); + showSuccess ( + sprintf + ( 'Port %s successfully linked with port %s', formatPortLink ($port_info['id'], $port_info['name'], NULL, NULL), formatPort ($remote_port_info) - ) - ); - addJS (<<<END -window.opener.location.reload(true); -window.close(); + ) + ); + addJS (<<<END + window.opener.location.reload(true); + window.close(); END - , TRUE); - } - else - { - // JS code to display port compatibility hint - addJS (<<<END -POIFC = {}; -$js_table -$(document).ready(function () { - $('select.porttype').change(onPortTypeChange); - onPortTypeChange(); -}); -function onPortTypeChange() { - var key = $('*[name=port_type]')[0].value + '-' + $('*[name=remote_port_type]')[0].value; - if (POIFC[key] == 1) - { - $('#hint-not-compat').hide(); - $('#hint-compat').show(); - } - else - { - $('#hint-compat').hide(); - $('#hint-not-compat').show(); - } -} -END - , TRUE); - addCSS (<<<END -.compat-hint { - display: none; - font-size: 125%; -} -.compat-hint#hint-compat { - color: green; -} -.compat-hint#hint-not-compat { - color: #804040; -} -END - , TRUE); - // render port type editor form - echo '<form method=GET>'; - echo '<input type=hidden name="module" value="popup">'; - echo '<input type=hidden name="helper" value="portlist">'; - echo '<input type=hidden name="port" value="' . $port_info['id'] . '">'; - echo '<input type=hidden name="remote_port" value="' . $remote_port_info['id'] . '">'; - echo '<input type=hidden name="cable" value="' . htmlspecialchars ($_REQUEST['cable'], ENT_QUOTES) . '">'; - echo '<p>The ports you have selected are not compatible. Please select a compatible transceiver pair.'; - echo '<p>'; - echo formatPort ($port_info) . ' '; - if ($port_info['iif_id'] == 1) - { - echo formatPortIIFOIF ($port_info); - echo '<input type=hidden name="port_type" value="' . $port_info['oif_id'] . '">'; - } - else - { - echo '<label>' . $port_info['iif_name'] . ' '; - printSelect (getExistingPortTypeOptions ($port_info['id']), array ('class' => 'porttype', 'name' => 'port_type'), $type_local); - echo '</label>'; + , true); + return; } - echo ' — '; - if ($remote_port_info['iif_id'] == 1) - { - echo formatPortIIFOIF ($remote_port_info); - echo '<input type=hidden name="remote_port_type" value="' . $remote_port_info['oif_id'] . '">'; - } - else - { - echo '<label>' . $remote_port_info['iif_name'] . ' '; - printSelect (getExistingPortTypeOptions ($remote_port_info['id']), array ('class' => 'porttype', 'name' => 'remote_port_type'), $type_remote); - echo '</label>'; - } - echo ' ' . formatPort ($remote_port_info); - echo '<p class="compat-hint" id="hint-not-compat">✕ Not compatible port types</p>'; - echo '<p class="compat-hint" id="hint-compat">✔ Compatible port types</p>'; - echo '<p><input type=submit name="do_link" value="Link">'; + }catch( Exception $e ){ + $dbxlink->rollBack(); + throw $e; } + return renderPopupPortSelector(); } function renderPopupPortSelector() @@ -353,6 +347,7 @@ function renderPopupPortSelector() assertUIntArg ('port'); $port_id = $_REQUEST['port']; $port_info = getPortInfo ($port_id); + $in_rack = isset ($_REQUEST['in_rack']); // fill port filter structure @@ -379,11 +374,34 @@ function renderPopupPortSelector() ! empty ($filter['objects']) || ! empty ($filter['ports']) ) - $spare_ports = findSparePorts ($port_info, $filter); + $ports_with_current = $ports = getSparePorts($port_info, $filter)->fetchAll(); + if( $port_info['linked'] ){ + $link = usePreparedSelectBlade('SELECT * FROM Link WHERE porta = ? OR portb = ?', array($port_id, $port_id))->fetch(PDO::FETCH_ASSOC); + + $current = getPortInfo( ($link['porta'] == $port_id) ? $link['portb'] : $link['porta'] ); + $port_info['cableid'] = $current['cableid'] = $link['cable']; + $port_info['cable_dict_key'] = $current['cable_dict_key'] = $link['cable_dict_key']; + $port_info['remote_id'] = $current['id']; + $ports_with_current[] = $current; + } + addJS('js/link_port_form.js'); + addJS(getLinkPortJavascript($port_info, $ports_with_current),true); + addCSS (<<<'END' +.reserved { + text-decoration: line-through; +} +.compatible { + background: #afa; +} +.incompatible { + background: #faa; +} +END + , TRUE); // display search form echo 'Link ' . formatPort ($port_info) . ' to...'; - echo '<form method=GET>'; + echo '<form method="POST">'; startPortlet ('Port list filter'); echo '<input type=hidden name="module" value="popup">'; echo '<input type=hidden name="helper" value="portlist">'; @@ -391,23 +409,59 @@ function renderPopupPortSelector() echo '<table align="center" valign="bottom"><tr>'; echo '<td class="tdleft"><label>Object name:<br><input type=text size=8 name="filter-obj" value="' . htmlspecialchars ($filter['objects'], ENT_QUOTES) . '"></label></td>'; echo '<td class="tdleft"><label>Port name:<br><input type=text size=6 name="filter-port" value="' . htmlspecialchars ($filter['ports'], ENT_QUOTES) . '"></label></td>'; + echo '</tr><tr>'; echo '<td class="tdleft" valign="bottom"><label><input type=checkbox name="in_rack"' . ($in_rack ? ' checked' : '') . '>Nearest racks</label></td>'; echo '<td valign="bottom"><input type=submit value="show ports"></td>'; echo '</tr></table>'; finishPortlet(); // display results - startPortlet ('Compatible spare ports'); - if (empty ($spare_ports)) - echo '(nothing found)'; - else - { - echo getSelect ($spare_ports, array ('name' => 'remote_port', 'size' => getConfigVar ('MAXSELSIZE')), NULL, FALSE); - echo "<p>Cable ID: <input type=text id=cable name=cable>"; - echo "<p><input type='submit' value='Link' name='do_link'>"; + startPortlet ('Link port'); + if( $ports_with_current ){ + echo '<div style="float: left;width:40%">'; + echo '<select name="remote_port" id="remote_port" size="',getConfigVar ('MAXSELSIZE'),'" style="width:100%">'; + if( $current ){ + echo '<optgroup label="current">'; + echo '<optgroup label=" ', htmlspecialchars($current['object_name']), '">'; + echo '<option value="',$current['id'],'" selected="selected">', htmlspecialchars($current['name'] ),'</option>'; + echo '</optgroup>'; + } + echo '<optgroup label="search result">'; + if( !$ports ){ + echo '<option disabled="disabled" value="">nothing found</option>'; + }else{ + $ports_by_object = array(); + foreach( $ports as $port ){ + if( !isset($ports_by_object[$port['object_name']]) ) $ports_by_object[$port['object_name']] = array(); + $ports_by_object[$port['object_name']][] = $port; + } + ksort( $ports_by_object ); + foreach( $ports_by_object as $name => $object_ports ){ + echo '<optgroup label=" ', htmlspecialchars($name), '">'; + foreach( sortPortList($object_ports, true) as $port ){ + echo '<option value="', $port['id'],'"',($port['reservation_comment'] ? ' class="reserved"':''),'>', htmlspecialchars($port['name']), '</option>'; + } + echo '</optgroup>'; + } + } + echo '</optgroup>'; + echo '</select>'; + echo '</div>'; + echo '<div style="margin-left: 41%">'; + echo '<p style="display:none">This port is reserved: <span id="reservation"></span></p>'; + echo '<p style="display:none"><label for="cable_type">Local Transceiver</label></br><select name="local_oif" id="local_oif" style="width:100%"></select></p>'; + echo '<p style="display:none"><label for="remote_oif">Remote Transceiver</label></br><select name="remote_oif" id="remote_oif" style="width:100%"></select></p>'; + echo '<p style="display:none"><label for="cable_type">Cable type</label></br><select name="cable_type" id="cable_type" style="width:100%"></select></p>'; + echo '<p><label for="cable">Cable ID: </label><br /><input type="text" id="cable" name="cable" style="width:100%" value="',htmlspecialchars($port_info['cableid']) ,'"/></p>'; + echo '<p><input type="submit" value="Link" name="do_link" id="submit"></p>'; + echo '<br style="clear:both" /></div>'; + }else{ + echo 'nothing found'; } + finishPortlet(); echo '</form>'; + echo '<br style="clear:both" />'; } function renderPopupIPv4Selector() diff --git a/wwwroot/js/link_port_form.js b/wwwroot/js/link_port_form.js new file mode 100644 index 0000000..0cf45a2 --- /dev/null +++ b/wwwroot/js/link_port_form.js @@ -0,0 +1,147 @@ +function initializeLinkportForm( PORT, PORTS, INNER_OUTER_COMPATIBILITY, OUTER_COMPATIBILITY, CABLES, OIF ){ + var $remote_port = $('#remote_port'),$remote_oif = $('#remote_oif'),$local_oif = $('#local_oif'),$cable_type = $('#cable_type'), $submit = $('#submit'), $reservation = $('#reservation'); + var compatClass = function(a,b){ + if( !a || !b ){ + return ''; + }else if( !OUTER_COMPATIBILITY[a] || !OUTER_COMPATIBILITY[a][b] ){ + return 'incompatible'; + }else{ + return 'compatible'; + } + } + var updateSelects = function(){ + var rp = $remote_port.val(), ro = $remote_oif.val(), lo = $local_oif.val(), ct = $cable_type.val(); + if( ro ) ro = parseInt(ro); + if( !lo ){ + lo = PORT.oif_id; + }else{ + lo = parseInt(lo); + } + if( !rp ){ + rp = PORT.remote_id; + } + if( !ct ){ + ct = PORT.cable_dict_key; + } + //remote_oif + $remote_oif.empty(); + var remote_port; + if( rp ){ + remote_port = $.grep(PORTS,function(p){ return p.id == rp })[0]; + if( !ro || remote_port.iif_id == 1 || INNER_OUTER_COMPATIBILITY[ remote_port.iif_id ].indexOf(ro) == -1 ){ + ro = remote_port.oif_id; + } + if( remote_port.reservation == "" ){ + $reservation.closest('p').hide(); + }else{ + $reservation.text( remote_port.reservation ); + $reservation.closest('p').show(); + } + if( remote_port.iif_id != 1 ){ + $remote_oif.closest('p').show(); + $remote_oif.attr('disabled',false); + }else{ + $remote_oif.closest('p').hide(); + $remote_oif.attr('disabled',true); + } + var rps = INNER_OUTER_COMPATIBILITY[ remote_port.iif_id ]; + rps.sort(function(a,b){ + return OIF[a].localeCompare(OIF[b]); + }).forEach( function(oif){ + $('<option>').val(oif).text( OIF[oif] ).addClass( compatClass( oif, lo ) ).appendTo($remote_oif); + }); + $remote_oif.val(ro); + }else{ + $remote_oif.closest('p').hide(); + $remote_oif.attr('disabled',true); + } + //local_oif + $local_oif.empty(); + if( PORT.iif_id != 1 ){ + $local_oif.closest('p').show(); + $local_oif.attr('disabled',false); + }else{ + $local_oif.closest('p').hide(); + $local_oif.attr('disabled',true); + } + var lps = INNER_OUTER_COMPATIBILITY[ PORT.iif_id ]; + lps.sort(function(a,b){ + return OIF[a].localeCompare(OIF[b]); + }).forEach( function(oif){ + $('<option>').val(oif).text( OIF[oif] ).addClass( compatClass( oif, ro ) ).appendTo($local_oif); + }); + $local_oif.val(lo); + if( rp && lo && ro ){ + // cables and compat! + var comb = OUTER_COMPATIBILITY[ ro ] ? OUTER_COMPATIBILITY[ ro ][ lo ] : null; + if( !comb ){ + $submit.attr('disabled',true); + $submit.val('Incompatible transceiver'); + $cable_type.closest('p').hide(); + }else{ + if( comb.cable_chapter_id ){ + $cable_type.empty(); + var cables = CABLES[comb.cable_chapter_id]; + if( cables ){ + var other; + $.each(cables,function(i,group){ + if( group.name == 'other' ){ + other = group; + return ; + } + var g = $('<optgroup>').attr('label',group.name).appendTo($cable_type); + $.each(group.values, function(j, opt){ + $('<option>').val(opt.key).text(opt.value).appendTo(g); + }); + }); + if( other ){ + $.each(other.values, function(j, opt){ + $('<option>').val(opt.key).text(opt.value).appendTo($cable_type); + }); + } + } + $('<option>').val('').text('').appendTo($cable_type); + $cable_type.val(ct); + $cable_type.closest('p').show(); + }else{ + // compatible but no cables + $cable_type.closest('p').hide(); + } + $submit.attr('disabled',false); + $submit.val('Link'); + } + }else{ + if( !rp ){ + $submit.attr('disabled',true); + $submit.val('Select a port'); + } + $cable_type.closest('p').hide(); + } + } + updateSelects(); + $remote_port.change(updateSelects); + var changeTransceiver = function( $a, $b ){ + var av = $a.val(); + var bv = $b.val(); + if( !OUTER_COMPATIBILITY[av] ){ + return ; + } + if( OUTER_COMPATIBILITY[av][bv] ){ + return; + } + $b.children('option').each(function(i,o ){ + if( OUTER_COMPATIBILITY[ av ][ $(o).val() ] ){ + $b.val( $(o).val() ); + return false; + } + }); + } + $local_oif.change(function(){ + changeTransceiver($local_oif,$remote_oif); + updateSelects(); + }); + $remote_oif.change(function(){ + changeTransceiver($remote_oif,$local_oif); + updateSelects(); + }); +} track_cable_type_0.19.13.correct.diff (32,223 bytes)
diff --git a/wwwroot/inc/database.php b/wwwroot/inc/database.php index d9f8e2c..1b9dd82 100644 --- a/wwwroot/inc/database.php +++ b/wwwroot/inc/database.php @@ -580,9 +580,10 @@ function getObjectPortsAndLinks ($object_id) { $portid = $ret[$tmpkey]['id']; $remote_id = NULL; - $query = "select porta, portb, cable from Link where porta = ? or portb = ?"; + $query = "select porta, portb, cable, cable_dict_key from Link where porta = ? or portb = ?"; $result = usePreparedSelectBlade ($query, array ($portid, $portid)); $cable = "CableID n/a"; + $cable_dict_key = null; if ($row = $result->fetch (PDO::FETCH_ASSOC)) { if ($portid != $row['porta']) @@ -590,6 +591,7 @@ function getObjectPortsAndLinks ($object_id) elseif ($portid != $row['portb']) $remote_id = $row['portb']; $cable = $row['cable']; + $cable_dict_key = $row['cable_dict_key']; } unset ($result); if ($remote_id) // there's a remote end here @@ -601,6 +603,7 @@ function getObjectPortsAndLinks ($object_id) $ret[$tmpkey]['remote_name'] = $row['name']; $ret[$tmpkey]['remote_object_id'] = $row['object_id']; $ret[$tmpkey]['cableid'] = $cable; + $ret[$tmpkey]['cable_dict_key'] = $cable_dict_key; } $ret[$tmpkey]['remote_id'] = $remote_id; unset ($result); @@ -1232,19 +1235,44 @@ function getAllIPv4Allocations () return $ret; } -function linkPorts ($porta, $portb, $cable = NULL) +function linkPorts ($porta, $portb, $cable = NULL, $cable_type = NULL, $update = false) { if ($porta == $portb) throw new InvalidArgException ('porta/portb', $porta, "Ports can't be the same"); global $dbxlink; - $dbxlink->exec ('LOCK TABLES Link WRITE'); + # the many locks are necessary. otherwise commitUnlinkPort could not access these tables: + $dbxlink->exec ('LOCK TABLES Link WRITE, Port AS pa WRITE, Port AS pb WRITE , RackObject WRITE'); $result = usePreparedSelectBlade ( - 'SELECT COUNT(*) FROM Link WHERE porta IN (?,?) OR portb IN (?,?)', + 'SELECT * FROM Link WHERE porta IN (?,?) OR portb IN (?,?)', array ($porta, $portb, $porta, $portb) ); - if ($result->fetchColumn () != 0) + if ( $update ) + { + $a = $result->fetch(); + if( $a ){ + if( ($a['porta'] == $porta && $a['portb'] == $portb) || ($a['portb'] == $porta && $a['porta'] == $portb) ) + { + // update! + $dbxlink->exec ('UNLOCK TABLES'); + usePreparedUpdateBlade( + 'Link', + array ( + 'cable' => ( mb_strlen ($cable) ? $cable : NULL ) , + 'cable_dict_key' => ( mb_strlen ($cable_type) ? intval($cable_type) : NULL ) + ), + array( 'porta' => $a['porta'], 'portb' => $a['portb'] ) + ); + + return ; + }else{ + commitUnlinkPort($porta); + commitUnlinkPort($portb); + } + } + } + else if ($result->fetch ()) { $dbxlink->exec ('UNLOCK TABLES'); return "Port ${porta} or ${portb} is already linked"; @@ -1263,7 +1291,8 @@ function linkPorts ($porta, $portb, $cable = NULL) ( 'porta' => $porta, 'portb' => $portb, - 'cable' => mb_strlen ($cable) ? $cable : NULL + 'cable' => mb_strlen ($cable) ? $cable : NULL, + 'cable_dict_key' => mb_strlen ($cable_type) ? intval($cable_type) : NULL ) ); $dbxlink->exec ('UNLOCK TABLES'); @@ -2311,9 +2340,10 @@ function commitUpdateUserAccount ($id, $new_username, $new_realname, $new_passwo function getPortOIFCompat () { $query = - "select type1, type2, d1.dict_value as type1name, d2.dict_value as type2name from " . + "select type1, type2, d1.dict_value as type1name, d2.dict_value as type2name, cable_chapter_id , c.name as cable_chapter_name from " . "PortCompat as pc inner join Dictionary as d1 on pc.type1 = d1.dict_key " . "inner join Dictionary as d2 on pc.type2 = d2.dict_key " . + "left join Chapter as c on pc.cable_chapter_id = c.id ". 'ORDER BY type1name, type2name'; $result = usePreparedSelectBlade ($query); return $result->fetchAll (PDO::FETCH_ASSOC); diff --git a/wwwroot/inc/interface.php b/wwwroot/inc/interface.php index 3e54e38..85fb28d 100644 --- a/wwwroot/inc/interface.php +++ b/wwwroot/inc/interface.php @@ -1164,7 +1164,24 @@ function renderPortsForObject ($object_id) 'object_id'=>$object_id)). "'>"; printImageHREF ('cut', 'Unlink this port'); - echo "</a></td>"; + echo "</a>"; + echo "<span"; + $helper_args = array + ( + 'port' => $port['id'], + ); + $popup_args = 'height=700, width=400, location=no, menubar=no, '. + 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no'; + echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args); + echo "\",\"findlink\",\"${popup_args}\");'"; + // end of onclick= + echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args); + echo "\",\"findlink\",\"${popup_args}\");'"; + // end of onclick= + echo '>'; + // end of <a> + printImageHREF ('plug', 'Link this port'); + echo "</span></td>"; } elseif (strlen ($port['reservation_comment'])) { @@ -3928,7 +3945,7 @@ function renderPortOIFCompatViewer() $order = 'odd'; $last_left_oif_id = NULL; echo '<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>'; - echo '<tr><th>From interface</th><th>To interface</th></tr>'; + echo '<tr><th>From interface</th><th>To interface</th><th>Cable</th></tr>'; foreach (getPortOIFCompat() as $pair) { if ($last_left_oif_id != $pair['type1']) @@ -3936,14 +3953,20 @@ function renderPortOIFCompatViewer() $order = $nextorder[$order]; $last_left_oif_id = $pair['type1']; } - echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td></tr>"; + echo "<tr class=row_${order}><td>${pair['type1name']}</td><td>${pair['type2name']}</td><td>${pair['cable_chapter_name']}</td></tr>"; } echo '</table>'; } function renderPortOIFCompatEditor() { - function printNewitemTR() + $raw_chaplist = getChapterList(); + $chaplist = array(); + $chaplist[0]=''; + foreach( $raw_chaplist as $chapter ){ + $chaplist[$chapter['id']]= htmlspecialchars( $chapter['name'] ); + } + function printNewitemTR($chaplist_local) { printOpFormIntro ('add'); echo '<tr><th class=tdleft>'; @@ -3952,6 +3975,10 @@ function renderPortOIFCompatEditor() printSelect (readChapter (CHAP_PORTTYPE), array ('name' => 'type1')); echo '</th><th class=tdleft>'; printSelect (readChapter (CHAP_PORTTYPE), array ('name' => 'type2')); + echo '</th><th class=tdleft>'; + printSelect( $chaplist_local, array( 'name' => 'cable_chapter_id' ) ); + echo '</th><th>'; + printImageHREF ('add', 'add pair', TRUE); echo '</th></tr></form>'; } @@ -3959,9 +3986,9 @@ function renderPortOIFCompatEditor() $last_left_oif_id = NULL; $order = 'odd'; echo '<br><table class=cooltable align=center border=0 cellpadding=5 cellspacing=0>'; - echo '<tr><th> </th><th>From Interface</th><th>To Interface</th></tr>'; + echo '<tr><th> </th><th>From Interface</th><th>To Interface</th><th>Cable</th><th></th></tr>'; if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') - printNewitemTR(); + printNewitemTR($chaplist); foreach (getPortOIFCompat() as $pair) { if ($last_left_oif_id != $pair['type1']) @@ -3969,13 +3996,19 @@ function renderPortOIFCompatEditor() $order = $nextorder[$order]; $last_left_oif_id = $pair['type1']; } + printOpFormIntro('upd',array('type1'=>$pair['type1'], 'type2' => $pair['type2']) ); echo "<tr class=row_${order}><td>"; echo '<a href="' . makeHrefProcess (array ('op' => 'del', 'type1' => $pair['type1'], 'type2' => $pair['type2'])) . '">'; printImageHREF ('delete', 'remove pair'); - echo "</a></td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td></tr>"; + echo "</a></td><td class=tdleft>${pair['type1name']}</td><td class=tdleft>${pair['type2name']}</td>"; + echo '<td>'; + printSelect($chaplist, array('name'=>'cable_chapter_id'), $pair['cable_chapter_id']); + echo '</td><td>'; + printImageHREF ('save', 'Save changes', TRUE); + echo "</td></tr></form>"; } if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') - printNewitemTR(); + printNewitemTR($chaplist); echo '</table>'; } diff --git a/wwwroot/inc/navigation.php b/wwwroot/inc/navigation.php index 7e25ec3..f32fdfc 100644 --- a/wwwroot/inc/navigation.php +++ b/wwwroot/inc/navigation.php @@ -453,6 +453,9 @@ $tabhandler['portmap']['default'] = 'renderPortOIFCompatViewer'; $tabhandler['portmap']['edit'] = 'renderPortOIFCompatEditor'; $ophandler['portmap']['edit']['add'] = 'tableHandler'; $ophandler['portmap']['edit']['del'] = 'tableHandler'; +$ophandler['portmap']['edit']['upd'] = 'tableHandler'; +$ophandler['portmap']['edit']['addPack'] = 'addOIFCompatPack'; +$ophandler['portmap']['edit']['delPack'] = 'delOIFCompatPack'; $page['portifcompat']['title'] = 'Enabled port types'; $page['portifcompat']['parent'] = 'config'; diff --git a/wwwroot/inc/ophandlers.php b/wwwroot/inc/ophandlers.php index 2fad512..3fc2e15 100644 --- a/wwwroot/inc/ophandlers.php +++ b/wwwroot/inc/ophandlers.php @@ -272,6 +272,21 @@ $opspec_list['portmap-edit-add'] = array ( array ('url_argname' => 'type1', 'assertion' => 'uint'), array ('url_argname' => 'type2', 'assertion' => 'uint'), + array ('url_argname' => 'cable_chapter_id', 'assertion' => 'uint0', 'if_empty' => 'NULL' ) + ), +); +$opspec_list['portmap-edit-upd'] = array +( + 'table' => 'PortCompat', + 'action' => 'UPDATE', + 'set_arglist' => array + ( + array ('url_argname' => 'cable_chapter_id', 'assertion' => 'uint0', 'if_empty' => 'NULL'), + ), + 'where_arglist' => array + ( + array ('url_argname' => 'type1', 'assertion' => 'uint'), + array ('url_argname' => 'type2', 'assertion' => 'uint') ), ); $opspec_list['portmap-edit-del'] = array diff --git a/wwwroot/inc/popup.php b/wwwroot/inc/popup.php index 15244cb..85cb212 100644 --- a/wwwroot/inc/popup.php +++ b/wwwroot/inc/popup.php @@ -34,7 +34,7 @@ function getProximateRacks ($rack_id, $proximity = 0) return $ret; } -function findSparePorts ($port_info, $filter) +function getSparePorts($port_info, $filter) { $qparams = array (); $query = " @@ -45,37 +45,34 @@ SELECT p.iif_id, p.type as oif_id, pii.iif_name, - d.dict_value as oif_name, p.object_id, o.name as object_name FROM Port p INNER JOIN RackObject o ON o.id = p.object_id INNER JOIN PortInnerInterface pii ON p.iif_id = pii.id -INNER JOIN Dictionary d ON d.dict_key = p.type "; // porttype filter (non-strict match) $query .= " INNER JOIN ( - SELECT Port.id FROM Port + SELECT p2.id FROM Port p2 INNER JOIN ( - SELECT DISTINCT pic2.iif_id + SELECT DISTINCT pic2.iif_id, pic2.oif_id FROM PortInterfaceCompat pic2 INNER JOIN PortCompat pc ON pc.type2 = pic2.oif_id "; if ($port_info['iif_id'] != 1) { - $query .= " INNER JOIN PortInterfaceCompat pic ON pic.oif_id = pc.type1 WHERE pic.iif_id = ? AND "; + $query .= " INNER JOIN PortInterfaceCompat pic ON pic.oif_id = pc.type1 WHERE pic.iif_id = ? "; $qparams[] = $port_info['iif_id']; } else { - $query .= " WHERE pc.type1 = ? AND "; + $query .= " WHERE pc.type1 = ? "; $qparams[] = $port_info['oif_id']; } $query .= " - pic2.iif_id <> 1 - ) AS sub1 USING (iif_id) + ) AS sub1 ON p2.iif_id = sub1.iif_id AND ( p2.iif_id <> 1 OR p2.type = sub1.oif_id ) UNION SELECT Port.id FROM Port @@ -113,42 +110,104 @@ INNER JOIN ( // ordering $query .= ' ORDER BY o.name'; - $ret = array(); - $result = usePreparedSelectBlade ($query, $qparams); - - $rows_by_pn = array(); - $prev_object_id = NULL; + return usePreparedSelectBlade ($query, $qparams); +} + +function getLinkPortJavascript($port_info, $ports) +{ + $required_oif = array(); + $required_iif = array(); + $required_chapter = array(); + if( count($ports) == 0 ){ + return ''; + } + $jsports = array(); + $compat = array(); + $buffer = array('$(function($){'); + $buffer[]='var PORT = { id:'.$port_info['id'].', name:"'.addslashes($port_info['name']).'",'; + $buffer[]=' object_name:"'.addslashes($port_info['object_name']).'",'; + $buffer[]=' oif_id:'.($port_info['oif_id'] ? $port_info['oif_id'] : 'null').', '; + $buffer[]=' iif_id:'.$port_info['iif_id'].', '; + $buffer[]=' cable:"'.addslashes($port_info['cableid']).'", '; + $buffer[]=' cable_dict_key:'.($port_info['cable_dict_key'] ? $port_info['cable_dict_key'] : 'null' ).', '; + $buffer[]=' remote_id:'.($port_info['remote_id'] ? $port_info['remote_id'] : 'null').'};'; + $buffer[]='var PORTS = ['; - // fetch port rows from the DB - while (TRUE) + $required_iif[$port_info['iif_id']]=true; + if( $port_info['oif_id'] ) $required_oif[$port_info['oif_id']]=true; + foreach( $ports as $port ){ + $required_iif[ $port['iif_id'] ]=true; + if( $port['oif_id'] ) $required_oif[$port['oif_id']]=true; + $buffer[]=' { id:'.$port['id'].', name:"'.addslashes($port['name']).'", object_name:"'.addslashes($port['object_name']).'", oif_id:'.($port['oif_id'] ? $port['oif_id'] : 'null').', iif_id:'.$port['iif_id'].', reservation:"'.addslashes($port['reservation_comment']).'"},'; + } + $buffer[]='];'; + + $incom = usePreparedSelectBlade('SELECT * FROM PortInterfaceCompat WHERE iif_id IN ('.questionMarks(count($required_iif)).') ORDER BY iif_id ', array_keys($required_iif)); + $buffer[]='var INNER_OUTER_COMPATIBILITY = {'; + $last_iif_id = null; + foreach( $incom as $in ) { - $row = $result->fetch (PDO::FETCH_ASSOC); - if (isset ($prev_object_id) and (! $row or $row['object_id'] != $prev_object_id)) + if( $in['iif_id'] != $last_iif_id ) { - // handle sorted object's portlist - foreach (sortPortList ($rows_by_pn) as $ports_subarray) - foreach ($ports_subarray as $port_row) - { - $port_description = $port_row['object_name'] . ' -- ' . $port_row['name']; - if (count ($ports_subarray) > 1) - { - $if_type = $port_row['iif_id'] == 1 ? $port_row['oif_name'] : $port_row['iif_name']; - $port_description .= " ($if_type)"; - } - if (! empty ($port_row['reservation_comment'])) - $port_description .= ' -- ' . $port_row['reservation_comment']; - $ret[$port_row['id']] = $port_description; - } - $rows_by_pn = array(); + if( $last_iif_id != null ) + { + $buffer[]=' ],'; + } + $buffer[]=' '.$in['iif_id'].': ['; + $last_iif_id = $in['iif_id']; } - $prev_object_id = $row['object_id']; - if ($row) - $rows_by_pn[$row['name']][] = $row; - else - break; + $required_oif[$in['oif_id']]=true; + $buffer[]=' '.$in['oif_id'].','; } + if( $last_iif_id != null ) + { + $buffer[]=' ]'; + } + $buffer[]='};'; - return $ret; + $query ='SELECT * FROM PortCompat pc'. + ' WHERE type1 IN ('.questionMarks(count($required_oif)).') AND type2 IN ('.questionMarks(count($required_oif)).');'; + $types = usePreparedSelectBlade($query, array_merge( array_keys($required_oif), array_keys($required_oif) ) ); + foreach( $types as $type ){ + @$compat[ $type['type1'] ][ $type['type2'] ] = array( 'cable_chapter_id'=> ($type['cable_chapter_id'] ? intval($type['cable_chapter_id']) : 'null') ); + if( $type['cable_chapter_id'] ) $required_chapter[intval($type['cable_chapter_id'])] = true; + } + $buffer[]='var OUTER_COMPATIBILITY = {'; + foreach( $compat as $a => $sub ){ + $buffer[]=' '.$a.': { '; + foreach( $sub as $b => $info ){ + $buffer[]=' '.$b.': {cable_chapter_id:'.$info['cable_chapter_id'].'},'; + } + $buffer[]=' },'; + } + $buffer[]='};'; + if( $required_chapter ){ + $buffer[]='var CABLES = {'; + $last_chapter_id = -1; + foreach( array_keys($required_chapter) as $chapter_id ){ + $chapter = cookOptgroups( readChapter( $chapter_id, 'o' ) ); + $buffer[]= $chapter_id.': ['; + foreach( $chapter as $group => $entries ){ + $buffer[]= ' {name: "'.addslashes($group).'", values:['; + foreach( $entries as $key => $value ){ + $buffer[]= ' {key: '.$key.', value: "'.addslashes($value).'"},'; + } + $buffer[]=' ]},'; + } + $buffer[]='],'; + } + $buffer[]='};'; + }else{ + $buffer[]='var CABLES = {};'; + } + $oifs = usePreparedSelectBlade('SELECT dict_key,dict_value FROM Dictionary WHERE chapter_id = 2 AND dict_key IN ('.questionMarks(count($required_oif)).');', array_keys($required_oif)); + $buffer[]='var OIF = {};'; + foreach( $oifs as $oif ){ + $buffer[]='OIF['.$oif['dict_key'].']= "'.addslashes($oif['dict_value']).'";'; + } + $buffer[]=' initializeLinkportForm( PORT, PORTS, INNER_OUTER_COMPATIBILITY, OUTER_COMPATIBILITY, CABLES, OIF )'; + $buffer[]='});'; + return join("\n",$buffer); } // Return a list of all objects which are possible parents @@ -221,131 +280,66 @@ function renderPopupObjectSelector() function handlePopupPortLink() { + global $dbxlink; assertUIntArg ('port'); assertUIntArg ('remote_port'); assertStringArg ('cable', TRUE); $port_info = getPortInfo ($_REQUEST['port']); $remote_port_info = getPortInfo ($_REQUEST['remote_port']); - $POIFC = getPortOIFCompat(); - if (isset ($_REQUEST['port_type']) and isset ($_REQUEST['remote_port_type'])) - { - $type_local = $_REQUEST['port_type']; - $type_remote = $_REQUEST['remote_port_type']; - } - else - { - $type_local = $port_info['oif_id']; - $type_remote = $remote_port_info['oif_id']; - } - $matches = FALSE; - $js_table = ''; - foreach ($POIFC as $pair) - if ($pair['type1'] == $type_local && $pair['type2'] == $type_remote) - { - $matches = TRUE; - break; + $dbxlink->beginTransaction(); + try{ + + if( $port_info['iif_id'] != 1 ){ + // updateable + assertUIntArg ('local_oif'); + if( $_POST['local_oif'] != $port_info['oif_id'] ){ + commitUpdatePortOIF( $port_info['id'], $_POST['local_oif']); + $port_info['oif_id'] = intval($_POST['local_oif']); + } } - else - $js_table .= "POIFC['${pair['type1']}-${pair['type2']}'] = 1;\n"; - - if ($matches) - { - if ($port_info['oif_id'] != $type_local) - commitUpdatePortOIF ($port_info['id'], $type_local); - if ($remote_port_info['oif_id'] != $type_remote) - commitUpdatePortOIF ($remote_port_info['id'], $type_remote); - linkPorts ($port_info['id'], $remote_port_info['id'], $_REQUEST['cable']); - showSuccess - ( - sprintf + if( $remote_port_info['iif_id'] != 1 ){ + // updateable + assertUIntArg ('remote_oif'); + if( $_POST['remote_oif'] != $remote_port_info['oif_id'] ){ + commitUpdatePortOIF( $remote_port_info['id'], $_POST['remote_oif']); + $remote_port_info['oif_id'] = intval($_POST['remote_oif']); + } + } + // now check compat + $compat = usePreparedSelectBlade('SELECT * FROM PortCompat WHERE ( type1 = ? AND type2 = ? ) OR ( type2 = ? AND type1= ? ) ', + array( $port_info['oif_id'],$remote_port_info['oif_id'],$port_info['oif_id'],$remote_port_info['oif_id']) )->fetchAll(); + if( !$compat ){ + throw new InvalidRequestArgException('oif_id', '', 'Ports are not compatible'); + }else{ + // :) + $cable_type = null; + if( $compat[0]['cable_chapter_id'] && $_POST['cable_type'] ){ + assertUIntArg('cable_type',true); + $cable_type = $_POST['cable_type']; + } + linkPorts( $port_info['id'], $remote_port_info['id'], $_POST['cable'], $cable_type, true ); + $dbxlink->commit(); + showSuccess ( + sprintf + ( 'Port %s successfully linked with port %s', formatPortLink ($port_info['id'], $port_info['name'], NULL, NULL), formatPort ($remote_port_info) - ) - ); - addJS (<<<END -window.opener.location.reload(true); -window.close(); + ) + ); + addJS (<<<END + window.opener.location.reload(true); + window.close(); END - , TRUE); - } - else - { - // JS code to display port compatibility hint - addJS (<<<END -POIFC = {}; -$js_table -$(document).ready(function () { - $('select.porttype').change(onPortTypeChange); - onPortTypeChange(); -}); -function onPortTypeChange() { - var key = $('*[name=port_type]')[0].value + '-' + $('*[name=remote_port_type]')[0].value; - if (POIFC[key] == 1) - { - $('#hint-not-compat').hide(); - $('#hint-compat').show(); - } - else - { - $('#hint-compat').hide(); - $('#hint-not-compat').show(); - } -} -END - , TRUE); - addCSS (<<<END -.compat-hint { - display: none; - font-size: 125%; -} -.compat-hint#hint-compat { - color: green; -} -.compat-hint#hint-not-compat { - color: #804040; -} -END - , TRUE); - // render port type editor form - echo '<form method=GET>'; - echo '<input type=hidden name="module" value="popup">'; - echo '<input type=hidden name="helper" value="portlist">'; - echo '<input type=hidden name="port" value="' . $port_info['id'] . '">'; - echo '<input type=hidden name="remote_port" value="' . $remote_port_info['id'] . '">'; - echo '<input type=hidden name="cable" value="' . htmlspecialchars ($_REQUEST['cable'], ENT_QUOTES) . '">'; - echo '<p>The ports you have selected are not compatible. Please select a compatible transceiver pair.'; - echo '<p>'; - echo formatPort ($port_info) . ' '; - if ($port_info['iif_id'] == 1) - { - echo formatPortIIFOIF ($port_info); - echo '<input type=hidden name="port_type" value="' . $port_info['oif_id'] . '">'; - } - else - { - echo '<label>' . $port_info['iif_name'] . ' '; - printSelect (getExistingPortTypeOptions ($port_info['id']), array ('class' => 'porttype', 'name' => 'port_type'), $type_local); - echo '</label>'; + , true); + return; } - echo ' — '; - if ($remote_port_info['iif_id'] == 1) - { - echo formatPortIIFOIF ($remote_port_info); - echo '<input type=hidden name="remote_port_type" value="' . $remote_port_info['oif_id'] . '">'; - } - else - { - echo '<label>' . $remote_port_info['iif_name'] . ' '; - printSelect (getExistingPortTypeOptions ($remote_port_info['id']), array ('class' => 'porttype', 'name' => 'remote_port_type'), $type_remote); - echo '</label>'; - } - echo ' ' . formatPort ($remote_port_info); - echo '<p class="compat-hint" id="hint-not-compat">✕ Not compatible port types</p>'; - echo '<p class="compat-hint" id="hint-compat">✔ Compatible port types</p>'; - echo '<p><input type=submit name="do_link" value="Link">'; + }catch( Exception $e ){ + $dbxlink->rollBack(); + throw $e; } + return renderPopupPortSelector(); } function renderPopupPortSelector() @@ -353,7 +347,8 @@ function renderPopupPortSelector() assertUIntArg ('port'); $port_id = $_REQUEST['port']; $port_info = getPortInfo ($port_id); - $in_rack = isset ($_REQUEST['in_rack']); + + $in_rack = $_REQUEST['in_rack'] != 'off';; // fill port filter structure $filter = array @@ -379,11 +374,34 @@ function renderPopupPortSelector() ! empty ($filter['objects']) || ! empty ($filter['ports']) ) - $spare_ports = findSparePorts ($port_info, $filter); + $ports_with_current = $ports = getSparePorts($port_info, $filter)->fetchAll(); + if( $port_info['linked'] ){ + $link = usePreparedSelectBlade('SELECT * FROM Link WHERE porta = ? OR portb = ?', array($port_id, $port_id))->fetch(PDO::FETCH_ASSOC); + + $current = getPortInfo( ($link['porta'] == $port_id) ? $link['portb'] : $link['porta'] ); + $port_info['cableid'] = $current['cableid'] = $link['cable']; + $port_info['cable_dict_key'] = $current['cable_dict_key'] = $link['cable_dict_key']; + $port_info['remote_id'] = $current['id']; + $ports_with_current[] = $current; + } + addJS('js/link_port_form.js'); + addJS(getLinkPortJavascript($port_info, $ports_with_current),true); + addCSS (<<<'END' +.reserved { + text-decoration: line-through; +} +.compatible { + background: #afa; +} +.incompatible { + background: #faa; +} +END + , TRUE); // display search form echo 'Link ' . formatPort ($port_info) . ' to...'; - echo '<form method=GET>'; + echo '<form method="POST">'; startPortlet ('Port list filter'); echo '<input type=hidden name="module" value="popup">'; echo '<input type=hidden name="helper" value="portlist">'; @@ -391,23 +409,59 @@ function renderPopupPortSelector() echo '<table align="center" valign="bottom"><tr>'; echo '<td class="tdleft"><label>Object name:<br><input type=text size=8 name="filter-obj" value="' . htmlspecialchars ($filter['objects'], ENT_QUOTES) . '"></label></td>'; echo '<td class="tdleft"><label>Port name:<br><input type=text size=6 name="filter-port" value="' . htmlspecialchars ($filter['ports'], ENT_QUOTES) . '"></label></td>'; - echo '<td class="tdleft" valign="bottom"><label><input type=checkbox name="in_rack"' . ($in_rack ? ' checked' : '') . '>Nearest racks</label></td>'; + echo '</tr><tr>'; + echo '<td class="tdleft" valign="bottom"><input type="hidden" name="in_rack" value="off" /><label><input type=checkbox name="in_rack"' . ($in_rack ? ' checked' : '') . '>Nearest racks</label></td>'; echo '<td valign="bottom"><input type=submit value="show ports"></td>'; echo '</tr></table>'; finishPortlet(); // display results - startPortlet ('Compatible spare ports'); - if (empty ($spare_ports)) - echo '(nothing found)'; - else - { - echo getSelect ($spare_ports, array ('name' => 'remote_port', 'size' => getConfigVar ('MAXSELSIZE')), NULL, FALSE); - echo "<p>Cable ID: <input type=text id=cable name=cable>"; - echo "<p><input type='submit' value='Link' name='do_link'>"; + startPortlet ('Link port'); + if( $ports_with_current ){ + echo '<div style="float: left;width:40%">'; + echo '<select name="remote_port" id="remote_port" size="',getConfigVar ('MAXSELSIZE'),'" style="width:100%">'; + if( $current ){ + echo '<optgroup label="current">'; + echo '<optgroup label=" ', htmlspecialchars($current['object_name']), '">'; + echo '<option value="',$current['id'],'" selected="selected">', htmlspecialchars($current['name'] ),'</option>'; + echo '</optgroup>'; + } + echo '<optgroup label="search result">'; + if( !$ports ){ + echo '<option disabled="disabled" value="">nothing found</option>'; + }else{ + $ports_by_object = array(); + foreach( $ports as $port ){ + if( !isset($ports_by_object[$port['object_name']]) ) $ports_by_object[$port['object_name']] = array(); + $ports_by_object[$port['object_name']][] = $port; + } + ksort( $ports_by_object ); + foreach( $ports_by_object as $name => $object_ports ){ + echo '<optgroup label=" ', htmlspecialchars($name), '">'; + foreach( sortPortList($object_ports, true) as $port ){ + echo '<option value="', $port['id'],'"',($port['reservation_comment'] ? ' class="reserved"':''),'>', htmlspecialchars($port['name']), '</option>'; + } + echo '</optgroup>'; + } + } + echo '</optgroup>'; + echo '</select>'; + echo '</div>'; + echo '<div style="margin-left: 41%">'; + echo '<p style="display:none">This port is reserved: <span id="reservation"></span></p>'; + echo '<p style="display:none"><label for="cable_type">Local Transceiver</label></br><select name="local_oif" id="local_oif" style="width:100%"></select></p>'; + echo '<p style="display:none"><label for="remote_oif">Remote Transceiver</label></br><select name="remote_oif" id="remote_oif" style="width:100%"></select></p>'; + echo '<p style="display:none"><label for="cable_type">Cable type</label></br><select name="cable_type" id="cable_type" style="width:100%"></select></p>'; + echo '<p><label for="cable">Cable ID: </label><br /><input type="text" id="cable" name="cable" style="width:100%" value="',htmlspecialchars($port_info['cableid']) ,'"/></p>'; + echo '<p><input type="submit" value="Link" name="do_link" id="submit"></p>'; + echo '<br style="clear:both" /></div>'; + }else{ + echo 'nothing found'; } + finishPortlet(); echo '</form>'; + echo '<br style="clear:both" />'; } function renderPopupIPv4Selector() diff --git a/wwwroot/js/link_port_form.js b/wwwroot/js/link_port_form.js new file mode 100644 index 0000000..0cf45a2 --- /dev/null +++ b/wwwroot/js/link_port_form.js @@ -0,0 +1,147 @@ +function initializeLinkportForm( PORT, PORTS, INNER_OUTER_COMPATIBILITY, OUTER_COMPATIBILITY, CABLES, OIF ){ + var $remote_port = $('#remote_port'),$remote_oif = $('#remote_oif'),$local_oif = $('#local_oif'),$cable_type = $('#cable_type'), $submit = $('#submit'), $reservation = $('#reservation'); + var compatClass = function(a,b){ + if( !a || !b ){ + return ''; + }else if( !OUTER_COMPATIBILITY[a] || !OUTER_COMPATIBILITY[a][b] ){ + return 'incompatible'; + }else{ + return 'compatible'; + } + } + var updateSelects = function(){ + var rp = $remote_port.val(), ro = $remote_oif.val(), lo = $local_oif.val(), ct = $cable_type.val(); + if( ro ) ro = parseInt(ro); + if( !lo ){ + lo = PORT.oif_id; + }else{ + lo = parseInt(lo); + } + if( !rp ){ + rp = PORT.remote_id; + } + if( !ct ){ + ct = PORT.cable_dict_key; + } + //remote_oif + $remote_oif.empty(); + var remote_port; + if( rp ){ + remote_port = $.grep(PORTS,function(p){ return p.id == rp })[0]; + if( !ro || remote_port.iif_id == 1 || INNER_OUTER_COMPATIBILITY[ remote_port.iif_id ].indexOf(ro) == -1 ){ + ro = remote_port.oif_id; + } + if( remote_port.reservation == "" ){ + $reservation.closest('p').hide(); + }else{ + $reservation.text( remote_port.reservation ); + $reservation.closest('p').show(); + } + if( remote_port.iif_id != 1 ){ + $remote_oif.closest('p').show(); + $remote_oif.attr('disabled',false); + }else{ + $remote_oif.closest('p').hide(); + $remote_oif.attr('disabled',true); + } + var rps = INNER_OUTER_COMPATIBILITY[ remote_port.iif_id ]; + rps.sort(function(a,b){ + return OIF[a].localeCompare(OIF[b]); + }).forEach( function(oif){ + $('<option>').val(oif).text( OIF[oif] ).addClass( compatClass( oif, lo ) ).appendTo($remote_oif); + }); + $remote_oif.val(ro); + }else{ + $remote_oif.closest('p').hide(); + $remote_oif.attr('disabled',true); + } + //local_oif + $local_oif.empty(); + if( PORT.iif_id != 1 ){ + $local_oif.closest('p').show(); + $local_oif.attr('disabled',false); + }else{ + $local_oif.closest('p').hide(); + $local_oif.attr('disabled',true); + } + var lps = INNER_OUTER_COMPATIBILITY[ PORT.iif_id ]; + lps.sort(function(a,b){ + return OIF[a].localeCompare(OIF[b]); + }).forEach( function(oif){ + $('<option>').val(oif).text( OIF[oif] ).addClass( compatClass( oif, ro ) ).appendTo($local_oif); + }); + $local_oif.val(lo); + if( rp && lo && ro ){ + // cables and compat! + var comb = OUTER_COMPATIBILITY[ ro ] ? OUTER_COMPATIBILITY[ ro ][ lo ] : null; + if( !comb ){ + $submit.attr('disabled',true); + $submit.val('Incompatible transceiver'); + $cable_type.closest('p').hide(); + }else{ + if( comb.cable_chapter_id ){ + $cable_type.empty(); + var cables = CABLES[comb.cable_chapter_id]; + if( cables ){ + var other; + $.each(cables,function(i,group){ + if( group.name == 'other' ){ + other = group; + return ; + } + var g = $('<optgroup>').attr('label',group.name).appendTo($cable_type); + $.each(group.values, function(j, opt){ + $('<option>').val(opt.key).text(opt.value).appendTo(g); + }); + }); + if( other ){ + $.each(other.values, function(j, opt){ + $('<option>').val(opt.key).text(opt.value).appendTo($cable_type); + }); + } + } + $('<option>').val('').text('').appendTo($cable_type); + $cable_type.val(ct); + $cable_type.closest('p').show(); + }else{ + // compatible but no cables + $cable_type.closest('p').hide(); + } + $submit.attr('disabled',false); + $submit.val('Link'); + } + }else{ + if( !rp ){ + $submit.attr('disabled',true); + $submit.val('Select a port'); + } + $cable_type.closest('p').hide(); + } + } + updateSelects(); + $remote_port.change(updateSelects); + var changeTransceiver = function( $a, $b ){ + var av = $a.val(); + var bv = $b.val(); + if( !OUTER_COMPATIBILITY[av] ){ + return ; + } + if( OUTER_COMPATIBILITY[av][bv] ){ + return; + } + $b.children('option').each(function(i,o ){ + if( OUTER_COMPATIBILITY[ av ][ $(o).val() ] ){ + $b.val( $(o).val() ); + return false; + } + }); + } + $local_oif.change(function(){ + changeTransceiver($local_oif,$remote_oif); + updateSelects(); + }); + $remote_oif.change(function(){ + changeTransceiver($remote_oif,$local_oif); + updateSelects(); + }); +} | ||||
Hi, I made good progress. The biggest changes happened to the link-port form. This was necessary, to keep the numbers of additional clicks low. Furthermore you can now select transceivers without submitting the form. Cheers! Hannes |
|
Hannes, I will review the patch and update this issue. | |
Nice! When you are done, I'll backport this to 0.19.13. | |
Hi, I just backported the feature on top of the 0.19.13 release. Cheers! |
|
Sorry, I forgot to check "nearest rack" by default. Corrected this. | |
Aaron, these changes would conflict with the patch panels code but there are good points in this work that should be considered. I have reassigned this issue to you. | |
Re-assigning to infrastation since he added the "Patch cables" feature. | |
Date Modified | Username | Field | Change |
---|---|---|---|
2012-04-12 11:46 |
|
New Issue | |
2012-04-19 10:40 |
|
File Added: track_cable_type.patch | |
2012-04-19 10:51 |
|
File Added: track_cable_type.sql | |
2012-04-19 10:55 |
|
Note Added: 0000657 | |
2012-04-22 08:10 | infrastation | Note Added: 0000661 | |
2012-04-22 08:10 | infrastation | Status | new => acknowledged |
2012-04-23 08:16 |
|
Note Added: 0000665 | |
2012-07-02 13:32 |
|
File Added: track_cable_type_0.19.13.diff | |
2012-07-02 13:33 |
|
Note Added: 0000699 | |
2012-07-03 07:12 |
|
File Added: track_cable_type_0.19.13.correct.diff | |
2012-07-03 07:12 |
|
Note Added: 0000700 | |
2012-08-23 14:34 | infrastation | Assigned To | => infrastation |
2012-08-23 14:34 | infrastation | Status | acknowledged => assigned |
2013-11-27 13:03 | infrastation | Relationship added | child of 333 |
2013-11-27 13:03 | infrastation | Assigned To | infrastation => adoom42 |
2013-11-27 13:05 | infrastation | Note Added: 0001989 | |
2015-06-11 03:59 | adoom42 | Note Added: 0002853 | |
2015-06-11 03:59 | adoom42 | Assigned To | adoom42 => infrastation |