From 4f0db6fb2fc8df85a40eb0706b58f898d27ece0e Mon Sep 17 00:00:00 2001 From: Ivan Hrynevytskyi Date: Mon, 26 Apr 2021 16:23:56 +0300 Subject: [PATCH] some refactoring, and start button addded --- .../elsa-designer-tree/elsa-designer-tree.css | 4 +- .../elsa-designer-tree/elsa-designer-tree.tsx | 125 +++++++++--------- 2 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.css b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.css index cf9fa5b7e..c8ca68a03 100644 --- a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.css +++ b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.css @@ -87,11 +87,11 @@ div.tree { } */ -.node.activity { +.node.activity, .node.start{ fill: transparent; } -.node.activity .label-container { +.node.activity .label-container, .node.start .label-container{ stroke: none; } diff --git a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx index 4cf88314b..b00523d8f 100644 --- a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx +++ b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx @@ -1,14 +1,21 @@ -import { Component, Host, h, Prop, State, Event, EventEmitter, Listen, Watch, Method } from '@stencil/core'; +import { Component, Host, h, Prop, State, Event, EventEmitter, Watch } from '@stencil/core'; import { Map, addConnection, findActivity, getChildActivities, getInboundConnections, getOutboundConnections, removeActivity } from '../../../../utils/utils'; -import { cleanup, destroy, updateConnections } from '../../../../utils/jsplumb-helper'; -import { ActivityDescriptor, ActivityDesignDisplayContext, ActivityModel, ActivityTraits, ConnectionModel, EventTypes, WorkflowModel, WorkflowPersistenceBehavior } from '../../../../models'; +import { + ActivityDescriptor, + ActivityDesignDisplayContext, + ActivityModel, + ActivityTraits, + ConnectionModel, + EventTypes, + WorkflowModel, + WorkflowPersistenceBehavior, +} from '../../../../models'; import { eventBus } from '../../../../services/event-bus'; import jsPlumb from 'jsplumb'; import * as d3 from 'd3'; import dagreD3 from 'dagre-d3'; -import { toggle } from 'el-transition'; import { registerClickOutside } from 'stencil-click-outside'; -import state from "../../../../utils/store"; +import state from '../../../../utils/store'; import uuid = jsPlumb.jsPlumbUtil.uuid; import { ActivityIcon } from '../../../icons/activity-icon'; @@ -63,7 +70,6 @@ export class ElsaWorkflowDesigner { this.workflowModel = newValue; } - // @Listen('edit-activity') handleEditActivity(activity: ActivityModel) { this.showActivityEditor(activity, true); } @@ -71,8 +77,6 @@ export class ElsaWorkflowDesigner { updateWorkflowModel(model: WorkflowModel) { this.workflowModel = model; this.workflowChanged.emit(model); - - console.log('rerendering') this.rerenderTree(); } @@ -84,7 +88,6 @@ export class ElsaWorkflowDesigner { disconnectedCallback() { eventBus.off(EventTypes.ActivityPicked, this.onActivityPicked); eventBus.off(EventTypes.UpdateActivity, this.onUpdateActivity); - cleanup(); } onActivityPicked = async args => { @@ -159,15 +162,22 @@ export class ElsaWorkflowDesigner { } this.updateWorkflowModel(workflowModel); + this.parentActivityId = null + this.parentActivityOutcome = null return activity; } + getRootActivities(): Array { + return getChildActivities(this.workflowModel, null); + } addConnection(sourceActivityId: string, targetActivityId: string, outcome: string) { const workflowModel = { ...this.workflowModel }; const connection: ConnectionModel = { sourceId: sourceActivityId, targetId: targetActivityId, outcome: outcome }; workflowModel.connections.push(connection); this.updateWorkflowModel(workflowModel); + this.parentActivityId = null + this.parentActivityOutcome = null } updateActivity(activity: ActivityModel) { @@ -190,14 +200,12 @@ export class ElsaWorkflowDesigner { this.renderNodes(); } - componentWillRender() { const activityModels = this.workflowModel.activities; const displayContexts: Map = {}; const activityDescriptors: Array = state.activityDescriptors; for (const model of activityModels) { - const descriptor = activityDescriptors.find(x => x.type == model.type); const description = model.description; const bodyText = description && description.length > 0 ? description : undefined; @@ -206,15 +214,15 @@ export class ElsaWorkflowDesigner { const displayContext: ActivityDesignDisplayContext = { activityModel: model, - activityIcon: , + activityIcon: , bodyDisplay: bodyDisplay, - outcomes: [...model.outcomes] + outcomes: [...model.outcomes], }; eventBus.emit(EventTypes.ActivityDesignDisplaying, this, displayContext); displayContexts[model.activityId] = displayContext; } - + this.activityDisplayContexts = displayContexts; } @@ -226,7 +234,6 @@ export class ElsaWorkflowDesigner { eventBus.emit(EventTypes.ShowActivityEditor, this, activity, animate); } - removeActivity(activity: ActivityModel) { let workflowModel = { ...this.workflowModel }; const incomingConnections = getInboundConnections(workflowModel, activity.activityId); @@ -235,7 +242,6 @@ export class ElsaWorkflowDesigner { // Remove activity (will also remove its connections). workflowModel = removeActivity(workflowModel, activity.activityId); - // For each incoming activity, try to connect it to a outgoing activity based on outcome. for (const incomingConnection of incomingConnections) { const incomingActivity = findActivity(workflowModel, incomingConnection.sourceId); @@ -246,15 +252,6 @@ export class ElsaWorkflowDesigner { this.updateWorkflowModel(workflowModel); } - // onOutcomeButtonClick(e: Event) { - // console.log(e) - // e.preventDefault(); - // console.log(e) - // // this.parentActivityId = activityId; - // // this.parentActivityOutcome = outcome; - // this.showActivityPicker(); - // } - applyZoom() { this.zoom = d3.zoom().on('zoom', event => { const { transform } = event; @@ -269,8 +266,26 @@ export class ElsaWorkflowDesigner { } setEnities() { - this.graph = new dagreD3.graphlib.Graph().setGraph({}) - console.log(this.workflowModel.activities) + this.graph = new dagreD3.graphlib.Graph().setGraph({}); + + const rootActivities = this.getRootActivities(); + + this.graph.setNode('start', { + shape: 'rect', + label: ``, + rx: 5, + ry: 5, + labelType: 'html', + class: 'start', + }); + + rootActivities.forEach(activity => { + this.graph.setEdge('start', `${activity.activityId}/start`, { + arrowhead: 'undirected', + }); + this.graph.setNode(`${activity.activityId}/start`, { shape: 'rect', activity, label: this.renderOutcomeButton(), labelType: 'html', class: 'add' }); + this.graph.setEdge(`${activity.activityId}/start`, activity.activityId, { arrowhead: 'undirected' }); + }); this.workflowModel.activities.forEach(activity => { this.graph.setNode(activity.activityId, this.createActivityOptions(activity)); @@ -278,7 +293,7 @@ export class ElsaWorkflowDesigner { activity.outcomes.forEach(outcome => { this.graph.setNode(`${activity.activityId}/${outcome}`, { shape: 'rect', outcome, activity, label: this.renderOutcomeButton(), labelType: 'html', class: 'add' }); this.graph.setEdge(activity.activityId, `${activity.activityId}/${outcome}`, { - label: `

${outcome}

`, + label: `

${outcome}

`, labelpos: 'c', labelType: 'html', arrowhead: 'undirected', @@ -289,17 +304,8 @@ export class ElsaWorkflowDesigner { this.workflowModel.connections.forEach(({ sourceId, targetId, outcome }) => { this.graph.setEdge(`${sourceId}/${outcome}`, targetId, { arrowhead: 'undirected' }); }); - - console.log(this.workflowModel.activities) - console.log(this.graph.nodes().map(node => this.graph.node(node))) } - - - // closeContextMenu() { - // leave(this.contextMenu); - // } - onDeleteActivityClick(e: Event) { e.preventDefault(); this.removeActivity(this.contextMenu.activity); @@ -319,40 +325,43 @@ export class ElsaWorkflowDesigner { this.dagreD3Renderer(this.innerD3Selected as any, this.graph as any); this.svgD3Selected.call(this.zoom.scaleTo, scaleAfter); this.innerD3Selected.attr('transform', prevTransform); + d3.selectAll('.node.add').each((n: any) => { const node = this.graph.node(n) as any; d3.select(node.elem).on('click', e => { e.preventDefault(); + d3.selectAll('.node.add svg').classed('text-green-400', false).classed('text-gray-400', true).classed('hover:text-blue-500', true); this.parentActivityId = node.activity.activityId; this.parentActivityOutcome = node.outcome; - if(e.shiftKey){ - d3.select(node.elem).select('svg').classed("text-green-400", true).classed("text-gray-400", false).classed('hover:text-blue-500', false) + if (e.shiftKey) { + d3.select(node.elem).select('svg').classed('text-green-400', true).classed('text-gray-400', false).classed('hover:text-blue-500', false); return; } this.showActivityPicker(); }); }); + + d3.selectAll('.node.start').each((n: any) => { + const node = this.graph.node(n) as any; + d3.select(node.elem).on('click', e => { + this.showActivityPicker(); + }); + }); + d3.selectAll('.node.activity').each((n: any) => { const node = this.graph.node(n) as any; - // console.log(d3.select(node.elem).select('.context-menu')); d3.select(node.elem).on('click', () => { - this.addConnection(this.parentActivityId, node.activity.activityId, this.parentActivityOutcome) - this.parentActivityId = null; - this.parentActivityOutcome = null; - }) - + if(this.parentActivityId && this.parentActivityOutcome){ + this.addConnection(this.parentActivityId, node.activity.activityId, this.parentActivityOutcome); + } + }); d3.select(node.elem) .select('button') .on('click', evt => { evt.stopPropagation(); this.handleContextMenuChange(evt.clientX, evt.clientY, true, node.activity); }); - // .on('click', () => toggleMenu())) }); - - // d3.selectAll('.node.add > rect').each((node) => { - // console.log(node) - // }) } rerenderTree() { @@ -361,10 +370,6 @@ export class ElsaWorkflowDesigner { this.renderNodes(); } - // createActivity() { - // this.graph.setNode('node-1', this.createActivityOptions({ displayName: 'node-1', activityId: '1' })); - // } - createActivityOptions(activity: ActivityModel) { return { shape: 'rect', @@ -388,13 +393,13 @@ export class ElsaWorkflowDesigner { } renderActivity(activity: ActivityModel) { - const displayContext = this.activityDisplayContexts[activity.activityId] || undefined + const displayContext = this.activityDisplayContexts[activity.activityId] || undefined; return `
- ${displayContext?.activityIcon || ""} + ${displayContext?.activityIcon || ''}

${activity.displayName}

@@ -420,14 +425,14 @@ ${this.renderActivityBody(activity.description)} renderActivityBody(description: string | null) { if (!description) return ''; return `
- ${description} -
`; + ${description} +
`; } render() { return ( (this.el = el)}> - (this.svg = el)} id="svg" style={{ height: '100vh', width: '100vw', pointerEvents: this.contextMenu.shown ? 'none' : '' }}> + (this.svg = el)} id="svg" style={{ height: '100vh', width: '100vw', pointerEvents: this.contextMenu.shown ? 'none' : '' }}> (this.inner = el)} />
-
}/> +
} /> ); }