mirror of
https://git.yoctoproject.org/poky
synced 2026-05-30 00:20:08 +00:00
bitbake: toastergui: implement date range filters for builds
Implement the completed_on and started_on filtering for
builds.
Also separate the name of a filter ("filter" in the querystring)
from its value ("filter_value" in the querystring). This enables
filtering to be defined in the querystring more intuitively,
and also makes it easier to add other types of filter (e.g.
by day).
[YOCTO #8738]
(Bitbake rev: d47c32e88c2d4a423f4d94d49759e557f425a539)
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
b929889cdd
commit
f8d383d87f
@@ -2,10 +2,11 @@ class QuerysetFilter(object):
|
|||||||
""" Filter for a queryset """
|
""" Filter for a queryset """
|
||||||
|
|
||||||
def __init__(self, criteria=None):
|
def __init__(self, criteria=None):
|
||||||
|
self.criteria = None
|
||||||
if criteria:
|
if criteria:
|
||||||
self.set_criteria(criteria)
|
self.set_criteria(criteria)
|
||||||
|
|
||||||
def set_criteria(self, criteria = None):
|
def set_criteria(self, criteria):
|
||||||
"""
|
"""
|
||||||
criteria is an instance of django.db.models.Q;
|
criteria is an instance of django.db.models.Q;
|
||||||
see https://docs.djangoproject.com/en/1.9/ref/models/querysets/#q-objects
|
see https://docs.djangoproject.com/en/1.9/ref/models/querysets/#q-objects
|
||||||
|
|||||||
@@ -397,11 +397,140 @@ function tableInit(ctx){
|
|||||||
$.cookie("cols", JSON.stringify(disabled_cols));
|
$.cookie("cols", JSON.stringify(disabled_cols));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the DOM/JS for the client side of a TableFilterActionToggle
|
||||||
|
*
|
||||||
|
* filterName: (string) internal name for the filter action
|
||||||
|
* filterActionData: (object)
|
||||||
|
* filterActionData.count: (number) The number of items this filter will
|
||||||
|
* show when selected
|
||||||
|
*/
|
||||||
|
function createActionToggle(filterName, filterActionData) {
|
||||||
|
var actionStr = '<div class="radio">' +
|
||||||
|
'<input type="radio" name="filter"' +
|
||||||
|
' value="' + filterName + '"';
|
||||||
|
|
||||||
|
if (Number(filterActionData.count) == 0) {
|
||||||
|
actionStr += ' disabled="disabled"';
|
||||||
|
}
|
||||||
|
|
||||||
|
actionStr += ' id="' + filterName + '">' +
|
||||||
|
'<input type="hidden" name="filter_value" value="on"' +
|
||||||
|
' data-value-for="' + filterName + '">' +
|
||||||
|
'<label class="filter-title"' +
|
||||||
|
' for="' + filterName + '">' +
|
||||||
|
filterActionData.title +
|
||||||
|
' (' + filterActionData.count + ')' +
|
||||||
|
'</label>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
return $(actionStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the DOM/JS for the client side of a TableFilterActionDateRange
|
||||||
|
*
|
||||||
|
* filterName: (string) internal name for the filter action
|
||||||
|
* filterValue: (string) from,to date range in format yyyy-mm-dd,yyyy-mm-dd;
|
||||||
|
* used to select the current values for the from/to datepickers;
|
||||||
|
* if this is partial (e.g. "yyyy-mm-dd,") only the applicable datepicker
|
||||||
|
* will have a date pre-selected; if empty, neither will
|
||||||
|
* filterActionData: (object) data for generating the action's HTML
|
||||||
|
* filterActionData.title: label for the radio button
|
||||||
|
* filterActionData.max: (string) maximum date for the pickers, in ISO 8601
|
||||||
|
* datetime format
|
||||||
|
* filterActionData.min: (string) minimum date for the pickers, ISO 8601
|
||||||
|
* datetime
|
||||||
|
*/
|
||||||
|
function createActionDateRange(filterName, filterValue, filterActionData) {
|
||||||
|
var action = $('<div class="radio">' +
|
||||||
|
'<input type="radio" name="filter"' +
|
||||||
|
' value="' + filterName + '" ' +
|
||||||
|
' id="' + filterName + '">' +
|
||||||
|
'<input type="hidden" name="filter_value" value=""' +
|
||||||
|
' data-value-for="' + filterName + '">' +
|
||||||
|
'<label class="filter-title"' +
|
||||||
|
' for="' + filterName + '">' +
|
||||||
|
filterActionData.title +
|
||||||
|
'</label>' +
|
||||||
|
'<input type="text" maxlength="10" class="input-small"' +
|
||||||
|
' data-date-from-for="' + filterName + '">' +
|
||||||
|
'<span class="help-inline">to</span>' +
|
||||||
|
'<input type="text" maxlength="10" class="input-small"' +
|
||||||
|
' data-date-to-for="' + filterName + '">' +
|
||||||
|
'<span class="help-inline get-help">(yyyy-mm-dd)</span>' +
|
||||||
|
'</div>');
|
||||||
|
|
||||||
|
var radio = action.find('[type="radio"]');
|
||||||
|
var value = action.find('[data-value-for]');
|
||||||
|
|
||||||
|
// make the datepickers for the range
|
||||||
|
var options = {
|
||||||
|
dateFormat: 'yy-mm-dd',
|
||||||
|
maxDate: new Date(filterActionData.max),
|
||||||
|
minDate: new Date(filterActionData.min)
|
||||||
|
};
|
||||||
|
|
||||||
|
// create date pickers, setting currently-selected from and to
|
||||||
|
// dates
|
||||||
|
var selectedFrom = null;
|
||||||
|
var selectedTo = null;
|
||||||
|
|
||||||
|
var selectedFromAndTo = [];
|
||||||
|
if (filterValue) {
|
||||||
|
selectedFromAndTo = filterValue.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedFromAndTo.length == 2) {
|
||||||
|
selectedFrom = selectedFromAndTo[0];
|
||||||
|
selectedTo = selectedFromAndTo[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
options.defaultDate = selectedFrom;
|
||||||
|
var inputFrom =
|
||||||
|
action.find('[data-date-from-for]').datepicker(options);
|
||||||
|
inputFrom.val(selectedFrom);
|
||||||
|
|
||||||
|
options.defaultDate = selectedTo;
|
||||||
|
var inputTo =
|
||||||
|
action.find('[data-date-to-for]').datepicker(options);
|
||||||
|
inputTo.val(selectedTo);
|
||||||
|
|
||||||
|
// set filter_value based on date pickers when
|
||||||
|
// one of their values changes
|
||||||
|
var changeHandler = function () {
|
||||||
|
value.val(inputFrom.val() + ',' + inputTo.val());
|
||||||
|
};
|
||||||
|
|
||||||
|
inputFrom.change(changeHandler);
|
||||||
|
inputTo.change(changeHandler);
|
||||||
|
|
||||||
|
// check the associated radio button on clicking a date picker
|
||||||
|
var checkRadio = function () {
|
||||||
|
radio.prop('checked', 'checked');
|
||||||
|
};
|
||||||
|
|
||||||
|
inputFrom.focus(checkRadio);
|
||||||
|
inputTo.focus(checkRadio);
|
||||||
|
|
||||||
|
// selecting a date in a picker constrains the date you can
|
||||||
|
// set in the other picker
|
||||||
|
inputFrom.change(function () {
|
||||||
|
inputTo.datepicker('option', 'minDate', inputFrom.val());
|
||||||
|
});
|
||||||
|
|
||||||
|
inputTo.change(function () {
|
||||||
|
inputFrom.datepicker('option', 'maxDate', inputTo.val());
|
||||||
|
});
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
function filterOpenClicked(){
|
function filterOpenClicked(){
|
||||||
var filterName = $(this).data('filter-name');
|
var filterName = $(this).data('filter-name');
|
||||||
|
|
||||||
/* We need to pass in the curren search so that the filter counts take
|
/* We need to pass in the current search so that the filter counts take
|
||||||
* into account the current search filter
|
* into account the current search term
|
||||||
*/
|
*/
|
||||||
var params = {
|
var params = {
|
||||||
'name' : filterName,
|
'name' : filterName,
|
||||||
@@ -443,46 +572,44 @@ function tableInit(ctx){
|
|||||||
when the filter popup's "Apply" button is clicked, the
|
when the filter popup's "Apply" button is clicked, the
|
||||||
value for the radio button which is checked is passed in the
|
value for the radio button which is checked is passed in the
|
||||||
querystring and applied to the queryset on the table
|
querystring and applied to the queryset on the table
|
||||||
*/
|
*/
|
||||||
|
var filterActionRadios = $('#filter-actions-' + ctx.tableName);
|
||||||
|
|
||||||
var filterActionRadios = $('#filter-actions-'+ctx.tableName);
|
$('#filter-modal-title-' + ctx.tableName).text(filterData.title);
|
||||||
|
|
||||||
$('#filter-modal-title-'+ctx.tableName).text(filterData.title);
|
filterActionRadios.empty();
|
||||||
|
|
||||||
filterActionRadios.text("");
|
|
||||||
|
|
||||||
|
// create a radio button + form elements for each action associated
|
||||||
|
// with the filter on this column of the table
|
||||||
for (var i in filterData.filter_actions) {
|
for (var i in filterData.filter_actions) {
|
||||||
var filterAction = filterData.filter_actions[i];
|
|
||||||
var action = null;
|
var action = null;
|
||||||
|
var filterActionData = filterData.filter_actions[i];
|
||||||
|
var filterName = filterData.name + ':' +
|
||||||
|
filterActionData.action_name;
|
||||||
|
|
||||||
if (filterAction.type === 'toggle') {
|
if (filterActionData.type === 'toggle') {
|
||||||
var actionTitle = filterAction.title + ' (' + filterAction.count + ')';
|
action = createActionToggle(filterName, filterActionData);
|
||||||
|
}
|
||||||
|
else if (filterActionData.type === 'daterange') {
|
||||||
|
var filterValue = tableParams.filter_value;
|
||||||
|
|
||||||
action = $('<label class="radio">' +
|
action = createActionDateRange(
|
||||||
'<input type="radio" name="filter" value="">' +
|
filterName,
|
||||||
'<span class="filter-title">' +
|
filterValue,
|
||||||
actionTitle +
|
filterActionData
|
||||||
'</span>' +
|
);
|
||||||
'</label>');
|
|
||||||
|
|
||||||
var radioInput = action.children("input");
|
|
||||||
if (Number(filterAction.count) == 0) {
|
|
||||||
radioInput.attr("disabled", "disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
radioInput.val(filterData.name + ':' + filterAction.action_name);
|
|
||||||
|
|
||||||
/* Setup the current selected filter, default to 'all' if
|
|
||||||
* no current filter selected.
|
|
||||||
*/
|
|
||||||
if ((tableParams.filter &&
|
|
||||||
tableParams.filter === radioInput.val()) ||
|
|
||||||
filterAction.action_name == 'all') {
|
|
||||||
radioInput.attr("checked", "checked");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action) {
|
if (action) {
|
||||||
|
// Setup the current selected filter, default to 'all' if
|
||||||
|
// no current filter selected
|
||||||
|
var radioInput = action.children('input[name="filter"]');
|
||||||
|
if ((tableParams.filter &&
|
||||||
|
tableParams.filter === radioInput.val()) ||
|
||||||
|
filterActionData.action_name == 'all') {
|
||||||
|
radioInput.attr("checked", "checked");
|
||||||
|
}
|
||||||
|
|
||||||
filterActionRadios.append(action);
|
filterActionRadios.append(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -571,7 +698,14 @@ function tableInit(ctx){
|
|||||||
filterBtnActive($(filterBtn), false);
|
filterBtnActive($(filterBtn), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
tableParams.filter = $(this).find("input[type='radio']:checked").val();
|
// checked radio button
|
||||||
|
var checkedFilter = $(this).find("input[name='filter']:checked");
|
||||||
|
tableParams.filter = checkedFilter.val();
|
||||||
|
|
||||||
|
// hidden field holding the value for the checked filter
|
||||||
|
var checkedFilterValue = $(this).find("input[data-value-for='" +
|
||||||
|
tableParams.filter + "']");
|
||||||
|
tableParams.filter_value = checkedFilterValue.val();
|
||||||
|
|
||||||
var filterBtn = $("#" + tableParams.filter.split(":")[0]);
|
var filterBtn = $("#" + tableParams.filter.split(":")[0]);
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,15 @@
|
|||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
from django.db.models import Q, Max, Min
|
||||||
|
from django.utils import dateparse, timezone
|
||||||
|
|
||||||
class TableFilter(object):
|
class TableFilter(object):
|
||||||
"""
|
"""
|
||||||
Stores a filter for a named field, and can retrieve the action
|
Stores a filter for a named field, and can retrieve the action
|
||||||
requested for that filter
|
requested from the set of actions for that filter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, title):
|
def __init__(self, name, title):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.title = title
|
self.title = title
|
||||||
@@ -64,42 +67,128 @@ class TableFilter(object):
|
|||||||
'filter_actions': filter_actions
|
'filter_actions': filter_actions
|
||||||
}
|
}
|
||||||
|
|
||||||
class TableFilterActionToggle(object):
|
class TableFilterAction(object):
|
||||||
"""
|
"""
|
||||||
Stores a single filter action which will populate one radio button of
|
A filter action which displays in the filter popup for a ToasterTable
|
||||||
a ToasterTable filter popup; this filter can either be on or off and
|
and uses an associated QuerysetFilter to filter the queryset for that
|
||||||
has no other parameters
|
ToasterTable
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, title, queryset_filter):
|
def __init__(self, name, title, queryset_filter):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.title = title
|
self.title = title
|
||||||
self.__queryset_filter = queryset_filter
|
self.queryset_filter = queryset_filter
|
||||||
self.type = 'toggle'
|
|
||||||
|
|
||||||
def set_params(self, params):
|
# set in subclasses
|
||||||
|
self.type = None
|
||||||
|
|
||||||
|
def set_filter_params(self, params):
|
||||||
"""
|
"""
|
||||||
params: (str) a string of extra parameters for the action;
|
params: (str) a string of extra parameters for the action;
|
||||||
the structure of this string depends on the type of action;
|
the structure of this string depends on the type of action;
|
||||||
it's ignored for a toggle filter action, which is just on or off
|
it's ignored for a toggle filter action, which is just on or off
|
||||||
"""
|
"""
|
||||||
pass
|
if not params:
|
||||||
|
return
|
||||||
|
|
||||||
def filter(self, queryset):
|
def filter(self, queryset):
|
||||||
return self.__queryset_filter.filter(queryset)
|
return self.queryset_filter.filter(queryset)
|
||||||
|
|
||||||
def to_json(self, queryset):
|
def to_json(self, queryset):
|
||||||
""" Dump as a JSON object """
|
""" Dump as a JSON object """
|
||||||
return {
|
return {
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'type': self.type,
|
'type': self.type,
|
||||||
'count': self.__queryset_filter.count(queryset)
|
'count': self.queryset_filter.count(queryset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TableFilterActionToggle(TableFilterAction):
|
||||||
|
"""
|
||||||
|
A single filter action which will populate one radio button of
|
||||||
|
a ToasterTable filter popup; this filter can either be on or off and
|
||||||
|
has no other parameters
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
super(TableFilterActionToggle, self).__init__(*args)
|
||||||
|
self.type = 'toggle'
|
||||||
|
|
||||||
|
class TableFilterActionDateRange(TableFilterAction):
|
||||||
|
"""
|
||||||
|
A filter action which will filter the queryset by a date range.
|
||||||
|
The date range can be set via set_params()
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, title, field, queryset_filter):
|
||||||
|
"""
|
||||||
|
field: the field to find the max/min range from in the queryset
|
||||||
|
"""
|
||||||
|
super(TableFilterActionDateRange, self).__init__(
|
||||||
|
name,
|
||||||
|
title,
|
||||||
|
queryset_filter
|
||||||
|
)
|
||||||
|
|
||||||
|
self.type = 'daterange'
|
||||||
|
self.field = field
|
||||||
|
|
||||||
|
def set_filter_params(self, params):
|
||||||
|
"""
|
||||||
|
params: (str) a string of extra parameters for the filtering
|
||||||
|
in the format "2015-12-09,2015-12-11" (from,to); this is passed in the
|
||||||
|
querystring and used to set the criteria on the QuerysetFilter
|
||||||
|
associated with this action
|
||||||
|
"""
|
||||||
|
|
||||||
|
# if params are invalid, return immediately, resetting criteria
|
||||||
|
# on the QuerysetFilter
|
||||||
|
try:
|
||||||
|
from_date_str, to_date_str = params.split(',')
|
||||||
|
except ValueError:
|
||||||
|
self.queryset_filter.set_criteria(None)
|
||||||
|
return
|
||||||
|
|
||||||
|
# one of the values required for the filter is missing, so set
|
||||||
|
# it to the one which was supplied
|
||||||
|
if from_date_str == '':
|
||||||
|
from_date_str = to_date_str
|
||||||
|
elif to_date_str == '':
|
||||||
|
to_date_str = from_date_str
|
||||||
|
|
||||||
|
date_from_naive = dateparse.parse_datetime(from_date_str + ' 00:00:00')
|
||||||
|
date_to_naive = dateparse.parse_datetime(to_date_str + ' 23:59:59')
|
||||||
|
|
||||||
|
tz = timezone.get_default_timezone()
|
||||||
|
date_from = timezone.make_aware(date_from_naive, tz)
|
||||||
|
date_to = timezone.make_aware(date_to_naive, tz)
|
||||||
|
|
||||||
|
args = {}
|
||||||
|
args[self.field + '__gte'] = date_from
|
||||||
|
args[self.field + '__lte'] = date_to
|
||||||
|
|
||||||
|
criteria = Q(**args)
|
||||||
|
self.queryset_filter.set_criteria(criteria)
|
||||||
|
|
||||||
|
def to_json(self, queryset):
|
||||||
|
""" Dump as a JSON object """
|
||||||
|
data = super(TableFilterActionDateRange, self).to_json(queryset)
|
||||||
|
|
||||||
|
# additional data about the date range covered by the queryset's
|
||||||
|
# records, retrieved from its <field> column
|
||||||
|
data['min'] = queryset.aggregate(Min(self.field))[self.field + '__min']
|
||||||
|
data['max'] = queryset.aggregate(Max(self.field))[self.field + '__max']
|
||||||
|
|
||||||
|
# a range filter has a count of None, as the number of records it
|
||||||
|
# will select depends on the date range entered
|
||||||
|
data['count'] = None
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
class TableFilterMap(object):
|
class TableFilterMap(object):
|
||||||
"""
|
"""
|
||||||
Map from field names to Filter objects for those fields
|
Map from field names to TableFilter objects for those fields
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__filters = {}
|
self.__filters = {}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ from django.core.urlresolvers import reverse
|
|||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from toastergui.tablefilter import TableFilter, TableFilterActionToggle
|
from toastergui.tablefilter import TableFilter
|
||||||
|
from toastergui.tablefilter import TableFilterActionToggle
|
||||||
|
from toastergui.tablefilter import TableFilterActionDateRange
|
||||||
|
|
||||||
class ProjectFilters(object):
|
class ProjectFilters(object):
|
||||||
def __init__(self, project_layers):
|
def __init__(self, project_layers):
|
||||||
@@ -1070,6 +1072,7 @@ class BuildsTable(ToasterTable):
|
|||||||
help_text='The date and time when the build started',
|
help_text='The date and time when the build started',
|
||||||
hideable=True,
|
hideable=True,
|
||||||
orderable=True,
|
orderable=True,
|
||||||
|
filter_name='started_on_filter',
|
||||||
static_data_name='started_on',
|
static_data_name='started_on',
|
||||||
static_data_template=started_on_template)
|
static_data_template=started_on_template)
|
||||||
|
|
||||||
@@ -1077,6 +1080,7 @@ class BuildsTable(ToasterTable):
|
|||||||
help_text='The date and time when the build finished',
|
help_text='The date and time when the build finished',
|
||||||
hideable=False,
|
hideable=False,
|
||||||
orderable=True,
|
orderable=True,
|
||||||
|
filter_name='completed_on_filter',
|
||||||
static_data_name='completed_on',
|
static_data_name='completed_on',
|
||||||
static_data_template=completed_on_template)
|
static_data_template=completed_on_template)
|
||||||
|
|
||||||
@@ -1149,6 +1153,38 @@ class BuildsTable(ToasterTable):
|
|||||||
outcome_filter.add_action(failed_builds_filter_action)
|
outcome_filter.add_action(failed_builds_filter_action)
|
||||||
self.add_filter(outcome_filter)
|
self.add_filter(outcome_filter)
|
||||||
|
|
||||||
|
# started on
|
||||||
|
started_on_filter = TableFilter(
|
||||||
|
'started_on_filter',
|
||||||
|
'Filter by date when build was started'
|
||||||
|
)
|
||||||
|
|
||||||
|
by_started_date_range_filter_action = TableFilterActionDateRange(
|
||||||
|
'date_range',
|
||||||
|
'Build date range',
|
||||||
|
'started_on',
|
||||||
|
QuerysetFilter()
|
||||||
|
)
|
||||||
|
|
||||||
|
started_on_filter.add_action(by_started_date_range_filter_action)
|
||||||
|
self.add_filter(started_on_filter)
|
||||||
|
|
||||||
|
# completed on
|
||||||
|
completed_on_filter = TableFilter(
|
||||||
|
'completed_on_filter',
|
||||||
|
'Filter by date when build was completed'
|
||||||
|
)
|
||||||
|
|
||||||
|
by_completed_date_range_filter_action = TableFilterActionDateRange(
|
||||||
|
'date_range',
|
||||||
|
'Build date range',
|
||||||
|
'completed_on',
|
||||||
|
QuerysetFilter()
|
||||||
|
)
|
||||||
|
|
||||||
|
completed_on_filter.add_action(by_completed_date_range_filter_action)
|
||||||
|
self.add_filter(completed_on_filter)
|
||||||
|
|
||||||
# failed tasks
|
# failed tasks
|
||||||
failed_tasks_filter = TableFilter(
|
failed_tasks_filter = TableFilter(
|
||||||
'failed_tasks_filter',
|
'failed_tasks_filter',
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block extraheadcontent %}
|
||||||
|
<link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'>
|
||||||
|
<link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'>
|
||||||
|
<link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'>
|
||||||
|
<script src="{% static 'js/jquery-ui.min.js' %}">
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %} All builds - Toaster {% endblock %}
|
{% block title %} All builds - Toaster {% endblock %}
|
||||||
|
|
||||||
@@ -34,29 +43,6 @@
|
|||||||
|
|
||||||
titleElt.text(title);
|
titleElt.text(title);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* {% if last_date_from and last_date_to %}
|
|
||||||
// TODO initialize the date range controls;
|
|
||||||
// this will need to be added via ToasterTable
|
|
||||||
date_init(
|
|
||||||
"started_on",
|
|
||||||
"{{last_date_from}}",
|
|
||||||
"{{last_date_to}}",
|
|
||||||
"{{dateMin_started_on}}",
|
|
||||||
"{{dateMax_started_on}}",
|
|
||||||
"{{daterange_selected}}"
|
|
||||||
);
|
|
||||||
|
|
||||||
date_init(
|
|
||||||
"completed_on",
|
|
||||||
"{{last_date_from}}",
|
|
||||||
"{{last_date_to}}",
|
|
||||||
"{{dateMin_completed_on}}",
|
|
||||||
"{{dateMax_completed_on}}",
|
|
||||||
"{{daterange_selected}}"
|
|
||||||
);
|
|
||||||
{% endif %}
|
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -183,13 +183,13 @@ class ToasterTable(TemplateView):
|
|||||||
|
|
||||||
return template.render(context)
|
return template.render(context)
|
||||||
|
|
||||||
def apply_filter(self, filters, **kwargs):
|
def apply_filter(self, filters, filter_value, **kwargs):
|
||||||
"""
|
"""
|
||||||
Apply a filter submitted in the querystring to the ToasterTable
|
Apply a filter submitted in the querystring to the ToasterTable
|
||||||
|
|
||||||
filters: (str) in the format:
|
filters: (str) in the format:
|
||||||
'<filter name>:<action name>!<action params>'
|
'<filter name>:<action name>'
|
||||||
where <action params> is optional
|
filter_value: (str) parameters to pass to the named filter
|
||||||
|
|
||||||
<filter name> and <action name> are used to look up the correct filter
|
<filter name> and <action name> are used to look up the correct filter
|
||||||
in the ToasterTable's filter map; the <action params> are set on
|
in the ToasterTable's filter map; the <action params> are set on
|
||||||
@@ -199,15 +199,8 @@ class ToasterTable(TemplateView):
|
|||||||
self.setup_filters(**kwargs)
|
self.setup_filters(**kwargs)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
filter_name, action_name_and_params = filters.split(':')
|
filter_name, action_name = filters.split(':')
|
||||||
|
action_params = urllib.unquote_plus(filter_value)
|
||||||
action_name = None
|
|
||||||
action_params = None
|
|
||||||
if re.search('!', action_name_and_params):
|
|
||||||
action_name, action_params = action_name_and_params.split('!')
|
|
||||||
action_params = urllib.unquote_plus(action_params)
|
|
||||||
else:
|
|
||||||
action_name = action_name_and_params
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -217,7 +210,7 @@ class ToasterTable(TemplateView):
|
|||||||
try:
|
try:
|
||||||
table_filter = self.filter_map.get_filter(filter_name)
|
table_filter = self.filter_map.get_filter(filter_name)
|
||||||
action = table_filter.get_action(action_name)
|
action = table_filter.get_action(action_name)
|
||||||
action.set_params(action_params)
|
action.set_filter_params(action_params)
|
||||||
self.queryset = action.filter(self.queryset)
|
self.queryset = action.filter(self.queryset)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# pass it to the user - programming error here
|
# pass it to the user - programming error here
|
||||||
@@ -247,13 +240,20 @@ class ToasterTable(TemplateView):
|
|||||||
|
|
||||||
|
|
||||||
def get_data(self, request, **kwargs):
|
def get_data(self, request, **kwargs):
|
||||||
"""Returns the data for the page requested with the specified
|
"""
|
||||||
parameters applied"""
|
Returns the data for the page requested with the specified
|
||||||
|
parameters applied
|
||||||
|
|
||||||
|
filters: filter and action name, e.g. "outcome:build_succeeded"
|
||||||
|
filter_value: value to pass to the named filter+action, e.g. "on"
|
||||||
|
(for a toggle filter) or "2015-12-11,2015-12-12" (for a date range filter)
|
||||||
|
"""
|
||||||
|
|
||||||
page_num = request.GET.get("page", 1)
|
page_num = request.GET.get("page", 1)
|
||||||
limit = request.GET.get("limit", 10)
|
limit = request.GET.get("limit", 10)
|
||||||
search = request.GET.get("search", None)
|
search = request.GET.get("search", None)
|
||||||
filters = request.GET.get("filter", None)
|
filters = request.GET.get("filter", None)
|
||||||
|
filter_value = request.GET.get("filter_value", "on")
|
||||||
orderby = request.GET.get("orderby", None)
|
orderby = request.GET.get("orderby", None)
|
||||||
nocache = request.GET.get("nocache", None)
|
nocache = request.GET.get("nocache", None)
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ class ToasterTable(TemplateView):
|
|||||||
if search:
|
if search:
|
||||||
self.apply_search(search)
|
self.apply_search(search)
|
||||||
if filters:
|
if filters:
|
||||||
self.apply_filter(filters, **kwargs)
|
self.apply_filter(filters, filter_value, **kwargs)
|
||||||
if orderby:
|
if orderby:
|
||||||
self.apply_orderby(orderby)
|
self.apply_orderby(orderby)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user