import { useMemo, useState, useEffect } from 'react'; import RefreshIcon from '@/assets/icons/refresh.svg?react'; import { Button, EmptyState, SearchInput, DataGrid, type DataGridColumn, type DataGridRowType, type ConvertedValue, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components'; import { useFullMetadata } from '../hooks/useFullMetadata'; import type { ExportDatabaseResponse, ExportDatabaseJsonData } from '@insforge/shared-schemas'; import { isSystemFunction } from '../constants'; import { DataUpdatePayload, DataUpdateResourceType, ServerEvents, SocketMessage, useSocket, } from '@/lib/contexts/SocketContext'; interface FunctionRow extends DataGridRowType { id: string; functionName: string; kind: string; functionDef: string; [key: string]: ConvertedValue | { [key: string]: string }[]; } function parseFunctionsFromMetadata(metadata: ExportDatabaseResponse | undefined): FunctionRow[] { if (!metadata || metadata.format !== 'json' || typeof metadata.data === 'string') { return []; } const data = metadata.data as ExportDatabaseJsonData; const functions: FunctionRow[] = []; data.functions.forEach((func) => { if (isSystemFunction(func.functionName)) { return; } functions.push({ id: func.functionName, functionName: func.functionName, kind: func.kind, functionDef: func.functionDef, }); }); return functions; } export default function FunctionsPage() { const [searchQuery, setSearchQuery] = useState(''); const [isRefreshing, setIsRefreshing] = useState(false); const { data: metadata, isLoading, error, refetch } = useFullMetadata(true); const { socket, isConnected } = useSocket(); const allFunctions = useMemo(() => parseFunctionsFromMetadata(metadata), [metadata]); useEffect(() => { if (!socket || !isConnected) { return; } const handleDataUpdate = (message: SocketMessage) => { if (message.payload?.resource === DataUpdateResourceType.DATABASE) { void refetch(); } }; socket.on(ServerEvents.DATA_UPDATE, handleDataUpdate); return () => { socket.off(ServerEvents.DATA_UPDATE, handleDataUpdate); }; }, [socket, isConnected, refetch]); const filteredFunctions = useMemo(() => { if (!searchQuery.trim()) { return allFunctions; } const query = searchQuery.toLowerCase(); return allFunctions.filter((func) => func.functionName.toLowerCase().includes(query)); }, [allFunctions, searchQuery]); const handleRefresh = async () => { setIsRefreshing(true); try { setSearchQuery(''); await refetch(); } finally { setIsRefreshing(false); } }; const columns: DataGridColumn[] = useMemo( () => [ { key: 'functionName', name: 'Name', width: 'minmax(200px, 2fr)', resizable: true, sortable: true, }, { key: 'kind', name: 'Type', width: 'minmax(120px, 1fr)', resizable: true, sortable: true, renderCell: ({ row }) => { const kindLabel = row.kind === 'f' ? 'Function' : row.kind === 'p' ? 'Procedure' : row.kind; return ( {kindLabel} ); }, }, { key: 'functionDef', name: 'Definition', width: 'minmax(400px, 8fr)', resizable: true, }, ], [] ); if (error) { return (
); } return (

Database Functions

{/* Separator */}
{/* Refresh button */}

{isRefreshing ? 'Refreshing...' : 'Refresh'}

{isLoading ? (
) : (
{searchQuery ? 'No functions match your search criteria' : 'No functions found'}
} />
)}
); }