Merge remote-tracking branch 'upstream/master' into elsa-2.0/fileactivities

This commit is contained in:
Cameron Cowen 2021-08-06 23:37:27 +01:00
commit bae7fbf5ba
355 changed files with 4737 additions and 92560 deletions

View file

@ -201,7 +201,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.BreakLoop", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Timers.Quartz", "src\samples\worker\Elsa.Samples.Timers.Quartz\Elsa.Samples.Timers.Quartz.csproj", "{FE724143-B24C-43DA-BBF5-15431BCA6E27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.AutoConnectNextActivityConsole", "src\samples\console\Elsa.Samples.AutoConnectNextActivityConsole\Elsa.Samples.AutoConnectNextActivityConsole.csproj", "{DB42A8DA-06CA-4402-9C87-8F7F055AB37E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.CustomOutcomeActivityConsole", "src\samples\console\Elsa.Samples.CustomOutcomeActivityConsole\Elsa.Samples.CustomOutcomeActivityConsole.csproj", "{DB42A8DA-06CA-4402-9C87-8F7F055AB37E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.UnitTests", "test\unit\Elsa.UnitTests\Elsa.UnitTests.csproj", "{F822DE2F-A91D-416E-BF4A-A6C466C1BF0A}"
EndProject
@ -229,6 +229,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.Azu
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "blazor", "blazor", "{D86B94DC-A53C-4A67-A820-828DD359C49B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElsaDashboard.Samples.AspNetCore.Monolith", "src\samples\dashboard\aspnetcore\ElsaDashboard.Samples.AspNetCore.Monolith\ElsaDashboard.Samples.AspNetCore.Monolith.csproj", "{F1EF5639-021A-4D22-9D4A-73D57C88EBFA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Persistence.YesSql", "src\samples\persistence\Elsa.Samples.Persistence.YesSql\Elsa.Samples.Persistence.YesSql.csproj", "{3A30EFFE-32D8-40B8-9C62-427037BB5424}"
@ -243,6 +244,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{D7F754
docker\Dockerfile-elsa-dashboard-and-server = docker\Dockerfile-elsa-dashboard-and-server
docker\README.md = docker\README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.EntityFramework.MySql", "src\persistence\Elsa.Persistence.EntityFramework\Elsa.Persistence.EntityFramework.MySql\Elsa.Persistence.EntityFramework.MySql.csproj", "{D55BC08B-CA82-478A-99F7-EDE90AC33160}"
EndProject
@ -262,12 +264,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "aspnetcore", "aspnetcore",
docker\Dockerfile-elsa-dashboard-and-server = docker\Dockerfile-elsa-dashboard-and-server
docker\README.md = docker\README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{3BF2C5A9-AC69-4587-833F-C16CFC97E100}"
ProjectSection(SolutionItems) = preProject
.github\workflows\publish-latest-dashboard-and-server-docker.yml = .github\workflows\publish-latest-dashboard-and-server-docker.yml
.github\workflows\publish-latest-dashboard-docker.yml = .github\workflows\publish-latest-dashboard-docker.yml
.github\workflows\publish-latest-designer-npm.yml = .github\workflows\publish-latest-designer-npm.yml
.github\workflows\publish-latest-server-docker.yml = .github\workflows\publish-latest-server-docker.yml
EndProjectSection
EndProject
@ -280,6 +285,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "providers", "providers", "{EC5D4AFD-3F7F-4B51-9C38-F18C60618731}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Providers.Redis", "src\providers\Elsa.Providers.Redis\Elsa.Providers.Redis.csproj", "{9ACA06DA-9AFE-41A2-8109-EFED8B9B14A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.Redis", "src\locking\Elsa.DistributedLocking.Redis\Elsa.DistributedLocking.Redis.csproj", "{D1644D32-AA51-4D10-942E-F2722DB963B4}"
EndProject
@ -309,6 +315,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Webhooks.Persistence.Y
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElsaDashboard.Web", "src\dashboards\ElsaDashboard\ElsaDashboard.Web.csproj", "{1129868E-BA72-44C4-941C-A28D9001504B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElsaDashboard.Samples.BlazorWasm", "src\samples\dashboard\blazor\ElsaDashboard.Samples.BlazorWasm\ElsaDashboard.Samples.BlazorWasm.csproj", "{24A99602-F743-4B1A-AC96-599F34AE916C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "html", "html", "{8E6215AB-FDD3-4011-B598-B6BB63F294BB}"
@ -319,6 +326,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "html", "html", "{8E6215AB-F
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElsaDashboard.Samples.BlazorServer", "src\samples\dashboard\blazor\ElsaDashboard.Samples.BlazorServer\ElsaDashboard.Samples.BlazorServer.csproj", "{6A03B177-09E0-4421-9704-945E6248AB69}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.EntityFramework.Oracle", "src\persistence\Elsa.Persistence.EntityFramework\Elsa.Persistence.EntityFramework.Oracle\Elsa.Persistence.EntityFramework.Oracle.csproj", "{FE6FC5F9-349A-4A3A-B291-CE0614030D5C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.FaultyWorkflows", "src\samples\aspnet\Elsa.Samples.FaultyWorkflows\Elsa.Samples.FaultyWorkflows.csproj", "{84751112-C2B7-41D4-98F5-D87D7C2E1DAE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Conductor", "src\activities\Elsa.Activities.Conductor\Elsa.Activities.Conductor.csproj", "{4D4022DD-244B-47EE-95FA-7071EC687B24}"
@ -327,6 +337,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "aspnetcore", "aspnetcore",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.CustomTenantIdSource", "src\samples\aspnet\Elsa.Samples.CustomTenantIdSource\Elsa.Samples.CustomTenantIdSource.csproj", "{6E191628-927B-42FB-8805-D2977D8FC4E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElsaDashboard.Samples.AspNetCore.SubPath", "src\samples\dashboard\aspnetcore\ElsaDashboard.Samples.AspNetCore.SubPath\ElsaDashboard.Samples.AspNetCore.SubPath.csproj", "{BB715C0C-BE88-4F7F-A43F-1F8DFC9A1388}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.MassTransitRabbitMq", "src\samples\aspnet\Elsa.Samples.MassTransitRabbitMq\Elsa.Samples.MassTransitRabbitMq.csproj", "{6BDC89F4-2E0A-4534-9BE4-10E771D06C93}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -749,6 +764,12 @@ Global
{84751112-C2B7-41D4-98F5-D87D7C2E1DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84751112-C2B7-41D4-98F5-D87D7C2E1DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84751112-C2B7-41D4-98F5-D87D7C2E1DAE}.Release|Any CPU.Build.0 = Release|Any CPU
{FE6FC5F9-349A-4A3A-B291-CE0614030D5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE6FC5F9-349A-4A3A-B291-CE0614030D5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE6FC5F9-349A-4A3A-B291-CE0614030D5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE6FC5F9-349A-4A3A-B291-CE0614030D5C}.Release|Any CPU.Build.0 = Release|Any CPU
{4D4022DD-244B-47EE-95FA-7071EC687B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D4022DD-244B-47EE-95FA-7071EC687B24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D4022DD-244B-47EE-95FA-7071EC687B24}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -757,6 +778,15 @@ Global
{6E191628-927B-42FB-8805-D2977D8FC4E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E191628-927B-42FB-8805-D2977D8FC4E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E191628-927B-42FB-8805-D2977D8FC4E3}.Release|Any CPU.Build.0 = Release|Any CPU
{BB715C0C-BE88-4F7F-A43F-1F8DFC9A1388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB715C0C-BE88-4F7F-A43F-1F8DFC9A1388}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB715C0C-BE88-4F7F-A43F-1F8DFC9A1388}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB715C0C-BE88-4F7F-A43F-1F8DFC9A1388}.Release|Any CPU.Build.0 = Release|Any CPU
{6BDC89F4-2E0A-4534-9BE4-10E771D06C93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BDC89F4-2E0A-4534-9BE4-10E771D06C93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BDC89F4-2E0A-4534-9BE4-10E771D06C93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BDC89F4-2E0A-4534-9BE4-10E771D06C93}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -897,9 +927,15 @@ Global
{8E6215AB-FDD3-4011-B598-B6BB63F294BB} = {4673732F-2853-47BD-91B8-C95C229D2C89}
{6A03B177-09E0-4421-9704-945E6248AB69} = {D86B94DC-A53C-4A67-A820-828DD359C49B}
{84751112-C2B7-41D4-98F5-D87D7C2E1DAE} = {22E75696-6FE9-436A-9097-EE21C603F818}
{FE6FC5F9-349A-4A3A-B291-CE0614030D5C} = {C865B0FD-E505-48F0-BFAF-0D4D7C1B5CA1}
{4D4022DD-244B-47EE-95FA-7071EC687B24} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{39DE1EE2-DF4F-44EB-9F5A-551BEADD6673} = {4673732F-2853-47BD-91B8-C95C229D2C89}
{6E191628-927B-42FB-8805-D2977D8FC4E3} = {22E75696-6FE9-436A-9097-EE21C603F818}
{BB715C0C-BE88-4F7F-A43F-1F8DFC9A1388} = {39DE1EE2-DF4F-44EB-9F5A-551BEADD6673}
{6BDC89F4-2E0A-4534-9BE4-10E771D06C93} = {22E75696-6FE9-436A-9097-EE21C603F818}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}

View file

@ -32,8 +32,7 @@ dotnet new console -n "MyConsoleApp"
cd MyConsoleApp
dotnet add package Elsa --prerelease
dotnet add package Elsa.Activities.Console --prerelease
dotnet add package Elsa
```
Create a new file called `HelloWorldWorkflow.cs` and add the following:
@ -146,16 +145,23 @@ Version 2.0
- [x] Distributed Hosting Support (support for multi-node environments)
- [x] Persistence: MongoDB, YesSQL, Entity Framework Core (SQL Server, SQLLite, PostgreSql)
- [x] New Workflow Designer + Dashboard
- [ ] Generic Command & Event Activities
Version 3.0
- [ ] Composite Activity Definitions (with designer support)
- [ ] Job Activities (simplify starting background processes while the workflow sleeps & gets resumed once the job finishes)
- [ ] Lucene Indexing
- [ ] Localization Support
- [ ] State Machines
- [x] Generic Command & Event Activities
- [x] State Machines
- [ ] Test Workflows from Designer
- [ ] Debug Workflows from Designer
- [ ] Sagas
- [ ] Localization Support
- [ ] Lucene Indexing
Version 3.0 (engine redesign)
- [ ] Programming model similar to WF
- [ ] Sequential Workflows
- [ ] Flowchart Workflows
- [ ] State Machine Workflows
- [ ] Sagas
- [ ] BPMS Workflows
- [ ] Actor Model for Distributed Workflows
## Workflow Designer

View file

@ -11,7 +11,7 @@ environment:
sonarcloud_api_key:
secure: qaE9kOVkGGFM7ZMf3YeliZxDU9udTCy6W5xXHJ9T+tXv5qXPMYlIdR7hyNgxW04A
version: 2.1.1.{build}
version: 2.3.0-preview.{build}
init:
- cmd: git config --global core.autocrlf true
@ -46,12 +46,12 @@ install:
cd ..\..\..\..\..
# dotnet tool install --global dotnet-sonarscanner
before_build:
- cmd: >-
docker-compose -f docker-compose.yaml up -d mongodb postgres
dotnet tool install --global dotnet-sonarscanner
#before_build:
# - cmd: >-
# docker-compose -f docker-compose.yaml up -d mongodb postgres
#
# - ps: >-
# if(-Not $env:APPVEYOR_PULL_REQUEST_NUMBER) {
# & dotnet-sonarscanner begin
@ -80,9 +80,7 @@ build_script:
dotnet build
# before_test:
# test_script:
#test_script:
# - ps: dotnet test --collect:"XPlat Code Coverage" --logger:xunit -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
# - ps: dotnet test

View file

@ -22,7 +22,6 @@ RUN dotnet restore "./src/dashboards/ElsaDashboard/ElsaDashboard.Web.csproj"
COPY src/. ./src
COPY *.props ./
COPY ./Nuget.Config ./
COPY --from=client-build /app/designer/elsa-workflows-studio ./src/designer/elsa-workflows-studio
COPY --from=client-build /app/designer/bindings/aspnet/Elsa.Designer.Components.Web ./src/designer/bindings/aspnet/Elsa.Designer.Components.Web
# build and publish (UseAppHost=false created platform independent binaries)

View file

@ -22,7 +22,6 @@ RUN dotnet restore "./src/samples/dashboard/aspnetcore/ElsaDashboard.Samples.Asp
COPY src/. ./src
COPY *.props ./
COPY ./Nuget.Config ./
COPY --from=client-build /app/designer/elsa-workflows-studio ./src/designer/elsa-workflows-studio
COPY --from=client-build /app/designer/bindings/aspnet/Elsa.Designer.Components.Web ./src/designer/bindings/aspnet/Elsa.Designer.Components.Web
# build and publish (UseAppHost=false creates platform independent binaries)

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.AzureServiceBus.Bookmarks

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.AzureServiceBus.Bookmarks

View file

@ -40,10 +40,10 @@ namespace Elsa.Activities.AzureServiceBus.Extensions
.AddBookmarkProvider<TopicMessageReceivedBookmarkProvider>()
;
options.AddCompetingConsumer<RestartServiceBusQueuesConsumer, WorkflowDefinitionPublished>();
options.AddCompetingConsumer<RestartServiceBusQueuesConsumer, WorkflowDefinitionRetracted>();
options.AddCompetingConsumer<RestartServiceBusTopicsConsumer, WorkflowDefinitionPublished>();
options.AddCompetingConsumer<RestartServiceBusTopicsConsumer, WorkflowDefinitionRetracted>();
options.AddPubSubConsumer<RestartServiceBusQueuesConsumer, WorkflowDefinitionPublished>("WorkflowDefinitionEvents");
options.AddPubSubConsumer<RestartServiceBusQueuesConsumer, WorkflowDefinitionRetracted>("WorkflowDefinitionEvents");
options.AddPubSubConsumer<RestartServiceBusTopicsConsumer, WorkflowDefinitionPublished>("WorkflowDefinitionEvents");
options.AddPubSubConsumer<RestartServiceBusTopicsConsumer, WorkflowDefinitionRetracted>("WorkflowDefinitionEvents");
options
.AddActivity<AzureServiceBusQueueMessageReceived>()

View file

@ -4,8 +4,10 @@ using System.Threading;
using System.Threading.Tasks;
using Elsa.Activities.AzureServiceBus.Models;
using Elsa.Activities.AzureServiceBus.Options;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Bookmarks;
using Elsa.Services.Models;
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.ServiceBus.Core;
using Microsoft.Extensions.Logging;
@ -72,9 +74,9 @@ namespace Elsa.Activities.AzureServiceBus.Services
};
var bookmark = CreateBookmark(message);
var launchContext = new CollectWorkflowsContext(ActivityType, bookmark, correlationId);
var launchContext = new WorkflowsQuery(ActivityType, bookmark, correlationId);
await _workflowLaunchpad.UseServiceAsync(service => service.CollectAndDispatchWorkflowsAsync(launchContext, model, cancellationToken));
await _workflowLaunchpad.UseServiceAsync(service => service.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(model), cancellationToken));
}
private Task ExceptionReceivedHandler(ExceptionReceivedEventArgs e)

View file

@ -1,18 +1,13 @@
using System;
using Elsa;
using Elsa.Activities.BlobStorage;
using Storage.Net.Blobs;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static ElsaOptionsBuilder AddBlobStorageActivities(this ElsaOptionsBuilder options, Func<IServiceProvider, IBlobStorage>? configureBlobStorage = default)
public static ElsaOptionsBuilder AddBlobStorageActivities(this ElsaOptionsBuilder options)
{
if (configureBlobStorage != default)
options.UseStorage(configureBlobStorage);
options
.AddActivity<WriteBlob>()
.AddActivity<ReadBlob>()

View file

@ -1,7 +1,9 @@
using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Providers.Bookmarks;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Activities.Conductor.Endpoints.Conductor.Events
@ -18,8 +20,8 @@ namespace Elsa.Activities.Conductor.Endpoints.Conductor.Events
public async Task<IActionResult> Handle(string eventName, EventModel model)
{
var bookmark = new EventBookmark(eventName.ToLowerInvariant());
var context = new CollectWorkflowsContext(nameof(EventReceived), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, model);
var context = new WorkflowsQuery(nameof(EventReceived), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, new WorkflowInput(model));
return Accepted(pendingWorkflows);
}

View file

@ -1,7 +1,9 @@
using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Providers.Bookmarks;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Activities.Conductor.Endpoints.Conductor.Events
@ -18,8 +20,8 @@ namespace Elsa.Activities.Conductor.Endpoints.Conductor.Events
public async Task<IActionResult> Handle(string eventName, EventModel model)
{
var bookmark = new EventBookmark(eventName);
var context = new CollectWorkflowsContext(nameof(EventReceived), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(context, model);
var context = new WorkflowsQuery(nameof(EventReceived), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(context, new WorkflowInput(model));
return Accepted(pendingWorkflows);
}

View file

@ -1,7 +1,9 @@
using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Providers.Bookmarks;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Activities.Conductor.Endpoints.Conductor.Tasks
@ -18,8 +20,8 @@ namespace Elsa.Activities.Conductor.Endpoints.Conductor.Tasks
public async Task<IActionResult> Handle(string taskName, TaskResultModel model)
{
var bookmark = new TaskBookmark(taskName.ToLowerInvariant());
var context = new CollectWorkflowsContext(nameof(RunTask), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, model);
var context = new WorkflowsQuery(nameof(RunTask), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, new WorkflowInput(model));
return Accepted(pendingWorkflows);
}

View file

@ -1,7 +1,9 @@
using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Providers.Bookmarks;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Activities.Conductor.Endpoints.Conductor.Tasks
@ -18,8 +20,8 @@ namespace Elsa.Activities.Conductor.Endpoints.Conductor.Tasks
public async Task<IActionResult> Handle(string taskName, TaskResultModel model)
{
var bookmark = new TaskBookmark(taskName.ToLowerInvariant());
var context = new CollectWorkflowsContext(nameof(RunTask), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(context, model);
var context = new WorkflowsQuery(nameof(RunTask), bookmark, model.CorrelationId, model.WorkflowInstanceId);
var pendingWorkflows = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(context, new WorkflowInput(model));
return Accepted(pendingWorkflows);
}

View file

@ -43,8 +43,8 @@ namespace Elsa.Activities.Conductor.Extensions
elsa
.AddActivitiesFrom<SendCommand>()
.AddCompetingConsumer<SendCommandConsumer, SendCommandModel>()
.AddCompetingConsumer<RunTaskConsumer, RunTaskModel>();
.AddCompetingConsumer<SendCommandConsumer, SendCommandModel>("ConductorCommand")
.AddCompetingConsumer<RunTaskConsumer, RunTaskModel>("ConductorCommand");
return elsa;
}

View file

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Services;
using Elsa.Metadata;
using Elsa.Providers.Activities;
using Elsa.Services;
using Elsa.Services.Models;
@ -39,19 +40,26 @@ namespace Elsa.Activities.Conductor.Providers.ActivityTypes
private async Task<ActivityType> CreateActivityTypeAsync(CommandDefinition command, CancellationToken cancellationToken)
{
var descriptor = await _describesActivityType.DescribeAsync<SendCommand>(cancellationToken);
async ValueTask<ActivityDescriptor> CreateDescriptorAsync()
{
var des = await _describesActivityType.DescribeAsync<SendCommand>(cancellationToken);
descriptor.Type = command.Name;
descriptor.DisplayName = command.DisplayName ?? command.Name;
descriptor.Description = command.Description;
descriptor.InputProperties = descriptor.InputProperties.Where(x => x.Name != nameof(SendCommand.CommandName)).ToArray();
des.Type = command.Name;
des.DisplayName = command.DisplayName ?? command.Name;
des.Description = command.Description;
des.InputProperties = des.InputProperties.Where(x => x.Name != nameof(SendCommand.CommandName)).ToArray();
return des;
}
var descriptor = await CreateDescriptorAsync();
return new ActivityType
{
Type = typeof(SendCommand),
TypeName = descriptor.Type,
DisplayName = descriptor.DisplayName,
Describe = () => descriptor,
DescribeAsync = CreateDescriptorAsync,
Description = descriptor.Description,
ActivateAsync = async context =>
{
@ -65,7 +73,7 @@ namespace Elsa.Activities.Conductor.Providers.ActivityTypes
};
}
private async Task<IEnumerable<CommandDefinition>> GetCommandsAsync(CancellationToken cancellationToken) =>
private async Task<IEnumerable<CommandDefinition>> GetCommandsAsync(CancellationToken cancellationToken) =>
await _scopedCommandsProviders.UseServiceAsync(async commandProviders => await GetCommandsAsync(commandProviders, cancellationToken).ToListAsync(cancellationToken));
private static async IAsyncEnumerable<CommandDefinition> GetCommandsAsync(IEnumerable<ICommandsProvider> commandProviders, [EnumeratorCancellation] CancellationToken cancellationToken)

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Services;
using Elsa.Metadata;
using Elsa.Providers.Activities;
using Elsa.Services;
using Elsa.Services.Models;
@ -39,20 +40,27 @@ namespace Elsa.Activities.Conductor.Providers.ActivityTypes
private async Task<ActivityType> CreateActivityTypeAsync(EventDefinition eventDefinition, CancellationToken cancellationToken)
{
var descriptor = await _describesActivityType.DescribeAsync<EventReceived>(cancellationToken);
async ValueTask<ActivityDescriptor> CreateDescriptorAsync()
{
var des = await _describesActivityType.DescribeAsync<EventReceived>(cancellationToken);
descriptor.Type = eventDefinition.Name;
descriptor.DisplayName = eventDefinition.DisplayName ?? eventDefinition.Name;
descriptor.Description = eventDefinition.Description;
descriptor.InputProperties = Array.Empty<ActivityInputDescriptor>();
descriptor.Outcomes = eventDefinition.Outcomes?.ToArray() ?? new[] { OutcomeNames.Done };
des.Type = eventDefinition.Name;
des.DisplayName = eventDefinition.DisplayName ?? eventDefinition.Name;
des.Description = eventDefinition.Description;
des.InputProperties = Array.Empty<ActivityInputDescriptor>();
des.Outcomes = eventDefinition.Outcomes?.ToArray() ?? new[] { OutcomeNames.Done };
return des;
}
var descriptor = await CreateDescriptorAsync();
return new ActivityType
{
Type = typeof(EventReceived),
TypeName = descriptor.Type,
DisplayName = descriptor.DisplayName,
Describe = () => descriptor,
DescribeAsync = CreateDescriptorAsync,
Description = descriptor.Description,
ActivateAsync = async context =>
{

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Elsa.Activities.Conductor.Models;
using Elsa.Activities.Conductor.Services;
using Elsa.Metadata;
using Elsa.Providers.Activities;
using Elsa.Services;
using Elsa.Services.Models;
@ -39,20 +40,27 @@ namespace Elsa.Activities.Conductor.Providers.ActivityTypes
private async Task<ActivityType> CreateActivityTypeAsync(TaskDefinition taskDefinition, CancellationToken cancellationToken)
{
var descriptor = await _describesActivityType.DescribeAsync<RunTask>(cancellationToken);
async ValueTask<ActivityDescriptor> CreateDescriptorAsync()
{
var des = await _describesActivityType.DescribeAsync<RunTask>(cancellationToken);
descriptor.Type = taskDefinition.Name;
descriptor.DisplayName = taskDefinition.DisplayName ?? taskDefinition.Name;
descriptor.Description = taskDefinition.Description;
descriptor.InputProperties = Array.Empty<ActivityInputDescriptor>();
descriptor.Outcomes = taskDefinition.Outcomes?.ToArray() ?? new[] { OutcomeNames.Done };
des.Type = taskDefinition.Name;
des.DisplayName = taskDefinition.DisplayName ?? taskDefinition.Name;
des.Description = taskDefinition.Description;
des.InputProperties = Array.Empty<ActivityInputDescriptor>();
des.Outcomes = taskDefinition.Outcomes?.ToArray() ?? new[] { OutcomeNames.Done };
return des;
}
var descriptor = await CreateDescriptorAsync();
return new ActivityType
{
Type = typeof(RunTask),
TypeName = descriptor.Type,
DisplayName = descriptor.DisplayName,
Describe = () => descriptor,
DescribeAsync = CreateDescriptorAsync,
Description = descriptor.Description,
ActivateAsync = async context =>
{

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Conductor.Providers.Bookmarks

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Conductor.Providers.Bookmarks

View file

@ -1,5 +1,5 @@
// ReSharper disable once CheckNamespace
namespace Elsa.Activities.Email
{
public record EmailAttachment(byte[] Content, string? FileName, string? ContentType);
public record EmailAttachment(object Content, string? FileName, string? ContentType);
}

View file

@ -13,6 +13,7 @@ using Elsa.ActivityResults;
using Elsa.Attributes;
using Elsa.Design;
using Elsa.Expressions;
using Elsa.Providers.WorkflowStorage;
using Elsa.Serialization;
using Elsa.Services;
using Elsa.Services.Models;
@ -66,7 +67,8 @@ namespace Elsa.Activities.Email
[ActivityInput(
Hint = "The attachments to send with the email message. Can be (an array of) a fully-qualified file path, URL, stream, byte array or instances of EmailAttachment.",
UIHint = ActivityInputUIHints.MultiLine,
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid },
DefaultWorkflowStorageProvider = TransientWorkflowStorageProvider.ProviderName
)]
public object? Attachments { get; set; }
@ -136,7 +138,14 @@ namespace Elsa.Activities.Email
{
var fileName = emailAttachment.FileName ?? $"Attachment-{++index}";
var contentType = emailAttachment.ContentType ?? "application/binary";
bodyBuilder.Attachments.Add(fileName, emailAttachment.Content, ContentType.Parse(contentType));
var parsedContentType = ContentType.Parse(contentType);
if(emailAttachment.Content is byte[] bytes)
bodyBuilder.Attachments.Add(fileName, bytes, parsedContentType);
else if(emailAttachment.Content is Stream stream)
await bodyBuilder.Attachments.AddAsync(fileName, stream, parsedContentType, cancellationToken);
break;
}
default:

View file

@ -11,17 +11,6 @@ namespace Elsa.Activities.Email.Handlers
{
public class ConfigureJavaScriptEngine : INotificationHandler<EvaluatingJavaScriptExpression>
{
private readonly IConfiguration _configuration;
private readonly IActivityTypeService _activityTypeService;
private readonly IWorkflowStorageService _workflowStorageService;
public ConfigureJavaScriptEngine(IConfiguration configuration, IActivityTypeService activityTypeService, IWorkflowStorageService workflowStorageService)
{
_configuration = configuration;
_activityTypeService = activityTypeService;
_workflowStorageService = workflowStorageService;
}
public Task Handle(EvaluatingJavaScriptExpression notification, CancellationToken cancellationToken)
{
var engine = notification.Engine;

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Entity.Bookmarks

View file

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Elsa.Activities.Entity.Bookmarks;
using Elsa.Activities.Entity.Models;
using Elsa.Models;
using Elsa.Services;
namespace Elsa.Activities.Entity.Extensions
@ -29,7 +30,7 @@ namespace Elsa.Activities.Entity.Extensions
contextId
);
await workflowDispatcher.DispatchAsync(new TriggerWorkflowsRequest(activityType, bookmark, input, correlationId, default, contextId, TenantId), cancellationToken);
await workflowDispatcher.DispatchAsync(new TriggerWorkflowsRequest(activityType, bookmark, new WorkflowInput(input), correlationId, default, contextId, TenantId), cancellationToken);
}
}
}

View file

@ -1,3 +1,4 @@
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
@ -131,6 +132,9 @@ namespace Elsa.Activities.Http
return;
}
if (content is Stream stream)
content = await stream.ReadBytesToEndAsync(cancellationToken);
if (content is byte[] buffer)
{

View file

@ -16,17 +16,17 @@ namespace Elsa.Activities.Http
public static ISetupActivity<WriteHttpResponse> WithStatusCode(this ISetupActivity<WriteHttpResponse> activity, Func<HttpStatusCode> value) => activity.Set(x => x.StatusCode, value);
public static ISetupActivity<WriteHttpResponse> WithStatusCode(this ISetupActivity<WriteHttpResponse> activity, HttpStatusCode value) => activity.Set(x => x.StatusCode, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, ValueTask<string?>> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<ValueTask<string?>> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, string?> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<string?> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, string? value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, ValueTask<object?>> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<ValueTask<object?>> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, object?> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, Func<object?> value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContent(this ISetupActivity<WriteHttpResponse> activity, object? value) => activity.Set(x => x.Content, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, ValueTask<string?>> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<ValueTask<string?>> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, string?> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<string?> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, string? value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, ValueTask<object?>> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<ValueTask<object?>> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, object?> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, Func<object?> value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithContentType(this ISetupActivity<WriteHttpResponse> activity, object? value) => activity.Set(x => x.ContentType, value);
public static ISetupActivity<WriteHttpResponse> WithResponseHeaders(this ISetupActivity<WriteHttpResponse> activity, Func<ActivityExecutionContext, ValueTask<HttpResponseHeaders?>> value) => activity.Set(x => x.ResponseHeaders, value);
public static ISetupActivity<WriteHttpResponse> WithResponseHeaders(this ISetupActivity<WriteHttpResponse> activity, Func<ValueTask<HttpResponseHeaders?>> value) => activity.Set(x => x.ResponseHeaders, value);

View file

@ -2,6 +2,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
using Microsoft.AspNetCore.Http;

View file

@ -1,5 +1,11 @@
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Activities.Http.Events;
using Elsa.Activities.Signaling.Models;
using Elsa.Activities.Signaling.Services;
using Elsa.Services;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Open.Linq.AsyncExtensions;
@ -11,16 +17,31 @@ namespace Elsa.Activities.Http.Endpoints.Signals
public class TriggerEndpoint : ControllerBase
{
private readonly ISignaler _signaler;
public TriggerEndpoint(ISignaler signaler) => _signaler = signaler;
private readonly ITokenService _tokenService;
private readonly IMediator _mediator;
public TriggerEndpoint(ISignaler signaler, ITokenService tokenService, IMediator mediator)
{
_signaler = signaler;
_tokenService = tokenService;
_mediator = mediator;
}
[HttpGet, HttpPost]
public async Task<IActionResult> Handle(string token)
public async Task<IActionResult> Handle(string token, CancellationToken cancellationToken)
{
var result = await _signaler.TriggerSignalTokenAsync(token).ToList();
if (!_tokenService.TryDecryptToken(token, out SignalModel signal))
return BadRequest();
return HttpContext.Response.HasStarted
var affectedWorkflows = await _signaler.TriggerSignalAsync(signal.Name, null, signal.WorkflowInstanceId, cancellationToken: cancellationToken).ToList();
await _mediator.Publish(new HttpTriggeredSignal(signal, affectedWorkflows), cancellationToken);
var response = HttpContext.Response;
return response.HasStarted || response.StatusCode != (int) HttpStatusCode.OK
? new EmptyResult()
: Ok(result);
: Ok(affectedWorkflows);
}
}
}

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
using Elsa.Activities.Signaling.Models;
using Elsa.Services.Models;
using MediatR;
namespace Elsa.Activities.Http.Events
{
public record HttpTriggeredSignal(SignalModel SignalModel, ICollection<CollectedWorkflow> AffectedWorkflows) : INotification;
}

View file

@ -10,6 +10,7 @@ using Elsa.Activities.Http.Models;
using Elsa.Activities.Http.Options;
using Elsa.Activities.Http.Parsers.Request;
using Elsa.Activities.Http.Services;
using Elsa.Models;
using Elsa.Persistence;
using Elsa.Services;
using Elsa.Services.Models;
@ -66,8 +67,8 @@ namespace Elsa.Activities.Http.Middleware
const string activityType = nameof(HttpEndpoint);
var bookmark = new HttpEndpointBookmark(path, method);
var collectWorkflowsContext = new CollectWorkflowsContext(activityType, bookmark, correlationId, default, default, TenantId);
var pendingWorkflows = await workflowLaunchpad.CollectWorkflowsAsync(collectWorkflowsContext, cancellationToken).ToList();
var collectWorkflowsContext = new WorkflowsQuery(activityType, bookmark, correlationId, default, default, TenantId);
var pendingWorkflows = await workflowLaunchpad.FindWorkflowsAsync(collectWorkflowsContext, cancellationToken).ToList();
if (!pendingWorkflows.Any())
{
@ -138,7 +139,7 @@ namespace Elsa.Activities.Http.Middleware
var useDispatch = httpContext.Request.GetUseDispatch();
if (useDispatch)
{
await workflowLaunchpad.DispatchPendingWorkflowAsync(pendingWorkflow, inputModel, cancellationToken);
await workflowLaunchpad.DispatchPendingWorkflowAsync(pendingWorkflow, new WorkflowInput(inputModel), cancellationToken);
httpContext.Response.ContentType = "application/json";
httpContext.Response.StatusCode = (int) HttpStatusCode.Accepted;
@ -146,7 +147,7 @@ namespace Elsa.Activities.Http.Middleware
}
else
{
await workflowLaunchpad.ExecutePendingWorkflowAsync(pendingWorkflow, inputModel, cancellationToken);
await workflowLaunchpad.ExecutePendingWorkflowAsync(pendingWorkflow, new WorkflowInput(inputModel), cancellationToken);
pendingWorkflowInstance = await workflowInstanceStore.FindByIdAsync(pendingWorkflow.WorkflowInstanceId, cancellationToken);
if (pendingWorkflowInstance is not null

View file

@ -8,25 +8,16 @@ namespace Elsa.Activities.Http.Services
{
public class DefaultAbsoluteUrlProvider : IAbsoluteUrlProvider
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IOptions<HttpActivityOptions> _options;
public DefaultAbsoluteUrlProvider(
IHttpContextAccessor httpContextAccessor,
IOptions<HttpActivityOptions> options)
{
_httpContextAccessor = httpContextAccessor;
_options = options;
}
public DefaultAbsoluteUrlProvider(IOptions<HttpActivityOptions> options) => _options = options;
public Uri ToAbsoluteUrl(string relativePath)
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext != null)
return httpContext.Request.ToAbsoluteUrl(relativePath);
var baseUrl = _options.Value.BaseUrl;
if (baseUrl == null)
throw new Exception("There was no base URL configured, which means no absolute URL can be generated from outside the context of an HTTP request. Please make sure that `HttpActivityOptions` is configured correctly. The configuration key used in most Elsa samples is usually: \"Elsa:Server:BaseUrl\"");
return new Uri(baseUrl, relativePath);
}
}

View file

@ -11,7 +11,7 @@ namespace Elsa.Activities.Http
{
public override void ConfigureElsa(ElsaOptionsBuilder elsa, IConfiguration configuration)
{
elsa.AddHttpActivities(configuration.GetSection("Elsa:Http").Bind);
elsa.AddHttpActivities(configuration.GetSection("Elsa:Server").Bind);
}
public override void ConfigureApp(IApplicationBuilder app) => app.UseHttpActivities();

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.MassTransit.Bookmarks

View file

@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Elsa.Activities.MassTransit.Bookmarks;
using Elsa.Activities.MassTransit.Consumers.MessageCorrelation;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
using MassTransit;
using MediatR;
@ -43,11 +45,15 @@ namespace Elsa.Activities.MassTransit.Consumers
MessageType = message.GetType().Name
};
await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(new CollectWorkflowsContext(
var workflowQuery = new WorkflowsQuery(
nameof(ReceiveMassTransitMessage),
bookmark,
correlationId.ToString()
));
);
var workflowInput = new WorkflowInput { Input = message };
await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(workflowQuery, workflowInput, context.CancellationToken);
}
}
}

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Rebus.Bookmarks

View file

@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Elsa.Activities.Rebus.Bookmarks;
using Elsa.Services;
using Elsa.Services.Models;
using Rebus.Extensions;
using Rebus.Handlers;
using Rebus.Messages;
@ -23,12 +24,13 @@ namespace Elsa.Activities.Rebus.Consumers
public async Task Handle(T message)
{
var correlationId = MessageContext.Current.TransportMessage.Headers.GetValueOrNull(Headers.CorrelationId);
await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(new CollectWorkflowsContext(
await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(new WorkflowsQuery(
nameof(RebusMessageReceived),
new MessageReceivedBookmark { MessageType = message.GetType().Name },
correlationId,
default,
TenantId));
TenantId),
new Models.WorkflowInput(message));
}
}
}

View file

@ -7,8 +7,10 @@ using Elsa.Activities.Telnyx.Models;
using Elsa.Activities.Telnyx.Providers.Bookmarks;
using Elsa.Activities.Telnyx.Webhooks.Events;
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Bookmarks;
using Elsa.Services.Models;
using MediatR;
namespace Elsa.Activities.Telnyx.Handlers
@ -40,8 +42,8 @@ namespace Elsa.Activities.Telnyx.Handlers
var correlationId = GetCorrelationId(receivedPayload);
var bookmark = CreateBookmark();
var context = new CollectWorkflowsContext(ActivityTypeName, bookmark, correlationId);
await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, receivedPayload, cancellationToken);
var context = new WorkflowsQuery(ActivityTypeName, bookmark, correlationId);
await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, new WorkflowInput(receivedPayload), cancellationToken);
}
protected virtual IBookmark CreateBookmark() => new GatherUsingSpeakBookmark();

View file

@ -9,6 +9,7 @@ using Elsa.Activities.Telnyx.Webhooks.Attributes;
using Elsa.Activities.Telnyx.Webhooks.Payloads.Abstract;
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
using Elsa.Metadata;
using Elsa.Providers.Activities;
using Elsa.Services;
using Elsa.Services.Models;
@ -58,19 +59,26 @@ namespace Elsa.Activities.Telnyx.Providers.ActivityTypes
private async Task<ActivityType> CreateWebhookActivityTypeAsync(Type payloadType, WebhookAttribute webhookAttribute, CancellationToken cancellationToken)
{
var descriptor = await _describesActivityType.DescribeAsync<Webhook>(cancellationToken);
async ValueTask<ActivityDescriptor> CreateDescriptorAsync()
{
var des = await _describesActivityType.DescribeAsync<Webhook>(cancellationToken);
descriptor.Description = webhookAttribute.Description;
descriptor.DisplayName = webhookAttribute.DisplayName;
descriptor.Type = webhookAttribute.ActivityType;
des.Description = webhookAttribute.Description;
des.DisplayName = webhookAttribute.DisplayName;
des.Type = webhookAttribute.ActivityType;
var outputProperties = descriptor.OutputProperties.Where(x => x.Name != nameof(Webhook.Output)).ToList();
outputProperties.Add(new ActivityOutputDescriptor(nameof(Webhook.Output), payloadType));
descriptor.OutputProperties = outputProperties.ToArray();
var outputProperties = des.OutputProperties.Where(x => x.Name != nameof(Webhook.Output)).ToList();
outputProperties.Add(new ActivityOutputDescriptor(nameof(Webhook.Output), payloadType));
des.OutputProperties = outputProperties.ToArray();
return des;
}
var descriptor = await CreateDescriptorAsync();
return new ActivityType
{
Describe = () => descriptor,
DescribeAsync = CreateDescriptorAsync,
Description = descriptor.Description,
DisplayName = descriptor.DisplayName,
TypeName = descriptor.Type,

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Elsa.Activities.Telnyx.Providers.ActivityTypes;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Activities;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Telnyx.Providers.Bookmarks

View file

@ -7,7 +7,9 @@ using Elsa.Activities.Telnyx.Webhooks.Events;
using Elsa.Activities.Telnyx.Webhooks.Payloads.Abstract;
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
using Elsa.Activities.Telnyx.Webhooks.Services;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
using MediatR;
using Microsoft.Extensions.Logging;
@ -41,9 +43,9 @@ namespace Elsa.Activities.Telnyx.Webhooks.Handlers
var correlationId = GetCorrelationId(payload);
var bookmark = new NotificationBookmark(eventType);
var context = new CollectWorkflowsContext(activityType, bookmark, correlationId);
var context = new WorkflowsQuery(activityType, bookmark, correlationId);
await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, webhook, cancellationToken);
await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, new WorkflowInput(webhook), cancellationToken);
}
private string GetCorrelationId(Payload payload)

View file

@ -1,7 +0,0 @@
namespace Elsa.Activities.Telnyx.Webhooks.Messages
{
public class WebhookReceived
{
}
}

View file

@ -1,4 +1,5 @@
using Elsa.Activities.Telnyx.Webhooks.Attributes;
using NodaTime;
namespace Elsa.Activities.Telnyx.Webhooks.Payloads.Call
{
@ -11,5 +12,6 @@ namespace Elsa.Activities.Telnyx.Webhooks.Payloads.Call
public string State { get; init; } = default!;
public string To { get; init; } = default!;
public string From { get; init; } = default!;
public Instant StartTime { get; set; } = default!;
}
}

View file

@ -2,6 +2,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
using NodaTime;

View file

@ -2,6 +2,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
using NodaTime;

View file

@ -2,6 +2,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
using NodaTime;

View file

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.UserTask.Bookmarks

View file

@ -7,6 +7,7 @@ using Elsa.Design;
using Elsa.Expressions;
using Elsa.Metadata;
using Elsa.Persistence.Specifications;
using Elsa.Providers.Activities;
using Elsa.Services;
using Elsa.Services.Models;
using Elsa.Webhooks.Models;
@ -53,52 +54,57 @@ namespace Elsa.Activities.Webhooks.ActivityTypes
var activityTypeName = webhook.Name.EndsWith(WebhooksActivityTypeSuffix) ? webhook.Name : $"{webhook.Name}{WebhooksActivityTypeSuffix}";
var activityDisplayName = activityTypeName.Humanize();
var descriptor = new ActivityDescriptor
ValueTask<ActivityDescriptor> CreateDescriptorAsync()
{
Type = activityTypeName,
DisplayName = activityDisplayName,
Category = WebhooksActivityCategory,
Outcomes = new[] { OutcomeNames.Done },
Traits = ActivityTraits.Trigger,
InputProperties = new[]
var descriptor = new ActivityDescriptor
{
new ActivityInputDescriptor(
nameof(HttpEndpoint.Path),
typeof(PathString),
ActivityInputUIHints.SingleLine,
"Path",
"The relative path that triggers this activity.",
null,
default,
0,
webhook.Path,
SyntaxNames.Literal,
new[] { SyntaxNames.Literal },
true
Type = activityTypeName!,
DisplayName = activityDisplayName!,
Category = WebhooksActivityCategory,
Outcomes = new[] { OutcomeNames.Done },
Traits = ActivityTraits.Trigger,
InputProperties = new[]
{
new ActivityInputDescriptor(
nameof(HttpEndpoint.Path),
typeof(PathString),
ActivityInputUIHints.SingleLine,
"Path",
"The relative path that triggers this activity.",
null,
default,
0,
webhook.Path,
SyntaxNames.Literal,
new[] { SyntaxNames.Literal },
true
),
new ActivityInputDescriptor(
nameof(HttpEndpoint.Methods),
typeof(HashSet<string>),
ActivityInputUIHints.CheckList,
"Request Method",
"Specify what request method this webhook should handle. Leave empty to handle both GET and POST requests",
new[] { "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD" },
default,
1,
new[] { "GET", "POST" },
SyntaxNames.Json,
new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid }
new ActivityInputDescriptor(
nameof(HttpEndpoint.Methods),
typeof(HashSet<string>),
ActivityInputUIHints.CheckList,
"Request Method",
"Specify what request method this webhook should handle. Leave empty to handle both GET and POST requests",
new[] { "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD" },
default,
1,
new[] { "GET", "POST" },
SyntaxNames.Json,
new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid }
)
},
OutputProperties = new[]
{
new ActivityOutputDescriptor
(
"Request",
typeof(Models.WebhookRequestModel),
"The received HTTP request."
)
}
},
OutputProperties = new[]
{
new ActivityOutputDescriptor
(
"Request",
typeof(Models.WebhookRequestModel),
"The received HTTP request."
)
}
};
return new ValueTask<ActivityDescriptor>(descriptor);
};
async ValueTask<IActivity> ActivateActivityAsync(ActivityExecutionContext context)
@ -122,7 +128,7 @@ namespace Elsa.Activities.Webhooks.ActivityTypes
[WebhookMarkerAttribute] = true,
["Path"] = webhook.Path,
},
Describe = () => descriptor
DescribeAsync = CreateDescriptorAsync
};
}
}

View file

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Elsa.Activities.Http;
using Elsa.Activities.Http.Bookmarks;
using Elsa.Activities.Webhooks.ActivityTypes;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa.Activities.Webhooks.Bookmarks

View file

@ -1,5 +1,7 @@
using Elsa.Activities.Webhooks.ActivityTypes;
using Elsa.Activities.Webhooks.Bookmarks;
using Elsa.Activities.Webhooks.Handlers;
using Elsa.Providers.Activities;
using Elsa.Services;
using Microsoft.Extensions.DependencyInjection;
@ -11,7 +13,8 @@ namespace Elsa.Activities.Webhooks.Extensions
{
elsaOptions.Services
.AddScoped<IActivityTypeProvider, WebhookActivityTypeProvider>()
.AddBookmarkProvider<WebhookBookmarkProvider>();
.AddBookmarkProvider<WebhookBookmarkProvider>()
.AddNotificationHandlersFrom<EvictWorkflowRegistryCacheHandler>();
return elsaOptions;
}

View file

@ -0,0 +1,29 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Caching;
using Elsa.Services.Workflows;
using Elsa.Webhooks.Events;
using MediatR;
namespace Elsa.Activities.Webhooks.Handlers
{
public class EvictWorkflowRegistryCacheHandler : INotificationHandler<WebhookDefinitionSaved>, INotificationHandler<WebhookDefinitionDeleted>
{
private readonly ICacheSignal _cacheSignal;
public EvictWorkflowRegistryCacheHandler(ICacheSignal cacheSignal)
{
_cacheSignal = cacheSignal;
}
public async Task Handle(WebhookDefinitionSaved notification, CancellationToken cancellationToken)
{
await _cacheSignal.TriggerTokenAsync(ActivityTypeService.CacheKey);
}
public async Task Handle(WebhookDefinitionDeleted notification, CancellationToken cancellationToken)
{
await _cacheSignal.TriggerTokenAsync(ActivityTypeService.CacheKey);
}
}
}

View file

@ -1,76 +0,0 @@
// using System.Threading;
// using System.Threading.Tasks;
// using Elsa.Persistence.Specifications;
// using Elsa.Services;
// using Elsa.Webhooks.Abstractions.Models;
// using Elsa.Webhooks.Abstractions.Persistence;
// using Elsa.Webhooks.Abstractions.Services;
// using MediatR;
//
// namespace Elsa.Activities.Webhooks.Services
// {
// public class WebhookPublisher : IWebhookPublisher
// {
// private readonly IWebhookDefinitionStore _webhookDefinitionStore;
// private readonly IIdGenerator _idGenerator;
// private readonly ICloner _cloner;
// private readonly IMediator _mediator;
//
// public WebhookPublisher(IWebhookDefinitionStore webhookDefinitionStore, IIdGenerator idGenerator, ICloner cloner, IMediator mediator)
// {
// _webhookDefinitionStore = webhookDefinitionStore;
// _idGenerator = idGenerator;
// _cloner = cloner;
// _mediator = mediator;
// }
//
// public WebhookDefinition New()
// {
// var definition = new WebhookDefinition
// {
// Id = _idGenerator.Generate(),
// Name = "New Webhook"
// };
//
// return definition;
// }
//
// public async Task<WebhookDefinition> SaveAsync(WebhookDefinition webhookDefinition, CancellationToken cancellationToken = default)
// {
// var webhook = webhookDefinition;
// webhook = Initialize(webhook);
//
// await _webhookDefinitionStore.SaveAsync(webhook, cancellationToken);
// return webhook;
// }
//
// public async Task<WebhookDefinition> UpdateAsync(WebhookDefinition webhookDefinition, CancellationToken cancellationToken = default)
// {
// var webhook = webhookDefinition;
// webhook = Initialize(webhook);
//
// await _webhookDefinitionStore.UpdateAsync(webhook, cancellationToken);
// return webhook;
// }
//
// public async Task DeleteAsync(string webhookId, CancellationToken cancellationToken = default)
// {
// var webhookDefinition = New();
// if (!string.IsNullOrWhiteSpace(webhookId))
// {
// webhookDefinition = await _webhookDefinitionStore.FindAsync(new EntityIdSpecification<WebhookDefinition>(webhookId), cancellationToken);
// }
// await _webhookDefinitionStore.DeleteAsync(webhookDefinition, cancellationToken);
// }
//
// public Task DeleteAsync(WebhookDefinition webhookDefinition, CancellationToken cancellationToken = default) => DeleteAsync(webhookDefinition, cancellationToken);
//
// private WebhookDefinition Initialize(WebhookDefinition webhookDefinition)
// {
// if (webhookDefinition.Id == null!)
// webhookDefinition.Id = _idGenerator.Generate();
//
// return webhookDefinition;
// }
// }
// }

View file

@ -1,15 +0,0 @@
// using System.Threading;
// using System.Threading.Tasks;
// using Elsa.Webhooks.Abstractions.Models;
//
// namespace Elsa.Webhooks.Abstractions.Services
// {
// public interface IWebhookPublisher
// {
// WebhookDefinition New();
// Task<WebhookDefinition> SaveAsync(WebhookDefinition webhookDefinition, CancellationToken cancellationToken = default);
// Task<WebhookDefinition> UpdateAsync(WebhookDefinition webhookDefinition, CancellationToken cancellationToken = default);
// Task DeleteAsync(string webhookId, CancellationToken cancellationToken = default);
// Task DeleteAsync(WebhookDefinition webhookDefinition, CancellationToken cancellationToken = default);
// }
// }

View file

@ -3,13 +3,8 @@ using System;
namespace Elsa.Attributes
{
[AttributeUsage(AttributeTargets.Property)]
public class ActivityInputAttribute : Attribute
public class ActivityInputAttribute : ActivityPropertyAttributeBase
{
/// <summary>
/// The technical name of the activity property.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// The user-friendly name of the activity property.
/// </summary>
@ -19,11 +14,6 @@ namespace Elsa.Attributes
/// A hint to workflow tooling what input control to use.
/// </summary>
public string? UIHint { get; set; }
/// <summary>
/// A brief description about this property for workflow tooling to use when displaying activity editors.
/// </summary>
public string? Hint { get; set; }
/// <summary>
/// A value representing options specific to a given UI hint.
@ -64,5 +54,20 @@ namespace Elsa.Attributes
/// The syntax to use by default when evaluating the value. Only used when the property definition doesn't have a syntax specified.
/// </summary>
public string[]? SupportedSyntaxes { get; set; }
/// <summary>
/// A value indicating whether this property should be displayed but as read-only.
/// </summary>
public bool? IsReadOnly { get; set; }
/// <summary>
/// A value indicating whether this property should be visible.
/// </summary>
public bool? IsBrowsable { get; set; }
/// <summary>
/// A value indicating whether this property MUST be evaluated at runtime to support the workflow designer.
/// </summary>
public bool IsDesignerCritical { get; set; }
}
}

View file

@ -3,16 +3,8 @@ using System;
namespace Elsa.Attributes
{
[AttributeUsage(AttributeTargets.Property)]
public class ActivityOutputAttribute : Attribute
public class ActivityOutputAttribute : ActivityPropertyAttributeBase
{
/// <summary>
/// The technical name of the activity property.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// A brief description about this property for workflow tooling to use when displaying activity editors.
/// </summary>
public string? Hint { get; set; }
}
}

View file

@ -0,0 +1,27 @@
using System;
namespace Elsa.Attributes
{
public abstract class ActivityPropertyAttributeBase : Attribute
{
/// <summary>
/// The technical name of the activity property.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// A brief description about this property for workflow tooling to use when displaying activity editors.
/// </summary>
public string? Hint { get; set; }
/// <summary>
/// The workflow storage provider to use by default to store the output value.
/// </summary>
public string? DefaultWorkflowStorageProvider { get; set; }
/// <summary>
/// A flag indicating whether or not the user is allowed to select a workflow provider.
/// </summary>
public bool DisableWorkflowProviderSelection { get; set; }
}
}

View file

@ -10,12 +10,7 @@ namespace Elsa.Design
public const string Dropdown = "dropdown";
public const string MultiText = "multi-text";
public const string CodeEditor = "code-editor";
/// <summary>
/// A list that allows the user to enter zero or more values.
/// </summary>
public const string DynamicList = "dynamic-list";
/// <summary>
/// An editor that allows the user to write a blob of JSON.
/// </summary>

View file

@ -0,0 +1,15 @@
using Elsa.Models;
using MediatR;
namespace Elsa.Events
{
public class WorkflowInputUpdated : INotification
{
public WorkflowInputUpdated(WorkflowInstance workflowInstance)
{
WorkflowInstance = workflowInstance;
}
public WorkflowInstance WorkflowInstance { get; }
}
}

View file

@ -0,0 +1,22 @@
using System;
namespace Elsa.Exceptions
{
public class TypeConversionException : Exception
{
public object Value { get; }
public Type TargetType { get; }
public TypeConversionException(string message, object value, Type targetType) : base(message)
{
Value = value;
TargetType = targetType;
}
public TypeConversionException(string message, object value, Type targetType, Exception innerException) : base(message, innerException)
{
Value = value;
TargetType = targetType;
}
}
}

View file

@ -3,7 +3,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa
{

View file

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using Elsa.Exceptions;
using Newtonsoft.Json.Linq;
using NodaTime;
using NodaTime.Text;
@ -53,8 +54,16 @@ namespace Elsa
if (underlyingSourceType != typeof(string))
return Enum.ToObject(underlyingTargetType, value);
}
try
{
return Convert.ChangeType(value, underlyingTargetType);
}
catch (InvalidCastException e)
{
throw new TypeConversionException($"Failed to convert an object of type {sourceType} to {underlyingTargetType}", value, underlyingTargetType, e);
}
return Convert.ChangeType(value, underlyingTargetType);
}
}
}

View file

@ -1,8 +1,8 @@
using System.Reflection;
using Elsa;
using Elsa.Providers.Workflow;
using Elsa.Providers.WorkflowContexts;
using Elsa.Services.Bookmarks;
using Elsa.Providers.Workflows;
using Elsa.Services;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection

View file

@ -3,7 +3,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Services;
using Elsa.Services.Bookmarks;
namespace Elsa
{

View file

@ -12,7 +12,7 @@ namespace Elsa
{
public static class WorkflowBlueprintExtensions
{
public static ValueTask<T?> GetActivityPropertyValue<TActivity, T>(
public static ValueTask<T?> EvaluateActivityPropertyValue<TActivity, T>(
this IWorkflowBlueprint workflowBlueprint,
string activityId,
Expression<Func<TActivity, T>> propertyExpression,
@ -21,21 +21,21 @@ namespace Elsa
{
var expression = (MemberExpression) propertyExpression.Body;
string propertyName = expression.Member.Name;
return GetActivityPropertyValue<T>(workflowBlueprint, activityId, propertyName, activityExecutionContext, cancellationToken);
return EvaluateActivityPropertyValue<T>(workflowBlueprint, activityId, propertyName, activityExecutionContext, cancellationToken);
}
public static async ValueTask<T?> GetActivityPropertyValue<T>(
public static async ValueTask<T?> EvaluateActivityPropertyValue<T>(
this IWorkflowBlueprint workflowBlueprint,
string activityId,
string propertyName,
ActivityExecutionContext activityExecutionContext,
CancellationToken cancellationToken)
{
var value = await workflowBlueprint.GetActivityPropertyValue(activityId, propertyName, activityExecutionContext, cancellationToken);
var value = await workflowBlueprint.EvaluateActivityPropertyValue(activityId, propertyName, activityExecutionContext, cancellationToken);
return value == null ? default : (T) value;
}
public static async ValueTask<object?> GetActivityPropertyValue(
public static async ValueTask<object?> EvaluateActivityPropertyValue(
this IWorkflowBlueprint workflowBlueprint,
string activityId,
string propertyName,
@ -43,12 +43,29 @@ namespace Elsa
CancellationToken cancellationToken)
{
var provider = workflowBlueprint.ActivityPropertyProviders.GetProvider(activityId, propertyName);
var value = provider != null ? await provider.GetValueAsync(activityExecutionContext, cancellationToken) : null;
if (provider == null)
return default!;
if (value == null)
{
// Get default value.
var activityTypeService = activityExecutionContext.GetService<IActivityTypeService>();
var activityBlueprint = workflowBlueprint.GetActivity(activityId)!;
var activityType = await activityTypeService.GetActivityTypeAsync(activityBlueprint.Type, cancellationToken);
var activityDescriptor = await activityTypeService.DescribeActivityType(activityType, cancellationToken);
var propertyDescriptor = activityDescriptor.InputProperties.FirstOrDefault(x => x.Name == propertyName);
var value = await provider.GetValueAsync(activityExecutionContext, cancellationToken);
return value!;
value = propertyDescriptor?.DefaultValue;
}
return value;
}
public static object? GetActivityPropertyRawValue(this IWorkflowBlueprint workflowBlueprint, string activityId, string propertyName)
{
var provider = workflowBlueprint.ActivityPropertyProviders.GetProvider(activityId, propertyName);
var value = provider?.RawValue;
return value;
}
public static IEnumerable<IWorkflowBlueprint> WithVersion(

View file

@ -21,12 +21,14 @@ namespace Elsa.Metadata
public string Category { get; set; }
public ActivityTraits Traits { get; set; }
public string[] Outcomes { get; set; }
[Obsolete("Use InputProperties instead.")]
public ActivityInputDescriptor[] Properties
{
get => InputProperties;
set => InputProperties = value;
}
public ActivityInputDescriptor[] InputProperties { get; set; }
public ActivityOutputDescriptor[] OutputProperties { get; set; }
}

View file

@ -7,7 +7,7 @@ namespace Elsa.Metadata
[Obsolete("Use ActivityInputDescriptor instead.")]
public class ActivityPropertyDescriptor : ActivityInputDescriptor
{
public ActivityPropertyDescriptor() : base()
public ActivityPropertyDescriptor()
{
}
@ -22,8 +22,9 @@ namespace Elsa.Metadata
object? defaultValue = default,
string? defaultSyntax = "Literal",
IEnumerable<string>? supportedSyntaxes = default,
bool? isDisabled = default)
: base (
bool isReadOnly = false,
bool isBrowsable = true)
: base(
name,
type,
uiHint,
@ -35,7 +36,8 @@ namespace Elsa.Metadata
defaultValue,
defaultSyntax,
supportedSyntaxes,
isDisabled
isReadOnly,
isBrowsable
)
{
}
@ -59,7 +61,11 @@ namespace Elsa.Metadata
object? defaultValue = default,
string? defaultSyntax = "Literal",
IEnumerable<string>? supportedSyntaxes = default,
bool? isDisabled = default)
bool isReadOnly = false,
bool isBrowsable = true,
bool isDesignerCritical = false,
string? defaultWorkflowStorageProvider = default,
bool disableWorkflowProviderSelection = false)
{
Name = name;
Type = type;
@ -72,7 +78,11 @@ namespace Elsa.Metadata
DefaultValue = defaultValue;
DefaultSyntax = defaultSyntax;
SupportedSyntaxes = supportedSyntaxes?.ToList() ?? new List<string>();
IsDisabled = isDisabled;
IsReadOnly = isReadOnly;
IsBrowsable = isBrowsable;
IsDesignerCritical = isDesignerCritical;
DefaultWorkflowStorageProvider = defaultWorkflowStorageProvider;
DisableWorkflowProviderSelection = disableWorkflowProviderSelection;
}
public string Name { get; set; } = default!;
@ -86,6 +96,10 @@ namespace Elsa.Metadata
public object? DefaultValue { get; set; }
public string? DefaultSyntax { get; set; }
public IList<string> SupportedSyntaxes { get; set; } = new List<string>();
public bool? IsDisabled { get; set; }
public bool? IsReadOnly { get; set; }
public bool? IsBrowsable { get; set; }
public bool IsDesignerCritical { get; set; }
public string? DefaultWorkflowStorageProvider { get; set; }
public bool DisableWorkflowProviderSelection { get; set; }
}
}

View file

@ -11,15 +11,21 @@ namespace Elsa.Metadata
public ActivityOutputDescriptor(
string name,
Type type,
string? hint = default)
string? hint = default,
string? defaultWorkflowStorageProvider = default,
bool disableWorkflowProviderSelection = false)
{
Name = name;
Type = type;
Hint = hint;
DefaultWorkflowStorageProvider = defaultWorkflowStorageProvider;
DisableWorkflowProviderSelection = disableWorkflowProviderSelection;
}
public string Name { get; set; } = default!;
public Type Type { get; set; } = default!;
public string? Hint { get; set; }
public string? DefaultWorkflowStorageProvider { get; set; }
public bool DisableWorkflowProviderSelection { get; set; }
}
}

View file

@ -6,6 +6,6 @@ namespace Elsa.Metadata
{
public interface IDescribesActivityType
{
Task<ActivityDescriptor?> DescribeAsync(Type activityType, CancellationToken cancellationToken = default);
Task<ActivityDescriptor> DescribeAsync(Type activityType, CancellationToken cancellationToken = default);
}
}

View file

@ -0,0 +1,4 @@
namespace Elsa.Models
{
public record WorkflowInput(object? Input = default, string? StorageProviderName = default);
}

View file

@ -30,6 +30,7 @@ namespace Elsa.Models
public Instant? CancelledAt { get; set; }
public Instant? FaultedAt { get; set; }
public Variables Variables { get; set; }
public WorkflowInputReference? Input { get; set; }
public WorkflowOutputReference? Output { get; set; }
public IDictionary<string, IDictionary<string, object?>> ActivityData { get; set; } = new Dictionary<string, IDictionary<string, object?>>();

View file

@ -1,5 +1,4 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Elsa.Models
@ -18,14 +17,13 @@ namespace Elsa.Models
WorkflowBurst,
/// <summary>
/// Workflow instances are persisted after the workflow executed scheduled activities.
/// Workflow instances are persisted after the workflow executed an activity.
/// </summary>
WorkflowPassCompleted,
/// <summary>
/// Workflow instances are persisted after each activity that executed.
/// </summary>
[Obsolete("Use WorkflowPassCompleted instead")]
ActivityExecuted
}
}

View file

@ -3,7 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using Elsa.Services.Models;
namespace Elsa.Services
namespace Elsa.Providers.Activities
{
public interface IActivityTypeProvider
{

View file

@ -3,7 +3,7 @@ using System.Threading;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Providers.Workflow
namespace Elsa.Providers.Workflows
{
/// <summary>
/// Represents a source of workflows for the <see cref="IWorkflowRegistry"/>

View file

@ -2,10 +2,9 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Providers.Workflow;
using Elsa.Services.Models;
namespace Elsa.Services
namespace Elsa.Providers.Workflows
{
public abstract class WorkflowProvider : IWorkflowProvider
{

View file

@ -1,4 +1,4 @@
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public class BookmarkFinderResult
{

View file

@ -1,4 +1,4 @@
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public enum BookmarkIndexingMode
{

View file

@ -3,7 +3,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public abstract class BookmarkProvider<T> : IBookmarkProvider where T : IBookmark
{

View file

@ -4,7 +4,7 @@ using System.Threading;
using System.Threading.Tasks;
using Elsa.Services.Models;
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public class BookmarkProviderContext
{

View file

@ -1,4 +1,4 @@
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public record BookmarkResult(IBookmark Bookmark, string? ActivityTypeName = default);
}

View file

@ -1,6 +1,6 @@
using Elsa.Services.Models;
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public class BookmarkedWorkflow
{

View file

@ -1,4 +1,4 @@
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public interface IBookmark
{

View file

@ -2,7 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public interface IBookmarkFinder
{

View file

@ -1,4 +1,4 @@
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public interface IBookmarkHasher
{

View file

@ -3,7 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using Elsa.Models;
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public interface IBookmarkIndexer
{

View file

@ -2,7 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public interface IBookmarkProvider
{

View file

@ -1,4 +1,4 @@
namespace Elsa.Services.Bookmarks
namespace Elsa.Services
{
public class NullBookmark : IBookmark
{

View file

@ -1,10 +1,10 @@
using Elsa.Services.Bookmarks;
using Elsa.Models;
namespace Elsa.Services
{
public record TriggerWorkflowsRequest(string ActivityType, IBookmark Bookmark, object? Input = default, string? CorrelationId = default, string? WorkflowInstanceId = default, string? ContextId = default, string? TenantId = default);
public record TriggerWorkflowsRequest(string ActivityType, IBookmark Bookmark, WorkflowInput? Input = default, string? CorrelationId = default, string? WorkflowInstanceId = default, string? ContextId = default, string? TenantId = default);
public record ExecuteWorkflowDefinitionRequest(string WorkflowDefinitionId, string? ActivityId = default, object? Input = default, string? CorrelationId = default, string? ContextId = default, string? TenantId = default);
public record ExecuteWorkflowDefinitionRequest(string WorkflowDefinitionId, string? ActivityId = default, WorkflowInput? Input = default, string? CorrelationId = default, string? ContextId = default, string? TenantId = default);
public record ExecuteWorkflowInstanceRequest(string WorkflowInstanceId, string? ActivityId, object? Input = default);
public record ExecuteWorkflowInstanceRequest(string WorkflowInstanceId, string? ActivityId = default, WorkflowInput? Input = default);
}

View file

@ -26,7 +26,7 @@ namespace Elsa.Services.Models
// Computed property setters that depend on actual workflow state might fault, since we might be using a fake activity execution context.
try
{
return await workflowBlueprint.GetActivityPropertyValue(activityId, propertyName, ActivityExecutionContext, cancellationToken);
return await workflowBlueprint.EvaluateActivityPropertyValue(activityId, propertyName, ActivityExecutionContext, cancellationToken);
}
catch (Exception)
{
@ -52,7 +52,7 @@ namespace Elsa.Services.Models
// Computed property setters that depend on actual workflow state might fault, since we might be using a fake activity execution context.
try
{
return await workflowBlueprint.GetActivityPropertyValue(activityId, propertyExpression, ActivityExecutionContext, cancellationToken);
return await workflowBlueprint.EvaluateActivityPropertyValue(activityId, propertyExpression, ActivityExecutionContext, cancellationToken);
}
catch (Exception)
{

View file

@ -180,7 +180,7 @@ namespace Elsa.Services.Models
public T GetWorkflowContext<T>() => WorkflowExecutionContext.GetWorkflowContext<T>();
public IDictionary<string, object?> GetActivityData() => GetActivityData(ActivityId);
public IDictionary<string, object?> GetActivityData(string activityId) => WorkflowExecutionContext.GetActivityData(activityId);
public Task<T?> GetActivityPropertyAsync<TActivity, T>(Expression<Func<TActivity, T>> propertyExpression, CancellationToken cancellationToken = default) where TActivity : IActivity => WorkflowExecutionContext.GetActivityPropertyAsync<TActivity, T>(ActivityId, propertyExpression, cancellationToken);
public Task<T?> GetActivityPropertyAsync<TActivity, T>(Expression<Func<TActivity, T>> propertyExpression, CancellationToken cancellationToken = default) where TActivity : IActivity => WorkflowExecutionContext.GetActivityPropertyAsync(ActivityId, propertyExpression, cancellationToken);
public void Fault(Exception exception) => WorkflowExecutionContext.Fault(exception, ActivityId, Input, Resuming);
private ICompositeActivityBlueprint GetContainerActivity()

View file

@ -50,7 +50,7 @@ namespace Elsa.Services.Models
/// </summary>
public Func<ActivityExecutionContext, IActivity,ValueTask<IActivityExecutionResult>> ResumeAsync { get; set; } = (_, _) => new ValueTask<IActivityExecutionResult>(new DoneResult());
public Func<ActivityDescriptor> Describe { get; set; } = () => new ActivityDescriptor();
public Func<ValueTask<ActivityDescriptor>> DescribeAsync { get; set; } = () => new ValueTask<ActivityDescriptor>(new ActivityDescriptor());
public bool IsBrowsable { get; set; } = true;
public IDictionary<string, object> Attributes { get; set; } = new Dictionary<string, object>();

Some files were not shown because too many files have changed in this diff Show more