fix: Separately show proceedings sessions with different names (#5005)
* refactor: Update call to deprecated add_event_info_to_session_qs * feat: Gather proceedings sessions in the view, grouped by name * feat: Begin using new session data format in templates (WIP) * feat: Show non-meeting groups (WIP) Non-meeting groups (all sessions are notmeet) now show up on the proceedings. Session materials associated with these groups are not shown, need to restore that functionality. * refactor: Rework template data, show materials for notmeet groups (WIP) * fix: Restore "No agenda", etc, when meeting materials are not present * chore: Remove commented out old code * fix: Restore contents in non-area sections of proceedings * chore: Remove commented-out stale code * fix: Suppress duplicate agendas for a group on proceedings * refactor: Generalize agenda deduplication and apply to minutes * refactor: Format multiple items per session; apply to bluesheets * refactor: Apply _format_materials to recordings, slides, and drafts * chore: Add comment about limitations of test_proceedings() test * test: Test separation of named sessions in the proceedings
This commit is contained in:
parent
b931c8e38f
commit
c6663eb593
|
@ -7310,7 +7310,12 @@ class ProceedingsTests(BaseMeetingTestCase):
|
|||
)
|
||||
|
||||
def test_proceedings(self):
|
||||
"""Proceedings should be displayed correctly"""
|
||||
"""Proceedings should be displayed correctly
|
||||
|
||||
Currently only tests that the view responds with a 200 response code and checks the ProceedingsMaterials
|
||||
at the top of the proceedings. Ought to actually test the display of the individual group/session
|
||||
materials as well.
|
||||
"""
|
||||
meeting = make_meeting_test_data(meeting=MeetingFactory(type_id='ietf', number='100'))
|
||||
session = Session.objects.filter(meeting=meeting, group__acronym="mars").first()
|
||||
GroupEventFactory(group=session.group,type='status_update')
|
||||
|
@ -7364,6 +7369,65 @@ class ProceedingsTests(BaseMeetingTestCase):
|
|||
self._assertMeetingHostsDisplayed(r, meeting)
|
||||
self._assertProceedingsMaterialsDisplayed(r, meeting)
|
||||
|
||||
def test_named_session(self):
|
||||
"""Session with a name should appear separately in the proceedings"""
|
||||
meeting = MeetingFactory(type_id='ietf', number='100')
|
||||
group = GroupFactory()
|
||||
plain_session = SessionFactory(meeting=meeting, group=group)
|
||||
named_session = SessionFactory(meeting=meeting, group=group, name='I Got a Name')
|
||||
for doc_type_id in ('agenda', 'minutes', 'bluesheets', 'recording', 'slides', 'draft'):
|
||||
# Set up sessions materials that will have distinct URLs for each session.
|
||||
# This depends on settings.MEETING_DOC_HREFS and may need updating if that changes.
|
||||
SessionPresentationFactory(
|
||||
session=plain_session,
|
||||
document__type_id=doc_type_id,
|
||||
document__uploaded_filename=f'upload-{doc_type_id}-plain',
|
||||
document__external_url=f'external_url-{doc_type_id}-plain',
|
||||
)
|
||||
SessionPresentationFactory(
|
||||
session=named_session,
|
||||
document__type_id=doc_type_id,
|
||||
document__uploaded_filename=f'upload-{doc_type_id}-named',
|
||||
document__external_url=f'external_url-{doc_type_id}-named',
|
||||
)
|
||||
|
||||
url = urlreverse('ietf.meeting.views.proceedings', kwargs={'num': meeting.number})
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
||||
plain_label = q(f'div#{group.acronym}')
|
||||
self.assertEqual(plain_label.text(), group.acronym)
|
||||
plain_row = plain_label.closest('tr')
|
||||
self.assertTrue(plain_row)
|
||||
|
||||
named_label = q(f'div#{slugify(named_session.name)}')
|
||||
self.assertEqual(named_label.text(), named_session.name)
|
||||
named_row = named_label.closest('tr')
|
||||
self.assertTrue(named_row)
|
||||
|
||||
for material in (sp.document for sp in plain_session.sessionpresentation_set.all()):
|
||||
if material.type_id == 'draft':
|
||||
expected_url = urlreverse(
|
||||
'ietf.doc.views_doc.document_main',
|
||||
kwargs={'name': material.canonical_name()},
|
||||
)
|
||||
else:
|
||||
expected_url = material.get_href(meeting)
|
||||
self.assertTrue(plain_row.find(f'a[href="{expected_url}"]'))
|
||||
self.assertFalse(named_row.find(f'a[href="{expected_url}"]'))
|
||||
|
||||
for material in (sp.document for sp in named_session.sessionpresentation_set.all()):
|
||||
if material.type_id == 'draft':
|
||||
expected_url = urlreverse(
|
||||
'ietf.doc.views_doc.document_main',
|
||||
kwargs={'name': material.canonical_name()},
|
||||
)
|
||||
else:
|
||||
expected_url = material.get_href(meeting)
|
||||
self.assertFalse(plain_row.find(f'a[href="{expected_url}"]'))
|
||||
self.assertTrue(named_row.find(f'a[href="{expected_url}"]'))
|
||||
|
||||
def test_proceedings_no_agenda(self):
|
||||
# Meeting number must be larger than the last special-cased proceedings (currently 96)
|
||||
meeting = MeetingFactory(type_id='ietf',populate_schedule=False,date=date_today(), number='100')
|
||||
|
|
|
@ -3586,6 +3586,74 @@ def upcoming_json(request):
|
|||
response = HttpResponse(json.dumps(data, indent=2, sort_keys=False), content_type='application/json;charset=%s'%settings.DEFAULT_CHARSET)
|
||||
return response
|
||||
|
||||
def organize_proceedings_sessions(sessions):
|
||||
# Collect sessions by Group, then bin by session name (including sessions with blank names).
|
||||
# If all of a group's sessions are 'notmeet', the processed data goes in not_meeting_sessions.
|
||||
# Otherwise, the data goes in meeting_sessions.
|
||||
meeting_groups = []
|
||||
not_meeting_groups = []
|
||||
for group_acronym, group_sessions in itertools.groupby(sessions, key=lambda s: s.group.acronym):
|
||||
by_name = {}
|
||||
is_meeting = False
|
||||
all_canceled = True
|
||||
group = None
|
||||
for s in sorted(
|
||||
group_sessions,
|
||||
key=lambda gs: (
|
||||
gs.official_timeslotassignment().timeslot.time
|
||||
if gs.official_timeslotassignment() else datetime.datetime(datetime.MAXYEAR, 1, 1)
|
||||
),
|
||||
):
|
||||
group = s.group
|
||||
if s.current_status != 'notmeet':
|
||||
is_meeting = True
|
||||
if s.current_status != 'canceled':
|
||||
all_canceled = False
|
||||
by_name.setdefault(s.name, [])
|
||||
if s.current_status != 'notmeet' or s.sessionpresentation_set.exists():
|
||||
by_name[s.name].append(s) # for notmeet, only include sessions with materials
|
||||
for sess_name, ss in by_name.items():
|
||||
def _format_materials(items):
|
||||
"""Format session/material for template
|
||||
|
||||
Input is a list of (session, materials) pairs. The materials value can be a single value or a list.
|
||||
"""
|
||||
material_times = {} # key is material, value is first timestamp it appeared
|
||||
for s, mats in items:
|
||||
timestamp = s.official_timeslotassignment().timeslot.time
|
||||
if not isinstance(mats, list):
|
||||
mats = [mats]
|
||||
for mat in mats:
|
||||
if mat and mat not in material_times:
|
||||
material_times[mat] = timestamp
|
||||
n_mats = len(material_times)
|
||||
result = []
|
||||
if n_mats == 1:
|
||||
result.append({'material': list(material_times)[0]}) # no 'time' when only a single material
|
||||
elif n_mats > 1:
|
||||
for mat, timestamp in material_times.items():
|
||||
result.append({'material': mat, 'time': timestamp})
|
||||
return result
|
||||
|
||||
entry = {
|
||||
'group': group,
|
||||
'name': sess_name,
|
||||
'canceled': all_canceled,
|
||||
# pass sessions instead of the materials here so session data (like time) is easily available
|
||||
'agendas': _format_materials((s, s.agenda()) for s in ss),
|
||||
'minutes': _format_materials((s, s.minutes()) for s in ss),
|
||||
'bluesheets': _format_materials((s, s.bluesheets()) for s in ss),
|
||||
'recordings': _format_materials((s, s.recordings()) for s in ss),
|
||||
'slides': _format_materials((s, s.slides()) for s in ss),
|
||||
'drafts': _format_materials((s, s.drafts()) for s in ss),
|
||||
}
|
||||
if is_meeting:
|
||||
meeting_groups.append(entry)
|
||||
else:
|
||||
not_meeting_groups.append(entry)
|
||||
return meeting_groups, not_meeting_groups
|
||||
|
||||
|
||||
def proceedings(request, num=None):
|
||||
|
||||
meeting = get_meeting(num)
|
||||
|
@ -3606,36 +3674,48 @@ def proceedings(request, num=None):
|
|||
today_utc = date_today(datetime.timezone.utc)
|
||||
|
||||
schedule = get_schedule(meeting, None)
|
||||
sessions = add_event_info_to_session_qs(
|
||||
Session.objects.filter(meeting__number=meeting.number)
|
||||
).filter(
|
||||
Q(timeslotassignments__schedule__in=[schedule, schedule.base if schedule else None]) | Q(current_status='notmeet')
|
||||
).select_related().order_by('-current_status')
|
||||
plenaries = sessions.filter(name__icontains='plenary').exclude(current_status='notmeet')
|
||||
ietf = sessions.filter(group__parent__type__slug = 'area').exclude(group__acronym='edu')
|
||||
irtf = sessions.filter(group__parent__acronym = 'irtf')
|
||||
training = sessions.filter(group__acronym__in=['edu','iaoc'], type_id__in=['regular', 'other',]).exclude(current_status='notmeet')
|
||||
iab = sessions.filter(group__parent__acronym = 'iab').exclude(current_status='notmeet')
|
||||
sessions = (
|
||||
meeting.session_set.with_current_status()
|
||||
.filter(Q(timeslotassignments__schedule__in=[schedule, schedule.base if schedule else None])
|
||||
| Q(current_status='notmeet'))
|
||||
.select_related()
|
||||
.order_by('-current_status')
|
||||
)
|
||||
|
||||
plenaries, _ = organize_proceedings_sessions(
|
||||
sessions.filter(name__icontains='plenary')
|
||||
.exclude(current_status='notmeet')
|
||||
)
|
||||
irtf, _ = organize_proceedings_sessions(
|
||||
sessions.filter(group__parent__acronym = 'irtf').order_by('group__acronym')
|
||||
)
|
||||
training, _ = organize_proceedings_sessions(
|
||||
sessions.filter(group__acronym__in=['edu','iaoc'], type_id__in=['regular', 'other',])
|
||||
.exclude(current_status='notmeet')
|
||||
)
|
||||
iab, _ = organize_proceedings_sessions(
|
||||
sessions.filter(group__parent__acronym = 'iab')
|
||||
.exclude(current_status='notmeet')
|
||||
)
|
||||
|
||||
ietf = sessions.filter(group__parent__type__slug = 'area').exclude(group__acronym='edu').order_by('group__parent__acronym', 'group__acronym')
|
||||
ietf_areas = []
|
||||
for area, area_sessions in itertools.groupby(
|
||||
ietf,
|
||||
key=lambda s: s.group.parent
|
||||
):
|
||||
meeting_groups, not_meeting_groups = organize_proceedings_sessions(area_sessions)
|
||||
ietf_areas.append((area, meeting_groups, not_meeting_groups))
|
||||
|
||||
cache_version = Document.objects.filter(session__meeting__number=meeting.number).aggregate(Max('time'))["time__max"]
|
||||
|
||||
ietf_areas = []
|
||||
for area, sessions in itertools.groupby(sorted(ietf, key=lambda s: (s.group.parent.acronym, s.group.acronym)), key=lambda s: s.group.parent):
|
||||
sessions = list(sessions)
|
||||
meeting_groups = set(s.group_id for s in sessions if s.current_status != 'notmeet')
|
||||
meeting_sessions = []
|
||||
not_meeting_sessions = []
|
||||
for s in sessions:
|
||||
if s.current_status == 'notmeet' and s.group_id not in meeting_groups:
|
||||
not_meeting_sessions.append(s)
|
||||
else:
|
||||
meeting_sessions.append(s)
|
||||
ietf_areas.append((area, meeting_sessions, not_meeting_sessions))
|
||||
|
||||
with timezone.override(meeting.tz()):
|
||||
return render(request, "meeting/proceedings.html", {
|
||||
'meeting': meeting,
|
||||
'plenaries': plenaries, 'ietf': ietf, 'training': training, 'irtf': irtf, 'iab': iab,
|
||||
'plenaries': plenaries,
|
||||
'training': training,
|
||||
'irtf': irtf,
|
||||
'iab': iab,
|
||||
'ietf_areas': ietf_areas,
|
||||
'cut_off_date': cut_off_date,
|
||||
'cor_cut_off_date': cor_cut_off_date,
|
||||
|
|
|
@ -5,111 +5,85 @@
|
|||
{% load proceedings_filters %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if session.name %}
|
||||
<div id="{{ session.name|slugify }}">{{ session.name }}</div>
|
||||
{% else %}
|
||||
<div id="{{ session.group.acronym }}">
|
||||
<a href="{% url 'ietf.group.views.group_home' acronym=session.group.acronym %}">{{ session.group.acronym }}</a>
|
||||
{% if entry.name %}
|
||||
<div id="{{ entry.name|slugify }}">{{ entry.name }}</div>
|
||||
{% elif entry.group.acronym %}
|
||||
<div id="{{ entry.group.acronym }}">
|
||||
<a href="{% url 'ietf.group.views.group_home' acronym=entry.group.acronym %}">{{ entry.group.acronym }}</a>
|
||||
</div>
|
||||
{% if session.group.state_id == "bof" %}<span class="badge rounded-pill bg-success">BOF</span>{% endif %}
|
||||
{% if entry.group.state_id == "bof" %}<span class="badge rounded-pill bg-success">BOF</span>{% endif %}
|
||||
{% else %}
|
||||
<h1>{{ entry.group }}</h1>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if session.all_meeting_sessions_cancelled %}
|
||||
{% if entry.canceled %}
|
||||
<td colspan="4">
|
||||
<span class="badge rounded-pill bg-danger">Session cancelled</span>
|
||||
</td>
|
||||
{% else %}
|
||||
{# artifacts #}
|
||||
<td>
|
||||
{% if session.all_meeting_agendas %}
|
||||
{% if session.all_meeting_agendas|length == 1 %}
|
||||
<a href="{{ session.all_meeting_agendas.0|meeting_href:meeting }}">Agenda</a>
|
||||
<br>
|
||||
{% else %}
|
||||
{% for agenda in session.all_meeting_agendas %}
|
||||
<a href="{{ agenda|meeting_href:meeting }}">
|
||||
Agenda {{ agenda.sessionpresentation_set.first.session.official_timeslotassignment.timeslot.time|date:"D G:i" }}
|
||||
</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if show_agenda == "True" and not meeting.proceedings_final %}
|
||||
{% for agenda in entry.agendas %}
|
||||
<a href="{{ agenda.material|meeting_href:meeting }}">
|
||||
Agenda
|
||||
{% if agenda.time %}{{agenda.time|date:"D G:i"}}{% endif %}
|
||||
</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
{% if show_agenda and not meeting.proceedings_final %}
|
||||
<span class="badge rounded-pill bg-warning">No agenda</span>
|
||||
<br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if session.all_meeting_minutes %}
|
||||
{% if session.all_meeting_minutes|length == 1 %}
|
||||
<a href="{{ session.all_meeting_minutes.0|meeting_href:meeting }}">Minutes</a>
|
||||
<br>
|
||||
{% else %}
|
||||
{% for minutes in session.all_meeting_minutes %}
|
||||
<a href="{{ minutes|meeting_href:meeting }}">
|
||||
Minutes {{ minutes.sessionpresentation_set.first.session.official_timeslotassignment.timeslot.time|date:"D G:i" }}
|
||||
</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if show_agenda == "True" and not meeting.proceedings_final %}
|
||||
{% endfor %}
|
||||
{% for minutes in entry.minutes %}
|
||||
<a href="{{ minutes.material|meeting_href:meeting }}">
|
||||
Minutes
|
||||
{% if minutes.time %}{{minutes.time|date:"D G:i"}}{% endif %}
|
||||
</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
{% if show_agenda and not meeting.proceedings_final %}
|
||||
<span class="badge rounded-pill bg-warning">No minutes</span>
|
||||
<br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if session.all_meeting_bluesheets %}
|
||||
{% if session.all_meeting_bluesheets|length == 1 %}
|
||||
<a href="{{ session.all_meeting_bluesheets.0|meeting_href:meeting }}">Bluesheets</a>
|
||||
<br>
|
||||
{% else %}
|
||||
{% for bs in session.all_meeting_bluesheets %}
|
||||
<a href="{{ bs|meeting_href:meeting }}">
|
||||
Bluesheets {{ bs.sessionpresentation_set.first.session.official_timeslotassignment.timeslot.time|date:"D G:i" }}
|
||||
</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% with session.group|status_for_meeting:meeting as status %}
|
||||
{% if status %}
|
||||
<a href="{% url 'ietf.group.views.group_about_status_meeting' acronym=session.group.acronym num=meeting.number %}">
|
||||
Status
|
||||
</a>
|
||||
<br>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% for bs in entry.bluesheets %}
|
||||
<a href="{{ bs.material|meeting_href:meeting }}">
|
||||
Bluesheets
|
||||
{% if bs.time %}{{ bs.time|date:"D G:i" }}{% endif %}
|
||||
</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# recordings #}
|
||||
<td>
|
||||
{% if session.all_meeting_sessions_for_group|length == 1 %}
|
||||
{% for rec in session.all_meeting_recordings %}
|
||||
<a href="{{ rec|meeting_href:meeting|default:"#" }}">{{ rec|hack_recording_title:False }}</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for rec in session.all_meeting_recordings %}
|
||||
<a href="{{ rec|meeting_href:meeting|default:"#" }}">{{ rec|hack_recording_title:True }}</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% for rec in entry.recordings %}
|
||||
<a href="{{ rec.material|meeting_href:meeting|default:"#" }}">
|
||||
{{ rec.material|hack_recording_title }}
|
||||
{% if rec.time %}{{ rec.time|date:"D G:i"}}{% endif %}
|
||||
</a>
|
||||
<br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# slides #}
|
||||
<td>
|
||||
{% with session.all_meeting_slides as slides %}
|
||||
{% for slide in slides %}
|
||||
<a href="{{ slide|meeting_href:meeting }}">{{ slide.title|clean_whitespace }}</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
{% if not meeting.proceedings_final %}<span class="badge rounded-pill bg-warning">No slides</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% for slide in entry.slides %}
|
||||
<a href="{{ slide.material|meeting_href:meeting }}">{{ slide.material.title|clean_whitespace }}</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
{% if not meeting.proceedings_final %}<span class="badge rounded-pill bg-warning">No slides</span>{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
{# drafts #}
|
||||
<td>
|
||||
{% with session.all_meeting_drafts as drafts %}
|
||||
{% for draft in drafts %}
|
||||
<a href="{% url "ietf.doc.views_doc.document_main" name=draft.canonical_name %}">{{ draft.canonical_name }}</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
{% if not meeting.proceedings_final %}<span class="badge rounded-pill bg-warning">No drafts</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% for draft in entry.drafts %}
|
||||
<a href="{% url "ietf.doc.views_doc.document_main" name=draft.material.canonical_name %}">
|
||||
{{ draft.material.canonical_name }}
|
||||
</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
{% if not meeting.proceedings_final %}<span class="badge rounded-pill bg-warning">No drafts</span>{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</tr>
|
||||
|
|
|
@ -23,10 +23,32 @@
|
|||
{% load cache %}
|
||||
{% cache 900 ietf_meeting_proceedings meeting.number cache_version %}
|
||||
{% include 'meeting/proceedings/introduction.html' with meeting=meeting only %}
|
||||
{% with "True" as show_agenda %}
|
||||
<!-- Plenaries -->
|
||||
{% if plenaries %}
|
||||
<h2 class="mt-5" id="plenaries">Plenaries</h2>
|
||||
<!-- Plenaries -->
|
||||
{% if plenaries %}
|
||||
<h2 class="mt-5" id="plenaries">Plenaries</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">Group</th>
|
||||
<th scope="col" data-sort="artifacts">Artifacts</th>
|
||||
<th scope="col" data-sort="recordings">Recordings</th>
|
||||
<th scope="col" data-sort="slides">Slides</th>
|
||||
<th scope="col" data-sort="drafts">Drafts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in plenaries %}
|
||||
{% include "meeting/group_proceedings.html" with entry=entry meeting=meeting show_agenda=True only %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<!-- Working groups -->
|
||||
{% for area, meeting_groups, not_meeting_groups in ietf_areas %}
|
||||
<h2 class="mt-5" id="{{ area.acronym }}">
|
||||
{{ area.acronym|upper }} <small class="text-muted">{{ area.name }}</small>
|
||||
</h2>
|
||||
{% if meeting_groups %}
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -38,161 +60,125 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in plenaries %}
|
||||
{% include "meeting/group_proceedings.html" %}
|
||||
{% for entry in meeting_groups %}
|
||||
{% include "meeting/group_proceedings.html" with entry=entry meeting=meeting show_agenda=True only %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<!-- Working groups -->
|
||||
{% for area, meeting_sessions, not_meeting_sessions in ietf_areas %}
|
||||
<h2 class="mt-5" id="{{ area.acronym }}">
|
||||
{{ area.acronym|upper }} <small class="text-muted">{{ area.name }}</small>
|
||||
</h2>
|
||||
{% if meeting_sessions %}
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">Group</th>
|
||||
<th scope="col" data-sort="artifacts">Artifacts</th>
|
||||
<th scope="col" data-sort="recordings">Recordings</th>
|
||||
<th scope="col" data-sort="slides">Slides</th>
|
||||
<th scope="col" data-sort="drafts">Drafts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in meeting_sessions %}
|
||||
{% ifchanged session.group.acronym %}
|
||||
{% include "meeting/group_proceedings.html" %}
|
||||
{% endifchanged %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% if not_meeting_sessions %}
|
||||
<p>
|
||||
{{ area.name }} groups not meeting:
|
||||
{% for session in not_meeting_sessions %}
|
||||
{% ifchanged session.group.acronym %}
|
||||
<a href="{% url 'ietf.group.views.group_home' acronym=session.group.acronym %}">{{ session.group.acronym }}</a>{% if not forloop.last %},{% endif %}
|
||||
{% endifchanged %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in not_meeting_sessions %}
|
||||
{% ifchanged session.group.acronym %}
|
||||
{% if session.sessionpresentation_set.exists %}
|
||||
{% include "meeting/group_proceedings.html" %}
|
||||
{% endif %}
|
||||
{% endifchanged %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Training Sessions -->
|
||||
{% if training %}
|
||||
{% with "False" as show_agenda %}
|
||||
<h2 class="mt-5" id="training">Training</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">Group</th>
|
||||
<th scope="col" data-sort="artifacts">Artifacts</th>
|
||||
<th scope="col" data-sort="recordings">Recordings</th>
|
||||
<th scope="col" data-sort="slides">Slides</th>
|
||||
<th scope="col" data-sort="drafts">Drafts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in training %}
|
||||
{% ifchanged %}
|
||||
{% include "meeting/group_proceedings.html" %}
|
||||
{% endifchanged %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
<!-- IAB Sessions -->
|
||||
{% if iab %}
|
||||
<h2 class="mt-5" id="iab">
|
||||
IAB <small class="text-muted">Internet Architecture Board</small>
|
||||
</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
{% if not_meeting_groups %}
|
||||
<p>
|
||||
{{ area.name }} groups not meeting:
|
||||
{% for entry in not_meeting_groups %}
|
||||
{% if entry.name == "" %}{# do not show named sessions in this list #}
|
||||
<a href="{% url 'ietf.group.views.group_home' acronym=entry.group.acronym %}">
|
||||
{{ entry.group.acronym }}
|
||||
</a>{% if not forloop.last %},{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">
|
||||
Group
|
||||
</th>
|
||||
<th scope="col" data-sort="artifacts">
|
||||
Artifacts
|
||||
</th>
|
||||
<th scope="col" data-sort="recordings">
|
||||
Recordings
|
||||
</th>
|
||||
<th scope="col" data-sort="slides">
|
||||
Slides
|
||||
</th>
|
||||
<th scope="col" data-sort="drafts">
|
||||
Drafts
|
||||
</th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in iab %}
|
||||
{% ifchanged %}
|
||||
{% include "meeting/group_proceedings.html" %}
|
||||
{% endifchanged %}
|
||||
{% endfor %}
|
||||
{% for entry in not_meeting_groups %}{% if entry.sessions_with_materials %}
|
||||
{% include "meeting/group_proceedings.html" with entry=entry meeting=meeting show_agenda=True only %}
|
||||
{% endif %}{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<!-- IRTF Sessions -->
|
||||
{% if irtf %}
|
||||
<h2 class="mt-5" id="irtf">
|
||||
IRTF <small class="text-muted">Internet Research Task Force</small>
|
||||
</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">
|
||||
Group
|
||||
</th>
|
||||
<th scope="col" data-sort="artifacts">
|
||||
Artifacts
|
||||
</th>
|
||||
<th scope="col" data-sort="recordings">
|
||||
Recordings
|
||||
</th>
|
||||
<th scope="col" data-sort="slides">
|
||||
Slides
|
||||
</th>
|
||||
<th scope="col" data-sort="drafts">
|
||||
Drafts
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in irtf|dictsort:"group.acronym" %}
|
||||
{% ifchanged %}
|
||||
{% include "meeting/group_proceedings.html" %}
|
||||
{% endifchanged %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
<!-- Training Sessions -->
|
||||
{% if training %}
|
||||
<h2 class="mt-5" id="training">Training</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">Group</th>
|
||||
<th scope="col" data-sort="artifacts">Artifacts</th>
|
||||
<th scope="col" data-sort="recordings">Recordings</th>
|
||||
<th scope="col" data-sort="slides">Slides</th>
|
||||
<th scope="col" data-sort="drafts">Drafts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in training %}
|
||||
{% include "meeting/group_proceedings.html" with entry=entry meeting=meeting show_agenda=False only %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<!-- IAB Sessions -->
|
||||
{% if iab %}
|
||||
<h2 class="mt-5" id="iab">
|
||||
IAB <small class="text-muted">Internet Architecture Board</small>
|
||||
</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">
|
||||
Group
|
||||
</th>
|
||||
<th scope="col" data-sort="artifacts">
|
||||
Artifacts
|
||||
</th>
|
||||
<th scope="col" data-sort="recordings">
|
||||
Recordings
|
||||
</th>
|
||||
<th scope="col" data-sort="slides">
|
||||
Slides
|
||||
</th>
|
||||
<th scope="col" data-sort="drafts">
|
||||
Drafts
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in iab %}
|
||||
{% include "meeting/group_proceedings.html" with entry=entry meeting=meeting show_agenda=True only %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<!-- IRTF Sessions -->
|
||||
{% if irtf %}
|
||||
<h2 class="mt-5" id="irtf">
|
||||
IRTF <small class="text-muted">Internet Research Task Force</small>
|
||||
</h2>
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-sort="group">
|
||||
Group
|
||||
</th>
|
||||
<th scope="col" data-sort="artifacts">
|
||||
Artifacts
|
||||
</th>
|
||||
<th scope="col" data-sort="recordings">
|
||||
Recordings
|
||||
</th>
|
||||
<th scope="col" data-sort="slides">
|
||||
Slides
|
||||
</th>
|
||||
<th scope="col" data-sort="drafts">
|
||||
Drafts
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in irtf %}
|
||||
{% include "meeting/group_proceedings.html" with entry=entry meeting=meeting show_agenda=True only %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endcache %}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
|
|
Loading…
Reference in a new issue