diff --git a/Samples.sln b/Samples.sln index 4f6eb3773..ae9b635e9 100644 --- a/Samples.sln +++ b/Samples.sln @@ -118,6 +118,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample21", "src\samples\Sam EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Dashboard.Web", "src\dashboard\Elsa.Dashboard.Web\Elsa.Dashboard.Web.csproj", "{AE0363D2-3630-4CDD-86A1-7D6A717361BD}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "server", "server", "{849F4EC1-2694-4D29-ABBA-A63E01700F27}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Server.GraphQL", "src\server\Elsa.Server.GraphQL\Elsa.Server.GraphQL.csproj", "{9E3B1169-6E3F-4885-9CAF-9BD6D7D8A2A5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Server.Host", "src\server\Elsa.Server.Host\Elsa.Server.Host.csproj", "{9CB171C8-7490-4D4C-A7B9-97B553444D12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Server.Core", "src\server\Elsa.Server.Core\Elsa.Server.Core.csproj", "{6B672FE5-4D5E-4D17-A616-6DDB1F973F8F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -300,6 +308,18 @@ Global {AE0363D2-3630-4CDD-86A1-7D6A717361BD}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE0363D2-3630-4CDD-86A1-7D6A717361BD}.Release|Any CPU.ActiveCfg = Release|Any CPU {AE0363D2-3630-4CDD-86A1-7D6A717361BD}.Release|Any CPU.Build.0 = Release|Any CPU + {9E3B1169-6E3F-4885-9CAF-9BD6D7D8A2A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E3B1169-6E3F-4885-9CAF-9BD6D7D8A2A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E3B1169-6E3F-4885-9CAF-9BD6D7D8A2A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E3B1169-6E3F-4885-9CAF-9BD6D7D8A2A5}.Release|Any CPU.Build.0 = Release|Any CPU + {9CB171C8-7490-4D4C-A7B9-97B553444D12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CB171C8-7490-4D4C-A7B9-97B553444D12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CB171C8-7490-4D4C-A7B9-97B553444D12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CB171C8-7490-4D4C-A7B9-97B553444D12}.Release|Any CPU.Build.0 = Release|Any CPU + {6B672FE5-4D5E-4D17-A616-6DDB1F973F8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B672FE5-4D5E-4D17-A616-6DDB1F973F8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B672FE5-4D5E-4D17-A616-6DDB1F973F8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B672FE5-4D5E-4D17-A616-6DDB1F973F8F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -356,6 +376,10 @@ Global {9B238B75-5A68-48B1-973A-59F0EFAB0A8B} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} {6BA81F4E-2B17-4C7B-ACB1-6588B0315582} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} {AE0363D2-3630-4CDD-86A1-7D6A717361BD} = {0DF567E8-2A21-4A1C-90E8-025F1EC615F3} + {849F4EC1-2694-4D29-ABBA-A63E01700F27} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925} + {9E3B1169-6E3F-4885-9CAF-9BD6D7D8A2A5} = {849F4EC1-2694-4D29-ABBA-A63E01700F27} + {9CB171C8-7490-4D4C-A7B9-97B553444D12} = {849F4EC1-2694-4D29-ABBA-A63E01700F27} + {6B672FE5-4D5E-4D17-A616-6DDB1F973F8F} = {849F4EC1-2694-4D29-ABBA-A63E01700F27} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158} diff --git a/Samples.sln.DotSettings b/Samples.sln.DotSettings index 5c438ec70..111eda3f2 100644 --- a/Samples.sln.DotSettings +++ b/Samples.sln.DotSettings @@ -1,6 +1,7 @@  False EF + QL True True True diff --git a/src/activities/Elsa.Activities.Email/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.Email/Extensions/ServiceCollectionExtensions.cs index c51037f4e..007054a50 100644 --- a/src/activities/Elsa.Activities.Email/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.Email/Extensions/ServiceCollectionExtensions.cs @@ -2,10 +2,9 @@ using System; using Elsa.Activities.Email.Activities; using Elsa.Activities.Email.Options; using Elsa.Activities.Email.Services; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -namespace Elsa.Activities.Email.Extensions +namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionExtensions { diff --git a/src/activities/Elsa.Activities.Http/Extensions/ApplicationBuilderExtensions.cs b/src/activities/Elsa.Activities.Http/Extensions/ApplicationBuilderExtensions.cs index a4db45ced..d492bc395 100644 --- a/src/activities/Elsa.Activities.Http/Extensions/ApplicationBuilderExtensions.cs +++ b/src/activities/Elsa.Activities.Http/Extensions/ApplicationBuilderExtensions.cs @@ -1,9 +1,8 @@ using Elsa.Activities.Http.Middleware; using Elsa.Activities.Http.RequestHandlers.Handlers; using Elsa.Activities.Http.Services; -using Microsoft.AspNetCore.Builder; -namespace Elsa.Activities.Http.Extensions +namespace Microsoft.AspNetCore.Builder { public static class ApplicationBuilderExtensions { diff --git a/src/activities/Elsa.Activities.Http/Extensions/HttpActivitiesServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.Http/Extensions/HttpActivitiesServiceCollectionExtensions.cs index 12bd423f3..5af08a160 100644 --- a/src/activities/Elsa.Activities.Http/Extensions/HttpActivitiesServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.Http/Extensions/HttpActivitiesServiceCollectionExtensions.cs @@ -9,11 +9,10 @@ using Elsa.Extensions; using Elsa.Scripting.Liquid.Extensions; 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 +namespace Microsoft.Extensions.DependencyInjection { public static class HttpActivitiesServiceCollectionExtensions { diff --git a/src/activities/Elsa.Activities.Timers/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.Timers/Extensions/ServiceCollectionExtensions.cs index f13b7907c..6578fb3c0 100644 --- a/src/activities/Elsa.Activities.Timers/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.Timers/Extensions/ServiceCollectionExtensions.cs @@ -2,10 +2,9 @@ using System; using Elsa.Activities.Timers.Activities; using Elsa.Activities.Timers.HostedServices; using Elsa.Activities.Timers.Options; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -namespace Elsa.Activities.Timers.Extensions +namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionExtensions { diff --git a/src/dashboard/Elsa.Dashboard.Web/Startup.cs b/src/dashboard/Elsa.Dashboard.Web/Startup.cs index de8fb85d9..3e9085080 100644 --- a/src/dashboard/Elsa.Dashboard.Web/Startup.cs +++ b/src/dashboard/Elsa.Dashboard.Web/Startup.cs @@ -1,8 +1,4 @@ -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Http.Extensions; -using Elsa.Activities.Timers.Extensions; using Elsa.Dashboard.Extensions; -using Elsa.Persistence.MongoDb.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; diff --git a/src/dashboard/Elsa.Dashboard/Elsa.Dashboard.csproj b/src/dashboard/Elsa.Dashboard/Elsa.Dashboard.csproj index 531b2b012..2722a71b1 100644 --- a/src/dashboard/Elsa.Dashboard/Elsa.Dashboard.csproj +++ b/src/dashboard/Elsa.Dashboard/Elsa.Dashboard.csproj @@ -37,6 +37,7 @@ + diff --git a/src/dashboard/Elsa.Dashboard/Extensions/DashboardServiceCollectionExtensions.cs b/src/dashboard/Elsa.Dashboard/Extensions/DashboardServiceCollectionExtensions.cs index 81bbf37c0..9e4cdaf88 100644 --- a/src/dashboard/Elsa.Dashboard/Extensions/DashboardServiceCollectionExtensions.cs +++ b/src/dashboard/Elsa.Dashboard/Extensions/DashboardServiceCollectionExtensions.cs @@ -23,11 +23,12 @@ namespace Elsa.Dashboard.Extensions Action configure = default ) { - var configuration = new ElsaBuilder(services); + var builder = new ElsaBuilder(services); services.AddControllersWithViews(); - configuration.WithElsaDashboard(); - configure?.Invoke(configuration); + services.AddElsaManagement(); + builder.WithElsaDashboard(); + configure?.Invoke(builder); var optionsBuilder = services.AddOptions(); options?.Invoke(optionsBuilder); @@ -51,17 +52,9 @@ namespace Elsa.Dashboard.Extensions var services = builder.Services; services - .AddSingleton() - .AddSingleton() - .AddSingleton() - .TryAddProvider(ServiceLifetime.Singleton) - .TryAddProvider(ServiceLifetime.Singleton) - .TryAddProvider(ServiceLifetime.Singleton) .AddHttpContextAccessor() - .AddScoped() .AddScoped() - .AddScoped() - .AddAutoMapperProfile(ServiceLifetime.Singleton); + .AddScoped(); services.AddScoped( sp => diff --git a/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs b/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs index b282c1c15..f2c6ce978 100644 --- a/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs +++ b/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs @@ -1,16 +1,18 @@ using System; +using Elsa; using Elsa.Models; +using Elsa.Persistence; +using Elsa.Persistence.MongoDb; using Elsa.Persistence.MongoDb.Serialization; using Elsa.Persistence.MongoDb.Services; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson; using MongoDb.Bson.NodaTime; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using MongoDB.Driver; -namespace Elsa.Persistence.MongoDb.Extensions +namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionExtensions { diff --git a/src/samples/Sample05/Program.cs b/src/samples/Sample05/Program.cs index d54591ef2..c5137e570 100644 --- a/src/samples/Sample05/Program.cs +++ b/src/samples/Sample05/Program.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Elsa.Activities.Console.Extensions; -using Elsa.Activities.Timers.Extensions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; diff --git a/src/samples/Sample06/Startup.cs b/src/samples/Sample06/Startup.cs index 5711cf2aa..820e8ca4c 100644 --- a/src/samples/Sample06/Startup.cs +++ b/src/samples/Sample06/Startup.cs @@ -1,5 +1,4 @@ -using Elsa.Activities.Http.Extensions; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/src/samples/Sample07/Startup.cs b/src/samples/Sample07/Startup.cs index f3391cb08..b784105d1 100644 --- a/src/samples/Sample07/Startup.cs +++ b/src/samples/Sample07/Startup.cs @@ -1,7 +1,4 @@ -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Http.Extensions; -using Elsa.Activities.Timers.Extensions; -using Elsa.Runtime; +using Elsa.Runtime; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/src/samples/Sample08/Startup.cs b/src/samples/Sample08/Startup.cs index 773ed631d..6dc0fcecf 100644 --- a/src/samples/Sample08/Startup.cs +++ b/src/samples/Sample08/Startup.cs @@ -1,7 +1,4 @@ -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Http.Extensions; -using Elsa.Activities.MassTransit.Extensions; -using Elsa.Activities.Timers.Extensions; +using Elsa.Activities.MassTransit.Extensions; using Elsa.Runtime; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; diff --git a/src/samples/Sample15/Program.cs b/src/samples/Sample15/Program.cs index b33028e5a..30b4a103d 100644 --- a/src/samples/Sample15/Program.cs +++ b/src/samples/Sample15/Program.cs @@ -5,7 +5,6 @@ using Elsa.Activities.Console.Extensions; using Elsa.Extensions; using Elsa.Models; using Elsa.Persistence; -using Elsa.Persistence.MongoDb.Extensions; using Elsa.Runtime; using Elsa.Services; using Microsoft.Extensions.Configuration; diff --git a/src/samples/Sample16/Startup.cs b/src/samples/Sample16/Startup.cs index 66c12fac1..c9fae88d2 100644 --- a/src/samples/Sample16/Startup.cs +++ b/src/samples/Sample16/Startup.cs @@ -1,8 +1,4 @@ -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Http.Extensions; -using Elsa.Activities.Timers.Extensions; using Elsa.Dashboard.Extensions; -using Elsa.Persistence.MongoDb.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; diff --git a/src/samples/Sample18/Program.cs b/src/samples/Sample18/Program.cs index 97c3c2f9d..85de0d738 100644 --- a/src/samples/Sample18/Program.cs +++ b/src/samples/Sample18/Program.cs @@ -1,9 +1,6 @@ using System.IO; -using System.Net.Mail; using System.Threading.Tasks; using Elsa.Activities.Console.Extensions; -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Timers.Extensions; using Elsa.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; diff --git a/src/samples/Sample19/Startup.cs b/src/samples/Sample19/Startup.cs index 0142477cb..fff1d8442 100644 --- a/src/samples/Sample19/Startup.cs +++ b/src/samples/Sample19/Startup.cs @@ -1,6 +1,3 @@ -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Http.Extensions; -using Elsa.Activities.Timers.Extensions; using Elsa.Dashboard.Extensions; using Elsa.Persistence.EntityFrameworkCore.Extensions; using Microsoft.AspNetCore.Builder; diff --git a/src/samples/Sample21/Startup.cs b/src/samples/Sample21/Startup.cs index d3c84aaa3..0943416ab 100644 --- a/src/samples/Sample21/Startup.cs +++ b/src/samples/Sample21/Startup.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Specialized; -using Elsa.Activities.Email.Extensions; -using Elsa.Activities.Http.Extensions; using Elsa.Activities.MassTransit.Extensions; -using Elsa.Activities.Timers.Extensions; using Elsa.Runtime; using GreenPipes; using MassTransit; diff --git a/src/scripting/Elsa.Scripting.JavaScript/Handlers/DateTimeScriptEngineConfigurator.cs b/src/scripting/Elsa.Scripting.JavaScript/Handlers/DateTimeScriptEngineConfigurator.cs index fc4300159..2a4d4850e 100644 --- a/src/scripting/Elsa.Scripting.JavaScript/Handlers/DateTimeScriptEngineConfigurator.cs +++ b/src/scripting/Elsa.Scripting.JavaScript/Handlers/DateTimeScriptEngineConfigurator.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Elsa.Scripting.JavaScript.Messages; using MediatR; using NodaTime; -using NodaTime.Text; namespace Elsa.Scripting.JavaScript.Handlers { diff --git a/src/server/Elsa.Server.Core/Elsa.Server.Core.csproj b/src/server/Elsa.Server.Core/Elsa.Server.Core.csproj new file mode 100644 index 000000000..065a3d064 --- /dev/null +++ b/src/server/Elsa.Server.Core/Elsa.Server.Core.csproj @@ -0,0 +1,24 @@ + + + + netstandard2.0 + latest + 1.0.0 + Elsa Contributors + + Elsa is a set of workflow libraries and tools that enable super-fast workflowing capabilities in any .NET Core application. + This package provides services to manage workflows, such as serialization and versioning. + + 2019 + https://github.com/elsa-workflows/elsa-core + https://github.com/elsa-workflows/elsa-core + GitHub + elsa, workflows + icon.png + + + + + + + diff --git a/src/server/Elsa.Server.Core/Extensions/ServiceCollectionExtensions.cs b/src/server/Elsa.Server.Core/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..20495b9e5 --- /dev/null +++ b/src/server/Elsa.Server.Core/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,23 @@ +using Elsa.AutoMapper.Extensions; +using Elsa.Mapping; +using Elsa.Serialization; +using Elsa.Serialization.Formatters; +using Elsa.Services; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddElsaManagement(this IServiceCollection services) + { + return services.AddSingleton() + .AddSingleton() + .AddSingleton() + .TryAddProvider(ServiceLifetime.Singleton) + .TryAddProvider(ServiceLifetime.Singleton) + .TryAddProvider(ServiceLifetime.Singleton) + .AddScoped() + .AddAutoMapperProfile(ServiceLifetime.Singleton); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.Core/icon.png b/src/server/Elsa.Server.Core/icon.png new file mode 100644 index 000000000..f978a2882 Binary files /dev/null and b/src/server/Elsa.Server.Core/icon.png differ diff --git a/src/server/Elsa.Server.GraphQL/Elsa.Server.GraphQL.csproj b/src/server/Elsa.Server.GraphQL/Elsa.Server.GraphQL.csproj new file mode 100644 index 000000000..5e89cefd2 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Elsa.Server.GraphQL.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + diff --git a/src/server/Elsa.Server.GraphQL/ElsaMutation.cs b/src/server/Elsa.Server.GraphQL/ElsaMutation.cs new file mode 100644 index 000000000..4a72fcc7f --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/ElsaMutation.cs @@ -0,0 +1,45 @@ +using System.Linq; +using Elsa.Models; +using Elsa.Server.GraphQL.Models; +using Elsa.Server.GraphQL.Types; +using Elsa.Services; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL +{ + public class ElsaMutation : ObjectGraphType + { + public ElsaMutation(IWorkflowPublisher publisher, IIdGenerator idGenerator) + { + FieldAsync( + "defineWorkflow", + "Create a new workflow definitions", + new QueryArguments(new QueryArgument> { Name = "workflowDefinition" }), + async context => + { + var model = context.GetArgument("workflowDefinition"); + var publish = model.Publish; + + var workflowDefinition = new WorkflowDefinitionVersion( + idGenerator.Generate(), + model.Id ?? idGenerator.Generate(), + 1, + model.Name, + model.Description, + model.Activities.Select(x => x.ToActivityDefinition()), + model.Connections, + model.IsSingleton, + model.IsDisabled, + new Variables() + ); + + if (publish) + await publisher.PublishAsync(workflowDefinition, context.CancellationToken); + else + await publisher.SaveDraftAsync(workflowDefinition, context.CancellationToken); + + return workflowDefinition; + }); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/ElsaQuery.cs b/src/server/Elsa.Server.GraphQL/ElsaQuery.cs new file mode 100644 index 000000000..33427bf70 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/ElsaQuery.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Elsa.Models; +using Elsa.Persistence; +using Elsa.Server.GraphQL.Types; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL +{ + public class ElsaQuery : ObjectGraphType + { + private readonly IWorkflowDefinitionStore workflowDefinitionStore; + + public ElsaQuery(IWorkflowDefinitionStore workflowDefinitionStore) + { + this.workflowDefinitionStore = workflowDefinitionStore; + + FieldAsync>("workflowDefinitions", resolve: ResolveWorkflowDefinitions); + } + + private async Task ResolveWorkflowDefinitions(ResolveFieldContext context) + { + var items = await workflowDefinitionStore.ListAsync(VersionOptions.All, context.CancellationToken); + + return items; + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/ElsaSchema.cs b/src/server/Elsa.Server.GraphQL/ElsaSchema.cs new file mode 100644 index 000000000..f3da2be20 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/ElsaSchema.cs @@ -0,0 +1,14 @@ +using System; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL +{ + public class ElsaSchema : Schema + { + public ElsaSchema(ElsaQuery query, ElsaMutation mutation, IServiceProvider serviceProvider) : base(serviceProvider) + { + Query = query; + Mutation = mutation; + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Extensions/GraphQLApplicationBuilderExtensions.cs b/src/server/Elsa.Server.GraphQL/Extensions/GraphQLApplicationBuilderExtensions.cs new file mode 100644 index 000000000..1adfeb90a --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Extensions/GraphQLApplicationBuilderExtensions.cs @@ -0,0 +1,12 @@ +using Elsa.Server.GraphQL; + +namespace Microsoft.AspNetCore.Builder +{ + public static class GraphQLApplicationBuilderExtensions + { + public static IApplicationBuilder UseElsaGraphQL(this IApplicationBuilder app) + { + return app.UseGraphQL(); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Extensions/GraphQLServiceCollectionExtensions.cs b/src/server/Elsa.Server.GraphQL/Extensions/GraphQLServiceCollectionExtensions.cs new file mode 100644 index 000000000..0d33f7b93 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Extensions/GraphQLServiceCollectionExtensions.cs @@ -0,0 +1,33 @@ +using System; +using Elsa; +using Elsa.AutoMapper.Extensions; +using Elsa.Mapping; +using Elsa.Serialization; +using Elsa.Serialization.Formatters; +using Elsa.Server.GraphQL; +using Elsa.Services; +using GraphQL.Server; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class GraphQLServiceCollectionExtensions + { + public static ElsaBuilder AddGraphQL(this ElsaBuilder builder, Action configure = null) + { + var services = builder.Services; + + services + .AddScoped() + .AddLogging(); + + var graphQLOptions = new GraphQLOptions(); + configure?.Invoke(graphQLOptions); + + services + .AddGraphQL(graphQLOptions) + .AddGraphTypes(ServiceLifetime.Scoped); + + return builder; + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Models/ActivityDefinitionInputModel.cs b/src/server/Elsa.Server.GraphQL/Models/ActivityDefinitionInputModel.cs new file mode 100644 index 000000000..f4b4f7484 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Models/ActivityDefinitionInputModel.cs @@ -0,0 +1,32 @@ +using Elsa.Models; +using Newtonsoft.Json.Linq; + +namespace Elsa.Server.GraphQL.Models +{ + public class ActivityDefinitionInputModel + { + public string Id { get; set; } + public string Type { get; set; } + public string Name { get; set; } + public string DisplayName { get; set; } + public string Description { get; set; } + public int Left { get; set; } + public int Top { get; set; } + public string State { get; set; } + + public ActivityDefinition ToActivityDefinition() + { + return new ActivityDefinition + { + Id = Id, + Type = Type, + Name = Name, + DisplayName = DisplayName, + Description = Description, + Top = Top, + Left = Left, + State = JObject.Parse(State ?? "{}") + }; + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Models/WorkflowDefinitionInputModel.cs b/src/server/Elsa.Server.GraphQL/Models/WorkflowDefinitionInputModel.cs new file mode 100644 index 000000000..dad286491 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Models/WorkflowDefinitionInputModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Elsa.Models; + +namespace Elsa.Server.GraphQL.Models +{ + public class WorkflowDefinitionInputModel + { + public string Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public bool IsSingleton { get; set; } + public bool IsDisabled { get; set; } + public bool Publish { get; set; } + public IReadOnlyCollection Activities { get; set; } + public IReadOnlyCollection Connections { get; set; } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Types/ActivityDefinitionInputType.cs b/src/server/Elsa.Server.GraphQL/Types/ActivityDefinitionInputType.cs new file mode 100644 index 000000000..ab479f8fd --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Types/ActivityDefinitionInputType.cs @@ -0,0 +1,21 @@ +using Elsa.Server.GraphQL.Models; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL.Types +{ + public class ActivityDefinitionInputType : ObjectGraphType + { + public ActivityDefinitionInputType() + { + Name = "ActivityDefinitionInput"; + + Field(x => x.Type).Description("The activity type name."); + Field(x => x.Description).Description("A description for the activity"); + Field(x => x.Name).Description("A name for the activity. Named activities make it easy to be referenced from workflow expressions."); + Field(x => x.State).Description("The state of the activity in JSON format."); + Field(x => x.DisplayName).Description("A display name for this activity to display in workflow designers."); + Field(x => x.Left).Description("The X coordinate of the activity when displayed in workflow designers."); + Field(x => x.Top).Description("The Y coordinate of the activity when displayed in workflow designers."); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Types/ActivityDefinitionType.cs b/src/server/Elsa.Server.GraphQL/Types/ActivityDefinitionType.cs new file mode 100644 index 000000000..e6d86dc8f --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Types/ActivityDefinitionType.cs @@ -0,0 +1,21 @@ +using Elsa.Models; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL.Types +{ + public class ActivityDefinitionType : ObjectGraphType + { + public ActivityDefinitionType() + { + Name = "ActivityDefinition"; + + Field(x => x.Type).Description("The activity type name."); + Field(x => x.Description).Description("A description for the activity"); + Field(x => x.Name).Description("A name for the activity. Named activities make it easy to be referenced from workflow expressions."); + Field(x => x.State).Description("The state of the activity"); + Field(x => x.DisplayName, type: typeof(string)).Description("A display name for this activity to display in workflow designers."); + Field(x => x.Left).Description("The X coordinate of the activity when displayed in workflow designers."); + Field(x => x.Top).Description("The Y coordinate of the activity when displayed in workflow designers."); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Types/ConnectionDefinitionType.cs b/src/server/Elsa.Server.GraphQL/Types/ConnectionDefinitionType.cs new file mode 100644 index 000000000..00f63f7a4 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Types/ConnectionDefinitionType.cs @@ -0,0 +1,17 @@ +using Elsa.Models; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL.Types +{ + public class ConnectionDefinitionType : ObjectGraphType + { + public ConnectionDefinitionType() + { + Name = "ConnectionDefinition"; + + Field(x => x.SourceActivityId).Description("The source activity ID to connect from."); + Field(x => x.Outcome).Description("The source activity outcome to connect from."); + Field(x => x.DestinationActivityId).Description("The destination activity ID to connect to."); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Types/WorkflowDefinitionInputType.cs b/src/server/Elsa.Server.GraphQL/Types/WorkflowDefinitionInputType.cs new file mode 100644 index 000000000..4186286a8 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Types/WorkflowDefinitionInputType.cs @@ -0,0 +1,22 @@ +using Elsa.Server.GraphQL.Models; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL.Types +{ + public class WorkflowDefinitionInputType : InputObjectGraphType + { + public WorkflowDefinitionInputType() + { + Name = "WorkflowDefinitionInput"; + + Field(x => x.Id).Description("The ID you wish to assign the workflow. Id no value is specified, an ID will be generated."); + Field(x => x.Name).Description("The name of the workflow"); + Field(x => x.Description).Description("The description of the workflow."); + Field(x => x.IsDisabled).Description("Whether the workflow should be disabled or not."); + Field(x => x.IsSingleton).Description("Whether the workflow should act as a singleton or not. When true, only one instance can execute at any given time."); + Field(x => x.Publish).Description("Whether the workflow should be published. If set to false, the workflow will be saved as a draft."); + Field(x => x.Activities, type: typeof(ListGraphType)).Description("A list of activities for the workflow."); + Field(x => x.Connections, type: typeof(ListGraphType)).Description("A list of connections between activities on the workflow."); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/Types/WorkflowDefinitionVersionType.cs b/src/server/Elsa.Server.GraphQL/Types/WorkflowDefinitionVersionType.cs new file mode 100644 index 000000000..e9efdb267 --- /dev/null +++ b/src/server/Elsa.Server.GraphQL/Types/WorkflowDefinitionVersionType.cs @@ -0,0 +1,25 @@ +using Elsa.Models; +using GraphQL.Types; + +namespace Elsa.Server.GraphQL.Types +{ + public class WorkflowDefinitionVersionType : ObjectGraphType + { + public WorkflowDefinitionVersionType() + { + Name = "WorkflowDefinitionVersion"; + + Field(x => x.Id).Description("The version ID of the workflow."); + Field(x => x.DefinitionId).Description("The ID of the workflow"); + Field(x => x.Version).Description("The version of the workflow."); + Field(x => x.Name).Description("The name of the workflow."); + Field(x => x.Description).Description("The description of the workflow."); + Field(x => x.IsDisabled).Description("Whether the workflow is enabled or not."); + Field(x => x.IsLatest).Description("Whether this is the latest version of the workflow."); + Field(x => x.IsPublished).Description("Whether the workflow is published or not."); + Field(x => x.IsSingleton).Description("Whether the workflow acts as a singleton or not. When true, only one instance can execute at any given time."); + Field(x => x.Activities, type: typeof(ListGraphType)).Description("A list of activities for the workflow."); + Field(x => x.Connections, type: typeof(ListGraphType)).Description("A list of connections between activities on the workflow."); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.GraphQL/icon.png b/src/server/Elsa.Server.GraphQL/icon.png new file mode 100644 index 000000000..f978a2882 Binary files /dev/null and b/src/server/Elsa.Server.GraphQL/icon.png differ diff --git a/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj b/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj new file mode 100644 index 000000000..176307b9a --- /dev/null +++ b/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + + diff --git a/src/server/Elsa.Server.Host/Program.cs b/src/server/Elsa.Server.Host/Program.cs new file mode 100644 index 000000000..7a04040bb --- /dev/null +++ b/src/server/Elsa.Server.Host/Program.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Server.Host +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.Host/Properties/launchSettings.json b/src/server/Elsa.Server.Host/Properties/launchSettings.json new file mode 100644 index 000000000..18ba17362 --- /dev/null +++ b/src/server/Elsa.Server.Host/Properties/launchSettings.json @@ -0,0 +1,26 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:16398" + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Elsa.Server.Host": { + "commandName": "Project", + "launchBrowser": false, + "applicationUrl": "http://localhost:16398", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/server/Elsa.Server.Host/Startup.cs b/src/server/Elsa.Server.Host/Startup.cs new file mode 100644 index 000000000..8f645dbca --- /dev/null +++ b/src/server/Elsa.Server.Host/Startup.cs @@ -0,0 +1,68 @@ +using GraphQL.Server.Ui.GraphiQL; +using GraphQL.Server.Ui.Playground; +using GraphQL.Server.Ui.Voyager; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Server.Host +{ + public class Startup + { + public Startup(IWebHostEnvironment environment, IConfiguration configuration) + { + Environment = environment; + Configuration = configuration; + } + + public IWebHostEnvironment Environment { get; } + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + var elsaSection = Configuration.GetSection("Elsa"); + + services + .AddElsa(elsa => elsa + .AddMongoDbStores(Configuration, "ElsaServer", "MongoDb") + .AddGraphQL(options => Configuration.GetSection("GraphQL").Bind(options))) + + .AddHttpActivities(options => options.Bind(elsaSection.GetSection("Http"))) + .AddEmailActivities(options => options.Bind(elsaSection.GetSection("Smtp"))) + .AddTimerActivities(options => options.Bind(elsaSection.GetSection("BackgroundRunner"))) + .AddElsaManagement(); + + EnableSynchronousIO(services); + } + + public void Configure(IApplicationBuilder app) + { + if (Environment.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpActivities(); + app.UseElsaGraphQL(); + app.UseGraphQLPlayground(new GraphQLPlaygroundOptions()); + app.UseGraphiQLServer(new GraphiQLOptions()); + app.UseGraphQLVoyager(new GraphQLVoyagerOptions()); + } + + private void EnableSynchronousIO(IServiceCollection services) + { + // Workaround until GraphQL can swap off Newtonsoft.Json and onto the new MS one. + // Depending on whether you're using IIS or Kestrel, the code required is different. + // See: https://github.com/graphql-dotnet/graphql-dotnet/issues/1116 + + // kestrel + services.Configure(options => { options.AllowSynchronousIO = true; }); + + // IIS + services.Configure(options => { options.AllowSynchronousIO = true; }); + } + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.Host/appsettings.Development.json b/src/server/Elsa.Server.Host/appsettings.Development.json new file mode 100644 index 000000000..e203e9407 --- /dev/null +++ b/src/server/Elsa.Server.Host/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/src/server/Elsa.Server.Host/appsettings.json b/src/server/Elsa.Server.Host/appsettings.json new file mode 100644 index 000000000..732036b5a --- /dev/null +++ b/src/server/Elsa.Server.Host/appsettings.json @@ -0,0 +1,17 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "MongoDb": "mongodb://localhost" + }, + "GraphQL": { + "ExposeExceptions": true, + "SetFieldMiddleware": false + } +}