Merge lp:~qa-dashboard/qa-dashboard/adding-view-based-breadcrumbs into lp:qa-dashboard
- adding-view-based-breadcrumbs
- Merge into dev
Proposed by
Chris Johnston
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Chris Johnston | ||||
Approved revision: | 364 | ||||
Merged at revision: | 389 | ||||
Proposed branch: | lp:~qa-dashboard/qa-dashboard/adding-view-based-breadcrumbs | ||||
Merge into: | lp:qa-dashboard | ||||
Diff against target: |
1771 lines (+781/-274) 24 files modified
bootspeed/templates/bootspeed/nav.html (+1/-1) bootspeed/views.py (+72/-0) common/bread_crumbs.py (+183/-0) common/static/css/style.css (+67/-0) common/templates/layout.html (+16/-1) eventstat/templates/power/eventstat/arch_breakdown.html (+0/-6) eventstat/templates/power/eventstat/image_details.html (+0/-6) eventstat/templates/power/eventstat/task_details.html (+0/-16) eventstat/templates/power/eventstat/task_overview.html (+0/-6) eventstat/templates/power/eventstat/upgrade_details.html (+0/-6) eventstat/views.py (+158/-69) idle_power/views.py (+30/-0) memory/templates/memory/machine_details.html (+0/-20) memory/templates/memory/machine_results.html (+0/-5) memory/views.py (+102/-10) power/urls.py (+1/-1) power/views.py (+59/-42) qa_dashboard/urls.py (+3/-3) smoke/templates/smoke/build_overview.html (+0/-14) smoke/templates/smoke/result_logs.html (+0/-25) smoke/templates/smoke/results.html (+0/-22) smoke/views.py (+69/-6) sru/templates/sru/overview_kernel.html (+0/-13) sru/views.py (+20/-2) |
||||
To merge this branch: | bzr merge lp:~qa-dashboard/qa-dashboard/adding-view-based-breadcrumbs | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andy Doan (community) | Approve | ||
Chris Johnston | Needs Resubmitting | ||
Review via email: mp+162376@code.launchpad.net |
Commit message
Add breadcrumbs across the dashboard
Description of the change
To post a comment you must log in.
Revision history for this message
Andy Doan (doanac) wrote : | # |
Revision history for this message
Andy Doan (doanac) wrote : | # |
I think we missed some stuff earlier: capitalize the first letter of:
827 + "upgrade details"
884 + "task details",
909 + "task details",
993 + "detailed view",
1201 + "machine upgrade results",
1256 + "machine upgrade details",
1591 + "image {build_number}"
Revision history for this message
Chris Johnston (cjohnston) : | # |
review:
Needs Resubmitting
Revision history for this message
Andy Doan (doanac) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bootspeed/templates/bootspeed/nav.html' |
2 | --- bootspeed/templates/bootspeed/nav.html 2012-12-14 15:16:40 +0000 |
3 | +++ bootspeed/templates/bootspeed/nav.html 2013-05-03 22:59:28 +0000 |
4 | @@ -5,7 +5,7 @@ |
5 | <ul class='left_nav'> |
6 | {% for arch in arches %} |
7 | <li{% if active = arch %} class="active"{% endif %}> |
8 | - <a href='{% url bootspeed_arch_overview arch %}'> |
9 | + <a href='{% url bootspeed_arch arch %}'> |
10 | {{ arch }} |
11 | </a> |
12 | </li> |
13 | |
14 | === modified file 'bootspeed/views.py' |
15 | --- bootspeed/views.py 2013-05-01 16:20:50 +0000 |
16 | +++ bootspeed/views.py 2013-05-03 22:59:28 +0000 |
17 | @@ -25,6 +25,13 @@ |
18 | |
19 | from django_tables2 import RequestConfig |
20 | |
21 | +from common.bread_crumbs import ( |
22 | + BreadCrumb, |
23 | + BreadCrumbTrail, |
24 | +) |
25 | + |
26 | +from smoke.views import index |
27 | + |
28 | from common.models import Bug |
29 | |
30 | from bootspeed.models import ( |
31 | @@ -71,6 +78,7 @@ |
32 | data = { |
33 | 'images': images, |
34 | 'releases': releases, |
35 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(overview), |
36 | } |
37 | |
38 | return render_to_response( |
39 | @@ -80,6 +88,7 @@ |
40 | ) |
41 | |
42 | |
43 | +@BreadCrumb("Bootspeed testing", parent=index, needs=['arch', ]) |
44 | @require_GET |
45 | def arch_overview(request, arch=None): |
46 | if arch is None: |
47 | @@ -94,6 +103,10 @@ |
48 | 'arch': arch, |
49 | 'arches': arches, |
50 | 'active': arch, |
51 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
52 | + arch_overview, |
53 | + arch=arch, |
54 | + ), |
55 | } |
56 | return render_to_response( |
57 | 'bootspeed/arch_overview.html', |
58 | @@ -102,6 +115,11 @@ |
59 | ) |
60 | |
61 | |
62 | +@BreadCrumb( |
63 | + "Aggregated data", |
64 | + parent=arch_overview, |
65 | + needs=['machine_id', 'arch'], |
66 | +) |
67 | @require_GET |
68 | def machine_data(request, machine_id, arch): |
69 | machine = get_object_or_404(Machine, id=machine_id) |
70 | @@ -110,6 +128,12 @@ |
71 | 'name': machine.name, |
72 | 'id': machine.id, |
73 | 'arch': arch, |
74 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
75 | + machine_data, |
76 | + machine_id=machine_id, |
77 | + machine=machine.name, |
78 | + arch=arch, |
79 | + ), |
80 | } |
81 | return render_to_response( |
82 | "bootspeed/machine_data.html", |
83 | @@ -118,6 +142,11 @@ |
84 | ) |
85 | |
86 | |
87 | +@BreadCrumb( |
88 | + "Raw data", |
89 | + parent=machine_data, |
90 | + needs=['machine_id', 'arch'], |
91 | +) |
92 | @require_GET |
93 | def machine_raw_data(request, machine_id, arch): |
94 | machine = get_object_or_404(Machine, id=machine_id) |
95 | @@ -150,11 +179,21 @@ |
96 | 'id': machine.id, |
97 | 'arch': arch, |
98 | 'table': table, |
99 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
100 | + machine_raw_data, |
101 | + machine_id=machine_id, |
102 | + machine=machine.name, |
103 | + arch=arch, |
104 | + ), |
105 | } |
106 | return render_to_response("bootspeed/machine_raw_data.html", data, |
107 | RequestContext(request)) |
108 | |
109 | |
110 | +@BreadCrumb( |
111 | + "Bugs by image", |
112 | + parent=arch_overview, |
113 | +) |
114 | @require_GET |
115 | def image_bugs_overview(request): |
116 | images = JobImage.objects.annotate( |
117 | @@ -177,6 +216,10 @@ |
118 | data = { |
119 | 'images': images, |
120 | 'unknown_images': unknown_images, |
121 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
122 | + image_bugs_overview, |
123 | + arch='amd64', |
124 | + ), |
125 | } |
126 | |
127 | return render_to_response( |
128 | @@ -186,6 +229,11 @@ |
129 | ) |
130 | |
131 | |
132 | +@BreadCrumb( |
133 | + "{image}", |
134 | + parent=image_bugs_overview, |
135 | + needs=['image_id'] |
136 | +) |
137 | @require_GET |
138 | def image_bugs_detail(request, image_id): |
139 | image_builds = ImageBuild.objects.filter(job_image=image_id) |
140 | @@ -194,6 +242,12 @@ |
141 | data = { |
142 | 'image_builds': image_builds, |
143 | 'image': image, |
144 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
145 | + image_bugs_detail, |
146 | + image_id=image_id, |
147 | + arch='amd64', |
148 | + image=image.build_number, |
149 | + ), |
150 | } |
151 | |
152 | return render_to_response( |
153 | @@ -203,6 +257,10 @@ |
154 | ) |
155 | |
156 | |
157 | +@BreadCrumb( |
158 | + "Bugs", |
159 | + parent=arch_overview, |
160 | +) |
161 | @require_GET |
162 | def bug_overview(request): |
163 | bugs = Bug.objects.annotate( |
164 | @@ -216,6 +274,10 @@ |
165 | |
166 | data = { |
167 | 'bugs': bugs, |
168 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
169 | + bug_overview, |
170 | + arch='amd64', |
171 | + ), |
172 | } |
173 | |
174 | return render_to_response( |
175 | @@ -225,6 +287,11 @@ |
176 | ) |
177 | |
178 | |
179 | +@BreadCrumb( |
180 | + "Builds affected", |
181 | + parent=bug_overview, |
182 | + needs=['bug_id'], |
183 | +) |
184 | @require_GET |
185 | def bug_detail(request, bug_id): |
186 | bug = get_object_or_404(Bug, id=bug_id) |
187 | @@ -232,6 +299,11 @@ |
188 | data = { |
189 | 'builds': bug.build_bugs.all(), |
190 | 'bug': bug, |
191 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
192 | + bug_detail, |
193 | + arch='amd64', |
194 | + bug_id=bug_id, |
195 | + ), |
196 | } |
197 | |
198 | return render_to_response( |
199 | |
200 | === added file 'common/bread_crumbs.py' |
201 | --- common/bread_crumbs.py 1970-01-01 00:00:00 +0000 |
202 | +++ common/bread_crumbs.py 2013-05-03 22:59:28 +0000 |
203 | @@ -0,0 +1,183 @@ |
204 | +# Copyright (C) 2010, 2011 Linaro Limited |
205 | +# |
206 | +# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org> |
207 | +# |
208 | +# This file is part of LAVA Server. |
209 | +# |
210 | +# LAVA Server is free software: you can redistribute it and/or modify |
211 | +# it under the terms of the GNU Affero General Public License version 3 |
212 | +# as published by the Free Software Foundation |
213 | +# |
214 | +# LAVA Server is distributed in the hope that it will be useful, |
215 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
216 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
217 | +# GNU General Public License for more details. |
218 | +# |
219 | +# You should have received a copy of the GNU Affero General Public License |
220 | +# along with LAVA Server. If not, see <http://www.gnu.org/licenses/>. |
221 | + |
222 | +""" |
223 | +lava_server.bread_crumbs |
224 | +======================== |
225 | + |
226 | +Bread crumb management for LAVA server. |
227 | + |
228 | +This system allows one to construct static trees of views or even site maps, |
229 | +where each view has at most one parent. In this model any view could be |
230 | +followed back through the parent link to create a bread crumb trail of named |
231 | +URLs. |
232 | + |
233 | +It is important to emphasize that this system is STATIC, that is, it is not |
234 | +based on browsing history. Regardless on how the user got to a particular view |
235 | +the bread crumb system will report the same set of pages. The idea is not to |
236 | +let users go back (that's the what the browser allows them to do) but to put |
237 | +the current page into context of where it "belongs". |
238 | + |
239 | +To use this system apply the @BreadCrumb(name, parent=parent_view, |
240 | +needs=['required', 'keywords']) decorator to your view function. To render |
241 | +breadcrumbs you can use the default template that is a part of |
242 | +"layout/content.html" template. Your context must include the bread_crumb_trail |
243 | +variable. To construct it call BreadCrumbTrail.leading_to(your_view_name, ...) |
244 | +passing any of the keyword arguments specified in needs of your and any parent |
245 | +views (yes this is annoying). |
246 | + |
247 | +A mistake in pairing 'needs' to keywords passed to BreadCrumbTrail.leading_to() |
248 | +will result in logged warnings (either a name of the URL being not |
249 | +constructible). To fix that simply add the missing keyword argument and reload. |
250 | +""" |
251 | + |
252 | +from django.core.urlresolvers import reverse |
253 | +import logging |
254 | + |
255 | + |
256 | +class BreadCrumb(object): |
257 | + """ |
258 | + A crumb of bread left in the forest of pages to let you go back to (no, not |
259 | + to where you came from) where the developer desired you to go. |
260 | + """ |
261 | + |
262 | + def __init__(self, name, parent=None, needs=None): |
263 | + """ |
264 | + Construct a bread crumb object. |
265 | + |
266 | + The name is the essential property creating the actual text visible on |
267 | + web pages. It may be a static string or a new-style python string |
268 | + template. Parent allows one to construct a static brad crumb tree where |
269 | + each crumb may have at most one parent. Needs, if specified, must be |
270 | + an array of strings that denote identifiers required to resolve the URL |
271 | + of this bread crumb. The identifiers are obtained from the call |
272 | + BreadCrumbTrail.leading_to(). |
273 | + """ |
274 | + self.name = name |
275 | + self.view = None |
276 | + self.parent = parent |
277 | + self.needs = needs or [] |
278 | + |
279 | + def __repr__(self): |
280 | + return "<BreadCrumb name=%r view=%r parent=%r>" % ( |
281 | + self.name, self.view, self.parent) |
282 | + |
283 | + def __call__(self, view): |
284 | + """ |
285 | + Call method, used when decorating function-based views |
286 | + |
287 | + It does not redefine the function (so is not a real decorator) but |
288 | + instead stores the bread crumb object in the _bread_crumb attribute of |
289 | + the function. |
290 | + """ |
291 | + self.view = view |
292 | + view._bread_crumb = self |
293 | + return view |
294 | + |
295 | + def get_name(self, kwargs): |
296 | + """ |
297 | + Get the name of this crumb. |
298 | + |
299 | + The name is formatted with the specified keyword arguments. |
300 | + """ |
301 | + try: |
302 | + return self.name.format(**kwargs) |
303 | + except: |
304 | + logging.exception( |
305 | + "Unable to construct breadcrumb name for view %r", self.view) |
306 | + raise |
307 | + |
308 | + def get_absolute_url(self, kwargs): |
309 | + """ |
310 | + Get the URL of this crumb. |
311 | + |
312 | + The URL is constructed with a call to Dajngo's reverse() function. It |
313 | + is supplemented with the same variables that were listed in needs array |
314 | + in the bread crumb constructor. The arguments are passed in order, from |
315 | + the kwargs dictionary. |
316 | + """ |
317 | + try: |
318 | + return reverse( |
319 | + self.view, |
320 | + args=[kwargs[name] for name in self.needs]) |
321 | + except: |
322 | + logging.exception( |
323 | + "Unable to construct breadcrumb URL for view %r", self.view) |
324 | + raise |
325 | + |
326 | + |
327 | +class LiveBreadCrumb(object): |
328 | + """ |
329 | + Bread crumb instance as observed by a particular request. |
330 | + |
331 | + It is a binding between the global view-specific bread crumb object and |
332 | + dynamic request-specific keyword arguments. |
333 | + |
334 | + For convenience it provides two bread crumb functions (get_name() and |
335 | + get_absolute_url()) that automatically provide the correct keyword |
336 | + arguments. |
337 | + """ |
338 | + |
339 | + def __init__(self, bread_crumb, kwargs): |
340 | + self.bread_crumb = bread_crumb |
341 | + self.kwargs = kwargs |
342 | + |
343 | + def __unicode__(self): |
344 | + return self.get_name() |
345 | + |
346 | + def get_name(self): |
347 | + return self.bread_crumb.get_name(self.kwargs) |
348 | + |
349 | + def get_absolute_url(self): |
350 | + return self.bread_crumb.get_absolute_url(self.kwargs) |
351 | + |
352 | + |
353 | +class BreadCrumbTrail(object): |
354 | + """ |
355 | + A list of live bread crumbs that lead from a particular view, along the |
356 | + parent chain, all the way to the root view (that is without any parent |
357 | + view). |
358 | + """ |
359 | + |
360 | + def __init__(self, bread_crumb_list, kwargs): |
361 | + self.bread_crumb_list = bread_crumb_list |
362 | + self.kwargs = kwargs |
363 | + |
364 | + def __iter__(self): |
365 | + for bread_crumb in self.bread_crumb_list: |
366 | + yield LiveBreadCrumb(bread_crumb, self.kwargs) |
367 | + |
368 | + @classmethod |
369 | + def leading_to(cls, view, **kwargs): |
370 | + """ |
371 | + Create an instance of BreadCrumbTrail that starts at the specified |
372 | + view. |
373 | + |
374 | + Additional keyword arguments, if provided, will be available to |
375 | + get_name() and get_absolute_url() of each LiveBreadCrumb that makes up |
376 | + this trail. In practice they should contain a set of arguments that are |
377 | + needed by any parent bread crumb URL or name. |
378 | + |
379 | + TODO: could we check this statically somehow? |
380 | + """ |
381 | + lst = [] |
382 | + while view is not None: |
383 | + lst.append(view._bread_crumb) |
384 | + view = view._bread_crumb.parent |
385 | + lst.reverse() |
386 | + return cls(lst, kwargs or {}) |
387 | |
388 | === modified file 'common/static/css/style.css' |
389 | --- common/static/css/style.css 2013-04-26 17:31:17 +0000 |
390 | +++ common/static/css/style.css 2013-05-03 22:59:28 +0000 |
391 | @@ -761,3 +761,70 @@ |
392 | overflow : hidden; |
393 | padding : 8px 8px 2px; |
394 | } |
395 | + |
396 | +/* Breadcrumbs */ |
397 | +#lava-breadcrumbs { |
398 | + /* Clear floats */ |
399 | + overflow: hidden; |
400 | + font-size: 80% |
401 | +} |
402 | +#lava-breadcrumbs li{ |
403 | + float: left; |
404 | + margin: 0 .5em 0 1em; |
405 | +} |
406 | + |
407 | +#lava-breadcrumbs a{ |
408 | + background: #ddd; |
409 | + padding: .3em .6em; |
410 | + float: left; |
411 | + text-decoration: none; |
412 | + text-shadow: 0 1px 0 rgba(255,255,255,.5); |
413 | + position: relative; |
414 | +} |
415 | + |
416 | +#lava-breadcrumbs a:hover{ |
417 | + background: #DD4814; |
418 | + color: white; |
419 | +} |
420 | + |
421 | +#lava-breadcrumbs a::before{ |
422 | + content: ""; |
423 | + position: absolute; |
424 | + top: 21px; |
425 | + margin-top: -1.8em; |
426 | + border-width: 1em 0 1em 1.3em; |
427 | + border-style: solid; |
428 | + border-color: #ddd #ddd #ddd transparent; |
429 | + left: -14px; |
430 | +} |
431 | + |
432 | +#lava-breadcrumbs a:hover::before{ |
433 | + border-color: #DD4814 #DD4814 #DD4814 transparent; |
434 | +} |
435 | + |
436 | +#lava-breadcrumbs a::after{ |
437 | + content: ""; |
438 | + position: absolute; |
439 | + top: 21px; |
440 | + margin-top: -1.8em; |
441 | + border-top: 1em solid transparent; |
442 | + border-bottom: 1em solid transparent; |
443 | + border-left: 1.3em solid #ddd; |
444 | + right: -14px; |
445 | +} |
446 | + |
447 | + |
448 | +#lava-breadcrumbs a:hover::after{ |
449 | + border-left-color: #DD4814; |
450 | +} |
451 | + |
452 | +#lava-breadcrumbs .current, |
453 | +#lava-breadcrumbs .current:hover{ |
454 | + font-weight: bold; |
455 | + background: none; |
456 | +} |
457 | + |
458 | +#lava-breadcrumbs .current::after, |
459 | +#lava-breadcrumbs .current::before{ |
460 | + content: normal; |
461 | +} |
462 | |
463 | === modified file 'common/templates/layout.html' |
464 | --- common/templates/layout.html 2013-05-01 18:08:38 +0000 |
465 | +++ common/templates/layout.html 2013-05-03 22:59:28 +0000 |
466 | @@ -26,7 +26,7 @@ |
467 | <li {% ifequal url.0 'smoke' %}class="active"{% endifequal %} id="main-nav"><a class="main-nav-item" href='{% url smoke_index %}'>Smoke</a></li> |
468 | <li {% ifequal url.0 'sru' %}class="active"{% endifequal %} id="main-nav"><a class="main-nav-item" href='{% url sru %}'>SRU</a></li> |
469 | <li {% ifequal url.0 'bootspeed' %}class="active"{% endifequal %}id="main-nav"><a class="main-nav-item" href="{% url bootspeed_arch %}">Bootspeed</a></li> |
470 | - <li {% ifequal url.0 'power' %}class="active"{% endifequal %}id="main-nav"><a class="main-nav-item" href="{% url power_arch %}">Power</a></li> |
471 | + <li {% ifequal url.0 'power' %}class="active"{% endifequal %}id="main-nav"><a class="main-nav-item" href="{% url power_overview %}">Power</a></li> |
472 | <li {% ifequal url.0 'memory' %}class="active"{% endifequal %}id="main-nav"><a class="main-nav-item" href="{% url memory_arch %}">Memory</a></li> |
473 | </ul> |
474 | </nav> |
475 | @@ -46,6 +46,21 @@ |
476 | </nav> |
477 | </div> |
478 | {% endblock %} |
479 | + <div class="grid_15"> |
480 | + {% block breadcrumb_container %} |
481 | + <!-- breadcrumbs --> |
482 | + <div id="lava-breadcrumbs"> |
483 | + <ul> |
484 | + {% block breadcrumbs %} |
485 | + {% for bread_crumb in bread_crumb_trail %} |
486 | + <li><a href="{{ bread_crumb.get_absolute_url }}">{{ bread_crumb.get_name }}</a></li> |
487 | + {% endfor %} |
488 | + {% endblock %} |
489 | + </ul> |
490 | + </div> |
491 | + <!-- !breadcrumbs --> |
492 | + {% endblock breadcrumb_container %} |
493 | + </div> |
494 | {% block content %}{% endblock %} |
495 | </div> |
496 | <div class='container_15 clearfix' id='footer'> |
497 | |
498 | === modified file 'eventstat/templates/power/eventstat/arch_breakdown.html' |
499 | --- eventstat/templates/power/eventstat/arch_breakdown.html 2013-05-03 00:46:34 +0000 |
500 | +++ eventstat/templates/power/eventstat/arch_breakdown.html 2013-05-03 22:59:28 +0000 |
501 | @@ -11,12 +11,6 @@ |
502 | {% endblock extra_headers %} |
503 | {% block content %} |
504 | |
505 | -<div id="breadcrumb"> |
506 | - <span class="crumb"> |
507 | - <a href="{% url eventstat_arch_overview arch %}">{{ arch }}</a> |
508 | - </span> |
509 | -</div> |
510 | - |
511 | <div class="grid_2 left_nav" style="height: 100%;"> |
512 | {% include "power/eventstat/task_type_include.html" %} |
513 | |
514 | |
515 | === modified file 'eventstat/templates/power/eventstat/image_details.html' |
516 | --- eventstat/templates/power/eventstat/image_details.html 2013-04-25 20:07:34 +0000 |
517 | +++ eventstat/templates/power/eventstat/image_details.html 2013-05-03 22:59:28 +0000 |
518 | @@ -14,12 +14,6 @@ |
519 | |
520 | {% block content %} |
521 | |
522 | -<div id="breadcrumb"> |
523 | - <span class="crumb"> |
524 | - <a href="{% url eventstat_arch_overview image.arch %}">{{ image.arch }}</a> |
525 | - </span> |
526 | -</div> |
527 | - |
528 | <div class="grid_2"> |
529 | {% include "power/eventstat/task_type_include.html" %} |
530 | </div> |
531 | |
532 | === modified file 'eventstat/templates/power/eventstat/task_details.html' |
533 | --- eventstat/templates/power/eventstat/task_details.html 2013-04-25 20:07:34 +0000 |
534 | +++ eventstat/templates/power/eventstat/task_details.html 2013-05-03 22:59:28 +0000 |
535 | @@ -18,22 +18,6 @@ |
536 | {% endblock extra_headers %} |
537 | {% block content %} |
538 | |
539 | -<div id="breadcrumb"> |
540 | - <span class="crumb"> |
541 | - <a href="{% url eventstat_arch_overview arch %}">{{ arch }}</a> |
542 | - </span> |
543 | - <span class="crumb-sep"> |
544 | - >> |
545 | - </span> |
546 | - <span class="crumb"> |
547 | - {% if image %} |
548 | - <a href="{% url eventstat_image_details image_id=image.id machine_id=machine.id task_type="all" %}">{{ image.build_number }}</a> |
549 | - {% else %} |
550 | - <a href="{% url eventstat_upgrade_details upgrade_id=upgrade.id machine_id=machine.id task_type="all" %}">{{ upgrade.date }}</a> |
551 | - {% endif %} |
552 | - </span> |
553 | -</div> |
554 | - |
555 | <div class="grid_15"> |
556 | <h2> |
557 | Wakeups for {{ task }} using {{ arch }} on {{ machine }} for |
558 | |
559 | === modified file 'eventstat/templates/power/eventstat/task_overview.html' |
560 | --- eventstat/templates/power/eventstat/task_overview.html 2013-04-25 20:07:34 +0000 |
561 | +++ eventstat/templates/power/eventstat/task_overview.html 2013-05-03 22:59:28 +0000 |
562 | @@ -11,12 +11,6 @@ |
563 | {% endblock extra_headers %} |
564 | {% block content %} |
565 | |
566 | -<div id="breadcrumb"> |
567 | - <span class="crumb"> |
568 | - <a href="{% url eventstat_arch_overview arch %}">{{ arch }}</a> |
569 | - </span> |
570 | -</div> |
571 | - |
572 | <div class="grid_2"> |
573 | {% include "power/eventstat/days_include.html" with day_urls=day_urls days=days %} |
574 | </div> |
575 | |
576 | === modified file 'eventstat/templates/power/eventstat/upgrade_details.html' |
577 | --- eventstat/templates/power/eventstat/upgrade_details.html 2013-04-25 20:07:34 +0000 |
578 | +++ eventstat/templates/power/eventstat/upgrade_details.html 2013-05-03 22:59:28 +0000 |
579 | @@ -13,12 +13,6 @@ |
580 | {% endblock extra_headers %} |
581 | {% block content %} |
582 | |
583 | -<div id="breadcrumb"> |
584 | - <span class="crumb"> |
585 | - <a href="{% url eventstat_arch_overview upgrade.arch %}">{{ upgrade.arch }}</a> |
586 | - </span> |
587 | -</div> |
588 | - |
589 | <div class="grid_2"> |
590 | {% include "power/eventstat/task_type_include.html" %} |
591 | </div> |
592 | |
593 | === modified file 'eventstat/views.py' |
594 | --- eventstat/views.py 2013-05-03 00:46:34 +0000 |
595 | +++ eventstat/views.py 2013-05-03 22:59:28 +0000 |
596 | @@ -28,6 +28,13 @@ |
597 | |
598 | from django_tables2 import RequestConfig |
599 | |
600 | +from common.bread_crumbs import ( |
601 | + BreadCrumb, |
602 | + BreadCrumbTrail, |
603 | +) |
604 | + |
605 | +from power.views import overview |
606 | + |
607 | from eventstat.models import ( |
608 | EventstatDetail, |
609 | EventstatImage, |
610 | @@ -89,6 +96,7 @@ |
611 | return retval |
612 | |
613 | |
614 | +@BreadCrumb("Wakeups", parent=overview) |
615 | @require_GET |
616 | def arch_overview(request, arch=None, days=None): |
617 | arches = get_arches() |
618 | @@ -153,7 +161,8 @@ |
619 | kwargs={ |
620 | 'arch': arch, |
621 | } |
622 | - ) |
623 | + ), |
624 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(arch_overview), |
625 | } |
626 | |
627 | return render_to_response( |
628 | @@ -163,6 +172,7 @@ |
629 | ) |
630 | |
631 | |
632 | +@BreadCrumb("All", parent=arch_overview) |
633 | @require_GET |
634 | def arch_breakdown( |
635 | request, |
636 | @@ -257,6 +267,12 @@ |
637 | days=days |
638 | ), |
639 | ), |
640 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
641 | + arch_breakdown, |
642 | + machine_id=machine_id, |
643 | + arch=arch, |
644 | + method=method, |
645 | + ), |
646 | } |
647 | |
648 | return render_to_response( |
649 | @@ -266,6 +282,91 @@ |
650 | ) |
651 | |
652 | |
653 | +@BreadCrumb( |
654 | + "{build_number} details", |
655 | + parent=arch_overview, |
656 | + needs=['image_id', 'machine_id', 'task_type'], |
657 | +) |
658 | +@require_GET |
659 | +def image_details(request, image_id, task_type, machine_id, days=None): |
660 | + image = get_object_or_404(EventstatImage, id=image_id) |
661 | + machine = get_object_or_404(EventstatMachine, id=machine_id) |
662 | + |
663 | + if days is None: |
664 | + days = DAYS |
665 | + else: |
666 | + days = int(days) |
667 | + |
668 | + results = EventstatDetail.objects.filter( |
669 | + publish=True, |
670 | + image=image, |
671 | + machine=machine, |
672 | + ran_at__gt=datetime.datetime.now() - datetime.timedelta(days=days), |
673 | + ).values( |
674 | + 'task', |
675 | + 'image_id', |
676 | + 'image__arch', |
677 | + 'machine_id', |
678 | + ).annotate( |
679 | + average=models.Avg('total'), |
680 | + minimum=models.Min('total'), |
681 | + maximum=models.Max('total'), |
682 | + stddev=models.StdDev('total'), |
683 | + ) |
684 | + |
685 | + if task_type != 'all': |
686 | + results = results.filter(task_type=task_type) |
687 | + |
688 | + table = TaskInstallTable(results) |
689 | + |
690 | + RequestConfig(request, paginate={"per_page": 100}).configure(table) |
691 | + |
692 | + data = { |
693 | + 'table': table, |
694 | + 'image': image, |
695 | + 'task_type': task_type, |
696 | + 'machine': machine, |
697 | + 'method': "install", |
698 | + 'days': days, |
699 | + 'day_urls': _generate_day_urls( |
700 | + 'eventstat_image_details', |
701 | + kwargs={ |
702 | + 'image_id': image_id, |
703 | + 'machine_id': machine_id, |
704 | + 'task_type': task_type, |
705 | + } |
706 | + ), |
707 | + 'task_type_urls': _generate_task_type_urls( |
708 | + 'eventstat_image_details', |
709 | + kwargs=dict( |
710 | + machine_id=machine_id, |
711 | + image_id=image_id, |
712 | + task_type=task_type, |
713 | + days=days |
714 | + ), |
715 | + ), |
716 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
717 | + image_details, |
718 | + machine_id=machine_id, |
719 | + image_id=image_id, |
720 | + task_type=task_type, |
721 | + days=days, |
722 | + build_number=image.build_number, |
723 | + ), |
724 | + } |
725 | + |
726 | + return render_to_response( |
727 | + "power/eventstat/image_details.html", |
728 | + data, |
729 | + RequestContext(request), |
730 | + ) |
731 | + |
732 | + |
733 | +@BreadCrumb( |
734 | + "Task overview", |
735 | + parent=arch_breakdown, |
736 | + needs=['arch', 'machine_id', 'method', 'method'], |
737 | +) |
738 | @require_GET |
739 | def task_overview(request, machine_id, arch, method, task, days=None): |
740 | |
741 | @@ -337,6 +438,13 @@ |
742 | 'task': task, |
743 | } |
744 | ), |
745 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
746 | + task_overview, |
747 | + machine_id=machine_id, |
748 | + arch=arch, |
749 | + method=method, |
750 | + task=task, |
751 | + ), |
752 | } |
753 | |
754 | return render_to_response( |
755 | @@ -346,73 +454,11 @@ |
756 | ) |
757 | |
758 | |
759 | -@require_GET |
760 | -def image_details(request, image_id, task_type, machine_id, days=None): |
761 | - image = get_object_or_404(EventstatImage, id=image_id) |
762 | - machine = get_object_or_404(EventstatMachine, id=machine_id) |
763 | - |
764 | - if days is None: |
765 | - days = DAYS |
766 | - else: |
767 | - days = int(days) |
768 | - |
769 | - results = EventstatDetail.objects.filter( |
770 | - publish=True, |
771 | - image=image, |
772 | - machine=machine, |
773 | - ran_at__gt=datetime.datetime.now() - datetime.timedelta(days=days), |
774 | - ).values( |
775 | - 'task', |
776 | - 'image_id', |
777 | - 'image__arch', |
778 | - 'machine_id', |
779 | - ).annotate( |
780 | - average=models.Avg('total'), |
781 | - minimum=models.Min('total'), |
782 | - maximum=models.Max('total'), |
783 | - stddev=models.StdDev('total'), |
784 | - ) |
785 | - |
786 | - if task_type != 'all': |
787 | - results = results.filter(task_type=task_type) |
788 | - |
789 | - table = TaskInstallTable(results) |
790 | - |
791 | - RequestConfig(request, paginate={"per_page": 100}).configure(table) |
792 | - |
793 | - data = { |
794 | - 'table': table, |
795 | - 'image': image, |
796 | - 'task_type': task_type, |
797 | - 'machine': machine, |
798 | - 'method': "install", |
799 | - 'days': days, |
800 | - 'day_urls': _generate_day_urls( |
801 | - 'eventstat_image_details', |
802 | - kwargs={ |
803 | - 'image_id': image_id, |
804 | - 'machine_id': machine_id, |
805 | - 'task_type': task_type, |
806 | - } |
807 | - ), |
808 | - 'task_type_urls': _generate_task_type_urls( |
809 | - 'eventstat_image_details', |
810 | - kwargs=dict( |
811 | - machine_id=machine_id, |
812 | - image_id=image_id, |
813 | - task_type=task_type, |
814 | - days=days |
815 | - ), |
816 | - ), |
817 | - } |
818 | - |
819 | - return render_to_response( |
820 | - "power/eventstat/image_details.html", |
821 | - data, |
822 | - RequestContext(request), |
823 | - ) |
824 | - |
825 | - |
826 | +@BreadCrumb( |
827 | + "Upgrade details", |
828 | + parent=image_details, |
829 | + needs=['upgrade_id', 'machine_id', 'task_type'], |
830 | +) |
831 | @require_GET |
832 | def upgrade_details(request, upgrade_id, task_type, machine_id, days=None): |
833 | upgrade = get_object_or_404(EventstatUpgrade, id=upgrade_id) |
834 | @@ -468,9 +514,17 @@ |
835 | machine_id=machine_id, |
836 | upgrade_id=upgrade_id, |
837 | task_type=task_type, |
838 | - days=days |
839 | + days=days, |
840 | + build_number=upgrade.build_number, |
841 | ), |
842 | ), |
843 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
844 | + upgrade_details, |
845 | + machine_id=machine_id, |
846 | + upgrade_id=upgrade_id, |
847 | + task_type=task_type, |
848 | + days=days, |
849 | + ), |
850 | } |
851 | |
852 | return render_to_response( |
853 | @@ -480,6 +534,11 @@ |
854 | ) |
855 | |
856 | |
857 | +@BreadCrumb( |
858 | + "Task details", |
859 | + parent=image_details, |
860 | + needs=['image_id', 'machine_id', 'task_type'], |
861 | +) |
862 | @require_GET |
863 | def image_task_details(request, image_id, task, machine_id): |
864 | image = get_object_or_404(EventstatImage, id=image_id) |
865 | @@ -501,6 +560,13 @@ |
866 | 'arch': image.arch, |
867 | 'task': task, |
868 | 'machine': machine, |
869 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
870 | + image_task_details, |
871 | + machine_id=machine_id, |
872 | + image_id=image_id, |
873 | + task_type=task, |
874 | + build_number=image.build_number, |
875 | + ), |
876 | } |
877 | |
878 | return render_to_response( |
879 | @@ -510,6 +576,11 @@ |
880 | ) |
881 | |
882 | |
883 | +@BreadCrumb( |
884 | + "Task details", |
885 | + parent=image_details, |
886 | + needs=['upgrade_id', 'machine_id', 'task'], |
887 | +) |
888 | @require_GET |
889 | def upgrade_task_details(request, upgrade_id, task, machine_id): |
890 | machine = get_object_or_404(EventstatMachine, id=machine_id) |
891 | @@ -530,6 +601,12 @@ |
892 | 'machine': machine, |
893 | 'upgrade': upgrade, |
894 | 'arch': upgrade.arch, |
895 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
896 | + upgrade_task_details, |
897 | + machine_id=machine_id, |
898 | + upgrade_id=upgrade_id, |
899 | + task=task, |
900 | + ), |
901 | } |
902 | |
903 | return render_to_response( |
904 | @@ -539,6 +616,11 @@ |
905 | ) |
906 | |
907 | |
908 | +@BreadCrumb( |
909 | + "Task details", |
910 | + parent=image_details, |
911 | + needs=['arch', 'method', 'machine_id', 'task'], |
912 | +) |
913 | @require_GET |
914 | def task_details(request, machine_id, arch, method, task, days=None): |
915 | |
916 | @@ -577,6 +659,13 @@ |
917 | 'arch': arch, |
918 | 'machine': machine, |
919 | 'task': task, |
920 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
921 | + task_details, |
922 | + machine_id=machine_id, |
923 | + task=task, |
924 | + arch=arch, |
925 | + method=method, |
926 | + ), |
927 | } |
928 | |
929 | return render_to_response( |
930 | |
931 | === modified file 'idle_power/views.py' |
932 | --- idle_power/views.py 2013-04-25 18:27:26 +0000 |
933 | +++ idle_power/views.py 2013-05-03 22:59:28 +0000 |
934 | @@ -25,6 +25,13 @@ |
935 | |
936 | from django_tables2 import RequestConfig |
937 | |
938 | +from common.bread_crumbs import ( |
939 | + BreadCrumb, |
940 | + BreadCrumbTrail, |
941 | +) |
942 | + |
943 | +from power.views import overview |
944 | + |
945 | from idle_power.config import get_testcases |
946 | |
947 | from idle_power.models import ( |
948 | @@ -35,6 +42,7 @@ |
949 | from idle_power.tables import DataTable, MachineTable |
950 | |
951 | |
952 | +@BreadCrumb("Software measurement", parent=overview) |
953 | @require_GET |
954 | def arch_overview(request, arch=None): |
955 | vals = IdlePowerDetail.objects.filter( |
956 | @@ -67,6 +75,7 @@ |
957 | 'active': arch, |
958 | 'chart_size': chart_size, |
959 | 'testcases': testcases, |
960 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(arch_overview), |
961 | } |
962 | |
963 | return render_to_response( |
964 | @@ -76,6 +85,11 @@ |
965 | ) |
966 | |
967 | |
968 | +@BreadCrumb( |
969 | + "Machine details", |
970 | + parent=arch_overview, |
971 | + needs=['machine_id', 'arch'], |
972 | +) |
973 | @require_GET |
974 | def machine_detail(request, machine_id, arch): |
975 | machine = get_object_or_404(IdlePowerMachine, id=machine_id) |
976 | @@ -96,6 +110,11 @@ |
977 | 'name': machine.name, |
978 | 'arch': arch, |
979 | 'table': table, |
980 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
981 | + machine_detail, |
982 | + arch=arch, |
983 | + machine_id=machine_id, |
984 | + ), |
985 | } |
986 | |
987 | return render_to_response( |
988 | @@ -105,6 +124,11 @@ |
989 | ) |
990 | |
991 | |
992 | +@BreadCrumb( |
993 | + "Detailed view", |
994 | + parent=machine_detail, |
995 | + needs=['machine_id', 'arch', 'build_number'], |
996 | +) |
997 | @require_GET |
998 | def machine_raw_data(request, machine_id, arch, build_number): |
999 | machine = get_object_or_404(IdlePowerMachine, id=machine_id) |
1000 | @@ -142,6 +166,12 @@ |
1001 | 'variant': details['image__variant'], |
1002 | 'jenkins_url': details['jenkins_url'], |
1003 | 'duration': details['duration'], |
1004 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1005 | + machine_raw_data, |
1006 | + arch=arch, |
1007 | + machine_id=machine_id, |
1008 | + build_number=build_number, |
1009 | + ), |
1010 | } |
1011 | return render_to_response( |
1012 | "idle_power/machine_raw_data.html", |
1013 | |
1014 | === modified file 'memory/templates/memory/machine_details.html' |
1015 | --- memory/templates/memory/machine_details.html 2013-04-11 17:31:16 +0000 |
1016 | +++ memory/templates/memory/machine_details.html 2013-05-03 22:59:28 +0000 |
1017 | @@ -10,26 +10,6 @@ |
1018 | {% endblock extra_headers %} |
1019 | {% block content %} |
1020 | |
1021 | -<div id="breadcrumb"> |
1022 | - <span class="crumb"> |
1023 | - {% if result.image %} |
1024 | - <a href="{% url memory_arch_overview arch %}">{{ arch }} - {{ result.image.variant }}</a> |
1025 | - {% else %} |
1026 | - <a href="{% url memory_arch_overview arch %}">{{ arch }} - {{ result.upgrade.variant }}</a> |
1027 | - {% endif %} |
1028 | - </span> |
1029 | - <span class='crumb-sep'> |
1030 | - >> |
1031 | - </span> |
1032 | - <span class="crumb"> |
1033 | - {% if result.image %} |
1034 | - <a href="{% url machine_image_results arch result.machine.id result.image.variant result.name %}">{{ result.name }}</a> |
1035 | - {% else %} |
1036 | - <a href="{% url machine_upgrade_results arch result.machine.id result.upgrade.variant result.name %}">{{ result.name }}</a> |
1037 | - {% endif %} |
1038 | - </span> |
1039 | -</div> |
1040 | - |
1041 | <div class="grid_15"> |
1042 | <h2>Memory consumption details for {{ result.name|upper }} on {{ result.machine.name }} using {{ arch }}</h2> |
1043 | </div> |
1044 | |
1045 | === modified file 'memory/templates/memory/machine_results.html' |
1046 | --- memory/templates/memory/machine_results.html 2013-04-03 17:43:27 +0000 |
1047 | +++ memory/templates/memory/machine_results.html 2013-05-03 22:59:28 +0000 |
1048 | @@ -7,11 +7,6 @@ |
1049 | <script src="http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js"></script> |
1050 | {% endblock extra_headers %} |
1051 | {% block content %} |
1052 | -<div id="breadcrumb"> |
1053 | - <span class="crumb"> |
1054 | - <a href="{% url memory_arch_overview arch %}">{{ arch }} - {{ variant }}</a> |
1055 | - </span> |
1056 | -</div> |
1057 | |
1058 | <div class="grid_15"> |
1059 | <h2>Memory consumption results for {{ arch }} on {{ machine }}</h2> |
1060 | |
1061 | === modified file 'memory/views.py' |
1062 | --- memory/views.py 2013-04-10 19:03:16 +0000 |
1063 | +++ memory/views.py 2013-05-03 22:59:28 +0000 |
1064 | @@ -27,6 +27,13 @@ |
1065 | redirect, |
1066 | ) |
1067 | |
1068 | +from common.bread_crumbs import ( |
1069 | + BreadCrumb, |
1070 | + BreadCrumbTrail, |
1071 | +) |
1072 | + |
1073 | +from smoke.views import index |
1074 | + |
1075 | from memory.models import ( |
1076 | MemoryMachine, |
1077 | MemoryMetric, |
1078 | @@ -79,6 +86,7 @@ |
1079 | return metrics |
1080 | |
1081 | |
1082 | +@BreadCrumb("Memory testing", parent=index) |
1083 | @require_GET |
1084 | def arch_overview(request, arch=None): |
1085 | arches = _get_memory_arches() |
1086 | @@ -109,6 +117,7 @@ |
1087 | 'active': arch, |
1088 | 'chart_size': chart_size, |
1089 | 'image_types': image_types, |
1090 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(arch_overview), |
1091 | } |
1092 | |
1093 | return render_to_response('memory/arch_overview.html', data, |
1094 | @@ -116,7 +125,7 @@ |
1095 | |
1096 | |
1097 | @require_GET |
1098 | -def _process_overview(request, arch, machine_id, upgrade=False): |
1099 | +def _process_overview(request, arch, machine_id, data, upgrade=False): |
1100 | arches = _get_memory_arches() |
1101 | |
1102 | machine = get_object_or_404(MemoryMachine, id=machine_id) |
1103 | @@ -136,7 +145,7 @@ |
1104 | if process is not None: |
1105 | processes = processes.filter(process=process) |
1106 | |
1107 | - data = { |
1108 | + data.update({ |
1109 | 'machine': machine, |
1110 | 'processes': processes, |
1111 | 'arch': arch, |
1112 | @@ -145,22 +154,63 @@ |
1113 | 'chart_size': chart_size, |
1114 | 'upgrade': upgrade, |
1115 | 'type': "upgrade" if upgrade else "image", |
1116 | - } |
1117 | + }) |
1118 | |
1119 | return render_to_response('memory/process_overview.html', data, |
1120 | RequestContext(request)) |
1121 | |
1122 | |
1123 | +@BreadCrumb( |
1124 | + "upgrade process overview", |
1125 | + parent=arch_overview, |
1126 | + needs=['arch', 'machine_id'], |
1127 | +) |
1128 | @require_GET |
1129 | def upgrade_process_overview(request, arch, machine_id): |
1130 | - return _process_overview(request, arch, machine_id, upgrade=True) |
1131 | - |
1132 | - |
1133 | + data = { |
1134 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1135 | + upgrade_process_overview, |
1136 | + arch=arch, |
1137 | + machine_id=machine_id, |
1138 | + ), |
1139 | + } |
1140 | + return _process_overview( |
1141 | + request, |
1142 | + arch, |
1143 | + machine_id, |
1144 | + upgrade=True, |
1145 | + data=data, |
1146 | + ) |
1147 | + |
1148 | + |
1149 | +@BreadCrumb( |
1150 | + "image process overview", |
1151 | + parent=arch_overview, |
1152 | + needs=['arch', 'machine_id'], |
1153 | +) |
1154 | @require_GET |
1155 | def image_process_overview(request, arch, machine_id): |
1156 | - return _process_overview(request, arch, machine_id, upgrade=False) |
1157 | - |
1158 | - |
1159 | + data = { |
1160 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1161 | + image_process_overview, |
1162 | + arch=arch, |
1163 | + machine_id=machine_id, |
1164 | + ), |
1165 | + } |
1166 | + return _process_overview( |
1167 | + request, |
1168 | + arch, |
1169 | + machine_id, |
1170 | + upgrade=False, |
1171 | + data=data, |
1172 | + ) |
1173 | + |
1174 | + |
1175 | +@BreadCrumb( |
1176 | + "Image results", |
1177 | + parent=arch_overview, |
1178 | + needs=['arch', 'machine_id', 'variant', 'metric'], |
1179 | +) |
1180 | @require_GET |
1181 | def machine_image_results(request, arch, machine_id, variant, metric): |
1182 | machine = get_object_or_404(MemoryMachine, id=machine_id) |
1183 | @@ -181,12 +231,24 @@ |
1184 | 'arch': arch, |
1185 | 'table': table, |
1186 | 'variant': variant, |
1187 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1188 | + machine_image_results, |
1189 | + arch=arch, |
1190 | + machine_id=machine_id, |
1191 | + variant=variant, |
1192 | + metric=metric, |
1193 | + ), |
1194 | } |
1195 | |
1196 | return render_to_response('memory/machine_results.html', data, |
1197 | RequestContext(request)) |
1198 | |
1199 | |
1200 | +@BreadCrumb( |
1201 | + "Machine upgrade results", |
1202 | + parent=arch_overview, |
1203 | + needs=['arch', 'machine_id', 'variant', 'metric'], |
1204 | +) |
1205 | @require_GET |
1206 | def machine_upgrade_results(request, arch, machine_id, variant, metric): |
1207 | machine = get_object_or_404(MemoryMachine, id=machine_id) |
1208 | @@ -207,16 +269,27 @@ |
1209 | 'arch': arch, |
1210 | 'table': table, |
1211 | 'variant': variant, |
1212 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1213 | + machine_upgrade_results, |
1214 | + arch=arch, |
1215 | + machine_id=machine_id, |
1216 | + variant=variant, |
1217 | + metric=metric, |
1218 | + ), |
1219 | } |
1220 | |
1221 | return render_to_response('memory/machine_results.html', data, |
1222 | RequestContext(request)) |
1223 | |
1224 | |
1225 | +@BreadCrumb( |
1226 | + "Details", |
1227 | + parent=machine_image_results, |
1228 | + needs=['arch', 'machine_id', 'result_id'], |
1229 | +) |
1230 | @require_GET |
1231 | def machine_image_details(request, arch, machine_id, result_id): |
1232 | result = get_object_or_404(MemoryResult, id=result_id) |
1233 | - |
1234 | details = result.memorydetail_set.all() |
1235 | |
1236 | data = [] |
1237 | @@ -279,12 +352,25 @@ |
1238 | 'arch': arch, |
1239 | 'table': table, |
1240 | 'totals': totals, |
1241 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1242 | + machine_image_details, |
1243 | + arch=arch, |
1244 | + machine_id=machine_id, |
1245 | + result_id=result_id, |
1246 | + variant=result.image.variant, |
1247 | + metric=result.metric.name, |
1248 | + ), |
1249 | } |
1250 | |
1251 | return render_to_response('memory/machine_details.html', data, |
1252 | RequestContext(request)) |
1253 | |
1254 | |
1255 | +@BreadCrumb( |
1256 | + "Machine upgrade details", |
1257 | + parent=arch_overview, |
1258 | + needs=['arch', 'machine_id', 'result_id'], |
1259 | +) |
1260 | @require_GET |
1261 | def machine_upgrade_details(request, arch, machine_id, result_id): |
1262 | result = get_object_or_404(MemoryResult, id=result_id) |
1263 | @@ -350,6 +436,12 @@ |
1264 | 'arch': arch, |
1265 | 'table': table, |
1266 | 'totals': totals, |
1267 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1268 | + machine_upgrade_details, |
1269 | + arch=arch, |
1270 | + machine_id=machine_id, |
1271 | + result_id=result_id, |
1272 | + ), |
1273 | } |
1274 | |
1275 | return render_to_response('memory/machine_details.html', data, |
1276 | |
1277 | === modified file 'power/urls.py' |
1278 | --- power/urls.py 2013-04-16 20:47:20 +0000 |
1279 | +++ power/urls.py 2013-05-03 22:59:28 +0000 |
1280 | @@ -20,7 +20,7 @@ |
1281 | |
1282 | urlpatterns = patterns( |
1283 | 'power.views', |
1284 | - url(r'^$', 'arch_overview', name='power_arch'), |
1285 | + url(r'^$', 'arch_overview', name='power_overview'), |
1286 | url( |
1287 | r'^arch/(?P<arch>\w+)/$', |
1288 | 'arch_overview', |
1289 | |
1290 | === modified file 'power/views.py' |
1291 | --- power/views.py 2013-03-21 18:59:36 +0000 |
1292 | +++ power/views.py 2013-05-03 22:59:28 +0000 |
1293 | @@ -24,6 +24,12 @@ |
1294 | redirect, |
1295 | ) |
1296 | |
1297 | +from common.bread_crumbs import ( |
1298 | + BreadCrumb, |
1299 | + BreadCrumbTrail, |
1300 | +) |
1301 | + |
1302 | +from smoke.views import index |
1303 | from power.models import ( |
1304 | PowerMachine, |
1305 | PowerMetric, |
1306 | @@ -58,21 +64,56 @@ |
1307 | return metrics |
1308 | |
1309 | |
1310 | +@BreadCrumb("Power testing", parent=index) |
1311 | @require_GET |
1312 | def overview(request): |
1313 | - machines = PowerMachine.objects.filter(publish=True) |
1314 | - |
1315 | - data = { |
1316 | - 'machines': machines, |
1317 | - } |
1318 | - |
1319 | - return render_to_response( |
1320 | - 'power/overview.html', |
1321 | - data, |
1322 | - RequestContext(request) |
1323 | - ) |
1324 | - |
1325 | - |
1326 | + data = { |
1327 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(overview), |
1328 | + } |
1329 | + |
1330 | + return _arch_overview(request, data=data, add_url='hardware/') |
1331 | + |
1332 | + |
1333 | +@BreadCrumb("Hardware measurement", parent=overview) |
1334 | +@require_GET |
1335 | +def arch_overview(request, arch=None): |
1336 | + data = { |
1337 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(arch_overview), |
1338 | + } |
1339 | + return _arch_overview(request, arch, data) |
1340 | + |
1341 | + |
1342 | +@require_GET |
1343 | +def _arch_overview(request, arch=None, data={}, add_url=''): |
1344 | + arches = _get_power_arches() |
1345 | + |
1346 | + chart_size = request.GET.get('size', '') |
1347 | + |
1348 | + if arch is None: |
1349 | + return redirect( |
1350 | + '{}arch/{}'.format( |
1351 | + add_url, arches[0] if len(arches) > 0 else "amd64" |
1352 | + ) |
1353 | + ) |
1354 | + |
1355 | + result = PowerMetric.objects.filter(image__arch=arch) |
1356 | + result = result.distinct('machine__name') |
1357 | + arches = _get_power_arches() |
1358 | + metrics = _get_metrics(arch=arch) |
1359 | + data.update({ |
1360 | + 'result': result, |
1361 | + 'arch': arch, |
1362 | + 'arches': arches, |
1363 | + 'active': arch, |
1364 | + 'metrics': metrics, |
1365 | + 'chart_size': chart_size, |
1366 | + }) |
1367 | + |
1368 | + return render_to_response('power/arch_overview.html', data, |
1369 | + RequestContext(request)) |
1370 | + |
1371 | + |
1372 | +@BreadCrumb("Power usage", parent=arch_overview, needs=['machine_id', 'arch']) |
1373 | @require_GET |
1374 | def machine_detail(request, machine_id, arch): |
1375 | machine = get_object_or_404(PowerMachine, id=machine_id) |
1376 | @@ -103,36 +144,12 @@ |
1377 | data = { |
1378 | 'machine': machine, |
1379 | 'table': table, |
1380 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1381 | + machine_detail, |
1382 | + machine_id=machine_id, |
1383 | + arch=arch, |
1384 | + ), |
1385 | } |
1386 | |
1387 | return render_to_response('power/machine_detail.html', data, |
1388 | RequestContext(request)) |
1389 | - |
1390 | - |
1391 | -@require_GET |
1392 | -def arch_overview(request, arch=None): |
1393 | - arches = _get_power_arches() |
1394 | - |
1395 | - chart_size = request.GET.get('size', '') |
1396 | - |
1397 | - if arch is None: |
1398 | - return redirect( |
1399 | - 'arch/{}'.format(arches[0] if len(arches) > 0 else "amd64") |
1400 | - ) |
1401 | - |
1402 | - result = PowerMetric.objects.filter(image__arch=arch) |
1403 | - result = result.distinct('machine__name') |
1404 | - arches = _get_power_arches() |
1405 | - metrics = _get_metrics(arch=arch) |
1406 | - |
1407 | - data = { |
1408 | - 'result': result, |
1409 | - 'arch': arch, |
1410 | - 'arches': arches, |
1411 | - 'active': arch, |
1412 | - 'metrics': metrics, |
1413 | - 'chart_size': chart_size, |
1414 | - } |
1415 | - |
1416 | - return render_to_response('power/arch_overview.html', data, |
1417 | - RequestContext(request)) |
1418 | |
1419 | === modified file 'qa_dashboard/urls.py' |
1420 | --- qa_dashboard/urls.py 2013-05-02 16:11:38 +0000 |
1421 | +++ qa_dashboard/urls.py 2013-05-03 22:59:28 +0000 |
1422 | @@ -26,6 +26,7 @@ |
1423 | |
1424 | urlpatterns = patterns( |
1425 | '', |
1426 | + url(r'^power/$', 'power.views.overview', name='power_overview'), |
1427 | url(r'^power/hardware/', include('power.urls')), |
1428 | url(r'^api/power/hardware/', include('power.urls_api')), |
1429 | url(r'^power/idle/', include('idle_power.urls')), |
1430 | @@ -86,11 +87,10 @@ |
1431 | |
1432 | urlpatterns += patterns( |
1433 | 'bootspeed.views', |
1434 | - url(r'^bootspeed/$', 'arch_overview', name='bootspeed_arch'), |
1435 | url( |
1436 | - r'^bootspeed/arch/(?P<arch>\w+)/$', |
1437 | + r'^bootspeed/(?:arch/(?P<arch>\w+)/)?$', |
1438 | 'arch_overview', |
1439 | - name='bootspeed_arch_overview' |
1440 | + name='bootspeed_arch', |
1441 | ), |
1442 | url( |
1443 | r'^bootspeed/machine/(?P<machine_id>\d+)/(?P<arch>\w+)/$', |
1444 | |
1445 | === modified file 'smoke/templates/smoke/build_overview.html' |
1446 | --- smoke/templates/smoke/build_overview.html 2013-04-29 23:27:29 +0000 |
1447 | +++ smoke/templates/smoke/build_overview.html 2013-05-03 22:59:28 +0000 |
1448 | @@ -15,20 +15,6 @@ |
1449 | //]]> |
1450 | </script> |
1451 | <div class='grid_15'> |
1452 | - <div id='breadcrumb'> |
1453 | - <span class='crumb'> |
1454 | - <a href='{% url smoke_overview release %}flat/'> |
1455 | - Smoke Testing |
1456 | - {{release|capfirst}} |
1457 | - </a> |
1458 | - </span> |
1459 | - <span class='crumb-sep'> |
1460 | - >> |
1461 | - </span> |
1462 | - <span class='crumb'> |
1463 | - Image {{run.build_no}} |
1464 | - </span> |
1465 | - </div> |
1466 | <h2> |
1467 | Summary of smoke testing for Ubuntu image {{run.build_no}} |
1468 | </h2> |
1469 | |
1470 | === modified file 'smoke/templates/smoke/result_logs.html' |
1471 | --- smoke/templates/smoke/result_logs.html 2013-04-02 21:09:05 +0000 |
1472 | +++ smoke/templates/smoke/result_logs.html 2013-05-03 22:59:28 +0000 |
1473 | @@ -14,31 +14,6 @@ |
1474 | //]]> |
1475 | </script> |
1476 | <div class='grid_15'> |
1477 | - <div id='breadcrumb'> |
1478 | - <span class='crumb'> |
1479 | - <a href='{% url smoke_overview release %}flat/'> |
1480 | - Smoke testing |
1481 | - {{ release|capfirst }} |
1482 | - </a> |
1483 | - </span> |
1484 | - <span class='crumb-sep'> |
1485 | - >> |
1486 | - </span> |
1487 | - <span class='crumb'> |
1488 | - <a href='{% url build_overview release image.run.id %}'> |
1489 | - Image {{image.run.build_no}} |
1490 | - </a> |
1491 | - </span> |
1492 | - <span class='crumb-sep'> |
1493 | - >> |
1494 | - </span> |
1495 | - <span class='crumb'> |
1496 | - Result logs for {{image.run.flavor}}-{{image.variant}}-{{image.arch}} {{result.name}} |
1497 | - </span> |
1498 | - <span class='crumb-sep'> |
1499 | - Logs |
1500 | - </span> |
1501 | - </div> |
1502 | <h2> |
1503 | Result Logs |
1504 | </h2> |
1505 | |
1506 | === modified file 'smoke/templates/smoke/results.html' |
1507 | --- smoke/templates/smoke/results.html 2013-04-29 23:27:29 +0000 |
1508 | +++ smoke/templates/smoke/results.html 2013-05-03 22:59:28 +0000 |
1509 | @@ -15,28 +15,6 @@ |
1510 | //]]> |
1511 | </script> |
1512 | <div class='grid_15'> |
1513 | - <div id='breadcrumb'> |
1514 | - <span class='crumb'> |
1515 | - <a href='{% url smoke_overview release %}flat/'> |
1516 | - Smoke testing |
1517 | - {{ release|capfirst }} |
1518 | - </a> |
1519 | - </span> |
1520 | - <span class='crumb-sep'> |
1521 | - >> |
1522 | - </span> |
1523 | - <span class='crumb'> |
1524 | - <a href='{% url build_overview release image.run.id %}'> |
1525 | - Image {{image.run.build_no}} |
1526 | - </a> |
1527 | - </span> |
1528 | - <span class='crumb-sep'> |
1529 | - >> |
1530 | - </span> |
1531 | - <span class='crumb'> |
1532 | - Smoke testing results for {{image.run.build_no}} {{image.run.flavor}}-{{image.variant}}-{{image.arch}} |
1533 | - </span> |
1534 | - </div> |
1535 | <h2> |
1536 | Results |
1537 | </h2> |
1538 | |
1539 | === modified file 'smoke/views.py' |
1540 | --- smoke/views.py 2013-05-02 16:11:38 +0000 |
1541 | +++ smoke/views.py 2013-05-03 22:59:28 +0000 |
1542 | @@ -18,6 +18,11 @@ |
1543 | from django.template import RequestContext |
1544 | from django.views.decorators.http import require_GET |
1545 | |
1546 | +from common.bread_crumbs import ( |
1547 | + BreadCrumb, |
1548 | + BreadCrumbTrail, |
1549 | +) |
1550 | + |
1551 | from smoke.models import ( |
1552 | Build, |
1553 | Result, |
1554 | @@ -35,6 +40,7 @@ |
1555 | return releases |
1556 | |
1557 | |
1558 | +@BreadCrumb("QA Dashboard") |
1559 | @require_GET |
1560 | def index(request): |
1561 | release = 'saucy' |
1562 | @@ -43,10 +49,12 @@ |
1563 | 'releases': _get_releases(), |
1564 | 'is_flat': True, |
1565 | 'active': release, |
1566 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(index), |
1567 | } |
1568 | return _process_flat_smoke_overview(request, release, data, limit=100) |
1569 | |
1570 | |
1571 | +@BreadCrumb("{release} smoke testing", parent=index, needs=['release']) |
1572 | @require_GET |
1573 | def overview(request, release, is_flat=False): |
1574 | data = { |
1575 | @@ -54,6 +62,10 @@ |
1576 | 'releases': _get_releases(), |
1577 | 'is_flat': False, |
1578 | 'active': release, |
1579 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1580 | + overview, |
1581 | + release=release, |
1582 | + ) |
1583 | } |
1584 | |
1585 | if request.GET.get('flat') is not None: |
1586 | @@ -100,6 +112,11 @@ |
1587 | ) |
1588 | |
1589 | |
1590 | +@BreadCrumb( |
1591 | + "Image {build_number}", |
1592 | + parent=overview, |
1593 | + needs=['release', 'run_id'], |
1594 | +) |
1595 | @require_GET |
1596 | def build_overview(request, release, run_id): |
1597 | try: |
1598 | @@ -109,13 +126,29 @@ |
1599 | |
1600 | # Again, eager loading of associations two levels deeper would be great. |
1601 | builds = run.build_set.all().exclude(publish=False) |
1602 | + data = { |
1603 | + 'release': release, |
1604 | + 'run': run, |
1605 | + 'builds': builds, |
1606 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1607 | + build_overview, |
1608 | + release=release, |
1609 | + build_number=run.build_no, |
1610 | + run_id=run_id, |
1611 | + ), |
1612 | + } |
1613 | return render_to_response( |
1614 | 'smoke/build_overview.html', |
1615 | - locals(), |
1616 | - RequestContext(request) |
1617 | + data, |
1618 | + RequestContext(request), |
1619 | ) |
1620 | |
1621 | |
1622 | +@BreadCrumb( |
1623 | + "{build_number} results", |
1624 | + parent=overview, |
1625 | + needs=['release', 'run_id', 'image_id'], |
1626 | +) |
1627 | @require_GET |
1628 | def results(request, release, run_id, image_id): |
1629 | try: |
1630 | @@ -124,15 +157,31 @@ |
1631 | ).select_related().get(id=image_id) |
1632 | except Build.DoesNotExist: |
1633 | raise Http404 |
1634 | - |
1635 | - results = image.result_set.all().exclude(publish=False) |
1636 | + image_results = image.result_set.all().exclude(publish=False) |
1637 | + data = { |
1638 | + 'release': release, |
1639 | + 'image': image, |
1640 | + 'results': image_results, |
1641 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1642 | + results, |
1643 | + release=release, |
1644 | + run_id=run_id, |
1645 | + image_id=image_id, |
1646 | + build_number=image.run.build_no, |
1647 | + ) |
1648 | + } |
1649 | return render_to_response( |
1650 | 'smoke/results.html', |
1651 | - locals(), |
1652 | + data, |
1653 | RequestContext(request) |
1654 | ) |
1655 | |
1656 | |
1657 | +@BreadCrumb( |
1658 | + "logs", |
1659 | + parent=results, |
1660 | + needs=['release', 'run_id', 'image_id', 'result_id'], |
1661 | +) |
1662 | @require_GET |
1663 | def results_logs(request, release, run_id, image_id, result_id): |
1664 | try: |
1665 | @@ -145,8 +194,22 @@ |
1666 | |
1667 | logs = result.resultlog_set.all().exclude(publish=False) |
1668 | |
1669 | + data = { |
1670 | + 'release': release, |
1671 | + 'image': image, |
1672 | + 'result': result, |
1673 | + 'logs': logs, |
1674 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1675 | + results_logs, |
1676 | + release=release, |
1677 | + run_id=run_id, |
1678 | + image_id=image_id, |
1679 | + result_id=result_id, |
1680 | + build_number=image.run.build_no, |
1681 | + ) |
1682 | + } |
1683 | return render_to_response( |
1684 | 'smoke/result_logs.html', |
1685 | - locals(), |
1686 | + data, |
1687 | RequestContext(request) |
1688 | ) |
1689 | |
1690 | === modified file 'sru/templates/sru/overview_kernel.html' |
1691 | --- sru/templates/sru/overview_kernel.html 2013-04-29 23:27:29 +0000 |
1692 | +++ sru/templates/sru/overview_kernel.html 2013-05-03 22:59:28 +0000 |
1693 | @@ -15,19 +15,6 @@ |
1694 | //]]> |
1695 | </script> |
1696 | <div class='grid_15'> |
1697 | - <div id='breadcrumb'> |
1698 | - <span class='crumb'> |
1699 | - <a href='{% url sru_overview release %}'> |
1700 | - SRU testing for {{release}} |
1701 | - </a> |
1702 | - </span> |
1703 | - <span class='crumb-sep'> |
1704 | - >> |
1705 | - </span> |
1706 | - <span class='crumb'> |
1707 | - Kernel {{kernel_version}} |
1708 | - </span> |
1709 | - </div> |
1710 | <h3> |
1711 | Summary of SRU testing for kernel {{kernel_version}} |
1712 | </h3> |
1713 | |
1714 | === modified file 'sru/views.py' |
1715 | --- sru/views.py 2013-05-01 16:12:06 +0000 |
1716 | +++ sru/views.py 2013-05-03 22:59:28 +0000 |
1717 | @@ -18,6 +18,12 @@ |
1718 | from django.template import RequestContext |
1719 | from datetime import date, timedelta |
1720 | |
1721 | +from common.bread_crumbs import ( |
1722 | + BreadCrumb, |
1723 | + BreadCrumbTrail, |
1724 | +) |
1725 | + |
1726 | +from smoke.views import index |
1727 | from sru.models import Kernel |
1728 | |
1729 | |
1730 | @@ -41,12 +47,14 @@ |
1731 | return releases |
1732 | |
1733 | |
1734 | +@BreadCrumb("SRU Testing", parent=index) |
1735 | @require_GET |
1736 | def overview(request, release=''): |
1737 | data = { |
1738 | 'releases': _get_kernel_releases(), |
1739 | 'active': release, |
1740 | - 'show_unknown': True |
1741 | + 'show_unknown': True, |
1742 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to(overview), |
1743 | } |
1744 | |
1745 | past_date = date.today() - timedelta(days=30) |
1746 | @@ -76,6 +84,11 @@ |
1747 | ) |
1748 | |
1749 | |
1750 | +@BreadCrumb( |
1751 | + "Summary of {kernel}", |
1752 | + parent=overview, |
1753 | + needs=['release', 'kernel'], |
1754 | +) |
1755 | @require_GET |
1756 | def overview_kernel(request, release=None, kernel_version=None): |
1757 | kernels = Kernel.objects.filter(version=kernel_version).select_related() |
1758 | @@ -83,7 +96,12 @@ |
1759 | data = { |
1760 | 'kernels': kernels, |
1761 | 'kernel_version': kernel_version, |
1762 | - 'release': release |
1763 | + 'release': release, |
1764 | + 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1765 | + overview_kernel, |
1766 | + release=release, |
1767 | + kernel=kernel_version, |
1768 | + ), |
1769 | } |
1770 | |
1771 | totals = { |
issue 1: http:// 91.189. 93.71:8000/ smoke/precise/ run/2427/ image/2427/ - use build number instead of date in the crumb. while you are in there you can also change the page title to include variant, arch, and type