Browse Source

feat: Integrate Elsa 3.0 module

pull/1568/head
colin 3 weeks ago
parent
commit
7e05b5340b
  1. 84
      Directory.Packages.props
  2. 15
      aspnet-core/LINGYUN.MicroService.Aspire.slnx
  3. 25
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.DbMigrator/appsettings.json
  4. 46
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/DataSeeds/OpenIddictDataSeeder.cs
  5. 64
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/App.razor
  6. 137
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/Index.razor
  7. 10
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/LoginRedirect.razor
  8. 13
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/Routes.razor
  9. 12
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/_Imports.razor
  10. 42
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/ElsaShellPermissionPolicyProvider.cs
  11. 130
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Extensions/ElsaStudioServiceCollectionExtensions.cs
  12. 47
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/LINGYUN.Abp.MicroService.WorkflowService.csproj
  13. 6
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Localization/Resources/en.json
  14. 6
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Localization/Resources/zh-Hans.json
  15. 22
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Navigation/UserMenuContributor.cs
  16. 6
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Login.cshtml
  17. 21
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Login.cshtml.cs
  18. 6
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Logout.cshtml
  19. 22
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Logout.cshtml.cs
  20. 42
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/_Host.cshtml
  21. 5
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/_ViewImports.cshtml
  22. 28
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Program.cs
  23. 214
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.Configure.cs
  24. 45
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.cs
  25. 103
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/appsettings.Development.json
  26. 8
      aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/package.json
  27. 49
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/AbpElsaNextAgentsBlazorModule.cs
  28. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/FodyWeavers.xml
  29. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/FodyWeavers.xsd
  30. 29
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/LINGYUN.Abp.ElsaNext.Agents.Blazor.csproj
  31. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/Localization/Resources/AgentsBlazor/en.json
  32. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/Localization/Resources/AgentsBlazor/zh-Hans.json
  33. 28
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/Navigation/ElsaStudioAgentsMenuContributor.cs
  34. 5
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/_Imports.razor
  35. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/FodyWeavers.xml
  36. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/FodyWeavers.xsd
  37. 27
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/LINGYUN.Abp.ElsaNext.Agents.csproj
  38. 22
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/LINGYUN/Abp/ElsaNext/Agents/AbpElsaNextAgentsModule.cs
  39. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/FodyWeavers.xml
  40. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/FodyWeavers.xsd
  41. 25
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/LINGYUN.Abp.ElsaNext.EntityFrameworkCore.csproj
  42. 57
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/LINGYUN/Abp/ElsaNext/EntityFrameworkCore/AbpElsaNextEntityFrameworkCoreModule.cs
  43. 49
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/AbpElsaNextSecretsBlazorModule.cs
  44. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/FodyWeavers.xml
  45. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/FodyWeavers.xsd
  46. 29
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/LINGYUN.Abp.ElsaNext.Secrets.Blazor.csproj
  47. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/Localization/Resources/SecretsBlazor/en.json
  48. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/Localization/Resources/SecretsBlazor/zh-Hans.json
  49. 28
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/Navigation/ElsaStudioSecretsMenuContributor.cs
  50. 5
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/_Imports.razor
  51. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/FodyWeavers.xml
  52. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/FodyWeavers.xsd
  53. 26
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/LINGYUN.Abp.ElsaNext.Secrets.csproj
  54. 24
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/LINGYUN/Abp/ElsaNext/Secrets/AbpElsaNextSecretsModule.cs
  55. 12
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Server/LINGYUN.Abp.ElsaNext.Server.csproj
  56. 36
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Server/LINGYUN/Abp/ElsaNext/Server/AbpElsaNextServerModule.cs
  57. 97
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs
  58. 12
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorOptions.cs
  59. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/FodyWeavers.xml
  60. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/FodyWeavers.xsd
  61. 43
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj
  62. 9
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json
  63. 9
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json
  64. 49
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Navigation/ElsaStudioMenuContributor.cs
  65. 6
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Navigation/ElsaStudioMenus.cs
  66. 26
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Properties/launchSettings.json
  67. 12
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor
  68. 61
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/AbpElsaNextStudioDashboardBlazorModule.cs
  69. 18
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Extensions/DashboardWidgetServiceCollectionExtensions.cs
  70. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/FodyWeavers.xml
  71. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/FodyWeavers.xsd
  72. 31
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.csproj
  73. 6
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Localization/Resources/ElsaStudioDashboardBlazor/en.json
  74. 6
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Localization/Resources/ElsaStudioDashboardBlazor/zh-Hans.json
  75. 31
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Navigation/ElsaStudioDashboardMenuContributor.cs
  76. 92
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Pages/Dashboard.razor
  77. 211
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Pages/Dashboard.razor.cs
  78. 120
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Services/ElsaStudioDashboardText.cs
  79. 59
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/ExecutionTrendWidget.razor
  80. 49
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/HotspotsWidget.razor
  81. 42
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/NeedsAttentionWidget.razor
  82. 46
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/OperationalHealthWidget.razor
  83. 101
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/RecentActivityWidget.razor
  84. 9
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/_Imports.razor
  85. 208
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/wwwroot/dashboard.css
  86. 87
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/AbpElsaNextStudioDiagnosticsOpenTelemetryBlazorModule.cs
  87. 20
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Extensions/OpenTelemetryWidgetServiceCollectionExtensions.cs
  88. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/FodyWeavers.xml
  89. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/FodyWeavers.xsd
  90. 34
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.csproj
  91. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Localization/Resources/ElsaStudioOpenTelemetryBlazor/en.json
  92. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Localization/Resources/ElsaStudioOpenTelemetryBlazor/zh-Hans.json
  93. 27
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Navigation/ElsaStudioOpenTelemetryMenuContributor.cs
  94. 5
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/_Imports.razor
  95. 74
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/AbpElsaNextStudioDiagnosticsStructuredLogsBlazorModule.cs
  96. 20
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/Extensions/OpenTelemetryWidgetServiceCollectionExtensions.cs
  97. 3
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/FodyWeavers.xml
  98. 30
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/FodyWeavers.xsd
  99. 33
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.csproj
  100. 7
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/Localization/Resources/ElsaStudioStructuredLogsBlazor/en.json

84
Directory.Packages.props

@ -2,7 +2,7 @@
<PropertyGroup>
<DotNetCoreCAPPackageVersion>10.0.0</DotNetCoreCAPPackageVersion>
<ElsaPackageVersion>2.17.0</ElsaPackageVersion>
<ElsaNextPackageVersion>3.6.0</ElsaNextPackageVersion>
<ElsaNextPackageVersion>3.8.0-rc2</ElsaNextPackageVersion>
<VoloAbpPackageVersion>10.6.0</VoloAbpPackageVersion>
<LINGYUNAbpPackageVersion>10.6.0</LINGYUNAbpPackageVersion>
<MicrosoftExtensionsPackageVersion>10.0.9</MicrosoftExtensionsPackageVersion>
@ -14,6 +14,7 @@
<!-- Abp Framework -->
<ItemGroup>
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="5.6.0" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.Server.MudBlazorLeptonXLiteTheme" Version="5.6.0" />
<PackageVersion Include="Volo.Abp.AI" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Core" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Account.Application" Version="$(VoloAbpPackageVersion)" />
@ -28,8 +29,14 @@
<PackageVersion Include="Volo.Abp.Account.Web.OpenIddict" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Authentication.OpenIdConnect" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.Web.Theming" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.WebAssembly" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.WebAssembly.Theming" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Components.WebAssembly.MudBlazorBasicTheme.Bundling" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.MultiTenancy" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc.Client.Common" Version="$(VoloAbpPackageVersion)" />
@ -48,6 +55,7 @@
<PackageVersion Include="Volo.Abp.Authorization" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Authorization.Abstractions" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Autofac" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Autofac.WebAssembly" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.AutoMapper" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.BackgroundJobs" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.BackgroundJobs.Abstractions" Version="$(VoloAbpPackageVersion)" />
@ -148,6 +156,7 @@
<PackageVersion Include="Volo.Abp.TestBase" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.TextTemplating.Core" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.TextTemplating.Scriban" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.TickerQ" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Timing" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Threading" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.UI.Navigation" Version="$(VoloAbpPackageVersion)" />
@ -162,9 +171,9 @@
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.9" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
@ -227,20 +236,76 @@
</ItemGroup>
<!-- Elsa Next-->
<ItemGroup>
<PackageVersion Include="CShells.AspNetCore" Version="0.0.28" />
<PackageVersion Include="Elsa.Agents" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Agents.Activities" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Agents.Api" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Agents.Core" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Agents.OpenAI" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Agents.Persistence.EFCore.Sqlite" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Api.Client" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Dashboard.Api" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Diagnostics.OpenTelemetry" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Diagnostics.StructuredLogs" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Expressions.CSharp" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Expressions.JavaScript" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Expressions.Liquid" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.ExternalAuthentication.OpenIdConnect" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Http" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Identity" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.OpenTelemetry" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Scheduling.Quartz" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Scheduling.Quartz.EFCore.Sqlite" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Secrets" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Secrets.Api" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Secrets.JavaScript" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Secrets.Persistence.EFCore.Sqlite" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Secrets" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Agents" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.Abstractions" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.ElsaIdentity.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.ElsaIdentity.BlazorWasm" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.ElsaIdentity.UI" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.OpenIdConnect.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.OpenIdConnect.BlazorWasm" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.UI" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Authentication.Themes" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Core" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Core.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Login.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Localization.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Core.BlazorWasm" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Dashboard" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Diagnostics.ConsoleLogs.Dashboard" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Diagnostics.StructuredLogs.Dashboard" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.DomInterop" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Http.Webhooks" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Login.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Login.BlazorWasm" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Login" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Localization" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Localization.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Localization.BlazorWasm" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Translations" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Agents" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.OpenIdConnect.BlazorServer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Settings" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Shell" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.WorkflowContexts" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Workflows" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Workflows.Dashboard" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Studio.Workflows.Designer" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Scheduling" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Expressions.CSharp" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Expressions.Liquid" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Http" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Persistence.EFCore" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Persistence.EFCore.MySQL" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Persistence.EFCore.PostgreSql" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.Persistence.EFCore.Sqlite" Version="$(ElsaNextPackageVersion)" />
<!--<PackageVersion Include="Elsa.UserTasks" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.UserTasks.Persistence.EFCore" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Elsa.UserTasks.Persistence.EFCore.Sqlite" Version="$(ElsaNextPackageVersion)" />-->
<PackageVersion Include="Elsa.Workflows.Runtime.Dashboard" Version="$(ElsaNextPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="$(MicrosoftAspNetCorePackageVersion)" />
</ItemGroup>
@ -278,6 +343,7 @@
</ItemGroup>
<!-- OpenTelemetry -->
<ItemGroup>
<PackageVersion Include="OpenTelemetry" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.17.0" />
@ -320,6 +386,7 @@
<PackageVersion Include="Oracle.ManagedDataAccess.Core" Version="23.26.300" />
<PackageVersion Include="Npgsql" Version="10.0.0" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="7.0.2" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.9" />
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="10.0.9" />
</ItemGroup>
<!-- Other -->
@ -392,6 +459,7 @@
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="10.0.9" />
<PackageVersion Include="Tencent.QCloud.Cos.Sdk" Version="5.4.37" />
<PackageVersion Include="TencentCloudSDK" Version="3.0.1273" />
<PackageVersion Include="TickerQ" Version="10.4.0" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.3.0" />
<PackageVersion Include="Yarp.Telemetry.Consumption" Version="2.3.0" />
</ItemGroup>

15
aspnet-core/LINGYUN.MicroService.Aspire.slnx

@ -130,8 +130,8 @@
<Project Path="framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj" />
</Folder>
<Folder Name="/framework/dynamic-definition/">
<Project Path="framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN.Abp.Dynamic.Definitions.csproj" />
<Project Path="framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN.Abp.Dynamic.Definitions.Core.csproj" />
<Project Path="framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN.Abp.Dynamic.Definitions.csproj" />
</Folder>
<Folder Name="/framework/dynamic-queryable/">
<Project Path="framework/dynamic-queryable/LINGYUN.Abp.Dynamic.Queryable.Application.Contracts/LINGYUN.Abp.Dynamic.Queryable.Application.Contracts.csproj" />
@ -552,6 +552,19 @@
<Project Path="modules/elsa/LINGYUN.Abp.Elsa.Server/LINGYUN.Abp.Elsa.Server.csproj" />
<Project Path="modules/elsa/LINGYUN.Abp.Elsa/LINGYUN.Abp.Elsa.csproj" />
</Folder>
<Folder Name="/modules/workflow/elsa3/">
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/LINGYUN.Abp.ElsaNext.Agents.Blazor.csproj" Id="fc82705b-186b-4d0d-80d2-473f08596b48" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Agents/LINGYUN.Abp.ElsaNext.Agents.csproj" Id="8699b2ee-5d73-4e7e-9f52-4ec02e5c8c52" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/LINGYUN.Abp.ElsaNext.Secrets.Blazor.csproj" Id="14b89b15-df06-4965-bd5d-2beaeb0179a6" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/LINGYUN.Abp.ElsaNext.Secrets.csproj" Id="f49baa76-12c5-4294-b942-fc6f5d49d3e6" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Server/LINGYUN.Abp.ElsaNext.Server.csproj" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.csproj" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.csproj" Id="86b1ee1c-6266-4003-8ab2-67aa497ea217" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.csproj" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Translations/LINGYUN.Abp.ElsaNext.Studio.Translations.csproj" />
<Project Path="modules/elsa/LINGYUN.Abp.ElsaNext/LINGYUN.Abp.ElsaNext.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/LINGYUN.Abp.Aliyun.Tests/LINGYUN.Abp.Aliyun.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj" />

25
aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.DbMigrator/appsettings.json

@ -7,7 +7,10 @@
"VueAdmin": {
"ClientId": "vue-admin-client",
"ClientSecret": "1q2w3e*",
"RootUrls": [ "http://localhost:5666" ]
"RootUrls": [
"http://localhost:5666",
"http://127.0.0.1:5666"
]
},
"InternalService": {
"ClientId": "InternalServiceClient",
@ -17,16 +20,34 @@
"ClientId": "vue-oauth-client",
"RootUrls": [
"http://localhost:5666",
"http://127.0.0.1:5666",
"http://localhost:30000",
"http://127.0.0.1:30000",
"http://localhost:30010",
"http://127.0.0.1:30010",
"http://localhost:30015",
"http://127.0.0.1:30015",
"http://localhost:30020",
"http://127.0.0.1:30020",
"http://localhost:30025",
"http://127.0.0.1:30025",
"http://localhost:30030",
"http://127.0.0.1:30030",
"http://localhost:30040",
"http://127.0.0.1:30040",
"http://localhost:30045",
"http://127.0.0.1:30045",
"http://localhost:30050",
"http://127.0.0.1:30050",
"http://localhost:30060",
"http://127.0.0.1:30060"
]
},
"ElsaStudioClient": {
"ClientId": "elsa-studio-client",
"RootUrls": [
"http://localhost:30050",
"http://localhost:30060"
"http://127.0.0.1:30050"
]
}
}

46
aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/DataSeeds/OpenIddictDataSeeder.cs

