Working version of EntrySelector

This commit is contained in:
2025-08-26 21:58:42 +02:00
parent 63058ef4a9
commit fe5668fbed
8 changed files with 67 additions and 35 deletions

View File

@@ -14,4 +14,13 @@ repositories_app, rt = fast_app()
def get(session, _id: str, entry: str): def get(session, _id: str, entry: str):
logger.debug(f"Entering {Routes.Select} with args {debug_session(session)}, {_id=}, {entry=}") logger.debug(f"Entering {Routes.Select} with args {debug_session(session)}, {_id=}, {entry=}")
instance = InstanceManager.get(session, _id) instance = InstanceManager.get(session, _id)
return instance.select_entry(entry) to_update = instance.select_entry(entry)
res = [instance]
if res is None:
return instance
if isinstance(to_update, (list, tuple)):
res.extend(to_update)
else:
res.append(to_update)
return tuple(res)

View File

@@ -11,6 +11,10 @@
display: inline-block; /* Ensure entries align horizontally if needed */ display: inline-block; /* Ensure entries align horizontally if needed */
} }
.es-entry-selected {
border: 2px solid var(--color-primary);
}
.es-entry:hover { .es-entry:hover {
background-color: var(--color-base-300); background-color: var(--color-base-300);
} }

View File

@@ -9,7 +9,7 @@ class EntrySelectorCommandManager(BaseCommandManager):
def select_entry(self, entry): def select_entry(self, entry):
return { return {
"hx-get": f"{ROUTE_ROOT}{Routes.Select}", "hx-get": f"{ROUTE_ROOT}{Routes.Select}",
"hx-target": f"#{self._owner.content_id}", "hx-target": f"#{self._id}",
"hx-swap": "innerHTML", "hx-swap": "outerHTML",
"hx-vals": f'{{"_id": "{self._id}", "entry": "{entry}"}}', "hx-vals": f'{{"_id": "{self._id}", "entry": "{entry}"}}',
} }

View File

@@ -9,12 +9,12 @@ logger = logging.getLogger("EntrySelector")
class EntrySelector(BaseComponentMultipleInstance): class EntrySelector(BaseComponentMultipleInstance):
def __init__(self, session, _id, owner, content_id, data=None, hooks=None, key=None, boundaries=None): def __init__(self, session, _id, owner, data=None, hooks=None, key=None, boundaries=None):
super().__init__(session, _id) super().__init__(session, _id)
self._key = key self._key = key
self._owner = owner # debugger component self._owner = owner # debugger component
self.data = data self.data = data
self.content_id = content_id self.selected = None
self.hooks = hooks self.hooks = hooks
self._boundaries = boundaries if boundaries else {"width": "300"} self._boundaries = boundaries if boundaries else {"width": "300"}
self._commands = EntrySelectorCommandManager(self) self._commands = EntrySelectorCommandManager(self)
@@ -22,20 +22,31 @@ class EntrySelector(BaseComponentMultipleInstance):
def set_data(self, data): def set_data(self, data):
self.data = data self.data = data
def set_selected(self, selected):
if selected is None:
self.selected = None
else:
self.selected = int(selected)
def set_boundaries(self, boundaries): def set_boundaries(self, boundaries):
self._boundaries = boundaries self._boundaries = boundaries
def select_entry(self, entry): def select_entry(self, entry):
logger.debug(f"Selecting entry {entry}") logger.debug(f"Selecting entry {entry}")
# return self._owner.select_entry(entry) self.set_selected(entry)
if self.hooks is not None and (on_entry_selected := self.hooks.get("on_entry_selected", None)) is not None:
return on_entry_selected(entry)
else:
return None
def _mk_content(self): def _mk_content(self):
if self.data is None: if not self.data:
return [Div("no entry")] return [Div("no entry")]
return [Div(index, return [Div(index,
**self._commands.select_entry(index), **self._commands.select_entry(index),
cls="es-entry") for index in range(self.data)] cls=f"es-entry {'es-entry-selected' if index == self.selected else ''}")
for index in range(self.data)]
def __ft__(self): def __ft__(self):
return Div( return Div(

View File

@@ -228,7 +228,7 @@ class WorkflowDesigner(BaseComponent):
self._error_message = self._player.global_error self._error_message = self._player.global_error
else: else:
self.properties.set_entry_selector_data(self._player.nb_items)
# change the tab and display the results # change the tab and display the results
self._player.set_boundaries(boundaries) self._player.set_boundaries(boundaries)
self.tabs_manager.add_tab(f"Workflow {self._designer_settings.workflow_name}", self._player, self._player.key) self.tabs_manager.add_tab(f"Workflow {self._designer_settings.workflow_name}", self._player, self._player.key)
@@ -238,6 +238,7 @@ class WorkflowDesigner(BaseComponent):
def stop_workflow(self): def stop_workflow(self):
self._error_message = None self._error_message = None
self._player.stop() self._player.stop()
self.properties.set_entry_selector_data(0)
return self.tabs_manager.refresh() return self.tabs_manager.refresh()
def on_processor_details_event(self, component_id: str, event_name: str, details: dict): def on_processor_details_event(self, component_id: str, event_name: str, details: dict):

View File

@@ -26,15 +26,13 @@ class WorkflowDesignerProperties(BaseComponent):
self._component = None self._component = None
self.update_layout() self.update_layout()
self.update_component(self._owner.get_state().selected_component_id) self.update_component(self._owner.get_state().selected_component_id)
self._input_entry_selector = InstanceManager.new(self._session, self.entry_selector = InstanceManager.new(self._session,
EntrySelector, EntrySelector,
owner=self, owner=self,
content_id=f"pic_{self._id}", hooks={"on_entry_selected": self.on_entry_selector_changed})
data=100)
self._output_entry_selector = InstanceManager.new(self._session, def set_entry_selector_data(self, data):
EntrySelector, self.entry_selector.set_data(data)
owner=self,
content_id=f"poc_{self._id}")
def update_layout(self): def update_layout(self):
if self._owner.get_state().properties_input_width is None: if self._owner.get_state().properties_input_width is None:
@@ -65,31 +63,38 @@ class WorkflowDesignerProperties(BaseComponent):
return self.__ft__(oob=oob) return self.__ft__(oob=oob)
def on_entry_selector_changed(self, entry):
return (self._mk_input(content="input:" + entry, oob=True),
self._mk_output(content="output:" + entry, oob=True))
def _mk_layout(self): def _mk_layout(self):
return Div( return Div(
self._mk_input(), self.entry_selector,
self._mk_properties(), Div(
self._mk_output(), self._mk_input(),
cls="flex", self._mk_properties(),
style="height: 100%; width: 100%; flex: 1;" self._mk_output(),
cls="flex",
style="height: 100%; width: 100%; flex: 1;"
)
) )
def _mk_input(self): def _mk_input(self, content=None, oob=False):
return Div( return Div(
self._input_entry_selector, content,
Div(id=f"pic_{self._id}"),
id=f"pi_{self._id}", id=f"pi_{self._id}",
style=f"width: {self.layout.input_width}px;", style=f"width: {self.layout.input_width}px;",
cls="wkf-properties-input" cls="wkf-properties-input",
hx_swap_oob=f'true' if oob else None,
) )
def _mk_output(self): def _mk_output(self, content=None, oob=False):
return Div( return Div(
self._output_entry_selector, content,
"Output Content",
id=f"po_{self._id}", id=f"po_{self._id}",
style=f"width: {self.layout.output_width}px;", style=f"width: {self.layout.output_width}px;",
cls="wkf-properties-output" cls="wkf-properties-output",
hx_swap_oob=f'true' if oob else None,
) )
def _mk_properties(self): def _mk_properties(self):

View File

@@ -53,6 +53,7 @@ class WorkflowPlayer(BaseComponent):
self.runtime_states = {} self.runtime_states = {}
self.global_error = None self.global_error = None
self.has_error = False self.has_error = False
self.nb_items = 0
def set_boundaries(self, boundaries: dict): def set_boundaries(self, boundaries: dict):
self._datagrid.set_boundaries(boundaries) self._datagrid.set_boundaries(boundaries)
@@ -93,6 +94,7 @@ class WorkflowPlayer(BaseComponent):
self.global_error = engine.global_error self.global_error = engine.global_error
else: # loop through the components and update the runtime states else: # loop through the components and update the runtime states
self.nb_items = engine.nb_items
for component in sorted_components: for component in sorted_components:
runtime_state = self.runtime_states.get(component.id) runtime_state = self.runtime_states.get(component.id)

View File

@@ -156,7 +156,7 @@ class WorkflowEngine:
self.global_error = None self.global_error = None
self.errors = {} self.errors = {}
self.debug = {} self.debug = {}
self.item_count = -1 self.nb_items = -1
def add_processor(self, processor: DataProcessor) -> 'WorkflowEngine': def add_processor(self, processor: DataProcessor) -> 'WorkflowEngine':
"""Add a data processor to the pipeline.""" """Add a data processor to the pipeline."""
@@ -201,10 +201,10 @@ class WorkflowEngine:
if not self.processors: if not self.processors:
self.has_error = False self.has_error = False
self.global_error = "No processors in the pipeline" self.global_error = "No processors in the pipeline"
self.item_count = -1 self.nb_items = -1
raise ValueError(self.global_error) raise ValueError(self.global_error)
self.item_count = 0 self.nb_items = 0
first_processor = self.processors[0] first_processor = self.processors[0]
if not isinstance(first_processor, DataProducer): if not isinstance(first_processor, DataProducer):
@@ -215,7 +215,7 @@ class WorkflowEngine:
self.debug[first_processor.component_id] = {"input": [], "output": []} self.debug[first_processor.component_id] = {"input": [], "output": []}
for item_linkage_id, item in enumerate(first_processor.process(None)): for item_linkage_id, item in enumerate(first_processor.process(None)):
self.item_count += 1 self.nb_items += 1
self.debug[first_processor.component_id]["output"].append(WorkflowPayload( self.debug[first_processor.component_id]["output"].append(WorkflowPayload(
processor_name=first_processor.__class__.__name__, processor_name=first_processor.__class__.__name__,
component_id=first_processor.component_id, component_id=first_processor.component_id,