diff options
author | David Reyna <David.Reyna@windriver.com> | 2015-03-21 18:01:38 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-03-25 12:39:53 +0000 |
commit | 6a934f488fd636829efbcb24058f92621e5a9fc6 (patch) | |
tree | cce4aaacc49ba4c179573de7f4ff2f2017044707 /bitbake | |
parent | e840b7a8fba16b857db4e74dd8331680a21e5eb1 (diff) | |
download | poky-6a934f488fd636829efbcb24058f92621e5a9fc6.tar.gz |
bitbake: toaster: build date range selections
Enable date range selections for build start and build complete in all
builds page for both managed and interactive mode. Disable the filter
counts.
[YOCTO #6040]
[YOCTO #7249]
[YOCTO #7461]
(Bitbake rev: 7c86ed5fb51c6237fa40fb454e58564ef027dd51)
Signed-off-by: David Reyna <David.Reyna@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
6 files changed, 277 insertions, 24 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/filtersnippet.js b/bitbake/lib/toaster/toastergui/static/js/filtersnippet.js new file mode 100755 index 0000000000..27b057e64e --- /dev/null +++ b/bitbake/lib/toaster/toastergui/static/js/filtersnippet.js | |||
@@ -0,0 +1,95 @@ | |||
1 | "use strict" | ||
2 | |||
3 | // The disable removes the 'datepicker' attribute and | ||
4 | // settings, so you have to re-initialize it each time | ||
5 | // the date range is selected and enabled | ||
6 | // DOM is used instead of jQuery to find the elements | ||
7 | // in all contexts | ||
8 | function date_enable (key, action) { | ||
9 | |||
10 | var elemFrom=document.getElementById("date_from_"+key); | ||
11 | var elemTo=document.getElementById("date_to_"+key); | ||
12 | |||
13 | if ('enable' == action) { | ||
14 | elemFrom.removeAttribute("disabled"); | ||
15 | elemTo.removeAttribute("disabled"); | ||
16 | |||
17 | $(elemFrom).datepicker(); | ||
18 | $(elemTo).datepicker(); | ||
19 | |||
20 | $(elemFrom).datepicker( "option", "dateFormat", "dd/mm/yy" ); | ||
21 | $(elemTo).datepicker( "option", "dateFormat", "dd/mm/yy" ); | ||
22 | |||
23 | $(elemFrom).datepicker( "setDate", elemFrom.getAttribute( "data-setDate") ); | ||
24 | $(elemTo).datepicker( "setDate", elemTo.getAttribute( "data-setDate") ); | ||
25 | $(elemFrom).datepicker( "option", "minDate", elemFrom.getAttribute( "data-minDate")); | ||
26 | $(elemTo).datepicker( "option", "minDate", elemTo.getAttribute( "data-minDate")); | ||
27 | $(elemFrom).datepicker( "option", "maxDate", elemFrom.getAttribute( "data-maxDate")); | ||
28 | $(elemTo).datepicker( "option", "maxDate", elemTo.getAttribute( "data-maxDate")); | ||
29 | } else { | ||
30 | elemFrom.setAttribute("disabled","disabled"); | ||
31 | elemTo.setAttribute("disabled","disabled"); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | // Initialize the date picker elements with their default state variables, and | ||
36 | // register the radio button and form actions | ||
37 | function date_init (key, from_date, to_date, min_date, max_date, initial_enable) { | ||
38 | |||
39 | var elemFrom=document.getElementById("date_from_"+key); | ||
40 | var elemTo=document.getElementById("date_to_"+key); | ||
41 | |||
42 | // Were there any daterange filters instantiated? (e.g. no builds found) | ||
43 | if (null == elemFrom) { | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | // init the datepicker context data | ||
48 | elemFrom.setAttribute( "data-setDate", from_date ); | ||
49 | elemTo.setAttribute( "data-setDate", to_date ); | ||
50 | elemFrom.setAttribute( "data-minDate", min_date); | ||
51 | elemTo.setAttribute( "data-minDate", min_date); | ||
52 | elemFrom.setAttribute( "data-maxDate", max_date); | ||
53 | elemTo.setAttribute( "data-maxDate", max_date); | ||
54 | |||
55 | // does the date set start enabled? | ||
56 | if (key == initial_enable) { | ||
57 | date_enable (key, "enable"); | ||
58 | } else { | ||
59 | date_enable (key, "disable"); | ||
60 | } | ||
61 | |||
62 | // catch the radio button selects for enable/disable | ||
63 | $('input:radio[name="filter"]').change(function(){ | ||
64 | if ($(this).val() == 'daterange') { | ||
65 | key=$(this).attr("data-key"); | ||
66 | date_enable (key, 'enable'); | ||
67 | } else { | ||
68 | key=$(this).attr("data-key"); | ||
69 | date_enable (key, 'disable'); | ||
70 | } | ||
71 | }); | ||
72 | |||
73 | // catch any new 'from' date as minDate for 'to' date | ||
74 | $("#date_from_"+key).change(function(){ | ||
75 | from_date = $("#date_from_"+key).val(); | ||
76 | $("#date_to_"+key).datepicker( "option", "minDate", from_date ); | ||
77 | }); | ||
78 | |||
79 | // catch the submit (just once) | ||
80 | $("form").unbind('submit'); | ||
81 | $("form").submit(function(e) { | ||
82 | // format a composite daterange filter value so that it can be parsed and post-processed in the view | ||
83 | var key=e.originalEvent.explicitOriginalTarget.getAttribute("data-key") | ||
84 | if (typeof key != "undefined") { | ||
85 | if ($("#date_from_"+key).length) { | ||
86 | var filter=key+"__gte!"+key+"__lt:"+$("#date_from_"+key).val()+"!"+$("#date_to_"+key).val()+"_daterange"; | ||
87 | $("#last_date_from_"+key).val($("#date_from_"+key).val()); | ||
88 | $("#last_date_to_"+key).val($("#date_to_"+key).val()); | ||
89 | $("#filter_value_"+key).val(filter); | ||
90 | } | ||
91 | } | ||
92 | return true; | ||
93 | }); | ||
94 | |||
95 | }; | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/build.html b/bitbake/lib/toaster/toastergui/templates/build.html index 684ec65884..f7ad2f4892 100644 --- a/bitbake/lib/toaster/toastergui/templates/build.html +++ b/bitbake/lib/toaster/toastergui/templates/build.html | |||
@@ -4,7 +4,24 @@ | |||
4 | {% load projecttags %} | 4 | {% load projecttags %} |
5 | {% load humanize %} | 5 | {% load humanize %} |
6 | 6 | ||
7 | {% block extraheadcontent %} | ||
8 | <link rel="stylesheet" href="/static/css/jquery-ui.min.css" type='text/css'> | ||
9 | <link rel="stylesheet" href="/static/css/jquery-ui.structure.min.css" type='text/css'> | ||
10 | <link rel="stylesheet" href="/static/css/jquery-ui.theme.min.css" type='text/css'> | ||
11 | <script src="/static/js/jquery-ui.min.js"></script> | ||
12 | <script src="/static/js/filtersnippet.js"></script> | ||
13 | {% endblock %} | ||
14 | |||
7 | {% block pagecontent %} | 15 | {% block pagecontent %} |
16 | |||
17 | <script> | ||
18 | // intiialize the date range controls | ||
19 | $(document).ready(function () { | ||
20 | date_init('started_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_started_on}}','{{dateMax_started_on}}','{{daterange_selected}}'); | ||
21 | date_init('completed_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_completed_on}}','{{dateMax_completed_on}}','{{daterange_selected}}'); | ||
22 | }); | ||
23 | </script> | ||
24 | |||
8 | <div class="row-fluid"> | 25 | <div class="row-fluid"> |
9 | 26 | ||
10 | {% include "mrb_section.html" %} | 27 | {% include "mrb_section.html" %} |
diff --git a/bitbake/lib/toaster/toastergui/templates/filtersnippet.html b/bitbake/lib/toaster/toastergui/templates/filtersnippet.html index fe70e7143e..f624d88bad 100644 --- a/bitbake/lib/toaster/toastergui/templates/filtersnippet.html +++ b/bitbake/lib/toaster/toastergui/templates/filtersnippet.html | |||
@@ -1,5 +1,6 @@ | |||
1 | {% load projecttags %} | 1 | {% load projecttags %} |
2 | <!-- '{{f.class}}' filter --> | 2 | <!-- '{{f.class}}' filter --> |
3 | {% with f.class as key %} | ||
3 | <form id="filter_{{f.class}}" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"> | 4 | <form id="filter_{{f.class}}" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"> |
4 | <input type="hidden" name="search" value="{{request.GET.search}}"/> | 5 | <input type="hidden" name="search" value="{{request.GET.search}}"/> |
5 | <div class="modal-header"> | 6 | <div class="modal-header"> |
@@ -13,22 +14,37 @@ | |||
13 | <div class="modal-body"> | 14 | <div class="modal-body"> |
14 | <p>{{f.label}}</p> | 15 | <p>{{f.label}}</p> |
15 | <label class="radio"> | 16 | <label class="radio"> |
16 | <input type="radio" name="filter" {%if request.GET.filter%}{{f.options|check_filter_status:request.GET.filter}} {%else%} checked {%endif%} value=""> All {%if filter_search_display%}{{filter_search_display|title}}{%else%}{{objectname|title}}{%endif%} ({{total_count}}) | 17 | <input type="radio" name="filter" {%if request.GET.filter%}{{f.options|check_filter_status:request.GET.filter}} {%else%} checked {%endif%} value="" data-key="{{key}}"> All {%if filter_search_display%}{{filter_search_display|title}}{%else%}{{objectname|title}}{%endif%} |
17 | </label> | 18 | </label> |
18 | {% for option in f.options %} | 19 | {% for option in f.options %} |
19 | {% if option.2 %} | 20 | {% if option.1 == 'daterange' %} |
20 | <label class="radio"> | 21 | <div class="form-inline"> |
21 | <input type="radio" name="filter" {%if request.GET.filter == option.1 %}checked{%endif%} value="{{option.1}}"> {{option.0}} (<span id="{{option.1}}_count">{{option.2}}</span>) | 22 | <label class="radio"> |
23 | <input type="radio" name="filter" id="filter_value_{{key}}" {%if key == daterange_selected %}checked{%endif%} value="{{option.1}}" data-key="{{key}}"> {{option.0}} | ||
22 | {% else %} | 24 | {% else %} |
23 | <label class="radio muted"> | 25 | {% if 1 %} |
24 | <input type="radio" name="filter" disabled {%if request.GET.filter == option.1 %}checked{%endif%} value="{{option.1}}"> {{option.0}} (<span id="{{option.1}}_count">{{option.2}}</span>) | 26 | <label class="radio"> |
27 | <input type="radio" name="filter" {%if request.GET.filter == option.1 %}checked{%endif%} value="{{option.1}}" data-key="{{key}}"> {{option.0}} | ||
28 | {% comment "do not disable radio selections by count for now" %}{% else %} | ||
29 | <label class="radio muted"> | ||
30 | <input type="radio" name="filter" disabled {%if request.GET.filter == option.1 %}checked{%endif%} value="{{option.1}}" data-key="{{key}}"> {{option.0}} | ||
31 | {% endcomment %}{% endif %} | ||
25 | {% endif %} | 32 | {% endif %} |
26 | {% if option.3 %}<i class="icon-question-sign get-help" data-placement="right" title="{{option.3}}"></i>{% endif %} | 33 | {% if option.3 %}<i class="icon-question-sign get-help" data-placement="right" title="{{option.3}}"></i>{% endif %} |
27 | </label> | 34 | </label> |
35 | {% if option.1 == 'daterange' %} | ||
36 | <input type="text" id="date_from_{{key}}" name="date_from_{{key}}" disabled class="input-small" /><label class="help-inline">to</label> | ||
37 | <input type="text" id="date_to_{{key}}" name="date_to_{{key}}" disabled class="input-small" /> | ||
38 | <label class="help-inline get-help" >(dd/mm/yyyy)</label> | ||
39 | </div> | ||
40 | {% endif %} | ||
28 | {% endfor %} | 41 | {% endfor %} |
42 | <!-- daterange persistence --> | ||
43 | <input type="hidden" id="last_date_from_{{key}}" name="last_date_from" value="{{last_date_from}}"/> | ||
44 | <input type="hidden" id="last_date_to_{{key}}" name="last_date_to" value="{{last_date_to}}"/> | ||
29 | </div> | 45 | </div> |
30 | <div class="modal-footer"> | 46 | <div class="modal-footer"> |
31 | <button type="submit" class="btn btn-primary">Apply</button> | 47 | <button type="submit" class="btn btn-primary" data-key="{{key}}">Apply</button> |
32 | {% if request.GET.filter %} | 48 | {% if request.GET.filter %} |
33 | {% if request.GET.filter|string_remove_regex:':.*' != f.options.0.1|string_remove_regex:':.*' %} | 49 | {% if request.GET.filter|string_remove_regex:':.*' != f.options.0.1|string_remove_regex:':.*' %} |
34 | <span class="help-inline pull-left">You can only apply one filter to the table. This filter will override the current filter.</span> | 50 | <span class="help-inline pull-left">You can only apply one filter to the table. This filter will override the current filter.</span> |
@@ -36,4 +52,4 @@ | |||
36 | {% endif %} | 52 | {% endif %} |
37 | </div> | 53 | </div> |
38 | </form> | 54 | </form> |
39 | 55 | {% endwith %} | |
diff --git a/bitbake/lib/toaster/toastergui/templates/managed_builds.html b/bitbake/lib/toaster/toastergui/templates/managed_builds.html index e23b832bae..63ae5408f5 100644 --- a/bitbake/lib/toaster/toastergui/templates/managed_builds.html +++ b/bitbake/lib/toaster/toastergui/templates/managed_builds.html | |||
@@ -4,7 +4,24 @@ | |||
4 | {% load projecttags %} | 4 | {% load projecttags %} |
5 | {% load humanize %} | 5 | {% load humanize %} |
6 | 6 | ||
7 | {% block extraheadcontent %} | ||
8 | <link rel="stylesheet" href="/static/css/jquery-ui.min.css" type='text/css'> | ||
9 | <link rel="stylesheet" href="/static/css/jquery-ui.structure.min.css" type='text/css'> | ||
10 | <link rel="stylesheet" href="/static/css/jquery-ui.theme.min.css" type='text/css'> | ||
11 | <script src="/static/js/jquery-ui.min.js"></script> | ||
12 | <script src="/static/js/filtersnippet.js"></script> | ||
13 | {% endblock %} | ||
14 | |||
7 | {% block pagecontent %} | 15 | {% block pagecontent %} |
16 | |||
17 | <script> | ||
18 | // initialize the date range controls | ||
19 | $(document).ready(function () { | ||
20 | date_init('created','{{last_date_from}}','{{last_date_to}}','{{dateMin_created}}','{{dateMax_created}}','{{daterange_selected}}'); | ||
21 | date_init('updated','{{last_date_from}}','{{last_date_to}}','{{dateMin_updated}}','{{dateMax_updated}}','{{daterange_selected}}'); | ||
22 | }); | ||
23 | </script> | ||
24 | |||
8 | <div class="row-fluid"> | 25 | <div class="row-fluid"> |
9 | 26 | ||
10 | {% include "managed_mrb_section.html" %} | 27 | {% include "managed_mrb_section.html" %} |
@@ -47,7 +64,7 @@ | |||
47 | {% for buildrequest in objects %}{% if buildrequest.build %} {% with build=buildrequest.build %} {# if we have a build, just display it #} | 64 | {% for buildrequest in objects %}{% if buildrequest.build %} {% with build=buildrequest.build %} {# if we have a build, just display it #} |
48 | <tr class="data"> | 65 | <tr class="data"> |
49 | <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a> | 66 | <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a> |
50 | {% if build.project %} | 67 | {% if build.project %} |
51 | <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}"> | 68 | <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}"> |
52 | <i class="icon-download-alt" title="" data-original-title="Download build log"></i> | 69 | <i class="icon-download-alt" title="" data-original-title="Download build log"></i> |
53 | </a> | 70 | </a> |
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py index 0ccf73a619..54700e3842 100644 --- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py +++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py | |||
@@ -125,6 +125,8 @@ def filtered_icon(options, filter): | |||
125 | for option in options: | 125 | for option in options: |
126 | if filter == option[1]: | 126 | if filter == option[1]: |
127 | return "btn-primary" | 127 | return "btn-primary" |
128 | if ('daterange' == option[1]) and filter.startswith(option[4]): | ||
129 | return "btn-primary" | ||
128 | return "" | 130 | return "" |
129 | 131 | ||
130 | @register.filter | 132 | @register.filter |
@@ -134,6 +136,8 @@ def filtered_tooltip(options, filter): | |||
134 | for option in options: | 136 | for option in options: |
135 | if filter == option[1]: | 137 | if filter == option[1]: |
136 | return "Showing only %s"%option[0] | 138 | return "Showing only %s"%option[0] |
139 | if ('daterange' == option[1]) and filter.startswith(option[4]): | ||
140 | return "Showing only %s"%option[0] | ||
137 | return "" | 141 | return "" |
138 | 142 | ||
139 | @register.filter | 143 | @register.filter |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 4ebcf6d54f..d999959446 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
@@ -35,7 +35,7 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger | |||
35 | from django.http import HttpResponseBadRequest, HttpResponseNotFound | 35 | from django.http import HttpResponseBadRequest, HttpResponseNotFound |
36 | from django.utils import timezone | 36 | from django.utils import timezone |
37 | from django.utils.html import escape | 37 | from django.utils.html import escape |
38 | from datetime import timedelta | 38 | from datetime import timedelta, datetime, date |
39 | from django.utils import formats | 39 | from django.utils import formats |
40 | from toastergui.templatetags.projecttags import json as jsonfilter | 40 | from toastergui.templatetags.projecttags import json as jsonfilter |
41 | import json | 41 | import json |
@@ -279,6 +279,65 @@ def _save_parameters_cookies(response, pagesize, orderby, request): | |||
279 | response.set_cookie(key='orderby', value=html_parser.unescape(orderby), path=request.path) | 279 | response.set_cookie(key='orderby', value=html_parser.unescape(orderby), path=request.path) |
280 | return response | 280 | return response |
281 | 281 | ||
282 | # date range: normalize GUI's dd/mm/yyyy to date object | ||
283 | def _normalize_input_date(date_str,default): | ||
284 | date_str=re.sub('/', '-', date_str) | ||
285 | # accept dd/mm/yyyy to d/m/yy | ||
286 | try: | ||
287 | date_in = datetime.strptime(date_str, "%d-%m-%Y") | ||
288 | except ValueError: | ||
289 | # courtesy try with two digit year | ||
290 | try: | ||
291 | date_in = datetime.strptime(date_str, "%d-%m-%y") | ||
292 | except ValueError: | ||
293 | return default | ||
294 | date_in = date_in.replace(tzinfo=default.tzinfo) | ||
295 | return date_in | ||
296 | |||
297 | # convert and normalize any received date range filter, for example: | ||
298 | # "completed_on__gte!completed_on__lt:01/03/2015!02/03/2015_daterange" to | ||
299 | # "completed_on__gte!completed_on__lt:2015-03-01!2015-03-02" | ||
300 | def _modify_date_range_filter(filter_string): | ||
301 | # was the date range radio button selected? | ||
302 | if 0 > filter_string.find('_daterange'): | ||
303 | return filter_string,'' | ||
304 | # normalize GUI dates to database format | ||
305 | filter_string = filter_string.replace('_daterange','').replace(':','!'); | ||
306 | filter_list = filter_string.split('!'); | ||
307 | if 4 != len(filter_list): | ||
308 | return filter_string | ||
309 | today = timezone.localtime(timezone.now()) | ||
310 | date_id = filter_list[1] | ||
311 | date_from = _normalize_input_date(filter_list[2],today) | ||
312 | date_to = _normalize_input_date(filter_list[3],today) | ||
313 | # swap dates if manually set dates are out of order | ||
314 | if date_to < date_from: | ||
315 | date_to,date_from = date_from,date_to | ||
316 | # convert to strings, make 'date_to' inclusive by moving to begining of next day | ||
317 | date_from_str = date_from.strftime("%Y-%m-%d") | ||
318 | date_to_str = (date_to+timedelta(days=1)).strftime("%Y-%m-%d") | ||
319 | filter_string=filter_list[0]+'!'+filter_list[1]+':'+date_from_str+'!'+date_to_str | ||
320 | daterange_selected = re.sub('__.*','', date_id) | ||
321 | return filter_string,daterange_selected | ||
322 | |||
323 | def _add_daterange_context(queryset_all, request, daterange_list): | ||
324 | # calculate the exact begining of local today and yesterday | ||
325 | today_begin = timezone.localtime(timezone.now()) | ||
326 | today_begin = date(today_begin.year,today_begin.month,today_begin.day) | ||
327 | yesterday_begin = today_begin-timedelta(days=1) | ||
328 | # add daterange persistent | ||
329 | context_date = {} | ||
330 | context_date['last_date_from'] = request.GET.get('last_date_from',timezone.localtime(timezone.now()).strftime("%d/%m/%Y")) | ||
331 | context_date['last_date_to' ] = request.GET.get('last_date_to' ,context_date['last_date_from']) | ||
332 | # calculate the date ranges, avoid second sort for 'created' | ||
333 | # fetch the respective max range from the database | ||
334 | context_date['daterange_filter']='' | ||
335 | for key in daterange_list: | ||
336 | queryset_key = queryset_all.order_by(key) | ||
337 | context_date['dateMin_'+key]=timezone.localtime(getattr(queryset_key.first(),key)).strftime("%d/%m/%Y") | ||
338 | context_date['dateMax_'+key]=timezone.localtime(getattr(queryset_key.last(),key)).strftime("%d/%m/%Y") | ||
339 | return context_date,today_begin,yesterday_begin | ||
340 | |||
282 | 341 | ||
283 | ## | 342 | ## |
284 | # build dashboard for a single build, coming in as argument | 343 | # build dashboard for a single build, coming in as argument |
@@ -1868,6 +1927,9 @@ if toastermain.settings.MANAGED: | |||
1868 | # boilerplate code that takes a request for an object type and returns a queryset | 1927 | # boilerplate code that takes a request for an object type and returns a queryset |
1869 | # for that object type. copypasta for all needed table searches | 1928 | # for that object type. copypasta for all needed table searches |
1870 | (filter_string, search_term, ordering_string) = _search_tuple(request, BuildRequest) | 1929 | (filter_string, search_term, ordering_string) = _search_tuple(request, BuildRequest) |
1930 | # post-process any date range filters | ||
1931 | filter_string,daterange_selected = _modify_date_range_filter(filter_string) | ||
1932 | |||
1871 | # we don't display in-progress or deleted builds | 1933 | # we don't display in-progress or deleted builds |
1872 | queryset_all = buildrequests.exclude(state = BuildRequest.REQ_DELETED) | 1934 | queryset_all = buildrequests.exclude(state = BuildRequest.REQ_DELETED) |
1873 | queryset_all = queryset_all.select_related("build", "build__project").annotate(Count('brerror')) | 1935 | queryset_all = queryset_all.select_related("build", "build__project").annotate(Count('brerror')) |
@@ -1918,6 +1980,7 @@ if toastermain.settings.MANAGED: | |||
1918 | 'fstypes' : fstypes_map, | 1980 | 'fstypes' : fstypes_map, |
1919 | 'search_term' : search_term, | 1981 | 'search_term' : search_term, |
1920 | 'total_count' : queryset_with_search.count(), | 1982 | 'total_count' : queryset_with_search.count(), |
1983 | 'daterange_selected' : daterange_selected, | ||
1921 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns | 1984 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns |
1922 | 'tablecols' : [ | 1985 | 'tablecols' : [ |
1923 | {'name': 'Outcome', # column with a single filter | 1986 | {'name': 'Outcome', # column with a single filter |
@@ -1956,6 +2019,10 @@ if toastermain.settings.MANAGED: | |||
1956 | } | 2019 | } |
1957 | ) | 2020 | ) |
1958 | 2021 | ||
2022 | # calculate the exact begining of local today and yesterday | ||
2023 | context_date,today_begin,yesterday_begin = _add_daterange_context(queryset_all, request, {'created','updated'}) | ||
2024 | context.update(context_date) | ||
2025 | |||
1959 | context['tablecols'].append( | 2026 | context['tablecols'].append( |
1960 | {'name': 'Started on', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column | 2027 | {'name': 'Started on', 'clclass': 'started_on', 'hidden' : 1, # this is an unchecked box, which hides the column |
1961 | 'qhelp': "The date and time you started the build", | 2028 | 'qhelp': "The date and time you started the build", |
@@ -1964,9 +2031,16 @@ if toastermain.settings.MANAGED: | |||
1964 | 'filter' : {'class' : 'created', | 2031 | 'filter' : {'class' : 'created', |
1965 | 'label': 'Show:', | 2032 | 'label': 'Show:', |
1966 | 'options' : [ | 2033 | 'options' : [ |
1967 | ("Today's builds" , 'created__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_all.filter(created__gte=timezone.now()).count()), | 2034 | ("Today's builds" , 'created__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(created__gte=today_begin).count()), |
1968 | ("Yesterday's builds", 'created__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_all.filter(created__gte=(timezone.now()-timedelta(hours=24))).count()), | 2035 | ("Yesterday's builds", |
1969 | ("This week's builds", 'created__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_all.filter(created__gte=(timezone.now()-timedelta(days=7))).count()), | 2036 | 'created__gte!created__lt:' |
2037 | +yesterday_begin.strftime("%Y-%m-%d")+'!' | ||
2038 | +today_begin.strftime("%Y-%m-%d"), | ||
2039 | queryset_all.filter( | ||
2040 | created__gte=yesterday_begin, | ||
2041 | created__lt=today_begin | ||
2042 | ).count()), | ||
2043 | ("Build date range", 'daterange', 1, '', 'created'), | ||
1970 | ] | 2044 | ] |
1971 | } | 2045 | } |
1972 | } | 2046 | } |
@@ -1980,9 +2054,16 @@ if toastermain.settings.MANAGED: | |||
1980 | 'filter' : {'class' : 'updated', | 2054 | 'filter' : {'class' : 'updated', |
1981 | 'label': 'Show:', | 2055 | 'label': 'Show:', |
1982 | 'options' : [ | 2056 | 'options' : [ |
1983 | ("Today's builds", 'updated__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=timezone.now()).count()), | 2057 | ("Today's builds" , 'updated__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=today_begin).count()), |
1984 | ("Yesterday's builds", 'updated__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=(timezone.now()-timedelta(hours=24))).count()), | 2058 | ("Yesterday's builds", |
1985 | ("This week's builds", 'updated__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_all.filter(updated__gte=(timezone.now()-timedelta(days=7))).count()), | 2059 | 'updated__gte!updated__lt:' |
2060 | +yesterday_begin.strftime("%Y-%m-%d")+'!' | ||
2061 | +today_begin.strftime("%Y-%m-%d"), | ||
2062 | queryset_all.filter( | ||
2063 | updated__gte=yesterday_begin, | ||
2064 | updated__lt=today_begin | ||
2065 | ).count()), | ||
2066 | ("Build date range", 'daterange', 1, '', 'updated'), | ||
1986 | ] | 2067 | ] |
1987 | } | 2068 | } |
1988 | } | 2069 | } |
@@ -3280,6 +3361,8 @@ else: | |||
3280 | # boilerplate code that takes a request for an object type and returns a queryset | 3361 | # boilerplate code that takes a request for an object type and returns a queryset |
3281 | # for that object type. copypasta for all needed table searches | 3362 | # for that object type. copypasta for all needed table searches |
3282 | (filter_string, search_term, ordering_string) = _search_tuple(request, Build) | 3363 | (filter_string, search_term, ordering_string) = _search_tuple(request, Build) |
3364 | # post-process any date range filters | ||
3365 | filter_string,daterange_selected = _modify_date_range_filter(filter_string) | ||
3283 | queryset_all = Build.objects.exclude(outcome = Build.IN_PROGRESS) | 3366 | queryset_all = Build.objects.exclude(outcome = Build.IN_PROGRESS) |
3284 | queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on') | 3367 | queryset_with_search = _get_queryset(Build, queryset_all, None, search_term, ordering_string, '-completed_on') |
3285 | queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on') | 3368 | queryset = _get_queryset(Build, queryset_all, filter_string, search_term, ordering_string, '-completed_on') |
@@ -3290,6 +3373,9 @@ else: | |||
3290 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | 3373 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) |
3291 | build_mru = Build.objects.order_by("-started_on")[:3] | 3374 | build_mru = Build.objects.order_by("-started_on")[:3] |
3292 | 3375 | ||
3376 | # calculate the exact begining of local today and yesterday, append context | ||
3377 | context_date,today_begin,yesterday_begin = _add_daterange_context(queryset_all, request, {'started_on','completed_on'}) | ||
3378 | |||
3293 | # set up list of fstypes for each build | 3379 | # set up list of fstypes for each build |
3294 | fstypes_map = {}; | 3380 | fstypes_map = {}; |
3295 | for build in build_info: | 3381 | for build in build_info: |
@@ -3320,6 +3406,7 @@ else: | |||
3320 | 'fstypes' : fstypes_map, | 3406 | 'fstypes' : fstypes_map, |
3321 | 'search_term' : search_term, | 3407 | 'search_term' : search_term, |
3322 | 'total_count' : queryset_with_search.count(), | 3408 | 'total_count' : queryset_with_search.count(), |
3409 | 'daterange_selected' : daterange_selected, | ||
3323 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns | 3410 | # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns |
3324 | 'tablecols' : [ | 3411 | 'tablecols' : [ |
3325 | {'name': 'Outcome', # column with a single filter | 3412 | {'name': 'Outcome', # column with a single filter |
@@ -3356,12 +3443,19 @@ else: | |||
3356 | 'filter' : {'class' : 'started_on', | 3443 | 'filter' : {'class' : 'started_on', |
3357 | 'label': 'Show:', | 3444 | 'label': 'Show:', |
3358 | 'options' : [ | 3445 | 'options' : [ |
3359 | ("Today's builds" , 'started_on__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_with_search.filter(started_on__gte=timezone.now()).count()), | 3446 | ("Today's builds" , 'started_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(started_on__gte=today_begin).count()), |
3360 | ("Yesterday's builds", 'started_on__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_with_search.filter(started_on__gte=(timezone.now()-timedelta(hours=24))).count()), | 3447 | ("Yesterday's builds", |
3361 | ("This week's builds", 'started_on__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_with_search.filter(started_on__gte=(timezone.now()-timedelta(days=7))).count()), | 3448 | 'started_on__gte!started_on__lt:' |
3449 | +yesterday_begin.strftime("%Y-%m-%d")+'!' | ||
3450 | +today_begin.strftime("%Y-%m-%d"), | ||
3451 | queryset_all.filter( | ||
3452 | started_on__gte=yesterday_begin, | ||
3453 | started_on__lt=today_begin | ||
3454 | ).count()), | ||
3455 | ("Build date range", 'daterange', 1, '', 'started_on'), | ||
3362 | ] | 3456 | ] |
3363 | } | 3457 | } |
3364 | }, | 3458 | }, |
3365 | {'name': 'Completed on', | 3459 | {'name': 'Completed on', |
3366 | 'qhelp': "The date and time the build finished", | 3460 | 'qhelp': "The date and time the build finished", |
3367 | 'orderfield': _get_toggle_order(request, "completed_on", True), | 3461 | 'orderfield': _get_toggle_order(request, "completed_on", True), |
@@ -3370,9 +3464,16 @@ else: | |||
3370 | 'filter' : {'class' : 'completed_on', | 3464 | 'filter' : {'class' : 'completed_on', |
3371 | 'label': 'Show:', | 3465 | 'label': 'Show:', |
3372 | 'options' : [ | 3466 | 'options' : [ |
3373 | ("Today's builds", 'completed_on__gte:'+timezone.now().strftime("%Y-%m-%d"), queryset_with_search.filter(completed_on__gte=timezone.now()).count()), | 3467 | ("Today's builds" , 'completed_on__gte:'+today_begin.strftime("%Y-%m-%d"), queryset_all.filter(completed_on__gte=today_begin).count()), |
3374 | ("Yesterday's builds", 'completed_on__gte:'+(timezone.now()-timedelta(hours=24)).strftime("%Y-%m-%d"), queryset_with_search.filter(completed_on__gte=(timezone.now()-timedelta(hours=24))).count()), | 3468 | ("Yesterday's builds", |
3375 | ("This week's builds", 'completed_on__gte:'+(timezone.now()-timedelta(days=7)).strftime("%Y-%m-%d"), queryset_with_search.filter(completed_on__gte=(timezone.now()-timedelta(days=7))).count()), | 3469 | 'completed_on__gte!completed_on__lt:' |
3470 | +yesterday_begin.strftime("%Y-%m-%d")+'!' | ||
3471 | +today_begin.strftime("%Y-%m-%d"), | ||
3472 | queryset_all.filter( | ||
3473 | completed_on__gte=yesterday_begin, | ||
3474 | completed_on__lt=today_begin | ||
3475 | ).count()), | ||
3476 | ("Build date range", 'daterange', 1, '', 'completed_on'), | ||
3376 | ] | 3477 | ] |
3377 | } | 3478 | } |
3378 | }, | 3479 | }, |
@@ -3433,6 +3534,9 @@ else: | |||
3433 | ] | 3534 | ] |
3434 | } | 3535 | } |
3435 | 3536 | ||
3537 | # merge daterange values | ||
3538 | context.update(context_date) | ||
3539 | |||
3436 | response = render(request, template, context) | 3540 | response = render(request, template, context) |
3437 | _save_parameters_cookies(response, pagesize, orderby, request) | 3541 | _save_parameters_cookies(response, pagesize, orderby, request) |
3438 | return response | 3542 | return response |