@ -576,5 +576,51 @@ public class OpenIddictDataSeeder : OpenIddictDataSeedContributorBase, ITransien
};
await PermissionDataSeeder.SeedAsync(ClientPermissionValueProvider.ProviderName, oauthClientId, oauthClientPermissions);
}
var elsaStudioClientId = configurationSection["ElsaStudioClient:ClientId"];
if (!elsaStudioClientId.IsNullOrWhiteSpace())
{
Logger.LogInformation("Seeding application {elsaStudioClientId}...", elsaStudioClientId);
var elsaStudioClientSecret = configurationSection["ElsaStudioClient:ClientSecret"];
var elsaStudioClientRootUrls = configurationSection.GetSection("ElsaStudioClient:RootUrls").Get<List<string>>() ?? [];
var elsaStudioClientRedirectUrls = new List<string>();
var elsaStudioClientPostLogoutRedirectUrls = new List<string>();
elsaStudioClientRootUrls.ForEach(url =>
{
elsaStudioClientRedirectUrls.Add(url.EnsureEndsWith('/'));
elsaStudioClientRedirectUrls.Add(url.EnsureEndsWith('/') + "signin-oidc");
elsaStudioClientRedirectUrls.Add(url.EnsureEndsWith('/') + "swagger/oauth2-redirect.html");
elsaStudioClientPostLogoutRedirectUrls.Add(url.EnsureEndsWith('/'));
elsaStudioClientPostLogoutRedirectUrls.Add(url.EnsureEndsWith('/') + "signout-oidc");
elsaStudioClientPostLogoutRedirectUrls.Add(url.EnsureEndsWith('/') + "signout-callback-oidc");
});
await CreateOrUpdateApplicationAsync(
OpenIddictConstants.ApplicationTypes.Web,
elsaStudioClientId,
!elsaStudioClientSecret.IsNullOrWhiteSpace()
? OpenIddictConstants.ClientTypes.Confidential
: OpenIddictConstants.ClientTypes.Public,
OpenIddictConstants.ConsentTypes.Implicit,
"Abp Elsa Studio Client",
elsaStudioClientSecret,
[OpenIddictConstants.GrantTypes.AuthorizationCode,
OpenIddictConstants.GrantTypes.RefreshToken,
OpenIddictConstants.GrantTypes.Password],
[OpenIddictConstants.Scopes.OpenId,
OpenIddictConstants.Scopes.Email,
OpenIddictConstants.Scopes.Roles,
OpenIddictConstants.Scopes.Address,
OpenIddictConstants.Scopes.Phone,
OpenIddictConstants.Scopes.Profile,
OpenIddictConstants.Scopes.OfflineAccess,
scope,
"workflow-service"],
elsaStudioClientRedirectUrls,
elsaStudioClientPostLogoutRedirectUrls);
}
}
}

64
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/App.razor

@ -0,0 +1,64 @@
@using System.Globalization
@using Microsoft.Extensions.Hosting
@using Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme.Bundling
@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Bundling
@using Volo.Abp.Localization
@inject IHostEnvironment Env
@{
var rtl = CultureHelper.IsRtl ? "rtl" : string.Empty;
}
<!DOCTYPE html>
<html lang="@CultureInfo.CurrentCulture.Name" dir="@rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Elsa Studio (Blazor Server)</title>
<base href="/" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<AbpStyles BundleName="@BlazorMudBlazorBasicThemeBundles.Styles.Global" />
@* Elsa Studio UI styles (RCL static assets) + offline icon-font fallback. *@
<link href="/_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.css" rel="stylesheet" />
<link href="/_content/Radzen.Blazor/css/material-base.css" rel="stylesheet" />
<link href="/_content/Elsa.Studio.Shell/css/shell.css" rel="stylesheet" />
<link href="/_content/Elsa.Studio.Workflows.Designer/designer.css" rel="stylesheet" />
<link href="/_content/Elsa.Studio.Workflows.Designer/designer.v1.css" rel="stylesheet" />
<link href="/_content/Elsa.Studio.Workflows.Designer/designer.v2.css" rel="stylesheet" />
<link href="/elsa-studio-icons.css" rel="stylesheet" />
<HeadOutlet @rendermode="InteractiveServer" />
</head>
<body>
<Routes @rendermode="InteractiveServer" />
<AbpScripts BundleName="@BlazorMudBlazorBasicThemeBundles.Scripts.Global" />
@* Monaco + Blazor Server bootstrap (mirrors the official Elsa Studio Server host). *@
<script src="/_content/MudBlazor/MudBlazor.min.js"></script>
<script src="/_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.js"></script>
<script src="/_content/Radzen.Blazor/Radzen.Blazor.js"></script>
<script src="/_content/BlazorMonaco/jsInterop.js"></script>
<script src="/_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js"></script>
<script src="/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js"></script>
<script src="/_framework/blazor.web.js"></script>
<div id="blazor-error-ui">
@if (Env.IsDevelopment())
{
<text>An unhandled exception has occurred. See browser dev tools for details.</text>
}
else if (Env.IsStaging() || Env.IsProduction())
{
<text>An error has occurred. This application may no longer respond until reloaded.</text>
}
<a href="" class="reload">Reload</a>
<a class="dismiss">&#10006;</a>
</div>
</body>
</html>

137
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/Index.razor

@ -0,0 +1,137 @@
@page "/"
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager Navigation
<MudGrid Class="mb-3">
<MudItem xs="12" md="6">
<MudCard Style="height: 100%;">
<MudCardContent>
@if (!IsAuthenticated)
{
<MudText Typo="Typo.h5" Class="mb-2">欢迎使用 Elsa 工作室</MudText>
<MudText Typo="Typo.body1" Class="mud-text-secondary mb-2">
以 Blazor Server 模式集成的 Elsa 工作流工作室:服务端渲染与交互,接口调用在服务端完成,凭据不出浏览器。
</MudText>
<MudButton Href="/Account/Login" Variant="Variant.Filled" Color="Color.Primary" Class="mb-4"
StartIcon="@Icons.Material.Filled.Login">登录</MudButton>
}
else
{
<MudText Typo="Typo.h5" Class="mb-2">欢迎回来</MudText>
<MudText Typo="Typo.body1" Class="mud-text-secondary mb-3">
通过左侧菜单进入 <strong>Elsa 工作室</strong>:管理工作流定义与实例,打开设计器进行可视化编排。
</MudText>
<MudButton StartIcon="@Icons.Material.Filled.AccountTree" Variant="Variant.Text" Color="Color.Primary"
OnClick="GoDefinitions">工作流定义</MudButton>
}
</MudCardContent>
</MudCard>
</MudItem>
<MudItem xs="12" md="6">
<MudCard Style="height: 100%;">
<MudCardContent>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="mb-2">
<MudIcon Icon="@Icons.Material.Filled.Info" Class="me-1" />关于
</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-3">
服务端 Blazor Server(SignalR)承载 Elsa Studio;认证走外部 OIDC AuthServer 授权码 + PKCE;
Studio 页面以 ABP 子页面呈现(路由在菜单中定义)。
</MudText>
<MudDivider Class="my-2" />
<MudText Typo="Typo.body2" Class="mud-text-secondary">
集成模块:LINGYUN.Abp.ElsaNext.Studio.Blazor
</MudText>
</MudCardContent>
</MudCard>
</MudItem>
</MudGrid>
<MudGrid>
<MudItem xs="12" lg="4">
<MudCard Style="height: 100%;">
<MudCardHeader>
<MudText Typo="Typo.h6">More from ABP.IO</MudText>
</MudCardHeader>
<MudCardContent Class="pt-0">
<MudList T="string" Dense="true">
<MudListItem Icon="@Icons.Material.Filled.Check" IconColor="Color.Primary"
Href="https://github.com/abpframework/abp/releases" Target="_blank">
Latest Release Logs
</MudListItem>
<MudListItem Icon="@Icons.Material.Filled.Check" IconColor="Color.Primary"
Href="https://abp.io/video-courses/essentials" Target="_blank">
Video Courses
</MudListItem>
<MudListItem Icon="@Icons.Material.Filled.Check" IconColor="Color.Primary"
Href="https://docs.abp.io/en/abp/latest/Samples/Index" Target="_blank">
Samples
</MudListItem>
<MudListItem Icon="@Icons.Material.Filled.Check" IconColor="Color.Primary"
Href="https://abp.io/books" Target="_blank">
Books
</MudListItem>
<MudListItem Icon="@Icons.Material.Filled.Check" IconColor="Color.Primary"
Href="https://abp.io/faq" Target="_blank">
FAQ
</MudListItem>
</MudList>
</MudCardContent>
</MudCard>
</MudItem>
<MudItem xs="12" lg="8">
<MudCard Style="height: 100%;">
<MudCardHeader>
<MudText Typo="Typo.h6">Follow us on Social Media</MudText>
</MudCardHeader>
<MudCardContent Class="pt-0">
<MudGrid Spacing="0">
<MudItem xs="12" sm="6">
<MudList T="string" Dense="true">
<MudListItem Href="https://twitter.com/abpframework" Target="_blank"
Icon="@Icons.Custom.Brands.Twitter" IconColor="Color.Primary">
X.com (Twitter)
</MudListItem>
<MudListItem Href="https://community.abp.io/discord" Target="_blank"
Icon="@Icons.Custom.Brands.Discord" IconColor="Color.Primary">
Discord
</MudListItem>
<MudListItem Href="https://stackoverflow.com/questions/tagged/abp" Target="_blank"
Icon="@Icons.Custom.Brands.StackOverflow" IconColor="Color.Primary">
Stack Overflow
</MudListItem>
</MudList>
</MudItem>
<MudItem xs="12" sm="6">
<MudList T="string" Dense="true">
<MudListItem Href="@("https://www.youtube.com/@Volosoft")" Target="_blank"
Icon="@Icons.Custom.Brands.YouTube" IconColor="Color.Error">
YouTube
</MudListItem>
<MudListItem Href="https://www.instagram.com/abpframework/" Target="_blank"
Icon="@Icons.Custom.Brands.Instagram" IconColor="Color.Secondary">
Instagram
</MudListItem>
<MudListItem Href="https://github.com/abpframework/abp" Target="_blank"
Icon="@Icons.Custom.Brands.GitHub" IconColor="Color.Dark">
GitHub
</MudListItem>
</MudList>
</MudItem>
</MudGrid>
</MudCardContent>
</MudCard>
</MudItem>
</MudGrid>
@code {
private bool IsAuthenticated;
protected override async Task OnInitializedAsync()
{
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
IsAuthenticated = state.User.Identity?.IsAuthenticated == true;
}
private void GoDefinitions() => Navigation.NavigateTo("/elsa/workflows/definitions");
}

10
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/LoginRedirect.razor

@ -0,0 +1,10 @@
@inject NavigationManager Navigation
@code
{
protected override void OnInitialized()
{
var returnUrl = Uri.EscapeDataString(Navigation.Uri);
Navigation.NavigateTo($"/Account/Login?returnUrl={returnUrl}", forceLoad: true);
}
}

13
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/Routes.razor

@ -0,0 +1,13 @@
@using Volo.Abp.AspNetCore.Components.Web.MudBlazorBasicTheme.Themes.Basic
@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing
@using Microsoft.Extensions.Options
@inject IOptions<AbpRouterOptions> RouterOptions
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="RouterOptions.Value.AdditionalAssemblies">
<Found Context="routeData">
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
<NotAuthorized>
<LoginRedirect />
</NotAuthorized>
</AuthorizeRouteView>
</Found>
</Router>

12
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Components/_Imports.razor

@ -0,0 +1,12 @@
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.JSInterop
@using MudBlazor
@using Volo.Abp.MudBlazorUI
@using Volo.Abp.MudBlazorUI.Components

42
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/ElsaShellPermissionPolicyProvider.cs

@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.MicroService.WorkflowService;
/// <summary>
/// Root <see cref="IAuthorizationPolicyProvider"/> for Shells hosting. Elsa 3.8.0-rc2 endpoints
/// declare FastEndpoints permission policies named "epPolicy:&lt;EndpointType&gt;" that CShells
/// registers inside the shell's own container, so ASP.NET's root policy provider (ABP's) cannot
/// resolve them. ABP authenticates /elsa/api with the AuthServer JWT and every validated token
/// carries Elsa's "all permissions" claim (see <see cref="WorkflowManagementNextBlazorServerModule"/>),
/// so epPolicy names are bridged to that grant; other policy names fall back to the defaults.
/// </summary>
public sealed class ElsaShellPermissionPolicyProvider : IAuthorizationPolicyProvider
{
// Allow-all policy (always-true assertion; AuthorizationPolicy rejects zero requirements).
private static readonly AuthorizationPolicy AllowAll = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
private readonly DefaultAuthorizationPolicyProvider _default = new(Options.Create(new AuthorizationOptions()));
/// <inheritdoc />
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
if (!policyName.StartsWith("epPolicy:", StringComparison.Ordinal))
return _default.GetPolicyAsync(policyName);
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireAssertion(context =>
context.User.HasClaim(Elsa.PermissionNames.ClaimType, Elsa.PermissionNames.All))
.Build();
return Task.FromResult<AuthorizationPolicy?>(policy);
}
/// <inheritdoc />
public Task<AuthorizationPolicy?> GetDefaultPolicyAsync() => Task.FromResult<AuthorizationPolicy?>(AllowAll);
/// <inheritdoc />
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() => Task.FromResult<AuthorizationPolicy?>(AllowAll);
}

130
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Extensions/ElsaStudioServiceCollectionExtensions.cs

@ -0,0 +1,130 @@
using Consul;
using Elsa.Studio.Authentication.Abstractions.ComponentProviders;
using Elsa.Studio.Authentication.Abstractions.Contracts;
using Elsa.Studio.Authentication.Abstractions.Models;
using Elsa.Studio.Authentication.OpenIdConnect.BlazorServer.Components;
using Elsa.Studio.Authentication.OpenIdConnect.BlazorServer.Services;
using Elsa.Studio.Authentication.OpenIdConnect.Contracts;
using Elsa.Studio.Authentication.OpenIdConnect.Models;
using Elsa.Studio.Authentication.OpenIdConnect.Services;
using Elsa.Studio.Contracts;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Polly;
using System;
using System.Linq;
using System.Net.Http;
namespace LINGYUN.Abp.MicroService.WorkflowService.Extensions;
public static class ElsaStudioServiceCollectionExtensions
{
internal const string AnonymousHttpClientName = "Elsa.Studio.Authentication.OpenIdConnect.BlazorServer.Anonymous";
public static IServiceCollection AddOpenIdConnectAuth(
this IServiceCollection services,
Action<OidcOptions> configure,
Func<IAsyncPolicy<HttpResponseMessage>> configureRetryPolicy = null)
{
var options = new OidcOptions();
configure(options);
services.AddSingleton<StudioAuthenticationProviderRegistration>(new StudioAuthenticationProviderRegistration(StudioAuthenticationProvider.OpenIdConnect));
// Ensure we always request the minimal identity scopes.
var configuredScopes = options.AuthenticationScopes?.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct(StringComparer.OrdinalIgnoreCase).ToArray() ?? Array.Empty<string>();
if (configuredScopes.Length == 0)
configuredScopes = ["openid", "profile", "offline_access"];
options.AuthenticationScopes = configuredScopes;
// Set Blazor Server defaults for callback paths if not explicitly specified.
options.CallbackPath ??= "/signin-oidc";
options.SignedOutCallbackPath ??= "/signout-callback-oidc";
// Register core services
services.AddHttpContextAccessor();
services.AddSingleton(options);
services.AddScoped<ITokenProvider, ServerTokenProvider>();
services.AddScoped<IHttpConnectionOptionsConfigurator, OidcHttpConnectionOptionsConfigurator>();
// Shared token refresh service used by both session refresh and backend API token acquisition
services.AddScoped<TokenRefreshService>();
// Cookie authentication events for automatic session token refresh (standard ASP.NET Core pattern)
services.AddScoped<AuthCookieEvents>();
// Configure ASP.NET Core authentication with cookie and OIDC
services.AddAuthentication(authOptions =>
{
authOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
authOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, cookieOptions =>
{
cookieOptions.Cookie.Name = "ElsaStudio.Auth";
cookieOptions.Cookie.HttpOnly = true;
cookieOptions.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;
cookieOptions.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax;
cookieOptions.ExpireTimeSpan = TimeSpan.FromHours(8);
cookieOptions.SlidingExpiration = true;
cookieOptions.LoginPath = "/Account/Login";
cookieOptions.AccessDeniedPath = "/Account/Login";
// Use custom events for automatic token refresh on every request validation
cookieOptions.EventsType = typeof(AuthCookieEvents);
})
.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, oidcOptions =>
{
oidcOptions.Authority = options.Authority;
oidcOptions.ClientId = options.ClientId;
oidcOptions.ClientSecret = options.ClientSecret;
oidcOptions.ResponseType = options.ResponseType;
oidcOptions.UsePkce = options.UsePkce;
oidcOptions.SaveTokens = options.SaveTokens;
oidcOptions.CallbackPath = options.CallbackPath;
oidcOptions.SignedOutCallbackPath = options.SignedOutCallbackPath;
oidcOptions.RequireHttpsMetadata = options.RequireHttpsMetadata;
oidcOptions.GetClaimsFromUserInfoEndpoint = options.GetClaimsFromUserInfoEndpoint;
oidcOptions.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Disable;
// Configure scopes
oidcOptions.Scope.Clear();
foreach (var scope in options.AuthenticationScopes)
{
oidcOptions.Scope.Add(scope);
}
// Map token response properties to enable token refresh
oidcOptions.MapInboundClaims = false;
if (!string.IsNullOrWhiteSpace(options.MetadataAddress))
{
oidcOptions.MetadataAddress = options.MetadataAddress;
}
// Configure token validation parameters
oidcOptions.TokenValidationParameters = new()
{
NameClaimType = options.NameClaimType,
RoleClaimType = options.RoleClaimType,
ValidateIssuer = true
};
});
// Add authorization services
services.AddAuthorizationCore();
// Use an OIDC-aware unauthorized component that initiates a challenge.
services.AddScoped<IUnauthorizedComponentProvider, UnauthorizedComponentProvider<ChallengeToLogin>>();
services.AddScoped<ILoginMethodCatalog, DirectOpenIdConnectLoginMethodCatalog>();
services.AddScoped<ILoginMethodComponentProvider, DirectOpenIdConnectLoginMethodComponentProvider>();
// HTTP client for token refresh requests with retry policy
var retryPolicy = configureRetryPolicy?.Invoke() ?? Elsa.Studio.Authentication.OpenIdConnect.BlazorServer.Extensions.ServiceCollectionExtensions.DefaultRetryPolicy;
services.AddHttpClient(AnonymousHttpClientName)
.AddPolicyHandler(retryPolicy);
return services;
}
}

