137 lines
3.7 KiB
Python
137 lines
3.7 KiB
Python
import logging
|
|
|
|
from fasthtml.fastapp import fast_app
|
|
from starlette.routing import Mount, Route
|
|
|
|
from myfasthtml.core.constants import Routes, ROUTE_ROOT
|
|
|
|
utils_app, utils_rt = fast_app()
|
|
logger = logging.getLogger("Commands")
|
|
|
|
|
|
def mount_if_not_exists(app, path: str, sub_app):
|
|
"""
|
|
Mounts a sub-application only if no Mount object already exists
|
|
at the specified path in the main application's router.
|
|
"""
|
|
is_mounted = False
|
|
|
|
for route in app.router.routes:
|
|
|
|
if isinstance(route, Mount):
|
|
if route.path == path:
|
|
is_mounted = True
|
|
break
|
|
|
|
if not is_mounted:
|
|
app.mount(path, app=sub_app)
|
|
|
|
|
|
def merge_classes(*args):
|
|
all_elements = []
|
|
for element in args:
|
|
if element is None or element == '':
|
|
continue
|
|
|
|
if isinstance(element, (tuple, list, set)):
|
|
all_elements.extend(element)
|
|
|
|
elif isinstance(element, dict):
|
|
if "cls" in element:
|
|
all_elements.append(element.pop("cls"))
|
|
elif "class" in element:
|
|
all_elements.append(element.pop("class"))
|
|
|
|
elif isinstance(element, str):
|
|
all_elements.append(element)
|
|
|
|
else:
|
|
raise ValueError(f"Cannot merge {element} of type {type(element)}")
|
|
|
|
if all_elements:
|
|
# Remove duplicates while preserving order
|
|
unique_elements = list(dict.fromkeys(all_elements))
|
|
return " ".join(unique_elements)
|
|
else:
|
|
return None
|
|
|
|
|
|
def debug_routes(app):
|
|
for route in app.router.routes:
|
|
if isinstance(route, Mount):
|
|
for sub_route in route.app.router.routes:
|
|
print(f"path={route.path}{sub_route.path}, method={sub_route.methods}, endpoint={sub_route.endpoint}")
|
|
elif isinstance(route, Route):
|
|
print(f"path={route.path}, methods={route.methods}, endpoint={route.endpoint}")
|
|
|
|
|
|
def mount_utils(app):
|
|
"""
|
|
Mounts the commands_app to the given application instance if the route does not already exist.
|
|
|
|
:param app: The application instance to which the commands_app will be mounted.
|
|
:type app: Any
|
|
:return: Returns the result of the mount operation performed by mount_if_not_exists.
|
|
:rtype: Any
|
|
"""
|
|
return mount_if_not_exists(app, ROUTE_ROOT, utils_app)
|
|
|
|
|
|
def get_default_ft_attr(ft):
|
|
"""
|
|
for every type of HTML element (ft) gives the default attribute to use for binding
|
|
:param ft:
|
|
:return:
|
|
"""
|
|
if ft.tag == "input":
|
|
if ft.attrs.get("type") == "checkbox":
|
|
return "checked"
|
|
elif ft.attrs.get("type") == "radio":
|
|
return "checked"
|
|
elif ft.attrs.get("type") == "file":
|
|
return "files"
|
|
else:
|
|
return "value"
|
|
else:
|
|
return None # indicate that the content of the FT should be updated
|
|
|
|
|
|
def get_default_attr(data):
|
|
all_attrs = data.__dict__.keys()
|
|
return next(iter(all_attrs))
|
|
|
|
|
|
@utils_rt(Routes.Commands)
|
|
def post(session: str, c_id: str):
|
|
"""
|
|
Default routes for all commands.
|
|
:param session:
|
|
:param c_id:
|
|
:return:
|
|
"""
|
|
logger.debug(f"Entering {Routes.Commands} with {session=}, {c_id=}")
|
|
from myfasthtml.core.commands import CommandsManager
|
|
command = CommandsManager.get_command(c_id)
|
|
if command:
|
|
return command.execute()
|
|
|
|
raise ValueError(f"Command with ID '{c_id}' not found.")
|
|
|
|
|
|
@utils_rt(Routes.Bindings)
|
|
def post(session: str, b_id: str, values: dict):
|
|
"""
|
|
Default routes for all bindings.
|
|
:param session:
|
|
:param b_id:
|
|
:param values:
|
|
:return:
|
|
"""
|
|
logger.debug(f"Entering {Routes.Bindings} with {session=}, {b_id=}, {values=}")
|
|
from myfasthtml.core.bindings import BindingsManager
|
|
binding = BindingsManager.get_binding(b_id)
|
|
if binding:
|
|
return binding.update(values)
|
|
|
|
raise ValueError(f"Binding with ID '{b_id}' not found.")
|