diff --git a/apps/web/components/imports/editor/Editor.tsx b/apps/web/components/imports/editor/Editor.tsx
index b32faaf8f..9ede8cb4b 100644
--- a/apps/web/components/imports/editor/Editor.tsx
+++ b/apps/web/components/imports/editor/Editor.tsx
@@ -49,6 +49,9 @@ export function OutputEditor({ templateId, switchToDestination }: OutputEditorPr
isSyncCustomizationLoading,
isCustomizationLoading,
isDestinationLoading,
+ allVariables,
+ formatVariableDisplay,
+ isSystemVariable,
} = useEditor({
templateId,
});
@@ -98,7 +101,7 @@ export function OutputEditor({ templateId, switchToDestination }: OutputEditorPr
id="format"
value={field.value}
onChange={field.onChange}
- variables={[...(customization?.recordVariables || []), ...(customization?.chunkVariables || [])]}
+ variables={allVariables}
/>
)}
/>
@@ -107,14 +110,16 @@ export function OutputEditor({ templateId, switchToDestination }: OutputEditorPr
- {customization?.chunkVariables.map((variable) => (
-
+ {allVariables.filter(isSystemVariable).map((variable) => (
+
))}
- {customization?.recordVariables.map((variable) => (
-
- ))}
+ {allVariables
+ .filter((variable) => !isSystemVariable(variable))
+ .map((variable) => (
+
+ ))}
diff --git a/apps/web/components/imports/validator/Validator.tsx b/apps/web/components/imports/validator/Validator.tsx
index 60c95816d..94688538f 100644
--- a/apps/web/components/imports/validator/Validator.tsx
+++ b/apps/web/components/imports/validator/Validator.tsx
@@ -20,13 +20,19 @@ import { useValidator } from '@hooks/useValidator';
import { VarItemWrapper } from '../editor/VarItemWrapper';
import { InformationIcon } from '@assets/icons/Information.icon';
import { TooltipLink } from '@components/guide-point';
+import { useMemo } from 'react';
+import { useEditor } from '@hooks/useEditor';
+import { DestinationsEnum } from '@impler/shared';
interface ValidatorProps {
templateId: string;
}
export function Validator({ templateId }: ValidatorProps) {
- const systemVariables = [
+ const { destination } = useEditor({ templateId });
+
+ // Existing system variables
+ const baseSystemVariables = [
'params.uploadId',
'params.fileName',
'params.data',
@@ -34,12 +40,26 @@ export function Validator({ templateId }: ValidatorProps) {
'params.totalRecords',
'params.chunkSize',
];
+
+ // Bubble.io specific system variables
+ const bubbleIoSystemVariables = ['extra.uploadId', 'extra.userId'];
+
const { colorScheme } = useMantineColorScheme();
const { control, editorVariables, onSave, isUpdateValidationsLoading, isValidationsLoading, testCodeResult } =
useValidator({
templateId,
});
+ // Combine all variables: base system variables + editor variables + Bubble.io variables (if applicable)
+ const allVariables = useMemo(() => {
+ const variables = [...baseSystemVariables, ...editorVariables];
+ if (destination?.destination === DestinationsEnum.BUBBLEIO) {
+ variables.push(...bubbleIoSystemVariables);
+ }
+
+ return variables;
+ }, [destination?.destination, editorVariables]);
+
return (
@@ -124,7 +144,7 @@ export function Validator({ templateId }: ValidatorProps) {
mode="javascript"
value={field.value}
onChange={field.onChange}
- variables={[...systemVariables]}
+ variables={allVariables}
/>
)}
/>
@@ -134,15 +154,10 @@ export function Validator({ templateId }: ValidatorProps) {
- {systemVariables.map((variable) => (
+ {allVariables.map((variable) => (
))}
-
- {editorVariables.map((variable) => (
-
- ))}
-
diff --git a/apps/web/hooks/useEditor.tsx b/apps/web/hooks/useEditor.tsx
index 078148118..6402bb475 100644
--- a/apps/web/hooks/useEditor.tsx
+++ b/apps/web/hooks/useEditor.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from 'react';
+import { useEffect, useMemo } from 'react';
import { useForm } from 'react-hook-form';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
@@ -83,6 +83,38 @@ export function useEditor({ templateId }: UseEditorProps) {
}
);
+ // Combine all variables: record variables + chunk variables + system variables
+ const allVariables = useMemo(() => {
+ const variables = [];
+
+ // Add schema variables (from record format)
+ if (customization?.recordVariables) {
+ variables.push(...customization.recordVariables.map((variable) => variable.substring(2, variable.length - 2)));
+ }
+
+ // Add system variables (from chunk format)
+ if (customization?.chunkVariables) {
+ variables.push(...customization.chunkVariables);
+ }
+
+ // Add Bubble.io specific system variables
+ if (destination?.destination === DestinationsEnum.BUBBLEIO) {
+ variables.push('extra.uploadId', 'extra.userId');
+ }
+
+ return variables;
+ }, [customization?.recordVariables, customization?.chunkVariables, destination?.destination]);
+
+ // Helper function to format variable display
+ const formatVariableDisplay = (variable: string) => {
+ return `"${variable}"`;
+ };
+
+ // Helper function to categorize variables
+ const isSystemVariable = (variable: string) => {
+ return variable.startsWith('extra.') || variable.startsWith('params.');
+ };
+
const validateFormat = (data: string): boolean => {
try {
JSON.parse(data);
@@ -137,10 +169,13 @@ export function useEditor({ templateId }: UseEditorProps) {
onSaveClick,
destination,
handleSubmit,
+ allVariables,
customization,
+ isSystemVariable,
syncCustomization,
updateCustomization,
isDestinationLoading,
+ formatVariableDisplay,
isCustomizationLoading,
isSyncCustomizationLoading,
isUpdateCustomizationLoading,
diff --git a/apps/web/hooks/useValidator.tsx b/apps/web/hooks/useValidator.tsx
index 4a46cacf9..18ccb05fc 100644
--- a/apps/web/hooks/useValidator.tsx
+++ b/apps/web/hooks/useValidator.tsx
@@ -7,7 +7,7 @@ import { notify } from '@libs/notify';
import { commonApi } from '@libs/api';
import { track } from '@libs/amplitude';
import { API_KEYS, MODAL_KEYS, MODAL_TITLES } from '@config';
-import { ICustomization, IErrorObject, IValidator } from '@impler/shared';
+import { ICustomization, IErrorObject, IValidator, DestinationsEnum } from '@impler/shared';
import { CodeOutput } from '@components/imports/validator/CodeOutput';
interface UseSchemaProps {
@@ -43,9 +43,14 @@ export function useValidator({ templateId }: UseSchemaProps) {
() => commonApi(API_KEYS.TEMPLATE_CUSTOMIZATION_GET as any, { parameters: [templateId] }),
{
onSuccess(data) {
- setEditorVariables([
- ...(data.recordVariables.map((variable) => variable.substring(2, variable.length - 2)) || []),
- ]);
+ // Get base variables from customization
+ const baseVariables = data.recordVariables?.map((variable) => variable.substring(2, variable.length - 2)) || [];
+
+ // Add static Bubble.io variables if destination is Bubble.io
+ const bubbleIoVariables =
+ data.destination === DestinationsEnum.BUBBLEIO ? ['extra.uploadId', 'extra.userId'] : [];
+
+ setEditorVariables([...baseVariables, ...bubbleIoVariables]);
},
}
);
diff --git a/libs/shared/src/entities/Customization/Customization.interface.ts b/libs/shared/src/entities/Customization/Customization.interface.ts
index 198b8b13b..c0735fb4b 100644
--- a/libs/shared/src/entities/Customization/Customization.interface.ts
+++ b/libs/shared/src/entities/Customization/Customization.interface.ts
@@ -1,6 +1,9 @@
+import { DestinationsEnum } from '../../types/destination/destination.types';
+
export interface ICustomization {
_id: string;
_templateId: string;
+ destination: DestinationsEnum;
recordVariables: string[];
chunkVariables: string[];
recordFormat: string;
diff --git a/libs/shared/src/utils/output.helpers.ts b/libs/shared/src/utils/output.helpers.ts
index 170a68000..024e040b0 100644
--- a/libs/shared/src/utils/output.helpers.ts
+++ b/libs/shared/src/utils/output.helpers.ts
@@ -148,3 +148,17 @@ export function getRecordFormat(chunkFormat: string) {
chunkFormat: JSON.stringify(format),
};
}
+
+export function extractExtraSystemVariables(format: string): string[] {
+ const variablePattern = /\{\{([^}]+)\}\}/g;
+ const variables: string[] = [];
+ let match;
+
+ while ((match = variablePattern.exec(format)) !== null) {
+ variables.push(match[1]);
+ }
+
+ const systemVariables = variables.filter((variable) => variable.startsWith('extra.'));
+
+ return systemVariables;
+}