show extra tags in the nodes page as well
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 15 Nov 2009 22:28:05 +0000 (22:28 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 15 Nov 2009 22:28:05 +0000 (22:28 +0000)
feature extracted in includes/plc_visibletags.php
fancier table headers with an optional title - could make footnotes less crucial
going to the slice page from the slices page opens the node toggle and closes details

planetlab/common/actions.php
planetlab/includes/plc_functions.php
planetlab/nodes/nodes.php
planetlab/slices/slice.php
plekit/php/table.php
plekit/tablesort/tablesort.js

index 2717d1e..ae98281 100644 (file)
@@ -643,7 +643,7 @@ Our support team will be glad to answer any question that you might have.
      drupal_set_message ("Removed $count node(s)");
    else
      drupal_set_error ("Could not remove selected nodes");
-   plc_redirect(l_slice($slice_id) . " &show_nodes=true");
+   plc_redirect(l_slice_nodes($slice_id));
    break;
  }
 
@@ -655,7 +655,7 @@ Our support team will be glad to answer any question that you might have.
      drupal_set_message ("Added $count node(s)");
    else
      drupal_set_error ("Could not add all selected nodes");
-   plc_redirect(l_slice($slice_id) . "&show_nodes=true" );
+   plc_redirect(l_slice_nodes($slice_id));
    break;
  }
 
index 53600ae..3e69f23 100644 (file)
@@ -2,9 +2,6 @@
 
 // $Id$
 
-// will trash this eventually
-  //require_once 'plc_functions_trash.php';
-
 # note: this needs to be consistent with the value in Monitor/monitor/wrapper/plc.py
 global $PENDING_CONSORTIUM_ID;
 $PENDING_CONSORTIUM_ID = 0;