47
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/LINGYUN.Abp.MicroService.WorkflowService.csproj

@ -7,20 +7,26 @@
<RootNamespace>LINGYUN.Abp.MicroService.WorkflowService</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Content Remove="Localization\Resources\*.json" />
<EmbeddedResource Include="Localization\Resources\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AgileConfig.Client" />
<PackageReference Include="CShells.AspNetCore" />
<PackageReference Include="DotNetCore.CAP.Dashboard" />
<PackageReference Include="DotNetCore.CAP.PostgreSql" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" />
<PackageReference Include="Elsa.Activities.Http" />
<PackageReference Include="Elsa.Activities.UserTask" />
<PackageReference Include="Elsa.Activities.Temporal.Quartz" />
<PackageReference Include="Elsa.Rebus.RabbitMq" />
<PackageReference Include="Elsa.Webhooks.Api" />
<PackageReference Include="Elsa.Agents.Persistence.EFCore.Sqlite" />
<PackageReference Include="Elsa.Persistence.EFCore.Sqlite" />
<PackageReference Include="Elsa.Scheduling.Quartz.EFCore.Sqlite" />
<PackageReference Include="Elsa.Secrets.Persistence.EFCore.Sqlite" />
<PackageReference Include="Elsa.Studio.Authentication.OpenIdConnect.BlazorServer" />
<PackageReference Include="Elsa.Studio.Authentication.Themes" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" />
<PackageReference Include="DistributedLock.Redis" />
<PackageReference Include="Quartz.Serialization.Json" />
<PackageReference Include="Rebus.RabbitMq" VersionOverride="10.0.1" />
<!--<PackageReference Include="Quartz.Serialization.Json" />-->
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Enrichers.Environment" />
<PackageReference Include="Serilog.Enrichers.AssemblyName" />
@ -31,14 +37,16 @@
<PackageReference Include="Serilog.Sinks.Elasticsearch" />
<PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="Volo.Abp.AspNetCore.Serilog" />
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme" />
<PackageReference Include="Volo.Abp.AspNetCore.MultiTenancy" />
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.NewtonsoftJson" />
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.OpenIdConnect" />
<PackageReference Include="Volo.Abp.Autofac" />
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" />
<PackageReference Include="Volo.Abp.EntityFrameworkCore.PostgreSql" />
<PackageReference Include="Volo.Abp.Http.Client.IdentityModel.Web" />
<PackageReference Include="Volo.Abp.Json" />
<PackageReference Include="Volo.Abp.Swashbuckle" />
<PackageReference Include="Volo.Abp.Http.Client.IdentityModel.Web" />
<PackageReference Include="Volo.Abp.FeatureManagement.EntityFrameworkCore" />
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" />
<PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" />
@ -62,23 +70,28 @@
<ItemGroup>
<ProjectReference Include="..\..\modules\blob-management\LINGYUN.Abp.BlobStoring.BlobManagement\LINGYUN.Abp.BlobStoring.BlobManagement.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.Elsa.EntityFrameworkCore.PostgreSql\LINGYUN.Abp.Elsa.EntityFrameworkCore.PostgreSql.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.Elsa.Notifications\LINGYUN.Abp.Elsa.Notifications.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.Elsa.Activities\LINGYUN.Abp.Elsa.Activities.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.Elsa.Server\LINGYUN.Abp.Elsa.Server.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.Elsa\LINGYUN.Abp.Elsa.csproj" />
<ProjectReference Include="..\..\modules\identity\LINGYUN.Abp.Identity.Session.AspNetCore\LINGYUN.Abp.Identity.Session.AspNetCore.csproj" />
<ProjectReference Include="..\..\modules\saas\LINGYUN.Abp.Saas.EntityFrameworkCore\LINGYUN.Abp.Saas.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\localization-management\LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore\LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\platform\LINGYUN.Abp.Emailing.Platform\LINGYUN.Abp.Emailing.Platform.csproj" />
<ProjectReference Include="..\..\modules\platform\LINGYUN.Abp.Sms.Platform\LINGYUN.Abp.Sms.Platform.csproj" />
<ProjectReference Include="..\..\modules\task-management\LINGYUN.Abp.BackgroundTasks.Quartz\LINGYUN.Abp.BackgroundTasks.Quartz.csproj" />
<!--<ProjectReference Include="..\..\modules\task-management\LINGYUN.Abp.BackgroundTasks.Quartz\LINGYUN.Abp.BackgroundTasks.Quartz.csproj" />
<ProjectReference Include="..\..\modules\task-management\LINGYUN.Abp.BackgroundTasks.DistributedLocking\LINGYUN.Abp.BackgroundTasks.DistributedLocking.csproj" />
<ProjectReference Include="..\..\modules\task-management\LINGYUN.Abp.Quartz.PostgresSqlInstaller\LINGYUN.Abp.Quartz.PostgresSqlInstaller.csproj" />
<ProjectReference Include="..\..\modules\task-management\LINGYUN.Abp.TaskManagement.EntityFrameworkCore\LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\task-management\LINGYUN.Abp.TaskManagement.EntityFrameworkCore\LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj" />-->
<ProjectReference Include="..\..\modules\text-templating\LINGYUN.Abp.TextTemplating.EntityFrameworkCore\LINGYUN.Abp.TextTemplating.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Agents.Blazor\LINGYUN.Abp.ElsaNext.Agents.Blazor.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Secrets.Blazor\LINGYUN.Abp.ElsaNext.Secrets.Blazor.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Server\LINGYUN.Abp.ElsaNext.Server.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor\LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor\LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.csproj" />
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor\LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.MicroService.ServiceDefaults\LINGYUN.Abp.MicroService.ServiceDefaults.csproj" />
</ItemGroup>

6
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Localization/Resources/en.json

@ -0,0 +1,6 @@
{
"culture": "en",
"texts": {
"Menu:Logout": "Logout"
}
}

6
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Localization/Resources/zh-Hans.json

@ -0,0 +1,6 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:Logout": "退出登录"
}
}

22
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Navigation/UserMenuContributor.cs

@ -0,0 +1,22 @@
using Localization.Resources.AbpUi;
using System.Threading.Tasks;
using Volo.Abp.UI.Navigation;
namespace LINGYUN.Abp.MicroService.WorkflowService.Navigation;
public class UserMenuContributor : IMenuContributor
{
public virtual Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name != StandardMenus.User)
{
return Task.CompletedTask;
}
var uiResource = context.GetLocalizer<AbpUiResource>();
context.Menu.AddItem(new ApplicationMenuItem("Auth.Logout", uiResource["Menu:Logout"], url: "~/Account/Logout", icon: "fa fa-power-off", order: int.MaxValue - 1000));
return Task.CompletedTask;
}
}

6
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Login.cshtml

@ -0,0 +1,6 @@
@page "/Account/Login"
@model LINGYUN.Abp.MicroService.WorkflowService.Pages.Auth.LoginModel
@{
ViewData["Title"] = "Login";
}
<p>Redirecting to the identity provider&hellip;</p>

21
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Login.cshtml.cs

@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LINGYUN.Abp.MicroService.WorkflowService.Pages.Auth;
/// <summary>
/// Triggers the standard OIDC authorization-code flow: signing in challenges the "oidc" scheme so
/// the user is redirected to the external AuthServer, then back to this host's cookie.
/// </summary>
public class LoginModel : PageModel
{
public IActionResult OnGet(string returnUrl = null)
{
var redirectUri = string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl;
return Challenge(
new AuthenticationProperties { RedirectUri = redirectUri },
OpenIdConnectDefaults.AuthenticationScheme);
}
}

6
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Logout.cshtml

@ -0,0 +1,6 @@
@page "/Account/Logout"
@model LINGYUN.Abp.MicroService.WorkflowService.Pages.Auth.LogoutModel
@{
ViewData["Title"] = "Logout";
}
<p>Signing out&hellip;</p>

22
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/Account/Logout.cshtml.cs

@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LINGYUN.Abp.MicroService.WorkflowService.Pages.Auth;
/// <summary>
/// Signs out the local cookie and ends the OIDC session at the external AuthServer.
/// </summary>
public class LogoutModel : PageModel
{
public IActionResult OnGet(string returnUrl = null)
{
var redirectUri = string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl;
return SignOut(
new AuthenticationProperties { RedirectUri = redirectUri },
CookieAuthenticationDefaults.AuthenticationScheme,
OpenIdConnectDefaults.AuthenticationScheme);
}
}

42
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/_Host.cshtml

