Wire up events for creating new public reports
This involved moving a lot of stuff to the platform layer since I don't want event interfaces leaking out. Also this includes a fix to the user authentication which I had previously broken by making a platform-layer user object independent of the database layer.
This commit is contained in:
parent
9a5cc4cf97
commit
e8d865d0ab
24 changed files with 915 additions and 541 deletions
120
html/static/js/events.js
Normal file
120
html/static/js/events.js
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// sse-manager.js - Include this in your common template
|
||||
window.SSEManager = (function () {
|
||||
let eventSource = null;
|
||||
let subscribers = new Map();
|
||||
let isConnected = false;
|
||||
let connectionPromise = null;
|
||||
|
||||
function subscribe(eventType, handler) {
|
||||
if (!subscribers.has(eventType)) {
|
||||
subscribers.set(eventType, []);
|
||||
}
|
||||
subscribers.get(eventType).push(handler);
|
||||
|
||||
// If already connected, attach the listener immediately
|
||||
if (isConnected && eventSource) {
|
||||
eventSource.addEventListener(eventType, handler);
|
||||
}
|
||||
}
|
||||
|
||||
function unsubscribe(eventType, handler) {
|
||||
if (subscribers.has(eventType)) {
|
||||
const handlers = subscribers.get(eventType);
|
||||
const index = handlers.indexOf(handler);
|
||||
if (index > -1) {
|
||||
handlers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
if (eventSource) {
|
||||
eventSource.removeEventListener(eventType, handler);
|
||||
}
|
||||
}
|
||||
|
||||
function connect(url) {
|
||||
if (connectionPromise) {
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
connectionPromise = new Promise((resolve, reject) => {
|
||||
eventSource = new EventSource(url);
|
||||
|
||||
eventSource.onopen = function () {
|
||||
isConnected = true;
|
||||
|
||||
// Attach all pre-registered handlers
|
||||
subscribers.forEach((handlers, eventType) => {
|
||||
handlers.forEach((handler) => {
|
||||
eventSource.addEventListener("message", (message) => {
|
||||
const data = JSON.parse(message.data);
|
||||
handler(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
console.log("SSE connected");
|
||||
resolve(eventSource);
|
||||
};
|
||||
|
||||
eventSource.onerror = function (err) {
|
||||
console.error("SSE error:", err);
|
||||
isConnected = false;
|
||||
|
||||
// Reconnect after delay
|
||||
setTimeout(() => {
|
||||
connectionPromise = null;
|
||||
connect(url);
|
||||
}, 5000);
|
||||
|
||||
if (!isConnected) {
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return connectionPromise;
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
if (eventSource) {
|
||||
eventSource.close();
|
||||
eventSource = null;
|
||||
isConnected = false;
|
||||
connectionPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
function ready(callback) {
|
||||
if (connectionPromise) {
|
||||
connectionPromise.then(callback);
|
||||
} else {
|
||||
// If connect hasn't been called yet, queue it
|
||||
const checkInterval = setInterval(() => {
|
||||
if (connectionPromise) {
|
||||
clearInterval(checkInterval);
|
||||
connectionPromise.then(callback);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
connect,
|
||||
disconnect,
|
||||
subscribe,
|
||||
unsubscribe,
|
||||
ready,
|
||||
};
|
||||
})();
|
||||
|
||||
// Initialize SSE for navigation notifications
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
SSEManager.connect("/api/events");
|
||||
});
|
||||
|
||||
function updateNotificationBadge(data) {
|
||||
const badge = document.querySelector(".notification-badge");
|
||||
if (badge) {
|
||||
badge.textContent = data.count;
|
||||
badge.style.display = data.count > 0 ? "block" : "none";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue