diff --git a/src/components/workflows/Readme.md b/src/components/workflows/Readme.md index 66b370c..242f6fe 100644 --- a/src/components/workflows/Readme.md +++ b/src/components/workflows/Readme.md @@ -16,6 +16,7 @@ using `_id={WORKFLOW_DESIGNER_INSTANCE_ID}{session['user_id']}{get_unique_id()}` | Properties Properties drag top | `ppt_{self._id}` | | Properties Properties drag left | `ppl_{self._id}` | | Properties Properties drag right | `ppr_{self._id}` | +| Properties Properties content | `ppc_{self._id}` | | Spliter | `s_{self._id}` | | Top element | `t_{self._id}` | | Form for properties | `f_{self._id}_{component_id}` | diff --git a/src/components/workflows/assets/Workflows.js b/src/components/workflows/assets/Workflows.js index b6aed49..bc7e329 100644 --- a/src/components/workflows/assets/Workflows.js +++ b/src/components/workflows/assets/Workflows.js @@ -205,7 +205,7 @@ function bindWorkflowDesignerToolbox(elementId) { // Also trigger server-side selection utils.makeRequest('/workflows/select-component', { component_id: designer.selectedComponent - }, `#p_${elementId}`, "outerHTML"); + }, `#ppc_${elementId}`, "outerHTML"); }, // Deselect all components diff --git a/src/components/workflows/commands.py b/src/components/workflows/commands.py index 3a1c3e1..6ec15f9 100644 --- a/src/components/workflows/commands.py +++ b/src/components/workflows/commands.py @@ -43,7 +43,7 @@ class WorkflowDesignerCommandManager(BaseCommandManager): def select_processor(self, component_id: str): return { "hx_post": f"{ROUTE_ROOT}{Routes.SelectProcessor}", - "hx-target": f"#p_{self._id}", + "hx-target": f"#ppc_{self._id}", "hx-swap": "outerHTML", "hx-trigger": "change", "hx-vals": f'js:{{"_id": "{self._id}", "component_id": "{component_id}"}}', diff --git a/src/components/workflows/components/WorkflowDesigner.py b/src/components/workflows/components/WorkflowDesigner.py index eb6d8ef..c699fed 100644 --- a/src/components/workflows/components/WorkflowDesigner.py +++ b/src/components/workflows/components/WorkflowDesigner.py @@ -25,7 +25,6 @@ from utils.DbManagementHelper import DbManagementHelper logger = logging.getLogger("WorkflowDesigner") - class WorkflowDesigner(BaseComponent): def __init__(self, session, _id=None, @@ -121,7 +120,7 @@ class WorkflowDesigner(BaseComponent): undo_redo_attrs = UndoRedoAttrs(f"Move Component '{component.title}'", on_undo=self.refresh_state) self._db.save_state(self._key, self._state, undo_redo_attrs) # update db - return self.refresh_designer(), self.properties.refresh(), self._undo_redo.refresh() + return self.refresh_designer(), self.properties.refresh(mode="form", oob=True), self._undo_redo.refresh() def delete_component(self, component_id): # Remove component @@ -191,7 +190,7 @@ class WorkflowDesigner(BaseComponent): undo_redo_attrs = UndoRedoAttrs(f"Select Component {component.title}", on_undo=self.refresh_state) self._db.save_state(self._key, self._state, undo_redo_attrs) - return self.properties.refresh(), self._undo_redo.refresh() + return self.properties.refresh(mode="form"), self._undo_redo.refresh() def save_properties(self, component_id: str, details: dict): if component_id in self._state.components: @@ -217,7 +216,7 @@ class WorkflowDesigner(BaseComponent): undo_redo_attrs = UndoRedoAttrs(f"Set Processor for {component.title}", on_undo=self.refresh_state) self._db.save_state(self._key, self._state, undo_redo_attrs) - return self.refresh_properties(), self._undo_redo.refresh() + return self.properties.refresh(mode="form"), self._undo_redo.refresh() def play_workflow(self, boundaries: dict): self._error_message = None diff --git a/src/components/workflows/components/WorkflowDesignerProperties.py b/src/components/workflows/components/WorkflowDesignerProperties.py index 1bbb19f..50ea720 100644 --- a/src/components/workflows/components/WorkflowDesignerProperties.py +++ b/src/components/workflows/components/WorkflowDesignerProperties.py @@ -2,7 +2,7 @@ from fasthtml.common import * from dataclasses import dataclass from components.BaseComponent import BaseComponent -from components.workflows.constants import COMPONENT_TYPES +from components.workflows.constants import COMPONENT_TYPES, PROCESSOR_TYPES from components_helpers import mk_dialog_buttons from core.utils import merge_classes @@ -44,12 +44,25 @@ class WorkflowDesignerProperties(BaseComponent): def update_component(self, component_id): if component_id is None or component_id not in self._owner.get_state().components: self._component = None - self._component = self._owner.get_state().components[component_id] + else: + self._component = self._owner.get_state().components[component_id] - def refresh(self, oob=True): + def refresh(self, mode="all", oob=False): self.update_component(self._owner.get_state().selected_component_id) + if mode == "form": + return self._mk_content(oob=oob) + return self.__ft__(oob=oob) + def _mk_layout(self): + return Div( + self._mk_input(), + self._mk_properties(), + self._mk_output(), + cls="flex", + style="height: 100%; width: 100%; flex: 1;" + ) + def _mk_input(self): return Div( "Input", @@ -66,30 +79,6 @@ class WorkflowDesignerProperties(BaseComponent): cls="wkf-properties-output" ) - def _mk_header(self, cls=None): - if self._component is None: - return None - - icon = COMPONENT_TYPES[self._component.type]["icon"] - color = COMPONENT_TYPES[self._component.type]["color"] - return Div( - Div( - Span(icon), - H4(self._component.title, cls="font-semibold text-xs"), - cls=f"rounded-lg border-2 {color} flex text-center px-2" - ), - H1(self._component.id, cls="ml-4"), - cls=merge_classes("flex mb-2", cls) - ) - - def _mk_form(self, cls=None): - if self._component is None: - return None - - return Div( - cls=merge_classes(cls) - ) - def _mk_properties(self): return Div( # Drag handle (20px height) @@ -100,9 +89,9 @@ class WorkflowDesignerProperties(BaseComponent): ), # Properties content + self._mk_content(cls="flex-1 overflow-y-auto"), - self._mk_header(cls="flex-none"), - self._mk_form(cls="flex-1 overflow-y-auto"), + # Dialog buttons mk_dialog_buttons(cls="flex-none mt-auto pb-2"), # Left resize handle @@ -122,22 +111,67 @@ class WorkflowDesignerProperties(BaseComponent): cls="wkf-properties-properties flex flex-col", ) - def _mk_layout(self): + def _mk_content(self, cls=None, oob=False): + return Div( - self._mk_input(), - self._mk_properties(), - self._mk_output(), - cls="flex", - style="height: 100%; width: 100%; flex: 1;" + self._header(), + self._form(), + cls=merge_classes(cls), + id=f"ppc_{self._id}", + hx_swap_oob=f'true' if oob else None, ) + def _header(self): + if self._component is None: + return None + + icon = COMPONENT_TYPES[self._component.type]["icon"] + color = COMPONENT_TYPES[self._component.type]["color"] + return Div( + Div( + Span(icon), + H4(self._component.title, cls="font-semibold text-xs"), + cls=f"rounded-lg border-2 {color} flex text-center px-2" + ), + cls=merge_classes("flex"), + ) + + def _form(self): + if self._component is None: + return None + + return Form( + self._mk_select_processor(), + self._content_details(), + ) + + def _mk_select_processor(self): + selected_processor_name = self._component.properties["processor_name"] + return Select( + *[Option(processor_name, selected="selected" if processor_name == selected_processor_name else None) + for processor_name in PROCESSOR_TYPES[self._component.type]], + cls="select select-sm m-2", + id="processor_name", + name="processor_name", + **self._commands.select_processor(self._component.id) + ) + + def _content_details(self): + component_type = self._component.type + processor_name = self._component.properties.get("processor_name", None) + key = f"_mk_details_{component_type}_{processor_name}" + if hasattr(self, key): + return getattr(self, key)() + else: + return Div(f"Component '{key}' not found") + def __ft__(self, oob=False): # return self.render() return Div( self._mk_layout(), style=f"height: {self._get_height()}px;", id=f"p_{self._id}", - hx_swap_oob='true' if oob else None, + hx_swap_oob=f'innerHTML' if oob else None, cls="wkf-properties" )