NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.22k stars 14.21k forks source link

homepage-dashboard: wrong layout order #357216

Open dafitt opened 7 hours ago

dafitt commented 7 hours ago

Describe the bug

services.homepage-dashboard.settings.layout = {
  "Services" = {
    icon = "mdi-tools";
    style = "row";
    columns = 1;
  };
  "Network" = {
    icon = "mdi-network";
    style = "row";
    columns = 4;
    useEqualHeights = true;
  };
};

When building with this config, the layout oder get's swapped and the /etc/homepage-dashboard/settings.yaml file will look like this:

...
layout:
  Network:
    columns: 4
    icon: mdi-network
    style: row
    useEqualHeights: true
  Services:
    columns: 1
    icon: mdi-tools
    style: row
...

When I view the attribute set config.services.homepage-dashboard.settings.layout with nix repl, it is already swapped, so i think nix is the culprit here.

The broken solution i tried

When I put the layout into a list/array, at first the correct order is established. But when i restart my system the website then seems to ignore the whole settings.yaml file: only the default layout, only the default theme, no background, ...

# now with a list:
services.homepage-dashboard.settings.layout = [
  {
    "Services" = {
      icon = "mdi-tools";
      style = "row";
      columns = 1;
    };
  }
  {
    "Network" = {
      icon = "mdi-network";
      style = "row";
      columns = 4;
      useEqualHeights = true;
    };
  }
];
...
layout:
- Services:
    columns: 1
    icon: mdi-tools
    style: row
- Network:
    columns: 4
    icon: mdi-network
    style: row
    useEqualHeights: true
...

Is the generated yaml file correct here? Shouldn't the bullet points - be indented -?

The website with this solution, after one system restart:

image

Expected behavior

It should look like this (layout):

image

Additional context

