Skip to main content
Glama

mcp-google-sheets

index.tsx4.81 kB
import { useQuery } from '@tanstack/react-query'; import { t } from 'i18next'; import { Check, CheckCircle, CheckIcon } from 'lucide-react'; import { useSearchParams } from 'react-router-dom'; import { useEffectOnce } from 'react-use'; import { PermissionNeededTooltip } from '@/components/custom/permission-needed-tooltip'; import { Button } from '@/components/ui/button'; import { DataTable, LIMIT_QUERY_PARAM, CURSOR_QUERY_PARAM, DataTableFilters, } from '@/components/ui/data-table'; import { toast } from '@/components/ui/use-toast'; import { issuesApi } from '@/features/issues/api/issues-api'; import { issueHooks } from '@/features/issues/hooks/issue-hooks'; import { useAuthorization } from '@/hooks/authorization-hooks'; import { authenticationSession } from '@/lib/authentication-session'; import { IssueStatus, Permission, PopulatedIssue } from '@activepieces/shared'; import { issuesTableColumns } from './columns'; export function IssuesTable() { const { refetch } = issueHooks.useIssuesNotification(); const [searchParams, setSearchParams] = useSearchParams(); const projectId = authenticationSession.getProjectId()!; const currentSearchParams = searchParams.toString(); const statusValues = searchParams.getAll('status'); const hasStatusFilter = statusValues.length > 0; useEffectOnce(() => { if (!hasStatusFilter) { const newSearchParams = new URLSearchParams(searchParams); newSearchParams.append('status', IssueStatus.UNRESOLVED); setSearchParams(newSearchParams); } }); const filters: DataTableFilters<keyof PopulatedIssue>[] = [ { type: 'select', title: t('Status'), accessorKey: 'status', options: [ { label: t('Unresolved'), value: IssueStatus.UNRESOLVED, }, { label: t('Resolved'), value: IssueStatus.RESOLVED, }, { label: t('Archived'), value: IssueStatus.ARCHIVED, }, ], icon: CheckIcon, }, ]; const { data, isLoading } = useQuery({ queryKey: ['issues', currentSearchParams, projectId], staleTime: 0, gcTime: 0, enabled: true, queryFn: () => { const cursor = searchParams.get(CURSOR_QUERY_PARAM); const limit = searchParams.get(LIMIT_QUERY_PARAM) ? parseInt(searchParams.get(LIMIT_QUERY_PARAM)!) : 10; return issuesApi.list({ projectId, cursor: cursor ?? undefined, limit, status: statusValues.length > 0 ? statusValues.map((value) => value as IssueStatus) : undefined, }); }, }); const handleMarkAsArchived = async ( flowDisplayName: string, issueId: string, ) => { await issuesApi.archive(issueId); refetch(); toast({ title: t('Success'), description: t('Issues in {flowDisplayName} is marked as archived.', { flowDisplayName, }), duration: 3000, }); }; const { checkAccess } = useAuthorization(); const userHasPermissionToMarkAsArchived = checkAccess( Permission.WRITE_ISSUES, ); return ( <div className="flex-col w-full"> <DataTable emptyStateTextTitle={t('No issues found')} emptyStateTextDescription={t( 'All your workflows are running smoothly.', )} emptyStateIcon={<CheckCircle className="size-14" />} page={data} isLoading={isLoading} columns={issuesTableColumns} filters={filters} bulkActions={[ { render: (selectedRows, resetSelection) => { return ( <div className="flex items-center gap-2"> <PermissionNeededTooltip hasPermission={userHasPermissionToMarkAsArchived} > <Button disabled={ !userHasPermissionToMarkAsArchived || selectedRows.length === 0 } className="gap-2" onClick={(e) => { selectedRows.forEach((row) => { handleMarkAsArchived(row.flowDisplayName, row.id); row.delete(); }); resetSelection(); }} > <Check className="size-3" /> {t('Mark as Archived')}{' '} {selectedRows.length === 0 ? '' : `(${selectedRows.length})`} </Button> </PermissionNeededTooltip> </div> ); }, }, ]} /> </div> ); }

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