Untitled
unknown
plain_text
5 months ago
22 kB
1
Indexable
import { StoreApi } from 'zustand'; import { AllowedDataType, ExecutedInOut, Input, InputSlug, NodeSystemType, SelectedDataType, WorkFlowNode, } from '@/app/workflows/[slug]/components/workflow.data'; import { executeFunction } from '@/actions/workflow/functionActions'; import { FieldData } from '@/lib/form/schema'; import { GetFieldKey, prepareSubmitData, } from '@/app/workflows/[slug]/components/WorkflowMain/nodes/Utils/formUtils'; import { FormEvents, FormStore } from './formTypes'; import { AutomationExecutionStore, NodesOutput } from './formAutomation.store'; import BE_API_V1 from '@/lib/api/api'; import { formEventSystem } from '@/app/forms/[formId]/components/preview/context/formEventSystem'; // Helper functions for node execution function resolveVariableInput( input: Input | undefined, executionContext: { [key: string]: any }, ): any { if (!input || !input.selected_data) { return undefined; } if (input.selected_data.selected_data_type === SelectedDataType.Expr) { const expr = input.selected_data.data as string; return expr.replace(/\{\{(.*?)\}\}/g, (match, variable) => { return executionContext[variable.trim()] || match; }); } return input.selected_data.data; } // Helper functions for node execution function resolveVariableInputv2( input: Input | undefined, nodesOutput: NodesOutput, ): any { if (!input || !input.selected_data) { return undefined; } if (input.selected_data.selected_data_type === SelectedDataType.Expr) { const expr = input.selected_data.data as string; return expr.replace(/\{@([\w._-]+)\}/g, (match, variable) => { const keys = variable.split('.'); return nodesOutput[`${keys[0]}.${keys[1]}`].data || match; }); } return input.selected_data.data; } function findFieldLocation(fieldId: string, formStore: any) { const state = formStore.getState(); for (const tab of state.tabs) { for (const section of tab.sections) { for (const row of section.rows) { for (const column of row.columns) { for (const component of column.component) { if (component.id === fieldId) { return { tabId: tab.id, sectionId: section.id, rowId: row.id, columnId: column.id, component, }; } } } } } } return null; } function findSecionLocation(sectionId: string, formStore: any) { const state = formStore.getState(); for (const tab of state.tabs) { for (const section of tab.sections) { if (section.id === sectionId) { return { tabId: tab.id, section, }; } } } return null; } function findTabLocation(tabId: string, formStore: any) { const state = formStore.getState(); for (const tab of state.tabs) { if (tab.id === tabId) { return { tab, }; } } return null; } export function getFrontendAutomationEventsFromType( systemType?: NodeSystemType, ): FormEvents { switch (systemType) { case NodeSystemType.FromOnLoad: return FormEvents.FORM_ON_LOAD; case NodeSystemType.ButtonOnClick: return FormEvents.BUTTON_ON_CLICK; case NodeSystemType.FieldOnChange: return FormEvents.FIELD_CHANGE; default: console.log('Unknown Type'); } return FormEvents.FORM_ON_LOAD; } // Trigger Handlers export function handleFormOnLoad(): ExecutedInOut { return { inputs: [], outputs: [ { data_type: AllowedDataType.DataTypeForm, slug: 'form_slug', data: '', has_many: false, }, ], run_status: 1, }; } export async function handleButtonOnClick( node: WorkFlowNode, nodesOutput: NodesOutput, ): Promise<ExecutedInOut> { const buttonId = resolveVariableInputv2( node?.inputs?.find((input) => input.slug === InputSlug.ButtonOnClick), nodesOutput, ); const inOut = { inputs: [ { data_type: AllowedDataType.DataTypeText, slug: InputSlug.ButtonOnClick, data: buttonId, has_many: false, }, ], outputs: [], run_status: 1, }; return inOut; } export async function handleTabOnSubmit( node: WorkFlowNode, formStore: StoreApi<AutomationExecutionStore>, executionContext: { [key: string]: any }, ): Promise<ExecutedInOut> { const tabId = resolveVariableInput( node?.inputs?.find((input) => input.slug === InputSlug.FormTabs), executionContext, ); // Implement tab submit logic using formStore return { inputs: [ { data_type: AllowedDataType.DataTypeText, slug: InputSlug.FormTabs, data: tabId, has_many: false, }, ], outputs: [], run_status: 1, }; } // Implement other handler functions similarly, using formStore to interact with form data export async function handleSetFields( node: WorkFlowNode, formStore: StoreApi<FormStore>, nodesOutput: NodesOutput, ): ExecutedInOut { const executedInOut: ExecutedInOut = { inputs: [], outputs: [], run_status: 1, }; try { const fieldsInput = node.inputs?.find( (input) => input.slug === InputSlug.FormFields, ); const fieldIds = resolveVariableInputv2( fieldsInput, nodesOutput, ) as string[]; if (!fieldIds || !Array.isArray(fieldIds)) { throw new Error('Invalid or missing field IDs'); } const { setFormValue } = formStore.getState(); const getField = formStore.getState().getComponentFieldData; fieldIds.forEach((fieldId) => { const attributeInput = node.inputs?.find( (input) => input.slug === `${InputSlug.AttributeSlugPrefix}${fieldId}`, ); if (attributeInput) { const value = resolveVariableInputv2(attributeInput, nodesOutput); const field = getField(fieldId); if (field) { const fieldData = field as FieldData; const key = GetFieldKey(fieldData); setFormValue(key, value); executedInOut?.inputs?.push({ data_type: attributeInput.allowed_data_types.type, slug: attributeInput.slug, data: value, has_many: attributeInput.allow_many ?? false, }); } } }); return executedInOut; } catch (error: any) { executedInOut.run_status = -1; executedInOut.error = error.message; return executedInOut; } } export async function handleTabSubmit( formStore: StoreApi<FormStore>, ): Promise<ExecutedInOut> { const {} = formStore.getState(); const inOut: ExecutedInOut = { outputs: [], run_status: 1, }; return inOut; } export async function handleFormSubmit( formStore: StoreApi<FormStore>, ): Promise<ExecutedInOut> { const {} = formStore.getState(); const inOut: ExecutedInOut = { outputs: [], run_status: 1, }; formEventSystem.notify(FormEvents.ON_FORM_SUBMIT, { action: FormEvents.ON_FORM_SUBMIT, }); return new Promise((resolve) => { const listener = (result: any) => { formEventSystem.unsubscribe(id); inOut.outputs?.push({ data_type: AllowedDataType.DataTypeObject, slug: InputSlug.SubmitForm, data: result, has_many: false, }); resolve(inOut); }; const id = formEventSystem.subscribe( FormEvents.ON_FORM_SUBMITTED, listener, ); }); } export function handleFieldOnChange( node: WorkFlowNode, formStore: any, nodesOutput: NodesOutput, ): ExecutedInOut { const fields = resolveVariableInputv2( node?.inputs?.find((input) => input.slug === InputSlug.FormFields), nodesOutput, ) as string[]; const inputs: any[] = []; fields.forEach((field) => { const value = resolveVariableInput( node?.inputs?.find( (input) => input.slug === `${InputSlug.AttributeSlugPrefix}${field}`, ), formStore.getState().executionContext, ); inputs.push({ data_type: AllowedDataType.DataTypeText, slug: `${InputSlug.AttributeSlugPrefix}${field}`, data: value, has_many: false, }); formStore.setFieldValue(field, value); }); return { inputs: [ { data_type: AllowedDataType.DataTypeText, slug: InputSlug.FormFields, data: fields, has_many: true, }, ...inputs, ], outputs: [], run_status: 1, }; } export function handleFieldShowHide( node: WorkFlowNode, formStore: any, ): ExecutedInOut { const executedInOut: ExecutedInOut = { inputs: [], outputs: [], run_status: 1, }; try { // Extract inputs from node const targetFieldsInput = node?.inputs?.find( (input) => input.slug === InputSlug.FormFields, ); const showHideInput = node?.inputs?.find( (input) => input.slug === InputSlug.FieldShowHide, ); if (!targetFieldsInput || !showHideInput) { return executedInOut; } const fieldIds = targetFieldsInput.selected_data?.data as string[]; // Assuming it's an array of field IDs const action = showHideInput?.selected_data?.data as 'show' | 'hide'; const input = { data_type: targetFieldsInput.allowed_data_types.type, slug: targetFieldsInput.slug, has_many: targetFieldsInput.allow_many ?? false, data: targetFieldsInput.selected_data, }; executedInOut?.inputs?.push(input); fieldIds.forEach((fieldId: string) => { // Get the field's location in the form const fieldLocation = findFieldLocation(fieldId, formStore); if (!fieldLocation) { return; } // Update the field's visibility formStore .getState() .updateComponent( fieldLocation.tabId, fieldLocation.sectionId, fieldLocation.rowId, fieldLocation.columnId, fieldId, { data: { ...fieldLocation.component.data, hide_by_default: action === 'hide', }, }, ); }); return executedInOut; } catch (error: any) { executedInOut.run_status = -1; executedInOut.error = error.message; return executedInOut; } } export function handleTabShowHide( node: WorkFlowNode, formStore: any, ): ExecutedInOut { const executedInOut: ExecutedInOut = { inputs: [], outputs: [], run_status: 1, }; try { const targetTab = node?.inputs?.find( (input) => input.slug === InputSlug.FormTabs, ); const showHideInput = node?.inputs?.find( (input) => input.slug === InputSlug.FieldShowHide, ); if (!targetTab || !showHideInput) { return executedInOut; } const tabId = targetTab.selected_data?.data as string; const action = showHideInput?.selected_data?.data as 'show' | 'hide'; const input = { data_type: targetTab.allowed_data_types.type, slug: targetTab.slug, has_many: targetTab.allow_many ?? false, data: targetTab.selected_data, }; executedInOut?.inputs?.push(input); // Now, perform the show/hide action on the formStore // Get the tab's location in the form const tabLocation = findTabLocation(tabId, formStore); if (!tabLocation) { return { ...executedInOut, run_status: -1, }; } const updatedTabData = { ...tabLocation.tab, hide_by_default: action === 'hide', }; // Update the tab's visibility formStore.getState().updateTab(tabLocation.tab.id, updatedTabData); return executedInOut; } catch (error: any) { executedInOut.run_status = -1; executedInOut.error = error.message; return executedInOut; } } export function handleSectionShowHide( node: WorkFlowNode, formStore: any, ): ExecutedInOut { const executedInOut: ExecutedInOut = { inputs: [], outputs: [], run_status: 1, }; try { // Extract inputs from node const targetSection = node?.inputs?.find( (input) => input.slug === InputSlug.FormSections, ); const showHideInput = node?.inputs?.find( (input) => input.slug === InputSlug.FieldShowHide, ); if (!targetSection || !showHideInput) { return executedInOut; } const sectionId = targetSection.selected_data?.data as string; const action = showHideInput?.selected_data?.data as 'show' | 'hide'; const input = { data_type: targetSection.allowed_data_types.type, slug: targetSection.slug, has_many: targetSection.allow_many ?? false, data: targetSection.selected_data, }; executedInOut?.inputs?.push(input); // Now, perform the show/hide action on the formStore // Get the section's location in the form const sectionLocation = findSecionLocation(sectionId, formStore); if (!sectionLocation) { return { ...executedInOut, run_status: -1, }; } const updatedSectionData = { ...sectionLocation.section, hide_by_default: action === 'hide', }; // Update the section's visibility formStore .getState() .updateSection( sectionLocation.tabId, sectionLocation.section.id, updatedSectionData, ); return executedInOut; } catch (error: any) { executedInOut.run_status = -1; executedInOut.error = error.message; return executedInOut; } } export function handleReadOrWrite( node: WorkFlowNode, formStore: any, ): ExecutedInOut { const executedInOut: ExecutedInOut = { inputs: [], outputs: [], run_status: 1, }; try { // Extract inputs from node const targetFieldsInput = node?.inputs?.find( (input) => input.slug === InputSlug.FormFields, ); const readAndWrite = node?.inputs?.find( (input) => input.slug === InputSlug.FieldReadWrite, ); if (!targetFieldsInput || !readAndWrite) { return executedInOut; } const fieldIds = targetFieldsInput.selected_data?.data as string[]; // Assuming it's an array of field IDs const action = readAndWrite?.selected_data?.data as 'read' | 'write'; const input = { data_type: targetFieldsInput.allowed_data_types.type, slug: targetFieldsInput.slug, has_many: targetFieldsInput.allow_many ?? false, data: targetFieldsInput.selected_data, }; executedInOut?.inputs?.push(input); // Now, perform the show/hide action on the formStore fieldIds.forEach((fieldId: string) => { // Get the field's location in the form const fieldLocation = findFieldLocation(fieldId, formStore); if (!fieldLocation) { return; } // Update the field's visibility formStore .getState() .updateComponent( fieldLocation.tabId, fieldLocation.sectionId, fieldLocation.rowId, fieldLocation.columnId, fieldId, { data: { ...fieldLocation.component.data, disabled: action === 'read', }, }, ); }); return executedInOut; } catch (error: any) { executedInOut.run_status = -1; executedInOut.error = error.message; return executedInOut; } } export function handleMandatory( node: WorkFlowNode, formStore: any, ): ExecutedInOut { const executedInOut: ExecutedInOut = { inputs: [], outputs: [], run_status: 1, }; try { // Extract inputs from node const targetFieldsInput = node?.inputs?.find( (input) => input.slug === InputSlug.FormFields, ); const mandatory = node?.inputs?.find( (input) => input.slug === InputSlug.FieldMandatory, ); if (!targetFieldsInput || !mandatory) { return executedInOut; } const fieldIds = targetFieldsInput.selected_data?.data as string[]; // Assuming it's an array of field IDs const action = mandatory?.selected_data?.data as | 'mandatory' | 'non_mandatory'; const input = { data_type: targetFieldsInput.allowed_data_types.type, slug: targetFieldsInput.slug, has_many: targetFieldsInput.allow_many ?? false, data: targetFieldsInput.selected_data, }; executedInOut?.inputs?.push(input); // Now, perform the show/hide action on the formStore fieldIds.forEach((fieldId: string) => { // Get the field's location in the form const fieldLocation = findFieldLocation(fieldId, formStore); if (!fieldLocation) { return; } // Update the field's visibility formStore .getState() .updateComponent( fieldLocation.tabId, fieldLocation.sectionId, fieldLocation.rowId, fieldLocation.columnId, fieldId, { data: { ...fieldLocation.component.data, validation: { ...fieldLocation.component.data.validation, required: action === 'mandatory', }, }, }, ); }); return executedInOut; } catch (error: any) { executedInOut.run_status = -1; executedInOut.error = error.message; return executedInOut; } } export function handleShowError( node: WorkFlowNode, formStore: any, nodesOutput: NodesOutput, ): ExecutedInOut { const fields = resolveVariableInputv2( node?.inputs?.find((input) => input.slug === InputSlug.FormFields), nodesOutput, ) as string[]; const inputs: any[] = []; fields.forEach((field) => { const value = resolveVariableInputv2( node?.inputs?.find( (input) => input.slug === `${InputSlug.AttributeSlugPrefix}${field}`, ), nodesOutput, ); inputs.push({ data_type: AllowedDataType.DataTypeText, slug: `${InputSlug.AttributeSlugPrefix}${field}`, data: value, has_many: false, }); formStore.setFieldValue(field, value); }); return { inputs: [ { data_type: AllowedDataType.DataTypeText, slug: InputSlug.FormFields, data: fields, has_many: true, }, ...inputs, ], outputs: [], run_status: 1, }; } export async function handleExecuteFunction( node: WorkFlowNode, formStore: any, nodesOutput: NodesOutput, ): Promise<ExecutedInOut> { const functionInput = node?.inputs?.find( (input) => input.slug === InputSlug.Function, ); const bodyInput = node?.inputs?.find( (input) => input.slug === InputSlug.Body, ); const functionData = resolveVariableInput(functionInput, nodesOutput); const fId = functionData.function_id; const bodyData = resolveVariableInput(bodyInput, nodesOutput); try { const data = await executeFunction(fId, JSON.parse(bodyData)); if (data.status === 'completed') { return { inputs: [], outputs: [ { data_type: AllowedDataType.DataTypeInt, slug: 'status_code', data: 200, // TODO has_many: false, }, { data_type: AllowedDataType.DataTypeJson, slug: 'response_body', data: data.result, has_many: false, }, ], run_status: 1, }; } return { inputs: [], outputs: [], run_status: -1, error: data.error, }; } catch (error) { return { inputs: [], outputs: [], run_status: -1, // error: error, }; } } export async function handleSendHttpRequest( node: WorkFlowNode, formStore: any, nodesOutput: NodesOutput, ): Promise<ExecutedInOut> { const urlInput = node?.inputs?.find((input) => input.slug === InputSlug.Url); const methodInput = node?.inputs?.find( (input) => input.slug === InputSlug.RequestType, ); const headersInput = node?.inputs?.find( (input) => input.slug === InputSlug.Headers, ); const bodyInput = node?.inputs?.find( (input) => input.slug === InputSlug.Body, ); const url = resolveVariableInputv2(urlInput, nodesOutput); const method = resolveVariableInputv2(methodInput, nodesOutput); const headers = resolveVariableInputv2(headersInput, nodesOutput); const body = resolveVariableInputv2(bodyInput, nodesOutput); // TODO add headers in better manner and set content type in headers try { const response = await fetch(url, { method, headers, body, }); const responseData = await response.text(); return { inputs: [], outputs: [ { data_type: AllowedDataType.DataTypeInt, slug: 'status_code', data: response.status, has_many: false, }, { data_type: AllowedDataType.DataTypeJson, slug: 'response_body', data: responseData, has_many: false, }, ], run_status: 1, }; } catch (error) { return { inputs: [], outputs: [], run_status: -1, // error: error.message, }; } } export function handleParseJson( node: WorkFlowNode, formStore: any, nodesOutput: NodesOutput, ): ExecutedInOut { const jsonInput = node?.inputs?.find((input) => input.slug === 'json'); const jsonAttributesInput = node?.inputs?.find( (input) => input.slug === InputSlug.JsonAttributes, ); const jsonString = resolveVariableInputv2(jsonInput, nodesOutput); const jsonAttributes = resolveVariableInput(jsonAttributesInput, nodesOutput); let parsedJson; try { parsedJson = JSON.parse(jsonString); } catch (error) { return { inputs: [ { data_type: AllowedDataType.DataTypeText, slug: 'json', data: jsonString, has_many: false, }, ], outputs: [], run_status: -1, error: 'Invalid JSON string', }; } const outputs: any[] = []; jsonAttributes.fields.forEach((field: any) => { const value = field.path .split('$:') .reduce((obj: any, key: string) => obj && obj[key], parsedJson); // const convertedValue = convertToDataType( // value, // field.outputType as AllowedDataType, // field.has_many, // ); outputs.push({ data_type: field.outputType, slug: field.path, data: value, has_many: field.has_many, }); }); return { inputs: [], outputs, run_status: 1, }; }
Editor is loading...
Leave a Comment