From 6c94f043ee4e0dcc83fc8ddf70ec4fa1462a529f Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Mon, 14 Feb 2011 17:36:38 +0100 Subject: [PATCH] reservations add/delete use ajax, no need to wait for the page to reload --- planetlab/css/my_slice.css | 5 +- planetlab/slices/leases-data.php | 89 ++++++++++++ planetlab/slices/leases.js | 226 ++++++++++++++++++++----------- planetlab/slices/slice.php | 37 +++-- plekit/prototype/prototype.js | 2 +- plekit/table/table.js | 2 - 6 files changed, 266 insertions(+), 95 deletions(-) create mode 100644 planetlab/slices/leases-data.php diff --git a/planetlab/css/my_slice.css b/planetlab/css/my_slice.css index 0a20eb2..2cf7430 100644 --- a/planetlab/css/my_slice.css +++ b/planetlab/css/my_slice.css @@ -28,8 +28,9 @@ div#leases_area { padding: 10px 25px; } -/* don't display the scheduler data table - not quite sure this works */ -table#leases_data { +/* this class is used to store data that needs to get passed to javascript code */ +/* these elements re not meant to be rendered */ +.hidden { display: none; } diff --git a/planetlab/slices/leases-data.php b/planetlab/slices/leases-data.php new file mode 100644 index 0000000..ae23a79 --- /dev/null +++ b/planetlab/slices/leases-data.php @@ -0,0 +1,89 @@ + +// that holds the data about leases + +// Require login +require_once 'plc_login.php'; + +// Get session and API handles +require_once 'plc_session.php'; +global $plc, $api; + +$sliceid=$_POST['sliceid']; +$slicename=$_POST['slicename']; +$leases_grain=$_POST['leases_grain']; +$leases_offset=$_POST['leases_offset']; +$leases_slots=$_POST['leases_slots']; +$leases_w=$_POST['leases_w']; + +// need to recompute reservable nodes for this slice +$node_columns=array('hostname','node_id'); +$reservable_nodes=$api->GetNodes(array('|slice_ids'=>intval($sliceid), 'node_type'=>'reservable'),$node_columns); + +// where to start from, expressed as an offset in hours from now +$rough_start=time()+$leases_offset*3600; +// show the next 36 grains +$duration=$leases_slots*$leases_grain; +$steps=$duration/$leases_grain; +$start=intval($rough_start/$leases_grain)*$leases_grain; +$end=$rough_start+$duration; +$lease_columns=array('lease_id','name','t_from','t_until','hostname','name'); +$leases=$api->GetLeases(array(']t_until'=>$rough_start,'[t_from'=>$end,'-SORT'=>'t_from'),$lease_columns); +// hash nodes -> leases +$host_hash=array(); +foreach ($leases as $lease) { + $hostname=$lease['hostname']; + if ( ! isset($host_hash[$hostname] )) { + $host_hash[$hostname]=array(); + } + // resync within the table + $lease['nfrom']=($lease['t_from']-$start)/$leases_grain; + $lease['nuntil']=($lease['t_until']-$start)/$leases_grain; + $host_hash[$hostname] []= $lease; +} +// leases_data is the name used by leases.js to locate this table +//echo ""; +// empty upper-left cell +echo ""; +// the timeslot headers read (timestamp,label) +$day_names=array('Su','M','Tu','W','Th','F','Sa'); +for ($i=0; $i<$steps; $i++) { + $timestamp=($start+$i*$leases_grain); + $day=$day_names[intval(strftime("%w",$timestamp))]; + $label=$day . strftime(" %H:%M",$timestamp); + // expose in each header cell the full timestamp, and how to display it - use & as a separator*/ + echo ""; +} +echo ""; +// todo - sort on hostnames +function sort_hostname ($a,$b) { return ($a['hostname']<$b['hostname'])?-1:1;} +usort($reservable_nodes,"sort_hostname"); +foreach ($reservable_nodes as $node) { + echo ""; + $hostname=$node['hostname']; + $leases=$host_hash[$hostname]; + $counter=0; + while ($counter<$steps) { + if ($leases && ($leases[0]['nfrom']<=$counter)) { + $lease=array_shift($leases); + /* nicer display, merge two consecutive leases for the same slice + avoid doing that for now, as it might makes things confusing */ + /* while ($leases && ($leases[0]['name']==$lease['name']) && ($leases[0]['nfrom']==$lease['nuntil'])) { + $lease['nuntil']=$leases[0]['nuntil']; + array_shift($leases); + }*/ + $duration=$lease['nuntil']-$counter; + echo ""; + $counter=$lease['nuntil']; + } else { + echo ""; + $counter+=1; + } + } + echo ""; +} +echo ""; +//echo "\n"; + +?> diff --git a/planetlab/slices/leases.js b/planetlab/slices/leases.js index 67019a6..bf98641 100644 --- a/planetlab/slices/leases.js +++ b/planetlab/slices/leases.js @@ -10,8 +10,8 @@ var y_header = 12; var y_sep = 10; // 1-grain leases attributes -// x_grain is configurable from $_GET -//var x_grain = 20; +// w_grain is configurable from $_GET +//var w_grain = 20; var y_node = 15; var radius= 6; @@ -51,36 +51,103 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s //////////////////////////////////////////////////////////// // the scheduler object -function Scheduler (sliceid, slicename, x_grain, axisx, axisy, data) { +function Scheduler (sliceid, slicename, w_grain) { + + // xxx-hacky dunno how to retrieve this object from an ajax callback + Scheduler.scheduler=this; // the data contains slice names, and lease_id, we need this to find our own leases (mine) this.sliceid=sliceid; this.slicename=slicename; - this.axisx=axisx; - this.axisy=axisy; - this.data=data; + this.paper=null; - this.x_grain = parseInt(x_grain); + this.w_grain = parseInt(w_grain); // the path for the triangle-shaped buttons - this.timebutton_path="M1,0L"+(this.x_grain-1)+",0L"+(this.x_grain/2)+","+y_header+"L1,0"; + this.timebutton_path="M1,0L"+(this.w_grain-1)+",0L"+(this.w_grain/2)+","+y_header+"L1,0"; - // utilities to keep track of all the leases - this.leases=[]; - this.append_lease = function (lease) { - this.leases.push(lease); + // how many time slots + this.nb_grains = function () { return this.axisx.length;} + + //////////////////// + // store the result of an ajax request in the leases_data table + this.set_html = function (html_data) { + var table_text = $$("table#leases_data")[0].innerHTML; + $$("table#leases_data")[0].innerHTML=html_data; + table_text = $$("table#leases_data")[0].innerHTML; + return true; } - // how many time slots - this.nb_grains = function () { return axisx.length;} + //////////////////// + // the names of the hidden fields that hold the input to this class + // are hard-wired for now + this.parse_html = function () { + this.sliceid=getInnerText($$("span#leases_sliceid")[0]).strip(); + this.slicename=getInnerText($$("span#leases_slicename")[0]).strip(); + this.leases_grain=getInnerText($$("span#leases_grain")[0]).strip(); + this.leases_offset=getInnerText($$("span#leases_offset")[0]).strip(); + this.leases_slots=getInnerText($$("span#leases_slots")[0]).strip(); + this.leases_w=getInnerText($$("span#leases_w")[0]).strip(); + + var table = $$("table#leases_data")[0]; + // no reservable nodes - no data + if ( ! table) return false; + // check for the body too xxx + // the nodelabels + var data = [], axisx = [], axisy = []; + table.getElementsBySelector("tbody>tr>th").each(function (cell) { + axisy.push(getInnerText(cell)); + }); + + // the timeslot labels + table.getElementsBySelector("thead>tr>th").each(function (cell) { + /* [0]: timestamp -- [1]: displayable*/ + axisx.push(getInnerText(cell).split("&")); + }); + + // leases - expect colspan to describe length in grains + // the text contents is expected to be lease_id & slicename + table.getElementsBySelector("tbody>tr>td").each(function (cell) { + var cell_data; + var slice_attributes=getInnerText(cell).split('&'); + // booked leases come with lease id and slice name + if (slice_attributes.length == 2) { + // leases is booked : slice_id, slice_name, duration in grains + cell_data=new Array (slice_attributes[0], slice_attributes[1], cell.colSpan); + } else { + cell_data = new Array ('','',cell.colSpan); + } + data.push(cell_data); + }); + + this.axisx=axisx; + this.axisy=axisy; + this.data=data; + return true; + } - this.init = function (canvas_id) { - this.total_width = x_nodelabel + this.nb_grains()*this.x_grain; + //////////////////// + // draw + this.draw_area = function (canvas_id) { + this.total_width = x_nodelabel + this.nb_grains()*this.w_grain; this.total_height = 2*y_header /* the timelabels */ + 2*y_sep /* extra space */ + y_node /* all-nodes & timebuttons row */ + (this.axisy.length)*(y_node+y_sep); /* the regular nodes and preceding space */ - paper = Raphael (canvas_id, this.total_width+x_sep, this.total_height); + // reuse for paper if exists with same size, or (re-)create otherwise + var paper; + if (this.paper == null) { + paper = Raphael (canvas_id, this.total_width+x_sep, this.total_height); + } else if (this.paper.width==this.total_width && this.paper.height==this.total_height) { + paper=this.paper; + paper.clear(); + } else { + $$("#"+canvas_id)[0].innerHTML=""; + paper = Raphael (canvas_id, this.total_width+x_sep, this.total_height); + } + this.paper=paper; + var axisx=this.axisx; + var axisy=this.axisy; // maintain the list of nodelabels for the 'all nodes' button this.nodelabels=[]; @@ -114,7 +181,7 @@ function Scheduler (sliceid, slicename, x_grain, axisx, axisy, data) { } else if ( (timestamp%(12*3600))==0) { paper.path(half_daymarker_path).attr({'translation':left+','+top}).attr(attr_daymarker); } - left+=(this.x_grain); + left+=(this.w_grain); } ////////// the row with the timeslot buttons (the one labeled 'All nodes') @@ -134,14 +201,15 @@ function Scheduler (sliceid, slicename, x_grain, axisx, axisy, data) { timebutton.from_time=axisx[i][0]; timebutton.scheduler=this; timebutton.click(timebutton_methods.click); - left+=(this.x_grain); + left+=(this.w_grain); } //////// the body of the scheduler : loop on nodes top += y_node+y_sep; var data_index=0; + this.leases=[]; for (var i=0, len=axisy.length; itr>td")[0]).split('&'); - var sliceid=slice_attributes[0]; - var slicename=slice_attributes[1]; - var x_grain=slice_attributes[2]; - // the nodelabels - table.getElementsBySelector("tbody>tr>th").each(function (cell) { - axisy.push(getInnerText(cell)); - }); - // the timeslot labels - table.getElementsBySelector("thead>tr>th").each(function (cell) { - /* [0]: timestamp -- [1]: displayable*/ - axisx.push(getInnerText(cell).split("&")); - }); - // leases - expect colspan to describe length in grains - // the text contents is expected to be lease_id & slicename - table.getElementsBySelector("tbody>tr>td").each(function (cell) { - var cell_data; - slice_attributes=getInnerText(cell).split('&'); - // booked leases come with lease id and slice name - if (slice_attributes.length == 2) { - // leases is booked : slice_id, slice_name, duration in grains - cell_data=new Array (slice_attributes[0], slice_attributes[1], cell.colSpan); - } else { - cell_data = new Array ('','',cell.colSpan); - } - data.push(cell_data); - }); - var scheduler = new Scheduler (sliceid,slicename, x_grain, axisx, axisy, data); - table.hide(); - // leases_area is a
created by slice.php as a placeholder - scheduler.init ("leases_area"); - + var sliceid = getInnerText($$("span#leases_sliceid")[0]).strip(); + var slicename = getInnerText($$("span#leases_slicename")[0]).strip(); + var w_grain = getInnerText($$("span#leases_w")[0]).strip(); + var scheduler = new Scheduler (sliceid,slicename,w_grain); + // parse the table with data, and if not empty, draw the scheduler + if (scheduler.parse_html ()) { + scheduler.draw_area("leases_area"); + } + + // attach behaviour to buttons + var refresh=$$("button#leases_refresh")[0]; + if (refresh) refresh.onclick = function () { scheduler.refresh();} var submit=$$("button#leases_submit")[0]; submit.onclick = function () { scheduler.submit(); } - var clear=$$("button#leases_clear")[0]; - clear.onclick = function () { scheduler.clear(); } + + scheduler.refresh(); } diff --git a/planetlab/slices/slice.php b/planetlab/slices/slice.php index 51248f9..dd71375 100644 --- a/planetlab/slices/slice.php +++ b/planetlab/slices/slice.php @@ -1,7 +1,5 @@ GetLeaseGranularity(); + + // these elements are for passing data to the javascript layer + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + // cut off if ($profiling) plc_debug_prof('6 granul',$grain); // where to start from, expressed as an offset in hours from now - $rough_start=time()+$resa_offset*3600; + $rough_start=time()+$leases_offset*3600; // show the next 36 grains - $duration=$resa_slots*$grain; + $duration=$leases_slots*$grain; $steps=$duration/$grain; $start=intval($rough_start/$grain)*$grain; $end=$rough_start+$duration; @@ -642,9 +651,9 @@ EOF; $host_hash[$hostname] []= $lease; } // leases_data is the name used by leases.js to locate this table - echo ""; + echo "
"; // pass (slice_id,slicename,x_grain) in the upper-left cell, as thead>tr>td - echo ""; + echo ""; // the timeslot headers read (timestamp,label) $day_names=array('Su','M','Tu','W','Th','F','Sa'); for ($i=0; $i<$steps; $i++) { @@ -689,7 +698,7 @@ EOF;
- +
EOF; diff --git a/plekit/prototype/prototype.js b/plekit/prototype/prototype.js index d229ea8..84020f2 120000 --- a/plekit/prototype/prototype.js +++ b/plekit/prototype/prototype.js @@ -1 +1 @@ -prototype-1.6.0.3.js \ No newline at end of file +prototype-1.7.0.0.js \ No newline at end of file diff --git a/plekit/table/table.js b/plekit/table/table.js index 0f86acb..31ab09c 100644 --- a/plekit/table/table.js +++ b/plekit/table/table.js @@ -1,5 +1,3 @@ -/* $Id$ */ - var debug=false; /* for debugging purposes */ -- 2.43.0