Skip to main content
Glama

Activepieces MCP Server

by eldoonreval
test-todo-dialog.tsxβ€’11.6 kB
import { useMutation } from '@tanstack/react-query'; import dayjs from 'dayjs'; import { t } from 'i18next'; import { UserRoundPen, Clock2, ChevronDown } from 'lucide-react'; import { useEffect, useState } from 'react'; import { ApMarkdown } from '@/components/custom/markdown'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogTitle, } from '@/components/ui/dialog'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Separator } from '@/components/ui/separator'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import { INTERNAL_ERROR_TOAST, toast } from '@/components/ui/use-toast'; import { sampleDataApi } from '@/features/flows/lib/sample-data-api'; import { todosApi } from '@/features/todos/lib/todos-api'; import { userHooks } from '@/hooks/user-hooks'; import { formatUtils } from '@/lib/utils'; import { STATUS_COLORS, UNRESOLVED_STATUS, StatusOption, MarkdownVariant, StepRunResponse, isNil, FileType, FlowOperationType, TodoWithAssignee, TodoType, Action, } from '@activepieces/shared'; import { useBuilderStateContext } from '../../builder-hooks'; type TodoTestingDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; todo: TodoWithAssignee; flowVersionId: string; projectId: string; currentStep: Action; type: TodoType; setErrorMessage: (errorMessage: string | undefined) => void; }; function TodoTestingDialog({ open, onOpenChange, todo, flowVersionId, projectId, currentStep, type, setErrorMessage, }: TodoTestingDialogProps) { const { data: currentUser } = userHooks.useCurrentUser(); const [status, setStatus] = useState<StatusOption>(todo.status); const [dialogOpenTime, setDialogOpenTime] = useState<Date | null>(null); const [, setForceUpdate] = useState(0); const [showMustResolveError, setShowMustResolveError] = useState(false); const { setSampleData, setSampleDataInput, applyOperation } = useBuilderStateContext((state) => { return { sampleDataInput: state.sampleDataInput[currentStep.name], setSampleData: state.setSampleData, setSampleDataInput: state.setSampleDataInput, applyOperation: state.applyOperation, }; }); const { mutate: resolveTodo, isPending: isResolvingTodo } = useMutation< StepRunResponse & { sampleDataFileId?: string; sampleDataInputFileId?: string; }, Error, void >({ mutationFn: async () => { const response = await todosApi.update(todo.id, { status: status, isTest: true, }); let sampleDataFileId: string | undefined = undefined; if (!isNil(response)) { const sampleFile = await sampleDataApi.save({ flowVersionId, stepName: currentStep.name, payload: { status: response.status.name, }, 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 { id: todo.id, input: currentStep.settings, success: true, output: response, standardError: '', standardOutput: '', sampleDataFileId, sampleDataInputFileId: sampleDataInputFile.id, }; }, onSuccess: ({ success, input, output, sampleDataFileId, sampleDataInputFileId, }) => { 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, }); const response = output as TodoWithAssignee; const statusName = response['status'].name; const statusOptions = response['statusOptions']; const publicUrl = response['resolveUrl']?.split('/flow-runs/')[0]; const links = statusOptions.map((option) => ({ status: option.name, url: publicUrl + `/todos/${response.id}/resolve?status=${option.name}&isTest=true`, })); switch (type) { case TodoType.INTERNAL: setSampleData(currentStep.name, { status: statusName, }); break; case TodoType.EXTERNAL: setSampleData(currentStep.name, { id: response.id, links, }); break; } setSampleDataInput(currentStep.name, input); onOpenChange(false); } }, onError: (error) => { console.error(error); toast(INTERNAL_ERROR_TOAST); }, }); useEffect(() => { if (open) { setDialogOpenTime(new Date()); const intervalId = setInterval(() => { setForceUpdate((prev) => prev + 1); }, 1000); return () => clearInterval(intervalId); } }, [open]); const isResolvedStatusSelected = status.name !== UNRESOLVED_STATUS.name; return ( <Dialog open={open} onOpenChange={onOpenChange}> <DialogContent className="w-full max-w-3xl"> <DialogTitle className="flex items-center gap-2 mb-4"> <span>Todo</span> <Badge variant="outline" className="text-xs"> {t('Test Environment')} </Badge> </DialogTitle> <div className="flex flex-col w-full max-h-[calc(100vh-250px)] min-h-[20px]"> <div className="flex flex-col gap-2"> <span>{todo.title}</span> </div> <div className="flex items-center justify-between"> <div className="flex items-center gap-4"> <div className="flex items-center gap-2"> <UserRoundPen className="h-4 w-4 text-muted-foreground" /> <span className="text-sm text-muted-foreground"> {t('Assigned to')} </span> <span className="text-sm"> {todo.assignee && ( <Tooltip> <TooltipTrigger asChild> <span className="text-sm font-medium"> {todo.assignee.firstName} {todo.assignee.lastName}{' '} {todo.assigneeId === currentUser?.id ? t('(Me)') : ''} </span> </TooltipTrigger> <TooltipContent> <span className="text-xs">{todo.assignee.email}</span> </TooltipContent> </Tooltip> )} </span> </div> <span className="text-sm"> / </span> <div className="flex items-center"> <span className="text-sm text-muted-foreground mr-2"> Status </span> <DropdownMenu> <DropdownMenuTrigger> <Button className="h-8 px-2 flex gap-2 items-center justify-between border-1 border" style={{ backgroundColor: STATUS_COLORS[status.variant].color, color: STATUS_COLORS[status.variant].textColor, }} > <> <span className="text-sm flex items-center justify-center py-0.5 px-2 rounded-full"> {status.name} </span> <ChevronDown className="h-4 w-4" /> </> </Button> </DropdownMenuTrigger> <DropdownMenuContent> <div className="flex flex-col gap-1"> {todo.statusOptions.map((status) => ( <DropdownMenuItem key={status.name} onClick={() => { setStatus(status); }} className="px-1 border-1 border" style={{ backgroundColor: STATUS_COLORS[status.variant].color, color: STATUS_COLORS[status.variant].textColor, }} > <span className="text-sm flex items-center justify-center px-2 rounded-full" style={{ backgroundColor: STATUS_COLORS[status.variant].color, color: STATUS_COLORS[status.variant].textColor, }} > {status.name} </span> </DropdownMenuItem> ))} </div> </DropdownMenuContent> </DropdownMenu> </div> </div> <div className="flex items-center gap-2"> <Clock2 className="h-4 w-4 text-muted-foreground" /> <span className="text-sm text-muted-foreground"> {dialogOpenTime ? formatUtils.formatDateToAgo(dialogOpenTime) : ''} </span> </div> </div> {showMustResolveError && !isResolvedStatusSelected && ( <div className="text-red-500 text-sm mt-2"> {t('Please select status to resolve the todo')} </div> )} <Separator className="mt-4 mb-6" /> <ScrollArea className="flex-grow pr-4"> <ApMarkdown markdown={todo.description ?? ''} variant={MarkdownVariant.BORDERLESS} /> </ScrollArea> </div> <DialogFooter className="justify-end"> <DialogClose asChild> <Button variant="outline">{t('Cancel')}</Button> </DialogClose> <TooltipProvider> <Tooltip> <TooltipTrigger asChild> <Button loading={isResolvingTodo} onClick={() => { if (isResolvedStatusSelected) { resolveTodo(); } else { setShowMustResolveError(true); } }} > {t('Resolve')} </Button> </TooltipTrigger> <TooltipContent>{t('Change status to resolved')}</TooltipContent> </Tooltip> </TooltipProvider> </DialogFooter> </DialogContent> </Dialog> ); } export { TodoTestingDialog };

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