Skip to content

Commit e99caeb

Browse files
authored
Merge pull request #167 from reflex-dev/create-datatable-app-for-tutorial
a tutorial app on the datatable
2 parents b34e4b7 + 9cc7289 commit e99caeb

File tree

6 files changed

+372
-0
lines changed

6 files changed

+372
-0
lines changed

datatable_tutorial/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.db
2+
*.py[cod]
3+
.web
4+
__pycache__/
4.19 KB
Binary file not shown.

datatable_tutorial/datatable_tutorial/__init__.py

Whitespace-only changes.
Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
import reflex as rx
2+
from typing import Any
3+
import asyncio
4+
import httpx
5+
6+
7+
class BaseState(rx.State):
8+
pass
9+
10+
11+
class DataTableState(BaseState):
12+
"""The app state."""
13+
14+
clicked_cell: str = "Cell clicked: "
15+
edited_cell: str = "Cell edited: "
16+
right_clicked_group_header: str = "Group header right clicked: "
17+
item_hovered: str = "Item Hovered: "
18+
deleted: str = "Deleted: "
19+
20+
cols: list[dict] = [
21+
{"title": "Title", "type": "str"},
22+
{
23+
"title": "Name",
24+
"type": "str",
25+
"group": "Data",
26+
"width": 300,
27+
},
28+
{
29+
"title": "Birth",
30+
"type": "str",
31+
"group": "Data",
32+
"width": 150,
33+
},
34+
{
35+
"title": "Human",
36+
"type": "bool",
37+
"group": "Data",
38+
"width": 80,
39+
},
40+
{
41+
"title": "House",
42+
"type": "str",
43+
"group": "Data",
44+
},
45+
{
46+
"title": "Wand",
47+
"type": "str",
48+
"group": "Data",
49+
"width": 250,
50+
},
51+
{
52+
"title": "Patronus",
53+
"type": "str",
54+
"group": "Data",
55+
},
56+
{
57+
"title": "Blood status",
58+
"type": "str",
59+
"group": "Data",
60+
"width": 200,
61+
},
62+
]
63+
64+
data: list[str] = [
65+
[
66+
"1",
67+
"Harry James Potter",
68+
"31 July 1980",
69+
True,
70+
"Gryffindor",
71+
"11' Holly phoenix feather",
72+
"Stag",
73+
"Half-blood",
74+
],
75+
[
76+
"2",
77+
"Ronald Bilius Weasley",
78+
"1 March 1980",
79+
True,
80+
"Gryffindor",
81+
"12' Ash unicorn tail hair",
82+
"Jack Russell terrier",
83+
"Pure-blood",
84+
],
85+
[
86+
"3",
87+
"Hermione Jean Granger",
88+
"19 September, 1979",
89+
True,
90+
"Gryffindor",
91+
"10¾' vine wood dragon heartstring",
92+
"Otter",
93+
"Muggle-born",
94+
],
95+
[
96+
"4",
97+
"Albus Percival Wulfric Brian Dumbledore",
98+
"Late August 1881",
99+
True,
100+
"Gryffindor",
101+
"15' Elder Thestral tail hair core",
102+
"Phoenix",
103+
"Half-blood",
104+
],
105+
[
106+
"5",
107+
"Rubeus Hagrid",
108+
"6 December 1928",
109+
False,
110+
"Gryffindor",
111+
"16' Oak unknown core",
112+
"None",
113+
"Part-Human (Half-giant)",
114+
],
115+
[
116+
"6",
117+
"Fred Weasley",
118+
"1 April, 1978",
119+
True,
120+
"Gryffindor",
121+
"Unknown",
122+
"Unknown",
123+
"Pure-blood",
124+
],
125+
[
126+
"7",
127+
"George Weasley",
128+
"1 April, 1978",
129+
True,
130+
"Gryffindor",
131+
"Unknown",
132+
"Unknown",
133+
"Pure-blood",
134+
],
135+
]
136+
137+
def get_clicked_data(self, pos) -> str:
138+
self.clicked_cell = f"Cell clicked: {pos}"
139+
140+
def get_edited_data(self, pos, val) -> str:
141+
col, row = pos
142+
self.data[row][col] = val["data"]
143+
self.edited_cell = f"Cell edited: {pos}, Cell value: {val['data']}"
144+
145+
def get_group_header_right_click(self, index, val):
146+
self.right_clicked_group_header = f"Group header right clicked at index: {index}, Group header value: {val['group']}"
147+
148+
def get_item_hovered(self, pos) -> str:
149+
self.item_hovered = (
150+
f"Item Hovered type: {pos['kind']}, Location: {pos['location']}"
151+
)
152+
153+
def get_deleted_item(self, selection):
154+
self.deleted = f"Deleted cell: {selection['current']['cell']}"
155+
156+
# def append_row(self):
157+
# print("13232")
158+
159+
def column_resize(self, col, width):
160+
self.cols[col["pos"]]["width"] = width
161+
162+
163+
class DataTableLiveState(BaseState):
164+
"The app state."
165+
166+
running: bool
167+
table_data: list[dict[str, Any]] = []
168+
rate: int = 0.4
169+
columns: list[dict[str, str]] = [
170+
{
171+
"title": "id",
172+
"id": "v1",
173+
"type": "int",
174+
"width": 100,
175+
},
176+
{
177+
"title": "advice",
178+
"id": "v2",
179+
"type": "str",
180+
"width": 750,
181+
},
182+
]
183+
184+
@rx.background
185+
async def live_stream(self):
186+
while True:
187+
await asyncio.sleep(1 / self.rate)
188+
async with self:
189+
if not self.running:
190+
break
191+
192+
if len(self.table_data) > 50:
193+
self.table_data.pop(0)
194+
195+
res = httpx.get("https://api.adviceslip.com/advice")
196+
data = res.json()
197+
self.table_data.append(
198+
{"v1": data["slip"]["id"], "v2": data["slip"]["advice"]}
199+
)
200+
201+
def toggle_pause(self):
202+
self.running = not self.running
203+
if self.running:
204+
return DataTableLiveState.live_stream
205+
206+
207+
darkTheme = {
208+
"accentColor": "#8c96ff",
209+
"accentLight": "rgba(202, 206, 255, 0.253)",
210+
"textDark": "#ffffff",
211+
"textMedium": "#b8b8b8",
212+
"textLight": "#a0a0a0",
213+
"textBubble": "#ffffff",
214+
"bgIconHeader": "#b8b8b8",
215+
"fgIconHeader": "#000000",
216+
"textHeader": "#a1a1a1",
217+
"textHeaderSelected": "#000000",
218+
"bgCell": "#16161b",
219+
"bgCellMedium": "#202027",
220+
"bgHeader": "#212121",
221+
"bgHeaderHasFocus": "#474747",
222+
"bgHeaderHovered": "#404040",
223+
"bgBubble": "#212121",
224+
"bgBubbleSelected": "#000000",
225+
"bgSearchResult": "#423c24",
226+
"borderColor": "rgba(225,225,225,0.2)",
227+
"drilldownBorder": "rgba(225,225,225,0.4)",
228+
"linkColor": "#4F5DFF",
229+
"headerFontStyle": "bold 14px",
230+
"baseFontStyle": "13px",
231+
"fontFamily": "Inter, Roboto, -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Ubuntu, noto, arial, sans-serif",
232+
}
233+
234+
235+
tab_style = {
236+
"color": "#494369",
237+
"font_weight": 600,
238+
"_selected": {
239+
"color": "#5646ED",
240+
"bg": "#F5EFFE",
241+
"padding_x": "0.5em",
242+
"padding_y": "0.25em",
243+
"border_radius": "8px",
244+
},
245+
}
246+
247+
248+
def index() -> rx.Component:
249+
return rx.fragment(
250+
rx.color_mode_button(rx.color_mode_icon(), float="right"),
251+
rx.vstack(
252+
rx.heading("Data Table Demo!", font_size="2em"),
253+
rx.vstack(
254+
rx.tabs(
255+
rx.tab_list(
256+
rx.tab("Static Data", style=tab_style),
257+
rx.tab("Live Data", style=tab_style),
258+
),
259+
rx.tab_panels(
260+
rx.tab_panel(
261+
rx.vstack(
262+
rx.heading(
263+
DataTableState.clicked_cell, size="lg", color="blue"
264+
),
265+
rx.heading(
266+
DataTableState.edited_cell, size="lg", color="green"
267+
),
268+
rx.heading(
269+
DataTableState.right_clicked_group_header,
270+
size="lg",
271+
color="orange",
272+
),
273+
rx.heading(
274+
DataTableState.item_hovered,
275+
size="lg",
276+
color="purple",
277+
),
278+
rx.heading(
279+
DataTableState.deleted, size="lg", color="red"
280+
),
281+
rx.data_editor(
282+
columns=DataTableState.cols,
283+
data=DataTableState.data,
284+
# rows=10,
285+
on_paste=True,
286+
draw_focus_ring=False,
287+
# fixed_shadow_x=True,
288+
freeze_columns=2,
289+
group_header_height=100,
290+
header_height=80,
291+
# max_column_auto_width=200,
292+
# this works just need to describe it
293+
# max_column_width=200,
294+
min_column_width=100,
295+
row_height=50,
296+
row_markers="clickable-number",
297+
# also mention smooth_scroll_y
298+
smooth_scroll_x=True,
299+
vertical_border=False,
300+
column_select="multi",
301+
# prevent_diagonal_scrolling=False,
302+
overscroll_x=0,
303+
on_cell_clicked=DataTableState.get_clicked_data,
304+
on_cell_edited=DataTableState.get_edited_data,
305+
on_group_header_context_menu=DataTableState.get_group_header_right_click,
306+
on_item_hovered=DataTableState.get_item_hovered,
307+
on_delete=DataTableState.get_deleted_item,
308+
# on_row_appended=DataTableState.append_row,
309+
on_column_resize=DataTableState.column_resize,
310+
theme=darkTheme,
311+
width="80vw",
312+
height="80vh",
313+
),
314+
),
315+
),
316+
rx.tab_panel(
317+
rx.vstack(
318+
rx.stack(
319+
rx.cond(
320+
~DataTableLiveState.running,
321+
rx.button(
322+
"Start",
323+
on_click=DataTableLiveState.toggle_pause,
324+
color_scheme="green",
325+
),
326+
rx.button(
327+
"Pause",
328+
on_click=DataTableLiveState.toggle_pause,
329+
color_scheme="red",
330+
),
331+
),
332+
),
333+
rx.data_editor(
334+
columns=DataTableLiveState.columns,
335+
data=DataTableLiveState.table_data,
336+
draw_focus_ring=True,
337+
row_height=50,
338+
smooth_scroll_x=True,
339+
smooth_scroll_y=True,
340+
column_select="single",
341+
# style
342+
theme=darkTheme,
343+
),
344+
overflow_x="auto",
345+
width="100%",
346+
),
347+
),
348+
),
349+
spacing="1.5em",
350+
font_size="2em",
351+
padding_top="10vh",
352+
width="90vw",
353+
),
354+
),
355+
),
356+
)
357+
358+
359+
# Add state and page to the app.
360+
app = rx.App()
361+
app.add_page(index)
362+
app.compile()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
reflex>=0.3.1

datatable_tutorial/rxconfig.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import reflex as rx
2+
3+
config = rx.Config(
4+
app_name="datatable_tutorial",
5+
)

0 commit comments

Comments
 (0)