diff --git a/Directory.Packages.props b/Directory.Packages.props index 0ae482e5..6858226c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -41,6 +41,7 @@ + diff --git a/src/modules/Directory.Build.props b/src/modules/Directory.Build.props index bd564a59..de79e646 100644 --- a/src/modules/Directory.Build.props +++ b/src/modules/Directory.Build.props @@ -17,4 +17,8 @@ - \ No newline at end of file + + + + + diff --git a/src/modules/scheduling/Elsa.Scheduling.Hangfire/ShellFeatures/HangfireShellFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Hangfire/ShellFeatures/HangfireShellFeature.cs index 31a02b28..393fce86 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Hangfire/ShellFeatures/HangfireShellFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Hangfire/ShellFeatures/HangfireShellFeature.cs @@ -1,4 +1,5 @@ using CShells.Features; +using Elsa.PackageManifest.Generator.Hints; using Hangfire; using Hangfire.MemoryStorage; using JetBrains.Annotations; @@ -16,8 +17,25 @@ namespace Elsa.Scheduling.Hangfire.ShellFeatures; [UsedImplicitly] public class HangfireShellFeature : IShellFeature { + [ManifestSetting( + DisplayName = "Use memory storage", + Description = "Use Hangfire's in-memory storage provider.", + Category = "Storage", + RestartRequired = true)] public bool UseMemoryStorage { get; set; } = true; + + [ManifestSetting( + DisplayName = "Worker count", + Description = "The number of Hangfire worker threads to run.", + Category = "Workers", + RestartRequired = true)] public int WorkerCount { get; set; } = 1; + + [ManifestSetting( + DisplayName = "Schedule polling interval", + Description = "The Hangfire schedule polling interval in seconds.", + Category = "Scheduling", + RestartRequired = true)] public int SchedulePollingIntervalSeconds { get; set; } = 1; public void ConfigureServices(IServiceCollection services) @@ -38,4 +56,3 @@ public void ConfigureServices(IServiceCollection services) }); } } - diff --git a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.MySql/ShellFeatures/QuartzMySqlFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.MySql/ShellFeatures/QuartzMySqlFeature.cs index 735f0793..2ccfb39f 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.MySql/ShellFeatures/QuartzMySqlFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.MySql/ShellFeatures/QuartzMySqlFeature.cs @@ -1,5 +1,6 @@ using CShells.Features; using CShells.Lifecycle; +using Elsa.PackageManifest.Generator.Hints; using Elsa.Scheduling.Quartz.EFCore.MySql; using Elsa.Scheduling.Quartz.ShellFeatures; using JetBrains.Annotations; @@ -17,15 +18,35 @@ namespace Elsa.Scheduling.Quartz.EFCore.MySql.ShellFeatures; Description = "Configures Quartz.NET to persist jobs and triggers in MySQL", DependsOn = [typeof(QuartzSchedulerFeature)])] [UsedImplicitly] +[ManifestInfrastructure("mysql-database", "database", Reason = "Stores Quartz scheduler data in MySQL.", Providers = new[] { "MySQL" }, ConfigurationKeys = new[] { "ConnectionString" })] public class QuartzMySqlFeature : IShellFeature { /// The MySQL connection string. + [ManifestSetting( + DisplayName = "Connection string", + Description = "The MySQL connection string used by the Quartz persistent job store.", + Category = "Persistence", + Secret = true, + Required = true, + HasRequired = true, + RestartRequired = true)] public string ConnectionString { get; set; } = "Server=localhost;Database=quartz;User=root;Password=root;"; /// Enable Quartz clustering. Defaults to true. + [ManifestSetting( + DisplayName = "Use clustering", + Description = "Enable Quartz clustering.", + Category = "Persistence", + RestartRequired = true)] public bool UseClustering { get; set; } = true; /// Use a pooled IDbContextFactory. Defaults to false. + [ManifestSetting( + DisplayName = "Use context pooling", + Description = "Use a pooled EF Core IDbContextFactory.", + Category = "Persistence", + Advanced = true, + RestartRequired = true)] public bool UseContextPooling { get; set; } public void ConfigureServices(IServiceCollection services) diff --git a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.PostgreSql/ShellFeatures/QuartzPostgreSqlFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.PostgreSql/ShellFeatures/QuartzPostgreSqlFeature.cs index 8a4f9a91..b43ff39a 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.PostgreSql/ShellFeatures/QuartzPostgreSqlFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.PostgreSql/ShellFeatures/QuartzPostgreSqlFeature.cs @@ -1,5 +1,6 @@ using CShells.Features; using CShells.Lifecycle; +using Elsa.PackageManifest.Generator.Hints; using Elsa.Scheduling.Quartz.EFCore.PostgreSql; using Elsa.Scheduling.Quartz.ShellFeatures; using JetBrains.Annotations; @@ -17,15 +18,35 @@ namespace Elsa.Scheduling.Quartz.EFCore.PostgreSql.ShellFeatures; Description = "Configures Quartz.NET to persist jobs and triggers in PostgreSQL", DependsOn = [typeof(QuartzSchedulerFeature)])] [UsedImplicitly] +[ManifestInfrastructure("postgresql-database", "database", Reason = "Stores Quartz scheduler data in PostgreSQL.", Providers = new[] { "PostgreSQL" }, ConfigurationKeys = new[] { "ConnectionString" })] public class QuartzPostgreSqlFeature : IShellFeature { /// The PostgreSQL connection string. + [ManifestSetting( + DisplayName = "Connection string", + Description = "The PostgreSQL connection string used by the Quartz persistent job store.", + Category = "Persistence", + Secret = true, + Required = true, + HasRequired = true, + RestartRequired = true)] public string ConnectionString { get; set; } = "Host=localhost;Database=quartz;Username=postgres;Password=postgres"; /// Enable Quartz clustering. Defaults to true. + [ManifestSetting( + DisplayName = "Use clustering", + Description = "Enable Quartz clustering.", + Category = "Persistence", + RestartRequired = true)] public bool UseClustering { get; set; } = true; /// Use a pooled IDbContextFactory. Defaults to false. + [ManifestSetting( + DisplayName = "Use context pooling", + Description = "Use a pooled EF Core IDbContextFactory.", + Category = "Persistence", + Advanced = true, + RestartRequired = true)] public bool UseContextPooling { get; set; } public void ConfigureServices(IServiceCollection services) diff --git a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.SqlServer/ShellFeatures/QuartzSqlServerFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.SqlServer/ShellFeatures/QuartzSqlServerFeature.cs index 76da2398..a4e8bf1e 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.SqlServer/ShellFeatures/QuartzSqlServerFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.SqlServer/ShellFeatures/QuartzSqlServerFeature.cs @@ -1,5 +1,6 @@ using CShells.Features; using CShells.Lifecycle; +using Elsa.PackageManifest.Generator.Hints; using Elsa.Scheduling.Quartz.EFCore.SqlServer; using Elsa.Scheduling.Quartz.ShellFeatures; using JetBrains.Annotations; @@ -17,15 +18,35 @@ namespace Elsa.Scheduling.Quartz.EFCore.SqlServer.ShellFeatures; Description = "Configures Quartz.NET to persist jobs and triggers in SQL Server", DependsOn = [typeof(QuartzSchedulerFeature)])] [UsedImplicitly] +[ManifestInfrastructure("sqlserver-database", "database", Reason = "Stores Quartz scheduler data in SQL Server.", Providers = new[] { "SQL Server" }, ConfigurationKeys = new[] { "ConnectionString" })] public class QuartzSqlServerFeature : IShellFeature { /// The SQL Server connection string. + [ManifestSetting( + DisplayName = "Connection string", + Description = "The SQL Server connection string used by the Quartz persistent job store.", + Category = "Persistence", + Secret = true, + Required = true, + HasRequired = true, + RestartRequired = true)] public string ConnectionString { get; set; } = "Server=localhost;Database=Quartz;Trusted_Connection=True;"; /// Enable Quartz clustering. Defaults to true. + [ManifestSetting( + DisplayName = "Use clustering", + Description = "Enable Quartz clustering.", + Category = "Persistence", + RestartRequired = true)] public bool UseClustering { get; set; } = true; /// Use a pooled IDbContextFactory. Defaults to false. + [ManifestSetting( + DisplayName = "Use context pooling", + Description = "Use a pooled EF Core IDbContextFactory.", + Category = "Persistence", + Advanced = true, + RestartRequired = true)] public bool UseContextPooling { get; set; } public void ConfigureServices(IServiceCollection services) diff --git a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.Sqlite/ShellFeatures/QuartzSqliteFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.Sqlite/ShellFeatures/QuartzSqliteFeature.cs index 4d849581..0597a164 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.Sqlite/ShellFeatures/QuartzSqliteFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Quartz.EFCore.Sqlite/ShellFeatures/QuartzSqliteFeature.cs @@ -1,5 +1,6 @@ using CShells.Features; using CShells.Lifecycle; +using Elsa.PackageManifest.Generator.Hints; using Elsa.Scheduling.Quartz.EFCore.Sqlite; using Elsa.Scheduling.Quartz.ShellFeatures; using JetBrains.Annotations; @@ -17,18 +18,39 @@ namespace Elsa.Scheduling.Quartz.EFCore.Sqlite.ShellFeatures; Description = "Configures Quartz.NET to persist jobs and triggers in SQLite", DependsOn = [typeof(QuartzSchedulerFeature)])] [UsedImplicitly] +[ManifestInfrastructure("sqlite-database", "database", Reason = "Stores Quartz scheduler data in SQLite.", Providers = new[] { "SQLite" }, ConfigurationKeys = new[] { "ConnectionString" })] public class QuartzSqliteFeature : IShellFeature, IPostConfigureShellServices { /// The SQLite connection string. + [ManifestSetting( + DisplayName = "Connection string", + Description = "The SQLite connection string used by the Quartz persistent job store.", + Category = "Persistence", + Secret = true, + Required = true, + HasRequired = true, + RestartRequired = true)] public string ConnectionString { get; set; } = "Data Source=quartz.db"; /// /// Enable Quartz clustering. Defaults to false — SQLite does not /// support true multi-node clustering. /// + [ManifestSetting( + DisplayName = "Use clustering", + Description = "Enable Quartz clustering. SQLite does not support true multi-node clustering.", + Category = "Persistence", + Advanced = true, + RestartRequired = true)] public bool UseClustering { get; set; } /// Use a pooled IDbContextFactory. Defaults to false. + [ManifestSetting( + DisplayName = "Use context pooling", + Description = "Use a pooled EF Core IDbContextFactory.", + Category = "Persistence", + Advanced = true, + RestartRequired = true)] public bool UseContextPooling { get; set; } public void ConfigureServices(IServiceCollection services) diff --git a/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzFeature.cs index acd6bd39..58af3e7f 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzFeature.cs @@ -1,5 +1,6 @@ using CShells.Features; using CShells.Lifecycle; +using Elsa.PackageManifest.Generator.Hints; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; using Quartz; @@ -18,21 +19,42 @@ public class QuartzFeature : IShellFeature, IPostConfigureShellServices /// /// Optional delay before the scheduler begins processing jobs after shell activation. /// + [ManifestSetting( + DisplayName = "Start delay", + Description = "Optional delay before the scheduler begins processing jobs after shell activation.", + Category = "Scheduler", + Advanced = true, + RestartRequired = true)] public TimeSpan? StartDelay { get; set; } /// /// Whether to wait for running jobs to complete before the scheduler shuts down on /// shell deactivation. Defaults to true. /// + [ManifestSetting( + DisplayName = "Wait for jobs to complete", + Description = "Wait for running jobs to complete before the scheduler shuts down on shell deactivation.", + Category = "Scheduler", + RestartRequired = true)] public bool WaitForJobsToComplete { get; set; } = true; /// /// The Quartz scheduler instance ID. Use "AUTO" (default) for automatic /// generation, which is required for clustering. /// + [ManifestSetting( + DisplayName = "Scheduler ID", + Description = "The Quartz scheduler instance ID. Use AUTO for automatic generation, which is required for clustering.", + Category = "Scheduler", + RestartRequired = true)] public string SchedulerId { get; set; } = "AUTO"; /// The Quartz scheduler name. Defaults to "ElsaScheduler". + [ManifestSetting( + DisplayName = "Scheduler name", + Description = "The Quartz scheduler name.", + Category = "Scheduler", + RestartRequired = true)] public string SchedulerName { get; set; } = "ElsaScheduler"; public void ConfigureServices(IServiceCollection services) diff --git a/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzSchedulerFeature.cs b/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzSchedulerFeature.cs index 243735ee..5a0c3751 100644 --- a/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzSchedulerFeature.cs +++ b/src/modules/scheduling/Elsa.Scheduling.Quartz/ShellFeatures/QuartzSchedulerFeature.cs @@ -16,7 +16,10 @@ namespace Elsa.Scheduling.Quartz.ShellFeatures; /// /// A feature that installs Quartz.NET implementations for . /// -[ShellFeature(DependsOn = [ +[ShellFeature( + DisplayName = "Quartz Workflow Scheduler", + Description = "Uses Quartz.NET to schedule workflow execution.", + DependsOn = [ typeof(QuartzFeature), typeof(SchedulingFeature), typeof(ResilienceFeature)])] @@ -34,4 +37,4 @@ public void ConfigureServices(IServiceCollection services) .AddSingleton() .AddQuartz(); } -} \ No newline at end of file +} diff --git a/src/modules/servicebus/Elsa.ServiceBus.AzureServiceBus/ShellFeatures/AzureServiceBusShellFeature.cs b/src/modules/servicebus/Elsa.ServiceBus.AzureServiceBus/ShellFeatures/AzureServiceBusShellFeature.cs index ed686070..84595dc2 100644 --- a/src/modules/servicebus/Elsa.ServiceBus.AzureServiceBus/ShellFeatures/AzureServiceBusShellFeature.cs +++ b/src/modules/servicebus/Elsa.ServiceBus.AzureServiceBus/ShellFeatures/AzureServiceBusShellFeature.cs @@ -1,4 +1,5 @@ using CShells.Features; +using Elsa.PackageManifest.Generator.Hints; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; @@ -11,8 +12,17 @@ namespace Elsa.ServiceBus.AzureServiceBus.ShellFeatures; DisplayName = "Azure Service Bus", Description = "Enables Azure Service Bus for message publishing and handling")] [UsedImplicitly] +[ManifestInfrastructure("azure-service-bus", "service-bus", Reason = "Publishes and consumes workflow messages through Azure Service Bus.", Providers = new[] { "Azure Service Bus" }, ConfigurationKeys = new[] { "ConnectionStringOrName" })] public class AzureServiceBusShellFeature : IShellFeature { + [ManifestSetting( + DisplayName = "Connection string or name", + Description = "The Azure Service Bus connection string or configured connection string name.", + Category = "Connection", + Secret = true, + Required = true, + HasRequired = true, + RestartRequired = true)] public string ConnectionStringOrName { get; set; } = string.Empty; public void ConfigureServices(IServiceCollection services) @@ -22,4 +32,3 @@ public void ConfigureServices(IServiceCollection services) .Configure(options => options.ConnectionStringOrName = ConnectionStringOrName); } } - diff --git a/src/modules/servicebus/Elsa.ServiceBus.Kafka/ShellFeatures/KafkaShellFeature.cs b/src/modules/servicebus/Elsa.ServiceBus.Kafka/ShellFeatures/KafkaShellFeature.cs index a289a4cb..ec65b5da 100644 --- a/src/modules/servicebus/Elsa.ServiceBus.Kafka/ShellFeatures/KafkaShellFeature.cs +++ b/src/modules/servicebus/Elsa.ServiceBus.Kafka/ShellFeatures/KafkaShellFeature.cs @@ -1,4 +1,5 @@ using CShells.Features; +using Elsa.PackageManifest.Generator.Hints; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; @@ -11,9 +12,15 @@ namespace Elsa.ServiceBus.Kafka.ShellFeatures; DisplayName = "Kafka Service Bus", Description = "Enables Apache Kafka for message publishing and handling")] [UsedImplicitly] +[ManifestInfrastructure("kafka-broker", "message-broker", Reason = "Publishes and consumes workflow messages through Apache Kafka.", Providers = new[] { "Apache Kafka" }, ConfigurationKeys = new[] { "WorkflowInstanceIdHeaderKey" })] public class KafkaShellFeature : IShellFeature { - public string WorkflowInstanceIdHeaderKey { get; set; } = "localhost:9092"; + [ManifestSetting( + DisplayName = "Workflow instance ID header key", + Description = "The Kafka message header key used to carry the workflow instance ID.", + Category = "Headers", + RestartRequired = true)] + public string WorkflowInstanceIdHeaderKey { get; set; } = "x-workflow-instance-id"; public void ConfigureServices(IServiceCollection services) { @@ -25,4 +32,3 @@ public void ConfigureServices(IServiceCollection services) }); } } - diff --git a/src/modules/servicebus/Elsa.ServiceBus.MassTransit.AzureServiceBus/ShellFeatures/MassTransitAzureServiceBusFeature.cs b/src/modules/servicebus/Elsa.ServiceBus.MassTransit.AzureServiceBus/ShellFeatures/MassTransitAzureServiceBusFeature.cs index 157b0af9..dec254bf 100644 --- a/src/modules/servicebus/Elsa.ServiceBus.MassTransit.AzureServiceBus/ShellFeatures/MassTransitAzureServiceBusFeature.cs +++ b/src/modules/servicebus/Elsa.ServiceBus.MassTransit.AzureServiceBus/ShellFeatures/MassTransitAzureServiceBusFeature.cs @@ -1,6 +1,7 @@ using Azure.Messaging.ServiceBus.Administration; using CShells.Configuration; using CShells.Features; +using Elsa.PackageManifest.Generator.Hints; using Elsa.ServiceBus.MassTransit.AzureServiceBus.Configurators; using Elsa.ServiceBus.MassTransit.AzureServiceBus.Handlers; using Elsa.ServiceBus.MassTransit.AzureServiceBus.HostedServices; @@ -30,12 +31,19 @@ namespace Elsa.ServiceBus.MassTransit.AzureServiceBus.ShellFeatures; Description = "Configures MassTransit to use Azure Service Bus as the message transport", DependsOn = [typeof(MassTransitFeature)])] [UsedImplicitly] +[ManifestInfrastructure("azure-service-bus", "service-bus", Reason = "Configures MassTransit to use Azure Service Bus as its transport.", Providers = new[] { "Azure Service Bus" }, ConfigurationKeys = new[] { "MassTransitAzureServiceBus:ConnectionStringOrName", "MassTransitAzureServiceBusCleanup" })] public class MassTransitAzureServiceBusFeature : IShellFeature { /// /// When true, registers a hosted service that periodically removes orphaned /// subscriptions whose connected queues no longer exist. /// + [ManifestSetting( + DisplayName = "Enable automated subscription cleanup", + Description = "Periodically removes orphaned Azure Service Bus subscriptions whose connected queues no longer exist.", + Category = "Cleanup", + Advanced = true, + RestartRequired = true)] public bool EnableAutomatedSubscriptionCleanup { get; set; } public void ConfigureServices(IServiceCollection services) @@ -71,4 +79,4 @@ public void ConfigureServices(IServiceCollection services) // Replace the default InMemoryTransportConfigurator. services.AddSingleton(); } -} \ No newline at end of file +} diff --git a/src/modules/servicebus/Elsa.ServiceBus.MassTransit.RabbitMq/ShellFeatures/MassTransitRabbitMqFeature.cs b/src/modules/servicebus/Elsa.ServiceBus.MassTransit.RabbitMq/ShellFeatures/MassTransitRabbitMqFeature.cs index badbdebf..30eab87d 100644 --- a/src/modules/servicebus/Elsa.ServiceBus.MassTransit.RabbitMq/ShellFeatures/MassTransitRabbitMqFeature.cs +++ b/src/modules/servicebus/Elsa.ServiceBus.MassTransit.RabbitMq/ShellFeatures/MassTransitRabbitMqFeature.cs @@ -1,5 +1,6 @@ using CShells.Configuration; using CShells.Features; +using Elsa.PackageManifest.Generator.Hints; using Elsa.ServiceBus.MassTransit.Contracts; using Elsa.ServiceBus.MassTransit.RabbitMq.Configurators; using Elsa.ServiceBus.MassTransit.RabbitMq.Options; @@ -25,6 +26,7 @@ namespace Elsa.ServiceBus.MassTransit.RabbitMq.ShellFeatures; Description = "Configures MassTransit to use RabbitMQ as the message transport", DependsOn = [typeof(MassTransitFeature)])] [UsedImplicitly] +[ManifestInfrastructure("rabbitmq-broker", "message-broker", Reason = "Configures MassTransit to use RabbitMQ as its transport.", Providers = new[] { "RabbitMQ" }, ConfigurationKeys = new[] { "MassTransitRabbitMq" })] public class MassTransitRabbitMqFeature : IShellFeature { public void ConfigureServices(IServiceCollection services)