From cb192a945ba40858ddf4490c4e14abb8ce1aaeb1 Mon Sep 17 00:00:00 2001 From: desiprisg Date: Fri, 8 Nov 2024 14:06:08 +0200 Subject: [PATCH] feat(dashboard): Autosuggestions for step variables --- .../steps/in-app/in-app-body.tsx | 9 +++- .../steps/in-app/in-app-subject.tsx | 8 ++- .../steps/in-app/in-app-tabs.tsx | 1 + .../utils/parseJSONSchemaToEditorVariables.ts | 49 +++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 apps/dashboard/src/utils/parseJSONSchemaToEditorVariables.ts diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-body.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-body.tsx index b43e4e801da9..ff6f20c12bbb 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-body.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-body.tsx @@ -6,6 +6,9 @@ import { FormControl, FormField, FormItem, FormMessage } from '@/components/prim import { InputField } from '@/components/primitives/input'; import { Editor } from '@/components/primitives/editor'; import { capitalize } from '@/utils/string'; +import { useFetchStep } from '@/hooks/use-fetch-step'; +import { useParams } from 'react-router-dom'; +import { parseJSONSchemaToLiquidVariables } from '@/utils/parseJSONSchemaToEditorVariables'; const bodyKey = 'body'; @@ -15,6 +18,10 @@ export const InAppBody = () => { formState: { errors }, } = useFormContext(); + const { workflowSlug = '', stepSlug = '' } = useParams<{ workflowSlug: string; stepSlug: string }>(); + + const { step } = useFetchStep({ workflowSlug, stepSlug }); + return ( { id={field.name} extensions={[ liquid({ - variables: [{ type: 'variable', label: 'asdf' }], + variables: step ? parseJSONSchemaToLiquidVariables(step.variables as any) : [], }), EditorView.lineWrapping, ]} diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-subject.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-subject.tsx index 0daf67acd719..21f36c9ce54b 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-subject.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-subject.tsx @@ -6,6 +6,9 @@ import { FormControl, FormField, FormItem, FormMessage } from '@/components/prim import { InputField } from '@/components/primitives/input'; import { Editor } from '@/components/primitives/editor'; import { capitalize } from '@/utils/string'; +import { useParams } from 'react-router-dom'; +import { useFetchStep } from '@/hooks/use-fetch-step'; +import { parseJSONSchemaToLiquidVariables } from '@/utils/parseJSONSchemaToEditorVariables'; const subjectKey = 'subject'; @@ -14,6 +17,9 @@ export const InAppSubject = () => { control, formState: { errors }, } = useFormContext(); + const { workflowSlug = '', stepSlug = '' } = useParams<{ workflowSlug: string; stepSlug: string }>(); + + const { step } = useFetchStep({ workflowSlug, stepSlug }); return ( { id={field.name} extensions={[ liquid({ - variables: [{ type: 'variable', label: 'asdf' }], + variables: step ? parseJSONSchemaToLiquidVariables(step.variables as any) : [], }), EditorView.lineWrapping, ]} diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx index ade24ef0d9b5..1eaaf7c6462f 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx @@ -97,6 +97,7 @@ export const InAppTabs = ({ workflow, step }: { workflow: WorkflowResponseDto; s }); setEditorValue(JSON.stringify(res.previewPayloadExample, null, 2)); }; + const formValues = useWatch(form); useDebouncedEffect( () => { diff --git a/apps/dashboard/src/utils/parseJSONSchemaToEditorVariables.ts b/apps/dashboard/src/utils/parseJSONSchemaToEditorVariables.ts new file mode 100644 index 000000000000..dad26a50af05 --- /dev/null +++ b/apps/dashboard/src/utils/parseJSONSchemaToEditorVariables.ts @@ -0,0 +1,49 @@ +interface JSONSchema { + type: string; + properties?: Record; + items?: JSONSchema; + description?: string; +} + +interface LiquidVariable { + type: 'variable'; + label: string; + detail: string; +} + +/** + * Parse JSON Schema and extract variables for Liquid autocompletion. + * @param schema - The JSON Schema to parse. + * @returns An array of variable objects suitable for the Liquid language. + */ +export function parseJSONSchemaToLiquidVariables(schema: JSONSchema): LiquidVariable[] { + const variables: LiquidVariable[] = []; + + function extractProperties(obj: JSONSchema, path = ''): void { + if (!obj || typeof obj !== 'object') return; + + if (obj.type === 'object' && obj.properties) { + for (const [key, value] of Object.entries(obj.properties)) { + const fullPath = path ? `${path}.${key}` : key; + + // Add each property as a variable for autocompletion + variables.push({ + type: 'variable', + label: `{{${fullPath}}}`, + detail: value.description || 'JSON Schema variable', + }); + + // Recursively process nested objects + if (value.type === 'object' || value.type === 'array') { + extractProperties(value, fullPath); + } + } + } else if (obj.type === 'array' && obj.items) { + // For arrays, add a placeholder for array indexing + extractProperties(obj.items, `${path}[0]`); + } + } + + extractProperties(schema); + return variables; +}