From: Thierry Parmentelat Date: Tue, 9 Apr 2013 06:43:35 +0000 (+0200) Subject: Merge branch 'master' of ssh://git.onelab.eu/git/myslice-django X-Git-Tag: myslice-0.2-1~169 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=c8ac1863026e5736065065e931e20de310cb3b06;hp=d2d493bdacd932283df536b3bb64a1b12e48a5f7;p=myslice.git Merge branch 'master' of ssh://git.onelab.eu/git/myslice-django --- diff --git a/manifold/js/manifold.js b/manifold/js/manifold.js index 934a1697..6209085b 100644 --- a/manifold/js/manifold.js +++ b/manifold/js/manifold.js @@ -25,27 +25,28 @@ var manifold = { insert_query : function (query) { manifold.all_queries[query.query_uuid]=query; - }, + }, find_query : function (query_uuid) { return manifold.all_queries[query_uuid]; }, debug_all_queries : function (msg) { for (var query_uuid in manifold.all_queries) { - console.log("manifold.debug " + msg + " " + query_uuid + " -> " + manifold.all_queries[query_uuid]); + $.publish("messages:debug","manifold.debug " + msg + " " + query_uuid + " -> " + manifold.all_queries[query_uuid]); } }, // trigger a query asynchroneously proxy_url : '/manifold/proxy/json/', - asynchroneous_debug : false, + asynchroneous_debug : true, // Executes all async. queries // input queries are specified as a list of {'query_uuid': , 'id': } asynchroneous_exec : function (query_uuid_domids) { // start spinners - if (manifold.asynchroneous_debug) console.log("Turning on spin with " + jQuery(".need-spin").length + " matches for .need-spin"); + if (manifold.asynchroneous_debug) + $.publish("messages.debug","Turning on spin with " + jQuery(".need-spin").length + " matches for .need-spin"); jQuery('.need-spin').spin(spin_presets); // We use js function closure to be able to pass the query (array) to the @@ -58,7 +59,7 @@ var manifold = { var query=manifold.find_query(tuple.query_uuid); var query_json=JSON.stringify (query); if (manifold.asynchroneous_debug) { - console.log ("sending POST on " + manifold.proxy_url + " with query= " + query.__repr()); + $.publish("messages:debug","sending POST on " + manifold.proxy_url + " with query= " + query.__repr()); } // not quite sure what happens if we send a string directly, as POST data is named.. // this gets reconstructed on the proxy side with ManifoldQuery.fill_from_POST @@ -67,7 +68,8 @@ var manifold = { }, asynchroneous_success : function (data, query, id) { - if (manifold.asynchroneous_debug) console.log ("received manifold result with code " + data.code); + if (manifold.asynchroneous_debug) + $.publish("messages:debug","received manifold result with code " + data.code); // xxx should have a nicer declaration of that enum in sync with the python code somehow if (data.code == 1) { alert("Your session has expired, please log in again"); diff --git a/plugins/hazelnut/hazelnut.js b/plugins/hazelnut/hazelnut.js index f38488c5..7afc726b 100644 --- a/plugins/hazelnut/hazelnut.js +++ b/plugins/hazelnut/hazelnut.js @@ -40,11 +40,11 @@ return this.each(function() { var $this = $(this); /* Events */ - $(this).on('show.Datatables', methods.show); + $this.on('show.Datatables', methods.show); /* An object that will hold private variables and methods */ var hazelnut = new Hazelnut (options); - $(this).data('Hazelnut', hazelnut); + $this.data('Hazelnut', hazelnut); var query_channel = '/query/' + options.query_uuid + '/changed'; var update_channel = '/update-set/' + options.query_uuid; diff --git a/plugins/updater/__init__.py b/plugins/updater/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/plugins/updater/updater.css b/plugins/updater/updater.css new file mode 100644 index 00000000..34345abd --- /dev/null +++ b/plugins/updater/updater.css @@ -0,0 +1,3 @@ +input.updater { + margin: 10px; +} diff --git a/plugins/updater/updater.html b/plugins/updater/updater.html new file mode 100644 index 00000000..7edc44da --- /dev/null +++ b/plugins/updater/updater.html @@ -0,0 +1 @@ + diff --git a/plugins/updater/updater.js b/plugins/updater/updater.js new file mode 100644 index 00000000..7c587e90 --- /dev/null +++ b/plugins/updater/updater.js @@ -0,0 +1,148 @@ +/** + * Description: associate with a Get query, maintains the 'Update' query that records pending changes + * Copyright (c) 2012 UPMC Sorbonne Universite - INRIA + * License: GPLv3 + */ + +( function ( $ ) { + + $.fn.Updater = function ( method ) { + /* Method calling logic */ + if ( methods[method] ) { + return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof method === 'object' || ! method ) { + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + method + ' does not exist on $.Updater' ); + } + }; + + var methods = { + init : function( options ) { + return this.each(function(){ + var $this = $(this); + var updater = new Updater (options); + $this.data('Updater',updater); + /* Subscribe to query updates */ + var results_channel = '/results/' + options.query_uuid + '/changed'; + $.subscribe(results_channel, function (e,rows) { updater.update_slice (e,rows); } ); + updater.arm_button(); + }); + }, + destroy : function( ) { + return this.each(function(){ + var $this = $(this); + $(window).unbind('Updater'); + data.Updater.remove(); + $this.removeData('Updater'); + }); + }, + + show : function( content ) { } + }; + + function Updater (options) { + this.options=options; + // xxx should try to locate update_query first, in case we have several Updaters + // on the same query + // however the mental model behind the global manifold object for now is + // to unambiguously find a query based on its query_uuid, which in the joomla + // implementation wouldn't fly + // we keep this for a later improvement + var query=manifold.find_query (options.query_uuid); + // very rough way of filling this for now + this.update_query = + new ManifoldQuery ("update", query.subject, null, query.filters, + {}, // params + query.fields, + undefined, /* unique */ + query.query_uuid, /* tmp */ + undefined, undefined /* maybe some day I'll get that one */); + + this.arm_button = function () { + $('#updater-' + this.options.plugin_uuid).click(this, this.submit_update_request); + }, + this.submit_update_request = function (e) { + var update_query = e.data.update_query; + $.publish("messages:debug","Updater.submit_update_request " + update_query.__repr()); + // xxx here - we need a valid query_uuid so the results will make it + manifold.asynchroneous_exec ( [ {'query_uuid': xxx, 'id': null}]); + // looks like a previous attempt to disable the button while the query is flying + //$('#updateslice-' + options.plugin_uuid).prop('disabled', true); + } + }; + + /* Private methods */ + + function update_resources(e, resources, change) { + data = e.data.instance.data().Slices; + + data.update_query.params['resource'] = resources + $.publish('/update/' + data.options.query_uuid, [data.update_query, true]); + } + + function update_leases(e, leases, change) { + data = e.data.instance.data().Slices; + + data.update_query.params['lease'] = leases + $.publish('/update/' + data.options.query_uuid, [data.update_query, true]); + } + + function update_slice(e, rows, query) { + /* This function is called twice : get and update */ + + var data = e.data.instance.data().Slices; + + /* Update placeholders and trigger subqueries updates */ + if (rows.length == 0) { + alert("no result"); + return; + } + var slice = rows[0]; + + /* for get */ + if (data.update_query == null) { + data.update_query = new Query('update','slice', 'now', query.filter, {"resource": null, "lease": null}, query.fields, 0, data.options.query_uuid); + } + /* In case of update the list of resources and leases should be updated accordingly */ + + /* only for get ? */ + $.each(slice, function(key, value) { + if (typeof value == 'string') { + $('#myslice__' + key).html(value); + } + }); + + /* TODO avoid repetitions + made this code generic and plugin-independent */ + + if (query.method == 'update') { + // XXX NON, les uuid doivent etre les memes que dans la query Get, cet appel devrait etre fait avant. + query.analyzed_subqueries(); + } + + /* NOTE: Dans le cadre d'un update, on n'a pas besoin de refaire tout + * le query plan et obtenir toutes les infos, par contre on ne peut pas + * savoir d'avance quels parametres ont été accordés, changés, etc. + * Dans le cas général, ca pourrait affecter le query plan... + * Par contre on n'a pas d'information sur toutes les resources, mais + * uniquement celles dans la liste. Comment gérer ? + */ + + /* Inform child plugins about their respective parts of the results */ + /* Only for get */ + var r_subq = query.analyzed_query.subqueries['resource']; + var l_subq = query.analyzed_query.subqueries['lease']; + $.publish('/results/' + r_subq.uuid + '/changed', [slice['resource'], r_subq]); + $.publish('/results/' + l_subq.uuid + '/changed', [slice['lease'], l_subq]); + + /* Subscribe to get notifications from child plugins */ + if (!data.child_subscribe) { + $.subscribe('/update-set/' + r_subq.uuid, {instance: e.data.instance}, update_resources); + $.subscribe('/update-set/' + l_subq.uuid, {instance: e.data.instance}, update_leases); + data.child_subscribe = true + } + + } + +})( jQuery ); + diff --git a/plugins/updater/updater.py b/plugins/updater/updater.py new file mode 100644 index 00000000..506416bd --- /dev/null +++ b/plugins/updater/updater.py @@ -0,0 +1,28 @@ +from unfold.plugin import Plugin + +class Updater (Plugin): + + def __init__ (self, query, label="Update", **settings): + Plugin.__init__ (self, **settings) + # xxx would make sense to check this is a Get query... + self.query=query + self.label=label + + def template_file (self): + return "updater.html" + + def requirements (self): + return { + 'js_files' : [ "js/updater.js" , "js/manifold.js", "js/manifold-query.js", ], + 'css_files' : "css/updater.css", + } + + # although this has no query, we need a plugin instance to be created in the js output + def export_json_settings (self): return True + # the js plugin expects a domid + def json_settings_list (self): return [ 'plugin_uuid', 'query_uuid' ] + + # and we don't need a spin wheel + def start_with_spin (self): return False + + def default_togglable (self): return False diff --git a/trash/pluginview.py b/trash/pluginview.py index baf867a3..190533b0 100644 --- a/trash/pluginview.py +++ b/trash/pluginview.py @@ -8,6 +8,7 @@ from django.shortcuts import render_to_response from django.contrib.auth.decorators import login_required from unfold.page import Page +from manifold.manifoldquery import ManifoldQuery from plugins.stack.stack import Stack from plugins.tabs.tabs import Tabs @@ -15,6 +16,7 @@ from plugins.lists.staticlist import StaticList from plugins.quickfilter.quickfilter import QuickFilter from plugins.raw.raw import Raw from plugins.messages.messages import Messages +from plugins.updater.updater import Updater from myslice.viewutils import topmenu_items, the_user from myslice.viewutils import hard_wired_slice_names, hard_wired_list, lorem_p, lorem, quickfilter_criterias @@ -27,12 +29,32 @@ def test_plugin_view (request): # variables that will get passed to this template template_env = {} + slicename='ple.inria.omftest' + main_query = ManifoldQuery (action='get', + subject='resource', + timestamp='latest', + fields=['network','type','hrn','hostname'], + filters= [ [ 'slice_hrn', '=', slicename, ] ], + ) + main_plugin = \ + Stack ( + page=page, + title='thestack', + togglable=False, + sons=[ \ Messages ( page=page, title="Runtime messages", domid="msgs-pre", - ) + ), + Updater ( + page=page, + title="Update me", + query=main_query, + label="Update me", + ), + ]) # define 'unfold1_main' to the template engine template_env [ 'unfold1_main' ] = main_plugin.render(request) diff --git a/unfold/plugin.py b/unfold/plugin.py index cc2eaeba..f9e1ea41 100644 --- a/unfold/plugin.py +++ b/unfold/plugin.py @@ -66,7 +66,7 @@ class Plugin: # which will result in 'foo' being accessible to the template engine # def __init__ (self, page, title, domid=None, - visible=True, togglable=True, toggled=None, **settings): + visible=True, togglable=None, toggled=None, **settings): self.page = page self.title=title # callers can provide their domid for css'ing @@ -75,9 +75,10 @@ class Plugin: self.classname=self._py_classname() self.plugin_classname=self._js_classname() self.visible=visible - self.togglable=togglable - if toggled is not None: self.toggled=toggled - else: self.toggled=self.default_toggled() + if togglable is None: self.togglable=self.default_togglable() + else: self.togglable=togglable + if toggled is None: self.toggled=self.default_toggled() + else: self.toggled=toggled # what comes from subclasses for (k,v) in settings.iteritems(): setattr(self,k,v) @@ -250,6 +251,7 @@ class Plugin: def template_file (self): return "undefined_template" def template_env (self, request): return {} + def default_togglable (self): return True def default_toggled (self): return 'persistent' # # tell the framework about requirements (for the document
)