From: Jordan Augé Date: Thu, 28 Nov 2013 15:39:12 +0000 (+0100) Subject: plugins.scheduler: scheduler almost working X-Git-Tag: myslice-0.3-0~106 X-Git-Url: http://git.onelab.eu/?p=myslice.git;a=commitdiff_plain;h=63d95a63befff4f3578163ae1fdb89a29009e7ee plugins.scheduler: scheduler almost working --- diff --git a/plugins/scheduler/__init__.py b/plugins/scheduler/__init__.py index 94a75716..c21e96b6 100644 --- a/plugins/scheduler/__init__.py +++ b/plugins/scheduler/__init__.py @@ -6,9 +6,11 @@ class Scheduler(Plugin): # pass columns as the initial set of columns # if None then this is taken from the query's fields # latitude,longitude, zoom : the starting point - def __init__ (self, query, query_lease = None, **settings): + def __init__ (self, query, query_all_resources, query_lease = None, **settings): Plugin.__init__ (self, **settings) self.query=query + self.query_all_resources = query_all_resources + self.query_all_resources_uuid = query_all_resources.query_uuid self.query_lease = query_lease self.query_lease_uuid = query_lease.query_uuid if query_lease else None @@ -37,4 +39,4 @@ class Scheduler(Plugin): # the list of things passed to the js plugin def json_settings_list (self): - return ['plugin_uuid','query_uuid', 'query_lease_uuid', ] + return ['plugin_uuid','query_uuid', 'query_lease_uuid', 'query_all_resources_uuid'] diff --git a/plugins/scheduler/static/js/scheduler.js b/plugins/scheduler/static/js/scheduler.js index 3c95832d..06ad5314 100644 --- a/plugins/scheduler/static/js/scheduler.js +++ b/plugins/scheduler/static/js/scheduler.js @@ -57,19 +57,22 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s //this.current_leases = Array(); /* Managing asynchronous reception of resources and leases */ - this._tmp_resources = Array(); - this.listLeases = Array(); + this._resources = Array(); + this._leases = Array(); this._received_resources = false; this._received_leases = false; - this.myLeases = Array(); - this.allLeases = Array(); + this._axisx = Array(); + this._nodelabels = Array(); + this._lease_elements = Array(); + //this.myLeases = Array(); + //this.allLeases = Array(); + + /* The time axis is an array of tuple (time, printable time) representing timeslots */ - this.axisx = Array(); - this.resources = Array(); this.data = Array(); this.default_granularity = 1800; /* 30 min */ - this.initial_timestamp = null; + this._initial_timestamp = null; /* This should be updated to be the ppcm of all granularities */ this.min_granularity = this.default_granularity; @@ -77,12 +80,14 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s // the data contains slice names, and lease_id, we need this to find our own leases (mine) this.paper=null; + /* XXX Events */ /* XXX Keys */ /* Listening to queries */ this.listen_query(options.query_uuid); + this.listen_query(options.query_all_resources_uuid, 'all_resources'); this.listen_query(options.query_lease_uuid, 'lease'); /* XXX GUI setup and event binding */ @@ -103,55 +108,16 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s // pass the result to init_axisx - done //console.log(currentDate); s.clear(); - s.init_axisx(currentDate); - s.draw(); + s._init_axisx(currentDate); + s._draw(); // Do we need to populate the timeslots with existing leases? // Look how to populate with initial_leases [we have to show the leases] } }); - //console.log(s.nodelabels[1]); - // Do we need to populate the timeslots with existing leases? - // Look how to populate with initial_leases - - // TODO -- DONE Note: autocomplete is not search box - // Implement a filtering functionality, on the name of the node - // http://jqueryui.com/autocomplete/ - // pass s.nodelabels to autocomplete function - //jQuery("#search").autocomplete('s.nodelabel'); - //console.log(s.nodelabel); - - /* - * TODO - * During init, there are no resources - * So the list of nodes is empty - * The function triggered by the subscription to the resources query - * var RESULTS_RESOURCES = '/results/' + options.resource_query_uuid + '/changed'; - * $.subscribe(RESULTS_RESOURCES, function(e, resources) { s.set_resources(resources); }); - * Will have to update the list of nodes available through autocomplete (availableTags) - * - * Be inspired by QueryEditor plugin - * - * Resources informations in s.axisy ??? - * - * Filter what has been selected in other plugins: - * QueryEditor - * QuickFilter - * AdvancedFilter - * - * Implement an action of filtering while typing - * filter what correspond to the user choice - * - $(function() { - var availableTags = ['omf','nitos','ple', s.nodelabel]; - $( "#search" ).autocomplete({ - source: availableTags - }); - }); - */ - this.init_axisx(''); - this.draw(); + this._init_axisx(''); + this._draw(); }, /* init */ @@ -171,17 +137,18 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s radius: 6, anim_delay: 350, checkboxes: false, - resource_query_uuid: null, /* resources */ - lease_query_uuid: null, /* leases */ }, /* PLUGIN EVENTS */ /* GUI EVENTS */ - /* GUI MANIPULATION */ + /************************** GUI MANIPULATION **************************/ - /* TEMPLATES */ + /* NOTE: All Raphael-dependent code should go here. Performance issues + * are suspected, it might be improved by a move to d3.js. The more + * general problem to solve is how to manipulate lots of svg objects. + */ /*************************** RECORD HANDLER ***************************/ @@ -189,17 +156,6 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s * Resources * ------------------------------------------------------------------ */ - on_new_record: function(record) - { - if ((typeof record.exclusive != 'undefined') && (record.exclusive)) { - this.resources.push(Array(record.urn, record.record_hrn, record.type)); - } - // ... if we do not have information about slivers (first update), update it - if (typeof record.sliver != 'undefined') { - // XXX - } - }, - on_query_in_progress: function() { this.spin(); }, @@ -207,18 +163,34 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s on_query_done: function() { /* We have received all leases */ if (this._received_resources) { - this.draw(this._canvas_id); + this._draw(this._canvas_id); this.unspin(); } this._received_leases = true; }, + + /* ------------------------------------------------------------------ + * All resources + * ------------------------------------------------------------------ */ + + on_all_resources_new_record: function(record) + { + if ((typeof record.exclusive != 'undefined') && (record.exclusive)) { + this._resources.push(Array(record.urn, record.hrn, record.type)); + } + // ... if we do not have information about slivers (first update), update it + if (typeof record.sliver != 'undefined') { + // XXX + } + }, + /* ------------------------------------------------------------------ * Leases * ------------------------------------------------------------------ */ on_lease_new_record: function(record) { - this.listLeases.push(record); + this._leases.push(record); // this.initial_leases=leases; }, @@ -226,30 +198,39 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s { /* We have received all resources */ if (this._received_leases) { - this.draw(this._canvas_id); + this._draw(this._canvas_id); this.unspin(); } this._received_resources = true; }, - /* INTERNAL FUNCTIONS */ + /************************** PRIVATE METHODS ***************************/ /** * @brief Return the number of time slots */ nb_grains: function () { - return this.axisx.length; + return this._axisx.length; }, /** * @brief Returns whether there is a pending lease at this timestamp */ - find_lease: function(urn, timestamp) + _lease_find: function(urn, timestamp) { var scheduler = this; var result = null; + $.each(scheduler._leases, function(i, lease) { + if ((lease[0] == urn) && + ((timestamp >= lease[1]) && (timestamp < (lease[1] + lease[2] * 1800)))) { + result = lease; + return false; // stop each + } + }); + +/* $.each(Array(scheduler.myLeases, scheduler.allLeases), function(i, array) { $.each(array, function(i, lease) { if (lease[0] == urn) { @@ -263,133 +244,139 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s if (result) return false; }); +*/ return result; }, /** * @brief Draw */ - draw: function() + _draw: function() { var canvas_id = this._canvas_id; var o = this.options; + var total_width = o.x_nodelabel + this.nb_grains() * this.options.leases_w; var total_height = 2 * o.y_header /* the timelabels */ + 2 * o.y_sep /* extra space */ + o.y_node /* all-nodes & timebuttons row */ - + (this.resources.length)*(o.y_node+o.y_sep); /* the regular nodes and preceding space */ + + (this._resources.length) * (o.y_node + o.y_sep); /* the regular nodes and preceding space */ /* reuse for paper if exists with same size, or (re-)create otherwise */ var paper; if (this.paper == null) { - paper = Raphael (canvas_id, total_width+o.x_sep, total_height); + paper = Raphael (canvas_id, total_width + o.x_sep, total_height); } else if (this.paper.width==total_width && this.paper.height==total_height) { paper=this.paper; paper.clear(); } else { $("#"+canvas_id)[0].innerHTML=""; - paper = Raphael (canvas_id, total_width+o.x_sep, total_height); + //this.elmt().html(); + paper = Raphael (canvas_id, total_width + o.x_sep, total_height); } - this.paper=paper; + this.paper = paper; /* the path for the triangle-shaped buttons */ - this.timebutton_path = "M1,0L"+(this.options.leases_w-1)+",0L"+(this.options.leases_w/2)+","+o.y_header+"L1,0"; + var timebutton_path = "M1,0L"+(this.options.leases_w-1)+",0L"+(this.options.leases_w/2)+","+o.y_header+"L1,0"; - var axisx = this.axisx; - var axisy = this.resources; + var axisx = this._axisx; + var axisy = this._resources; /* maintain the list of nodelabels for the 'all nodes' button */ - this.nodelabels=[]; + this._nodelabels = []; /* create the time slots legend */ var top = 0; var left = o.x_nodelabel; - var daymarker_height= 2*o.y_header + 2*o.y_sep + (axisy.length+1)*(o.y_node+o.y_sep); - var daymarker_path="M0,0L0," + daymarker_height; + var daymarker_height = 2*o.y_header + 2*o.y_sep + (axisy.length + 1) * (o.y_node + o.y_sep); + var daymarker_path = "M0,0L0," + daymarker_height; var half_daymarker_off= 2*o.y_header + o.y_sep; var half_daymarker_path="M0," + half_daymarker_off + "L0," + daymarker_height; var col=0; - for (var i=0, len=axisx.length; i < len; ++i) { + for (var i=0, len = axisx.length; i < len; ++i) { /* pick the printable part */ - var timelabel=axisx[i][1]; + var timelabel = axisx[i][1]; var y = top + o.y_header; - if (col%2 == 0) y += o.y_header; + if (col % 2 == 0) + y += o.y_header; col +=1; /* display time label */ - var timelabel=paper.text(left,y,timelabel).attr(txt_timelabel).attr({"text-anchor":"middle"}); + var timelabel = paper.text(left, y, timelabel).attr(txt_timelabel).attr({"text-anchor": "middle"}); /* draw vertical line */ - var path_spec="M"+left+" "+(y+o.y_header/2)+"L"+left+" "+this.total_height; - var rule=paper.path(path_spec).attr(attr_rules); + var path_spec = "M" + left + " " + (y+o.y_header / 2) + "L" + left + " " + this.total_height; + var rule = paper.path(path_spec).attr(attr_rules); /* show a day marker when relevant */ - var timestamp=parseInt(axisx[i][0]); - if ( (timestamp%(24*3600))==0) { - paper.path(daymarker_path).attr({'translation':left+','+top}).attr(attr_daymarker); + var timestamp = parseInt(axisx[i][0]); + if ((timestamp % (24 * 3600)) == 0) { + paper.path(daymarker_path).attr({'translation': left + ',' + top}).attr(attr_daymarker); } else if ( (timestamp%(12*3600))==0) { - paper.path(half_daymarker_path).attr({'translation':left+','+top}).attr(attr_daymarker); + paper.path(half_daymarker_path).attr({'translation': left + ',' + top}).attr(attr_daymarker); } - left += this.options.leases_w; + left += o.leases_w; } ////////// the row with the timeslot buttons (the one labeled 'All nodes') - this.granularity= this.min_granularity; // XXX axisx[1][0]-axisx[0][0]; + this.granularity = this.min_granularity; // XXX axisx[1][0]-axisx[0][0]; // move two lines down - top += 2*o.y_header + 2*o.y_sep; - left=o.x_nodelabel; + top += 2 * o.y_header + 2 * o.y_sep; + left = o.x_nodelabel; // all nodes buttons - var allnodes = paper.text (o.x_nodelabel-o.x_sep,top+o.y_node/2,"All nodes").attr(txt_allnodes) - .attr ({"font-size":o.y_node, "text-anchor":"end","baseline":"bottom"}); - allnodes.scheduler=this; - allnodes.click(this.allnodes_methods.click); + var allnodes = paper.text(o.x_nodelabel - o.x_sep, top + o.y_node / 2, "All nodes").attr(txt_allnodes) + .attr({"font-size": o.y_node, "text-anchor": "end", "baseline": "bottom"}); + //allnodes.scheduler = this; + allnodes.click(this._allnodes_click); // XXX click // timeslot buttons [it's the triangles above the slots] - for (var i=0, len=axisx.length; i < len; ++i) { - var timebutton=paper.path(this.timebutton_path).attr({'translation':left+','+top}).attr(attr_timebutton); - timebutton.from_time=axisx[i][0]; - timebutton.scheduler=this; - timebutton.click(this.timebutton_methods.click); - left+=(this.options.leases_w); + for (var i = 0, len = axisx.length; i < len; ++i) { + var timebutton = paper.path(timebutton_path).attr({'translation':left + ',' + top}).attr(attr_timebutton); + timebutton.from_time = axisx[i][0]; + timebutton.scheduler = this; + timebutton.click(this._timebutton_click); + left += (o.leases_w); } //////// the body of the scheduler : loop on nodes top += o.y_node + o.y_sep; - var data_index=0; - this.leases=[]; - for (var i=0, len=axisy.length; i0) ? 1 : 0; - for (var i=0, len=scheduler.nodelabels.length; i0) ? 1 : 0; + for (var i=0, len=this._nodelabels.length; i=until_time) { - if (scan.current == "free") relevant_free.push(scan); - else if (scan.current == "mine") relevant_mine.push(scan); - } + + /* clicking */ + _timebutton_click: function (event) + { + var scheduler = this.scheduler; + var from_time = this.from_time; + var until_time = new Date(from_time.getTime() + scheduler.granularity); + /* scan leases on selected nodes, store in two arrays */ + var relevant_free = [], relevant_mine = []; + for (var i = 0, len = scheduler._lease_elements.length; i < len; ++i) { + var scan = scheduler._lease_elements[i]; + if (!scan.nodelabel.selected) + continue; + // overlap ? + if (scan.from_time <= from_time && scan.until_time >= until_time) { + if (scan.current == "free") + relevant_free.push(scan); + else if (scan.current == "mine") + relevant_mine.push(scan); } - // window.console.log("Found " + relevant_free.length + " free and " + relevant_mine.length + " mine"); - /* decide what to do, whether book or release */ - if (relevant_mine.length==0 && relevant_free.length==0) { - alert ("Nothing to do in this timeslot on the selected nodes"); - return; + } + // window.console.log("Found " + relevant_free.length + " free and " + relevant_mine.length + " mine"); + /* decide what to do, whether book or release */ + if (relevant_mine.length == 0 && relevant_free.length == 0) { + alert ("Nothing to do in this timeslot on the selected nodes"); + return; + } + // if at least one is free, let's book + if (relevant_free.length > 0) { + for (var i = 0, len = relevant_free.length; i < len; ++i) { + var lease = relevant_free[i]; + scheduler._lease_init_mine(lease, scheduler._lease_click_free); } - // if at least one is free, let's book - if (relevant_free.length > 0) { - for (var i=0, len=relevant_free.length; i