diff --git a/packages/toolpad-app/src/runtime/ToolpadApp.tsx b/packages/toolpad-app/src/runtime/ToolpadApp.tsx index b0417dc8b2a..87dd9a28aa6 100644 --- a/packages/toolpad-app/src/runtime/ToolpadApp.tsx +++ b/packages/toolpad-app/src/runtime/ToolpadApp.tsx @@ -378,6 +378,13 @@ function parseBinding( result: { value: bindable }, }; } + + if (bindingType === 'env') { + return { + scopePath, + result: { value: bindable }, + }; + } if (bindingType === 'jsExpression') { return { scopePath, diff --git a/packages/toolpad-app/src/runtime/evalJsBindings.ts b/packages/toolpad-app/src/runtime/evalJsBindings.ts index 9563d9d1e62..989f1df0c2c 100644 --- a/packages/toolpad-app/src/runtime/evalJsBindings.ts +++ b/packages/toolpad-app/src/runtime/evalJsBindings.ts @@ -3,7 +3,7 @@ import { mapValues } from '@mui/toolpad-utils/collections'; // TODO: remove these lodash-es imports // eslint-disable-next-line no-restricted-imports import { setWith, clone, set as setObjectPath } from 'lodash-es'; - +import { getBindingType } from './bindings'; /** * Updates an object's property value for a given path in an immutable way. */ @@ -116,8 +116,8 @@ export function buildGlobalScope( ): Record { const globalScope = { ...base }; for (const binding of Object.values(bindings)) { - if (binding.scopePath) { - const value = binding.result?.value; + const value = binding.result?.value; + if (binding.scopePath && getBindingType(value) === 'const') { setObjectPath(globalScope, binding.scopePath, value); } } diff --git a/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx index 33aac7801db..c8966bad6cd 100644 --- a/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx +++ b/packages/toolpad-app/src/toolpad/AppEditor/BindingEditor.tsx @@ -71,7 +71,7 @@ interface BindingEditorContext { disabled?: boolean; propType?: PropValueType; liveBinding?: LiveBinding; - envVarNames?: string[]; + env?: Record; } const [useBindingEditorContext, BindingEditorContextProvider] = @@ -138,8 +138,8 @@ function JsExpressionPreview({ jsRuntime, input, globalScope }: JsExpressionPrev export interface EnvBindingEditorProps extends WithControlledProp {} export function EnvBindingEditor({ value, onChange }: EnvBindingEditorProps) { - const { envVarNames = [] } = useBindingEditorContext(); - + const context = useBindingEditorContext(); + const envVarNames = Object.keys(context.env ?? {}); const handleInputChange = React.useCallback( (event: React.SyntheticEvent, newValue: string | null) => { onChange({ @@ -195,10 +195,10 @@ export function ValueBindingEditor({ value, onChange, error }: ValueBindingEdito globalScopeMeta = {}, jsRuntime, propType, - envVarNames, + env, } = useBindingEditorContext(); - const hasEnv = Boolean(envVarNames); + const hasEnv = Boolean(env); const [activeTab, setActiveTab] = React.useState(getValueBindingTab(value)); React.useEffect(() => { @@ -616,7 +616,7 @@ export interface BindingEditorProps extends WithControlledProp; } export function BindingEditor({ @@ -630,7 +630,7 @@ export function BindingEditor({ value, onChange, liveBinding, - envVarNames, + env, }: BindingEditorProps) { const [open, setOpen] = React.useState(false); const handleOpen = React.useCallback(() => setOpen(true), []); @@ -687,9 +687,9 @@ export function BindingEditor({ disabled, propType, liveBinding, - envVarNames, + env, }), - [disabled, envVarNames, globalScope, jsRuntime, label, liveBinding, propType, resolvedMeta], + [disabled, env, globalScope, jsRuntime, label, liveBinding, propType, resolvedMeta], ); return ( diff --git a/packages/toolpad-app/src/toolpad/AppEditor/GlobalScopeExplorer.tsx b/packages/toolpad-app/src/toolpad/AppEditor/GlobalScopeExplorer.tsx index bf23cc198c5..7d04a104d6b 100644 --- a/packages/toolpad-app/src/toolpad/AppEditor/GlobalScopeExplorer.tsx +++ b/packages/toolpad-app/src/toolpad/AppEditor/GlobalScopeExplorer.tsx @@ -57,7 +57,6 @@ function groupScopeMeta(value: Record, meta: ScopeMeta): Explor value: value[key], }); } - return structure; } diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx index 5fd6910b048..ec4c7ae8459 100644 --- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx +++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/BindableEditor.tsx @@ -31,7 +31,7 @@ export interface BindableEditorProps extends WithControlledProp; globalScopeMeta: ScopeMeta; - envVarNames?: string[]; + env?: Record; sx?: SxProps; } @@ -47,7 +47,7 @@ export default function BindableEditor({ liveBinding, globalScope = {}, globalScopeMeta = {}, - envVarNames, + env, sx, }: BindableEditorProps) { const propTypeControls = usePropControlsContext(); @@ -103,7 +103,7 @@ export default function BindableEditor({ disabled={disabled || !bindable} hidden={!bindable} liveBinding={liveBinding} - envVarNames={envVarNames} + env={env} /> diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx index 57f6f67acfc..1f03f33dc12 100644 --- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx +++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/ParametersEditor.tsx @@ -16,7 +16,7 @@ export interface StringRecordEntriesEditorProps autoFocus?: boolean; sx?: SxProps; jsRuntime: JsRuntime; - envVarNames?: string[]; + env?: Record; disabled?: boolean; } @@ -33,7 +33,7 @@ export default function ParametersEditor({ jsRuntime, disabled, globalScopeMeta, - envVarNames, + env, }: StringRecordEntriesEditorProps) { const fieldInputRef = React.useRef(null); @@ -84,7 +84,7 @@ export default function ParametersEditor({ onChange(value.map((entry, i) => (i === index ? [entry[0], newBinding] : entry))) } disabled={disabled} - envVarNames={envVarNames} + env={env} /> diff --git a/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx b/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx index dcad772a52b..ef59a0e469d 100644 --- a/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx +++ b/packages/toolpad-app/src/toolpadDataSources/rest/client.tsx @@ -15,8 +15,7 @@ import { } from '@mui/material'; import { Controller, useForm } from 'react-hook-form'; import { TabContext, TabList } from '@mui/lab'; -import { useBrowserJsRuntime } from '@mui/toolpad-core/jsBrowserRuntime'; -import { useServerJsRuntime } from '@mui/toolpad-core/jsServerRuntime'; +import { createServerJsRuntime } from '@mui/toolpad-core/jsServerRuntime'; import { Panel, PanelGroup, PanelResizeHandle } from '../../components/resizablePanels'; import { ClientDataSource, ConnectionEditorProps, QueryEditorProps } from '../../types'; import { @@ -266,8 +265,8 @@ function QueryEditor({ }, { retry: false }, ); - const envVarNames = React.useMemo(() => introspection?.data?.envVarNames || [], [introspection]); + const env = React.useMemo(() => introspection?.data?.env, [introspection]); const handleParamsChange = React.useCallback( (newParams: [string, BindableAttrValue][]) => { setInput((existing) => ({ ...existing, params: newParams })); @@ -334,12 +333,10 @@ function QueryEditor({ ); const paramsEntries = input.params || EMPTY_PARAMS; - - const jsBrowserRuntime = useBrowserJsRuntime(); - const jsServerRuntime = useServerJsRuntime(); + const jsServerRuntime = React.useMemo(() => createServerJsRuntime(env ?? {}), [env]); const paramsEditorLiveValue = useEvaluateLiveBindingEntries({ - jsRuntime: jsBrowserRuntime, + jsRuntime: jsServerRuntime, input: paramsEntries, globalScope, }); @@ -482,7 +479,7 @@ function QueryEditor({ globalScopeMeta={QUERY_SCOPE_META} liveValue={liveHeaders} jsRuntime={jsServerRuntime} - envVarNames={envVarNames} + env={env} /> @@ -530,7 +527,8 @@ function QueryEditor({ globalScope={globalScope} globalScopeMeta={globalScopeMeta} liveValue={paramsEditorLiveValue} - jsRuntime={jsBrowserRuntime} + jsRuntime={jsServerRuntime} + env={env} /> diff --git a/packages/toolpad-app/src/toolpadDataSources/rest/server.ts b/packages/toolpad-app/src/toolpadDataSources/rest/server.ts index c2bcdff1f1d..bf490d91609 100644 --- a/packages/toolpad-app/src/toolpadDataSources/rest/server.ts +++ b/packages/toolpad-app/src/toolpadDataSources/rest/server.ts @@ -136,21 +136,21 @@ async function execBase( project: IToolpadProject, connection: Maybe, fetchQuery: FetchQuery, - params: Record, + params: Record>, ): Promise { const har = createHarLog(); const instrumentedFetch = withHarInstrumentation(fetch, { har }); const jsRuntime = createServerJsRuntime(process.env); + const resolvedParams = resolveBindableEntries(jsRuntime, Object.entries(params), {}); const queryScope = { // @TODO: remove deprecated query after v1 query: params, - parameters: params, + parameters: Object.fromEntries(resolvedParams), }; const runtimeConfig = await project.getRuntimeConfig(); const urlvalue = fetchQuery.url || getDefaultUrl(runtimeConfig, connection); - const resolvedUrl = resolveBindable(jsRuntime, urlvalue, queryScope); const resolvedSearchParams = resolveBindableEntries( jsRuntime, @@ -211,7 +211,6 @@ async function execBase( } catch (rawError) { error = serializeError(errorFrom(rawError)); } - return { data, untransformedData, error, har }; } @@ -232,9 +231,7 @@ export default function createDatasource( switch (query.kind) { case 'introspection': { const env = await loadEnvFile(project); - const envVarNames = Object.keys(env); - - return { envVarNames }; + return { env }; } case 'debugExec': return execBase(project, connection, query.query, query.params); diff --git a/packages/toolpad-app/src/toolpadDataSources/rest/types.ts b/packages/toolpad-app/src/toolpadDataSources/rest/types.ts index eaf590346fd..f7ea42e80e4 100644 --- a/packages/toolpad-app/src/toolpadDataSources/rest/types.ts +++ b/packages/toolpad-app/src/toolpadDataSources/rest/types.ts @@ -125,5 +125,5 @@ export interface FetchResult extends ExecFetchResult { } export type IntrospectionResult = { - envVarNames: string[]; + env: Record; };