diff --git a/src/components/BaseComponent.py b/src/components/BaseComponent.py index 5b98cfb..1054805 100644 --- a/src/components/BaseComponent.py +++ b/src/components/BaseComponent.py @@ -1,4 +1,4 @@ -from core.utils import get_user_id +from core.utils import get_user_id, get_unique_id class BaseComponent: @@ -51,3 +51,12 @@ class BaseComponentSingleton(BaseComponent): @classmethod def create_component_id(cls, session): return f"{cls.COMPONENT_INSTANCE_ID}{session['user_id']}" + + +class BaseComponentMultipleInstance(BaseComponent): + COMPONENT_INSTANCE_ID = None + + @classmethod + def create_component_id(cls, session): + component_id = cls.COMPONENT_INSTANCE_ID or cls.__name__ + return get_unique_id(f"{component_id}{session['user_id']}") diff --git a/src/components/entryselector/EntrySelectorApp.py b/src/components/entryselector/EntrySelectorApp.py new file mode 100644 index 0000000..a145b11 --- /dev/null +++ b/src/components/entryselector/EntrySelectorApp.py @@ -0,0 +1,17 @@ +import logging + +from fasthtml.fastapp import fast_app + +from components.entryselector.constants import Routes +from core.instance_manager import debug_session, InstanceManager + +logger = logging.getLogger("EntrySelectorApp") + +repositories_app, rt = fast_app() + + +@rt(Routes.Select) +def get(session, _id: str, entry: str): + logger.debug(f"Entering {Routes.Select} with args {debug_session(session)}, {_id=}, {entry=}") + instance = InstanceManager.get(session, _id) + return instance.select_entry(entry) diff --git a/src/components/entryselector/__init__.py b/src/components/entryselector/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/components/entryselector/assets/__init__.py b/src/components/entryselector/assets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/components/entryselector/commands.py b/src/components/entryselector/commands.py new file mode 100644 index 0000000..2b2f631 --- /dev/null +++ b/src/components/entryselector/commands.py @@ -0,0 +1,15 @@ +from components.BaseCommandManager import BaseCommandManager +from components.entryselector.constants import Routes, ROUTE_ROOT + + +class EntrySelectorCommandManager(BaseCommandManager): + def __init__(self, owner): + super().__init__(owner) + + def select_entry(self, entry): + return { + "hx-get": f"{ROUTE_ROOT}{Routes.Select}", + "hx-target": f"#{self._owner.content_id}", + "hx-swap": "innerHTML", + "hx-vals": f'{{"_id": "{self._id}", "entry": "{entry}"}}', + } \ No newline at end of file diff --git a/src/components/entryselector/components/EntrySelector.py b/src/components/entryselector/components/EntrySelector.py new file mode 100644 index 0000000..7896d2d --- /dev/null +++ b/src/components/entryselector/components/EntrySelector.py @@ -0,0 +1,46 @@ +import logging + +from fasthtml.components import * + +from components.BaseComponent import BaseComponentMultipleInstance +from components.entryselector.commands import EntrySelectorCommandManager + +logger = logging.getLogger("EntrySelector") + + +class EntrySelector(BaseComponentMultipleInstance): + def __init__(self, session, _id, owner, content_id, data=None, hooks=None, key=None, boundaries=None): + super().__init__(session, _id) + self._key = key + self._owner = owner # debugger component + self.data = data + self.content_id = content_id + self.hooks = hooks + self._boundaries = boundaries if boundaries else {"width": "300"} + self._commands = EntrySelectorCommandManager(self) + + def set_data(self, data): + self.data = data + + def set_boundaries(self, boundaries): + self._boundaries = boundaries + + def select_entry(self, entry): + logger.debug(f"Selecting entry {entry}") + # return self._owner.select_entry(entry) + + def _mk_content(self): + if self.data is None: + return [Div("no entry")] + + return [Div(index, + **self._commands.select_entry(index), + cls="es-entry") for index in range(self.data)] + + def __ft__(self): + return Div( + *self._mk_content(), + style=f"width: {self._boundaries['width']}px;", + cls="flex", + id=f"{self._id}", + ) diff --git a/src/components/entryselector/components/__init__.py b/src/components/entryselector/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/components/entryselector/constants.py b/src/components/entryselector/constants.py new file mode 100644 index 0000000..9942ce9 --- /dev/null +++ b/src/components/entryselector/constants.py @@ -0,0 +1,5 @@ +ROUTE_ROOT = "/es" # for EntrySelector + + +class Routes: + Select = "/select" diff --git a/src/components/workflows/components/WorkflowDesignerProperties.py b/src/components/workflows/components/WorkflowDesignerProperties.py index 800d0d2..787a170 100644 --- a/src/components/workflows/components/WorkflowDesignerProperties.py +++ b/src/components/workflows/components/WorkflowDesignerProperties.py @@ -1,9 +1,10 @@ from fasthtml.common import * -from dataclasses import dataclass from components.BaseComponent import BaseComponent +from components.entryselector.components.EntrySelector import EntrySelector from components.workflows.constants import COMPONENT_TYPES, PROCESSOR_TYPES from components_helpers import mk_dialog_buttons +from core.instance_manager import InstanceManager from core.jira import JiraRequestTypes, DEFAULT_SEARCH_FIELDS from utils.DbManagementHelper import DbManagementHelper @@ -25,6 +26,14 @@ class WorkflowDesignerProperties(BaseComponent): self._component = None self.update_layout() self.update_component(self._owner.get_state().selected_component_id) + self._input_entry_selector = InstanceManager.new(self._session, + EntrySelector, + owner=self, + content_id=f"pic_{self._id}", data=100) + self._output_entry_selector = InstanceManager.new(self._session, + EntrySelector, + owner=self, + content_id=f"poc_{self._id}") def update_layout(self): if self._owner.get_state().properties_input_width is None: @@ -66,7 +75,8 @@ class WorkflowDesignerProperties(BaseComponent): def _mk_input(self): return Div( - "Input", + self._input_entry_selector, + Div(id=f"pic_{self._id}"), id=f"pi_{self._id}", style=f"width: {self.layout.input_width}px;", cls="wkf-properties-input" @@ -74,7 +84,8 @@ class WorkflowDesignerProperties(BaseComponent): def _mk_output(self): return Div( - "Output", + self._output_entry_selector, + "Output Content", id=f"po_{self._id}", style=f"width: {self.layout.output_width}px;", cls="wkf-properties-output" @@ -186,7 +197,7 @@ class WorkflowDesignerProperties(BaseComponent): selected="selected" if name.value == request_type else None) def _mk_input_group(): - if request_type == JiraRequestTypes.Search.value or request_type == "issues": # remove issues at some point + if request_type == JiraRequestTypes.Search.value or request_type == "issues": # remove issues at some point return [ Div( Input(type="text", diff --git a/src/core/instance_manager.py b/src/core/instance_manager.py index 8f6cd2d..b3f4c36 100644 --- a/src/core/instance_manager.py +++ b/src/core/instance_manager.py @@ -47,6 +47,10 @@ class InstanceManager: return InstanceManager._instances[key] + @staticmethod + def new(session, instance_type, **kwargs): + return InstanceManager.get(session, instance_type.create_component_id(session), instance_type, **kwargs) + @staticmethod def register(session: dict | None, instance, instance_id: str = None): """ diff --git a/src/main.py b/src/main.py index 377f2a3..ecdd6dc 100644 --- a/src/main.py +++ b/src/main.py @@ -146,6 +146,7 @@ register_component("theme_controller", "components.themecontroller", "ThemeContr register_component("main_layout", "components.drawerlayout", "DrawerLayoutApp") register_component("undo_redo", "components.undo_redo", "UndoRedoApp") register_component("tabs", "components.tabs", "TabsApp") # before repositories +register_component("entryselector", "components.entryselector", "EntrySelectorApp") register_component("applications", "components.applications", "ApplicationsApp") register_component("repositories", "components.repositories", "RepositoriesApp") register_component("workflows", "components.workflows", "WorkflowsApp")