Fixed unit tests

This commit is contained in:
2026-03-11 20:59:07 +01:00
parent e01d2cd74b
commit e704dad62c
15 changed files with 353 additions and 679 deletions

View File

@@ -224,6 +224,10 @@ class DataGrid(MultipleInstance):
self._columns = None
self.commands = Commands(self)
# reset
self._state.selection.selected = None
self._state.selection.last_selected = None
# Obtain DataService from DataServicesManager (no parent hierarchy)
data_services_manager = InstancesManager.get_by_type(self._session, DataServicesManager)
data_service_id = self.get_data_service_id_from_data_grid_id(self._id)
@@ -264,7 +268,7 @@ class DataGrid(MultipleInstance):
# self._columns_manager.bind_command("SaveColumnDetails", self.commands.on_column_changed())
if self._settings.enable_formatting:
provider = InstancesManager.get_by_type(self._session, DatagridMetadataProvider, None)
provider = DatagridMetadataProvider(self._parent)
completion_engine = FormattingCompletionEngine(provider, self.get_table_name())
editor_conf = DslEditorConf(engine_id=completion_engine.get_id())
dsl = FormattingDSL()
@@ -305,6 +309,10 @@ class DataGrid(MultipleInstance):
def _fast_access(self):
return self._data_service.get_store().ns_fast_access
@property
def _row_data(self):
return self._data_service.get_store().ns_row_data
def _apply_sort(self, df):
if df is None:
return None
@@ -413,9 +421,9 @@ class DataGrid(MultipleInstance):
if self._state.table_format:
return self._state.table_format
# Get global tables formatting from DatagridMetadataProvider
provider = InstancesManager.get_by_type(self._session, DatagridMetadataProvider, None)
return provider.all_tables_formats if provider is not None else []
# Get global tables formatting from DataGridsManager
dgm = self.get_parent()
return dgm.get_state().all_tables_formats if dgm is not None else []
def _init_columns(self):
# Populate UI state from DataService columns when creating a new grid
@@ -494,22 +502,6 @@ class DataGrid(MultipleInstance):
self._state.save()
def handle_reorder_columns(self, order: list[str]):
"""Reorder columns based on a full ordered list of column IDs.
Args:
order: List of col_id strings in the desired display order.
Columns not present in order are appended at the end.
"""
logger.debug(f"handle_reorder_columns: {order=}")
columns_by_id = {c.col_id: c for c in self._state.columns}
new_order = [columns_by_id[col_id] for col_id in order if col_id in columns_by_id]
remaining = [c for c in self._state.columns if c.col_id not in order]
self._state.columns = new_order + remaining
self._init_columns()
self._state.save()
return self.render_partial("table")
def calculate_optimal_column_width(self, col_id: str) -> int:
"""
Calculate optimal width for a column based on content.
@@ -625,6 +617,42 @@ class DataGrid(MultipleInstance):
self._state.save()
return self.render_partial()
def handle_columns_reorder(self, order: list[str]):
"""Reorder columns based on a full ordered list of column IDs.
Args:
order: List of col_id strings in the desired display order.
Columns not present in order are appended at the end.
"""
logger.debug(f"handle_reorder_columns: {order=}")
columns_by_id = {c.col_id: c for c in self._state.columns}
new_order = [columns_by_id[col_id] for col_id in order if col_id in columns_by_id]
remaining = [c for c in self._state.columns if c.col_id not in order]
self._state.columns = new_order + remaining
self._init_columns()
self._state.save()
return self.render_partial("table")
def handle_columns_updates(self, updates: dict[str, dict]):
logger.debug(f"handle_columns_update: {updates=}")
def _update(col_def):
need_saving = False
for key, value in update.items():
if hasattr(col_def, key):
setattr(col_def, key, value)
need_saving = True
return need_saving
for col_id, update in updates.items():
column_state = [col_def for col_def in self._columns if col_def.col_id == col_id][0]
if _update(column_state.get_col_ui_state()):
self._state.save()
if _update(column_state.get_col_def()):
self._data_service.save_state()
return self.render_partial("table")
def handle_toggle_columns_manager(self):
logger.debug(f"toggle_columns_manager")
self._panel.set_title(side="right", title="Columns")
@@ -803,7 +831,7 @@ class DataGrid(MultipleInstance):
formatted_value = None
rules = self._get_format_rules(col_pos, row_index, col_def)
if rules:
row_data = self._df_store.ns_row_data[row_index] if row_index < len(self._df_store.ns_row_data) else None
row_data = self._row_data[row_index] if row_index < len(self._row_data) else None
style, formatted_value = self._formatting_engine.apply_format(rules, value, row_data)
# Use formatted value or convert to string

View File

@@ -23,6 +23,14 @@ class Commands(BaseCommands):
self._owner,
self._owner.handle_on_reorder
).htmx(target=f"#{self._id}")
def toggle_column_visibility(self, col_id: str):
return Command("ToggleColumnVisibility",
"Toggle column visibility",
self._owner,
self._owner.handle_toggle_column_visibility,
kwargs={"col_id": col_id}
).htmx(target=f"#{self._id}")
class DataGridColumnsList(MultipleInstance):
@@ -43,7 +51,14 @@ class DataGridColumnsList(MultipleInstance):
def handle_on_reorder(self, order: list):
logger.debug(f"on_reorder {order=}")
ret = self._parent.handle_reorder_columns(order)
ret = self._parent.handle_columns_reorder(order)
return self.render(), ret
def handle_toggle_column_visibility(self, col_id):
logger.debug(f"handle_toggle_column_visibility {col_id=}")
col_def = [c for c in self.columns if c.col_id == col_id][0]
updates = {col_id: {"visible": not col_def.visible}}
ret = self._parent.handle_columns_updates(updates)
return self.render(), ret
def mk_column_label(self, col_def: DataGridColumnState):
@@ -51,7 +66,7 @@ class DataGridColumnsList(MultipleInstance):
mk.icon(grip_horizontal, cls="mf-drag-handle cursor-grab mr-1 opacity-40"),
mk.mk(
Input(type="checkbox", cls="checkbox checkbox-sm", checked=col_def.visible),
# command=self.commands.toggle_column(col_def.col_id)
command=self.commands.toggle_column_visibility(col_def.col_id)
),
mk.mk(
Div(

View File

@@ -127,7 +127,7 @@ class DataGridFormattingEditor(DslEditor):
from myfasthtml.controls.DataGridsManager import DataGridsManager
manager = InstancesManager.get_by_type(self._session, DataGridsManager)
if manager:
manager.all_tables_formats = tables_rules
manager.get_state().all_tables_formats = tables_rules
# Step 6: Update state atomically
self._parent.get_state().update(state)

View File

@@ -15,6 +15,7 @@ from myfasthtml.core.DataGridsRegistry import DataGridsRegistry
from myfasthtml.core.commands import Command
from myfasthtml.core.data.DataServicesManager import DataServicesManager
from myfasthtml.core.dbmanager import DbObject
from myfasthtml.core.formatting.dataclasses import FormatRule
from myfasthtml.core.instances import InstancesManager, SingleInstance
from myfasthtml.icons.fluent_p1 import table_add20_regular
from myfasthtml.icons.fluent_p3 import folder_open20_regular
@@ -31,10 +32,11 @@ class DocumentDefinition:
class DataGridsState(DbObject):
def __init__(self, owner, name=None):
super().__init__(owner, name=name)
def __init__(self, owner, save_state, name=None):
super().__init__(owner, save_state=save_state, name=name)
with self.initializing():
self.elements: list[DocumentDefinition] = []
self.all_tables_formats: list[FormatRule] = []
class Commands(BaseCommands):
@@ -87,12 +89,12 @@ class DataGridsManager(SingleInstance):
by DataServicesManager and DataService.
"""
def __init__(self, parent, _id=None):
def __init__(self, parent, _id=None, save_state=None):
if not getattr(self, "_is_new_instance", False):
return
super().__init__(parent, _id=_id)
self.commands = Commands(self)
self._state = DataGridsState(self)
self._state = DataGridsState(self, save_state)
self._tree = self._mk_tree()
self._tree.bind_command("SelectNode", self.commands.show_document())
self._tree.bind_command("DeleteNode", self.commands.delete_grid(), when="before")
@@ -102,6 +104,9 @@ class DataGridsManager(SingleInstance):
# Data layer — session-scoped singletons
self._data_services_manager = DataServicesManager(self._parent)
def get_state(self):
return self._state
# ------------------------------------------------------------------
# Grid lifecycle
# ------------------------------------------------------------------

View File

@@ -78,6 +78,12 @@ class DataGridColumnState:
self._col_def = col_def
self._col_ui_state = col_ui_state
def get_col_def(self):
return self._col_def
def get_col_ui_state(self):
return self._col_ui_state
@property
def col_id(self):
return self._col_def.col_id