@ -1,42 +0,0 @@
@page "/"
@inject IConfiguration Configuration;
@{
var serverUrl = Configuration["Elsa:Server:BaseUrl"];
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Elsa Workflows</title>
<link rel="icon" type="image/png" sizes="32x32" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/favicon-16x16.png">
<link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/fonts/inter/inter.css">
<link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/elsa-workflows-studio.css">
<script src="/_content/Elsa.Designer.Components.Web/monaco-editor/min/vs/loader.js"></script>
<script type="module" src="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/elsa-workflows-studio.esm.js"></script>
</head>
<body>
<elsa-studio-root server-url="@serverUrl" base-path="" monaco-lib-path="./_content/Elsa.Designer.Components.Web/monaco-editor/min">
<elsa-studio-dashboard></elsa-studio-dashboard>
</elsa-studio-root>
</body>
<script type="module">
// Import publicly exposed services.
import { WebhooksPlugin, WorkflowSettingsPlugin } from "/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/index.esm.js";
// Get a handle to the elsa-studio-root element.
const elsaStudioRoot = document.querySelector('elsa-studio-root');
// Configure Elsa during the 'initializing' event.
elsaStudioRoot.addEventListener('initializing', e => {
const elsa = e.detail;
elsa.pluginManager.registerPlugins([
WebhooksPlugin,
WorkflowSettingsPlugin
]);
});
</script>
</html>

5
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Pages/_ViewImports.cshtml

@ -1,2 +1,3 @@
@using Microsoft.Extensions.Configuration
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Http
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

28
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/Program.cs

@ -1,20 +1,25 @@
using LINGYUN.Abp.Identity.Session.AspNetCore;
using Elsa.Extensions;
using LINGYUN.Abp.Identity.Session.AspNetCore;
using LINGYUN.Abp.MicroService.WorkflowService;
using LINGYUN.Abp.MicroService.WorkflowService.Components;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Serilog;
using System;
using System.IO;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.IO;
using Volo.Abp.Modularity.PlugIns;
Log.Information("Starting WorkflowService Host...");
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseStaticWebAssets();
builder.Host.AddAppSettingsSecretsJson()
.UseAutofac()
.ConfigureAppConfiguration((context, config) =>
@ -27,7 +32,7 @@ builder.Host.AddAppSettingsSecretsJson()
.UseSerilog((context, provider, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
});
}, writeToProviders: true);
builder.AddServiceDefaults();
@ -49,18 +54,19 @@ await app.InitializeApplicationAsync();
app.MapDefaultEndpoints();
app.UseForwardedHeaders();
// 本地化
app.UseMapRequestLocalization();
app.UseCors();
app.UseCorrelationId();
app.MapAbpStaticAssets();
app.UseMapRequestLocalization();
app.UseRouting();
app.UseCors();
app.UseStaticFiles();
app.MapAbpStaticAssets();
app.UseAuthentication();
app.UseJwtTokenMiddleware();
app.UseMultiTenancy();
app.UseAbpSession();
app.UseDynamicClaims();
app.UseAuthorization();
app.UseAntiforgery();
app.UseSwagger();
app.UseAbpSwaggerUI(options =>
{
@ -70,9 +76,15 @@ app.UseAbpSwaggerUI(options =>
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
options.OAuthScopes(configuration["AuthServer:Audience"]);
});
app.UseWorkflowsApi(); // Use Elsa API endpoints.
app.UseWorkflows(); // Use Elsa middleware for HTTP Endpoint activities.
app.UseAuditing();
app.UseAbpSerilogEnrichers();
app.UseConfiguredEndpoints();
app.UseHttpActivities();
app.UseConfiguredEndpoints(builder =>
{
builder.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddAdditionalAssemblies(builder.ServiceProvider.GetRequiredService<IOptions<AbpRouterOptions>>().Value.AdditionalAssemblies.ToArray());
});
await app.RunAsync();

214
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.Configure.cs

@ -1,11 +1,21 @@
using DotNetCore.CAP;
using Elsa;
using Elsa.Options;
using Elsa.Rebus.RabbitMq;
using LINGYUN.Abp.BackgroundTasks;
using Elsa.Agents;
using Elsa.Extensions;
using Elsa.Features.Services;
using Elsa.Persistence.EFCore.Extensions;
using Elsa.Persistence.EFCore.Modules.Management;
using Elsa.Persistence.EFCore.Modules.Runtime;
using Elsa.Secrets.Persistence.EFCore.Extensions;
using Elsa.Secrets.Persistence.EFCore.Sqlite.Extensions;
using Elsa.Studio.Authentication.OpenIdConnect.HttpMessageHandlers;
using Elsa.Studio.Workflows.Designer.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.LocalizationManagement;
using LINGYUN.Abp.MicroService.WorkflowService.Extensions;
using LINGYUN.Abp.MicroService.WorkflowService.Navigation;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using Localization.Resources.AbpUi;
using Medallion.Threading;
using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Authentication.JwtBearer;
@ -17,15 +27,17 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi;
using Quartz;
using StackExchange.Redis;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.Auditing;
@ -38,18 +50,11 @@ using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Quartz;
using Volo.Abp.Security.Claims;
using Volo.Abp.Threading;
using Volo.Abp.Timing;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using ConsoleStartup = Elsa.Activities.Console.Startup;
using HttpStartup = Elsa.Activities.Http.Startup;
using JavaScriptStartup = Elsa.Scripting.JavaScript.Startup;
using TemporalQuartzStartup = Elsa.Activities.Temporal.Quartz.Startup;
using UserTaskStartup = Elsa.Activities.UserTask.Startup;
using WebhooksListEndpoint = Elsa.Webhooks.Api.Endpoints.List;
using WebhooksStartup = Elsa.Activities.Webhooks.Startup;
namespace LINGYUN.Abp.MicroService.WorkflowService;
@ -105,102 +110,109 @@ public partial class WorkflowServiceModule
private void PreConfigureQuartz(IConfiguration configuration)
{
PreConfigure<AbpQuartzOptions>(options =>
{
// 如果使用持久化存储, 则配置quartz持久层
if (configuration.GetSection("Quartz:UsePersistentStore").Get<bool>())
{
var settings = configuration.GetSection("Quartz:Properties").Get<Dictionary<string, string>>();
if (settings != null)
{
foreach (var setting in settings)
{
options.Properties[setting.Key] = setting.Value;
}
}
//PreConfigure<AbpQuartzOptions>(options =>
//{
// // 如果使用持久化存储, 则配置quartz持久层
// if (configuration.GetSection("Quartz:UsePersistentStore").Get<bool>())
// {
// var settings = configuration.GetSection("Quartz:Properties").Get<Dictionary<string, string>>();
// if (settings != null)
// {
// foreach (var setting in settings)
// {
// options.Properties[setting.Key] = setting.Value;
// }
// }
options.Configurator += (config) =>
{
config.UsePersistentStore(store =>
{
store.UseProperties = false;
store.UseNewtonsoftJsonSerializer();
});
};
}
});
// options.Configurator += (config) =>
// {
// config.UsePersistentStore(store =>
// {
// store.UseProperties = false;
// store.UseNewtonsoftJsonSerializer();
// });
// };
// }
//});
}
private void ConfigureBackgroundTasks(IServiceCollection services, IConfiguration configuration)
{
Configure<AbpBackgroundTasksOptions>(options =>
{
options.NodeName = services.GetApplicationName();
});
//Configure<AbpBackgroundTasksOptions>(options =>
//{
// options.NodeName = services.GetApplicationName();
//});
}
private void PreConfigureElsa(IServiceCollection services, IConfiguration configuration)
{
var elsaSection = configuration.GetSection("Elsa");
var startups = new[]
PreConfigure<AbpAspNetCoreComponentsWebOptions>(options =>
{
options.IsBlazorWebApp = true;
});
PreConfigure<IModule>(elsa =>
{
elsa.UseWorkflowManagement(management =>
{
typeof(ConsoleStartup),
typeof(HttpStartup),
typeof(UserTaskStartup),
typeof(TemporalQuartzStartup),
typeof(JavaScriptStartup),
typeof(WebhooksStartup),
};
management.UseEntityFrameworkCore(ef => ef.UseSqlite());
});
PreConfigure<ElsaOptionsBuilder>(elsa =>
{
elsa
.AddActivitiesFrom<WorkflowServiceModule>()
.AddWorkflowsFrom<WorkflowServiceModule>()
.AddFeatures(startups, configuration)
.ConfigureWorkflowChannels(options => elsaSection.GetSection("WorkflowChannels").Bind(options))
.UseRabbitMq(elsaSection["Rebus:RabbitMQ:Connection"]);
elsa.DistributedLockingOptionsBuilder
.UseProviderFactory(sp => name =>
{
var provider = sp.GetRequiredService<IDistributedLockProvider>();
elsa.UseWorkflowRuntime(runtime =>
{
runtime.UseEntityFrameworkCore(ef => ef.UseSqlite());
});
return provider.CreateLock(name);
});
});
elsa.UseAgentPersistence(agent =>
{
agent.UseEntityFrameworkCore(ef => ef.UseSqlite());
});
services.AddNotificationHandlersFrom<WorkflowServiceModule>();
elsa.UseSecrets(secret =>
{
secret.UseEntityFrameworkCore(ef => ef.UseSqlite());
});
elsa.UseQuartz(quartz =>
{
quartz.UseSqlite();
});
elsa.UseScheduling(scheduling =>
{
scheduling.UseQuartzScheduler();
});
});
PreConfigure<IMvcBuilder>(mvcBuilder =>
PreConfigure<AbpElsaNextStudioBlazorOptions>(options =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(WebhooksListEndpoint).Assembly);
options.BackendApiConfig.ConfigureHttpClientBuilder = options =>
{
options.AuthenticationHandler = typeof(OidcAuthenticatingApiHttpMessageHandler);
options.ConfigureHttpClient = (_, client) =>
{
// Set a long time out to simplify debugging both Elsa Studio and the Elsa Server backend.
client.Timeout = TimeSpan.FromHours(1);
};
};
});
services.AddRazorComponents()
.AddInteractiveServerComponents(options =>
{
options.RootComponents.RegisterCustomElsaStudioElements();
});
}
private void ConfigureEndpoints(IServiceCollection services)
private void ConfigureElsa(IServiceCollection services, IConfiguration configuration)
{
// 不需要
//Configure<AbpEndpointRouterOptions>(options =>
//Configure<AbpElsaNextShellOptions>(options =>
//{
// options.EndpointConfigureActions.Add(
// (context) =>
// {
// context.Endpoints.MapFallbackToPage("/_Host");
// });
// options.WithFeature<SqliteWorkflowPersistenceShellFeature>();
//});
var preActions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>();
services.AddAbpApiVersioning(options =>
{
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
//options.ApiVersionReader = new HeaderApiVersionReader("api-version"); //Supports header too
//options.ApiVersionReader = new MediaTypeApiVersionReader(); //Supports accept header too
}, mvcOptions =>
services.AddOpenIdConnectAuth(options =>
{
mvcOptions.ConfigureAbp(preActions.Configure());
configuration.GetSection("Authentication:OpenIdConnect").Bind(options);
});
}
@ -296,6 +308,16 @@ public partial class WorkflowServiceModule
{
options.ExposeIntegrationServices = true;
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new UserMenuContributor());
});
Configure<AbpRouterOptions>(options =>
{
options.AppAssembly = typeof(WorkflowServiceModule).Assembly;
});
}
private void ConfigureVirtualFileSystem()
@ -411,6 +433,9 @@ public partial class WorkflowServiceModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
options.Resources.Get<AbpUiResource>()
.AddVirtualJson("/Localization/Resources");
});
Configure<AbpLocalizationCultureMapOptions>(options =>
@ -438,7 +463,7 @@ public partial class WorkflowServiceModule
options.AutoValidate = false;
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
services.AddAuthentication()
.AddAbpJwtBearer(options =>
{
configuration.GetSection("AuthServer").Bind(options);
@ -454,7 +479,20 @@ public partial class WorkflowServiceModule
{
options.TokenValidationParameters.ValidAudiences = validAudiences;
}
});
options.Events ??= new JwtBearerEvents();
var previousOnTokenValidated = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await previousOnTokenValidated(context);
if (context.Principal?.Identity?.IsAuthenticated == true)
{
context.Principal.AddIdentity(new ClaimsIdentity(
new[] { new Claim(Elsa.PermissionNames.ClaimType, Elsa.PermissionNames.All) }));
}
};
})
;
services
.AddDataProtection()

45
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/WorkflowServiceModule.cs

@ -2,16 +2,17 @@
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
using LINGYUN.Abp.AuditLogging.Elasticsearch;
using LINGYUN.Abp.Authorization.OrganizationUnits;
using LINGYUN.Abp.BackgroundTasks.DistributedLocking;
using LINGYUN.Abp.BackgroundTasks.Quartz;
using LINGYUN.Abp.BlobStoring.BlobManagement;
using LINGYUN.Abp.Claims.Mapping;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.Dynamic.Definitions;
using LINGYUN.Abp.Elsa;
using LINGYUN.Abp.Elsa.Activities;
using LINGYUN.Abp.Elsa.EntityFrameworkCore.PostgreSql;
using LINGYUN.Abp.Elsa.Notifications;
using LINGYUN.Abp.ElsaNext.Agents.Blazor;
using LINGYUN.Abp.ElsaNext.Secrets.Blazor;
using LINGYUN.Abp.ElsaNext.Server;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor;
using LINGYUN.Abp.Emailing.Platform;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling.Emailing;
@ -19,20 +20,19 @@ using LINGYUN.Abp.Http.Client.Wrapper;
using LINGYUN.Abp.Identity.Session.AspNetCore;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.Quartz.PostgresSqlInstaller;
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.TaskManagement.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
using Volo.Abp.AspNetCore.Components.Server.MudBlazorBasicTheme;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.NewtonsoftJson;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Caching.StackExchangeRedis;
@ -52,29 +52,33 @@ namespace LINGYUN.Abp.MicroService.WorkflowService;
typeof(AbpAuditLoggingElasticsearchModule),
typeof(AbpAspNetCoreSerilogModule),
typeof(AbpBlobStoringBlobManagementModule),
typeof(AbpElsaModule),
typeof(AbpElsaServerModule),
typeof(AbpElsaActivitiesModule),
typeof(AbpElsaNotificationsModule),
typeof(AbpElsaNextServerModule),
typeof(AbpElsaNextStudioBlazorModule),
typeof(AbpElsaNextAgentsBlazorModule),
typeof(AbpElsaNextSecretsBlazorModule),
typeof(AbpElsaNextStudioDashboardBlazorModule),
typeof(AbpElsaNextStudioDiagnosticsOpenTelemetryBlazorModule),
typeof(AbpElsaNextStudioDiagnosticsStructuredLogsBlazorModule),
typeof(AbpEmailingExceptionHandlingModule),
typeof(AbpHttpClientIdentityModelWebModule),
typeof(AbpAspNetCoreMultiTenancyModule),
typeof(AbpBackgroundTasksQuartzModule),
typeof(AbpBackgroundTasksDistributedLockingModule),
typeof(AbpQuartzPostgresSqlInstallerModule),
typeof(TaskManagementEntityFrameworkCoreModule),
//typeof(AbpBackgroundTasksQuartzModule),
//typeof(AbpBackgroundTasksDistributedLockingModule),
//typeof(AbpQuartzPostgresSqlInstallerModule),
//typeof(TaskManagementEntityFrameworkCoreModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpSaasEntityFrameworkCoreModule),
typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpElsaEntityFrameworkCorePostgreSqlModule),
typeof(AbpAuthorizationOrganizationUnitsModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule),
typeof(AbpTextTemplatingScribanModule),
typeof(AbpDataDbMigratorModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpAspNetCoreMvcModule),
typeof(AbpAspNetCoreComponentsServerMudBlazorBasicThemeModule),
typeof(AbpSwashbuckleModule),
typeof(AbpCAPEventBusModule),
typeof(AbpLocalizationCultureMapModule),
@ -83,7 +87,6 @@ namespace LINGYUN.Abp.MicroService.WorkflowService;
typeof(AbpSmsPlatformModule),
typeof(AbpEmailingPlatformModule),
typeof(AbpClaimsMappingModule),
typeof(AbpAspNetCoreMvcNewtonsoftModule),
typeof(AbpAspNetCoreHttpOverridesModule),
typeof(AbpDynamicDefinitionsModule),
typeof(AbpIdentitySessionAspNetCoreModule),
@ -120,15 +123,13 @@ public partial class WorkflowServiceModule : AbpModule
ConfigureAuditing(configuration);
ConfigureIdentity(configuration);
ConfigureMultiTenancy(configuration);
ConfigureEndpoints(context.Services);
ConfigureMvc(context.Services, configuration);
ConfigureCors(context.Services, configuration);
ConfigureElsa(context.Services, configuration);
ConfigureSwagger(context.Services, configuration);
ConfigureBlobStoring(context.Services, configuration);
ConfigureDistributedLock(context.Services, configuration);
ConfigureBackgroundTasks(context.Services, configuration);
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
context.Services.AddRazorPages();
}
}

103
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/appsettings.Development.json

@ -33,71 +33,28 @@
}
},
"Elsa": {
"Features": {
"DefaultPersistence": {
"Enabled": true,
"ConnectionStringIdentifier": "Default",
"YesSql": {
"MySql": {
"Enabled": true
}
},
"EntityFrameworkCore": {
"MySql": {
"Enabled": true
}
}
},
"Console": true,
"Http": true,
"Email": true,
"TemporalQuartz": true,
"JavaScriptActivities": true,
"UserTask": true,
"Conductor": true,
"Telnyx": true,
"BlobStoring": true,
"Emailing": true,
"Notification": true,
"Sms": true,
"IM": true,
"PublishWebhook": true,
"Webhooks": {
"Enabled": true,
"ConnectionStringIdentifier": "Default",
"YesSql": {
"MySql": {
"Enabled": true
}
},
"EntityFrameworkCore": {
"MySql": {
"Enabled": true
}
}
},
"WorkflowSettings": {
"Enabled": true,
"ConnectionStringIdentifier": "Default",
"YesSql": {
"MySql": {
"Enabled": true
}
},
"EntityFrameworkCore": {
"MySql": {
"Enabled": true
}
}
}
"Http": {
"BaseUrl": "http://localhost:30050"
},
"Rebus": {
"RabbitMQ": {
"Connection": "amqp://admin:123456@localhost:5672/"
}
"Secrets": {
"EncryptionKey": "Q0hBTkdFX01FX1RPX0FfU0VDVVJFX1JBTkRPTV9LRVk="
},
"Server": {
"BaseUrl": "http://localhost:30035"
"EnableRealTimeWorkflows": true
},
"Studio": {
"Backend": {
"Url": "http://localhost:30050/elsa/api"
},
"DesignerOptions": {
"UseReactFlow": false
},
"Shell": {
"DisableAuthorization": true
},
"Presentation": {
"Theme": "classic"
}
}
},
"RemoteServices": {
@ -159,8 +116,26 @@
"ValidAudiences": [ "lingyun-abp-application" ],
"MapInboundClaims": false,
"RequireHttpsMetadata": false,
"ElsaClientId": "InternalServiceClient",
"SwaggerClientId": "vue-oauth-client"
"ClientId": "elsa-studio-client",
"SwaggerClientId": "elsa-studio-client"
},
"Authentication": {
"OpenIdConnect": {
"Authority": "http://localhost:44385",
"ClientId": "elsa-studio-client",
"ClientSecret": null,
"AuthenticationScopes": [
"openid",
"profile",
"roles",
"email",
"offline_access",
"workflow-service"
],
"MapInboundClaims": false,
"RequireHttpsMetadata": false,
"SaveTokens": true
}
},
"Logging": {
"Serilog": {

8
aspnet-core/aspire/LINGYUN.Abp.MicroService.WorkflowService/package.json

@ -0,0 +1,8 @@
{
"version": "10.6.0",
"name": "aspire-workflow-service",
"private": true,
"dependencies": {
"@abp/aspnetcore.components.server.basictheme": "10.6.0"
}
}

49
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/AbpElsaNextAgentsBlazorModule.cs

@ -0,0 +1,49 @@
using Elsa.Studio.Extensions;
using LINGYUN.Abp.ElsaNext.Agents.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.ElsaNext.Agents.Blazor;
[DependsOn(
typeof(AbpElsaNextAgentsModule),
typeof(AbpElsaNextStudioBlazorModule))]
public class AbpElsaNextAgentsBlazorModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
Configure<AbpRouterOptions>(options =>
{
options.AdditionalAssemblies.Add(typeof(Elsa.Studio.Agents.Feature).Assembly);
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new ElsaStudioAgentsMenuContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpElsaNextAgentsBlazorModule>("LINGYUN.Abp.ElsaNext.Agents.Blazor");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<ElsaStudioResource>()
.AddVirtualJson("/Localization/Resources/AgentsBlazor");
});
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>();
context.Services.AddAgentsModule(elsaNextStudioBlazoeOptions.BackendApiConfig);
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

29
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/LINGYUN.Abp.ElsaNext.Agents.Blazor.csproj

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.ElsaNext.Agents.Blazor</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Agents.Blazor</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup>
<ItemGroup>
<Content Remove="Localization\Resources\AgentsBlazor\*.json" />
<EmbeddedResource Include="Localization\Resources\AgentsBlazor\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Elsa.Studio.Agents" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Agents\LINGYUN.Abp.ElsaNext.Agents.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
</ItemGroup>
</Project>

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/Localization/Resources/AgentsBlazor/en.json

@ -0,0 +1,7 @@
{
"culture": "en",
"texts": {
"Menu:Agents": "Agents",
"Agents": "Agents"
}
}

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/Localization/Resources/AgentsBlazor/zh-Hans.json

@ -0,0 +1,7 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:Agents": "代理列表",
"Agents": "代理列表"
}
}

28
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/Navigation/ElsaStudioAgentsMenuContributor.cs

@ -0,0 +1,28 @@
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using System.Threading.Tasks;
using Volo.Abp.UI.Navigation;
namespace LINGYUN.Abp.ElsaNext.Agents.Blazor.Navigation;
public class ElsaStudioAgentsMenuContributor : IMenuContributor
{
public Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
var menu = context.Menu;
var l = context.GetLocalizer<ElsaStudioResource>();
var group = menu.GetMenuItemOrNull(ElsaStudioMenus.GroupName);
group?.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".Agents",
l["Menu:Agents"],
url: "/ai/agents",
icon: "fa fa-bots",
order: 5));
}
return Task.CompletedTask;
}
}

