the tabs plugin has a persistent_active feature to enable saving the active tab in...
[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 ui.topmenu                      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.querytable              import QueryTable 
15 from plugins.queryupdater            import QueryUpdater
16 from plugins.googlemap               import GoogleMap
17 from plugins.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 from plugins.slicestat               import SliceStat
24
25 from myslice.config                  import Config
26
27 tmp_default_slice='ple.upmc.myslicedemo'
28
29 # temporary : turn off the users part to speed things up
30 #do_query_users=True
31 do_query_users=False
32
33 insert_messages=False
34 #insert_messages=True
35
36 class SliceView (LoginRequiredAutoLogoutView):
37
38     def get (self,request, slicename=tmp_default_slice):
39     
40         page = Page(request)
41         page.add_css_files ('css/slice-view.css')
42         page.add_js_files  ( [ "js/common.functions.js" ] )
43         page.add_js_chunks ('$(function() { messages.debug("sliceview: jQuery version " + $.fn.jquery); });')
44         page.add_js_chunks ('$(function() { messages.debug("sliceview: users turned %s"); });'%("on" if do_query_users else "off"))
45         config=Config()
46         page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(config.manifold_url()))
47         page.expose_js_metadata()
48     
49         metadata = page.get_metadata()
50         resource_md = metadata.details_by_object('resource')
51         resource_fields = [column['name'] for column in resource_md['column']]
52     
53         user_md = metadata.details_by_object('user')
54         user_fields = ['user_hrn'] # [column['name'] for column in user_md['column']]
55     
56         # TODO The query to run is embedded in the URL
57         main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
58         main_query.select(
59                 'slice_hrn',
60                 'resource.hrn', 'resource.hostname', 'resource.type', 
61                 'resource.network_hrn',
62                 #'lease.urn',
63                 'user.user_hrn',
64                 #'application.measurement_point.counter'
65         )
66     
67         query_resource_all = Query.get('resource').select(resource_fields)
68         if do_query_users:
69             query_user_all = Query.get('user').select(user_fields)
70     
71         aq = AnalyzedQuery(main_query, metadata=metadata)
72         page.enqueue_query(main_query, analyzed_query=aq)
73         page.enqueue_query(query_resource_all)
74         if do_query_users:
75             page.enqueue_query(query_user_all)
76     
77         # ... and for the relations
78         # XXX Let's hardcode resources for now
79         sq_resource    = aq.subquery('resource')
80         sq_user        = aq.subquery('user')
81         sq_lease       = aq.subquery('lease')
82         sq_measurement = aq.subquery('measurement')
83         
84     
85         # Prepare the display according to all metadata
86         # (some parts will be pending, others can be triggered by users).
87         # 
88         # For example slice measurements will not be requested by default...
89     
90         # Create the base layout (Stack)...
91         main_stack = Stack (
92             page=page,
93             title="Slice %s"%slicename,
94             sons=[],
95         )
96     
97         # ... responsible for the slice properties...
98     
99         # a nice header
100         main_stack.insert (
101             Raw (page=page,
102                  togglable=False, 
103                  toggled=True,
104                  html="<h2 class='well well-lg'> Slice %s</h2>"%slicename)
105         )
106     
107         # --------------------------------------------------------------------------
108         # QueryUpdater (Pending Operations)
109
110         main_stack.insert(QueryUpdater(
111             page                = page,
112             title               = 'Pending operations',
113             query               = main_query,
114             togglable           = True,
115             # start turned off, it will open up itself when stuff comes in
116             toggled             = False, 
117             domid               = 'pending',
118             outline_complete    = True,
119         ))
120
121         # --------------------------------------------------------------------------
122         # Filter Resources
123        
124         filter_query_editor = QueryEditor(
125             page  = page,
126             query = sq_resource, 
127             query_all = query_resource_all,
128             title = "Select Columns",
129             domid = 'select-columns',
130             )
131         filter_active_filters = ActiveFilters(
132             page  = page,
133             query = sq_resource,
134             title = "Active Filters",
135             )
136         filters_area = Stack(
137             page                = page,
138             title               = 'Filter Resources',
139             domid               = 'filters',
140             sons                = [filter_query_editor, filter_active_filters],
141             togglable           = True,
142             toggled             = 'persistent',
143             outline_complete    = True, 
144         )
145         main_stack.insert (filters_area)
146
147         # --------------------------------------------------------------------------
148         # RESOURCES
149         # the resources part is made of a Tabs (Geographic, List), 
150
151         resources_as_gmap = GoogleMap(
152             page       = page,
153             title      = 'Geographic view',
154             domid      = 'resources-map',
155             # tab's sons preferably turn this off
156             togglable  = False,
157             query      = sq_resource,
158             query_all  = query_resource_all,
159             googlemap_api_key = Config().googlemap_api_key(),
160             checkboxes = True,
161             # center on Paris
162             latitude   = 49.,
163             longitude  = 9,
164             zoom       = 4,
165         )
166
167         resources_as_3dmap = SensLabMap(
168             page       = page,
169             title      = '3D Map',
170             domid      = 'senslabmap',
171             query      = sq_resource,
172             query_all  = query_resource_all,
173         )
174
175         resources_as_list = QueryTable( 
176             page       = page,
177             domid      = 'resources-list',
178             title      = 'List view',
179             # this is the query at the core of the slice list
180             query      = sq_resource,
181             query_all  = query_resource_all,
182             checkboxes = True,
183             datatables_options = { 
184                 'iDisplayLength': 25,
185                 'bLengthChange' : True,
186                 'bAutoWidth'    : True,
187                 },
188             )
189
190        # with the new 'Filter' stuff on top, no need for anything but the querytable
191         resources_as_list_area = resources_as_list 
192
193         resources_area = Tabs ( page=page, 
194                                 domid="resources",
195                                 togglable=True,
196                                 title="Resources",
197                                 outline_complete=True,
198                                 sons=[ resources_as_gmap, 
199                                        resources_as_3dmap,
200                                        resources_as_list_area, ],
201                                 active_domid = 'resources-map',
202                                 persistent_active=True,
203                                 )
204         main_stack.insert (resources_area)
205
206         # --------------------------------------------------------------------------
207         # USERS
208     
209         if do_query_users:
210             tab_users = Tabs(
211                 page                = page,
212                 domid               = 'users',
213                 outline_complete    = True,
214                 togglable           = True,
215                 title               = 'Users',
216                 active_domid        = 'users-list',
217                 )
218             main_stack.insert(tab_users)
219     
220             tab_users.insert(QueryTable( 
221                 page        = page,
222                 title       = 'Users List',
223                 domid       = 'users-list',
224                 # tab's sons preferably turn this off
225                 togglable   = False,
226                 # this is the query at the core of the slice list
227                 query       = sq_user,
228                 query_all  = query_user_all,
229                 checkboxes  = True,
230                 datatables_options = { 
231                     'iDisplayLength' : 25,
232                     'bLengthChange'  : True,
233                     'bAutoWidth'     : True,
234                 },
235             ))
236
237 # DEMO    
238         # --------------------------------------------------------------------------
239         # MEASUREMENTS
240         measurements_stats_cpu = SliceStat(
241             title = "CPU Usage",
242             domid = 'resources-stats-cpu',
243             page  = page,
244             stats = 'slice',
245             key   = 'hrn',
246             query = 'none',
247             slicename = slicename,
248             o = 'cpu'
249         )
250         
251         measurements_stats_mem = SliceStat(
252             title = "Memory Usage",
253             domid = 'resources-stats-mem',
254             page  = page,
255             stats = 'slice',
256             key   = 'hrn',
257             query = 'none',
258             slicename = slicename,
259             o = 'mem'
260         )
261         
262         measurements_stats_asb = SliceStat(
263             title = "Traffic Sent",
264             domid = 'resources-stats-asb',
265             page  = page,
266             stats = 'slice',
267             key   = 'hrn',
268             query = 'none',
269             slicename = slicename,
270             o = 'asb'
271         )
272         
273         measurements_stats_arb = SliceStat(
274             title = "Traffic Received",
275             domid = 'resources-stats-arb',
276             page  = page,
277             stats = 'slice',
278             key   = 'hrn',
279             query = 'none',
280             slicename = slicename,
281             o = 'arb'
282         )
283
284         tab_measurements = Tabs ( page=page,
285                                 domid="measurements",
286                                 togglable=True,
287                                 toggled  = False,
288                                 title="Measurements",
289                                 outline_complete=True,
290                                 sons=[ measurements_stats_cpu, measurements_stats_mem, measurements_stats_asb, measurements_stats_arb ],
291                                 active_domid = 'measurements_stats_cpu',
292                                 )
293         main_stack.insert (tab_measurements)
294         
295 #        tab_measurements = Tabs (
296 #            page                = page,
297 #            active_domid        = 'measurements-list',
298 #            outline_complete    = True,
299 #            togglable           = True,
300 #            title               = 'Measurements',
301 #            domid               = 'measurements',
302 #        )
303 #        main_stack.insert(tab_measurements)
304 #    
305 #        tab_measurements.insert(QueryTable( 
306 #            page        = page,
307 #            title       = 'Measurements',
308 #            domid       = 'measurements-list',
309 #            # tab's sons preferably turn this off
310 #            togglable   = False,
311 #            # this is the query at the core of the slice list
312 #            query       = sq_measurement,
313 #            # do NOT set checkboxes to False
314 #            # this table being otherwise empty, it just does not fly with dataTables
315 #            checkboxes  = True,
316 #            datatables_options = { 
317 #                'iDisplayLength' : 25,
318 #                'bLengthChange'  : True,
319 #                'bAutoWidth'     : True,
320 #            },
321 #        ))
322 #    
323 #        # --------------------------------------------------------------------------
324 #        # MESSAGES (we use transient=False for now)
325         if insert_messages:
326             main_stack.insert(Messages(
327                     page   = page,
328                     title  = "Runtime messages for slice %s"%slicename,
329                     domid  = "msgs-pre",
330                     levels = "ALL",
331                     # plain messages are probably less nice for production but more reliable for development for now
332                     transient = False,
333                     # these make sense only in non-transient mode..
334                     togglable = True,
335                     toggled = 'persistent',
336                     outline_complete = True,
337                     ))
338     
339     
340         # variables that will get passed to the view-unfold1.html template
341         template_env = {}
342         
343         # define 'unfold_main' to the template engine - the main contents
344         template_env [ 'unfold_main' ] = main_stack.render(request)
345     
346         # more general variables expected in the template
347         template_env [ 'title' ] = '%(slicename)s'%locals()
348         # the menu items on the top
349         template_env [ 'topmenu_items' ] = topmenu_items('Slice', request) 
350         # so we can sho who is logged
351         template_env [ 'username' ] = the_user (request) 
352     
353         # don't forget to run the requests
354         page.expose_queries ()
355     
356         # xxx create another plugin with the same query and a different layout (with_datatables)
357         # show that it worls as expected, one single api call to backend and 2 refreshed views
358     
359         # the prelude object in page contains a summary of the requirements() for all plugins
360         # define {js,css}_{files,chunks}
361         prelude_env = page.prelude_env()
362         template_env.update(prelude_env)
363         result=render_to_response ('view-unfold1.html',template_env,
364                                    context_instance=RequestContext(request))
365         return result