Use updated filter scheme for week-view and agenda

- Legacy-Id: 18457
This commit is contained in:
Jennifer Richards 2020-09-01 15:54:44 +00:00
parent b1e3c1fe92
commit d9d5234217
4 changed files with 228 additions and 99 deletions

View file

@ -285,10 +285,6 @@ class SlideReorderTests(MeetingTestCase):
@skipIf(skip_selenium, skip_message)
class AgendaTests(MeetingTestCase):
# Groups whose display logic is inverted in agenda.html. These have
# toggles with class 'pickviewneg' in the template.
PICKVIEWNEG = ['iepg', 'tools', 'edu', 'ietf', 'iesg', 'iab']
def setUp(self):
super(AgendaTests, self).setUp()
self.meeting = make_meeting_test_data()
@ -377,40 +373,75 @@ class AgendaTests(MeetingTestCase):
self.assertEqual(result[4], ['item1', 'item3'], 'Removing middle item from list failed')
self.assertEqual(result[5], ['item1', 'item2'], 'Removing last item from list failed')
def do_agenda_view_filter_test(self, querystring, visible_groups=()):
self.login()
self.driver.get(self.absreverse('ietf.meeting.views.agenda') + querystring)
self.assert_agenda_item_visibility(visible_groups)
weekview_iframe = self.driver.find_element_by_id('weekview')
if len(querystring) == 0:
self.assertFalse(weekview_iframe.is_displayed(), 'Weekview should be hidden when filters off')
else:
self.assertTrue(weekview_iframe.is_displayed(), 'Weekview should be visible when filters on')
self.driver.switch_to.frame(weekview_iframe)
self.assert_weekview_item_visibility(visible_groups)
self.driver.switch_to.default_content()
def test_agenda_view_filter_show_one(self):
"""Filtered agenda view should display only matching rows (one group selected)"""
self.login()
self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?show=mars')
self.assert_agenda_item_visibility(['mars'] + self.PICKVIEWNEG) # ames and secretariat not selected
self.do_agenda_view_filter_test('?show=mars', ['mars'])
def test_agenda_view_filter_show_two(self):
"""Filtered agenda view should display only matching rows (two groups selected)"""
self.login()
self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?show=mars,ames')
self.assert_agenda_item_visibility(['mars', 'ames'] + self.PICKVIEWNEG) # secretariat not selected
self.do_agenda_view_filter_test('?show=mars,ames', ['mars', 'ames'])
def test_agenda_view_filter_all(self):
"""Filtered agenda view should display only matching rows (all groups selected)"""
self.login()
self.driver.get(self.absreverse('ietf.meeting.views.agenda'))
self.assert_agenda_item_visibility()
self.do_agenda_view_filter_test('', None) # None means all should be visible
def test_agenda_view_filter_hide(self):
self.login()
self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?hide=ietf')
self.assert_agenda_item_visibility([g for g in self.PICKVIEWNEG if g != 'ietf'])
self.do_agenda_view_filter_test('?hide=ietf', [])
def test_agenda_view_filter_show_and_hide(self):
self.login()
self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?show=mars&hide=ietf')
self.assert_agenda_item_visibility(
['mars'] + [g for g in self.PICKVIEWNEG if g != 'ietf']
)
self.do_agenda_view_filter_test('?show=mars&hide=ietf', ['mars'])
def assert_agenda_item_visibility(self, visible_groups=()):
def test_agenda_view_filter_show_and_hide_same_group(self):
self.do_agenda_view_filter_test('?show=mars&hide=mars', [])
def test_agenda_view_filter_showtypes(self):
self.do_agenda_view_filter_test('?showtypes=plenary', ['ietf']) # ietf has a plenary session
def test_agenda_view_filter_hidetypes(self):
self.do_agenda_view_filter_test('?hidetypes=plenary', [])
def test_agenda_view_filter_showtypes_and_hidetypes(self):
self.do_agenda_view_filter_test('?showtypes=plenary&hidetypes=regular', ['ietf']) # ietf has a plenary session
def test_agenda_view_filter_showtypes_and_hidetypes_same_type(self):
self.do_agenda_view_filter_test('?showtypes=plenary&hidetypes=plenary', [])
def test_agenda_view_filter_show_and_showtypes(self):
self.do_agenda_view_filter_test('?show=mars&showtypes=plenary', ['mars', 'ietf']) # ietf has a plenary session
def test_agenda_view_filter_show_and_hidetypes(self):
self.do_agenda_view_filter_test('?show=ietf,mars&hidetypes=plenary', ['mars']) # ietf has a plenary session
def test_agenda_view_filter_hide_and_hidetypes(self):
self.do_agenda_view_filter_test('?hide=ietf,mars&hidetypes=plenary', [])
def test_agenda_view_filter_show_hide_and_showtypes(self):
self.do_agenda_view_filter_test('?show=mars&hide=ames&showtypes=plenary,regular', ['mars', 'ietf']) # ietf has plenary session
def test_agenda_view_filter_show_hide_and_hidetypes(self):
self.do_agenda_view_filter_test('?show=mars,ietf&hide=ames&hidetypes=plenary', ['mars']) # ietf has plenary session
def test_agenda_view_filter_all_params(self):
self.do_agenda_view_filter_test('?show=secretariat,ietf&hide=ames&showtypes=regular&hidetypes=plenary',
['secretariat', 'mars'])
def assert_agenda_item_visibility(self, visible_groups=None):
"""Assert that correct items are visible in current browser window
If visible_groups is empty (the default), expects all items to be visible.
If visible_groups is None (the default), expects all items to be visible.
"""
for item in self.get_expected_items():
row_id = self.row_id_for_item(item)
@ -419,11 +450,33 @@ class AgendaTests(MeetingTestCase):
except NoSuchElementException:
item_row = None
self.assertIsNotNone(item_row, 'No row for schedule item "%s"' % row_id)
if len(visible_groups) == 0 or item.session.group.acronym in visible_groups:
if visible_groups is None or item.session.group.acronym in visible_groups:
self.assertTrue(item_row.is_displayed(), 'Row for schedule item "%s" is not displayed but should be' % row_id)
else:
self.assertFalse(item_row.is_displayed(), 'Row for schedule item "%s" is displayed but should not be' % row_id)
def assert_weekview_item_visibility(self, visible_groups=None):
for item in self.get_expected_items():
if item.session.name:
label = item.session.name
elif item.timeslot.type_id == 'break':
label = item.timeslot.name
elif item.session.group:
label = item.session.group.name
else:
label = 'Free Slot'
try:
item_div = self.driver.find_element_by_xpath('//div/span[contains(text(),"%s")]/..' % label)
except NoSuchElementException:
item_div = None
if visible_groups is None or item.session.group.acronym in visible_groups:
self.assertIsNotNone(item_div, 'No weekview entry for "%s" (%s)' % (label, item.slug()))
self.assertTrue(item_div.is_displayed(), 'Entry for "%s (%s)" is not displayed but should be' % (label, item.slug()))
else:
self.assertIsNone(item_div, 'Unexpected weekview entry for "%s" (%s)' % (label, item.slug()))
def test_agenda_view_group_filter_toggle(self):
"""Clicking a group toggle enables/disables agenda filtering"""
group_acronym = 'mars'
@ -449,7 +502,7 @@ class AgendaTests(MeetingTestCase):
group_button.click()
# Check visibility
self.assert_agenda_item_visibility([group_acronym] + self.PICKVIEWNEG)
self.assert_agenda_item_visibility([group_acronym])
# Click the group button again
group_button = WebDriverWait(self.driver, 2).until(

View file

@ -801,7 +801,7 @@ class MeetingTests(TestCase):
# ames regular session should be suppressed
self.do_ical_filter_test(
meeting,
querystring='?show=mars&hide=ames&showtypes=plenary,regular',
querystring='?show=ietf&hide=ames&showtypes=regular',
expected_session_summaries=[
'IETF Plenary',
'mars - Martian Special Interest Group',

View file

@ -120,12 +120,12 @@
{% endif %}
<p>Also show special sessions of these groups:</p>
<div class="btn-group btn-group-justified">
<div class="btn-group"><button class="btn btn-default pickviewneg active iepg"> IEPG</button></div>
<div class="btn-group"><button class="btn btn-default pickviewneg active tools"> Tools</button></div>
<div class="btn-group"><button class="btn btn-default pickviewneg active edu"> EDU</button></div>
<div class="btn-group"><button class="btn btn-default pickviewneg active ietf"> IETF</button></div>
<div class="btn-group"><button class="btn btn-default pickviewneg active iesg"> IESG</button></div>
<div class="btn-group"><button class="btn btn-default pickviewneg active iab"> IAB</button></div>
<div class="btn-group"><button class="btn btn-default pickview iepg"> IEPG</button></div>
<div class="btn-group"><button class="btn btn-default pickview tools"> Tools</button></div>
<div class="btn-group"><button class="btn btn-default pickview edu"> EDU</button></div>
<div class="btn-group"><button class="btn btn-default pickview ietf"> IETF</button></div>
<div class="btn-group"><button class="btn btn-default pickview iesg"> IESG</button></div>
<div class="btn-group"><button class="btn btn-default pickview iab"> IAB</button></div>
</div>
</div>
</div>
@ -362,10 +362,13 @@
function parse_query_params(qs) {
var params = {};
qs = qs.replace(/^\?/, '');
$.each(qs.split('&'), function(i, v) {
var toks = v.split('=', 2)
params[toks[0]] = toks[1].toLowerCase();
});
if (qs) {
var param_strs = qs.split('&');
for (var ii = 0; ii < param_strs.length; ii++) {
var toks = param_strs[ii].split('=', 2)
params[toks[0]] = toks[1] || true;
}
}
return params;
}
@ -374,43 +377,56 @@
return qparams[filt] ? qparams[filt].split(',') : [];
}
function toggle_visibility() {
var qparams = parse_query_params(window.location.search);
var show_groups = get_filter_from_qparams(qparams, 'show');
var hide_groups = get_filter_from_qparams(qparams, 'hide');
function get_filter_params(qparams) {
return {
show_groups: get_filter_from_qparams(qparams, 'show'),
hide_groups: get_filter_from_qparams(qparams, 'hide'),
show_types: get_filter_from_qparams(qparams, 'showtypes'),
hide_types: get_filter_from_qparams(qparams, 'hidetypes'),
};
}
function toggle_visibility(filter_params) {
// reset UI elements to default state
$(".pickview").removeClass("active disabled");
$(".pickviewneg").addClass("active");
if (show_groups.length || hide_groups.length) {
// if groups were selected for filtering, hide all rows that are
// hidden by default, show all rows that are shown by default
if (filter_params['show_groups'].length ||
filter_params['hide_groups'].length ||
filter_params['show_types'].length ||
filter_params['hide_types'].length
) {
// if groups were selected for filtering, hide all rows by default
$('[id^="row-"]').hide();
$.each($(".pickviewneg").text().trim().split(/ +/), function (i, v) {
v = v.trim().toLowerCase();
$('[id^="row-"]').filter('[id*="-' + v + '"]').show();
});
// show the customizer
$("#customize").collapse("show");
// loop through the has items and change the UI element and row visibilities accordingly
$.each(hide_groups, function (i, v) {
// this is a "negative" item: when present, hide these rows
$('[id^="row-"]').filter('[id*="-' + v + '"]').hide();
$(".view." + v).find("button").removeClass("active disabled");
$("button.pickviewneg." + v).removeClass("active");
});
$.each(show_groups, function (i, v) {
// this is a regular item: when present, show these rows
$.each(filter_params['show_groups'], function (i, v) {
// this is a regular item by wg: when present, show these rows
$('[id^="row-"]').filter('[id*="-' + v + '"]').show();
$(".view." + v).find("button").addClass("active disabled");
$("button.pickview." + v).addClass("active");
});
$.each(filter_params['show_types'], function (i, v) {
// this is a regular item by type: when present, show these rows
$('[id^="row-"]').filter('[timeslot-type*="' + v + '"]').show();
});
$.each(filter_params['hide_groups'], function (i, v) {
// this is a "negative" item by wg: when present, hide these rows
$('[id^="row-"]').filter('[id*="-' + v + '"]').hide();
$(".view." + v).find("button").removeClass("active disabled");
$("button.pickviewneg." + v).removeClass("active");
});
$.each(filter_params['hide_types'], function (i, v) {
// this is a "negative" item by type: when present, hide these rows
$('[id^="row-"]').filter('[timeslot-type*="' + v + '"]').hide();
});
// show the week view
$("#weekview").attr("src", "week-view.html" + window.location.search).removeClass("hidden");
update_weekview();
$("#weekview").removeClass("hidden");
// show the custom .ics link
$("#ical-link").attr("href",$("#ical-link").attr("href").split("?")[0]+window.location.search);
@ -426,16 +442,14 @@
$(".pickview, .pickviewneg").click(function () {
// Get clicked item label
var item = $(this).text().trim().toLowerCase();
var qparams = parse_query_params(window.location.search);
var show_groups = get_filter_from_qparams(qparams, 'show');
var hide_groups = get_filter_from_qparams(qparams, 'hide');
var fp = get_filter_params(parse_query_params(window.location.search));
if ($(this).hasClass("pickviewneg")) {
toggle_list_item(hide_groups, item);
toggle_list_item(fp['hide_groups'], item);
} else {
toggle_list_item(show_groups, item);
toggle_list_item(fp['show_groups'], item);
}
update_filters(show_groups, hide_groups);
update_filters(fp);
});
/* Add to list if not present, remove if present */
@ -448,14 +462,20 @@
}
}
function update_filters(show, hide) {
function update_filters(filter_params) {
var qparams = [];
var search = '';
if (show.length > 0) {
qparams.push('show=' + show.join());
if (filter_params['show_groups'].length > 0) {
qparams.push('show=' + filter_params['show_groups'].join());
}
if (hide.length > 0) {
qparams.push('hide=' + hide.join());
if (filter_params['hide_groups'].length > 0) {
qparams.push('hide=' + filter_params['hide_groups'].join());
}
if (filter_params['show_types'].length > 0) {
qparams.push('showtypes=' + filter_params['show_types'].join());
}
if (filter_params['hide_types'].length > 0) {
qparams.push('hidetypes=' + filter_params['hide_types'].join());
}
if (qparams.length > 0) {
search = '?' + qparams.join('&');
@ -466,15 +486,32 @@
if (window.history && window.history.replaceState) {
// Keep current origin, replace search string, no page reload
history.replaceState({}, document.title, new_url);
toggle_visibility();
toggle_visibility(filter_params);
} else {
// No window.history.replaceState support, page reload required
window.location = new_url;
}
}
function update_weekview() {
var wv_iframe = document.getElementById('weekview');
var wv_window = wv_iframe.contentWindow;
var new_url = 'week-view.html' + window.location.search;
if (wv_iframe.src && wv_window.history && wv_window.history.replaceState) {
wv_window.history.replaceState({}, '', new_url);
wv_window.draw_calendar()
} else {
// ho history.replaceState, page reload required
wv_iframe.src = new_url;
}
}
$(document).ready(function () {
toggle_visibility();
toggle_visibility(
get_filter_params(
parse_query_params(window.location.search)
)
);
});
$(".modal").on("show.bs.modal", function () {

View file

@ -107,33 +107,60 @@
}
}
//===========================================================================
function is_visible(include) {
function parse_query_params(qs) {
var params = {};
qs = qs.replace(/^\?/, '').toLowerCase();
if (qs) {
var param_strs = qs.split('&');
for (var ii = 0; ii < param_strs.length; ii++) {
var toks = param_strs[ii].split('=', 2)
params[toks[0]] = toks[1] || true;
}
}
return params;
}
//===========================================================================
function get_filter_from_qparams(qparams, filt) {
return qparams[filt] ? qparams[filt].split(',') : [];
}
function get_filter_params(qparams) {
return {
show_groups: get_filter_from_qparams(qparams, 'show'),
hide_groups: get_filter_from_qparams(qparams, 'hide'),
show_types: get_filter_from_qparams(qparams, 'showtypes'),
hide_types: get_filter_from_qparams(qparams, 'hidetypes'),
};
}
//===========================================================================
function is_visible(query_params) {
// Returns a method to filter objects for visibility
// Accepts show, hide, showtypes, and hidetypes filters. Also accepts
// '@<state>' to show sessions in a particular state (e.g., @bof).
// Current types are:
// Session, Other, Break, Plenary
var fp = get_filter_params(query_params);
return function (item) {
// "-wgname" will remove a working group from the output.
// "~Type" will add that type to the output.
// "-~Type" will remove that type from the output
// "@bof" will include all BOFs
// Current types are:
// Session, Other, Break, Plenary
var item_group = (item.group || '').toLowerCase();
var item_type = (item.type || '').toLowerCase();
var item_area = (item.area || '').toLowerCase();
var item_state = (item.state || '').toLowerCase();
if ("group" in item) {
if (include[(item.group).toLowerCase()]) { return true; }
if (include["-"+(item.group).toLowerCase()]) { return false; }
if ((fp['hide_groups'].indexOf(item_group) >= 0) ||
(fp['hide_types'].indexOf(item_type) >= 0)) {
return false;
}
if ("state" in item) {
if (include["@"+(item.state).toLowerCase()]) { return true; }
}
if (include["~"+(item.type).toLowerCase()]) { return true; }
if (include["-~"+(item.type).toLowerCase()]) { return false; }
if ("area" in item) {
if (include[(item.area).toLowerCase()]) { return true; }
}
if (item.type === "Plenary") { return true; }
if (item.type === "Other") { return true; }
return false;
return ((fp['show_groups'].indexOf(item_group) >= 0) ||
(fp['show_groups'].indexOf(item_area) >= 0) ||
(fp['show_types'].indexOf(item_type) >= 0) ||
query_params['@'+item_state]);
}
}
@ -143,16 +170,23 @@
var width = document.body.clientWidth;
var height = document.body.clientHeight;
var include = {};
window.location.hash.replace("#",'').split(',').forEach(function(key){
include[(key + "").toLowerCase()] = true;
});
var visible_items = all_items;
var qs = window.location.search;
if (qs.length > 1) {
visible_items = visible_items.filter(is_visible(parse_query_params(qs)));
}
var visible_items = all_items.filter(is_visible(include));
var start_day = visible_items[0].day;
var start_day;
var day_start;
if (visible_items.length > 0) {
start_day = visible_items[0].day;
day_start = visible_items[0].start_time;
} else {
// fallback in case all items were filtered
start_day = all_items[0].day;
day_start = all_items[0].start_time;
}
var end_day = start_day;
var day_start = visible_items[0].start_time;
var day_end = 0;
compute_swimlanes(visible_items);
@ -324,6 +358,11 @@
document.body.appendChild(e);
});
// Div to indicate rendering has occurred, for testing purposes.
var elt = document.createElement('div');
elt.id = 'wv-end';
document.body.appendChild(elt);
}
//===========================================================================