From f455e71be5efc58174925f635e888a439d584de0 Mon Sep 17 00:00:00 2001 From: Bergasha Date: Fri, 28 Aug 2026 17:36:41 +1000 Subject: [PATCH] fix(board): remove per-widget refresh indicator (#6731) The small refresh-circle overlay that appeared in a widget's top-right corner during a background refetch wasn't adding useful signal and just added visual noise. Drop the isWidgetRefreshing detection, the indicator markup/CSS, and the now-dead query-key/runtime-query plumbing that only existed to power it. Updated the lazy-widgets e2e test to drop its assertions on the now -removed [data-widget-refreshing] marker; the behavior it was really verifying (cached content stays visible during a background refetch, which completes cleanly) is still covered by the existing network -level checks in the same test. --- .../board/items/item-content.module.css | 14 ---------- .../components/board/items/item-content.tsx | 27 +------------------ e2e/lazy-widgets.spec.ts | 2 -- 3 files changed, 1 insertion(+), 42 deletions(-) diff --git a/apps/nextjs/src/components/board/items/item-content.module.css b/apps/nextjs/src/components/board/items/item-content.module.css index 1e1226291..c00ac34d4 100644 --- a/apps/nextjs/src/components/board/items/item-content.module.css +++ b/apps/nextjs/src/components/board/items/item-content.module.css @@ -1,17 +1,3 @@ -.refreshIndicator { - position: absolute; - top: 0.25rem; - right: 0.25rem; - z-index: 3; - display: grid; - place-items: center; - width: 1.25rem; - height: 1.25rem; - border-radius: 999px; - background: color-mix(in srgb, var(--mantine-color-body) 78%, transparent); - pointer-events: none; -} - .settingsButton { position: absolute; top: -34px; diff --git a/apps/nextjs/src/components/board/items/item-content.tsx b/apps/nextjs/src/components/board/items/item-content.tsx index 7964923c5..2e5647ca9 100644 --- a/apps/nextjs/src/components/board/items/item-content.tsx +++ b/apps/nextjs/src/components/board/items/item-content.tsx @@ -4,7 +4,7 @@ import { createPortal } from "react-dom"; import dynamic from "next/dynamic"; import { Box, Button, Center, Loader, Portal } from "@mantine/core"; import { useElementSize, useIsomorphicEffect } from "@mantine/hooks"; -import { QueryErrorResetBoundary, useIsFetching, useQueryClient } from "@tanstack/react-query"; +import { QueryErrorResetBoundary, useQueryClient } from "@tanstack/react-query"; import combineClasses from "clsx"; import { NoIntegrationSelectedError } from "@homarr/widgets/errors/classes"; import type { FallbackProps } from "react-error-boundary"; @@ -19,7 +19,6 @@ import { WidgetError } from "@homarr/widgets/errors"; import { createWidgetRuntimeState, getWidgetQueryKeys, - getWidgetRuntimeQueries, supportsAdvancedFocus as definitionSupportsAdvancedFocus, } from "@homarr/widgets/definition"; import type { WidgetComponentProps, WidgetDefinition, WidgetRuntimeRef } from "@homarr/widgets/definition"; @@ -40,7 +39,6 @@ import { useItemActions } from "./item-actions"; import itemContentClasses from "./item-content.module.css"; import { WidgetContextMenu } from "./widget-context-menu"; import { removeWidgetDataQueries } from "./widget-query-recovery"; -import { matchesWidgetItemQuery } from "./widget-query-scope"; const BoardItemMenu = dynamic(() => import("./item-menu").then((module) => module.BoardItemMenu), { ssr: false, @@ -158,24 +156,6 @@ const LoadedBoardItemContent = ({ () => ({ ...item, options: reduceWidgetOptionsWithDefinition(definition, settings, item.options) }), [definition, item, settings], ); - const widgetQueryKeys = useMemo(() => getWidgetQueryKeys(definition, item.kind), [definition, item.kind]); - const isWidgetRefreshing = - useIsFetching({ - predicate: (query) => - query.state.data !== undefined && - matchesWidgetItemQuery( - query.queryKey, - widgetQueryKeys, - { - itemId: item.id, - boardId: board.id, - integrationIds: item.integrationIds, - options: menuItem.options, - runtimeQueries: getWidgetRuntimeQueries(widgetRuntimeRef), - }, - definition.queryMatcher, - ), - }) > 0; const [manualSurface, setManualSurface] = useState(null); const [surfacePortalTarget, setSurfacePortalTarget] = useState(null); const { active, viewportSize, open, close, dismiss, hover, leave } = useAdvancedFocus(); @@ -343,11 +323,6 @@ const LoadedBoardItemContent = ({ /> - {isWidgetRefreshing && ( - - - - )} ); diff --git a/e2e/lazy-widgets.spec.ts b/e2e/lazy-widgets.spec.ts index 4a595f754..bb6a6f268 100644 --- a/e2e/lazy-widgets.spec.ts +++ b/e2e/lazy-widgets.spec.ts @@ -163,7 +163,6 @@ describe("lazy widget application graph", () => { }); await expect.poll(() => refreshRequestStarted, { timeout: 10_000 }).toBe(true); await expect(cachedDownload).toBeVisible({ timeout: 5_000 }); - await expect(downloadsWidget.locator("[data-widget-refreshing]")).toBeVisible(); const refreshedDownloadsResponse = page.waitForResponse( (response) => response.url().includes("widget.downloads.getJobsAndStatuses") && response.ok(), @@ -171,7 +170,6 @@ describe("lazy widget application graph", () => { releaseRefresh(); releaseRefresh = undefined; await refreshedDownloadsResponse; - await expect(downloadsWidget.locator("[data-widget-refreshing]")).toHaveCount(0); await page.unroute(downloadsRequestPattern, delayDownloadsRefresh); expect(pageErrors).toEqual([]); expect(hydrationErrors).toEqual([]);