Implement editing of properties of embedded activity
This commit is contained in:
parent
dc46bfe1bb
commit
715741e25f
|
|
@ -5,16 +5,16 @@
|
|||
* It contains typing information for all components that exist in this project.
|
||||
*/
|
||||
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
|
||||
import { ActionDefinition, ActionInvokedArgs, Activity, ActivitySelectedArgs, ContainerSelectedArgs, EditChildActivityArgs, GraphUpdatedArgs, IntellisenseContext, SelectListItem, TabChangedArgs, TabDefinition, Variable, WorkflowDefinition, WorkflowDefinitionSummary, WorkflowInstance, WorkflowInstanceSummary } from "./models";
|
||||
import { ActionDefinition, ActionInvokedArgs, Activity, ActivitySelectedArgs, ChildActivitySelectedArgs, ContainerSelectedArgs, EditChildActivityArgs, GraphUpdatedArgs, IntellisenseContext, SelectListItem, TabChangedArgs, TabDefinition, Variable, WorkflowDefinition, WorkflowDefinitionSummary, WorkflowInstance, WorkflowInstanceSummary } from "./models";
|
||||
import { ActivityIdUpdatedArgs, ActivityUpdatedArgs, DeleteActivityRequestedArgs } from "./components/designer/workflow-definition-editor/activity-properties-editor";
|
||||
import { Button } from "./components/shared/button-group/models";
|
||||
import { ContainerActivityComponent } from "./components/activities/container-activity-component";
|
||||
import { AddActivityArgs } from "./components/designer/canvas/canvas";
|
||||
import { AddActivityArgs, UpdateActivityArgs } from "./components/designer/canvas/canvas";
|
||||
import { ActivityInputContext } from "./services/node-input-driver";
|
||||
import { ContextMenuAnchorPoint, MenuItem, MenuItemGroup } from "./components/shared/context-menu/models";
|
||||
import { DropdownButtonItem, DropdownButtonOrigin } from "./components/shared/dropdown-button/models";
|
||||
import { Graph } from "@antv/x6";
|
||||
import { AddActivityArgs as AddActivityArgs1 } from "./components/designer/canvas/canvas";
|
||||
import { AddActivityArgs as AddActivityArgs1, UpdateActivityArgs as UpdateActivityArgs1 } from "./components/designer/canvas/canvas";
|
||||
import { ExpressionChangedArs } from "./components/designer/input-control-switch/input-control-switch";
|
||||
import { CreateLabelEventArgs, DeleteLabelEventArgs, Label, UpdateLabelEventArgs } from "./modules/labels/models";
|
||||
import { MonacoLib, MonacoValueChangedArgs } from "./components/shared/monaco-editor/monaco-editor";
|
||||
|
|
@ -47,6 +47,7 @@ export namespace Components {
|
|||
"importGraph": (root: Activity) => Promise<void>;
|
||||
"interactiveMode": boolean;
|
||||
"reset": () => Promise<void>;
|
||||
"updateActivity": (args: UpdateActivityArgs) => Promise<void>;
|
||||
"updateLayout": () => Promise<void>;
|
||||
"zoomToFit": () => Promise<void>;
|
||||
}
|
||||
|
|
@ -68,10 +69,9 @@ export namespace Components {
|
|||
"value": string;
|
||||
}
|
||||
interface ElsaDefaultActivityTemplate {
|
||||
"activityJson": string;
|
||||
"activityId": string;
|
||||
"activityType": string;
|
||||
"displayType": string;
|
||||
"selected": boolean;
|
||||
}
|
||||
interface ElsaDropdownButton {
|
||||
"icon"?: any;
|
||||
|
|
@ -89,6 +89,7 @@ export namespace Components {
|
|||
"import": (root: Activity) => Promise<void>;
|
||||
"interactiveMode": boolean;
|
||||
"reset": () => Promise<void>;
|
||||
"updateActivity": (args: UpdateActivityArgs) => Promise<void>;
|
||||
"updateLayout": () => Promise<void>;
|
||||
"zoomToFit": () => Promise<void>;
|
||||
}
|
||||
|
|
@ -665,11 +666,11 @@ declare namespace LocalJSX {
|
|||
"value"?: string;
|
||||
}
|
||||
interface ElsaDefaultActivityTemplate {
|
||||
"activityJson"?: string;
|
||||
"activityId"?: string;
|
||||
"activityType"?: string;
|
||||
"displayType"?: string;
|
||||
"onChildActivitySelected"?: (event: CustomEvent<ChildActivitySelectedArgs>) => void;
|
||||
"onEditChildActivity"?: (event: CustomEvent<EditChildActivityArgs>) => void;
|
||||
"selected"?: boolean;
|
||||
}
|
||||
interface ElsaDropdownButton {
|
||||
"icon"?: any;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import {AddActivityArgs} from '../designer/canvas/canvas';
|
||||
import {AddActivityArgs, UpdateActivityArgs} from '../designer/canvas/canvas';
|
||||
import {Activity} from '../../models';
|
||||
|
||||
export interface ContainerActivityComponent {
|
||||
updateLayout(): Promise<void>;
|
||||
addActivity(args: AddActivityArgs): Promise<void>;
|
||||
updateActivity(args: UpdateActivityArgs): Promise<void>;
|
||||
export(): Promise<Activity>
|
||||
import(root: Activity): Promise<void>;
|
||||
zoomToFit(): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import './shapes';
|
|||
import './ports';
|
||||
import {ActivityNode as ActivityNodeShape} from './shapes';
|
||||
import {ContainerActivityComponent} from '../container-activity-component';
|
||||
import {AddActivityArgs} from '../../designer/canvas/canvas';
|
||||
import {AddActivityArgs, UpdateActivityArgs} from '../../designer/canvas/canvas';
|
||||
import {Activity, ActivitySelectedArgs, ContainerSelectedArgs, GraphUpdatedArgs} from '../../../models';
|
||||
import {createGraph} from './graph-factory';
|
||||
import {Connection, Flowchart} from './models';
|
||||
|
|
@ -107,6 +107,23 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
graph.addNode(node);
|
||||
}
|
||||
|
||||
@Method()
|
||||
async updateActivity(args: UpdateActivityArgs) {
|
||||
const nodeId = args.id;
|
||||
const activity = args.activity;
|
||||
const node = this.graph.getNodes().find(x => x.id == nodeId) as any;
|
||||
|
||||
// Update the node's data with the activity.
|
||||
node.data = activity;
|
||||
|
||||
// Updating the node's activity property to trigger a rerender.
|
||||
node.activity = activity;
|
||||
|
||||
// If the ID of the activity changed, we need to update connection references (X6 stores deep copies of data).
|
||||
if (activity.id !== nodeId)
|
||||
this.syncEdgeData(nodeId, activity);
|
||||
}
|
||||
|
||||
@Method()
|
||||
async export(): Promise<Activity> {
|
||||
return this.exportInternal();
|
||||
|
|
@ -201,7 +218,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
flowchart.activities = activities;
|
||||
flowchart.connections = connections;
|
||||
flowchart.start = startActivity?.id;
|
||||
flowchart.metadata = {};
|
||||
flowchart.metadata = {...flowchart.metadata};
|
||||
flowchart.applicationProperties = {};
|
||||
flowchart.variables = [];
|
||||
|
||||
|
|
@ -293,18 +310,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
|
||||
const args: ActivitySelectedArgs = {
|
||||
activity: activity,
|
||||
applyChanges: a => {
|
||||
|
||||
// Update the node's data with the activity.
|
||||
node.data = a;
|
||||
|
||||
// Updating the node's activity property to trigger a rerender.
|
||||
node.activity = a;
|
||||
|
||||
// If the ID of the activity changed, we need to update connection references (X6 stores deep copies of data).
|
||||
if (a.id !== activityId)
|
||||
this.syncEdgeData(activityId, a);
|
||||
},
|
||||
applyChanges: async a => await this.updateActivity({id: activityId, activity: a}),
|
||||
deleteActivity: a => node.remove({deep: true})
|
||||
};
|
||||
|
||||
|
|
@ -345,8 +351,6 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
this.activityContextMenu.style.top = `${localPos.y}px`;
|
||||
this.activityContextMenu.style.left = `${localPos.x}px`;
|
||||
|
||||
debugger;
|
||||
|
||||
await this.activityContextMenu.open();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import {Component, h, Prop, State, Event, EventEmitter, Listen, Element} from "@
|
|||
import {camelCase} from 'lodash';
|
||||
import {ActivityIcon, ActivityIconRegistry} from "../../../services";
|
||||
import {Container} from "typedi";
|
||||
import {Activity, ActivityDescriptor, ActivityKind, EditChildActivityArgs, Port} from "../../../models";
|
||||
import {Activity, ActivityDescriptor, ActivityKind, ActivitySelectedArgs, ChildActivitySelectedArgs, EditChildActivityArgs, Port} from "../../../models";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {isNullOrWhitespace} from "../../../utils";
|
||||
import WorkflowEditorTunnel from "../state";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-default-activity-template',
|
||||
|
|
@ -13,7 +14,6 @@ import {isNullOrWhitespace} from "../../../utils";
|
|||
export class DefaultActivityTemplate {
|
||||
private readonly iconRegistry: ActivityIconRegistry;
|
||||
private activityDescriptor: ActivityDescriptor;
|
||||
private parsedActivity: Activity;
|
||||
private icon: ActivityIcon;
|
||||
private portElements: Array<HTMLElement> = [];
|
||||
|
||||
|
|
@ -23,21 +23,13 @@ export class DefaultActivityTemplate {
|
|||
|
||||
@Prop({attribute: 'activity-type'}) activityType: string;
|
||||
@Prop({attribute: 'display-type'}) displayType: string;
|
||||
@Prop({attribute: 'activity'}) activityJson: string;
|
||||
@Prop() selected: boolean;
|
||||
@Prop({attribute: 'activity-id'}) activityId: string;
|
||||
@Event() editChildActivity: EventEmitter<EditChildActivityArgs>;
|
||||
@Event() childActivitySelected: EventEmitter<ChildActivitySelectedArgs>;
|
||||
@State() private selectedPortName: string;
|
||||
|
||||
componentWillLoad() {
|
||||
const iconRegistry = this.iconRegistry;
|
||||
|
||||
const encodedActivityJson = this.activityJson;
|
||||
|
||||
if (!isNullOrWhitespace(encodedActivityJson)) {
|
||||
const decodedActivityJson = decodeURI(encodedActivityJson);
|
||||
this.parsedActivity = JSON.parse(decodedActivityJson);
|
||||
}
|
||||
|
||||
this.activityDescriptor = descriptorsStore.activityDescriptors.find(x => x.activityType == this.activityType);
|
||||
const activityType = this.activityType;
|
||||
this.icon = iconRegistry.has(activityType) ? iconRegistry.get(activityType) : null;
|
||||
|
|
@ -49,41 +41,49 @@ export class DefaultActivityTemplate {
|
|||
|
||||
render() {
|
||||
const activityDescriptor = this.activityDescriptor;
|
||||
const activity = this.parsedActivity;
|
||||
const canStartWorkflow = activity?.canStartWorkflow;
|
||||
const icon = this.icon;
|
||||
const textColor = canStartWorkflow ? 'text-white' : 'text-gray-700';
|
||||
const isTrigger = activityDescriptor?.kind == ActivityKind.Trigger;
|
||||
const backgroundColor = canStartWorkflow ? isTrigger ? 'bg-green-400' : 'bg-blue-400' : 'bg-white';
|
||||
const iconBackgroundColor = isTrigger ? 'bg-green-500' : 'bg-blue-500';
|
||||
const borderColor = this.selected ? 'border-blue-600' : canStartWorkflow ? isTrigger ? 'border-green-600' : 'border-blue-600' : 'border-gray-300';
|
||||
const displayTypeIsPicker = this.displayTypeIsPicker;
|
||||
const displayTypeIsEmbedded = this.displayTypeIsEmbedded;
|
||||
const containerCssClass = displayTypeIsEmbedded ? '' : 'drop-shadow-md';
|
||||
const contentCssClass = displayTypeIsPicker ? 'px-2 py-2' : 'px-4 py-4';
|
||||
let displayText = activity?.metadata?.displayText;
|
||||
|
||||
if (isNullOrWhitespace(displayText))
|
||||
displayText = activityDescriptor?.displayName;
|
||||
const activityId = this.activityId;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div class={`activity-wrapper border ${borderColor} ${backgroundColor} ${containerCssClass} rounded text-white overflow-hidden`}>
|
||||
<div class="activity-content-wrapper flex flex-row">
|
||||
<div class={`flex flex-shrink items-center ${iconBackgroundColor}`}>
|
||||
{this.renderIcon(icon)}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class={contentCssClass}>
|
||||
<span class={textColor}>{displayText}</span>
|
||||
<div>
|
||||
{this.renderPorts()}
|
||||
<WorkflowEditorTunnel.Consumer>
|
||||
{({nodeMap}) => {
|
||||
const activity: Activity = nodeMap[activityId];
|
||||
const canStartWorkflow = activity?.canStartWorkflow;
|
||||
const icon = this.icon;
|
||||
const textColor = canStartWorkflow ? 'text-white' : 'text-gray-700';
|
||||
const isTrigger = activityDescriptor?.kind == ActivityKind.Trigger;
|
||||
const backgroundColor = canStartWorkflow ? isTrigger ? 'bg-green-400' : 'bg-blue-400' : 'bg-white';
|
||||
const iconBackgroundColor = isTrigger ? 'bg-green-500' : 'bg-blue-500';
|
||||
const borderColor = canStartWorkflow ? isTrigger ? 'border-green-600' : 'border-blue-600' : 'border-gray-300';
|
||||
const displayTypeIsPicker = this.displayTypeIsPicker;
|
||||
const displayTypeIsEmbedded = this.displayTypeIsEmbedded;
|
||||
const containerCssClass = displayTypeIsEmbedded ? '' : 'drop-shadow-md';
|
||||
const contentCssClass = displayTypeIsPicker ? 'px-2 py-2' : 'px-4 py-4';
|
||||
let displayText = activity?.metadata?.displayText;
|
||||
|
||||
if (isNullOrWhitespace(displayText))
|
||||
displayText = activityDescriptor?.displayName;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div class={`activity-wrapper border ${borderColor} ${backgroundColor} ${containerCssClass} rounded text-white overflow-hidden`}>
|
||||
<div class="activity-content-wrapper flex flex-row">
|
||||
<div class={`flex flex-shrink items-center ${iconBackgroundColor}`}>
|
||||
{this.renderIcon(icon)}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class={contentCssClass}>
|
||||
<span class={textColor}>{displayText}</span>
|
||||
<div>
|
||||
{this.renderPorts(activity)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</WorkflowEditorTunnel.Consumer>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ export class DefaultActivityTemplate {
|
|||
);
|
||||
}
|
||||
|
||||
private renderPorts = () => {
|
||||
private renderPorts = (activity: Activity) => {
|
||||
|
||||
if (this.displayTypeIsPicker)
|
||||
return undefined;
|
||||
|
|
@ -113,16 +113,16 @@ export class DefaultActivityTemplate {
|
|||
|
||||
return (
|
||||
<div class="activity-ports mt-2 flex space-x-2">
|
||||
{ports.map(port => this.renderPort(port))}
|
||||
{ports.map(port => this.renderPort(activity, port))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
private renderPort = (port: Port) => {
|
||||
const canStartWorkflow = this.parsedActivity?.canStartWorkflow;
|
||||
private renderPort = (activity: Activity, port: Port) => {
|
||||
const canStartWorkflow = activity.canStartWorkflow;
|
||||
const textColor = canStartWorkflow ? 'text-white' : 'text-gray-700';
|
||||
const borderColor = port.name == this.selectedPortName ? 'border-blue-600' : 'border-gray-300';
|
||||
const portName = camelCase(port.name);
|
||||
const activity = this.parsedActivity;
|
||||
const childActivity: Activity = activity ? activity[portName] : null;
|
||||
const childActivityDescriptor: ActivityDescriptor = childActivity != null ? descriptorsStore.activityDescriptors.find(x => x.activityType == childActivity.typeName) : null;
|
||||
let childActivityDisplayText = childActivity?.metadata?.displayText;
|
||||
|
|
@ -137,7 +137,10 @@ export class DefaultActivityTemplate {
|
|||
</div>
|
||||
<div>
|
||||
{childActivity ? (
|
||||
<div class="relative block w-full border-2 border-gray-300 border-solid rounded-lg p-5 text-center focus:outline-none">
|
||||
<div class={`relative block w-full border-2 ${borderColor} border-solid rounded-lg p-5 text-center focus:outline-none`}
|
||||
onMouseDown={this.onChildActivityMouseDown}
|
||||
onClick={e => this.onChildActivityClick(e, activity, childActivity, port)}
|
||||
>
|
||||
<div class="flex space-x-2">
|
||||
<div class="flex-grow">
|
||||
<span class={textColor}>{childActivityDisplayText}</span>
|
||||
|
|
@ -196,4 +199,20 @@ export class DefaultActivityTemplate {
|
|||
e.preventDefault();
|
||||
this.editChildActivity.emit({parentActivityId: parentActivity.id, port: port});
|
||||
};
|
||||
|
||||
private onChildActivityMouseDown = (e: MouseEvent) => {
|
||||
// Prevent X6 from capturing the click event.
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
private onChildActivityClick = (e: MouseEvent, parentActivity: Activity, childActivity: Activity, port: Port) => {
|
||||
const args: ChildActivitySelectedArgs = {
|
||||
parentActivity: parentActivity,
|
||||
childActivity: childActivity,
|
||||
port: port
|
||||
};
|
||||
|
||||
this.selectedPortName = port.name;
|
||||
this.childActivitySelected.emit(args);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ export interface AddActivityArgs {
|
|||
y?: number;
|
||||
}
|
||||
|
||||
export interface UpdateActivityArgs {
|
||||
id: string;
|
||||
activity: Activity;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-canvas',
|
||||
styleUrl: 'canvas.scss',
|
||||
|
|
@ -29,6 +34,11 @@ export class Canvas {
|
|||
await this.root.addActivity(args);
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async updateActivity(args: UpdateActivityArgs): Promise<void> {
|
||||
await this.root.updateActivity(args);
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async updateLayout(): Promise<void> {
|
||||
await this.root.updateLayout();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import {createProviderConsumer} from "@stencil/state-tunnel";
|
||||
import {h} from "@stencil/core";
|
||||
import {ActivityDescriptor, WorkflowDefinition} from "../../models";
|
||||
import {Activity, WorkflowDefinition} from "../../models";
|
||||
import {Hash} from "../../utils";
|
||||
|
||||
// export interface WorkflowDesignerState {
|
||||
// workflowDefinition: WorkflowDefinition;
|
||||
// }
|
||||
//
|
||||
// export default createProviderConsumer<WorkflowDesignerState>(
|
||||
// {
|
||||
// workflowDefinition: null,
|
||||
// },
|
||||
// (subscribe, child) => (<context-consumer subscribe={subscribe} renderer={child}/>)
|
||||
// );
|
||||
export interface WorkflowDesignerState {
|
||||
workflowDefinition: WorkflowDefinition;
|
||||
nodeMap: Hash<Activity>;
|
||||
}
|
||||
|
||||
export default createProviderConsumer<WorkflowDesignerState>(
|
||||
{
|
||||
workflowDefinition: null,
|
||||
nodeMap: {}
|
||||
},
|
||||
(subscribe, child) => (<context-consumer subscribe={subscribe} renderer={child}/>)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {PanelPosition, PanelStateChangedArgs} from '../panel/models';
|
|||
import {
|
||||
Activity,
|
||||
ActivityDescriptor,
|
||||
ActivitySelectedArgs,
|
||||
ActivitySelectedArgs, ChildActivitySelectedArgs,
|
||||
ContainerSelectedArgs,
|
||||
EditChildActivityArgs,
|
||||
GraphUpdatedArgs,
|
||||
|
|
@ -22,6 +22,8 @@ import {Flowchart} from "../../activities/flowchart/models";
|
|||
import {ActivityPropertyChangedEventArgs, WorkflowDefinitionPropsUpdatedArgs, WorkflowDefinitionUpdatedArgs, WorkflowEditorEventTypes} from "./models";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {WorkflowNavigationItem} from "../workflow-navigator/models";
|
||||
import WorkflowEditorTunnel, {WorkflowDesignerState} from "../state";
|
||||
import {Hash} from "../../../utils";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-workflow-definition-editor',
|
||||
|
|
@ -36,7 +38,7 @@ export class WorkflowDefinitionEditor {
|
|||
private canvas: HTMLElsaCanvasElement;
|
||||
private container: HTMLDivElement;
|
||||
private toolbox: HTMLElsaWorkflowDefinitionEditorToolboxElement;
|
||||
private nodes: Array<ActivityNode> = [];
|
||||
private nodeMap: Hash<Activity> = {};
|
||||
private applyActivityChanges: (activity: Activity) => void;
|
||||
private deleteActivity: (activity: Activity) => void;
|
||||
private readonly emitActivityChangedDebounced: (e: ActivityPropertyChangedEventArgs) => void;
|
||||
|
|
@ -90,6 +92,21 @@ export class WorkflowDefinitionEditor {
|
|||
this.deleteActivity = e.detail.deleteActivity;
|
||||
}
|
||||
|
||||
@Listen('childActivitySelected')
|
||||
private async handleChildActivitySelected(e: CustomEvent<ChildActivitySelectedArgs>) {
|
||||
const {parentActivity, childActivity, port} = e.detail;
|
||||
this.selectedActivity = childActivity;
|
||||
const parentActivityId = parentActivity.id;
|
||||
|
||||
this.applyActivityChanges = async a => {
|
||||
return await this.canvas.updateActivity({id: parentActivityId, activity: parentActivity});
|
||||
};
|
||||
this.deleteActivity = a => {
|
||||
const portName = camelCase(port.name);
|
||||
delete parentActivity[portName];
|
||||
};
|
||||
}
|
||||
|
||||
@Listen('graphUpdated')
|
||||
private async handleGraphUpdated(e: CustomEvent<GraphUpdatedArgs>) {
|
||||
const workflowDefinition = await this.getWorkflowDefinitionInternal();
|
||||
|
|
@ -108,7 +125,7 @@ export class WorkflowDefinitionEditor {
|
|||
|
||||
this.currentWorkflowPath = [...this.currentWorkflowPath, item];
|
||||
const portName = camelCase(e.detail.port.name);
|
||||
const parentActivity = this.nodes.find(x => x.activity.id == parentActivityId).activity;
|
||||
const parentActivity = this.nodeMap[parentActivityId];
|
||||
const childActivity = parentActivity[portName] as Activity;
|
||||
|
||||
if (!childActivity) {
|
||||
|
|
@ -116,6 +133,8 @@ export class WorkflowDefinitionEditor {
|
|||
} else {
|
||||
await this.canvas.importGraph(childActivity);
|
||||
}
|
||||
|
||||
this.selectedActivity = null;
|
||||
}
|
||||
|
||||
@Method()
|
||||
|
|
@ -145,7 +164,13 @@ export class WorkflowDefinitionEditor {
|
|||
@Method()
|
||||
async updateWorkflowDefinition(workflowDefinition: WorkflowDefinition): Promise<void> {
|
||||
this.workflowDefinitionState = workflowDefinition;
|
||||
this.nodes = flatten(walkActivities(workflowDefinition.root));
|
||||
const nodes = flatten(walkActivities(workflowDefinition.root));
|
||||
const nodeMap = {};
|
||||
|
||||
for (const node of nodes)
|
||||
nodeMap[node.activity.id] = node.activity;
|
||||
|
||||
this.nodeMap = nodeMap;
|
||||
|
||||
if (this.currentWorkflowPath.length == 0)
|
||||
this.currentWorkflowPath = [{activityId: workflowDefinition.root.id, portName: null}];
|
||||
|
|
@ -197,32 +222,39 @@ export class WorkflowDefinitionEditor {
|
|||
render() {
|
||||
|
||||
const workflowDefinition = this.workflowDefinitionState;
|
||||
const nodeMap = this.nodeMap;
|
||||
|
||||
const tunnelState: WorkflowDesignerState = {
|
||||
workflowDefinition: this.workflowDefinitionState,
|
||||
nodeMap: nodeMap
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="absolute inset-0" ref={el => this.container = el}>
|
||||
<elsa-workflow-definition-editor-toolbar zoomToFit={this.onZoomToFit}/>
|
||||
<elsa-workflow-navigator items={this.currentWorkflowPath} workflowDefinition={workflowDefinition} onNavigate={this.onNavigateHierarchy}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-picker-container"
|
||||
position={PanelPosition.Left}
|
||||
onExpandedStateChanged={e => this.onActivityPickerPanelStateChanged(e.detail)}>
|
||||
<elsa-workflow-definition-editor-toolbox ref={el => this.toolbox = el}/>
|
||||
</elsa-panel>
|
||||
<elsa-canvas
|
||||
class="absolute" ref={el => this.canvas = el}
|
||||
interactiveMode={true}
|
||||
onDragOver={this.onDragOver}
|
||||
onDrop={this.onDrop}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-editor-container"
|
||||
position={PanelPosition.Right}
|
||||
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
|
||||
<div class="object-editor-container">
|
||||
{this.renderSelectedObject()}
|
||||
</div>
|
||||
</elsa-panel>
|
||||
|
||||
</div>
|
||||
<WorkflowEditorTunnel.Provider state={tunnelState}>
|
||||
<div class="absolute inset-0" ref={el => this.container = el}>
|
||||
<elsa-workflow-definition-editor-toolbar zoomToFit={this.onZoomToFit}/>
|
||||
<elsa-workflow-navigator items={this.currentWorkflowPath} workflowDefinition={workflowDefinition} onNavigate={this.onNavigateHierarchy}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-picker-container"
|
||||
position={PanelPosition.Left}
|
||||
onExpandedStateChanged={e => this.onActivityPickerPanelStateChanged(e.detail)}>
|
||||
<elsa-workflow-definition-editor-toolbox ref={el => this.toolbox = el}/>
|
||||
</elsa-panel>
|
||||
<elsa-canvas
|
||||
class="absolute" ref={el => this.canvas = el}
|
||||
interactiveMode={true}
|
||||
onDragOver={this.onDragOver}
|
||||
onDrop={this.onDrop}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-editor-container"
|
||||
position={PanelPosition.Right}
|
||||
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
|
||||
<div class="object-editor-container">
|
||||
{this.renderSelectedObject()}
|
||||
</div>
|
||||
</elsa-panel>
|
||||
</div>
|
||||
</WorkflowEditorTunnel.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -244,12 +276,12 @@ export class WorkflowDefinitionEditor {
|
|||
private getWorkflowDefinitionInternal = async (): Promise<WorkflowDefinition> => {
|
||||
const activity: Activity = await this.canvas.exportGraph();
|
||||
const workflowDefinition = this.workflowDefinitionState;
|
||||
const nodes = this.nodes;
|
||||
const nodeMap = this.nodeMap;
|
||||
const currentWorkflowPath = this.currentWorkflowPath;
|
||||
const currentWorkflowNavigationItem = currentWorkflowPath[currentWorkflowPath.length - 1];
|
||||
const currentActivityId = currentWorkflowNavigationItem.activityId;
|
||||
const currentPortName = currentWorkflowNavigationItem.portName;
|
||||
const currentActivity = nodes.find(x => x.activity.id == currentActivityId).activity;
|
||||
const currentActivity = nodeMap[currentActivityId];
|
||||
|
||||
if (!activity.id) {
|
||||
const descriptor = descriptorsStore.activityDescriptors.find(x => x.activityType == activity.typeName);
|
||||
|
|
@ -329,6 +361,7 @@ export class WorkflowDefinitionEditor {
|
|||
|
||||
private onActivityUpdated = (e: CustomEvent<ActivityUpdatedArgs>) => {
|
||||
const updatedActivity = e.detail.activity;
|
||||
this.nodeMap[updatedActivity.id] = updatedActivity;
|
||||
this.applyActivityChanges(updatedActivity);
|
||||
this.emitActivityChangedDebounced({...e.detail, workflowEditor: this.el});
|
||||
this.saveChangesDebounced();
|
||||
|
|
@ -358,7 +391,7 @@ export class WorkflowDefinitionEditor {
|
|||
private onNavigateHierarchy = async (e: CustomEvent<WorkflowNavigationItem>) => {
|
||||
const item = e.detail;
|
||||
const activityId = item.activityId;
|
||||
let activity = this.nodes.find(x => x.activity.id == activityId).activity;
|
||||
let activity = this.nodeMap[activityId];
|
||||
const path = this.currentWorkflowPath;
|
||||
const index = path.indexOf(item);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'reflect-metadata';
|
|||
import {h} from "@stencil/core";
|
||||
import {Container, Service} from "typedi";
|
||||
import {ActivityDisplayContext, ActivityDriver} from '../../services';
|
||||
import {isNullOrWhitespace} from "../../utils";
|
||||
|
||||
@Service()
|
||||
export class DefaultActivityDriver implements ActivityDriver {
|
||||
|
|
@ -11,9 +10,9 @@ export class DefaultActivityDriver implements ActivityDriver {
|
|||
const activityDescriptor = context.activityDescriptor;
|
||||
const activityType = activityDescriptor.activityType;
|
||||
const activity = context.activity;
|
||||
const activityId = activity?.id;
|
||||
const displayType = context.displayType;
|
||||
const activityJson = displayType == 'designer' ? encodeURI(JSON.stringify(activity)) : '';
|
||||
|
||||
return (`<elsa-default-activity-template activity-type="${activityType}" activity="${activityJson}" display-type="${displayType}" />`);
|
||||
return (`<elsa-default-activity-template activity-type="${activityType}" activity-id="${activityId}" display-type="${displayType}" />`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,3 +17,9 @@ export interface EditChildActivityArgs {
|
|||
parentActivityId: string;
|
||||
port: Port;
|
||||
}
|
||||
|
||||
export interface ChildActivitySelectedArgs {
|
||||
parentActivity: Activity;
|
||||
childActivity: Activity;
|
||||
port: Port;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import _, {camelCase} from 'lodash';
|
|||
import {ActivityInput, VersionOptions} from '../models';
|
||||
import {ActivityInputContext} from '../services/node-input-driver';
|
||||
|
||||
export interface Hash<TValue> {
|
||||
[key: string]: TValue;
|
||||
}
|
||||
|
||||
export function formatTimestamp(timestamp?: Date, defaultText?: string): string {
|
||||
return !!timestamp ? moment(timestamp).format('DD-MM-YYYY HH:mm:ss') : defaultText;
|
||||
}
|
||||
|
|
@ -82,7 +86,8 @@ export const serializeQueryString = (queryString: object): string => {
|
|||
const queryStringItems = _.map(filteredItems, (v, k) => {
|
||||
if (Array.isArray(v)) {
|
||||
return v.map(item => `${k}=${item}`).join('&');
|
||||
};
|
||||
}
|
||||
;
|
||||
return `${k}=${v}`;
|
||||
});
|
||||
return queryStringItems.length > 0 ? `?${queryStringItems.join('&')}` : '';
|
||||
|
|
|
|||
Loading…
Reference in a new issue