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