Skip to main content
Glama

mcp-google-sheets

index.tsx5.96 kB
import { nanoid } from 'nanoid'; import { useRef, useEffect } from 'react'; import DataGrid, { DataGridHandle } from 'react-data-grid'; import 'react-data-grid/lib/styles.css'; import { useNavigate } from 'react-router-dom'; import { useSocket } from '@/components/socket-provider'; import { useTheme } from '@/components/theme-provider'; import { AgentRunDialog } from '@/features/agents/agent-run-dialog'; import { ApTableFooter } from '@/features/tables/components/ap-table-footer'; import { ApTableHeader } from '@/features/tables/components/ap-table-header'; import { useTableState } from '@/features/tables/components/ap-table-state-provider'; import { useTableColumns, mapRecordsToRows, } from '@/features/tables/components/table-columns'; import { recordsApi } from '@/features/tables/lib/records-api'; import { Row, ROW_HEIGHT_MAP, RowHeight } from '@/features/tables/lib/types'; import { useAuthorization } from '@/hooks/authorization-hooks'; import { flagsHooks } from '@/hooks/flags-hooks'; import { authenticationSession } from '@/lib/authentication-session'; import { cn } from '@/lib/utils'; import { AgentRun, AgentTaskStatus, ApFlagId, Permission, WebsocketClientEvent, } from '@activepieces/shared'; import './react-data-grid.css'; const ApTableEditorPage = () => { const navigate = useNavigate(); const projectId = authenticationSession.getProjectId(); const [ table, setAgentRunId, selectedRecords, setSelectedRecords, selectedCell, setSelectedCell, createRecord, fields, records, selectedAgentRunId, setSelectedAgentRunId, setRecords, ] = useTableState((state) => [ state.table, state.setAgentRunId, state.selectedRecords, state.setSelectedRecords, state.selectedCell, state.setSelectedCell, state.createRecord, state.fields, state.records, state.selectedAgentRunId, state.setSelectedAgentRunId, state.setRecords, ]); const gridRef = useRef<DataGridHandle>(null); const { theme } = useTheme(); const { data: maxRecords } = flagsHooks.useFlag<number>( ApFlagId.MAX_RECORDS_PER_TABLE, ); const socket = useSocket(); const userHasTableWritePermission = useAuthorization().checkAccess( Permission.WRITE_TABLE, ); const isAllowedToCreateRecord = userHasTableWritePermission && maxRecords && records.length < maxRecords; const createEmptyRecord = () => { createRecord({ uuid: nanoid(), agentRunId: null, values: [], }); requestAnimationFrame(() => { gridRef.current?.scrollToCell({ rowIdx: records.length, idx: 0, }); setSelectedCell({ rowIdx: records.length, columnIdx: 1, }); }); }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( selectedCell && !(event.target as HTMLElement).closest( `#editable-cell-${selectedCell.rowIdx}-${selectedCell.columnIdx}`, ) ) { setSelectedCell(null); } }; document.addEventListener('click', handleClickOutside); return () => document.removeEventListener('click', handleClickOutside); }, [selectedCell]); useEffect(() => { socket.on( WebsocketClientEvent.AGENT_RUN_PROGRESS, async (agentRun: AgentRun) => { if (agentRun.metadata?.tableId === table.id) { setAgentRunId( agentRun.metadata.recordId!, agentRun.status === AgentTaskStatus.IN_PROGRESS ? agentRun.id : null, ); if ( agentRun.status === AgentTaskStatus.COMPLETED || agentRun.status === AgentTaskStatus.FAILED ) { const records = await recordsApi.list({ tableId: table.id, limit: 999999, cursor: undefined, }); setRecords(records.data); } } }, ); return () => { socket.off(WebsocketClientEvent.AGENT_RUN_PROGRESS); }; }, [table.id, setAgentRunId, socket]); const columns = useTableColumns(createEmptyRecord); const rows = mapRecordsToRows(records, fields); const handleBack = () => { navigate(`/projects/${projectId}/tables`); }; return ( <div className="w-full flex flex-col justify-start items-start h-full"> <div className="flex items-center justify-between w-full pr-4 border-b"> <ApTableHeader onBack={handleBack} /> </div> <div className="flex w-full flex-col flex-1 h-full"> <div className="flex-1 flex flex-col"> <div className="flex-1"> <DataGrid ref={gridRef} columns={columns} rows={rows} rowKeyGetter={(row: Row) => row.id} selectedRows={selectedRecords} onSelectedRowsChange={setSelectedRecords} className={cn( 'scroll-smooth w-full h-full bg-muted/30', theme === 'dark' ? 'rdg-dark' : 'rdg-light', )} bottomSummaryRows={ userHasTableWritePermission ? [{ id: 'new-record' }] : [] } rowHeight={ROW_HEIGHT_MAP[RowHeight.DEFAULT]} headerRowHeight={ROW_HEIGHT_MAP[RowHeight.DEFAULT]} summaryRowHeight={ isAllowedToCreateRecord ? ROW_HEIGHT_MAP[RowHeight.DEFAULT] : 0 } /> </div> <ApTableFooter fieldsCount={fields.length} recordsCount={records.length} /> </div> </div> <AgentRunDialog agentRunId={selectedAgentRunId} open={!!selectedAgentRunId} onOpenChange={(open) => { if (!open) { setSelectedAgentRunId(null); } }} /> </div> ); }; ApTableEditorPage.displayName = 'ApTableEditorPage'; export { ApTableEditorPage };

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/activepieces/activepieces'

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