diff --git a/src/myfasthtml/controls/DataGrid.py b/src/myfasthtml/controls/DataGrid.py index 909e7ea..53aba86 100644 --- a/src/myfasthtml/controls/DataGrid.py +++ b/src/myfasthtml/controls/DataGrid.py @@ -1,9 +1,10 @@ from typing import Optional +from fastcore.basics import NotStr from fasthtml.components import Div from myfasthtml.controls.BaseCommands import BaseCommands -from myfasthtml.controls.datagrid_objects import DataGridColumnState, DataGridRowState, DataGridFooterConf, \ +from myfasthtml.controls.datagrid_objects import DataGridColumnState, DataGridRowState, \ DatagridSelectionState, DataGridHeaderFooterConf, DatagridEditionState from myfasthtml.core.dbmanager import DbObject from myfasthtml.core.instances import MultipleInstance @@ -24,6 +25,7 @@ class DatagridState(DbObject): self.filtered: dict = {} self.edition: DatagridEditionState = DatagridEditionState() self.selection: DatagridSelectionState = DatagridSelectionState() + self.html = None class DatagridSettings(DbObject): @@ -46,13 +48,17 @@ class Commands(BaseCommands): class DataGrid(MultipleInstance): def __init__(self, parent, settings=None, _id=None): super().__init__(parent, _id=_id) - self._settings = DatagridSettings(self).update(settings) + self._settings = DatagridSettings(self) self._state = DatagridState(self) self.commands = Commands(self) + def set_html(self, html): + self._state.html = html + def render(self): return Div( - self._id + NotStr(self._state.html), + id=self._id ) def __ft__(self): diff --git a/src/myfasthtml/controls/DataGridsManager.py b/src/myfasthtml/controls/DataGridsManager.py index aada9f5..2f065e2 100644 --- a/src/myfasthtml/controls/DataGridsManager.py +++ b/src/myfasthtml/controls/DataGridsManager.py @@ -1,11 +1,12 @@ from dataclasses import dataclass import pandas as pd -from fastcore.basics import NotStr from fasthtml.components import Div from myfasthtml.controls.BaseCommands import BaseCommands +from myfasthtml.controls.DataGrid import DataGrid from myfasthtml.controls.FileUpload import FileUpload +from myfasthtml.controls.Panel import Panel from myfasthtml.controls.TabsManager import TabsManager from myfasthtml.controls.TreeView import TreeView, TreeNode from myfasthtml.controls.helpers import mk @@ -76,8 +77,10 @@ class DataGridsManager(MultipleInstance): def open_from_excel(self, tab_id, file_upload: FileUpload): excel_content = file_upload.get_content() - df = pd.read_excel(excel_content) - content = df.to_html(index=False) + df = pd.read_excel(excel_content, file_upload.get_sheet_name()) + html = df.to_html(index=False) + dg = DataGrid(self._tabs_manager) + dg.set_html(html) document = DocumentDefinition( namespace=file_upload.get_file_basename(), name=file_upload.get_sheet_name(), @@ -89,7 +92,7 @@ class DataGridsManager(MultipleInstance): parent_id = self._tree.ensure_path(document.namespace) tree_node = TreeNode(label=document.name, type="excel", parent=parent_id) self._tree.add_node(tree_node, parent_id=parent_id) - return self._mk_tree(), self._tabs_manager.change_tab_content(tab_id, document.name, NotStr(content)) + return self._mk_tree(), self._tabs_manager.change_tab_content(tab_id, document.name, Panel(self).set_main(dg)) def clear_tree(self): self._state.elements = [] diff --git a/src/myfasthtml/controls/TabsManager.py b/src/myfasthtml/controls/TabsManager.py index f7825d8..07a12f0 100644 --- a/src/myfasthtml/controls/TabsManager.py +++ b/src/myfasthtml/controls/TabsManager.py @@ -111,10 +111,10 @@ class TabsManager(MultipleInstance): if tab_id not in self._state.tabs: return Div("Tab not found.") tab_config = self._state.tabs[tab_id] - if tab_config["component_type"] is None: + if tab_config["component"] is None: return Div("Tab content does not support serialization.") try: - return InstancesManager.get(self._session, tab_config["component_id"]) + return InstancesManager.get(self._session, tab_config["component"][1]) except Exception as e: logger.error(f"Error while retrieving tab content: {e}") return Div("Failed to retrieve tab content.") @@ -384,8 +384,7 @@ class TabsManager(MultipleInstance): if component_id is not None: for tab_id, tab_data in self._state.tabs.items(): - if (tab_data.get('component_type') == component_type and - tab_data.get('component_id') == component_id and + if (tab_data.get('component') == (component_type, component_id) and tab_data.get('label') == label): return tab_id @@ -399,16 +398,21 @@ class TabsManager(MultipleInstance): # Extract component ID if the component has a get_id() method component_type, component_id = None, None + parent_type, parent_id = None, None if isinstance(component, BaseInstance): component_type = component.get_prefix() component_id = component.get_id() + parent = component.get_parent() + if parent: + parent_type = parent.get_prefix() + parent_id = parent.get_id() # Add tab metadata to state state.tabs[tab_id] = { 'id': tab_id, 'label': label, - 'component_type': component_type, - 'component_id': component_id + 'component': (component_type, component_id) if component_type else None, + 'component_parent': (parent_type, parent_id) if parent_type else None } # Add tab to order list diff --git a/src/myfasthtml/controls/TreeView.py b/src/myfasthtml/controls/TreeView.py index fd93536..30f8926 100644 --- a/src/myfasthtml/controls/TreeView.py +++ b/src/myfasthtml/controls/TreeView.py @@ -37,6 +37,7 @@ class TreeNode: type: str = "default" parent: Optional[str] = None children: list[str] = field(default_factory=list) + bag: Optional[dict] = None # to keep extra info class TreeViewState(DbObject): diff --git a/src/myfasthtml/core/dbmanager.py b/src/myfasthtml/core/dbmanager.py index 97dd8ed..c4bdb00 100644 --- a/src/myfasthtml/core/dbmanager.py +++ b/src/myfasthtml/core/dbmanager.py @@ -98,6 +98,8 @@ class DbObject: properties = {} if args: arg = args[0] + if arg is None: + return self if not isinstance(arg, (dict, SimpleNamespace)): raise ValueError("Only dict or Expando are allowed as argument") properties |= vars(arg) if isinstance(arg, SimpleNamespace) else arg diff --git a/tests/controls/test_tabsmanager.py b/tests/controls/test_tabsmanager.py index c3599bc..0ec7cdc 100644 --- a/tests/controls/test_tabsmanager.py +++ b/tests/controls/test_tabsmanager.py @@ -51,8 +51,8 @@ class TestTabsManagerBehaviour: assert tab_id in tabs_manager.get_state().tabs assert tabs_manager.get_state().tabs[tab_id]["label"] == "Tab1" assert tabs_manager.get_state().tabs[tab_id]["id"] == tab_id - assert tabs_manager.get_state().tabs[tab_id]["component_type"] is None - assert tabs_manager.get_state().tabs[tab_id]["component_id"] is None + assert tabs_manager.get_state().tabs[tab_id]["component"] is None + assert tabs_manager.get_state().tabs[tab_id]["component_parent"] is None assert tabs_manager.get_state().tabs_order == [tab_id] assert tabs_manager.get_state().active_tab == tab_id @@ -61,9 +61,12 @@ class TestTabsManagerBehaviour: vis_network = VisNetwork(tabs_manager, nodes=[], edges=[]) tab_id = tabs_manager.create_tab("Network", vis_network) + component_type, component_id = vis_network.get_prefix(), vis_network.get_id() + parent_type, parent_id = tabs_manager.get_prefix(), tabs_manager.get_id() + assert tab_id is not None - assert tabs_manager.get_state().tabs[tab_id]["component_type"] == vis_network.get_prefix() - assert tabs_manager.get_state().tabs[tab_id]["component_id"] == vis_network.get_id() + assert tabs_manager.get_state().tabs[tab_id]["component"] == (component_type, component_id) + assert tabs_manager.get_state().tabs[tab_id]["component_parent"] == (parent_type, parent_id) def test_i_can_create_multiple_tabs(self, tabs_manager): """Test creating multiple tabs maintains correct order and activation."""