diff --git a/apps/web-app/src/components/ui/DataTable/DataTable.tsx b/apps/web-app/src/components/ui/DataTable/DataTable.tsx index 6d350f3..1ccf3c0 100644 --- a/apps/web-app/src/components/ui/DataTable/DataTable.tsx +++ b/apps/web-app/src/components/ui/DataTable/DataTable.tsx @@ -26,16 +26,9 @@ function CellWithTooltip({ children, className }: { children: React.ReactNode; c const textContent = element.textContent || ''; setTooltipContent(textContent); - console.log('Element dimensions:', { - scrollWidth: element.scrollWidth, - clientWidth: element.clientWidth, - textContent, - isOverflowing: element.scrollWidth > element.clientWidth - }); - // Check if content is overflowing by comparing scroll width to client width const isOverflowing = element.scrollWidth > element.clientWidth; - if (isOverflowing || textContent.length > 10) { // Temporarily show tooltip for testing + if (isOverflowing && textContent.trim().length > 0) { setShowTooltip(true); } } @@ -174,9 +167,15 @@ export function DataTable({ maxWidth: `${cell.column.getSize()}px`, }} > - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - + {(cell.column.columnDef as any).disableTooltip ? ( +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+ ) : ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + )} ))} diff --git a/apps/web-app/src/features/exchanges/components/ExchangesTable.tsx b/apps/web-app/src/features/exchanges/components/ExchangesTable.tsx index 5a829fa..416cac9 100644 --- a/apps/web-app/src/features/exchanges/components/ExchangesTable.tsx +++ b/apps/web-app/src/features/exchanges/components/ExchangesTable.tsx @@ -1,5 +1,5 @@ import { DataTable } from '@/components/ui'; -import { PlusIcon, XMarkIcon, CheckIcon } from '@heroicons/react/24/outline'; +import { PlusIcon, XMarkIcon, CheckIcon, TrashIcon } from '@heroicons/react/24/outline'; import { ColumnDef } from '@tanstack/react-table'; import { useCallback, useMemo, useState, useEffect } from 'react'; import { useExchanges } from '../hooks/useExchanges'; @@ -28,8 +28,8 @@ export function ExchangesTable() { const handleCellEdit = useCallback( async (id: string, field: string, value: string) => { - if (field === 'name') { - await updateExchange(id, { name: value }); + if (field === 'name' || field === 'code') { + await updateExchange(id, { [field]: value }); } setEditingCell(null); setEditValue(''); @@ -48,6 +48,16 @@ export function ExchangesTable() { setAddProviderDialog({ exchangeId, exchangeName }); }, []); + const handleDeleteExchange = useCallback(async (exchangeId: string, exchangeName: string) => { + if (confirm(`Are you sure you want to delete "${exchangeName}"? This will hide the exchange and make all its provider mappings available for remapping.`)) { + const success = await updateExchange(exchangeId, { active: false }); + if (success) { + // Optionally refresh the list or show a success message + refetch(); + } + } + }, [updateExchange, refetch]); + const handleToggleProviderMapping = useCallback( async (mappingId: string, currentStatus: boolean) => { const success = await updateProviderMapping(mappingId, { active: !currentStatus }); @@ -94,28 +104,50 @@ export function ExchangesTable() { }, size: 40, enableResizing: false, - }, - { - id: 'id', - header: 'ID', - accessorKey: 'id', - size: 80, - cell: ({ getValue }) => ( - - {getValue() as string} - - ), + disableTooltip: true, }, { id: 'code', header: 'Code', accessorKey: 'code', - size: 100, - cell: ({ getValue }) => ( - - {getValue() as string} - - ), + size: 120, + cell: ({ getValue, row, cell }) => { + const isEditing = + editingCell?.id === row.original.id && editingCell?.field === 'code'; + + if (isEditing) { + return ( + setEditValue(e.target.value)} + onBlur={() => handleCellEdit(row.original.id, 'code', editValue)} + onKeyDown={e => { + if (e.key === 'Enter') { + handleCellEdit(row.original.id, 'code', editValue); + } else if (e.key === 'Escape') { + setEditingCell(null); + setEditValue(''); + } + }} + className="w-full bg-surface border border-border rounded px-2 py-1 text-sm font-mono" + autoFocus + /> + ); + } + + return ( +
{ + setEditingCell({ id: row.original.id, field: 'code' }); + setEditValue(getValue() as string); + }} + > + {getValue() as string} +
+ ); + }, }, { id: 'name', @@ -185,6 +217,7 @@ export function ExchangesTable() { header: 'Active', accessorKey: 'active', size: 80, + disableTooltip: true, cell: ({ getValue, row }) => { const isActive = getValue() as boolean; return ( @@ -205,31 +238,58 @@ export function ExchangesTable() { header: 'Provider Mappings', accessorKey: 'provider_mapping_count', size: 180, + disableTooltip: true, cell: ({ getValue, row }) => { const totalMappings = parseInt(getValue() as string) || 0; const activeMappings = parseInt(row.original.active_mapping_count) || 0; const verifiedMappings = parseInt(row.original.verified_mapping_count) || 0; - const providers = row.original.providers; + + // Parse provider mappings from the expanded data or from a summary field + const exchangeId = row.original.id; + const mappings = expandedRowData[exchangeId] || []; + + const handleLoadMappings = async () => { + if (mappings.length === 0 && totalMappings > 0) { + const details = await fetchExchangeDetails(exchangeId); + if (details) { + setExpandedRowData(prev => ({ + ...prev, + [exchangeId]: details.provider_mappings + })); + } + } + }; return ( -
+
{totalMappings} total + {activeMappings > 0 && ( + + {activeMappings} active + + )}
-
- - - {activeMappings} active - - - ✓ {verifiedMappings} verified - -
- {providers && ( -
- {providers} + {mappings.length > 0 ? ( +
+ {mappings.slice(0, 3).map((mapping, index) => ( + + {mapping.provider.toLowerCase()} + ({mapping.provider_exchange_code}) + + ))} + {mappings.length > 3 && ( + +{mappings.length - 3} more + )}
+ ) : totalMappings > 0 ? ( +
Hover to load mappings...
+ ) : ( +
No mappings
)}
); @@ -238,16 +298,27 @@ export function ExchangesTable() { { id: 'actions', header: 'Actions', - size: 120, + size: 140, + disableTooltip: true, cell: ({ row }) => ( - +
+ + +
), }, { @@ -265,10 +336,13 @@ export function ExchangesTable() { }, [ editingCell, editValue, + expandedRowData, handleCellEdit, handleToggleActive, handleAddProviderMapping, + handleDeleteExchange, handleRowExpand, + fetchExchangeDetails, ]); if (error) {