Jump to section
- Docker container breaking changes
- CLI breaking changes
- New widgets
- Docker containers
- Custom API
- Server stats
- Split column
- Calendar (reworked)
- New features
- Auto reload on config change
- Environment variables anywhere in the config
- Include files in the config
- Custom HTML in document <head>
- Support for selfh.st and Dashboard icons
- New styles
- [Monitor]
compact
- [Videos]
vertical-list
- [Monitor]
- Widget enhancements
- [Twitch channels] stream preview on hover
- [RSS] request headers,
limit
per feed,preserve-order
- [Videos]
playlists
- [Group] support for
title-url
- [Monitor]
alt-status-codes
,error-url
- [Extension] specify if content should have no frame
- [Bookmarks]
target
for links,same-tab
andhide-arrow
for groups - [Reddit]
proxy
- [Search]
placeholder
and clear input on search - [Markets]
chart-link-template
,symbol-link-template
andsort-by
- [Releases]
include-prereleases
- [DNS stats]
hide-graph
,hide-top-domains
andallow-insecure
- [Clock] now displays exact time difference for timezones
- Fixes
- Been a while
- Community overhaul
- Thank you
Docker container breaking changes
Until now, setting up Glance using its Docker container involved a somewhat unusual step where the config file was solely mounted as a volume. This tripped up some users and caused unnecessary confusion due to a few odd behaviors.
The default location of the config file has now been changed to /app/config/glance.yml
from /app/glance.yml
. That means your docker-compose.yml
file should now look like the following:
services:
glance:
image: glanceapp/glance
volumes:
- ./config:/app/config
This also requires that you place your glance.yml
file in a config
directory in the same location as your docker-compose.yml
file. If you're unsure what changes you need to make, there is an upgrade guide available here as well as a new recommended docker compose directory structure available here.
CLI breaking changes
Previously, you could run the following to validate your config file without starting Glance:
glance --config /path/to/config.yml --check-config
For the sake of consistency with the few new added comands (and because this shouldn't have been a flag in the first place), this has now been changed to:
glance --config /path/to/config.yml config:validate
New widgets
Docker containers
Display the status of your Docker containers along with an icon and an optional short description.
- type: docker-containers
hide-by-default: false
Note
The widget requires access to docker.sock
. If you're running Glance inside a container, this can be done by mounting the socket as a volume:
services:
glance:
image: glanceapp/glance
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Configuration of the containers is done via labels applied to each container:
jellyfin:
image: jellyfin/jellyfin:latest
labels:
glance.name: Jellyfin
glance.icon: si:jellyfin
glance.url: https://jellyfin.domain.com
glance.description: Movies & shows
For services with multiple containers you can specify a glance.id
on the "main" container and glance.parent
on each "child" container:
View
docker-compose.yml
services:
immich-server:
image: ghcr.io/immich-app/immich-server
labels:
glance.name: Immich
glance.icon: si:immich
glance.url: https://immich.domain.com
glance.description: Image & video management
glance.id: immich
redis:
image: docker.io/redis:6.2-alpine
labels:
glance.parent: immich
glance.name: Redis
database:
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0
labels:
glance.parent: immich
glance.name: DB
proxy:
image: nginx:stable
labels:
glance.parent: immich
glance.name: Proxy
This will place all child containers under the Immich
container when hovering over its icon:
If any of the child containers are down, their status will propagate up to the parent container:
(thanks @baranovskis & @reality-exe, inspired by https://github.com/DVDAndroid/glance-docker-container-ext)
Custom API
Display data from any JSON API in an entirely customizable template.
Note
With great power come great requirements.
The configuration of this widget requires some basic knowledge of programming, HTML, CSS, the Go template language and Glance-specific concepts.
View
glance.yml
- type: custom-api
title: Random Fact
cache: 6h
url: https://uselessfacts.jsph.pl/api/v2/facts/random
template: |
<p class="size-h4 color-paragraph">{{ .JSON.String "text" }}</p>
View
glance.yml
- type: custom-api
title: Immich stats
cache: 1d
url: https://${IMMICH_URL}/api/server/statistics
headers:
x-api-key: ${IMMICH_API_KEY}
Accept: application/json
template: |
<div class="flex justify-between text-center">
<div>
<div class="color-highlight size-h3">{{ .JSON.Int "photos" | formatNumber }}</div>
<div class="size-h6">PHOTOS</div>
</div>
<div>
<div class="color-highlight size-h3">{{ .JSON.Int "videos" | formatNumber }}</div>
<div class="size-h6">VIDEOS</div>
</div>
<div>
<div class="color-highlight size-h3">{{ div (.JSON.Int "usage" | toFloat) 1073741824 | toInt | formatNumber }}GB</div>
<div class="size-h6">USAGE</div>
</div>
</div>
View
glance.yml
- type: custom-api
title: Steam Specials
cache: 12h
url: https://store.steampowered.com/api/featuredcategories?cc=us
template: |
<ul class="list list-gap-10 collapsible-container" data-collapse-after="5">
{{ range .JSON.Array "specials.items" }}
<li>
<a class="size-h4 color-highlight block text-truncate" href="https://store.steampowered.com/app/{{ .Int "id" }}/">{{ .String "name" }}</a>
<ul class="list-horizontal-text">
<li>{{ div (.Int "final_price" | toFloat) 100 | printf "$%.2f" }}</li>
{{ $discount := .Int "discount_percent" }}
<li{{ if ge $discount 40 }} class="color-positive"{{ end }}>{{ $discount }}% off</li>
</ul>
</li>
{{ end }}
</ul>
(thanks @reality-exe)
Server stats
There are other projects dedicated to providing this kind of functionality and this is not meant to be a replacement for any of them, it's intended for people who just want the most basic information about their server without setting up a separate monitoring solution. Things will get improved based on feedback, but the goal is to keep it simple and minimal. If you're looking for a more feature-rich server monitoring solution, Beszel looks like a good choice. With that out of the way:
- type: server-stats
servers:
- type: local
name: Services
# optionally override the sensor used to determine CPU temperature
# cpu-temp-sensor: thermal_zone0
# optionally hide swap
# hide-swap: true
# optionally hide or rename mountpoints
# mountpoints:
# "/boot/efi":
# hide: true
# name: EFI
There's a bunch of bars and their purpose might not be immediately obvious:
- CPU - 1m and 15m average load
- RAM - RAM and SWAP
- Disk – the two mountpoints with the highest usage percentages
If your CPU is feeling a little spicy (assuming Glance was able to determine your CPU sensor) and reaches >=80°C, you'll see a little flame icon next to it. The progress indicators will also turn red (or the equivalent of your negative color) to hopefully grab your attention if anything is unusually high:
Now, it's not uncommon to have multiple servers at home these days, and you'd probably want to see their stats as well, so there's support for that too:
View
glance.yml
- type: server-stats
servers:
- type: remote
name: Services
url: http://${SERVER_IP}:27973
token: ${AGENT_TOKEN}
- type: remote
name: DNS
url: http://${SERVER_IP}:27973
token: ${AGENT_TOKEN}
After looking for an existing solution to delegate this job to, nothing quite fit all of the following criteria:
- Super minimal and lightweight
- Does nothing in the background, no storage, just provides system info when asked
- HTTP JSON API
- Optional authentication
- Easy, configurable installation with both a single binary and a Docker container
- Supports x86_64 and ARM
As a result, somewhat contradictory to the first paragraph, I decided to build one (it will be made available in the next couple of days). It's quite simple, very much work in progress, and I'm not sure how well it will work for everyone, but it's an option for those who want to go with this approach. It's not required if you just want to see the stats of the server Glance is installed on, only if you want to see the stats of multiple servers, in which case you'd have to install it on each. Here's what the setup process looks like:
agent-install-demo.mp4
Installed, configured and uninstalled like it never existed in less than a minute.
Because the agent provides this information via a simple HTTP JSON API, you could use the custom API widget to display the stats in any way you like:
View
glance.yml
- type: custom-api
title: Server stats
url: http://${SERVER_IP}:27973/api/sysinfo/all
headers:
Authorization: Bearer ${AGENT_TOKEN}
template: |
<div class="flex justify-between text-center">
<div>
<div class="color-highlight size-h3">{{ .JSON.Int "cpu.load1_percent" }}%</div>
<div class="size-h6">CPU</div>
</div>
<div>
<div class="color-highlight size-h3">{{ .JSON.Int "memory.used_percent" }}%</div>
<div class="size-h6">RAM</div>
</div>
<div>
<div class="color-highlight size-h3">{{ .JSON.Int "mountpoints.0.used_percent" }}%</div>
<div class="size-h6">DISK</div>
</div>
</div>
- type: custom-api
title: Server stats
url: http://${SERVER_IP}:27973/api/sysinfo/all
headers:
Authorization: Bearer ${AGENT_TOKEN}
template: |
<div class="flex flex-column gap-5">
<div class="flex gap-20 items-center">
<div class="size-h5" style="width: 4ch">CPU</div>
<div class="progress-bar grow">
<div class="progress-value" style="--percent: {{ .JSON.Int "cpu.load1_percent" }}"></div>
</div>
<div class="color-highlight text-very-compact text-right" style="width: 4ch">{{ .JSON.Int "cpu.load1_percent" }} <span class="color-base size-h5">%</span></div>
</div>
<div class="flex gap-20 items-center">
<div class="size-h5" style="width: 4ch">RAM</div>
<div class="progress-bar grow">
<div class="progress-value" style="--percent: {{ .JSON.Int "memory.used_percent" }}"></div>
</div>
<div class="color-highlight text-very-compact text-right" style="width: 4ch">{{ .JSON.Int "memory.used_percent" }} <span class="color-base size-h5">%</span></div>
</div>
<div class="flex gap-20 items-center">
<div class="size-h5" style="width: 4ch">DISK</div>
<div class="progress-bar grow">
<div class="progress-value" style="--percent: {{ .JSON.Int "mountpoints.0.used_percent" }}"></div>
</div>
<div class="color-highlight text-very-compact text-right" style="width: 4ch">{{ .JSON.Int "mountpoints.0.used_percent" }} <span class="color-base size-h5">%</span></div>
</div>
</div>
There are plans to also add the ability to view the stats of Docker containers, so you could combine this with the Docker containers widget and see the status of your containers across multiple servers.
Support for other providers (such as Glances) are likely be added once everything else gets fleshed out a bit more.
(thanks @FedeP14 and shirou for the excellent module)
Split column
The ways in which you could organize your widgets has so far been somewhat limited. This widget brings a new dimension that you play around with by allowing you to vertically split a full sized column into multiple smaller columns of equal width.
Two widgets side by side in a full
column:
View
glance.yml
# ...
- size: full
widgets:
- type: split-column
widgets:
- type: hacker-news
collapse-after: 3
- type: lobsters
collapse-after: 3
- type: videos
# ...
You can also achieve a number of new full page layouts that were previously not possible, such as:
3 column layout where all columns have equal width:
View
glance.yml
pages:
- name: Home
columns:
- size: full
widgets:
- type: split-column
max-columns: 3
widgets:
- type: reddit
subreddit: selfhosted
collapse-after: 15
- type: reddit
subreddit: homelab
collapse-after: 15
- type: reddit
subreddit: sysadmin
collapse-after: 15
4 column layout where all columns have equal width (and the page is set to width: wide
):
View
glance.yml
pages:
- name: Home
width: wide
columns:
- size: full
widgets:
- type: split-column
max-columns: 4
widgets:
- type: reddit
subreddit: selfhosted
collapse-after: 15
- type: reddit
subreddit: homelab
collapse-after: 15
- type: reddit
subreddit: linux
collapse-after: 15
- type: reddit
subreddit: sysadmin
collapse-after: 15
Masonry layout with up to 5 columns where all columns have equal width (and the page is set to width: wide
):
View
glance.yml
define:
- &subreddit-settings
type: reddit
collapse-after: 5
pages:
- name: Home
width: wide
columns:
- size: full
widgets:
- type: split-column
max-columns: 5
widgets:
- subreddit: selfhosted
<<: *subreddit-settings
- subreddit: homelab
<<: *subreddit-settings
- subreddit: linux
<<: *subreddit-settings
- subreddit: sysadmin
<<: *subreddit-settings
- subreddit: DevOps
<<: *subreddit-settings
- subreddit: Networking
<<: *subreddit-settings
- subreddit: DataHoarding
<<: *subreddit-settings
- subreddit: OpenSource
<<: *subreddit-settings
- subreddit: Privacy
<<: *subreddit-settings
- subreddit: FreeSoftware
<<: *subreddit-settings
Just like the group
widget, you can insert any widget type, you can even insert a group
widget inside of a split-column
widget, but you can't insert a split-column
widget inside of a group
widget.
Note
This does not create new columns in the usual sense, meaning that you won't see a "dot" in the mobile navigation for each of these columns, it will just be a single dot. When viewing the page on a mobile device, all columns will turn into in a single one with the widgets stacked on top of each other in the order they were defined.
Calendar
The calendar widget has been reworked to look and behave more like an actual calendar.
- type: calendar
first-day-of-week: monday # make it any day of the week you need
Previously, the calendar would display the time of the server running Glance. This has now been changed to display the current time in the user's timezone based on their browser settings. As a result, mounting /etc/timezone
and /etc/localtime
in your Docker container is no longer necessary.
Because the new calendar is considered WIP and does not yet include the same 3 week view, the old calendar widget is still available under the widget type calendar-legacy
. The old calendar widget also has a new property for setting the first day of the week as sunday via start-sunday: true
(thanks @xendke).
Note
If you do want to use the legacy calendar you would still need to mount /etc/timezone
and /etc/localtime
in your Docker container.
This release was also meant to include the ability to add calendar events from ICS feeds, however unfortunately this feature turned out to be more complex than anticipated and will be included in a future release instead.
New features
Auto reload on config change
Finally, the highly requested feature of automatically reloading Glance when the config changes has been implemented. There are some things that break this functionality, such as deleting the config file, but for the most part it should work as expected. Note that changing environment variable values still requires a full manual restart.
Caution
Reloading the config clears your cached data, so be mindful when making lots of changes as you may end up hitting rate limits on APIs.
(thanks @bcurran3 & @helloteemo & @arminus & everyone else who suggested this or tried implementing it)
Environment variables anywhere in the config
Up until now, the ability to use environment variables worked only on specific properties in the config and needed to be added individually for each property. This functionality has now been expanded to work anywhere in the config:
pages:
- name: Home
columns:
- size: ${WORKS_HERE}
widgets:
- type: ${WORKS_HERE}
limit: ${WORKS_HERE}
collapse-after: ${AND_HERE}
cache: ${AS_WELL_AS_HERE}
feeds:
- url: ${AND_OF_COURSE_HERE}
- ${EVEN_HERE}: https://${HERE_TOO}/feed
If you need to use the syntax ${NAME}
in your config without it being interpreted as an environment variable, you can escape it by prefixing with a backslash \
:
something: \${NOT_AN_ENV_VAR}
Include files in the config
Having a single, ever-growing config file can get a little overwhelming, especially with how picky YAML can be about indentation. To help with this, you can now split your config into multiple files and include them in the main config:
theme:
!include: theme.yml
pages:
!include: home.yml
!include: news.yml
!include: homelab.yml
# these paths also work:
!include: ../pages/home.yml
!include: pages/news.yml
!include: /etc/opt/glance/homelab.yml
# can be anywhere in the config, so long as they are on their own line:
- name: Example
columns:
- size: small
!include: example-left.yml
- size: full
!include: example-middle.yml
- size: small
!include: example-right.yml
The path of each file is relative to the main config file but you can also specify an absolute path. Changes to these included files will also trigger an automatic reload.
The proper indentation is automatically applied to the included content based on where it's included. The included file itself should have no extra indentation.
Note
For now, the !include
directive only works in the main config file and not in included files.
Note
The !include
directive is a preprocessing step, meaning that all files first get "stitched" together and then parsed as a single YAML file. Any YAML syntax errors will report the line number in the concatenated text, not the original file. To help with debugging, there is a new command that prints the full parsed config file with all includes resolved:
glance --config /path/to/config.yml config:print
You can pipe the output to less -N
which will display line numbers.
Note
(yes, that's 3 notes in a row)
Because of the above note, including a file does not override existing keys at the same level. This will result in an error because the key collapse-after
is defined twice:
reddit-settings.yml
:
collapse-after: 5
limit: 10
glance.yml
:
- type: reddit
subreddit: linux
collapse-after: 10
!include: reddit-settings.yml
To reuse properties like this use YAML anchors instead.
Custom HTML in document <head>
Previously, if you wanted to insert HTML into the document across all pages, you had to do so through the custom-footer
property which wasn't ideal. You can now insert custom HTML in the document's <head>:
# this is a top level property
document:
head: |
<meta http-equiv="refresh" content="120">
<script>alert("probably don't do this... but you could if you wanted to!");</script>
(thank you to the peeps from the Discord server for bringing this up)
Support for selfh.st and Dashboard icons
You can now use selfh.st and Dashboard icons in the icon
property of widgets such as the monitor
and bookmarks
:
icon: si:github # simple icons
icon: sh:github # selfh.st icons
icon: di:github # Dashboard icons
(thanks @2q2code)
New styles
[Monitor] compact
- type: monitor
style: compact
(thanks for the idea Gato :D)
[Videos] vertical-list
- type: videos
style: vertical-list
Widget enhancements
[Twitch channels] stream preview on hover
(thanks for the idea @uykukacinca)
[RSS] request headers, limit
per feed, preserve-order
You can now specify request headers on a per-feed basis:
- type: rss
feeds:
- url: https://domain.com/rss
headers:
User-Agent: Custom User Agent
Authorization: Bearer ${FEED_TOKEN}
# etc...
You can also limit the number of items per feed, for those feeds which post a little too frequently and push the rest of the articles from other feeds down:
- type: rss
feeds:
- url: https://domain.com/rss
limit: 5
And finally, you can now preserve the order of the items in each feed, useful for feeds which place their most important articles at the top:
- type: rss
preserve-order: true
feeds:
- url: https://domain.com/rss
(thanks @paulkakell & @lunik1)
[Videos] playlists
You can now add YouTube playlists to the videos widget:
- type: videos
playlists:
- PL8mG-RkN2uTyZZ00ObwZxxoG_nJbs3qec
- PL8mG-RkN2uTxTK4m_Vl2dYR9yE41kRdBg
(thanks @DickenSerm & @vishalkadam47)
[Group] support for title-url
The title-url
property now works for widgets placed inside of a group. To open their link in a new tab you can either middle click on any of the titles, or click again on the currently selected widget's title.
[Monitor] alt-status-codes
, error-url
You can now specify alternative status codes to be considered as "up" for the monitor widget:
- type: monitor
title: Services
sites:
- title: Jellyfin
url: https://jellyfin.yourdomain.com
icon: sh:jellyfin
alt-status-codes: [401, 403]
You can also specify an alternative URL for the site for when it is down:
- type: monitor
title: Services
sites:
- title: Jellyfin
url: https://jellyfin.yourdomain.com
icon: sh:jellyfin
error-url: https://status.yourdomain.com
(thanks @cmeadowstech & @JeckDev)
[Extension] specify if content should have no frame
Extensions can now return a Widget-Content-Frameless
header with a value of true
to have their content displayed without a frame (the lighter background and border).
(thanks @DallasHoff)
[Bookmarks] target
for links, same-tab
and hide-arrow
for groups
You can now specify the target for links in the bookmarks widget:
- type: bookmarks
groups:
- links:
- title: Gmail
url: https://mail.google.com/mail/u/0/
target: _parent
In addition, you can now specify same-tab
, hide-arrow
and target
on groups and have each link in the group inherit those properties, or override them for a specific link:
- type: bookmarks
groups:
- same-tab: true # ╺┓
hide-arrow: true # ╺╋╸ default for all links in this group
target: _parent # ╺┛
links:
- title: Link
url: ...
- title: Link
url: ...
same-tab: false # override for this link
- title: Link
url: ...
[Reddit] proxy
You can now use a standard HTTP proxy in the Reddit widget for instances where Reddit is blocked:
- type: reddit
subreddit: linux
proxy:
url: http://proxy.com:8080
allow-insecure: true
timeout: 10s
(thanks Bifrons)
[Search] placeholder
and clear input on search
You can now specify a placeholder text for the search widget:
- type: search
placeholder: Search...
In addition, when performing a search in a new tab, the search query will be cleared from the input field. You can press Up arrow to bring back the last search query.
[Markets] chart-link-template
, symbol-link-template
and sort-by
You can now specify a sort order of change
for descending order based on the stock's percentage change (e.g. 1% would be sorted higher than -1%).
- type: markets
sort-by: change
markets:
- symbol: AAPL
You can also specify a template for the chart-link
and symbol-link
so you don't have to repeat the same URL for each market:
- type: markets
chart-link-template: https://tradingview.com/chart?symbol={SYMBOL}
symbol-link-template: https://finance.yahoo.com/quote/{SYMBOL}
markets:
- symbol: AAPL
- symbol: TSLA
- symbol: MSFT
- symbol: GOOGL
(thanks @ehaughee)
[Releases] include-prereleases
You can now include prereleases in the releases widget for individual repositories (only supports GitHub for now):
- type: releases
repositories:
- repository: glanceapp/glance
include-prereleases: true
- immich/immich-server
- jellyfin/jellyfin
- go-gitea/gitea
(thanks @Mystically11)
[DNS stats] hide-graph
, hide-top-domains
and allow-insecure
You can now hide the graph as well as top domains in the DNS stats widget:
- type: dns-stats
hide-graph: true
hide-top-domains: true
You can also use an insecure connection to the API by setting allow-insecure: true
if you're using a self-signed certificate.
(thanks @zatevakhin)
[Clock] now displays exact time difference for other timezones
(thanks @oliver-mitchell)
Fixes
- URLs in the config with non-http/https schemas will no longer be escaped (thanks @kamilkosek)
- Titles in RSS feeds with special characters will now be properly displayed (thanks @marb08)
- Various visual bug fixes on iOS (thanks @DallasHoff)
Been a while
It's been almost 5 months since v0.6.0 and that's a long time to wait for new stuff. As new feature requests kept coming in I got stuck in a "I'll add this to the next release" loop, so the amount of things needing to be done grew out of hand. I want to avoid making this mistake again in the future by releasing smaller but more frequent updates.
I'm sorry for the wait y'all, I'll try and do better. I hope there's at least one thing in this release for everyone to get excited about.
There's a lot of new stuff out at once so inevitably there may be some bugs, I'll try and prioritize fixing those and releasing hotfixes over the next few weeks.
Community overhaul
The community side of the repository has gone through a bit of an overhaul. Previously, there were no guidelines around where and how to submit feature requests, bug reports or ask for help, so they were scattered across the issues and discussions which made them difficult to keep track of. Now, clear guidelines are in place: feature requests and bug reports should be submitted exclusively via issues. The discussions as well as Discord server will be for general discussions, help and sharing guides/resources.
Thank you
To all the sponsors who have continued to support the project even in the lack of activity during the last couple of months and to everyone who has contributed in the meantime. Also, I'd like to thank Ethan for featuring Glance on selfh.st! It's been a great motivator to see Glance listed alongside so many other great projects.