5
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents.Blazor/_Imports.razor

@ -0,0 +1,5 @@
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Web
@using Elsa.Studio.Components
@using Elsa.Studio.Localization
@using MudBlazor

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

27
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/LINGYUN.Abp.ElsaNext.Agents.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.ElsaNext.Agents</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Agents</PackageId>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa.Agents" />
<PackageReference Include="Elsa.Agents.Api" />
<PackageReference Include="Elsa.Agents.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext\LINGYUN.Abp.ElsaNext.csproj" />
</ItemGroup>
</Project>

22
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Agents/LINGYUN/Abp/ElsaNext/Agents/AbpElsaNextAgentsModule.cs

@ -0,0 +1,22 @@
using Elsa.Agents;
using Elsa.Extensions;
using Elsa.Features.Services;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ElsaNext.Agents;
[DependsOn(
typeof(AbpElsaNextModule))]
public class AbpElsaNextAgentsModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IModule>(elsa =>
{
elsa.UseAgents();
elsa.UseAgentActivities();
elsa.UseAgentsApi();
});
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

25
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/LINGYUN.Abp.ElsaNext.EntityFrameworkCore.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.ElsaNext.EntityFrameworkCore</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.EntityFrameworkCore</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa.Persistence.EFCore" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Volo.Abp.EntityFrameworkCore" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext\LINGYUN.Abp.ElsaNext.csproj" />
</ItemGroup>
</Project>

57
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.EntityFrameworkCore/LINGYUN/Abp/ElsaNext/EntityFrameworkCore/AbpElsaNextEntityFrameworkCoreModule.cs

@ -0,0 +1,57 @@
using Elsa.Alterations.Extensions;
using Elsa.Extensions;
using Elsa.Features.Services;
using Elsa.Persistence.EFCore.Modules.Alterations;
using Elsa.Persistence.EFCore.Modules.Identity;
using Elsa.Persistence.EFCore.Modules.Labels;
using Elsa.Persistence.EFCore.Modules.Management;
using Elsa.Persistence.EFCore.Modules.Runtime;
using Elsa.Persistence.EFCore.Modules.Tenants;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ElsaNext.EntityFrameworkCore;
[DependsOn(typeof(AbpElsaNextModule))]
public class AbpElsaNextEntityFrameworkCoreModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var labelFeature = context.Services.GetPreConfigureActions<EFCoreLabelPersistenceFeature>();
var alterationsFeature = context.Services.GetPreConfigureActions<EFCoreAlterationsPersistenceFeature>();
var workflowManagementFeature = context.Services.GetPreConfigureActions<WorkflowManagementPersistenceFeature>();
var workflowRuntimeFeature = context.Services.GetPreConfigureActions<EFCoreWorkflowRuntimePersistenceFeature>();
PreConfigure<IModule>(elsa =>
{
elsa.UseLabels(label =>
{
label.UseEntityFrameworkCore(efCore =>
{
labelFeature.Configure(efCore);
});
});
elsa.UseAlterations(alterations =>
{
alterations.UseEntityFrameworkCore(efCore =>
{
alterationsFeature.Configure(efCore);
});
});
elsa.UseWorkflowManagement(management =>
{
management.UseEntityFrameworkCore(efCore =>
{
workflowManagementFeature.Configure(efCore);
});
});
elsa.UseWorkflowRuntime(runtime =>
{
runtime.UseEntityFrameworkCore(efCore =>
{
workflowRuntimeFeature.Configure(efCore);
});
});
});
}
}

49
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/AbpElsaNextSecretsBlazorModule.cs

@ -0,0 +1,49 @@
using Elsa.Studio.Secrets.Extensions;
using LINGYUN.Abp.ElsaNext.Secrets.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.ElsaNext.Secrets.Blazor;
[DependsOn(
typeof(AbpElsaNextSecretsModule),
typeof(AbpElsaNextStudioBlazorModule))]
public class AbpElsaNextSecretsBlazorModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
Configure<AbpRouterOptions>(options =>
{
options.AdditionalAssemblies.Add(typeof(Elsa.Studio.Secrets.Feature).Assembly);
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new ElsaStudioSecretsMenuContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpElsaNextSecretsBlazorModule>("LINGYUN.Abp.ElsaNext.Secrets.Blazor");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<ElsaStudioResource>()
.AddVirtualJson("/Localization/Resources/SecretsBlazor");
});
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>();
context.Services.AddSecretsModule(elsaNextStudioBlazoeOptions.BackendApiConfig);
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

29
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/LINGYUN.Abp.ElsaNext.Secrets.Blazor.csproj

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.ElsaNext.Secrets.Blazor</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Secrets.Blazor</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup>
<ItemGroup>
<Content Remove="Localization\Resources\SecretsBlazor\*.json" />
<EmbeddedResource Include="Localization\Resources\SecretsBlazor\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Elsa.Studio.Secrets" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Secrets\LINGYUN.Abp.ElsaNext.Secrets.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
</ItemGroup>
</Project>

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/Localization/Resources/SecretsBlazor/en.json

@ -0,0 +1,7 @@
{
"culture": "en",
"texts": {
"Menu:Secrets": "Secrets",
"Secrets": "Secrets"
}
}

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/Localization/Resources/SecretsBlazor/zh-Hans.json

@ -0,0 +1,7 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:Secrets": "机密列表",
"Secrets": "机密列表"
}
}

28
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/Navigation/ElsaStudioSecretsMenuContributor.cs

@ -0,0 +1,28 @@
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using System.Threading.Tasks;
using Volo.Abp.UI.Navigation;
namespace LINGYUN.Abp.ElsaNext.Secrets.Blazor.Navigation;
public class ElsaStudioSecretsMenuContributor : IMenuContributor
{
public Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
var menu = context.Menu;
var l = context.GetLocalizer<ElsaStudioResource>();
var group = menu.GetMenuItemOrNull(ElsaStudioMenus.GroupName);
group?.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".Secrets",
l["Menu:Secrets"],
url: "/security/secrets",
icon: "fa fa-key",
order: 6));
}
return Task.CompletedTask;
}
}

5
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets.Blazor/_Imports.razor

@ -0,0 +1,5 @@
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Web
@using Elsa.Studio.Components
@using Elsa.Studio.Localization
@using MudBlazor

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

26
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/LINGYUN.Abp.ElsaNext.Secrets.csproj

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.ElsaNext.Secrets</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Secrets</PackageId>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa.Secrets" />
<PackageReference Include="Elsa.Secrets.JavaScript" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext\LINGYUN.Abp.ElsaNext.csproj" />
</ItemGroup>
</Project>

24
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Secrets/LINGYUN/Abp/ElsaNext/Secrets/AbpElsaNextSecretsModule.cs

@ -0,0 +1,24 @@
using Elsa.Extensions;
using Elsa.Features.Services;
using Microsoft.Extensions.Configuration;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ElsaNext.Secrets;
[DependsOn(
typeof(AbpElsaNextModule))]
public class AbpElsaNextSecretsModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa");
PreConfigure<IModule>(elsa =>
{
elsa.UseSecrets(secret =>
{
secret.ConfigureOptions = options => configuration.GetSection("Secrets").Bind(options);
});
elsa.UseSecretsJavaScript();
});
}
}

12
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Server/LINGYUN.Abp.ElsaNext.Server.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
@ -7,16 +7,20 @@
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.ElsaNext.Server</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Server</PackageId>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
<Nullable>Enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.CSharp" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Api.Common" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Dashboard.Api" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Expressions.CSharp" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Expressions.JavaScript" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Expressions.Liquid" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Http" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Scheduling" VersionOverride="$(ElsaNextPackageVersion)" />
<PackageReference Include="Elsa.Workflows.Api" VersionOverride="$(ElsaNextPackageVersion)" />
</ItemGroup>

36
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Server/LINGYUN/Abp/ElsaNext/Server/AbpElsaNextServerModule.cs

@ -1,5 +1,6 @@
using Elsa.Extensions;
using Elsa.Extensions;
using Elsa.Features.Services;
using Microsoft.Extensions.Configuration;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ElsaNext.Server;
@ -9,27 +10,40 @@ public class AbpElsaNextServerModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa");
PreConfigure<IModule>(elsa =>
{
// see: https://v3.elsaworkflows.io/docs/installation/elsa-server
// Expose Elsa API endpoints.
elsa.UseWorkflowsApi();
// Setup a SignalR hub for real-time updates from the server.
elsa.UseRealTimeWorkflows();
// Use timer activities.
elsa.UseScheduling();
// Enable C# workflow expressions
elsa.UseCSharp();
// Enable JavaScript workflow expressions.
elsa.UseJavaScript();
// Enable Liquid workflow expressions.
elsa.UseLiquid();
// Enable C# workflow expressions
elsa.UseCSharp();
// Enable HTTP activities.
elsa.UseHttp();
elsa.UseHttp(http =>
{
http.ConfigureHttpOptions = options => configuration.GetSection("Http").Bind(options);
});
// Use timer activities.
elsa.UseScheduling();
// Expose Elsa API endpoints.
elsa.UseWorkflowsApi();
// Operational dashboard API
elsa.UseDashboardApi();
if (configuration["Server:EnableRealTimeWorkflows"] != "false")
{
elsa.UseRealTimeWorkflows();
}
// Register custom activities from the application, if any.
elsa.AddActivitiesFrom<AbpElsaNextServerModule>();

97
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs

@ -0,0 +1,97 @@
using Elsa.Studio.Core.BlazorServer.Extensions;
using Elsa.Studio.Extensions;
using Elsa.Studio.Localization.BlazorServer.Extensions;
using Elsa.Studio.Localization.Models;
using Elsa.Studio.Models;
using Elsa.Studio.Settings.Extensions;
using Elsa.Studio.Shell.Extensions;
using Elsa.Studio.Workflows.Designer.Options;
using Elsa.Studio.Workflows.Extensions;
using LINGYUN.Abp.ElsaNext.Localization;
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor;
[DependsOn(
typeof(AbpElsaNextModule),
typeof(AbpElsaNextStudioTranslationsModule),
typeof(AbpLocalizationModule),
typeof(AbpUiNavigationModule),
typeof(AbpVirtualFileSystemModule),
typeof(AbpAspNetCoreComponentsWebThemingMudBlazorModule))]
public class AbpElsaNextStudioBlazorModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
PreConfigure<AbpElsaNextStudioBlazorOptions>(options =>
{
options.BackendApiConfig = new BackendApiConfig
{
ConfigureBackendOptions = backend => configuration.GetSection("Backend").Bind(backend),
};
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new ElsaStudioMenuContributor());
});
Configure<AbpRouterOptions>(options =>
{
options.AdditionalAssemblies.Add(typeof(Elsa.Studio.Settings.Feature).Assembly);
options.AdditionalAssemblies.Add(typeof(Elsa.Studio.Workflows.Feature).Assembly);
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpElsaNextStudioBlazorModule>("LINGYUN.Abp.ElsaNext.Studio.Blazor");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<ElsaStudioResource>()
.AddBaseTypes(typeof(ElsaNextResource))
.AddVirtualJson("/Localization/Resources/ElsaStudioBlazor");
});
context.Services.AddCore(options => configuration.GetSection("Presentation").Bind(options));
context.Services.AddShell(options => configuration.GetSection("Shell").Bind(options));
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>();
context.Services.AddRemoteBackend(elsaNextStudioBlazoeOptions.BackendApiConfig);
context.Services.AddWorkflowsModule();
context.Services.AddSettingsModule();
Configure<DesignerOptions>(configuration.GetSection("DesignerOptions"));
var abpLocalizationOptions = context.Services.ExecutePreConfiguredActions<AbpLocalizationOptions>();
context.Services.AddLocalizationModule(new LocalizationConfig
{
ConfigureLocalizationOptions = options =>
{
options.SupportedCultures = abpLocalizationOptions.Languages.Select(x => x.CultureName).ToArray();
}
});
context.Services.AddElsaStudioTranslations();
}
}

12
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorOptions.cs

@ -0,0 +1,12 @@
using Elsa.Studio.Models;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor;
public class AbpElsaNextStudioBlazorOptions
{
public BackendApiConfig BackendApiConfig { get; set; }
public AbpElsaNextStudioBlazorOptions()
{
BackendApiConfig = new BackendApiConfig();
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

43
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj

@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>LINGYUN.Abp.ElsaNext.Studio.Blazor</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Studio.Blazor</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Localization" />
<PackageReference Include="Volo.Abp.UI.Navigation" />
<PackageReference Include="Volo.Abp.VirtualFileSystem" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext\LINGYUN.Abp.ElsaNext.csproj" />
<!-- ABP-hosted Elsa Studio UI copy (en/zh-Hans) + Elsa ILocalizationProvider bridge. -->
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Translations\LINGYUN.Abp.ElsaNext.Studio.Translations.csproj" />
</ItemGroup>
<ItemGroup>
<!-- Elsa Studio, Blazor Server hosting pieces (Elsa.Studio 3.8.0-rc2). -->
<PackageReference Include="Elsa.Studio.Core.BlazorServer" />
<PackageReference Include="Elsa.Studio.Settings" />
<PackageReference Include="Elsa.Studio.Shell" />
<PackageReference Include="Elsa.Studio.Workflows" />
<PackageReference Include="Elsa.Studio.Workflows.Designer" />
<PackageReference Include="Elsa.Api.Client" />
<PackageReference Include="Elsa.Studio.Authentication.Abstractions" />
<PackageReference Include="Elsa.Studio.Localization.BlazorServer" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\**\*.json" />
</ItemGroup>
</Project>

9
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json

@ -0,0 +1,9 @@
{
"culture": "en",
"texts": {
"Menu:ElsaStudio": "Elsa Studio",
"Menu:WorkflowDefinitions": "Workflow Definitions",
"Menu:WorkflowInstances": "Workflow Instances",
"Menu:Settings": "Settings"
}
}

9
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json

@ -0,0 +1,9 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:ElsaStudio": "Elsa 工作室",
"Menu:WorkflowDefinitions": "工作流定义",
"Menu:WorkflowInstances": "工作流实例",
"Menu:Settings": "设置"
}
}

