Skip to content

Commit 0ad293d

Browse files
feat: add slides / session materials links to session details modal (ietf-tools#4535)
* feat: add propose/upload slides button to session details modal * refactor: remove unneeded chaining operator * test: fix quotes around template string * feat: link to meeting materials page from AgendaDetailsModal * refactor: compute session details URL in JS instead of view * chore: restyle materials page link * test: fix test case to match changes to session modal
1 parent 6f2114f commit 0ad293d

3 files changed

Lines changed: 90 additions & 31 deletions

File tree

client/agenda/AgendaDetailsModal.vue

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ n-modal(v-model:show='modalShown')
5555
)
5656
i.bi.bi-journal-text.me-2
5757
span Notepad
58+
n-button.float-end(
59+
ghost
60+
color='gray'
61+
strong
62+
tag='a'
63+
:href='eventDetails.detailsUrl'
64+
target='_blank'
65+
aria-label='Materials page'
66+
)
67+
span.me-2 {{props.event.groupAcronym}} materials page
68+
i.bi.bi-box-arrow-up-right
5869
.detail-content
5970
.detail-title
6071
h6
@@ -95,19 +106,29 @@ n-modal(v-model:show='modalShown')
95106
:src='eventDetails.materialsUrl'
96107
)
97108
template(v-else-if='state.tab === `slides`')
98-
.text-center(v-if='state.isLoading')
99-
n-spin(description='Loading slides...')
100-
.text-center.p-3(v-else-if='!state.materials || !state.materials.slides || state.materials.slides.length < 1')
101-
span No slides submitted for this session.
102-
.list-group(v-else)
103-
a.list-group-item(
104-
v-for='slide of state.materials.slides'
105-
:key='slide.id'
106-
:href='slide.url'
107-
target='_blank'
108-
)
109-
i.bi.me-2(:class='`bi-filetype-` + slide.ext')
110-
span {{slide.title}}
109+
n-card(
110+
:bordered='false'
111+
size='small'
112+
)
113+
.text-center(v-if='state.isLoading')
114+
n-spin(description='Loading slides...')
115+
.text-center.p-3(v-else-if='!state.materials || !state.materials.slides || !state.materials.slides.decks || state.materials.slides.decks.length < 1')
116+
span No slides submitted for this session.
117+
.list-group(v-else)
118+
a.list-group-item(
119+
v-for='deck of state.materials.slides.decks'
120+
:key='deck.id'
121+
:href='deck.url'
122+
target='_blank'
123+
)
124+
i.bi.me-2(:class='`bi-filetype-` + deck.ext')
125+
span {{deck.title}}
126+
template(#action, v-if='state.materials.slides.actions')
127+
n-button(
128+
v-for='action of state.materials.slides.actions'
129+
tag='a'
130+
:href='action.url'
131+
) {{action.label}}
111132
template(v-else)
112133
.text-center(v-if='state.isLoading')
113134
n-spin(description='Loading minutes...')
@@ -184,9 +205,10 @@ const eventDetails = computed(() => {
184205
title: props.event.type === 'regular' ? `${props.event.groupName} (${props.event.acronym})` : props.event.name,
185206
showAgenda: props.event.flags.showAgenda,
186207
materialsUrl: materialsUrl,
208+
detailsUrl: `/meeting/${agendaStore.meeting.number}/session/${props.event.acronym}/`,
187209
tarUrl: `/meeting/${agendaStore.meeting.number}/agenda/${props.event.acronym}-drafts.tgz`,
188210
pdfUrl: `/meeting/${agendaStore.meeting.number}/agenda/${props.event.acronym}-drafts.pdf`,
189-
notepadUrl: `https://notes.ietf.org/notes-ietf-${agendaStore.meeting.number}-${props.event.type === 'plenary' ? 'plenary' : props.event.acronym}`
211+
notepadUrl: `https://notes.ietf.org/notes-ietf-${agendaStore.meeting.number}-${props.event.type === 'plenary' ? 'plenary' : props.event.acronym}`,
190212
}
191213
})
192214
@@ -219,7 +241,10 @@ async function fetchSessionMaterials () {
219241
state.isLoading = true
220242
221243
try {
222-
const resp = await fetch(`/api/meeting/session/${props.event.sessionId}/materials`, { credentials: 'omit' })
244+
const resp = await fetch(
245+
`/api/meeting/session/${props.event.sessionId}/materials`,
246+
{ credentials: 'include' }
247+
)
223248
if (!resp.ok) {
224249
throw new Error(resp.statusText)
225250
}

ietf/meeting/views.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,10 +1642,32 @@ def api_get_session_materials (request, session_id=None):
16421642
session = get_object_or_404(Session,pk=session_id)
16431643

16441644
minutes = session.minutes()
1645+
slides_actions = []
1646+
if can_manage_session_materials(request.user, session.group, session):
1647+
slides_actions.append({
1648+
'label': 'Upload slides',
1649+
'url': reverse(
1650+
'ietf.meeting.views.upload_session_slides',
1651+
kwargs={'num': session.meeting.number, 'session_id': session.pk},
1652+
),
1653+
})
1654+
elif not session.is_material_submission_cutoff():
1655+
slides_actions.append({
1656+
'label': 'Propose slides',
1657+
'url': reverse(
1658+
'ietf.meeting.views.propose_session_slides',
1659+
kwargs={'num': session.meeting.number, 'session_id': session.pk},
1660+
),
1661+
})
1662+
else:
1663+
pass # no action available if it's past cutoff
16451664

16461665
return JsonResponse({
16471666
"url": session.agenda().get_href(),
1648-
"slides": list(map(agenda_extract_slide, session.slides())),
1667+
"slides": {
1668+
"decks": list(map(agenda_extract_slide, session.slides())),
1669+
"actions": slides_actions,
1670+
},
16491671
"minutes": {
16501672
"id": minutes.id,
16511673
"title": minutes.title,
@@ -1700,7 +1722,10 @@ def agenda_extract_schedule (item):
17001722
"audioStream": item.timeslot.location.audio_stream_url() if item.timeslot.location else "",
17011723
"webex": item.timeslot.location.webex_url() if item.timeslot.location else "",
17021724
"onsiteTool": item.timeslot.location.onsite_tool_url() if item.timeslot.location else "",
1703-
"calendar": reverse('ietf.meeting.views.agenda_ical', kwargs={'num': item.schedule.meeting.number, 'session_id': item.session.id, })
1725+
"calendar": reverse(
1726+
'ietf.meeting.views.agenda_ical',
1727+
kwargs={'num': item.schedule.meeting.number, 'session_id': item.session.id},
1728+
),
17041729
}
17051730
# "slotType": {
17061731
# "slug": item.slot_type.slug

playwright/tests/meeting/agenda.spec.js

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,18 @@ test.describe('past - desktop', () => {
368368
const materialsUrl = (new URL(event.agenda.url)).pathname
369369
const materialsInfo = {
370370
url: event.agenda.url,
371-
slides: _.times(5, idx => ({
372-
id: 100000 + idx,
373-
title: faker.commerce.productName(),
374-
url: `/meeting/${meetingData.meeting.number}/materials/slides-${meetingData.meeting.number}-${event.acronym}-${faker.internet.domainWord()}`,
375-
ext: ['pdf', 'html', 'md', 'txt', 'pptx'][idx]
376-
})),
371+
slides: {
372+
decks: _.times(5, idx => ({
373+
id: 100000 + idx,
374+
title: faker.commerce.productName(),
375+
url: `/meeting/${meetingData.meeting.number}/materials/slides-${meetingData.meeting.number}-${event.acronym}-${faker.internet.domainWord()}`,
376+
ext: ['pdf', 'html', 'md', 'txt', 'pptx'][idx]
377+
})),
378+
actions: [{
379+
label: 'Propose slides',
380+
url: `/meeting/${meetingData.meeting.number}/session/${event.sessionId}/propose_slides`
381+
}]
382+
},
377383
minutes: {
378384
ext: 'md',
379385
id: 123456,
@@ -427,13 +433,16 @@ test.describe('past - desktop', () => {
427433
await navLocator.nth(1).click()
428434
await expect(navLocator.nth(1)).toHaveClass(/active/)
429435
await expect(navLocator.first()).not.toHaveClass(/active/)
430-
const slidesLocator = page.locator('.agenda-eventdetails .detail-text > .list-group > .list-group-item')
431-
await expect(slidesLocator).toHaveCount(materialsInfo.slides.length)
432-
for (let idx = 0; idx < materialsInfo.slides.length; idx++) {
433-
await expect(slidesLocator.nth(idx)).toHaveAttribute('href', materialsInfo.slides[idx].url)
434-
await expect(slidesLocator.nth(idx).locator('.bi')).toHaveClass(new RegExp(`bi-filetype-${materialsInfo.slides[idx].ext}`))
435-
await expect(slidesLocator.nth(idx).locator('span')).toContainText(materialsInfo.slides[idx].title)
436+
const slideDecksLocator = page.locator('.agenda-eventdetails .detail-text .n-card__content > .list-group > .list-group-item')
437+
await expect(slideDecksLocator).toHaveCount(materialsInfo.slides.decks.length)
438+
for (let idx = 0; idx < materialsInfo.slides.decks.length; idx++) {
439+
await expect(slideDecksLocator.nth(idx)).toHaveAttribute('href', materialsInfo.slides.decks[idx].url)
440+
await expect(slideDecksLocator.nth(idx).locator('.bi')).toHaveClass(new RegExp(`bi-filetype-${materialsInfo.slides.decks[idx].ext}`))
441+
await expect(slideDecksLocator.nth(idx).locator('span')).toContainText(materialsInfo.slides.decks[idx].title)
436442
}
443+
const slideActionButtonLocator = page.locator('.agenda-eventdetails .detail-text .n-card__action > a')
444+
await expect(slideActionButtonLocator).toHaveCount(1)
445+
await expect(slideActionButtonLocator.first().locator('span')).toContainText('Propose slides')
437446
// Minutes Tab
438447
await navLocator.last().click()
439448
await expect(navLocator.last()).toHaveClass(/active/)
@@ -442,7 +451,7 @@ test.describe('past - desktop', () => {
442451
// Footer Buttons
443452
const hedgeDocLink = `https://notes.ietf.org/notes-ietf-${meetingData.meeting.number}-${event.type === 'plenary' ? 'plenary' : event.acronym}`
444453
const footerBtnsLocator = page.locator('.agenda-eventdetails .detail-action > a')
445-
await expect(footerBtnsLocator).toHaveCount(3)
454+
await expect(footerBtnsLocator).toHaveCount(4)
446455
await expect(footerBtnsLocator.first()).toContainText('Download as tarball')
447456
await expect(footerBtnsLocator.first()).toHaveAttribute('href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.tgz`)
448457
await expect(footerBtnsLocator.nth(1)).toContainText('Download as PDF')
@@ -483,7 +492,7 @@ test.describe('past - desktop', () => {
483492
await expect(page.locator('.agenda-eventdetails')).toBeVisible()
484493
// Slides Tab
485494
await page.locator('.agenda-eventdetails .detail-nav > a').nth(1).click()
486-
await expect(page.locator('.agenda-eventdetails .detail-text')).toContainText('No slides submitted for this session.')
495+
await expect(page.locator('.agenda-eventdetails .detail-text .n-card__content')).toContainText('No slides submitted for this session.')
487496
// Minutes Tab
488497
await page.locator('.agenda-eventdetails .detail-nav > a').nth(2).click()
489498
await expect(page.locator('.agenda-eventdetails .detail-text')).toContainText('No minutes submitted for this session.')

0 commit comments

Comments
 (0)