Skip to content

Commit 8890ec6

Browse files
committed
Keep cards rendered with stale data on transient backend errors
1 parent 0a74eaa commit 8890ec6

3 files changed

Lines changed: 37 additions & 4 deletions

File tree

‎frontend/src/components/FmiWeatherBox.tsx‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const WeatherBox: React.FC<WeatherBoxProps> = ({ className }) => {
9090
);
9191
}
9292

93-
if (error) {
93+
if (error && !data) {
9494
return (
9595
<Box className={className}>
9696
<OfflineState label="säätiedot" />
@@ -102,6 +102,8 @@ const WeatherBox: React.FC<WeatherBoxProps> = ({ className }) => {
102102
return null;
103103
}
104104

105+
const isStale = !!error;
106+
105107
// Aggregate hourly PV forecast points to per-day kWh + hour count.
106108
// Days with partial coverage (e.g. first/last day of the 66h window) are
107109
// dropped from the chart to avoid showing misleading near-zero totals.
@@ -188,6 +190,14 @@ const WeatherBox: React.FC<WeatherBoxProps> = ({ className }) => {
188190
>
189191
{demo ? "" : (location?.displayName ?? "")}
190192
</span>
193+
{isStale && (
194+
<Icon
195+
size={14}
196+
css={{ color: theme.colors.text.muted, opacity: 0.7 }}
197+
>
198+
cloud_off
199+
</Icon>
200+
)}
191201
</div>
192202
<div
193203
css={{

‎frontend/src/components/SolisBox.tsx‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@ const SolisBox: React.FC<SolisBoxProps> = ({ className }) => {
2929
// Not configured: hide entirely.
3030
if (error?.status === 503) return null;
3131

32-
const offline = !!error || data?.status === 2;
33-
if (offline) {
32+
// Full offline state when:
33+
// - inverter reports offline (status=2)
34+
// - network error and we have nothing cached to render
35+
const inverterOffline = data?.status === 2;
36+
const networkErrorNoData = !!error && !data;
37+
if (inverterOffline || networkErrorNoData) {
3438
const lastSeen = data?.updated_at ? new Date(data.updated_at) : null;
3539
return (
3640
<Box className={className}>
@@ -41,6 +45,8 @@ const SolisBox: React.FC<SolisBoxProps> = ({ className }) => {
4145

4246
if (!data) return null;
4347

48+
const isStale = !!error;
49+
4450
const isAlarm = data.status === 3;
4551
const displayPower = data.power.toFixed(1);
4652

@@ -142,6 +148,11 @@ const SolisBox: React.FC<SolisBoxProps> = ({ className }) => {
142148
{isAlarm ? "warning" : "solar_power"}
143149
</Icon>
144150
{data.power_unit}
151+
{isStale && (
152+
<Icon size={14} css={{ opacity: 0.6 }}>
153+
cloud_off
154+
</Icon>
155+
)}
145156
</div>
146157
<div
147158
css={{

‎frontend/src/components/TemperatureBox.tsx‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ const TemperatureBox: React.FC<TemperatureBoxProps> = ({
5656
null,
5757
);
5858

59-
if (error) {
59+
// Full offline UI only when we have no prior data to fall back on.
60+
// With cached sensors, render the normal card and surface a subtle stale
61+
// hint instead — avoids flashing offline state during standby reconnects.
62+
const isStale = !!error && sensors.length > 0;
63+
if (error && sensors.length === 0) {
6064
return (
6165
<Box
6266
className={classNames(className)}
@@ -212,12 +216,20 @@ const TemperatureBox: React.FC<TemperatureBoxProps> = ({
212216
>
213217
<div
214218
css={{
219+
display: "inline-flex",
220+
alignItems: "center",
221+
gap: 6,
215222
...theme.typography.label,
216223
color: theme.colors.text.muted,
217224
letterSpacing: "0.04em",
218225
}}
219226
>
220227
{title}
228+
{isStale && (
229+
<Icon size={14} css={{ opacity: 0.6 }}>
230+
cloud_off
231+
</Icon>
232+
)}
221233
</div>
222234
<div
223235
css={{

0 commit comments

Comments
 (0)