refactor: replace serverdata with suspense query (#1265)
* refactor: replace serverdata with suspense query * fix: deepsource issues
This commit is contained in:
@@ -39,16 +39,25 @@ export default function DnsHoleControlsWidget({
|
||||
options,
|
||||
integrationIds,
|
||||
isEditMode,
|
||||
serverData,
|
||||
}: WidgetComponentProps<typeof widgetKind>) {
|
||||
// DnsHole integrations with interaction permissions
|
||||
const integrationsWithInteractions = useIntegrationsWithInteractAccess()
|
||||
.map(({ id }) => id)
|
||||
.filter((id) => integrationIds.includes(id));
|
||||
|
||||
// Initial summaries, null summary means disconnected, undefined status means processing
|
||||
const [summaries, setSummaries] = useState(serverData?.initialData ?? []);
|
||||
|
||||
const [summaries] = clientApi.widget.dnsHole.summary.useSuspenseQuery(
|
||||
{
|
||||
widgetKind: "dnsHoleControls",
|
||||
integrationIds,
|
||||
},
|
||||
{
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
retry: false,
|
||||
},
|
||||
);
|
||||
const utils = clientApi.useUtils();
|
||||
// Subscribe to summary updates
|
||||
clientApi.widget.dnsHole.subscribeToSummary.useSubscription(
|
||||
{
|
||||
@@ -57,8 +66,20 @@ export default function DnsHoleControlsWidget({
|
||||
},
|
||||
{
|
||||
onData: (data) => {
|
||||
setSummaries((prevSummaries) =>
|
||||
prevSummaries.map((summary) => (summary.integration.id === data.integration.id ? data : summary)),
|
||||
utils.widget.dnsHole.summary.setData(
|
||||
{
|
||||
widgetKind: "dnsHoleControls",
|
||||
integrationIds,
|
||||
},
|
||||
(prevData) => {
|
||||
if (!prevData) return undefined;
|
||||
|
||||
const newData = prevData.map((summary) =>
|
||||
summary.integration.id === data.integration.id ? { ...summary, summary: data.summary } : summary,
|
||||
);
|
||||
|
||||
return newData;
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -67,39 +88,77 @@ export default function DnsHoleControlsWidget({
|
||||
// Mutations for dnsHole state, set to undefined on click, and change again on settle
|
||||
const { mutate: enableDns } = clientApi.widget.dnsHole.enable.useMutation({
|
||||
onSettled: (_, error, { integrationId }) => {
|
||||
setSummaries((prevSummaries) =>
|
||||
prevSummaries.map((data) => ({
|
||||
...data,
|
||||
summary:
|
||||
data.integration.id === integrationId && data.summary
|
||||
? { ...data.summary, status: error ? "disabled" : "enabled" }
|
||||
: data.summary,
|
||||
})),
|
||||
utils.widget.dnsHole.summary.setData(
|
||||
{
|
||||
widgetKind: "dnsHoleControls",
|
||||
integrationIds,
|
||||
},
|
||||
(prevData) => {
|
||||
if (!prevData) return [];
|
||||
|
||||
return prevData.map((item) =>
|
||||
item.integration.id === integrationId && item.summary
|
||||
? {
|
||||
...item,
|
||||
summary: {
|
||||
...item.summary,
|
||||
status: error ? "disabled" : "enabled",
|
||||
},
|
||||
}
|
||||
: item,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
const { mutate: disableDns } = clientApi.widget.dnsHole.disable.useMutation({
|
||||
onSettled: (_, error, { integrationId }) => {
|
||||
setSummaries((prevSummaries) =>
|
||||
prevSummaries.map((data) => ({
|
||||
...data,
|
||||
summary:
|
||||
data.integration.id === integrationId && data.summary
|
||||
? { ...data.summary, status: error ? "enabled" : "disabled" }
|
||||
: data.summary,
|
||||
})),
|
||||
utils.widget.dnsHole.summary.setData(
|
||||
{
|
||||
widgetKind: "dnsHoleControls",
|
||||
integrationIds,
|
||||
},
|
||||
(prevData) => {
|
||||
if (!prevData) return [];
|
||||
|
||||
return prevData.map((item) =>
|
||||
item.integration.id === integrationId && item.summary
|
||||
? {
|
||||
...item,
|
||||
summary: {
|
||||
...item.summary,
|
||||
status: error ? "enabled" : "disabled",
|
||||
},
|
||||
}
|
||||
: item,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
const toggleDns = (integrationId: string) => {
|
||||
const integrationStatus = summaries.find(({ integration }) => integration.id === integrationId);
|
||||
if (!integrationStatus?.summary?.status) return;
|
||||
setSummaries((prevSummaries) =>
|
||||
prevSummaries.map((data) => ({
|
||||
...data,
|
||||
summary:
|
||||
data.integration.id === integrationId && data.summary ? { ...data.summary, status: undefined } : data.summary,
|
||||
})),
|
||||
utils.widget.dnsHole.summary.setData(
|
||||
{
|
||||
widgetKind: "dnsHoleControls",
|
||||
integrationIds,
|
||||
},
|
||||
(prevData) => {
|
||||
if (!prevData) return [];
|
||||
|
||||
return prevData.map((item) =>
|
||||
item.integration.id === integrationId && item.summary
|
||||
? {
|
||||
...item,
|
||||
summary: {
|
||||
...item.summary,
|
||||
status: undefined,
|
||||
},
|
||||
}
|
||||
: item,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (integrationStatus.summary.status === "enabled") {
|
||||
disableDns({ integrationId, duration: 0 });
|
||||
|
||||
@@ -7,7 +7,7 @@ import { optionsBuilder } from "../../options";
|
||||
|
||||
export const widgetKind = "dnsHoleControls";
|
||||
|
||||
export const { definition, componentLoader, serverDataLoader } = createWidgetDefinition(widgetKind, {
|
||||
export const { definition, componentLoader } = createWidgetDefinition(widgetKind, {
|
||||
icon: IconDeviceGamepad,
|
||||
options: optionsBuilder.from((factory) => ({
|
||||
showToggleAllButtons: factory.switch({
|
||||
@@ -21,6 +21,4 @@ export const { definition, componentLoader, serverDataLoader } = createWidgetDef
|
||||
message: (t) => t("widget.dnsHoleControls.error.internalServerError"),
|
||||
},
|
||||
},
|
||||
})
|
||||
.withServerData(() => import("./serverData"))
|
||||
.withDynamicImport(() => import("./component"));
|
||||
}).withDynamicImport(() => import("./component"));
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
import { widgetKind } from ".";
|
||||
import type { WidgetProps } from "../../definition";
|
||||
|
||||
export default async function getServerDataAsync({ integrationIds }: WidgetProps<typeof widgetKind>) {
|
||||
if (integrationIds.length === 0) {
|
||||
return {
|
||||
initialData: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const currentDns = await api.widget.dnsHole.summary({
|
||||
widgetKind,
|
||||
integrationIds,
|
||||
});
|
||||
|
||||
return {
|
||||
initialData: currentDns,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
initialData: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
import { useMemo } from "react";
|
||||
import type { BoxProps } from "@mantine/core";
|
||||
import { Avatar, AvatarGroup, Box, Card, Flex, Stack, Text, Tooltip } from "@mantine/core";
|
||||
import { useElementSize } from "@mantine/hooks";
|
||||
@@ -20,12 +20,20 @@ import { widgetKind } from ".";
|
||||
import type { WidgetComponentProps, WidgetProps } from "../../definition";
|
||||
import { NoIntegrationSelectedError } from "../../errors";
|
||||
|
||||
export default function DnsHoleSummaryWidget({
|
||||
options,
|
||||
integrationIds,
|
||||
serverData,
|
||||
}: WidgetComponentProps<typeof widgetKind>) {
|
||||
const [summaries, setSummaries] = useState(serverData?.initialData ?? []);
|
||||
export default function DnsHoleSummaryWidget({ options, integrationIds }: WidgetComponentProps<typeof widgetKind>) {
|
||||
const [summaries] = clientApi.widget.dnsHole.summary.useSuspenseQuery(
|
||||
{
|
||||
widgetKind,
|
||||
integrationIds,
|
||||
},
|
||||
{
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
retry: false,
|
||||
},
|
||||
);
|
||||
const utils = clientApi.useUtils();
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
@@ -36,8 +44,21 @@ export default function DnsHoleSummaryWidget({
|
||||
},
|
||||
{
|
||||
onData: (data) => {
|
||||
setSummaries((prevSummaries) =>
|
||||
prevSummaries.map((summary) => (summary.integration.id === data.integration.id ? data : summary)),
|
||||
utils.widget.dnsHole.summary.setData(
|
||||
{
|
||||
widgetKind,
|
||||
integrationIds,
|
||||
},
|
||||
(prevData) => {
|
||||
if (!prevData) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const newData = prevData.map((item) =>
|
||||
item.integration.id === data.integration.id ? { ...item, summary: data.summary } : item,
|
||||
);
|
||||
return newData;
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -46,17 +67,10 @@ export default function DnsHoleSummaryWidget({
|
||||
const data = useMemo(
|
||||
() =>
|
||||
summaries
|
||||
.filter(
|
||||
(
|
||||
pair,
|
||||
): pair is {
|
||||
integration: typeof pair.integration;
|
||||
timestamp: typeof pair.timestamp;
|
||||
summary: DnsHoleSummary;
|
||||
} => pair.summary !== null && Math.abs(dayjs(pair.timestamp).diff()) < 30000,
|
||||
)
|
||||
.flatMap(({ summary }) => summary),
|
||||
[summaries, serverData],
|
||||
.filter((pair) => Math.abs(dayjs(pair.timestamp).diff()) < 30000)
|
||||
.flatMap(({ summary }) => summary)
|
||||
.filter((summary) => summary !== null),
|
||||
[summaries],
|
||||
);
|
||||
|
||||
if (integrationIds.length === 0) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { optionsBuilder } from "../../options";
|
||||
|
||||
export const widgetKind = "dnsHoleSummary";
|
||||
|
||||
export const { definition, componentLoader, serverDataLoader } = createWidgetDefinition(widgetKind, {
|
||||
export const { definition, componentLoader } = createWidgetDefinition(widgetKind, {
|
||||
icon: IconAd,
|
||||
options: optionsBuilder.from((factory) => ({
|
||||
usePiHoleColors: factory.switch({
|
||||
@@ -28,6 +28,4 @@ export const { definition, componentLoader, serverDataLoader } = createWidgetDef
|
||||
message: (t) => t("widget.dnsHoleSummary.error.internalServerError"),
|
||||
},
|
||||
},
|
||||
})
|
||||
.withServerData(() => import("./serverData"))
|
||||
.withDynamicImport(() => import("./component"));
|
||||
}).withDynamicImport(() => import("./component"));
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
import { widgetKind } from ".";
|
||||
import type { WidgetProps } from "../../definition";
|
||||
|
||||
export default async function getServerDataAsync({ integrationIds }: WidgetProps<typeof widgetKind>) {
|
||||
if (integrationIds.length === 0) {
|
||||
return {
|
||||
initialData: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const currentDns = await api.widget.dnsHole.summary({
|
||||
widgetKind,
|
||||
integrationIds,
|
||||
});
|
||||
|
||||
return {
|
||||
initialData: currentDns,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
initialData: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user