Compare commits

...

3 Commits

Author SHA1 Message Date
Elijah
93c59eccaa remove redundant None defaults from optional types 2023-11-06 16:22:25 +00:00
Elijah
70b76fea21 custom serializer for data editor props 2023-11-06 16:21:40 +00:00
Elijah
b10cab04cb Data Editor Icon header to Column 2023-11-06 16:21:36 +00:00
2 changed files with 205 additions and 127 deletions

View File

@ -1,8 +1,7 @@
"""Data Editor component from glide-data-grid.""" """Data Editor component from glide-data-grid."""
from __future__ import annotations from __future__ import annotations
from enum import Enum from typing import Any, Callable, Dict, List, Literal, Optional, Union
from typing import Any, Callable, Dict, List, Optional, Union
from reflex.base import Base from reflex.base import Base
from reflex.components.component import Component, NoSSRComponent from reflex.components.component import Component, NoSSRComponent
@ -11,95 +10,114 @@ from reflex.utils import console, format, imports, types
from reflex.utils.serializers import serializer from reflex.utils.serializers import serializer
from reflex.vars import ImportVar, Var, get_unique_variable_name from reflex.vars import ImportVar, Var, get_unique_variable_name
LiteralDataEditorGridColumnIcons = Literal[
# TODO: Fix the serialization issue for custom types. "headerRowID",
class GridColumnIcons(Enum): "headerCode",
"""An Enum for the available icons in DataEditor.""" "headerNumber",
"headerString",
Array = "array" "headerBoolean",
AudioUri = "audio_uri" "headerAudioUri",
Boolean = "boolean" "headerVideoUri",
HeaderCode = "code" "headerEmoji",
Date = "date" "headerImage",
Email = "email" "headerUri",
Emoji = "emoji" "headerPhone",
GeoDistance = "geo_distance" "headerMarkdown",
IfThenElse = "if_then_else" "headerDate",
Image = "image" "headerTime",
JoinStrings = "join_strings" "headerEmail",
Lookup = "lookup" "headerReference",
Markdown = "markdown" "headerIfThenElse",
Math = "math" "headerSingleValue",
Number = "number" "headerLookup",
Phone = "phone" "headerTextTemplate",
Reference = "reference" "headerMath",
Rollup = "rollup" "headerRollup",
RowID = "row_id" "headerJoinStrings",
SingleValue = "single_value" "headerSplitString",
SplitString = "split_string" "headerGeoDistance",
String = "string" "headerArray",
TextTemplate = "text_template" "rowOwnerOverlay",
Time = "time" "protectedColumnOverlay",
Uri = "uri" ]
VideoUri = "video_uri" LiteralDataEditorColumnStyle = Literal["normal", "highlight"]
# @serializer class DataEditorProp(Base):
# def serialize_gridcolumn_icon(icon: GridColumnIcons) -> str: """Base class for Data Editor custom prop class."""
# """Serialize grid column icon.
# Args: def dict(self) -> dict:
# icon: the Icon to serialize. """Retrieve dict and format keys to camel case.
# Returns: Returns:
# The serialized value. Formatted dict.
# """ """
# return "prefix" + str(icon) res = super().dict()
return {format.to_camel_case(k): v for k, v in res.items() if v is not None}
# class DataEditorColumn(Base): class DataEditorTheme(DataEditorProp):
# """Column."""
# title: str
# id: Optional[str] = None
# type_: str = "str"
class DataEditorTheme(Base):
"""The theme for the DataEditor component.""" """The theme for the DataEditor component."""
accent_color: Optional[str] = None accent_color: Optional[str]
accent_fg: Optional[str] = None accent_fg: Optional[str]
accent_light: Optional[str] = None accent_light: Optional[str]
base_font_style: Optional[str] = None base_font_style: Optional[str]
bg_bubble: Optional[str] = None bg_bubble: Optional[str]
bg_bubble_selected: Optional[str] = None bg_bubble_selected: Optional[str]
bg_cell: Optional[str] = None bg_cell: Optional[str]
bg_cell_medium: Optional[str] = None bg_cell_medium: Optional[str]
bg_header: Optional[str] = None bg_header: Optional[str]
bg_header_has_focus: Optional[str] = None bg_header_has_focus: Optional[str]
bg_header_hovered: Optional[str] = None bg_header_hovered: Optional[str]
bg_icon_header: Optional[str] = None bg_icon_header: Optional[str]
bg_search_result: Optional[str] = None bg_search_result: Optional[str]
border_color: Optional[str] = None border_color: Optional[str]
cell_horizontal_padding: Optional[int] = None cell_horizontal_padding: Optional[int]
cell_vertical_padding: Optional[int] = None cell_vertical_padding: Optional[int]
drilldown_border: Optional[str] = None drilldown_border: Optional[str]
editor_font_size: Optional[str] = None editor_font_size: Optional[str]
fg_icon_header: Optional[str] = None fg_icon_header: Optional[str]
font_family: Optional[str] = None font_family: Optional[str]
header_bottom_border_color: Optional[str] = None header_bottom_border_color: Optional[str]
header_font_style: Optional[str] = None header_font_style: Optional[str]
horizontal_border_color: Optional[str] = None horizontal_border_color: Optional[str]
line_height: Optional[int] = None line_height: Optional[int]
link_color: Optional[str] = None link_color: Optional[str]
text_bubble: Optional[str] = None text_bubble: Optional[str]
text_dark: Optional[str] = None text_dark: Optional[str]
text_group_header: Optional[str] = None text_group_header: Optional[str]
text_header: Optional[str] = None text_header: Optional[str]
text_header_selected: Optional[str] = None text_header_selected: Optional[str]
text_light: Optional[str] = None text_light: Optional[str]
text_medium: Optional[str] = None text_medium: Optional[str]
class TrailingRowOptions(DataEditorProp):
"""Trailing Row options."""
hint: Optional[str]
add_icon: Optional[str]
target_column: Optional[int]
theme_override: Optional[DataEditorTheme]
disabled: Optional[bool]
class DataEditorColumn(DataEditorProp):
"""Column."""
title: str
id: Optional[str]
type_: str = "str"
group: Optional[str]
icon: Optional[LiteralDataEditorGridColumnIcons]
overlay_icon: Optional[LiteralDataEditorGridColumnIcons]
has_menu: Optional[bool]
grow: Optional[int]
style: Optional[LiteralDataEditorColumnStyle]
theme_override: Optional[DataEditorTheme]
trailing_row_options: Optional[TrailingRowOptions]
grow_offset: Optional[int]
class DataEditor(NoSSRComponent): class DataEditor(NoSSRComponent):
@ -114,7 +132,7 @@ class DataEditor(NoSSRComponent):
rows: Var[int] rows: Var[int]
# Headers of the columns for the data grid. # Headers of the columns for the data grid.
columns: Var[List[Dict[str, Any]]] columns: Var[List[DataEditorColumn]]
# The data. # The data.
data: Var[List[List[Any]]] data: Var[List[List[Any]]]
@ -307,9 +325,17 @@ class DataEditor(NoSSRComponent):
"Cannot pass in both a pandas dataframe and columns to the data_editor component." "Cannot pass in both a pandas dataframe and columns to the data_editor component."
) )
else: else:
props["columns"] = [ if (
format.format_data_editor_column(col) for col in columns not isinstance(columns, list)
] or isinstance(columns, list)
and columns
and not isinstance(columns[0], dict)
):
raise ValueError(
"Data Editor columns field should be a list of dictionaries"
)
props["columns"] = [DataEditorColumn(**c) for c in columns]
if "theme" in props: if "theme" in props:
theme = props.get("theme") theme = props.get("theme")
@ -386,15 +412,13 @@ class DataEditor(NoSSRComponent):
@serializer @serializer
def serialize_dataeditortheme(theme: DataEditorTheme): def serialize_data_editor_prop(prop: DataEditorProp) -> dict:
"""The serializer for the data editor theme. """The serializer for the data editor theme.
Args: Args:
theme: The theme to serialize. prop: The prop to serialize.
Returns: Returns:
The serialized theme. The serialized prop.
""" """
return format.json_dumps( return prop.dict()
{format.to_camel_case(k): v for k, v in theme.__dict__.items() if v is not None}
)

