Working on Datagrid interaction

This commit is contained in:
2025-12-08 22:39:26 +01:00
parent 045f01b48a
commit b26abc4257
6 changed files with 36 additions and 17 deletions

View File

@@ -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):

View File

@@ -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 = []

View File

@@ -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

View File

@@ -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):

View File

@@ -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

View File

@@ -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."""