Skip to main content
Glama

Activepieces MCP Server

by eldoonreval
test-step-hooks.tsβ€’10.6 kB
import { useMutation } from '@tanstack/react-query'; import dayjs from 'dayjs'; import deepEqual from 'deep-equal'; import { t } from 'i18next'; import { useFormContext, UseFormReturn } from 'react-hook-form'; import { useSocket } from '@/components/socket-provider'; import { INTERNAL_ERROR_TOAST, toast } from '@/components/ui/use-toast'; import { flowRunsApi } from '@/features/flow-runs/lib/flow-runs-api'; import { sampleDataApi } from '@/features/flows/lib/sample-data-api'; import { triggerEventsApi } from '@/features/flows/lib/trigger-events-api'; import { api } from '@/lib/api'; import { wait } from '@/lib/utils'; import { Action, ApErrorParams, ErrorCode, FileType, FlowOperationType, FlowVersion, isNil, parseToJsonIfPossible, PopulatedFlow, StepRunResponse, Trigger, TriggerEventWithPayload, } from '@activepieces/shared'; import { useBuilderStateContext } from '../builder-hooks'; import { testStepUtils } from './test-step-utils'; const useRequiredStateToTestSteps = () => { const form = useFormContext<Trigger>(); const builderState = useBuilderStateContext((state) => ({ flow: state.flow, flowVersion: state.flowVersion, setSampleData: state.setSampleData, setSampleDataInput: state.setSampleDataInput, applyOperation: state.applyOperation, flowVersionId: state.flowVersion.id, projectId: state.flow.projectId, })); return { form, builderState }; }; const testStepHooks = { useSimulateTrigger: ({ setErrorMessage, onSuccess, }: { setErrorMessage: ((msg: string | undefined) => void) | undefined; onSuccess: () => void; }) => { const { form, builderState } = useRequiredStateToTestSteps(); const flowId = builderState.flow.id; return useMutation<TriggerEventWithPayload[], Error, AbortSignal>({ mutationFn: async (abortSignal: AbortSignal) => { setErrorMessage?.(undefined); const ids = ( await triggerEventsApi.list({ flowId, cursor: undefined, limit: 5 }) ).data.map((triggerEvent) => triggerEvent.id); const webhookSimulation = await triggerEventsApi.getWebhookSimulation( flowId, ); if (!webhookSimulation) { await triggerEventsApi.startWebhookSimulation(flowId); } // TODO REFACTOR: replace this with a websocket let attempt = 0; while (attempt < 1000) { if (abortSignal.aborted) { return []; } const newData = await triggerEventsApi.list({ flowId, cursor: undefined, limit: 5, }); const newIds = newData.data.map((triggerEvent) => triggerEvent.id); if (!deepEqual(ids, newIds)) { if (newData.data.length > 0) { await updateTriggerSampleData({ data: newData.data[0], form, builderState, }); } return newData.data; } await wait(2000); attempt++; } return []; }, onSuccess: async (results) => { if (results.length > 0) { onSuccess(); await triggerEventsApi.deleteWebhookSimulation(flowId); } }, onError: async (error) => { console.error(error); await triggerEventsApi.deleteWebhookSimulation(flowId); setErrorMessage?.( testStepUtils.formatErrorMessage( t('There is no sample data available found for this trigger.'), ), ); }, }); }, useSaveMockData: ({ onSuccess }: { onSuccess: () => void }) => { const { form, builderState } = useRequiredStateToTestSteps(); const flowId = builderState.flow.id; return useMutation({ mutationFn: async (mockData: unknown) => { const data = await triggerEventsApi.saveTriggerMockdata( flowId, mockData, ); await updateTriggerSampleData({ data, form, builderState }); return data; }, onSuccess, }); }, usePollTrigger: ({ setErrorMessage, onSuccess, }: { setErrorMessage: (msg: string | undefined) => void; onSuccess: () => void; }) => { const { form, builderState } = useRequiredStateToTestSteps(); const flowId = builderState.flow.id; return useMutation<TriggerEventWithPayload[], Error, void>({ mutationFn: async () => { setErrorMessage(undefined); const { data } = await triggerEventsApi.pollTrigger({ flowId, }); if (data.length > 0) { await updateTriggerSampleData({ builderState, data: data[0], form, }); } return data; }, onSuccess: async (data) => { if (data.length > 0) { onSuccess(); } }, onError: (error) => { if (api.isError(error)) { const apError = error.response?.data as ApErrorParams; let message = 'Failed to run test step, please ensure settings are correct.'; if (apError.code === ErrorCode.TEST_TRIGGER_FAILED) { message = JSON.stringify( { message: 'Failed to run test step, please ensure settings are correct.', error: parseToJsonIfPossible(apError.params.message), }, null, 2, ); } setErrorMessage(message); } else { setErrorMessage( testStepUtils.formatErrorMessage( t('Internal error, please try again later.'), ), ); } }, }); }, useUpdateTriggerSampleData: () => { const { form, builderState } = useRequiredStateToTestSteps(); return useMutation({ mutationFn: async (data: TriggerEventWithPayload) => { await updateTriggerSampleData({ data, form, builderState }); }, }); }, useTestAction: ({ currentStep, setErrorMessage, setConsoleLogs, onSuccess, }: { currentStep: Action; setErrorMessage: ((msg: string | undefined) => void) | undefined; setConsoleLogs: ((logs: string | null) => void) | undefined; onSuccess: (() => void) | undefined; }) => { const socket = useSocket(); const { flowVersionId, projectId, setSampleData, setSampleDataInput, applyOperation, } = useRequiredStateToTestSteps().builderState; return useMutation<StepRunResponse, Error, StepRunResponse | undefined>({ mutationFn: async (preExistingSampleData?: StepRunResponse) => { const testStepResponse = preExistingSampleData ?? (await flowRunsApi.testStep(socket, { flowVersionId, stepName: currentStep.name, })); let sampleDataFileId: string | undefined = undefined; if (testStepResponse.success && !isNil(testStepResponse.output)) { const sampleFile = await sampleDataApi.save({ flowVersionId, stepName: currentStep.name, payload: testStepResponse.output, projectId, fileType: FileType.SAMPLE_DATA, }); sampleDataFileId = sampleFile.id; } const sampleDataInputFile = await sampleDataApi.save({ flowVersionId, stepName: currentStep.name, payload: currentStep.settings, projectId, fileType: FileType.SAMPLE_DATA_INPUT, }); return { ...testStepResponse, sampleDataFileId, sampleDataInputFileId: sampleDataInputFile.id, }; }, onSuccess: ({ success, input, output, sampleDataFileId, sampleDataInputFileId, standardOutput, standardError, }) => { if (success) { setErrorMessage?.(undefined); const newInputUiInfo: Action['settings']['inputUiInfo'] = { ...currentStep.settings.inputUiInfo, sampleDataFileId, sampleDataInputFileId, currentSelectedData: undefined, lastTestDate: dayjs().toISOString(), }; const currentStepCopy: Action = JSON.parse( JSON.stringify(currentStep), ); currentStepCopy.settings.inputUiInfo = newInputUiInfo; applyOperation({ type: FlowOperationType.UPDATE_ACTION, request: currentStepCopy, }); } else { setErrorMessage?.( testStepUtils.formatErrorMessage( JSON.stringify(output) || t('Failed to run test step and no error message was returned'), ), ); } setSampleData(currentStep.name, output); setSampleDataInput(currentStep.name, input); setConsoleLogs?.(standardOutput || standardError); onSuccess?.(); }, onError: (error) => { console.error(error); toast(INTERNAL_ERROR_TOAST); }, }); }, }; async function updateTriggerSampleData({ data, form, builderState, }: { data: TriggerEventWithPayload; form: UseFormReturn<Trigger>; builderState: { flow: PopulatedFlow; flowVersion: FlowVersion; setSampleData: (stepName: string, payload: unknown) => void; setSampleDataInput: (stepName: string, payload: unknown) => void; }; }) { let sampleDataFileId: string | undefined = undefined; const formValues = form.getValues(); const { flow, flowVersion, setSampleData, setSampleDataInput } = builderState; const sampleDataInputFile = await sampleDataApi.save({ flowVersionId: flowVersion.id, stepName: formValues.name, payload: formValues.settings?.input ?? {}, projectId: flow.projectId, fileType: FileType.SAMPLE_DATA_INPUT, }); if (!isNil(data.payload)) { const sampleDataFile = await sampleDataApi.save({ flowVersionId: flowVersion.id, stepName: formValues.name, payload: data.payload, projectId: flow.projectId, fileType: FileType.SAMPLE_DATA, }); sampleDataFileId = sampleDataFile.id; } form.setValue( 'settings.inputUiInfo', { ...formValues.settings.inputUiInfo, sampleDataFileId, sampleDataInputFileId: sampleDataInputFile.id, currentSelectedData: undefined, lastTestDate: dayjs().toISOString(), }, { shouldValidate: true }, ); setSampleData(formValues.name, data.payload); setSampleDataInput(formValues.name, formValues.settings?.input ?? {}); } export default testStepHooks;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/eldoonreval/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server