glance
glance copied to clipboard
[REQUEST] Autorefresh page/elements content on set interval
Add the ability to autorefresh content on glance page - my use case is I often leave open the glance page and view it from time to time, but I always have to refresh manually. An option to autorefresh the content on the page at a set interval would be nice. Also maybe last refreshed datetime or 'minutes ago' could be added to elements, to keep track of the freshness of information displayed.
Building on this, we've got now the ability to put in <HEAD> a method to auto refresh the content on all Glance pages. This is awesome. Definitely helps to keep certain pages that concentrate certain widgets up to date (RSS, YouTube, etc.).
However, I have several pages with embedded external applications (Beszel being one of them). With the current implementation, the auto refresh at the '<HEAD>' level, it refreshes all pages. A little annoying with Beszel since it will default to the server list, in its case.
If we could specify this behavior at a page level (or a widget level), that would greatly increase the flexibility (and also control API call frequency).
Examples:
- On an external data page hosting different RSS widgets, market widgets, Reddit widgets, and YouTube widgets, as a user, I want to be able to specific different refresh intervals for each widget so that I can control the flow of data and have them update within reasonable intervals for the type of data.
- On a Glance installation, as a user, I want to specify the refresh interval for each page individually, so that a global refresh does not impact my workflow or my place on a specific page.
Same problem here. I have a page especially for my own self-hosted services and these in most cases throw a timeout, since they go through Pangolin with Crowdsec on a Hetzner server in Germany, so the time usually takes longer than expected. It would be interesting to add a field for both time and maximum retries I suppose.
It could be great as well to be able to set a cache renewal time, where (for example) every 10 minutes a widget's data could be fetched on the glance application level, even without the website loaded. This could make longer querying widgets load instantly when the page is opened.
Hey folks, jumping on this issue. I was thinking on something similar, though simpler: a refresh button on the nav bar, to the right (next to the theme switcher). Clicking on it would trigger a refresh on all the widgets.
I find myself always refreshing when I get to Glance (I keep it in a pinned tab), so it would be great to have a built in way.
Of course a timer would be better, but we could keep improving on it.
I'm a developer and I could try and take a stab at it, if the team thinks it makes sense.
I think that would be helpful! Could also be helpful when you want to occasionally reset all the cache for all the widgets, and trigger a fresh refetch for everything.
It would be great if each widget could have its own refresh setting, much like the cache settings. Doing it this way will not be too intrusive to the user. For now, I've am using a workaround to refresh the page using a Greasemonkey script (if you use Firefox or Chrome, Tampermonkey is one way to go about doing that). You can either copy this script and paste it into Tampermonkey as a new script, or you can adapt it so it works directly in your browser's console or even turn it into a bookmarklet. Make sure to update your glance self hosted URL in the Match section.
You can also change the refresh timer to your linking to say.
// ==UserScript==
// @name Idle Page Refresher
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Refresh the page only when it's idle. Will not refresh if the web page is being interacted with mouse/scroll action.
// @author Mochi
// @match <YourURL>/*
// ==/UserScript==
let lastInteractionTime = Date.now();
const TIMER = 60000; //1 minute
function checkIdleStatus() {
const currentTime = Date.now();
const idleTime = currentTime - lastInteractionTime;
if (idleTime > TIMER) { // Adjust the threshold as needed
console.log("Page is idle, refreshing...");
location.reload();
} else {
console.log("User is active, no refresh.");
}
}
function resetTimer() {
lastInteractionTime = Date.now();
}
// Event listeners for user interactions
document.addEventListener('scroll', resetTimer);
document.addEventListener('mousemove', resetTimer);
document.addEventListener('keydown', resetTimer);
document.addEventListener('mousedown', resetTimer);
setInterval(checkIdleStatus, TIMER);
Hey folks, I got something working here:
The screenshot is self explanatory, but here's the breakdown:
- New nav bar element with a refresh icon
- Upon hover, a popover menu appears with 2 options
- Refresh now is a link that reloads the page from the server (similar to a
location.reload, but not quite the same) - Auto-refresh will set a 3 minutes timer. It will remember your choice by leveraging the
localStorage
@svilenmarkov would love your input on this. I got it all done locally, I can push a PR if you'd like to take a look.
@andrecalil Have a look at this discussion, since a lot of that still applies.
The front-end wasn't built in a way where you can unload/unmount anything, so refreshing individual widgets without reloading the entire page isn't possible currently. I'm not sure how a dedicated refresh button on the page is any different than just hitting the refresh button in your browser.
@svilenmarkov the way I've done it leverages the setupPage function, which fetches the page and updates the document HTML. So it's not exactly a simple location.reload (such as a browser refetch would do) neither individual to each widget.
Regarding "a dedicated button is the same as refreshing": (1) as stated above, it's not the same functionality. Still, (2) the more interesting feature is the auto-refresh. As the OP here explained, his Glance page is always open, such as mine. Being able to get back to it and see it updated would be quite helpful.
Reworked the UI a bit. Here's a quick demo:
https://github.com/user-attachments/assets/f3303fc5-8d52-46b6-bff1-57e0846d02f6
@svilenmarkov if you'd like to take this into consideration, here's the PR: https://github.com/glanceapp/glance/pull/793
the way I've done it leverages the setupPage function, which fetches the page and updates the document HTML
The setupPage function calls other functions, some of which add event listeners to the window/document and have no way of removing those listeners. If you simply call the setupPage function over and over, you're creating a memory leak since those active event listeners still hold references to elements that were removed from the DOM and will never get garbage collected.
As for the auto-refresh, you can already do that if you really wanted to:
document:
head: |
<script>
setTimeout(() => location.reload(), 3 * 60 * 1000);
</script>
It's not as ergonomic as your implementation, though I'm still on the fence about providing this functionality natively because if you do the math, that's a lot of unnecessary requests which would bombard the generous API's Glance relies on. Not just from yourself, but from the potentially hundreds/thousands of users who would enable it in tandem.
This may get added in the future, with the caveat of having to be enabled on a per-widget basis, along with only updating those widgets while Glance is in the foreground.
The
setupPagefunction calls other functions, some of which add event listeners to thewindow/documentand have no way of removing those listeners. If you simply call thesetupPagefunction over and over, you're creating a memory leak since those active event listeners still hold references to elements that were removed from the DOM and will never get garbage collected.
Super valid point. My first version included a new API endpoint that would simply return the page. I removed that since I thought I could leverage the setupPage. This could easily be fixed though.
It's not as ergonomic as your implementation, though I'm still on the fence about providing this functionality natively because if you do the math, that's a lot of unnecessary requests which would bombard the generous API's Glance relies on. Not just from yourself, but from the potentially hundreds/thousands of users who would enable it in tandem.
I see, I hadn't considered this effect. I could also add a new param for it, and we could default it to false.
So, unless someone decided to, it would be off by default and a little less reachable.
What if you do something like this:
const widgetsToUpdate = ['widget1', 'widget2', 'widget3']
const pageToAutoUpdate = 'your-page'
async function autoUpdate() {
console.info(`Executing ${autoUpdate.name}. Time: ${new Date().toLocaleString("en-US")}`);
console.info(`Page: ${pageData.slug}`);
if (pageData.slug !== pageToAutoUpdate) return;
const updatedContent = await getUpdatedContent();
const parser = new DOMParser();
const updatedContentDoc = parser.parseFromString(updatedContent, 'text/html');
for (let widget of widgetsToUpdate) {
const elementsToUpdate = document.getElementsByClassName(widget);
if (!elementsToUpdate || elementsToUpdate.length == 0) continue;
const rootElement = elementsToUpdate[0];
const updatedElements = updatedContentDoc.getElementsByClassName(widget);
if (!updatedElements || updatedElements.length == 0) continue;
rootElement.innerHTML = updatedElements[0].innerHTML;
}
}
async function getUpdatedContent() {
const response = await fetch(`${pageData.baseURL}/api/pages/${pageToAutoUpdate}/content`);
if(!response.ok){
console.error(`Error fetchL ${response.status} ${response.statusText}`);
return "";
}
return await response.text();
}
setInterval(autoUpdate, 10000);
You're not going to mess with eventListeners, you're not adding more listeners to the dom that would lead to a memory leak overtime if not taken care of