fix: refine widget modernization
This commit is contained in:
1 parent
6f2cd7fc2b
commit
777bbd89a1
44 files changed
+259
-320
No files matched your search
@@ -33,6 +33,20 @@ export interface Firewall {
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface FirewallQueryState {
|
||||
isPending: boolean;
|
||||
isFetching: boolean;
|
||||
isError: boolean;
|
||||
data?: readonly { error?: string }[];
|
||||
}
|
||||
|
||||
export const hasTotalFirewallFailure = (queries: readonly FirewallQueryState[]) =>
|
||||
queries.every((query) => !query.isPending && !query.isFetching) &&
|
||||
queries.every(
|
||||
(query) =>
|
||||
query.isError || (query.data !== undefined && query.data.length > 0 && query.data.every(({ error }) => error)),
|
||||
);
|
||||
|
||||
export default function FirewallWidget({
|
||||
integrationIds,
|
||||
width,
|
||||
@@ -48,34 +62,44 @@ export default function FirewallWidget({
|
||||
setSelectedFirewall(value ?? "");
|
||||
}, []);
|
||||
|
||||
const { data: firewallsCpuData = [] } = clientApi.widget.firewall.getFirewallCpuStatus.useQuery({ integrationIds });
|
||||
const { data: firewallsMemoryData = [] } = clientApi.widget.firewall.getFirewallMemoryStatus.useQuery({
|
||||
const cpuQuery = clientApi.widget.firewall.getFirewallCpuStatus.useQuery({ integrationIds });
|
||||
const memoryQuery = clientApi.widget.firewall.getFirewallMemoryStatus.useQuery({
|
||||
integrationIds,
|
||||
});
|
||||
const { data: firewallsVersionData = [] } = clientApi.widget.firewall.getFirewallVersionStatus.useQuery({
|
||||
const versionQuery = clientApi.widget.firewall.getFirewallVersionStatus.useQuery({
|
||||
integrationIds,
|
||||
});
|
||||
const { data: firewallsInterfacesData = [] } = clientApi.widget.firewall.getFirewallInterfacesStatus.useQuery({
|
||||
const interfacesQuery = clientApi.widget.firewall.getFirewallInterfacesStatus.useQuery({
|
||||
integrationIds,
|
||||
});
|
||||
const firewallsCpuData = cpuQuery.data ?? [];
|
||||
const firewallsMemoryData = memoryQuery.data ?? [];
|
||||
const firewallsVersionData = versionQuery.data ?? [];
|
||||
const firewallsInterfacesData = interfacesQuery.data ?? [];
|
||||
const queries = [cpuQuery, memoryQuery, versionQuery, interfacesQuery];
|
||||
const hasTotalFailure = hasTotalFirewallFailure(queries);
|
||||
|
||||
const [accordionValue, setAccordionValue] = useLocalStorage<string | null>({
|
||||
key: `homarr-${itemId}-firewall`,
|
||||
defaultValue: "interfaces",
|
||||
});
|
||||
|
||||
const initialSelectedFirewall = firewallsVersionData[0]?.integration.id ?? "";
|
||||
const activeFirewall = firewallsVersionData.some(({ integration }) => integration.id === selectedFirewall)
|
||||
? selectedFirewall
|
||||
: initialSelectedFirewall;
|
||||
const displayedFirewallIds = isAdvanced
|
||||
? firewallsVersionData.map(({ integration }) => integration.id)
|
||||
: activeFirewall
|
||||
? [activeFirewall]
|
||||
: [];
|
||||
const dropdownItems = firewallsVersionData.map((firewall) => ({
|
||||
label: firewall.integration.name,
|
||||
value: firewall.integration.id,
|
||||
if (hasTotalFailure) {
|
||||
throw new Error(t("widget.firewall.error.internalServerError"));
|
||||
}
|
||||
|
||||
const firewallMetadata = new Map(
|
||||
[...firewallsVersionData, ...firewallsCpuData, ...firewallsMemoryData, ...firewallsInterfacesData].map(
|
||||
({ integration }) => [integration.id, integration] as const,
|
||||
),
|
||||
);
|
||||
const firewallIds = [...firewallMetadata.keys()];
|
||||
const initialSelectedFirewall = firewallIds[0] ?? "";
|
||||
const activeFirewall = firewallMetadata.has(selectedFirewall) ? selectedFirewall : initialSelectedFirewall;
|
||||
const displayedFirewallIds = isAdvanced ? firewallIds : activeFirewall ? [activeFirewall] : [];
|
||||
const dropdownItems = firewallIds.map((firewallId) => ({
|
||||
label: firewallMetadata.get(firewallId)?.name ?? firewallId,
|
||||
value: firewallId,
|
||||
}));
|
||||
|
||||
return (
|
||||
@@ -90,7 +114,7 @@ export default function FirewallWidget({
|
||||
isTiny={isTiny}
|
||||
/>
|
||||
<FirewallVersion
|
||||
firewallsVersionData={firewallsVersionData}
|
||||
firewallsVersionData={firewallsVersionData.filter(({ error }) => !error)}
|
||||
selectedFirewall={activeFirewall}
|
||||
isTiny={isTiny}
|
||||
/>
|
||||
@@ -104,16 +128,17 @@ export default function FirewallWidget({
|
||||
const version = firewallsVersionData.find(({ integration }) => integration.id === firewallId);
|
||||
const interfaces = firewallsInterfacesData.find(({ integration }) => integration.id === firewallId);
|
||||
const hasError = Boolean(cpu?.error || memory?.error || version?.error || interfaces?.error);
|
||||
const metadata = firewallMetadata.get(firewallId);
|
||||
|
||||
return (
|
||||
<FirewallPanel
|
||||
key={firewallId}
|
||||
name={version?.integration.name ?? cpu?.integration.name ?? firewallId}
|
||||
kind={version?.integration.kind}
|
||||
version={version?.summary.version}
|
||||
cpu={cpu?.summary.total}
|
||||
memory={memory?.summary.percent}
|
||||
interfaces={interfaces?.summary}
|
||||
name={metadata?.name ?? firewallId}
|
||||
kind={metadata?.kind}
|
||||
version={version?.error ? undefined : version?.summary.version}
|
||||
cpu={cpu?.error ? undefined : cpu?.summary.total}
|
||||
memory={memory?.error ? undefined : memory?.summary.percent}
|
||||
interfaces={interfaces?.error ? undefined : interfaces?.summary}
|
||||
hasError={hasError}
|
||||
isAdvanced={isAdvanced}
|
||||
isTiny={isTiny}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { hasTotalFirewallFailure } from "./component";
|
||||
|
||||
const failedQuery = {
|
||||
isPending: false,
|
||||
isFetching: false,
|
||||
isError: false,
|
||||
data: [{ error: "offline" }],
|
||||
};
|
||||
|
||||
describe("firewall failure state", () => {
|
||||
it("rejects only after every dimension fails", () => {
|
||||
expect(hasTotalFirewallFailure([failedQuery, failedQuery, failedQuery, failedQuery])).toBe(true);
|
||||
expect(
|
||||
hasTotalFirewallFailure([failedQuery, failedQuery, failedQuery, { ...failedQuery, data: [{ error: undefined }] }]),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("lets an error-only persisted cache recover while it refetches", () => {
|
||||
expect(hasTotalFirewallFailure([failedQuery, failedQuery, { ...failedQuery, isFetching: true }, failedQuery])).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -21,6 +21,7 @@ export interface FirewallIntegration {
|
||||
|
||||
export const FirewallVersion = ({ firewallsVersionData, selectedFirewall, isTiny }: FirewallVersionProps) => {
|
||||
const t = useI18n();
|
||||
const version = firewallsVersionData.find(({ integration }) => integration.id === selectedFirewall)?.summary.version;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@@ -31,11 +32,7 @@ export const FirewallVersion = ({ firewallsVersionData, selectedFirewall, isTiny
|
||||
size={isTiny ? "8px" : "xs"}
|
||||
style={{ minHeight: "24px" }}
|
||||
>
|
||||
{firewallsVersionData
|
||||
.filter(({ integration }) => integration.id === selectedFirewall)
|
||||
.map(({ summary, integration }) => (
|
||||
<span key={integration.id}>{formatVersion(summary.version, t("widget.firewall.versionUnknown"))}</span>
|
||||
))}
|
||||
{formatVersion(version ?? "", t("widget.firewall.versionUnknown"))}
|
||||
</Badge>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,6 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("firewall", {
|
||||
icon: IconWall,
|
||||
queryKey: [["widget", "firewall"]],
|
||||
refetchInterval: 5,
|
||||
createOptions() {
|
||||
return optionsBuilder.from(() => ({}));
|
||||
|
||||
Reference in new issue
Block a user