49
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Navigation/ElsaStudioMenuContributor.cs

@ -0,0 +1,49 @@
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Volo.Abp.UI.Navigation;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
public class ElsaStudioMenuContributor : IMenuContributor
{
public Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
AddStudioMenu(context);
}
return Task.CompletedTask;
}
private static void AddStudioMenu(MenuConfigurationContext context)
{
var l = context.GetLocalizer<ElsaStudioResource>();
var elsaStudioMenu = new ApplicationMenuItem(
ElsaStudioMenus.GroupName,
l["Menu:ElsaStudio"],
icon: "fa fa-diagram-project");
elsaStudioMenu.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".WorkflowDefinitions",
l["Menu:WorkflowDefinitions"],
url: "/workflows/definitions",
icon: "fa fa-list",
order: 1));
elsaStudioMenu.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".WorkflowInstances",
l["Menu:WorkflowInstances"],
url: "/workflows/instances",
icon: "fa fa-cogs",
order: 2));
elsaStudioMenu.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".Settings",
l["Menu:Settings"],
url: "/settings",
icon: "fa fa-gear",
order: 99));
context.Menu.AddItem(elsaStudioMenu);
}
}

6
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Navigation/ElsaStudioMenus.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
public static class ElsaStudioMenus
{
public const string GroupName = "ElsaStudio";
}

26
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Properties/launchSettings.json

@ -0,0 +1,26 @@
{
"iisSettings": {
"iisExpress": {
"applicationUrl": "http://localhost:34746",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5130",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

12
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor

@ -0,0 +1,12 @@
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using MudBlazor
@using Elsa.Studio.Components
@using Elsa.Studio.Workflows.Components.WorkflowDefinitionEditor
@using Elsa.Studio.Workflows.Components.WorkflowInstanceViewer
@using Elsa.Studio.Workflows.Components.WorkflowDefinitionList
@using Elsa.Studio.Workflows.Components.WorkflowInstanceList

61
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/AbpElsaNextStudioDashboardBlazorModule.cs

@ -0,0 +1,61 @@
using Elsa.Extensions;
using Elsa.Features.Services;
using Elsa.Studio.Dashboard.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor;
[DependsOn(typeof(AbpElsaNextStudioBlazorModule))]
public class AbpElsaNextStudioDashboardBlazorModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IModule>(elsa =>
{
elsa.UseWorkflowRuntimeDashboard();
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
Configure<AbpRouterOptions>(options =>
{
options.AdditionalAssemblies.Add(typeof(AbpElsaNextStudioDashboardBlazorModule).Assembly);
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new ElsaStudioDashboardMenuContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpElsaNextStudioDashboardBlazorModule>("LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<ElsaStudioResource>()
.AddVirtualJson("/Localization/Resources/ElsaStudioDashboardBlazor");
});
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>();
context.Services.AddDashboardModule(elsaNextStudioBlazoeOptions.BackendApiConfig);
context.Services.AddDashboardWidgets();
context.Services.AddScoped<ElsaStudioDashboardText>();
}
}

18
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Extensions/DashboardWidgetServiceCollectionExtensions.cs

@ -0,0 +1,18 @@
using Elsa.Studio.Dashboard.Widgets;
using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Widgets;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Extensions;
public static class DashboardWidgetServiceCollectionExtensions
{
public static IServiceCollection AddDashboardWidgets(this IServiceCollection services)
{
return services
.AddDashboardWidget<OperationalHealthWidget>("dashboard.workflow.metrics", DashboardWidgetZones.Metrics, 100, "Workflow metrics", payloadKind: "WorkflowInstances")
.AddDashboardWidget<NeedsAttentionWidget>("dashboard.needs-attention", DashboardWidgetZones.Findings, 100, "Needs attention")
.AddDashboardWidget<ExecutionTrendWidget>("dashboard.workflow.trend", DashboardWidgetZones.Trend, 100, "Workflow trends", payloadKind: "WorkflowTrends")
.AddDashboardWidget<RecentActivityWidget>("dashboard.workflow.recent-activity", DashboardWidgetZones.Activity, 100, "Recent activity", payloadKind: "RecentActivity")
.AddDashboardWidget<HotspotsWidget>("dashboard.workflow.hotspots", DashboardWidgetZones.SecondaryPanels, 100, "Workflow hotspots", payloadKind: "WorkflowHotspots");
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

31
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.csproj

@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor</PackageId>
</PropertyGroup>
<ItemGroup>
<!-- Elsa Studio Dashboard (official, rc2): page shell, zones, models and API client. The
workflow widgets are re-implemented in this module (Widgets/) as localized copies. -->
<PackageReference Include="Elsa.Studio.Dashboard" />
<!-- 使用自定义仪表板组件 -->
<!--<PackageReference Include="Elsa.Studio.Workflows.Dashboard" />-->
<PackageReference Include="Elsa.Workflows.Runtime.Dashboard" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\**\*.json" />
</ItemGroup>
</Project>

6
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Localization/Resources/ElsaStudioDashboardBlazor/en.json

@ -0,0 +1,6 @@
{
"culture": "en",
"texts": {
"Menu:Dashboard": "Dashboard"
}
}

6
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Localization/Resources/ElsaStudioDashboardBlazor/zh-Hans.json

@ -0,0 +1,6 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:Dashboard": "仪表盘"
}
}

31
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Navigation/ElsaStudioDashboardMenuContributor.cs

@ -0,0 +1,31 @@
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Volo.Abp.UI.Navigation;
namespace LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Navigation;
/// <summary>
/// Adds the dashboard page to the "ElsaStudio" menu group (created by the Studio.Blazor module;
/// created here too when absent so this module stays self-contained).
/// </summary>
public class ElsaStudioDashboardMenuContributor : IMenuContributor
{
public Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
var menu = context.Menu;
var l = context.GetLocalizer<ElsaStudioResource>();
var group = menu.GetMenuItemOrNull(ElsaStudioMenus.GroupName);
group?.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".Dashboard",
l["Menu:Dashboard"],
url: "/dashboard",
icon: "fa fa-chart-line",
order: 0));
}
return Task.CompletedTask;
}
}

92
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Pages/Dashboard.razor

@ -0,0 +1,92 @@
@page "/dashboard"
@attribute [Authorize]
@inherits StudioComponentBase
@inject ILocalizer Localizer
<HeadContent>
<link rel="stylesheet" href="_content/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/dashboard.css" />
</HeadContent>
<PageTitle>@Localizer["Dashboard"]</PageTitle>
<MudContainer MaxWidth="MaxWidth.False" Class="dashboard-shell" Style="@DashboardStyles.Shell">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="dashboard-header" Spacing="3" Style="@DashboardStyles.Header">
<MudStack Spacing="1">
<MudText Typo="Typo.h4">@Localizer["Dashboard"]</MudText>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Class="flex-wrap">
<MudText Typo="Typo.body2" Class="dashboard-muted">@BackendLabel</MudText>
@if (_snapshot != null)
{
var runtime = _snapshot.Overview.Runtime.Status;
<MudChip T="string" Size="Size.Small" Variant="Variant.Filled" Color="@DashboardUiMapper.RuntimeColor(runtime)" Icon="@Icons.Material.Outlined.Circle">@Text.RuntimeStatusLabel(runtime)</MudChip>
}
else
{
<MudChip T="string" Size="Size.Small" Variant="Variant.Filled" Color="Color.Error" Icon="@Icons.Material.Outlined.CloudOff">@StatusLabel</MudChip>
}
<MudText Typo="Typo.caption" Class="dashboard-muted">@LastRefreshedLabel</MudText>
</MudStack>
</MudStack>
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.FlexEnd" Spacing="1" Class="flex-wrap">
<MudToggleGroup T="string" Value="@_selectedRange" ValueChanged="OnRangeChangedAsync" Color="Color.Primary" SelectionMode="SelectionMode.SingleSelection" Size="Size.Small">
@foreach (var option in DashboardRangeMapper.Options)
{
<MudToggleItem T="string" Value="@option.Value">@option.Label</MudToggleItem>
}
</MudToggleGroup>
<MudTooltip Text="@Localizer["Refresh dashboard"]" Delay="400">
<MudIconButton Icon="@Icons.Material.Outlined.Refresh" Color="Color.Primary" Disabled="@_loading" OnClick="RefreshAsync" aria-label="Refresh dashboard" />
</MudTooltip>
</MudStack>
</MudStack>
@if (!string.IsNullOrWhiteSpace(_message))
{
<MudAlert Severity="@AlertSeverity" Dense="true" Class="mb-4">@_message</MudAlert>
}
@if (_loading && _snapshot == null)
{
<MudGrid Spacing="2" Class="mb-4">
@for (var i = 0; i < 6; i++)
{
<MudItem xs="12" sm="6" md="4" xl="2">
<MudSkeleton Height="112px" Animation="Animation.Wave" />
</MudItem>
}
</MudGrid>
<MudSkeleton Height="360px" Animation="Animation.Wave" />
}
else if (_snapshot == null)
{
<MudPaper Outlined="true" Elevation="0" Class="dashboard-panel dashboard-empty-state" Style="@DashboardStyles.EmptyPanel">
<MudIcon Icon="@Icons.Material.Outlined.DashboardCustomize" Color="Color.Default" />
<MudText Typo="Typo.h6">@StatusLabel</MudText>
<MudText Typo="Typo.body2" Class="dashboard-muted">@(_message ?? @Localizer["Dashboard data is unavailable from the selected backend."])</MudText>
</MudPaper>
}
else
{
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.Metrics)" Context="@WidgetContext" />
<MudStack Spacing="2" Class="dashboard-main-stack">
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.Trend)" Context="@WidgetContext" />
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.PrimaryPanels)" Context="@WidgetContext" />
<MudGrid Spacing="2" Class="dashboard-activity-grid">
<MudItem xs="12" lg="8">
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.Activity)" Context="@WidgetContext" />
</MudItem>
<MudItem xs="12" lg="4">
<MudStack Spacing="2">
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.Findings)" Context="@WidgetContext" />
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.SecondaryPanels)" Context="@WidgetContext" />
</MudStack>
</MudItem>
</MudGrid>
<DashboardWidgetZone Widgets="@GetWidgets(DashboardWidgetZones.DiagnosticsStatus)" Context="@WidgetContext" Class="dashboard-diagnostics-grid" ItemClass="dashboard-diagnostics-grid-item" />
</MudStack>
}
</MudContainer>

211
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Pages/Dashboard.razor.cs

@ -0,0 +1,211 @@
using Elsa.Studio.Contracts;
using Elsa.Studio.Dashboard.Models;
using Elsa.Studio.Dashboard.Services;
using Elsa.Studio.Dashboard.Widgets;
using Elsa.Studio.Localization;
using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Pages;
/// <summary>
/// Elsa Studio dashboard page (official Elsa.Studio.Dashboard content hosted under
/// <c>/elsa/workflows/dashboard</c>). The dashboard service reads the Elsa dashboard API with the
/// circuit session token; the widgets (metrics/trend/activity/...) come from the official
/// dashboard modules.
/// </summary>
public partial class Dashboard : IAsyncDisposable
{
private CancellationTokenSource? _loadCancellationTokenSource;
private DashboardSnapshot? _snapshot;
private DashboardLoadStatus _status = DashboardLoadStatus.Unavailable;
private string _selectedRange = DashboardRangeKeys.TwentyFourHours;
private string? _message;
private bool _loading;
private bool _disposed;
private bool _subscribedToFeatureInitialized;
private DateTimeOffset? _lastRefreshedAt;
[Inject] private IDashboardService DashboardService { get; set; } = null!;
[Inject] private IDashboardWidgetRegistry WidgetRegistry { get; set; } = null!;
[Inject] private IEnumerable<DashboardWidgetDescriptor> Widgets { get; set; } = [];
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
[Inject] private IFeatureService FeatureService { get; set; } = null!;
[Inject] private ElsaStudioDashboardText Text { get; set; } = null!;
private DashboardWidgetContext WidgetContext => new(
_selectedRange,
_loading,
_lastRefreshedAt,
_status,
_message,
_snapshot,
RefreshAsync,
NavigationManager);
private string BackendLabel
{
get
{
if (_snapshot == null)
return Localizer["Selected backend"];
var overview = _snapshot.Overview;
var backendName = string.IsNullOrWhiteSpace(overview.BackendName) ? Localizer["Backend"] : overview.BackendName;
return string.IsNullOrWhiteSpace(overview.EnvironmentName) ? backendName : $"{backendName} / {overview.EnvironmentName}";
}
}
private string LastRefreshedLabel => _lastRefreshedAt == null ? Localizer["Not refreshed yet"] : $"{Localizer["Refreshed"]} {Text.RelativeTimestamp(_lastRefreshedAt)}";
private string StatusLabel => _status switch
{
DashboardLoadStatus.Unauthorized => Localizer["No access"],
DashboardLoadStatus.BackendDisconnected => Localizer["Backend disconnected"],
DashboardLoadStatus.Failed => Localizer["Refresh failed"],
DashboardLoadStatus.Loaded => Localizer["Loaded"],
_ => Localizer["Dashboard unavailable"]
};
private Severity AlertSeverity => _status switch
{
DashboardLoadStatus.Unauthorized => Severity.Warning,
DashboardLoadStatus.Loaded => Severity.Info,
_ => Severity.Error
};
private IReadOnlyCollection<DashboardWidgetDescriptor> GetWidgets(string zone) =>
Widgets
.Concat(WidgetRegistry.List())
.DistinctBy(x => x.Id)
.Where(x => x.Zone == zone && x.IsVisible(WidgetContext))
.OrderBy(x => x.Order)
.ThenBy(x => x.Id, StringComparer.Ordinal)
.ToList();
protected override async Task OnInitializedAsync()
{
// Features register their widgets into the (singleton) widget registry during
// InitializeFeaturesAsync; the official host triggers this from its own startup tasks, so
// do it here to be safe when hosting the page standalone in an ABP layout.
try
{
await FeatureService.InitializeFeaturesAsync();
}
catch (Exception)
{
// Remote feature discovery is unavailable (e.g. backend feature API down); the page
// still renders the DI-registered widgets.
}
await RefreshAsync();
}
protected override void OnAfterRender(bool firstRender)
{
if (!firstRender || _disposed)
return;
FeatureService.Initialized += OnFeatureServiceInitialized;
_subscribedToFeatureInitialized = true;
}
private void OnFeatureServiceInitialized()
{
_ = RefreshWidgetsAfterFeatureInitializationAsync();
}
private async Task RefreshWidgetsAfterFeatureInitializationAsync()
{
if (_disposed)
return;
try
{
await InvokeAsync(StateHasChanged);
}
catch (InvalidOperationException) when (_disposed)
{
}
}
private async Task OnRangeChangedAsync(string? range)
{
var selectedRange = DashboardRangeMapper.Normalize(range);
if (_selectedRange == selectedRange)
return;
_selectedRange = selectedRange;
await RefreshAsync();
}
private async Task RefreshAsync()
{
await LoadAsync(_selectedRange);
}
private async Task LoadAsync(string range)
{
await CancelCurrentLoadAsync();
var cancellationTokenSource = new CancellationTokenSource();
_loadCancellationTokenSource = cancellationTokenSource;
_loading = true;
_message = null;
try
{
var result = await DashboardService.LoadAsync(range, cancellationToken: cancellationTokenSource.Token);
_status = result.Status;
if (result.Snapshot != null)
{
_snapshot = result.Snapshot;
_lastRefreshedAt = DateTimeOffset.UtcNow;
_message = null;
}
else
{
_message = result.Message;
}
}
catch (OperationCanceledException) when (cancellationTokenSource.IsCancellationRequested)
{
}
catch (Exception e)
{
_status = DashboardLoadStatus.Failed;
_message = e.Message;
}
finally
{
if (ReferenceEquals(_loadCancellationTokenSource, cancellationTokenSource))
{
_loading = false;
_loadCancellationTokenSource = null;
}
cancellationTokenSource.Dispose();
}
}
private async Task CancelCurrentLoadAsync()
{
if (_loadCancellationTokenSource == null)
return;
await _loadCancellationTokenSource.CancelAsync();
_loadCancellationTokenSource = null;
}
public async ValueTask DisposeAsync()
{
_disposed = true;
if (_subscribedToFeatureInitialized)
FeatureService.Initialized -= OnFeatureServiceInitialized;
await CancelCurrentLoadAsync();
}
}

