Reimplement compose and add tiling windows

This commit is contained in:
2026-03-12 22:03:30 +00:00
parent 79766d279d
commit 6ceff63b71
126 changed files with 5111 additions and 10796 deletions

224
core/settings_navigation.py Normal file
View File

@@ -0,0 +1,224 @@
from __future__ import annotations
from django.urls import reverse
SETTINGS_NAVIGATION_TREE = (
{
"key": "general",
"label": "General",
"href_name": "notifications_settings",
"children": (
{
"key": "notifications",
"label": "Notifications",
"href_name": "notifications_settings",
"route_names": ("notifications_settings", "notifications_update"),
},
{
"key": "system",
"label": "System",
"href_name": "system_settings",
"route_names": ("system_settings",),
},
{
"key": "accessibility",
"label": "Accessibility",
"href_name": "accessibility_settings",
"route_names": ("accessibility_settings",),
},
),
},
{
"key": "security",
"label": "Security",
"href_name": "encryption_settings",
"children": (
{
"key": "encryption",
"label": "Encryption",
"href_name": "encryption_settings",
"route_names": ("security_settings", "encryption_settings"),
},
{
"key": "permissions",
"label": "Permissions",
"href_name": "permission_settings",
"route_names": ("permission_settings",),
},
{
"key": "security_2fa",
"label": "2FA",
"href_name": "security_2fa",
"route_names": (
"security_2fa",
"profile",
"setup",
"backup_tokens",
"disable",
"phone_create",
"phone_delete",
),
},
),
},
{
"key": "ai",
"label": "AI",
"href_name": "ai_models",
"children": (
{
"key": "ai_models",
"label": "Models",
"href_name": "ai_models",
"route_names": (
"ai_settings",
"ai_models",
"ais",
"ai_create",
"ai_update",
"ai_delete",
),
},
{
"key": "ai_traces",
"label": "Traces",
"href_name": "ai_execution_log",
"route_names": (
"ai_execution_log",
"ai_execution_run_detail",
"ai_execution_run_detail_tab",
),
},
),
},
{
"key": "modules",
"label": "Modules",
"href_name": "command_routing",
"children": (
{
"key": "command_routing",
"label": "Commands",
"href_name": "command_routing",
"route_names": ("modules_settings", "command_routing"),
},
{
"key": "business_plans",
"label": "Business Plans",
"href_name": "business_plan_inbox",
"route_names": ("business_plan_inbox", "business_plan_editor"),
},
{
"key": "tasks",
"label": "Task Automation",
"href_name": "tasks_settings",
"route_names": ("tasks_settings",),
},
{
"key": "translation",
"label": "Translation",
"href_name": "translation_settings",
"route_names": ("translation_settings", "translation_preview"),
},
{
"key": "behavioral",
"label": "Behavioral Signals",
"href_name": "behavioral_signals_settings",
"route_names": (
"availability_settings",
"behavioral_signals_settings",
),
},
),
},
)
def _route_names_for_node(node: dict) -> set[str]:
route_names = {
str(value).strip()
for value in tuple(node.get("route_names") or ())
if str(value).strip()
}
for child in tuple(node.get("children") or ()):
route_names.update(_route_names_for_node(child))
return route_names
def _tab(label: str, href_name: str, active: bool) -> dict:
return {
"label": str(label or "").strip(),
"href": reverse(href_name),
"active": bool(active),
}
def _find_active_path(nodes, url_name: str) -> list[dict]:
for node in tuple(nodes or ()):
node_routes = _route_names_for_node(node)
if url_name in node_routes:
child_path = _find_active_path(node.get("children") or (), url_name)
return [node, *child_path]
return []
def build_settings_navigation(url_name: str) -> dict | None:
current_route = str(url_name or "").strip()
if not current_route:
return None
active_path = _find_active_path(SETTINGS_NAVIGATION_TREE, current_route)
if not active_path:
return None
active_group = active_path[0]
navigation = {
"title": str(active_group.get("label") or "Settings"),
"groups": [
_tab(
group.get("label") or "",
group.get("href_name") or "",
bool(group.get("key")) == bool(active_group.get("key"))
and str(group.get("key") or "") == str(active_group.get("key") or ""),
)
for group in SETTINGS_NAVIGATION_TREE
],
"tabs": [],
"rows": [],
}
nodes = tuple(active_group.get("children") or ())
depth = 1
while nodes:
active_key = ""
if depth < len(active_path):
active_key = str(active_path[depth].get("key") or "")
tabs = [
_tab(
node.get("label") or "",
node.get("href_name") or "",
str(node.get("key") or "") == active_key,
)
for node in nodes
]
navigation["rows"].append(
{
"depth": depth,
"tabs": tabs,
}
)
if depth == 1:
navigation["tabs"] = tabs
current = next(
(
node
for node in nodes
if str(node.get("key") or "") == active_key
),
None,
)
nodes = tuple((current or {}).get("children") or ())
depth += 1
return navigation