Working on undo redo capabilities

This commit is contained in:
2025-07-24 23:41:27 +02:00
parent 1ceddfac7c
commit aa8aa8f58c
14 changed files with 203 additions and 7 deletions

View File

@@ -11,6 +11,7 @@ from components.drawerlayout.assets.icons import icon_panel_contract_regular, ic
from components.drawerlayout.constants import DRAWER_LAYOUT_INSTANCE_ID
from components.repositories.components.Repositories import Repositories
from components.tabs.components.MyTabs import MyTabs
from components.undo_redo.components.UndoRedo import UndoRedo
from components.workflows.components.Workflows import Workflows
from core.instance_manager import InstanceManager
from core.settings_management import SettingsManager
@@ -31,6 +32,7 @@ class DrawerLayout(BaseComponent):
self._ai_buddy = self._create_component(AIBuddy)
self._admin = self._create_component(Admin)
self._applications = self._create_component(Applications)
self._undo_redo = self._create_component(UndoRedo)
self.top_components = self._get_sub_components("TOP", [self._ai_buddy])
self.bottom_components = self._get_sub_components("BOTTOM", [self._ai_buddy])
@@ -53,12 +55,16 @@ class DrawerLayout(BaseComponent):
name="sidebar"
),
Div(
Label(
Input(type="checkbox",
onclick=f"document.getElementById('sidebar_{self._id}').classList.toggle('collapsed');"),
icon_panel_contract_regular,
icon_panel_expand_regular,
cls="swap",
Div(
Label(
Input(type="checkbox",
onclick=f"document.getElementById('sidebar_{self._id}').classList.toggle('collapsed');"),
icon_panel_contract_regular,
icon_panel_expand_regular,
cls="swap mr-4",
),
self._undo_redo,
cls="flex"
),
Div(*[component for component in self.top_components], name="top", cls='dl-top'),
Div(self._tabs, id=f"page_{self._id}", name="page", cls='dl-page'),

View File

@@ -0,0 +1,23 @@
import logging
from fasthtml.fastapp import fast_app
from components.undo_redo.constants import Routes
from core.instance_manager import debug_session, InstanceManager
logger = logging.getLogger("UndoRedoApp")
undo_redo_app, rt = fast_app()
@rt(Routes.Undo)
def post(session, _id: str):
logger.debug(f"Entering {Routes.Undo} with args {debug_session(session)}, {_id=}")
instance = InstanceManager.get(session, _id)
return instance.undo()
@rt(Routes.Redo)
def post(session, _id: str):
logger.debug(f"Entering {Routes.Redo} with args {debug_session(session)}, {_id=}")
instance = InstanceManager.get(session, _id)
return instance.redo()

View File

View File

@@ -0,0 +1,7 @@
from fastcore.basics import NotStr
# carbon Undo
icon_undo = NotStr("""<svg name="undo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><path d="M20 10H7.815l3.587-3.586L10 5l-6 6l6 6l1.402-1.415L7.818 12H20a6 6 0 0 1 0 12h-8v2h8a8 8 0 0 0 0-16z" fill="currentColor"></path></svg>""")
# carbon Redo
icon_redo = NotStr("""<svg name="redo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><path d="M12 10h12.185l-3.587-3.586L22 5l6 6l-6 6l-1.402-1.415L24.182 12H12a6 6 0 0 0 0 12h8v2h-8a8 8 0 0 1 0-16z" fill="currentColor"></path></svg>""")

View File

@@ -0,0 +1,25 @@
from components.BaseCommandManager import BaseCommandManager
from components.undo_redo.constants import ROUTE_ROOT, Routes
class UndoRedoCommandManager(BaseCommandManager):
def __init__(self, owner):
super().__init__(owner)
def undo(self):
return {
"hx-post": f"{ROUTE_ROOT}{Routes.Undo}",
"hx-trigger": "click, keyup[ctrlKey&&key=='z'] from:body",
"hx-target": f"#{self._id}",
"hx-swap": "innerHTML",
"hx-vals": f'{{"_id": "{self._id}"}}',
}
def redo(self):
return {
"hx-post": f"{ROUTE_ROOT}{Routes.Redo}",
"hx_trigger": "click, keyup[ctrlKey&&key=='y'] from:body",
"hx-target": f"#{self._id}",
"hx-swap": "innerHTML",
"hx-vals": f'{{"_id": "{self._id}"}}',
}

View File

@@ -0,0 +1,89 @@
import logging
from abc import ABC, abstractmethod
from fasthtml.components import *
from components.BaseComponent import BaseComponentSingleton
from components.undo_redo.assets.icons import icon_redo, icon_undo
from components.undo_redo.commands import UndoRedoCommandManager
from components.undo_redo.constants import UNDO_REDO_INSTANCE_ID
from components_helpers import mk_icon
logger = logging.getLogger("UndoRedoApp")
class CommandHistory(ABC):
def __init__(self, name, desc):
self.name = name
self.desc = desc
@abstractmethod
def undo(self):
pass
@abstractmethod
def redo(self):
pass
class UndoRedo(BaseComponentSingleton):
COMPONENT_INSTANCE_ID = UNDO_REDO_INSTANCE_ID
def __init__(self, session, _id, settings_manager=None, tabs_manager=None):
super().__init__(session, _id, settings_manager, tabs_manager)
self.index = 0
self.history = []
self._commands = UndoRedoCommandManager(self)
def push(self, command: CommandHistory):
self.history.append(command)
self.index += 1
def undo(self):
logger.info(f"Undo command")
return self
def redo(self):
logger.info("Redo command")
if self.index > 0:
self.history.clear()
self.index = 0
else:
self.push("something")
return self
def __ft__(self):
return Div(
self._mk_undo(),
self._mk_redo(),
id=self._id,
cls="flex"
)
def _mk_undo(self):
if self._can_undo():
return mk_icon(icon_undo,
size=24,
**self._commands.undo())
else:
return mk_icon(icon_undo,
size=24,
can_select=False,
cls="mmt-btn-disabled")
def _mk_redo(self):
if self._can_redo():
return mk_icon(icon_redo,
size=24,
**self._commands.redo())
else:
return mk_icon(icon_redo,
size=24,
can_select=False,
cls="mmt-btn-disabled")
def _can_undo(self):
return self.index > 0
def _can_redo(self):
return self.index < len(self.history) - 1

View File

@@ -0,0 +1,8 @@
UNDO_REDO_INSTANCE_ID = "__UndoRedo__"
ROUTE_ROOT = "/undo"
class Routes:
Undo = "/undo"
Redo = "/redo"