Merge branch 'master' of git://git.onelab.eu/myslice
[myslice.git] / portal / sliceview.py
1 from django.template                 import RequestContext
2 from django.shortcuts                import render_to_response
3
4 from unfold.loginrequired            import LoginRequiredAutoLogoutView
5
6 from unfold.page                     import Page
7 from manifold.core.query             import Query, AnalyzedQuery
8
9 from myslice.viewutils               import topmenu_items, the_user
10
11 from plugins.raw                     import Raw
12 from plugins.stack                   import Stack
13 from plugins.tabs                    import Tabs
14 from plugins.hazelnut                import Hazelnut 
15 from plugins.resources_selected      import ResourcesSelected
16 from plugins.googlemap               import GoogleMap
17 from plugins.senslabmap.senslabmap   import SensLabMap
18 from plugins.querycode               import QueryCode
19 from plugins.query_editor            import QueryEditor
20 from plugins.active_filters          import ActiveFilters
21 from plugins.quickfilter             import QuickFilter
22 from plugins.messages                import Messages
23
24 tmp_default_slice='ple.upmc.myslicedemo'
25
26 # temporary : turn off the users part to speed things up
27 #do_query_users=True
28 do_query_users=False
29
30 class SliceView (LoginRequiredAutoLogoutView):
31
32     def get (self,request, slicename=tmp_default_slice):
33     
34         page = Page(request)
35         page.add_css_files ('css/slice-view.css')
36         page.add_js_files  ( [ "js/common.functions.js" ] )
37         page.add_js_chunks ('$(function() { console.log("sliceview: jQuery version " + $.fn.jquery); });')
38         page.add_js_chunks ('$(function() { console.log("sliceview: users turned %s"); });'%("on" if do_query_users else "off"))
39         page.expose_js_metadata()
40     
41         metadata = page.get_metadata()
42         resource_md = metadata.details_by_object('resource')
43         resource_fields = [column['name'] for column in resource_md['column']]
44     
45         user_md = metadata.details_by_object('user')
46         user_fields = ['user_hrn'] # [column['name'] for column in user_md['column']]
47     
48         # TODO The query to run is embedded in the URL
49         main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
50         main_query.select(
51                 'slice_hrn',
52                 'resource.resource_hrn', 'resource.hostname', 'resource.type', 'resource.network_hrn',
53                 #'lease.urn',
54                 'user.user_hrn',
55                 #'application.measurement_point.counter'
56         )
57     
58         query_resource_all = Query.get('resource').select(resource_fields)
59         if do_query_users:
60             query_user_all = Query.get('user').select(user_fields)
61     
62         aq = AnalyzedQuery(main_query, metadata=metadata)
63         page.enqueue_query(main_query, analyzed_query=aq)
64         page.enqueue_query(query_resource_all)
65         if do_query_users:
66             page.enqueue_query(query_user_all)
67     
68         # ... and for the relations
69         # XXX Let's hardcode resources for now
70         sq_resource    = aq.subquery('resource')
71         sq_user        = aq.subquery('user')
72         sq_lease       = aq.subquery('lease')
73         sq_measurement = aq.subquery('measurement')
74         
75     
76         # Prepare the display according to all metadata
77         # (some parts will be pending, others can be triggered by users).
78         # 
79         # For example slice measurements will not be requested by default...
80     
81         # Create the base layout (Stack)...
82         main_stack = Stack (
83             page=page,
84             title="Slice %s"%slicename,
85             sons=[],
86         )
87     
88         # ... responsible for the slice properties...
89     
90         # a nice header
91         main_stack.insert (
92             Raw (page=page,
93                  togglable=False, 
94                  toggled=True,
95                  html="<h2 class='well well-lg'> Slice %s</h2>"%slicename)
96         )
97     
98         # --------------------------------------------------------------------------
99         # ResourcesSelected (Pending Operations)
100
101         main_stack.insert(ResourcesSelected(
102             page                = page,
103             title               = 'Pending operations',
104             query               = main_query,
105             togglable           = True,
106             domid               = 'pending',
107             outline_complete    = True,
108         ))
109     
110         # --------------------------------------------------------------------------
111         # RESOURCES
112         # the resources part is made of a Tabs (Geographic, List), 
113
114         resources_as_map = GoogleMap(
115             page       = page,
116             title      = 'Geographic view',
117             domid      = 'resources-map',
118             # tab's sons preferably turn this off
119             togglable  = False,
120             query      = sq_resource,
121             query_all  = query_resource_all,
122             checkboxes = True,
123             # center on Paris
124             latitude   = 49.,
125             longitude  = 2.2,
126             zoom       = 3,
127         )
128
129         resources_as_list = Hazelnut( 
130             page       = page,
131             domid      = 'resources-list',
132             # this is the query at the core of the slice list
133             query      = sq_resource,
134             query_all  = query_resource_all,
135             checkboxes = True,
136             datatables_options = { 
137                 # for now we turn off sorting on the checkboxes columns this way
138                 # this of course should be automatic in hazelnut
139                 'aoColumns'     : [None, None, None, None, {'bSortable': False}],
140                 'iDisplayLength': 25,
141                 'bLengthChange' : True,
142                 'bAutoWidth'    : True,
143                 },
144             )
145
146         resources_query_editor = QueryEditor(
147             page  = page,
148             query = query_resource_all,
149             title = "Select Columns",
150             )
151         resources_active_filters = ActiveFilters(
152             page  = page,
153             query = sq_resource,
154             title = "Active Filters ?",
155             )
156
157         # List area itself is a Stack with hazelnut on top,
158         # and a togglable tabs for customization plugins 
159         resources_as_list_area = Stack(
160             page        = page,
161             title       = 'Resources as a List',
162             domid       = 'resources-list-area',
163             sons= [ resources_as_list, 
164                     Tabs ( page=page,
165                            title="Customize Resources layout",
166                            togglable=True,
167                            toggled='persistent',
168                            domid="customize-resources",
169                            outline_complete=True,
170                            sons = [ resources_query_editor, resources_active_filters, ],
171                            ),
172                     ],
173             )
174         resources_area = Tabs ( page=page, 
175                                 domid="resources",
176                                 togglable=True,
177                                 title="Resources",
178                                 outline_complete=True,
179                                 sons=[ resources_as_map, resources_as_list_area, ],
180                                 active_domid = 'resources-map',
181                                 )
182         main_stack.insert (resources_area)
183
184
185         # --------------------------------------------------------------------------
186         # USERS
187     
188         if do_query_users:
189             tab_users = Tabs(
190                 page                = page,
191                 domid               = 'users',
192                 outline_complete    = True,
193                 togglable           = True,
194                 title               = 'Users',
195                 active_domid        = 'checkboxes2',
196                 )
197             main_stack.insert(tab_users)
198     
199             tab_users.insert(Hazelnut( 
200                 page        = page,
201                 title       = 'Users List',
202                 domid       = 'checkboxes2',
203                 # tab's sons preferably turn this off
204                 togglable   = False,
205                 # this is the query at the core of the slice list
206                 query       = sq_user,
207                 query_all  = query_user_all,
208                 checkboxes  = True,
209                 datatables_options = { 
210                     'iDisplayLength' : 25,
211                     'bLengthChange'  : True,
212                     'bAutoWidth'     : True,
213                 },
214             ))
215     
216         # --------------------------------------------------------------------------
217         # MEASUREMENTS
218         tab_measurements = Tabs (
219             page                = page,
220             active_domid        = 'checkboxes3',
221             outline_complete    = True,
222             togglable           = True,
223             title               = 'Measurements',
224             domid               = 'measurements',
225         )
226         main_stack.insert(tab_measurements)
227     
228         tab_measurements.insert(Hazelnut( 
229             page        = page,
230             title       = 'Measurements',
231             domid       = 'checkboxes3',
232             # tab's sons preferably turn this off
233             togglable   = False,
234             # this is the query at the core of the slice list
235             query       = sq_measurement,
236             checkboxes  = True,
237             datatables_options = { 
238                 'iDisplayLength' : 25,
239                 'bLengthChange'  : True,
240                 'bAutoWidth'     : True,
241             },
242         ))
243     
244         # --------------------------------------------------------------------------
245         # MESSAGES (we use transient=False for now)
246         main_stack.insert(Messages(
247             page   = page,
248             title  = "Runtime messages for slice %s"%slicename,
249             domid  = "msgs-pre",
250             levels = "ALL",
251             # plain messages are probably less nice for production but more reliable for development for now
252             transient = False,
253             # these make sense only in non-transient mode..
254             togglable = True,
255             toggled = 'persistent',
256             outline_complete = True,
257         ))
258     
259     
260         # variables that will get passed to the view-unfold1.html template
261         template_env = {}
262         
263         # define 'unfold1_main' to the template engine - the main contents
264         template_env [ 'unfold1_main' ] = main_stack.render(request)
265     
266         # more general variables expected in the template
267         template_env [ 'title' ] = '%(slicename)s'%locals()
268         # the menu items on the top
269         template_env [ 'topmenu_items' ] = topmenu_items('Slice', request) 
270         # so we can sho who is logged
271         template_env [ 'username' ] = the_user (request) 
272     
273         # don't forget to run the requests
274         page.expose_queries ()
275     
276         # xxx create another plugin with the same query and a different layout (with_datatables)
277         # show that it worls as expected, one single api call to backend and 2 refreshed views
278     
279         # the prelude object in page contains a summary of the requirements() for all plugins
280         # define {js,css}_{files,chunks}
281         prelude_env = page.prelude_env()
282         template_env.update(prelude_env)
283         result=render_to_response ('view-unfold1.html',template_env,
284                                    context_instance=RequestContext(request))
285         return result