From fa72ebcac4255a97a272c7668b7273cd7a2e5880 Mon Sep 17 00:00:00 2001 From: cardosofede Date: Wed, 26 Jul 2023 23:36:00 +0200 Subject: [PATCH] (feat) add ui components --- ui_components/__init__.py | 0 ui_components/bot_performance_card.py | 34 +++++++++++++++ ui_components/card.py | 34 +++++++++++++++ ui_components/dashboard.py | 60 +++++++++++++++++++++++++++ ui_components/datagrid.py | 51 +++++++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 ui_components/__init__.py create mode 100644 ui_components/bot_performance_card.py create mode 100644 ui_components/card.py create mode 100644 ui_components/dashboard.py create mode 100644 ui_components/datagrid.py diff --git a/ui_components/__init__.py b/ui_components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ui_components/bot_performance_card.py b/ui_components/bot_performance_card.py new file mode 100644 index 0000000..d25e233 --- /dev/null +++ b/ui_components/bot_performance_card.py @@ -0,0 +1,34 @@ +from streamlit_elements import mui +from ui_components.dashboard import Dashboard + + +class BotPerformanceCard(Dashboard.Item): + DEFAULT_CONTENT = ( + "This impressive paella is a perfect party dish and a fun meal to cook " + "together with your guests. Add 1 cup of frozen peas along with the mussels, " + "if you like." + ) + + def __init__(self, board, x, y, w, h, **item_props): + super().__init__(board, x, y, w, h, isResizable=False, **item_props) + + def __call__(self, bot_config: dict): + with mui.Card(key=self._key, + sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, + elevation=2): + color = "green" if bot_config["is_running"] else "red" + mui.CardHeader( + title=bot_config["bot_name"], + subheader=f"Running since {bot_config['start_date']}", + avatar=mui.Avatar("🤖", sx={"bgcolor": color}), + className=self._draggable_class, + ) + + with mui.CardContent(sx={"flex": 1}): + mui.Typography(bot_config["balances"]) + mui.Typography(bot_config["trades"]) + mui.Typography(bot_config["pnl"]) + + with mui.CardActions(disableSpacing=True): + mui.IconButton(mui.icon.Stop) + mui.IconButton(mui.icon.Share) diff --git a/ui_components/card.py b/ui_components/card.py new file mode 100644 index 0000000..10b9a90 --- /dev/null +++ b/ui_components/card.py @@ -0,0 +1,34 @@ +from streamlit_elements import mui +from ui_components.dashboard import Dashboard + + +class Card(Dashboard.Item): + + DEFAULT_CONTENT = ( + "This impressive paella is a perfect party dish and a fun meal to cook " + "together with your guests. Add 1 cup of frozen peas along with the mussels, " + "if you like." + ) + + def __call__(self, content): + with mui.Card(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1): + mui.CardHeader( + title="Shrimp and Chorizo Paella", + subheader="September 14, 2016", + avatar=mui.Avatar("R", sx={"bgcolor": "red"}), + action=mui.IconButton(mui.icon.MoreVert), + className=self._draggable_class, + ) + mui.CardMedia( + component="img", + height=194, + image="https://mui.com/static/images/cards/paella.jpg", + alt="Paella dish", + ) + + with mui.CardContent(sx={"flex": 1}): + mui.Typography(content) + + with mui.CardActions(disableSpacing=True): + mui.IconButton(mui.icon.Favorite) + mui.IconButton(mui.icon.Share) diff --git a/ui_components/dashboard.py b/ui_components/dashboard.py new file mode 100644 index 0000000..abc81a4 --- /dev/null +++ b/ui_components/dashboard.py @@ -0,0 +1,60 @@ +from uuid import uuid4 +from abc import ABC, abstractmethod +from streamlit_elements import dashboard, mui +from contextlib import contextmanager + + +class Dashboard: + + DRAGGABLE_CLASS = "draggable" + + def __init__(self): + self._layout = [] + + def _register(self, item): + self._layout.append(item) + + @contextmanager + def __call__(self, **props): + # Draggable classname query selector. + props["draggableHandle"] = f".{Dashboard.DRAGGABLE_CLASS}" + + with dashboard.Grid(self._layout, **props): + yield + + class Item(ABC): + + def __init__(self, board, x, y, w, h, **item_props): + self._key = str(uuid4()) + self._draggable_class = Dashboard.DRAGGABLE_CLASS + self._dark_mode = True + board._register(dashboard.Item(self._key, x, y, w, h, **item_props)) + + def _switch_theme(self): + self._dark_mode = not self._dark_mode + + @contextmanager + def title_bar(self, padding="5px 15px 5px 15px", dark_switcher=True): + with mui.Stack( + className=self._draggable_class, + alignItems="center", + direction="row", + spacing=1, + sx={ + "padding": padding, + "borderBottom": 1, + "borderColor": "divider", + }, + ): + yield + + if dark_switcher: + if self._dark_mode: + mui.IconButton(mui.icon.DarkMode, onClick=self._switch_theme) + else: + mui.IconButton(mui.icon.LightMode, sx={"color": "#ffc107"}, onClick=self._switch_theme) + + @abstractmethod + def __call__(self): + """Show elements.""" + raise NotImplementedError diff --git a/ui_components/datagrid.py b/ui_components/datagrid.py new file mode 100644 index 0000000..b8fbf88 --- /dev/null +++ b/ui_components/datagrid.py @@ -0,0 +1,51 @@ +import json + +from streamlit_elements import mui +from .dashboard import Dashboard + + +class DataGrid(Dashboard.Item): + DEFAULT_COLUMNS = [ + {"field": 'id', "headerName": 'ID', "width": 90}, + {"field": 'firstName', "headerName": 'First name', "width": 150, "editable": True, }, + {"field": 'lastName', "headerName": 'Last name', "width": 150, "editable": True, }, + {"field": 'age', "headerName": 'Age', "type": 'number', "width": 110, "editable": True, }, + ] + DEFAULT_ROWS = [ + {"id": 1, "lastName": 'Snow', "firstName": 'Jon', "age": 35}, + {"id": 2, "lastName": 'Lannister', "firstName": 'Cersei', "age": 42}, + {"id": 3, "lastName": 'Lannister', "firstName": 'Jaime', "age": 45}, + {"id": 4, "lastName": 'Stark', "firstName": 'Arya', "age": 16}, + {"id": 5, "lastName": 'Targaryen', "firstName": 'Daenerys', "age": None}, + {"id": 6, "lastName": 'Melisandre', "firstName": None, "age": 150}, + {"id": 7, "lastName": 'Clifford', "firstName": 'Ferrara', "age": 44}, + {"id": 8, "lastName": 'Frances', "firstName": 'Rossini', "age": 36}, + {"id": 9, "lastName": 'Roxie', "firstName": 'Harvey', "age": 65}, + ] + + def _handle_edit(self, params): + print(params) + + def __call__(self, json_data): + try: + data = json.loads(json_data) + except json.JSONDecodeError: + data = self.DEFAULT_ROWS + + with mui.Paper(key=self._key, + sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, + elevation=1): + with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False): + mui.icon.ViewCompact() + mui.Typography("Data grid") + + with mui.Box(sx={"flex": 1, "minHeight": 0}): + mui.DataGrid( + columns=self.DEFAULT_COLUMNS, + rows=data, + pageSize=5, + rowsPerPageOptions=[5], + checkboxSelection=True, + disableSelectionOnClick=True, + onCellEditCommit=self._handle_edit, + )