Enhancing InstancesDebugger.py. I can display properties

This commit is contained in:
2025-12-02 22:09:37 +01:00
parent 378775cdf9
commit e96ac5ddfd
7 changed files with 82 additions and 22 deletions

View File

@@ -1,6 +1,7 @@
from myfasthtml.controls.Panel import Panel
from myfasthtml.controls.Properties import Properties
from myfasthtml.controls.VisNetwork import VisNetwork
from myfasthtml.core.commands import LambdaCommand
from myfasthtml.core.commands import Command
from myfasthtml.core.instances import SingleInstance, InstancesManager
from myfasthtml.core.network_utils import from_parent_child_list
@@ -9,13 +10,23 @@ class InstancesDebugger(SingleInstance):
def __init__(self, parent, _id=None):
super().__init__(parent, _id=_id)
self._panel = Panel(self, _id="-panel")
self._command = Command("ShowInstance",
"Display selected Instance",
self.on_network_event).htmx(target=f"#{self._panel.get_id()}_r")
def render(self):
nodes, edges = self._get_nodes_and_edges()
c = LambdaCommand(lambda event_data: print("received", event_data))
vis_network = VisNetwork(self, nodes=nodes, edges=edges, _id="-vis", events_handlers={"select_node": c})
vis_network = VisNetwork(self, nodes=nodes, edges=edges, _id="-vis", events_handlers={"select_node": self._command})
return self._panel.set_main(vis_network)
def on_network_event(self, event_data: dict):
session, instance_id = event_data["nodes"][0].split("#")
properties = {"Id": "_id", "Parent Id": "_parent._id"}
return self._panel.set_right(Properties(self,
InstancesManager.get(session, instance_id),
properties,
_id="-properties"))
def _get_nodes_and_edges(self):
instances = self._get_instances()
nodes, edges = from_parent_child_list(

View File

@@ -46,6 +46,7 @@ class Panel(MultipleInstance):
sides, and adjust the width of the sides dynamically. The class also handles rendering
the panel with appropriate HTML elements and JavaScript for interactivity.
"""
def __init__(self, parent, conf=None, _id=None):
super().__init__(parent, _id=_id)
self.conf = conf or PanelConf()
@@ -66,35 +67,35 @@ class Panel(MultipleInstance):
def set_right(self, right):
self._right = right
return self
return Div(self._right, id=f"{self._id}_r")
def set_left(self, left):
self._left = left
return self
return Div(self._left, id=f"{self._id}_l")
def _mk_right(self):
if not self.conf.right:
return None
resizer = Div(
cls="mf-resizer mf-resizer-right",
data_command_id=self.commands.update_side_width("right").id,
data_side="right"
)
return Div(resizer, self._right, cls="mf-panel-right")
return Div(resizer, Div(self._right, id=f"{self._id}_r"), cls="mf-panel-right")
def _mk_left(self):
if not self.conf.left:
return None
resizer = Div(
cls="mf-resizer mf-resizer-left",
data_command_id=self.commands.update_side_width("left").id,
data_side="left"
)
return Div(self._left, resizer, cls="mf-panel-left")
return Div(Div(self._left, id=f"{self._id}_l"), resizer, cls="mf-panel-left")
def render(self):
return Div(

View File

@@ -0,0 +1,44 @@
from fasthtml.components import Div
from myutils.Expando import Expando
from myfasthtml.core.instances import MultipleInstance
class Properties(MultipleInstance):
def __init__(self, parent, obj=None, properties: dict = None, _id=None):
super().__init__(parent, _id=_id)
self.obj = obj
self.properties = properties or self._get_default_properties(obj)
self.expando = self._create_expando()
def set_obj(self, obj, properties: list[str] = None):
self.obj = obj
self.properties = properties or self._get_default_properties(obj)
def render(self):
return Div(
*[Div(k, ":", v) for k, v in self.expando.as_dict().items()],
id=self._id,
)
def _create_expando(self):
res = {}
for attr_name, mapping in self.properties.items():
attrs_path = mapping.split(".")
current = self.obj
for attr in attrs_path:
if hasattr(current, attr):
current = getattr(current, attr)
else:
res[attr_name] = None
break
res[attr_name] = current
return Expando(res)
@staticmethod
def _get_default_properties(obj):
return {k: k for k, v in dir(obj) if not k.startswith("_")} if obj else {}
def __ft__(self):
return self.render()

View File

@@ -101,13 +101,15 @@ class VisNetwork(MultipleInstance):
event_handlers_js += f"""
network.on('{vis_event_name}', function(params) {{
const event_data = {{
event_name: '{event_name}',
nodes: params.nodes,
edges: params.edges,
pointer: params.pointer
}};
htmx.ajax('POST', '{command_htmx_options['url']}', {{
values: {{event_data: JSON.stringify(event_data)}},
swap: 'none'
target: '{command_htmx_options['target']}',
swap: '{command_htmx_options['swap']}'
}});
}});
"""

View File

@@ -1,4 +1,5 @@
import inspect
import json
import uuid
from typing import Optional
@@ -98,14 +99,12 @@ class BaseCommand:
return f"{ROUTE_ROOT}{Routes.Commands}?c_id={self.id}"
def ajax_htmx_options(self):
res = {"url": self.url}
if "hx-target" in self._htmx_extra:
res["target"] = self._htmx_extra["hx-target"]
if "hx-swap" in self._htmx_extra:
res["swap"] = self._htmx_extra["hx-swap"]
res["values"] = {}
return res
return {
"url": self.url,
"target": self._htmx_extra.get("hx-target", "this"),
"swap": self._htmx_extra.get("hx-swap", "outerHTML"),
"values": {}
}
def get_ft(self):
return self._ft
@@ -151,6 +150,8 @@ class Command(BaseCommand):
return float(value)
elif param.annotation == list:
return value.split(",")
elif param.annotation == dict:
return json.loads(value)
return value
def ajax_htmx_options(self):

View File

@@ -84,7 +84,7 @@ class BaseInstance:
return self._prefix
def get_full_id(self) -> str:
return f"{InstancesManager.get_session_id(self._session)}-{self._id}"
return f"{InstancesManager.get_session_id(self._session)}#{self._id}"
def get_full_parent_id(self) -> Optional[str]:
parent = self.get_parent()

View File

@@ -3,6 +3,7 @@ from collections.abc import Callable
ROOT_COLOR = "#ff9999"
GHOST_COLOR = "#cccccc"
def from_nested_dict(trees: list[dict]) -> tuple[list, list]:
"""
Convert a list of nested dictionaries to vis.js nodes and edges format.