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

@@ -39,7 +39,25 @@ Dynamic selects use `x-homarr.optionsSource` and a named query. Add `itemsPath`
### Named requests and parameter bindings
Request parameters are a map from parameter name to `string`, `number`, or `boolean`. Query and body templates reference them with `{ "$param": "name" }`. Load queries receive matching widget options automatically; manual queries and actions receive `params` from their runtime component.
Request parameters are a map from parameter name to `string`, `number`, or `boolean`. Query and body templates reference them with `{ "$param": "name" }`. Declaring a parameter does not give it a value, even when an option or temporary input has the same name.
For a load query, bind every parameter explicitly in `optionsBinding`. Each entry is either `{ "$option": "optionName" }` or a primitive literal matching the declared parameter type:
```json
{
"pathTemplate": "/api/endpoints/{endpointId}/docker/containers/json",
"parameters": { "endpointId": "string", "showAll": "boolean" },
"queryTemplate": { "all": { "$param": "showAll" } },
"optionsBinding": {
"endpointId": { "$option": "endpointId" },
"showAll": false
}
}
```
For manual queries and actions, `SubFetch`, `ActionButton`, or `ToggleSwitch` supplies the complete parameter object through its `params` prop. This is the only route from JSX values such as `inputs.search` or a loop variable into a request.
Dynamic option requests also run without a JSX invoker. If they declare parameters, give them explicit `optionsBinding` entries so the configuration form can resolve those values.
<CanonicalCustomWidgetExample
id="named-widget-requests"
@@ -13,7 +13,7 @@ Queries and actions support GET, POST, PUT, PATCH, and DELETE. `kind`, not metho
Successful actions evict the declared queries from both the browser and server response cache before refetching them.
Path parameters use `{name}`. Structured query/body templates use `{ "$param": "name" }`. Runtime values can come from validated options, temporary `inputs`, and explicit action parameters.
Path parameters use `{name}`. Structured query/body templates use `{ "$param": "name" }`. Every declared parameter has an explicit source: load queries use `optionsBinding` entries containing `{ "$option": "optionName" }` or a primitive literal, while manual queries and actions receive the full parameter object from the invoking component's `params` prop. Homarr never matches parameter names to option or input names implicitly.
## Protections
@@ -10,7 +10,7 @@ Use the first schema/JSX diagnostic and its path. Ensure source/request IDs are
## Request fails
Check the source network scope, base URL, credentials, request method/path/body, runtime parameters, and board permission. The preview journal shows redacted method, request ID, path template, status, and duration without credentials.
Check the source network scope, base URL, credentials, request method/path/body, runtime parameters, and board permission. For “invalid placeholder” or an unresolved parameter on a load query, first verify that every declared parameter has an explicit `optionsBinding` option reference or literal. Matching parameter and option names are not a binding. The preview journal shows redacted method, request ID, path template, status, and duration without credentials.
## Mantine prop warning