fix(custom-widgets): require explicit request bindings

This commit is contained in:
Thomas Camlong committed 2026-07-20 17:02:59 +02:00
1 parent 4c69ad90df
commit a26846fa31
23 files changed
+363 -52

No files matched your search

@@ -1,5 +1,5 @@
import { fetchApi } from "@homarr/api/client";
import { customWidgetDefinitionSchema } from "@homarr/custom-widgets/core";
import { customWidgetDefinitionSchema, resolveCustomWidgetOptionsBinding } from "@homarr/custom-widgets/core";
import type { CustomWidgetSource, HomarrCustomWidgetV2 } from "@homarr/custom-widgets/core";
import type { CustomWidgetFormValues } from "@homarr/custom-widgets/workbench";
import type { UseFormReturnType } from "@mantine/form";
@@ -70,13 +70,8 @@ export async function loadPreviewQueries(definition: HomarrCustomWidgetV2, sessi
const data: Record<string, unknown> = {};
const status: Record<string, unknown> = {};
for (const request of definition.requests.filter((entry) => entry.kind === "query" && entry.trigger === "load")) {
const params = Object.fromEntries(
Object.entries(request.parameters).flatMap(([name, type]) => {
const value = definition.defaultOptions[name];
return typeof value === type ? [[name, value as string | number | boolean]] : [];
}),
);
try {
const params = resolveCustomWidgetOptionsBinding(request, definition.defaultOptions);
const result = await fetchApi.customWidget.previewQuery.query({ sessionId, requestId: request.id, params });
data[request.id] = result.data;
status[request.id] = { loading: false, ...result };
@@ -3,6 +3,7 @@ import { Badge, Box, Container, Group, Paper, Stack, Text, Title } from "@mantin
import { api } from "@homarr/api/server";
import { auth } from "@homarr/auth/next";
import { resolveCustomWidgetOptionsBinding } from "@homarr/custom-widgets/core";
import CustomJsxDisplay from "@homarr/widgets/custom-api/custom-jsx-display";
export default async function CustomWidgetPreviewPage({ params }: { params: Promise<{ id: string }> }) {
@@ -15,14 +16,11 @@ export default async function CustomWidgetPreviewPage({ params }: { params: Prom
const loadRequests = preview.requests.filter((request) => request.kind === "query" && request.trigger === "load");
const results = await Promise.all(
loadRequests.map(async (request) => {
const requestParams = Object.fromEntries(
Object.entries(request.parameters).flatMap(([name, type]) => {
const value = preview.defaultOptions[name];
return typeof value === type ? [[name, value as string | number | boolean]] : [];
}),
);
const result = await api.customWidget
.previewQuery({ sessionId: id, requestId: request.id, params: requestParams })
const result = await Promise.resolve()
.then(() => resolveCustomWidgetOptionsBinding(request, preview.defaultOptions))
.then((requestParams) =>
api.customWidget.previewQuery({ sessionId: id, requestId: request.id, params: requestParams }),
)
.catch((cause: unknown) => ({
ok: false,
status: 0,