Skip to content

Commit

Permalink
feat: rework datatables
Browse files Browse the repository at this point in the history
DATATR-1763

Signed-off-by: Jonathan Perchoc <[email protected]>
  • Loading branch information
jperchoc committed Dec 13, 2024
1 parent 54e17af commit de328be
Show file tree
Hide file tree
Showing 50 changed files with 1,511 additions and 465 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"status-PENDING": "En attente",
"status-UPDATING": "Mise à jour",
"status-ERROR": "En erreur",
"status-ERROR_INCONSISTENT_SPEC": "En erreur",
"status-ERROR_INCONSISTENT_SPEC": "Erreur spec",
"status-READY": "Disponible"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,12 @@ import { PointerEvent } from './helpers/pointerEvent';
// it is requiered for DropdownMenus
// source: https://github.com/radix-ui/primitives/issues/856#issuecomment-928704064
window.PointerEvent = PointerEvent as any;

const originalConsoleError = console.error;

console.error = (...args) => {
if (typeof args[0] === 'string' && args[0].includes('connect ECONNREFUSED')) {
return;
}
originalConsoleError(...args);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { flexRender } from '@tanstack/react-table';
import { useDataTableContext } from './DataTableContext';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';

export const MENU_COLUMN_ID = 'actions';

export function DataTable() {
const { table, globalFilter, columnFilters, data } = useDataTableContext();
const { t } = useTranslation('pci-databases-analytics/components/data-table');

const rows = useMemo(() => table.getRowModel()?.rows, [
table,
globalFilter,
columnFilters.filters,
data,
]);
const headerGroups = table.getHeaderGroups();
return (
<Table>
<TableHeader className="border bg-gray-50">
{headerGroups.map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header, index) => {
const isEmptyHeader = header.id === MENU_COLUMN_ID;
// Get a reference to the previous header
const isEmptyNextHeader =
headerGroup.headers[index + 1]?.id === MENU_COLUMN_ID;
return (
<TableHead
key={header.id}
className={`border font-semibold text-primary-800 ${
isEmptyHeader
? 'border-l-0' // Remove left border for empty headers
: ''
} ${
isEmptyNextHeader
? 'border-r-0' // Remove right border from current column if next header is empty
: ''
}`}
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody className="border">
{rows?.length ? (
rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={headerGroups[0].headers.length}
className="h-24 text-center"
>
{t('noResult')}
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import {
ColumnDef,
SortingState,
Table,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table';
import { ReactNode, createContext, useContext, useMemo, useState } from 'react';
import { useColumnFilters } from './useColumnFilters.hook';
import { applyFilters } from '@/lib/filters';
import { ColumnFilter } from './DatatableDefaultFilterButton';
import { DataTable } from './DataTable';
import { DataTablePagination } from './DatatablePagination';

interface DataTableProviderProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
pageSize?: number;
itemNumber?: number;
filtersDefinition?: ColumnFilter[];
children?: ReactNode;
}

interface DataTableContextValue<TData> {
table: Table<TData>;
filtersDefinition?: ColumnFilter[];
columnFilters: ReturnType<typeof useColumnFilters>;
globalFilter: string;
data: TData[];
filteredData: TData[];
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const DataTableContext = createContext<DataTableContextValue<any> | null>(null);

export function DataTableProvider<TData, TValue>({
columns,
data,
pageSize,
filtersDefinition,
children,
}: DataTableProviderProps<TData, TValue>) {
const [sorting, setSorting] = useState<SortingState>([
{
id: columns[0]?.id as string,
desc: false,
},
]);
const [globalFilter, setGlobalFilter] = useState<string>('');
const columnFilters = useColumnFilters();

const filteredData = useMemo(
() => applyFilters(data || [], columnFilters.filters) as TData[],
[columnFilters.filters, data],
);
const table = useReactTable({
data: filteredData,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
state: {
sorting,
globalFilter,
},
initialState: {
pagination: { pageSize: pageSize ?? 5 },
},
onGlobalFilterChange: (e) => {
setGlobalFilter(e);
},
globalFilterFn: 'auto',
});
const contextValue: DataTableContextValue<TData> = {
table,
filtersDefinition,
columnFilters,
globalFilter,
data,
filteredData,
};
return (
<DataTableContext.Provider value={contextValue}>
{children || (
<>
<DataTable />
<DataTablePagination />
</>
)}
</DataTableContext.Provider>
);
}

export function useDataTableContext<TData>() {
const context = useContext<DataTableContextValue<TData>>(DataTableContext);
if (!context) {
throw new Error(
'useDataTableContext must be used within a DataTableProvider',
);
}
return context as DataTableContextValue<TData>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ReactNode } from 'react';

const DatatableAction = ({ children }: { children: ReactNode }) => {
return <>{children || <></>}</>;
};

export default DatatableAction;
Loading

0 comments on commit de328be

Please sign in to comment.