feat: replace old agenda with agenda-neue (#4406)
* feat: remove old agenda (django-side) * fix: bring in latest commits * test: remove -neue from playwright tests * test: remove agenda selenium js tests * test: remove agenda views tests * fix: remove deprecated agenda views (week-view, agenda-by, floor-plan) * test: fix failing python tests * test: remove more deprecated tests * chore: remove deprecated templates * test: remove unused import * feat: handle agenda personalize with filter + move agenda specific stuff out of root component * fix: redirect deprecated urls to agenda / floorplan * feat: agenda - open picker mode when from personalize path * fix: safari doesn't support device-pixel-content-box property on ResizeObserver * test: move floor plan test into main agenda test Co-authored-by: Robert Sparks <rjsparks@nostrum.com>
This commit is contained in:
parent
8560bec09c
commit
6f2114fb0c
|
@ -1,9 +1,9 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
n-theme
|
n-theme
|
||||||
n-message-provider
|
n-message-provider
|
||||||
.app-error(v-if='agendaStore.criticalError')
|
.app-error(v-if='siteStore.criticalError')
|
||||||
i.bi.bi-x-octagon-fill.me-2
|
i.bi.bi-x-octagon-fill.me-2
|
||||||
span {{agendaStore.criticalError}}
|
span {{siteStore.criticalError}}
|
||||||
.app-container(ref='appContainer')
|
.app-container(ref='appContainer')
|
||||||
router-view.meeting
|
router-view.meeting
|
||||||
</template>
|
</template>
|
||||||
|
@ -12,13 +12,13 @@ n-theme
|
||||||
import { onBeforeUnmount ,onMounted, ref } from 'vue'
|
import { onBeforeUnmount ,onMounted, ref } from 'vue'
|
||||||
import { NMessageProvider } from 'naive-ui'
|
import { NMessageProvider } from 'naive-ui'
|
||||||
|
|
||||||
import { useAgendaStore } from './agenda/store'
|
import { useSiteStore } from './shared/store'
|
||||||
|
|
||||||
import NTheme from './components/n-theme.vue'
|
import NTheme from './components/n-theme.vue'
|
||||||
|
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
|
|
||||||
|
@ -29,14 +29,14 @@ const appContainer = ref(null)
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(entries => {
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
agendaStore.$patch({ viewport: Math.round(window.innerWidth) })
|
siteStore.$patch({ viewport: Math.round(window.innerWidth) })
|
||||||
// for (const entry of entries) {
|
// for (const entry of entries) {
|
||||||
// const newWidth = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width
|
// const newWidth = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width
|
||||||
// }
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
resizeObserver.observe(appContainer.value, { box: 'device-pixel-content-box' })
|
resizeObserver.observe(appContainer.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
@ -47,7 +47,6 @@ onBeforeUnmount(() => {
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "bootstrap/scss/functions";
|
@import "bootstrap/scss/functions";
|
||||||
@import "bootstrap/scss/variables";
|
@import "bootstrap/scss/variables";
|
||||||
@import "./shared/breakpoints";
|
|
||||||
|
|
||||||
.app-error {
|
.app-error {
|
||||||
background-color: $red-500;
|
background-color: $red-500;
|
||||||
|
@ -57,69 +56,4 @@ onBeforeUnmount(() => {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meeting {
|
|
||||||
> h1 {
|
|
||||||
font-weight: 500;
|
|
||||||
color: $gray-700;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
@media screen and (max-width: $bs5-break-sm) {
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
font-size: .95em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 700;
|
|
||||||
background: linear-gradient(220deg, $blue-500 20%, $purple-500 70%);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
box-decoration-break: clone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-h1-badges {
|
|
||||||
display: flex;
|
|
||||||
justify-content: end;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 700;
|
|
||||||
background-color: $pink-500;
|
|
||||||
box-shadow: 0 0 5px 0 rgba($pink-500, .5);
|
|
||||||
color: #FFF;
|
|
||||||
padding: 5px 8px;
|
|
||||||
border-radius: 6px;
|
|
||||||
|
|
||||||
& + span {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-warning {
|
|
||||||
background-color: $red-500 !important;
|
|
||||||
box-shadow: 0 0 5px 0 rgba($red-500, .5) !important;
|
|
||||||
color: #FFF;
|
|
||||||
animation: warningBorderFlash 1s ease infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
> h4 {
|
|
||||||
@media screen and (max-width: $bs5-break-sm) {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
font-size: .8em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
span #[strong IETF {{agendaStore.meeting.number}}] Meeting Agenda {{titleExtra}}
|
span #[strong IETF {{agendaStore.meeting.number}}] Meeting Agenda {{titleExtra}}
|
||||||
.meeting-h1-badges.d-none.d-sm-flex
|
.meeting-h1-badges.d-none.d-sm-flex
|
||||||
span.meeting-warning(v-if='agendaStore.meeting.warningNote') {{agendaStore.meeting.warningNote}}
|
span.meeting-warning(v-if='agendaStore.meeting.warningNote') {{agendaStore.meeting.warningNote}}
|
||||||
span.meeting-beta BETA
|
|
||||||
h4
|
h4
|
||||||
span {{agendaStore.meeting.city}}, {{ meetingDate }}
|
span {{agendaStore.meeting.city}}, {{ meetingDate }}
|
||||||
h6.float-end.d-none.d-lg-inline(v-if='meetingUpdated') #[span.text-muted Updated:] {{ meetingUpdated }}
|
h6.float-end.d-none.d-lg-inline(v-if='meetingUpdated') #[span.text-muted Updated:] {{ meetingUpdated }}
|
||||||
|
@ -54,7 +53,7 @@
|
||||||
@click='setTimezone(`UTC`)'
|
@click='setTimezone(`UTC`)'
|
||||||
) UTC
|
) UTC
|
||||||
n-select.agenda-timezone-ddn(
|
n-select.agenda-timezone-ddn(
|
||||||
v-if='agendaStore.viewport > 1250'
|
v-if='siteStore.viewport > 1250'
|
||||||
v-model:value='agendaStore.timezone'
|
v-model:value='agendaStore.timezone'
|
||||||
:options='timezones'
|
:options='timezones'
|
||||||
placeholder='Select Time Zone'
|
placeholder='Select Time Zone'
|
||||||
|
@ -134,7 +133,7 @@
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
// -> Anchored Day Quick Access Menu
|
// -> Anchored Day Quick Access Menu
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
.col-auto.d-print-none(v-if='agendaStore.viewport >= 990')
|
.col-auto.d-print-none(v-if='siteStore.viewport >= 990')
|
||||||
agenda-quick-access
|
agenda-quick-access
|
||||||
|
|
||||||
agenda-mobile-bar
|
agenda-mobile-bar
|
||||||
|
@ -166,6 +165,9 @@ import MeetingNavigation from './MeetingNavigation.vue'
|
||||||
import timezones from '../shared/timezones'
|
import timezones from '../shared/timezones'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store'
|
||||||
|
|
||||||
|
import './agenda.scss'
|
||||||
|
|
||||||
// MESSAGE PROVIDER
|
// MESSAGE PROVIDER
|
||||||
|
|
||||||
|
@ -174,6 +176,7 @@ const message = useMessage()
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// ROUTER
|
// ROUTER
|
||||||
|
|
||||||
|
@ -215,7 +218,35 @@ watch(() => agendaStore.meetingDays, () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => agendaStore.isLoaded, handleCurrentMeetingRedirect)
|
watch(() => agendaStore.isLoaded, () => {
|
||||||
|
if (route.query.show) {
|
||||||
|
// Handle legacy ?show= parameter
|
||||||
|
const keywords = route.query.show.split(',').map(k => k.trim()).filter(k => !!k)
|
||||||
|
if (keywords?.length > 0) {
|
||||||
|
const pickedIds = []
|
||||||
|
for (const ev of agendaStore.scheduleAdjusted) {
|
||||||
|
if (keywords.includes(ev.sessionKeyword)) {
|
||||||
|
pickedIds.push(ev.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pickedIds.length > 0) {
|
||||||
|
agendaStore.$patch({
|
||||||
|
pickerMode: true,
|
||||||
|
pickerModeView: true,
|
||||||
|
pickedEvents: pickedIds
|
||||||
|
})
|
||||||
|
agendaStore.persistMeetingPreferences()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (route.query.pick) {
|
||||||
|
// Handle legacy /personalize path (open picker mode)
|
||||||
|
agendaStore.$patch({ pickerMode: true })
|
||||||
|
router.replace({ query: null })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCurrentMeetingRedirect()
|
||||||
|
})
|
||||||
|
|
||||||
// COMPUTED
|
// COMPUTED
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.agenda-mobile-bar(v-if='agendaStore.viewport < 990')
|
.agenda-mobile-bar(v-if='siteStore.viewport < 990')
|
||||||
button(@click='agendaStore.$patch({ filterShown: true })')
|
button(@click='agendaStore.$patch({ filterShown: true })')
|
||||||
i.bi.bi-filter-square-fill.me-2
|
i.bi.bi-filter-square-fill.me-2
|
||||||
span Filters
|
span Filters
|
||||||
|
@ -31,6 +31,7 @@ import {
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store';
|
||||||
|
|
||||||
// MESSAGE PROVIDER
|
// MESSAGE PROVIDER
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ const message = useMessage()
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// Download Ics Options
|
// Download Ics Options
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, h } from 'vue'
|
import { computed, h } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
import {
|
import {
|
||||||
NAffix,
|
NAffix,
|
||||||
|
@ -119,6 +120,7 @@ import {
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store';
|
||||||
|
|
||||||
// MESSAGE PROVIDER
|
// MESSAGE PROVIDER
|
||||||
|
|
||||||
|
@ -127,6 +129,12 @@ const message = useMessage()
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
|
// ROUTER
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
// Download Ics Options
|
// Download Ics Options
|
||||||
|
|
||||||
|
@ -146,7 +154,7 @@ const downloadIcsOptions = [
|
||||||
// COMPUTED
|
// COMPUTED
|
||||||
|
|
||||||
const shortMode = computed(() => {
|
const shortMode = computed(() => {
|
||||||
return agendaStore.viewport <= 1350
|
return siteStore.viewport <= 1350
|
||||||
})
|
})
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
@ -163,6 +171,9 @@ function pickerModify () {
|
||||||
}
|
}
|
||||||
function pickerDiscard () {
|
function pickerDiscard () {
|
||||||
agendaStore.$patch({ pickerMode: false })
|
agendaStore.$patch({ pickerMode: false })
|
||||||
|
if (route.query.show) {
|
||||||
|
router.push({ query: null })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadIcs (key) {
|
function downloadIcs (key) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ n-drawer(v-model:show='isShown', placement='bottom', :height='state.drawerHeight
|
||||||
template(#header)
|
template(#header)
|
||||||
span Calendar View
|
span Calendar View
|
||||||
.agenda-calendar-actions
|
.agenda-calendar-actions
|
||||||
template(v-if='agendaStore.viewport > 990')
|
template(v-if='siteStore.viewport > 990')
|
||||||
i.bi.bi-globe.me-2
|
i.bi.bi-globe.me-2
|
||||||
small.me-2: strong Timezone:
|
small.me-2: strong Timezone:
|
||||||
n-button-group
|
n-button-group
|
||||||
|
@ -91,10 +91,12 @@ import bootstrap5Plugin from '@fullcalendar/bootstrap5'
|
||||||
import AgendaDetailsModal from './AgendaDetailsModal.vue'
|
import AgendaDetailsModal from './AgendaDetailsModal.vue'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store'
|
||||||
|
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
th.agenda-table-head-check(v-if='pickerModeActive')
|
th.agenda-table-head-check(v-if='pickerModeActive')
|
||||||
th.agenda-table-head-time Time
|
th.agenda-table-head-time Time
|
||||||
th.agenda-table-head-location(colspan='2') Location
|
th.agenda-table-head-location(colspan='2') Location
|
||||||
th.agenda-table-head-event(colspan='2') {{ agendaStore.viewport < 990 ? '' : 'Event' }}
|
th.agenda-table-head-event(colspan='2') {{ siteStore.viewport < 990 ? '' : 'Event' }}
|
||||||
tbody
|
tbody
|
||||||
tr.agenda-table-display-noresult(
|
tr.agenda-table-display-noresult(
|
||||||
v-if='!meetingEvents || meetingEvents.length < 1'
|
v-if='!meetingEvents || meetingEvents.length < 1'
|
||||||
|
@ -58,13 +58,13 @@
|
||||||
span.badge {{item.location.short}}
|
span.badge {{item.location.short}}
|
||||||
span {{item.location.name}}
|
span {{item.location.name}}
|
||||||
router-link.discreet(
|
router-link.discreet(
|
||||||
:to='`/meeting/` + agendaStore.meeting.number + `/floor-plan-neue?room=` + xslugify(item.room)'
|
:to='`/meeting/` + agendaStore.meeting.number + `/floor-plan?room=` + xslugify(item.room)'
|
||||||
:aria-label='item.room'
|
:aria-label='item.room'
|
||||||
) {{item.room}}
|
) {{item.room}}
|
||||||
span(v-else) {{item.room}}
|
span(v-else) {{item.room}}
|
||||||
//- CELL - GROUP --------------------------
|
//- CELL - GROUP --------------------------
|
||||||
td.agenda-table-cell-group(v-if='item.type === `regular`')
|
td.agenda-table-cell-group(v-if='item.type === `regular`')
|
||||||
span.badge(v-if='agendaStore.areaIndicatorsShown && agendaStore.viewport > 1200') {{item.groupAcronym}}
|
span.badge(v-if='agendaStore.areaIndicatorsShown && siteStore.viewport > 1200') {{item.groupAcronym}}
|
||||||
a.discreet(:href='`/group/` + item.acronym + `/about/`') {{item.acronym}}
|
a.discreet(:href='`/group/` + item.acronym + `/about/`') {{item.acronym}}
|
||||||
//- CELL - NAME ---------------------------
|
//- CELL - NAME ---------------------------
|
||||||
td.agenda-table-cell-name
|
td.agenda-table-cell-name
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
template(v-else)
|
template(v-else)
|
||||||
span.badge.is-cancelled(v-if='!isMobile && item.status === `canceled`') Cancelled
|
span.badge.is-cancelled(v-if='!isMobile && item.status === `canceled`') Cancelled
|
||||||
span.badge.is-rescheduled(v-else-if='!isMobile && item.status === `resched`') Rescheduled
|
span.badge.is-rescheduled(v-else-if='!isMobile && item.status === `resched`') Rescheduled
|
||||||
.agenda-table-cell-links-buttons(v-else-if='agendaStore.viewport < 1200 && item.links && item.links.length > 0')
|
.agenda-table-cell-links-buttons(v-else-if='siteStore.viewport < 1200 && item.links && item.links.length > 0')
|
||||||
n-dropdown(
|
n-dropdown(
|
||||||
v-if='!agendaStore.colorPickerVisible'
|
v-if='!agendaStore.colorPickerVisible'
|
||||||
trigger='click'
|
trigger='click'
|
||||||
|
@ -201,6 +201,7 @@ import {
|
||||||
import AgendaDetailsModal from './AgendaDetailsModal.vue'
|
import AgendaDetailsModal from './AgendaDetailsModal.vue'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store'
|
||||||
|
|
||||||
// MESSAGE PROVIDER
|
// MESSAGE PROVIDER
|
||||||
|
|
||||||
|
@ -209,6 +210,7 @@ const message = useMessage()
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// DATA
|
// DATA
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ const meetingEvents = computed(() => {
|
||||||
|
|
||||||
return reduce(sortBy(agendaStore.scheduleAdjusted, 'adjustedStartDate'), (acc, item) => {
|
return reduce(sortBy(agendaStore.scheduleAdjusted, 'adjustedStartDate'), (acc, item) => {
|
||||||
const isLive = current >= item.adjustedStart && current < item.adjustedEnd
|
const isLive = current >= item.adjustedStart && current < item.adjustedEnd
|
||||||
const itemTimeSlot = agendaStore.viewport > 576 ?
|
const itemTimeSlot = siteStore.viewport > 576 ?
|
||||||
`${item.adjustedStart.toFormat('HH:mm')} - ${item.adjustedEnd.toFormat('HH:mm')}` :
|
`${item.adjustedStart.toFormat('HH:mm')} - ${item.adjustedEnd.toFormat('HH:mm')}` :
|
||||||
`${item.adjustedStart.toFormat('HH:mm')} ${item.adjustedEnd.toFormat('HH:mm')}`
|
`${item.adjustedStart.toFormat('HH:mm')} ${item.adjustedEnd.toFormat('HH:mm')}`
|
||||||
|
|
||||||
|
@ -482,7 +484,7 @@ const pickedEvents = computed({
|
||||||
})
|
})
|
||||||
|
|
||||||
const isMobile = computed(() => {
|
const isMobile = computed(() => {
|
||||||
return agendaStore.viewport < 576
|
return siteStore.viewport < 576
|
||||||
})
|
})
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
|
@ -198,6 +198,8 @@ import {
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store'
|
||||||
|
|
||||||
import timezones from '../shared/timezones'
|
import timezones from '../shared/timezones'
|
||||||
|
|
||||||
// MESSAGE PROVIDER
|
// MESSAGE PROVIDER
|
||||||
|
@ -207,6 +209,7 @@ const message = useMessage()
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
|
|
||||||
|
@ -266,7 +269,7 @@ const calcOffset = computed(() => {
|
||||||
return agendaStore.nowDebugDiff ? JSON.stringify(agendaStore.nowDebugDiff.toObject()) : 'None'
|
return agendaStore.nowDebugDiff ? JSON.stringify(agendaStore.nowDebugDiff.toObject()) : 'None'
|
||||||
})
|
})
|
||||||
const panelWidth = computed(() => {
|
const panelWidth = computed(() => {
|
||||||
return agendaStore.viewport > 500 ? 500 : agendaStore.viewport
|
return siteStore.viewport > 500 ? 500 : siteStore.viewport
|
||||||
})
|
})
|
||||||
|
|
||||||
// WATCHERS
|
// WATCHERS
|
||||||
|
|
|
@ -59,13 +59,18 @@ import find from 'lodash/find'
|
||||||
import xslugify from '../shared/xslugify'
|
import xslugify from '../shared/xslugify'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
import { useAgendaStore } from './store'
|
import { useAgendaStore } from './store'
|
||||||
|
import { useSiteStore } from '../shared/store'
|
||||||
|
|
||||||
import MeetingNavigation from './MeetingNavigation.vue'
|
import MeetingNavigation from './MeetingNavigation.vue'
|
||||||
|
|
||||||
|
import './agenda.scss'
|
||||||
|
|
||||||
// STORES
|
// STORES
|
||||||
|
|
||||||
const agendaStore = useAgendaStore()
|
const agendaStore = useAgendaStore()
|
||||||
|
const siteStore = useSiteStore()
|
||||||
|
|
||||||
// ROUTER
|
// ROUTER
|
||||||
|
|
||||||
|
@ -144,7 +149,7 @@ watch(() => state.currentRoom, () => {
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
watch(() => agendaStore.viewport, () => {
|
watch(() => siteStore.viewport, () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
computePlanSizeRatio()
|
computePlanSizeRatio()
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,7 +10,7 @@ ul.nav.nav-tabs.meeting-nav(v-if='agendaStore.isLoaded')
|
||||||
router-link.nav-link(
|
router-link.nav-link(
|
||||||
v-else
|
v-else
|
||||||
active-class='active'
|
active-class='active'
|
||||||
:to='`/meeting/` + agendaStore.meeting.number + `/` + tab.key + `-neue`'
|
:to='`/meeting/` + agendaStore.meeting.number + `/` + tab.key'
|
||||||
)
|
)
|
||||||
i.bi.me-2.d-none.d-sm-inline(:class='tab.icon')
|
i.bi.me-2.d-none.d-sm-inline(:class='tab.icon')
|
||||||
span {{tab.title}}
|
span {{tab.title}}
|
||||||
|
|
68
client/agenda/agenda.scss
Normal file
68
client/agenda/agenda.scss
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
@import "bootstrap/scss/functions";
|
||||||
|
@import "bootstrap/scss/variables";
|
||||||
|
@import "../shared/breakpoints";
|
||||||
|
|
||||||
|
.meeting {
|
||||||
|
> h1 {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
@media screen and (max-width: $bs5-break-sm) {
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
font-size: .95em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(220deg, $blue-500 20%, $purple-500 70%);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
box-decoration-break: clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-h1-badges {
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
background-color: $pink-500;
|
||||||
|
box-shadow: 0 0 5px 0 rgba($pink-500, .5);
|
||||||
|
color: #FFF;
|
||||||
|
padding: 5px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
& + span {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-warning {
|
||||||
|
background-color: $red-500 !important;
|
||||||
|
box-shadow: 0 0 5px 0 rgba($red-500, .5) !important;
|
||||||
|
color: #FFF;
|
||||||
|
animation: warningBorderFlash 1s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
> h4 {
|
||||||
|
@media screen and (max-width: $bs5-break-sm) {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
font-size: .8em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ import { DateTime } from 'luxon'
|
||||||
import uniqBy from 'lodash/uniqBy'
|
import uniqBy from 'lodash/uniqBy'
|
||||||
import murmur from 'murmurhash-js/murmurhash3_gc'
|
import murmur from 'murmurhash-js/murmurhash3_gc'
|
||||||
|
|
||||||
|
import { useSiteStore } from '../shared/store'
|
||||||
|
|
||||||
const urlRe = /http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+/
|
const urlRe = /http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+/
|
||||||
const conferenceDomains = ['webex.com', 'zoom.us', 'jitsi.org', 'meetecho.com', 'gather.town']
|
const conferenceDomains = ['webex.com', 'zoom.us', 'jitsi.org', 'meetecho.com', 'gather.town']
|
||||||
|
|
||||||
|
@ -23,7 +25,6 @@ export const useAgendaStore = defineStore('agenda', {
|
||||||
{ hex: '#20c997', tag: 'Attended' }
|
{ hex: '#20c997', tag: 'Attended' }
|
||||||
],
|
],
|
||||||
colorAssignments: {},
|
colorAssignments: {},
|
||||||
criticalError: null,
|
|
||||||
currentTab: 'agenda',
|
currentTab: 'agenda',
|
||||||
dayIntersectId: '',
|
dayIntersectId: '',
|
||||||
defaultCalendarView: 'week',
|
defaultCalendarView: 'week',
|
||||||
|
@ -35,7 +36,6 @@ export const useAgendaStore = defineStore('agenda', {
|
||||||
infoNoteShown: true,
|
infoNoteShown: true,
|
||||||
isCurrentMeeting: false,
|
isCurrentMeeting: false,
|
||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
isMobile: /Mobi/i.test(navigator.userAgent),
|
|
||||||
listDayCollapse: false,
|
listDayCollapse: false,
|
||||||
meeting: {},
|
meeting: {},
|
||||||
nowDebugDiff: null,
|
nowDebugDiff: null,
|
||||||
|
@ -50,7 +50,6 @@ export const useAgendaStore = defineStore('agenda', {
|
||||||
settingsShown: false,
|
settingsShown: false,
|
||||||
timezone: DateTime.local().zoneName,
|
timezone: DateTime.local().zoneName,
|
||||||
useHedgeDoc: false,
|
useHedgeDoc: false,
|
||||||
viewport: Math.round(window.innerWidth),
|
|
||||||
visibleDays: []
|
visibleDays: []
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
|
@ -119,10 +118,11 @@ export const useAgendaStore = defineStore('agenda', {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
meetingDays () {
|
meetingDays () {
|
||||||
|
const siteStore = useSiteStore()
|
||||||
return uniqBy(this.scheduleAdjusted, 'adjustedStartDate').sort().map(s => ({
|
return uniqBy(this.scheduleAdjusted, 'adjustedStartDate').sort().map(s => ({
|
||||||
slug: s.id.toString(),
|
slug: s.id.toString(),
|
||||||
ts: s.adjustedStartDate,
|
ts: s.adjustedStartDate,
|
||||||
label: this.viewport < 1350 ? DateTime.fromISO(s.adjustedStartDate).toFormat('ccc LLL d') : DateTime.fromISO(s.adjustedStartDate).toLocaleString(DateTime.DATE_HUGE)
|
label: siteStore.viewport < 1350 ? DateTime.fromISO(s.adjustedStartDate).toFormat('ccc LLL d') : DateTime.fromISO(s.adjustedStartDate).toLocaleString(DateTime.DATE_HUGE)
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
isMeetingLive (state) {
|
isMeetingLive (state) {
|
||||||
|
@ -168,7 +168,10 @@ export const useAgendaStore = defineStore('agenda', {
|
||||||
this.isLoaded = true
|
this.isLoaded = true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
this.criticalError = `Failed to load this meeting: ${err.message}`
|
const siteStore = useSiteStore()
|
||||||
|
siteStore.$patch({
|
||||||
|
criticalError: `Failed to load this meeting: ${err.message}`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hideLoadingScreen()
|
this.hideLoadingScreen()
|
||||||
|
|
|
@ -3,9 +3,12 @@ import { createRouter, createWebHistory } from 'vue-router'
|
||||||
export default createRouter({
|
export default createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// MEETING
|
||||||
|
// ---------------------------------------------------------
|
||||||
{
|
{
|
||||||
name: 'agenda',
|
name: 'agenda',
|
||||||
path: '/meeting/:meetingNumber(\\d+)?/agenda-neue',
|
path: '/meeting/:meetingNumber(\\d+)?/agenda',
|
||||||
component: () => import('./agenda/Agenda.vue'),
|
component: () => import('./agenda/Agenda.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
hideLeftMenu: true
|
hideLeftMenu: true
|
||||||
|
@ -13,11 +16,18 @@ export default createRouter({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'floor-plan',
|
name: 'floor-plan',
|
||||||
path: '/meeting/:meetingNumber(\\d+)?/floor-plan-neue',
|
path: '/meeting/:meetingNumber(\\d+)?/floor-plan',
|
||||||
component: () => import('./agenda/FloorPlan.vue'),
|
component: () => import('./agenda/FloorPlan.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
hideLeftMenu: true
|
hideLeftMenu: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// -> Redirects
|
||||||
|
{
|
||||||
|
path: '/meeting/:meetingNumber(\\d+)?/agenda/personalize',
|
||||||
|
redirect: to => {
|
||||||
|
return { name: 'agenda', query: { ...to.query, pick: true } }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
9
client/shared/store.js
Normal file
9
client/shared/store.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useSiteStore = defineStore('site', {
|
||||||
|
state: () => ({
|
||||||
|
criticalError: null,
|
||||||
|
isMobile: /Mobi/i.test(navigator.userAgent),
|
||||||
|
viewport: Math.round(window.innerWidth)
|
||||||
|
})
|
||||||
|
})
|
|
@ -453,7 +453,7 @@ class Room(models.Model):
|
||||||
if not mtg_num:
|
if not mtg_num:
|
||||||
return None
|
return None
|
||||||
elif self.floorplan:
|
elif self.floorplan:
|
||||||
base_url = urlreverse('ietf.meeting.views.floor_plan', kwargs=dict(num=mtg_num))
|
base_url = urlreverse('floor-plan', kwargs=dict(num=mtg_num))
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
return f'{base_url}?room={xslugify(self.name)}'
|
return f'{base_url}?room={xslugify(self.name)}'
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@ from pyquery import PyQuery
|
||||||
from lxml.etree import tostring
|
from lxml.etree import tostring
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO, BytesIO
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from urllib.parse import urlparse, urlsplit, quote
|
from urllib.parse import urlparse, urlsplit
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
@ -51,7 +51,6 @@ from ietf.name.models import SessionStatusName, ImportantDateName, RoleName, Pro
|
||||||
from ietf.utils.decorators import skip_coverage
|
from ietf.utils.decorators import skip_coverage
|
||||||
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
|
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
|
||||||
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
|
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
|
||||||
from ietf.utils.text import xslugify
|
|
||||||
|
|
||||||
from ietf.person.factories import PersonFactory
|
from ietf.person.factories import PersonFactory
|
||||||
from ietf.group.factories import GroupFactory, GroupEventFactory, RoleFactory
|
from ietf.group.factories import GroupFactory, GroupEventFactory, RoleFactory
|
||||||
|
@ -166,7 +165,7 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
time_interval = r"%s<span.*/span>-%s" % (slot.utc_start_time().strftime("%H:%M").lstrip("0"), (slot.utc_start_time() + slot.duration).strftime("%H:%M").lstrip("0"))
|
time_interval = r"%s<span.*/span>-%s" % (slot.utc_start_time().strftime("%H:%M").lstrip("0"), (slot.utc_start_time() + slot.duration).strftime("%H:%M").lstrip("0"))
|
||||||
|
|
||||||
# Extremely rudementary test of agenda-neue - to be replaced with back-end tests as the front-end tests are developed.
|
# Extremely rudementary test of agenda-neue - to be replaced with back-end tests as the front-end tests are developed.
|
||||||
r = self.client.get(urlreverse("agenda-neue", kwargs=dict(num=meeting.number,utc='-utc')))
|
r = self.client.get(urlreverse("agenda", kwargs=dict(num=meeting.number,utc='-utc')))
|
||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
|
|
||||||
# Agenda API tests
|
# Agenda API tests
|
||||||
|
@ -213,53 +212,14 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=meeting.number,utc='-utc')))
|
|
||||||
self.assertEqual(r.status_code, 200)
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
agenda_content = q("#content").html()
|
|
||||||
self.assertIn(session.group.acronym, agenda_content)
|
|
||||||
self.assertIn(session.group.name, agenda_content)
|
|
||||||
self.assertIn(session.group.parent.acronym.upper(), agenda_content)
|
|
||||||
self.assertIn(slot.location.name, agenda_content)
|
|
||||||
self.assertRegex(agenda_content, time_interval)
|
|
||||||
self.assertIsNotNone(q(':input[value="%s"]' % meeting.time_zone),
|
|
||||||
'Time zone selector should show meeting timezone')
|
|
||||||
self.assertIsNotNone(q('.nav *:contains("%s")' % meeting.time_zone),
|
|
||||||
'Time zone indicator should be in nav sidebar')
|
|
||||||
|
|
||||||
# plain
|
# plain
|
||||||
time_interval = r"%s<span.*/span>-%s" % (slot.time.strftime("%H:%M").lstrip("0"), (slot.time + slot.duration).strftime("%H:%M").lstrip("0"))
|
time_interval = r"%s<span.*/span>-%s" % (slot.time.strftime("%H:%M").lstrip("0"), (slot.time + slot.duration).strftime("%H:%M").lstrip("0"))
|
||||||
|
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=meeting.number)))
|
|
||||||
self.assertEqual(r.status_code, 200)
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
agenda_content = q("#content").html()
|
|
||||||
self.assertIn(session.group.acronym, agenda_content)
|
|
||||||
self.assertIn(session.group.name, agenda_content)
|
|
||||||
self.assertIn(session.group.parent.acronym.upper(), agenda_content)
|
|
||||||
self.assertIn(slot.location.name, agenda_content)
|
|
||||||
self.assertRegex(agenda_content, time_interval)
|
|
||||||
self.assertIn(registration_text, agenda_content)
|
|
||||||
|
|
||||||
# Make sure there's a frame for the session agenda and it points to the right place
|
|
||||||
assignment_url = urlreverse('ietf.meeting.views.session_materials', kwargs=dict(session_id=session.pk))
|
|
||||||
self.assertTrue(
|
|
||||||
any(
|
|
||||||
[assignment_url in x.attrib["data-src"]
|
|
||||||
for x in q('tr div.modal-body div.session-materials')]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# future meeting, no agenda
|
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=future_meeting.number)))
|
|
||||||
self.assertContains(r, "There is no agenda available yet.")
|
|
||||||
self.assertTemplateUsed(r, 'meeting/no-agenda.html')
|
|
||||||
|
|
||||||
# text
|
# text
|
||||||
# the rest of the results don't have as nicely formatted times
|
# the rest of the results don't have as nicely formatted times
|
||||||
time_interval = "%s-%s" % (slot.time.strftime("%H%M").lstrip("0"), (slot.time + slot.duration).strftime("%H%M").lstrip("0"))
|
time_interval = "%s-%s" % (slot.time.strftime("%H%M").lstrip("0"), (slot.time + slot.duration).strftime("%H%M").lstrip("0"))
|
||||||
|
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=meeting.number, ext=".txt")))
|
r = self.client.get(urlreverse("ietf.meeting.views.agenda_plain", kwargs=dict(num=meeting.number, ext=".txt")))
|
||||||
self.assertContains(r, session.group.acronym)
|
self.assertContains(r, session.group.acronym)
|
||||||
self.assertContains(r, session.group.name)
|
self.assertContains(r, session.group.name)
|
||||||
self.assertContains(r, session.group.parent.acronym.upper())
|
self.assertContains(r, session.group.parent.acronym.upper())
|
||||||
|
@ -267,16 +227,13 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
|
|
||||||
self.assertContains(r, time_interval)
|
self.assertContains(r, time_interval)
|
||||||
|
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=meeting.number,name=meeting.unofficial_schedule.name,owner=meeting.unofficial_schedule.owner.email())))
|
|
||||||
self.assertContains(r, 'not the official schedule')
|
|
||||||
|
|
||||||
# future meeting, no agenda
|
# future meeting, no agenda
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=future_meeting.number, ext=".txt")))
|
r = self.client.get(urlreverse("ietf.meeting.views.agenda_plain", kwargs=dict(num=future_meeting.number, ext=".txt")))
|
||||||
self.assertContains(r, "There is no agenda available yet.")
|
self.assertContains(r, "There is no agenda available yet.")
|
||||||
self.assertTemplateUsed(r, 'meeting/no-agenda.txt')
|
self.assertTemplateUsed(r, 'meeting/no-agenda.txt')
|
||||||
|
|
||||||
# CSV
|
# CSV
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=meeting.number, ext=".csv")))
|
r = self.client.get(urlreverse("ietf.meeting.views.agenda_plain", kwargs=dict(num=meeting.number, ext=".csv")))
|
||||||
self.assertContains(r, session.group.acronym)
|
self.assertContains(r, session.group.acronym)
|
||||||
self.assertContains(r, session.group.name)
|
self.assertContains(r, session.group.name)
|
||||||
self.assertContains(r, session.group.parent.acronym.upper())
|
self.assertContains(r, session.group.parent.acronym.upper())
|
||||||
|
@ -304,30 +261,11 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
'ietf.meeting.views.session_details',
|
'ietf.meeting.views.session_details',
|
||||||
kwargs=dict(num=meeting.number, acronym=session.group.acronym)),
|
kwargs=dict(num=meeting.number, acronym=session.group.acronym)),
|
||||||
msg_prefix='ical should contain link to meeting materials page for session')
|
msg_prefix='ical should contain link to meeting materials page for session')
|
||||||
self.assertContains(
|
|
||||||
r,
|
|
||||||
urlreverse(
|
|
||||||
'ietf.meeting.views.agenda', kwargs=dict(num=meeting.number)
|
|
||||||
) + f'#row-{session.official_timeslotassignment().slug()}',
|
|
||||||
msg_prefix='ical should contain link to agenda entry for session')
|
|
||||||
|
|
||||||
# week view
|
# Floor Plan
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.week_view", kwargs=dict(num=meeting.number)))
|
r = self.client.get(urlreverse('floor-plan', kwargs=dict(num=meeting.number)))
|
||||||
self.assertNotContains(r, 'CANCELLED')
|
self.assertEqual(r.status_code, 200)
|
||||||
self.assertContains(r, session.group.acronym)
|
|
||||||
self.assertContains(r, slot.location.name)
|
|
||||||
self.assertContains(r, registration_text)
|
|
||||||
|
|
||||||
# week view with a cancelled session
|
|
||||||
SchedulingEvent.objects.create(
|
|
||||||
session=session,
|
|
||||||
status=SessionStatusName.objects.get(slug='canceled'),
|
|
||||||
by=Person.objects.get(name='(System)')
|
|
||||||
)
|
|
||||||
r = self.client.get(urlreverse("ietf.meeting.views.week_view", kwargs=dict(num=meeting.number)))
|
|
||||||
self.assertContains(r, 'CANCELLED')
|
|
||||||
self.assertContains(r, session.group.acronym)
|
|
||||||
self.assertContains(r, slot.location.name)
|
|
||||||
|
|
||||||
@override_settings(PROCEEDINGS_V1_BASE_URL='https://example.com/{meeting.number}')
|
@override_settings(PROCEEDINGS_V1_BASE_URL='https://example.com/{meeting.number}')
|
||||||
def test_agenda_redirects_for_old_meetings(self):
|
def test_agenda_redirects_for_old_meetings(self):
|
||||||
|
@ -336,7 +274,7 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
MeetingFactory(type_id='ietf', number='35', populate_schedule=False)
|
MeetingFactory(type_id='ietf', number='35', populate_schedule=False)
|
||||||
r = self.client.get(
|
r = self.client.get(
|
||||||
urlreverse(
|
urlreverse(
|
||||||
'ietf.meeting.views.agenda',
|
'agenda',
|
||||||
kwargs={'num': '35', 'ext': '.html'},
|
kwargs={'num': '35', 'ext': '.html'},
|
||||||
))
|
))
|
||||||
self.assertRedirects(r, 'https://example.com/35', fetch_redirect_response=False)
|
self.assertRedirects(r, 'https://example.com/35', fetch_redirect_response=False)
|
||||||
|
@ -345,7 +283,7 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
meeting_with_schedule = MeetingFactory(type_id='ietf', number='36', populate_schedule=True)
|
meeting_with_schedule = MeetingFactory(type_id='ietf', number='36', populate_schedule=True)
|
||||||
r = self.client.get(
|
r = self.client.get(
|
||||||
urlreverse(
|
urlreverse(
|
||||||
'ietf.meeting.views.agenda',
|
'agenda',
|
||||||
kwargs={'num': '36', 'ext': '.html'},
|
kwargs={'num': '36', 'ext': '.html'},
|
||||||
))
|
))
|
||||||
self.assertRedirects(r, 'https://example.com/36', fetch_redirect_response=False)
|
self.assertRedirects(r, 'https://example.com/36', fetch_redirect_response=False)
|
||||||
|
@ -354,7 +292,7 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
SessionFactory(meeting=meeting_with_schedule)
|
SessionFactory(meeting=meeting_with_schedule)
|
||||||
r = self.client.get(
|
r = self.client.get(
|
||||||
urlreverse(
|
urlreverse(
|
||||||
'ietf.meeting.views.agenda',
|
'agenda',
|
||||||
kwargs={'num': '36', 'ext': '.html'},
|
kwargs={'num': '36', 'ext': '.html'},
|
||||||
))
|
))
|
||||||
self.assertRedirects(r, 'https://example.com/36', fetch_redirect_response=False)
|
self.assertRedirects(r, 'https://example.com/36', fetch_redirect_response=False)
|
||||||
|
@ -364,201 +302,10 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
# Meetings pre-64 are redirected, but should be a 404 if there is no Meeting instance
|
# Meetings pre-64 are redirected, but should be a 404 if there is no Meeting instance
|
||||||
r = self.client.get(
|
r = self.client.get(
|
||||||
urlreverse(
|
urlreverse(
|
||||||
'ietf.meeting.views.agenda',
|
'agenda',
|
||||||
kwargs={'num': '32', 'ext': '.html'},
|
kwargs={'num': '32', 'ext': '.html'},
|
||||||
))
|
))
|
||||||
self.assertEqual(r.status_code, 404)
|
self.assertEqual(r.status_code, 404)
|
||||||
# Check a post-64 meeting as well
|
|
||||||
r = self.client.get(
|
|
||||||
urlreverse(
|
|
||||||
'ietf.meeting.views.agenda',
|
|
||||||
kwargs={'num': '150', 'ext': '.html'},
|
|
||||||
))
|
|
||||||
self.assertEqual(r.status_code, 404)
|
|
||||||
|
|
||||||
|
|
||||||
def test_meeting_agenda_filters_ignored(self):
|
|
||||||
"""The agenda view should ignore filter querystrings
|
|
||||||
|
|
||||||
(They are handled by javascript on the front end)
|
|
||||||
"""
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
expected_items = meeting.schedule.assignments.exclude(timeslot__type__in=['lead','offagenda'])
|
|
||||||
expected_rows = ['row-%s' % item.slug() for item in expected_items]
|
|
||||||
|
|
||||||
r = self.client.get(urlreverse('ietf.meeting.views.agenda'))
|
|
||||||
for row_id in expected_rows:
|
|
||||||
self.assertContains(r, row_id)
|
|
||||||
|
|
||||||
r = self.client.get(urlreverse('ietf.meeting.views.agenda') + '?show=mars')
|
|
||||||
for row_id in expected_rows:
|
|
||||||
self.assertContains(r, row_id)
|
|
||||||
|
|
||||||
r = self.client.get(urlreverse('ietf.meeting.views.agenda') + '?show=mars&hide=ames,mars,plenary,ietf,bof')
|
|
||||||
for row_id in expected_rows:
|
|
||||||
self.assertContains(r, row_id)
|
|
||||||
|
|
||||||
def test_agenda_iab_session(self):
|
|
||||||
date = datetime.date.today()
|
|
||||||
meeting = MeetingFactory(type_id='ietf', date=date )
|
|
||||||
make_meeting_test_data(meeting=meeting)
|
|
||||||
|
|
||||||
iab = Group.objects.get(acronym='iab')
|
|
||||||
venus = Group.objects.create(
|
|
||||||
name="Three letter acronym",
|
|
||||||
acronym="venus",
|
|
||||||
description="This group discusses exploration of Venus",
|
|
||||||
state_id="active",
|
|
||||||
type_id="program",
|
|
||||||
parent=iab,
|
|
||||||
list_email="venus@ietf.org",
|
|
||||||
)
|
|
||||||
venus_session = SessionFactory(
|
|
||||||
meeting=meeting,
|
|
||||||
group=venus,
|
|
||||||
attendees=10,
|
|
||||||
requested_duration=datetime.timedelta(minutes=60),
|
|
||||||
add_to_schedule=False,
|
|
||||||
)
|
|
||||||
system_person = Person.objects.get(name="(System)")
|
|
||||||
SchedulingEvent.objects.create(session=venus_session, status_id='schedw', by=system_person)
|
|
||||||
room = Room.objects.create(meeting=meeting,
|
|
||||||
name="Aphrodite",
|
|
||||||
capacity=100,
|
|
||||||
functional_name="Aphrodite Room")
|
|
||||||
room.session_types.add('regular')
|
|
||||||
session_date = meeting.date + datetime.timedelta(days=1)
|
|
||||||
slot3 = TimeSlot.objects.create(meeting=meeting, type_id='regular', location=room,
|
|
||||||
duration=datetime.timedelta(minutes=60),
|
|
||||||
time=datetime.datetime.combine(session_date, datetime.time(13, 30)))
|
|
||||||
SchedTimeSessAssignment.objects.create(timeslot=slot3, session=venus_session, schedule=meeting.schedule)
|
|
||||||
url = urlreverse('ietf.meeting.views.agenda', kwargs=dict(num=meeting.number))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertContains(r, 'venus')
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
venus_row = q('[id*="-iab-"]').html()
|
|
||||||
self.assertIn('venus', venus_row)
|
|
||||||
|
|
||||||
def test_agenda_current_audio(self):
|
|
||||||
date = datetime.date.today()
|
|
||||||
meeting = MeetingFactory(type_id='ietf', date=date )
|
|
||||||
make_meeting_test_data(meeting=meeting)
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda", kwargs=dict(num=meeting.number))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertContains(r, "Audio stream")
|
|
||||||
|
|
||||||
def test_agenda_by_room(self):
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_room",kwargs=dict(num=meeting.number))
|
|
||||||
login_testing_unauthorized(self,"secretary",url)
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['mars','IESG Breakfast','Test Room','Breakfast Room']]))
|
|
||||||
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_room",kwargs=dict(num=meeting.number,name=meeting.unofficial_schedule.name,owner=meeting.unofficial_schedule.owner.email()))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['mars','Test Room',]]))
|
|
||||||
self.assertNotContains(r, 'IESG Breakfast')
|
|
||||||
|
|
||||||
def test_agenda_by_type(self):
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number))
|
|
||||||
login_testing_unauthorized(self,"secretary",url)
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['mars','IESG Breakfast','Test Room','Breakfast Room']]))
|
|
||||||
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number,name=meeting.unofficial_schedule.name,owner=meeting.unofficial_schedule.owner.email()))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['mars','Test Room',]]))
|
|
||||||
self.assertNotContains(r, 'IESG Breakfast')
|
|
||||||
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number,type='regular'))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['mars','Test Room']]))
|
|
||||||
self.assertFalse(any([x in unicontent(r) for x in ['IESG Breakfast','Breakfast Room']]))
|
|
||||||
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number,type='lead'))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertFalse(any([x in unicontent(r) for x in ['mars','Test Room']]))
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['IESG Breakfast','Breakfast Room']]))
|
|
||||||
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number,type='lead',name=meeting.unofficial_schedule.name,owner=meeting.unofficial_schedule.owner.email()))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertFalse(any([x in unicontent(r) for x in ['IESG Breakfast','Breakfast Room']]))
|
|
||||||
|
|
||||||
|
|
||||||
def test_agenda_week_view(self):
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
url = urlreverse("ietf.meeting.views.week_view",kwargs=dict(num=meeting.number)) + "?show=farfut"
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertEqual(r.status_code,200)
|
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ['redraw_weekview', 'draw_calendar', ]]))
|
|
||||||
|
|
||||||
# Specifying a time zone should not change the output (time zones are handled by the JS)
|
|
||||||
url = urlreverse("ietf.meeting.views.week_view",kwargs=dict(num=meeting.number)) + "?show=farfut&" + quote("tz=Asia/Bangkok", safe='=')
|
|
||||||
r_with_tz = self.client.get(url)
|
|
||||||
self.assertEqual(r_with_tz.status_code,200)
|
|
||||||
self.assertEqual(r.content, r_with_tz.content)
|
|
||||||
|
|
||||||
def test_agenda_personalize(self):
|
|
||||||
"""Session selection page should have a checkbox for each session with appropriate keywords"""
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_personalize",kwargs=dict(num=meeting.number))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertEqual(r.status_code,200)
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
for assignment in SchedTimeSessAssignment.objects.filter(
|
|
||||||
schedule__in=[meeting.schedule, meeting.schedule.base],
|
|
||||||
session__on_agenda=True,
|
|
||||||
):
|
|
||||||
row = q('#row-{}'.format(assignment.slug()))
|
|
||||||
self.assertIsNotNone(row, 'No row for assignment {}'.format(assignment))
|
|
||||||
checkboxes = row('input[type="checkbox"][name="selected-sessions"]')
|
|
||||||
self.assertEqual(len(checkboxes), 1,
|
|
||||||
'Row for assignment {} does not have a checkbox input'.format(assignment))
|
|
||||||
checkbox = checkboxes.eq(0)
|
|
||||||
kw_token = assignment.session.docname_token_only_for_multiple()
|
|
||||||
self.assertEqual(
|
|
||||||
checkbox.attr('data-filter-item'),
|
|
||||||
assignment.session.group.acronym.lower() + (
|
|
||||||
'' if kw_token is None else f'-{kw_token}'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_agenda_personalize_updates_urls(self):
|
|
||||||
"""The correct URLs should be updated when filter settings change on the personalize agenda view
|
|
||||||
|
|
||||||
Tests that the expected elements have the necessary classes. The actual update of these fields
|
|
||||||
is tested in the JS tests
|
|
||||||
"""
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
url = urlreverse("ietf.meeting.views.agenda_personalize",kwargs=dict(num=meeting.number))
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertEqual(r.status_code,200)
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
|
|
||||||
# Find all the elements expected to be updated
|
|
||||||
expected_elements = []
|
|
||||||
nav_tab_anchors = q('ul.nav.nav-tabs > li > a')
|
|
||||||
for anchor in nav_tab_anchors.items():
|
|
||||||
text = anchor.text().strip()
|
|
||||||
if text in ['Agenda (New)', 'Agenda', 'UTC agenda', 'Personalize agenda']:
|
|
||||||
expected_elements.append(anchor)
|
|
||||||
for btn in q('.buttonlist a.btn').items():
|
|
||||||
text = btn.text().strip()
|
|
||||||
if text in ['View personal agenda', 'Download .ics of filtered agenda', 'Subscribe to filtered agenda']:
|
|
||||||
expected_elements.append(btn)
|
|
||||||
|
|
||||||
# Check that all the expected elements have the correct classes
|
|
||||||
for elt in expected_elements:
|
|
||||||
self.assertTrue(elt.has_class('agenda-link'))
|
|
||||||
self.assertTrue(elt.has_class('filterable'))
|
|
||||||
|
|
||||||
# Finally, check that there are no unexpected elements marked to be updated.
|
|
||||||
# If there are, they should be added to the test above.
|
|
||||||
self.assertEqual(len(expected_elements),
|
|
||||||
len(q('.agenda-link.filterable')),
|
|
||||||
'Unexpected elements updated')
|
|
||||||
|
|
||||||
@override_settings(MEETING_MATERIALS_SERVE_LOCALLY=False, MEETING_DOC_HREFS = settings.MEETING_DOC_CDN_HREFS)
|
@override_settings(MEETING_MATERIALS_SERVE_LOCALLY=False, MEETING_DOC_HREFS = settings.MEETING_DOC_CDN_HREFS)
|
||||||
def test_materials_through_cdn(self):
|
def test_materials_through_cdn(self):
|
||||||
|
@ -822,40 +569,6 @@ class MeetingTests(BaseMeetingTestCase):
|
||||||
self.assertContains(r, t1.time.strftime('%Y%m%dT%H%M%S'))
|
self.assertContains(r, t1.time.strftime('%Y%m%dT%H%M%S'))
|
||||||
self.assertNotContains(r, t2.time.strftime('%Y%m%dT%H%M%S'))
|
self.assertNotContains(r, t2.time.strftime('%Y%m%dT%H%M%S'))
|
||||||
|
|
||||||
def test_meeting_agenda_has_static_ical_links(self):
|
|
||||||
"""Links to the agenda_ical view must appear on the agenda page
|
|
||||||
|
|
||||||
Confirms that these have the correct querystrings. Does not test the JS-based
|
|
||||||
'Customized schedule' button.
|
|
||||||
"""
|
|
||||||
meeting = make_meeting_test_data()
|
|
||||||
|
|
||||||
# get the agenda
|
|
||||||
url = urlreverse('ietf.meeting.views.agenda', kwargs=dict(num=meeting.number))
|
|
||||||
r = self.client.get(url)
|
|
||||||
|
|
||||||
# Check that it has the links we expect
|
|
||||||
ical_url = urlreverse('ietf.meeting.views.agenda_ical', kwargs=dict(num=meeting.number))
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
content = q('#content').html()
|
|
||||||
|
|
||||||
assignments = meeting.schedule.assignments.exclude(timeslot__type__in=['lead', 'offagenda'])
|
|
||||||
|
|
||||||
# Assume the test meeting is not using historic groups
|
|
||||||
groups = [a.session.group for a in assignments if a.session is not None]
|
|
||||||
for g in groups:
|
|
||||||
if g.parent_id is not None:
|
|
||||||
self.assertIn('%s?show=%s' % (ical_url, g.parent.acronym.lower()), content)
|
|
||||||
|
|
||||||
# The 'non-area events' are those whose keywords are in the last column of buttons
|
|
||||||
na_col = q('#customize .col-1:last') # find the column
|
|
||||||
non_area_labels = [e.attrib['data-filter-item']
|
|
||||||
for e in na_col.find('button.pickview')]
|
|
||||||
assert len(non_area_labels) > 0 # test setup must produce at least one label for this test
|
|
||||||
|
|
||||||
# Should be a 'non-area events' link showing appropriate types
|
|
||||||
self.assertIn('%s?show=%s' % (ical_url, ','.join(non_area_labels).lower()), content)
|
|
||||||
|
|
||||||
def test_parse_agenda_filter_params(self):
|
def test_parse_agenda_filter_params(self):
|
||||||
def _r(show=(), hide=(), showtypes=(), hidetypes=()):
|
def _r(show=(), hide=(), showtypes=(), hidetypes=()):
|
||||||
"""Helper to create expected result dict"""
|
"""Helper to create expected result dict"""
|
||||||
|
@ -4008,12 +3721,6 @@ class SessionDetailsTests(TestCase):
|
||||||
self.assertTrue(all([x in unicontent(r) for x in ('slides','agenda','minutes','draft')]))
|
self.assertTrue(all([x in unicontent(r) for x in ('slides','agenda','minutes','draft')]))
|
||||||
self.assertNotContains(r, 'deleted')
|
self.assertNotContains(r, 'deleted')
|
||||||
|
|
||||||
q = PyQuery(r.content)
|
|
||||||
self.assertTrue(q('div#session-buttons-%s' % session.id),
|
|
||||||
'Session detail page does not contain session tool buttons')
|
|
||||||
self.assertFalse(q('div#session-buttons-%s span.bi-arrows-fullscreen' % session.id),
|
|
||||||
'The session detail page is incorrectly showing the "Show meeting materials" button')
|
|
||||||
|
|
||||||
def test_session_details_has_import_minutes_buttons(self):
|
def test_session_details_has_import_minutes_buttons(self):
|
||||||
group = GroupFactory.create(
|
group = GroupFactory.create(
|
||||||
type_id='wg',
|
type_id='wg',
|
||||||
|
@ -5684,25 +5391,6 @@ class AjaxTests(TestCase):
|
||||||
self.assertNotIn('error', data)
|
self.assertNotIn('error', data)
|
||||||
self.assertEqual(data['utc'], '20:00')
|
self.assertEqual(data['utc'], '20:00')
|
||||||
|
|
||||||
class FloorPlanTests(TestCase):
|
|
||||||
def test_floor_plan_page(self):
|
|
||||||
make_meeting_test_data()
|
|
||||||
meeting = Meeting.objects.filter(type_id='ietf').order_by('id').last()
|
|
||||||
floorplan = FloorPlanFactory.create(meeting=meeting)
|
|
||||||
|
|
||||||
# Extremely rudimentary test of floor-plan-neue
|
|
||||||
url = urlreverse('floor-plan-neue')
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertEqual(r.status_code, 200)
|
|
||||||
|
|
||||||
url = urlreverse('ietf.meeting.views.floor_plan')
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertEqual(r.status_code, 200)
|
|
||||||
|
|
||||||
url = urlreverse('ietf.meeting.views.floor_plan', kwargs={'floor': xslugify(floorplan.name)} )
|
|
||||||
r = self.client.get(url)
|
|
||||||
self.assertEqual(r.status_code, 200)
|
|
||||||
|
|
||||||
class IphoneAppJsonTests(TestCase):
|
class IphoneAppJsonTests(TestCase):
|
||||||
def test_iphone_app_json_interim(self):
|
def test_iphone_app_json_interim(self):
|
||||||
make_interim_test_data()
|
make_interim_test_data()
|
||||||
|
|
|
@ -7,6 +7,13 @@ from django.conf import settings
|
||||||
from ietf.meeting import views, views_proceedings
|
from ietf.meeting import views, views_proceedings
|
||||||
from ietf.utils.urls import url
|
from ietf.utils.urls import url
|
||||||
|
|
||||||
|
class AgendaRedirectView(RedirectView):
|
||||||
|
ignore_kwargs = ('owner', 'name')
|
||||||
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
|
for kwarg in self.ignore_kwargs:
|
||||||
|
kwargs.pop(kwarg, None)
|
||||||
|
return super().get_redirect_url(*args, **kwargs)
|
||||||
|
|
||||||
safe_for_all_meeting_types = [
|
safe_for_all_meeting_types = [
|
||||||
url(r'^session/(?P<acronym>[-a-z0-9]+)/?$', views.session_details),
|
url(r'^session/(?P<acronym>[-a-z0-9]+)/?$', views.session_details),
|
||||||
url(r'^session/(?P<session_id>\d+)/drafts$', views.add_session_drafts),
|
url(r'^session/(?P<session_id>\d+)/drafts$', views.add_session_drafts),
|
||||||
|
@ -33,16 +40,13 @@ type_ietf_only_patterns = [
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/delete$' % settings.URL_REGEXPS, views.delete_schedule),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/delete$' % settings.URL_REGEXPS, views.delete_schedule),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/make_official$' % settings.URL_REGEXPS, views.make_schedule_official),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/make_official$' % settings.URL_REGEXPS, views.make_schedule_official),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s(\.(?P<ext>.html))?/?$' % settings.URL_REGEXPS, views.agenda),
|
url(r'^agenda/%(owner)s/%(schedule_name)s(\.(?P<ext>.html))?/?$' % settings.URL_REGEXPS, views.agenda),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/week-view(?:.html)?/?$' % settings.URL_REGEXPS, views.week_view),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/week-view(?:.html)?/?$' % settings.URL_REGEXPS, AgendaRedirectView.as_view(pattern_name='agenda', permanent=True)),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/by-room/?$' % settings.URL_REGEXPS, views.agenda_by_room),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/by-room/?$' % settings.URL_REGEXPS, AgendaRedirectView.as_view(pattern_name='agenda', permanent=True)),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/by-type/?$' % settings.URL_REGEXPS, views.agenda_by_type),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/by-type/?$' % settings.URL_REGEXPS, AgendaRedirectView.as_view(pattern_name='agenda', permanent=True)),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/by-type/(?P<type>[a-z]+)$' % settings.URL_REGEXPS, views.agenda_by_type),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/by-type/(?P<type>[a-z]+)$' % settings.URL_REGEXPS, AgendaRedirectView.as_view(pattern_name='agenda', permanent=True)),
|
||||||
url(r'^agenda/%(owner)s/%(schedule_name)s/new/$' % settings.URL_REGEXPS, views.new_meeting_schedule),
|
url(r'^agenda/%(owner)s/%(schedule_name)s/new/$' % settings.URL_REGEXPS, views.new_meeting_schedule),
|
||||||
url(r'^agenda/by-room$', views.agenda_by_room),
|
|
||||||
url(r'^agenda/by-type$', views.agenda_by_type),
|
|
||||||
url(r'^agenda/by-type/(?P<type>[a-z]+)$', views.agenda_by_type),
|
|
||||||
url(r'^agenda/by-type/(?P<type>[a-z]+)/ics$', views.agenda_by_type_ics),
|
url(r'^agenda/by-type/(?P<type>[a-z]+)/ics$', views.agenda_by_type_ics),
|
||||||
url(r'^agenda/personalize', views.agenda_personalize),
|
url(r'^agenda/personalize', views.agenda, name='agenda-personalize'),
|
||||||
url(r'^agendas/list$', views.list_schedules),
|
url(r'^agendas/list$', views.list_schedules),
|
||||||
url(r'^agendas/edit$', RedirectView.as_view(pattern_name='ietf.meeting.views.list_schedules', permanent=True)),
|
url(r'^agendas/edit$', RedirectView.as_view(pattern_name='ietf.meeting.views.list_schedules', permanent=True)),
|
||||||
url(r'^agendas/diff/$', views.diff_schedules),
|
url(r'^agendas/diff/$', views.diff_schedules),
|
||||||
|
@ -64,10 +68,9 @@ type_interim_patterns = [
|
||||||
]
|
]
|
||||||
|
|
||||||
type_ietf_only_patterns_id_optional = [
|
type_ietf_only_patterns_id_optional = [
|
||||||
url(r'^agenda(?P<utc>-utc)?(?P<ext>\.html)?/?$', views.agenda),
|
url(r'^agenda(?P<utc>-utc)?(?P<ext>\.html)?/?$', views.agenda, name='agenda'),
|
||||||
url(r'^agenda(?P<ext>\.txt)$', views.agenda),
|
url(r'^agenda(?P<ext>\.txt)$', views.agenda_plain),
|
||||||
url(r'^agenda(?P<ext>\.csv)$', views.agenda),
|
url(r'^agenda(?P<ext>\.csv)$', views.agenda_plain),
|
||||||
url(r'^agenda-neue(?P<utc>-utc)?(?P<ext>\.html)?/?$', views.agenda_neue, name='agenda-neue'),
|
|
||||||
url(r'^agenda/edit$',
|
url(r'^agenda/edit$',
|
||||||
RedirectView.as_view(pattern_name='ietf.meeting.views.edit_meeting_schedule', permanent=True),
|
RedirectView.as_view(pattern_name='ietf.meeting.views.edit_meeting_schedule', permanent=True),
|
||||||
name='ietf.meeting.views.edit_meeting_schedule'),
|
name='ietf.meeting.views.edit_meeting_schedule'),
|
||||||
|
@ -76,11 +79,10 @@ type_ietf_only_patterns_id_optional = [
|
||||||
url(r'^agenda/agenda\.ics$', views.agenda_ical),
|
url(r'^agenda/agenda\.ics$', views.agenda_ical),
|
||||||
url(r'^agenda\.ics$', views.agenda_ical),
|
url(r'^agenda\.ics$', views.agenda_ical),
|
||||||
url(r'^agenda.json$', views.agenda_json),
|
url(r'^agenda.json$', views.agenda_json),
|
||||||
url(r'^agenda/week-view(?:.html)?/?$', views.week_view),
|
url(r'^agenda/week-view(?:.html)?/?$', RedirectView.as_view(pattern_name='agenda', permanent=True)),
|
||||||
url(r'^floor-plan/?$', views.floor_plan),
|
url(r'^floor-plan/?$', views.agenda, name='floor-plan'),
|
||||||
url(r'^floor-plan-neue/?$', views.agenda_neue, name='floor-plan-neue'),
|
url(r'^floor-plan/(?P<floor>[-a-z0-9_]+)/?$', RedirectView.as_view(pattern_name='floor-plan', permanent=True)),
|
||||||
url(r'^floor-plan/(?P<floor>[-a-z0-9_]+)/?$', views.floor_plan),
|
url(r'^week-view(?:.html)?/?$', RedirectView.as_view(pattern_name='agenda', permanent=True)),
|
||||||
url(r'^week-view(?:.html)?/?$', views.week_view),
|
|
||||||
url(r'^materials(?:.html)?/?$', views.materials),
|
url(r'^materials(?:.html)?/?$', views.materials),
|
||||||
url(r'^request_minutes/?$', views.request_minutes),
|
url(r'^request_minutes/?$', views.request_minutes),
|
||||||
url(r'^materials/%(document)s((?P<ext>\.[a-z0-9]+)|/)?$' % settings.URL_REGEXPS, views.materials_document),
|
url(r'^materials/%(document)s((?P<ext>\.[a-z0-9]+)|/)?$' % settings.URL_REGEXPS, views.materials_document),
|
||||||
|
|
|
@ -1502,11 +1502,10 @@ def get_assignments_for_agenda(schedule):
|
||||||
|
|
||||||
|
|
||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
def agenda(request, num=None, name=None, base=None, ext=None, owner=None, utc=""):
|
def agenda_plain(request, num=None, name=None, base=None, ext=None, owner=None, utc=""):
|
||||||
base = base if base else 'agenda'
|
base = base if base else 'agenda'
|
||||||
ext = ext if ext else '.html'
|
ext = ext if ext else '.txt'
|
||||||
mimetype = {
|
mimetype = {
|
||||||
".html":"text/html; charset=%s"%settings.DEFAULT_CHARSET,
|
|
||||||
".txt": "text/plain; charset=%s"%settings.DEFAULT_CHARSET,
|
".txt": "text/plain; charset=%s"%settings.DEFAULT_CHARSET,
|
||||||
".csv": "text/csv; charset=%s"%settings.DEFAULT_CHARSET,
|
".csv": "text/csv; charset=%s"%settings.DEFAULT_CHARSET,
|
||||||
}
|
}
|
||||||
|
@ -1570,7 +1569,7 @@ def agenda(request, num=None, name=None, base=None, ext=None, owner=None, utc=""
|
||||||
return rendered_page
|
return rendered_page
|
||||||
|
|
||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
def agenda_neue(request, num=None, name=None, base=None, ext=None, owner=None, utc=""):
|
def agenda(request, num=None, name=None, base=None, ext=None, owner=None, utc=""):
|
||||||
# Get current meeting if not specified
|
# Get current meeting if not specified
|
||||||
if num is None:
|
if num is None:
|
||||||
num = get_current_ietf_meeting_num()
|
num = get_current_ietf_meeting_num()
|
||||||
|
@ -1586,7 +1585,7 @@ def agenda_neue(request, num=None, name=None, base=None, ext=None, owner=None, u
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect(f'{settings.PROCEEDINGS_V1_BASE_URL.format(meeting=meeting)}')
|
return HttpResponseRedirect(f'{settings.PROCEEDINGS_V1_BASE_URL.format(meeting=meeting)}')
|
||||||
|
|
||||||
return render(request, "meeting/agenda-neue.html", {
|
return render(request, "meeting/agenda.html", {
|
||||||
"meetingData": {
|
"meetingData": {
|
||||||
"meetingNumber": num
|
"meetingNumber": num
|
||||||
}
|
}
|
||||||
|
@ -1834,45 +1833,6 @@ def agenda_csv(schedule, filtered_assignments):
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@role_required('Area Director','Secretariat','IAB')
|
|
||||||
def agenda_by_room(request, num=None, name=None, owner=None):
|
|
||||||
meeting = get_meeting(num)
|
|
||||||
if name is None:
|
|
||||||
schedule = get_schedule(meeting)
|
|
||||||
else:
|
|
||||||
person = get_person_by_email(owner)
|
|
||||||
schedule = get_schedule_by_name(meeting, person, name)
|
|
||||||
|
|
||||||
assignments = SchedTimeSessAssignment.objects.filter(
|
|
||||||
schedule__in=[schedule, schedule.base if schedule else None]
|
|
||||||
).prefetch_related('timeslot', 'timeslot__location', 'session', 'session__group', 'session__group__parent')
|
|
||||||
|
|
||||||
ss_by_day = OrderedDict()
|
|
||||||
for day in assignments.dates('timeslot__time','day'):
|
|
||||||
ss_by_day[day]=[]
|
|
||||||
for ss in assignments.order_by('timeslot__location__functional_name','timeslot__location__name','timeslot__time'):
|
|
||||||
day = ss.timeslot.time.date()
|
|
||||||
ss_by_day[day].append(ss)
|
|
||||||
return render(request,"meeting/agenda_by_room.html",{"meeting":meeting,"schedule":schedule,"ss_by_day":ss_by_day})
|
|
||||||
|
|
||||||
@role_required('Area Director','Secretariat','IAB')
|
|
||||||
def agenda_by_type(request, num=None, type=None, name=None, owner=None):
|
|
||||||
meeting = get_meeting(num)
|
|
||||||
if name is None:
|
|
||||||
schedule = get_schedule(meeting)
|
|
||||||
else:
|
|
||||||
person = get_person_by_email(owner)
|
|
||||||
schedule = get_schedule_by_name(meeting, person, name)
|
|
||||||
assignments = SchedTimeSessAssignment.objects.filter(
|
|
||||||
schedule__in=[schedule, schedule.base if schedule else None]
|
|
||||||
).prefetch_related(
|
|
||||||
'timeslot', 'timeslot__location', 'session', 'session__group', 'session__group__parent'
|
|
||||||
).order_by('session__type__slug','timeslot__time','session__group__acronym')
|
|
||||||
|
|
||||||
if type:
|
|
||||||
assignments = assignments.filter(session__type__slug=type)
|
|
||||||
return render(request,"meeting/agenda_by_type.html",{"meeting":meeting,"schedule":schedule,"assignments":assignments})
|
|
||||||
|
|
||||||
@role_required('Area Director','Secretariat','IAB')
|
@role_required('Area Director','Secretariat','IAB')
|
||||||
def agenda_by_type_ics(request,num=None,type=None):
|
def agenda_by_type_ics(request,num=None,type=None):
|
||||||
meeting = get_meeting(num)
|
meeting = get_meeting(num)
|
||||||
|
@ -1887,42 +1847,6 @@ def agenda_by_type_ics(request,num=None,type=None):
|
||||||
updated = meeting.updated()
|
updated = meeting.updated()
|
||||||
return render(request,"meeting/agenda.ics",{"schedule":schedule,"updated":updated,"assignments":assignments},content_type="text/calendar")
|
return render(request,"meeting/agenda.ics",{"schedule":schedule,"updated":updated,"assignments":assignments},content_type="text/calendar")
|
||||||
|
|
||||||
|
|
||||||
def agenda_personalize(request, num):
|
|
||||||
meeting = get_ietf_meeting(num) # num may be None, which requests the current meeting
|
|
||||||
if meeting is None or meeting.schedule is None:
|
|
||||||
raise Http404('No such meeting')
|
|
||||||
|
|
||||||
# Select and prepare sessions that should be included
|
|
||||||
filtered_assignments = preprocess_assignments_for_agenda(
|
|
||||||
get_assignments_for_agenda(meeting.schedule),
|
|
||||||
meeting
|
|
||||||
)
|
|
||||||
tagger = AgendaKeywordTagger(assignments=filtered_assignments)
|
|
||||||
tagger.apply() # annotate assignments with filter_keywords attribute
|
|
||||||
tagger.apply_session_keywords() # annotate assignments with session_keyword attribute
|
|
||||||
|
|
||||||
# Now prep the filter UI
|
|
||||||
filter_organizer = AgendaFilterOrganizer(assignments=filtered_assignments)
|
|
||||||
|
|
||||||
is_current_meeting = (num is None) or (num == get_current_ietf_meeting_num())
|
|
||||||
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"meeting/agenda.html",
|
|
||||||
{
|
|
||||||
'personalize': True,
|
|
||||||
'schedule': meeting.schedule,
|
|
||||||
'updated': meeting.updated(),
|
|
||||||
'filtered_assignments': filtered_assignments,
|
|
||||||
'filter_categories': filter_organizer.get_filter_categories(),
|
|
||||||
'non_area_labels': filter_organizer.get_non_area_keywords(),
|
|
||||||
'timezone': meeting.time_zone,
|
|
||||||
'is_current_meeting': is_current_meeting,
|
|
||||||
'cache_time': 150 if is_current_meeting else 3600,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def session_draft_list(num, acronym):
|
def session_draft_list(num, acronym):
|
||||||
try:
|
try:
|
||||||
agendas = Document.objects.filter(type="agenda",
|
agendas = Document.objects.filter(type="agenda",
|
||||||
|
@ -2025,70 +1949,6 @@ def session_draft_pdf(request, num, acronym):
|
||||||
os.unlink(pdfn)
|
os.unlink(pdfn)
|
||||||
return HttpResponse(pdf_contents, content_type="application/pdf")
|
return HttpResponse(pdf_contents, content_type="application/pdf")
|
||||||
|
|
||||||
def week_view(request, num=None, name=None, owner=None):
|
|
||||||
meeting = get_meeting(num)
|
|
||||||
|
|
||||||
if name is None:
|
|
||||||
schedule = get_schedule(meeting)
|
|
||||||
else:
|
|
||||||
person = get_person_by_email(owner)
|
|
||||||
schedule = get_schedule_by_name(meeting, person, name)
|
|
||||||
|
|
||||||
if not schedule:
|
|
||||||
raise Http404
|
|
||||||
|
|
||||||
filtered_assignments = SchedTimeSessAssignment.objects.filter(
|
|
||||||
schedule__in=[schedule, schedule.base],
|
|
||||||
session__on_agenda=True,
|
|
||||||
)
|
|
||||||
filtered_assignments = preprocess_assignments_for_agenda(filtered_assignments, meeting)
|
|
||||||
AgendaKeywordTagger(assignments=filtered_assignments).apply()
|
|
||||||
|
|
||||||
items = []
|
|
||||||
for a in filtered_assignments:
|
|
||||||
# we don't HTML escape any of these as the week-view code is using createTextNode
|
|
||||||
item = {
|
|
||||||
"key": str(a.timeslot.pk),
|
|
||||||
"utc_time": a.timeslot.utc_start_time().strftime("%Y%m%dT%H%MZ"), # ISO8601 compliant
|
|
||||||
"duration": a.timeslot.duration.seconds,
|
|
||||||
"type": a.slot_type().name,
|
|
||||||
"filter_keywords": ",".join(a.filter_keywords),
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.session:
|
|
||||||
if a.session.historic_group:
|
|
||||||
item["group"] = a.session.historic_group.acronym
|
|
||||||
|
|
||||||
if a.session.name:
|
|
||||||
item["name"] = a.session.name
|
|
||||||
elif a.slot_type().slug == "break":
|
|
||||||
item["name"] = a.timeslot.name
|
|
||||||
item["area"] = a.slot_type().slug
|
|
||||||
item["group"] = a.slot_type().slug
|
|
||||||
elif a.session.historic_group:
|
|
||||||
item["name"] = a.session.historic_group.name
|
|
||||||
if a.session.historic_group.state_id == "bof":
|
|
||||||
item["name"] += " BOF"
|
|
||||||
|
|
||||||
item["state"] = a.session.historic_group.state.name
|
|
||||||
if a.session.historic_group.historic_parent:
|
|
||||||
item["area"] = a.session.historic_group.historic_parent.acronym
|
|
||||||
|
|
||||||
if a.timeslot.show_location:
|
|
||||||
item["room"] = a.timeslot.get_location()
|
|
||||||
|
|
||||||
if a.session and a.session.agenda():
|
|
||||||
item["agenda"] = a.session.agenda().get_href()
|
|
||||||
|
|
||||||
if a.session.current_status == 'canceled':
|
|
||||||
item["name"] = "CANCELLED - " + item["name"]
|
|
||||||
|
|
||||||
items.append(item)
|
|
||||||
|
|
||||||
return render(request, "meeting/week-view.html", {
|
|
||||||
"items": json.dumps(items),
|
|
||||||
})
|
|
||||||
|
|
||||||
def ical_session_status(assignment):
|
def ical_session_status(assignment):
|
||||||
if assignment.session.current_status == 'canceled':
|
if assignment.session.current_status == 'canceled':
|
||||||
return "CANCELLED"
|
return "CANCELLED"
|
||||||
|
@ -3694,24 +3554,6 @@ def upcoming_json(request):
|
||||||
response = HttpResponse(json.dumps(data, indent=2, sort_keys=False), content_type='application/json;charset=%s'%settings.DEFAULT_CHARSET)
|
response = HttpResponse(json.dumps(data, indent=2, sort_keys=False), content_type='application/json;charset=%s'%settings.DEFAULT_CHARSET)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def floor_plan(request, num=None, floor=None, ):
|
|
||||||
meeting = get_meeting(num)
|
|
||||||
schedule = meeting.schedule
|
|
||||||
floors = FloorPlan.objects.filter(meeting=meeting).order_by('order')
|
|
||||||
if floor:
|
|
||||||
floors = [ f for f in floors if xslugify(f.name) == floor ]
|
|
||||||
for floor in floors:
|
|
||||||
try:
|
|
||||||
floor.image.width
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise Http404('Missing floorplan image for %s' % floor)
|
|
||||||
return render(request, 'meeting/floor-plan.html', {
|
|
||||||
"meeting": meeting,
|
|
||||||
"schedule": schedule,
|
|
||||||
"number": num,
|
|
||||||
"floors": floors,
|
|
||||||
})
|
|
||||||
|
|
||||||
def proceedings(request, num=None):
|
def proceedings(request, num=None):
|
||||||
|
|
||||||
meeting = get_meeting(num)
|
meeting = get_meeting(num)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'ietf.meeting.views.agenda' num=meeting.number ext='.txt' %}" target="_blank">View Agenda</a>.</li>
|
<li><a href="{% url 'ietf.meeting.views.agenda_plain' num=meeting.number ext='.txt' %}" target="_blank">View Agenda</a>.</li>
|
||||||
</ul>
|
</ul>
|
|
@ -236,13 +236,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
|
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
|
||||||
href="{% url 'agenda-neue' %}">
|
href="{% url 'agenda' %}">
|
||||||
Agenda (New)
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda' %}">
|
|
||||||
Agenda
|
Agenda
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -254,7 +248,7 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
|
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
|
||||||
href="{% url 'ietf.meeting.views.floor_plan' %}">
|
href="{% url 'floor-plan' %}">
|
||||||
Floor plan
|
Floor plan
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{# Copyright The IETF Trust 2015-2021, All Rights Reserved #}
|
|
||||||
{% load origin %}
|
|
||||||
{% load static %}
|
|
||||||
{% load ietf_filters %}
|
|
||||||
{% load textfilters %}
|
|
||||||
{% load htmlfilters agenda_custom_tags %}
|
|
||||||
{% load django_vite %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
IETF {{ meetingData.meetingNumber }} Meeting Agenda
|
|
||||||
{% endblock %}
|
|
||||||
{% block pagehead %}
|
|
||||||
<!-- AGENDA VUE COMPONENT -->
|
|
||||||
<!-- [html-validate-disable-block void-style, attribute-empty-style] -->
|
|
||||||
{{ meetingData|json_script:"meeting-data" }}
|
|
||||||
{% vite_asset 'client/main.js' %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block morecss %}
|
|
||||||
body {
|
|
||||||
font-family: 'Montserrat', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes initspinner {
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-loading {
|
|
||||||
position: fixed;
|
|
||||||
top: 60px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - 60px);
|
|
||||||
background-color: rgba(255,255,255,.75);
|
|
||||||
z-index: 2000000000;
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-loading:before {
|
|
||||||
content: '';
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
margin-top: -25px;
|
|
||||||
margin-left: -25px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border-top: 2px solid #999;
|
|
||||||
border-right: 2px solid transparent;
|
|
||||||
animation: initspinner .6s linear infinite;
|
|
||||||
z-index: 2000000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-loading:after {
|
|
||||||
content: 'Loading meeting {{ meetingData.meetingNumber }}...';
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -100px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #999;
|
|
||||||
z-index: 2000000000;
|
|
||||||
}
|
|
||||||
{% endblock %}
|
|
||||||
{% block precontent %}
|
|
||||||
<div class="meeting-switch">
|
|
||||||
<i class="bi bi-arrow-left-right me-2"></i>
|
|
||||||
<a href="{% url 'ietf.meeting.views.agenda' num=meetingData.meetingNumber %}">Switch to Legacy Agenda Display</a>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% origin %}
|
|
||||||
<div id="app"></div>
|
|
||||||
<div id="app-loading"></div>
|
|
||||||
{% endblock %}
|
|
|
@ -5,529 +5,69 @@
|
||||||
{% load ietf_filters %}
|
{% load ietf_filters %}
|
||||||
{% load textfilters %}
|
{% load textfilters %}
|
||||||
{% load htmlfilters agenda_custom_tags %}
|
{% load htmlfilters agenda_custom_tags %}
|
||||||
|
{% load django_vite %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
IETF {{ schedule.meeting.number }} Meeting Agenda
|
IETF {{ meetingData.meetingNumber }} Meeting Agenda
|
||||||
{% if "-utc" in request.path %}(UTC){% endif %}
|
|
||||||
{% if personalize %}Personalization{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block pagehead %}
|
{% block pagehead %}
|
||||||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
<!-- AGENDA VUE COMPONENT -->
|
||||||
|
<!-- [html-validate-disable-block void-style, attribute-empty-style] -->
|
||||||
|
{{ meetingData|json_script:"meeting-data" }}
|
||||||
|
{% vite_asset 'client/main.js' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block morecss %}#weekview iframe { height: 25em; }{% endblock %}
|
{% block morecss %}
|
||||||
{% block precontent %}
|
body {
|
||||||
<div class="meeting-switch">
|
font-family: 'Montserrat', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
<i class="bi bi-arrow-left-right me-2"></i>
|
}
|
||||||
<a href="{% url 'agenda-neue' num=schedule.meeting.number %}">Switch to New Agenda Display</a>
|
|
||||||
</div>
|
@keyframes initspinner {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 60px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
background-color: rgba(255,255,255,.75);
|
||||||
|
z-index: 2000000000;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-loading:before {
|
||||||
|
content: '';
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
margin-top: -25px;
|
||||||
|
margin-left: -25px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top: 2px solid #999;
|
||||||
|
border-right: 2px solid transparent;
|
||||||
|
animation: initspinner .6s linear infinite;
|
||||||
|
z-index: 2000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-loading:after {
|
||||||
|
content: 'Loading meeting {{ meetingData.meetingNumber }}...';
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -100px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #999;
|
||||||
|
z-index: 2000000000;
|
||||||
|
}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% origin %}
|
{% origin %}
|
||||||
{% if "-utc" in request.path %}
|
<div id="app"></div>
|
||||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=updated selected="agenda-utc" title_extra="(UTC)" %}
|
<div id="app-loading"></div>
|
||||||
{% elif personalize %}
|
|
||||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=updated selected="select-sessions" title_extra="" %}
|
|
||||||
{% else %}
|
|
||||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=updated selected="agenda" title_extra="" %}
|
|
||||||
{% endif %}
|
|
||||||
{# the contents of #extra-nav will be moved into the RH nav panel #}
|
|
||||||
<div id="extra-nav" class="d-none">
|
|
||||||
<div class="d-flex flex-column px-2">
|
|
||||||
{% if now.date <= schedule.meeting.end_date %}
|
|
||||||
<a class="btn btn-sm btn-primary my-3 now-link" href="#">Jump to current session</a>
|
|
||||||
{% endif %}
|
|
||||||
<div class="d-flex">
|
|
||||||
{% include 'meeting/tz-display.html' with id_suffix="-rh" meeting_timezone=timezone minimal=True only %}
|
|
||||||
</div>
|
|
||||||
<div class="small text-muted">
|
|
||||||
Showing <span class="current-tz">{{ timezone|split:"_"|join:" "|split:"/"|join:" / " }}</span> time
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{# cache this part -- it takes 3-6 seconds to generate #}
|
|
||||||
{% load cache %}
|
|
||||||
{% cache cache_time ietf_meeting_agenda_utc schedule.meeting.number request.path %}
|
|
||||||
<h2>
|
|
||||||
{% if personalize %}
|
|
||||||
Session selection
|
|
||||||
{% else %}
|
|
||||||
Agenda
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
{% if is_current_meeting %}
|
|
||||||
<p class="alert alert-info my-3">
|
|
||||||
<b>Note:</b> IETF agendas are subject to change, up to and during a meeting.
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% if schedule.meeting.agenda_info_note %}
|
|
||||||
<p class="alert alert-info my-3">
|
|
||||||
{{ schedule.meeting.agenda_info_note|removetags:"h1"|safe }}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% include 'meeting/tz-display.html' with id_suffix="" meeting_timezone=timezone only %}
|
|
||||||
{% include "meeting/agenda_filter.html" with filter_categories=filter_categories customize_button_text="Filter this agenda view..." always_show=personalize %}
|
|
||||||
{% include "meeting/agenda_personalize_buttonlist.html" with meeting=schedule.meeting personalize=personalize only %}
|
|
||||||
<div class="input-group mb-3">
|
|
||||||
<button class="btn btn-outline-primary dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
aria-expanded="false"
|
|
||||||
{% if filter_categories|length < 3 %}disabled{% endif %}>
|
|
||||||
Download area agenda
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
{% for fc in filter_categories %}
|
|
||||||
{% if not forloop.last %}
|
|
||||||
{# skip the last group, it's the office hours/misc #}
|
|
||||||
{% for p in fc|dictsort:"label" %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{% url "ietf.meeting.views.agenda_ical" num=schedule.meeting.number %}?show={{ p.keyword }}">
|
|
||||||
{{ p.label }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<a class="btn btn-outline-primary {% if non_area_keywords|length == 0 %}disabled{% endif %}"
|
|
||||||
href="{% if non_area_keywords %}{% url 'ietf.meeting.views.agenda_ical' num=schedule.meeting.number %}?show={{ non_area_keywords|join:',' }}{% else %}#{% endif %}">
|
|
||||||
Download non-area events
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div id="weekview" class="d-none mt-3">
|
|
||||||
<h2>
|
|
||||||
Schedule
|
|
||||||
{% if schedule.meeting.agenda_warning_note %}
|
|
||||||
<span class="badge rounded-pill bg-danger">
|
|
||||||
{{ schedule.meeting.agenda_warning_note|removetags:"h1" |safe }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
<iframe title="Schedule" class="w-100 overflow-hidden border border-dark"></iframe>
|
|
||||||
</div>
|
|
||||||
<h2 class="mt-3">
|
|
||||||
{% if personalize %}Personalize{% endif %}
|
|
||||||
Detailed Agenda
|
|
||||||
{% if schedule.meeting.agenda_warning_note %}
|
|
||||||
<span class="badge rounded-pill bg-danger">
|
|
||||||
{{ schedule.meeting.agenda_warning_note|removetags:"h1" |safe }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
{% if personalize %}
|
|
||||||
<p>
|
|
||||||
Check boxes below to select individual sessions.
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
<table id="agenda-table" class="table table-sm tablesorter">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
{% if personalize %}<th scope="col"></th>{% endif %}
|
|
||||||
<th scope="col"></th>
|
|
||||||
<th scope="col" data-sort="loc"></th>
|
|
||||||
<th scope="col" data-sort="group"></th>
|
|
||||||
<th scope="col" data-sort="area"></th>
|
|
||||||
<th scope="col" data-sort="desc"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in filtered_assignments %}
|
|
||||||
{% ifchanged item.timeslot.time|date:"Y-m-d" %}
|
|
||||||
<tr class="table-primary show-with-children">
|
|
||||||
<th scope="col" colspan="{% if personalize %}6{% else %}5{% endif %}"
|
|
||||||
id="slot-{{ item.timeslot.time|slugify }}"
|
|
||||||
class="nav-heading">
|
|
||||||
{{ item.timeslot.time|date:"l, F j, Y" }}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
{% endifchanged %}
|
|
||||||
{% if item|is_special_agenda_item %}
|
|
||||||
<tr id="row-{{ item.slug }}"
|
|
||||||
data-filter-keywords="{{ item.filter_keywords|join:',' }}"
|
|
||||||
data-slot-start-ts="{{ item.start_timestamp }}"
|
|
||||||
data-slot-end-ts="{{ item.end_timestamp }}">
|
|
||||||
{% if personalize %}
|
|
||||||
<td class="text-center">
|
|
||||||
{% if item.session_keyword %}
|
|
||||||
<label class="d-none"
|
|
||||||
aria-label="Select session"
|
|
||||||
for="{{ item.session_keyword }}-{{ item.slug }}">
|
|
||||||
</label>
|
|
||||||
<input type="checkbox"
|
|
||||||
class="pickview form-check-input"
|
|
||||||
title="Select session"
|
|
||||||
name="selected-sessions"
|
|
||||||
id="{{ item.session_keyword }}-{{ item.slug }}"
|
|
||||||
value="{{ item.session_keyword }}"
|
|
||||||
data-filter-keywords="{{ item.filter_keywords|join:',' }}"
|
|
||||||
data-filter-item="{{ item.session_keyword }}">
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% endif %}
|
|
||||||
<td class="text-end">{% include "meeting/timeslot_start_end.html" %}</td>
|
|
||||||
<td colspan="3">
|
|
||||||
{% if item.timeslot.show_location and item.timeslot.location %}
|
|
||||||
{% location_anchor item.timeslot %}
|
|
||||||
{{ item.timeslot.get_html_location }}
|
|
||||||
{% end_location_anchor %}
|
|
||||||
{% endif %}
|
|
||||||
{% if item.timeslot.show_location and item.timeslot.get_html_location %}
|
|
||||||
{% with item.timeslot.location.floorplan as floor %}
|
|
||||||
{% if item.timeslot.location.floorplan %}
|
|
||||||
<div class="d-none d-sm-block float-end">
|
|
||||||
<a href="{% url 'ietf.meeting.views.floor_plan' num=schedule.meeting.number %}#floor-{{ floor.name|xslugify }}"
|
|
||||||
class="float-end"
|
|
||||||
title="{{ floor.name }}">
|
|
||||||
<span class="badge rounded-pill bg-secondary">{{ floor.short }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% agenda_anchor item.session %}
|
|
||||||
{% assignment_display_name item %}
|
|
||||||
{% end_agenda_anchor %}
|
|
||||||
{% if item.session.current_status == 'canceled' %}
|
|
||||||
<span class="badge rounded-pill bg-danger float-end">CANCELLED</span>
|
|
||||||
{% else %}
|
|
||||||
{% if item.slot_type.slug == 'other' %}
|
|
||||||
{% if item.session.agenda or item.session.remote_instructions or item.session.agenda_note %}
|
|
||||||
<div class="float-end ps-2">
|
|
||||||
{% include "meeting/session_buttons_include.html" with show_agenda=True item=item schedule=schedule %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div>
|
|
||||||
{% for slide in item.session.slides %}
|
|
||||||
<a href="{{ slide.get_href }}">{{ slide.title|clean_whitespace }}</a>
|
|
||||||
<br>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% elif item|is_regular_agenda_item or item|is_plenary_agenda_item %}
|
|
||||||
{% if item|is_regular_agenda_item %}
|
|
||||||
{% ifchanged %}
|
|
||||||
<tr class="table-secondary session-label-row show-with-children"
|
|
||||||
data-slot-start-ts="{{ item.start_timestamp }}"
|
|
||||||
data-slot-end-ts="{{ item.end_timestamp }}">
|
|
||||||
{% if personalize %}<th scope="row" class="text-center"></th>{% endif %}
|
|
||||||
<th scope="row" class="text-end">{% include "meeting/timeslot_start_end.html" %}</th>
|
|
||||||
<th scope="row" colspan="4">
|
|
||||||
{{ item.timeslot.time|date:"l" }}
|
|
||||||
{{ item.timeslot.name|capfirst_allcaps }}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
{% endifchanged %}
|
|
||||||
{% endif %}
|
|
||||||
{% if item.session.historic_group %}
|
|
||||||
<tr id="row-{{ item.slug }}"
|
|
||||||
{% if item.slot_type.slug == 'plenary' %}class="{{ item.slot_type.slug }}danger"{% endif %}
|
|
||||||
data-filter-keywords="{{ item.filter_keywords|join:',' }}"
|
|
||||||
data-slot-start-ts="{{ item.start_timestamp }}"
|
|
||||||
data-slot-end-ts="{{ item.end_timestamp }}">
|
|
||||||
{% if personalize %}
|
|
||||||
<td class="text-center">
|
|
||||||
{% if item.session_keyword %}
|
|
||||||
<label class="d-none"
|
|
||||||
aria-label="Select session"
|
|
||||||
for="{{ item.session_keyword }}">
|
|
||||||
</label>
|
|
||||||
<input type="checkbox"
|
|
||||||
class="pickview form-check-input"
|
|
||||||
title="Select session"
|
|
||||||
name="selected-sessions"
|
|
||||||
id="{{ item.session_keyword }}"
|
|
||||||
value="{{ item.session_keyword }}"
|
|
||||||
data-filter-keywords="{{ item.filter_keywords|join:',' }}"
|
|
||||||
data-filter-item="{{ item.session_keyword }}">
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% endif %}
|
|
||||||
{% if item.slot_type.slug == 'plenary' %}
|
|
||||||
<td class="text-end">{% include "meeting/timeslot_start_end.html" %}</td>
|
|
||||||
<td colspan="3">
|
|
||||||
{% if item.timeslot.show_location and item.timeslot.location %}
|
|
||||||
{% location_anchor item.timeslot %}
|
|
||||||
{{ item.timeslot.get_html_location }}
|
|
||||||
{% end_location_anchor %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% else %}
|
|
||||||
<td>
|
|
||||||
{% with item.timeslot.location.floorplan as floor %}
|
|
||||||
{% if item.timeslot.location.floorplan %}
|
|
||||||
<div class="d-none d-sm-block">
|
|
||||||
<a href="{% url 'ietf.meeting.views.floor_plan' num=schedule.meeting.number %}#floor-{{ floor.name|xslugify }}"
|
|
||||||
class="float-end"
|
|
||||||
title="{{ floor.name }}">
|
|
||||||
<span class="badge rounded-pill bg-secondary">{{ floor.short }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if item.timeslot.show_location and item.timeslot.location %}
|
|
||||||
{% location_anchor item.timeslot %}
|
|
||||||
{{ item.timeslot.get_html_location }}
|
|
||||||
{% end_location_anchor %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if item.session.historic_group.historic_parent.acronym %}
|
|
||||||
<div class="d-none d-sm-block">{{ item.session.historic_group.historic_parent.acronym }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="d-none d-sm-block">
|
|
||||||
{% if item.session.historic_group %}
|
|
||||||
<a href="{% url 'ietf.group.views.group_about' acronym=item.session.historic_group.acronym %}">
|
|
||||||
{{ item.session.historic_group.acronym }}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{{ item.session.historic_group.acronym }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
{% endif %}
|
|
||||||
<td>
|
|
||||||
{% if item.session.current_status == 'canceled' %}
|
|
||||||
<span class="badge rounded-pill bg-danger float-end">Cancelled</span>
|
|
||||||
{% else %}
|
|
||||||
<div class="float-end ps-2">
|
|
||||||
{% include "meeting/session_buttons_include.html" with show_agenda=True session=item.session meeting=schedule.meeting %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="d-sm-none">
|
|
||||||
{% if item.session.historic_group %}
|
|
||||||
<a href="{% url 'ietf.group.views.group_about' acronym=item.session.historic_group.acronym %}">
|
|
||||||
{{ item.session.historic_group.acronym }}</a>
|
|
||||||
{% else %}
|
|
||||||
{{ item.session.historic_group.acronym }}
|
|
||||||
{% endif %}
|
|
||||||
{% if item.session.historic_group.historic_parent.acronym %}
|
|
||||||
<span class="text-muted">{{ item.session.historic_group.historic_parent.acronym }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% agenda_anchor item.session %}
|
|
||||||
{% assignment_display_name item %}
|
|
||||||
{% end_agenda_anchor %}
|
|
||||||
{% if item.session.historic_group.state_id == "bof" %}
|
|
||||||
<span class="badge rounded-pill bg-success float-end">BOF</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if item.session.current_status == 'resched' %}
|
|
||||||
<div class="badge rounded-pill bg-danger float-end">
|
|
||||||
Rescheduled
|
|
||||||
{% if item.session.rescheduled_to %}
|
|
||||||
TO
|
|
||||||
<div class="timetooltip reschedtimetooltip">
|
|
||||||
<div data-start-time="{{ item.session.rescheduled_to.utc_start_time|date:"U" }}"
|
|
||||||
data-end-time="{{ item.session.rescheduled_to.utc_end_time|date:"U" }}"
|
|
||||||
{% if item.timeslot.time|date:"l" != item.session.rescheduled_to.time|date:"l" %} data-weekday="1"{% endif %}>
|
|
||||||
{% if "-utc" in request.path %}
|
|
||||||
{{ item.session.rescheduled_to.utc_start_time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.utc_end_time|date:"G:i" }}
|
|
||||||
{% else %}
|
|
||||||
{{ item.session.rescheduled_to.time|date:"l G:i"|upper }}-{{ item.session.rescheduled_to.end_time|date:"G:i" }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if item.session.agenda_note|first_url|conference_url %}
|
|
||||||
<br>
|
|
||||||
<a href="{{ item.session.agenda_note|first_url }}">{{ item.session.agenda_note|slice:":23" }}
|
|
||||||
</a>
|
|
||||||
{% elif item.session.agenda_note %}
|
|
||||||
<br>
|
|
||||||
<span class="text-danger small">{{ item.session.agenda_note }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% if personalize %}{# only show second copy of buttons for the personalize tab #}
|
|
||||||
{% include "meeting/agenda_personalize_buttonlist.html" with meeting=schedule.meeting personalize=personalize only %}
|
|
||||||
{% endif %}
|
|
||||||
{% endcache %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js %}
|
|
||||||
<script src="{% static 'ietf/js/agenda_filter.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
// Update the agenda display with specified filters
|
|
||||||
function update_agenda_display(filter_params) {
|
|
||||||
var agenda_rows=$('[id^="row-"]')
|
|
||||||
|
|
||||||
if (!agenda_filter.filtering_is_enabled(filter_params)) {
|
|
||||||
// When filtering is not enabled, show all sessions
|
|
||||||
agenda_rows.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if groups were selected for filtering, hide all rows by default
|
|
||||||
agenda_rows.filter(function(index, row) {
|
|
||||||
return !!$(row).attr('data-filter-keywords');
|
|
||||||
}).hide();
|
|
||||||
|
|
||||||
// loop through the has items and change the UI element and row visibilities accordingly
|
|
||||||
$.each(filter_params.show, function (i, v) {
|
|
||||||
// this is a regular item by wg: when present, show these rows
|
|
||||||
agenda_filter.rows_matching_filter_keyword(agenda_rows, v).show();
|
|
||||||
});
|
|
||||||
$.each(filter_params.hide, function (i, v) {
|
|
||||||
// this is a "negative" item by wg: when present, hide these rows
|
|
||||||
agenda_filter.rows_matching_filter_keyword(agenda_rows, v).hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Now hide any session label rows with no visible sessions. Identify
|
|
||||||
// by matching on start/end timestamps.
|
|
||||||
$('tr.session-label-row').each(function(i, e) {
|
|
||||||
var start_ts = $(e).attr('data-slot-start-ts');
|
|
||||||
var end_ts = $(e).attr('data-slot-end-ts');
|
|
||||||
var visible_rows = agenda_rows.filter(
|
|
||||||
'[data-slot-start-ts="' + start_ts + '"]' +
|
|
||||||
'[data-slot-end-ts="' + end_ts + '"]' +
|
|
||||||
':visible'
|
|
||||||
);
|
|
||||||
if (visible_rows.length > 0) {
|
|
||||||
$(e).show();
|
|
||||||
} else {
|
|
||||||
$(e).hide();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_ical_links(filter_params) {
|
|
||||||
$(".ical-link").toggleClass("d-none", !agenda_filter.filtering_is_enabled(filter_params));
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_weekview(filter_params) {
|
|
||||||
var weekview = $("#weekview");
|
|
||||||
if (agenda_filter.filtering_is_enabled(filter_params)) {
|
|
||||||
weekview.removeClass("d-none");
|
|
||||||
} else {
|
|
||||||
weekview.addClass("d-none");
|
|
||||||
}
|
|
||||||
update_weekview_display();
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_weekview_display() {
|
|
||||||
var weekview = $("#weekview");
|
|
||||||
if (!weekview.hasClass('d-none')) {
|
|
||||||
var queryparams = window.location.search;
|
|
||||||
if (queryparams) {
|
|
||||||
queryparams += '&tz=' + encodeURIComponent(ietf_timezone.get_current_tz().toLowerCase());
|
|
||||||
} else {
|
|
||||||
queryparams = '?tz=' + encodeURIComponent(ietf_timezone.get_current_tz().toLowerCase());
|
|
||||||
}
|
|
||||||
var new_url = 'week-view.html' + queryparams;
|
|
||||||
var wv_iframe = $(weekview).children('iframe');
|
|
||||||
var wv_window = wv_iframe.contentWindow;
|
|
||||||
if (wv_iframe.src && wv_window.location.hostname && wv_window.history && wv_window.history.replaceState) {
|
|
||||||
wv_window.history.replaceState({}, '', new_url);
|
|
||||||
wv_window.redraw_weekview();
|
|
||||||
} else {
|
|
||||||
// either have not yet loaded the iframe or we do not support history replacement
|
|
||||||
$(wv_iframe).attr("src", new_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_view(filter_params) {
|
|
||||||
update_agenda_display(filter_params);
|
|
||||||
update_weekview(filter_params)
|
|
||||||
update_ical_links(filter_params)
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<script src="{% static 'ietf/js/list.js' %}">
|
|
||||||
</script>
|
|
||||||
<script src="{% static 'ietf/js/moment.js' %}">
|
|
||||||
</script>
|
|
||||||
<script src="{% static 'ietf/js/timezone.js' %}">
|
|
||||||
</script>
|
|
||||||
<script src="{% static 'ietf/js/agenda_materials.js' %}">
|
|
||||||
</script>
|
|
||||||
<script src="{% static 'ietf/js/agenda_timezone.js' %}">
|
|
||||||
</script>
|
|
||||||
{% if personalize %}
|
|
||||||
<script src="{% static 'ietf/js/agenda_personalize.js' %}">
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
<script>
|
|
||||||
{% if settings.DEBUG and settings.DEBUG_AGENDA %}
|
|
||||||
speedup = +urlParam('speedup');
|
|
||||||
if (speedup < 1) {
|
|
||||||
speedup = 1;
|
|
||||||
}
|
|
||||||
start_time = moment().utc();
|
|
||||||
if (urlParam('date')) {
|
|
||||||
offset_time = moment.tz(decodeURIComponent(urlParam('date')), "UTC");
|
|
||||||
} else {
|
|
||||||
offset_time = start_time;
|
|
||||||
}
|
|
||||||
if (speedup > 1 || offset_time !== start_time) {
|
|
||||||
moment.now = function () {
|
|
||||||
return (+new Date() - start_time) * speedup + offset_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{% else %}
|
|
||||||
speedup = 1;
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
// Methods/variables here that are not in ietf_timezone or agenda_filter are from agenda_timezone.js
|
|
||||||
meeting_timezone = '{{ timezone }}';
|
|
||||||
|
|
||||||
// First, initialize_moments(). This must be done before calling any of the update methods.
|
|
||||||
// It does not need timezone info, so safe to call before initializing ietf_timezone.
|
|
||||||
initialize_moments(); // fills in moments in the agenda data
|
|
||||||
|
|
||||||
// Now set up callbacks related to ietf_timezone. This must happen before calling initialize().
|
|
||||||
// In particular, set_current_tz_cb() must be called before the update methods are called.
|
|
||||||
set_current_tz_cb(ietf_timezone.get_current_tz); // give agenda_timezone access to this method
|
|
||||||
ietf_timezone.set_tz_change_callback(function(newtz) {
|
|
||||||
update_times(newtz);
|
|
||||||
update_weekview_display();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// With callbacks in place, call ietf_timezone.initialize(). This will call the tz_change callback
|
|
||||||
// after setting things up.
|
|
||||||
{% if "-utc" in request.path %}
|
|
||||||
ietf_timezone.initialize('UTC');
|
|
||||||
{% else %}
|
|
||||||
ietf_timezone.initialize(meeting_timezone);
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
// Now make other setup calls from agenda_timezone.js
|
|
||||||
add_tooltips();
|
|
||||||
init_timers(speedup);
|
|
||||||
|
|
||||||
// Finally, set up the agenda filter UI. This does not depend on the timezone.
|
|
||||||
{% if personalize %}
|
|
||||||
agenda_filter.set_update_callback(function (e) {
|
|
||||||
handleFilterParamUpdate(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('agenda-table')
|
|
||||||
.addEventListener('click', handleTableClick);
|
|
||||||
{% else %}
|
|
||||||
agenda_filter.set_update_callback(update_view);
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
agenda_filter.enable();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
|
@ -23,6 +23,6 @@ DESCRIPTION:{{item.timeslot.name|ics_esc}}\n{% if item.session.agenda_note %}
|
||||||
\n
|
\n
|
||||||
Session materials: {% absurl 'ietf.meeting.views.session_details' num=schedule.meeting.number acronym=item.session.group.acronym %}\n{% if schedule.meeting.get_number is not None %}
|
Session materials: {% absurl 'ietf.meeting.views.session_details' num=schedule.meeting.number acronym=item.session.group.acronym %}\n{% if schedule.meeting.get_number is not None %}
|
||||||
\n{# link agenda for ietf meetings #}
|
\n{# link agenda for ietf meetings #}
|
||||||
See in schedule: {% absurl 'ietf.meeting.views.agenda' num=schedule.meeting.number %}#row-{{ item.slug }}\n{% endif %}
|
See in schedule: {% absurl 'agenda' num=schedule.meeting.number %}#row-{{ item.slug }}\n{% endif %}
|
||||||
END:VEVENT
|
END:VEVENT
|
||||||
{% endif %}{% endfor %}END:VCALENDAR{% endcache %}{% endautoescape %}
|
{% endif %}{% endfor %}END:VCALENDAR{% endcache %}{% endautoescape %}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block morecss %}
|
|
||||||
.type-lead:after { content: " (DO NOT POST)"; color:red; }
|
|
||||||
.type-offagenda:after { content:" (not published on agenda)"; }
|
|
||||||
{% endblock %}
|
|
||||||
{% block title %}Agenda for {{ meeting }} by room{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% include "meeting/meeting_heading.html" with updated=meeting.updated selected="by-room" title_extra="By room" %}
|
|
||||||
<div class="daylist">
|
|
||||||
{% for day,sessions in ss_by_day.items %}
|
|
||||||
<h2 class="daylistentry mt-5">{{ day|date:'l, j F Y' }}</h2>
|
|
||||||
{% regroup sessions by timeslot.get_functional_location as room_list %}
|
|
||||||
<div class="roomlist">
|
|
||||||
{% for room in room_list %}
|
|
||||||
<strong class="roomlistentry">{{ room.grouper|default:"Location Unavailable" }}</strong>
|
|
||||||
<ul class="sessionlist">
|
|
||||||
{% for ss in room.list %}
|
|
||||||
<li class="sessionlistentry type-{{ ss.slot_type.slug }} {% if ss.schedule_id != meeting.schedule_id %}from-base-schedule{% endif %}">
|
|
||||||
{{ ss.timeslot.time|date:"H:i" }}-{{ ss.timeslot.end_time|date:"H:i" }} {{ ss.session.short_name }}
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,49 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block morecss %}
|
|
||||||
.type-lead:after { content: " (DO NOT POST)"; color:red; }
|
|
||||||
.type-offagenda:after { content:" (not published on agenda)"; }
|
|
||||||
{% endblock %}
|
|
||||||
{% block title %}Agenda for {{ meeting }} by Session Type{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% include "meeting/meeting_heading.html" with updated=meeting.updated selected="by-type" title_extra="By session type" %}
|
|
||||||
{% regroup assignments by session.type_id as type_list %}
|
|
||||||
<div class="typelist">
|
|
||||||
{% for type in type_list %}
|
|
||||||
<div class="typelistentry">
|
|
||||||
<h2 class="mt-5">{{ type.grouper|title }}</h2>
|
|
||||||
{% if schedule == meeting.schedule %}
|
|
||||||
<a class="btn btn-primary ical-link"
|
|
||||||
href="{% url "ietf.meeting.views.agenda_by_type_ics" num=meeting.number type=type.grouper %}">
|
|
||||||
Download to Calendar
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<div class="daylist">
|
|
||||||
{% regroup type.list by timeslot.time|date:"l Y-M-d" as daylist %}
|
|
||||||
{% for day in daylist %}
|
|
||||||
<div class="daylistentry">
|
|
||||||
<h3 class="mt-4">{{ day.grouper }}</h3>
|
|
||||||
<table class="table table-sm table-borderless sessiontable">
|
|
||||||
<tbody>
|
|
||||||
{% for ss in day.list %}
|
|
||||||
<tr {% if ss.schedule_id != meeting.schedule_id %}class="from-base-schedule"{% endif %}>
|
|
||||||
<td>{{ ss.timeslot.time|date:"H:i" }}-{{ ss.timeslot.end_time|date:"H:i" }}</td>
|
|
||||||
<td>{{ ss.timeslot.get_hidden_location }}</td>
|
|
||||||
<td class="type-{{ ss.session.type_id }}">{{ ss.session.short_name }}</td>
|
|
||||||
<td class="text-end">
|
|
||||||
{% if ss.session.type_id == 'regular' or ss.session.type_id == 'plenary' or ss.session.type_id == 'other' %}
|
|
||||||
<a href="{% url 'ietf.meeting.views.session_details' num=meeting.number acronym=ss.session.group.acronym %}">
|
|
||||||
Materials
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,24 +0,0 @@
|
||||||
{% comment %}
|
|
||||||
Buttons for the agenda_personalize.html template
|
|
||||||
|
|
||||||
Required parameters:
|
|
||||||
meeting - meeting being displayed
|
|
||||||
personalize - if True, show buttons relevant only for personalize tab
|
|
||||||
{% endcomment %}
|
|
||||||
{% load agenda_custom_tags %}
|
|
||||||
<div class="mb-3 buttonlist">
|
|
||||||
<a class="btn btn-sm btn-outline-primary ical-link agenda-link filterable"
|
|
||||||
href="{% webcal_url 'ietf.meeting.views.agenda_ical' num=meeting.number %}">
|
|
||||||
Subscribe to filtered agenda
|
|
||||||
</a>
|
|
||||||
<a class="btn btn-sm btn-outline-primary ical-link agenda-link filterable"
|
|
||||||
href="{% url "ietf.meeting.views.agenda_ical" num=meeting.number %}">
|
|
||||||
Download .ics of filtered agenda
|
|
||||||
</a>
|
|
||||||
{% if personalize %}
|
|
||||||
<a class="btn btn-sm btn-outline-primary agenda-link filterable"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">
|
|
||||||
View personal agenda
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
|
@ -1,107 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
|
||||||
{% load origin %}
|
|
||||||
{% load ietf_filters %}
|
|
||||||
{% load textfilters %}
|
|
||||||
{% load static %}
|
|
||||||
{% block title %}
|
|
||||||
IETF {{ meeting.number }} meeting agenda
|
|
||||||
{% if "-utc" in request.path %}(UTC){% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block bodyAttrs %}onload="automaticarrow(); checkParams();" onresize="checkParams();"{% endblock %}
|
|
||||||
{% block precontent %}
|
|
||||||
<div class="meeting-switch">
|
|
||||||
<i class="bi bi-arrow-left-right me-2"></i>
|
|
||||||
<a href="{% url 'floor-plan-neue' num=schedule.meeting.number %}">Switch to New Agenda Display</a>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% origin %}
|
|
||||||
{% include "meeting/meeting_heading.html" with selected="floor-plan" title_extra="Floor Plan" %}
|
|
||||||
{% for floor in floors %}
|
|
||||||
<h2 class="mt-4" id="floor-{{ floor.name|xslugify }}">{{ floor.name }}</h2>
|
|
||||||
<div class="row rooms">
|
|
||||||
<div class="col-sm-2">
|
|
||||||
{% for f in floors %}
|
|
||||||
{% for room in f.room_set.all %}
|
|
||||||
<a href="javascript: setarrow('room-{{ room.name|xslugify }}')">{{ room.name }}</a>
|
|
||||||
<br>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
{% for f in floors %}
|
|
||||||
{% for room in f.room_set.all %}
|
|
||||||
{% if room.functional_display_name %}
|
|
||||||
<a href="javascript: setarrow('room-{{ room.name|xslugify }}')">{{ room.functional_display_name }}</a>
|
|
||||||
<br>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<div class="floor-plan position-relative">
|
|
||||||
{% if floor.image %}
|
|
||||||
<img id="floor-{{ floor.name|xslugify }}-image"
|
|
||||||
alt="{{ floor.name }} Map"
|
|
||||||
class="img-fluid w-100"
|
|
||||||
src="{{ floor.image.url }}">
|
|
||||||
{# We need as many of these as we can have individual rooms combining into one #}
|
|
||||||
<div id="floor-{{ floor.name|xslugify }}-arrowdiv0"
|
|
||||||
class="position-absolute" hidden>
|
|
||||||
<img alt="Location arrow" src="{% static 'ietf/images/arrow-ani.webp' %}">
|
|
||||||
</div>
|
|
||||||
<div id="floor-{{ floor.name|xslugify }}-arrowdiv1"
|
|
||||||
class="position-absolute" hidden>
|
|
||||||
<img alt="Location arrow" src="{% static 'ietf/images/arrow-ani.webp' %}">
|
|
||||||
</div>
|
|
||||||
<div id="floor-{{ floor.name|xslugify }}-arrowdiv2"
|
|
||||||
class="position-absolute" hidden>
|
|
||||||
<img alt="Location arrow" src="{% static 'ietf/images/arrow-ani.webp' %}">
|
|
||||||
</div>
|
|
||||||
<div id="floor-{{ floor.name|xslugify }}-arrowdiv3"
|
|
||||||
class="position-absolute" hidden>
|
|
||||||
<img alt="Location arrow" src="{% static 'ietf/images/arrow-ani.webp' %}">
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
No floor image available yet.
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block js %}
|
|
||||||
<script src="{% static 'ietf/js/room_params.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
// These must match the 'arrowdiv' divs above
|
|
||||||
var arrowsuffixlist = [ '0', '1', '2', '3' ];
|
|
||||||
var floorlist = [{% for floor in floors %}{% if not forloop.first %}, {%endif%}'floor-{{floor.name|xslugify}}'{% endfor %}];
|
|
||||||
|
|
||||||
function roommap(nm)
|
|
||||||
{
|
|
||||||
var c = findroom(nm);
|
|
||||||
if (c) return nm;
|
|
||||||
var m = suffixmap(nm);
|
|
||||||
// console.log("m=" + m);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findroom(nm)
|
|
||||||
{
|
|
||||||
var left = 0, top = 0, right = 0, bottom = 0, floor="", width=0;
|
|
||||||
|
|
||||||
if (0) { }
|
|
||||||
{% for room in meeting.room_set.all %}{% if room.floorplan %}
|
|
||||||
else if (nm == 'room-{{room.name|xslugify}}') { left = {{room.left}}; top = {{room.top}}; right = {{room.right}}; bottom = {{room.bottom}}; floor='floor-{{room.floorplan.name|xslugify}}'; width={{room.floorplan.image.width}}; }{% endif %}{% endfor %}
|
|
||||||
|
|
||||||
{% for room in meeting.room_set.all %}{% if room.functional_display_name %}{% if room.floorplan %}
|
|
||||||
else if (nm == '{{room.functional_name|xslugify}}') { left = {{room.left}}; top = {{room.top}}; right = {{room.right}}; bottom = {{room.bottom}}; floor='floor-{{room.floorplan.name|xslugify}}'; width={{room.floorplan.image.width}}; }{% endif %}{% endif %}{% endfor %}
|
|
||||||
|
|
||||||
else return null;
|
|
||||||
|
|
||||||
// console.log("nm=" + nm + ",left=" + left + ",top=" + top + ",r=" + right + ",b=" + bottom);
|
|
||||||
return [left, top, right, bottom, floor, width];
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
|
@ -1,85 +0,0 @@
|
||||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
|
||||||
{% load origin %}
|
|
||||||
{% origin %}
|
|
||||||
{# assumes meeting is in context #}
|
|
||||||
{% load origin %}
|
|
||||||
{% load ietf_filters htmlfilters %}
|
|
||||||
{% origin %}
|
|
||||||
<h1>
|
|
||||||
IETF {{ meeting.number }} meeting agenda
|
|
||||||
{% if personalize %}personalization{% endif %}
|
|
||||||
{% if schedule.meeting.agenda_warning_note %}
|
|
||||||
<span class="badge rounded-pill bg-danger">
|
|
||||||
{{ schedule.meeting.agenda_warning_note|removetags:"h1" |safe }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if title_extra %}
|
|
||||||
<br>
|
|
||||||
<small class="text-muted">{{ title_extra }}</small>
|
|
||||||
{% endif %}
|
|
||||||
</h1>
|
|
||||||
<div class="lead row">
|
|
||||||
<div class="{% if updated %}col-6{% else %}col-12{% endif %}">
|
|
||||||
{{ meeting.city|default:"Location TBD" }}, {{ meeting.date|date:"F j" }}{% if meeting.date.month != meeting.end_date.month %} - {{ meeting.end_date|date:"F " }}{% else %}-{% endif %}{{ meeting.end_date|date:"j, Y" }}
|
|
||||||
</div>
|
|
||||||
{% if updated %}
|
|
||||||
<div class="col-6 text-end">
|
|
||||||
Updated {{ updated|date:"Y-m-d \a\t G:i (T)" }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if schedule != meeting.schedule %}
|
|
||||||
<div class="alert alert-danger my-3">
|
|
||||||
This is schedule <b>{{ schedule.owner.email }}/{{ schedule.name }}</b>, not the official schedule.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{# a tags with the agenda-link filterable classes will be updated with show/hide parameters #}
|
|
||||||
<ul class="nav nav-tabs my-3">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link agenda-link filterable {% if selected == "agenda" %}active{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">
|
|
||||||
Agenda
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% if user|has_role:"Secretariat,Area Director,IAB" %}
|
|
||||||
{% if schedule != meeting.schedule %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if selected == "by-room" %}active{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda_by_room' num=meeting.number name=schedule.name owner=schedule.owner.email %}">
|
|
||||||
By
|
|
||||||
room
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if selected == "by-type" %}active{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda_by_type' num=meeting.number name=schedule.name owner=schedule.owner.email %}">
|
|
||||||
By
|
|
||||||
type
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if selected == "by-room" %}active{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda_by_room' num=meeting.number %}">
|
|
||||||
By room
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if selected == "by-type" %}active{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda_by_type' num=meeting.number %}">
|
|
||||||
By type
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if selected == "floor-plan" %}active{% endif %}"
|
|
||||||
href="{% url 'ietf.meeting.views.floor_plan' num=meeting.number %}">
|
|
||||||
Floor plan
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda' num=meeting.number ext='.txt' %}">Plaintext</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
|
@ -1,9 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
|
||||||
{% load origin %}
|
|
||||||
{% block title %}IETF {{ meeting.number }} Meeting Agenda{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% origin %}
|
|
||||||
{% include "meeting/meeting_heading.html" with title_extra="" selected="" %}
|
|
||||||
<div class="alert alert-warning my-3">There is no agenda available yet.</div>
|
|
||||||
{% endblock %}
|
|
|
@ -37,7 +37,7 @@
|
||||||
<a href="{% url 'ietf.meeting.views.session_details' num=meeting.number acronym=meeting.responsible_group.acronym %}">{{ meeting.number }}</a>
|
<a href="{% url 'ietf.meeting.views.session_details' num=meeting.number acronym=meeting.responsible_group.acronym %}">{{ meeting.number }}</a>
|
||||||
{% if meeting.interim_meeting_cancelled %}<span class="badge rounded-pill bg-warning">Cancelled</span>{% endif %}
|
{% if meeting.interim_meeting_cancelled %}<span class="badge rounded-pill bg-warning">Cancelled</span>{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">IETF-{{ meeting.number }}</a>
|
<a href="{% url 'agenda' num=meeting.number %}">IETF-{{ meeting.number }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none d-sm-table-cell">
|
<td class="d-none d-sm-table-cell">
|
||||||
|
|
|
@ -11,7 +11,7 @@ This renders the list of links below the title on the meeting proceedings page.
|
||||||
<a href="{% url 'ietf.meeting.views.proceedings_attendees' num=meeting.number %}">Participants</a>
|
<a href="{% url 'ietf.meeting.views.proceedings_attendees' num=meeting.number %}">Participants</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="proceedings-row">
|
<div class="proceedings-row">
|
||||||
<a href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">Meeting Agenda</a>
|
<a href="{% url 'agenda' num=meeting.number %}">Meeting Agenda</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="proceedings-row">
|
<div class="proceedings-row">
|
||||||
<a href="{% url 'ietf.meeting.views.proceedings_progress_report' num=meeting.number %}">Activity Report</a>
|
<a href="{% url 'ietf.meeting.views.proceedings_progress_report' num=meeting.number %}">Activity Report</a>
|
||||||
|
|
|
@ -1,379 +0,0 @@
|
||||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
|
||||||
{% load origin %}
|
|
||||||
{% load static %}
|
|
||||||
{% load textfilters %}
|
|
||||||
{% load ietf_filters %}
|
|
||||||
{% origin %}
|
|
||||||
{% if item and item|should_show_agenda_session_buttons %}
|
|
||||||
{% with slug=item.slug %}
|
|
||||||
{% with session=item.session %}
|
|
||||||
{% with timeslot=item.timeslot %}
|
|
||||||
{% with meeting=schedule.meeting %}
|
|
||||||
{% if session.agenda and show_agenda %}
|
|
||||||
{# Note: if called with show_agenda=True, calling template must load agenda_materials.js, needed by session_agenda_include.html #}
|
|
||||||
{% include "meeting/session_agenda_include.html" with slug=slug session=session timeslot=timeslot only %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="d-flex">
|
|
||||||
{% if timeslot.location.video_stream_url or timeslot.location.onsite_tool_url %}
|
|
||||||
<div id="session-meetecho-buttons-{{ session.pk }}"
|
|
||||||
role="group"
|
|
||||||
class="btn-group btn-group-sm d-none d-lg-flex me-1">
|
|
||||||
{# Video stream (meetecho) #}
|
|
||||||
{% if timeslot.location.video_stream_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ timeslot.location.video_stream_url|format:session }}"
|
|
||||||
aria-label="Full Client with Video"
|
|
||||||
title="Full Client with Video">
|
|
||||||
<i class="bi bi-camera-video"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{# Onsite tool (meetecho_onsite) #}
|
|
||||||
{% if timeslot.location.onsite_tool_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ timeslot.location.onsite_tool_url|format:session }}"
|
|
||||||
aria-label="Onsite tool"
|
|
||||||
title="Onsite tool">
|
|
||||||
<i class="bi bi-phone"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div id="session-buttons-{{ session.pk }}"
|
|
||||||
role="group"
|
|
||||||
class="btn-group btn-group-sm d-none d-lg-flex">
|
|
||||||
{% with acronym=session.historic_group.acronym %}
|
|
||||||
{% if session.agenda and show_agenda %}
|
|
||||||
{# agenda pop-up button #}
|
|
||||||
<button class="btn btn-outline-primary"
|
|
||||||
data-bs-toggle="modal" type="button"
|
|
||||||
data-bs-target="#modal-{{ slug }}"
|
|
||||||
aria-label="Show meeting materials"
|
|
||||||
title="Show meeting materials">
|
|
||||||
<i class="bi bi-arrows-fullscreen"></i>
|
|
||||||
</button>
|
|
||||||
{# materials tar file #}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{% url 'ietf.meeting.views.session_draft_tarfile' num=meeting.number acronym=acronym %}"
|
|
||||||
aria-label="Download meeting materials as .tar archive"
|
|
||||||
title="Download meeting materials as .tar archive">
|
|
||||||
<i class="bi bi-file-zip"></i>
|
|
||||||
</a>
|
|
||||||
{# materials PDF file #}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{% url 'ietf.meeting.views.session_draft_pdf' num=meeting.number acronym=acronym %}"
|
|
||||||
aria-label="Download meeting materials as PDF file"
|
|
||||||
title="Download meeting materials as PDF file">
|
|
||||||
<i class="bi bi-file-pdf"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{# HedgeDoc #}
|
|
||||||
{% if use_codimd %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ session.notes_url }}"
|
|
||||||
aria-label="Notepad for note-takers"
|
|
||||||
title="Notepad for note-takers">
|
|
||||||
<i class="bi bi-journal-text"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{# show stream buttons up till end of session, then show archive buttons #}
|
|
||||||
{% if now < timeslot.utc_end_time %}
|
|
||||||
{# Chat #}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ session.chat_room_url }}"
|
|
||||||
aria-label="Chat room for {{ session.chat_room_name }}"
|
|
||||||
title="Chat room for {{ session.chat_room_name }}">
|
|
||||||
<i class="bi bi-chat"></i>
|
|
||||||
</a>
|
|
||||||
{# Audio stream #}
|
|
||||||
{% if timeslot.location.audio_stream_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ timeslot.location.audio_stream_url|format:session }}"
|
|
||||||
aria-label="Audio stream"
|
|
||||||
title="Audio stream">
|
|
||||||
<i class="bi bi-headphones"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{# Remote call-in #}
|
|
||||||
{% if session.agenda_note|first_url|conference_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ session.agenda_note|first_url }}"
|
|
||||||
aria-label="Online conference"
|
|
||||||
title="Online conference">
|
|
||||||
<i class="bi bi-people"></i>
|
|
||||||
</a>
|
|
||||||
{% elif session.remote_instructions|first_url|conference_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ session.remote_instructions|first_url }}"
|
|
||||||
aria-label="Online conference"
|
|
||||||
title="Online conference">
|
|
||||||
<i class="bi bi-people"></i>
|
|
||||||
</a>
|
|
||||||
{% elif timeslot.location.webex_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ timeslot.location.webex_url|format:session }}"
|
|
||||||
aria-label="Webex session"
|
|
||||||
title="Webex session">
|
|
||||||
<i class="bi bi-people"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{# iCalendar item #}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda_ical' num=meeting.number session_id=session.id %}"
|
|
||||||
aria-label="icalendar entry for {{ acronym }} session on {{ timeslot.utc_start_time|date:'Y-m-d H:i' }} UTC"
|
|
||||||
title="icalendar entry for {{ acronym }} session on {{ timeslot.utc_start_time|date:'Y-m-d H:i' }} UTC">
|
|
||||||
<i class="bi bi-calendar"></i>
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{# Chat logs #}
|
|
||||||
{% if meeting.number|add:"0" >= 60 %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ session.chat_archive_url }}"
|
|
||||||
aria-label="Chat logs for {{ session.chat_room_name }}"
|
|
||||||
title="Chat logs for {{ session.chat_room_name }}">
|
|
||||||
<i class="bi bi-file-text"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{# Recordings #}
|
|
||||||
{% if meeting.number|add:"0" >= 80 %}
|
|
||||||
{% with session.recordings as recordings %}
|
|
||||||
{% if recordings %}
|
|
||||||
{# There's no guaranteed order, so this is a bit messy: #}
|
|
||||||
{# First, the audio recordings, if any #}
|
|
||||||
{% for r in recordings %}
|
|
||||||
{% if r.get_href and 'audio' in r.get_href %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ r.get_href }}"
|
|
||||||
aria-label="{{ r.title }}"
|
|
||||||
title="{{ r.title }}">
|
|
||||||
<i class="bi bi-file-play"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{# Then the youtube recordings #}
|
|
||||||
{% for r in recordings %}
|
|
||||||
{% if r.get_href and 'youtu' in r.get_href %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ r.get_href }}"
|
|
||||||
aria-label="{{ r.title }}"
|
|
||||||
title="{{ r.title }}">
|
|
||||||
<i class="bi bi-file-slides"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{# Finally, any other recordings #}
|
|
||||||
{% for r in recordings %}
|
|
||||||
{% if r.get_href and not 'audio' in r.get_href and not 'youtu' in r.get_href %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="{{ r.get_href }}"
|
|
||||||
aria-label="{{ r.title }}"
|
|
||||||
title="{{ r.title }}">
|
|
||||||
<i class="bi bi-file-play"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
{% if timeslot.location.video_stream_url %}
|
|
||||||
<a class="btn btn-outline-primary"
|
|
||||||
role="button"
|
|
||||||
href="https://www.meetecho.com/ietf{{ meeting.number }}/recordings#{{ acronym.upper }}"
|
|
||||||
aria-label="Session recording"
|
|
||||||
title="Session recording">
|
|
||||||
<i class="bi bi-file-slides"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
</div>
|
|
||||||
<div class="dropdown d-lg-none">
|
|
||||||
<button class="btn btn-outline-primary btn-sm dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
aria-label="Info"
|
|
||||||
id="session-buttons-dropdown-{{ session.pk }}"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="false">
|
|
||||||
<i class="bi bi-info-lg"></i>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu"
|
|
||||||
aria-labelledby="session-buttons-dropdown-{{ session.pk }}">
|
|
||||||
{% with acronym=session.historic_group.acronym %}
|
|
||||||
{% if session.agenda and show_agenda %}
|
|
||||||
{# agenda pop-up button #}
|
|
||||||
<li>
|
|
||||||
<button class="dropdown-item" type="button"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#modal-{{ slug }}">
|
|
||||||
<i class="bi bi-arrows-fullscreen"></i> Show meeting materials
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
{# materials tar file #}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{% url 'ietf.meeting.views.session_draft_tarfile' num=meeting.number acronym=acronym %}">
|
|
||||||
<i class="bi bi-file-zip"></i> Meeting materials archive
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{# materials PDF file #}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{% url 'ietf.meeting.views.session_draft_pdf' num=meeting.number acronym=acronym %}">
|
|
||||||
<i class="bi bi-file-pdf"></i> Meeting materials PDF
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# HedgeDoc #}
|
|
||||||
{% if use_codimd %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="{{ session.notes_url }}">
|
|
||||||
<i class="bi bi-journal-text"></i> Notepad for note-takers
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# show stream buttons up till end of session, then show archive buttons #}
|
|
||||||
{% if now < timeslot.utc_end_time %}
|
|
||||||
{# Chat #}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ session.chat_room_url }}">
|
|
||||||
<i class="bi bi-chat"></i> Chat room
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{# Video stream (meetecho) #}
|
|
||||||
{% if timeslot.location.video_stream_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ timeslot.location.video_stream_url|format:session }}">
|
|
||||||
<i class="bi bi-camera-video"></i> Video stream
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# Onsite tool (meetecho_onsite) #}
|
|
||||||
{% if timeslot.location.onsite_tool_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ timeslot.location.onsite_tool_url|format:session }}">
|
|
||||||
<i class="bi bi-phone"></i> Onsite tool
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# Audio stream #}
|
|
||||||
{% if timeslot.location.audio_stream_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ timeslot.location.audio_stream_url|format:session }}">
|
|
||||||
<i class="bi bi-headphones"></i> Audio stream
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# Remote call-in #}
|
|
||||||
{% if session.agenda_note|first_url|conference_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="{{ session.agenda_note|first_url }}">
|
|
||||||
<i class="bi bi-people"></i> Online conference
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% elif session.remote_instructions|first_url|conference_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ session.remote_instructions|first_url }}">
|
|
||||||
<i class="bi bi-people"></i> Online conference
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% elif timeslot.location.webex_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ timeslot.location.webex_url|format:session }}">
|
|
||||||
<i class="bi bi-people"></i> Webex session
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# iCalendar item #}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{% url 'ietf.meeting.views.agenda_ical' num=meeting.number session_id=session.id %}">
|
|
||||||
<i class="bi bi-calendar"></i> Add to calendar
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
{# Chat logs #}
|
|
||||||
{% if meeting.number|add:"0" >= 60 %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ session.chat_archive_url }}">
|
|
||||||
<i class="bi bi-file-text"></i> Chat logs
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{# Recordings #}
|
|
||||||
{% if meeting.number|add:"0" >= 80 %}
|
|
||||||
{% with session.recordings as recordings %}
|
|
||||||
{% if recordings %}
|
|
||||||
{# There's no guaranteed order, so this is a bit messy: #}
|
|
||||||
{# First, the audio recordings, if any #}
|
|
||||||
{% for r in recordings %}
|
|
||||||
{% if r.get_href and 'audio' in r.get_href %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="{{ r.get_href }}">
|
|
||||||
<i class="bi bi-file-play"></i> {{ r.title }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{# Then the youtube recordings #}
|
|
||||||
{% for r in recordings %}
|
|
||||||
{% if r.get_href and 'youtu' in r.get_href %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="{{ r.get_href }}">
|
|
||||||
<i class="bi bi-file-slides"></i> {{ r.title }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{# Finally, any other recordings #}
|
|
||||||
{% for r in recordings %}
|
|
||||||
{% if r.get_href and not 'audio' in r.get_href and not 'youtu' in r.get_href %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="{{ r.get_href }}">
|
|
||||||
<i class="bi bi-file-play"></i> {{ r.title }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
{% if timeslot.location.video_stream_url %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="https://www.meetecho.com/ietf{{ meeting.number }}/recordings#{{ acronym.upper }}">
|
|
||||||
<i class="bi bi-file-slides"></i> Session recording
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
|
@ -21,10 +21,6 @@
|
||||||
{# see note in the included templates re: show_agenda parameter and required JS import #}
|
{# see note in the included templates re: show_agenda parameter and required JS import #}
|
||||||
{% if meeting.type.slug == 'interim' %}
|
{% if meeting.type.slug == 'interim' %}
|
||||||
{% include "meeting/interim_session_buttons.html" with show_agenda=False show_empty=False %}
|
{% include "meeting/interim_session_buttons.html" with show_agenda=False show_empty=False %}
|
||||||
{% else %}
|
|
||||||
{% with schedule=meeting.schedule %}
|
|
||||||
{% include "meeting/session_buttons_include.html" with show_agenda=False %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<div class="timetooltip">
|
|
||||||
<div class="time"
|
|
||||||
data-start-time="{{ item.start_timestamp }}"
|
|
||||||
data-end-time="{{ item.end_timestamp }}">
|
|
||||||
{% if "-utc" in request.path %}
|
|
||||||
{{ item.timeslot.utc_start_time|date:"H:i" }}<span class="d-lg-none"><br></span>-{{ item.timeslot.utc_end_time|date:"H:i" }}
|
|
||||||
{% else %}
|
|
||||||
{{ item.timeslot.time|date:"H:i" }}<span class="d-lg-none"><br></span>-{{ item.timeslot.end_time|date:"H:i" }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -58,7 +58,7 @@
|
||||||
<td>ietf</td>
|
<td>ietf</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="ietf-meeting-link"
|
<a class="ietf-meeting-link"
|
||||||
href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">
|
href="{% url 'agenda' num=meeting.number %}">
|
||||||
IETF {{ meeting.number }}
|
IETF {{ meeting.number }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
ietf_meeting_number: '{{ meeting.number }}',
|
ietf_meeting_number: '{{ meeting.number }}',
|
||||||
start_moment: moment.tz('{{meeting.date}}', '{{ meeting.time_zone }}').startOf('day'),
|
start_moment: moment.tz('{{meeting.date}}', '{{ meeting.time_zone }}').startOf('day'),
|
||||||
end_moment: moment.tz('{{meeting.end}}', '{{ meeting.time_zone }}').endOf('day'),
|
end_moment: moment.tz('{{meeting.end}}', '{{ meeting.time_zone }}').endOf('day'),
|
||||||
url: '{% url 'ietf.meeting.views.agenda' num=meeting.number %}'
|
url: '{% url 'agenda' num=meeting.number %}'
|
||||||
}{% if not forloop.last %}, {% endif %}
|
}{% if not forloop.last %}, {% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% else %} {# if it's not a Meeting, it's a Session #}
|
{% else %} {# if it's not a Meeting, it's a Session #}
|
||||||
|
|
|
@ -26,6 +26,6 @@ CLASS:PUBLIC
|
||||||
DTSTART;VALUE=DATE{% if meeting.time_zone %};TZID={{ meeting.time_zone|ics_esc }}{% endif %}:{{ meeting.date|date:"Ymd" }}
|
DTSTART;VALUE=DATE{% if meeting.time_zone %};TZID={{ meeting.time_zone|ics_esc }}{% endif %}:{{ meeting.date|date:"Ymd" }}
|
||||||
DTEND;VALUE=DATE{% if meeting.time_zone %};TZID={{ meeting.time_zone|ics_esc }}{% endif %}:{{ meeting.end_date|date:"Ymd" }}
|
DTEND;VALUE=DATE{% if meeting.time_zone %};TZID={{ meeting.time_zone|ics_esc }}{% endif %}:{{ meeting.end_date|date:"Ymd" }}
|
||||||
DTSTAMP:{{ meeting.cached_updated|date:"Ymd" }}T{{ meeting.cached_updated|date:"His" }}Z
|
DTSTAMP:{{ meeting.cached_updated|date:"Ymd" }}T{{ meeting.cached_updated|date:"His" }}Z
|
||||||
URL:{{ request.scheme }}://{{ request.get_host }}{% url 'ietf.meeting.views.agenda' num=meeting.number %}
|
URL:{{ request.scheme }}://{{ request.get_host }}{% url 'agenda' num=meeting.number %}
|
||||||
END:VEVENT
|
END:VEVENT
|
||||||
{% endfor %}END:VCALENDAR{% endautoescape %}
|
{% endfor %}END:VCALENDAR{% endautoescape %}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
|
||||||
{% load origin %}
|
|
||||||
{% load static %}
|
|
||||||
{# FIXME: the weekview only renders correctly in quirks mode, i.e., not in HTML5 with "<!DOCTYPE html>" in the next line; it should be rewritten with fullcalendar #}
|
|
||||||
{# <!DOCTYPE html> #}
|
|
||||||
<html lang="en">
|
|
||||||
{% origin %}
|
|
||||||
<head>
|
|
||||||
<title>Weekview</title>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<script src="{% static 'ietf/js/agenda_filter.js' %}"></script>
|
|
||||||
<script src="{% static 'ietf/js/moment.js' %}"></script>
|
|
||||||
<script src="{% static 'ietf/js/week-view.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
var all_items = {{ items | safe }};
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
// Set up events for drawing the calendar
|
|
||||||
function redraw_weekview() {
|
|
||||||
var query_params = agenda_filter.parse_query_params(window.location.search);
|
|
||||||
var timezone_name = query_params.tz || 'utc';
|
|
||||||
|
|
||||||
items = prepare_items(all_items, timezone_name);
|
|
||||||
draw_calendar(items, agenda_filter.get_filter_params(query_params));
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("resize", redraw_weekview, false);
|
|
||||||
window.addEventListener("load", redraw_weekview, false);
|
|
||||||
window.addEventListener("hashchange", redraw_weekview, false);
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>
|
|
||||||
Error loading calendar.
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -51,7 +51,7 @@ test.describe('past - desktop', () => {
|
||||||
// Visit agenda page and await Meeting Data API call to complete
|
// Visit agenda page and await Meeting Data API call to complete
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
||||||
page.goto(`/meeting/${meetingData.meeting.number}/agenda-neue`)
|
page.goto(`/meeting/${meetingData.meeting.number}/agenda`)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Wait for page to be ready
|
// Wait for page to be ready
|
||||||
|
@ -191,7 +191,7 @@ test.describe('past - desktop', () => {
|
||||||
if (event.location?.short) {
|
if (event.location?.short) {
|
||||||
// Has floor badge
|
// Has floor badge
|
||||||
await expect(row.locator('.agenda-table-cell-room > a')).toContainText(event.room)
|
await expect(row.locator('.agenda-table-cell-room > a')).toContainText(event.room)
|
||||||
await expect(row.locator('.agenda-table-cell-room > a')).toHaveAttribute('href', `/meeting/${meetingData.meeting.number}/floor-plan-neue?room=${xslugify(event.room)}`)
|
await expect(row.locator('.agenda-table-cell-room > a')).toHaveAttribute('href', `/meeting/${meetingData.meeting.number}/floor-plan?room=${xslugify(event.room)}`)
|
||||||
await expect(row.locator('.agenda-table-cell-room > .badge')).toContainText(event.location.short)
|
await expect(row.locator('.agenda-table-cell-room > .badge')).toContainText(event.location.short)
|
||||||
} else {
|
} else {
|
||||||
// No floor badge
|
// No floor badge
|
||||||
|
@ -1079,7 +1079,7 @@ test.describe('future - desktop', () => {
|
||||||
// Visit agenda page and await Meeting Data API call to complete
|
// Visit agenda page and await Meeting Data API call to complete
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
||||||
page.goto(`/meeting/${meetingData.meeting.number}/agenda-neue`)
|
page.goto(`/meeting/${meetingData.meeting.number}/agenda`)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Wait for page to be ready
|
// Wait for page to be ready
|
||||||
|
@ -1247,7 +1247,7 @@ test.describe('live - desktop', () => {
|
||||||
// Visit agenda page and await Meeting Data API call to complete
|
// Visit agenda page and await Meeting Data API call to complete
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
||||||
page.goto(`/meeting/${meetingData.meeting.number}/agenda-neue`)
|
page.goto(`/meeting/${meetingData.meeting.number}/agenda`)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Wait for page to be ready
|
// Wait for page to be ready
|
||||||
|
@ -1328,7 +1328,7 @@ test.describe('past - small screens', () => {
|
||||||
// Visit agenda page and await Meeting Data API call to complete
|
// Visit agenda page and await Meeting Data API call to complete
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
||||||
page.goto(`/meeting/${meetingData.meeting.number}/agenda-neue`)
|
page.goto(`/meeting/${meetingData.meeting.number}/agenda`)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Wait for page to be ready
|
// Wait for page to be ready
|
||||||
|
|
|
@ -12,7 +12,7 @@ seedrandom(TEST_SEED.toString(), { global: true })
|
||||||
faker.seed(TEST_SEED)
|
faker.seed(TEST_SEED)
|
||||||
|
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
// FLOOR-PLAN-NEUE | All Viewports
|
// FLOOR-PLAN | All Viewports
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
|
|
||||||
test.describe('floor-plan', () => {
|
test.describe('floor-plan', () => {
|
||||||
|
@ -42,7 +42,7 @@ test.describe('floor-plan', () => {
|
||||||
// Visit floor plan page and await Meeting Data API call to complete
|
// Visit floor plan page and await Meeting Data API call to complete
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
||||||
page.goto(`/meeting/${meetingData.meeting.number}/floor-plan-neue`)
|
page.goto(`/meeting/${meetingData.meeting.number}/floor-plan`)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Wait for page to be ready
|
// Wait for page to be ready
|
||||||
|
|
Loading…
Reference in a new issue