Implement editing of properties of embedded activity

This commit is contained in:
Sipke Schoorstra 2022-06-25 14:01:22 +02:00
parent dc46bfe1bb
commit 715741e25f
10 changed files with 199 additions and 118 deletions

View file

@ -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;

View file

@ -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>;

View file

@ -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();
}

View file

@ -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);
};
}

View file

@ -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();

View file

@ -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}/>)
);

View file

@ -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);

View file

@ -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}" />`);
}
}

View file

@ -17,3 +17,9 @@ export interface EditChildActivityArgs {
parentActivityId: string;
port: Port;
}
export interface ChildActivitySelectedArgs {
parentActivity: Activity;
childActivity: Activity;
port: Port;
}

View file

@ -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('&')}` : '';