Skip to main content
Glama

Activepieces MCP Server

by eldoonreval
index.tsxβ€’10.7 kB
import { useQuery } from '@tanstack/react-query'; import { ColumnDef } from '@tanstack/react-table'; import { t } from 'i18next'; import { CheckCircle, CheckIcon, Tag, User } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import { useLocation, useSearchParams } from 'react-router-dom'; import { Checkbox } from '@/components/ui/checkbox'; import { CURSOR_QUERY_PARAM, DataTable, LIMIT_QUERY_PARAM, RowDataWithActions, } from '@/components/ui/data-table'; import { DataTableColumnHeader } from '@/components/ui/data-table/data-table-column-header'; import { StatusIconWithText } from '@/components/ui/status-icon-with-text'; import { TableTitle } from '@/components/ui/table-title'; import { UserFullName } from '@/components/ui/user-fullname'; import { projectMembersHooks } from '@/features/team/lib/project-members-hooks'; import { todosApi } from '@/features/todos/lib/todos-api'; import { userHooks } from '@/hooks/user-hooks'; import { authenticationSession } from '@/lib/authentication-session'; import { formatUtils } from '@/lib/utils'; import { Todo, TodoWithAssignee, UNRESOLVED_STATUS, RESOLVED_STATUS, STATUS_COLORS, } from '@activepieces/shared'; import { TodoDetails } from './todo-details'; function TodosPage() { const [selectedRows, setSelectedRows] = useState<Array<Todo>>([]); const [selectedTask, setSelectedTask] = useState<TodoWithAssignee | null>( null, ); const [drawerOpen, setDrawerOpen] = useState(false); const [rowIndex, setRowIndex] = useState(0); const location = useLocation(); const projectId = authenticationSession.getProjectId()!; const platformId = authenticationSession.getPlatformId()!; const { data: currentUser } = userHooks.useCurrentUser(); const [searchParams, setSearchParams] = useSearchParams(); useEffect(() => { if (!location.search.includes('assignee')) { setSearchParams((prev) => { if (currentUser) { prev.set('assignee', currentUser.email); } prev.set('status', UNRESOLVED_STATUS.name); return prev; }); } }, []); const { data, isLoading } = useQuery({ queryKey: ['todos', location, projectId], queryFn: () => { const cursor = searchParams.get(CURSOR_QUERY_PARAM); const limit = searchParams.get(LIMIT_QUERY_PARAM) ? parseInt(searchParams.get(LIMIT_QUERY_PARAM)!) : 10; const assigneeId = searchParams.get('assigneeId') ?? undefined; const flowId = searchParams.get('flowId') ?? undefined; const title = searchParams.get('title') ?? undefined; const status = searchParams.getAll('status') ?? undefined; const isUnresolved = status.length === 1 && status[0] === UNRESOLVED_STATUS.name ? true : false; const isAllStatus = status.length === 0 || status.length === 2; const statusOptions = isAllStatus ? undefined : isUnresolved ? [UNRESOLVED_STATUS.name] : [RESOLVED_STATUS.name]; return todosApi.list({ projectId, cursor: cursor ?? undefined, limit, platformId, assigneeId, flowId, statusOptions, title, }); }, }); const filteredData = useMemo(() => { if (!data?.data) return undefined; const searchParams = new URLSearchParams(location.search); const assigneeEmails = searchParams.getAll('assignee'); if (assigneeEmails.length === 0) return data; return { data: data.data.filter( (task) => task.assignee && assigneeEmails.includes(task.assignee.email), ), next: data.next, previous: data.previous, }; }, [data, location.search]); const { projectMembers } = projectMembersHooks.useProjectMembers(); const assigneeOptions = [ ...(currentUser ? [ { label: t('Me Only'), value: currentUser.email, }, ] : []), ...(projectMembers ?.filter((member) => member.user.email !== currentUser?.email) .map((member) => ({ label: `${member.user.firstName} ${member.user.lastName} (${member.user.email})`, value: member.user.email, })) ?? []), ]; const filters = [ { type: 'select', title: t('Assigned to'), accessorKey: 'assignee', icon: User, options: assigneeOptions ?? [], } as const, { type: 'select', title: t('Status'), accessorKey: 'status', options: [ { label: t('Unresolved'), value: UNRESOLVED_STATUS.name, }, { label: t('Resolved'), value: RESOLVED_STATUS.name, }, ], icon: CheckIcon, } as const, { type: 'input', title: t('Title'), accessorKey: 'title', icon: Tag, options: [], } as const, ]; const columns: ColumnDef<RowDataWithActions<TodoWithAssignee>, unknown>[] = [ { id: 'select', header: ({ table }) => ( <Checkbox checked={ table.getIsAllPageRowsSelected() || table.getIsSomePageRowsSelected() } onCheckedChange={(value) => { const isChecked = !!value; table.toggleAllPageRowsSelected(isChecked); if (isChecked) { const allRows = table .getRowModel() .rows.map((row) => row.original); const newSelectedRows = [...allRows, ...selectedRows]; const uniqueRows = Array.from( new Map( newSelectedRows.map((item) => [item.id, item]), ).values(), ); setSelectedRows(uniqueRows); } else { const filteredRows = selectedRows.filter((row) => { return !table .getRowModel() .rows.some((r) => r.original.id === row.id); }); setSelectedRows(filteredRows); } }} /> ), cell: ({ row }) => { const isChecked = selectedRows.some( (selectedRow) => selectedRow.id === row.original.id, ); return ( <Checkbox checked={isChecked} onCheckedChange={(value) => { const isChecked = !!value; let newSelectedRows = [...selectedRows]; if (isChecked) { const exists = newSelectedRows.some( (selectedRow) => selectedRow.id === row.original.id, ); if (!exists) { newSelectedRows.push(row.original); } } else { newSelectedRows = newSelectedRows.filter( (selectedRow) => selectedRow.id !== row.original.id, ); } setSelectedRows(newSelectedRows); row.toggleSelected(!!value); }} /> ); }, accessorKey: 'select', }, { accessorKey: 'title', header: ({ column }) => ( <DataTableColumnHeader column={column} title={t('Title')} /> ), cell: ({ row }) => { return ( <div className="flex items-center gap-2">{row.original.title}</div> ); }, }, { accessorKey: 'assignee', header: ({ column }) => ( <DataTableColumnHeader column={column} title={t('Assigned to')} /> ), cell: ({ row }) => { return ( <div className="text-left"> {row.original.assignee && ( <UserFullName firstName={row.original.assignee.firstName} lastName={row.original.assignee.lastName} email={row.original.assignee.email} /> )} {!row.original.assignee && <div className="text-left">-</div>} </div> ); }, }, { accessorKey: 'status', header: ({ column }) => ( <DataTableColumnHeader column={column} title={t('Status')} /> ), cell: ({ row }) => { return ( <div className="text-left"> <StatusIconWithText icon={CheckIcon} text={row.original.status.name} color={STATUS_COLORS[row.original.status.variant].color} textColor={STATUS_COLORS[row.original.status.variant].textColor} /> </div> ); }, }, { accessorKey: 'created', header: ({ column }) => ( <DataTableColumnHeader column={column} title={t('Date Created')} /> ), cell: ({ row }) => { return ( <div className="text-left"> {formatUtils.formatDate(new Date(row.original.created))} </div> ); }, }, ]; return ( <div className="flex-col w-full"> <div className="flex items-center gap-2"> <TableTitle description={t( 'Manage todos for your project that are created by automations', )} beta={true} > {t('Todos')} </TableTitle> </div> <DataTable emptyStateTextTitle={t('No todos found')} emptyStateTextDescription={t( 'You do not have any pending todos. Great job!', )} emptyStateIcon={<CheckCircle className="size-14" />} columns={columns} page={filteredData} isLoading={isLoading} filters={filters} onRowClick={(row) => { setSelectedTask(row); setDrawerOpen(true); setRowIndex(data?.data.findIndex((task) => task.id === row.id) ?? 0); }} /> {selectedTask && ( <TodoDetails key={selectedTask.id} currentTodo={selectedTask} open={drawerOpen} onOpenChange={setDrawerOpen} onClose={() => { setSelectedTask(null); setDrawerOpen(false); }} onNext={() => { if (!data || !data.data.length) return; const length = data.data.length; const nextIndex = (rowIndex + 1) % length; setRowIndex(nextIndex); setSelectedTask(data.data[nextIndex]); }} onPrevious={() => { if (!data || !data.data.length) return; const length = data.data.length; const previousIndex = (rowIndex - 1 + length) % length; setRowIndex(previousIndex); setSelectedTask(data.data[previousIndex]); }} /> )} </div> ); } export { TodosPage };

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