From 7c701a91164927c3650866a00be7a045d9093387 Mon Sep 17 00:00:00 2001 From: Kodjo Sossouvi Date: Wed, 3 Dec 2025 22:57:43 +0100 Subject: [PATCH] Refactored Properties component to support grouped structures, updated InstancesDebugger and styles, and upgraded myutils to 0.5.0. --- requirements.txt | 2 +- src/myfasthtml/assets/myfasthtml.css | 77 ++++++++++++++++++++ src/myfasthtml/controls/InstancesDebugger.py | 5 +- src/myfasthtml/controls/Properties.py | 54 ++++++++------ src/myfasthtml/core/instances.py | 3 +- 5 files changed, 114 insertions(+), 27 deletions(-) diff --git a/requirements.txt b/requirements.txt index c9899e0..a735de4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,7 @@ mdurl==0.1.2 more-itertools==10.8.0 myauth==0.2.1 mydbengine==0.1.0 -myutils==0.4.0 +myutils==0.5.0 nh3==0.3.1 numpy==2.3.5 oauthlib==3.3.1 diff --git a/src/myfasthtml/assets/myfasthtml.css b/src/myfasthtml/assets/myfasthtml.css index 9bfe73f..26b5131 100644 --- a/src/myfasthtml/assets/myfasthtml.css +++ b/src/myfasthtml/assets/myfasthtml.css @@ -3,6 +3,7 @@ --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; --spacing: 0.25rem; + --text-xs: 0.6875rem; --text-sm: 0.875rem; --text-sm--line-height: calc(1.25 / 0.875); --text-xl: 1.25rem; @@ -11,6 +12,7 @@ --radius-md: 0.375rem; --default-font-family: var(--font-sans); --default-mono-font-family: var(--font-mono); + --properties-font-size: var(--text-xs); } @@ -671,4 +673,79 @@ height: 100%; overflow: auto; border-left: 1px solid var(--color-border-primary); + padding: 0.5rem; } + +/* *********************************************** */ +/* ************* Properties Component ************ */ +/* *********************************************** */ + +/* Properties container */ +.mf-properties { + display: flex; + flex-direction: column; + gap: 1rem; +} + +/* Group card - using DaisyUI card styling */ +.mf-properties-group-card { + background-color: var(--color-base-100); + border: 1px solid color-mix(in oklab, var(--color-base-content) 10%, transparent); + border-radius: var(--radius-md); + overflow: hidden; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +/* Group header - gradient using DaisyUI primary color */ +.mf-properties-group-header { + background: linear-gradient(135deg, var(--color-primary) 0%, color-mix(in oklab, var(--color-primary) 80%, black) 100%); + color: var(--color-primary-content); + padding: calc(var(--properties-font-size) * 0.5) calc(var(--properties-font-size) * 0.75); + font-weight: 700; + font-size: var(--properties-font-size); +} + +/* Group content area */ +.mf-properties-group-content { + display: flex; + flex-direction: column; +} + +/* Property row */ +.mf-properties-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: calc(var(--properties-font-size) * 0.4) calc(var(--properties-font-size) * 0.75); + border-bottom: 1px solid color-mix(in oklab, var(--color-base-content) 5%, transparent); + transition: background-color 0.15s ease; + gap: calc(var(--properties-font-size) * 0.75); +} + +.mf-properties-row:last-child { + border-bottom: none; +} + +.mf-properties-row:hover { + background-color: color-mix(in oklab, var(--color-base-content) 3%, transparent); +} + +/* Property key - normal font */ +.mf-properties-key { + font-weight: 600; + color: color-mix(in oklab, var(--color-base-content) 70%, transparent); + flex: 0 0 40%; + font-size: var(--properties-font-size); +} + +/* Property value - monospace font */ +.mf-properties-value { + font-family: var(--default-mono-font-family); + color: var(--color-base-content); + flex: 1; + text-align: right; + font-size: var(--properties-font-size); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} \ No newline at end of file diff --git a/src/myfasthtml/controls/InstancesDebugger.py b/src/myfasthtml/controls/InstancesDebugger.py index d4c1810..4526ea8 100644 --- a/src/myfasthtml/controls/InstancesDebugger.py +++ b/src/myfasthtml/controls/InstancesDebugger.py @@ -21,7 +21,10 @@ class InstancesDebugger(SingleInstance): def on_network_event(self, event_data: dict): session, instance_id = event_data["nodes"][0].split("#") - properties = {"Id": "_id", "Parent Id": "_parent._id"} + properties = {"Main": {"Id": "_id", "Parent Id": "_parent._id"}, + "State": {"*": "_state"}, + "Commands": {"*": "commands"}, + } return self._panel.set_right(Properties(self, InstancesManager.get(session, instance_id), properties, diff --git a/src/myfasthtml/controls/Properties.py b/src/myfasthtml/controls/Properties.py index 8055d29..0aa1e02 100644 --- a/src/myfasthtml/controls/Properties.py +++ b/src/myfasthtml/controls/Properties.py @@ -1,44 +1,50 @@ from fasthtml.components import Div -from myutils.Expando import Expando +from myutils.ProxyObject import ProxyObject from myfasthtml.core.instances import MultipleInstance class Properties(MultipleInstance): - def __init__(self, parent, obj=None, properties: dict = None, _id=None): + def __init__(self, parent, obj=None, groups: 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() + self.groups = groups + self.properties_by_group = self._create_properties_by_group() - def set_obj(self, obj, properties: list[str] = None): + def set_obj(self, obj, groups: dict = None): self.obj = obj - self.properties = properties or self._get_default_properties(obj) + self.groups = groups + self.properties_by_group = self._create_properties_by_group() def render(self): return Div( - *[Div(k, ":", v) for k, v in self.expando.as_dict().items()], + *[ + Div( + Div(group_name if group_name is not None else "", cls="mf-properties-group-header"), + Div( + *[ + Div( + Div(k, cls="mf-properties-key"), + Div(str(v), cls="mf-properties-value", title=str(v)), + cls="mf-properties-row" + ) + for k, v in proxy.as_dict().items() + ], + cls="mf-properties-group-content" + ), + cls="mf-properties-group-card" + ) + for group_name, proxy in self.properties_by_group.items() + ], id=self._id, + cls="mf-properties" ) - 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 + def _create_properties_by_group(self): + if self.groups is None: + return {None: ProxyObject(self.obj, {"*": ""})} - 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 {} + return {k: ProxyObject(self.obj, v) for k, v in self.groups.items()} def __ft__(self): return self.render() diff --git a/src/myfasthtml/core/instances.py b/src/myfasthtml/core/instances.py index 4d45958..a25df37 100644 --- a/src/myfasthtml/core/instances.py +++ b/src/myfasthtml/core/instances.py @@ -176,7 +176,8 @@ class InstancesManager: :param instance_id: :return: """ - key = (InstancesManager.get_session_id(session), instance_id) + session_id = InstancesManager.get_session_id(session) if isinstance(session, dict) else session + key = (session_id, instance_id) return InstancesManager.instances[key] @staticmethod