feat(pm/umber): init grocy #144

merged
opened by a.starrysky.fyi targeting main from private/minion/push-zoqyltwplryx

Grocy is a stock tracking application for groceries. I'd like to use it to keep track of some of my stuff, so let's host it on umber!

Changed files
+61
packetmix
systems
+34
packetmix/systems/umber/grocy.nix
···
··· 1 + # SPDX-FileCopyrightText: 2025 FreshlyBakedCake 2 + # 3 + # SPDX-License-Identifier: MIT 4 + 5 + { pkgs, lib, ... }: 6 + { 7 + services.grocy = { 8 + enable = true; 9 + package = pkgs.stdenv.mkDerivation { 10 + name = "grocy-custom-js"; 11 + src = pkgs.grocy; 12 + 13 + dontBuild = true; 14 + installPhase = '' 15 + mkdir -p $out/ 16 + cp -r * $out/ 17 + 18 + mkdir -p $out/data/ 19 + cp ${./grocy/custom_js.html} $out/data/custom_js.html # we need to specify the filename explicitly, as otherwise this'll have a hash 20 + ''; 21 + }; 22 + hostName = "grocy.starrysky.fyi"; 23 + 24 + settings.currency = "GBP"; 25 + }; 26 + 27 + services.nginx.virtualHosts."grocy.starrysky.fyi" = { 28 + acmeRoot = null; 29 + forceSSL = lib.mkForce false; 30 + onlySSL = true; 31 + }; 32 + 33 + clicks.storage.impermanence.persist.directories = [ "/var/lib/grocy" ]; 34 + }
+27
packetmix/systems/umber/grocy/custom_js.html
···
··· 1 + <!-- 2 + SPDX-FileCopyrightText: 2026 Freshly Baked Cake 3 + 4 + SPDX-License-Identifier: MIT 5 + --> 6 + 7 + <script> 8 + { 9 + const locationFilter = document.getElementById("location-filter"); 10 + let desiredLocation = GetUriParam("location"); 11 + if (locationFilter !== null && desiredLocation !== null) 12 + { 13 + if (locationFilter.selectedOptions.length === 0 || locationFilter.selectedOptions[0].value === "all") { 14 + // Don't trigger if we select a different option and refresh the page 15 + desiredLocation = desiredLocation.replaceAll("_", " ") // WikiText needs underscores to be spaces 16 + const option = locationFilter.querySelector(`option[value="${desiredLocation}"]`) 17 + ?? locationFilter.querySelector(`option[value^="${desiredLocation}"]`) 18 + ?? locationFilter.querySelector(`option[value*="${desiredLocation}"]`); 19 + // Search first for an exact match, then a match which starts with, then a match which contains 20 + if (option) { 21 + locationFilter.value = option.value; 22 + locationFilter.dispatchEvent(new Event('change')); 23 + } 24 + } 25 + } 26 + } 27 + </script>