Personal Glance dashboard config.
0

Configure Feed

Select the types of activity you want to include in your feed.

jarvis, clean up my fucking repo

Adam0 (Jul 15, 2026, 11:19 PM EDT) 718bc61e d3cb0674

+155 -163
+1 -1
assets/icons/beszel.svg assets/icons/beszel/icon.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><linearGradient id="beszel_svg__a" x1="433.391" x2="-10.605" y1="446.179" y2="73.621" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#52cf83"/><stop offset=".63" style="stop-color:#6d98d2"/><stop offset="1" style="stop-color:#7b7bfc"/></linearGradient><path d="M307.2 512h-256V0h256c21.5 0 41.4 4.1 60 12.4 18 7.8 34.4 19 48.3 32.9C429.6 59 440.6 75 448.4 93.6c8.3 19 12.4 39 12.4 60 .1 7.9-.6 15.7-2.2 23.4-.4 2-.9 3.9-1.5 5.9-2.6 10.1-6.2 19.9-11 29.3-4.8 9-10.7 17.3-17.6 24.9-5.6 6.4-12 12.1-19 16.8-1 .8-1.9 1.5-2.9 2.2q12.45 7.35 21.9 18.3c6.8 7.8 12.7 16.3 17.6 25.6 4.8 9.3 8.5 19.1 11 29.3 1.9 7.2 3.1 14.5 3.7 21.9.1 2.4.1 4.9 0 7.3 0 21.5-4.1 41.4-12.4 60-7.8 18-19 34.4-32.9 48.3-13.7 14.1-29.7 25.4-48.3 33.6-18.6 7.7-38.6 11.6-60 11.6M153.6 102.4v102.4h153.6c5.7.2 11.4-.5 16.8-2.2 1-.5 2-.9 2.9-1.5 6.3-2.4 11.9-6.1 16.8-11 4.7-4.6 8.4-10.1 11-16.1 2.4-6.3 3.7-13.2 3.7-20.5 0-5.7-1-11.4-2.9-16.8-.2-1-.5-2-.7-2.9-2.9-6.3-6.6-11.9-11-16.8-4.9-4.5-10.6-7.9-16.8-10.2-5.8-2.6-12-4.1-18.3-4.4zm0 204.8v102.4h153.6c5.7 0 11.4-1 16.8-2.9 1-.2 2-.5 2.9-.7 6.3-2.9 11.9-6.6 16.8-11 4.7-4.6 8.4-10.1 11-16.1 2.4-6 3.7-12.5 3.7-19v-1.5c0-5.7-1-11.4-2.9-16.8-.2-1-.5-2-.7-2.9-2.9-6.3-6.6-11.9-11-16.8-4.8-4.7-10.5-8.5-16.8-11-5.8-2.6-12-4.1-18.3-4.4H153.6z" style="fill:url(#beszel_svg__a)"/></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><linearGradient id="beszel_svg__a" x1="433.391" x2="-10.605" y1="446.179" y2="73.621" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#52cf83"/><stop offset=".63" style="stop-color:#6d98d2"/><stop offset="1" style="stop-color:#7b7bfc"/></linearGradient><path d="M307.2 512h-256V0h256c21.5 0 41.4 4.1 60 12.4 18 7.8 34.4 19 48.3 32.9C429.6 59 440.6 75 448.4 93.6c8.3 19 12.4 39 12.4 60 .1 7.9-.6 15.7-2.2 23.4-.4 2-.9 3.9-1.5 5.9-2.6 10.1-6.2 19.9-11 29.3-4.8 9-10.7 17.3-17.6 24.9-5.6 6.4-12 12.1-19 16.8-1 .8-1.9 1.5-2.9 2.2q12.45 7.35 21.9 18.3c6.8 7.8 12.7 16.3 17.6 25.6 4.8 9.3 8.5 19.1 11 29.3 1.9 7.2 3.1 14.5 3.7 21.9.1 2.4.1 4.9 0 7.3 0 21.5-4.1 41.4-12.4 60-7.8 18-19 34.4-32.9 48.3-13.7 14.1-29.7 25.4-48.3 33.6-18.6 7.7-38.6 11.6-60 11.6M153.6 102.4v102.4h153.6c5.7.2 11.4-.5 16.8-2.2 1-.5 2-.9 2.9-1.5 6.3-2.4 11.9-6.1 16.8-11 4.7-4.6 8.4-10.1 11-16.1 2.4-6.3 3.7-13.2 3.7-20.5 0-5.7-1-11.4-2.9-16.8-.2-1-.5-2-.7-2.9-2.9-6.3-6.6-11.9-11-16.8-4.9-4.5-10.6-7.9-16.8-10.2-5.8-2.6-12-4.1-18.3-4.4zm0 204.8v102.4h153.6c5.7 0 11.4-1 16.8-2.9 1-.2 2-.5 2.9-.7 6.3-2.9 11.9-6.6 16.8-11 4.7-4.6 8.4-10.1 11-16.1 2.4-6 3.7-12.5 3.7-19v-1.5c0-5.7-1-11.4-2.9-16.8-.2-1-.5-2-.7-2.9-2.9-6.3-6.6-11.9-11-16.8-4.8-4.7-10.5-8.5-16.8-11-5.8-2.6-12-4.1-18.3-4.4H153.6z" style="fill:url(#beszel_svg__a)"/></svg>
+1
assets/icons/beszel/fire.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.074.945A4.993 4.993 0 0 0 6 5v.032c.004.6.114 1.176.311 1.709.16.428-.204.91-.61.7a5.023 5.023 0 0 1-1.868-1.677c-.202-.304-.648-.363-.848-.058a6 6 0 1 0 8.017-1.901l-.004-.007a4.98 4.98 0 0 1-2.18-2.574c-.116-.31-.477-.472-.744-.28Zm.78 6.178a3.001 3.001 0 1 1-3.473 4.341c-.205-.365.215-.694.62-.59a4.008 4.008 0 0 0 1.873.03c.288-.065.413-.386.321-.666A3.997 3.997 0 0 1 8 8.999c0-.585.126-1.14.351-1.641a.42.42 0 0 1 .503-.235Z" clip-rule="evenodd"/></svg>
+1
assets/icons/beszel/server.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 0 0-.12-1.03l-2.268-9.64a3.375 3.375 0 0 0-3.285-2.602H7.923a3.375 3.375 0 0 0-3.285 2.602l-2.268 9.64a4.5 4.5 0 0 0-.12 1.03v.228m19.5 0a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3m19.5 0a3 3 0 0 0-3-3H5.25a3 3 0 0 0-3 3m16.5 0h.008v.008h-.008v-.008Zm-3 0h.008v.008h-.008v-.008Z"/></svg>
+1 -1
assets/icons/check.svg assets/icons/status/check.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-square-rounded-check"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 2c-.218 0 -.432 .002 -.642 .005l-.616 .017l-.299 .013l-.579 .034l-.553 .046c-4.785 .464 -6.732 2.411 -7.196 7.196l-.046 .553l-.034 .579c-.005 .098 -.01 .198 -.013 .299l-.017 .616l-.004 .318l-.001 .324c0 .218 .002 .432 .005 .642l.017 .616l.013 .299l.034 .579l.046 .553c.464 4.785 2.411 6.732 7.196 7.196l.553 .046l.579 .034c.098 .005 .198 .01 .299 .013l.616 .017l.642 .005l.642 -.005l.616 -.017l.299 -.013l.579 -.034l.553 -.046c4.785 -.464 6.732 -2.411 7.196 -7.196l.046 -.553l.034 -.579c.005 -.098 .01 -.198 .013 -.299l.017 -.616l.005 -.642l-.005 -.642l-.017 -.616l-.013 -.299l-.034 -.579l-.046 -.553c-.464 -4.785 -2.411 -6.732 -7.196 -7.196l-.553 -.046l-.579 -.034a28.058 28.058 0 0 0 -.299 -.013l-.616 -.017l-.318 -.004l-.324 -.001zm2.293 7.293a1 1 0 0 1 1.497 1.32l-.083 .094l-4 4a1 1 0 0 1 -1.32 .083l-.094 -.083l-2 -2a1 1 0 0 1 1.32 -1.497l.094 .083l1.293 1.292l3.293 -3.292z" fill="currentColor" /></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-square-rounded-check"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 2c-.218 0 -.432 .002 -.642 .005l-.616 .017l-.299 .013l-.579 .034l-.553 .046c-4.785 .464 -6.732 2.411 -7.196 7.196l-.046 .553l-.034 .579c-.005 .098 -.01 .198 -.013 .299l-.017 .616l-.004 .318l-.001 .324c0 .218 .002 .432 .005 .642l.017 .616l.013 .299l.034 .579l.046 .553c.464 4.785 2.411 6.732 7.196 7.196l.553 .046l.579 .034c.098 .005 .198 .01 .299 .013l.616 .017l.642 .005l.642 -.005l.616 -.017l.299 -.013l.579 -.034l.553 -.046c4.785 -.464 6.732 -2.411 7.196 -7.196l.046 -.553l.034 -.579c.005 -.098 .01 -.198 .013 -.299l.017 -.616l.005 -.642l-.005 -.642l-.017 -.616l-.013 -.299l-.034 -.579l-.046 -.553c-.464 -4.785 -2.411 -6.732 -7.196 -7.196l-.553 -.046l-.579 -.034a28.058 28.058 0 0 0 -.299 -.013l-.616 -.017l-.318 -.004l-.324 -.001zm2.293 7.293a1 1 0 0 1 1.497 1.32l-.083 .094l-4 4a1 1 0 0 1 -1.32 .083l-.094 -.083l-2 -2a1 1 0 0 1 1.32 -1.497l.094 .083l1.293 1.292l3.293 -3.292z" fill="currentColor" /></svg>
assets/icons/dockhand.png

