2 Commits

Author SHA1 Message Date
3de9aff15c Added CommandsDebugger 2025-11-16 23:06:00 +01:00
cdccd0cbaa Fixed InstancesDebugger not showing. Added mk.label 2025-11-16 22:35:56 +01:00
6 changed files with 113 additions and 17 deletions

View File

@@ -3,6 +3,7 @@ import logging.config
import yaml import yaml
from fasthtml import serve from fasthtml import serve
from myfasthtml.controls.CommandsDebugger import CommandsDebugger
from myfasthtml.controls.InstancesDebugger import InstancesDebugger from myfasthtml.controls.InstancesDebugger import InstancesDebugger
from myfasthtml.controls.Layout import Layout from myfasthtml.controls.Layout import Layout
from myfasthtml.controls.TabsManager import TabsManager from myfasthtml.controls.TabsManager import TabsManager
@@ -32,17 +33,26 @@ def index(session):
layout.set_footer("Goodbye World") layout.set_footer("Goodbye World")
tabs_manager = TabsManager(layout, _id=f"{Ids.TabsManager}-main") tabs_manager = TabsManager(layout, _id=f"{Ids.TabsManager}-main")
instances_debugger = InstancesManager.get(session, Ids.InstancesDebugger, InstancesDebugger, layout)
btn_show_right_drawer = mk.button("show", btn_show_right_drawer = mk.button("show",
command=layout.commands.toggle_drawer("right"), command=layout.commands.toggle_drawer("right"),
id="btn_show_right_drawer_id") id="btn_show_right_drawer_id")
btn_show_instances_debugger = mk.icon(volume_object_storage, instances_debugger = InstancesManager.get(session, Ids.InstancesDebugger, InstancesDebugger, layout)
btn_show_instances_debugger = mk.label("Instances",
icon=volume_object_storage,
command=tabs_manager.commands.add_tab("Instances", instances_debugger), command=tabs_manager.commands.add_tab("Instances", instances_debugger),
id=instances_debugger.get_id()) id=instances_debugger.get_id())
commands_debugger = InstancesManager.get(session, Ids.CommandsDebugger, CommandsDebugger, layout)
btn_show_commands_debugger = mk.label("Commands",
icon=None,
command=tabs_manager.commands.add_tab("Commands", commands_debugger),
id=commands_debugger.get_id())
layout.header_left.add(tabs_manager.add_tab_btn()) layout.header_left.add(tabs_manager.add_tab_btn())
layout.header_right.add(btn_show_right_drawer) layout.header_right.add(btn_show_right_drawer)
layout.left_drawer.add(btn_show_instances_debugger) layout.left_drawer.add(btn_show_instances_debugger)
layout.left_drawer.add(btn_show_commands_debugger)
layout.set_main(tabs_manager) layout.set_main(tabs_manager)
return layout return layout

View File