120
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Services/ElsaStudioDashboardText.cs

@ -0,0 +1,120 @@
using Elsa.Studio.Dashboard.Models;
using Elsa.Studio.Localization;
using LINGYUN.Abp.ElsaNext.Studio.Translations;
using System.Globalization;
namespace LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services;
/// <summary>
/// Culture-aware text and metric formatting for the dashboard widgets. The official Elsa Studio
/// dashboard widgets hard-code their English copy and format numbers with the ambient thread
/// culture, so this module renders localized copies that resolve every label through
/// <see cref="ILocalizer"/> (which follows the ABP UI culture captured on the circuit) and format
/// numbers with that same culture.
/// </summary>
public class ElsaStudioDashboardText
{
private readonly ILocalizer _localizer;
public ElsaStudioDashboardText(ILocalizer localizer)
{
_localizer = localizer;
}
/// <summary>The UI culture captured at prerender (fallback: current thread culture).</summary>
public CultureInfo Culture => CultureInfo.CurrentUICulture;
/// <summary>Localized text for the given key (falls back to the key itself).</summary>
public string this[string key] => _localizer[key];
/// <summary>Localized capability label of the "needs attention" backend capability.</summary>
public string CapabilityLabel(DashboardCapabilityStatus? capability)
{
return capability?.Status switch
{
"Available" => _localizer["Available"],
"Unauthorized" => _localizer["No access"],
"NotInstalled" => _localizer["Not installed"],
_ => _localizer["Unavailable"]
};
}
/// <summary>Localized label of the runtime status chip shown in the dashboard header.</summary>
public string RuntimeStatusLabel(string? status)
{
return status switch
{
DashboardRuntimeStatusKeys.AcceptingWork => _localizer["Accepting work"],
DashboardRuntimeStatusKeys.Paused => _localizer["Paused"],
DashboardRuntimeStatusKeys.Draining => _localizer["Draining"],
_ => _localizer["Unavailable"]
};
}
/// <summary>Humanized caption for the selected dashboard range.</summary>
public string RangeCaption(string selectedRange)
{
return selectedRange switch
{
DashboardRangeKeys.OneHour => _localizer["Last hour"],
DashboardRangeKeys.SevenDays => _localizer["Last 7 days"],
_ => _localizer["Last 24 hours"]
};
}
public string Count(long value) => value.ToString("N0", Culture);
public string Count(int value) => Count((long)value);
public string Duration(TimeSpan? value)
{
if (value == null)
return "N/A";
var duration = value.Value;
if (duration.TotalMilliseconds < 1000)
return $"{duration.TotalMilliseconds:N0} ms";
if (duration.TotalMinutes < 1)
return $"{duration.TotalSeconds:N1} s";
if (duration.TotalHours < 1)
return $"{duration.TotalMinutes:N1} min";
return $"{duration.TotalHours:N1} h";
}
public string DateTime(DateTimeOffset? value)
{
return value == null ? "N/A" : value.Value.ToLocalTime().ToString("g", Culture);
}
public string RelativeTimestamp(DateTimeOffset? value)
{
if (value == null)
return "N/A";
var elapsed = DateTimeOffset.UtcNow - value.Value.ToUniversalTime();
if (elapsed.TotalSeconds < 60)
return _localizer["Just now"];
if (elapsed.TotalMinutes < 60)
return $"{elapsed.TotalMinutes:N0} {_localizer["min ago"]}";
if (elapsed.TotalHours < 24)
return $"{elapsed.TotalHours:N0} {_localizer["h ago"]}";
return $"{elapsed.TotalDays:N0} {_localizer["d ago"]}";
}
/// <summary>Trend chart x-axis label for a bucket timestamp.</summary>
public string TrendLabel(DateTimeOffset value, string granularity)
{
var local = value.ToLocalTime();
return granularity == DashboardTrendGranularity.Day
? local.ToString(Culture.Name.StartsWith("zh", StringComparison.OrdinalIgnoreCase) ? "M月d日" : "MMM d", Culture)
: local.ToString("HH:mm", Culture);
}
}

59
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/ExecutionTrendWidget.razor

@ -0,0 +1,59 @@
@using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services
@inject ElsaStudioDashboardText Text
@if (Context.Snapshot != null)
{
var response = Context.Snapshot.Trend;
<MudPaper Outlined="true" Elevation="0" Class="dashboard-panel dashboard-section dashboard-chart-panel" Style="@DashboardStyles.ChartPanel">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="dashboard-section-header" Style="@DashboardStyles.SectionHeader">
<MudText Typo="Typo.subtitle1">@Text["Execution trend"]</MudText>
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.FlexEnd" Spacing="1" Class="dashboard-trend-actions" Style="@DashboardStyles.TrendActions">
<MudText Typo="Typo.caption" Class="dashboard-muted">@RangeCaption(response)</MudText>
</MudStack>
</MudStack>
@if (Context.Loading)
{
<MudSkeleton Height="220px" Animation="Animation.Wave" />
}
else if (response.Buckets.Count == 0)
{
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Text">@Text["No workflow activity in this range."]</MudAlert>
}
else
{
<div class="dashboard-trend-chart-frame">
<MudChart T="double"
Class="dashboard-trend-chart"
ChartType="ChartType.Line"
ChartSeries="@Series(response)"
ChartLabels="@Labels(response)"
Width="100%"
Height="220px"
MatchBoundsToSize="true" />
</div>
}
</MudPaper>
}
@code {
[Parameter] public DashboardWidgetContext Context { get; set; } = null!;
[Parameter] public DashboardWidgetDescriptor Descriptor { get; set; } = null!;
private string RangeCaption(DashboardTrendResponse response) =>
$"{Text.DateTime(response.From)} - {Text.DateTime(response.To)}";
private string[] Labels(DashboardTrendResponse response) => response.Buckets
.Select(x => Text.TrendLabel(x.From, response.Granularity))
.ToArray();
private List<ChartSeries<double>> Series(DashboardTrendResponse response) =>
[
new() { Name = Text["Started"], Data = response.Buckets.Select(x => (double)x.CreatedOrStarted).ToArray() },
new() { Name = Text["Finished"], Data = response.Buckets.Select(x => (double)x.Finished).ToArray() },
new() { Name = Text["Faulted"], Data = response.Buckets.Select(x => (double)x.Faulted).ToArray() },
new() { Name = Text["Suspended"], Data = response.Buckets.Select(x => (double)x.Suspended).ToArray() }
];
}

49
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/HotspotsWidget.razor

@ -0,0 +1,49 @@
@using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services
@inject ElsaStudioDashboardText Text
@if (Context.Snapshot?.Hotspots != null)
{
var response = Context.Snapshot.Hotspots;
<MudPaper Outlined="true" Elevation="0" Class="dashboard-panel dashboard-section" Style="@DashboardStyles.Panel">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="dashboard-section-header" Style="@DashboardStyles.SectionHeader">
<MudText Typo="Typo.subtitle1">@Text["Workflow hotspots"]</MudText>
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined">@MetricLabel(response.Metric)</MudChip>
</MudStack>
@if (response.Items.Count == 0)
{
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Text">@Text["No hotspots in this range."]</MudAlert>
}
else
{
<MudTable T="DashboardHotspot" Items="@response.Items" Dense="true" Hover="true" Elevation="0" Breakpoint="Breakpoint.Sm">
<HeaderContent>
<MudTh>@Text["Workflow"]</MudTh>
<MudTh>@Text["Value"]</MudTh>
<MudTh>@Text["Avg duration"]</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="@Text["Workflow"]">
<MudStack Spacing="0">
<MudText Typo="Typo.body2">@DisplayName(context)</MudText>
<MudText Typo="Typo.caption" Class="dashboard-muted">@context.DefinitionId</MudText>
</MudStack>
</MudTd>
<MudTd DataLabel="@Text["Value"]">@Text.Count(context.Value)</MudTd>
<MudTd DataLabel="@Text["Avg duration"]">@Text.Duration(context.AverageDuration)</MudTd>
</RowTemplate>
</MudTable>
}
</MudPaper>
}
@code {
[Parameter] public DashboardWidgetContext Context { get; set; } = null!;
[Parameter] public DashboardWidgetDescriptor Descriptor { get; set; } = null!;
private string MetricLabel(string? metric) => string.IsNullOrWhiteSpace(metric) ? string.Empty : Text[metric];
private static string DisplayName(DashboardHotspot item) => string.IsNullOrWhiteSpace(item.WorkflowName) ? item.DefinitionId : item.WorkflowName!;
}

42
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/NeedsAttentionWidget.razor

@ -0,0 +1,42 @@
@using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services
@inject ElsaStudioDashboardText Text
@if (Context.Snapshot != null)
{
var findings = Context.Snapshot.NeedsAttention.Findings;
var capability = Context.Snapshot.NeedsAttention.Capability;
<MudPaper Outlined="true" Elevation="0" Class="dashboard-panel dashboard-section" Style="@DashboardStyles.Panel">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="dashboard-section-header" Style="@DashboardStyles.SectionHeader">
<MudText Typo="Typo.subtitle1">@Text["Needs attention"]</MudText>
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined" Color="@DashboardUiMapper.CapabilityColor(capability)">@Text.CapabilityLabel(capability)</MudChip>
</MudStack>
@if (findings.Count == 0)
{
<MudAlert Severity="Severity.Success" Dense="true" Variant="Variant.Text" Icon="@Icons.Material.Outlined.CheckCircle">
@Text["No active findings in the selected range."]
</MudAlert>
}
else
{
<MudList T="DashboardFinding" Dense="true" Class="dashboard-finding-list" Style="@DashboardStyles.FindingList">
@foreach (var item in findings.OrderBy(x => x.Priority).Take(8))
{
<MudListItem T="DashboardFinding" Value="@item" Icon="@DashboardUiMapper.SeverityIcon(item.Severity)" IconColor="@DashboardUiMapper.SeverityColor(item.Severity)">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="2" Class="dashboard-finding-row" Style="@DashboardStyles.FindingRow">
<MudText Typo="Typo.body2">@item.Message</MudText>
<MudChip T="string" Size="Size.Small" Variant="Variant.Text" Color="@DashboardUiMapper.SeverityColor(item.Severity)">@item.Severity</MudChip>
</MudStack>
</MudListItem>
}
</MudList>
}
</MudPaper>
}
@code {
[Parameter] public DashboardWidgetContext Context { get; set; } = null!;
[Parameter] public DashboardWidgetDescriptor Descriptor { get; set; } = null!;
}

46
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/OperationalHealthWidget.razor

@ -0,0 +1,46 @@
@using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services
@inject ElsaStudioDashboardText Text
@if (Context.Snapshot != null)
{
var metrics = Context.Snapshot.Overview.WorkflowInstances;
var healthMetrics = new[]
{
new HealthMetric(Text["Running"], Text.Count(metrics.Running), Text["Current active instances"], Icons.Material.Outlined.PlayCircle, Color.Info),
new HealthMetric(Text["Completed"], Text.Count(metrics.Completed), Text.RangeCaption(Context.SelectedRange), Icons.Material.Outlined.CheckCircle, Color.Success),
new HealthMetric(Text["Faulted"], Text.Count(metrics.Faulted), Text.RangeCaption(Context.SelectedRange), Icons.Material.Outlined.ErrorOutline, metrics.Faulted > 0 ? Color.Error : Color.Default),
new HealthMetric(Text["Suspended"], Text.Count(metrics.Suspended), Text["Current suspended instances"], Icons.Material.Outlined.PauseCircle, metrics.Suspended > 0 ? Color.Warning : Color.Default),
new HealthMetric(Text["Avg duration"], Text.Duration(metrics.AverageDuration), Text.RangeCaption(Context.SelectedRange), Icons.Material.Outlined.Timer, Color.Default),
new HealthMetric(Text["Needs attention"], Text.Count(Context.Snapshot.NeedsAttention.Findings.Count), Text["Prioritized findings"], Icons.Material.Outlined.ReportProblem, Context.Snapshot.NeedsAttention.Findings.Count > 0 ? Color.Warning : Color.Success)
};
<div class="dashboard-operational-health">
<MudText Typo="Typo.subtitle1" Class="dashboard-operational-health-heading">@Text["Operational health"]</MudText>
<div class="dashboard-operational-health-metrics">
@foreach (var metric in healthMetrics)
{
<div class="dashboard-operational-health-metric">
@MetricContent(metric)
</div>
}
</div>
</div>
}
@code {
[Parameter] public DashboardWidgetContext Context { get; set; } = null!;
[Parameter] public DashboardWidgetDescriptor Descriptor { get; set; } = null!;
private RenderFragment<HealthMetric> MetricContent => metric => @<text>
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="2">
<MudText Typo="Typo.overline">@metric.Label</MudText>
<MudIcon Icon="@metric.Icon" Size="Size.Small" Color="@metric.Color" />
</MudStack>
<MudText Typo="Typo.h5" Color="@metric.Color" Class="dashboard-operational-health-value">@metric.Value</MudText>
<MudText Typo="Typo.caption" Class="dashboard-operational-health-caption">@metric.Caption</MudText>
</text>;
private sealed record HealthMetric(string Label, string Value, string Caption, string Icon, Color Color);
}

101
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/Widgets/RecentActivityWidget.razor

