diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py index fab10fad2..9a7d64867 100644 --- a/ietf/meeting/helpers.py +++ b/ietf/meeting/helpers.py @@ -256,6 +256,10 @@ class AgendaFilterOrganizer(AgendaKeywordTool): self.special_filters = None if self._use_legacy_keywords(): self.extra_labels += ('Plenary',) # need this when not using session purpose + self.manual_extra_labels = set() + + def add_extra_filter(self, kw): + self.manual_extra_labels.add(kw) def get_non_area_keywords(self): """Get list of any 'non-area' (aka 'special') keywords @@ -436,13 +440,13 @@ class AgendaFilterOrganizer(AgendaKeywordTool): def _extra_filters(self): """Get list of filters corresponding to self.extra_labels""" item_source = self.assignments or self.sessions or [] - candidates = set(self.extra_labels) + candidates = set(self.extra_labels).union(self.manual_extra_labels) return self._filter_column( label=None, keyword=None, children=[ self._filter_entry(label=label, keyword=xslugify(label), toggled_by=[], is_bof=False) - for label in candidates if any( + for label in candidates if label in self.manual_extra_labels or any( # Keep only those that will affect at least one session [label.lower() in item.filter_keywords for item in item_source] )] diff --git a/ietf/meeting/tests_js.py b/ietf/meeting/tests_js.py index 607f28123..0e6a42343 100644 --- a/ietf/meeting/tests_js.py +++ b/ietf/meeting/tests_js.py @@ -1076,9 +1076,9 @@ class InterimTests(IetfSeleniumTestCase): unexpected.add(entry.text) advance_month() - self.assertEqual(seen, visible_meetings, "Expected calendar entries not shown.") - self.assertEqual(not_visible, set(), "Hidden calendar entries for expected interim meetings.") - self.assertEqual(unexpected, set(), "Unexpected calendar entries visible") + self.assertCountEqual(seen, visible_meetings, "Expected calendar entries not shown.") + self.assertCountEqual(not_visible, set(), "Hidden calendar entries for expected interim meetings.") + self.assertCountEqual(unexpected, set(), "Unexpected calendar entries visible") def do_upcoming_view_filter_test(self, querystring, visible_meetings=()): self.login() @@ -1152,102 +1152,85 @@ class InterimTests(IetfSeleniumTestCase): ietf_meetings = set(self.all_ietf_meetings()) self.do_upcoming_view_filter_test('', ietf_meetings.union(self.displayed_interims())) + def test_upcoming_view_show_ietf_meetings(self): + self.do_upcoming_view_filter_test('?show=ietf-meetings', self.all_ietf_meetings()) + def test_upcoming_view_filter_show_group(self): # Show none - ietf_meetings = set(self.all_ietf_meetings()) - self.do_upcoming_view_filter_test('?show=', ietf_meetings) + self.do_upcoming_view_filter_test('?show=') # Show one - self.do_upcoming_view_filter_test('?show=mars', - ietf_meetings.union( - self.displayed_interims(groups=['mars']) - )) + self.do_upcoming_view_filter_test('?show=mars', self.displayed_interims(groups=['mars'])) # Show two - self.do_upcoming_view_filter_test('?show=mars,ames', - ietf_meetings.union( - self.displayed_interims(groups=['mars', 'ames']) - )) + self.do_upcoming_view_filter_test('?show=mars,ames',self.displayed_interims(groups=['mars', 'ames'])) + + # Show two plus ietf-meetings + self.do_upcoming_view_filter_test( + '?show=ietf-meetings,mars,ames', + set(self.all_ietf_meetings()).union(self.displayed_interims(groups=['mars', 'ames'])) + ) def test_upcoming_view_filter_show_area(self): mars = Group.objects.get(acronym='mars') area = mars.parent - ietf_meetings = set(self.all_ietf_meetings()) - self.do_upcoming_view_filter_test('?show=%s' % area.acronym, - ietf_meetings.union( - self.displayed_interims(groups=['mars', 'ames']) - )) + self.do_upcoming_view_filter_test('?show=%s' % area.acronym, self.displayed_interims(groups=['mars', 'ames'])) def test_upcoming_view_filter_show_type(self): - ietf_meetings = set(self.all_ietf_meetings()) - self.do_upcoming_view_filter_test('?show=plenary', - ietf_meetings.union( - self.displayed_interims(groups=['sg']) - )) + self.do_upcoming_view_filter_test('?show=plenary', self.displayed_interims(groups=['sg'])) def test_upcoming_view_filter_hide_group(self): mars = Group.objects.get(acronym='mars') area = mars.parent # Without anything shown, should see only ietf meetings - ietf_meetings = set(self.all_ietf_meetings()) - self.do_upcoming_view_filter_test('?hide=mars', ietf_meetings) + self.do_upcoming_view_filter_test('?hide=mars') # With group shown - self.do_upcoming_view_filter_test('?show=ames,mars&hide=mars', - ietf_meetings.union( - self.displayed_interims(groups=['ames']) - )) + self.do_upcoming_view_filter_test('?show=ames,mars&hide=mars', self.displayed_interims(groups=['ames'])) # With area shown - self.do_upcoming_view_filter_test('?show=%s&hide=mars' % area.acronym, - ietf_meetings.union( - self.displayed_interims(groups=['ames']) - )) - + self.do_upcoming_view_filter_test('?show=%s&hide=mars' % area.acronym, self.displayed_interims(groups=['ames'])) # With type shown - self.do_upcoming_view_filter_test('?show=plenary&hide=sg', - ietf_meetings) + self.do_upcoming_view_filter_test('?show=plenary&hide=sg') def test_upcoming_view_filter_hide_area(self): mars = Group.objects.get(acronym='mars') area = mars.parent - # Without anything shown, should see only ietf meetings - ietf_meetings = set(self.all_ietf_meetings()) - self.do_upcoming_view_filter_test('?hide=%s' % area.acronym, ietf_meetings) + # Without anything shown, should see nothing + self.do_upcoming_view_filter_test('?hide=%s' % area.acronym) # With area shown - self.do_upcoming_view_filter_test('?show=%s&hide=%s' % (area.acronym, area.acronym), - ietf_meetings) + self.do_upcoming_view_filter_test('?show=%s&hide=%s' % (area.acronym, area.acronym)) # With group shown - self.do_upcoming_view_filter_test('?show=mars&hide=%s' % area.acronym, ietf_meetings) + self.do_upcoming_view_filter_test('?show=mars&hide=%s' % area.acronym) # With type shown - self.do_upcoming_view_filter_test('?show=regular&hide=%s' % area.acronym, ietf_meetings) + self.do_upcoming_view_filter_test('?show=regular&hide=%s' % area.acronym) + + # with IETF meetings shown + self.do_upcoming_view_filter_test('?show=ietf-meetings,hide=%s' % area.acronym, self.all_ietf_meetings()) def test_upcoming_view_filter_hide_type(self): - mars = Group.objects.get(acronym='mars') - area = mars.parent - - # Without anything shown, should see only ietf meetings - ietf_meetings = set(self.all_ietf_meetings()) - self.do_upcoming_view_filter_test('?hide=regular', ietf_meetings) + # Without anything shown, should see nothing + self.do_upcoming_view_filter_test('?hide=regular') # With group shown - self.do_upcoming_view_filter_test('?show=mars&hide=regular', ietf_meetings) + self.do_upcoming_view_filter_test('?show=mars&hide=regular') # With type shown - self.do_upcoming_view_filter_test('?show=plenary,regular&hide=%s' % area.acronym, - ietf_meetings.union( - self.displayed_interims(groups=['sg']) - )) + self.do_upcoming_view_filter_test( + '?show=plenary,regular&hide=regular', + self.displayed_interims(groups=['sg']) + ) + + # With interim-meetings shown + self.do_upcoming_view_filter_test('?show=plenary,regular&hide=regular', self.displayed_interims(groups=['sg'])) def test_upcoming_view_filter_whitespace(self): """Whitespace in filter lists should be ignored""" - meetings = set(self.all_ietf_meetings()) - meetings.update(self.displayed_interims(groups=['mars'])) - self.do_upcoming_view_filter_test('?show=mars , ames &hide= ames', meetings) + self.do_upcoming_view_filter_test('?show=mars , ames &hide= ames', self.displayed_interims(groups=['mars'])) def test_upcoming_view_time_zone_selection(self): def _assert_interim_tz_correct(sessions, tz): diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 673faba58..482d3ccc6 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -4507,8 +4507,16 @@ class InterimTests(TestCase): # Just a quick check of functionality - details tested by test_js.InterimTests make_meeting_test_data(create_interims=True) url = urlreverse("ietf.meeting.views.upcoming_ical") - r = self.client.get(url + '?show=mars') + r = self.client.get(url + '?show=mars') + self.assertEqual(r.status_code, 200) + assert_ical_response_is_valid(self, r, + expected_event_summaries=[ + 'mars - Martian Special Interest Group', + ], + expected_event_count=1) + + r = self.client.get(url + '?show=mars,ietf-meetings') self.assertEqual(r.status_code, 200) assert_ical_response_is_valid(self, r, expected_event_summaries=[ diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 6fe1e95e8..d269bbd70 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -3456,6 +3456,10 @@ def upcoming(request): # Set up for agenda filtering - only one filter_category here AgendaKeywordTagger(sessions=interim_sessions).apply() filter_organizer = AgendaFilterOrganizer(sessions=interim_sessions, single_category=True) + # Allow filtering to show only IETF Meetings. This adds a button labeled "IETF Meetings" to the + # "Other" column of the filter UI. When enabled, this adds the keyword "ietf-meetings" to the "show" + # filter list. The IETF meetings are explicitly labeled with this keyword in upcoming.html. + filter_organizer.add_extra_filter('IETF Meetings') entries = list(ietf_meetings) entries.extend(list(interim_sessions)) @@ -3544,9 +3548,14 @@ def upcoming_ical(request): a.session = sessions.get(a.session_id) or a.session a.session.ical_status = ical_session_status(a) - # handle IETFs separately - ietfs = [m for m in meetings if m.type_id == 'ietf'] - preprocess_meeting_important_dates(ietfs) + # Handle IETFs separately. Manually apply the 'ietf-meetings' filter. + if filter_params is None or ( + 'ietf-meetings' in filter_params['show'] and 'ietf-meetings' not in filter_params['hide'] + ): + ietfs = [m for m in meetings if m.type_id == 'ietf'] + preprocess_meeting_important_dates(ietfs) + else: + ietfs = [] meeting_vtz = {meeting.vtimezone() for meeting in meetings} meeting_vtz.discard(None) diff --git a/ietf/templates/meeting/upcoming.html b/ietf/templates/meeting/upcoming.html index c974d7338..eece8383f 100644 --- a/ietf/templates/meeting/upcoming.html +++ b/ietf/templates/meeting/upcoming.html @@ -46,7 +46,12 @@ {% for entry in entries %} + {% if entry|classname == 'Session' %} + data-filter-keywords="{{ entry.filter_keywords|join:',' }}" + {% elif entry|classname == 'Meeting' %} + data-filter-keywords="ietf-meetings" + {% endif %} + > {% if entry|classname == 'Meeting' %} {% with meeting=entry %}