@@ -2,20 +2,19 @@
--color-border-primary: color-mix(in oklab, var(--color-primary) 40%, #0000); --color-border-primary: color-mix(in oklab, var(--color-primary) 40%, #0000);
} }
.mf-icon-16 {
width: 16px;
min-width: 16px;
height: 16px;
margin-top: auto;
}
.mf-icon-20 { .mf-icon-20 {
width: 20px; width: 20px;
min-width: 20px; min-width: 20px;
height: 20px; height: 20px;
margin-top: auto; margin-top: auto;
margin-bottom: auto;
}
.mf-icon-16 {
width: 16px;
min-width: 16px;
height: 16px;
margin-top: auto;
margin-bottom: 4px;
} }
.mf-icon-24 { .mf-icon-24 {
@@ -23,7 +22,14 @@
min-width: 24px; min-width: 24px;
height: 24px; height: 24px;
margin-top: auto; margin-top: auto;
margin-bottom: 4px;
}
.mf-icon-28 {
width: 28px;
min-width: 28px;
height: 28px;
margin-top: auto;
} }
.mf-icon-32 { .mf-icon-32 {
@@ -31,7 +37,6 @@
min-width: 32px; min-width: 32px;
height: 32px; height: 32px;
margin-top: auto; margin-top: auto;
margin-bottom: 4px;
} }
/* /*

View File

@@ -0,0 +1,40 @@
from myfasthtml.controls.VisNetwork import VisNetwork
from myfasthtml.controls.helpers import Ids
from myfasthtml.core.commands import CommandsManager
from myfasthtml.core.instances import SingleInstance
from myfasthtml.core.network_utils import from_parent_child_list
class CommandsDebugger(SingleInstance):
def __init__(self, session, parent, _id=None):
super().__init__(session, Ids.CommandsDebugger, parent)
def render(self):
commands = self._get_commands()
nodes, edges = from_parent_child_list(commands,
id_getter=lambda x: str(x.id),
label_getter=lambda x: x.name,
parent_getter=lambda x: str(self.get_command_parent(x))
)
vis_network = VisNetwork(self, nodes=nodes, edges=edges)
return vis_network
@staticmethod
def get_command_parent(command):
if (ft := command.get_ft()) is None:
return None
if hasattr(ft, "get_id") and callable(ft.get_id):
return ft.get_id()
if hasattr(ft, "get_prefix") and callable(ft.get_prefix):
return ft.get_prefix()
if hasattr(ft, "attrs"):
return ft.attrs.get("id", None)
return None
def _get_commands(self):
return list(CommandsManager.commands.values())
def __ft__(self):
return self.render()

View File

@@ -9,6 +9,7 @@ class Ids:
# Please keep the alphabetical order # Please keep the alphabetical order
AuthProxy = "mf-auth-proxy" AuthProxy = "mf-auth-proxy"
Boundaries = "mf-boundaries" Boundaries = "mf-boundaries"
CommandsDebugger = "mf-commands-debugger"
DbManager = "mf-dbmanager" DbManager = "mf-dbmanager"
InstancesDebugger = "mf-instances-debugger" InstancesDebugger = "mf-instances-debugger"
Layout = "mf-layout" Layout = "mf-layout"
@@ -41,6 +42,27 @@ class mk:
return mk.mk(Div(icon, cls=merged_cls, **kwargs), command=command, binding=binding) return mk.mk(Div(icon, cls=merged_cls, **kwargs), command=command, binding=binding)
@staticmethod
def label(text: str,
icon=None,
size: str = "sm",
cls='',
command: Command = None,
binding: Binding = None,
**kwargs):
merged_cls = merge_classes("flex", cls, kwargs)
icon_part = Span(icon, cls=f"mf-icon-{mk.convert_size(size)} mr-1") if icon else None
text_part = Span(text, cls=f"text-{size}")
return mk.mk(Label(icon_part, text_part, cls=merged_cls, **kwargs), command=command, binding=binding)
@staticmethod
def convert_size(size: str):
return (size.replace("xs", "16").
replace("sm", "20").
replace("md", "24").
replace("lg", "28").
replace("xl", "32"))
@staticmethod @staticmethod
def manage_command(ft, command: Command): def manage_command(ft, command: Command):
if command: if command:

View File

@@ -30,6 +30,7 @@ class BaseCommand:
self.description = description self.description = description
self._htmx_extra = {} self._htmx_extra = {}
self._bindings = [] self._bindings = []
self._ft = None
# register the command # register the command
CommandsManager.register(self) CommandsManager.register(self)
@@ -68,6 +69,7 @@ class BaseCommand:
:param ft: :param ft:
:return: :return:
""" """
self._ft = ft
htmx = self.get_htmx_params() htmx = self.get_htmx_params()
ft.attrs |= htmx ft.attrs |= htmx
return ft return ft
@@ -95,6 +97,9 @@ class BaseCommand:
def url(self): def url(self):
return f"{ROUTE_ROOT}{Routes.Commands}?c_id={self.id}" return f"{ROUTE_ROOT}{Routes.Commands}?c_id={self.id}"
def get_ft(self):
return self._ft
def __str__(self): def __str__(self):
return f"Command({self.name})" return f"Command({self.name})"

View File

@@ -1,12 +1,26 @@
import logging
from myfasthtml.controls.CommandsDebugger import CommandsDebugger
from myfasthtml.controls.InstancesDebugger import InstancesDebugger
from myfasthtml.controls.VisNetwork import VisNetwork from myfasthtml.controls.VisNetwork import VisNetwork
from myfasthtml.controls.helpers import Ids from myfasthtml.controls.helpers import Ids
from myfasthtml.core.instances import BaseInstance from myfasthtml.core.instances import BaseInstance, InstancesManager
logger = logging.getLogger("InstancesHelper")
class InstancesHelper: class InstancesHelper:
@staticmethod @staticmethod
def dynamic_get(parent: BaseInstance, component_type: str, instance_id: str): def dynamic_get(parent: BaseInstance, component_type: str, instance_id: str):
if component_type == Ids.VisNetwork: if component_type == Ids.VisNetwork:
return VisNetwork(parent, _id=instance_id) return InstancesManager.get(parent.get_session(), instance_id,
VisNetwork, parent=parent, _id=instance_id)
elif component_type == Ids.InstancesDebugger:
return InstancesManager.get(parent.get_session(), instance_id,
InstancesDebugger, parent.get_session(), parent, instance_id)
elif component_type == Ids.CommandsDebugger:
return InstancesManager.get(parent.get_session(), instance_id,
CommandsDebugger, parent.get_session(), parent, instance_id)
logger.warning(f"Unknown component type: {component_type}")
return None return None