From bac28d9e1c35b58698777506dc08cc8dda137024 Mon Sep 17 00:00:00 2001 From: ajnart Date: Tue, 7 Jul 2026 18:13:54 +0200 Subject: [PATCH] fix: context menu refresh stays open with loading spinner, cache age reacts to refetch --- .../components/board/items/widget-context-menu.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/nextjs/src/components/board/items/widget-context-menu.tsx b/apps/nextjs/src/components/board/items/widget-context-menu.tsx index 415151a52..b8d416214 100644 --- a/apps/nextjs/src/components/board/items/widget-context-menu.tsx +++ b/apps/nextjs/src/components/board/items/widget-context-menu.tsx @@ -2,10 +2,10 @@ import type { MutableRefObject, ReactNode } from "react"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { Group, Menu, Switch, Text } from "@mantine/core"; +import { Group, Loader, Menu, Switch, Text } from "@mantine/core"; import { IconCopy, IconLayoutKanban, IconRefresh, IconSettings, IconTrash } from "@tabler/icons-react"; import type { QueryClient } from "@tanstack/react-query"; -import { useQueryClient } from "@tanstack/react-query"; +import { useIsFetching, useQueryClient } from "@tanstack/react-query"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; @@ -50,8 +50,9 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont const queryClient = useQueryClient(); const widgetQueryKey = useMemo(() => [["widget", item.kind]], [item.kind]); + const isWidgetFetching = useIsFetching({ queryKey: widgetQueryKey }) > 0; const handleRefetch = useCallback(() => { - void queryClient.invalidateQueries({ queryKey: widgetQueryKey }); + void queryClient.refetchQueries({ queryKey: widgetQueryKey, type: "all" }); }, [queryClient, widgetQueryKey]); const options = useMemo( @@ -223,7 +224,7 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont <> {(toggleOptions.length > 0 || visibleWidgetActions.length > 0 || isEditMode) && } - } onClick={handleRefetch}> + : } onClick={handleRefetch} disabled={isWidgetFetching}> {tMenu("refresh")} @@ -266,12 +267,16 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont }; const WidgetCacheAge = ({ queryClient, queryKey }: { queryClient: QueryClient; queryKey: unknown[] }) => { + const isFetching = useIsFetching({ queryKey }) > 0; + // ponytail: 1s tick for "just now" → "1s ago" transition; useIsFetching handles refetch reactivity const [, setTick] = useState(0); useEffect(() => { const id = setInterval(() => setTick((n) => n + 1), 1000); return () => clearInterval(id); }, []); + if (isFetching) return ; + const timestamps = queryClient .getQueryCache() .findAll({ queryKey })