I can show WorkflowPlayer tab
This commit is contained in:
@@ -29,7 +29,7 @@ class DataGridDbManager:
|
||||
def __init__(self, session: dict, settings_manager: SettingsManager, key: tuple):
|
||||
self._session = session
|
||||
self._settings_manager = settings_manager
|
||||
self._key = "#".join(make_safe_id(item) for item in key) if key else ""
|
||||
self._key = self._key_as_string(key)
|
||||
|
||||
# init the db if needed
|
||||
if self._settings_manager and not self._settings_manager.exists(self._session, self._get_db_entry()):
|
||||
@@ -38,6 +38,16 @@ class DataGridDbManager:
|
||||
def _get_db_entry(self):
|
||||
return f"{DATAGRID_DB_ENTRY}_{self._key}"
|
||||
|
||||
@staticmethod
|
||||
def _key_as_string(key):
|
||||
if not key:
|
||||
return ""
|
||||
|
||||
if isinstance(key, tuple):
|
||||
return "#".join(make_safe_id(item) for item in key)
|
||||
|
||||
return make_safe_id(key)
|
||||
|
||||
def save_settings(self, settings: DataGridSettings):
|
||||
if self._settings_manager is None:
|
||||
return
|
||||
|
||||
@@ -65,6 +65,7 @@ def post(session, _id: str, from_id: str, to_id: str):
|
||||
instance = InstanceManager.get(session, _id)
|
||||
return instance.add_connection(from_id, to_id)
|
||||
|
||||
|
||||
@rt(Routes.DeleteConnection)
|
||||
def post(session, _id: str, from_id: str, to_id: str):
|
||||
logger.debug(
|
||||
@@ -72,6 +73,7 @@ def post(session, _id: str, from_id: str, to_id: str):
|
||||
instance = InstanceManager.get(session, _id)
|
||||
return instance.delete_connection(from_id, to_id)
|
||||
|
||||
|
||||
@rt(Routes.ResizeDesigner)
|
||||
def post(session, _id: str, designer_height: int):
|
||||
logger.debug(
|
||||
@@ -122,4 +124,12 @@ def post(session, _id: str, component_id: str, event_name: str, details: dict):
|
||||
details.pop("_id")
|
||||
details.pop("component_id")
|
||||
details.pop("event_name")
|
||||
return instance.on_processor_details_event(component_id, event_name, details)
|
||||
return instance.on_processor_details_event(component_id, event_name, details)
|
||||
|
||||
|
||||
@rt(Routes.PlayWorkflow)
|
||||
def post(session, _id: str, tab_boundaries: str):
|
||||
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))
|
||||
|
||||
25
src/components/workflows/assets/icons.py
Normal file
25
src/components/workflows/assets/icons.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from fastcore.basics import NotStr
|
||||
|
||||
# Fluent Play20Filled
|
||||
icon_play = NotStr(
|
||||
"""<svg name="play" 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="M17.222 8.685a1.5 1.5 0 0 1 0 2.628l-10 5.498A1.5 1.5 0 0 1 5 15.496V4.502a1.5 1.5 0 0 1 2.223-1.314l10 5.497z" fill="currentColor"></path></g></svg>""")
|
||||
|
||||
# Fluent Pause20Filled
|
||||
icon_pause = NotStr(
|
||||
"""<svg name="pause" 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="M12 3.5A1.5 1.5 0 0 1 13.5 2h2A1.5 1.5 0 0 1 17 3.5v13a1.5 1.5 0 0 1-1.5 1.5h-2a1.5 1.5 0 0 1-1.5-1.5v-13zm-9 0A1.5 1.5 0 0 1 4.5 2h2A1.5 1.5 0 0 1 8 3.5v13A1.5 1.5 0 0 1 6.5 18h-2A1.5 1.5 0 0 1 3 16.5v-13z" fill="currentColor"></path></g></svg>""")
|
||||
|
||||
# Fluent Stop20Filled
|
||||
icon_stop = 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="M4.5 3A1.5 1.5 0 0 0 3 4.5v11A1.5 1.5 0 0 0 4.5 17h11a1.5 1.5 0 0 0 1.5-1.5v-11A1.5 1.5 0 0 0 15.5 3h-11z" fill="currentColor"></path></g></svg>""")
|
||||
|
||||
# fluent PlayCircle20Regular
|
||||
icon_play_circle = NotStr(
|
||||
"""<svg name="play" 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="M9.125 7.184A.75.75 0 0 0 8 7.834v4.333a.75.75 0 0 0 1.125.65l4.125-2.384a.5.5 0 0 0 0-.866L9.125 7.184zM2 10a8 8 0 1 1 16 0a8 8 0 0 1-16 0zm8-7a7 7 0 1 0 0 14a7 7 0 0 0 0-14z" fill="currentColor"></path></g></svg>""")
|
||||
|
||||
# fluent PauseCircle20Regular
|
||||
icon_pause_circle = NotStr(
|
||||
"""<svg name="pause" 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="M9 7.5a.5.5 0 0 0-1 0v5a.5.5 0 0 0 1 0v-5zm3 0a.5.5 0 0 0-1 0v5a.5.5 0 0 0 1 0v-5zM10 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16zm-7 8a7 7 0 1 1 14 0a7 7 0 0 1-14 0z" fill="currentColor"></path></g></svg>""")
|
||||
|
||||
# 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>""")
|
||||
@@ -34,7 +34,7 @@ class WorkflowDesignerCommandManager(BaseCommandManager):
|
||||
def __init__(self, owner):
|
||||
super().__init__(owner)
|
||||
|
||||
def select_processor(self, component_id :str):
|
||||
def select_processor(self, component_id: str):
|
||||
return {
|
||||
"hx_post": f"{ROUTE_ROOT}{Routes.SelectProcessor}",
|
||||
"hx-target": f"#p_{self._id}",
|
||||
@@ -67,3 +67,32 @@ class WorkflowDesignerCommandManager(BaseCommandManager):
|
||||
"hx-swap": "outerHTML",
|
||||
"hx-vals": f'js:{{"_id": "{self._id}", "component_id": "{component_id}", "event_name": "{event_name}"}}',
|
||||
}
|
||||
|
||||
def play_workflow(self):
|
||||
return {
|
||||
"hx_post": f"{ROUTE_ROOT}{Routes.PlayWorkflow}",
|
||||
"hx-target": f"#{self._owner.tabs_manager.get_id()}",
|
||||
"hx-swap": "outerHTML",
|
||||
"hx-vals": f'js:{{"_id": "{self._id}", "tab_boundaries": getTabContentBoundaries("{self._owner.tabs_manager.get_id()}")}}',
|
||||
}
|
||||
|
||||
def pause_workflow(self):
|
||||
return {
|
||||
"hx_post": f"{ROUTE_ROOT}{Routes.PauseWorkflow}",
|
||||
"hx-target": f"#{self._owner.tabs_manager.get_id()}",
|
||||
"hx-swap": "outerHTML",
|
||||
"hx-vals": f'js:{{"_id": "{self._id}", "tab_boundaries": getTabContentBoundaries("{self._owner.tabs_manager.get_id()}")}}',
|
||||
}
|
||||
|
||||
def stop_workflow(self):
|
||||
return {
|
||||
"hx_post": f"{ROUTE_ROOT}{Routes.StopWorkflow}",
|
||||
"hx-target": f"#{self._owner.tabs_manager.get_id()}",
|
||||
"hx-swap": "outerHTML",
|
||||
"hx-vals": f'js:{{"_id": "{self._id}", "tab_boundaries": getTabContentBoundaries("{self._owner.tabs_manager.get_id()}")}}',
|
||||
}
|
||||
|
||||
|
||||
class WorkflowPlayerCommandManager(BaseCommandManager):
|
||||
def __init__(self, owner):
|
||||
super().__init__(owner)
|
||||
|
||||
@@ -5,11 +5,14 @@ from fasthtml.components import *
|
||||
from fasthtml.xtend import Script
|
||||
|
||||
from components.BaseComponent import BaseComponent
|
||||
from components.workflows.assets.icons import icon_play, icon_pause, icon_stop
|
||||
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, \
|
||||
Connection, WorkflowsDesignerDbManager
|
||||
from components_helpers import apply_boundaries, mk_tooltip, mk_dialog_buttons
|
||||
Connection, WorkflowsDesignerDbManager, WorkflowsPlayerSettings
|
||||
from components_helpers import apply_boundaries, mk_tooltip, mk_dialog_buttons, mk_icon
|
||||
from core.instance_manager import InstanceManager
|
||||
from core.utils import get_unique_id, make_safe_id
|
||||
from utils.DbManagementHelper import DbManagementHelper
|
||||
|
||||
@@ -47,11 +50,13 @@ class WorkflowDesigner(BaseComponent):
|
||||
def __init__(self, session,
|
||||
_id=None,
|
||||
settings_manager=None,
|
||||
tabs_manager=None,
|
||||
key: str = None,
|
||||
designer_settings: WorkflowsDesignerSettings = None,
|
||||
boundaries: dict = None):
|
||||
super().__init__(session, _id)
|
||||
self._settings_manager = settings_manager
|
||||
self.tabs_manager = tabs_manager
|
||||
self._key = key
|
||||
self._designer_settings = designer_settings
|
||||
self._db = WorkflowsDesignerDbManager(session, settings_manager)
|
||||
@@ -169,6 +174,23 @@ class WorkflowDesigner(BaseComponent):
|
||||
self._db.save_state(self._key, self._state)
|
||||
return self.refresh_properties()
|
||||
|
||||
def play_workflow(self, boundaries: dict):
|
||||
if self._state.selected_component_id is None:
|
||||
return self.error_message("No component selected")
|
||||
|
||||
workflow_name = self._designer_settings.workflow_name
|
||||
player = InstanceManager.get(self._session,
|
||||
WorkflowPlayer.create_component_id(self._session, workflow_name),
|
||||
WorkflowPlayer,
|
||||
settings_manager=self._settings_manager,
|
||||
tabs_manager=self.tabs_manager,
|
||||
player_settings=WorkflowsPlayerSettings(workflow_name),
|
||||
boundaries=boundaries)
|
||||
|
||||
self.tabs_manager.add_tab(f"Workflow {workflow_name}", player, player.key)
|
||||
# player.start(self._state.selected_component_id)
|
||||
return self.tabs_manager.refresh()
|
||||
|
||||
def on_processor_details_event(self, component_id: str, event_name: str, details: dict):
|
||||
if component_id in self._state.components:
|
||||
component = self._state.components[component_id]
|
||||
@@ -183,6 +205,7 @@ class WorkflowDesigner(BaseComponent):
|
||||
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"),
|
||||
self._mk_media(),
|
||||
self._mk_designer(),
|
||||
Div(cls="wkf-splitter", id=f"s_{self._id}"),
|
||||
self._mk_properties(),
|
||||
@@ -259,6 +282,14 @@ class WorkflowDesigner(BaseComponent):
|
||||
style=f"height:{self._state.designer_height}px;"
|
||||
)
|
||||
|
||||
def _mk_media(self):
|
||||
return Div(
|
||||
mk_icon(icon_play, cls="mr-1", **self.commands.play_workflow()),
|
||||
mk_icon(icon_pause, cls="mr-1", **self.commands.play_workflow()),
|
||||
mk_icon(icon_stop, cls="mr-1", **self.commands.play_workflow()),
|
||||
cls=f"media-controls flex m-2"
|
||||
)
|
||||
|
||||
def _mk_processor_properties(self, component, processor_name):
|
||||
if processor_name == "Jira":
|
||||
return self._mk_jira_processor_details(component)
|
||||
|
||||
51
src/components/workflows/components/WorkflowPlayer.py
Normal file
51
src/components/workflows/components/WorkflowPlayer.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from fasthtml.components import *
|
||||
|
||||
from components.BaseComponent import BaseComponent
|
||||
from components.datagrid_new.components.DataGrid import DataGrid
|
||||
from components.datagrid_new.settings import DataGridSettings
|
||||
from components.workflows.commands import WorkflowPlayerCommandManager
|
||||
from components.workflows.constants import WORKFLOW_PLAYER_INSTANCE_ID
|
||||
from components.workflows.db_management import WorkflowsPlayerSettings
|
||||
from core.utils import get_unique_id, make_safe_id
|
||||
|
||||
grid_settings = DataGridSettings(
|
||||
header_visible=True,
|
||||
filter_all_visible=True,
|
||||
views_visible=False,
|
||||
open_file_visible=False,
|
||||
open_settings_visible=False)
|
||||
|
||||
|
||||
class WorkflowPlayer(BaseComponent):
|
||||
def __init__(self, session,
|
||||
_id=None,
|
||||
settings_manager=None,
|
||||
tabs_manager=None,
|
||||
player_settings: WorkflowsPlayerSettings = None,
|
||||
boundaries: dict = None):
|
||||
super().__init__(session, _id)
|
||||
self._settings_manager = settings_manager
|
||||
self.tabs_manager = tabs_manager
|
||||
self.key = f"__WorkflowPlayer_{player_settings.workflow_name}"
|
||||
self._player_settings = player_settings
|
||||
self._boundaries = boundaries
|
||||
self.commands = WorkflowPlayerCommandManager(self)
|
||||
self._datagrid = DataGrid(self._session,
|
||||
DataGrid.create_component_id(session),
|
||||
self.key,
|
||||
grid_settings=grid_settings,
|
||||
boundaries=boundaries)
|
||||
|
||||
def __ft__(self):
|
||||
return Div(
|
||||
self._datagrid,
|
||||
id=self._id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_component_id(session, suffix=None):
|
||||
prefix = f"{WORKFLOW_PLAYER_INSTANCE_ID}{session['user_id']}"
|
||||
if suffix is None:
|
||||
suffix = get_unique_id()
|
||||
|
||||
return make_safe_id(f"{prefix}{suffix}")
|
||||
@@ -101,6 +101,7 @@ class Workflows(BaseComponentSingleton):
|
||||
WorkflowDesigner.create_component_id(self._session, workflow_name),
|
||||
WorkflowDesigner,
|
||||
settings_manager=self._settings_manager,
|
||||
tabs_manager=self.tabs_manager,
|
||||
key=workflow_name,
|
||||
designer_settings=WorkflowsDesignerSettings(workflow_name=workflow_name),
|
||||
boundaries=tab_boundaries)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
WORKFLOWS_INSTANCE_ID = "__Workflows__"
|
||||
WORKFLOW_DESIGNER_INSTANCE_ID = "__WorkflowDesigner__"
|
||||
WORKFLOW_PLAYER_INSTANCE_ID = "__WorkflowPlayer__"
|
||||
WORKFLOWS_DB_ENTRY = "Workflows"
|
||||
WORKFLOW_DESIGNER_DB_ENTRY = "WorkflowDesigner"
|
||||
WORKFLOW_DESIGNER_DB_SETTINGS_ENTRY = "Settings"
|
||||
@@ -27,4 +28,8 @@ class Routes:
|
||||
SaveProperties = "/save-properties"
|
||||
CancelProperties = "/cancel-properties"
|
||||
SelectProcessor = "/select-processor"
|
||||
OnProcessorDetailsEvent = "/on-processor-details-event"
|
||||
OnProcessorDetailsEvent = "/on-processor-details-event"
|
||||
PlayWorkflow = "/play-workflow"
|
||||
PauseWorkflow = "/pause-workflow"
|
||||
StopWorkflow = "/stop-workflow"
|
||||
|
||||
@@ -41,6 +41,11 @@ class WorkflowsDesignerState:
|
||||
selected_component_id = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class WorkflowsPlayerSettings:
|
||||
workflow_name: str = "No Name"
|
||||
|
||||
|
||||
@dataclass
|
||||
class WorkflowsSettings:
|
||||
workflows: list[str] = field(default_factory=list)
|
||||
|
||||
Reference in New Issue
Block a user