Fixed double Panel double instantiation

This commit is contained in:
2026-03-23 21:41:06 +01:00
parent 0e1087a614
commit 7f099b14f6
5 changed files with 29 additions and 33 deletions

View File

@@ -4,7 +4,7 @@ from fasthtml.components import Div
from myfasthtml.controls.HierarchicalCanvasGraph import HierarchicalCanvasGraph, HierarchicalCanvasGraphConf from myfasthtml.controls.HierarchicalCanvasGraph import HierarchicalCanvasGraph, HierarchicalCanvasGraphConf
from myfasthtml.controls.Panel import Panel from myfasthtml.controls.Panel import Panel
from myfasthtml.controls.Properties import Properties from myfasthtml.controls.Properties import Properties, PropertiesConf
from myfasthtml.core.commands import Command from myfasthtml.core.commands import Command
from myfasthtml.core.instances import SingleInstance, UniqueInstance, MultipleInstance, InstancesManager from myfasthtml.core.instances import SingleInstance, UniqueInstance, MultipleInstance, InstancesManager
@@ -73,10 +73,11 @@ class InstancesDebugger(SingleInstance):
"Commands": {"*": "commands"}, "Commands": {"*": "commands"},
} }
return self._panel.set_right(Properties(self, return self._panel.set_right(Properties(
InstancesManager.get(session, instance_id), self,
properties_def, conf=PropertiesConf(obj=InstancesManager.get(session, instance_id), groups=properties_def),
_id="-properties")) _id="-properties",
))
def _get_instance_kind(self, instance) -> str: def _get_instance_kind(self, instance) -> str:
"""Determine the instance kind for visualization. """Determine the instance kind for visualization.

View File

@@ -104,7 +104,7 @@ class Panel(MultipleInstance):
the panel with appropriate HTML elements and JavaScript for interactivity. the panel with appropriate HTML elements and JavaScript for interactivity.
""" """
def __init__(self, parent, conf: Optional[PanelConf] = None, _id="-panel"): def __init__(self, parent, conf: Optional[PanelConf] = None, _id=None):
super().__init__(parent, _id=_id) super().__init__(parent, _id=_id)
self.conf = conf or PanelConf() self.conf = conf or PanelConf()
self.commands = Commands(self) self.commands = Commands(self)

View File

@@ -161,7 +161,7 @@ class Profiler(SingleInstance):
def __init__(self, parent, _id=None): def __init__(self, parent, _id=None):
super().__init__(parent, _id=_id) super().__init__(parent, _id=_id)
self._panel = Panel(self, conf=PanelConf(show_right_title=False, show_display_right=False)) self._panel = Panel(self, conf=PanelConf(show_right_title=False, show_display_right=False), _id="-panel")
self._panel.set_side_visible("right", True) self._panel.set_side_visible("right", True)
self._selected_id: str | None = None self._selected_id: str | None = None
self._detail_view: str = "tree" self._detail_view: str = "tree"
@@ -339,8 +339,7 @@ class Profiler(SingleInstance):
kwargs_obj = SimpleNamespace(**trace.kwargs) if trace.kwargs else SimpleNamespace() kwargs_obj = SimpleNamespace(**trace.kwargs) if trace.kwargs else SimpleNamespace()
kwargs_props = Properties( kwargs_props = Properties(
self, self,
obj=kwargs_obj, conf=PropertiesConf(obj=kwargs_obj, groups={"kwargs": {"*": ""}}),
groups={"kwargs": {"*": ""}},
_id="-detail-kwargs", _id="-detail-kwargs",
) )

View File

@@ -24,22 +24,18 @@ class PropertiesConf:
class Properties(MultipleInstance): class Properties(MultipleInstance):
def __init__(self, parent, obj=None, groups: dict = None, conf: PropertiesConf = None, _id=None): def __init__(self, parent, conf: PropertiesConf = None, _id=None):
super().__init__(parent, _id=_id) super().__init__(parent, _id=_id)
if conf is not None: self.conf = conf or PropertiesConf()
self.obj = conf.obj self._refresh()
self.groups = conf.groups
self._types = conf.types or {}
else:
self.obj = obj
self.groups = groups
self._types = {}
self.properties_by_group = self._create_properties_by_group()
def set_obj(self, obj, groups: dict = None): def set_conf(self, conf: PropertiesConf):
self.obj = obj self.conf = conf
self.groups = groups self._refresh()
self.properties_by_group = self._create_properties_by_group()
def _refresh(self):
self._types = self.conf.types or {}
self._properties_by_group = self._create_properties_by_group()
def _mk_group_content(self, properties: dict): def _mk_group_content(self, properties: dict):
return Div( return Div(
@@ -57,7 +53,7 @@ class Properties(MultipleInstance):
def _mk_property_value(self, value): def _mk_property_value(self, value):
for t, renderer in self._types.items(): for t, renderer in self._types.items():
if isinstance(value, t): if isinstance(value, t):
return renderer(value, self.obj) return renderer(value, self.conf.obj)
if isinstance(value, dict): if isinstance(value, dict):
return self._mk_group_content(value) return self._mk_group_content(value)
@@ -73,9 +69,9 @@ class Properties(MultipleInstance):
"""Render a group's content. """Render a group's content.
When the group contains exactly one property whose type is registered in When the group contains exactly one property whose type is registered in
``_types``, the type renderer replaces the entire group content (not just ``conf.types``, the type renderer replaces the entire group content (not
the value cell). This lets custom renderers (e.g. span trees) fill the just the value cell). This lets custom renderers (e.g. span trees) fill
full card width without a key/value row wrapper. the full card width without a key/value row wrapper.
Otherwise, the standard key/value row layout is used. Otherwise, the standard key/value row layout is used.
@@ -90,7 +86,7 @@ class Properties(MultipleInstance):
k, v = next(iter(properties.items())) k, v = next(iter(properties.items()))
for t, renderer in self._types.items(): for t, renderer in self._types.items():
if isinstance(v, t): if isinstance(v, t):
return renderer(v, self.obj) return renderer(v, self.conf.obj)
return self._mk_group_content(properties) return self._mk_group_content(properties)
def render(self): def render(self):
@@ -104,17 +100,17 @@ class Properties(MultipleInstance):
), ),
cls="mf-properties-group-card" cls="mf-properties-group-card"
) )
for group_name, proxy in self.properties_by_group.items() for group_name, proxy in self._properties_by_group.items()
], ],
id=self._id, id=self._id,
cls="mf-properties" cls="mf-properties"
) )
def _create_properties_by_group(self): def _create_properties_by_group(self):
if self.groups is None: if self.conf.groups is None:
return {None: ProxyObject(self.obj, {"*": ""})} return {None: ProxyObject(self.conf.obj, {"*": ""})}
return {k: ProxyObject(self.obj, v) for k, v in self.groups.items()} return {k: ProxyObject(self.conf.obj, v) for k, v in self.conf.groups.items()}
def __ft__(self): def __ft__(self):
return self.render() return self.render()

View File

@@ -247,7 +247,7 @@ class InstancesManager:
""" """
key = (InstancesManager.get_session_id(session), instance.get_id()) key = (InstancesManager.get_session_id(session), instance.get_id())
if isinstance(instance, SingleInstance) and key in InstancesManager.instances: if key in InstancesManager.instances and not isinstance(instance, UniqueInstance):
raise DuplicateInstanceError(instance) raise DuplicateInstanceError(instance)
InstancesManager.instances[key] = instance InstancesManager.instances[key] = instance