diff --git a/src/bundles/Elsa.WorkflowServer.Web/Program.cs b/src/bundles/Elsa.WorkflowServer.Web/Program.cs index ca7ebbf62..73ba9740c 100644 --- a/src/bundles/Elsa.WorkflowServer.Web/Program.cs +++ b/src/bundles/Elsa.WorkflowServer.Web/Program.cs @@ -40,7 +40,7 @@ services .UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString))) .UseWorkflowRuntime(runtime => { - runtime.UseProtoActor(proto => proto.PersistenceProvider = _ => new SqliteProvider(new SqliteConnectionStringBuilder(sqliteConnectionString))); + //runtime.UseProtoActor(proto => proto.PersistenceProvider = _ => new SqliteProvider(new SqliteConnectionStringBuilder(sqliteConnectionString))); runtime.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)); runtime.UseAsyncWorkflowStateExporter(); }) diff --git a/src/designer/elsa-workflows-designer/src/components.d.ts b/src/designer/elsa-workflows-designer/src/components.d.ts index b7288eb1d..3db2892ec 100644 --- a/src/designer/elsa-workflows-designer/src/components.d.ts +++ b/src/designer/elsa-workflows-designer/src/components.d.ts @@ -243,6 +243,11 @@ export namespace Components { interface ElsaVariablesEditor { "variables"?: Array; } + interface ElsaVariablesViewer { + "variables"?: Array; + "workflowDefinition": WorkflowDefinition; + "workflowInstance": WorkflowInstance; + } interface ElsaWidgets { "widgets": Array; } @@ -692,6 +697,12 @@ declare global { prototype: HTMLElsaVariablesEditorElement; new (): HTMLElsaVariablesEditorElement; }; + interface HTMLElsaVariablesViewerElement extends Components.ElsaVariablesViewer, HTMLStencilElement { + } + var HTMLElsaVariablesViewerElement: { + prototype: HTMLElsaVariablesViewerElement; + new (): HTMLElsaVariablesViewerElement; + }; interface HTMLElsaWidgetsElement extends Components.ElsaWidgets, HTMLStencilElement { } var HTMLElsaWidgetsElement: { @@ -832,6 +843,7 @@ declare global { "elsa-variable-editor-dialog-content": HTMLElsaVariableEditorDialogContentElement; "elsa-variable-picker-input": HTMLElsaVariablePickerInputElement; "elsa-variables-editor": HTMLElsaVariablesEditorElement; + "elsa-variables-viewer": HTMLElsaVariablesViewerElement; "elsa-widgets": HTMLElsaWidgetsElement; "elsa-workflow-definition-browser": HTMLElsaWorkflowDefinitionBrowserElement; "elsa-workflow-definition-editor": HTMLElsaWorkflowDefinitionEditorElement; @@ -1070,6 +1082,11 @@ declare namespace LocalJSX { "onVariablesChanged"?: (event: ElsaVariablesEditorCustomEvent>) => void; "variables"?: Array; } + interface ElsaVariablesViewer { + "variables"?: Array; + "workflowDefinition"?: WorkflowDefinition; + "workflowInstance"?: WorkflowInstance; + } interface ElsaWidgets { "widgets"?: Array; } @@ -1185,6 +1202,7 @@ declare namespace LocalJSX { "elsa-variable-editor-dialog-content": ElsaVariableEditorDialogContent; "elsa-variable-picker-input": ElsaVariablePickerInput; "elsa-variables-editor": ElsaVariablesEditor; + "elsa-variables-viewer": ElsaVariablesViewer; "elsa-widgets": ElsaWidgets; "elsa-workflow-definition-browser": ElsaWorkflowDefinitionBrowser; "elsa-workflow-definition-editor": ElsaWorkflowDefinitionEditor; @@ -1250,6 +1268,7 @@ declare module "@stencil/core" { "elsa-variable-editor-dialog-content": LocalJSX.ElsaVariableEditorDialogContent & JSXBase.HTMLAttributes; "elsa-variable-picker-input": LocalJSX.ElsaVariablePickerInput & JSXBase.HTMLAttributes; "elsa-variables-editor": LocalJSX.ElsaVariablesEditor & JSXBase.HTMLAttributes; + "elsa-variables-viewer": LocalJSX.ElsaVariablesViewer & JSXBase.HTMLAttributes; "elsa-widgets": LocalJSX.ElsaWidgets & JSXBase.HTMLAttributes; "elsa-workflow-definition-browser": LocalJSX.ElsaWorkflowDefinitionBrowser & JSXBase.HTMLAttributes; "elsa-workflow-definition-editor": LocalJSX.ElsaWorkflowDefinitionEditor & JSXBase.HTMLAttributes; diff --git a/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-viewer.tsx b/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-viewer.tsx new file mode 100644 index 000000000..1d6702ad5 --- /dev/null +++ b/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-viewer.tsx @@ -0,0 +1,68 @@ +import {Component, Event, EventEmitter, h, Prop, State, Watch} from "@stencil/core"; +import {DeleteIcon, EditIcon} from "../../icons/tooling"; +import {StorageDriverDescriptor, Variable, WorkflowInstance} from "../../../models"; +import descriptorsStore from "../../../data/descriptors-store"; +import {ModalActionClickArgs, ModalActionDefinition, ModalActionType, ModalDialogInstance, ModalDialogService} from "../../shared/modal-dialog"; +import {Container} from "typedi"; +import {WorkflowDefinition} from "../../../modules/workflow-definitions/models/entities"; + +@Component({ + tag: 'elsa-variables-viewer', + shadow: false +}) +export class VariablesViewer { + + @Prop() variables?: Array; + @Prop() workflowDefinition: WorkflowDefinition; + @Prop() workflowInstance: WorkflowInstance; + + render() { + const variables = this.variables; + const storageDrivers: Array = descriptorsStore.storageDrivers; + + return ( +
+
+ + + + + + + + + + + {variables.map(variable => { + const storage = storageDrivers.find(x => x.typeName == variable.storageDriverTypeName); + const storageName = storage?.displayName ?? '-'; + const descriptor = descriptorsStore.variableDescriptors.find(x => x.typeName == variable.typeName); + const typeDisplayName = descriptor?.displayName ?? variable.typeName; + const variableValue = this.getVariableValue(variable, storage); + + return ( + + + + + + ); + } + )} + +
NameTypeStorageValue
{variable.name}{typeDisplayName}{storageName}{variableValue}
+
+
+ ); + } + + private getVariableValue(variable: Variable, storage: StorageDriverDescriptor) : any { + if(storage.typeName !== 'Elsa.Workflows.Core.Implementations.WorkflowStorageDriver, Elsa.Workflows.Core') + return null; + + const workflowInstance = this.workflowInstance; + const persistentVariables = workflowInstance.properties.PersistentVariablesDictionary; + const key = `${workflowInstance.id}:Workflow1:${variable.name}`; + return persistentVariables[key]; + } +} diff --git a/src/designer/elsa-workflows-designer/src/components/shared/forms/info-list.tsx b/src/designer/elsa-workflows-designer/src/components/shared/forms/info-list.tsx index 4d86db2fd..c6a37b28b 100644 --- a/src/designer/elsa-workflows-designer/src/components/shared/forms/info-list.tsx +++ b/src/designer/elsa-workflows-designer/src/components/shared/forms/info-list.tsx @@ -17,12 +17,12 @@ export const InfoList: FunctionalComponent = ({ title, dictionary
-

{title}

+

{title}

-
+
{entries.map(([k, v]) => ( -
+
{k}
{v} diff --git a/src/designer/elsa-workflows-designer/src/models/api.ts b/src/designer/elsa-workflows-designer/src/models/api.ts index b5bd4c667..4f300eb2a 100644 --- a/src/designer/elsa-workflows-designer/src/models/api.ts +++ b/src/designer/elsa-workflows-designer/src/models/api.ts @@ -42,7 +42,7 @@ export interface WorkflowInstanceSummary { } export interface WorkflowInstance extends WorkflowInstanceSummary { - workflowState: WorkflowState; + properties: any; } export interface PagedList { diff --git a/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx b/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx index 9560e8644..0b66a6ce8 100644 --- a/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx @@ -56,6 +56,7 @@ export class DefaultActivityTemplate { const hasEmbeddedPorts = embeddedPorts.length > 0; const canStartWorkflow = activity?.canStartWorkflow; const icon = this.icon; + const hasIcon = !!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'; @@ -95,7 +96,7 @@ export class DefaultActivityTemplate {
-
+
{this.renderIcon(icon)} {displayText}
@@ -146,16 +147,11 @@ export class DefaultActivityTemplate { private renderPort = (activity: Activity, port: Port) => { const canStartWorkflow = activity?.canStartWorkflow == true; - const textColor = canStartWorkflow ? 'text-white' : 'text-gray-700'; + const displayTextClass = canStartWorkflow ? 'text-white' : 'text-gray-600'; const borderColor = port.name == this.selectedPortName ? 'border-blue-600' : 'border-gray-300'; const activityDescriptor = this.activityDescriptor; const portProvider = this.portProviderRegistry.get(activityDescriptor.typeName); const activityProperty = portProvider.resolvePort(port.name, {activity, activityDescriptor}) as Activity; - const childActivityDescriptor: ActivityDescriptor = activityProperty != null ? descriptorsStore.activityDescriptors.find(x => x.typeName == activityProperty.type) : null; - let childActivityDisplayText = activityProperty?.metadata?.displayText; - - if (isNullOrWhitespace(childActivityDisplayText)) - childActivityDisplayText = childActivityDescriptor?.displayName; const renderActivityProperty = () => { @@ -167,7 +163,7 @@ export class DefaultActivityTemplate { onMouseDown={e => e.stopPropagation()} class="text-gray-400 hover:text-gray-600">
- {port.displayName} + {port.displayName}
@@ -184,7 +180,7 @@ export class DefaultActivityTemplate { onClick={e => this.onEditChildActivityClick(e, activity, port)} onMouseDown={e => e.stopPropagation()}>
- {port.displayName} + {port.displayName}
@@ -199,7 +195,7 @@ export class DefaultActivityTemplate { onClick={e => this.onEditChildActivityClick(e, activity, port)} onMouseDown={e => e.stopPropagation()}>
- {port.displayName} + {port.displayName}
diff --git a/src/designer/elsa-workflows-designer/src/modules/workflow-instances/components/properties.tsx b/src/designer/elsa-workflows-designer/src/modules/workflow-instances/components/properties.tsx index 32a738b14..7ef54ab56 100644 --- a/src/designer/elsa-workflows-designer/src/modules/workflow-instances/components/properties.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/workflow-instances/components/properties.tsx @@ -1,5 +1,5 @@ import {Component, Event, EventEmitter, h, Method, Prop, State, Watch} from '@stencil/core'; -import {TabChangedArgs, WorkflowInstance} from '../../../models'; +import {TabChangedArgs, Variable, WorkflowInstance} from '../../../models'; import {InfoList} from "../../../components/shared/forms/info-list"; import {formatTimestamp, isNullOrWhitespace} from "../../../utils"; import {PropertiesTabModel, TabModel, WorkflowInstancePropertiesDisplayingArgs, WorkflowInstancePropertiesEventTypes, WorkflowInstancePropertiesViewerModel} from "../models"; @@ -147,8 +147,10 @@ export class WorkflowDefinitionPropertiesEditor { }; private renderVariablesTab = () => { + const variables: Array = this.workflowDefinition?.variables ?? []; + return
- TODO: Variables editor +
}; diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Elsa.EntityFrameworkCore.PostgreSql.csproj b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Elsa.EntityFrameworkCore.PostgreSql.csproj index 62c1e515c..068431fe6 100644 --- a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Elsa.EntityFrameworkCore.PostgreSql.csproj +++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Elsa.EntityFrameworkCore.PostgreSql.csproj @@ -12,10 +12,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -23,14 +24,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - diff --git a/src/modules/Elsa.EntityFrameworkCore.SqlServer/Elsa.EntityFrameworkCore.SqlServer.csproj b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Elsa.EntityFrameworkCore.SqlServer.csproj index 3a43cb149..8afb22c1e 100644 --- a/src/modules/Elsa.EntityFrameworkCore.SqlServer/Elsa.EntityFrameworkCore.SqlServer.csproj +++ b/src/modules/Elsa.EntityFrameworkCore.SqlServer/Elsa.EntityFrameworkCore.SqlServer.csproj @@ -12,7 +12,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/modules/Elsa.EntityFrameworkCore.Sqlite/Elsa.EntityFrameworkCore.Sqlite.csproj b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Elsa.EntityFrameworkCore.Sqlite.csproj index a26ee4a02..1c3519d70 100644 --- a/src/modules/Elsa.EntityFrameworkCore.Sqlite/Elsa.EntityFrameworkCore.Sqlite.csproj +++ b/src/modules/Elsa.EntityFrameworkCore.Sqlite/Elsa.EntityFrameworkCore.Sqlite.csproj @@ -13,8 +13,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/modules/Elsa.EntityFrameworkCore/Elsa.EntityFrameworkCore.csproj b/src/modules/Elsa.EntityFrameworkCore/Elsa.EntityFrameworkCore.csproj index bb12113bb..b9391ecdd 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Elsa.EntityFrameworkCore.csproj +++ b/src/modules/Elsa.EntityFrameworkCore/Elsa.EntityFrameworkCore.csproj @@ -19,9 +19,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs index 44540688a..080683a69 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs @@ -25,7 +25,6 @@ namespace Elsa.EntityFrameworkCore.Modules.Management public void Configure(EntityTypeBuilder builder) { builder.Ignore(x => x.WorkflowState); - builder.Ignore(x => x.Fault); builder.Property("Data"); builder.Property(x => x.Status).HasConversion>(); builder.Property(x => x.SubStatus).HasConversion>(); diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstanceStore.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstanceStore.cs index 13b1114ff..42b9aacd4 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstanceStore.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstanceStore.cs @@ -33,24 +33,30 @@ public class EFCoreWorkflowInstanceStore : IWorkflowInstanceStore public async Task FindByIdAsync(string id, CancellationToken cancellationToken = default) => await _store.FindAsync(x => x.Id == id, Load, cancellationToken); + /// public async Task SaveAsync(WorkflowInstance record, CancellationToken cancellationToken = default) => await _store.SaveAsync(record, Save, cancellationToken); + /// public async Task SaveManyAsync(IEnumerable records, CancellationToken cancellationToken = default) => await _store.SaveManyAsync(records, Save, cancellationToken); + /// public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) => await _store.DeleteWhereAsync(x => x.Id == id, cancellationToken) > 0; + /// public async Task DeleteManyAsync(IEnumerable ids, CancellationToken cancellationToken = default) { var idList = ids.ToList(); return await _store.DeleteWhereAsync(x => idList.Contains(x.Id), cancellationToken); } + /// public async Task DeleteManyByDefinitionIdAsync(string definitionId, CancellationToken cancellationToken = default) => await _store.DeleteWhereAsync(x => x.DefinitionId == definitionId, cancellationToken); + /// public async Task> FindManyAsync(FindWorkflowInstancesArgs args, CancellationToken cancellationToken = default) { var dbContext = await _store.CreateDbContextAsync(cancellationToken); @@ -94,9 +100,9 @@ public class EFCoreWorkflowInstanceStore : IWorkflowInstanceStore return await query.PaginateAsync(x => WorkflowInstanceSummary.FromInstance(x), pageArgs); } - public WorkflowInstance Save(ManagementElsaDbContext managementElsaDbContext, WorkflowInstance entity) + private WorkflowInstance Save(ManagementElsaDbContext managementElsaDbContext, WorkflowInstance entity) { - var data = new WorkflowInstanceState(entity.WorkflowState, entity.Fault); + var data = entity.WorkflowState; var options = _serializerOptionsProvider.CreatePersistenceOptions(ReferenceHandler.Preserve); var json = JsonSerializer.Serialize(data, options); @@ -104,39 +110,22 @@ public class EFCoreWorkflowInstanceStore : IWorkflowInstanceStore return entity; } - public WorkflowInstance? Load(ManagementElsaDbContext managementElsaDbContext, WorkflowInstance? entity) + private WorkflowInstance? Load(ManagementElsaDbContext managementElsaDbContext, WorkflowInstance? entity) { if (entity == null) return null; - var data = new WorkflowInstanceState(entity.WorkflowState, entity.Fault); + var data = entity.WorkflowState; var json = (string?)managementElsaDbContext.Entry(entity).Property("Data").CurrentValue; if (!string.IsNullOrWhiteSpace(json)) { var options = _serializerOptionsProvider.CreatePersistenceOptions(ReferenceHandler.Preserve); - data = JsonSerializer.Deserialize(json, options)!; + data = JsonSerializer.Deserialize(json, options)!; } - entity.WorkflowState = data.WorkflowState; - entity.Fault = data.Fault; + entity.WorkflowState = data; return entity; } - - private class WorkflowInstanceState - { - public WorkflowInstanceState() - { - } - - public WorkflowInstanceState(WorkflowState workflowState, WorkflowFaultState? fault) - { - WorkflowState = workflowState; - Fault = fault; - } - - public WorkflowState WorkflowState { get; init; } = default!; - public WorkflowFaultState? Fault { get; set; } - } } \ No newline at end of file diff --git a/src/modules/Elsa.Http/Handlers/DefaultHttpEndpointWorkflowFaultHandler.cs b/src/modules/Elsa.Http/Handlers/DefaultHttpEndpointWorkflowFaultHandler.cs index 2945f4ccd..1ef27a7c6 100644 --- a/src/modules/Elsa.Http/Handlers/DefaultHttpEndpointWorkflowFaultHandler.cs +++ b/src/modules/Elsa.Http/Handlers/DefaultHttpEndpointWorkflowFaultHandler.cs @@ -7,20 +7,25 @@ using Microsoft.AspNetCore.Http; namespace Elsa.Http.Handlers; // ReSharper disable once ClassWithVirtualMembersNeverInherited.Global +/// +/// A default fault handler that writes information about the fault to the . +/// public class DefaultHttpEndpointWorkflowFaultHandler : IHttpEndpointWorkflowFaultHandler { + /// public virtual async ValueTask HandleAsync(HttpEndpointFaultedWorkflowContext context) { var httpContext = context.HttpContext; var workflowInstance = context.WorkflowInstance; + var fault = workflowInstance.WorkflowState.Fault!; httpContext.Response.ContentType = MediaTypeNames.Application.Json; httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError; var faultedResponse = JsonSerializer.Serialize(new { - errorMessage = $"Workflow faulted at {workflowInstance.FaultedAt!} with error: {workflowInstance.Fault!.Message}", - exception = workflowInstance.Fault?.Exception, + errorMessage = $"Workflow faulted at {workflowInstance.FaultedAt!} with error: {fault.Message}", + exception = fault.Exception, workflow = new { name = workflowInstance.Name, diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Mappers.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Mappers.cs index b87ebb5c7..16c3d630d 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Mappers.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Mappers.cs @@ -20,7 +20,8 @@ public class WorkflowInstanceMapper : ResponseMapper SubStatus = e.SubStatus, CorrelationId = e.CorrelationId, Name = e.Name, - Fault = e.Fault, + Properties = e.WorkflowState.Properties, + Fault = e.WorkflowState.Fault, CancelledAt = e.CancelledAt, CreatedAt = e.CreatedAt, FaultedAt = e.FaultedAt, diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Models.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Models.cs index 1e9ce30fb..428e758d1 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Models.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Get/Models.cs @@ -19,6 +19,7 @@ public class Response public WorkflowSubStatus SubStatus { get; set; } public string? CorrelationId { get; set; } public string? Name { get; set; } + public PropertyBag Properties { get; set; } public WorkflowFaultState? Fault { get; set; } public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset? LastExecutedAt { get; set; } diff --git a/src/modules/Elsa.Workflows.Core/Activities/SetName.cs b/src/modules/Elsa.Workflows.Core/Activities/SetName.cs index 0eeaeab59..b42f41b26 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/SetName.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/SetName.cs @@ -6,19 +6,23 @@ using Elsa.Workflows.Core.Models; namespace Elsa.Workflows.Core.Activities; /// -/// Sets a transient property on the workflow execution context the specified name value. -/// This value is used by the component to update the name of the workflow instance. +/// Sets a property on the workflow execution context with the specified name value. /// [Activity("Elsa", "Workflows", "Set the name of the workflow instance to a specified value.")] public class SetName : Activity { - internal static readonly object WorkflowInstanceNameKey = new(); + /// + /// The property key name used to store the workflow instance name. + /// + public const string WorkflowInstanceNameKey = "WorkflowInstanceName"; + /// [JsonConstructor] public SetName([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line) { } + /// public SetName(Input value, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) { Value = value; @@ -29,9 +33,10 @@ public class SetName : Activity /// public Input Value { get; set; } = new(""); + /// protected override void Execute(ActivityExecutionContext context) { var value = context.Get(Value); - context.WorkflowExecutionContext.TransientProperties[WorkflowInstanceNameKey] = value!; + context.WorkflowExecutionContext.SetProperty(WorkflowInstanceNameKey, value!); } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Implementations/WorkflowStateSerializer.cs b/src/modules/Elsa.Workflows.Core/Implementations/WorkflowStateSerializer.cs index d01246547..b5a83cd5b 100644 --- a/src/modules/Elsa.Workflows.Core/Implementations/WorkflowStateSerializer.cs +++ b/src/modules/Elsa.Workflows.Core/Implementations/WorkflowStateSerializer.cs @@ -49,7 +49,7 @@ public class WorkflowStateSerializer : IWorkflowStateSerializer private void DeserializeProperties(WorkflowState state, WorkflowExecutionContext workflowExecutionContext) { - workflowExecutionContext.Properties = state.Properties.Properties; + workflowExecutionContext.Properties = state.Properties.Dictionary; } private static void DeserializeCompletionCallbacks(WorkflowState state, WorkflowExecutionContext workflowExecutionContext) diff --git a/src/modules/Elsa.Workflows.Core/Models/ActivityExecutionContext.cs b/src/modules/Elsa.Workflows.Core/Models/ActivityExecutionContext.cs index 175133933..73541d089 100644 --- a/src/modules/Elsa.Workflows.Core/Models/ActivityExecutionContext.cs +++ b/src/modules/Elsa.Workflows.Core/Models/ActivityExecutionContext.cs @@ -44,7 +44,7 @@ public class ActivityExecutionContext /// /// A dictionary of values that can be associated with this activity execution context. /// - public IDictionary Properties { get; set; } = new Dictionary(); + public PropertyBag Properties { get; set; } = new(); /// /// A transient dictionary of values that can be associated with this activity execution context. @@ -162,18 +162,18 @@ public class ActivityExecutionContext /// /// Returns a property value associated with the current activity context. /// - public T? GetProperty(string key) => Properties.TryGetValue(key, out var value) ? value : default; + public T? GetProperty(string key) => Properties.Dictionary.TryGetValue(key, out var value) ? value : default; /// /// Returns a property value associated with the current activity context. /// public T GetProperty(string key, Func defaultValue) { - if (Properties.TryGetValue(key, out var value)) + if (Properties.Dictionary.TryGetValue(key, out var value)) return value!; value = defaultValue(); - Properties[key] = value!; + Properties.Dictionary[key] = value!; return value!; } @@ -181,7 +181,7 @@ public class ActivityExecutionContext /// /// Stores a property associated with the current activity context. /// - public void SetProperty(string key, T? value) => Properties[key] = value!; + public void SetProperty(string key, T? value) => Properties.Dictionary[key] = value!; /// /// Updates a property associated with the current activity context. @@ -190,7 +190,7 @@ public class ActivityExecutionContext { var value = GetProperty(key); value = updater(value); - Properties[key] = value; + Properties.Dictionary[key] = value; return value; } diff --git a/src/modules/Elsa.Workflows.Core/Models/PropertyBag.cs b/src/modules/Elsa.Workflows.Core/Models/PropertyBag.cs index 35a872dc8..a7e42dd59 100644 --- a/src/modules/Elsa.Workflows.Core/Models/PropertyBag.cs +++ b/src/modules/Elsa.Workflows.Core/Models/PropertyBag.cs @@ -11,10 +11,10 @@ public class PropertyBag { } - public PropertyBag(IDictionary properties) + public PropertyBag(IDictionary dictionary) { - Properties = properties; + Dictionary = dictionary; } - public IDictionary Properties { get; init; } + public IDictionary Dictionary { get; init; } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Models/WorkflowExecutionContext.cs b/src/modules/Elsa.Workflows.Core/Models/WorkflowExecutionContext.cs index 26002fc43..c1c9972f4 100644 --- a/src/modules/Elsa.Workflows.Core/Models/WorkflowExecutionContext.cs +++ b/src/modules/Elsa.Workflows.Core/Models/WorkflowExecutionContext.cs @@ -132,12 +132,12 @@ public class WorkflowExecutionContext public IDictionary Output { get; } = new Dictionary(); /// - /// A dictionary that can be used by application code and activities to store information. Values need to be serializable, since this dictionary will be persisted alongside the workflow instance. + /// A dictionary that can be used by application code and activities to store information. Values need to be serializable. /// public IDictionary Properties { get; set; } = new Dictionary(); /// - /// A dictionary that can be used by application code and middleware to store information and even services. Values do not need to be serializable, since this dictionary will not be persisted. + /// A dictionary that can be used by application code and middleware to store information and even services. Values do not need to be serializable. /// All data will be gone once workflow execution completes. /// public IDictionary TransientProperties { get; set; } = new Dictionary(); diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PropertyBagConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PropertyBagConverter.cs index 7ecd356c5..5df5f55c5 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PropertyBagConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PropertyBagConverter.cs @@ -14,6 +14,6 @@ public class PropertyBagConverter : JsonConverter public override void Write(Utf8JsonWriter writer, PropertyBag value, JsonSerializerOptions options) { - JsonSerializer.Serialize(writer, value.Properties); + JsonSerializer.Serialize(writer, value.Dictionary); } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/State/ActivityExecutionContextState.cs b/src/modules/Elsa.Workflows.Core/State/ActivityExecutionContextState.cs index 9108d09a6..c16164083 100644 --- a/src/modules/Elsa.Workflows.Core/State/ActivityExecutionContextState.cs +++ b/src/modules/Elsa.Workflows.Core/State/ActivityExecutionContextState.cs @@ -1,3 +1,5 @@ +using Elsa.Workflows.Core.Models; + namespace Elsa.Workflows.Core.State; public class ActivityExecutionContextState @@ -15,6 +17,6 @@ public class ActivityExecutionContextState public string? ParentContextId { get; set; } public string ScheduledActivityId { get; set; } = default!; public string? OwnerActivityId { get; set; } - public IDictionary Properties { get; set; } = new Dictionary(); + public PropertyBag Properties { get; set; } = new(); //public RegisterState Register { get; set; } = default!; } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Management/Entities/WorkflowInstance.cs b/src/modules/Elsa.Workflows.Management/Entities/WorkflowInstance.cs index 36a06c7ea..c9768ae0f 100644 --- a/src/modules/Elsa.Workflows.Management/Entities/WorkflowInstance.cs +++ b/src/modules/Elsa.Workflows.Management/Entities/WorkflowInstance.cs @@ -15,7 +15,6 @@ public class WorkflowInstance : Entity public WorkflowSubStatus SubStatus { get; set; } public string? CorrelationId { get; set; } public string? Name { get; set; } - public WorkflowFaultState? Fault { get; set; } public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset? LastExecutedAt { get; set; } public DateTimeOffset? FinishedAt { get; set; } diff --git a/src/modules/Elsa.Workflows.Runtime/Implementations/AsyncWorkflowStateExporter.cs b/src/modules/Elsa.Workflows.Runtime/Implementations/AsyncWorkflowStateExporter.cs index 259977a62..182f7d983 100644 --- a/src/modules/Elsa.Workflows.Runtime/Implementations/AsyncWorkflowStateExporter.cs +++ b/src/modules/Elsa.Workflows.Runtime/Implementations/AsyncWorkflowStateExporter.cs @@ -1,7 +1,9 @@ using Elsa.Common.Models; using Elsa.Common.Services; +using Elsa.Extensions; using Elsa.Mediator.Models; using Elsa.Mediator.Services; +using Elsa.Workflows.Core.Activities; using Elsa.Workflows.Core.Models; using Elsa.Workflows.Core.State; using Elsa.Workflows.Management.Entities; @@ -70,6 +72,8 @@ public class AsyncWorkflowStateExporter : IWorkflowStateExporter, ICommandHandle workflowInstance.SubStatus = workflowState.SubStatus; workflowInstance.CorrelationId = workflowState.CorrelationId; workflowInstance.LastExecutedAt = now; + workflowInstance.WorkflowState = workflowState; + workflowInstance.Name = workflowState.Properties.Dictionary.GetValue(SetName.WorkflowInstanceNameKey) as string; // TODO: Store timestamps such as CancelledAt, FaultedAt, etc.