Dialog box at the bottom. Property layout fully operationnel
This commit is contained in:
@@ -59,6 +59,7 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
background-color: var(--color-base-100); /* bg-base-100 */
|
background-color: var(--color-base-100); /* bg-base-100 */
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,10 +80,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.wkf-properties-properties {
|
.wkf-properties-properties {
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wkf-properties-handle-left {
|
.wkf-properties-handle-left {
|
||||||
@@ -105,6 +106,28 @@
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wkf-properties-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: move;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wkf-properties-handle-top {
|
||||||
|
background-image: radial-gradient(var(--color-splitter) 40%, transparent 0);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-size: 4px 4px;
|
||||||
|
cursor: move;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 8px;
|
||||||
|
width: 20px;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.wkf-canvas {
|
.wkf-canvas {
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ from components.workflows.assets.icons import icon_play, icon_pause, icon_stop,
|
|||||||
from components.workflows.commands import WorkflowDesignerCommandManager
|
from components.workflows.commands import WorkflowDesignerCommandManager
|
||||||
from components.workflows.components.WorkflowDesignerProperties import WorkflowDesignerProperties
|
from components.workflows.components.WorkflowDesignerProperties import WorkflowDesignerProperties
|
||||||
from components.workflows.components.WorkflowPlayer import WorkflowPlayer
|
from components.workflows.components.WorkflowPlayer import WorkflowPlayer
|
||||||
from components.workflows.constants import WORKFLOW_DESIGNER_INSTANCE_ID, ProcessorTypes
|
from components.workflows.constants import WORKFLOW_DESIGNER_INSTANCE_ID, ProcessorTypes, COMPONENT_TYPES, \
|
||||||
|
PROCESSOR_TYPES
|
||||||
from components.workflows.db_management import WorkflowsDesignerSettings, WorkflowComponent, \
|
from components.workflows.db_management import WorkflowsDesignerSettings, WorkflowComponent, \
|
||||||
Connection, WorkflowsDesignerDbManager, ComponentState, WorkflowsDesignerState
|
Connection, WorkflowsDesignerDbManager, ComponentState, WorkflowsDesignerState
|
||||||
from components_helpers import apply_boundaries, mk_tooltip, mk_dialog_buttons, mk_icon
|
from components_helpers import apply_boundaries, mk_tooltip, mk_dialog_buttons, mk_icon
|
||||||
@@ -23,32 +24,6 @@ from utils.DbManagementHelper import DbManagementHelper
|
|||||||
|
|
||||||
logger = logging.getLogger("WorkflowDesigner")
|
logger = logging.getLogger("WorkflowDesigner")
|
||||||
|
|
||||||
# Component templates
|
|
||||||
COMPONENT_TYPES = {
|
|
||||||
ProcessorTypes.Producer: {
|
|
||||||
"title": "Data Producer",
|
|
||||||
"description": "Generates or loads data",
|
|
||||||
"icon": "📊",
|
|
||||||
"color": "bg-green-100 border-green-300 text-neutral"
|
|
||||||
},
|
|
||||||
ProcessorTypes.Filter: {
|
|
||||||
"title": "Data Filter",
|
|
||||||
"description": "Filters and transforms data",
|
|
||||||
"icon": "🔍",
|
|
||||||
"color": "bg-blue-100 border-blue-300 text-neutral"
|
|
||||||
},
|
|
||||||
ProcessorTypes.Presenter: {
|
|
||||||
"title": "Data Presenter",
|
|
||||||
"description": "Displays or exports data",
|
|
||||||
"icon": "📋",
|
|
||||||
"color": "bg-purple-100 border-purple-300 text-neutral"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PROCESSOR_TYPES = {
|
|
||||||
ProcessorTypes.Producer: ["Repository", "Jira"],
|
|
||||||
ProcessorTypes.Filter: ["Default"],
|
|
||||||
ProcessorTypes.Presenter: ["Default"]}
|
|
||||||
|
|
||||||
|
|
||||||
class WorkflowDesigner(BaseComponent):
|
class WorkflowDesigner(BaseComponent):
|
||||||
@@ -216,7 +191,7 @@ class WorkflowDesigner(BaseComponent):
|
|||||||
undo_redo_attrs = UndoRedoAttrs(f"Select Component {component.title}", on_undo=self.refresh_state)
|
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)
|
self._db.save_state(self._key, self._state, undo_redo_attrs)
|
||||||
|
|
||||||
return self.refresh_properties(), self._undo_redo.refresh()
|
return self.properties.refresh(), self._undo_redo.refresh()
|
||||||
|
|
||||||
def save_properties(self, component_id: str, details: dict):
|
def save_properties(self, component_id: str, details: dict):
|
||||||
if component_id in self._state.components:
|
if component_id in self._state.components:
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ from fasthtml.common import *
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from components.BaseComponent import BaseComponent
|
from components.BaseComponent import BaseComponent
|
||||||
|
from components.workflows.constants import COMPONENT_TYPES
|
||||||
|
from components_helpers import mk_dialog_buttons
|
||||||
|
from core.utils import merge_classes
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -17,12 +20,12 @@ class WorkflowDesignerProperties(BaseComponent):
|
|||||||
self._owner = owner
|
self._owner = owner
|
||||||
self._boundaries = self._owner.get_boundaries()
|
self._boundaries = self._owner.get_boundaries()
|
||||||
self._commands = self._owner.commands
|
self._commands = self._owner.commands
|
||||||
self.layout = self.compute_layout()
|
self.layout = None
|
||||||
|
self._component = None
|
||||||
|
self.update_layout()
|
||||||
|
self.update_component(self._owner.get_state().selected_component_id)
|
||||||
|
|
||||||
def update_layout(self):
|
def update_layout(self):
|
||||||
self.layout = self.compute_layout()
|
|
||||||
|
|
||||||
def compute_layout(self) -> DesignerLayout:
|
|
||||||
if self._owner.get_state().properties_input_width is None:
|
if self._owner.get_state().properties_input_width is None:
|
||||||
input_width = self._boundaries["width"] // 3
|
input_width = self._boundaries["width"] // 3
|
||||||
properties_width = self._boundaries["width"] // 3
|
properties_width = self._boundaries["width"] // 3
|
||||||
@@ -32,13 +35,19 @@ class WorkflowDesignerProperties(BaseComponent):
|
|||||||
properties_width = self._owner.get_state().properties_properties_width
|
properties_width = self._owner.get_state().properties_properties_width
|
||||||
output_width = self._owner.get_state().properties_output_width
|
output_width = self._owner.get_state().properties_output_width
|
||||||
|
|
||||||
return DesignerLayout(
|
self.layout = DesignerLayout(
|
||||||
input_width=input_width,
|
input_width=input_width,
|
||||||
properties_width=properties_width,
|
properties_width=properties_width,
|
||||||
output_width=output_width
|
output_width=output_width
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
def refresh(self, oob=True):
|
def refresh(self, oob=True):
|
||||||
|
self.update_component(self._owner.get_state().selected_component_id)
|
||||||
return self.__ft__(oob=oob)
|
return self.__ft__(oob=oob)
|
||||||
|
|
||||||
def _mk_input(self):
|
def _mk_input(self):
|
||||||
@@ -57,30 +66,44 @@ class WorkflowDesignerProperties(BaseComponent):
|
|||||||
cls="wkf-properties-output"
|
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):
|
def _mk_properties(self):
|
||||||
return Div(
|
return Div(
|
||||||
# Drag handle (20px height)
|
# Drag handle (20px height)
|
||||||
Div(
|
Div(
|
||||||
"Properties",
|
A(cls="wkf-properties-handle-top"),
|
||||||
|
cls="wkf-properties-top",
|
||||||
id=f"ppt_{self._id}",
|
id=f"ppt_{self._id}",
|
||||||
style="height: 20px; background-color: #ddd; cursor: move; text-align: center; line-height: 20px; font-weight: bold; font-size: 12px; border-bottom: 1px solid #bbb;"
|
|
||||||
),
|
),
|
||||||
|
|
||||||
# Properties content
|
# Properties content
|
||||||
Div(
|
|
||||||
Input(placeholder="output name", style="width: 100%; margin-bottom: 10px;"),
|
self._mk_header(cls="flex-none"),
|
||||||
Select(
|
self._mk_form(cls="flex-1 overflow-y-auto"),
|
||||||
Option("Repository", value="repository"),
|
mk_dialog_buttons(cls="flex-none mt-auto pb-2"),
|
||||||
Option("Jira", value="jira"),
|
|
||||||
style="width: 100%; margin-bottom: 10px;"
|
|
||||||
),
|
|
||||||
Div(
|
|
||||||
Button("Save", **self._commands.on_save(), style="margin-right: 5px; padding: 5px 10px;"),
|
|
||||||
Button("Cancel", **self._commands.on_cancel(), style="padding: 5px 10px;"),
|
|
||||||
style="text-align: center;"
|
|
||||||
),
|
|
||||||
style=f"padding: 10px; box-sizing: border-box;"
|
|
||||||
),
|
|
||||||
|
|
||||||
# Left resize handle
|
# Left resize handle
|
||||||
Div(
|
Div(
|
||||||
@@ -95,9 +118,8 @@ class WorkflowDesignerProperties(BaseComponent):
|
|||||||
),
|
),
|
||||||
|
|
||||||
id=f"pp_{self._id}",
|
id=f"pp_{self._id}",
|
||||||
style=f"width: {self.layout.properties_width}px;",
|
style=f"width: {self.layout.properties_width}px; height: 100%;",
|
||||||
cls="wkf-properties-properties"
|
cls="wkf-properties-properties flex flex-col",
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _mk_layout(self):
|
def _mk_layout(self):
|
||||||
|
|||||||
@@ -6,11 +6,39 @@ WORKFLOW_DESIGNER_DB_ENTRY = "WorkflowDesigner"
|
|||||||
WORKFLOW_DESIGNER_DB_SETTINGS_ENTRY = "Settings"
|
WORKFLOW_DESIGNER_DB_SETTINGS_ENTRY = "Settings"
|
||||||
WORKFLOW_DESIGNER_DB_STATE_ENTRY = "State"
|
WORKFLOW_DESIGNER_DB_STATE_ENTRY = "State"
|
||||||
|
|
||||||
|
|
||||||
class ProcessorTypes:
|
class ProcessorTypes:
|
||||||
Producer = "producer"
|
Producer = "producer"
|
||||||
Filter = "filter"
|
Filter = "filter"
|
||||||
Presenter = "presenter"
|
Presenter = "presenter"
|
||||||
|
|
||||||
|
|
||||||
|
COMPONENT_TYPES = {
|
||||||
|
ProcessorTypes.Producer: {
|
||||||
|
"title": "Data Producer",
|
||||||
|
"description": "Generates or loads data",
|
||||||
|
"icon": "📊",
|
||||||
|
"color": "bg-green-100 border-green-300 text-neutral"
|
||||||
|
},
|
||||||
|
ProcessorTypes.Filter: {
|
||||||
|
"title": "Data Filter",
|
||||||
|
"description": "Filters and transforms data",
|
||||||
|
"icon": "🔍",
|
||||||
|
"color": "bg-blue-100 border-blue-300 text-neutral"
|
||||||
|
},
|
||||||
|
ProcessorTypes.Presenter: {
|
||||||
|
"title": "Data Presenter",
|
||||||
|
"description": "Displays or exports data",
|
||||||
|
"icon": "📋",
|
||||||
|
"color": "bg-purple-100 border-purple-300 text-neutral"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESSOR_TYPES = {
|
||||||
|
ProcessorTypes.Producer: ["Repository", "Jira"],
|
||||||
|
ProcessorTypes.Filter: ["Default"],
|
||||||
|
ProcessorTypes.Presenter: ["Default"]}
|
||||||
|
|
||||||
ROUTE_ROOT = "/workflows"
|
ROUTE_ROOT = "/workflows"
|
||||||
|
|
||||||
|
|
||||||
@@ -34,4 +62,3 @@ class Routes:
|
|||||||
PauseWorkflow = "/pause-workflow"
|
PauseWorkflow = "/pause-workflow"
|
||||||
StopWorkflow = "/stop-workflow"
|
StopWorkflow = "/stop-workflow"
|
||||||
Refresh = "/refresh"
|
Refresh = "/refresh"
|
||||||
|
|
||||||
Reference in New Issue
Block a user