Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ag_grid_demo/ag_grid_demo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import model_dm as model_dm
from . import model_wrapper_customized as model_wrapper_customized
from . import model_wrapper_simple as model_wrapper_simple
from . import selected_items as selected_items
from . import tree as tree
76 changes: 16 additions & 60 deletions ag_grid_demo/ag_grid_demo/ag_grid_demo.py
Original file line number Diff line number Diff line change
@@ -1,71 +1,27 @@
"""Welcome to Reflex! This file showcases the custom component in a basic app."""

import reflex as rx
from reflex_ag_grid import ag_grid
import pandas as pd


df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv"
)

column_defs = [
ag_grid.column_def(field="direction"),
ag_grid.column_def(field="strength"),
ag_grid.column_def(field="frequency"),
]


class BasicGridState(rx.State):
selection: list[dict[str, str]] = []


def selected_item(item: dict[str, str]) -> rx.Component:
return rx.card(
rx.data_list.root(
rx.foreach(
item,
lambda kv: rx.data_list.item(
rx.data_list.label(kv[0]),
rx.data_list.value(kv[1]),
),
),
),
)
from .common import demo, DemoState


@demo(
route="/",
title="AG Grid Demo",
description="A collection of examples using AG Grid in Reflex.",
)
def index():
return rx.hstack(
rx.vstack(
ag_grid(
id="ag_grid_basic_1",
row_data=df.to_dict("records"),
column_defs=column_defs,
row_selection="multiple",
on_selection_changed=lambda rows, _0, _1: BasicGridState.set_selection(
rows
),
width="50vw",
),
rx.heading("Other demos"),
rx.link("Simple ModelWrapper", href="/model"),
rx.text(
rx.link("Customized ModelWrapper", href="/model-auth"),
" (Generate data)",
),
rx.link("Tree (enterprise)", href="/tree"),
),
rx.vstack(
rx.heading("Selected Items"),
rx.hstack(
rx.foreach(
BasicGridState.selection,
selected_item,
return rx.flex(
rx.foreach(
DemoState.pages,
lambda page: rx.card(
rx.vstack(
rx.link(page.title, href=page.route),
rx.text(page.description),
),
wrap="wrap",
width="300px",
),
max_width="48vw",
),
wrap="wrap",
spacing="3",
)


Expand Down
128 changes: 128 additions & 0 deletions ag_grid_demo/ag_grid_demo/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"""Common components used by all demo pages."""

import dataclasses
from functools import wraps
import inspect
from pathlib import Path
import reflex as rx


@dataclasses.dataclass(frozen=True)
class DemoPage:
"""A demo page."""

route: str
title: str
description: str


_DEMO_PAGES: dict[str, DemoPage] = {}


class DemoState(rx.State):
"""State for the demo pages."""

@rx.var(cache=True)
def pages(self) -> list[DemoPage]:
return [p for p in _DEMO_PAGES.values() if p.route != "/"]


def demo_dropdown():
"""Dropdown to navigate between demo pages."""

return rx.select.root(
rx.select.trigger(placeholder="Select Demo"),
rx.select.content(
rx.foreach(
DemoState.pages,
lambda page: rx.select.item(
rx.heading(page.title, size="3"), value=page.route
),
)
),
value=rx.cond(
rx.State.router.page.path == "/",
"",
rx.State.router.page.path,
),
on_change=rx.redirect,
)


def demo_template(page):
"""Template for all demo pages."""

page_data = _DEMO_PAGES[page.__name__]
page_file = Path(inspect.getfile(page))
page_source = page_file.read_text()
relative_page_file = page_file.relative_to(
Path(__file__, "..", "..", "..", "..").resolve()
)

return rx.container(
rx.color_mode.button(position="top-right"),
rx.hstack(
demo_dropdown(),
rx.spacer(),
rx.link(
rx.heading("reflex-ag-grid demo", size="4"),
href="/",
),
width="100%",
align="center",
),
rx.text(page_data.description, margin_left="10px", margin_top="5px"),
rx.tabs.root(
rx.tabs.list(
rx.tabs.trigger(
rx.hstack(rx.icon("eye"), rx.text("Example")), value="example"
),
rx.tabs.trigger(
rx.hstack(rx.icon("code"), rx.text("Source")), value="source"
),
margin_bottom="1em",
),
rx.tabs.content(page(), value="example", height="fit-content"),
rx.tabs.content(
rx.card(
rx.inset(
rx.badge(
rx.code(str(relative_page_file)),
width="100%",
size="2",
height="3em",
radius="none",
),
side="top",
pb="current",
),
rx.code_block(
page_source, language="python", show_line_numbers=True
),
),
value="source",
),
default_value="example",
margin_top="1em",
),
rx.logo(),
size="4",
)


def demo(route: str, title: str, description: str, **kwargs):
"""Decorator to add the demo page to the demo registry."""

def decorator(page):
_DEMO_PAGES[page.__name__] = DemoPage(
route=route, title=title, description=description
)

@rx.page(route=route, title=title, description=description, **kwargs)
@wraps(page)
def inner():
return demo_template(page)

return inner

return decorator
Original file line number Diff line number Diff line change
@@ -1,57 +1,9 @@
import datetime

import faker
import reflex as rx
from sqlmodel import Column, DateTime, Field, func

from reflex_ag_grid.wrapper import model_wrapper, ModelWrapper


class Friend(rx.Model, table=True):
name: str
age: int
years_known: int
owes_me: bool = False
has_a_dog: bool = False
spouse_is_annoying: bool = False
met: datetime.datetime = Field(
sa_column=Column(DateTime(timezone=True), server_default=func.now()),
)

@classmethod
def generate_fakes(cls, n: int) -> list["Friend"]:
new_friends = []
fake = faker.Faker()
for _ in range(n):
name = fake.name()
age = fake.random_int(min=18, max=80)
years_known = fake.random_int(min=0, max=age)
new_friends.append(
Friend(
name=name,
age=age,
years_known=years_known,
owes_me=fake.pybool(20),
has_a_dog=fake.pybool(60),
spouse_is_annoying=fake.pybool(30),
met=fake.date_time_between(
start_date=f"-{years_known+1}y", end_date=f"-{years_known}y"
),
),
)
return new_friends

from reflex_ag_grid.wrapper import ModelWrapper

# Basic Example of a ModelWrapper with no customization
@rx.page("/model")
def model_page():
return rx.box(
model_wrapper(
model_class=Friend,
),
width="100vw",
height="100vh",
)
from .common import demo
from .model_wrapper_simple import Friend


# This bogus auth state demonstrates how an extended ModelWrapper can check
Expand Down Expand Up @@ -105,7 +57,7 @@ async def _get_data(self, start, end, filter_model, sort_model):
auth_state = await self.get_state(AuthState)
if not auth_state.logged_in:
return [] # no records for logged out users
return super()._get_data(
return await super()._get_data(
start, end, filter_model=filter_model, sort_model=sort_model
)

Expand All @@ -117,7 +69,11 @@ def selected_items(self) -> list[Friend]:


# Advanced example of an extended ModelWrapper with custom behavior
@rx.page("/model-auth")
@demo(
route="/model-auth",
title="Customized ModelWrapper",
description="Extended infinite-row ModelWrapper with custom behavior and auth.",
)
def model_page_auth():
grid = FriendModelWrapper.create(
model_class=Friend,
Expand All @@ -141,7 +97,8 @@ def model_page_auth():
),
rx.box(
grid,
width="100vw",
height="90vh",
width="100%",
height="65vh",
padding_bottom="60px", # for scroll bar and controls
),
)
60 changes: 60 additions & 0 deletions ag_grid_demo/ag_grid_demo/model_wrapper_simple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import datetime

import faker
import reflex as rx
from sqlmodel import Column, DateTime, Field, func

from reflex_ag_grid.wrapper import model_wrapper

from .common import demo


class Friend(rx.Model, table=True):
name: str
age: int
years_known: int
owes_me: bool = False
has_a_dog: bool = False
spouse_is_annoying: bool = False
met: datetime.datetime = Field(
sa_column=Column(DateTime(timezone=True), server_default=func.now()),
)

@classmethod
def generate_fakes(cls, n: int) -> list["Friend"]:
new_friends = []
fake = faker.Faker()
for _ in range(n):
name = fake.name()
age = fake.random_int(min=18, max=80)
years_known = fake.random_int(min=0, max=age)
new_friends.append(
Friend(
name=name,
age=age,
years_known=years_known,
owes_me=fake.pybool(20),
has_a_dog=fake.pybool(60),
spouse_is_annoying=fake.pybool(30),
met=fake.date_time_between(
start_date=f"-{years_known+1}y", end_date=f"-{years_known}y"
),
),
)
return new_friends


@demo(
route="/model",
title="Simple ModelWrapper",
description="Basic example of an infinite-row ModelWrapper with no customization.",
)
def model_page():
return rx.box(
model_wrapper(
model_class=Friend,
),
width="100%",
height="71vh",
padding_bottom="60px", # for scroll bar and controls
)
Loading