services.homepage-dashboard ```nix # https://gethomepage.dev/ services.homepage-dashboard = { enable = true; package = pkgs.homepage-dashboard.overrideAttrs (old: { postInstall = (old.postInstall or "") + '' install -Dm444 ${./background.webp} $out/share/homepage/public/images/background.webp # put background image in place ''; }); listenPort = 8080; openFirewall = true; # https://gethomepage.dev/configs/settings/ settings = { language = "de"; startUrl = "https://${hostConfig.networking.domain}"; base = "https://${hostConfig.networking.domain}"; target = "_blank"; color = "neutral"; # https://gethomepage.dev/configs/settings/#color-palette headerStyle = "boxed"; # underlined boxed clean boxedWidgets background = { image = "/images/background.webp"; opacity = 70; # 0-100 }; cardBlur = "xl"; # sm md xl iconStyle = "theme"; layout = let hostLayout = { icon = "mdi-server"; style = "row"; columns = 3; initiallyCollapsed = true; }; in [ { "Services" = { icon = "mdi-tools"; style = "row"; columns = 1; }; } { "Network" = { icon = "mdi-network"; style = "row"; columns = 4; useEqualHeights = true; }; } { "barebonej3160" = hostLayout; } { "minisforumhm80" = hostLayout; } ]; }; #bookmarks = [ ]; widgets = [ # Information Widgets # https://gethomepage.dev/widgets/info/ { logo.icon = ""; } { search = { provider = "custom"; url = "https://searx.${hostConfig.networking.domain}/search?q="; focus = true; target = "_blank"; }; } { datetime = { # https://gethomepage.dev/widgets/info/datetime/ text_size = "3xl"; format = { dateStyle = "medium"; timeStyle = "short"; hourCycle = "h23"; }; }; } { openmeteo = { label = "Palling"; latitude = "48.00"; longitude = "12.63"; units = "metric"; provider = "openweathermap"; cache = 5; }; } ]; services = let jointlyGlancesWidgetSettings = url: { type = "glances"; inherit url; refreshInterval = 5000; #TODO 24.11: version = "4"; }; hostWidgets = hostGlancesUrl: [ { "Information".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "info"; }; } { "Top Processes".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "process"; }; } { "Network Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "network:wan"; }; } { "CPU Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "cpu"; }; } { "Memory Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "memory"; chart = false; }; } { "Disk Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "fs:/"; chart = false; }; } ]; in [ # https://gethomepage.dev/configs/services/ # https://gethomepage.dev/configs/services/#icons { "Services" = [ { "Bitwarden" = { description = "A secure and convenient password manager."; icon = "si-bitwarden"; href = "https://bitwarden.${hostConfig.networking.domain}"; }; } { "Ntfy" = { description = "Send and receive push notifications to your phone or desktop via scripts or API."; icon = "si-ntfy"; href = "https://ntfy.${hostConfig.networking.domain}"; }; } { "Mail" = { description = "Roundcube Webmail."; icon = "si-roundcube"; href = "https://mail.${hostConfig.networking.domain}"; }; } { "Searx" = { description = "A internet metasearch engine which aggregates results from various search services and databases."; icon = "si-searxng"; href = "https://searx.${hostConfig.networking.domain}"; }; } { "Forgejo" = { description = "A self-hosted lightweight software forge (like github)."; icon = "si-forgejo"; href = "https://forgejo.${hostConfig.networking.domain}"; }; } ]; } { "Network" = [ { "Adguardhome" = { description = "Network-wide ads & trackers blocking DNS server."; icon = "si-adguard"; href = "https://adguardhome.${hostConfig.networking.domain}"; widget = { type = "adguard"; url = "http://[${hostConfig.schallernetz.servers."adguardhome".ip6Address}]"; username = "{{HOMEPAGE_VAR_ADGUARD_USER}}"; password = "{{HOMEPAGE_VAR_ADGUARD_PASSWORD}}"; }; }; } { "dode" = { description = "Our DNS provider 'Domain Offensive'."; icon = "mdi-domain"; href = "https://my.do.de"; }; } { "Uptime Kuma" = { description = "A fancy self-hosted monitoring tool."; icon = "si-uptimekuma"; href = "https://uptimekuma.${hostConfig.networking.domain}"; }; } ]; } { "barebonej3160" = (hostWidgets "http://barebonej3160.${hostConfig.networking.domain}:61209"); } { "minisforumhm80" = (hostWidgets "http://minisforumhm80.${hostConfig.networking.domain}:61209"); } ]; environmentFile = config.age.secrets."environmentFile".path; #` HOMEPAGE_VAR_XXX= }; ```

Metadata

Notify maintainers

@jnsgruk


Note for maintainers: Please tag this issue in your PR.


Add a :+1: reaction to issues you find important.

jnsgruk commented 7 hours ago

Hi, I think you're just nested one layer too deep? Try something like:

services.homepage-dashboard = {
  settings = {
    # Settings here
  };
  services = [
    {
      "Services" = {
        icon = "mdi-tools";
        style = "row";
        columns = 1;
      };
    }
    {
      "Network" = {
        icon = "mdi-network";
        style = "row";
        columns = 4;
        useEqualHeights = true;
      };
    }
  ];
};
dafitt commented 5 hours ago

Thank you @jnsgruk for your answer. But i think you misunderstood. I am really referring to services.homepage-dashboard.settings.layout (see https://gethomepage.dev/configs/settings/#layout) option.

I omitted services.homepage-dashboard.services since i thought it is irrelevant for the bug. But here my full services.homepage-dashboard including services.homepage-dashboard.services if its relevant:

services.homepage-dashboard
```nix # https://gethomepage.dev/ services.homepage-dashboard = { enable = true; package = pkgs.homepage-dashboard.overrideAttrs (old: { postInstall = (old.postInstall or "") + '' install -Dm444 ${./background.webp} $out/share/homepage/public/images/background.webp # put background image in place ''; }); listenPort = 8080; openFirewall = true; # https://gethomepage.dev/configs/settings/ settings = { language = "de"; startUrl = "https://${hostConfig.networking.domain}"; base = "https://${hostConfig.networking.domain}"; target = "_blank"; color = "neutral"; # https://gethomepage.dev/configs/settings/#color-palette headerStyle = "boxed"; # underlined boxed clean boxedWidgets background = { image = "/images/background.webp"; opacity = 70; # 0-100 }; cardBlur = "xl"; # sm md xl iconStyle = "theme"; layout = let hostLayout = { icon = "mdi-server"; style = "row"; columns = 3; initiallyCollapsed = true; }; in [ { "Services" = { icon = "mdi-tools"; style = "row"; columns = 1; }; } { "Network" = { icon = "mdi-network"; style = "row"; columns = 4; useEqualHeights = true; }; } { "barebonej3160" = hostLayout; } { "minisforumhm80" = hostLayout; } ]; }; #bookmarks = [ ]; widgets = [ # Information Widgets # https://gethomepage.dev/widgets/info/ { logo.icon = ""; } { search = { provider = "custom"; url = "https://searx.${hostConfig.networking.domain}/search?q="; focus = true; target = "_blank"; }; } { datetime = { # https://gethomepage.dev/widgets/info/datetime/ text_size = "3xl"; format = { dateStyle = "medium"; timeStyle = "short"; hourCycle = "h23"; }; }; } { openmeteo = { label = "Palling"; latitude = "48.00"; longitude = "12.63"; units = "metric"; provider = "openweathermap"; cache = 5; }; } ]; services = let jointlyGlancesWidgetSettings = url: { type = "glances"; inherit url; refreshInterval = 5000; #TODO 24.11: version = "4"; }; hostWidgets = hostGlancesUrl: [ { "Information".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "info"; }; } { "Top Processes".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "process"; }; } { "Network Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "network:wan"; }; } { "CPU Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "cpu"; }; } { "Memory Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "memory"; chart = false; }; } { "Disk Usage".widget = (jointlyGlancesWidgetSettings hostGlancesUrl) // { metric = "fs:/"; chart = false; }; } ]; in [ # https://gethomepage.dev/configs/services/ # https://gethomepage.dev/configs/services/#icons { "Services" = [ { "Bitwarden" = { description = "A secure and convenient password manager."; icon = "si-bitwarden"; href = "https://bitwarden.${hostConfig.networking.domain}"; }; } { "Ntfy" = { description = "Send and receive push notifications to your phone or desktop via scripts or API."; icon = "si-ntfy"; href = "https://ntfy.${hostConfig.networking.domain}"; }; } { "Mail" = { description = "Roundcube Webmail."; icon = "si-roundcube"; href = "https://mail.${hostConfig.networking.domain}"; }; } { "Searx" = { description = "A internet metasearch engine which aggregates results from various search services and databases."; icon = "si-searxng"; href = "https://searx.${hostConfig.networking.domain}"; }; } { "Forgejo" = { description = "A self-hosted lightweight software forge (like github)."; icon = "si-forgejo"; href = "https://forgejo.${hostConfig.networking.domain}"; }; } ]; } { "Network" = [ { "Adguardhome" = { description = "Network-wide ads & trackers blocking DNS server."; icon = "si-adguard"; href = "https://adguardhome.${hostConfig.networking.domain}"; widget = { type = "adguard"; url = "http://[${hostConfig.schallernetz.servers."adguardhome".ip6Address}]"; username = "{{HOMEPAGE_VAR_ADGUARD_USER}}"; password = "{{HOMEPAGE_VAR_ADGUARD_PASSWORD}}"; }; }; } { "dode" = { description = "Our DNS provider 'Domain Offensive'."; icon = "mdi-domain"; href = "https://my.do.de"; }; } { "Uptime Kuma" = { description = "A fancy self-hosted monitoring tool."; icon = "si-uptimekuma"; href = "https://uptimekuma.${hostConfig.networking.domain}"; }; } ]; } { "barebonej3160" = (hostWidgets "http://barebonej3160.${hostConfig.networking.domain}:61209"); } { "minisforumhm80" = (hostWidgets "http://minisforumhm80.${hostConfig.networking.domain}:61209"); } ]; environmentFile = config.age.secrets."environmentFile".path; #` HOMEPAGE_VAR_XXX= }; ```
jnsgruk commented 4 hours ago

Hmm, so reading through the docs, most of the layout examples show a map, rather than a list of maps like in your config.

What happens if you do something like this:

{
  settings = {
    # ...

    layout =
      let
        hostLayout = {
          icon = "mdi-server";
          style = "row";
          columns = 3;
          initiallyCollapsed = true;
        };
      in
      {
        "Services" = {
          icon = "mdi-tools";
          style = "row";
          columns = 1;
        };

        "Network" = {
          icon = "mdi-network";
          style = "row";
          columns = 4;
          useEqualHeights = true;
        };
        "barebonej3160" = hostLayout;
        "minisforumhm80" = hostLayout;
      };
  };
}
dafitt commented 2 hours ago

What happens if you do something like this:

Then "Services" and "Network" get swapped in the website (so "Network" is first).