fix: harden widget error feedback
This commit is contained in:
5 files changed
+29
-8
No files matched your search
@@ -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.
|
||||
|
||||
<WidgetInteractionGuide />
|
||||
|
||||
|
||||
@@ -2185,6 +2185,7 @@
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"loadFailed": "Unable to load entity",
|
||||
"toggleFailed": "Unable to update entity"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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 (
|
||||
<Group key={`${integrationId}:${session.sessionId}`} justify="space-between" wrap="nowrap" p="sm">
|
||||
<Stack gap={0} style={{ minWidth: 0 }}>
|
||||
<Stack gap={0} style={{ minWidth: 0, flex: 1 }}>
|
||||
<Text size="sm" fw={600} truncate>
|
||||
{currentlyPlaying.name}
|
||||
</Text>
|
||||
@@ -75,9 +75,15 @@ export default function AudioStatsWidget({
|
||||
{currentlyPlaying.seasonName ?? currentlyPlaying.albumName ?? session.user.username}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Badge variant="light" style={{ flexShrink: 0 }}>
|
||||
{session.sessionName}
|
||||
</Badge>
|
||||
<Tooltip
|
||||
label={session.sessionName}
|
||||
events={{ hover: true, focus: true, touch: true }}
|
||||
position="left"
|
||||
>
|
||||
<Badge variant="light" maw="40%" style={{ flexShrink: 0 }} tabIndex={0}>
|
||||
{session.sessionName}
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -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({
|
||||
<Text ta="center" c="dimmed" fw={500} size={isTiny ? "xs" : "sm"} lineClamp={2} maw="100%">
|
||||
{displayName}
|
||||
</Text>
|
||||
{queryErrorLabel && (
|
||||
<Text size="xs" c="orange" ta="center" lineClamp={1} maw="100%" aria-live="polite">
|
||||
{queryErrorLabel}
|
||||
</Text>
|
||||
)}
|
||||
{displayMode === "advanced" && entity && (
|
||||
<>
|
||||
<Group justify="center" gap={4}>
|
||||
|
||||
@@ -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"));
|
||||
Reference in new issue
Block a user