refactor: resilient integration queries + simplification

- Extract settleIntegrationQueries helper (Promise.allSettled + logging)
  so one failing integration no longer kills the entire widget
- Convert 16 widget routers from Promise.all to settleIntegrationQueries
- Add onSettled query invalidation to downloads and media-requests mutations
- Inline 4 single-use firewall useUpdating* hooks
- Deduplicate firewall router (4 identical procedures → shared factory)
- Fix system-resources chart duplicate initial point (ref-based dedup)
- Simplify docker table refresh (refetch + isFetching, drop manual state)
- Trim invalidateIntegrationCacheAsync to session-store only (dead scan)
- Fix Beszel getAlerts: inner Promise.allSettled so systems failure
  doesn't discard alerts
This commit is contained in:
Thomas Camlong committed 2026-06-25 11:56:05 +02:00
1 parent cf5934aef6
commit 26a8d219af
24 files changed
+242 -408

No files matched your search

@@ -1,6 +1,6 @@
"use client";
import { useCallback, useState } from "react";
import { useCallback } from "react";
import { useRouter } from "next/navigation";
import type { MantineColor } from "@mantine/core";
import { ActionIcon, Avatar, Badge, Box, Button, Group, Menu, Text, Tooltip } from "@mantine/core";
@@ -153,17 +153,13 @@ const createColumns = (t: TranslationFunction): MRT_ColumnDef<DockerContainer>[]
export function DockerTable({ containers, timestamp }: RouterOutputs["docker"]["getContainers"]) {
const t = useI18n();
const tDocker = useScopedI18n("docker");
const { data } = clientApi.docker.getContainers.useQuery(undefined, {
const { data, isFetching, refetch } = clientApi.docker.getContainers.useQuery(undefined, {
initialData: { containers, timestamp },
refetchOnMount: false,
});
const relativeTime = useTimeAgo(data.timestamp);
const utils = clientApi.useUtils();
const [isPending, setIsPending] = useState(false);
const mutate = useCallback(() => {
setIsPending(true);
void utils.docker.getContainers
.invalidate()
void refetch()
.then(() => {
showSuccessNotification({
title: tDocker("action.refresh.notification.success.title"),
@@ -175,9 +171,8 @@ export function DockerTable({ containers, timestamp }: RouterOutputs["docker"]["
title: tDocker("action.refresh.notification.error.title"),
message: tDocker("action.refresh.notification.error.message"),
});
})
.finally(() => setIsPending(false));
}, [utils, tDocker]);
});
}, [refetch, tDocker]);
const table = useTranslatedMantineReactTable({
data: data.containers,
@@ -203,7 +198,7 @@ export function DockerTable({ containers, timestamp }: RouterOutputs["docker"]["
mantineTableHeadCellProps: { style: { padding: "4px 8px" } },
renderRowActions: ({ row }: { row: MRT_Row<DockerContainer> }) => <ContainerRowMenu container={row.original} />,
renderTopToolbarCustomActions: () => (
<Button variant="default" rightSection={<IconRefresh size="1rem" />} onClick={() => mutate()} loading={isPending}>
<Button variant="default" rightSection={<IconRefresh size="1rem" />} onClick={() => mutate()} loading={isFetching}>
{tDocker("action.refresh.label")}
</Button>
),