View File

@ -16,41 +16,95 @@ from reflex.utils import console, format, imports, types
from reflex.utils.serializers import serializer from reflex.utils.serializers import serializer
from reflex.vars import ImportVar, Var, get_unique_variable_name from reflex.vars import ImportVar, Var, get_unique_variable_name
class GridColumnIcons(Enum): ... LiteralDataEditorGridColumnIcons = Literal[
"headerRowID",
"headerCode",
"headerNumber",
"headerString",
"headerBoolean",
"headerAudioUri",
"headerVideoUri",
"headerEmoji",
"headerImage",
"headerUri",
"headerPhone",
"headerMarkdown",
"headerDate",
"headerTime",
"headerEmail",
"headerReference",
"headerIfThenElse",
"headerSingleValue",
"headerLookup",
"headerTextTemplate",
"headerMath",
"headerRollup",
"headerJoinStrings",
"headerSplitString",
"headerGeoDistance",
"headerArray",
"rowOwnerOverlay",
"protectedColumnOverlay",
]
class DataEditorTheme(Base): LiteralDataEditorColumnStyle = Literal["normal", "highlight"]
accent_color: Optional[str]
accent_fg: Optional[str] class DataEditorProp(Base): ...
accent_light: Optional[str]
base_font_style: Optional[str] class DataEditorTheme(DataEditorProp):
bg_bubble: Optional[str] accent_color: Optional[str] = None
bg_bubble_selected: Optional[str] accent_fg: Optional[str] = None
bg_cell: Optional[str] accent_light: Optional[str] = None
bg_cell_medium: Optional[str] base_font_style: Optional[str] = None
bg_header: Optional[str] bg_bubble: Optional[str] = None
bg_header_has_focus: Optional[str] bg_bubble_selected: Optional[str] = None
bg_header_hovered: Optional[str] bg_cell: Optional[str] = None
bg_icon_header: Optional[str] bg_cell_medium: Optional[str] = None
bg_search_result: Optional[str] bg_header: Optional[str] = None
border_color: Optional[str] bg_header_has_focus: Optional[str] = None
cell_horizontal_padding: Optional[int] bg_header_hovered: Optional[str] = None
cell_vertical_padding: Optional[int] bg_icon_header: Optional[str] = None
drilldown_border: Optional[str] bg_search_result: Optional[str] = None
editor_font_size: Optional[str] border_color: Optional[str] = None
fg_icon_header: Optional[str] cell_horizontal_padding: Optional[int] = None
font_family: Optional[str] cell_vertical_padding: Optional[int] = None
header_bottom_border_color: Optional[str] drilldown_border: Optional[str] = None
header_font_style: Optional[str] editor_font_size: Optional[str] = None
horizontal_border_color: Optional[str] fg_icon_header: Optional[str] = None
line_height: Optional[int] font_family: Optional[str] = None
link_color: Optional[str] header_bottom_border_color: Optional[str] = None
text_bubble: Optional[str] header_font_style: Optional[str] = None
text_dark: Optional[str] horizontal_border_color: Optional[str] = None
text_group_header: Optional[str] line_height: Optional[int] = None
text_header: Optional[str] link_color: Optional[str] = None
text_header_selected: Optional[str] text_bubble: Optional[str] = None
text_light: Optional[str] text_dark: Optional[str] = None
text_medium: Optional[str] text_group_header: Optional[str] = None
text_header: Optional[str] = None
text_header_selected: Optional[str] = None
text_light: Optional[str] = None
text_medium: Optional[str] = None
class TrailingRowOptions(DataEditorProp):
hint: Optional[str]
add_icon: Optional[str]
target_column: Optional[int]
theme_override: Optional[DataEditorTheme]
disabled: Optional[bool]
class DataEditorColumn(DataEditorProp):
title: str
id: Optional[str] = None
type_: str = "str"
group: Optional[str]
icon: Optional[LiteralDataEditorGridColumnIcons]
overlay_icon: Optional[LiteralDataEditorGridColumnIcons]
has_menu: Optional[bool]
grow: Optional[int]
style: Optional[LiteralDataEditorColumnStyle]
theme_override: Optional[DataEditorTheme]
trailing_row_options: Optional[TrailingRowOptions]
grow_offset: Optional[int]
class DataEditor(NoSSRComponent): class DataEditor(NoSSRComponent):
def get_event_triggers(self) -> Dict[str, Callable]: ... def get_event_triggers(self) -> Dict[str, Callable]: ...