-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(pci.ai.notebook): udpate data table
Signed-off-by: Arthur Bullet <[email protected]>
- Loading branch information
Showing
34 changed files
with
1,322 additions
and
320 deletions.
There are no files selected for viewing
123 changes: 123 additions & 0 deletions
123
packages/manager/apps/pci-ai-notebooks/src/components/data-table/DataTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import React, { ReactElement, useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { flexRender } from '@tanstack/react-table'; | ||
import { ChevronDown, ChevronUp } from 'lucide-react'; | ||
import { useDataTableContext } from './DataTableContext'; | ||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
} from '@/components/ui/table'; | ||
import { Button } from '../ui/button'; | ||
|
||
export const MENU_COLUMN_ID = 'actions'; | ||
|
||
interface DatatableProps<TData> { | ||
renderRowExpansion?: (row: TData) => ReactElement | null; | ||
} | ||
|
||
export function DataTable<TData>({ | ||
renderRowExpansion, | ||
}: DatatableProps<TData>) { | ||
const { table, rows } = useDataTableContext(); | ||
const { t } = useTranslation('pci-databases-analytics/components/data-table'); | ||
const [expandedRows, setExpandedRows] = useState<Record<string, boolean>>({}); | ||
|
||
const toggleRowExpansion = (rowId: string) => { | ||
setExpandedRows((prev) => ({ | ||
...prev, | ||
[rowId]: !prev[rowId], | ||
})); | ||
}; | ||
|
||
const headerGroups = table.getHeaderGroups(); | ||
return ( | ||
<Table> | ||
<TableHeader className="border bg-gray-50"> | ||
{headerGroups.map((headerGroup) => ( | ||
<TableRow key={headerGroup.id}> | ||
{renderRowExpansion && ( | ||
<TableHead className="border-r-0 w-6"></TableHead> | ||
)} | ||
{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 || renderRowExpansion | ||
? 'border-l-0' // Remove left border for empty headers and row extend column | ||
: '' | ||
} ${ | ||
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) => ( | ||
<React.Fragment key={row.id}> | ||
<TableRow data-state={row.getIsSelected() && 'selected'}> | ||
{renderRowExpansion && ( | ||
<TableCell> | ||
<Button | ||
variant="ghost" | ||
onClick={() => toggleRowExpansion(row.id)} | ||
data-testid="table-row-expand-button" | ||
> | ||
{expandedRows[row.id] ? ( | ||
<ChevronUp className="h-4 w-4" /> | ||
) : ( | ||
<ChevronDown className="h-4 w-4" /> | ||
)} | ||
</Button> | ||
</TableCell> | ||
)} | ||
{row.getVisibleCells().map((cell) => ( | ||
<TableCell key={cell.id}> | ||
{flexRender(cell.column.columnDef.cell, cell.getContext())} | ||
</TableCell> | ||
))} | ||
</TableRow> | ||
{expandedRows[row.id] && renderRowExpansion && ( | ||
<TableRow> | ||
<TableCell colSpan={headerGroups[0].headers.length + 1}> | ||
{renderRowExpansion(row.original as TData)} | ||
</TableCell> | ||
</TableRow> | ||
)} | ||
</React.Fragment> | ||
)) | ||
) : ( | ||
<TableRow> | ||
<TableCell | ||
colSpan={headerGroups[0].headers.length} | ||
className="h-24 text-center" | ||
> | ||
{t('noResult')} | ||
</TableCell> | ||
</TableRow> | ||
)} | ||
</TableBody> | ||
</Table> | ||
); | ||
} |
122 changes: 122 additions & 0 deletions
122
packages/manager/apps/pci-ai-notebooks/src/components/data-table/DataTableContext.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { | ||
ColumnDef, | ||
Row, | ||
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[]; | ||
sorting: SortingState; | ||
rows: Row<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 rows = useMemo(() => table.getRowModel()?.rows, [ | ||
table, | ||
globalFilter, | ||
columnFilters.filters, | ||
data, | ||
sorting, | ||
]); | ||
|
||
const contextValue: DataTableContextValue<TData> = { | ||
table, | ||
filtersDefinition, | ||
columnFilters, | ||
globalFilter, | ||
data, | ||
filteredData, | ||
sorting, | ||
rows, | ||
}; | ||
|
||
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>; | ||
} |
7 changes: 7 additions & 0 deletions
7
packages/manager/apps/pci-ai-notebooks/src/components/data-table/DatatableAction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
Oops, something went wrong.