datatable.py 4.1 KB

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