@ -0,0 +1,101 @@
@using LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor.Services
@inject NavigationManager NavigationManager
@inject ElsaStudioDashboardText Text
@if (Context.Snapshot != null)
{
var items = Context.Snapshot.RecentActivity.Items;
<MudPaper Outlined="true" Elevation="0" Class="dashboard-panel dashboard-section" Style="@DashboardStyles.Panel">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="dashboard-section-header" Style="@DashboardStyles.SectionHeader">
<MudText Typo="Typo.subtitle1">@Text["Recent workflow activity"]</MudText>
<MudText Typo="Typo.caption" Class="dashboard-muted">@items.Count @(items.Count == 1 ? Text["item"] : Text["items"])</MudText>
</MudStack>
<MudTable T="DashboardRecentActivityItem" Items="@items" Dense="true" Hover="true" Elevation="0" Breakpoint="Breakpoint.Sm" RowClassFunc="GetRowClass" OnRowClick="OnRowClick">
<HeaderContent>
<MudTh>@Text["Workflow / instance"]</MudTh>
<MudTh>@Text["Status"]</MudTh>
<MudTh>@Text["Sub status"]</MudTh>
<MudTh>@Text["Incidents"]</MudTh>
<MudTh>@Text["Duration"]</MudTh>
<MudTh>@Text["Updated"]</MudTh>
<MudTh></MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="@Text["Workflow / instance"]">
<MudStack Spacing="0">
<MudText Typo="Typo.body2">@DisplayName(context)</MudText>
<MudText Typo="Typo.caption" Class="dashboard-muted">@context.InstanceId</MudText>
</MudStack>
</MudTd>
<MudTd DataLabel="@Text["Status"]">
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined" Color="@StatusColor(context.Status)">@LocalizedStatus(context.Status)</MudChip>
</MudTd>
<MudTd DataLabel="@Text["Sub status"]">
<MudChip T="string" Size="Size.Small" Variant="Variant.Text" Color="@SubStatusColor(context.SubStatus)">@LocalizedStatus(context.SubStatus)</MudChip>
</MudTd>
<MudTd DataLabel="@Text["Incidents"]">@Text.Count(context.IncidentCount)</MudTd>
<MudTd DataLabel="@Text["Duration"]">@Text.Duration(context.Duration)</MudTd>
<MudTd DataLabel="@Text["Updated"]">@Text.RelativeTimestamp(context.UpdatedAt ?? context.FinishedAt ?? context.CreatedAt)</MudTd>
<MudTd>
<MudTooltip Text="@Text["Open workflow instance"]">
<MudIconButton Icon="@Icons.Material.Outlined.OpenInNew" Size="Size.Small" Href="@InstanceUrl(context)" aria-label="@($"{Text["Open workflow instance"]} {context.InstanceId}")" />
</MudTooltip>
</MudTd>
</RowTemplate>
<NoRecordsContent>
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Text">@Text["No workflow instances changed in this range."]</MudAlert>
</NoRecordsContent>
</MudTable>
</MudPaper>
}
@code {
[Parameter] public DashboardWidgetContext Context { get; set; } = null!;
[Parameter] public DashboardWidgetDescriptor Descriptor { get; set; } = null!;
private void OnRowClick(TableRowClickEventArgs<DashboardRecentActivityItem> args)
{
if (args.Item == null)
return;
NavigationManager.NavigateTo(InstanceUrl(args.Item));
}
// Official deep links target the standalone Studio host routes; this ABP host hosts the
// instance viewer at /elsa/workflows/instances/{id}, so build that link directly.
private static string InstanceUrl(DashboardRecentActivityItem item) => $"workflows/instances/{item.InstanceId}";
private string LocalizedStatus(string? status) => string.IsNullOrWhiteSpace(status) ? string.Empty : Text[status];
private static string DisplayName(DashboardRecentActivityItem item) => string.IsNullOrWhiteSpace(item.WorkflowName) ? item.DefinitionId : item.WorkflowName!;
private static string GetRowClass(DashboardRecentActivityItem item, int rowNumber)
{
return item.SubStatus is "Faulted" or "Interrupted" || item.IncidentCount > 0 ? "dashboard-row-warning" : string.Empty;
}
private static Color StatusColor(string status)
{
return status switch
{
"Running" => Color.Info,
"Finished" or "Completed" => Color.Success,
"Faulted" => Color.Error,
_ => Color.Default
};
}
private static Color SubStatusColor(string subStatus)
{
return subStatus switch
{
"Faulted" => Color.Error,
"Interrupted" or "Suspended" => Color.Warning,
"Finished" or "Completed" => Color.Success,
_ => Color.Default
};
}
}

9
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/_Imports.razor

@ -0,0 +1,9 @@
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Web
@using Elsa.Studio.Components
@using Elsa.Studio.Dashboard.Components
@using Elsa.Studio.Dashboard.Models
@using Elsa.Studio.Dashboard.Services
@using Elsa.Studio.Dashboard.Widgets
@using Elsa.Studio.Localization
@using MudBlazor

208
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Dashboard.Blazor/wwwroot/dashboard.css

@ -0,0 +1,208 @@
/* Elsa Studio Dashboard visuals for the localized dashboard page/widgets (this module).
The ABP Blazor theme layout does not load Razor Class Library scoped-css bundles, so these
rules are global (class names are dashboard-specific) and injected by the page via <HeadContent>.
Mirrors the official Elsa.Studio.Dashboard / Elsa.Studio.Workflows.Dashboard scoped css. */
.dashboard-shell {
width: 100%;
max-width: none;
min-height: 100%;
padding: 24px 32px 32px;
box-sizing: border-box;
background: var(--mud-palette-background);
}
.dashboard-header {
gap: 12px 16px;
margin-bottom: 14px;
}
.dashboard-muted {
color: var(--mud-palette-text-secondary);
}
.dashboard-panel {
border-radius: 8px;
background: var(--mud-palette-surface);
}
.dashboard-shell .dashboard-panel {
border-radius: 8px;
background: var(--mud-palette-surface);
}
.dashboard-empty-state {
text-align: center;
}
.dashboard-metrics {
margin-bottom: 8px;
}
.dashboard-card-link {
color: inherit;
display: block;
height: 100%;
}
.dashboard-shell .dashboard-card-link {
color: inherit;
display: block;
height: 100%;
}
.dashboard-shell .dashboard-metric-card {
min-height: 104px;
height: 100%;
padding: 12px;
transition: border-color 120ms ease, background-color 120ms ease;
}
.dashboard-shell .dashboard-metric-card-clickable:hover,
.dashboard-shell .dashboard-metric-card-clickable:focus-within {
border-color: var(--mud-palette-primary);
background: rgba(var(--mud-palette-primary-rgb), 0.04);
}
.dashboard-shell .dashboard-metric-value {
line-height: 1.1;
margin-top: 6px;
}
.dashboard-main-stack {
margin-top: 8px;
}
.dashboard-activity-grid {
margin-top: 0;
}
.dashboard-shell .dashboard-section {
padding: 14px;
}
.dashboard-shell .dashboard-section-header {
margin-bottom: 10px;
}
.dashboard-shell .dashboard-chart-panel {
min-height: 320px;
}
.dashboard-shell .dashboard-finding-list {
margin: -6px;
}
.dashboard-shell .dashboard-finding-row {
width: 100%;
min-width: 0;
}
.dashboard-shell .dashboard-finding-row .mud-typography {
min-width: 0;
}
.dashboard-shell .dashboard-row-warning {
background: rgba(var(--mud-palette-warning-rgb), 0.08);
}
.dashboard-shell .dashboard-diagnostics-block {
border: 1px solid var(--mud-palette-lines-default);
border-radius: 8px;
padding: 12px;
}
.dashboard-shell .dashboard-diagnostics-value {
min-height: 28px;
}
.dashboard-shell .mud-table-cell {
padding: 6px 10px;
}
/* Operational health metrics (localized copy of the official metrics widget) */
.dashboard-operational-health {
margin-bottom: 8px;
}
.dashboard-operational-health-heading {
margin-bottom: 14px;
}
.dashboard-operational-health-metrics {
display: grid;
gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.dashboard-operational-health-metric {
background: var(--mud-palette-surface);
border: 1px solid var(--mud-palette-lines-default);
border-radius: 8px;
min-width: 0;
padding: 12px 14px;
transition: border-color 120ms ease, background-color 120ms ease;
}
.dashboard-operational-health-metric:hover,
.dashboard-operational-health-metric:focus-within {
border-color: var(--mud-palette-primary);
}
.dashboard-operational-health-value {
line-height: 1.1;
margin-top: 8px;
}
.dashboard-operational-health-caption {
color: var(--mud-palette-text-secondary);
}
/* Execution trend chart (localized copy of the official trend widget) */
.dashboard-trend-chart-frame {
width: 100%;
min-width: 0;
height: 260px;
}
.dashboard-trend-chart-frame .dashboard-trend-chart {
width: 100% !important;
min-width: 0;
}
.dashboard-trend-chart-frame .dashboard-trend-chart svg {
width: 100% !important;
max-width: 100%;
}
.dashboard-trend-chart-frame .mud-chart-legend {
width: 100%;
justify-content: center;
margin-top: 6px;
}
@media (max-width: 768px) {
.dashboard-shell {
padding: 16px;
}
.dashboard-header {
align-items: flex-start;
gap: 10px;
}
.dashboard-shell .dashboard-section {
padding: 12px;
}
}
@media (max-width: 720px) {
.dashboard-trend-chart-frame {
height: 260px;
}
}

87
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/AbpElsaNextStudioDiagnosticsOpenTelemetryBlazorModule.cs

@ -0,0 +1,87 @@
using Elsa.Diagnostics.OpenTelemetry.Extensions;
using Elsa.Extensions;
using Elsa.Features.Services;
using Elsa.OpenTelemetry.Middleware;
using Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard.Extensions;
using Elsa.Studio.Diagnostics.OpenTelemetry.Extensions;
using Elsa.Workflows.Telemetry;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor;
[DependsOn(
typeof(AbpAspNetCoreModule),
typeof(AbpElsaNextStudioBlazorModule))]
public class AbpElsaNextStudioDiagnosticsOpenTelemetryBlazorModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IModule>(elsa =>
{
elsa.UseWorkflows(workflows =>
{
workflows.WithDefaultWorkflowExecutionPipeline(pipeline =>
pipeline.UseWorkflowExecutionTracing());
workflows.WithDefaultActivityExecutionPipeline(pipeline =>
pipeline.UseActivityExecutionTracing());
});
elsa.UseOpenTelemetry();
elsa.UseOpenTelemetryDiagnostics();
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
Configure<AbpRouterOptions>(options =>
{
options.AdditionalAssemblies.Add(typeof(Elsa.Studio.Diagnostics.OpenTelemetry.Feature).Assembly);
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new ElsaStudioOpenTelemetryMenuContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpElsaNextStudioDiagnosticsOpenTelemetryBlazorModule>("LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<ElsaStudioResource>()
.AddVirtualJson("/Localization/Resources/ElsaStudioOpenTelemetryBlazor");
});
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>();
context.Services.AddOpenTelemetryDiagnosticsModule(elsaNextStudioBlazoeOptions.BackendApiConfig);
context.Services.AddOpenTelemetryDashboardModule();
context.Services.AddOpenTelemetryDashboardWidget();
context.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing.AddSource(WorkflowInstrumentation.ActivitySourceName))
.WithMetrics(metrics => metrics.AddMeter(WorkflowInstrumentation.MeterName));
Configure<AbpEndpointRouterOptions>(options =>
{
options.EndpointConfigureActions.Add((context) =>
{
context.Endpoints.MapOpenTelemetryHub();
});
});
}
}

20
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Extensions/OpenTelemetryWidgetServiceCollectionExtensions.cs

@ -0,0 +1,20 @@
using Elsa.Studio.Dashboard.Widgets;
using Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard.UI.Dashboard;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.Extensions;
public static class OpenTelemetryWidgetServiceCollectionExtensions
{
public static IServiceCollection AddOpenTelemetryDashboardWidget(this IServiceCollection services)
{
return services
.AddDashboardWidget<OpenTelemetryDashboardWidget>(
"diagnostics.open-telemetry",
DashboardWidgetZones.DiagnosticsStatus,
300,
"OpenTelemetry",
requiredBackendCapability: "OpenTelemetry",
payloadKind: "OpenTelemetry.StorageDiagnostics");
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

34
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.csproj

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="Elsa.OpenTelemetry" />
<PackageReference Include="Elsa.Diagnostics.OpenTelemetry" />
<PackageReference Include="Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
</ItemGroup>
<ItemGroup>
<Content Remove="Localization\**\*.json" />
<EmbeddedResource Include="Localization\**\*.json" />
</ItemGroup>
</Project>

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Localization/Resources/ElsaStudioOpenTelemetryBlazor/en.json

@ -0,0 +1,7 @@
{
"culture": "en",
"texts": {
"Menu:OpenTelemetry": "Open Telemetry",
"OpenTelemetry": "Open Telemetry"
}
}

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Localization/Resources/ElsaStudioOpenTelemetryBlazor/zh-Hans.json

@ -0,0 +1,7 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:OpenTelemetry": "Open Telemetry",
"OpenTelemetry": "Open Telemetry"
}
}

27
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/Navigation/ElsaStudioOpenTelemetryMenuContributor.cs

@ -0,0 +1,27 @@
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Volo.Abp.UI.Navigation;
namespace LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor.Navigation;
public class ElsaStudioOpenTelemetryMenuContributor : IMenuContributor
{
public Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
var menu = context.Menu;
var l = context.GetLocalizer<ElsaStudioResource>();
var group = menu.GetMenuItemOrNull(ElsaStudioMenus.GroupName);
group?.AddItem(new ApplicationMenuItem(
ElsaStudioMenus.GroupName + ".OpenTelemetry",
l["Menu:OpenTelemetry"],
url: "/diagnostics/opentelemetry",
icon: "fa fa-x-ray",
order: 4));
}
return Task.CompletedTask;
}
}

5
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.OpenTelemetry.Blazor/_Imports.razor

@ -0,0 +1,5 @@
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Web
@using Elsa.Studio.Components
@using Elsa.Studio.Localization
@using MudBlazor

74
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/AbpElsaNextStudioDiagnosticsStructuredLogsBlazorModule.cs

@ -0,0 +1,74 @@
using Elsa.Diagnostics.StructuredLogs.Extensions;
using Elsa.Extensions;
using Elsa.Features.Services;
using Elsa.Studio.Diagnostics.StructuredLogs.Dashboard.Extensions;
using Elsa.Studio.Diagnostics.StructuredLogs.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Blazor;
using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.Navigation;
using LINGYUN.Abp.ElsaNext.Studio.Translations.Localization;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore;
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor;
[DependsOn(
typeof(AbpAspNetCoreModule),
typeof(AbpElsaNextStudioBlazorModule))]
public class AbpElsaNextStudioDiagnosticsStructuredLogsBlazorModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IModule>(elsa =>
{
elsa.UseStructuredLogs();
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Configuration.GetSection("Elsa:Studio");
Configure<AbpRouterOptions>(options =>
{
// options.AdditionalAssemblies.Add(typeof(Elsa.Studio.Diagnostics.StructuredLogs.Feature).Assembly);
options.AdditionalAssemblies.Add(typeof(AbpElsaNextStudioDiagnosticsStructuredLogsBlazorModule).Assembly);
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new ElsaStudioStructuredLogsMenuContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpElsaNextStudioDiagnosticsStructuredLogsBlazorModule>("LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<ElsaStudioResource>()
.AddVirtualJson("/Localization/Resources/ElsaStudioStructuredLogsBlazor");
});
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>();
context.Services.AddStructuredLogsModule(elsaNextStudioBlazoeOptions.BackendApiConfig);
context.Services.AddStructuredLogsDashboardModule();
context.Services.AddStructuredLogsDashboardWidget();
Configure<AbpEndpointRouterOptions>(options =>
{
options.EndpointConfigureActions.Add((context) =>
{
context.Endpoints.MapStructuredLogsHub();
});
});
}
}

20
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/Extensions/OpenTelemetryWidgetServiceCollectionExtensions.cs

@ -0,0 +1,20 @@
using Elsa.Studio.Dashboard.Widgets;
using Elsa.Studio.Diagnostics.StructuredLogs.Dashboard.UI.Dashboard;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.Extensions;
public static class OpenTelemetryWidgetServiceCollectionExtensions
{
public static IServiceCollection AddStructuredLogsDashboardWidget(this IServiceCollection services)
{
return services
.AddDashboardWidget<StructuredLogsDashboardWidget>(
"diagnostics.structured-logs",
DashboardWidgetZones.DiagnosticsStatus,
100,
"Structured logs",
requiredBackendCapability: "StructuredLogs",
payloadKind: "Diagnostics.StructuredLogs");
}
}

3
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait />
</Weavers>

30
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

33
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor.csproj

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor</AssemblyName>
<PackageId>LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore" />
</ItemGroup>
<ItemGroup>
<!-- Official Elsa Studio structured-logs module (rc2): services, SignalR observer, API client
and the viewer page component reused by this module's ABP page (see Pages/). -->
<PackageReference Include="Elsa.Diagnostics.StructuredLogs" />
<PackageReference Include="Elsa.Studio.Diagnostics.StructuredLogs.Dashboard" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\**\*.json" />
</ItemGroup>
</Project>

7
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Diagnostics.StructuredLogs.Blazor/Localization/Resources/ElsaStudioStructuredLogsBlazor/en.json

@ -0,0 +1,7 @@
{
"culture": "en",
"texts": {
"Menu:StructuredLogs": "Structured logs",
"Logs": "Structured logs"
}
}

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

Loading…
Cancel
Save