From 5010ecf1886155537b47740928c2fdb78facbcd7 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Sun, 2 Aug 2026 17:34:52 +0200 Subject: [PATCH] fix: harden widget error feedback --- .../widgets/smart-home-entity-state/index.mdx | 1 + packages/translation/src/lang/en.json | 1 + packages/widgets/src/audio-stats/component.tsx | 16 +++++++++++----- .../src/smart-home/entity-state/component.tsx | 11 +++++++++-- .../widgets/src/smart-home/entity-state/index.ts | 8 +++++++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/apps/docs/docs/widgets/smart-home-entity-state/index.mdx b/apps/docs/docs/widgets/smart-home-entity-state/index.mdx index 28c83d3aa..9cd6d19a8 100644 --- a/apps/docs/docs/widgets/smart-home-entity-state/index.mdx +++ b/apps/docs/docs/widgets/smart-home-entity-state/index.mdx @@ -45,6 +45,7 @@ import temperature from "./img/temperature.png"; ### Interactions - Toggle entity state by clicking on the entity (only when clickable enabled). +- If Homarr cannot refresh an entity, the last known state stays visible but toggling is disabled until the connection recovers. diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 6012f83fb..e7e7e407a 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -2185,6 +2185,7 @@ } }, "error": { + "loadFailed": "Unable to load entity", "toggleFailed": "Unable to update entity" } }, diff --git a/packages/widgets/src/audio-stats/component.tsx b/packages/widgets/src/audio-stats/component.tsx index eb9adb1a5..2fdb6484e 100644 --- a/packages/widgets/src/audio-stats/component.tsx +++ b/packages/widgets/src/audio-stats/component.tsx @@ -1,6 +1,6 @@ "use client"; -import { Badge, Group, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core"; +import { Badge, Group, ScrollArea, SimpleGrid, Stack, Text, Tooltip } from "@mantine/core"; import { getQueryKey } from "@trpc/react-query"; import { clientApi } from "@homarr/api/client"; @@ -67,7 +67,7 @@ export default function AudioStatsWidget({ if (!currentlyPlaying) return null; return ( - + {currentlyPlaying.name} @@ -75,9 +75,15 @@ export default function AudioStatsWidget({ {currentlyPlaying.seasonName ?? currentlyPlaying.albumName ?? session.user.username} - - {session.sessionName} - + + + {session.sessionName} + + ); })} diff --git a/packages/widgets/src/smart-home/entity-state/component.tsx b/packages/widgets/src/smart-home/entity-state/component.tsx index 94950135c..e3f776f66 100644 --- a/packages/widgets/src/smart-home/entity-state/component.tsx +++ b/packages/widgets/src/smart-home/entity-state/component.tsx @@ -50,7 +50,9 @@ export default function SmartHomeEntityStateWidget({ const apiUnit = entity?.attributes.unit_of_measurement; const unit = options.entityUnit || (typeof apiUnit === "string" ? apiUnit : ""); const attribute = unit.length > 0 ? ` ${unit}` : ""; - const isActionable = options.clickable && canInteract && entity !== undefined && !isEntityPending && !isPending; + const isActionable = + options.clickable && canInteract && entity !== undefined && !entityError && !isEntityPending && !isPending; + const queryErrorLabel = entityError ? t("widget.smartHome-entityState.error.loadFailed") : undefined; const handleClick = useCallback(() => { if (isEditMode) { @@ -108,7 +110,7 @@ export default function SmartHomeEntityStateWidget({ onClick={handleClick} disabled={!isActionable} aria-label={`${displayName}: ${state}${attribute}`} - aria-description={error?.message} + aria-description={queryErrorLabel ?? (error ? t("widget.smartHome-entityState.error.toggleFailed") : undefined)} w="100%" h="100%" styles={{ @@ -127,6 +129,11 @@ export default function SmartHomeEntityStateWidget({ {displayName} + {queryErrorLabel && ( + + {queryErrorLabel} + + )} {displayMode === "advanced" && entity && ( <> diff --git a/packages/widgets/src/smart-home/entity-state/index.ts b/packages/widgets/src/smart-home/entity-state/index.ts index 649116bce..93a12a872 100644 --- a/packages/widgets/src/smart-home/entity-state/index.ts +++ b/packages/widgets/src/smart-home/entity-state/index.ts @@ -1,4 +1,4 @@ -import { IconBinaryTree } from "@tabler/icons-react"; +import { IconBinaryTree, IconServerOff } from "@tabler/icons-react"; import { getIntegrationKindsByCategory } from "@homarr/definitions"; @@ -22,4 +22,10 @@ export const { definition, componentLoader } = createWidgetDefinition("smartHome })); }, supportedIntegrations: getIntegrationKindsByCategory("smartHomeServer"), + errors: { + INTERNAL_SERVER_ERROR: { + icon: IconServerOff, + message: (t) => t("widget.smartHome-entityState.error.loadFailed"), + }, + }, }).withDynamicImport(() => import("./component"));