datatable.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. """Table components."""
  2. from __future__ import annotations
  3. from typing import Any, Dict, List, Union
  4. from reflex.components.component import Component
  5. from reflex.components.tags import Tag
  6. from reflex.ivars.base import ImmutableVar, LiteralVar, is_computed_var
  7. from reflex.utils import types
  8. from reflex.utils.imports import ImportDict
  9. from reflex.utils.serializers import serialize
  10. from reflex.vars import Var
  11. class Gridjs(Component):
  12. """A component that wraps a nivo bar component."""
  13. library = "gridjs-react@6.0.1"
  14. lib_dependencies: List[str] = ["gridjs@6.0.6"]
  15. class DataTable(Gridjs):
  16. """A data table component."""
  17. tag = "Grid"
  18. alias = "DataTableGrid"
  19. # The data to display. Either a list of lists or a pandas dataframe.
  20. data: Any
  21. # The list of columns to display. Required if data is a list and should not be provided
  22. # if the data field is a dataframe
  23. columns: Var[List]
  24. # Enable a search bar.
  25. search: Var[bool]
  26. # Enable sorting on columns.
  27. sort: Var[bool]
  28. # Enable resizable columns.
  29. resizable: Var[bool]
  30. # Enable pagination.
  31. pagination: Var[Union[bool, Dict]]
  32. @classmethod
  33. def create(cls, *children, **props):
  34. """Create a datatable component.
  35. Args:
  36. *children: The children of the component.
  37. **props: The props to pass to the component.
  38. Returns:
  39. The datatable component.
  40. Raises:
  41. ValueError: If a pandas dataframe is passed in and columns are also provided.
  42. """
  43. data = props.get("data")
  44. columns = props.get("columns")
  45. # The annotation should be provided if data is a computed var. We need this to know how to
  46. # render pandas dataframes.
  47. if is_computed_var(data) and data._var_type == Any:
  48. raise ValueError(
  49. "Annotation of the computed var assigned to the data field should be provided."
  50. )
  51. if (
  52. columns is not None
  53. and is_computed_var(columns)
  54. and columns._var_type == Any
  55. ):
  56. raise ValueError(
  57. "Annotation of the computed var assigned to the column field should be provided."
  58. )
  59. # If data is a pandas dataframe and columns are provided throw an error.
  60. if (
  61. types.is_dataframe(type(data))
  62. or (isinstance(data, ImmutableVar) and types.is_dataframe(data._var_type))
  63. ) and columns is not None:
  64. raise ValueError(
  65. "Cannot pass in both a pandas dataframe and columns to the data_table component."
  66. )
  67. # If data is a list and columns are not provided, throw an error
  68. if (
  69. (isinstance(data, ImmutableVar) and types._issubclass(data._var_type, List))
  70. or issubclass(type(data), List)
  71. ) and columns is None:
  72. raise ValueError(
  73. "column field should be specified when the data field is a list type"
  74. )
  75. # Create the component.
  76. return super().create(
  77. *children,
  78. **props,
  79. )
  80. def add_imports(self) -> ImportDict:
  81. """Add the imports for the datatable component.
  82. Returns:
  83. The import dict for the component.
  84. """
  85. return {"": "gridjs/dist/theme/mermaid.css"}
  86. def _render(self) -> Tag:
  87. if isinstance(self.data, ImmutableVar) and types.is_dataframe(
  88. self.data._var_type
  89. ):
  90. self.columns = self.data._replace(
  91. _var_name=f"{self.data._var_name}.columns",
  92. _var_type=List[Any],
  93. )
  94. self.data = self.data._replace(
  95. _var_name=f"{self.data._var_name}.data",
  96. _var_type=List[List[Any]],
  97. )
  98. if types.is_dataframe(type(self.data)):
  99. # If given a pandas df break up the data and columns
  100. data = serialize(self.data)
  101. assert isinstance(data, dict), "Serialized dataframe should be a dict."
  102. self.columns = LiteralVar.create(data["columns"])
  103. self.data = LiteralVar.create(data["data"])
  104. # Render the table.
  105. return super()._render()