From 06adc1d0d1f31472d125625e8ff11cbbb291da73 Mon Sep 17 00:00:00 2001 From: colin Date: Fri, 11 Sep 2026 15:16:52 +0800 Subject: [PATCH] feat: Add Webhooks Activities Module --- ...UN.Abp.MicroService.WorkflowService.csproj | 3 + .../WorkflowServiceModule.Configure.cs | 10 ++ .../WorkflowServiceModule.cs | 7 + .../AbpElsaNextStudioWebhooksBlazorModule.cs | 17 ++ .../Components/WebhookPicker.razor | 130 +++++++++++++++ .../Components/WebhookSelectDialog.razor | 156 ++++++++++++++++++ .../Extensions/ServiceCollectionExtensions.cs | 13 ++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++++ .../Handlers/WebhookPickerHandler.cs | 25 +++ ...Abp.ElsaNext.Studio.Webhooks.Blazor.csproj | 20 +++ .../_Imports.razor | 5 + .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++++ .../LINGYUN.Abp.ElsaNext.Webhooks.csproj | 26 +++ .../Webhooks/AbpElsaNextWebhooksModule.cs | 38 +++++ .../Webhooks/Activities/PublishWebhook.cs | 60 +++++++ .../Webhooks/Extensions/ModuleExtensions.cs | 14 ++ .../Webhooks/Features/WebhooksFeature.cs | 17 ++ .../Webhooks/Localization/Resources/en.json | 12 ++ .../Localization/Resources/zh-Hans.json | 12 ++ .../Webhooks/UIHints/WebhooksUIHints.cs | 6 + 22 files changed, 637 insertions(+) create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/AbpElsaNextStudioWebhooksBlazorModule.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookPicker.razor create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookSelectDialog.razor create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Extensions/ServiceCollectionExtensions.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xml create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xsd create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Handlers/WebhookPickerHandler.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.csproj create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/_Imports.razor create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xml create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xsd create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN.Abp.ElsaNext.Webhooks.csproj create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/AbpElsaNextWebhooksModule.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Activities/PublishWebhook.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Extensions/ModuleExtensions.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Features/WebhooksFeature.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/en.json create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/zh-Hans.json create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/UIHints/WebhooksUIHints.cs diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/LINGYUN.Abp.MicroService.WorkflowService.csproj b/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/LINGYUN.Abp.MicroService.WorkflowService.csproj index cf1c97bab..24fea9115 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/LINGYUN.Abp.MicroService.WorkflowService.csproj +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/LINGYUN.Abp.MicroService.WorkflowService.csproj @@ -82,6 +82,7 @@ --> + @@ -98,6 +99,8 @@ + + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.Configure.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.Configure.cs index d2cd66737..8fae4cdf1 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.Configure.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.Configure.cs @@ -17,6 +17,7 @@ using LINGYUN.Abp.MicroService.WorkflowService.Extensions; using LINGYUN.Abp.MicroService.WorkflowService.Navigation; using LINGYUN.Abp.Notifications; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Abp.WebhooksManagement; using Localization.Resources.AbpUi; using Medallion.Threading; using Medallion.Threading.Redis; @@ -352,6 +353,15 @@ public partial class WorkflowServiceModule }); } + private void ConfigureWebhooksManagement() + { + Configure(options => + { + options.IsDynamicWebhookStoreEnabled = true; + options.SaveStaticWebhooksToDatabase = false; + }); + } + private void ConfigureMultiTenancy(IConfiguration configuration) { // 多租户 diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.cs index 708f3824e..1faded37d 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.cs @@ -19,6 +19,8 @@ using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor; using LINGYUN.Abp.ElsaNext.Studio.Identity.Blazor; using LINGYUN.Abp.ElsaNext.Studio.Notifications.Blazor; using LINGYUN.Abp.ElsaNext.Studio.Saas.Blazor; +using LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor; +using LINGYUN.Abp.ElsaNext.Webhooks; using LINGYUN.Abp.Emailing.Platform; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; @@ -31,6 +33,7 @@ using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LINGYUN.Abp.Sms.Platform; +using LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; @@ -63,6 +66,7 @@ namespace LINGYUN.Abp.MicroService.WorkflowService; typeof(AbpElsaNextBlobStoringModule), typeof(AbpElsaNextEmailModule), typeof(AbpElsaNextNotificationsModule), + typeof(AbpElsaNextWebhooksModule), typeof(AbpElsaNextServerModule), typeof(AbpElsaNextStudioBlazorModule), typeof(AbpElsaNextAgentsBlazorModule), @@ -73,6 +77,7 @@ namespace LINGYUN.Abp.MicroService.WorkflowService; typeof(AbpElsaNextStudioIdentityBlazorModule), typeof(AbpElsaNextStudioNotificationsBlazorModule), typeof(AbpElsaNextStudioSaasBlazorModule), + typeof(AbpElsaNextStudioWebhooksBlazorModule), typeof(AbpEmailingExceptionHandlingModule), typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpAspNetCoreMultiTenancyModule), @@ -87,6 +92,7 @@ namespace LINGYUN.Abp.MicroService.WorkflowService; typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpLocalizationManagementEntityFrameworkCoreModule), typeof(AbpNotificationsEntityFrameworkCoreModule), + typeof(WebhooksManagementEntityFrameworkCoreModule), typeof(AbpAuthorizationOrganizationUnitsModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule), @@ -135,6 +141,7 @@ public partial class WorkflowServiceModule : AbpModule ConfigureVirtualFileSystem(); ConfigureNotificationsManagement(); ConfigurePermissionManagement(); + ConfigureWebhooksManagement(); ConfigureTiming(configuration); ConfigureCaching(configuration); ConfigureAuditing(configuration); diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/AbpElsaNextStudioWebhooksBlazorModule.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/AbpElsaNextStudioWebhooksBlazorModule.cs new file mode 100644 index 000000000..afff5a6ef --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/AbpElsaNextStudioWebhooksBlazorModule.cs @@ -0,0 +1,17 @@ +using LINGYUN.Abp.ElsaNext.Studio.Blazor; +using LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.Extensions; +using LINGYUN.Abp.ElsaNext.Webhooks; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor; + +[DependsOn( + typeof(AbpElsaNextWebhooksModule), + typeof(AbpElsaNextStudioBlazorModule))] +public class AbpElsaNextStudioWebhooksBlazorModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddWebhooksUIHintHandlers(); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookPicker.razor b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookPicker.razor new file mode 100644 index 000000000..66f5f0b5b --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookPicker.razor @@ -0,0 +1,130 @@ +@using Elsa.Api.Client.Shared.UIHints.DropDown +@using Elsa.Studio.Models +@using LINGYUN.Abp.ElsaNext.Studio.Blazor.Components +@using LINGYUN.Abp.Webhooks +@using Microsoft.Extensions.Localization +@inject ILocalizer Localizer + +@inherits StudioComponentBase +@{ + var inputDescriptor = EditorContext.InputDescriptor; + var displayName = inputDescriptor.DisplayName; + var description = inputDescriptor.Description; +} + + + + + + + +@code { + private SelectListItem? _selectedItem; + + [Parameter] public DisplayInputEditorContext EditorContext { get; set; } = null!; + + [Inject] protected IDialogService DialogService { get; set; } = null!; + [Inject] private IStringLocalizerFactory StringLocalizerFactory { get; set; } = null!; + [Inject] private IWebhookDefinitionManager WebhookDefinitionManager { get; set; } = null!; + + protected async override Task OnInitializedAsync() + { + var selectedItem = await ResolveSelectedItemAsync(); + + if (selectedItem != null) + { + await InvokeAsync(() => _selectedItem = selectedItem); + } + } + + private async Task ResolveSelectedItemAsync() + { + var value = EditorContext.GetLiteralValueOrDefault(); + + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + var webhookDefine = await WebhookDefinitionManager.GetOrNullAsync(value); + if (webhookDefine != null) + { + return new SelectListItem( + webhookDefine.DisplayName != null + ? webhookDefine.DisplayName.Localize(StringLocalizerFactory) + : webhookDefine.Name, + webhookDefine.Name); + } + + return new SelectListItem(value, value); + } + + private async Task OpenSelectDialogAsync() + { + if (EditorContext.IsReadOnly) + { + return; + } + + var inputDescriptor = EditorContext.InputDescriptor; + var parameters = new DialogParameters + { + { x => x.Title, Localizer[inputDescriptor.DisplayName ?? inputDescriptor.Name] }, + { x => x.SelectedValue, _selectedItem?.Value } + }; + var options = new DialogOptions + { + CloseOnEscapeKey = true, + FullWidth = true, + MaxWidth = MaxWidth.Medium + }; + + var dialog = await DialogService.ShowAsync(string.Empty, parameters, options); + var result = await dialog.Result; + + if (result is { Canceled: false, Data: SelectListItem item }) + { + await InvokeAsync(async () => + { + _selectedItem = item; + await EditorContext.UpdateValueOrLiteralExpressionAsync(item.Value); + }); + } + } + + private MudTextFieldExIcon[] GetAdornmentIcons() => + [ + new() + { + Icon = Icons.Material.Filled.Search, + Tooltip = Localizer["Search"], + Disabled = EditorContext.IsReadOnly, + OnClick = OpenSelectDialogAsync + }, + new() + { + Icon = Icons.Material.Filled.Clear, + Tooltip = Localizer["Clear"], + Visible = _selectedItem != null, + Disabled = EditorContext.IsReadOnly, + OnClick = ClearAsync + } + ]; + + private async Task ClearAsync() + { + await InvokeAsync(async () => + { + _selectedItem = null; + await EditorContext.UpdateValueOrLiteralExpressionAsync(string.Empty); + }); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookSelectDialog.razor b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookSelectDialog.razor new file mode 100644 index 000000000..7d3770a97 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Components/WebhookSelectDialog.razor @@ -0,0 +1,156 @@ +@using System.Threading +@using Elsa.Api.Client.Shared.UIHints.DropDown +@using LINGYUN.Abp.Webhooks +@using Microsoft.Extensions.Localization +@inject ILocalizer Localizer + +@implements IDisposable + + + + @Title + + + + + + + + @Localizer["Name"] + + + + @context.Text + + @if (context.Value == SelectedValue) + { + + } + else + { + + @Localizer["Select"] + + } + + + + + + + @Localizer["No results found"] + + + + + + @Localizer["Cancel"] + + + +@code { + private const int DebounceIntervalMilliseconds = 350; + + private MudTable? _table; + private string? _searchText; + private CancellationTokenSource? _debounceCancellationTokenSource; + + [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; + + [Parameter] public string Title { get; set; } = string.Empty; + + [Parameter] public string? SelectedValue { get; set; } + + [Inject] private IStringLocalizerFactory StringLocalizerFactory { get; set; } = null!; + [Inject] private IWebhookDefinitionManager WebhookDefinitionManager { get; set; } = null!; + + public void Dispose() + { + _debounceCancellationTokenSource?.Cancel(); + _debounceCancellationTokenSource?.Dispose(); + } + + private async Task OnSearchTextChangedAsync(string? searchValue) + { + _searchText = searchValue; + + _debounceCancellationTokenSource?.Cancel(); + _debounceCancellationTokenSource?.Dispose(); + _debounceCancellationTokenSource = new CancellationTokenSource(); + + try + { + await Task.Delay(DebounceIntervalMilliseconds, _debounceCancellationTokenSource.Token); + + var table = _table; + + if (table != null) + { + await InvokeAsync(() => table.ReloadServerData()); + } + } + catch (OperationCanceledException) + { + } + } + + private async Task> LoadTenantsAsync(TableState state, CancellationToken cancellationToken) + { + var filter = string.IsNullOrWhiteSpace(_searchText) ? null : _searchText.Trim(); + + var webhooks = await WebhookDefinitionManager.GetWebhooksAsync(); + + var items = webhooks + .Select(webhook => new SelectListItem( + webhook.DisplayName != null + ? webhook.DisplayName.Localize(StringLocalizerFactory) + : webhook.Name, + webhook.Name)) + .WhereIf(!string.IsNullOrWhiteSpace(filter), x => x.Text.Contains(filter!) || x.Value.Contains(filter!)) + .OrderBy(x => x.Text) + .Skip(state.Page * state.PageSize) + .Take(state.PageSize) + .ToList(); + + return new TableData + { + Items = items, + TotalItems = webhooks.Count, + }; + } + + private async Task OnRowClickAsync(TableRowClickEventArgs args) + { + await SelectAsync(args.Item); + } + + private Task SelectAsync(SelectListItem? item) + { + if (item == null) + { + return Task.CompletedTask; + } + + MudDialog.Close(DialogResult.Ok(item)); + return Task.CompletedTask; + } + + private void CancelAsync() + { + MudDialog.Cancel(); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Extensions/ServiceCollectionExtensions.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..69b9a5395 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,13 @@ +using Elsa.Studio.Extensions; +using LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.Handlers; +using Microsoft.Extensions.DependencyInjection; + +namespace LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.Extensions; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddWebhooksUIHintHandlers(this IServiceCollection services) + { + return services.AddUIHintHandler(); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xml b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xml new file mode 100644 index 000000000..5d6962159 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xsd b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Handlers/WebhookPickerHandler.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Handlers/WebhookPickerHandler.cs new file mode 100644 index 000000000..b48cb92ef --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/Handlers/WebhookPickerHandler.cs @@ -0,0 +1,25 @@ +using Elsa.Studio; +using Elsa.Studio.Contracts; +using Elsa.Studio.Models; +using LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.Components; +using LINGYUN.Abp.ElsaNext.Webhooks.UIHints; +using Microsoft.AspNetCore.Components; + +namespace LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.Handlers; + +public class WebhookPickerHandler : IUIHintHandler +{ + public bool GetSupportsUIHint(string uiHint) => uiHint is WebhooksUIHints.WebhookPicker; + + public string UISyntax => WellKnownSyntaxNames.Object; + + public RenderFragment DisplayInputEditor(DisplayInputEditorContext context) + { + return builder => + { + builder.OpenComponent(0, typeof(WebhookPicker)); + builder.AddAttribute(1, nameof(WebhookPicker.EditorContext), context); + builder.CloseComponent(); + }; + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.csproj b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.csproj new file mode 100644 index 000000000..8ae04f812 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor.csproj @@ -0,0 +1,20 @@ + + + + + + + net10.0 + LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor + LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor + false + false + false + + + + + + + + diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/_Imports.razor b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/_Imports.razor new file mode 100644 index 000000000..1f6d130e9 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Webhooks.Blazor/_Imports.razor @@ -0,0 +1,5 @@ +@using Microsoft.AspNetCore.Components.Web +@using Elsa.Studio.Components +@using Elsa.Studio.Localization +@using MudBlazor +@using MudExtensions \ No newline at end of file diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xml b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xml new file mode 100644 index 000000000..5d6962159 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xsd b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN.Abp.ElsaNext.Webhooks.csproj b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN.Abp.ElsaNext.Webhooks.csproj new file mode 100644 index 000000000..5b370bf52 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN.Abp.ElsaNext.Webhooks.csproj @@ -0,0 +1,26 @@ + + + + + + + net10.0 + LINGYUN.Abp.ElsaNext.Webhooks + LINGYUN.Abp.ElsaNext.Webhooks + false + false + false + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/AbpElsaNextWebhooksModule.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/AbpElsaNextWebhooksModule.cs new file mode 100644 index 000000000..2ee5a3bf0 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/AbpElsaNextWebhooksModule.cs @@ -0,0 +1,38 @@ +using Elsa.Features.Services; +using LINGYUN.Abp.ElsaNext.Localization; +using LINGYUN.Abp.ElsaNext.Webhooks.Extensions; +using LINGYUN.Abp.Webhooks; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.ElsaNext.Webhooks; + +[DependsOn( + typeof(AbpWebhooksModule), + typeof(AbpElsaNextModule))] +public class AbpElsaNextWebhooksModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(elsa => + { + elsa.UseAbpWebhooks(); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources"); + }); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Activities/PublishWebhook.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Activities/PublishWebhook.cs new file mode 100644 index 000000000..42671e57f --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Activities/PublishWebhook.cs @@ -0,0 +1,60 @@ +using Elsa.Extensions; +using Elsa.Workflows; +using Elsa.Workflows.Attributes; +using Elsa.Workflows.Models; +using Elsa.Workflows.UIHints; +using LINGYUN.Abp.ElsaNext.Webhooks.UIHints; +using LINGYUN.Abp.Webhooks; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.ElsaNext.Webhooks.Activities; + +[Activity("Elsa", "Webhooks", "Send webhooks to subscriptions.", Kind = ActivityKind.Task)] +public class PublishWebhook : CodeActivity +{ + [Input( + Description = "Unique name of the webhook.", + UIHint = WebhooksUIHints.WebhookPicker)] + public Input WebhookName { get; set; } = default!; + + [Input(Description = "Data to send.")] + public Input WebhookData { get; set; } = default!; + + [Input(Description = "If true, It sends the exact same data as the parameter to clients.")] + public Input SendExactSameData { get; set; } = default!; + + [Input(Description = "If true, webhook will only contain given headers. If false given headers will be added to predefined headers in subscription.")] + public Input UseOnlyGivenHeaders { get; set; } = default!; + + [Input( + Description = "That headers will be sent with the webhook.", + UIHint = InputUIHints.Dictionary)] + public Input> Headers { get; set; } = default!; + + protected async override ValueTask ExecuteAsync(ActivityExecutionContext context) + { + var webhookPublisher = context.GetRequiredService(); + + var webhookName = WebhookName.Get(context); + var webhookData = WebhookData.Get(context); + var sendExactSameData = SendExactSameData.GetOrDefault(context) ?? true; + WebhookHeader? webhookHeader = null; + var headers = Headers.GetOrDefault(context); + if (headers != null) + { + var useOnlyGivenHeaders = UseOnlyGivenHeaders.GetOrDefault(context) ?? false; + webhookHeader = new WebhookHeader + { + UseOnlyGivenHeaders = useOnlyGivenHeaders, + Headers = headers, + }; + } + + await webhookPublisher.PublishAsync( + webhookName, + webhookData, + sendExactSameData, + webhookHeader); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Extensions/ModuleExtensions.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Extensions/ModuleExtensions.cs new file mode 100644 index 000000000..c8b0eb992 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Extensions/ModuleExtensions.cs @@ -0,0 +1,14 @@ +using Elsa.Features.Services; +using LINGYUN.Abp.ElsaNext.Webhooks.Features; +using System; + +namespace LINGYUN.Abp.ElsaNext.Webhooks.Extensions; + +public static class ModuleExtensions +{ + public static IModule UseAbpWebhooks(this IModule configuration, Action? configure = null) + { + configuration.Configure(configure); + return configuration; + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Features/WebhooksFeature.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Features/WebhooksFeature.cs new file mode 100644 index 000000000..b5fc3a94e --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Features/WebhooksFeature.cs @@ -0,0 +1,17 @@ +using Elsa.Extensions; +using Elsa.Features.Abstractions; +using Elsa.Features.Services; + +namespace LINGYUN.Abp.ElsaNext.Webhooks.Features; + +public class WebhooksFeature : FeatureBase +{ + public WebhooksFeature(IModule module) : base(module) + { + } + + public override void Configure() + { + Module.AddActivitiesFrom(); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/en.json b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/en.json new file mode 100644 index 000000000..cdcb12d4e --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/en.json @@ -0,0 +1,12 @@ +{ + "culture": "en", + "texts": { + "Webhooks": "Webhooks", + "Publish Webhook": "Publish Webhook", + "Send webhooks to subscriptions.": "Send webhooks to subscriptions.", + "Data to send.": "Data to send.", + "If true, It sends the exact same data as the parameter to clients.": "If true, It sends the exact same data as the parameter to clients.", + "If true, webhook will only contain given headers. If false given headers will be added to predefined headers in subscription.": "If true, webhook will only contain given headers. If false given headers will be added to predefined headers in subscription.", + "That headers will be sent with the webhook.": "That headers will be sent with the webhook." + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/zh-Hans.json b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..f22eb4e92 --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/Localization/Resources/zh-Hans.json @@ -0,0 +1,12 @@ +{ + "culture": "zh-Hans", + "texts": { + "Webhooks": "Webhooks", + "Publish Webhook": "发布Webhook", + "Send webhooks to subscriptions.": "向订阅方发布Webhook。", + "Data to send.": "要发送的数据。", + "If true, It sends the exact same data as the parameter to clients.": "如果为True,它会向客户端发送与参数完全相同的数据。", + "If true, webhook will only contain given headers. If false given headers will be added to predefined headers in subscription.": "如果为True,webhook 将仅包含指定的标头。如果为False,则在订阅中预定义的标头将添加给定的标头。", + "That headers will be sent with the webhook.": "将随 webhook 一起发送的请求头。" + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/UIHints/WebhooksUIHints.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/UIHints/WebhooksUIHints.cs new file mode 100644 index 000000000..ad30cb94e --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Webhooks/LINGYUN/Abp/ElsaNext/Webhooks/UIHints/WebhooksUIHints.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.ElsaNext.Webhooks.UIHints; + +public static class WebhooksUIHints +{ + public const string WebhookPicker = "webhook-picker"; +}