* feat: Total ids on IESG dashboard * IESG I-D code comments * Using Robert's query forIESG dashboard total_ids * Hiding columns in later IESG Dashboard tables * Changing IESG dashboard var name to match column table * Updating IESG pre_pubreqquery * IESG dashboard prepub req safeParser and graphs * IESG dashboard fixing Playwright API usage * IESG dashboard fixing Playwright API usage (2) * Updating .gitignore for /geckodriver.log * IESG ad test title * feat: pages left to ballot on [WIP] * Adding geckodriver.log to gitignore * [WIP] pages left to ballot on * integrating pages left to ballot on WIP * Tests for ad pages remaining * Setting states to test ballot items * refactor ad_pages_left_to_ballot_on count logic * WIP tests for pages left to ballot on * chore: remove whitespace change * fix: look into the BallotPositionDocEventObject * chore: remove prints * fix: restructure test * style: fix js code styling * fix: only show graph for ADs/Secretariat --------- Co-authored-by: Matthew Holloway <Matthew Holloway> Co-authored-by: holloway <matthew@holloway.co.nz> Co-authored-by: Nicolas Giard <github@ngpixel.com> Co-authored-by: Matthew Holloway <matthew@staff.ietf.org>
285 lines
11 KiB
HTML
285 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
|
{% load origin static %}
|
|
{% load ietf_filters %}
|
|
{% block pagehead %}
|
|
<link rel="stylesheet" href="{% static 'ietf/css/list.css' %}">
|
|
<link rel="stylesheet" href="{% static 'ietf/css/highcharts.css' %}">
|
|
{% endblock %}
|
|
{% block morecss %}
|
|
table .border-bottom { border-bottom-color: var(--highcharts-neutral-color-80) !important; }
|
|
.highcharts-container .highcharts-axis-labels { font-size: .7rem; }
|
|
.highcharts-container .highcharts-graph { stroke-width: 2.5; }
|
|
.highcharts-container .highcharts-color-0 {
|
|
fill: var(--bs-primary);
|
|
stroke: var(--bs-primary);
|
|
}
|
|
.highcharts-container .highcharts-data-label text {
|
|
font-size: 1rem;
|
|
font-weight: inherit;
|
|
}
|
|
{% endblock %}
|
|
{% block title %}IESG Dashboard{% endblock %}
|
|
{% block content %}
|
|
{% origin %}
|
|
<h1>IESG Dashboard</h1>
|
|
{% if user|has_role:"Area Director,Secretariat" %}
|
|
<div class="alert alert-info my-3">
|
|
{{ delta }}-day trend graphs
|
|
are only shown to logged-in Area Directors.
|
|
</div>
|
|
{% endif %}
|
|
{% for dt in metadata %}
|
|
<h2 class="mt-5" id="{{ dt.type.0 }}">{{ dt.type.1 }} State Counts</h2>
|
|
<table class="table table-sm table-striped table-bordered tablesorter navskip">
|
|
<thead class="wrap-anywhere">
|
|
<tr>
|
|
<th scope="col" data-sort="name">Area Director</th>
|
|
{% if dt.type.1 == "Internet-Draft" %}
|
|
<th scope="col" data-sort="pre-pubreq">Pre pubreq</th>
|
|
{% endif %}
|
|
{% for state, state_name in dt.states %}
|
|
<th scope="col" class="col-1" data-sort="{{ state }}-num"
|
|
>
|
|
<a href="{% url 'ietf.doc.views_help.state_help' type='draft-iesg' %}#{{ state }}">
|
|
{{ state_name|split:'/'|join:'/<wbr>' }}
|
|
</a>
|
|
</th>
|
|
{% endfor %}
|
|
</tr>
|
|
</thead>
|
|
<tbody class="table-group-divider">
|
|
{% for ad in dt.ads %}
|
|
<tr>
|
|
<td>
|
|
<a href="{{ ad.dashboard }}">{{ ad.name }}</a>
|
|
</td>
|
|
{% if dt.type.1 == "Internet-Draft" %}
|
|
<td
|
|
class="col-1 align-bottom"
|
|
data-sum="pre-pubreq"
|
|
{% if user|has_role:"Area Director,Secretariat" %}
|
|
data-series-graph
|
|
{% endif %}
|
|
>
|
|
{{ ad.pre_pubreq }}
|
|
</td>
|
|
{% endif %}
|
|
{% for state, state_name in dt.states %}
|
|
<td class="col-1 align-bottom"
|
|
id="{{ dt.type.0 }}-{{ ad|slugify }}-{{ state }}">
|
|
<div id="chart-{{ dt.type.0 }}-{{ ad|slugify }}-{{ state }}"></div>
|
|
</td>
|
|
{% endfor %}
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
<tfoot class="table-group-divider">
|
|
<tr>
|
|
<th scope="row">Sum</th>
|
|
{% if dt.type.1 == "Internet-Draft" %}
|
|
<td class="align-bottom">
|
|
<div
|
|
data-sum-result="pre-pubreq"
|
|
{% if user|has_role:"Area Director,Secretariat" %}
|
|
data-series-graph
|
|
{% endif %}
|
|
></div>
|
|
</td>
|
|
{% endif %}
|
|
{% for state, state_name in dt.states %}
|
|
<td class="align-bottom">
|
|
<div id="chart-{{ dt.type.0 }}-sum-{{ state }}"></div>
|
|
</td>
|
|
{% endfor %}
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
{% endfor %}
|
|
{% endblock %}
|
|
{% block js %}
|
|
<script src="{% static "ietf/js/list.js" %}"></script>
|
|
<script>
|
|
$(document)
|
|
.ready(function () {
|
|
$("[data-bs-toggle='popover']")
|
|
.popover({
|
|
html: true,
|
|
trigger: "hover focus click"
|
|
});
|
|
});
|
|
</script>
|
|
<script src="{% static "ietf/js/highcharts.js" %}"></script>
|
|
{{ data|json_script:"data" }}
|
|
|
|
<script>
|
|
function highchartsConfigFactory({ element, ymax, series }){
|
|
return {
|
|
title: { text: undefined },
|
|
chart: {
|
|
type: "line",
|
|
animation: false,
|
|
renderTo: element,
|
|
panning: { enabled: false },
|
|
spacing: [4, 0, 5, 0],
|
|
height: "45%"
|
|
},
|
|
scrollbar: { enabled: false },
|
|
tooltip: { enabled: false },
|
|
navigator: { enabled: false },
|
|
exporting: { enabled: false },
|
|
legend: { enabled: false },
|
|
credits: { enabled: false },
|
|
xAxis: {
|
|
title: { text: undefined},
|
|
labels: { enabled: false },
|
|
zoomEnabled: false,
|
|
tickLength: 0
|
|
},
|
|
yAxis: {
|
|
title: { text: undefined},
|
|
zoomEnabled: false,
|
|
tickLength: 0,
|
|
labels: { x: -3 },
|
|
min: 0,
|
|
max: ymax,
|
|
tickInterval: ymax
|
|
},
|
|
plotOptions: {
|
|
series: {
|
|
animation: false,
|
|
dataLabels: {
|
|
enabled: true,
|
|
inside: true,
|
|
padding: 0,
|
|
formatter: function() {
|
|
// only label the last
|
|
// (= current-day) point in
|
|
// the curve with today's
|
|
// value
|
|
if (this.point.index + 1 ==
|
|
this.series.points.length) {
|
|
return this.y
|
|
}
|
|
return undefined
|
|
}
|
|
}
|
|
}
|
|
},
|
|
series: [{
|
|
name: undefined,
|
|
data: series,
|
|
enableMouseTracking: false
|
|
}]
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
const GRAPH_BUFFER = 2;
|
|
|
|
function safeParseFloat(text) {
|
|
const trimNumber = text.trim()
|
|
if(!trimNumber.match(/^[0-9.]+$/)) {
|
|
console.warn(`Unable to parse "${trimNumber}" as a number.`)
|
|
return Number.NaN
|
|
}
|
|
return parseFloat(text)
|
|
}
|
|
|
|
Array.from(document.querySelectorAll("table"))
|
|
.filter(table => Boolean(table.querySelector("[data-sum]")))
|
|
.forEach(table => {
|
|
const sums = Array.from(table.querySelectorAll("[data-sum]")).reduce((
|
|
sumsAccumulator,
|
|
cell
|
|
) => {
|
|
const key = cell.dataset.sum
|
|
const value = safeParseFloat(cell.textContent)
|
|
if(key && !isNaN(value)) {
|
|
sumsAccumulator[key] = (sumsAccumulator[key] || 0) + (value || 0)
|
|
}
|
|
return sumsAccumulator
|
|
}, {})
|
|
|
|
Array.from(table.querySelectorAll('[data-sum-result]')).forEach(result => {
|
|
const key = result.dataset.sumResult
|
|
const value = sums[key]
|
|
|
|
if(value) {
|
|
result.innerText = value
|
|
}
|
|
})
|
|
|
|
Array.from(table.querySelectorAll('[data-series-graph]')).forEach(element => {
|
|
const endValue = safeParseFloat(element.innerText)
|
|
if(isNaN(endValue)) throw Error("Can't render Highcharts chart with non-numerical " + element.innerText)
|
|
|
|
const ymax = Math.max(1, endValue + GRAPH_BUFFER)
|
|
|
|
Highcharts.chart(
|
|
highchartsConfigFactory({
|
|
element,
|
|
ymax,
|
|
series: [endValue]
|
|
})
|
|
)
|
|
})
|
|
})
|
|
</script>
|
|
<script>
|
|
const data = JSON.parse(document.getElementById("data").textContent)
|
|
|
|
Object.entries(data).forEach(([dt, ads]) => {
|
|
max = {}
|
|
Object.entries(ads).forEach(([ad, states]) => {
|
|
Object.entries(states).forEach(([state, buckets]) => {
|
|
buckets.series = buckets.map((x) => x.length)
|
|
if (ad != "sum") {
|
|
max[state] = Math.max(...buckets.series, max[state] ? max[state] : 0)
|
|
}
|
|
})
|
|
})
|
|
|
|
Object.entries(ads).forEach(([ad, states]) => {
|
|
Object.entries(states).forEach(([state, buckets]) => {
|
|
const cell = `chart-${dt}-${ad}-${state}`
|
|
|
|
// if there is only a single datapoint in the
|
|
// bucket, display it without a graph
|
|
if (buckets.series.length == 1) {
|
|
document.getElementById(cell).innerHTML = buckets.series[0]
|
|
return
|
|
}
|
|
|
|
// if a bucket has all zeroes, fake a Highcharts
|
|
// plot with HTML, to reduce the number of plot
|
|
// objects on the page
|
|
if (buckets.series.every((x) => x === 0)) {
|
|
// document.getElementById(cell).innerHTML = `
|
|
// <div class="position-relative">
|
|
// <div class="position-absolute bottom-0 start-0">
|
|
// <div style="font-size: .7rem;" class="ms-1">0</div>
|
|
// </div>
|
|
// <div class="position-absolute bottom-0 end-0 w-100 ps-1">
|
|
// <div class="border-bottom mb-1 ms-3">0</div>
|
|
// </div>
|
|
// </div>
|
|
// `;
|
|
return
|
|
}
|
|
|
|
// else actually create a graph
|
|
const ymax = Math.max(1, ad !== "sum" ? max[state] : Math.max(...buckets.series))
|
|
Highcharts.chart(
|
|
highchartsConfigFactory({
|
|
element: cell,
|
|
ymax,
|
|
series: buckets.series
|
|
})
|
|
)
|
|
})
|
|
})
|
|
})
|
|
</script>
|
|
{% endblock %} |