Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ietf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@
AGENDA_CACHE_TIMEOUT_DEFAULT = 8 * 24 * 60 * 60 # 8 days
AGENDA_CACHE_TIMEOUT_CURRENT_MEETING = 6 * 60 # 6 minutes


WSGI_APPLICATION = "ietf.wsgi.application"

AUTHENTICATION_BACKENDS = ( 'ietf.ietfauth.backends.CaseInsensitiveModelBackend', )
Expand Down Expand Up @@ -1270,7 +1271,7 @@ def skip_unreadable_post(record):
except ImportError:
pass

STATS_NAMES_LIMIT = 25
STATS_TIMELINE_CACHE_TIMEOUT = 86400

UTILS_MEETING_CONFERENCE_DOMAINS = ['webex.com', 'zoom.us', 'jitsi.org', 'meetecho.com', 'gather.town', ]
UTILS_TEST_RANDOM_STATE_FILE = '.factoryboy_random_state'
Expand Down
57 changes: 57 additions & 0 deletions ietf/static/js/meeting_stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright The IETF Trust 2026, All Rights Reserved
document.addEventListener('DOMContentLoaded', () => {
// Need to use autocolors plug-in else all slices are gray...
const autocolors = window['chartjs-plugin-autocolors']
Chart.register(autocolors)
// ── Safely parse JSON data injected from Django view ──
const totalChartData = JSON.parse(document.getElementById('total-chart-data').textContent)
const inPersonChartData = JSON.parse(document.getElementById('in-person-chart-data').textContent)

function displayChart (id, data) {
const ctx = document.getElementById(id).getContext('2d')
new Chart(ctx, {
type: 'pie', // Change to 'doughnut' for a donut chart
data: data,
options: {
responsive: true,
plugins: {
autocolors: {
mode: 'data' // Required for Pie charts to color individual slices
},
legend: {
position: 'bottom',
labels: {
padding: 20,
font: { size: 13 },
color: '#475569',
generateLabels: function (chart) {
const dataset = chart.data.datasets[0]
return chart.data.labels.map((label, i) => ({
text: `${label}: ${dataset.data[i]}`,
fillStyle: dataset.backgroundColor[i],
hidden: false,
index: i,
}))
}
}
},
tooltip: {
callbacks: {
label: function (context) {
const label = context.label || ''
const value = context.raw
const total = context.dataset.data.reduce((a, b) => a + b, 0)
const percentage = ((value / total) * 100).toFixed(1)

return `${label}: ${value} (${percentage}%)`
}
}
}
}
}
})
}

displayChart('totalRegistrationChart', totalChartData)
displayChart('inPersonRegistrationChart', inPersonChartData)
})
84 changes: 84 additions & 0 deletions ietf/static/js/meeting_timeline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright The IETF Trust 2026, All Rights Reserved
document.addEventListener('DOMContentLoaded', () => {
// ── Safely parse JSON data injected from Django view ──
const totalChartData = JSON.parse(document.getElementById('total-chart-data').textContent)
const inPersonChartData = JSON.parse(document.getElementById('in-person-chart-data').textContent)
const statsType = JSON.parse(document.getElementById('stats-type-data').textContent)
const stackedLines = statsType === 'total'

function displayChart (id, data) {
const ctx = document.getElementById(id).getContext('2d')
return new Chart(ctx, {
type: 'line', // Change to 'doughnut' for a donut chart
data: data,
options: {
responsive: true,
scales: {
y: {
stacked: stackedLines,
},
x: {
title: {
display: true,
text: 'IETF Meeting Number',
},
},
},
plugins: {
legend: {
position: 'bottom',
labels: {
usePointStyle: true,
padding: 15,
font: { size: 12 },
},
},
tooltip: {
backgroundColor: 'rgba(0,0,0,0.8)',
titleFont: { size: 14 },
bodyFont: { size: 13 },
callbacks: {
title: function (items) {
return `IETF Meeting ${items[0].label}`
},
label: function (context) {
return ` ${context.dataset.label}: ${context.parsed.y} participants`
}
}
},
zoom: {
zoom: {
wheel: { enabled: true }, // scroll to zoom
pinch: { enabled: true }, // pinch on mobile
drag: { enabled: true }, // drag to select range
mode: 'xy', // zoom X-axis and Y-axis
},
pan: {
enabled: true,
mode: 'xy', // pan X-axis and Y-axis
},
},
}
}
})
}

const totalChart = displayChart('totalRegistrationChart', totalChartData)
if (inPersonChartData !== null) {
inPersonChart = displayChart('inPersonRegistrationChart', inPersonChartData)
}
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
totalChart.resetZoom()
if (inPersonChart !== null) {
inPersonChart.resetZoom()
}
}
})
document.getElementById('resetButton').addEventListener('click', () => {
totalChart.resetZoom()
if (inPersonChart !== null) {
inPersonChart.resetZoom()
}
})
})
Loading