-
Notifications
You must be signed in to change notification settings - Fork 0
Add Table component
#92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
21bd665
Implement Table.tsx
b-yogesh dfc8c9e
Implement table.py
b-yogesh 1725a21
add table
b-yogesh 86bee36
add tests
b-yogesh c4bea32
add demo
b-yogesh 5e14f95
update CHANGES.md
b-yogesh 1b4d4f3
Merge branch 'main' into yogesh-41-basic-table
b-yogesh 62aac25
[WIP] - update table component
b-yogesh fd0d6e4
Finish update table component
b-yogesh 7e40aff
update TableRow type def syntax
b-yogesh 3bbadeb
update CHANGES.md
b-yogesh d199da8
fix linting
b-yogesh b10701f
Update chartlets.py/chartlets/components/table.py
b-yogesh a6a6e2d
add typealias import
b-yogesh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| * New (MUI) components | ||
| - `DataGrid` | ||
| - `Dialog` | ||
| - `Table` | ||
|
|
||
| ## Version 0.1.3 (from 2025/01/28) | ||
|
|
||
|
|
||
This file contains hidden or 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,76 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
| import { fireEvent, render, screen } from "@testing-library/react"; | ||
| import "@testing-library/jest-dom"; | ||
| import { Table } from "@/plugins/mui/Table"; | ||
| import { createChangeHandler } from "@/plugins/mui/common.test"; | ||
|
|
||
| describe("Table", () => { | ||
| const rows = [ | ||
| ["John", "Doe"], | ||
| ["Johnie", "Undoe"], | ||
| ]; | ||
| const columns = [ | ||
| { id: "firstName", label: "First Name" }, | ||
| { id: "lastName", label: "Last Name" }, | ||
| ]; | ||
|
|
||
| it("should render the Table component", () => { | ||
| render( | ||
| <Table | ||
| id="table" | ||
| type={"Table"} | ||
| rows={rows} | ||
| columns={columns} | ||
| onChange={() => {}} | ||
| />, | ||
| ); | ||
|
|
||
| const table = screen.getByRole("table"); | ||
| expect(table).toBeDefined(); | ||
| columns.forEach((column) => { | ||
| expect(screen.getByText(column.label)).toBeInTheDocument(); | ||
| }); | ||
| rows.forEach((row, index) => { | ||
| expect(screen.getByText(row[index])).toBeInTheDocument(); | ||
| }); | ||
| }); | ||
|
|
||
| it("should not render the Table component when no columns provided", () => { | ||
| render(<Table id="table" type={"Table"} rows={rows} onChange={() => {}} />); | ||
|
|
||
| const table = screen.queryByRole("table"); | ||
| expect(table).toBeNull(); | ||
| }); | ||
|
|
||
| it("should not render the Table component when no rows provided", () => { | ||
| render(<Table id="table" type={"Table"} rows={rows} onChange={() => {}} />); | ||
|
|
||
| const table = screen.queryByRole("table"); | ||
| expect(table).toBeNull(); | ||
| }); | ||
|
|
||
| it("should call onChange on row click", () => { | ||
| const { recordedEvents, onChange } = createChangeHandler(); | ||
| render( | ||
| <Table | ||
| id="table" | ||
| type={"Table"} | ||
| rows={rows} | ||
| columns={columns} | ||
| onChange={onChange} | ||
| />, | ||
| ); | ||
|
|
||
| fireEvent.click(screen.getAllByRole("row")[1]); | ||
| expect(recordedEvents.length).toEqual(1); | ||
| expect(recordedEvents[0]).toEqual({ | ||
| componentType: "Table", | ||
| id: "table", | ||
| property: "value", | ||
| value: { | ||
| firstName: "John", | ||
| lastName: "Doe", | ||
| }, | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or 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,110 @@ | ||
| import { | ||
| Paper, | ||
| Table as MuiTable, | ||
| TableBody, | ||
| TableCell, | ||
| TableContainer, | ||
| TableHead, | ||
| TableRow, | ||
| } from "@mui/material"; | ||
| import type { ComponentProps, ComponentState } from "@/index"; | ||
| import type { SxProps } from "@mui/system"; | ||
|
|
||
| interface TableCellProps { | ||
| id: string | number; | ||
| size?: "medium" | "small"; | ||
| align?: "inherit" | "left" | "center" | "right" | "justify"; | ||
| sx?: SxProps; | ||
| } | ||
|
|
||
| interface TableColumn extends TableCellProps { | ||
| label: string; | ||
| } | ||
|
|
||
| interface TableState extends ComponentState { | ||
| rows?: (string | number | boolean | undefined)[][]; | ||
| columns?: TableColumn[]; | ||
| hover?: boolean; | ||
| stickyHeader?: boolean; | ||
| } | ||
|
|
||
| interface TableProps extends ComponentProps, TableState {} | ||
|
|
||
| export const Table = ({ | ||
| type, | ||
| id, | ||
| style, | ||
| rows, | ||
| columns, | ||
| hover, | ||
| stickyHeader, | ||
| onChange, | ||
| }: TableProps) => { | ||
| if (!columns || columns.length === 0) { | ||
| return <div>No columns provided.</div>; | ||
| } | ||
|
|
||
| if (!rows || rows.length === 0) { | ||
| return <div>No rows provided.</div>; | ||
| } | ||
|
|
||
| const handleRowClick = (row: (string | number | boolean | undefined)[]) => { | ||
| const rowData = row.reduce( | ||
| (acc, cell, cellIndex) => { | ||
| const columnId = columns[cellIndex]?.id; | ||
| if (columnId) { | ||
| acc[columnId] = cell; | ||
| } | ||
| return acc; | ||
| }, | ||
| {} as Record<string, string | number | boolean | undefined>, | ||
| ); | ||
| if (id) { | ||
| onChange({ | ||
| componentType: type, | ||
| id: id, | ||
| property: "value", | ||
| value: rowData, | ||
| }); | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <TableContainer component={Paper} sx={style} id={id}> | ||
| <MuiTable stickyHeader={stickyHeader}> | ||
| <TableHead> | ||
| <TableRow> | ||
| {columns.map((column) => ( | ||
| <TableCell | ||
| key={column.id} | ||
| align={column.align || "inherit"} | ||
| size={column.size || "medium"} | ||
| > | ||
| {column.label} | ||
| </TableCell> | ||
| ))} | ||
| </TableRow> | ||
| </TableHead> | ||
| <TableBody> | ||
| {rows.map((row, row_index) => ( | ||
| <TableRow | ||
| hover={hover} | ||
| key={row_index} | ||
| onClick={() => handleRowClick(row)} | ||
| > | ||
| {row?.map((item, item_index) => ( | ||
| <TableCell | ||
| key={item_index} | ||
| align={columns[item_index].align || "inherit"} | ||
| size={columns[item_index].size || "medium"} | ||
| > | ||
| {item} | ||
| </TableCell> | ||
| ))} | ||
| </TableRow> | ||
| ))} | ||
| </TableBody> | ||
| </MuiTable> | ||
| </TableContainer> | ||
| ); | ||
| }; |
This file contains hidden or 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
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| * New (MUI) components | ||
| - `DataGrid` | ||
| - `Dialog` | ||
| - `Table` | ||
|
|
||
|
|
||
| ## Version 0.1.3 (from 2025/01/28) | ||
|
|
||
This file contains hidden or 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
This file contains hidden or 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,43 @@ | ||
| from dataclasses import dataclass | ||
| from typing import Literal, TypedDict, TypeAlias | ||
| from chartlets import Component | ||
|
|
||
|
|
||
| class TableCellProps(TypedDict, total=False): | ||
| """Represents common properties of a table cell.""" | ||
|
|
||
| id: str | int | float | ||
| """The unique identifier for the cell.""" | ||
|
|
||
| size: Literal['medium', 'small'] | str | None | ||
| """The size of the cell.""" | ||
|
|
||
| align: Literal["inherit", "left", "center", "right", "justify"] | None | ||
| """The alignment of the cell content.""" | ||
|
|
||
|
|
||
| class TableColumn(TableCellProps): | ||
| """Defines a column in the table.""" | ||
|
|
||
| label: str | ||
| """The display label for the column header.""" | ||
|
|
||
|
|
||
| TableRow: TypeAlias = list[list[str | int | float | bool | None]] | ||
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class Table(Component): | ||
| """A basic Table with configurable rows and columns.""" | ||
|
|
||
| columns: list[TableColumn] | None = None | ||
| """The columns to display in the table.""" | ||
|
|
||
| rows: TableRow | None = None | ||
| """The rows of data to display in the table.""" | ||
|
|
||
| hover: bool | None = None | ||
| """A boolean indicating whether to highlight a row when hovered over""" | ||
|
|
||
| stickyHeader: bool | None = None | ||
| """A boolean to set the header of the table sticky""" | ||
This file contains hidden or 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
This file contains hidden or 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,58 @@ | ||
| from chartlets import Component, Input, Output | ||
| from chartlets.components import Box, Typography, Table | ||
|
|
||
| from server.context import Context | ||
| from server.panel import Panel | ||
|
|
||
| from chartlets.components.table import TableColumn, TableRow | ||
|
|
||
| panel = Panel(__name__, title="Panel F") | ||
|
|
||
|
|
||
| # noinspection PyUnusedLocal | ||
| @panel.layout() | ||
| def render_panel( | ||
| ctx: Context, | ||
| ) -> Component: | ||
| columns: list[TableColumn] = [ | ||
| {"id": "id", "label": "ID", "sortDirection": "desc"}, | ||
| { | ||
| "id": "firstName", | ||
| "label": "First Name", | ||
| "align": "left", | ||
| "sortDirection": "desc", | ||
| }, | ||
| {"id": "lastName", "label": "Last Name", "align": "center"}, | ||
| {"id": "age", "label": "Age"}, | ||
| ] | ||
|
|
||
| rows: TableRow = [ | ||
| ["1", "John", "Doe", 30], | ||
| ["2", "Jane", "Smith", 25], | ||
| ["3", "Peter", "Jones", 40], | ||
| ] | ||
|
|
||
| table = Table(id="table", rows=rows, columns=columns, hover=True) | ||
|
|
||
| title_text = Typography(id="title_text", children=["Basic Table"]) | ||
| info_text = Typography(id="info_text", children=["Click on any row."]) | ||
|
|
||
| return Box( | ||
| style={ | ||
| "display": "flex", | ||
| "flexDirection": "column", | ||
| "width": "100%", | ||
| "height": "100%", | ||
| "gap": "6px", | ||
| }, | ||
| children=[title_text, table, info_text], | ||
| ) | ||
|
|
||
|
|
||
| # noinspection PyUnusedLocal | ||
| @panel.callback(Input("table"), Output("info_text", "children")) | ||
| def update_info_text( | ||
| ctx: Context, | ||
| table_row: int, | ||
| ) -> list[str]: | ||
| return [f"The clicked row value is {table_row}."] |
This file contains hidden or 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,38 @@ | ||
| from chartlets.components.table import TableColumn, Table, TableRow | ||
| from tests.component_test import make_base | ||
|
|
||
|
|
||
| class TableTest(make_base(Table)): | ||
|
|
||
| def test_is_json_serializable_empty(self): | ||
| self.assert_is_json_serializable( | ||
| self.cls(), | ||
| { | ||
| "type": "Table", | ||
| }, | ||
| ) | ||
|
|
||
| columns: list[TableColumn] = [ | ||
| {"id": "id", "label": "ID"}, | ||
| {"id": "firstName", "label": "First Name"}, | ||
| {"id": "lastName", "label": "Last Name"}, | ||
| {"id": "age", "label": "Age"}, | ||
| ] | ||
| rows: TableRow = [ | ||
| ["John", "Doe", 30], | ||
| ["Jane", "Smith", 25], | ||
| ["Johnie", "Undoe", 40], | ||
| ] | ||
| hover: bool = True | ||
| style = {"background-color": "lightgray", "width": "100%"} | ||
|
|
||
| self.assert_is_json_serializable( | ||
| self.cls(columns=columns, rows=rows, style=style, hover=hover), | ||
| { | ||
| "type": "Table", | ||
| "columns": columns, | ||
| "rows": rows, | ||
| "style": style, | ||
| "hover": hover, | ||
| }, | ||
| ) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.