Merge branch 'develop'

# Conflicts:
#	Samples.sln
#	src/activities/Elsa.Activities.Timers/Elsa.Activities.Timers.csproj
#	src/core/Elsa.Abstractions/Services/IActivityBuilder.cs
#	src/core/Elsa.Core/Elsa.Core.csproj
#	src/core/Elsa.Core/WorkflowBuilders/ActivityBuilder.cs
#	src/samples/Sample17/Activities/CreatePerson.cs
#	src/samples/Sample17/CreatePersonWorkflow.cs
#	src/samples/Sample17/Program.cs
#	src/samples/Sample17/Sample17.csproj
This commit is contained in:
Sipke Schoorstra 2019-10-27 16:05:55 +01:00
commit bc04b00196
144 changed files with 2099 additions and 1314 deletions

View file

@ -37,8 +37,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.YesSql", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.UserTask", "src\activities\Elsa.Activities.UserTask\Elsa.Activities.UserTask.csproj", "{BC0F57E2-AB64-4026-B6E3-E03D9133DB26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.AutoMapper.Extensions", "src\core\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj", "{6CEF6AFB-635D-4FB4-B9EC-0806DD95E1BC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Persistence.EntityFrameworkCore", "src\persistence\Elsa.Persistence.EntityFrameworkCore\Elsa.Persistence.EntityFrameworkCore.csproj", "{349D4C87-E17F-4F51-B493-1994BF631D37}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dashboard", "dashboard", "{8B87D79A-F0DE-4F88-81D3-8C8C69108ADB}"
@ -53,6 +51,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.DocumentDb
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.Dropbox", "src\activities\Elsa.Activities.Dropbox\Elsa.Activities.Dropbox.csproj", "{5A3C9D59-21FE-4BE3-A00A-FF3F198EEC97}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{9E1AF14C-0BEC-4BC2-810C-85FC25A9DDD4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripting", "scripting", "{5E230C5F-7A64-4E95-A790-DF40CC66DA31}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.AutoMapper.Extensions", "src\utils\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj", "{72DA50EC-8A99-4D4F-BF61-DEF105BDAE10}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Scripting.JavaScript", "src\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj", "{DA91DAF2-4C59-4468-8F1D-6A500D218A1E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Scripting.Liquid", "src\scripting\Elsa.Scripting.Liquid\Elsa.Scripting.Liquid.csproj", "{9A2D1E3E-328F-4E02-86F8-84974925C1E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.ControlFlow", "src\activities\Elsa.Activities.ControlFlow\Elsa.Activities.ControlFlow.csproj", "{3FC85C9D-CC20-4F54-9936-029F19FBFBE1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.Workflows", "src\activities\Elsa.Activities.Workflows\Elsa.Activities.Workflows.csproj", "{1BB8EC9E-AEBD-438B-9FA7-B7FA78999D7D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa", "src\core\Elsa\Elsa.csproj", "{ED2A4FE5-821B-46F7-B72F-E66DE0D66C93}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -95,10 +109,6 @@ Global
{BC0F57E2-AB64-4026-B6E3-E03D9133DB26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC0F57E2-AB64-4026-B6E3-E03D9133DB26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC0F57E2-AB64-4026-B6E3-E03D9133DB26}.Release|Any CPU.Build.0 = Release|Any CPU
{6CEF6AFB-635D-4FB4-B9EC-0806DD95E1BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CEF6AFB-635D-4FB4-B9EC-0806DD95E1BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CEF6AFB-635D-4FB4-B9EC-0806DD95E1BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CEF6AFB-635D-4FB4-B9EC-0806DD95E1BC}.Release|Any CPU.Build.0 = Release|Any CPU
{349D4C87-E17F-4F51-B493-1994BF631D37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{349D4C87-E17F-4F51-B493-1994BF631D37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{349D4C87-E17F-4F51-B493-1994BF631D37}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -123,6 +133,30 @@ Global
{5A3C9D59-21FE-4BE3-A00A-FF3F198EEC97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A3C9D59-21FE-4BE3-A00A-FF3F198EEC97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A3C9D59-21FE-4BE3-A00A-FF3F198EEC97}.Release|Any CPU.Build.0 = Release|Any CPU
{72DA50EC-8A99-4D4F-BF61-DEF105BDAE10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72DA50EC-8A99-4D4F-BF61-DEF105BDAE10}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72DA50EC-8A99-4D4F-BF61-DEF105BDAE10}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72DA50EC-8A99-4D4F-BF61-DEF105BDAE10}.Release|Any CPU.Build.0 = Release|Any CPU
{DA91DAF2-4C59-4468-8F1D-6A500D218A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA91DAF2-4C59-4468-8F1D-6A500D218A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA91DAF2-4C59-4468-8F1D-6A500D218A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA91DAF2-4C59-4468-8F1D-6A500D218A1E}.Release|Any CPU.Build.0 = Release|Any CPU
{9A2D1E3E-328F-4E02-86F8-84974925C1E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A2D1E3E-328F-4E02-86F8-84974925C1E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A2D1E3E-328F-4E02-86F8-84974925C1E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A2D1E3E-328F-4E02-86F8-84974925C1E3}.Release|Any CPU.Build.0 = Release|Any CPU
{3FC85C9D-CC20-4F54-9936-029F19FBFBE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3FC85C9D-CC20-4F54-9936-029F19FBFBE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FC85C9D-CC20-4F54-9936-029F19FBFBE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FC85C9D-CC20-4F54-9936-029F19FBFBE1}.Release|Any CPU.Build.0 = Release|Any CPU
{1BB8EC9E-AEBD-438B-9FA7-B7FA78999D7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BB8EC9E-AEBD-438B-9FA7-B7FA78999D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BB8EC9E-AEBD-438B-9FA7-B7FA78999D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BB8EC9E-AEBD-438B-9FA7-B7FA78999D7D}.Release|Any CPU.Build.0 = Release|Any CPU
{ED2A4FE5-821B-46F7-B72F-E66DE0D66C93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED2A4FE5-821B-46F7-B72F-E66DE0D66C93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED2A4FE5-821B-46F7-B72F-E66DE0D66C93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED2A4FE5-821B-46F7-B72F-E66DE0D66C93}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -140,7 +174,6 @@ Global
{76710230-AC6D-4E54-9A06-15F34C155118} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{4DB0741F-EAD9-4E37-862D-A1DA12462B7D} = {76710230-AC6D-4E54-9A06-15F34C155118}
{BC0F57E2-AB64-4026-B6E3-E03D9133DB26} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{6CEF6AFB-635D-4FB4-B9EC-0806DD95E1BC} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
{349D4C87-E17F-4F51-B493-1994BF631D37} = {76710230-AC6D-4E54-9A06-15F34C155118}
{8B87D79A-F0DE-4F88-81D3-8C8C69108ADB} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{493FC3E3-34FE-4F8D-AF37-38A5F5541FBD} = {8B87D79A-F0DE-4F88-81D3-8C8C69108ADB}
@ -148,6 +181,14 @@ Global
{120E4BF9-4A42-4BB9-A0B2-9597160D6E37} = {8B87D79A-F0DE-4F88-81D3-8C8C69108ADB}
{39EBECE7-538B-431C-AAB7-901AB16E6D4A} = {76710230-AC6D-4E54-9A06-15F34C155118}
{5A3C9D59-21FE-4BE3-A00A-FF3F198EEC97} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{9E1AF14C-0BEC-4BC2-810C-85FC25A9DDD4} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{5E230C5F-7A64-4E95-A790-DF40CC66DA31} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{72DA50EC-8A99-4D4F-BF61-DEF105BDAE10} = {9E1AF14C-0BEC-4BC2-810C-85FC25A9DDD4}
{DA91DAF2-4C59-4468-8F1D-6A500D218A1E} = {5E230C5F-7A64-4E95-A790-DF40CC66DA31}
{9A2D1E3E-328F-4E02-86F8-84974925C1E3} = {5E230C5F-7A64-4E95-A790-DF40CC66DA31}
{3FC85C9D-CC20-4F54-9936-029F19FBFBE1} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{1BB8EC9E-AEBD-438B-9FA7-B7FA78999D7D} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{ED2A4FE5-821B-46F7-B72F-E66DE0D66C93} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}

167
README.md
View file

@ -10,6 +10,41 @@ Workflows can be defined not only using code but also as JSON, YAML or XML.
Follow the [Getting Started](https://elsa-workflows.github.io/elsa-core/docs/installing-elsa-core) instructions on the [Elsa Workflows documentation site](https://elsa-workflows.github.io/elsa-core).
## Roadmap
Version 1.0
- [x] Workflow Invoker
- [x] Long-running Workflows
- [x] Workflows as code
- [x] Workflows as data
- [x] Correlation
- [x] Persistence: CosmosDB, Entity Framework Core, MongoDB, YesSQL
- [x] HTML5 Workflow Designer Web Component
- [x] ASP.NET Core Workflow Dashboard
- [x] JavaScript Expressions
- [x] Liquid Expressions
- [x] Primitive Activities
- [X] Control Flow Activities
- [x] Workflow Activities
- [x] Timer Activities
- [x] HTTP Activities
- [x] Email Activities
Version 2.0
- [ ] Service Bus Messaging
- [ ] Generic Command & Event Activities
- [ ] Workflow Host REST API
- [ ] Workflow Host gRPC API
- [ ] Distributed Hosting Support (support for multi-node environments)
- [ ] Localization Support
Version 3.0
- [ ] State Machines
- [ ] Container Activities
## Workflow Designer
Workflows can be visually designed using [Elsa Designer](https://github.com/elsa-workflows/elsa-designer-html), a reusable & extensible HTML5 web component built with [StencilJS](https://stenciljs.com/).
@ -69,107 +104,6 @@ The following providers will be supported:
Currently, workflows can be stored in YAML or JSON format.
The following demonstrates a simple workflow expressed in YAML and JSON, respectively:
**YAML**
```yaml
activities:
- name: WriteLine
id: activity-1
textExpression:
syntax: PlainText
expression: Hi! What's your name?
- name: ReadLine
id: activity-2
argumentName: name
- name: WriteLine
id: activity-3
textExpression:
syntax: JavaScript
expression: '`Nice to meet you, ${name}!`'
connections:
- source:
activityId: activity-1
name: Done
target:
activityId: activity-2
- source:
activityId: activity-2
name: Done
target:
activityId: activity-3
```
**JSON**
```json
{
"activities": [
{
"name": "WriteLine",
"id": "activity-1",
"textExpression": {
"syntax": "PlainText",
"expression": "Hi! What's your name?"
}
},
{
"id": "activity-2",
"name": "ReadLine",
"argumentName": "name"
},
{
"name": "WriteLine",
"id": "activity-3",
"textExpression": {
"syntax": "JavaScript",
"expression": "`Nice to meet you, ${name}!`"
}
}
],
"connections": [
{
"source": {
"activityId": "activity-1",
"name": "Done"
},
"target": {
"activityId": "activity-2"
}
},
{
"source": {
"activityId": "activity-2",
"name": "Done"
},
"target": {
"activityId": "activity-3"
}
}
]
}
```
The following demonstrates loading a workflow from a YAML string:
```c#
// Setup a service collection and use the FileSystemProvider for both workflow definitions and workflow instances.
var services = new ServiceCollection()
.AddWorkflowsInvoker()
.AddConsoleActivities()
.AddSingleton(Console.In)
.BuildServiceProvider();
// Load the data and specify data format.
var data = Resources.SampleWorkflowDefinition;
var format = YamlTokenFormatter.FormatName; // "YAML"
// Deserialize the workflow from data.
var serializer = services.GetService<IWorkflowSerializer>();
var workflowDefinition = await serializer.DeserializeAsync(data, format, CancellationToken.None);
// Invoke the workflow.
var invoker = services.GetService<IWorkflowInvoker>();
await invoker.InvokeAsync(workflowDefinition);
```
## Long Running Workflows
Elsa has native support for long-running workflows. As soon as a workflow is halted because of some blocking activity, the workflow is persisted.
@ -240,35 +174,12 @@ TODO: describe all the steps to add packages and register services.
TODO: describe all the steps to add packages and register services.
## Running Elsa Workflows Dashboard
### Building & Running Elsa Workflows Dashboard
In order to run Elsa on your local machine, follow these steps:
In order to build & run Elsa on your local machine, follow these steps:
1. Clone the repository.
2. Run NPM install on all folders containing packages.json (or run `node npm-install.js` - a script in the root that recursively installs the Node packages)
3. Execute gulp build from the directory src\dashboard\Elsa.Dashboard\Theme\argon-dashboard
4. Open a shell and navigate to `src/samples/SampleDashboard.Web` and run `dotnet run`.
5. Navigate to https://localhost:44397/elsa/home
## Running Elsa Workflows Host
(TODO)
## Roadmap
(TODO)
- Describe all the features (core engine, runtime, webbased designer, YAML, scripting, separation of designer from invoker from engine).
- Describe various use cases.
- Describe how to use.
- Describe architecture.
- Describe how to implement (custom host, custom dashboard).
- Implement more activities
- Implement integration with Orchard Core (separate repo)
- Detailed documentation
- Open API Activity Harvester
- MassTransit Activity Harvester
- RabbitMQ Activities
- Azure Service Bus Activities
- Automatic UI for Activity Editor
4. Open a shell and navigate to `src/samples/Sample16` and run `dotnet run`.
5. Navigate to https://localhost:8632/elsa/home

View file

@ -57,8 +57,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.YesSql", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample10", "src\samples\Sample10\Sample10.csproj", "{E0076858-353F-4302-9690-920204E38BF6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.AutoMapper.Extensions", "src\core\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj", "{F7633BE5-0335-4148-8FB7-EAED9A2276A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample11", "src\samples\Sample11\Sample11.csproj", "{0C3BB425-2FED-4ADF-8DBE-D68DF0CA5A41}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.UserTask", "src\activities\Elsa.Activities.UserTask\Elsa.Activities.UserTask.csproj", "{823F80B6-E241-43F7-83BD-29FBB58A77F9}"
@ -89,6 +87,24 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample16", "src\samples\Sam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample17", "src\samples\Sample17\Sample17.csproj", "{8854DF17-D566-49C9-8210-68AB8F5659FA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripting", "scripting", "{9C3C685E-3D7D-4638-A031-24F71CF74B52}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.ControlFlow", "src\activities\Elsa.Activities.ControlFlow\Elsa.Activities.ControlFlow.csproj", "{1F8E7DFB-824E-4B9F-9866-482B191CF005}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.Workflows", "src\activities\Elsa.Activities.Workflows\Elsa.Activities.Workflows.csproj", "{9017817D-A3D1-4068-97BF-FCA1EF3BFC50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa", "src\core\Elsa\Elsa.csproj", "{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Scripting.JavaScript", "src\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj", "{18BE8F72-E528-4617-B1B1-07BD35337DFC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Scripting.Liquid", "src\scripting\Elsa.Scripting.Liquid\Elsa.Scripting.Liquid.csproj", "{01DC21DD-C6E2-4B21-864E-97D29448F777}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{0D276728-DDA8-46A0-91A9-D44401D66DA9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.AutoMapper.Extensions", "src\utils\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj", "{102626A4-8BA6-45A8-A69C-F5EB1F155BE7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample18", "src\samples\Sample18\Sample18.csproj", "{616AA0BA-FBDD-4ABE-B688-A3F79F38C698}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -167,10 +183,6 @@ Global
{E0076858-353F-4302-9690-920204E38BF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0076858-353F-4302-9690-920204E38BF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0076858-353F-4302-9690-920204E38BF6}.Release|Any CPU.Build.0 = Release|Any CPU
{F7633BE5-0335-4148-8FB7-EAED9A2276A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7633BE5-0335-4148-8FB7-EAED9A2276A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7633BE5-0335-4148-8FB7-EAED9A2276A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7633BE5-0335-4148-8FB7-EAED9A2276A2}.Release|Any CPU.Build.0 = Release|Any CPU
{0C3BB425-2FED-4ADF-8DBE-D68DF0CA5A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C3BB425-2FED-4ADF-8DBE-D68DF0CA5A41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C3BB425-2FED-4ADF-8DBE-D68DF0CA5A41}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -227,6 +239,34 @@ Global
{8854DF17-D566-49C9-8210-68AB8F5659FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8854DF17-D566-49C9-8210-68AB8F5659FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8854DF17-D566-49C9-8210-68AB8F5659FA}.Release|Any CPU.Build.0 = Release|Any CPU
{1F8E7DFB-824E-4B9F-9866-482B191CF005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F8E7DFB-824E-4B9F-9866-482B191CF005}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F8E7DFB-824E-4B9F-9866-482B191CF005}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F8E7DFB-824E-4B9F-9866-482B191CF005}.Release|Any CPU.Build.0 = Release|Any CPU
{9017817D-A3D1-4068-97BF-FCA1EF3BFC50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9017817D-A3D1-4068-97BF-FCA1EF3BFC50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9017817D-A3D1-4068-97BF-FCA1EF3BFC50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9017817D-A3D1-4068-97BF-FCA1EF3BFC50}.Release|Any CPU.Build.0 = Release|Any CPU
{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B}.Release|Any CPU.Build.0 = Release|Any CPU
{18BE8F72-E528-4617-B1B1-07BD35337DFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18BE8F72-E528-4617-B1B1-07BD35337DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18BE8F72-E528-4617-B1B1-07BD35337DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18BE8F72-E528-4617-B1B1-07BD35337DFC}.Release|Any CPU.Build.0 = Release|Any CPU
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.Build.0 = Release|Any CPU
{102626A4-8BA6-45A8-A69C-F5EB1F155BE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{102626A4-8BA6-45A8-A69C-F5EB1F155BE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{102626A4-8BA6-45A8-A69C-F5EB1F155BE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{102626A4-8BA6-45A8-A69C-F5EB1F155BE7}.Release|Any CPU.Build.0 = Release|Any CPU
{616AA0BA-FBDD-4ABE-B688-A3F79F38C698}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{616AA0BA-FBDD-4ABE-B688-A3F79F38C698}.Debug|Any CPU.Build.0 = Debug|Any CPU
{616AA0BA-FBDD-4ABE-B688-A3F79F38C698}.Release|Any CPU.ActiveCfg = Release|Any CPU
{616AA0BA-FBDD-4ABE-B688-A3F79F38C698}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -253,7 +293,6 @@ Global
{600C4AE0-0585-4181-9CEC-2BB43430C713} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{905C1067-2119-443D-B5FE-DA8E027FAD62} = {600C4AE0-0585-4181-9CEC-2BB43430C713}
{E0076858-353F-4302-9690-920204E38BF6} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{F7633BE5-0335-4148-8FB7-EAED9A2276A2} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
{0C3BB425-2FED-4ADF-8DBE-D68DF0CA5A41} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{823F80B6-E241-43F7-83BD-29FBB58A77F9} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{D0F68FBB-17C6-421E-B8AE-AAAFE111BF0B} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
@ -270,6 +309,15 @@ Global
{8C51A528-F9B5-464E-AAD1-1ADC44697085} = {600C4AE0-0585-4181-9CEC-2BB43430C713}
{DFE72CF4-C77C-4932-A00F-A8D325E603CE} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{8854DF17-D566-49C9-8210-68AB8F5659FA} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{9C3C685E-3D7D-4638-A031-24F71CF74B52} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{1F8E7DFB-824E-4B9F-9866-482B191CF005} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{9017817D-A3D1-4068-97BF-FCA1EF3BFC50} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
{6BB5EB72-AD9A-41ED-A6AA-0FF1093EA41B} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
{18BE8F72-E528-4617-B1B1-07BD35337DFC} = {9C3C685E-3D7D-4638-A031-24F71CF74B52}
{01DC21DD-C6E2-4B21-864E-97D29448F777} = {9C3C685E-3D7D-4638-A031-24F71CF74B52}
{0D276728-DDA8-46A0-91A9-D44401D66DA9} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{102626A4-8BA6-45A8-A69C-F5EB1F155BE7} = {0D276728-DDA8-46A0-91A9-D44401D66DA9}
{616AA0BA-FBDD-4ABE-B688-A3F79F38C698} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}

View file

@ -13,11 +13,8 @@ namespace Elsa.Activities.Console.Activities
/// </summary>
[ActivityDefinition(
Category = "Console",
Description = "Read text from standard in."
)]
[ActivityDefinitionDesigner(
Description =
"a => !!a.state.variableName ? `Read text from standard in and store into <strong>${ a.state.variableName }</strong>.` : 'Read text from standard in.'",
Description = "Read text from standard in.",
RuntimeDescription = "a => !!a.state.variableName ? `Read text from standard in and store into <strong>${ a.state.variableName }</strong>.` : 'Read text from standard in.'",
Outcomes = new[] { OutcomeNames.Done }
)]
public class ReadLine : Activity

View file

@ -15,11 +15,8 @@ namespace Elsa.Activities.Console.Activities
/// </summary>
[ActivityDefinition(
Category = "Console",
Description = "Write text to standard out."
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.textExpression ? `Write <strong>${ x.state.textExpression.expression }</strong> to standard out.` : x.definition.description",
Description = "Write text to standard out.",
RuntimeDescription = "x => !!x.state.textExpression ? `Write <strong>${ x.state.textExpression.expression }</strong> to standard out.` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class WriteLine : Activity

View file

@ -17,8 +17,4 @@
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
</ItemGroup>
</Project>

View file

@ -1,70 +1,71 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow
{
[ActivityDefinition(Category = "Control Flow", Description = "Iterate over a collection.", Icon = "far fa-circle")]
public class ForEach : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public ForEach(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "Enter an expression that evaluates to an array of items to iterate over.")]
public WorkflowExpression<IList<object>> CollectionExpression
{
get => GetState(() => new JavaScriptExpression<IList<object>>("[]"));
set => SetState(value);
}
[ActivityProperty(Hint = "Enter a name for the iterator variable.")]
public string IteratorName
{
get => GetState(() => "CurrentValue");
set => SetState(value);
}
public int CurrentIndex
{
get => GetState(() => 0);
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext context,
CancellationToken cancellationToken)
{
var collection = await expressionEvaluator.EvaluateAsync(CollectionExpression, context, cancellationToken);
var index = CurrentIndex;
if (index >= collection.Count)
{
context.EndScope();
CurrentIndex = 0;
return Done();
}
var value = collection[index];
CurrentIndex++;
if (index == 0)
{
context.BeginScope();
}
context.CurrentScope.SetVariable(IteratorName, value);
return Outcome(OutcomeNames.Iterate);
}
}
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow.Activities
{
[ActivityDefinition(Category = "Control Flow", Description = "Iterate over a collection.", Icon = "far fa-circle")]
public class ForEach : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public ForEach(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "Enter an expression that evaluates to an array of items to iterate over.")]
public WorkflowExpression<IList<object>> CollectionExpression
{
get => GetState(() => new JavaScriptExpression<IList<object>>("[]"));
set => SetState(value);
}
[ActivityProperty(Hint = "Enter a name for the iterator variable.")]
public string IteratorName
{
get => GetState(() => "CurrentValue");
set => SetState(value);
}
public int CurrentIndex
{
get => GetState(() => 0);
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext context,
CancellationToken cancellationToken)
{
var collection = await expressionEvaluator.EvaluateAsync(CollectionExpression, context, cancellationToken);
var index = CurrentIndex;
if (index >= collection.Count)
{
context.EndScope();
CurrentIndex = 0;
return Done();
}
var value = collection[index];
CurrentIndex++;
if (index == 0)
{
context.BeginScope();
}
context.CurrentScope.SetVariable(IteratorName, value);
return Outcome(OutcomeNames.Iterate);
}
}
}

View file

@ -1,30 +1,30 @@
using System.Collections.Generic;
using Elsa.Attributes;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow
{
[ActivityDefinition(
Category = "Control Flow",
Description = "Fork workflow execution into multiple branches.",
Icon = "fas fa-code-branch fa-rotate-180")]
[ActivityDefinitionDesigner(Outcomes = "x => x.state.branches")]
public class Fork : Activity
{
[ActivityProperty(
Hint = "Enter one or more names representing branches, separated with a comma. Example: Branch 1, Branch 2"
)]
public IList<string> Branches
{
get => GetState(() => new List<string>());
set => SetState(value);
}
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
{
return Outcomes(Branches);
}
}
using System.Collections.Generic;
using Elsa.Attributes;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow.Activities
{
[ActivityDefinition(
Category = "Control Flow",
Description = "Fork workflow execution into multiple branches.",
Icon = "fas fa-code-branch fa-rotate-180",
Outcomes = "x => x.state.branches")]
public class Fork : Activity
{
[ActivityProperty(
Hint = "Enter one or more names representing branches, separated with a comma. Example: Branch 1, Branch 2"
)]
public IList<string> Branches
{
get => GetState(() => new List<string>());
set => SetState(value);
}
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
{
return Outcomes(Branches);
}
}
}

View file

@ -1,49 +1,47 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow
{
[ActivityDefinition(
DisplayName = "If/Else",
Category = "Control Flow",
Description = "Evaluate a Boolean expression and continue execution depending on the result."
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.expression ? `Evaluate <strong>${ x.state.expression.expression }</strong> and continue execution depending on the result.` : x.definition.description",
Outcomes = new[] { OutcomeNames.True, OutcomeNames.False }
)]
public class IfElse : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public IfElse(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "The expression to evaluate. The evaluated value will be used to switch on.")]
public WorkflowExpression<bool> ConditionExpression
{
get => GetState(() => new JavaScriptExpression<bool>("true"));
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var result = await expressionEvaluator.EvaluateAsync(
ConditionExpression,
workflowContext,
cancellationToken
);
return Outcome(result ? OutcomeNames.True : OutcomeNames.False);
}
}
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow.Activities
{
[ActivityDefinition(
DisplayName = "If/Else",
Category = "Control Flow",
Description = "Evaluate a Boolean expression and continue execution depending on the result.",
RuntimeDescription = "x => !!x.state.expression ? `Evaluate <strong>${ x.state.expression.expression }</strong> and continue execution depending on the result.` : x.definition.description",
Outcomes = new[] { OutcomeNames.True, OutcomeNames.False }
)]
public class IfElse : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public IfElse(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "The expression to evaluate. The evaluated value will be used to switch on.")]
public WorkflowExpression<bool> ConditionExpression
{
get => GetState(() => new JavaScriptExpression<bool>("true"));
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var result = await expressionEvaluator.EvaluateAsync(
ConditionExpression,
workflowContext,
cancellationToken
);
return Outcome(result ? OutcomeNames.True : OutcomeNames.False);
}
}
}

View file

@ -1,147 +1,144 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Design;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Extensions;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow
{
[ActivityDefinition(
Category = "Control Flow",
Description = "Merge workflow execution back into a single branch.",
Icon = "fas fa-code-branch"
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.joinMode ? `Merge workflow execution back into a single branch using mode <strong>${ x.state.joinMode }</strong>` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class Join : Activity, IWorkflowEventHandler
{
public Join()
{
InboundTransitions = new List<string>().AsReadOnly();
}
public enum JoinMode
{
WaitAll,
WaitAny
}
[ActivityProperty(
Type = ActivityPropertyTypes.Select,
Hint = "Either 'WaitAll' or 'WaitAny'")
]
[SelectOptions("WaitAll", "WaitAny")]
public JoinMode Mode
{
get => GetState(() => JoinMode.WaitAll);
set => SetState(value);
}
public IReadOnlyCollection<string> InboundTransitions
{
get => GetState<IReadOnlyCollection<string>>();
set => SetState(value);
}
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
{
var recordedInboundTransitions = InboundTransitions ?? new List<string>();
var workflow = workflowContext.Workflow;
var inboundConnections = workflow.GetInboundConnections(Id);
var done = false;
switch (Mode)
{
case JoinMode.WaitAll:
done = inboundConnections.All(x => recordedInboundTransitions.Contains(GetTransitionKey(x)));
break;
case JoinMode.WaitAny:
done = inboundConnections.Any(x => recordedInboundTransitions.Contains(GetTransitionKey(x)));
break;
}
if (done)
{
// Remove any inbound blocking activities.
var ancestorActivityIds = workflow.GetInboundActivityPath(Id).ToList();
var blockingActivities =
workflow.BlockingActivities.Where(x => ancestorActivityIds.Contains(x.Id)).ToList();
foreach (var blockingActivity in blockingActivities)
{
workflow.BlockingActivities.Remove(blockingActivity);
}
}
return done ? Done() : Noop();
}
private void RecordInboundTransitions(WorkflowExecutionContext workflowContext, IActivity activity)
{
var workflow = workflowContext.Workflow;
// Get outbound connections of the executing activity.
var outboundConnections = workflow.GetOutboundConnections(activity.Id);
// Get any connection that is pointing to this activity.
var inboundTransitionsQuery =
from connection in outboundConnections
let destinationActivity = connection.Target.Activity
where destinationActivity.Type == nameof(Join)
select connection;
var inboundConnections = inboundTransitionsQuery.ToList();
// For each inbound connection, record the transition.
foreach (var inboundConnection in inboundConnections)
{
var joinActivity = (Join)inboundConnection.Target.Activity;
var inboundTransitions = joinActivity.InboundTransitions ?? new List<string>();
joinActivity.InboundTransitions = inboundTransitions
.Union(new[] { GetTransitionKey(inboundConnection) })
.Distinct()
.ToList();
}
}
private string GetTransitionKey(Connection connection)
{
var sourceActivityId = connection.Source.Activity.Id;
var sourceOutcomeName = connection.Source.Outcome;
return $"@{sourceActivityId}_{sourceOutcomeName}";
}
Task IWorkflowEventHandler.ActivityExecutedAsync(
WorkflowExecutionContext workflowContext,
IActivity activity,
CancellationToken cancellationToken)
{
RecordInboundTransitions(workflowContext, activity);
return Task.CompletedTask;
}
public Task ActivityFaultedAsync(
WorkflowExecutionContext workflowExecutionContext,
IActivity activity,
string message,
CancellationToken cancellationToken) => Task.CompletedTask;
Task IWorkflowEventHandler.InvokingHaltedActivitiesAsync(
WorkflowExecutionContext workflowExecutionContext,
CancellationToken cancellationToken) => Task.CompletedTask;
Task IWorkflowEventHandler.WorkflowInvokedAsync(
WorkflowExecutionContext workflowExecutionContext,
CancellationToken cancellationToken) => Task.CompletedTask;
}
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Design;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Extensions;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow.Activities
{
[ActivityDefinition(
Category = "Control Flow",
Description = "Merge workflow execution back into a single branch.",
Icon = "fas fa-code-branch",
RuntimeDescription = "x => !!x.state.joinMode ? `Merge workflow execution back into a single branch using mode <strong>${ x.state.joinMode }</strong>` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class Join : Activity, IWorkflowEventHandler
{
public Join()
{
InboundTransitions = new List<string>().AsReadOnly();
}
public enum JoinMode
{
WaitAll,
WaitAny
}
[ActivityProperty(
Type = ActivityPropertyTypes.Select,
Hint = "Either 'WaitAll' or 'WaitAny'")
]
[SelectOptions("WaitAll", "WaitAny")]
public JoinMode Mode
{
get => GetState(() => JoinMode.WaitAll);
set => SetState(value);
}
public IReadOnlyCollection<string> InboundTransitions
{
get => GetState<IReadOnlyCollection<string>>();
set => SetState(value);
}
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
{
var recordedInboundTransitions = InboundTransitions ?? new List<string>();
var workflow = workflowContext.Workflow;
var inboundConnections = workflow.GetInboundConnections(Id);
var done = false;
switch (Mode)
{
case JoinMode.WaitAll:
done = inboundConnections.All(x => recordedInboundTransitions.Contains(GetTransitionKey(x)));
break;
case JoinMode.WaitAny:
done = inboundConnections.Any(x => recordedInboundTransitions.Contains(GetTransitionKey(x)));
break;
}
if (done)
{
// Remove any inbound blocking activities.
var ancestorActivityIds = workflow.GetInboundActivityPath(Id).ToList();
var blockingActivities =
workflow.BlockingActivities.Where(x => ancestorActivityIds.Contains(x.Id)).ToList();
foreach (var blockingActivity in blockingActivities)
{
workflow.BlockingActivities.Remove(blockingActivity);
}
}
return done ? Done() : Noop();
}
private void RecordInboundTransitions(WorkflowExecutionContext workflowContext, IActivity activity)
{
var workflow = workflowContext.Workflow;
// Get outbound connections of the executing activity.
var outboundConnections = workflow.GetOutboundConnections(activity.Id);
// Get any connection that is pointing to this activity.
var inboundTransitionsQuery =
from connection in outboundConnections
let destinationActivity = connection.Target.Activity
where destinationActivity.Type == nameof(Join)
select connection;
var inboundConnections = inboundTransitionsQuery.ToList();
// For each inbound connection, record the transition.
foreach (var inboundConnection in inboundConnections)
{
var joinActivity = (Join)inboundConnection.Target.Activity;
var inboundTransitions = joinActivity.InboundTransitions ?? new List<string>();
joinActivity.InboundTransitions = inboundTransitions
.Union(new[] { GetTransitionKey(inboundConnection) })
.Distinct()
.ToList();
}
}
private string GetTransitionKey(Connection connection)
{
var sourceActivityId = connection.Source.Activity.Id;
var sourceOutcomeName = connection.Source.Outcome;
return $"@{sourceActivityId}_{sourceOutcomeName}";
}
Task IWorkflowEventHandler.ActivityExecutedAsync(
WorkflowExecutionContext workflowContext,
IActivity activity,
CancellationToken cancellationToken)
{
RecordInboundTransitions(workflowContext, activity);
return Task.CompletedTask;
}
public Task ActivityFaultedAsync(
WorkflowExecutionContext workflowExecutionContext,
IActivity activity,
string message,
CancellationToken cancellationToken) => Task.CompletedTask;
Task IWorkflowEventHandler.InvokingHaltedActivitiesAsync(
WorkflowExecutionContext workflowExecutionContext,
CancellationToken cancellationToken) => Task.CompletedTask;
Task IWorkflowEventHandler.WorkflowInvokedAsync(
WorkflowExecutionContext workflowExecutionContext,
CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View file

@ -1,54 +1,52 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow
{
[ActivityDefinition(
Category = "Control Flow",
Description = "Switch execution based on a given expression.",
Icon = "far fa-list-alt"
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.expression ? `Switch execution based on <strong>${ x.state.expression.expression }</strong>.` : x.definition.description",
Outcomes = "x => x.state.cases.map(c => c.toString())"
)]
public class Switch : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public Switch(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
Cases = new List<string>();
}
[ActivityProperty(Hint = "The expression to evaluate. The evaluated value will be used to switch on.")]
public WorkflowExpression<string> Expression
{
get => GetState<WorkflowExpression<string>>();
set => SetState(value);
}
[ActivityProperty(Hint = "A comma-separated list of possible outcomes of the expression.")]
public IReadOnlyCollection<string> Cases
{
get => GetState<IReadOnlyCollection<string>>();
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var result = await expressionEvaluator.EvaluateAsync(Expression, workflowContext, cancellationToken);
return Outcome(result);
}
}
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow.Activities
{
[ActivityDefinition(
Category = "Control Flow",
Description = "Switch execution based on a given expression.",
Icon = "far fa-list-alt",
RuntimeDescription = "x => !!x.state.expression ? `Switch execution based on <strong>${ x.state.expression.expression }</strong>.` : x.definition.description",
Outcomes = "x => x.state.cases.map(c => c.toString())"
)]
public class Switch : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public Switch(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
Cases = new List<string>();
}
[ActivityProperty(Hint = "The expression to evaluate. The evaluated value will be used to switch on.")]
public WorkflowExpression<string> Expression
{
get => GetState<WorkflowExpression<string>>();
set => SetState(value);
}
[ActivityProperty(Hint = "A comma-separated list of possible outcomes of the expression.")]
public IReadOnlyCollection<string> Cases
{
get => GetState<IReadOnlyCollection<string>>();
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var result = await expressionEvaluator.EvaluateAsync(Expression, workflowContext, cancellationToken);
return Outcome(result);
}
}
}

View file

@ -0,0 +1,57 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Results;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.ControlFlow.Activities
{
[ActivityDefinition(Category = "Control Flow", Description = "Execute while a given condition is true.", Icon = "far fa-circle")]
public class While : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public While(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "Enter an expression that evaluates to a boolean value.")]
public WorkflowExpression<bool> ConditionExpression
{
get => GetState(() => new JavaScriptExpression<bool>("true"));
set => SetState(value);
}
public bool HasStarted
{
get => GetState(() => false);
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext context,
CancellationToken cancellationToken)
{
var loop = await expressionEvaluator.EvaluateAsync(ConditionExpression, context, cancellationToken);
if(HasStarted)
context.EndScope();
if (loop)
{
if (!HasStarted)
HasStarted = true;
context.BeginScope();
return Outcome(OutcomeNames.Iterate);
}
return Done();
}
}
}

View file

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,21 @@
using Elsa.Activities.ControlFlow.Activities;
using Elsa.Services;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Activities.ControlFlow.Extensions
{
public static class ControlFlowServiceCollectionExtensions
{
public static IServiceCollection AddControlFlowActivities(this IServiceCollection services)
{
return services
.AddActivity<ForEach>()
.AddActivity<While>()
.AddActivity<Fork>()
.AddActivity<Join>()
.AddSingleton<IWorkflowEventHandler>(sp => sp.GetRequiredService<Join>())
.AddActivity<IfElse>()
.AddActivity<Switch>();
}
}
}

View file

@ -18,7 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.0.0" />
</ItemGroup>
</Project>

View file

@ -23,11 +23,8 @@ namespace Elsa.Activities.Http.Activities
[ActivityDefinition(
Category = "HTTP",
DisplayName = "Send HTTP Request",
Description = "Send an HTTP request."
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.url ? `Send HTTP <strong>${ x.state.method } ${ x.state.url.expression }</strong>.` : x.definition.description",
Description = "Send an HTTP request.",
RuntimeDescription = "x => !!x.state.url ? `Send HTTP <strong>${ x.state.method } ${ x.state.url.expression }</strong>.` : x.definition.description",
Outcomes = "x => !!x.state.supportedStatusCodes ? x.state.supportedStatusCodes : []"
)]
public class HttpRequestAction : Activity

View file

@ -20,11 +20,8 @@ namespace Elsa.Activities.Http.Activities
[ActivityDefinition(
Category = "HTTP",
DisplayName = "Receive HTTP Request",
Description = "Receive an incoming HTTP request."
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.path ? `Handle <strong>${ x.state.method } ${ x.state.path }</strong>.` : x.definition.description",
Description = "Receive an incoming HTTP request.",
RuntimeDescription = "x => !!x.state.path ? `Handle <strong>${ x.state.method } ${ x.state.path }</strong>.` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class HttpRequestEvent : Activity
@ -118,7 +115,7 @@ namespace Elsa.Activities.Http.Activities
var parser = SelectContentParser(request.ContentType);
var content = await request.ReadContentAsBytesAsync(cancellationToken);
model.Content = await parser.ParseAsync(content, request.ContentType);
model.Body = await parser.ParseAsync(content, request.ContentType);
}
Output["Content"] = model;

View file

@ -18,11 +18,8 @@ namespace Elsa.Activities.Http.Activities
[ActivityDefinition(
Category = "HTTP",
DisplayName = "Send HTTP Response",
Description = "Send an HTTP response."
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.statusCode ? `Send an HTTP <strong>${ x.state.statusCode }</strong> - <strong>${ x.state.contentType }</strong> response` : x.definition.description",
Description = "Send an HTTP response.",
RuntimeDescription = "x => !!x.state.statusCode ? `Send an HTTP <strong>${ x.state.statusCode }</strong> - <strong>${ x.state.contentType }</strong> response` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class HttpResponseAction : Activity

View file

@ -15,6 +15,8 @@
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj" />
<ProjectReference Include="..\..\scripting\Elsa.Scripting.Liquid\Elsa.Scripting.Liquid.csproj" />
</ItemGroup>
<ItemGroup>
@ -23,7 +25,6 @@
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.0.0" />
</ItemGroup>

View file

@ -1,55 +1,56 @@
using System;
using Elsa.Activities.Http.Activities;
using Elsa.Activities.Http.Formatters;
using Elsa.Activities.Http.Options;
using Elsa.Activities.Http.RequestHandlers.Handlers;
using Elsa.Activities.Http.Scripting;
using Elsa.Activities.Http.Services;
using Elsa.Scripting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace Elsa.Activities.Http.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddHttpActivities(
this IServiceCollection services,
Action<OptionsBuilder<HttpActivityOptions>> options = null)
{
options?.Invoke(services.AddOptions<HttpActivityOptions>());
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddHttpClient(nameof(HttpRequestAction));
services
.AddActivity<HttpRequestEvent>()
.AddActivity<HttpResponseAction>()
.AddActivity<HttpRequestAction>();
services
.AddSingleton<ITokenService, TokenService>()
.AddSingleton<IContentFormatter, DefaultContentFormatter>()
.AddSingleton<IContentFormatter, JsonContentFormatter>()
.AddSingleton<IScriptEngineConfigurator, HttpScriptEngineConfigurator>()
.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddSingleton<IAbsoluteUrlProvider, DefaultAbsoluteUrlProvider>()
.AddHttpContextAccessor()
.AddDataProtection();
return services
.AddScoped(sp => sp.GetRequiredService<IHttpContextAccessor>().HttpContext)
.AddRequestHandler<TriggerRequestHandler>()
.AddRequestHandler<SignalRequestHandler>();
}
public static IServiceCollection AddRequestHandler<THandler>(this IServiceCollection services)
where THandler : class, IRequestHandler
{
return services.AddScoped<THandler>();
}
}
using System;
using Elsa.Activities.Http.Activities;
using Elsa.Activities.Http.Formatters;
using Elsa.Activities.Http.Options;
using Elsa.Activities.Http.RequestHandlers.Handlers;
using Elsa.Activities.Http.Services;
using Elsa.Scripting;
using Elsa.Scripting.JavaScript;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace Elsa.Activities.Http.Extensions
{
public static class HttpActivitiesServiceCollectionExtensions
{
public static IServiceCollection AddHttpActivities(
this IServiceCollection services,
Action<OptionsBuilder<HttpActivityOptions>> options = null)
{
options?.Invoke(services.AddOptions<HttpActivityOptions>());
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddHttpClient(nameof(HttpRequestAction));
services
.AddActivity<HttpRequestEvent>()
.AddActivity<HttpResponseAction>()
.AddActivity<HttpRequestAction>();
services
.AddSingleton<ITokenService, TokenService>()
.AddSingleton<IContentFormatter, DefaultContentFormatter>()
.AddSingleton<IContentFormatter, JsonContentFormatter>()
.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddSingleton<IAbsoluteUrlProvider, DefaultAbsoluteUrlProvider>()
.AddHttpContextAccessor()
.AddMediatR(typeof(HttpActivitiesServiceCollectionExtensions))
.AddDataProtection();
return services
.AddScoped(sp => sp.GetRequiredService<IHttpContextAccessor>().HttpContext)
.AddRequestHandler<TriggerRequestHandler>()
.AddRequestHandler<SignalRequestHandler>();
}
public static IServiceCollection AddRequestHandler<THandler>(this IServiceCollection services)
where THandler : class, IRequestHandler
{
return services.AddScoped<THandler>();
}
}
}

View file

@ -1,31 +1,36 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Activities.Http.Models;
using Elsa.Activities.Http.Services;
using Elsa.Scripting;
using Elsa.Scripting.JavaScript.Messages;
using Elsa.Services.Models;
using Jint;
using MediatR;
using Microsoft.AspNetCore.Http;
namespace Elsa.Activities.Http.Scripting
namespace Elsa.Activities.Http.Handlers
{
public class HttpScriptEngineConfigurator : IScriptEngineConfigurator
public class HttpJavaScriptHandler : INotificationHandler<EvaluatingJavaScriptExpression>
{
private readonly ITokenService _tokenService;
private readonly ITokenService tokenService;
private readonly IAbsoluteUrlProvider absoluteUrlProvider;
private readonly IHttpContextAccessor httpContextAccessor;
public HttpScriptEngineConfigurator(
public HttpJavaScriptHandler(
ITokenService tokenService,
IAbsoluteUrlProvider absoluteUrlProvider,
IHttpContextAccessor httpContextAccessor)
{
this._tokenService = tokenService;
this.tokenService = tokenService;
this.absoluteUrlProvider = absoluteUrlProvider;
this.httpContextAccessor = httpContextAccessor;
}
public void Configure(Engine engine, WorkflowExecutionContext workflowExecutionContext)
public Task Handle(EvaluatingJavaScriptExpression notification, CancellationToken cancellationToken)
{
var engine = notification.Engine;
var workflowExecutionContext = notification.WorkflowExecutionContext;
engine.SetValue(
"queryString",
(Func<string, string>) (key => httpContextAccessor.HttpContext.Request.Query[key].ToString())
@ -38,13 +43,15 @@ namespace Elsa.Activities.Http.Scripting
"signalUrl",
(Func<string, string>) (signal => GenerateUrl(signal, workflowExecutionContext))
);
return Task.CompletedTask;
}
private string GenerateUrl(string signal, WorkflowExecutionContext workflowExecutionContext)
{
var workflowInstanceId = workflowExecutionContext.Workflow.Id;
var payload = new Signal(signal, workflowInstanceId);
var token = _tokenService.CreateToken(payload);
var token = tokenService.CreateToken(payload);
var url = $"/workflows/signal?token={token}";
return absoluteUrlProvider.ToAbsoluteUrl(url).ToString();

View file

@ -0,0 +1,21 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Activities.Http.Models;
using Elsa.Scripting.Liquid.Messages;
using Fluid;
using MediatR;
namespace Elsa.Activities.Http.Handlers
{
public class HttpLiquidHandler : INotificationHandler<EvaluatingLiquidExpression>
{
public Task Handle(EvaluatingLiquidExpression notification, CancellationToken cancellationToken)
{
var context = notification.TemplateContext;
context.MemberAccessStrategy.Register<HttpRequestModel>();
return Task.CompletedTask;
}
}
}

View file

@ -9,7 +9,7 @@ namespace Elsa.Activities.Http.Models
public string Method { get; set; }
public IDictionary<string, StringValuesModel> QueryString { get; set; }
public IDictionary<string, StringValuesModel> Headers { get; set; }
public object Content { get; set; }
public object Body { get; set; }
public IDictionary<string, StringValuesModel> Form { get; set; }
}
}

View file

@ -14,9 +14,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MassTransit.AspNetCore" Version="5.5.2" />
<PackageReference Include="MassTransit.Extensions.DependencyInjection" Version="5.5.2" />
<PackageReference Include="MassTransit.RabbitMQ" Version="5.5.2" />
<PackageReference Include="MassTransit.AspNetCore" Version="5.5.6" />
<PackageReference Include="MassTransit.Extensions.DependencyInjection" Version="5.5.6" />
<PackageReference Include="MassTransit.RabbitMQ" Version="5.5.6" />
</ItemGroup>
<ItemGroup>

View file

@ -13,11 +13,8 @@ namespace Elsa.Activities.Timers.Activities
{
[ActivityDefinition(
Category = "Timers",
Description = "Triggers periodically based on a specified CRON expression."
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.cronExpression ? `<strong>${ x.state.cronExpression.expression }</strong>.` : x.definition.description",
Description = "Triggers periodically based on a specified CRON expression.",
RuntimeDescription = "x => !!x.state.cronExpression ? `<strong>${ x.state.cronExpression.expression }</strong>.` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class CronEvent : Activity
@ -43,7 +40,7 @@ namespace Elsa.Activities.Timers.Activities
get => GetState<Instant?>();
set => SetState(value);
}
protected override async Task<bool> OnCanExecuteAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
{
return StartTime == null || await IsExpiredAsync(context, cancellationToken);
@ -54,7 +51,8 @@ namespace Elsa.Activities.Timers.Activities
return Halt();
}
protected override async Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext context,
protected override async Task<ActivityExecutionResult> OnResumeAsync(
WorkflowExecutionContext context,
CancellationToken cancellationToken)
{
if (await IsExpiredAsync(context, cancellationToken))
@ -62,11 +60,12 @@ namespace Elsa.Activities.Timers.Activities
StartTime = null;
return Done();
}
return Halt();
}
private async Task<bool> IsExpiredAsync(WorkflowExecutionContext workflowContext,
private async Task<bool> IsExpiredAsync(
WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var cronExpression = await expressionEvaluator.EvaluateAsync(
@ -76,10 +75,10 @@ namespace Elsa.Activities.Timers.Activities
);
var schedule = CrontabSchedule.Parse(cronExpression);
var now = clock.GetCurrentInstant();
if (StartTime == null)
StartTime = now;
var nextOccurrence = schedule.GetNextOccurrence(StartTime.Value.ToDateTimeUtc());
return now.ToDateTimeUtc() >= nextOccurrence;

View file

@ -18,7 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.0.0" />
<PackageReference Include="NCrontab" Version="3.3.1" />
</ItemGroup>

View file

@ -7,7 +7,7 @@ using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Workflows
namespace Elsa.Activities.Workflows.Activities
{
/// <summary>
/// Sets the CorrelationId of the workflow to a given value.

View file

@ -5,10 +5,11 @@ using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Results;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Workflows
namespace Elsa.Activities.Workflows.Activities
{
[ActivityDefinition(
Category = "Workflows",

View file

@ -7,7 +7,7 @@ using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Workflows
namespace Elsa.Activities.Workflows.Activities
{
/// <summary>
/// Halts workflow execution until the specified signal is received.

View file

@ -3,7 +3,7 @@ using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Workflows
namespace Elsa.Activities.Workflows.Activities
{
[ActivityDefinition(
Category = "Workflows",

View file

@ -5,10 +5,12 @@ using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Results;
using Elsa.Scripting.JavaScript;
using Elsa.Scripting.JavaScript.Services;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Workflows
namespace Elsa.Activities.Workflows.Activities
{
/// <summary>
/// Triggers the specified signal.
@ -41,7 +43,7 @@ namespace Elsa.Activities.Workflows
)]
public WorkflowExpression<Variables> Input
{
get => GetState(() => new WorkflowExpression<Variables>(JavaScriptEvaluator.SyntaxName, "{}"));
get => GetState(() => new WorkflowExpression<Variables>(JavaScriptExpressionEvaluator.SyntaxName, "{}"));
set => SetState(value);
}

View file

@ -6,10 +6,11 @@ using Elsa.Expressions;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Results;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Workflows
namespace Elsa.Activities.Workflows.Activities
{
[ActivityDefinition(
Category = "Workflows",

View file

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,19 @@
using Elsa.Activities.Workflows.Activities;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Activities.Workflows.Extensions
{
public static class WorkflowActivityServiceCollectionExtensions
{
public static IServiceCollection AddWorkflowActivities(this IServiceCollection services)
{
return services
.AddActivity<TriggerWorkflow>()
.AddActivity<Correlate>()
.AddActivity<Signaled>()
.AddActivity<Trigger>()
.AddActivity<Start>()
.AddActivity<Finish>();
}
}
}

View file

@ -8,7 +8,9 @@ namespace Elsa.Attributes
public string Type { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public string RuntimeDescription { get; set; }
public string Category { get; set; }
public string Icon { get; set; }
public object Outcomes { get; set; }
}
}

View file

@ -1,11 +0,0 @@
using System;
namespace Elsa.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
public class ActivityDefinitionDesignerAttribute : Attribute
{
public string Description { get; set; }
public object Outcomes { get; set; }
}
}

View file

@ -15,7 +15,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Jint" Version="3.0.0-beta-1612" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="3.0.0" />
@ -25,4 +24,8 @@
<PackageReference Include="System.ComponentModel.Annotations" Version="4.6.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Scripting" />
</ItemGroup>
</Project>

View file

@ -12,6 +12,7 @@ namespace Elsa.Models
public ActivityDefinition()
{
State = new JObject();
}
public ActivityDefinition(string id, string type, JObject state, int left = 0, int top = 0)
@ -25,6 +26,15 @@ namespace Elsa.Models
public string Id { get; set; }
public string Type { get; set; }
public string Name
{
get => State.ContainsKey(nameof(Name)) ? State[nameof(Name)].Value<string>() : default;
set => State[nameof(Name)] = value;
}
public string DisplayName { get; set; }
public string Description { get; set; }
public int Left { get; set; }
public int Top { get; set; }
public JObject State { get; set; }

View file

@ -1,10 +0,0 @@
using Elsa.Services.Models;
using Jint;
namespace Elsa.Scripting
{
public interface IScriptEngineConfigurator
{
void Configure(Engine engine, WorkflowExecutionContext workflowExecutionContext);
}
}

View file

@ -2,6 +2,7 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Results;
@ -12,15 +13,36 @@ using Newtonsoft.Json.Linq;
namespace Elsa.Services
{
public abstract class ActivityBase : IActivity
{
{
public JObject State { get; set; } = new JObject();
public Variables Output { get; set; } = new Variables();
[JsonIgnore]
public Variables TransientOutput { get; } = new Variables();
public virtual string Type => GetType().Name;
public string Id { get; set; }
[ActivityProperty(Label = "Name", Hint = "Optionally provide a name for this activity. You can reference named activities from expressions.")]
public string Name {
get => GetState<string>();
set => SetState(value);
}
[ActivityProperty(Hint = "Optionally provide a custom title for this activity.")]
public string Title
{
get => GetState<string>();
set => SetState(value);
}
[ActivityProperty(Hint = "Optionally provide a custom description for this activity.")]
public string Description
{
get => GetState<string>();
set => SetState(value);
}
public Task<bool> CanExecuteAsync(WorkflowExecutionContext context, CancellationToken cancellationToken) => OnCanExecuteAsync(context, cancellationToken);
public Task<ActivityExecutionResult> ExecuteAsync(WorkflowExecutionContext context, CancellationToken cancellationToken) => OnExecuteAsync(context, cancellationToken);

View file

@ -7,13 +7,16 @@ namespace Elsa.Services
public interface IActivityBuilder
{
string Id { get; set; }
string Name { get; set; }
ActivityDefinition Activity { get; }
IActivityBuilder StartWith<T>(Action<T> setup = default, string id = default) where T: class, IActivity;
IActivityBuilder Add<T>(Action<T> setup = default, string id = null) where T : class, IActivity;
IActivityBuilder StartWith<T>(Action<T> setup = default, string name = null) where T: class, IActivity;
IActivityBuilder Add<T>(Action<T> setup = default, string name = null) where T : class, IActivity;
IOutcomeBuilder When(string outcome);
IActivityBuilder Then<T>(Action<T> setup = null, Action<IActivityBuilder> branch = null, string id = null) where T : class, IActivity;
IActivityBuilder WithId(string id);
IWorkflowBuilder Then(string activityId);
IActivityBuilder Then<T>(Action<T> setup = null, Action<IActivityBuilder> branch = null, string name = null) where T : class, IActivity;
IActivityBuilder WithDisplayName(string displayName);
IActivityBuilder WithDescription(string description);
IWorkflowBuilder Then(string activityName);
IActivityBuilder Then(IActivityBuilder targetActivity);
WorkflowDefinitionVersion Build();
ActivityDefinition BuildActivity();
}

View file

@ -8,8 +8,8 @@ namespace Elsa.Services
{
IActivityBuilder Source { get; }
string Outcome { get; }
IActivityBuilder Then<T>(Action<T> setup = default, Action<IActivityBuilder> branch = null, string id = default) where T : class, IActivity;
IActivityBuilder Then<T>(Action<T> setup = default, Action<IActivityBuilder> branch = default, string name = default) where T : class, IActivity;
WorkflowDefinitionVersion Build();
IConnectionBuilder Then(string activityId);
IConnectionBuilder Then(string activityName);
}
}

View file

@ -14,8 +14,8 @@ namespace Elsa.Services
IWorkflowBuilder WithName(string name);
IWorkflowBuilder WithDescription(string description);
IWorkflowBuilder AsSingleton(bool value = true);
IActivityBuilder Add<T>(Action<T> setupActivity = default, string id = default) where T : class, IActivity;
IActivityBuilder StartWith<T>(Action<T> setup = default, string id = default) where T: class, IActivity;
IActivityBuilder Add<T>(Action<T> setupActivity = default, string name = default) where T : class, IActivity;
IActivityBuilder StartWith<T>(Action<T> setup = default, string name = default) where T: class, IActivity;
IConnectionBuilder Connect(IActivityBuilder source, IActivityBuilder target, string outcome = default);
IConnectionBuilder Connect(Func<IActivityBuilder> source, Func<IActivityBuilder> target, string outcome = default);
WorkflowDefinitionVersion Build();

View file

@ -28,10 +28,15 @@ namespace Elsa.Services.Models
string Type { get; }
/// <summary>
/// Unique identifier of this activity
/// Unique identifier of this activity.
/// </summary>
string Id { get; set; }
/// <summary>
/// Name identifier of this activity.
/// </summary>
string Name { get; set; }
/// <summary>
/// Returns a value of whether the specified activity can execute.
/// </summary>

View file

@ -12,8 +12,7 @@ namespace Elsa.Services.Models
{
public Workflow(
string id,
string definitionId,
int version,
WorkflowDefinitionVersion definition,
Instant createdAt,
IEnumerable<IActivity> activities,
IEnumerable<Connection> connections,
@ -21,8 +20,7 @@ namespace Elsa.Services.Models
string correlationId = default) : this()
{
Id = id;
DefinitionId = definitionId;
Version = version;
Definition = definition;
CreatedAt = createdAt;
CorrelationId = correlationId;
Activities = activities.ToList();
@ -30,6 +28,8 @@ namespace Elsa.Services.Models
Input = new Variables(input ?? Variables.Empty);
}
public Workflow()
{
Scopes = new Stack<WorkflowExecutionScope>(new[] { new WorkflowExecutionScope() });
@ -38,8 +38,7 @@ namespace Elsa.Services.Models
}
public string Id { get; set; }
public string DefinitionId { get; }
public int Version { get; }
public WorkflowDefinitionVersion Definition { get; }
public string CorrelationId { get; set; }
public WorkflowStatus Status { get; set; }
public Instant CreatedAt { get; set; }
@ -63,8 +62,8 @@ namespace Elsa.Services.Models
return new WorkflowInstance
{
Id = Id,
DefinitionId = DefinitionId,
Version = Version,
DefinitionId = Definition.DefinitionId,
Version = Definition.Version,
CorrelationId = CorrelationId,
Status = Status,
CreatedAt = CreatedAt,

View file

@ -31,7 +31,7 @@ namespace Elsa.Services.Models
public WorkflowExecutionScope CurrentScope => Workflow.Scopes.Peek();
public Variables TransientState { get; } = new Variables();
public IActivity CurrentActivity { get; private set; }
public void ScheduleActivities(params IActivity[] activities) => ScheduleActivities((IEnumerable<IActivity>) activities);
public void ScheduleActivities(params IActivity[] activities) => ScheduleActivities((IEnumerable<IActivity>)activities);
public void ScheduleActivities(IEnumerable<IActivity> activities)
{
@ -43,7 +43,7 @@ namespace Elsa.Services.Models
public void BeginScope() => Workflow.Scopes.Push(new WorkflowExecutionScope());
public void EndScope() => Workflow.Scopes.Pop();
public void ScheduleActivity(IActivity activity)
{
scheduledActivities.Push(activity);
@ -53,8 +53,28 @@ namespace Elsa.Services.Models
public IActivity PopScheduledActivity() => CurrentActivity = scheduledActivities.Pop();
public void ScheduleHaltingActivity(IActivity activity) => scheduledHaltingActivities.Push(activity);
public IActivity PopScheduledHaltingActivity() => scheduledHaltingActivities.Pop();
public void SetVariable(string name, object value) => CurrentScope.SetVariable(name, value);
public T GetVariable<T>(string name) => CurrentScope.GetVariable<T>(name);
public void SetVariable(string name, object value)
{
// Get the first scope (starting from the oldest one) containing the variable (existing variable). Otherwise use the current scope (new variable declaration)
var scope = Workflow.Scopes.Reverse().FirstOrDefault(x => x.Variables.ContainsKey(name)) ?? CurrentScope;
scope.SetVariable(name, value);
}
public T GetVariable<T>(string name)
{
// Get the first scope (starting from the newest one) containing the variable.
var scope = Workflow.Scopes.FirstOrDefault(x => x.Variables.ContainsKey(name)) ?? CurrentScope;
return scope.GetVariable<T>(name);
}
public object GetVariable(string name)
{
// Get the first scope (starting from the newest one) containing the variable.
var scope = Workflow.Scopes.FirstOrDefault(x => x.Variables.ContainsKey(name)) ?? CurrentScope;
return scope.GetVariable(name);
}
public void SetLastResult(object value) => CurrentScope.LastResult = value;
public void Start()
@ -62,7 +82,7 @@ namespace Elsa.Services.Models
Workflow.StartedAt = clock.GetCurrentInstant();
Workflow.Status = WorkflowStatus.Executing;
}
public void Fault(IActivity activity, Exception exception) => Fault(activity, exception.Message);
public void Fault(IActivity activity, string errorMessage)
@ -88,11 +108,16 @@ namespace Elsa.Services.Models
Workflow.Status = WorkflowStatus.Finished;
Workflow.BlockingActivities.Clear();
}
public void Abort()
{
Workflow.AbortedAt = clock.GetCurrentInstant();
Workflow.Status = WorkflowStatus.Aborted;
}
public Variables GetVariables() => Workflow.Scopes
.Reverse()
.Select(x => x.Variables)
.Aggregate(Variables.Empty, (x, y) => new Variables(x.Union(y)));
}
}

View file

@ -1,58 +1,55 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Primitives
{
[ActivityDefinition(
DisplayName = "Set Variable",
Description = "Set variable on the workflow.",
Category = "Primitives"
)]
[ActivityDefinitionDesigner(
Description =
"x => !!x.state.variableName ? `<strong>${x.state.variableName}</strong> = <strong>${x.state.valueExpression.expression}</strong><br/>${x.state.valueExpression.syntax}` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class SetVariable : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public SetVariable(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "The name of the variable to store the value into.")]
public string VariableName
{
get => GetState<string>();
set => SetState(value);
}
[ActivityProperty(Hint = "An expression that evaluates to the value to store in the variable.")]
public WorkflowExpression ValueExpression
{
get => GetState<WorkflowExpression>();
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var value = await expressionEvaluator.EvaluateAsync(
ValueExpression,
ValueExpression.Type,
workflowContext,
cancellationToken
);
workflowContext.CurrentScope.SetVariable(VariableName, value);
return Done();
}
}
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Expressions;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities
{
[ActivityDefinition(
DisplayName = "Set Variable",
Description = "Set variable on the workflow.",
Category = "Primitives",
RuntimeDescription = "x => !!x.state.variableName ? `<strong>${x.state.variableName}</strong> = <strong>${x.state.valueExpression.expression}</strong><br/>${x.state.valueExpression.syntax}` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done }
)]
public class SetVariable : Activity
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public SetVariable(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
[ActivityProperty(Hint = "The name of the variable to store the value into.")]
public string VariableName
{
get => GetState<string>();
set => SetState(value);
}
[ActivityProperty(Hint = "An expression that evaluates to the value to store in the variable.")]
public WorkflowExpression ValueExpression
{
get => GetState<WorkflowExpression>();
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext workflowContext,
CancellationToken cancellationToken)
{
var value = await expressionEvaluator.EvaluateAsync(
ValueExpression,
ValueExpression.Type,
workflowContext,
cancellationToken
);
workflowContext.SetVariable(VariableName, value);
return Done();
}
}
}

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<LangVersion>8</LangVersion>
<RootNamespace>Elsa</RootNamespace>
<PackageVersion>1.0.0</PackageVersion>
<Authors>Sipke Schoorstra</Authors>
@ -16,10 +16,11 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="9.0.0" />
<PackageReference Include="Humanizer.Core" Version="2.7.9" />
<PackageReference Include="MediatR" Version="7.0.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
@ -29,14 +30,14 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="2.2.0" />
<PackageReference Include="Elsa.Scrutor" Version="3.0.2.25" />
<PackageReference Include="Elsa.Scrutor" Version="3.0.2.26" />
<PackageReference Include="YamlDotNet.NetStandard" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\utils\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj" />
<ProjectReference Include="..\Elsa.Abstractions\Elsa.Abstractions.csproj" />
<ProjectReference Include="..\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj" />
</ItemGroup>
</Project>

View file

@ -2,16 +2,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Elsa;
using Elsa.Activities.ControlFlow;
using Elsa.Activities.Primitives;
using Elsa.Activities.Workflows;
using Elsa.Activities;
using Elsa.AutoMapper.Extensions;
using Elsa.Caching;
using Elsa.Expressions;
using Elsa.Mapping;
using Elsa.Persistence;
using Elsa.Persistence.Memory;
using Elsa.Scripting;
using Elsa.Serialization;
using Elsa.Serialization.Formatters;
using Elsa.Services;
@ -28,7 +25,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class ElsaServiceCollectionExtensions
{
public static IServiceCollection AddWorkflows(
public static IServiceCollection AddElsaCore(
this IServiceCollection services,
Action<ElsaBuilder> configure = null)
{
@ -115,12 +112,9 @@ namespace Microsoft.Extensions.DependencyInjection
.TryAddProvider<ITokenFormatter, YamlTokenFormatter>(ServiceLifetime.Singleton)
.TryAddProvider<ITokenFormatter, XmlTokenFormatter>(ServiceLifetime.Singleton)
.TryAddProvider<IExpressionEvaluator, LiteralEvaluator>(ServiceLifetime.Singleton)
.TryAddProvider<IExpressionEvaluator, JavaScriptEvaluator>(ServiceLifetime.Singleton)
.AddSingleton<IScriptEngineConfigurator, CommonScriptEngineConfigurator>()
.AddSingleton<IScriptEngineConfigurator, DateTimeScriptEngineConfigurator>()
.AddScoped<IWorkflowFactory, WorkflowFactory>()
.AddSingleton<IActivityInvoker, ActivityInvoker>()
.AddSingleton<IWorkflowExpressionEvaluator, WorkflowExpressionEvaluator>()
.AddScoped<IWorkflowExpressionEvaluator, WorkflowExpressionEvaluator>()
.AddSingleton<IWorkflowSerializerProvider, WorkflowSerializerProvider>()
.AddSingleton<IWorkflowRegistry, WorkflowRegistry>()
.AddScoped<IWorkflowEventHandler, PersistenceWorkflowEventHandler>()
@ -133,9 +127,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddTransient<IWorkflowBuilder, WorkflowBuilder>()
.AddTransient<Func<IWorkflowBuilder>>(sp => sp.GetRequiredService<IWorkflowBuilder>)
.AddAutoMapperProfile<WorkflowDefinitionProfile>(ServiceLifetime.Singleton)
.AddPrimitiveActivities()
.AddControlFlowActivities()
.AddWorkflowActivities();
.AddPrimitiveActivities();
return configuration;
}
@ -170,27 +162,5 @@ namespace Microsoft.Extensions.DependencyInjection
return services
.AddActivity<SetVariable>();
}
private static IServiceCollection AddControlFlowActivities(this IServiceCollection services)
{
return services
.AddActivity<ForEach>()
.AddActivity<Fork>()
.AddActivity<Join>()
.AddSingleton<IWorkflowEventHandler>(sp => sp.GetRequiredService<Join>())
.AddActivity<IfElse>()
.AddActivity<Switch>();
}
private static IServiceCollection AddWorkflowActivities(this IServiceCollection services)
{
return services
.AddActivity<TriggerWorkflow>()
.AddActivity<Correlate>()
.AddActivity<Signaled>()
.AddActivity<Trigger>()
.AddActivity<Start>()
.AddActivity<Finish>();
}
}
}

View file

@ -7,22 +7,20 @@ using Elsa.Attributes;
using Elsa.Design;
using Elsa.Expressions;
using Elsa.Services.Models;
using Elsa.WorkflowDesigner.Models;
using Humanizer;
namespace Elsa.WorkflowDesigner
namespace Elsa.Metadata
{
public static class ActivityDescriber
{
public static ActivityDefinitionModel Describe<T>() where T : IActivity
public static ActivityDescriptor Describe<T>() where T : IActivity
{
return Describe(typeof(T));
}
public static ActivityDefinitionModel Describe(Type activityType)
public static ActivityDescriptor Describe(Type activityType)
{
var activityDefinitionAttribute = activityType.GetCustomAttribute<ActivityDefinitionAttribute>();
var activityDesignerAttribute = activityType.GetCustomAttribute<ActivityDefinitionDesignerAttribute>();
var typeName = activityDefinitionAttribute?.Type ?? activityType.Name;
var displayName =
@ -30,25 +28,22 @@ namespace Elsa.WorkflowDesigner
activityType.Name.Humanize(LetterCasing.Title);
var description = activityDefinitionAttribute?.Description;
var runtimeDescription = activityDefinitionAttribute?.RuntimeDescription;
var category = activityDefinitionAttribute?.Category ?? "Miscellaneous";
var icon = activityDefinitionAttribute?.Icon;
var designerDescription = activityDesignerAttribute?.Description;
var designerOutcomes = activityDesignerAttribute?.Outcomes ?? new[] { OutcomeNames.Done };
var outcomes = activityDefinitionAttribute?.Outcomes ?? new[] { OutcomeNames.Done };
var properties = DescribeProperties(activityType);
return new ActivityDefinitionModel
return new ActivityDescriptor
{
Type = typeName.Pascalize(),
DisplayName = displayName,
Description = description,
RuntimeDescription = runtimeDescription,
Category = category,
Icon = icon,
Properties = properties.ToArray(),
Designer = new ActivityDesignerSettings
{
Description = designerDescription,
Outcomes = designerOutcomes
}
Outcomes = outcomes
};
}
@ -61,7 +56,7 @@ namespace Elsa.WorkflowDesigner
var activityProperty = propertyInfo.GetCustomAttribute<ActivityPropertyAttribute>();
if (activityProperty == null)
yield break;
continue;
yield return new ActivityPropertyDescriptor
(

View file

@ -1,23 +1,24 @@
namespace Elsa.WorkflowDesigner.Models
namespace Elsa.Metadata
{
public class ActivityDefinitionModel
public class ActivityDescriptor
{
public ActivityDefinitionModel()
public ActivityDescriptor()
{
Type = "Activity";
Properties = new ActivityPropertyDescriptor[0];
Category = "Miscellaneous";
DisplayName = "Activity";
Properties = new ActivityPropertyDescriptor[0];
Designer = new ActivityDesignerSettings();
Outcomes = null;
}
public string Type { get; set; }
public string DisplayName { get; set; }
public string? Description { get; set; }
public string? RuntimeDescription { get; set; }
public string Category { get; set; }
public string? Icon { get; set; }
public object? Outcomes { get; set; }
public ActivityPropertyDescriptor[] Properties { get; set; }
public ActivityDesignerSettings Designer { get; set; }
}
}

View file

@ -1,4 +1,4 @@
namespace Elsa.WorkflowDesigner.Models
namespace Elsa.Metadata
{
public class ActivityPropertyDescriptor
{

View file

@ -52,8 +52,7 @@ namespace Elsa.Services
var id = idGenerator.Generate();
var workflow = new Workflow(
id,
definition.DefinitionId,
definition.Version,
definition,
clock.GetCurrentInstant(),
activities,
connections,

View file

@ -8,25 +8,27 @@ namespace Elsa.WorkflowBuilders
{
public class ActivityBuilder : IActivityBuilder
{
public ActivityBuilder(WorkflowBuilder workflowBuilder, ActivityDefinition activity, string id)
public ActivityBuilder(WorkflowBuilder workflowBuilder, ActivityDefinition activity)
{
WorkflowBuilder = workflowBuilder;
Activity = activity;
Id = id;
}
public WorkflowBuilder WorkflowBuilder { get; }
public ActivityDefinition Activity { get; }
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string DisplayName { get; set; }
public IActivityBuilder StartWith<T>(Action<T> setup = default, string id = default) where T : class, IActivity
public IActivityBuilder StartWith<T>(Action<T> setup = default, string name = default) where T : class, IActivity
{
return Add(setup, id);
return Add(setup, name);
}
public IActivityBuilder Add<T>(Action<T> setup = default, string id = null) where T : class, IActivity
public IActivityBuilder Add<T>(Action<T> setup = default, string name = default) where T : class, IActivity
{
return WorkflowBuilder.Add(setup, id);
return WorkflowBuilder.Add(setup, name);
}
public IOutcomeBuilder When(string outcome)
@ -34,31 +36,53 @@ namespace Elsa.WorkflowBuilders
return new OutcomeBuilder(WorkflowBuilder, this, outcome);
}
public IActivityBuilder Then<T>(Action<T> setup = null, Action<IActivityBuilder> branch = null, string id = null) where T : class, IActivity
public IActivityBuilder Then<T>(Action<T> setup = null, Action<IActivityBuilder> branch = null, string name = default) where T : class, IActivity
{
var activityBuilder = When(null).Then(setup, branch, id);
var activityBuilder = When(null).Then(setup, branch, name);
return activityBuilder;
}
public IActivityBuilder WithId(string id)
public IActivityBuilder WithName(string name)
{
Id = id;
Name = name;
return this;
}
public IActivityBuilder WithDisplayName(string displayName)
{
DisplayName = displayName;
return this;
}
public IWorkflowBuilder Then(string activityId)
public IActivityBuilder WithDescription(string description)
{
Description = description;
return this;
}
public IWorkflowBuilder Then(string activityName)
{
WorkflowBuilder.Connect(
() => this,
() => WorkflowBuilder.Activities.First(x => x.Id == activityId)
() => WorkflowBuilder.Activities.First(x => x.Name== activityName)
);
return WorkflowBuilder;
}
public IActivityBuilder Then(IActivityBuilder targetActivity)
{
WorkflowBuilder.Connect(this, targetActivity);
return this;
}
public ActivityDefinition BuildActivity()
{
Activity.Id = Id;
Activity.Name = Name;
Activity.DisplayName = Name;
Activity.Description = Description;
Activity.DisplayName = DisplayName;
return Activity;
}

View file

@ -19,9 +19,9 @@ namespace Elsa.WorkflowBuilders
public IActivityBuilder Source { get; }
public string Outcome { get; }
public IActivityBuilder Then<T>(Action<T> setup = default, Action<IActivityBuilder> branch = null, string id = default) where T : class, IActivity
public IActivityBuilder Then<T>(Action<T> setup = default, Action<IActivityBuilder> branch = default, string name = default) where T : class, IActivity
{
var target = WorkflowBuilder.Add(setup, id);
var target = WorkflowBuilder.Add(setup, name);
branch?.Invoke(target);
WorkflowBuilder.Connect(Source, target, Outcome);
@ -30,11 +30,11 @@ namespace Elsa.WorkflowBuilders
public WorkflowDefinitionVersion Build() => WorkflowBuilder.Build();
public IConnectionBuilder Then(string activityId)
public IConnectionBuilder Then(string activityName)
{
return WorkflowBuilder.Connect(
() => Source,
() => WorkflowBuilder.Activities.First(x => x.Id == activityId),
() => WorkflowBuilder.Activities.First(x => x.Name == activityName),
Outcome);
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Elsa.Metadata;
using Elsa.Models;
using Elsa.Services;
using Elsa.Services.Models;
@ -59,30 +60,29 @@ namespace Elsa.WorkflowBuilders
IsSingleton = value;
return this;
}
public IWorkflowBuilder Disable()
{
IsDisabled = true;
return this;
}
public IWorkflowBuilder Enable()
{
IsDisabled = false;
return this;
}
public IActivityBuilder Add<T>(
Action<T> setupActivity = default,
string id = default) where T : class, IActivity
public IActivityBuilder Add<T>(Action<T> setupActivity = default, string name = default) where T : class, IActivity
{
var activity = activityResolver.ResolveActivity(setupActivity);
var activityBlueprint = ActivityDefinition.FromActivity(activity);
var activityBuilder = new ActivityBuilder(this, activityBlueprint, id);
if (id != null)
activity.Id = id;
var activityBuilder = new ActivityBuilder(this, activityBlueprint);
var activityDescriptor = ActivityDescriber.Describe<T>();
activity.Name = name;
activityBuilder.DisplayName = activityDescriptor.DisplayName;
activityBuilder.Description = activityDescriptor.Description;
activityBuilders.Add(activityBuilder);
return activityBuilder;
}
@ -107,11 +107,9 @@ namespace Elsa.WorkflowBuilders
}
public IActivityBuilder StartWith<T>(
Action<T> setupActivity,
string id = null) where T : class, IActivity
public IActivityBuilder StartWith<T>(Action<T> setupActivity, string name = default) where T : class, IActivity
{
return Add(setupActivity, id);
return Add(setupActivity, name);
}
public WorkflowDefinitionVersion Build()
@ -139,7 +137,11 @@ namespace Elsa.WorkflowBuilders
connections,
IsSingleton,
IsDisabled,
Variables.Empty);
Variables.Empty)
{
IsPublished = true,
IsLatest = true
};
}
}
}

19
src/core/Elsa/Elsa.csproj Normal file
View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.ControlFlow\Elsa.Activities.ControlFlow.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.UserTask\Elsa.Activities.UserTask.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Workflows\Elsa.Activities.Workflows.csproj" />
<ProjectReference Include="..\..\scripting\Elsa.Scripting.Liquid\Elsa.Scripting.Liquid.csproj" />
<ProjectReference Include="..\Elsa.Core\Elsa.Core.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,29 @@
using System;
using Elsa;
using Elsa.Activities.ControlFlow.Extensions;
using Elsa.Activities.UserTask.Extensions;
using Elsa.Activities.Workflows.Extensions;
using Elsa.Scripting.JavaScript;
using Elsa.Scripting.JavaScript.Extensions;
using Elsa.Scripting.Liquid;
using Elsa.Scripting.Liquid.Extensions;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ElsaServiceCollectionExtensions
{
public static IServiceCollection AddElsa(
this IServiceCollection services,
Action<ElsaBuilder> configure = null)
{
return services
.AddElsaCore(configure)
.AddJavaScriptExpressionEvaluator()
.AddLiquidExpressionEvaluator()
.AddControlFlowActivities()
.AddWorkflowActivities()
.AddUserTaskActivities();
}
}
}

View file

@ -1,3 +1,4 @@
using Elsa.Metadata;
using Elsa.WorkflowDesigner.Models;
namespace Elsa.Dashboard.Areas.Elsa.ViewModels
@ -11,7 +12,7 @@ namespace Elsa.Dashboard.Areas.Elsa.ViewModels
public string Description { get; set; }
public bool IsSingleton { get; set; }
public bool IsDisabled { get; set; }
public ActivityDefinitionModel[] ActivityDefinitions { get; set; }
public ActivityDescriptor[] ActivityDefinitions { get; set; }
public WorkflowModel WorkflowModel { get; set; }
}
}

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Elsa.Metadata;
using Elsa.Models;
using Elsa.WorkflowDesigner.Models;
@ -11,7 +12,7 @@ namespace Elsa.Dashboard.Areas.Elsa.ViewModels
WorkflowInstance workflowInstance,
WorkflowDefinitionVersion workflowDefinition,
WorkflowModel workflowModel,
IEnumerable<ActivityDefinitionModel> activityDefinitions,
IEnumerable<ActivityDescriptor> activityDefinitions,
string returnUrl)
{
WorkflowInstance = workflowInstance;
@ -24,7 +25,7 @@ namespace Elsa.Dashboard.Areas.Elsa.ViewModels
public WorkflowInstance WorkflowInstance { get; }
public WorkflowDefinitionVersion WorkflowDefinition { get; }
public WorkflowModel WorkflowModel { get; }
public ActivityDefinitionModel[] ActivityDefinitions { get; }
public ActivityDescriptor[] ActivityDefinitions { get; }
public string ReturnUrl { get; }
}
}

View file

@ -32,8 +32,8 @@
<!-- CSS Files -->
<link href="~/_content/Elsa.Dashboard/assets/css/argon-dashboard.css?v=1.1.0" rel="stylesheet"/>
<link href="~/_content/Elsa.Dashboard/assets/css/elsa.css?v=1.1.0" rel="stylesheet"/>
<script type="module" src="https://unpkg.com/@@elsa-workflows/elsa-workflow-designer@0.0.59/dist/elsa-workflow-designer/elsa-workflow-designer.esm.js"></script>
<script nomodule="" src="https://unpkg.com/@@elsa-workflows/elsa-workflow-designer@0.0.59/dist/elsa-workflow-designer/elsa-workflow-designer.js"></script>
<script type="module" src="https://unpkg.com/@@elsa-workflows/elsa-workflow-designer@0.0.61/dist/elsa-workflow-designer/elsa-workflow-designer.esm.js"></script>
<script nomodule="" src="https://unpkg.com/@@elsa-workflows/elsa-workflow-designer@0.0.61/dist/elsa-workflow-designer/elsa-workflow-designer.js"></script>
@await RenderSectionAsync("HeadScripts", false)
</head>

View file

@ -12,9 +12,6 @@
</div>
<div class="col-4 text-right">
<a href="#!" class="btn btn-secondary" onclick="exportWorkflow()">Download</a>
<a href="#!" class="btn btn-secondary" data-toggle="modal" data-target="#workflow-properties-modal">
<i class="ni ni-settings-gear-65"></i>
</a>
</div>
</div>
</div>

View file

@ -1,5 +1,6 @@
using System;
using Elsa.Dashboard.Options;
using Elsa.Metadata;
using Elsa.Services.Models;
using Elsa.WorkflowDesigner;
using Microsoft.Extensions.DependencyInjection;

View file

@ -1,25 +1,26 @@
using System.Collections;
using System.Collections.Generic;
using Elsa.Metadata;
using Elsa.WorkflowDesigner.Models;
namespace Elsa.Dashboard.Options
{
public class ActivityDefinitionList : IEnumerable<ActivityDefinitionModel>
public class ActivityDefinitionList : IEnumerable<ActivityDescriptor>
{
public ActivityDefinitionList()
{
Items = new Dictionary<string, ActivityDefinitionModel>();
Items = new Dictionary<string, ActivityDescriptor>();
}
private IDictionary<string, ActivityDefinitionModel> Items { get; }
private IDictionary<string, ActivityDescriptor> Items { get; }
public ActivityDefinitionList Add(ActivityDefinitionModel item)
public ActivityDefinitionList Add(ActivityDescriptor item)
{
Items[item.Type] = item;
return this;
}
public IEnumerator<ActivityDefinitionModel> GetEnumerator() => Items.Values.GetEnumerator();
public IEnumerator<ActivityDescriptor> GetEnumerator() => Items.Values.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{

View file

@ -15,12 +15,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.7.2" />
<PackageReference Include="Humanizer.Core" Version="2.7.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
</ItemGroup>
</Project>

View file

@ -1,8 +0,0 @@
namespace Elsa.WorkflowDesigner.Models
{
public class ActivityDesignerSettings
{
public object? Description { get; set; }
public object? Outcomes { get; set; }
}
}

View file

@ -1,3 +1,4 @@
using Elsa.Metadata;
using Elsa.WorkflowDesigner.Models;
using Elsa.WorkflowDesigner.ViewModels;
using Microsoft.AspNetCore.Mvc;
@ -10,13 +11,13 @@ namespace Elsa.WorkflowDesigner.ViewComponents
{
public IViewComponentResult Invoke(
string id,
ActivityDefinitionModel[]? activityDefinitions = null,
ActivityDescriptor[]? activityDefinitions = null,
WorkflowModel? workflow = null,
bool? isReadonly = null)
{
var model = new WorkflowDesignerViewComponentModel(
id,
Serialize(activityDefinitions ?? new ActivityDefinitionModel[0]),
Serialize(activityDefinitions ?? new ActivityDescriptor[0]),
Serialize(workflow ?? new WorkflowModel()),
isReadonly.GetValueOrDefault()
);

View file

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.6.0" />
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.8.1" />
</ItemGroup>
<ItemGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>latest</LangVersion>
<PackageVersion>1.0.0</PackageVersion>
<Authors>Sipke Schoorstra</Authors>
@ -15,11 +15,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FlexLabs.EntityFrameworkCore.Upsert" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
<PackageReference Include="FlexLabs.EntityFrameworkCore.Upsert" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
</ItemGroup>
<ItemGroup>

View file

@ -14,7 +14,6 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
</ItemGroup>

View file

@ -1,6 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Persistence.MongoDb.Extensions
namespace Elsa.Persistence.MongoDb
{
public class MongoElsaBuilder : ElsaBuilder
{

View file

@ -15,17 +15,16 @@
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj" />
<ProjectReference Include="..\..\core\Elsa.AutoMapper.Extensions\Elsa.AutoMapper.Extensions.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
<PackageReference Include="YesSql.Core" Version="2.0.0-beta-1395" />
<PackageReference Include="YesSql.Provider.MySql" Version="1.0.0-beta-1395" />
<PackageReference Include="YesSql.Provider.PostgreSql" Version="1.0.0-beta-1395" />
<PackageReference Include="YesSql.Provider.Sqlite" Version="1.0.0-beta-1395" />
<PackageReference Include="YesSql.Provider.SqlServer" Version="1.0.0-beta-1395" />
<PackageReference Include="YesSql.Core" Version="2.0.0-beta-1437" />
<PackageReference Include="YesSql.Provider.MySql" Version="1.0.0-beta-1437" />
<PackageReference Include="YesSql.Provider.PostgreSql" Version="1.0.0-beta-1437" />
<PackageReference Include="YesSql.Provider.Sqlite" Version="1.0.0-beta-1437" />
<PackageReference Include="YesSql.Provider.SqlServer" Version="1.0.0-beta-1437" />
</ItemGroup>
</Project>

View file

@ -15,7 +15,7 @@ namespace Sample01
{
// Setup a service collection.
var services = new ServiceCollection()
.AddWorkflows()
.AddElsa()
.AddActivity<HelloWorld>()
.AddActivity<GoodByeWorld>()
.BuildServiceProvider();

View file

@ -2,12 +2,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

View file

@ -17,7 +17,7 @@ namespace Sample02
{
// Setup a service collection.
var services = new ServiceCollection()
.AddWorkflows()
.AddElsa()
.AddConsoleActivities()
.BuildServiceProvider();

View file

@ -2,12 +2,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

View file

@ -19,7 +19,7 @@ namespace Sample03
{
// Setup a service collection.
var services = new ServiceCollection()
.AddWorkflows()
.AddElsa()
.AddConsoleActivities()
.BuildServiceProvider();

View file

@ -2,12 +2,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

View file

@ -1,7 +1,10 @@
using Elsa;
using Elsa.Activities;
using Elsa.Activities.Console.Activities;
using Elsa.Activities.ControlFlow;
using Elsa.Activities.ControlFlow.Activities;
using Elsa.Expressions;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
using Sample04.Activities;
@ -13,57 +16,65 @@ namespace Sample04
public void Build(IWorkflowBuilder builder)
{
builder
.StartWith<WriteLine>(x => x.TextExpression = new LiteralExpression("Welcome to Calculator Workflow!"), "welcome")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Enter number 1:"), id: "enter-first-number-prompt")
.Then<ReadLine>(x => x.VariableName = "number1", id: "read-first-number")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Enter number 2:"), id: "enter-second-number-prompt")
.Then<ReadLine>(x => x.VariableName = "number2", id: "read-second-number")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Now enter the operation you wish to apply. Options are: add, subtract, multiply or divide:"), id: "enter-operation-prompt")
.Then<ReadLine>(x => x.VariableName = "operation", id: "read-operation")
.Then<Switch>(@switch =>
.StartWith<WriteLine>(x => x.TextExpression = new LiteralExpression("Welcome to Calculator Workflow!")).WithDisplayName("Welcome")
.Then<SetVariable>(
x =>
{
@switch.Expression = new JavaScriptExpression<string>("operation");
@switch.Cases = new[] { "add", "subtract", "multiply", "divide" };
},
@switch =>
x.VariableName = "Exit";
x.ValueExpression = new JavaScriptExpression<bool>("false");
}).WithDisplayName("Initialize Exit Variable")
.Then<While>(
x => x.ConditionExpression = new JavaScriptExpression<bool>("!Exit"),
whileActivity =>
{
@switch
.When("add")
.Then<Sum>(SetupOperation, id: "perform-sum")
.Then("show-result");
@switch
.When("subtract")
.Then<Subtract>(SetupOperation, id: "perform-subtract")
.Then("show-result");
@switch
.When("multiply")
.Then<Multiply>(SetupOperation, id: "perform-multiply")
.Then("show-result");
@switch
.When("divide")
.Then<Divide>(SetupOperation, id: "perform-divide")
.Then("show-result");
},
"inspect-selected-operation"
)
.Add<WriteLine>(x => x.TextExpression = new JavaScriptExpression<string>("`Result: ${result}`"), "show-result")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Try again? (y/n)"), id: "try-again-prompt")
.Then<ReadLine>(x => x.VariableName = "retry", id: "read-try-again")
.Then<IfElse>(
x => x.ConditionExpression = new JavaScriptExpression<bool>("retry.toLowerCase() === 'y'"),
ifElse =>
{
ifElse
.When(OutcomeNames.True)
.Then("enter-first-number-prompt");
ifElse
.When(OutcomeNames.False)
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Bye!"), id: "say-good-bye");
}, id: "inspect-retry");
whileActivity
.When(OutcomeNames.Iterate)
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Enter number 1:"))
.Then<ReadLine>(x => x.VariableName = "number1")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Enter number 2:"))
.Then<ReadLine>(x => x.VariableName = "number2")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Now enter the operation you wish to apply. Options are: add, subtract, multiply or divide:"))
.Then<ReadLine>(x => x.VariableName = "operation")
.Then<Switch>(
@switch =>
{
@switch.Expression = new JavaScriptExpression<string>("operation");
@switch.Cases = new[] { "add", "subtract", "multiply", "divide" };
},
@switch =>
{
@switch
.When("add")
.Then<Sum>(SetupOperation).WithName("PerformSum")
.Then("ShowResult");
@switch
.When("subtract")
.Then<Subtract>(SetupOperation).WithName("PerformSubtract")
.Then("ShowResult");
@switch
.When("multiply")
.Then<Multiply>(SetupOperation).WithName("PerformMultiply")
.Then("ShowResult");
@switch
.When("divide")
.Then<Divide>(SetupOperation).WithName("PerformDivide")
.Then("ShowResult");
}
).WithName("InspectSelectedOperation")
.Add<WriteLine>(x => x.TextExpression = new JavaScriptExpression<string>("`Result: ${result}`")).WithName("ShowResult")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Try again? (y/n)"))
.Then<ReadLine>().WithName("TryAgain")
.Then<SetVariable>(x =>
{
x.VariableName = "Exit";
x.ValueExpression = new JavaScriptExpression<bool>("TryAgain.Input !== 'y' && TryAgain.Input !== 'Y'");
})
.Then(whileActivity);
}).WithDisplayName("While")
.Then<WriteLine>(x => x.TextExpression = new LiteralExpression("Bye!"));
}
private void SetupOperation(ArithmeticOperation operation)

View file

@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Elsa.Activities.Console.Extensions;
using Elsa.Services;
@ -16,7 +17,8 @@ namespace Sample04
{
// Setup a service collection.
var services = new ServiceCollection()
.AddWorkflows()
.AddSingleton(Console.In)
.AddElsa()
.AddConsoleActivities()
.AddActivity<Sum>()
.AddActivity<Subtract>()
@ -35,7 +37,8 @@ namespace Sample04
Console.WriteLine("Workflow has ended. Here are the activities that have executed:");
foreach (var logEntry in workflow.ExecutionLog)
{
Console.WriteLine("{0}: {1}", logEntry.Timestamp, logEntry.ActivityId);
var activity = workflow.Definition.Activities.First(x => x.Id == logEntry.ActivityId);
Console.WriteLine("{0}: {1}", logEntry.Timestamp, activity.DisplayName);
}
Console.ReadLine();
}

View file

@ -6,8 +6,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

View file

@ -31,9 +31,9 @@ namespace Sample05
private static void ConfigureServices(IServiceCollection services)
{
services
.AddWorkflows()
.AddWorkflow<RecurringWorkflow>()
.AddElsa()
.AddConsoleActivities()
.AddWorkflow<RecurringWorkflow>()
.AddTimerActivities(options => options.Configure(x => x.SweepInterval = Period.FromSeconds(1)));
}
}

View file

@ -2,6 +2,7 @@ using System;
using Elsa.Activities.Console.Activities;
using Elsa.Activities.Timers.Activities;
using Elsa.Expressions;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;

View file

@ -6,9 +6,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -5,8 +5,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

View file

@ -19,7 +19,7 @@ namespace Sample06
public void ConfigureServices(IServiceCollection services)
{
services
.AddWorkflows()
.AddElsa()
.AddHttpActivities()
.AddWorkflow<HelloWorldWorkflow>();
}

View file

@ -2,13 +2,16 @@ using System;
using System.Net;
using System.Net.Http;
using Elsa;
using Elsa.Activities;
using Elsa.Activities.Email.Activities;
using Elsa.Activities.Http.Activities;
using Elsa.Activities.ControlFlow;
using Elsa.Activities.Primitives;
using Elsa.Activities.ControlFlow.Activities;
using Elsa.Activities.Timers.Activities;
using Elsa.Activities.Workflows;
using Elsa.Activities.Workflows.Activities;
using Elsa.Expressions;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
@ -25,14 +28,13 @@ namespace Sample07
x.Method = HttpMethod.Post.Method;
x.Path = new Uri("/documents", UriKind.Relative);
x.ReadContent = true;
},
"WaitForDocument"
)
}
).WithName("WaitForDocument")
.Then<SetVariable>(
x =>
{
x.VariableName = "Document";
x.ValueExpression = new JavaScriptExpression<object>("lastResult().Content");
x.ValueExpression = new JavaScriptExpression<object>("WaitForDocument.Content");
}
)
.Then<SendEmail>(
@ -83,9 +85,8 @@ namespace Sample07
fork
.When("Remind")
.Then<TimerEvent>(
x => x.TimeoutExpression = new LiteralExpression<TimeSpan>("00:00:10"),
id: "RemindTimer"
)
x => x.TimeoutExpression = new LiteralExpression<TimeSpan>("00:00:10")
).WithName("RemindTimer")
.Then<IfElse>(
x => x.ConditionExpression = new JavaScriptExpression<bool>("!!Approved"),
ifElse =>
@ -112,7 +113,7 @@ namespace Sample07
);
}
)
.Then<Join>(x => x.Mode = Join.JoinMode.WaitAny, id: "Join")
.Then<Join>(x => x.Mode = Join.JoinMode.WaitAny).WithName("Join")
.Then<SetVariable>(
x =>
{

View file

@ -5,10 +5,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>

View file

@ -21,7 +21,7 @@ namespace Sample07
public void ConfigureServices(IServiceCollection services)
{
services
.AddWorkflows()
.AddElsa()
.AddTaskExecutingServer()
.AddHttpActivities(options => options.Bind(Configuration.GetSection("Http")))
.AddEmailActivities(options => options.Bind(Configuration.GetSection("Smtp")))

View file

@ -5,15 +5,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MassTransit.AspNetCore" Version="5.5.2" />
<PackageReference Include="MassTransit.AspNetCore" Version="5.5.6" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.MassTransit\Elsa.Activities.MassTransit.csproj" />
<ProjectReference Include="..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>

View file

@ -25,7 +25,7 @@ namespace Sample08
public void ConfigureServices(IServiceCollection services)
{
services
.AddWorkflows()
.AddElsa()
.AddTaskExecutingServer()
.AddHttpActivities()
.AddTimerActivities(options => options.Configure(x => x.SweepInterval = Period.FromSeconds(10)))

View file

@ -1,12 +1,14 @@
using System;
using System.Net;
using System.Net.Http;
using Elsa.Activities;
using Elsa.Activities.Email.Activities;
using Elsa.Activities.Http.Activities;
using Elsa.Activities.MassTransit.Activities;
using Elsa.Activities.ControlFlow;
using Elsa.Activities.Primitives;
using Elsa.Activities.ControlFlow.Activities;
using Elsa.Expressions;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
using Sample08.Messages;

View file

@ -1,8 +1,9 @@
using System;
using Elsa.Activities;
using Elsa.Activities.MassTransit.Activities;
using Elsa.Activities.Timers.Activities;
using Elsa.Activities.Primitives;
using Elsa.Expressions;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;
using Sample08.Messages;

View file

@ -30,18 +30,17 @@ namespace Sample09
private static IServiceProvider BuildServices()
{
return new ServiceCollection()
.AddWorkflows()
.AddElsa()
.AddConsoleActivities()
.AddSingleton(Console.In)
.BuildServiceProvider();
}
private static async Task<string> ReadEmbeddedResourceAsync(string resourceName)
{
var assembly = typeof(Program).GetTypeInfo().Assembly;
using (var reader = new StreamReader(assembly.GetManifestResourceStream(resourceName)))
{
return await reader.ReadToEndAsync();
}
using var reader = new StreamReader(assembly.GetManifestResourceStream(resourceName));
return await reader.ReadToEndAsync();
}
}
}

View file

@ -7,8 +7,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj"/>
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj"/>
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj"/>
</ItemGroup>
<ItemGroup>

View file

@ -25,46 +25,44 @@ namespace Sample10
var startupRunner = services.GetRequiredService<IStartupRunner>();
await startupRunner.StartupAsync();
using (var scope = services.CreateScope())
{
var definitionStore = scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionStore>();
var workflowDefinitionId = nameof(HelloWorldWorkflow);
using var scope = services.CreateScope();
var definitionStore = scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionStore>();
const string workflowDefinitionId = nameof(HelloWorldWorkflow);
// When running this program multiple times, we should delete the created workflow definition before adding it to the store again.
await definitionStore.DeleteAsync(workflowDefinitionId);
// When running this program multiple times, we should delete the created workflow definition before adding it to the store again.
await definitionStore.DeleteAsync(workflowDefinitionId);
// Create a workflow definition.
var registry = services.GetService<IWorkflowRegistry>();
var workflowDefinition = await registry.GetWorkflowDefinitionAsync<HelloWorldWorkflow>();
// Create a workflow definition.
var registry = services.GetService<IWorkflowRegistry>();
var workflowDefinition = await registry.GetWorkflowDefinitionAsync<HelloWorldWorkflow>();
// Mark this definition as the "latest" version.
workflowDefinition.IsLatest = true;
workflowDefinition.Version = 1;
// Mark this definition as the "latest" version.
workflowDefinition.IsLatest = true;
workflowDefinition.Version = 1;
// Persist the workflow definition.
// Persist the workflow definition.
await definitionStore.SaveAsync(workflowDefinition);
await definitionStore.SaveAsync(workflowDefinition);
// Load the workflow definition.
workflowDefinition = await definitionStore.GetByIdAsync(
workflowDefinition.DefinitionId,
VersionOptions.Latest);
// Load the workflow definition.
workflowDefinition = await definitionStore.GetByIdAsync(
workflowDefinition.DefinitionId,
VersionOptions.Latest);
// Execute the workflow.
var invoker = scope.ServiceProvider.GetRequiredService<IWorkflowInvoker>();
var executionContext = await invoker.StartAsync(workflowDefinition);
// Execute the workflow.
var invoker = scope.ServiceProvider.GetRequiredService<IWorkflowInvoker>();
var executionContext = await invoker.StartAsync(workflowDefinition);
// Persist the workflow instance.
var instanceStore = scope.ServiceProvider.GetRequiredService<IWorkflowInstanceStore>();
var workflowInstance = executionContext.Workflow.ToInstance();
await instanceStore.SaveAsync(workflowInstance);
}
// Persist the workflow instance.
var instanceStore = scope.ServiceProvider.GetRequiredService<IWorkflowInstanceStore>();
var workflowInstance = executionContext.Workflow.ToInstance();
await instanceStore.SaveAsync(workflowInstance);
}
private static IServiceProvider BuildServices()
{
return new ServiceCollection()
.AddWorkflows(
.AddElsa(
x => x.AddYesSqlStores(
options => options
.UseSqLite(

View file

@ -7,11 +7,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj"/>
<ProjectReference Include="..\..\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj"/>
<ProjectReference Include="..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj"/>
<ProjectReference Include="..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj"/>
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj"/>
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj"/>
<ProjectReference Include="..\..\persistence\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj"/>
</ItemGroup>

View file

@ -1,6 +1,8 @@
using Elsa.Activities.Console.Activities;
using Elsa.Activities.Workflows;
using Elsa.Activities.Workflows.Activities;
using Elsa.Expressions;
using Elsa.Scripting.JavaScript;
using Elsa.Services;
using Elsa.Services.Models;

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using Elsa.Activities.Console.Extensions;
using Elsa.Activities.Workflows;
using Elsa.Activities.Workflows.Activities;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Services;
@ -49,7 +50,7 @@ namespace Sample11
private static IServiceProvider BuildServices()
{
return new ServiceCollection()
.AddWorkflows()
.AddElsa()
.AddConsoleActivities()
.AddWorkflow<CorrelationWorkflow>()
.BuildServiceProvider();

View file

@ -6,8 +6,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
</ItemGroup>
</Project>

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