@@ -215,7 +212,7 @@ function tab_nodegroups()   { return array ('label'=>'Nodegroups', 'url'=>l_nodegr
 function tablook_event()       { return array('image'=>'/planetlab/icons/event.png','height'=>18);}
 function tablook_comon()       { return array('image'=>'/planetlab/icons/comon.png','height'=>18);}
 
-////////////////////
+
 
 //////////////////////////////////////////////////////////// validation functions
 function topdomain ($hostname) {
index ebe8079..951e985 100644 (file)
@@ -16,6 +16,7 @@ include 'plc_header.php';
 // Common functions
 require_once 'plc_functions.php';
 require_once 'plc_peers.php';
+require_once 'plc_visibletags.php';
 require_once 'linetabs.php';
 require_once 'table.php';
 require_once 'nifty.php';
@@ -61,7 +62,12 @@ function node_status ($node) {
 }
 
 // fetch nodes 
-$node_columns=array('hostname','node_type','site_id','node_id','boot_state','run_level','interface_ids','peer_id', 'arch','slice_ids');
+$node_fixed_columns=array('hostname','node_type','site_id','node_id','boot_state','run_level',
+                         'interface_ids','peer_id', 'slice_ids');
+$visibletags = new VisibleTags ($api, 'node');
+$visiblecolumns = $visibletags->column_names();
+$node_columns=array_merge($node_fixed_columns,$visiblecolumns);
+
 // server-side filtering - set pattern in $_GET for filtering on hostname
 if ($pattern) {
   $node_filter['hostname']=$pattern;
@@ -150,17 +156,31 @@ if ( ! $nodes ) {
 $nifty=new PlekitNifty ('','objects-list','big');
 $nifty->start();
 $headers = array (); $offset=0;
-if (plc_is_admin()) { $headers["I"]="int"; $offset=1; }
-$headers["P"]="string";
-$headers["R"]="string";
+$notes=array();
+
+// fixed columns
+if (plc_is_admin()) { 
+  $short="I"; $long="node_id"; $type='int'; 
+       $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
+  $offset=1; 
+ }
+$short="P"; $long="Peer"; $type='string'; 
+       $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
+$short="D"; $long="toplevel domain name"; $type='string'; 
+       $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
 $headers["Site"]="string";
 $headers["State"]="string";
+               $notes []= "state* = node doesn't have an observed state, preferred state is displayed";
 $headers["Hostname"]="string";
 $headers["Type"]="string";
-$headers["IP"]="sortIPAddress";
-$headers["A"]="string";
-$headers["S"]='int';
-$headers["?"]="string";
+$short="IP"; $long="IP Address"; $type='sortIPAddress'; 
+       $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
+$short="SL"; $long="Number of slivers"; $type='int'; 
+       $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
+
+$headers=array_merge($headers,$visibletags->headers());
+$notes=array_merge($notes,$visibletags->notes());
+$headers["?"]="string";                $notes []= "? = extra status info";
 
 # initial sort on hostnames
 $table=new PlekitTable ("nodes",$headers,4+$offset);
@@ -192,20 +212,13 @@ foreach ($nodes as $node) {
   $table->cell (l_node_t($node_id,$hostname));
   $table->cell ($node_type);
   $table->cell (l_interface_t($interface_id,$ip),array('only-if'=> !$peer_id));
-  $table->cell ($node['arch'],array('only-if'=> !$peer_id));
   $table->cell (count($node['slice_ids']));
+  foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
   $table->cell (node_status($node));
   $table->row_end();
   
 }
 
-$notes=array();
-if (plc_is_admin()) $notes []= "I = node_id";
-$notes []= "R = region";
-$notes []= "A = arch";
-$notes []= "S = number of slivers";
-$notes []= "? = status";
-$notes []= "status* = node doesn't have an observed state, preferred state is displayed";
 $table->end(array('notes'=>$notes));
 $nifty->end();
 
index 9649136..91721ce 100644 (file)
@@ -16,6 +16,7 @@ include 'plc_header.php';
 // Common functions
 require_once 'plc_functions.php';
 require_once 'plc_peers.php';
+require_once 'plc_visibletags.php';
 require_once 'linetabs.php';
 require_once 'table.php';
 require_once 'details.php';
@@ -51,9 +52,7 @@ $name= $slice['name'];
 $expires = date( "d/m/Y", $slice['expires'] );
 $site_id= $slice['site_id'];
 
-//$node_ids=$slice['node_ids'];
 $person_ids=$slice['person_ids'];
-//$slice_tag_ids= $slice['slice_tag_ids'];
 
 // get peers
 $peer_id= $slice['peer_id'];
@@ -65,13 +64,6 @@ $sites= $api->GetSites( array( $site_id ) );
 $site=$sites[0];
 $site_name= $site['name'];
 $max_slices = $site['max_slices'];
-// xxx PIs
-//$pis=$api->GetPersons(...)
-
-// get all persons info
-if (!empty($person_ids))
-  $persons=$api->GetPersons($person_ids,array('email','enabled'));
-
 
 //////////////////////////////////////// building blocks for the renew area
 // Constants
@@ -268,11 +260,16 @@ $toggle->end();
 
 //////////////////// persons
 $person_columns = array('email','person_id','first_name','last_name','roles');
-$persons=$api->GetPersons(array('person_id'=>$slice['person_ids']));
-// just propose to add everyone else, 
+// get persons in slice
+if (!empty($person_ids))
+  $persons=$api->GetPersons(array('person_id'=>$slice['person_ids']),$person_columns);
+// just propose to add everyone else
+// xxx this is maybe too much for admins as it slows stuff down 
 // as regular persons can see only a fraction of the db anyway
 $potential_persons=
-  $api->GetPersons(array('~person_id'=>$slice['person_ids'],'peer_id'=>NULL,'enabled'=>true),
+  $api->GetPersons(array('~person_id'=>$slice['person_ids'],
+                        'peer_id'=>NULL,
+                        'enabled'=>true),
                   $person_columns);
 $count=count($persons);
 
@@ -388,35 +385,10 @@ $toggle->end();
 
 // minimal list as a start
 $node_fixed_columns = array('hostname','node_id','peer_id','slice_ids_whitelist','run_level','boot_state');
-// scan tag types to find relevant additional columns
-$nodeui_tag_types = $api->GetTagTypes(array('category'=>'node*/ui*'));
-// extract tagname
-$node_tag_columns = array_map(create_function('$tt','return $tt["tagname"];'),$nodeui_tag_types);
-// build an ordered list of chunks {'tagname','header','rank','description'}
-$more_tags = array();
-foreach ($nodeui_tag_types as $tag_type) {
-  $tagname=$tag_type['tagname'];
-  $chunk=array();
-  $chunk['tagname']=$tagname;
-  $chunk['header']=$tagname;
-  $chunk['rank']=$tagname;
-  $chunk['type']='string';
-  $chunk['description']=$tag_type['description'];
-  $category_tokens=split('/',$tag_type['category']);
-  foreach ($category_tokens as $token) {
-    $assign=split('=',$token);
-    if (count($assign)==2) 
-      $chunk[$assign[0]]=$assign[1];
-  }
-  $more_tags []= $chunk;
-}
-
-function sort_chunks ($ch1, $ch2) { return strcmp($ch1['rank'],$ch2['rank']); }
-usort ($more_tags, sort_chunks);
-
-//plc_debug('ordered additional tags',$more_tags);
-
-$node_columns=array_merge($node_fixed_columns,$node_tag_columns);
+// create a VisibleTags object : basically the list of tag columns to show
+$visibletags = new VisibleTags ($api, 'node');
+$visiblecolumns = $visibletags->column_names();
+$node_columns=array_merge($node_fixed_columns,$visiblecolumns);
 $nodes=$api->GetNodes(array('node_id'=>$slice['node_ids']),$node_columns);
 $potential_nodes=$api->GetNodes(array('~node_id'=>$slice['node_ids']),$node_columns);
 $count=count($nodes);
@@ -438,13 +410,12 @@ $headers=array();
 $notes=array();
 $headers['peer']='string';
 $headers['hostname']='string';
-$headers['S']='string';
-$notes[]='S = last known status';
-foreach ($more_tags as $chunk) {
-  $header=$chunk['header'];
-  $headers[$header]=$chunk['type'];
-  if ($header != $chunk['tagname']) $notes []= $header . ' = ' . $chunk['description'];
-}
+$short="ST"; $long="Last known status"; $type='string'; 
+       $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
+// the extra tags
+$headers=array_merge($headers,$visibletags->headers());
+$notes=array_merge($notes,$visibletags->notes());
+
 if ($privileges) $headers[plc_delete_icon()]="none";
 
 $table_options = array('notes'=>$notes,
@@ -463,7 +434,7 @@ if ($nodes) foreach ($nodes as $node) {
   if ( empty($run_level)) $run_level=$node['boot_state'];
   $class=($run_level == 'boot') ? 'node-ok' : 'node-ko';
   $table->cell($run_level,array('class'=>$class));
-  foreach ($more_tags as $chunk) $table->cell($node[$chunk['tagname']]);
+  foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
 
   if ($privileges) $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
   $table->row_end();
@@ -509,11 +480,9 @@ if ($privileges) {
     $headers['hostname']='string';
     $headers['S']='string';
     $notes[]='S = last known status';
-    foreach ($more_tags as $chunk) {
-      $header=$chunk['header'];
-      $headers[$header]=$chunk['type'];
-      if ($header != $chunk['tagname']) $notes []= $header . ' = ' . $chunk['description'];
-    }
+    // the extra tags
+    $headers=array_merge($headers,$visibletags->headers());
+    $notes=array_merge($notes,$visibletags->notes());
     $headers['+']="none";
     
     $table=new PlekitTable('add_nodes',$headers,'1', $table_options);
@@ -529,7 +498,7 @@ if ($privileges) {
        if ( empty($run_level)) $run_level=$node['boot_state'];
        $class=($run_level == 'boot') ? 'node-ok' : 'node-ko';
        $table->cell($run_level,array('class'=>$class));
-       foreach ($more_tags as $chunk) $table->cell($node[$chunk['tagname']]);
+       foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
        $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
        $table->row_end();
       }
index 480bd8b..dc5bd8e 100644 (file)
@@ -15,7 +15,14 @@ drupal_set_html_head('
 
 ////////////////////////////////////////
 // table_id: <table>'s id tag - WARNING : do not use '-' in table ids as it's used for generating javascript code
-// headers: an associative array "label"=>"type" 
+// headers: an associative array; the values can take several forms
+//      simple/legacy form is "label"=>"type" 
+//      more advanced form is "label"=>options, it self a dict with the following known keys
+//         (*) 'type': the type for sorting; this is passed to the javascript layer for custom sorting
+//             default is to use 'text', custom sort functions can be specified with e.g. 'type'=>'sortAlphaNumericBottom'
+//             a special case is for type to be 'date-format' like e.g. 'type'=>'date-dmy'
+//             setting type to 'none' gives an non-sortable column
+//        (*) 'title': if set, this is used in the "Sort on ``<title>''" bubble
 // sort_column: the column to sort on at load-time - set to negative number for no onload- sorting
 // options : an associative array to override options 
 //  - bullets1 : set to true if you want decorative bullets in column 1 (need white background)
@@ -131,7 +138,16 @@ class PlekitTable {
     if ($this->caption) 
       print "<caption> $this->caption </caption>";
     print "<tr>";
-    foreach ($this->headers as $label => $type) {
+    foreach ($this->headers as $label => $colspec) {
+      // which form is being used
+      if (is_array($colspec)) {
+       $type=$colspec['type'];
+       $title=ucfirst($colspec['title']);
+      } else {
+       // simple/legacy form
+       $type=$colspec;
+       $title=NULL;
+      }
       switch ($type) {
       case "none" : 
        $class=""; break;
@@ -142,7 +158,8 @@ class PlekitTable {
       default:
        $class="sortable-sort" . $type; break;
       }
-      printf ('<th class="%s plekit_table">%s</th>',$class,$label);
+      $title_part=$title ? "title=\"$title\"" : "";
+      print ("<th class=\"$class plekit_table\" $title_part>$label</th>\n");
     }
 
     print "</tr></thead><tbody>";
index c52382c..e9e8058 100644 (file)
@@ -213,8 +213,8 @@ fdTableSort = {
                                                         columnNumSortObj[i]["thNode"] = workArr[c][i];
                                                         columnNumSortObj["active"] = true;
                                                 };
-
-                                                thtext = fdTableSort.getInnerText(workArr[c][i], true);
+                                               th_elt = workArr[c][i];
+                                                thtext = fdTableSort.getInnerText(th_elt, true);
                                                 
                                                 for(var cn = workArr[c][i].childNodes.length; cn--;) {
                                                         // Skip image nodes and links created by the filter script.
@@ -230,7 +230,12 @@ fdTableSort = {
                                                 aclone = a.cloneNode(true);
                                                 //aclone.appendChild(document.createTextNode(thtext));
                                                 aclone.innerHTML = thtext;
-                                                aclone.title = "Sort on \u201c" + thtext.replace('<br />', '') + "\u201d";
+                                               //if the <th> has title set, use this as an alternate text for the 'sort on ...'
+                                               if (th_elt.title) {
+                                                 aclone.title = th_elt.title;
+                                               } else {
+                                                 aclone.title = "Sort on \u201c" + (th_elt.title ? th_elt.title : thtext.replace('<br />', '')) + "\u201d";
+                                               }
                                                 aclone.onclick = aclone.onkeydown = workArr[c][i].onclick = fdTableSort.initWrapper;
                                                 workArr[c][i].appendChild(aclone);
                                                 if(showArrow) workArr[c][i].appendChild(span.cloneNode(false));