diff --git a/apps/builder/app/builder/features/settings-panel/resource-panel.tsx b/apps/builder/app/builder/features/settings-panel/resource-panel.tsx index a902ea12b76d..fa70518756d3 100644 --- a/apps/builder/app/builder/features/settings-panel/resource-panel.tsx +++ b/apps/builder/app/builder/features/settings-panel/resource-panel.tsx @@ -66,18 +66,17 @@ import { type InstancePath, } from "~/shared/awareness"; import { updateWebstudioData } from "~/shared/instance-utils"; -import { - computeExpression, - rebindTreeVariablesMutable, -} from "~/shared/data-variables"; +import { rebindTreeVariablesMutable } from "~/shared/data-variables"; import { parseCurl, type CurlRequest } from "./curl"; export const parseResource = ({ id, + control, name, formData, }: { id: string; + control?: string; name?: string; formData: FormData; }) => { @@ -87,6 +86,7 @@ export const parseResource = ({ const headerValues = formData.getAll("header-value") as string[]; return Resource.parse({ id, + control, name: name ?? formData.get("name"), url: formData.get("url"), searchParams: searchParamNames @@ -253,7 +253,7 @@ const SearchParamPair = ({ }) => { const evaluatedValue = evaluateExpressionWithinScope(value, scope); // expressions with variables or objects cannot be edited from input - const isValueUnbound = + const isValueUnboundString = isLiteralExpression(value) && typeof evaluatedValue === "string"; return ( @@ -284,7 +284,7 @@ const SearchParamPair = ({ onChange(name, newValue)} onRemove={(evaluatedValue) => @@ -377,7 +377,7 @@ const HeaderPair = ({ }) => { const evaluatedValue = evaluateExpressionWithinScope(value, scope); // expressions with variables or objects cannot be edited from input - const isValueUnbound = + const isValueUnboundString = isLiteralExpression(value) && typeof evaluatedValue === "string"; return ( @@ -408,7 +408,7 @@ const HeaderPair = ({ onChange(name, newValue)} onRemove={(evaluatedValue) => @@ -558,7 +558,7 @@ export const getResourceScopeForInstance = ({ const name = encodeDataVariableId(dataSourceId); scope[name] = value; aliases.set(name, dataSource.name); - variableValues.set(dataSource.name, value); + variableValues.set(dataSourceId, value); } } } @@ -621,7 +621,7 @@ export const useResourceScope = ({ variable }: { variable?: DataSource }) => { const key = encodeDataVariableId(variable.id); delete newScope[key]; newAliases.delete(key); - newVariableValues.delete(variable.name); + newVariableValues.delete(variable.id); } return { scope: newScope, @@ -796,7 +796,10 @@ const parseHeaders = (headers: Resource["headers"]) => { let maxAge: undefined | string; let bodyType: BodyType; const newHeaders = headers.filter((header) => { - const value = computeExpression(header.value, new Map()).toLowerCase(); + // cast raw expression result to string + const value = String( + evaluateExpressionWithinScope(header.value, {}) + ).toLowerCase(); if (isCacheControl(header.name)) { // move simple header like Cache-Control: max-age=10 to dedicated input // preserve more complex cache-control @@ -818,7 +821,7 @@ const parseHeaders = (headers: Resource["headers"]) => { return false; } } - return false; + return true; }); return { headers: newHeaders, maxAge, bodyType }; }; @@ -980,8 +983,6 @@ export const SystemResourceForm = forwardRef< ? resources.get(variable.resourceId) : undefined; - const method = "get"; - const localResources = [ { label: "Sitemap", @@ -1006,19 +1007,15 @@ export const SystemResourceForm = forwardRef< if (scopeInstanceId === undefined) { return; } - const name = z.string().parse(formData.get("name")); - const newResource: Resource = { + const newResource: Resource = parseResource({ id: resource?.id ?? nanoid(), - name, control: "system", - url: localResource.value, - method, - headers: [], - }; + formData, + }); const newVariable: DataSource = { id: variable?.id ?? nanoid(), scopeInstanceId, - name, + name: newResource.name, type: "resource", resourceId: newResource.id, }; @@ -1037,6 +1034,8 @@ export const SystemResourceForm = forwardRef< return ( <> + + + {!headers.some(({ name }) => isContentType(name)) && ( + <> + + + + )} + + { try { const { method, searchParams, headers, body } = resourceRequest; - // cloudflare workers fail when fetching url contains spaces - // even though new URL suppose to trim them on parsing by spec - const url = new URL(resourceRequest.url.trim()); - if (searchParams) { - for (const { name, value } of searchParams) { - url.searchParams.append(name, serializeValue(value)); + let href = resourceRequest.url; + try { + // cloudflare workers fail when fetching url contains spaces + // even though new URL suppose to trim them on parsing by spec + const url = new URL(resourceRequest.url.trim()); + if (searchParams) { + for (const { name, value } of searchParams) { + url.searchParams.append(name, serializeValue(value)); + } } + href = url.href; + } catch { + // empty block } const requestHeaders = new Headers( headers.map(({ name, value }): [string, string] => [ @@ -46,7 +52,7 @@ export const loadResource = async ( if (method !== "get" && body !== undefined) { requestInit.body = serializeValue(body); } - const response = await customFetch(url.href, requestInit); + const response = await customFetch(href, requestInit); let data = await response.text(); @@ -59,7 +65,7 @@ export const loadResource = async ( if (!response.ok) { console.error( - `Failed to load resource: ${url} - ${response.status}: ${JSON.stringify(data).slice(0, 300)}` + `Failed to load resource: ${href} - ${response.status}: ${JSON.stringify(data).slice(0, 300)}` ); }