This is a binary file and will not be displayed.

+1
assets/icons/dockhand/container-running.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#808080" stroke-width="2"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5M12 22V12"/><path d="m16 12.75 8.25 5.125L16 22Z" fill="#22c55e" stroke="none"/></svg>
+1
assets/icons/dockhand/container-stopped.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#808080" stroke-width="2"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5M12 22V12"/><rect x="16" y="13.75" width="8.25" height="8.25" fill="#ef4444" stroke="none"/></svg>
assets/icons/dockhand/icon.png

This is a binary file and will not be displayed.

+1
assets/icons/dockhand/images.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#808080" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
+1
assets/icons/dockhand/networks.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#808080" stroke-width="2"><rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3M12 12V8"/></svg>
+1
assets/icons/dockhand/stacks.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#808080" stroke-width="2"><path d="m12 2-9 5 9 5 9-5-9-5ZM3 12l9 5 9-5M3 17l9 5 9-5"/></svg>
+1
assets/icons/dockhand/volumes.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#808080" stroke-width="2"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5M3 12a9 3 0 0 0 18 0"/></svg>
+1 -1
assets/icons/immich.svg assets/icons/immich/icon.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><path d="M238.8 155.5c33.5 29.7 60.5 61.5 77.9 91.5 29.9-53.4 49.8-116.9 50.1-157.3v-.8c0-59.8-59.7-83.1-111.1-83.1S144.6 29 144.6 88.8V92c28.7 12.8 62.6 35.6 94.2 63.5" style="fill:#fa2921"/><path d="M55.9 318.6c21-23.3 53.1-48.6 89.4-69.9 38.6-22.7 77.2-38.6 111.1-45.8-41.6-44.9-95.8-83.5-134.1-96.2-.3-.1-.5-.2-.7-.2-57-18.7-97.6 30.9-113.5 79.8S-4.1 299.1 52.8 317.6c.8.2 1.8.6 3.1 1" style="fill:#ed79b5"/><path d="M503.9 185.4C488 136.6 447.4 87 390.5 105.5c-.8.3-1.8.6-3.1 1-3.3 31.2-14.4 70.5-31.2 109.1-17.9 41.1-39.8 76.6-62.9 102.4 60 11.9 126.5 11.3 165.1-1 .3-.1.5-.2.7-.2 57-18.6 60.6-82.5 44.8-131.4" style="fill:#ffb400"/><path d="M205 366.3c-9.7-43.7-12.8-85.3-9.3-119.8-55.5 25.7-109 65.3-133 97.8-.2.2-.3.4-.5.6-35.2 48.4-.6 102.3 41 132.5s103.5 46.4 138.7-1.9c.5-.7 1.1-1.5 1.9-2.6-15.6-27.1-29.7-65.5-38.8-106.6" style="fill:#1e83f7"/><path d="M448.8 341.9c-30.7 6.5-71.5 8.1-113.4 4-44.6-4.3-85.1-14.2-116.8-28.2 7.2 60.8 28.4 123.8 51.9 156.7.2.2.3.4.5.6 35.2 48.4 97.1 32.2 138.7 1.9 41.6-30.2 76.2-84.1 41-132.5-.5-.6-1.1-1.4-1.9-2.5" style="fill:#18c249"/></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><path d="M238.8 155.5c33.5 29.7 60.5 61.5 77.9 91.5 29.9-53.4 49.8-116.9 50.1-157.3v-.8c0-59.8-59.7-83.1-111.1-83.1S144.6 29 144.6 88.8V92c28.7 12.8 62.6 35.6 94.2 63.5" style="fill:#fa2921"/><path d="M55.9 318.6c21-23.3 53.1-48.6 89.4-69.9 38.6-22.7 77.2-38.6 111.1-45.8-41.6-44.9-95.8-83.5-134.1-96.2-.3-.1-.5-.2-.7-.2-57-18.7-97.6 30.9-113.5 79.8S-4.1 299.1 52.8 317.6c.8.2 1.8.6 3.1 1" style="fill:#ed79b5"/><path d="M503.9 185.4C488 136.6 447.4 87 390.5 105.5c-.8.3-1.8.6-3.1 1-3.3 31.2-14.4 70.5-31.2 109.1-17.9 41.1-39.8 76.6-62.9 102.4 60 11.9 126.5 11.3 165.1-1 .3-.1.5-.2.7-.2 57-18.6 60.6-82.5 44.8-131.4" style="fill:#ffb400"/><path d="M205 366.3c-9.7-43.7-12.8-85.3-9.3-119.8-55.5 25.7-109 65.3-133 97.8-.2.2-.3.4-.5.6-35.2 48.4-.6 102.3 41 132.5s103.5 46.4 138.7-1.9c.5-.7 1.1-1.5 1.9-2.6-15.6-27.1-29.7-65.5-38.8-106.6" style="fill:#1e83f7"/><path d="M448.8 341.9c-30.7 6.5-71.5 8.1-113.4 4-44.6-4.3-85.1-14.2-116.8-28.2 7.2 60.8 28.4 123.8 51.9 156.7.2.2.3.4.5.6 35.2 48.4 97.1 32.2 138.7 1.9 41.6-30.2 76.2-84.1 41-132.5-.5-.6-1.1-1.4-1.9-2.5" style="fill:#18c249"/></svg>
+1
assets/icons/immich/photos.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13.73 15 9.83 21.76A10 10 0 0 0 18.32 19.75L14.66 13.4M2.46 15a10 10 0 0 0 5.99 6.34L12.12 15M8.54 12 4.64 5.25A10 10 0 0 0 2.2 14H9.69M21.8 10H14.31l5.05 8.75A10 10 0 0 0 21.8 10M21.54 9a10 10 0 0 0-5.99-6.34L11.88 9M9.4 10.5l4.77-8.26A10 10 0 0 0 5.68 4.25l3.72 6.25Z"/></svg>
+1
assets/icons/immich/storage.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11 2v20a10 10 0 0 1 0-20Zm2 0v9h9a10 10 0 0 0-9-9Zm0 11v9a10 10 0 0 0 9-9h-9Z"/></svg>
+1
assets/icons/immich/videos.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 16.5v-9l6 4.5m-4-10a10 10 0 1 0 0 20 10 10 0 0 0 0-20Z"/></svg>
+1
assets/icons/status/disabled.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 5Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"/></svg>
+1
assets/icons/status/enabled.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd"/></svg>
+1
assets/icons/status/widget-error.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"/></svg>
+1 -1
assets/icons/warning.svg assets/icons/status/warning.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-alert-square-rounded"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 2l.642 .005l.616 .017l.299 .013l.579 .034l.553 .046c4.687 .455 6.65 2.333 7.166 6.906l.03 .29l.046 .553l.041 .727l.006 .15l.017 .617l.005 .642l-.005 .642l-.017 .616l-.013 .299l-.034 .579l-.046 .553c-.455 4.687 -2.333 6.65 -6.906 7.166l-.29 .03l-.553 .046l-.727 .041l-.15 .006l-.617 .017l-.642 .005l-.642 -.005l-.616 -.017l-.299 -.013l-.579 -.034l-.553 -.046c-4.687 -.455 -6.65 -2.333 -7.166 -6.906l-.03 -.29l-.046 -.553l-.041 -.727l-.006 -.15l-.017 -.617l-.004 -.318v-.648l.004 -.318l.017 -.616l.013 -.299l.034 -.579l.046 -.553c.455 -4.687 2.333 -6.65 6.906 -7.166l.29 -.03l.553 -.046l.727 -.041l.15 -.006l.617 -.017c.21 -.003 .424 -.005 .642 -.005zm.01 13l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -8a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z" /></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-alert-square-rounded"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 2l.642 .005l.616 .017l.299 .013l.579 .034l.553 .046c4.687 .455 6.65 2.333 7.166 6.906l.03 .29l.046 .553l.041 .727l.006 .15l.017 .617l.005 .642l-.005 .642l-.017 .616l-.013 .299l-.034 .579l-.046 .553c-.455 4.687 -2.333 6.65 -6.906 7.166l-.29 .03l-.553 .046l-.727 .041l-.15 .006l-.617 .017l-.642 .005l-.642 -.005l-.616 -.017l-.299 -.013l-.579 -.034l-.553 -.046c-4.687 -.455 -6.65 -2.333 -7.166 -6.906l-.03 -.29l-.046 -.553l-.041 -.727l-.006 -.15l-.017 -.617l-.004 -.318v-.648l.004 -.318l.017 -.616l.013 -.299l.034 -.579l.046 -.553c.455 -4.687 2.333 -6.65 6.906 -7.166l.29 -.03l.553 -.046l.727 -.041l.15 -.006l.617 -.017c.21 -.003 .424 -.005 .642 -.005zm.01 13l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -8a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z" /></svg>
+1 -1
assets/icons/x.svg assets/icons/status/x.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-square-rounded-x"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 2l.324 .001l.318 .004l.616 .017l.299 .013l.579 .034l.553 .046c4.785 .464 6.732 2.411 7.196 7.196l.046 .553l.034 .579c.005 .098 .01 .198 .013 .299l.017 .616l.005 .642l-.005 .642l-.017 .616l-.013 .299l-.034 .579l-.046 .553c-.464 4.785 -2.411 6.732 -7.196 7.196l-.553 .046l-.579 .034c-.098 .005 -.198 .01 -.299 .013l-.616 .017l-.642 .005l-.642 -.005l-.616 -.017l-.299 -.013l-.579 -.034l-.553 -.046c-4.785 -.464 -6.732 -2.411 -7.196 -7.196l-.046 -.553l-.034 -.579a28.058 28.058 0 0 1 -.013 -.299l-.017 -.616c-.003 -.21 -.005 -.424 -.005 -.642l.001 -.324l.004 -.318l.017 -.616l.013 -.299l.034 -.579l.046 -.553c.464 -4.785 2.411 -6.732 7.196 -7.196l.553 -.046l.579 -.034c.098 -.005 .198 -.01 .299 -.013l.616 -.017c.21 -.003 .424 -.005 .642 -.005zm-1.489 7.14a1 1 0 0 0 -1.218 1.567l1.292 1.293l-1.292 1.293l-.083 .094a1 1 0 0 0 1.497 1.32l1.293 -1.292l1.293 1.292l.094 .083a1 1 0 0 0 1.32 -1.497l-1.292 -1.293l1.292 -1.293l.083 -.094a1 1 0 0 0 -1.497 -1.32l-1.293 1.292l-1.293 -1.292l-.094 -.083z" fill="currentColor" /></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-square-rounded-x"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 2l.324 .001l.318 .004l.616 .017l.299 .013l.579 .034l.553 .046c4.785 .464 6.732 2.411 7.196 7.196l.046 .553l.034 .579c.005 .098 .01 .198 .013 .299l.017 .616l.005 .642l-.005 .642l-.017 .616l-.013 .299l-.034 .579l-.046 .553c-.464 4.785 -2.411 6.732 -7.196 7.196l-.553 .046l-.579 .034c-.098 .005 -.198 .01 -.299 .013l-.616 .017l-.642 .005l-.642 -.005l-.616 -.017l-.299 -.013l-.579 -.034l-.553 -.046c-4.785 -.464 -6.732 -2.411 -7.196 -7.196l-.046 -.553l-.034 -.579a28.058 28.058 0 0 1 -.013 -.299l-.017 -.616c-.003 -.21 -.005 -.424 -.005 -.642l.001 -.324l.004 -.318l.017 -.616l.013 -.299l.034 -.579l.046 -.553c.464 -4.785 2.411 -6.732 7.196 -7.196l.553 -.046l.579 -.034c.098 -.005 .198 -.01 .299 -.013l.616 -.017c.21 -.003 .424 -.005 .642 -.005zm-1.489 7.14a1 1 0 0 0 -1.218 1.567l1.292 1.293l-1.292 1.293l-.083 .094a1 1 0 0 0 1.497 1.32l1.293 -1.292l1.293 1.292l.094 .083a1 1 0 0 0 1.32 -1.497l-1.292 -1.293l1.292 -1.293l.083 -.094a1 1 0 0 0 -1.497 -1.32l-1.293 1.292l-1.293 -1.292l-.094 -.083z" fill="currentColor" /></svg>
+66 -3
assets/user.css
··· 1 + .asset-icon { 2 + display: inline-block; 3 + flex-shrink: 0; 4 + background-color: var(--asset-color, var(--color-primary)); 5 + -webkit-mask: var(--asset-icon) center / contain no-repeat; 6 + mask: var(--asset-icon) center / contain no-repeat; 7 + } 8 + 9 + .widget-error-icon, 10 + .server-icon { 11 + width: 3rem; 12 + height: 3rem; 13 + } 14 + 15 + .indexer-status-icon { 16 + display: block; 17 + width: 20px; 18 + height: 20px; 19 + } 20 + 21 + .server-spicy-cpu-icon { 22 + width: 1.2em; 23 + height: 1.2em; 24 + margin-left: 0.3rem; 25 + } 26 + 27 + .immich-stats { 28 + display: grid; 29 + grid-template-columns: repeat(3, minmax(0, 1fr)); 30 + gap: 1rem; 31 + } 32 + 33 + .immich-stat { 34 + display: flex; 35 + align-items: center; 36 + gap: 0.7rem; 37 + min-width: 0; 38 + } 39 + 40 + .immich-stat-icon { 41 + width: 1.8rem; 42 + height: 1.8rem; 43 + } 44 + 45 + .immich-storage-label { 46 + display: flex; 47 + justify-content: space-between; 48 + margin: 1rem 0 0.4rem; 49 + color: var(--color-text-subdue); 50 + font-size: var(--font-size-tiny); 51 + } 52 + 53 + @container widget (max-width: 420px) { 54 + .immich-stat { 55 + gap: 0.4rem; 56 + } 57 + 58 + .immich-stat-icon { 59 + width: 1.4rem; 60 + height: 1.4rem; 61 + } 62 + } 63 + 1 64 .monitor-site { 2 - --access-icon: url("/assets/icons/x.svg"); 65 + --access-icon: url("/assets/icons/status/x.svg"); 3 66 --access-color: var(--color-negative); 4 67 --access-tooltip: "Admin-only page."; 5 68 } ··· 21 84 [href^="https://ttrss."] 22 85 ) 23 86 ) { 24 - --access-icon: url("/assets/icons/check.svg"); 87 + --access-icon: url("/assets/icons/status/check.svg"); 25 88 --access-color: var(--color-positive); 26 89 --access-tooltip: "User access allowed."; 27 90 } ··· 36 99 [href^="https://ncps."] 37 100 ) 38 101 ) { 39 - --access-icon: url("/assets/icons/warning.svg"); 102 + --access-icon: url("/assets/icons/status/warning.svg"); 40 103 --access-color: hsl(34, 95%, 55%); 41 104 --access-tooltip: "Ask for account creation."; 42 105 }
+4 -4
config/home.yml
··· 39 39 sites: 40 40 - title: Beszel 41 41 url: https://beszel.${GROUND_DOMAIN} 42 - icon: /assets/icons/beszel.svg 42 + icon: /assets/icons/beszel/icon.svg 43 43 - title: Speedtest 44 44 url: https://speedtest.${GROUND_DOMAIN} 45 45 icon: /assets/icons/speedtest.svg ··· 103 103 password: ${authentik_password} 104 104 - title: immich 105 105 url: https://immich.${GROUND_DOMAIN} 106 - icon: /assets/icons/immich.svg 106 + icon: /assets/icons/immich/icon.svg 107 107 108 108 - type: monitor 109 109 cache: 8m ··· 208 208 sites: 209 209 - title: Dockhand 210 210 url: https://dockhand.${GROUND_DOMAIN} 211 - icon: /assets/icons/dockhand.png 211 + icon: /assets/icons/dockhand/icon.png 212 212 - title: Cloudbeaver 213 213 url: https://cloudbeaver.${GROUND_DOMAIN} 214 214 icon: /assets/icons/cloudbeaver.svg ··· 251 251 immich-machine-learning-1: 252 252 name: Immich machine learning 253 253 description: Smart search, facial recognition, and metadata jobs. 254 - icon: /assets/icons/immich.svg 254 + icon: /assets/icons/immich/icon.svg 255 255 hide: false 256 256 immich-postgres-1: 257 257 name: Postgres for Immich
+66 -151
config/statistics.yml
··· 294 294 Authorization: Bearer ${DOCKHAND_API_TOKEN} 295 295 template: | 296 296 <style> 297 - svg.icon { 297 + .dockhand-icon { 298 298 height: 1.5em; 299 - stroke: gray; 300 - fill: none; 301 299 margin-bottom: 0.25em; 302 300 } 303 301 </style> ··· 322 320 <div data-popover-type="text" data-popover-text="Running containers" 323 321 style="flex:1; display:flex; flex-direction:column; align-items:center;"> 324 322 <div class="size-h3 color-highlight">{{ $running }}</div> 325 - <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="2"> 326 - <path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/> 327 - <path d="m3.3 7 8.7 5 8.7-5"/> 328 - <path d="M12 22V12"/> 329 - <polygon points="16,12.75 16,22 24.25,17.875" fill="#22c55e" stroke="none"/> 330 - </svg> 323 + <img class="dockhand-icon" src="/assets/icons/dockhand/container-running.svg" alt=""> 331 324 </div> 332 325 333 326 <div data-popover-type="text" data-popover-text="Stopped containers" 334 327 style="flex:1; display:flex; flex-direction:column; align-items:center;"> 335 328 <div class="size-h3 color-highlight">{{ $stopped }}</div> 336 - <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="2"> 337 - <path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/> 338 - <path d="m3.3 7 8.7 5 8.7-5"/> 339 - <path d="M12 22V12"/> 340 - <rect x="16.0" y="13.75" width="8.25" height="8.25" fill="#ef4444" stroke="none"/> 341 - </svg> 329 + <img class="dockhand-icon" src="/assets/icons/dockhand/container-stopped.svg" alt=""> 342 330 </div> 343 331 344 332 <div data-popover-type="html" data-popover-position="bottom" data-popover-margin="0.2rem" ··· 365 353 <div class="color-highlight">{{ printf "%d.%02d GB" $totalGB $decimal }}</div> 366 354 </div> 367 355 </div> 368 - <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="2" style="margin-top:0.25rem;"> 369 - <rect x="3" y="3" width="18" height="18" rx="2"/> 370 - <circle cx="8.5" cy="8.5" r="1.5"/> 371 - <path d="M21 15l-5-5L5 21"/> 372 - </svg> 356 + <img class="dockhand-icon" src="/assets/icons/dockhand/images.svg" alt="" style="margin-top:0.25rem;"> 373 357 </div> 374 358 375 359 <div data-popover-type="text" data-popover-text="Volumes" 376 360 style="flex:1; display:flex; flex-direction:column; align-items:center;"> 377 361 <div class="size-h3 color-highlight">{{ len $volumes }}</div> 378 - <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="2"> 379 - <ellipse cx="12" cy="5" rx="9" ry="3"/> 380 - <path d="M3 5V19A9 3 0 0 0 21 19V5"/> 381 - <path d="M3 12A9 3 0 0 0 21 12"/> 382 - </svg> 362 + <img class="dockhand-icon" src="/assets/icons/dockhand/volumes.svg" alt=""> 383 363 </div> 384 364 385 - <div data-popover-type="html" data-popover-margin="0.2rem" data-popover-position="bottom" 365 + <div data-popover-type="html" data-popover-margin="0.2rem" data-popover-position="bottom" data-popover-max-width="400px" 386 366 style="flex:1; display:flex; flex-direction:column; align-items:center;"> 387 - <div data-popover-html=""> 367 + <div data-popover-html="" style="white-space:nowrap; width:max-content;"> 388 368 <div style="margin-bottom:0.75rem;">Networks</div> 389 369 {{ range $networks }} 390 - <div style="display:flex; justify-content:space-between; gap:1rem; min-width:220px;"> 391 - <div class="size-h5 text-compact">{{ .String "name" }}</div> 392 - <div class="size-h5 color-highlight"> 370 + <div style="display:grid; grid-template-columns:max-content max-content; justify-content:space-between; gap:1rem; min-width:220px; white-space:nowrap;"> 371 + <div class="size-h5 text-compact" style="white-space:nowrap;">{{ .String "name" }}</div> 372 + <div class="size-h5 color-highlight" style="white-space:nowrap;"> 393 373 {{ $cfg := .Array "ipam.config" }} 394 374 {{ if gt (len $cfg) 0 }} 395 375 {{ (index $cfg 0).String "subnet" }} ··· 401 381 {{ end }} 402 382 </div> 403 383 <div class="size-h3 color-highlight">{{ len $networks }}</div> 404 - <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="2"> 405 - <rect x="16" y="16" width="6" height="6" rx="1"/> 406 - <rect x="2" y="16" width="6" height="6" rx="1"/> 407 - <rect x="9" y="2" width="6" height="6" rx="1"/> 408 - <path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/> 409 - <path d="M12 12V8"/> 410 - </svg> 384 + <img class="dockhand-icon" src="/assets/icons/dockhand/networks.svg" alt=""> 411 385 </div> 412 386 413 387 <div data-popover-type="text" data-popover-text="Stacks" 414 388 style="flex:1; display:flex; flex-direction:column; align-items:center;"> 415 389 <div class="size-h3 color-highlight">{{ len $stacks }}</div> 416 - <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="2"> 417 - <path d="M12 2 3 7l9 5 9-5-9-5z"/> 418 - <path d="M3 12l9 5 9-5"/> 419 - <path d="M3 17l9 5 9-5"/> 420 - </svg> 390 + <img class="dockhand-icon" src="/assets/icons/dockhand/stacks.svg" alt=""> 421 391 </div> 422 392 </div> 423 393 ··· 442 412 {{ if or (eq $apiBaseUrl "") (eq $key "") (eq $url "") }} 443 413 <div class="widget-error-header"> 444 414 <div class="color-negative size-h3">ERROR</div> 445 - <svg class="widget-error-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"> 446 - <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"></path> 447 - </svg> 415 + <span class="asset-icon widget-error-icon" style="--asset-icon: url('/assets/icons/status/widget-error.svg'); --asset-color: var(--color-negative)"></span> 448 416 </div> 449 417 <p class="break-all">Some options are not set or malformed.</p> 450 418 {{ else }} ··· 478 446 {{ if .Bool "enable" }} 479 447 <div class="margin-left-auto shrink-0" data-popover-type="text" data-popover-position="above" data-popover-text="Enabled" aria-label="Enabled"> 480 448 <div class="monitor-site-status-icon-compact" title="Enabled"> 481 - <svg fill="var(--color-positive)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> 482 - <path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd"></path> 483 - </svg> 449 + <span class="asset-icon indexer-status-icon" style="--asset-icon: url('/assets/icons/status/enabled.svg'); --asset-color: var(--color-positive)"></span> 484 450 </div> 485 451 </div> 486 452 {{ else }} 487 453 <div class="margin-left-auto shrink-0" data-popover-type="text" data-popover-position="above" data-popover-text="Disabled" aria-label="Disabled"> 488 454 <div class="monitor-site-status-icon-compact" title="Disabled"> 489 - <svg fill="var(--color-negative)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> 490 - <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 5Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"></path> 491 - </svg> 455 + <span class="asset-icon indexer-status-icon" style="--asset-icon: url('/assets/icons/status/disabled.svg'); --asset-color: var(--color-negative)"></span> 492 456 </div> 493 457 </div> 494 458 {{ end }} ··· 501 465 {{ end }} 502 466 503 467 - type: custom-api 504 - title: Immich Stats 505 - hide-header: true 506 - cache: 10m 507 - url: https://immich.${GROUND_DOMAIN}/api/server/statistics 508 - headers: 509 - x-api-key: ${IMMICH_API_KEY} 510 - subrequests: 511 - storage: 512 - url: https://immich.${GROUND_DOMAIN}/api/server/storage 513 - headers: 514 - x-api-key: ${IMMICH_API_KEY} 515 - options: 516 - show-cards: true 517 - show-storage-bar: true 518 - template: | 519 - {{ $photos := .JSON.Int "photos" }} 520 - {{ $videos := .JSON.Int "videos" }} 521 - {{ $usageBytes := .JSON.Int "usage" }} 522 - {{ $usageGiB := div (toFloat $usageBytes) 1073741824.0 }} 523 - {{ $storage := .Subrequest "storage" }} 524 - {{ $storage_ok := and (ge $storage.Response.StatusCode 200) (le $storage.Response.StatusCode 299) }} 525 - {{ $totalGiB := 0.0 }} 526 - {{ $percentage := 0.0 }} 527 - {{ $storageError := "" }} 528 - {{ if $storage_ok }} 529 - {{ $totalGiB = div (toFloat ($storage.JSON.Int "diskSizeRaw")) 1073741824.0 }} 530 - {{ $percentage = $storage.JSON.Float "diskUsagePercentage" }} 531 - {{ else }} 532 - {{ $storageError = printf "%d %s" $storage.Response.StatusCode $storage.Response.Status }} 533 - {{ end }} 534 - {{ $showCards := .Options.BoolOr "show-cards" true }} 535 - {{ $showStorageBar := .Options.BoolOr "show-storage-bar" true }} 536 - 537 - {{ if $showCards }} 538 - <div style="display: flex; gap: 16px; flex-wrap: wrap;{{ if $showStorageBar }} margin-bottom: 16px;{{ end }}"> 539 - <div style="display: flex; flex-direction: column; justify-content: space-between; background-color: var(--color-widget-background-highlight); border-radius: 12px; padding: 20px; flex: 1; min-width: 200px;"> 540 - <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;"> 541 - <svg style="width: 40px; height: 40px; color: var(--color-primary); flex-shrink: 0;" viewBox="0 0 24 24" fill="currentColor"> 542 - <path d="M13.73,15L9.83,21.76C10.53,21.91 11.25,22 12,22C14.4,22 16.6,21.15 18.32,19.75L14.66,13.4M2.46,15C3.38,17.92 5.61,20.26 8.45,21.34L12.12,15M8.54,12L4.64,5.25C3,7 2,9.39 2,12C2,12.68 2.07,13.35 2.2,14H9.69M21.8,10H14.31L14.6,10.5L19.36,18.75C21,16.97 22,14.6 22,12C22,11.31 21.93,10.64 21.8,10M21.54,9C20.62,6.07 18.39,3.74 15.55,2.66L11.88,9M9.4,10.5L14.17,2.24C13.47,2.09 12.75,2 12,2C9.6,2 7.4,2.84 5.68,4.25L9.34,10.6L9.4,10.5Z"/> 543 - </svg> 544 - <span style="font-weight: 600; font-size: 1.8rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--color-text-highlight);">Photos</span> 545 - </div> 546 - <div style="font-family: ui-monospace, monospace; font-size: 1.85rem; font-weight: 700; color: var(--color-text-highlight); word-break: break-all;"> 547 - {{ if lt $photos 10 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">000000000</span>{{ else if lt $photos 100 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">00000000</span>{{ else if lt $photos 1000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">0000000</span>{{ else if lt $photos 10000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">000000</span>{{ else if lt $photos 100000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">00000</span>{{ else if lt $photos 1000000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">0000</span>{{ end }}{{ $photos }} 548 - </div> 549 - </div> 550 - 551 - <div style="display: flex; flex-direction: column; justify-content: space-between; background-color: var(--color-widget-background-highlight); border-radius: 12px; padding: 20px; flex: 1; min-width: 200px;"> 552 - <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;"> 553 - <svg style="width: 40px; height: 40px; color: var(--color-primary); flex-shrink: 0;" viewBox="0 0 24 24" fill="currentColor"> 554 - <path d="M10,16.5V7.5L16,12M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/> 555 - </svg> 556 - <span style="font-weight: 600; font-size: 1.8rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--color-text-highlight);">Videos</span> 557 - </div> 558 - <div style="font-family: ui-monospace, monospace; font-size: 1.85rem; font-weight: 700; color: var(--color-text-highlight); word-break: break-all;"> 559 - {{ if lt $videos 10 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">000000000</span>{{ else if lt $videos 100 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">00000000</span>{{ else if lt $videos 1000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">0000000</span>{{ else if lt $videos 10000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">000000</span>{{ else if lt $videos 100000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">00000</span>{{ else if lt $videos 1000000 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">0000</span>{{ end }}{{ $videos }} 560 - </div> 561 - </div> 562 - 563 - <div style="display: flex; flex-direction: column; justify-content: space-between; background-color: var(--color-widget-background-highlight); border-radius: 12px; padding: 20px; flex: 1; min-width: 200px;"> 564 - <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;"> 565 - <svg style="width: 40px; height: 40px; color: var(--color-primary); flex-shrink: 0;" viewBox="0 0 24 24" fill="currentColor"> 566 - <path d="M11,2V22C5.9,21.5 2,17.2 2,12C2,6.8 5.9,2.5 11,2M13,2V11H22C21.5,6.2 17.8,2.5 13,2M13,13V22C17.7,21.5 21.5,17.8 22,13H13Z"/> 567 - </svg> 568 - <span style="font-weight: 600; font-size: 1.8rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--color-text-highlight);">Storage</span> 569 - </div> 570 - <div style="font-family: ui-monospace, monospace; font-size: 1.85rem; font-weight: 700; color: var(--color-text-highlight); word-break: break-all;"> 571 - {{ $gib := printf "%.0f" $usageGiB }} 572 - {{ if lt $usageGiB 10.0 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">000000000</span>{{ else if lt $usageGiB 100.0 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">00000000</span>{{ else if lt $usageGiB 1000.0 }}<span style="color: var(--color-text-subdue); font-weight: 400; opacity: 0.6;">0000000</span>{{ end }}{{ $gib }}<span style="font-size: 1.5rem; font-weight: 500; color: var(--color-text-subdue); margin-left: 8px;">GiB</span> 573 - </div> 574 - </div> 575 - </div> 576 - {{ end }} 577 - 578 - {{ if $showStorageBar }} 579 - <div style="background-color: var(--color-widget-background-highlight); border-radius: 12px; padding: 20px;"> 580 - <div style="font-weight: 600; color: var(--color-text-highlight); margin-bottom: 8px; font-size: 1.6rem;">Storage space</div> 581 - {{ if gt $totalGiB 0.0 }} 582 - <div style="color: var(--color-text-highlight); font-size: 1.4rem; margin-bottom: 12px; font-weight: 500;">{{ printf "%.1f" $usageGiB }} GiB of {{ printf "%.1f" $totalGiB }} GiB used</div> 583 - <div style="color: var(--color-text-subdue); font-size: 1.35rem; margin-bottom: 12px;">{{ printf "%.1f" $percentage }}% full</div> 584 - {{ else }} 585 - <div style="color: var(--color-text-highlight); font-size: 1.4rem; margin-bottom: 12px; font-weight: 500;">{{ printf "%.1f" $usageGiB }} GiB used</div> 586 - <div style="color: var(--color-text-negative); font-size: 1.35rem; margin-bottom: 12px;">Total storage unavailable ({{ $storageError }}). Ensure API key has permissions for /api/server/storage.</div> 587 - {{ end }} 588 - <div style="height: 12px; width: 100%; background-color: var(--color-text-subdue); border-radius: 6px; overflow: hidden; opacity: 0.2;"> 589 - <div style="height: 100%; background-color: var(--color-primary); border-radius: 6px; transition: width 0.3s ease; width: {{ if gt $totalGiB 0.0 }}{{ printf "%.1f" $percentage }}%{{ else }}0%{{ end }};"></div> 590 - </div> 591 - </div> 592 - {{ end }} 593 - 594 - - type: custom-api 595 468 title: Server Stats 596 469 cache: 5m 597 470 options: ··· 606 479 {{ define "errorMsg" }} 607 480 <div class="widget-error-header"> 608 481 <div class="color-negative size-h3">ERROR</div> 609 - <svg class="widget-error-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"> 610 - <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"></path> 611 - </svg> 482 + <span class="asset-icon widget-error-icon" style="--asset-icon: url('/assets/icons/status/widget-error.svg'); --asset-color: var(--color-negative)"></span> 612 483 </div> 613 484 <p class="break-all">{{ . }}</p> 614 485 {{ end }} ··· 729 600 </div> 730 601 </div> 731 602 {{- end }} 732 - <svg class="server-icon" stroke="var(--color-{{ if eq $status "up" }}positive{{ else }}negative{{ end }})" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"> 733 - <path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 0 0-.12-1.03l-2.268-9.64a3.375 3.375 0 0 0-3.285-2.602H7.923a3.375 3.375 0 0 0-3.285 2.602l-2.268 9.64a4.5 4.5 0 0 0-.12 1.03v.228m19.5 0a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3m19.5 0a3 3 0 0 0-3-3H5.25a3 3 0 0 0-3 3m16.5 0h.008v.008h-.008v-.008Zm-3 0h.008v.008h-.008v-.008Z"></path> 734 - </svg> 603 + <span class="asset-icon server-icon" style="--asset-icon: url('/assets/icons/beszel/server.svg'); --asset-color: var(--color-{{ if eq $status "up" }}positive{{ else }}negative{{ end }})"></span> 735 604 </div> 736 605 </div> 737 606 ··· 740 609 <div class="flex items-end size-h5"> 741 610 <div>CPU</div> 742 611 {{- if ge $systemTemp 80.0 }} 743 - <svg class="server-spicy-cpu-icon" fill="var(--color-negative)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"> 744 - <path fill-rule="evenodd" d="M8.074.945A4.993 4.993 0 0 0 6 5v.032c.004.6.114 1.176.311 1.709.16.428-.204.91-.61.7a5.023 5.023 0 0 1-1.868-1.677c-.202-.304-.648-.363-.848-.058a6 6 0 1 0 8.017-1.901l-.004-.007a4.98 4.98 0 0 1-2.18-2.574c-.116-.31-.477-.472-.744-.28Zm.78 6.178a3.001 3.001 0 1 1-3.473 4.341c-.205-.365.215-.694.62-.59a4.008 4.008 0 0 0 1.873.03c.288-.065.413-.386.321-.666A3.997 3.997 0 0 1 8 8.999c0-.585.126-1.14.351-1.641a.42.42 0 0 1 .503-.235Z" clip-rule="evenodd"></path> 745 - </svg> 612 + <span class="asset-icon server-spicy-cpu-icon" style="--asset-icon: url('/assets/icons/beszel/fire.svg'); --asset-color: var(--color-negative)"></span> 746 613 {{- end }} 747 614 <div class="color-highlight margin-left-auto text-very-compact">{{ $cpuLoad }} <span class="color-base">%</span></div> 748 615 </div> ··· 849 716 {{ end }} 850 717 {{ end }} 851 718 {{ end }} 719 + {{ end }} 720 + 721 + - type: custom-api 722 + title: Immich Stats 723 + cache: 10m 724 + url: https://immich.${GROUND_DOMAIN}/api/server/statistics 725 + headers: 726 + x-api-key: ${IMMICH_API_KEY} 727 + subrequests: 728 + storage: 729 + url: https://immich.${GROUND_DOMAIN}/api/server/storage 730 + headers: 731 + x-api-key: ${IMMICH_API_KEY} 732 + template: | 733 + {{ $photos := .JSON.Int "photos" }} 734 + {{ $videos := .JSON.Int "videos" }} 735 + {{ $usageGiB := div (toFloat (.JSON.Int "usage")) 1073741824.0 }} 736 + {{ $storage := .Subrequest "storage" }} 737 + {{ $storageOK := and (ge $storage.Response.StatusCode 200) (le $storage.Response.StatusCode 299) }} 738 + {{ $totalGiB := 0.0 }} 739 + {{ $percentage := 0.0 }} 740 + {{ if $storageOK }} 741 + {{ $totalGiB = div (toFloat ($storage.JSON.Int "diskSizeRaw")) 1073741824.0 }} 742 + {{ $percentage = $storage.JSON.Float "diskUsagePercentage" }} 743 + {{ end }} 744 + 745 + <div class="immich-stats"> 746 + <div class="immich-stat"> 747 + <span class="asset-icon immich-stat-icon" style="--asset-icon: url('/assets/icons/immich/photos.svg')"></span> 748 + <div><div class="color-highlight size-h3">{{ $photos | formatNumber }}</div><div class="size-h6">PHOTOS</div></div> 749 + </div> 750 + <div class="immich-stat"> 751 + <span class="asset-icon immich-stat-icon" style="--asset-icon: url('/assets/icons/immich/videos.svg')"></span> 752 + <div><div class="color-highlight size-h3">{{ $videos | formatNumber }}</div><div class="size-h6">VIDEOS</div></div> 753 + </div> 754 + <div class="immich-stat"> 755 + <span class="asset-icon immich-stat-icon" style="--asset-icon: url('/assets/icons/immich/storage.svg')"></span> 756 + <div><div class="color-highlight size-h3">{{ printf "%.1f" $usageGiB }} <span class="color-base size-h5">GiB</span></div><div class="size-h6">STORAGE</div></div> 757 + </div> 758 + </div> 759 + {{ if $storageOK }} 760 + <div class="immich-storage-label"> 761 + <span>{{ printf "%.1f" $usageGiB }} / {{ printf "%.1f" $totalGiB }} GiB</span> 762 + <span>{{ printf "%.1f" $percentage }}%</span> 763 + </div> 764 + <div class="progress-bar"><div class="progress-value" style="--percent: {{ $percentage }}"></div></div> 765 + {{ else }} 766 + <div class="color-negative size-h5 margin-top-10">Storage total unavailable.</div> 852 767 {{ end }} 853 768 854 769 - size: small