Another implementation of undo/redo
This commit is contained in:
@@ -129,14 +129,20 @@ def post(session, _id: str, component_id: str, event_name: str, details: dict):
|
||||
|
||||
@rt(Routes.PlayWorkflow)
|
||||
def post(session, _id: str, tab_boundaries: str):
|
||||
logger.debug(
|
||||
f"Entering {Routes.PlayWorkflow} with args {debug_session(session)}, {_id=}")
|
||||
logger.debug(f"Entering {Routes.PlayWorkflow} with args {debug_session(session)}, {_id=}")
|
||||
instance = InstanceManager.get(session, _id)
|
||||
return instance.play_workflow(json.loads(tab_boundaries))
|
||||
|
||||
|
||||
@rt(Routes.StopWorkflow)
|
||||
def post(session, _id: str):
|
||||
logger.debug(
|
||||
f"Entering {Routes.StopWorkflow} with args {debug_session(session)}, {_id=}")
|
||||
logger.debug(f"Entering {Routes.StopWorkflow} with args {debug_session(session)}, {_id=}")
|
||||
instance = InstanceManager.get(session, _id)
|
||||
return instance.stop_workflow()
|
||||
return instance.stop_workflow()
|
||||
|
||||
|
||||
@rt(Routes.Refresh)
|
||||
def post(session, _id: str):
|
||||
logger.debug(f"Entering {Routes.Refresh} with args {debug_session(session)}, {_id=}")
|
||||
instance = InstanceManager.get(session, _id)
|
||||
return instance.refresh()
|
||||
|
||||
@@ -23,3 +23,6 @@ icon_pause_circle = NotStr(
|
||||
# fluent RecordStop20Regular
|
||||
icon_stop_circle = NotStr(
|
||||
"""<svg name="stop" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 20 20"><g fill="none"><path d="M10 3a7 7 0 1 0 0 14a7 7 0 0 0 0-14zm-8 7a8 8 0 1 1 16 0a8 8 0 0 1-16 0zm5-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V8z" fill="currentColor"></path></g></svg>""")
|
||||
|
||||
# fluent ArrowClockwise20Regular
|
||||
icon_refresh = NotStr("""<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 20 20"><g fill="none"><path d="M3.066 9.05a7 7 0 0 1 12.557-3.22l.126.17H12.5a.5.5 0 1 0 0 1h4a.5.5 0 0 0 .5-.5V2.502a.5.5 0 0 0-1 0v2.207a8 8 0 1 0 1.986 4.775a.5.5 0 0 0-.998.064A7 7 0 1 1 3.066 9.05z" fill="currentColor"></path></g></svg>""")
|
||||
@@ -1,23 +1,6 @@
|
||||
from components.BaseCommandManager import BaseCommandManager
|
||||
from components.undo_redo.components.UndoRedo import CommandHistory
|
||||
from components.workflows.constants import Routes, ROUTE_ROOT
|
||||
|
||||
class AddConnectorCommand(CommandHistory):
|
||||
|
||||
def __init__(self, owner, connector):
|
||||
super().__init__("Add connector", "Add connector", owner)
|
||||
self.connector = connector
|
||||
|
||||
def undo(self):
|
||||
del self.owner.get_state().components[self.connector.id]
|
||||
self.owner.get_db().save_state(self.owner.get_key(), self.owner.get_state()) # update db
|
||||
return self.owner.refresh_designer(True)
|
||||
|
||||
def redo(self, oob=True):
|
||||
self.owner.get_state().components[self.connector.id] = self.connector
|
||||
self.owner.get_db().save_state(self.owner.get_key(), self.owner.get_state()) # update db
|
||||
return self.owner.refresh_designer(oob)
|
||||
|
||||
|
||||
class WorkflowsCommandManager(BaseCommandManager):
|
||||
def __init__(self, owner):
|
||||
@@ -108,6 +91,13 @@ class WorkflowDesignerCommandManager(BaseCommandManager):
|
||||
"hx-swap": "outerHTML",
|
||||
"hx-vals": f'js:{{"_id": "{self._id}"}}',
|
||||
}
|
||||
|
||||
def refresh(self):
|
||||
return {
|
||||
"hx_post": f"{ROUTE_ROOT}{Routes.Refresh}",
|
||||
"hx-swap": "none",
|
||||
"hx-vals": f'js:{{"_id": "{self._id}"}}',
|
||||
}
|
||||
|
||||
|
||||
class WorkflowPlayerCommandManager(BaseCommandManager):
|
||||
|
||||
@@ -6,8 +6,9 @@ from fasthtml.xtend import Script
|
||||
|
||||
from assets.icons import icon_error
|
||||
from components.BaseComponent import BaseComponent
|
||||
from components.workflows.assets.icons import icon_play, icon_pause, icon_stop
|
||||
from components.workflows.commands import WorkflowDesignerCommandManager, AddConnectorCommand
|
||||
from components.undo_redo.constants import UndoRedoAttrs
|
||||
from components.workflows.assets.icons import icon_play, icon_pause, icon_stop, icon_refresh
|
||||
from components.workflows.commands import WorkflowDesignerCommandManager
|
||||
from components.workflows.components.WorkflowPlayer import WorkflowPlayer
|
||||
from components.workflows.constants import WORKFLOW_DESIGNER_INSTANCE_ID, ProcessorTypes
|
||||
from components.workflows.db_management import WorkflowsDesignerSettings, WorkflowComponent, \
|
||||
@@ -63,6 +64,7 @@ class WorkflowDesigner(BaseComponent):
|
||||
self._key = key
|
||||
self._designer_settings = designer_settings
|
||||
self._db = WorkflowsDesignerDbManager(session, settings_manager)
|
||||
self._undo_redo = ComponentsInstancesHelper.get_undo_redo(session)
|
||||
self._state = self._db.load_state(key)
|
||||
self._boundaries = boundaries
|
||||
self.commands = WorkflowDesignerCommandManager(self)
|
||||
@@ -96,6 +98,13 @@ class WorkflowDesigner(BaseComponent):
|
||||
def refresh_properties(self, oob=False):
|
||||
return self._mk_properties(oob)
|
||||
|
||||
def refresh(self):
|
||||
return self.__ft__(oob=True)
|
||||
|
||||
def refresh_state(self):
|
||||
self._state = self._db.load_state(self._key)
|
||||
return self.__ft__(oob=True)
|
||||
|
||||
def add_component(self, component_type, x, y):
|
||||
self._state.component_counter += 1
|
||||
|
||||
@@ -111,24 +120,19 @@ class WorkflowDesigner(BaseComponent):
|
||||
description=info["description"],
|
||||
properties={"processor_name": PROCESSOR_TYPES[component_type][0]}
|
||||
)
|
||||
|
||||
command = AddConnectorCommand(self, component)
|
||||
undo_redo = ComponentsInstancesHelper.get_undo_redo(self._session)
|
||||
#undo_redo.push(command)
|
||||
self._state.components[component_id] = component
|
||||
self._db.save_state(self._key, self._state) # update db
|
||||
undo_redo.snapshot("add_component")
|
||||
return command.redo(), undo_redo.refresh()
|
||||
# self._state.components[component_id] = component
|
||||
# self._db.save_state(self._key, self._state) # update db
|
||||
# return self.refresh_designer()
|
||||
|
||||
undo_redo_attrs = UndoRedoAttrs(f"Add Component '{component_type}'", on_undo=lambda: self.refresh_state())
|
||||
self._db.save_state(self._key, self._state, undo_redo_attrs) # update db
|
||||
|
||||
return self.refresh_designer(), self._undo_redo.refresh()
|
||||
|
||||
def move_component(self, component_id, x, y):
|
||||
if component_id in self._state.components:
|
||||
self._state.selected_component_id = component_id
|
||||
self._state.components[component_id].x = int(x)
|
||||
self._state.components[component_id].y = int(y)
|
||||
self._db.save_state(self._key, self._state) # update db
|
||||
self._db.save_state(self._key, self._state, ) # update db
|
||||
|
||||
return self.refresh_designer(), self.refresh_properties(True)
|
||||
|
||||
@@ -247,12 +251,13 @@ class WorkflowDesigner(BaseComponent):
|
||||
def get_workflow_connections(self):
|
||||
return self._state.connections
|
||||
|
||||
def __ft__(self):
|
||||
def __ft__(self, oob=False):
|
||||
return Div(
|
||||
H1(f"{self._designer_settings.workflow_name}", cls="text-xl font-bold"),
|
||||
P("Drag components from the toolbox to the canvas to create your workflow.", cls="text-sm mb-6"),
|
||||
Div(
|
||||
self._mk_media(),
|
||||
#self._mk_refresh_button(),
|
||||
self._mk_error_message(),
|
||||
cls="flex mb-2",
|
||||
id=f"t_{self._id}"
|
||||
@@ -263,6 +268,7 @@ class WorkflowDesigner(BaseComponent):
|
||||
Script(f"bindWorkflowDesigner('{self._id}');"),
|
||||
**apply_boundaries(self._boundaries),
|
||||
id=f"{self._id}",
|
||||
hx_swap_oob='true' if oob else None,
|
||||
)
|
||||
|
||||
def _mk_connection_svg(self, conn: Connection):
|
||||
@@ -384,6 +390,9 @@ class WorkflowDesigner(BaseComponent):
|
||||
cls=f"media-controls flex m-2"
|
||||
)
|
||||
|
||||
def _mk_refresh_button(self):
|
||||
return mk_icon(icon_refresh, **self.commands.refresh())
|
||||
|
||||
def _mk_error_message(self):
|
||||
if not self._error_message:
|
||||
return Div()
|
||||
|
||||
@@ -32,4 +32,5 @@ class Routes:
|
||||
PlayWorkflow = "/play-workflow"
|
||||
PauseWorkflow = "/pause-workflow"
|
||||
StopWorkflow = "/stop-workflow"
|
||||
Refresh = "/refresh"
|
||||
|
||||
@@ -2,10 +2,12 @@ import enum
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from components.undo_redo.constants import UndoRedoAttrs
|
||||
from components.workflows.constants import WORKFLOWS_DB_ENTRY, WORKFLOW_DESIGNER_DB_ENTRY, \
|
||||
WORKFLOW_DESIGNER_DB_SETTINGS_ENTRY, WORKFLOW_DESIGNER_DB_STATE_ENTRY
|
||||
from core.settings_management import SettingsManager
|
||||
from core.utils import make_safe_id
|
||||
from utils.ComponentsInstancesHelper import ComponentsInstancesHelper
|
||||
|
||||
logger = logging.getLogger("WorkflowsSettings")
|
||||
|
||||
@@ -158,6 +160,7 @@ class WorkflowsDesignerDbManager:
|
||||
def __init__(self, session: dict, settings_manager: SettingsManager):
|
||||
self._session = session
|
||||
self._settings_manager = settings_manager
|
||||
self._undo_redo = ComponentsInstancesHelper.get_undo_redo(session)
|
||||
|
||||
@staticmethod
|
||||
def _get_db_entry(key):
|
||||
@@ -169,11 +172,17 @@ class WorkflowsDesignerDbManager:
|
||||
WORKFLOW_DESIGNER_DB_SETTINGS_ENTRY,
|
||||
settings)
|
||||
|
||||
def save_state(self, key: str, state: WorkflowsDesignerState):
|
||||
def save_state(self, key: str, state: WorkflowsDesignerState, undo_redo_attrs: UndoRedoAttrs = None):
|
||||
db_entry = self._get_db_entry(key)
|
||||
self._settings_manager.put(self._session,
|
||||
self._get_db_entry(key),
|
||||
db_entry,
|
||||
WORKFLOW_DESIGNER_DB_STATE_ENTRY,
|
||||
state)
|
||||
|
||||
if undo_redo_attrs is not None:
|
||||
self._undo_redo.snapshot(undo_redo_attrs,
|
||||
db_entry,
|
||||
WORKFLOW_DESIGNER_DB_STATE_ENTRY)
|
||||
|
||||
def save_all(self, key: str, settings: WorkflowsDesignerSettings = None, state: WorkflowsDesignerState = None):
|
||||
items = {}
|
||||
|
||||
Reference in New Issue
Block a user