Remove & merge Node base type
This commit is contained in:
parent
059356029d
commit
1c47d4b80d
|
|
@ -35,7 +35,7 @@ public class Join : Activity
|
|||
var workflowExecutionContext = context.WorkflowExecutionContext;
|
||||
|
||||
// Record last executed activity ID.
|
||||
var lastActivityId = context.WorkflowExecutionContext.ExecutionLog.LastOrDefault(x => x.EventName == WorkflowExecutionLogEventNames.Executed)?.NodeId;
|
||||
var lastActivityId = context.WorkflowExecutionContext.ExecutionLog.LastOrDefault(x => x.EventName == WorkflowExecutionLogEventNames.Executed)?.ActivityId;
|
||||
|
||||
if (lastActivityId != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ public class OutboundActivityNodeResolver : IActivityNodeResolver
|
|||
|
||||
private static IEnumerable<IActivity?> GetSinglePorts(IActivity activity)
|
||||
{
|
||||
var nodeType = activity.GetType();
|
||||
var activityType = activity.GetType();
|
||||
|
||||
var ports =
|
||||
from prop in nodeType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
from prop in activityType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
where typeof(IActivity).IsAssignableFrom(prop.PropertyType) || typeof(IEnumerable<IActivity>).IsAssignableFrom(prop.PropertyType)
|
||||
let portAttr = prop.GetCustomAttribute<OutboundAttribute>()
|
||||
let nodeAttr = prop.GetCustomAttribute<NodeAttribute>()
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ public class WorkflowExecutionContext
|
|||
|
||||
public void RemoveCompletionCallback(ActivityCompletionCallbackEntry entry) => _completionCallbackEntries.Remove(entry);
|
||||
|
||||
public ActivityNode FindNodeById(string nodeId) => NodeIdLookup[nodeId];
|
||||
public ActivityNode FindActivityNodeById(string nodeId) => NodeIdLookup[nodeId];
|
||||
public ActivityNode FindNodeByActivity(IActivity activity) => NodeActivityLookup[activity];
|
||||
public IActivity FindActivityById(string activityId) => FindNodeById(activityId).Activity;
|
||||
public IActivity FindActivityById(string activityId) => FindActivityNodeById(activityId).Activity;
|
||||
public T? GetProperty<T>(string key) => Properties.TryGetValue(key, out var value) ? (T?)value : default(T);
|
||||
public void SetProperty<T>(string key, T value) => Properties[key] = value;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
namespace Elsa.Models;
|
||||
|
||||
public record WorkflowExecutionLogEntry(string NodeId, string NodeType, DateTimeOffset Timestamp, string? EventName, string? Message, string? Source, object? Payload);
|
||||
public record WorkflowExecutionLogEntry(string ActivityId, string ActivityType, DateTimeOffset Timestamp, string? EventName, string? Message, string? Source, object? Payload);
|
||||
|
|
@ -78,16 +78,16 @@ public class IdentityGraphService : IIdentityGraphService
|
|||
return name;
|
||||
}
|
||||
|
||||
private int GetNextIndexFor(string nodeType, IDictionary<string, int> identityCounters)
|
||||
private int GetNextIndexFor(string activityType, IDictionary<string, int> identityCounters)
|
||||
{
|
||||
if (!identityCounters.TryGetValue(nodeType, out var index))
|
||||
if (!identityCounters.TryGetValue(activityType, out var index))
|
||||
{
|
||||
identityCounters[nodeType] = index;
|
||||
identityCounters[activityType] = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = identityCounters[nodeType] + 1;
|
||||
identityCounters[nodeType] = index;
|
||||
index = identityCounters[activityType] + 1;
|
||||
identityCounters[activityType] = index;
|
||||
}
|
||||
|
||||
return index;
|
||||
|
|
|
|||
|
|
@ -66,17 +66,17 @@ public class WorkflowStateSerializer : IWorkflowStateSerializer
|
|||
|
||||
private void SetOutput(WorkflowState state, WorkflowExecutionContext workflowExecutionContext)
|
||||
{
|
||||
foreach (var nodeEntry in state.ActivityOutput)
|
||||
foreach (var entry in state.ActivityOutput)
|
||||
{
|
||||
var nodeId = nodeEntry.Key;
|
||||
var node = workflowExecutionContext.FindNodeById(nodeId);
|
||||
var nodeType = node.GetType();
|
||||
var activityId = entry.Key;
|
||||
var node = workflowExecutionContext.FindActivityNodeById(activityId);
|
||||
var activityType = node.Activity.GetType();
|
||||
|
||||
foreach (var outputEntry in nodeEntry.Value)
|
||||
foreach (var outputEntry in entry.Value)
|
||||
{
|
||||
var propertyName = outputEntry.Key;
|
||||
var propertyValue = outputEntry.Value;
|
||||
var propertyInfo = nodeType.GetProperty(propertyName, BindingFlags.Public)!;
|
||||
var propertyInfo = activityType.GetProperty(propertyName, BindingFlags.Public)!;
|
||||
propertyInfo.SetValue(node, propertyValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ public class WorkflowStateSerializer : IWorkflowStateSerializer
|
|||
foreach (var completionCallbackEntry in state.CompletionCallbacks)
|
||||
{
|
||||
var owner = workflowExecutionContext.ActivityExecutionContexts.First(x => x.Id == completionCallbackEntry.OwnerId);
|
||||
var child = workflowExecutionContext.FindNodeById(completionCallbackEntry.ChildId).Activity;
|
||||
var child = workflowExecutionContext.FindActivityNodeById(completionCallbackEntry.ChildId).Activity;
|
||||
var callbackName = completionCallbackEntry.MethodName;
|
||||
var callbackDelegate = owner.Activity.GetActivityCompletionCallback(callbackName);
|
||||
workflowExecutionContext.AddCompletionCallback(owner, child, callbackDelegate);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,15 @@ using Elsa.Contracts;
|
|||
|
||||
namespace Elsa.Management.Models;
|
||||
|
||||
public class ActivityDescriptor : NodeDescriptor
|
||||
public class ActivityDescriptor
|
||||
{
|
||||
public string ActivityType { get; init; } = default!;
|
||||
public string Category { get; init; } = default!;
|
||||
public string? DisplayName { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ICollection<InputDescriptor> InputProperties { get; init; } = new List<InputDescriptor>();
|
||||
public ICollection<OutputDescriptor> OutputProperties { get; init; } = new List<OutputDescriptor>();
|
||||
|
||||
[JsonIgnore] public Func<ActivityConstructorContext, IActivity> Constructor { get; init; } = default!;
|
||||
public ActivityTraits Traits { get; set; } = ActivityTraits.Action;
|
||||
public ICollection<Port> InPorts { get; init; } = new List<Port>();
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
namespace Elsa.Management.Models;
|
||||
|
||||
public abstract class NodeDescriptor
|
||||
{
|
||||
public string NodeType { get; init; } = default!;
|
||||
public string Category { get; init; } = default!;
|
||||
public string? DisplayName { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ICollection<InputDescriptor> InputProperties { get; init; } = new List<InputDescriptor>();
|
||||
public ICollection<OutputDescriptor> OutputProperties { get; init; } = new List<OutputDescriptor>();
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Contracts;
|
||||
|
||||
namespace Elsa.Management.Models;
|
||||
|
||||
public class TriggerDescriptor : NodeDescriptor
|
||||
{
|
||||
[JsonIgnore] public Func<TriggerConstructorContext, IEventGenerator> Constructor { get; init; } = default!;
|
||||
}
|
||||
|
||||
public record TriggerConstructorContext(JsonElement Element, JsonSerializerOptions SerializerOptions);
|
||||
|
|
@ -25,7 +25,7 @@ public class ActivityJsonConverter : JsonConverter<IActivity>
|
|||
if (!JsonDocument.TryParseValue(ref reader, out var doc))
|
||||
throw new JsonException("Failed to parse JsonDocument");
|
||||
|
||||
if (!doc.RootElement.TryGetProperty("nodeType", out var activityTypeNameElement))
|
||||
if (!doc.RootElement.TryGetProperty("typeName", out var activityTypeNameElement))
|
||||
throw new JsonException("Failed to extract activity type property");
|
||||
|
||||
var activityTypeName = activityTypeNameElement.GetString()!;
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ public class FlowchartJsonConverter : JsonConverter<Flowchart>
|
|||
|
||||
var model = new
|
||||
{
|
||||
NodeType = value.TypeName,
|
||||
Id = value.Id,
|
||||
Metadata = value.Metadata,
|
||||
value.TypeName,
|
||||
value.Id,
|
||||
value.Metadata,
|
||||
Start = value.Start?.Id,
|
||||
Activities = value.Activities,
|
||||
Connections = value.Connections
|
||||
value.Activities,
|
||||
value.Connections
|
||||
};
|
||||
|
||||
JsonSerializer.Serialize(writer, model, connectionSerializerOptions);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class ActivityDescriber : IActivityDescriber
|
|||
{
|
||||
Category = category,
|
||||
Description = description,
|
||||
NodeType = fullTypeName,
|
||||
ActivityType = fullTypeName,
|
||||
DisplayName = displayName,
|
||||
Traits = isTrigger ? ActivityTraits.Trigger : ActivityTraits.Action,
|
||||
OutPorts = outboundPorts.ToList(),
|
||||
|
|
@ -106,7 +106,8 @@ public class ActivityDescriber : IActivityDescriber
|
|||
foreach (var propertyInfo in properties)
|
||||
{
|
||||
var activityPropertyAttribute = propertyInfo.GetCustomAttribute<OutputAttribute>();
|
||||
var wrappedPropertyType = propertyInfo.PropertyType.GenericTypeArguments[0];
|
||||
var typeArgs = propertyInfo.PropertyType.GenericTypeArguments;
|
||||
var wrappedPropertyType = typeArgs.Any() ? typeArgs[0] : typeof(object);
|
||||
|
||||
yield return new OutputDescriptor
|
||||
(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class ActivityRegistry : IActivityRegistry
|
|||
var descriptors = ListByProvider(provider).ToList();
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
_activityDescriptors.Remove(descriptor.NodeType);
|
||||
_activityDescriptors.Remove(descriptor.ActivityType);
|
||||
|
||||
_providedActivityDescriptors.Remove(provider);
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ public class ActivityRegistry : IActivityRegistry
|
|||
|
||||
private void Add(ActivityDescriptor descriptor, ICollection<ActivityDescriptor> target)
|
||||
{
|
||||
_activityDescriptors.Add(descriptor.NodeType, descriptor);
|
||||
_activityDescriptors.Add(descriptor.ActivityType, descriptor);
|
||||
target.Add(descriptor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { ActionDefinition, ActionInvokedArgs, Activity, ActivityDescriptor, Acti
|
|||
import { ActivityUpdatedArgs, DeleteActivityRequestedArgs } from "./components/designer/activity-properties-editor/activity-properties-editor";
|
||||
import { ContainerActivityComponent } from "./components/activities/container-activity-component";
|
||||
import { AddActivityArgs } from "./components/designer/canvas/canvas";
|
||||
import { NodeInputContext } from "./services/node-input-driver";
|
||||
import { ActivityInputContext } from "./services/node-input-driver";
|
||||
import { MenuItem } from "./components/shared/context-menu/models";
|
||||
import { DropdownButtonItem, DropdownButtonOrigin } from "./components/shared/dropdown-button/models";
|
||||
import { Graph } from "@antv/x6";
|
||||
|
|
@ -38,10 +38,10 @@ export namespace Components {
|
|||
"updateLayout": () => Promise<void>;
|
||||
}
|
||||
interface ElsaCheckListInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaCodeEditorInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaContextMenu {
|
||||
"menuItems": Array<MenuItem>;
|
||||
|
|
@ -53,7 +53,7 @@ export namespace Components {
|
|||
"text": string;
|
||||
}
|
||||
interface ElsaDropdownInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaFlowchart {
|
||||
"activityDescriptors": Array<ActivityDescriptor>;
|
||||
|
|
@ -112,10 +112,10 @@ export namespace Components {
|
|||
"value": string;
|
||||
}
|
||||
interface ElsaMultiLineInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaMultiTextInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaPager {
|
||||
"page": number;
|
||||
|
|
@ -126,10 +126,10 @@ export namespace Components {
|
|||
"position": PanelPosition;
|
||||
}
|
||||
interface ElsaRadioListInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaSingleLineInput {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaSlideOverPanel {
|
||||
"actions": Array<ActionDefinition>;
|
||||
|
|
@ -145,7 +145,7 @@ export namespace Components {
|
|||
"serverUrl": string;
|
||||
}
|
||||
interface ElsaSwitchEditor {
|
||||
"inputContext": NodeInputContext;
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaToolbox {
|
||||
"graph": Graph;
|
||||
|
|
@ -423,10 +423,10 @@ declare namespace LocalJSX {
|
|||
"interactiveMode"?: boolean;
|
||||
}
|
||||
interface ElsaCheckListInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaCodeEditorInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaContextMenu {
|
||||
"menuItems"?: Array<MenuItem>;
|
||||
|
|
@ -439,7 +439,7 @@ declare namespace LocalJSX {
|
|||
"text"?: string;
|
||||
}
|
||||
interface ElsaDropdownInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaFlowchart {
|
||||
"activityDescriptors"?: Array<ActivityDescriptor>;
|
||||
|
|
@ -504,10 +504,10 @@ declare namespace LocalJSX {
|
|||
"value"?: string;
|
||||
}
|
||||
interface ElsaMultiLineInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaMultiTextInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaPager {
|
||||
"onPaginated"?: (event: CustomEvent<PagerData>) => void;
|
||||
|
|
@ -520,10 +520,10 @@ declare namespace LocalJSX {
|
|||
"position"?: PanelPosition;
|
||||
}
|
||||
interface ElsaRadioListInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaSingleLineInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaSlideOverPanel {
|
||||
"actions"?: Array<ActionDefinition>;
|
||||
|
|
@ -539,7 +539,7 @@ declare namespace LocalJSX {
|
|||
"serverUrl"?: string;
|
||||
}
|
||||
interface ElsaSwitchEditor {
|
||||
"inputContext"?: NodeInputContext;
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaToolbox {
|
||||
"graph"?: Graph;
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ function walkRecursive(node: ActivityNode, activity: Activity, collectedActiviti
|
|||
function getPorts(node: ActivityNode, activity: Activity, descriptors: Array<ActivityDescriptor>): Array<ActivityPort> {
|
||||
const portProviderRegistry = Container.get(PortProviderRegistry);
|
||||
const transposeHandlerRegistry = Container.get(TransposeHandlerRegistry);
|
||||
const transposeHandler = transposeHandlerRegistry.get(activity.nodeType);
|
||||
const transposeHandler = transposeHandlerRegistry.get(activity.typeName);
|
||||
const portProvider = portProviderRegistry.get(activity.nodeType);
|
||||
const activityDescriptor = descriptors.find(x => x.nodeType == activity.nodeType);
|
||||
const activityDescriptor = descriptors.find(x => x.activityType == activity.typeName);
|
||||
const untransposedConnections = transposeHandler.untranspose({activity, activityDescriptor});
|
||||
return untransposedConnections.map(x => ({activity: x.target, port: x.sourcePort}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export class DefaultNodeHandler implements ActivityNodeHandler {
|
|||
|
||||
createDesignerNode(context: CreateUINodeContext): Node.Metadata {
|
||||
const {activityDescriptor, activity, x, y} = context;
|
||||
const provider = this.portProviderRegistry.get(activityDescriptor.nodeType);
|
||||
const provider = this.portProviderRegistry.get(activityDescriptor.activityType);
|
||||
const providerContext: PortProviderContext = {activityDescriptor, activity};
|
||||
let inPorts = provider.getInboundPorts(providerContext);
|
||||
let outPorts = provider.getOutboundPorts(providerContext);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
|
||||
const activity: Activity = {
|
||||
id: uuid(),
|
||||
nodeType: descriptor.nodeType,
|
||||
typeName: descriptor.activityType,
|
||||
metadata: {
|
||||
designer: {
|
||||
position: {
|
||||
|
|
@ -161,9 +161,9 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
for (const connection of connections) {
|
||||
const source = activities.find(x => x.id == connection.source);
|
||||
const target = activities.find(x => x.id == connection.target);
|
||||
const sourceDescriptor = activityDescriptors.find(x => x.nodeType == source.nodeType);
|
||||
const targetDescriptor = activityDescriptors.find(x => x.nodeType == target.nodeType);
|
||||
const transposeHandler = transposeHandlerRegistry.get(source.nodeType);
|
||||
const sourceDescriptor = activityDescriptors.find(x => x.activityType == source.typeName);
|
||||
const targetDescriptor = activityDescriptors.find(x => x.activityType == target.typeName);
|
||||
const transposeHandler = transposeHandlerRegistry.get(source.typeName);
|
||||
|
||||
if (transposeHandler.transpose({source, target, connection, sourceDescriptor, targetDescriptor})) {
|
||||
// Remove the target activity from the list.
|
||||
|
|
@ -175,7 +175,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
}
|
||||
|
||||
return {
|
||||
nodeType: 'Workflows.Flowchart',
|
||||
typeName: 'Workflows.Flowchart',
|
||||
activities: remainingActivities,
|
||||
connections: remainingConnections,
|
||||
id: this.rootId,
|
||||
|
|
@ -207,7 +207,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
const activity = activityNode.activity;
|
||||
const position = activity.metadata.designer?.position || {x: 100, y: 100};
|
||||
const {x, y} = position;
|
||||
const descriptor = descriptors.find(x => x.nodeType == activity.nodeType)
|
||||
const descriptor = descriptors.find(x => x.activityType == activity.typeName)
|
||||
return this.nodeFactory.createNode(descriptor, activity, x, y);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export class NodeFactory {
|
|||
}
|
||||
|
||||
public createNode(activityDescriptor: ActivityDescriptor, activity: Activity, x: number, y: number): Node.Metadata {
|
||||
const handler = this.handlerRegistry.createHandler(activityDescriptor.nodeType);
|
||||
const handler = this.handlerRegistry.createHandler(activityDescriptor.activityType);
|
||||
return handler.createDesignerNode({activityDescriptor, activity, x, y});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export class ActivityNode extends Shape.HTML {
|
|||
createHtml() {
|
||||
const activityDescriptor = this.activityDescriptor as ActivityDescriptor;
|
||||
const activity = this.activity as Activity;
|
||||
const activityType = activityDescriptor.nodeType;
|
||||
const activityType = activityDescriptor.activityType;
|
||||
const driverRegistry = Container.get(ActivityDriverRegistry);
|
||||
const driver = driverRegistry.createDriver(activityType);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ import {
|
|||
Activity,
|
||||
ActivityDescriptor,
|
||||
DefaultActions, InputDescriptor,
|
||||
RenderNodePropContext,
|
||||
RenderNodePropsContext,
|
||||
RenderActivityPropContext,
|
||||
RenderActivityPropsContext,
|
||||
TabChangedArgs,
|
||||
TabDefinition
|
||||
} from '../../../models';
|
||||
import {InputDriverRegistry} from "../../../services";
|
||||
import {Container} from "typedi";
|
||||
import {NodeInputContext} from "../../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../../services/node-input-driver";
|
||||
import {FormEntry} from "../../shared/forms/form-entry";
|
||||
|
||||
export interface ActivityUpdatedArgs {
|
||||
|
|
@ -31,7 +31,7 @@ export interface DeleteActivityRequestedArgs {
|
|||
})
|
||||
export class ActivityPropertiesEditor {
|
||||
private slideOverPanel: HTMLElsaSlideOverPanelElement;
|
||||
private renderContext: RenderNodePropsContext;
|
||||
private renderContext: RenderActivityPropsContext;
|
||||
private readonly inputDriverRegistry: InputDriverRegistry;
|
||||
|
||||
constructor() {
|
||||
|
|
@ -58,11 +58,11 @@ export class ActivityPropertiesEditor {
|
|||
public componentWillRender() {
|
||||
const activity = this.activity;
|
||||
const activityDescriptor = this.findActivityDescriptor();
|
||||
const title = activityDescriptor?.displayName ?? activityDescriptor?.nodeType ?? 'Unknown Activity';
|
||||
const title = activityDescriptor?.displayName ?? activityDescriptor?.activityType ?? 'Unknown Activity';
|
||||
const driverRegistry = this.inputDriverRegistry;
|
||||
|
||||
const renderPropertyContexts: Array<RenderNodePropContext> = activityDescriptor.inputProperties.map(inputDescriptor => {
|
||||
const renderInputContext: NodeInputContext = {
|
||||
const renderPropertyContexts: Array<RenderActivityPropContext> = activityDescriptor.inputProperties.map(inputDescriptor => {
|
||||
const renderInputContext: ActivityInputContext = {
|
||||
node: activity,
|
||||
nodeDescriptor: activityDescriptor,
|
||||
inputDescriptor,
|
||||
|
|
@ -80,15 +80,15 @@ export class ActivityPropertiesEditor {
|
|||
});
|
||||
|
||||
this.renderContext = {
|
||||
node: activity,
|
||||
nodeDescriptor: activityDescriptor,
|
||||
activity,
|
||||
activityDescriptor,
|
||||
title,
|
||||
properties: renderPropertyContexts
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {nodeDescriptor, title} = this.renderContext;
|
||||
const {activityDescriptor, title} = this.renderContext;
|
||||
|
||||
const propertiesTab: TabDefinition = {
|
||||
displayText: 'Properties',
|
||||
|
|
@ -100,7 +100,7 @@ export class ActivityPropertiesEditor {
|
|||
content: () => this.renderCommonTab()
|
||||
};
|
||||
|
||||
const tabs = !!nodeDescriptor ? [propertiesTab, commonTab] : [];
|
||||
const tabs = !!activityDescriptor ? [propertiesTab, commonTab] : [];
|
||||
const actions = [DefaultActions.Delete(this.onDeleteActivity)];
|
||||
|
||||
return (
|
||||
|
|
@ -111,7 +111,7 @@ export class ActivityPropertiesEditor {
|
|||
);
|
||||
}
|
||||
|
||||
private findActivityDescriptor = (): ActivityDescriptor => !!this.activity ? this.activityDescriptors.find(x => x.nodeType == this.activity.nodeType) : null;
|
||||
private findActivityDescriptor = (): ActivityDescriptor => !!this.activity ? this.activityDescriptors.find(x => x.activityType == this.activity.typeName) : null;
|
||||
private onSelectedTabIndexChanged = (e: CustomEvent<TabChangedArgs>) => this.selectedTabIndex = e.detail.selectedTabIndex
|
||||
|
||||
private onActivityIdChanged = (e: any) => {
|
||||
|
|
@ -148,8 +148,8 @@ export class ActivityPropertiesEditor {
|
|||
private onDeleteActivity = () => this.deleteActivityRequested.emit({activity: this.activity});
|
||||
|
||||
private renderPropertiesTab = () => {
|
||||
const {node, properties} = this.renderContext;
|
||||
const activityId = node.id;
|
||||
const {activity, properties} = this.renderContext;
|
||||
const activityId = activity.id;
|
||||
|
||||
return <div>
|
||||
<FormEntry fieldId="ActivityId" label="ID" hint="The ID of the activity.">
|
||||
|
|
@ -157,7 +157,7 @@ export class ActivityPropertiesEditor {
|
|||
</FormEntry>
|
||||
|
||||
{properties.filter(x => !!x.inputControl).map(propertyContext => {
|
||||
const key = `${node.id}-${propertyContext.inputContext.inputDescriptor.name}`;
|
||||
const key = `${activity.id}-${propertyContext.inputContext.inputDescriptor.name}`;
|
||||
return <div key={key}>
|
||||
{propertyContext.inputControl}
|
||||
</div>;
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ export class ToolboxActivities {
|
|||
const activityDriverRegistry = Container.get(ActivityDriverRegistry);
|
||||
|
||||
for (const activityDescriptor of value) {
|
||||
const nodeType = activityDescriptor.nodeType;
|
||||
const driver = activityDriverRegistry.createDriver(nodeType);
|
||||
const activityType = activityDescriptor.activityType;
|
||||
const driver = activityDriverRegistry.createDriver(activityType);
|
||||
const html = driver.display({displayType: 'picker', activityDescriptor: activityDescriptor});
|
||||
|
||||
renderedActivities.set(nodeType, html);
|
||||
renderedActivities.set(activityType, html);
|
||||
}
|
||||
|
||||
this.renderedActivities = renderedActivities;
|
||||
|
|
@ -108,7 +108,7 @@ export class ToolboxActivities {
|
|||
<div class={`space-y-1 ${categoryContentClass}`}>
|
||||
|
||||
{activityDescriptors.map(activityDescriptor => {
|
||||
const activityHtml = renderedActivities.get(activityDescriptor.nodeType);
|
||||
const activityHtml = renderedActivities.get(activityDescriptor.activityType);
|
||||
return (
|
||||
<div class="w-full flex items-center pl-10 pr-2 py-2">
|
||||
<div class="cursor-move"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {Component, h, Prop, State} from '@stencil/core';
|
||||
import {uniq} from 'lodash'
|
||||
import {JsonExpression, LiteralExpression, SelectList, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getSelectListItems, getInputPropertyValue, parseJson} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
export class CheckList {
|
||||
private selectList: SelectList = {items: [], isFlagsEnum: false};
|
||||
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
@State() private selectedValues?: Array<string> = [];
|
||||
@State() private selectedValue?: number;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, h, Prop} from '@stencil/core';
|
||||
import {EditorHeight, LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue} from "../../utils";
|
||||
import {MonacoValueChangedArgs} from "../shared/monaco-editor/monaco-editor";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
|
@ -16,7 +16,7 @@ interface CodeEditorOptions {
|
|||
shadow: false
|
||||
})
|
||||
export class CodeEditorInput {
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
|
||||
public render() {
|
||||
const inputContext = this.inputContext;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, Prop, h} from '@stencil/core';
|
||||
import {LiteralExpression, SelectList, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue, getSelectListItems} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
shadow: false
|
||||
})
|
||||
export class SingleLineInput {
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
|
||||
private selectList: SelectList = {items: [], isFlagsEnum: false};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, Prop, h} from '@stencil/core';
|
||||
import {LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
shadow: false
|
||||
})
|
||||
export class MultiLineInput {
|
||||
@Prop() inputContext: NodeInputContext;
|
||||
@Prop() inputContext: ActivityInputContext;
|
||||
|
||||
public render() {
|
||||
const inputContext = this.inputContext;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, Prop, h} from '@stencil/core';
|
||||
import {JsonExpression, LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue, parseJson} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
shadow: false
|
||||
})
|
||||
export class MultiTextInput {
|
||||
@Prop() inputContext: NodeInputContext;
|
||||
@Prop() inputContext: ActivityInputContext;
|
||||
|
||||
public render() {
|
||||
const inputContext = this.inputContext;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, h, Prop, State} from '@stencil/core';
|
||||
import {LiteralExpression, SelectList, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getSelectListItems, getInputPropertyValue} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
export class RadioList {
|
||||
private selectList: SelectList = {items: [], isFlagsEnum: false};
|
||||
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
@State() private selectedValue?: string;
|
||||
|
||||
public async componentWillLoad() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, h, Prop} from '@stencil/core';
|
||||
import {LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
shadow: false
|
||||
})
|
||||
export class SingleLineInput {
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
|
||||
public render() {
|
||||
const inputContext = this.inputContext;
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ export class DefaultActivityDriver implements ActivityDriver {
|
|||
display(context: ActivityDisplayContext): any {
|
||||
const iconRegistry = this.iconRegistry;
|
||||
const activityDescriptor = context.activityDescriptor;
|
||||
const nodeType = activityDescriptor.nodeType;
|
||||
const activityType = activityDescriptor.activityType;
|
||||
const text = activityDescriptor?.displayName;
|
||||
const isTrigger = (activityDescriptor?.traits & ActivityTraits.Trigger) == ActivityTraits.Trigger;
|
||||
const borderColor = isTrigger ? 'border-green-600' : 'border-blue-600';
|
||||
const backgroundColor = isTrigger ? 'bg-green-400' : 'bg-blue-400';
|
||||
const iconBackgroundColor = isTrigger ? 'bg-green-500' : 'bg-blue-500';
|
||||
const icon = iconRegistry.has(nodeType) ? iconRegistry.get(nodeType) : null;
|
||||
const icon = iconRegistry.has(activityType) ? iconRegistry.get(activityType) : null;
|
||||
|
||||
return (`
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {NodeInputDriver, NodeInputContext} from "../../services/node-input-driver";
|
||||
import {NodeInputDriver, ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {Container} from "typedi";
|
||||
import {InputControlRegistry} from "../../services/input-control-registry";
|
||||
import {h} from "@stencil/core";
|
||||
|
|
@ -16,14 +16,14 @@ export class DefaultInputDriver implements NodeInputDriver {
|
|||
return -1;
|
||||
}
|
||||
|
||||
renderInput(context: NodeInputContext): any {
|
||||
renderInput(context: ActivityInputContext): any {
|
||||
const inputDescriptor = context.inputDescriptor;
|
||||
const uiHint = inputDescriptor.uiHint;
|
||||
const inputControl = this.inputControlRegistry.get(uiHint);
|
||||
return inputControl(context);
|
||||
}
|
||||
|
||||
supportsInput(context: NodeInputContext): boolean {
|
||||
supportsInput(context: ActivityInputContext): boolean {
|
||||
const uiHint = context.inputDescriptor.uiHint;
|
||||
return this.inputControlRegistry.has(uiHint);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,11 @@ export interface ActivityDescriptorResponse {
|
|||
activityDescriptors: Array<ActivityDescriptor>;
|
||||
}
|
||||
|
||||
export interface NodeDescriptor {
|
||||
nodeType: string;
|
||||
export interface ActivityDescriptor {
|
||||
activityType: string;
|
||||
displayName: string;
|
||||
category: string;
|
||||
inputProperties: Array<InputDescriptor>
|
||||
}
|
||||
|
||||
export interface ActivityDescriptor extends NodeDescriptor {
|
||||
traits: ActivityTraits;
|
||||
inPorts: Array<Port>;
|
||||
outPorts: Array<Port>;
|
||||
|
|
@ -23,7 +20,7 @@ export enum ActivityTraits {
|
|||
Trigger = 2
|
||||
}
|
||||
|
||||
export interface NodePropertyDescriptor {
|
||||
export interface PropertyDescriptor {
|
||||
name: string;
|
||||
type: Type;
|
||||
displayName?: string;
|
||||
|
|
@ -32,7 +29,7 @@ export interface NodePropertyDescriptor {
|
|||
isBrowsable?: boolean;
|
||||
}
|
||||
|
||||
export interface InputDescriptor extends NodePropertyDescriptor {
|
||||
export interface InputDescriptor extends PropertyDescriptor {
|
||||
uiHint?: string;
|
||||
options?: any;
|
||||
category?: string;
|
||||
|
|
@ -42,7 +39,7 @@ export interface InputDescriptor extends NodePropertyDescriptor {
|
|||
isReadOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface OutputDescriptor extends NodePropertyDescriptor {
|
||||
export interface OutputDescriptor extends PropertyDescriptor {
|
||||
}
|
||||
|
||||
export interface Port {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,14 @@ import {Type} from "./shared";
|
|||
import {Expression} from "./expressions";
|
||||
import {VersionOptions} from "./api";
|
||||
|
||||
export interface Node {
|
||||
export interface Activity {
|
||||
id: string;
|
||||
nodeType: string;
|
||||
typeName: string;
|
||||
metadata: any;
|
||||
|
||||
[name: string]: any;
|
||||
}
|
||||
|
||||
export interface Activity extends Node {
|
||||
}
|
||||
|
||||
export interface Trigger extends Activity {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Activity, Node} from "./core";
|
||||
import {ActivityDescriptor, InputDescriptor, NodeDescriptor} from "./api";
|
||||
import {NodeInputContext} from "../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../services/node-input-driver";
|
||||
import {Activity} from "./core";
|
||||
import {ActivityDescriptor} from "./api";
|
||||
|
||||
export interface TabDefinition {
|
||||
displayText: string;
|
||||
|
|
@ -66,15 +66,15 @@ export class DefaultActions {
|
|||
});
|
||||
}
|
||||
|
||||
export interface RenderNodePropsContext {
|
||||
node: Node;
|
||||
nodeDescriptor: NodeDescriptor;
|
||||
export interface RenderActivityPropsContext {
|
||||
activity: Activity;
|
||||
activityDescriptor: ActivityDescriptor;
|
||||
title: string;
|
||||
properties: Array<RenderNodePropContext>;
|
||||
properties: Array<RenderActivityPropContext>;
|
||||
}
|
||||
|
||||
export interface RenderNodePropContext {
|
||||
inputContext: NodeInputContext
|
||||
export interface RenderActivityPropContext {
|
||||
inputContext: ActivityInputContext
|
||||
inputControl?: any;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, h, Prop, State} from "@stencil/core";
|
||||
import {camelCase} from 'lodash';
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {mapSyntaxToLanguage} from "../../utils";
|
||||
import {SyntaxNames} from "../../models";
|
||||
import {SwitchCase} from "./models";
|
||||
|
|
@ -14,7 +14,7 @@ import {FormEntry} from "../../components/shared/forms/form-entry";
|
|||
shadow: false
|
||||
})
|
||||
export class SwitchEditor {
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
@State() private cases: Array<SwitchCase> = [];
|
||||
private supportedSyntaxes: Array<string> = [SyntaxNames.JavaScript, SyntaxNames.Literal];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import {Service} from 'typedi';
|
||||
import {NodeInputDriver, NodeInputContext} from './node-input-driver';
|
||||
import {NodeInputDriver, ActivityInputContext} from './node-input-driver';
|
||||
import {DefaultInputDriver} from "../drivers/input/default-input-driver";
|
||||
|
||||
@Service()
|
||||
|
|
@ -12,7 +12,7 @@ export class InputDriverRegistry {
|
|||
this.drivers = _.orderBy(drivers, x => x.priority, 'desc');
|
||||
}
|
||||
|
||||
public get(context: NodeInputContext): NodeInputDriver {
|
||||
public get(context: ActivityInputContext): NodeInputDriver {
|
||||
return this.drivers.find(x => x.supportsInput(context));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import {InputDescriptor, NodeDescriptor, Node} from "../models";
|
||||
import {Activity, ActivityDescriptor, InputDescriptor} from "../models";
|
||||
|
||||
export interface NodeInputContext {
|
||||
node: Node;
|
||||
nodeDescriptor: NodeDescriptor;
|
||||
export interface ActivityInputContext {
|
||||
node: Activity;
|
||||
nodeDescriptor: ActivityDescriptor;
|
||||
inputDescriptor: InputDescriptor;
|
||||
notifyInputChanged: () => void;
|
||||
inputChanged: (value: any, syntax: string) => void;
|
||||
}
|
||||
|
||||
export interface NodeInputDriver {
|
||||
supportsInput(context: NodeInputContext): boolean;
|
||||
supportsInput(context: ActivityInputContext): boolean;
|
||||
|
||||
get priority(): number;
|
||||
|
||||
renderInput(context: NodeInputContext): any;
|
||||
renderInput(context: ActivityInputContext): any;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import moment from 'moment';
|
||||
import {camelCase} from 'lodash';
|
||||
import {ActivityInput, VersionOptions} from '../models';
|
||||
import {NodeInputContext} from '../services/node-input-driver';
|
||||
import {ActivityInputContext} from '../services/node-input-driver';
|
||||
|
||||
export function formatTimestamp(timestamp?: Date, defaultText?: string): string {
|
||||
return !!timestamp ? moment(timestamp).format('DD-MM-YYYY HH:mm:ss') : defaultText;
|
||||
|
|
@ -50,13 +50,13 @@ export const mapSyntaxToLanguage = (syntax: string): string => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getInputPropertyName = (inputContext: NodeInputContext) => {
|
||||
export const getInputPropertyName = (inputContext: ActivityInputContext) => {
|
||||
const inputProperty = inputContext.inputDescriptor;
|
||||
const propertyName = inputProperty.name;
|
||||
return camelCase(propertyName);
|
||||
}
|
||||
|
||||
export const getInputPropertyValue = (inputContext: NodeInputContext): ActivityInput => {
|
||||
export const getInputPropertyValue = (inputContext: ActivityInputContext): ActivityInput => {
|
||||
const propName = getInputPropertyName(inputContext);
|
||||
return inputContext.node[propName] as ActivityInput;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class WorkflowBookmarkScheduler : IWorkflowBookmarkScheduler
|
|||
var resumeAt = payload.ResumeAt;
|
||||
var job = new ResumeWorkflowJob(workflowInstanceId, bookmark.ToBookmark());
|
||||
var schedule = new SpecificInstantSchedule(resumeAt);
|
||||
await _jobScheduler.ScheduleAsync(job, schedule, groupKeys, cancellationToken);
|
||||
await _jobScheduler.ScheduleAsync(job, bookmark.Id, schedule, groupKeys, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +50,7 @@ public class WorkflowBookmarkScheduler : IWorkflowBookmarkScheduler
|
|||
|
||||
foreach (var bookmark in delayBookmarks)
|
||||
{
|
||||
var job = new ResumeWorkflowJob(workflowInstanceId, bookmark.ToBookmark());
|
||||
await _jobScheduler.UnscheduleAsync(job, cancellationToken);
|
||||
await _jobScheduler.UnscheduleAsync(bookmark.Id, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ public class WorkflowTriggerScheduler : IWorkflowTriggerScheduler
|
|||
// Schedule trigger.
|
||||
var (dateTime, timeSpan) = JsonSerializer.Deserialize<TimerPayload>(trigger.Data!)!;
|
||||
var groupKeys = new[] { RootGroupKey, trigger.WorkflowDefinitionId };
|
||||
await _jobScheduler.ScheduleAsync(new RunWorkflowJob(trigger.WorkflowDefinitionId), new RecurringSchedule(dateTime, timeSpan), groupKeys, cancellationToken);
|
||||
await _jobScheduler.ScheduleAsync(new RunWorkflowJob(trigger.WorkflowDefinitionId), trigger.WorkflowDefinitionId, new RecurringSchedule(dateTime, timeSpan), groupKeys, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Contracts;
|
||||
using Elsa.Models;
|
||||
|
|
@ -11,6 +12,20 @@ namespace Elsa.Modules.Scheduling.Triggers;
|
|||
/// </summary>
|
||||
public class Timer : EventGenerator
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Timer()
|
||||
{
|
||||
}
|
||||
|
||||
public Timer(TimeSpan interval) : this(new Input<TimeSpan>(interval))
|
||||
{
|
||||
}
|
||||
|
||||
public Timer(Input<TimeSpan> interval)
|
||||
{
|
||||
Interval = interval;
|
||||
}
|
||||
|
||||
[Input] public Input<TimeSpan> Interval { get; set; } = default!;
|
||||
|
||||
protected override IEnumerable<object> GetTriggerData(TriggerIndexingContext context)
|
||||
|
|
@ -20,6 +35,9 @@ public class Timer : EventGenerator
|
|||
var executeAt = clock.UtcNow.Add(interval);
|
||||
yield return new TimerPayload(executeAt, interval);
|
||||
}
|
||||
|
||||
public static Timer FromTimeSpan(TimeSpan value) => new(value);
|
||||
public static Timer FromSeconds(double value) => FromTimeSpan(TimeSpan.FromSeconds(value));
|
||||
}
|
||||
|
||||
public record TimerPayload(DateTimeOffset StartAt, TimeSpan Interval);
|
||||
|
|
@ -31,8 +31,8 @@ public class PersistWorkflowExecutionLogMiddleware : WorkflowExecutionMiddleware
|
|||
var entries = context.ExecutionLog.Select(x => new WorkflowExecutionLogRecord
|
||||
{
|
||||
Id = _identityGenerator.GenerateId(),
|
||||
ActivityId = x.NodeId,
|
||||
ActivityType = x.NodeType,
|
||||
ActivityId = x.ActivityId,
|
||||
ActivityType = x.ActivityType,
|
||||
Message = x.Message,
|
||||
EventName = x.EventName,
|
||||
WorkflowInstanceId = context.Id,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ services
|
|||
.AddProtoActorWorkflowHost()
|
||||
.IndexWorkflowTriggers()
|
||||
.AddElsaManagement()
|
||||
.AddJobs(new QuartzJobSchedulerProvider(), new HangfireJobQueueProvider())
|
||||
.AddJobServices(new QuartzJobSchedulerProvider(), new HangfireJobQueueProvider())
|
||||
.AddHttpActivityServices()
|
||||
.AddJobServices()
|
||||
.AddAzureServiceBusServices(options => configuration.GetSection("AzureServiceBus").Bind(options))
|
||||
|
|
@ -53,6 +53,7 @@ services
|
|||
{
|
||||
// Register workflows.
|
||||
options.Workflows.Add(nameof(HelloWorldWorkflow), new HelloWorldWorkflow());
|
||||
options.Workflows.Add(nameof(HeartbeatWorkflow), new HeartbeatWorkflow());
|
||||
options.Workflows.Add(nameof(HttpWorkflow), new HttpWorkflow());
|
||||
options.Workflows.Add(nameof(ForkedHttpWorkflow), new ForkedHttpWorkflow());
|
||||
options.Workflows.Add(nameof(CompositeActivitiesWorkflow), new CompositeActivitiesWorkflow());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using Elsa.Activities.Console;
|
||||
using Elsa.Activities.Workflows;
|
||||
using Elsa.Contracts;
|
||||
using Elsa.Modules.Scheduling.Triggers;
|
||||
using Elsa.Runtime.Contracts;
|
||||
|
||||
namespace Elsa.Samples.Web1.Workflows;
|
||||
|
||||
public class HeartbeatWorkflow : IWorkflow
|
||||
{
|
||||
public void Build(IWorkflowDefinitionBuilder workflow)
|
||||
{
|
||||
workflow.WithRoot(new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Timer(TimeSpan.FromSeconds(10))
|
||||
{
|
||||
CanStartWorkflow = true
|
||||
},
|
||||
new WriteLine(context => $"Heartbeat at {context.GetRequiredService<ISystemClock>().UtcNow}")
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue