From 1c09714c438402b5bf1d343585fc88625c7ddb36 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Tue, 25 Feb 2025 21:46:38 +0100 Subject: [PATCH 001/133] fix: make sure healthcheck dont use a proxy #394 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a5557c8..99ea180 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ COPY --from=build-stage --chown=${UID}:${GID} /app/dist/assets /www/default-asse USER ${UID}:${GID} HEALTHCHECK --start-period=10s --start-interval=1s --interval=30s --timeout=5s --retries=3 \ - CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1 + CMD wget --no-verbose -Y off --tries=1 --spider http://127.0.0.1:${PORT}/ || exit 1 EXPOSE ${PORT} From 36d753df58ee5aa67c79f559a3a282a1a9a4f42f Mon Sep 17 00:00:00 2001 From: tanasegabriel Date: Wed, 26 Feb 2025 18:03:30 +0000 Subject: [PATCH 002/133] Fix quicklinks conditional icon rendering --- src/components/services/Generic.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/services/Generic.vue b/src/components/services/Generic.vue index 9b67310..610ccbd 100644 --- a/src/components/services/Generic.vue +++ b/src/components/services/Generic.vue @@ -28,7 +28,7 @@ :target="link.target" rel="noreferrer" > - Date: Thu, 27 Feb 2025 13:50:36 +0100 Subject: [PATCH 003/133] fix(search): Allow usage of the hotkey in the text --- src/components/SearchInput.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/SearchInput.vue b/src/components/SearchInput.vue index 8a31884..22e540e 100644 --- a/src/components/SearchInput.vue +++ b/src/components/SearchInput.vue @@ -29,7 +29,7 @@ export default { emits: ["search-open", "search-focus", "search-cancel", "input"], mounted() { this._keyListener = function (event) { - if (event.key === this.hotkey) { + if (!this.hasFocus() && event.key === this.hotkey) { event.preventDefault(); this.focus(); } @@ -63,6 +63,9 @@ export default { this.$refs.search.focus(); }); }, + hasFocus: function () { + return document.activeElement == this.$refs.search + }, setSearchURL: function (value) { const url = new URL(window.location); if (value === "") { From 13fb05696a9a958acd5890dac381c2d4bb494b37 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Fri, 28 Feb 2025 19:21:32 +0100 Subject: [PATCH 004/133] feat(logs): get lighthttpd accesslog in docker logs --- entrypoint.sh | 1 + lighttpd.conf | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/entrypoint.sh b/entrypoint.sh index f7effc9..2998611 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -14,4 +14,5 @@ if [[ "${INIT_ASSETS}" == "1" ]] && [[ ! -f "/www/assets/config.yml" ]]; then fi echo "Starting webserver" +exec 3>&1 exec lighttpd -D -f /lighttpd.conf diff --git a/lighttpd.conf b/lighttpd.conf index a6e9ff5..2965450 100644 --- a/lighttpd.conf +++ b/lighttpd.conf @@ -2,7 +2,7 @@ include "/etc/lighttpd/mime-types.conf" include_shell "/etc/lighttpd/ipv6.sh" server.port = env.PORT -server.modules = ( "mod_alias" ) +server.modules = ( "mod_alias", "mod_accesslog" ) server.username = "lighttpd" server.groupname = "lighttpd" server.document-root = "/www" @@ -10,3 +10,5 @@ alias.url = ( env.SUBFOLDER => "/www" ) server.indexfiles = ("index.html") server.follow-symlink = "enable" server.feature-flags += ( "server.clock-jump-restart" => 0 ) +server.max-request-field-size = 65535 +accesslog.filename = "/dev/fd/3" From 20fb0c2254bf53e2df1332afaf68b8a72baf6958 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sat, 1 Mar 2025 09:24:44 +0100 Subject: [PATCH 005/133] fix(cards): Avoid lowercase letters cut off #794 --- src/assets/components/base.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/assets/components/base.scss b/src/assets/components/base.scss index 6d5c1d4..541a003 100644 --- a/src/assets/components/base.scss +++ b/src/assets/components/base.scss @@ -4,7 +4,7 @@ @mixin ellipsis() { white-space: nowrap; - overflow: hidden; + overflow-x: hidden; text-overflow: ellipsis; } @@ -171,9 +171,9 @@ .title { font-size: 1.1em; - line-height: 1.2em; + line-height: 1.3em; font-weight: 500; - margin-bottom: 4px; + margin-bottom: 3px; @include ellipsis(); } From 12a004a9e160f880d9bcd1133512cef72a5e5d36 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sat, 1 Mar 2025 09:25:49 +0100 Subject: [PATCH 006/133] chore: Set official config --- eslint.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index d406376..7d5f195 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -18,6 +18,6 @@ export default [ }, }, { - ignores: ["*.d.ts", "**/coverage", "**/dist"], + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], }, ]; From 2a0387f90e781c2c6ae85736269e8a4a152f52ab Mon Sep 17 00:00:00 2001 From: Molham Al Nasr Date: Fri, 28 Feb 2025 10:09:14 +0100 Subject: [PATCH 007/133] fix(Dockerfile): ensure VERSION_TAG is correctly passed as a build argument The VERSION_TAG label was not correctly set in the built image due to a missing ARG definition in the Dockerfile. This commit adds ARG VERSION_TAG so that the build argument can be properly passed and used in image labels. Fixes #881 --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 99ea180..d0fe3ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,8 @@ RUN pnpm build # production stage FROM alpine:3.21 +ARG VERSION_TAG + LABEL \ org.label-schema.schema-version="1.0" \ org.label-schema.version="$VERSION_TAG" \ From a8f7d09bd4e1618ff7bc84feb206bb41a819167e Mon Sep 17 00:00:00 2001 From: Molham Al Nasr Date: Fri, 28 Feb 2025 12:17:01 +0100 Subject: [PATCH 008/133] fix(Dockerfile): add default value for ARG VERSION_TAG to prevent build errors Added a default value `latest` to the ARG VERSION_TAG in the Dockerfile. This ensures that the build does not fail when the VERSION_TAG argument is not explicitly provided, making manual builds more reliable. Fixes #881 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d0fe3ec..1a55d92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ RUN pnpm build # production stage FROM alpine:3.21 -ARG VERSION_TAG +ARG VERSION_TAG=latest LABEL \ org.label-schema.schema-version="1.0" \ From 4bd449e036a22a725ff7236fc5b1d7e39ee0238c Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sat, 1 Mar 2025 09:53:14 +0100 Subject: [PATCH 009/133] fix(navbar): Adjust icon spacing #857 --- src/components/Navbar.vue | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/Navbar.vue b/src/components/Navbar.vue index d361230..7cf6f56 100644 --- a/src/components/Navbar.vue +++ b/src/components/Navbar.vue @@ -26,10 +26,7 @@ :href="link.url" :target="link.target" > - + {{ link.name }} @@ -65,3 +62,11 @@ export default { }, }; + + From 60a45191b9c759f0232217c3854ac5a266aa1dd5 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sat, 1 Mar 2025 09:56:26 +0100 Subject: [PATCH 010/133] Release 25.03.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f7edac0..7a79148 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homer", - "version": "25.02.2", + "version": "25.03.1", "type": "module", "scripts": { "dev": "vite", From 11934c3995ecd52e304f9627fc078c95e9780204 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Tue, 4 Mar 2025 21:24:20 +0100 Subject: [PATCH 011/133] fix: hide overflow to avoid scroll bars in cards #885 --- src/assets/components/base.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/components/base.scss b/src/assets/components/base.scss index 541a003..87c7455 100644 --- a/src/assets/components/base.scss +++ b/src/assets/components/base.scss @@ -4,7 +4,7 @@ @mixin ellipsis() { white-space: nowrap; - overflow-x: hidden; + overflow: hidden; text-overflow: ellipsis; } From 7dfb3b8faf74cbbfe1d0960f3bb4b05090264fc2 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Tue, 4 Mar 2025 21:27:53 +0100 Subject: [PATCH 012/133] release 25.03.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a79148..a06b6f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homer", - "version": "25.03.1", + "version": "25.03.2", "type": "module", "scripts": { "dev": "vite", From c546fc160579990d540b5d942962227c0bef968b Mon Sep 17 00:00:00 2001 From: Cees Bos Date: Fri, 28 Feb 2025 16:13:28 +0100 Subject: [PATCH 013/133] Add YAML config schema for auto complete support --- .schema/config-schema.json | 353 +++++++++++++++++++++++++++++++++++++ docs/tips-and-tricks.md | 15 ++ 2 files changed, 368 insertions(+) create mode 100644 .schema/config-schema.json diff --git a/.schema/config-schema.json b/.schema/config-schema.json new file mode 100644 index 0000000..ddf0bec --- /dev/null +++ b/.schema/config-schema.json @@ -0,0 +1,353 @@ +{ + "$id": "https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json", + "$schema": "http://json-schema.org/draft-07/schema", + "description": "https://github.com/bastienwirtz/homer/blob/main/docs/configuration.md", + "examples": [], + "title": "Homer Dashboard configuration", + "type": "object", + "definitions": { + "Colors": { + "type": "object", + "additionalProperties": false, + "properties": { + "light": { + "$ref": "#/definitions/ColorSet" + }, + "dark": { + "$ref": "#/definitions/ColorSet" + } + }, + "title": "Colors" + }, + "ColorSet": { + "type": "object", + "additionalProperties": false, + "properties": { + "highlight-primary": { + "type": "string" + }, + "highlight-secondary": { + "type": "string" + }, + "highlight-hover": { + "type": "string" + }, + "background": { + "type": "string" + }, + "card-background": { + "type": "string" + }, + "text": { + "type": "string" + }, + "text-header": { + "type": "string" + }, + "text-title": { + "type": "string" + }, + "text-subtitle": { + "type": "string" + }, + "card-shadow": { + "type": "string" + }, + "link": { + "type": "string" + }, + "link-hover": { + "type": "string" + }, + "background-image": { + "type": "string" + } + } + }, + "Defaults": { + "type": "object", + "additionalProperties": false, + "properties": { + "layout": { + "enum": [ + "colums", + "list" + ], + "description": "Layout of the dashboard, either 'column' or 'list'" + }, + "colorTheme": { + "enum": [ + "auto", + "light", + "dark" + ], + "description": "One of 'auto', 'light', or 'dark'" + } + }, + "title": "Defaults" + }, + "Hotkey": { + "type": "object", + "additionalProperties": false, + "properties": { + "search": { + "type": "string", + "description": "hotkey for search, e.g. Shift" + } + }, + "required": [ + "search" + ] + }, + "Link": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name as soon in the navbar" + }, + "icon": { + "type": "string", + "description": "Fontawesome icon" + }, + "url": { + "type": "string", + "description": "Url of the link. When #filename is used, it is a link to another homer page, while 'filename' is the name of the config file" + }, + "target": { + "type": "string", + "description": "html tag target attribute like _blank for a new page" + } + }, + "required": [ + "name", + "url" + ], + "title": "Link" + }, + "Message": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "mapping": { + "$ref": "#/definitions/Mapping", + "description": "Mapping for the content loaded from the URL" + }, + "refreshInterval": { + "type": "integer", + "description": "The refresh interval in milliseconds for reloading the message url" + }, + "style": { + "type": "string", + "description": "See https://bulma.io/documentation/components/message/#colors for styling options" + }, + "title": { + "type": "string", + "description": "Title of the message box" + }, + "icon": { + "type": "string", + "description": "Fontawesome icon for the message box" + }, + "content": { + "type": "string", + "description": "HTML content for the message box" + } + }, + "title": "Messagebox" + }, + "Mapping": { + "type": "object", + "additionalProperties": true, + "title": "Mapping" + }, + "Proxy": { + "type": "object", + "additionalProperties": false, + "properties": { + "useCredentials": { + "type": "boolean", + "description": "# send cookies & authorization headers when fetching service specific data. Set to `true` if you use an authentication proxy. Can be overrided on service level. " + }, + "headers": { + "$ref": "#/definitions/Headers", + "description": "send custom headers when fetching service specific data. Can also be set on a service level." + } + }, + "title": "Proxy" + }, + "Headers": { + "type": "object", + "additionalProperties": true, + "title": "Headers" + }, + "Service": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Service name" + }, + "icon": { + "type": "string", + "description": "Fontawesome icon for the service" + }, + "logo": { + "type": "string", + "description": "A path to an image can also be provided. Note that icon take precedence if both icon and logo are set." + }, + "class": { + "type": "string", + "description": "Optional css class to add on the service group. Example 'highlight-purple'" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Item" + } + } + }, + "required": [ + "items" + ], + "title": "Service" + }, + "Item": { + "type": "object", + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + }, + "logo": { + "type": "string", + "description": "Path to a logo. Alternatively a fa icon can be provided" + }, + "icon": { + "type": "string", + "description": "Fontawesome icon for the item, alternative for logo" + }, + "subtitle": { + "type": "string" + }, + "tag": { + "type": "string", + "description": "Show tag" + }, + "keywords": { + "type": "string", + "description": "Optional keyword used for searching purpose" + }, + "url": { + "type": "string", + "description": "Url of this item" + }, + "target": { + "type": "string", + "description": "html tag target attribute like _blank for a new page" + }, + "tagstyle": { + "type": "string", + "description": "Styleclass for the tag" + }, + "type": { + "type": "string", + "description": "Optional, loads a specific component that provides extra features. MUST MATCH a file name (without file extension) available in `src/components/services`" + } + }, + "title": "Item" + } + }, + "properties": { + "externalConfig": { + "type": "string", + "description": "Use external configuration file. Using this will ignore remaining config in this file externalConfig: https://example.com/server-luci/config.yaml" + }, + "title": { + "type": "string", + "description": "Title of the dashboard" + }, + "subtitle": { + "type": "string", + "description": "Subtitle of the dashboard" + }, + "documentTitle": { + "type": "string", + "description": "Title of the document. When not filled, title (and subtitle will be used)" + }, + "logo": { + "type": "string", + "description": "Path to logo image" + }, + "icon": { + "type": "string", + "description": "Dashboard icon" + }, + "header": { + "type": "boolean", + "description": "Show header, default is true" + }, + "hotkey": { + "$ref": "#/definitions/Hotkey", + "description": "Define hotkeys, for example for search" + }, + "footer": { + "type": "string", + "description": "HTML shown as footer" + }, + "columns": { + "type": "string", + "description": "'auto' or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)", + "format": "integer" + }, + "connectivityCheck": { + "type": "boolean", + "description": "# whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example). You should set it to true when using an authentication proxy, it also reloads the page when a redirection is detected when checking connectivity." + }, + "proxy": { + "$ref": "#/definitions/Proxy", + "description": "Optional: Proxy / hosting option" + }, + "defaults": { + "$ref": "#/definitions/Defaults" + }, + "theme": { + "type": "string", + "description": "'default' or one of the themes available in 'src/assets/themes'" + }, + "stylesheet": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Will load custom CSS files. Especially useful for custom icon sets. Entries are paths to the stylesheets" + }, + "colors": { + "$ref": "#/definitions/Colors" + }, + "message": { + "$ref": "#/definitions/Message", + "description": "Messagebox" + }, + "links": { + "description": "Links in the navigation bar", + "type": "array", + "items": { + "$ref": "#/definitions/Link" + } + }, + "services": { + "description": "Services", + "type": "array", + "items": { + "$ref": "#/definitions/Service" + } + } + } +} diff --git a/docs/tips-and-tricks.md b/docs/tips-and-tricks.md index 8317ecd..437b586 100644 --- a/docs/tips-and-tricks.md +++ b/docs/tips-and-tricks.md @@ -78,6 +78,21 @@ Then when Homer reads your config, it will substitute your anchors automatically The end result is that if you want to update the name or style of any particular tag, just update it once, in the tags section! Great if you have a lot of services or a lot of tags! +## YAML auto complete with a YAML schema + +A lot of editor support auto completion, see +The homer schema is available here: + +For example with IntelliJ you can define: + +```yaml +# $schema: https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json +``` +With VSCode you can define it like this: +```yaml +# yaml-language-server: $schema=https://raw.githubusercontent.com/bastienwirtz/homer/main/.schema/config-schema.json +``` + ## Remotely edit your config with Code Server #### `by @JamiePhonic` From 1b607b63571a5ca3e43e212185229c45cfd7c5c8 Mon Sep 17 00:00:00 2001 From: Cees Bos Date: Fri, 7 Mar 2025 16:34:58 +0100 Subject: [PATCH 014/133] Update schema based on review --- .schema/config-schema.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.schema/config-schema.json b/.schema/config-schema.json index ddf0bec..eaea0b7 100644 --- a/.schema/config-schema.json +++ b/.schema/config-schema.json @@ -105,7 +105,7 @@ "properties": { "name": { "type": "string", - "description": "Name as soon in the navbar" + "description": "Name as seen in the navbar" }, "icon": { "type": "string", @@ -121,7 +121,6 @@ } }, "required": [ - "name", "url" ], "title": "Link" @@ -298,8 +297,15 @@ "description": "Define hotkeys, for example for search" }, "footer": { - "type": "string", - "description": "HTML shown as footer" + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string" + } + ], + "description": "footer Line content. HTML is supported. Set false if you want to hide it." }, "columns": { "type": "string", From c812bda08f4e90499587867fcf698559f51e7707 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Mon, 17 Mar 2025 21:47:21 +0100 Subject: [PATCH 015/133] fix(docker): disable log for healthcheck requests --- lighttpd.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lighttpd.conf b/lighttpd.conf index 2965450..e892bb9 100644 --- a/lighttpd.conf +++ b/lighttpd.conf @@ -12,3 +12,7 @@ server.follow-symlink = "enable" server.feature-flags += ( "server.clock-jump-restart" => 0 ) server.max-request-field-size = 65535 accesslog.filename = "/dev/fd/3" + +# Avoid logging docker healthcheck request +$HTTP["remote-ip"] == "127.0.0.1" { accesslog.filename = "" } +$HTTP["remote-ip"] == "[::1]" { accesslog.filename = "" } From 76e6c7069605542b63987a3bc4fa434a74809969 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Mon, 17 Mar 2025 21:54:56 +0100 Subject: [PATCH 016/133] release 25.03.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a06b6f9..50bb9f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homer", - "version": "25.03.2", + "version": "25.03.3", "type": "module", "scripts": { "dev": "vite", From 50acb9957e81f75bb28747ad1434132c3c5cb752 Mon Sep 17 00:00:00 2001 From: Cees Bos Date: Wed, 19 Mar 2025 22:25:34 +0100 Subject: [PATCH 017/133] Add Linkding support --- docs/customservices.md | 22 +++++++++ src/components/services/Linkding.vue | 68 ++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/components/services/Linkding.vue diff --git a/docs/customservices.md b/docs/customservices.md index 7ddaaaa..8274546 100644 --- a/docs/customservices.md +++ b/docs/customservices.md @@ -25,6 +25,7 @@ within Homer: - [Immich](#immich) - [Jellystat](#jellystat) - [Lidarr, Prowlarr, Sonarr, Readarr and Radarr](#lidarr-prowlarr-sonarr-readarr-and-radarr) +- [Linkding](#linkding) - [Mealie](#mealie) - [Medusa](#medusa) - [Nextcloud](#nextcloud) @@ -276,6 +277,27 @@ If you are using an older version of Radarr or Sonarr which don't support the ne legacyApi: true ``` +## Linkding + +This integration makes it possible to query Linkding and list multiple results from Linkding. +Linkding has to be configured with CORS enabled. Linkding does not support that, but a reverse proxy in front can fix that. +For example if you use Traefik, documentation about that is here: https://doc.traefik.io/traefik/middlewares/http/headers/#cors-headers +Examples for various servers can be found at https://enable-cors.org/server.html. + +This integration supports at max 15 results from Linkding. But you can add it multiple times to you dashboard with different queries to retrieve what you need. + +```yaml + - name: "Linkding" + # Url to Linkding instance + url: https://ld.ceesbos.nl + token: "" + type: "Linkding" + # Maximum number of items returned by Linkding, minimal 1 and max 15 + limit: 10 + # query to do on Linkding. User #tagname to search for tags + query: "#ToDo #Homer" +``` + ## Mealie First off make sure to remove an existing `subtitle` as it will take precedence if set. diff --git a/src/components/services/Linkding.vue b/src/components/services/Linkding.vue new file mode 100644 index 0000000..840650a --- /dev/null +++ b/src/components/services/Linkding.vue @@ -0,0 +1,68 @@ + + + \ No newline at end of file From 37716c8d423aa8351423c5ab5f1d677c01f99ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20B=C3=A9langer?= <56379077+mbelangergit@users.noreply.github.com> Date: Wed, 19 Mar 2025 19:40:21 -0400 Subject: [PATCH 018/133] Fix typos in config-schema.json --- .schema/config-schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.schema/config-schema.json b/.schema/config-schema.json index eaea0b7..f751668 100644 --- a/.schema/config-schema.json +++ b/.schema/config-schema.json @@ -70,10 +70,10 @@ "properties": { "layout": { "enum": [ - "colums", + "columns", "list" ], - "description": "Layout of the dashboard, either 'column' or 'list'" + "description": "Layout of the dashboard, either 'columns' or 'list'" }, "colorTheme": { "enum": [ From e1fdb0069b67490553f99dfddb06dfb7bbc0f1d9 Mon Sep 17 00:00:00 2001 From: Cees Bos Date: Thu, 20 Mar 2025 18:27:59 +0100 Subject: [PATCH 019/133] Fix issues in Linkding integration revealed by code check in the pipeline --- src/components/services/Linkding.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/services/Linkding.vue b/src/components/services/Linkding.vue index 840650a..97aab9a 100644 --- a/src/components/services/Linkding.vue +++ b/src/components/services/Linkding.vue @@ -1,5 +1,5 @@ From 28ad80369ff4733d448cdf8bcb08010f3979b0f8 Mon Sep 17 00:00:00 2001 From: Molham Date: Sat, 19 Apr 2025 14:19:28 +0200 Subject: [PATCH 054/133] add support to dynamic interval time for polling the status --- docs/customservices.md | 3 ++- src/components/services/PiHole.vue | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/customservices.md b/docs/customservices.md index fc6d318..ac77ba3 100644 --- a/docs/customservices.md +++ b/docs/customservices.md @@ -468,10 +468,11 @@ The following configuration is available for the PiHole service. - name: "Pi-hole" logo: "assets/tools/sample.png" # subtitle: "Network-wide Ad Blocking" # optional, if no subtitle is defined, PiHole statistics will be shown - url: "http://192.168.0.151/admin" + url: "http://192.168.0.151/admin" # For v6 API, do not include /admin in the URL apikey: "<---insert-api-key-here--->" # optional, needed if web interface is password protected type: "PiHole" apiVersion: 5 # optional, defaults to 5. Use 6 if your PiHole instance uses API v6 + checkInterval: 3000 # optional, defaults to 300000. interval in ms to check Pi-hole status ``` **Remarks:** diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 004f382..9a20d42 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -68,8 +68,12 @@ export default { methods: { startStatusPolling: function () { this.fetchStatus(); - // Poll every 5 minutes - this.pollInterval = setInterval(this.fetchStatus, 300000); + // Set the interval to the checkInterval or default to 5 minutes + const interval = parseInt(this.item.checkInterval, 10) || 300000; + if (this.item.checkInterval < 1000) { + this.item.checkInterval = 1000; + } + this.pollInterval = setInterval(this.fetchStatus, interval); }, stopStatusPolling: function () { if (this.pollInterval) { From 4684b23a8c46a49c27960c00ee3b1f3583d1b63f Mon Sep 17 00:00:00 2001 From: Molham Date: Sat, 19 Apr 2025 14:46:18 +0200 Subject: [PATCH 055/133] better handle errors and set the subtitle as a message holder for errors --- src/components/services/PiHole.vue | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 9a20d42..a2b1ccf 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -42,7 +42,7 @@ export default { }), computed: { percentage: function () { - if (this.percent_blocked) { + if (typeof this.percent_blocked === 'number' && this.percent_blocked >= 0) { return this.percent_blocked.toFixed(1); } return ""; @@ -66,6 +66,11 @@ export default { } }, methods: { + handleError: function (error, status) { + console.error(error); + this.subtitle = error; + this.status = status; + }, startStatusPolling: function () { this.fetchStatus(); // Set the interval to the checkInterval or default to 5 minutes @@ -93,7 +98,7 @@ export default { } } } catch (e) { - console.error("Failed to load cached session:", e); + this.handleError(`Failed to load cached session: ${e}`, "error"); this.removeCacheSession(); } }, @@ -110,15 +115,14 @@ export default { method: 'DELETE' }); } catch (e) { - console.error("Failed to delete session:", e); + this.handleError(`Failed to delete session: ${e}`, "error"); } finally { this.removeCacheSession(); } }, authenticate: async function () { if (!this.item.apikey) { - console.error("API key is required for PiHole authentication"); - this.status = "disabled"; + this.handleError("API key is required for PiHole authentication", "disabled"); return false; } @@ -145,8 +149,7 @@ export default { } throw new Error("Invalid authentication response"); } catch (e) { - console.error("Authentication failed:", e); - this.status = "disabled"; + this.handleError(`Authentication failed: ${e}`, "disabled"); return false; } }, @@ -184,12 +187,11 @@ export default { throw new Error(`HTTP error: ${response.status}`); } } catch (e) { - console.error("Failed to fetch status:", e); - if (e.message.includes("HTTP error: 401") || e.message.includes("HTTP error: 403")) { + if (e.includes("HTTP error: 401") || e.includes("HTTP error: 403")) { this.removeCacheSession(); return this.retryWithDelay(); } - this.status = "disabled"; + this.handleError(`Failed to fetch status: ${e}`, "disabled"); this.removeCacheSession(); } }, @@ -214,8 +216,7 @@ export default { throw new Error(`HTTP error: ${response.status}`); } } catch (e) { - console.error("Failed to fetch v5 status:", e); - this.status = "error"; + this.handleError(`Failed to fetch v5 status: ${e}`, "error"); } }, } From 59b0ed76885fc07733e9cdb0814b9d3b25c0f69f Mon Sep 17 00:00:00 2001 From: Molham Date: Sat, 19 Apr 2025 14:48:10 +0200 Subject: [PATCH 056/133] set this.status after checking the response is OK --- src/components/services/PiHole.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index a2b1ccf..353ccd0 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -170,11 +170,11 @@ export default { const url = `${this.endpoint}/${`api/stats/summary?sid=${encodeURIComponent(this.sessionId)}`.replace(/^\/+/, '')}`; const response = await fetch(url); - this.status = "enabled"; if (response.ok) { const result = await response.json(); if (result?.queries?.percent_blocked !== undefined) { + this.status = "enabled"; this.percent_blocked = result.queries.percent_blocked; this.retryCount = 0; } else { From 07207dca5521c7ff51982cfb3db22409b5439890 Mon Sep 17 00:00:00 2001 From: Molham Date: Sat, 19 Apr 2025 15:19:08 +0200 Subject: [PATCH 057/133] reset the api_v5 function to fetch the remote api with this.fetch --- src/components/services/PiHole.vue | 37 ++++++++++-------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 353ccd0..bb9afc0 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -42,7 +42,7 @@ export default { }), computed: { percentage: function () { - if (typeof this.percent_blocked === 'number' && this.percent_blocked >= 0) { + if (this.percent_blocked) { return this.percent_blocked.toFixed(1); } return ""; @@ -187,37 +187,24 @@ export default { throw new Error(`HTTP error: ${response.status}`); } } catch (e) { - if (e.includes("HTTP error: 401") || e.includes("HTTP error: 403")) { + if (e.message.includes("HTTP error: 401") || e.message.includes("HTTP error: 403")) { this.removeCacheSession(); return this.retryWithDelay(); } - this.handleError(`Failed to fetch status: ${e}`, "disabled"); + this.handleError(`Failed to fetch status: ${e.message || e}`, "disabled"); this.removeCacheSession(); } }, async fetchStatus_v5() { - try { - const params = {}; - if (this.item.apikey) { - params.auth = this.item.apikey; - } - const url = new URL(`${this.endpoint}/api.php`); - Object.keys(params).forEach(key => url.searchParams.append(key, params[key])); - - const response = await fetch(url); - this.status = response.status.toString(); - - if (response.ok) { - const result = await response.json(); - if (result?.ads_percentage_today !== undefined) { - this.percent_blocked = result.ads_percentage_today; - } - } else { - throw new Error(`HTTP error: ${response.status}`); - } - } catch (e) { - this.handleError(`Failed to fetch v5 status: ${e}`, "error"); - } + const authQueryParams = this.item.apikey + ? `?summaryRaw&auth=${this.item.apikey}` + : ""; + const result = await this.fetch(`/api.php${authQueryParams}`).catch((e) => + this.handleError(`Failed to fetch status: ${e}`, "disabled"), + ); + + this.status = result.status; + this.percent_blocked = result.ads_percentage_today; }, } }; From 9e314c960b2612163dd3320c347deebec4513e51 Mon Sep 17 00:00:00 2001 From: Molham Date: Sat, 19 Apr 2025 15:31:19 +0200 Subject: [PATCH 058/133] fix integration test --- src/components/services/PiHole.vue | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index bb9afc0..afbc5c6 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -39,6 +39,8 @@ export default { retryCount: 0, maxRetries: 3, retryDelay: 5000, + localCheckInterval: 1000, // Default value or a fallback + pollInterval: null, }), computed: { percentage: function () { @@ -53,6 +55,8 @@ export default { }, created() { if (parseInt(this.item.apiVersion, 10) === 6) { + // Set the interval to the checkInterval or default to 5 minutes + this.localCheckInterval = parseInt(this.item.checkInterval, 10) || 300000; this.loadCachedSession(); this.startStatusPolling(); } else { @@ -73,12 +77,10 @@ export default { }, startStatusPolling: function () { this.fetchStatus(); - // Set the interval to the checkInterval or default to 5 minutes - const interval = parseInt(this.item.checkInterval, 10) || 300000; - if (this.item.checkInterval < 1000) { - this.item.checkInterval = 1000; + if (this.localCheckInterval < 1000) { + this.localCheckInterval = 1000; } - this.pollInterval = setInterval(this.fetchStatus, interval); + this.pollInterval = setInterval(this.fetchStatus, this.localCheckInterval); }, stopStatusPolling: function () { if (this.pollInterval) { From ad76093a389f799f029acba3b1d94afb21c55193 Mon Sep 17 00:00:00 2001 From: Molham Date: Sat, 19 Apr 2025 21:10:44 +0200 Subject: [PATCH 059/133] modify service.js mixin to accept one more parameter and return full response and use this.fetch in PiHole.vue --- src/components/services/PiHole.vue | 10 +++++++--- src/mixins/service.js | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index afbc5c6..1703bf3 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -169,10 +169,14 @@ export default { const authenticated = await this.authenticate(); if (!authenticated) return; } + const options = { + method: "GET", + headers: { + 'Content-Type': 'application/json' + } + }; + const response = await this.fetch(`api/stats/summary?sid=${encodeURIComponent(this.sessionId)}`, options, false, true); - const url = `${this.endpoint}/${`api/stats/summary?sid=${encodeURIComponent(this.sessionId)}`.replace(/^\/+/, '')}`; - const response = await fetch(url); - if (response.ok) { const result = await response.json(); if (result?.queries?.percent_blocked !== undefined) { diff --git a/src/mixins/service.js b/src/mixins/service.js index d52fc29..f1e77bf 100644 --- a/src/mixins/service.js +++ b/src/mixins/service.js @@ -12,7 +12,7 @@ export default { } }, methods: { - fetch: function (path, init, json = true) { + fetch: function (path, init, json = true, returnFullResponse = false) { let options = {}; if (this.proxy?.useCredentials) { @@ -58,6 +58,10 @@ export default { ); } + if (returnFullResponse) { + return response; + } + return json ? response.json() : response.text(); }); }, From 42f3a3ee71e236f6a3871febbafd8a11a83fae85 Mon Sep 17 00:00:00 2001 From: Molham Date: Sun, 20 Apr 2025 00:58:37 +0200 Subject: [PATCH 060/133] reset the mixin service.js and make use of the actual error message from the current service.js --- src/components/services/PiHole.vue | 27 ++++++++++----------------- src/mixins/service.js | 6 +----- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 1703bf3..654cd86 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -44,7 +44,7 @@ export default { }), computed: { percentage: function () { - if (this.percent_blocked) { + if (this.percent_blocked >= 0) { return this.percent_blocked.toFixed(1); } return ""; @@ -156,6 +156,7 @@ export default { } }, retryWithDelay: async function () { + console.log("Retrying authentication..."); if (this.retryCount < this.maxRetries) { this.retryCount++; await new Promise(resolve => setTimeout(resolve, this.retryDelay)); @@ -175,25 +176,17 @@ export default { 'Content-Type': 'application/json' } }; - const response = await this.fetch(`api/stats/summary?sid=${encodeURIComponent(this.sessionId)}`, options, false, true); + const response = await this.fetch(`api/stats/summary?sid=${encodeURIComponent(this.sessionId)}`); - if (response.ok) { - const result = await response.json(); - if (result?.queries?.percent_blocked !== undefined) { - this.status = "enabled"; - this.percent_blocked = result.queries.percent_blocked; - this.retryCount = 0; - } else { - throw new Error("Invalid response format"); - } - } else if (response.status === 401) { - this.removeCacheSession(); - return this.retryWithDelay(); - } else { - throw new Error(`HTTP error: ${response.status}`); + if (response?.queries?.percent_blocked === undefined) { + throw new Error("Invalid response format"); } + + this.status = "enabled"; + this.percent_blocked = response.queries.percent_blocked; + this.retryCount = 0; } catch (e) { - if (e.message.includes("HTTP error: 401") || e.message.includes("HTTP error: 403")) { + if (e.message.includes("401 error") || e.message.includes("403 error")) { this.removeCacheSession(); return this.retryWithDelay(); } diff --git a/src/mixins/service.js b/src/mixins/service.js index f1e77bf..d52fc29 100644 --- a/src/mixins/service.js +++ b/src/mixins/service.js @@ -12,7 +12,7 @@ export default { } }, methods: { - fetch: function (path, init, json = true, returnFullResponse = false) { + fetch: function (path, init, json = true) { let options = {}; if (this.proxy?.useCredentials) { @@ -58,10 +58,6 @@ export default { ); } - if (returnFullResponse) { - return response; - } - return json ? response.json() : response.text(); }); }, From 15f59b9e36aae7abf72ba1bd075a7e7617795c66 Mon Sep 17 00:00:00 2001 From: Molham Date: Sun, 20 Apr 2025 01:02:27 +0200 Subject: [PATCH 061/133] delete unused object --- src/components/services/PiHole.vue | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 654cd86..55656e9 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -170,12 +170,6 @@ export default { const authenticated = await this.authenticate(); if (!authenticated) return; } - const options = { - method: "GET", - headers: { - 'Content-Type': 'application/json' - } - }; const response = await this.fetch(`api/stats/summary?sid=${encodeURIComponent(this.sessionId)}`); if (response?.queries?.percent_blocked === undefined) { From 347a3d062b08fcfd54fd9aefe75ab435375efdf5 Mon Sep 17 00:00:00 2001 From: Molham Date: Wed, 30 Apr 2025 13:59:01 +0200 Subject: [PATCH 062/133] remove deleteing the session over the API call when leaving the page --- src/components/services/PiHole.vue | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 55656e9..8ca67b8 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -66,7 +66,6 @@ export default { beforeDestroy() { if (parseInt(this.item.apiVersion, 10) === 6) { this.stopStatusPolling(); - this.deleteSession(); } }, methods: { @@ -109,19 +108,6 @@ export default { this.sessionId = null; this.sessionExpiry = null; }, - deleteSession: async function () { - if (!this.sessionId) return; - - try { - await this.fetch(`/api/auth/session/${encodeURIComponent(this.sessionId)}`, { - method: 'DELETE' - }); - } catch (e) { - this.handleError(`Failed to delete session: ${e}`, "error"); - } finally { - this.removeCacheSession(); - } - }, authenticate: async function () { if (!this.item.apikey) { this.handleError("API key is required for PiHole authentication", "disabled"); From acb304adeca43500c04be6c1e5e8465ea0ed3e88 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sun, 4 May 2025 14:15:57 +0200 Subject: [PATCH 063/133] deps update --- package.json | 8 ++++---- pnpm-lock.yaml | 38 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index cec7286..54584ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homer", - "version": "25.04.1", + "version": "25.05.1", "type": "module", "scripts": { "dev": "vite", @@ -11,10 +11,10 @@ }, "dependencies": { "@fortawesome/fontawesome-free": "^6.7.2", - "bulma": "^1.0.3", + "bulma": "^1.0.4", "lodash.merge": "^4.6.2", "vue": "^3.5.13", - "yaml": "^2.7.0" + "yaml": "^2.7.1" }, "devDependencies": { "@eslint/js": "^9.21.0", @@ -30,7 +30,7 @@ "vite-plugin-pwa": "^0.21.1" }, "license": "Apache-2.0", - "packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af", + "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39", "pnpm": { "neverBuiltDependencies": [] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24694e8..467bd5f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^6.7.2 version: 6.7.2 bulma: - specifier: ^1.0.3 - version: 1.0.3 + specifier: ^1.0.4 + version: 1.0.4 lodash.merge: specifier: ^4.6.2 version: 4.6.2 @@ -21,15 +21,15 @@ importers: specifier: ^3.5.13 version: 3.5.13 yaml: - specifier: ^2.7.0 - version: 2.7.0 + specifier: ^2.7.1 + version: 2.7.1 devDependencies: '@eslint/js': specifier: ^9.21.0 version: 9.21.0 '@vitejs/plugin-vue': specifier: ^5.2.1 - version: 5.2.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0))(vue@3.5.13) + version: 5.2.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1))(vue@3.5.13) '@vue/eslint-config-prettier': specifier: ^10.2.0 version: 10.2.0(eslint@9.21.0)(prettier@3.5.2) @@ -53,10 +53,10 @@ importers: version: 1.85.0 vite: specifier: ^6.1.6 - version: 6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0) + version: 6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1) vite-plugin-pwa: specifier: ^0.21.1 - version: 0.21.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0))(workbox-build@7.3.0)(workbox-window@7.3.0) + version: 0.21.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1))(workbox-build@7.3.0)(workbox-window@7.3.0) packages: @@ -1116,8 +1116,8 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - bulma@1.0.3: - resolution: {integrity: sha512-9eVXBrXwlU337XUXBjIIq7i88A+tRbJYAjXQjT/21lwam+5tpvKF0R7dCesre9N+HV9c6pzCNEPKrtgvBBes2g==} + bulma@1.0.4: + resolution: {integrity: sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g==} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} @@ -2523,8 +2523,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} engines: {node: '>= 14'} hasBin: true @@ -3480,9 +3480,9 @@ snapshots: '@types/trusted-types@2.0.7': {} - '@vitejs/plugin-vue@5.2.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0))(vue@3.5.13)': + '@vitejs/plugin-vue@5.2.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1))(vue@3.5.13)': dependencies: - vite: 6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0) + vite: 6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1) vue: 3.5.13 '@vue/compiler-core@3.5.13': @@ -3657,7 +3657,7 @@ snapshots: buffer-from@1.1.2: {} - bulma@1.0.3: {} + bulma@1.0.4: {} call-bind-apply-helpers@1.0.2: dependencies: @@ -4998,18 +4998,18 @@ snapshots: varint@6.0.0: {} - vite-plugin-pwa@0.21.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0))(workbox-build@7.3.0)(workbox-window@7.3.0): + vite-plugin-pwa@0.21.1(vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1))(workbox-build@7.3.0)(workbox-window@7.3.0): dependencies: debug: 4.4.0 pretty-bytes: 6.1.1 tinyglobby: 0.2.12 - vite: 6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0) + vite: 6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1) workbox-build: 7.3.0 workbox-window: 7.3.0 transitivePeerDependencies: - supports-color - vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.0): + vite@6.1.6(sass-embedded@1.85.0)(terser@5.39.0)(yaml@2.7.1): dependencies: esbuild: 0.24.2 postcss: 8.5.3 @@ -5018,7 +5018,7 @@ snapshots: fsevents: 2.3.3 sass-embedded: 1.85.0 terser: 5.39.0 - yaml: 2.7.0 + yaml: 2.7.1 vue-eslint-parser@9.4.3(eslint@9.21.0): dependencies: @@ -5219,6 +5219,6 @@ snapshots: yallist@3.1.1: {} - yaml@2.7.0: {} + yaml@2.7.1: {} yocto-queue@0.1.0: {} From a5eeb1e44e5bc550f81ef95b8dd8f44075e1b326 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sun, 4 May 2025 15:12:06 +0200 Subject: [PATCH 064/133] feat(smart-cards): handle dynamic loading error --- src/assets/components/base.scss | 4 ++++ src/components/Service.vue | 10 ++++++---- src/components/services/OpenWeather.vue | 12 ++++++++---- src/components/services/_error.vue | 22 ++++++++++++++++++++++ 4 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 src/components/services/_error.vue diff --git a/src/assets/components/base.scss b/src/assets/components/base.scss index 87c7455..b88211e 100644 --- a/src/assets/components/base.scss +++ b/src/assets/components/base.scss @@ -55,6 +55,10 @@ background-color: var(--card-background); } } + .component-error .card { + border: 1px solid rgba(255, 33, 33, 0.664); + background-color: rgba(255, 58, 58, 0.24); + } .message { .message-body { diff --git a/src/components/Service.vue b/src/components/Service.vue index 405bf10..f250aae 100644 --- a/src/components/Service.vue +++ b/src/components/Service.vue @@ -5,7 +5,7 @@ From 1afa0afd00428f320fa8dd5108d5caee51e4f245 Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Sun, 4 May 2025 15:15:12 +0200 Subject: [PATCH 065/133] chore(lint): Apply lint --- src/components/services/DockerSocketProxy.vue | 28 ++++++-- src/components/services/PiHole.vue | 68 ++++++++++++------ src/components/services/Plex.vue | 70 +++++++++++-------- src/components/services/SABnzbd.vue | 3 +- 4 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/components/services/DockerSocketProxy.vue b/src/components/services/DockerSocketProxy.vue index ab33709..444f11a 100644 --- a/src/components/services/DockerSocketProxy.vue +++ b/src/components/services/DockerSocketProxy.vue @@ -2,16 +2,28 @@