reflex/reflex/components/gridjs/datatable.py

130 lines
3.9 KiB
Python

"""Table components."""
from __future__ import annotations
from typing import Any, Dict, List, Union
from reflex.components.component import Component
from reflex.components.tags import Tag
from reflex.ivars.base import ImmutableVar, LiteralVar, is_computed_var
from reflex.utils import types
from reflex.utils.imports import ImportDict
from reflex.utils.serializers import serialize
from reflex.vars import Var
class Gridjs(Component):
"""A component that wraps a nivo bar component."""
library = "gridjs-react@6.0.1"
lib_dependencies: List[str] = ["gridjs@6.0.6"]
class DataTable(Gridjs):
"""A data table component."""
tag = "Grid"
alias = "DataTableGrid"
# The data to display. Either a list of lists or a pandas dataframe.
data: Any
# The list of columns to display. Required if data is a list and should not be provided
# if the data field is a dataframe
columns: Var[List]
# Enable a search bar.
search: Var[bool]
# Enable sorting on columns.
sort: Var[bool]
# Enable resizable columns.
resizable: Var[bool]
# Enable pagination.
pagination: Var[Union[bool, Dict]]
@classmethod
def create(cls, *children, **props):
"""Create a datatable component.
Args:
*children: The children of the component.
**props: The props to pass to the component.
Returns:
The datatable component.
Raises:
ValueError: If a pandas dataframe is passed in and columns are also provided.
"""
data = props.get("data")
columns = props.get("columns")
# The annotation should be provided if data is a computed var. We need this to know how to
# render pandas dataframes.
if is_computed_var(data) and data._var_type == Any:
raise ValueError(
"Annotation of the computed var assigned to the data field should be provided."
)
if (
columns is not None
and is_computed_var(columns)
and columns._var_type == Any
):
raise ValueError(
"Annotation of the computed var assigned to the column field should be provided."
)
# If data is a pandas dataframe and columns are provided throw an error.
if (
types.is_dataframe(type(data))
or (isinstance(data, ImmutableVar) and types.is_dataframe(data._var_type))
) and columns is not None:
raise ValueError(
"Cannot pass in both a pandas dataframe and columns to the data_table component."
)
# If data is a list and columns are not provided, throw an error
if (
(isinstance(data, ImmutableVar) and types._issubclass(data._var_type, List))
or issubclass(type(data), List)
) and columns is None:
raise ValueError(
"column field should be specified when the data field is a list type"
)
# Create the component.
return super().create(
*children,
**props,
)
def add_imports(self) -> ImportDict:
"""Add the imports for the datatable component.
Returns:
The import dict for the component.
"""
return {"": "gridjs/dist/theme/mermaid.css"}
def _render(self) -> Tag:
if isinstance(self.data, ImmutableVar) and types.is_dataframe(
self.data._var_type
):
self.columns = self.data.columns
self.data = self.data.data
if types.is_dataframe(type(self.data)):
# If given a pandas df break up the data and columns
data = serialize(self.data)
assert isinstance(data, dict), "Serialized dataframe should be a dict."
self.columns = LiteralVar.create(data["columns"])
self.data = LiteralVar.create(data["data"])
# Render the table.
return super()._render()