mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 03:13:42 -05:00
improve polling performance and remove unused updateContent module
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
const tableContainer = document.getElementById('activityContainer');
|
||||
const currentUserName = tableContainer.getAttribute('data-currentUserName');
|
||||
const currentServiceId = tableContainer.getAttribute('data-currentServiceId');
|
||||
let pollInterval;
|
||||
let isPolling = false;
|
||||
const POLL_INTERVAL_MS = 25000;
|
||||
const COLORS = {
|
||||
delivered: '#0076d6',
|
||||
failed: '#fa9441',
|
||||
@@ -153,8 +156,6 @@
|
||||
.on('mouseout', function() {
|
||||
tooltip.style('display', 'none');
|
||||
})
|
||||
.transition()
|
||||
.duration(1000)
|
||||
.attr('y', d => y(d[1]))
|
||||
.attr('height', d => {
|
||||
const calculatedHeight = y(d[0]) - y(d[1]);
|
||||
@@ -209,28 +210,35 @@
|
||||
table.append(tbody);
|
||||
};
|
||||
|
||||
const fetchData = function(type) {
|
||||
const fetchData = async function(type) {
|
||||
if (isPolling) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ctx = document.getElementById('weeklyChart');
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
isPolling = true;
|
||||
|
||||
var userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
var url = type === 'service'
|
||||
? `/services/${currentServiceId}/daily-stats.json?timezone=${encodeURIComponent(userTimezone)}`
|
||||
: `/services/${currentServiceId}/daily-stats-by-user.json?timezone=${encodeURIComponent(userTimezone)}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
const data = await response.json();
|
||||
labels = [];
|
||||
deliveredData = [];
|
||||
failedData = [];
|
||||
@@ -277,10 +285,38 @@
|
||||
}
|
||||
|
||||
return data;
|
||||
})
|
||||
.catch(error => console.error('Error fetching daily stats:', error));
|
||||
};
|
||||
setInterval(() => fetchData(currentType), 25000);
|
||||
} catch (error) {
|
||||
console.error('Error fetching daily stats:', error);
|
||||
} finally {
|
||||
isPolling = false;
|
||||
}
|
||||
};
|
||||
|
||||
function startPolling() {
|
||||
fetchData(currentType);
|
||||
|
||||
pollInterval = setInterval(() => {
|
||||
fetchData(currentType);
|
||||
}, POLL_INTERVAL_MS);
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
pollInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.hidden) {
|
||||
stopPolling();
|
||||
} else {
|
||||
stopPolling();
|
||||
startPolling();
|
||||
}
|
||||
});
|
||||
|
||||
startPolling();
|
||||
const handleDropdownChange = function(event) {
|
||||
const selectedValue = event.target.value;
|
||||
currentType = selectedValue;
|
||||
|
||||
@@ -14,7 +14,6 @@ import Button from 'govuk-frontend/components/button/button';
|
||||
import Radios from 'govuk-frontend/components/radios/radios';
|
||||
|
||||
// Modules from 3rd party vendors
|
||||
import morphdom from 'morphdom';
|
||||
|
||||
/**
|
||||
* TODO: Ideally this would be a NodeList.prototype.forEach polyfill
|
||||
@@ -67,13 +66,8 @@ var Frontend = {
|
||||
"initAll": initAll
|
||||
}
|
||||
|
||||
var vendor = {
|
||||
"morphdom": morphdom
|
||||
}
|
||||
|
||||
// The exported object will be assigned to window.GOVUK in our production code
|
||||
// (bundled into an IIFE by RollupJS)
|
||||
export {
|
||||
Frontend,
|
||||
vendor
|
||||
Frontend
|
||||
}
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function (...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), wait);
|
||||
};
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const isJobPage = window.location.pathname.includes('/jobs/');
|
||||
if (!isJobPage) return;
|
||||
@@ -15,69 +7,105 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const featureEnabled = jobEl?.dataset?.feature === 'true';
|
||||
const apiHost = jobEl?.dataset?.host;
|
||||
|
||||
if (!jobId) return;
|
||||
if (!jobId || !featureEnabled) return;
|
||||
|
||||
if (featureEnabled) {
|
||||
const socket = io(apiHost);
|
||||
const DEFAULT_INTERVAL_MS = 10000;
|
||||
const MIN_INTERVAL_MS = 1000;
|
||||
const MAX_INTERVAL_MS = 30000;
|
||||
|
||||
socket.on('connect_error', (err) => {
|
||||
console.error('Socket connect_error:', err);
|
||||
});
|
||||
let pollInterval;
|
||||
let currentInterval = DEFAULT_INTERVAL_MS;
|
||||
let isPolling = false;
|
||||
|
||||
socket.on('error', (err) => {
|
||||
console.error('Socket error:', err);
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('join', { room: `job-${jobId}` });
|
||||
});
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
socket.emit('leave', { room: `job-${jobId}` });
|
||||
});
|
||||
|
||||
const debouncedUpdate = debounce((data) => {
|
||||
updateAllJobSections();
|
||||
}, 1000);
|
||||
|
||||
socket.on('job_updated', (data) => {
|
||||
if (data.job_id !== jobId) return;
|
||||
debouncedUpdate(data);
|
||||
});
|
||||
function calculateBackoff(responseTime) {
|
||||
return Math.min(
|
||||
MAX_INTERVAL_MS,
|
||||
Math.max(
|
||||
MIN_INTERVAL_MS,
|
||||
Math.floor((250 * Math.sqrt(responseTime)) - 1000)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function updateAllJobSections() {
|
||||
async function updateAllJobSections() {
|
||||
if (document.hidden || isPolling) return;
|
||||
|
||||
isPolling = true;
|
||||
const startTime = Date.now();
|
||||
|
||||
const resourceEl = document.querySelector('[data-socket-update="status"]');
|
||||
const url = resourceEl?.dataset?.resource;
|
||||
|
||||
if (!url) {
|
||||
console.warn('No resource URL found for job updates');
|
||||
isPolling = false;
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(url)
|
||||
.then((res) => res.json())
|
||||
.then(({ status, counts, notifications }) => {
|
||||
const sections = {
|
||||
status: document.querySelector('[data-socket-update="status"]'),
|
||||
counts: document.querySelector('[data-socket-update="counts"]'),
|
||||
notifications: document.querySelector(
|
||||
'[data-socket-update="notifications"]'
|
||||
),
|
||||
};
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
|
||||
if (status && sections.status) {
|
||||
sections.status.innerHTML = status;
|
||||
}
|
||||
if (counts && sections.counts) {
|
||||
sections.counts.innerHTML = counts;
|
||||
}
|
||||
if (notifications && sections.notifications) {
|
||||
sections.notifications.innerHTML = notifications;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error fetching job update partials:', err);
|
||||
});
|
||||
const sections = {
|
||||
status: document.querySelector('[data-socket-update="status"]'),
|
||||
counts: document.querySelector('[data-socket-update="counts"]'),
|
||||
notifications: document.querySelector('[data-socket-update="notifications"]'),
|
||||
};
|
||||
|
||||
if (data.status && sections.status) {
|
||||
sections.status.innerHTML = data.status;
|
||||
}
|
||||
if (data.counts && sections.counts) {
|
||||
sections.counts.innerHTML = data.counts;
|
||||
}
|
||||
if (data.notifications && sections.notifications) {
|
||||
sections.notifications.innerHTML = data.notifications;
|
||||
}
|
||||
|
||||
const responseTime = Date.now() - startTime;
|
||||
currentInterval = calculateBackoff(responseTime);
|
||||
|
||||
if (data.stop === 1 || data.finished === true) {
|
||||
stopPolling();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching job updates:', error);
|
||||
currentInterval = Math.min(currentInterval * 2, MAX_INTERVAL_MS);
|
||||
} finally {
|
||||
isPolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
updateAllJobSections();
|
||||
|
||||
function scheduleNext() {
|
||||
if (pollInterval) clearTimeout(pollInterval);
|
||||
pollInterval = setTimeout(() => {
|
||||
updateAllJobSections();
|
||||
scheduleNext();
|
||||
}, currentInterval);
|
||||
}
|
||||
|
||||
scheduleNext();
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollInterval) {
|
||||
clearTimeout(pollInterval);
|
||||
pollInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.hidden) {
|
||||
stopPolling();
|
||||
} else {
|
||||
startPolling();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('beforeunload', stopPolling);
|
||||
|
||||
startPolling();
|
||||
});
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
{% macro ajax_block(partials, url, key, finished=False, form='') %}
|
||||
{% if not finished %}
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{ url }}"
|
||||
data-key="{{ key }}"
|
||||
data-form="{{ form }}"
|
||||
>
|
||||
{% endif %}
|
||||
{{ partials[key]|safe }}
|
||||
{% if not finished %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ partials[key]|safe }}
|
||||
{% endmacro %}
|
||||
|
||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -19,7 +19,6 @@
|
||||
"govuk-frontend": "2.13.0",
|
||||
"gulp-merge": "^0.1.1",
|
||||
"jquery": "3.7.1",
|
||||
"morphdom": "^2.7.7",
|
||||
"playwright": "^1.55.0",
|
||||
"python": "^0.0.4",
|
||||
"query-command-supported": "1.0.0",
|
||||
@@ -11204,12 +11203,6 @@
|
||||
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/morphdom": {
|
||||
"version": "2.7.7",
|
||||
"resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.7.tgz",
|
||||
"integrity": "sha512-04GmsiBcalrSCNmzfo+UjU8tt3PhZJKzcOy+r1FlGA7/zri8wre3I1WkYN9PT3sIeIKfW9bpyElA+VzOg2E24g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"govuk-frontend": "2.13.0",
|
||||
"gulp-merge": "^0.1.1",
|
||||
"jquery": "3.7.1",
|
||||
"morphdom": "^2.7.7",
|
||||
"playwright": "^1.55.0",
|
||||
"python": "^0.0.4",
|
||||
"query-command-supported": "1.0.0",
|
||||
|
||||
Reference in New Issue
Block a user