From 724dee55c5402ca38bbba998755de84be70b6eed Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 6 Sep 2026 15:35:06 +0200 Subject: [PATCH] fix(weather): handle disabled external connections (#6780) --- .../docs/advanced/environment-variables/index.mdx | 2 +- apps/docs/docs/widgets/weather/index.mdx | 5 +++-- packages/api/src/router/location.ts | 3 +++ packages/translation/src/lang/en.json | 1 + packages/widgets/src/weather/component.tsx | 15 ++++++++++++--- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/apps/docs/docs/advanced/environment-variables/index.mdx b/apps/docs/docs/advanced/environment-variables/index.mdx index d9aa03901..d81c57160 100644 --- a/apps/docs/docs/advanced/environment-variables/index.mdx +++ b/apps/docs/docs/advanced/environment-variables/index.mdx @@ -31,7 +31,7 @@ Using the `PUID` and `PGID` will require you to set the correct permissions on t | `PGID` | Group ID to run the container as | Any valid group ID | `0` | | `LOG_LEVEL` | Log level to use | `debug` / `info` / `warn` / `error` | `info` | | `BASE_URL` | Public Homarr origin used by MCP OAuth metadata and redirects. Set this when a reverse proxy does not preserve the public host and protocol. | HTTP(S) origin without a path | - | -| `NO_EXTERNAL_CONNECTION` | Disables Homarr's internet-backed requests, including update checks, weather, and RSS feeds | `true` or `false` | `false` | +| `NO_EXTERNAL_CONNECTION` | Disables Homarr's internet-backed requests, including update checks, weather, location search, and RSS feeds | `true` or `false` | `false` | | `ENABLE_DNS_CACHING` | Enables dns caching. Enabled by default, but if you experience issues with IPv6 or static IPs, see [#4006](https://github.com/homarr-labs/homarr/issues/4006) or disable this flag | `true` or `false` | `true` | | `HOMARR_DISABLE_IPV6` | Disables the IPv6 listener of the internal nginx proxy, even when the host supports IPv6. IPv6 is normally disabled automatically when the host has no IPv6 configured. See [#4596](https://github.com/homarr-labs/homarr/issues/4596) | `true` or `false` | `false` | | `HOMARR_WEBSITE_URL` | Main Homarr documentation/site base used by runtime links. Must be an absolute HTTP(S) URL. | HTTP(S) URL | `https://homarr.dev` | diff --git a/apps/docs/docs/widgets/weather/index.mdx b/apps/docs/docs/widgets/weather/index.mdx index 931cb87b6..1ec1cabcd 100644 --- a/apps/docs/docs/widgets/weather/index.mdx +++ b/apps/docs/docs/widgets/weather/index.mdx @@ -31,5 +31,6 @@ adds hourly temperature and precipitation charts and the complete seven-day fore Weather and location data come from Open-Meteo. Active weather refreshes every ten minutes; identical location requests can reuse a server response for five minutes. Failed refreshes keep the last successful data with an error indicator. -Set `NO_EXTERNAL_CONNECTION=true` to disable this and other internet-backed requests. Allowlist -`https://open-meteo.com` when outbound access is restricted. +Set `NO_EXTERNAL_CONNECTION=true` to disable this and other internet-backed requests. Weather data and the city search +inside the widget configuration are unavailable while it is enabled. Allowlist `https://open-meteo.com` when outbound +access is restricted. diff --git a/packages/api/src/router/location.ts b/packages/api/src/router/location.ts index 050d66cb4..c5687a0be 100644 --- a/packages/api/src/router/location.ts +++ b/packages/api/src/router/location.ts @@ -1,5 +1,6 @@ import { z } from "zod/v4"; +import { env } from "@homarr/common/env"; import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http"; import { withTimeoutAsync } from "@homarr/core/infrastructure/http/timeout"; @@ -37,6 +38,8 @@ export const locationRouter = createTRPCRouter({ .input(locationSearchCityInput) .output(locationSearchCityOutput) .query(async ({ input }) => { + if (env.NO_EXTERNAL_CONNECTION) return { results: [] }; + const url = new URL("https://geocoding-api.open-meteo.com/v1/search"); url.searchParams.set("name", input.query); const res = await withTimeoutAsync(async (signal) => { diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index a4f0fd69e..3ef6ed947 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -3125,6 +3125,7 @@ } }, "currentWindSpeed": "{currentWindSpeed} {unit}", + "disabled": "Weather data is unavailable because outbound connections are disabled", "dailyForecast": { "sunrise": "Sunrise", "sunset": "Sunset", diff --git a/packages/widgets/src/weather/component.tsx b/packages/widgets/src/weather/component.tsx index 9b47565d2..d78a0ce3a 100644 --- a/packages/widgets/src/weather/component.tsx +++ b/packages/widgets/src/weather/component.tsx @@ -1,10 +1,10 @@ "use client"; -import { Box } from "@mantine/core"; +import { Box, Center, Text } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; +import { useI18n } from "@homarr/translation/client"; -import { WidgetEmptyState } from "../common/empty-state"; import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state"; import { WidgetQueryLoadingState } from "../common/query-state-indicator"; import type { WidgetComponentProps } from "../definition"; @@ -19,6 +19,7 @@ export default function WeatherWidget({ height, displayMode, }: WidgetComponentProps<"weather">) { + const t = useI18n("widget.weather"); const input = { latitude: options.location.latitude, longitude: options.location.longitude, @@ -27,7 +28,15 @@ export default function WeatherWidget({ const weather = getUsableWidgetQueryData(weatherQuery); if (isInitialWidgetQueryPending(weatherQuery)) return ; - if (!weather) return ; + if (!weather) { + return ( +
+ + {t("disabled")} + +
+ ); + } return (