Added Controls testing + documentation

This commit is contained in:
2025-12-05 19:17:21 +01:00
parent 1d20fb8650
commit 8e5fa7f752
37 changed files with 4868 additions and 363 deletions

View File

@@ -1,4 +1,5 @@
import inspect
import json
import uuid
from typing import Optional
@@ -97,6 +98,14 @@ class BaseCommand:
def url(self):
return f"{ROUTE_ROOT}{Routes.Commands}?c_id={self.id}"
def ajax_htmx_options(self):
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
@@ -126,7 +135,7 @@ class Command(BaseCommand):
def __init__(self, name, description, callback, *args, **kwargs):
super().__init__(name, description)
self.callback = callback
self.callback_parameters = dict(inspect.signature(callback).parameters)
self.callback_parameters = dict(inspect.signature(callback).parameters) if callback else {}
self.args = args
self.kwargs = kwargs
@@ -141,8 +150,17 @@ 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):
res = super().ajax_htmx_options()
if self.kwargs:
res["values"] |= self.kwargs
res["values"]["c_id"] = f"{self.id}" # cannot be overridden
return res
def execute(self, client_response: dict = None):
ret_from_bindings = []

View File

@@ -1,5 +1,39 @@
from enum import Enum
DEFAULT_COLUMN_WIDTH = 100
ROUTE_ROOT = "/myfasthtml"
class Routes:
Commands = "/commands"
Bindings = "/bindings"
Bindings = "/bindings"
class ColumnType(Enum):
RowIndex = "RowIndex"
Text = "Text"
Number = "Number"
Datetime = "DateTime"
Bool = "Boolean"
Choice = "Choice"
List = "List"
class ViewType(Enum):
Table = "Table"
Chart = "Chart"
Form = "Form"
class FooterAggregation(Enum):
Sum = "Sum"
Mean = "Mean"
Min = "Min"
Max = "Max"
Count = "Count"
FilteredSum = "FilteredSum"
FilteredMean = "FilteredMean"
FilteredMin = "FilteredMin"
FilteredMax = "FilteredMax"
FilteredCount = "FilteredCount"

View File

@@ -39,7 +39,7 @@ class DbObject:
def __init__(self, owner: BaseInstance, name=None, db_manager=None):
self._owner = owner
self._name = name or self.__class__.__name__
self._name = name or owner.get_full_id()
self._db_manager = db_manager or DbManager(self._owner)
self._finalize_initialization()
@@ -112,6 +112,7 @@ class DbObject:
setattr(self, k, v)
self._save_self()
self._initializing = old_state
return self
def copy(self):
as_dict = self._get_properties().copy()

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()
@@ -176,11 +176,22 @@ class InstancesManager:
:param instance_id:
:return:
"""
key = (InstancesManager.get_session_id(session), instance_id)
session_id = InstancesManager.get_session_id(session)
key = (session_id, instance_id)
return InstancesManager.instances[key]
@staticmethod
def get_by_type(session: dict, cls: type):
session_id = InstancesManager.get_session_id(session)
res = [i for s, i in InstancesManager.instances.items() if s[0] == session_id and isinstance(i, cls)]
assert len(res) <= 1, f"Multiple instances of type {cls.__name__} found"
assert len(res) > 0, f"No instance of type {cls.__name__} found"
return res[0]
@staticmethod
def get_session_id(session):
if isinstance(session, str):
return session
if session is None:
return "** NOT LOGGED IN **"
if "user_info" not in session:

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.