Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix environment binding preview #3413

Merged
merged 1 commit into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/toolpad-studio/src/server/EnvManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export default class EnvManager {
this.watcher.on('change', handleChange);
}

async getDeclaredValues(): Promise<Record<string, string>> {
return this.values;
async getDeclaredKeys(): Promise<string[]> {
return Object.keys(this.values);
}

// eslint-disable-next-line class-methods-use-this
Expand Down
54 changes: 31 additions & 23 deletions packages/toolpad-studio/src/toolpad/AppEditor/BindingEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,12 @@ interface BindingEditorContext {
label: string;
globalScope: Record<string, unknown>;
globalScopeMeta: ScopeMeta;
/**
* Serverside binding, use the QuickJs runtime to evaluate bindings
*/
jsRuntime: JsRuntime;
disabled?: boolean;
propType?: PropValueType;
liveBinding?: LiveBinding;
env?: Record<string, string>;
env: Record<string, string | undefined>;
declaredEnvKeys: string[];
}

const [useBindingEditorContext, BindingEditorContextProvider] =
Expand Down Expand Up @@ -137,13 +135,10 @@ function JsExpressionPreview({ jsRuntime, input, globalScope }: JsExpressionPrev
export interface EnvBindingEditorProps extends WithControlledProp<EnvAttrValue | null> {}

export function EnvBindingEditor({ value, onChange }: EnvBindingEditorProps) {
const context = useBindingEditorContext();
const envVarNames = Object.keys(context.env ?? {});
const { declaredEnvKeys, env } = useBindingEditorContext();
const handleInputChange = React.useCallback(
(event: React.SyntheticEvent, newValue: string | null) => {
onChange({
$$env: newValue || '',
});
onChange({ $$env: newValue || '' });
},
[onChange],
);
Expand All @@ -153,7 +148,7 @@ export function EnvBindingEditor({ value, onChange }: EnvBindingEditorProps) {
<Typography>Assign to an environment variable</Typography>
<Autocomplete
freeSolo
options={envVarNames}
options={declaredEnvKeys}
value={value?.$$env || ''}
onInputChange={handleInputChange}
renderInput={(params) => (
Expand All @@ -163,23 +158,25 @@ export function EnvBindingEditor({ value, onChange }: EnvBindingEditorProps) {
sx={{ my: 3 }}
label="Environment variable name"
helperText={
value?.$$env && !envVarNames.includes(value.$$env)
value?.$$env && !declaredEnvKeys.includes(value.$$env)
? 'Warning: This variable is not in your env file!'
: ''
}
/>
)}
/>
Value:
<JsonView sx={{ flex: 1 }} src={value?.$$env ? env[value?.$$env] : undefined} />
</Box>
);
}

function getValueBindingTab(value: Maybe<BindableAttrValue<any>>) {
if (value?.$$env) {
return 'env';
if (value?.$$env === undefined) {
return 'jsExpression';
}

return 'jsExpression';
return 'env';
}

export interface ValueBindingEditorProps
Expand Down Expand Up @@ -207,6 +204,7 @@ export function ValueBindingEditor({ value, onChange, error }: ValueBindingEdito
const handleTabChange = (event: React.SyntheticEvent, newValue: BindableType) => {
setActiveTab(newValue);
};

const jsExpressionBindingEditor = (
<Stack direction="row" sx={{ height: 400, gap: 2, my: hasEnv ? 3 : 0 }}>
<GlobalScopeExplorer sx={{ width: 250 }} value={globalScope} meta={globalScopeMeta} />
Expand Down Expand Up @@ -254,15 +252,11 @@ export function ValueBindingEditor({ value, onChange, error }: ValueBindingEdito

const envBindingEditor = (
<EnvBindingEditor
value={(value as EnvAttrValue)?.$$env ? (value as EnvAttrValue) : null}
value={(value as EnvAttrValue)?.$$env !== undefined ? (value as EnvAttrValue) : null}
onChange={onChange}
/>
);

if (!hasEnv) {
return jsExpressionBindingEditor;
}

return (
<TabContext value={activeTab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
Expand Down Expand Up @@ -594,7 +588,8 @@ export function BindingEditorDialog<V>({
<ValueBindingEditor
error={error}
value={
(input as JsExpressionAttrValue)?.$$jsExpression || (input as EnvAttrValue)?.$$env
(input as JsExpressionAttrValue)?.$$jsExpression !== undefined ||
(input as EnvAttrValue)?.$$env !== undefined
? (input as JsExpressionAttrValue | EnvAttrValue)
: null
}
Expand Down Expand Up @@ -629,7 +624,8 @@ export interface BindingEditorProps<V> extends WithControlledProp<BindableAttrVa
hidden?: boolean;
propType?: PropValueType;
liveBinding?: LiveBinding;
env?: Record<string, string>;
env?: Record<string, string | undefined>;
declaredEnvKeys?: string[];
}

export function BindingEditor<V>({
Expand All @@ -644,6 +640,7 @@ export function BindingEditor<V>({
onChange,
liveBinding,
env,
declaredEnvKeys,
}: BindingEditorProps<V>) {
const [open, setOpen] = React.useState(false);
const handleOpen = React.useCallback(() => setOpen(true), []);
Expand Down Expand Up @@ -700,9 +697,20 @@ export function BindingEditor<V>({
disabled,
propType,
liveBinding,
env,
env: env ?? {},
declaredEnvKeys: declaredEnvKeys ?? [],
}),
[disabled, env, globalScope, jsRuntime, label, liveBinding, propType, resolvedMeta],
[
disabled,
env,
globalScope,
jsRuntime,
label,
liveBinding,
propType,
resolvedMeta,
declaredEnvKeys,
],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export interface BindableEditorProps<V> extends WithControlledProp<BindableAttrV
liveBinding?: LiveBinding;
globalScope?: Record<string, unknown>;
globalScopeMeta: ScopeMeta;
env?: Record<string, string>;
env?: Record<string, string | undefined>;
declaredEnvKeys?: string[];
sx?: SxProps;
}

Expand All @@ -54,6 +55,7 @@ export default function BindableEditor<V>({
globalScope = {},
globalScopeMeta = {},
env,
declaredEnvKeys,
sx,
}: BindableEditorProps<V>) {
const propTypeControls = usePropControlsContext();
Expand Down Expand Up @@ -120,6 +122,7 @@ export default function BindableEditor<V>({
hidden={!bindable}
liveBinding={liveBinding}
env={env}
declaredEnvKeys={declaredEnvKeys}
/>
</React.Fragment>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export interface StringRecordEntriesEditorProps
autoFocus?: boolean;
sx?: SxProps;
jsRuntime: JsRuntime;
env?: Record<string, string>;
env?: Record<string, string | undefined>;
declaredEnvKeys?: string[];
disabled?: boolean;
}

Expand All @@ -34,6 +35,7 @@ export default function ParametersEditor({
disabled,
globalScopeMeta,
env,
declaredEnvKeys,
}: StringRecordEntriesEditorProps) {
const fieldInputRef = React.useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -94,6 +96,7 @@ export default function ParametersEditor({
}
disabled={disabled}
env={env}
declaredEnvKeys={declaredEnvKeys}
/>

<IconButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@ function QueryEditor({
[appStateApi],
);

const env = React.useMemo(() => introspection?.data?.env, [introspection]);
const env = React.useMemo(() => introspection?.data?.env ?? {}, [introspection?.data?.env]);
const declaredEnvKeys = React.useMemo(
() => introspection?.data?.declaredEnvKeys ?? [],
[introspection?.data?.declaredEnvKeys],
);
const handleParamsChange = React.useCallback(
(newParams: [string, BindableAttrValue<string>][]) => {
appStateApi.updateQueryDraft((draft) => ({
Expand Down Expand Up @@ -650,6 +654,7 @@ function QueryEditor({
liveValue={paramsEditorLiveValue}
jsRuntime={jsServerRuntime}
env={env}
declaredEnvKeys={declaredEnvKeys}
/>
</TabPanel>
</TabContext>
Expand Down
11 changes: 5 additions & 6 deletions packages/toolpad-studio/src/toolpadDataSources/rest/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@ import {
RawBody,
RestConnectionParams,
UrlEncodedBody,
IntrospectionResult,
} from './types';
import applyTransform from '../applyTransform';
import { HTTP_NO_BODY, getAuthenticationHeaders, parseBaseUrl } from './shared';
import type { IToolpadProject } from '../server';

async function loadEnvFile(project: IToolpadProject) {
return project.envManager.getDeclaredValues();
}

function resolveBindable<T>(
jsRuntime: JsRuntime,
bindable: BindableAttrValue<T>,
Expand Down Expand Up @@ -229,8 +226,10 @@ export default function createDatasource(
async execPrivate(connection: Maybe<RestConnectionParams>, query: FetchPrivateQuery) {
switch (query.kind) {
case 'introspection': {
const env = await loadEnvFile(project);
return { env };
return {
env: process.env,
declaredEnvKeys: await project.envManager.getDeclaredKeys(),
} satisfies IntrospectionResult;
}
case 'debugExec':
return execBase(project, connection, query.query, query.params);
Expand Down
3 changes: 2 additions & 1 deletion packages/toolpad-studio/src/toolpadDataSources/rest/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,6 @@ export interface FetchResult extends ExecFetchResult<any> {
}

export type IntrospectionResult = {
env: Record<string, string>;
env: Record<string, string | undefined>;
declaredEnvKeys: string[];
};
Loading