bitbake: toastergui: implement "today" and "yesterday" filters
Add the "today" and "yesterday" filters to the started_on and completed_on columns in the builds table. During this work, some minor adjustments were made to the behaviour of the builds table: * Amend filter action variable names so they're more succinct. * Retain order in which actions are added to a filter, as this ordering is used in the UI when displaying the filter actions. * Always show the table chrome, otherwise it's not possible to edit the columns shown until there are 10 or more results. * Because date range searches may return no results, make sure that the search bar and "show all results" link are visible when the query returns no results. [YOCTO #8738] (Bitbake rev: f17cfa009e58833e0e55884fa04de8abd522b6bc) 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:
parent
f8d383d87f
commit
33b011c158
|
@ -22,7 +22,3 @@ class QuerysetFilter(object):
|
|||
return queryset.filter(self.criteria)
|
||||
else:
|
||||
return queryset
|
||||
|
||||
def count(self, queryset):
|
||||
""" Returns a count of the elements in the filtered queryset """
|
||||
return self.filter(queryset).count()
|
||||
|
|
|
@ -71,22 +71,11 @@ function tableInit(ctx){
|
|||
|
||||
if (tableData.total === 0){
|
||||
tableContainer.hide();
|
||||
/* If we were searching show the new search bar and return */
|
||||
if (tableParams.search){
|
||||
$("#new-search-input-"+ctx.tableName).val(tableParams.search);
|
||||
$("#no-results-"+ctx.tableName).show();
|
||||
}
|
||||
$("#new-search-input-"+ctx.tableName).val(tableParams.search);
|
||||
$("#no-results-"+ctx.tableName).show();
|
||||
table.trigger("table-done", [tableData.total, tableParams]);
|
||||
|
||||
return;
|
||||
|
||||
/* We don't want to clutter the place with the table chrome if there
|
||||
* are only a few results */
|
||||
} else if (tableData.total <= 10 &&
|
||||
!tableParams.filter &&
|
||||
!tableParams.search){
|
||||
$("#table-chrome-"+ctx.tableName).hide();
|
||||
pagination.hide();
|
||||
} else {
|
||||
tableContainer.show();
|
||||
$("#no-results-"+ctx.tableName).hide();
|
||||
|
@ -399,13 +388,14 @@ function tableInit(ctx){
|
|||
|
||||
/**
|
||||
* Create the DOM/JS for the client side of a TableFilterActionToggle
|
||||
* or TableFilterActionDay
|
||||
*
|
||||
* 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) {
|
||||
function createActionRadio(filterName, filterActionData) {
|
||||
var actionStr = '<div class="radio">' +
|
||||
'<input type="radio" name="filter"' +
|
||||
' value="' + filterName + '"';
|
||||
|
@ -471,8 +461,7 @@ function tableInit(ctx){
|
|||
minDate: new Date(filterActionData.min)
|
||||
};
|
||||
|
||||
// create date pickers, setting currently-selected from and to
|
||||
// dates
|
||||
// create date pickers, setting currently-selected from and to dates
|
||||
var selectedFrom = null;
|
||||
var selectedTo = null;
|
||||
|
||||
|
@ -496,6 +485,20 @@ function tableInit(ctx){
|
|||
action.find('[data-date-to-for]').datepicker(options);
|
||||
inputTo.val(selectedTo);
|
||||
|
||||
// if the radio button is checked and one or both of the datepickers are
|
||||
// empty, populate them with today's date
|
||||
radio.change(function () {
|
||||
var now = new Date();
|
||||
|
||||
if (inputFrom.val() === '') {
|
||||
inputFrom.datepicker('setDate', now);
|
||||
}
|
||||
|
||||
if (inputTo.val() === '') {
|
||||
inputTo.datepicker('setDate', now);
|
||||
}
|
||||
});
|
||||
|
||||
// set filter_value based on date pickers when
|
||||
// one of their values changes
|
||||
var changeHandler = function () {
|
||||
|
@ -553,7 +556,8 @@ function tableInit(ctx){
|
|||
{
|
||||
title: '<label for radio button inside the popup>',
|
||||
name: '<name of the filter action>',
|
||||
count: <number of items this filter will show>
|
||||
count: <number of items this filter will show>,
|
||||
... additional data for the action ...
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -567,11 +571,12 @@ function tableInit(ctx){
|
|||
filter
|
||||
|
||||
the filterName is set on the column filter icon, and corresponds
|
||||
to a value in the table's filters property
|
||||
to a value in the table's filter map
|
||||
|
||||
when the filter popup's "Apply" button is clicked, the
|
||||
value for the radio button which is checked is passed in the
|
||||
querystring and applied to the queryset on the table
|
||||
querystring, along with a filter_value, and applied to the
|
||||
queryset on the table
|
||||
*/
|
||||
var filterActionRadios = $('#filter-actions-' + ctx.tableName);
|
||||
|
||||
|
@ -587,10 +592,12 @@ function tableInit(ctx){
|
|||
var filterName = filterData.name + ':' +
|
||||
filterActionData.action_name;
|
||||
|
||||
if (filterActionData.type === 'toggle') {
|
||||
action = createActionToggle(filterName, filterActionData);
|
||||
if (filterActionData.type === 'toggle' ||
|
||||
filterActionData.type === 'day') {
|
||||
action = createActionRadio(filterName, filterActionData);
|
||||
}
|
||||
else if (filterActionData.type === 'daterange') {
|
||||
// current values for the from/to dates
|
||||
var filterValue = tableParams.filter_value;
|
||||
|
||||
action = createActionDateRange(
|
||||
|
@ -601,7 +608,7 @@ function tableInit(ctx){
|
|||
}
|
||||
|
||||
if (action) {
|
||||
// Setup the current selected filter, default to 'all' if
|
||||
// Setup the current selected filter; default to 'all' if
|
||||
// no current filter selected
|
||||
var radioInput = action.children('input[name="filter"]');
|
||||
if ((tableParams.filter &&
|
||||
|
@ -707,13 +714,12 @@ function tableInit(ctx){
|
|||
tableParams.filter + "']");
|
||||
tableParams.filter_value = checkedFilterValue.val();
|
||||
|
||||
var filterBtn = $("#" + tableParams.filter.split(":")[0]);
|
||||
|
||||
/* All === remove filter */
|
||||
if (tableParams.filter.match(":all$")) {
|
||||
tableParams.filter = null;
|
||||
filterBtnActive(filterBtn, false);
|
||||
tableParams.filter_value = null;
|
||||
} else {
|
||||
var filterBtn = $("#" + tableParams.filter.split(":")[0]);
|
||||
filterBtnActive(filterBtn, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,18 @@
|
|||
# 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.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
from django.db.models import Q, Max, Min
|
||||
from django.utils import dateparse, timezone
|
||||
from datetime import timedelta
|
||||
from querysetfilter import QuerysetFilter
|
||||
|
||||
class TableFilter(object):
|
||||
"""
|
||||
Stores a filter for a named field, and can retrieve the action
|
||||
requested from the set of actions for that filter
|
||||
requested from the set of actions for that filter;
|
||||
the order in which actions are added governs the order in which they
|
||||
are returned in the JSON for the filter
|
||||
"""
|
||||
|
||||
def __init__(self, name, title):
|
||||
|
@ -32,7 +37,11 @@ class TableFilter(object):
|
|||
self.title = title
|
||||
self.__filter_action_map = {}
|
||||
|
||||
# retains the ordering of actions
|
||||
self.__filter_action_keys = []
|
||||
|
||||
def add_action(self, action):
|
||||
self.__filter_action_keys.append(action.name)
|
||||
self.__filter_action_map[action.name] = action
|
||||
|
||||
def get_action(self, action_name):
|
||||
|
@ -56,7 +65,8 @@ class TableFilter(object):
|
|||
})
|
||||
|
||||
# add other filter actions
|
||||
for action_name, filter_action in self.__filter_action_map.iteritems():
|
||||
for action_name in self.__filter_action_keys:
|
||||
filter_action = self.__filter_action_map[action_name]
|
||||
obj = filter_action.to_json(queryset)
|
||||
obj['action_name'] = action_name
|
||||
filter_actions.append(obj)
|
||||
|
@ -67,6 +77,40 @@ class TableFilter(object):
|
|||
'filter_actions': filter_actions
|
||||
}
|
||||
|
||||
class TableFilterQueryHelper(object):
|
||||
def dateStringsToQ(self, field_name, date_from_str, date_to_str):
|
||||
"""
|
||||
Convert the date strings from_date_str and to_date_str into a
|
||||
set of args in the form
|
||||
|
||||
{'<field_name>__gte': <date from>, '<field_name>__lte': <date to>}
|
||||
|
||||
where date_from and date_to are Django-timezone-aware dates; then
|
||||
convert that into a Django Q object
|
||||
|
||||
Returns the Q object based on those criteria
|
||||
"""
|
||||
|
||||
# one of the values required for the filter is missing, so set
|
||||
# it to the one which was supplied
|
||||
if date_from_str == '':
|
||||
date_from_str = date_to_str
|
||||
elif date_to_str == '':
|
||||
date_to_str = date_from_str
|
||||
|
||||
date_from_naive = dateparse.parse_datetime(date_from_str + ' 00:00:00')
|
||||
date_to_naive = dateparse.parse_datetime(date_to_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[field_name + '__gte'] = date_from
|
||||
args[field_name + '__lte'] = date_to
|
||||
|
||||
return Q(**args)
|
||||
|
||||
class TableFilterAction(object):
|
||||
"""
|
||||
A filter action which displays in the filter popup for a ToasterTable
|
||||
|
@ -99,7 +143,7 @@ class TableFilterAction(object):
|
|||
return {
|
||||
'title': self.title,
|
||||
'type': self.type,
|
||||
'count': self.queryset_filter.count(queryset)
|
||||
'count': self.filter(queryset).count()
|
||||
}
|
||||
|
||||
class TableFilterActionToggle(TableFilterAction):
|
||||
|
@ -113,15 +157,70 @@ class TableFilterActionToggle(TableFilterAction):
|
|||
super(TableFilterActionToggle, self).__init__(*args)
|
||||
self.type = 'toggle'
|
||||
|
||||
class TableFilterActionDay(TableFilterAction):
|
||||
"""
|
||||
A filter action which filters according to the named datetime field and a
|
||||
string representing a day ("today" or "yesterday")
|
||||
"""
|
||||
|
||||
TODAY = 'today'
|
||||
YESTERDAY = 'yesterday'
|
||||
|
||||
def __init__(self, name, title, field, day,
|
||||
queryset_filter = QuerysetFilter(), query_helper = TableFilterQueryHelper()):
|
||||
"""
|
||||
field: (string) the datetime field to filter by
|
||||
day: (string) "today" or "yesterday"
|
||||
"""
|
||||
super(TableFilterActionDay, self).__init__(
|
||||
name,
|
||||
title,
|
||||
queryset_filter
|
||||
)
|
||||
self.type = 'day'
|
||||
self.field = field
|
||||
self.day = day
|
||||
self.query_helper = query_helper
|
||||
|
||||
def filter(self, queryset):
|
||||
"""
|
||||
Apply the day filtering before returning the queryset;
|
||||
this is done here as the value of the filter criteria changes
|
||||
depending on when the filtering is applied
|
||||
"""
|
||||
|
||||
criteria = None
|
||||
date_str = None
|
||||
now = timezone.now()
|
||||
|
||||
if self.day == self.YESTERDAY:
|
||||
increment = timedelta(days=1)
|
||||
wanted_date = now - increment
|
||||
else:
|
||||
wanted_date = now
|
||||
|
||||
wanted_date_str = wanted_date.strftime('%Y-%m-%d')
|
||||
|
||||
criteria = self.query_helper.dateStringsToQ(
|
||||
self.field,
|
||||
wanted_date_str,
|
||||
wanted_date_str
|
||||
)
|
||||
|
||||
self.queryset_filter.set_criteria(criteria)
|
||||
|
||||
return self.queryset_filter.filter(queryset)
|
||||
|
||||
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):
|
||||
def __init__(self, name, title, field,
|
||||
queryset_filter = QuerysetFilter(), query_helper = TableFilterQueryHelper()):
|
||||
"""
|
||||
field: the field to find the max/min range from in the queryset
|
||||
field: (string) the field to find the max/min range from in the queryset
|
||||
"""
|
||||
super(TableFilterActionDateRange, self).__init__(
|
||||
name,
|
||||
|
@ -131,9 +230,13 @@ class TableFilterActionDateRange(TableFilterAction):
|
|||
|
||||
self.type = 'daterange'
|
||||
self.field = field
|
||||
self.query_helper = query_helper
|
||||
|
||||
def set_filter_params(self, params):
|
||||
"""
|
||||
This filter depends on the user selecting some input, so it needs
|
||||
to have its parameters set before its queryset is filtered
|
||||
|
||||
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
|
||||
|
@ -143,30 +246,18 @@ class TableFilterActionDateRange(TableFilterAction):
|
|||
# if params are invalid, return immediately, resetting criteria
|
||||
# on the QuerysetFilter
|
||||
try:
|
||||
from_date_str, to_date_str = params.split(',')
|
||||
date_from_str, date_to_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)
|
||||
criteria = self.query_helper.dateStringsToQ(
|
||||
self.field,
|
||||
date_from_str,
|
||||
date_to_str
|
||||
)
|
||||
self.queryset_filter.set_criteria(criteria)
|
||||
|
||||
def to_json(self, queryset):
|
||||
|
@ -179,7 +270,8 @@ class TableFilterActionDateRange(TableFilterAction):
|
|||
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
|
||||
# will select depends on the date range entered and we don't know
|
||||
# that ahead of time
|
||||
data['count'] = None
|
||||
|
||||
return data
|
||||
|
|
|
@ -32,6 +32,7 @@ import itertools
|
|||
from toastergui.tablefilter import TableFilter
|
||||
from toastergui.tablefilter import TableFilterActionToggle
|
||||
from toastergui.tablefilter import TableFilterActionDateRange
|
||||
from toastergui.tablefilter import TableFilterActionDay
|
||||
|
||||
class ProjectFilters(object):
|
||||
def __init__(self, project_layers):
|
||||
|
@ -65,20 +66,20 @@ class LayersTable(ToasterTable):
|
|||
|
||||
criteria = Q(projectlayer__in=self.project_layers)
|
||||
|
||||
in_project_filter_action = TableFilterActionToggle(
|
||||
in_project_action = TableFilterActionToggle(
|
||||
"in_project",
|
||||
"Layers added to this project",
|
||||
QuerysetFilter(criteria)
|
||||
)
|
||||
|
||||
not_in_project_filter_action = TableFilterActionToggle(
|
||||
not_in_project_action = TableFilterActionToggle(
|
||||
"not_in_project",
|
||||
"Layers not added to this project",
|
||||
QuerysetFilter(~criteria)
|
||||
)
|
||||
|
||||
in_current_project_filter.add_action(in_project_filter_action)
|
||||
in_current_project_filter.add_action(not_in_project_filter_action)
|
||||
in_current_project_filter.add_action(in_project_action)
|
||||
in_current_project_filter.add_action(not_in_project_action)
|
||||
self.add_filter(in_current_project_filter)
|
||||
|
||||
def setup_queryset(self, *args, **kwargs):
|
||||
|
@ -221,20 +222,20 @@ class MachinesTable(ToasterTable):
|
|||
"Filter by project machines"
|
||||
)
|
||||
|
||||
in_project_filter_action = TableFilterActionToggle(
|
||||
in_project_action = TableFilterActionToggle(
|
||||
"in_project",
|
||||
"Machines provided by layers added to this project",
|
||||
project_filters.in_project
|
||||
)
|
||||
|
||||
not_in_project_filter_action = TableFilterActionToggle(
|
||||
not_in_project_action = TableFilterActionToggle(
|
||||
"not_in_project",
|
||||
"Machines provided by layers not added to this project",
|
||||
project_filters.not_in_project
|
||||
)
|
||||
|
||||
in_current_project_filter.add_action(in_project_filter_action)
|
||||
in_current_project_filter.add_action(not_in_project_filter_action)
|
||||
in_current_project_filter.add_action(in_project_action)
|
||||
in_current_project_filter.add_action(not_in_project_action)
|
||||
self.add_filter(in_current_project_filter)
|
||||
|
||||
def setup_queryset(self, *args, **kwargs):
|
||||
|
@ -354,20 +355,20 @@ class RecipesTable(ToasterTable):
|
|||
'Filter by project recipes'
|
||||
)
|
||||
|
||||
in_project_filter_action = TableFilterActionToggle(
|
||||
in_project_action = TableFilterActionToggle(
|
||||
'in_project',
|
||||
'Recipes provided by layers added to this project',
|
||||
project_filters.in_project
|
||||
)
|
||||
|
||||
not_in_project_filter_action = TableFilterActionToggle(
|
||||
not_in_project_action = TableFilterActionToggle(
|
||||
'not_in_project',
|
||||
'Recipes provided by layers not added to this project',
|
||||
project_filters.not_in_project
|
||||
)
|
||||
|
||||
table_filter.add_action(in_project_filter_action)
|
||||
table_filter.add_action(not_in_project_filter_action)
|
||||
table_filter.add_action(in_project_action)
|
||||
table_filter.add_action(not_in_project_action)
|
||||
self.add_filter(table_filter)
|
||||
|
||||
def setup_queryset(self, *args, **kwargs):
|
||||
|
@ -1137,20 +1138,20 @@ class BuildsTable(ToasterTable):
|
|||
'Filter builds by outcome'
|
||||
)
|
||||
|
||||
successful_builds_filter_action = TableFilterActionToggle(
|
||||
successful_builds_action = TableFilterActionToggle(
|
||||
'successful_builds',
|
||||
'Successful builds',
|
||||
QuerysetFilter(Q(outcome=Build.SUCCEEDED))
|
||||
)
|
||||
|
||||
failed_builds_filter_action = TableFilterActionToggle(
|
||||
failed_builds_action = TableFilterActionToggle(
|
||||
'failed_builds',
|
||||
'Failed builds',
|
||||
QuerysetFilter(Q(outcome=Build.FAILED))
|
||||
)
|
||||
|
||||
outcome_filter.add_action(successful_builds_filter_action)
|
||||
outcome_filter.add_action(failed_builds_filter_action)
|
||||
outcome_filter.add_action(successful_builds_action)
|
||||
outcome_filter.add_action(failed_builds_action)
|
||||
self.add_filter(outcome_filter)
|
||||
|
||||
# started on
|
||||
|
@ -1159,14 +1160,29 @@ class BuildsTable(ToasterTable):
|
|||
'Filter by date when build was started'
|
||||
)
|
||||
|
||||
by_started_date_range_filter_action = TableFilterActionDateRange(
|
||||
'date_range',
|
||||
'Build date range',
|
||||
started_today_action = TableFilterActionDay(
|
||||
'today',
|
||||
'Today\'s builds',
|
||||
'started_on',
|
||||
QuerysetFilter()
|
||||
'today'
|
||||
)
|
||||
|
||||
started_on_filter.add_action(by_started_date_range_filter_action)
|
||||
started_yesterday_action = TableFilterActionDay(
|
||||
'yesterday',
|
||||
'Yesterday\'s builds',
|
||||
'started_on',
|
||||
'yesterday'
|
||||
)
|
||||
|
||||
by_started_date_range_action = TableFilterActionDateRange(
|
||||
'date_range',
|
||||
'Build date range',
|
||||
'started_on'
|
||||
)
|
||||
|
||||
started_on_filter.add_action(started_today_action)
|
||||
started_on_filter.add_action(started_yesterday_action)
|
||||
started_on_filter.add_action(by_started_date_range_action)
|
||||
self.add_filter(started_on_filter)
|
||||
|
||||
# completed on
|
||||
|
@ -1175,14 +1191,29 @@ class BuildsTable(ToasterTable):
|
|||
'Filter by date when build was completed'
|
||||
)
|
||||
|
||||
by_completed_date_range_filter_action = TableFilterActionDateRange(
|
||||
'date_range',
|
||||
'Build date range',
|
||||
completed_today_action = TableFilterActionDay(
|
||||
'today',
|
||||
'Today\'s builds',
|
||||
'completed_on',
|
||||
QuerysetFilter()
|
||||
'today'
|
||||
)
|
||||
|
||||
completed_on_filter.add_action(by_completed_date_range_filter_action)
|
||||
completed_yesterday_action = TableFilterActionDay(
|
||||
'yesterday',
|
||||
'Yesterday\'s builds',
|
||||
'completed_on',
|
||||
'yesterday'
|
||||
)
|
||||
|
||||
by_completed_date_range_action = TableFilterActionDateRange(
|
||||
'date_range',
|
||||
'Build date range',
|
||||
'completed_on'
|
||||
)
|
||||
|
||||
completed_on_filter.add_action(completed_today_action)
|
||||
completed_on_filter.add_action(completed_yesterday_action)
|
||||
completed_on_filter.add_action(by_completed_date_range_action)
|
||||
self.add_filter(completed_on_filter)
|
||||
|
||||
# failed tasks
|
||||
|
@ -1193,18 +1224,18 @@ class BuildsTable(ToasterTable):
|
|||
|
||||
criteria = Q(task_build__outcome=Task.OUTCOME_FAILED)
|
||||
|
||||
with_failed_tasks_filter_action = TableFilterActionToggle(
|
||||
with_failed_tasks_action = TableFilterActionToggle(
|
||||
'with_failed_tasks',
|
||||
'Builds with failed tasks',
|
||||
QuerysetFilter(criteria)
|
||||
)
|
||||
|
||||
without_failed_tasks_filter_action = TableFilterActionToggle(
|
||||
without_failed_tasks_action = TableFilterActionToggle(
|
||||
'without_failed_tasks',
|
||||
'Builds without failed tasks',
|
||||
QuerysetFilter(~criteria)
|
||||
)
|
||||
|
||||
failed_tasks_filter.add_action(with_failed_tasks_filter_action)
|
||||
failed_tasks_filter.add_action(without_failed_tasks_filter_action)
|
||||
failed_tasks_filter.add_action(with_failed_tasks_action)
|
||||
failed_tasks_filter.add_action(without_failed_tasks_action)
|
||||
self.add_filter(failed_tasks_filter)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
{% include 'mrb_section.html' %}
|
||||
{% endwith %}
|
||||
|
||||
<h1 class="page-header top-air" data-role="page-title"></h1>
|
||||
<h1 class="page-header top-air" data-role="page-title"></h1>
|
||||
|
||||
{% url 'builds' as xhr_table_url %}
|
||||
{% include 'toastertable.html' %}
|
||||
|
|
|
@ -32,8 +32,11 @@
|
|||
<a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
|
||||
<i class="icon-remove"></i>
|
||||
</a>
|
||||
<button class="btn search-submit-{{table_name}}" >Search</button>
|
||||
<button class="btn btn-link remove-search-btn-{{table_name}}">Show {{title|lower}}
|
||||
<button class="btn search-submit-{{table_name}}">
|
||||
Search
|
||||
</button>
|
||||
<button class="btn btn-link show-all-{{table_name}}">
|
||||
Show {{title|lower}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue