X-Git-Url: http://git.onelab.eu/?p=myslice.git;a=blobdiff_plain;f=plugins%2Fscheduler%2Fstatic%2Fjs%2Fscheduler.js;h=c9b2096831f7b91d6a084d6e6a8870e22c48d298;hp=79292e5af7a611f765491741f71db1f7ac9e04bf;hb=864c51bf4c1330e2a1a1b5978b8a8dc5afe01763;hpb=365e932c846dcd93f35f4cae9a04be0f7056d0a5 diff --git a/plugins/scheduler/static/js/scheduler.js b/plugins/scheduler/static/js/scheduler.js index 79292e5a..c9b20968 100644 --- a/plugins/scheduler/static/js/scheduler.js +++ b/plugins/scheduler/static/js/scheduler.js @@ -45,11 +45,11 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s init: function(options, element) { + this.classname="scheduler"; this._super(options, element); /* Member variables */ - this.options = options; - this.canvas_id = 'leases_area-' + options.plugin_uuid; + this._canvas_id = this.id('leases_area'); this.query_uuid = options.query_uuid; this.rows = null; @@ -57,22 +57,30 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s //this.current_resources = Array(); //this.current_leases = Array(); - this.myLeases = Array(); - this.allLeases = Array(); + /* Managing asynchronous reception of resources and leases */ + this._resources = Array(); + this._leases = Array(); + this._received_resources = false; + this._received_leases = false; - this.listLeases = 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.axisy = 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; // the data contains slice names, and lease_id, we need this to find our own leases (mine) - this.paper=null; + this._paper=null; + /* XXX Events */ @@ -80,7 +88,8 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s /* Listening to queries */ this.listen_query(options.query_uuid); - this.listen_query(options.query_lease_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 */ jQuery("#datepicker").datetimepicker({ @@ -100,55 +109,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 */ @@ -168,71 +138,134 @@ 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 ***************************/ + + /* ------------------------------------------------------------------ + * Resources + * ------------------------------------------------------------------ */ - /* QUERY HANDLERS */ + on_query_in_progress: function() { + this.spin(); + }, - set_resources: function(resources) + on_query_done: function() { + /* We have received all leases */ + if (this._received_resources) { + this._draw(this._canvas_id); + this.unspin(); + } + this._received_leases = true; + }, + + /* ------------------------------------------------------------------ + * All resources + * ------------------------------------------------------------------ */ + + on_all_resources_query_in_progress: function() { + console.log("all resources query in progress"); + }, + + on_all_resources_new_record: function(record) { - //console.log(resources); - var scheduler = this; - jQuery.each(resources, function(i, resource) { - // ... add reservable ones to the x axis - if ((typeof resource.exclusive != 'undefined') && (resource.exclusive)) { - scheduler.axisy.push(Array(resource.urn, resource.resource_hrn, resource.type)); - } - // ... if we do not have information about slivers (first update), update it - if (typeof resource.sliver != 'undefined') { - // XXX - } - }); + 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 + } + }, - this.draw(this.canvas_id); - } + /* ------------------------------------------------------------------ + * Leases + * ------------------------------------------------------------------ */ + + on_lease_new_record: function(record) + { + this._leases.push(record); + // this.initial_leases=leases; + }, - this.set_leases = function(leases) { - this.initial_leases=leases; - this.draw(this.canvas_id); - } + on_lease_field_state_changed: function(data) + { + var lease = data.value; + var urn = lease[0]; + var start_time = lease[1]; + + var lease_element = this._lease_element_find(urn, start_time); + if (!lease_element) { + console.log("Alert: lease element not found"); + return; + } - this.update_resources = function(resources) { - // - } + switch(data.request) { + case FIELD_REQUEST_ADD: + case FIELD_REQUEST_ADD_RESET: + this._leases.push(data.value); + this._lease_init_mine(lease_element); + break; + case FIELD_REQUEST_REMOVE: + case FIELD_REQUEST_REMOVE_RESET: + // We remove data.value (aka keep those leases different from data.value + this._leases = $.grep(this._leases, function(x) { return x != data.value; }); + this._lease_init_free(lease_element); + break; + default: + break; - this.update_leases = function(leases) { - // - } + } + }, - /* RECORD HANDLERS */ + on_lease_query_done: function(record) + { + /* We have received all resources */ + if (this._received_leases) { + 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) { @@ -246,133 +279,152 @@ var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-s if (result) return false; }); +*/ return result; }, + /* Iterative search through raphael.js objects, no forEach, no getById in the current version */ + _lease_element_find: function(urn, start_time) + { + var date = new Date(start_time*1000); + var pos = this._paper.top; + while (pos) { + if (pos.key == urn + "-" + date) + return pos; + pos = pos.prev; + } + return null; + }, + /** * @brief Draw */ - draw: function() + _draw: function() { - var canvas_id = this.canvas_id; + 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.axisy.length)*(o.y_node+o.y_sep); /* the regular nodes and preceding space */ + + o.y_node /* all-nodes & timebuttons row */ + + (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); - } else if (this.paper.width==total_width && this.paper.height==total_height) { - paper=this.paper; + if (this._paper == null) { + 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); + $("#"+canvas_id)[0].innerHTML=""; + //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.axisy; + 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(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(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