Browse Source

Merge branch 'dev' into 401

pull/19952/head
maliming 2 years ago
parent
commit
966d81b6ca
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 6
      Directory.Packages.props
  2. 101
      README.md
  3. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  4. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
  5. 20
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  6. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  7. 4
      docs/en/CLI.md
  8. 83
      docs/en/Data-Filtering.md
  9. 7
      docs/en/Local-Event-Bus.md
  10. 6
      docs/en/Modules/Cms-Kit/Comments.md
  11. 112
      docs/en/Multi-Tenancy.md
  12. 13
      docs/en/Themes/LeptonXLite/Angular.md
  13. 19
      docs/en/UI/Angular/Account-Module.md
  14. 2
      docs/en/UI/Angular/Basic-Theme.md
  15. 117
      docs/en/UI/Angular/Component-Replacement.md
  16. 37
      docs/en/UI/Angular/Confirmation-Service.md
  17. 8
      docs/en/UI/Angular/Feature-Libraries.md
  18. 52
      docs/en/UI/Angular/Form-Validation.md
  19. 22
      docs/en/UI/Angular/HTTP-Error-Handling.md
  20. 183
      docs/en/UI/Angular/Localization.md
  21. 9
      docs/en/UI/Angular/OAuth-Module.md
  22. 4
      docs/en/UI/AspNetCore/Static-JavaScript-Proxies.md
  23. 4
      docs/en/docs-nav.json
  24. BIN
      docs/en/images/book-mastering-abp-framework.png
  25. BIN
      docs/en/images/cmskit-module-comments-settings.png
  26. BIN
      docs/en/images/db-options.png
  27. BIN
      docs/en/images/ddd-microservice-simple.png
  28. BIN
      docs/en/images/ui-options.png
  29. 83
      docs/zh-Hans/Data-Filtering.md
  30. 8
      docs/zh-Hans/Local-Event-Bus.md
  31. 27
      docs/zh-Hans/UI/Angular/Localization.md
  32. 1
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
  33. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
  34. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebOptions.cs
  35. 1
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
  36. 27
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ClientProxyExceptionEventHandler.cs
  37. 57
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/CachedBundleDynamicFileProvider.cs
  38. 22
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/InMemoryFileInfoCacheItem.cs
  39. 5
      framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs
  40. 14
      framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs
  41. 9
      framework/src/Volo.Abp.BlazoriseUI/Components/UiPageProgress.razor.cs
  42. 172
      framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs
  43. 16
      framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisExtensions.cs
  44. 18
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingService.cs
  45. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs
  46. 16
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BundleCommand.cs
  47. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs
  48. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ModuleInfo.cs
  49. 13
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs
  50. 13
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveFileStep.cs
  51. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppNoLayersTemplateBase.cs
  52. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs
  53. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs
  54. 11
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
  55. 10
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
  56. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/PackageVersionCheckerService.cs
  57. 16
      framework/src/Volo.Abp.Core/Volo/Abp/Check.cs
  58. 2
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ExposeServicesAttribute.cs
  59. 8
      framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/MySQL/AbpEntityFrameworkCoreMySQLModule.cs
  60. 6
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/Oracle/Devart/AbpEntityFrameworkCoreOracleDevartModule.cs
  61. 6
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/Oracle/AbpEntityFrameworkCoreOracleModule.cs
  62. 8
      framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/PostgreSql/AbpEntityFrameworkCorePostgreSqlModule.cs
  63. 8
      framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/SqlServer/AbpEntityFrameworkCoreSqlServerModule.cs
  64. 9
      framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs
  65. 21
      framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreDbContextOptionsBuilderExtensions.cs
  66. 68
      framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreModelBuilderExtensions.cs
  67. 38
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  68. 62
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsExtension.cs
  69. 49
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityQueryProvider.cs
  70. 6
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs
  71. 59
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpCompiledQueryCacheKeyGenerator.cs
  72. 21
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpEfCoreCurrentDbContext.cs
  73. 25
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpEfCoreDataFilterDbFunctionMethods.cs
  74. 10
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpEfCoreGlobalFilterOptions.cs
  75. 16
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/IAbpEfCoreDbFunctionContext.cs
  76. 18
      framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs
  77. 65
      framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.swagger.js
  78. 6
      framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DynamicFileProvider.cs
  79. 2
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingTestModule.cs
  80. 20
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AutoRegistrationHelper_Tests.cs
  81. 4
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs
  82. 2
      latest-versions.json
  83. 14
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.js
  84. 2
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/AbpAspNetCoreComponentsWebAssemblyBasicThemeModule.cs
  85. 2
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
  86. 2
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/WebAssemblyRedirectToLogin.razor
  87. 6
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json
  88. 276
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock
  89. 4
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json
  90. 280
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock
  91. 1
      modules/blogging/app/Volo.BloggingTestApp/Program.cs
  92. 4
      modules/blogging/app/Volo.BloggingTestApp/package.json
  93. 318
      modules/blogging/app/Volo.BloggingTestApp/yarn.lock
  94. 2
      modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json
  95. 2
      modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/tr.json
  96. 45
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.cshtml
  97. 6
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml
  98. 2
      modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json
  99. 258
      modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock
  100. 2
      modules/cms-kit/.gitignore

6
Directory.Packages.props

@ -38,8 +38,8 @@
<PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" />
<PackageVersion Include="FluentValidation" Version="11.8.0" /> <PackageVersion Include="FluentValidation" Version="11.8.0" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.6" /> <PackageVersion Include="Hangfire.AspNetCore" Version="1.8.14" />
<PackageVersion Include="Hangfire.SqlServer" Version="1.8.6" /> <PackageVersion Include="Hangfire.SqlServer" Version="1.8.14" />
<PackageVersion Include="HtmlSanitizer" Version="8.0.746" /> <PackageVersion Include="HtmlSanitizer" Version="8.0.746" />
<PackageVersion Include="IdentityModel" Version="6.2.0" /> <PackageVersion Include="IdentityModel" Version="6.2.0" />
<PackageVersion Include="IdentityServer4" Version="4.1.2" /> <PackageVersion Include="IdentityServer4" Version="4.1.2" />
@ -174,4 +174,4 @@
<PackageVersion Include="ConfigureAwait.Fody" Version="3.3.2" /> <PackageVersion Include="ConfigureAwait.Fody" Version="3.3.2" />
<PackageVersion Include="Fody" Version="6.8.0" /> <PackageVersion Include="Fody" Version="6.8.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

101
README.md

@ -1,22 +1,18 @@
# ABP Framework # ABP Framework
![build and test](https://img.shields.io/github/actions/workflow/status/abpframework/abp/build-and-test.yml?branch=dev&style=flat-square) ![build and test](https://img.shields.io/github/actions/workflow/status/abpframework/abp/build-and-test.yml?branch=dev&style=flat-square) 🔹 [![codecov](https://codecov.io/gh/abpframework/abp/branch/dev/graph/badge.svg?token=jUKLCxa6HF)](https://codecov.io/gh/abpframework/abp) 🔹 [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [![NuGet (with prereleases)](https://img.shields.io/nuget/vpre/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [![MyGet (nightly builds)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) 🔹
[![codecov](https://codecov.io/gh/abpframework/abp/branch/dev/graph/badge.svg?token=jUKLCxa6HF)](https://codecov.io/gh/abpframework/abp) [![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [![Code of Conduct](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](https://github.com/abpframework/abp/blob/dev/CODE_OF_CONDUCT.md) 🔹 [![CLA Signed](https://cla-assistant.io/readme/badge/abpframework/abp)](https://cla-assistant.io/abpframework/abp) 🔹 [![Discord Shield](https://discord.com/api/guilds/951497912645476422/widget.png?style=shield)](https://discord.gg/abp)
[![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![NuGet (with prereleases)](https://img.shields.io/nuget/vpre/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) ABP Framework is a complete **infrastructure** based on **ASP.NET Core** that creates **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**.
[![MyGet (nightly builds)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![ABP Platform](https://github.com/abpframework/abp/assets/9526587/47531496-4088-406d-9c69-63cb0ffec2ba)](https://abp.io)
[![Code of Conduct](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](https://github.com/abpframework/abp/blob/dev/CODE_OF_CONDUCT.md)
[![CLA Signed](https://cla-assistant.io/readme/badge/abpframework/abp)](https://cla-assistant.io/abpframework/abp)
[![ABP Discord server](https://img.shields.io/discord/951497912645476422?label=Discord)](https://discord.gg/abp)
ABP Framework is a complete **infrastructure** based on **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**. Check out https://abp.io
## Getting Started ## Getting Started
- [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index) is a single-part, quick-start tutorial to build a simple application with the ABP Framework. Start with this tutorial if you want to quickly understand how ABP works. - [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index) is a single-part, quick-start tutorial to build a simple application with the ABP Framework. Start with this tutorial if you want to understand how ABP works quickly.
- [Getting Started guide](https://docs.abp.io/en/abp/latest/Getting-Started) can be used to create and run ABP based solutions with different options and details. - [Getting Started guide](https://docs.abp.io/en/abp/latest/Getting-Started) can be used to create and run ABP-based solutions with different options and details.
- [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1) is a complete tutorial to develop a full stack web application with all aspects of a real-life solution. - [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1) is a complete tutorial on developing a full-stack web application with all aspects of a real-life solution.
### Quick Start ### Quick Start
@ -34,28 +30,26 @@ Create a new solution:
> See the [CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all available options. > See the [CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all available options.
### UI Framework Options ### UI Framework Options
<img width="500" src="docs/en/images/ui-options.png"> <img width="500" src="docs/en/images/ui-options.png">
### Database Provider Options ### Database Provider Options
<img width="500" src="docs/en/images/db-options.png"> <img width="500" src="docs/en/images/db-options.png">
## The Book: Mastering ABP Framework
Written by the creator of ABP Framework, this book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques.
* [Buy on Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q)
* [Buy on Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242)
* [More details about the book](https://abp.io/books/mastering-abp-framework)
![book-mastering-abp-framework](docs/en/images/book-mastering-abp-framework.png)
## What ABP Provides? ## What ABP Provides?
ABP provides a **full stack developer experience**. ABP provides a **full stack developer experience**.
### Architecture ### Architecture
<img src="docs/en/images/ddd-microservice-simple.png"> <img src="docs/en/images/ddd-microservice-simple.png">
@ -64,30 +58,48 @@ ABP offers a complete, **modular** and **layered** software architecture based o
ABP Framework is suitable for **[microservice solutions](https://docs.abp.io/en/abp/latest/Microservice-Architecture)** as well as monolithic applications. ABP Framework is suitable for **[microservice solutions](https://docs.abp.io/en/abp/latest/Microservice-Architecture)** as well as monolithic applications.
### Infrastructure ### Infrastructure
There are a lot of features provided by the ABP Framework to achieve real world scenarios easier, like [Event Bus](https://docs.abp.io/en/abp/latest/Event-Bus), [Background Job System](https://docs.abp.io/en/abp/latest/Background-Jobs), [Audit Logging](https://docs.abp.io/en/abp/latest/Audit-Logging), [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing), [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding), [Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering), etc. There are a lot of features provided by the ABP Framework to achieve real-world scenarios easier, like [Event Bus](https://docs.abp.io/en/abp/latest/Event-Bus), [Background Job System](https://docs.abp.io/en/abp/latest/Background-Jobs), [Audit Logging](https://docs.abp.io/en/abp/latest/Audit-Logging), [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing), [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding), [Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering), etc.
### Cross-Cutting Concerns
ABP also simplifies (and even automates wherever possible) cross-cutting concerns and common non-functional requirements like [Exception Handling](https://docs.abp.io/en/abp/latest/Exception-Handling), [Validation](https://docs.abp.io/en/abp/latest/Validation), [Authorization](https://docs.abp.io/en/abp/latest/Authorization), [Localization](https://docs.abp.io/en/abp/latest/Localization), [Caching](https://docs.abp.io/en/abp/latest/Caching), [Dependency Injection](https://docs.abp.io/en/abp/latest/Dependency-Injection), [Setting Management](https://docs.abp.io/en/abp/latest/Settings), etc.
### Cross Cutting Concerns
ABP also simplifies (and even automates wherever possible) cross cutting concerns and common non-functional requirements like [Exception Handling](https://docs.abp.io/en/abp/latest/Exception-Handling), [Validation](https://docs.abp.io/en/abp/latest/Validation), [Authorization](https://docs.abp.io/en/abp/latest/Authorization), [Localization](https://docs.abp.io/en/abp/latest/Localization), [Caching](https://docs.abp.io/en/abp/latest/Caching), [Dependency Injection](https://docs.abp.io/en/abp/latest/Dependency-Injection), [Setting Management](https://docs.abp.io/en/abp/latest/Settings), etc.
### Application Modules ### Application Modules
ABP is a modular framework and the Application Modules provide **pre-built application functionalities**; ABP is a modular framework and the Application Modules provide **pre-built application functionalities**;
- [**Account**](https://docs.abp.io/en/abp/latest/Modules/Account): Provides UI for the account management and allows user to login/register to the application. - [**Account**](https://docs.abp.io/en/abp/latest/Modules/Account): Provides UI for the account management and allows user to login/register to the application.
- **[Identity](https://docs.abp.io/en/abp/latest/Modules/Identity)**: Manages organization units, roles, users and their permissions, based on the Microsoft Identity library. - **[Identity](https://docs.abp.io/en/abp/latest/Modules/Identity)**: Manages organization units, roles, users and their permissions based on the Microsoft Identity library.
- [**OpenIddict**](https://docs.abp.io/en/abp/latest/Modules/OpenIddict): Integrates to OpenIddict. - [**OpenIddict**](https://docs.abp.io/en/abp/latest/Modules/OpenIddict): Integrates to OpenIddict.
- [**Tenant Management**](https://docs.abp.io/en/abp/latest/Modules/Tenant-Management): Manages tenants for a [multi-tenant](https://docs.abp.io/en/abp/latest/Multi-Tenancy) (SaaS) application. - [**Tenant Management**](https://docs.abp.io/en/abp/latest/Modules/Tenant-Management): Manages tenants for a [multi-tenant](https://docs.abp.io/en/abp/latest/Multi-Tenancy) (SaaS) application.
See the [Application Modules](https://docs.abp.io/en/abp/latest/Modules/Index) document for all pre-built modules. See the [Application Modules](https://docs.abp.io/en/abp/latest/Modules/Index) document for all pre-built modules.
### Startup Templates ### Startup Templates
The [Startup templates](https://docs.abp.io/en/abp/latest/Startup-Templates/Index) are pre-built Visual Studio solution templates. You can create your own solution based on these templates to **immediately start your development**. The [Startup templates](https://docs.abp.io/en/abp/latest/Startup-Templates/Index) are pre-built Visual Studio solution templates. You can create your own solution based on these templates to **immediately start your development**.
## ABP Community
## Mastering ABP Framework Book
This book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques. It is written by the creator and team lead of the ABP Framework. You can buy from [Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q) or [Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242). Find further info about the book at [abp.io/books/mastering-abp-framework](https://abp.io/books/mastering-abp-framework).
![book-mastering-abp-framework](docs/en/images/book-mastering-abp-framework.png)
## The Community
### ABP Community Web Site ### ABP Community Web Site
@ -103,28 +115,31 @@ See the [sample projects](https://docs.abp.io/en/abp/latest/Samples/Index) built
### Want to Contribute? ### Want to Contribute?
ABP is a community-driven open source project. See [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index) if you want to be a part of this project. ABP is a community-driven open-source project. See [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index) if you want to participate in this project.
## Official Links ## Official Links
* <a href="https://abp.io/" target="_blank">Main Web Site</a> * [Home Website](https://abp.io)
* <a href="https://abp.io/get-started" target="_blank">Get Started</a> * [Get Started](https://abp.io/get-started)
* <a href="https://abp.io/features" target="_blank">Features</a> * [Features](https://abp.io/features)
* <a href="https://docs.abp.io/" target="_blank">Documentation</a> * [Documents](https://docs.abp.io/)
* <a href="https://docs.abp.io/en/abp/latest/Samples/Index" target="_blank">Samples</a> * [Samples](https://docs.abp.io/en/abp/latest/Samples/Index)
* <a href="https://blog.abp.io/" target="_blank">Blog</a> * [Blog](https://blog.abp.io/)
* <a href="https://community.abp.io/" target="_blank">Community</a> * [Community](https://community.abp.io/)
* <a href="https://stackoverflow.com/questions/tagged/abp" target="_blank">Stack overflow</a> * [Stackoverflow](https://stackoverflow.com/questions/tagged/abp)
* <a href="https://twitter.com/abpframework" target="_blank">Twitter</a> * [Twitter](https://twitter.com/abpframework)
## Support ABP
## Support the ABP Framework GitHub repository stars are an important indicator of popularity and the size of the community. If you like ABP Framework, support us by clicking the star :star: on the repository.
Love ABP Framework? **Please give a star** to this repository :star:
## Discord Channel
You can use this link to join the ABP Community Discord Server: https://discord.gg/abp ## Discord Server
## ABP Commercial We have a Discord server where you can chat with other ABP users. Share your ideas, report technical issues, showcase your creations, share the tips that worked for you and catch up with the latest news and announcements about ABP Framework. Join 👉 https://discord.gg/abp.
See also [ABP Commercial](https://commercial.abp.io/) if you are looking for pre-built application modules, professional themes, code generation tooling and premium support for the ABP Framework.

3
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -621,6 +621,7 @@
"DeleteImageConfirmationMessage": "Are you sure you want to delete the image for \"{0}\"?", "DeleteImageConfirmationMessage": "Are you sure you want to delete the image for \"{0}\"?",
"DeleteImageSuccessMessage": "Image successfully deleted", "DeleteImageSuccessMessage": "Image successfully deleted",
"DeleteImage": "Delete Image", "DeleteImage": "Delete Image",
"NetTerms": "Terms (Days)" "NetTerms": "Terms (Days)",
"AbpStudioName": "Abp Studio name"
} }
} }

2
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json

@ -59,7 +59,7 @@
"MilestoneErrorMessage": "Couldn't get the current milestone details from Github.", "MilestoneErrorMessage": "Couldn't get the current milestone details from Github.",
"QuestionItemErrorMessage": "Couldn't get the latest question details from Stackoverflow.", "QuestionItemErrorMessage": "Couldn't get the latest question details from Stackoverflow.",
"Oops": "Oops!", "Oops": "Oops!",
"CreatePostSuccessMessage": "The Post has been successfully submitted. It will be published once it has been reviewed by the site admin.", "CreatePostSuccessMessage": "Your post has been successfully submitted. It will be published after review by the site administrator.",
"ChooseCoverImage": "Choose a cover image...", "ChooseCoverImage": "Choose a cover image...",
"CoverImage": "Cover Image", "CoverImage": "Cover Image",
"ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!", "ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!",

20
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json

@ -16,7 +16,7 @@
"Title": "Title", "Title": "Title",
"CreationTime": "Creation time", "CreationTime": "Creation time",
"Save": "Save", "Save": "Save",
"SameUrlAlreadyExist": "Same url already exists if you want to add this post, you should change the url!", "SameUrlAlreadyExist": "Same URL already exists! You must change the URL!",
"UrlIsNotValid": "Url is not valid.", "UrlIsNotValid": "Url is not valid.",
"UrlNotFound": "Url not found.", "UrlNotFound": "Url not found.",
"UrlContentNotFound": "Url content not found.", "UrlContentNotFound": "Url content not found.",
@ -33,7 +33,7 @@
"FeatureRequest": "Feature Request", "FeatureRequest": "Feature Request",
"CreatePostTitleInfo": "Title of the post to be shown on the post list.", "CreatePostTitleInfo": "Title of the post to be shown on the post list.",
"CreatePostSummaryInfo": "A short summary of the post to be shown on the post list. Maximum length: <b>{0}</b>", "CreatePostSummaryInfo": "A short summary of the post to be shown on the post list. Maximum length: <b>{0}</b>",
"CreatePostCoverInfo": "For creating an effective post, add a cover photo. Upload 16:9 aspect ratio pictures for the best view.<br/> Maximum file size: <b>1MB.</b>", "CreatePostCoverInfo": "To create an effective post, add a cover photo. Upload <b>16:9 aspect ratio</b> pictures for the best view.<br/> Maximum file size is <b>1MB.</b>",
"ThisExtensionIsNotAllowed": "This extension is not allowed.", "ThisExtensionIsNotAllowed": "This extension is not allowed.",
"TheFileIsTooLarge": "The file is too large.", "TheFileIsTooLarge": "The file is too large.",
"GoToThePost": "Go to the Post", "GoToThePost": "Go to the Post",
@ -56,7 +56,7 @@
"MilestoneErrorMessage": "Could not get the current milestone details from Github.", "MilestoneErrorMessage": "Could not get the current milestone details from Github.",
"QuestionItemErrorMessage": "Could not get the latest question details from Stackoverflow.", "QuestionItemErrorMessage": "Could not get the latest question details from Stackoverflow.",
"Oops": "Oops!", "Oops": "Oops!",
"CreatePostSuccessMessage": "The Post has been successfully submitted. It will be published after a review from the site admin.", "CreatePostSuccessMessage": "Your post has been successfully submitted. It will be published after review by the site administrator.",
"Browse": "Browse", "Browse": "Browse",
"CoverImage": "Cover Image", "CoverImage": "Cover Image",
"ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!", "ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!",
@ -125,7 +125,7 @@
"YoutubeVideoSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit the video URL using the form.", "YoutubeVideoSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit the video URL using the form.",
"YoutubeVideoSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Visitors will be able to watch your video content directly on this website.", "YoutubeVideoSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Visitors will be able to watch your video content directly on this website.",
"ExternalContent": "External Content", "ExternalContent": "External Content",
"ExternalContentSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Create a content on any public platform (Medium, your own blog or anywhere you like).", "ExternalContentSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Create content on any public platform (Medium, your own blog or anywhere you like).",
"ExternalContentSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit your content URL using the form.", "ExternalContentSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit your content URL using the form.",
"ExternalContentSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Visitors are redirected to the content on the original website.", "ExternalContentSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Visitors are redirected to the content on the original website.",
"ChooseYourContentType": "Please choose the way you want to add your content.", "ChooseYourContentType": "Please choose the way you want to add your content.",
@ -135,12 +135,12 @@
"GitHubUserNameValidationMessage": "Your Github username can not include whitespace, please make sure your Github username is correct.", "GitHubUserNameValidationMessage": "Your Github username can not include whitespace, please make sure your Github username is correct.",
"PersonalSiteUrlValidationMessage": "Your personal site URL can not include whitespace, please make sure your personal site URL is correct.", "PersonalSiteUrlValidationMessage": "Your personal site URL can not include whitespace, please make sure your personal site URL is correct.",
"TwitterUserNameValidationMessage": "Your Twitter username can not include whitespace, please make sure your Twitter username is correct.", "TwitterUserNameValidationMessage": "Your Twitter username can not include whitespace, please make sure your Twitter username is correct.",
"LinkedinUrlValidationMessage": "Your Linkedin URL can not include whitespace, please make sure your Linkedin URL is correct.", "LinkedinUrlValidationMessage": "Your LinkedIn URL can not include whitespace, please make sure your LinkedIn URL is correct.",
"NoPostsFound": "No posts found!", "NoPostsFound": "No posts found!",
"SearchInPosts": "Search in posts...", "SearchInPosts": "Search in posts...",
"MinimumSearchContent": "You must enter at least 3 characters!", "MinimumSearchContent": "You must enter at least 3 characters!",
"Volo.AbpIo.Domain:060001": "Source URL(\"{PostUrl}\") is not Github URL", "Volo.AbpIo.Domain:060001": "Source URL(\"{PostUrl}\") is not Github URL",
"Volo.AbpIo.Domain:060002": "Post Content is not available from Github(\"{PostUrl}\") resource.", "Volo.AbpIo.Domain:060002": "Post Content is not available from GitHub(\"{PostUrl}\") resource.",
"Volo.AbpIo.Domain:060003": "No post content found!", "Volo.AbpIo.Domain:060003": "No post content found!",
"SeeMore": "See More", "SeeMore": "See More",
"JoinTheABPCommunity": "Join the ABP Community", "JoinTheABPCommunity": "Join the ABP Community",
@ -171,14 +171,14 @@
"Discord_Page_Announce": "We are happy to announce ABP Community Discord Server!", "Discord_Page_Announce": "We are happy to announce ABP Community Discord Server!",
"Discord_Page_Description_1": "ABP Community has been growing since day one. We wanted to take it to the next step by creating an official ABP Discord server so the ABP Community can interact with each other using the wonders of instant messaging.", "Discord_Page_Description_1": "ABP Community has been growing since day one. We wanted to take it to the next step by creating an official ABP Discord server so the ABP Community can interact with each other using the wonders of instant messaging.",
"Discord_Page_Description_2": "ABP Community Discord Server is the place where you can showcase your creations using ABP Framework, share the tips that worked for you, catch up with the latest news and announcements about ABP Framework, just chat with community members to exchange ideas, and have fun!", "Discord_Page_Description_2": "ABP Community Discord Server is the place where you can showcase your creations using ABP Framework, share the tips that worked for you, catch up with the latest news and announcements about ABP Framework, just chat with community members to exchange ideas, and have fun!",
"Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team is present on the server to monitor.", "Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team present on the server to monitor.",
"Discord_Page_JoinToServer": "Join ABP Discord Server", "Discord_Page_JoinToServer": "Join ABP Discord Server",
"Events_Page_MetaTitle": "ABP Community Events", "Events_Page_MetaTitle": "ABP Community Events",
"Events_Page_MetaDescription": "The live shows, hosted by the ABP Team, are casual sessions full of community content, demos, Q&A, and discussions around what's happening in ABP.", "Events_Page_MetaDescription": "The live shows, hosted by the ABP Team, are casual sessions full of community content, demos, Q&A, and discussions around what's happening in ABP.",
"Events_Page_Title": "ABP<span class=\"gradient-community\"> Community</span> Talks", "Events_Page_Title": "ABP<span class=\"gradient-community\"> Community</span> Talks",
"Members_Page_WritingFromUser": "Read writing from {0} on ABP Community.", "Members_Page_WritingFromUser": "Read writing from {0} on ABP Community.",
"Post_Create_Page_MetaTitle": "New Post", "Post_Create_Page_MetaTitle": "New Post",
"Post_Create_Page_MetaDescription": "Create your post for sharing your experiences about ABP framework and contributing the ABP Community.", "Post_Create_Page_MetaDescription": "Create your post for sharing your experiences about the ABP framework and contributing to the ABP Community.",
"Post_Create_Page_CreateNewPost": "Create New Post", "Post_Create_Page_CreateNewPost": "Create New Post",
"Post_Index_Page_MetaDescription": "ABP Community's purpose is to create a contribution environment for developers who use the ABP framework.", "Post_Index_Page_MetaDescription": "ABP Community's purpose is to create a contribution environment for developers who use the ABP framework.",
"Layout_Title": "{0} | ABP Community", "Layout_Title": "{0} | ABP Community",
@ -193,7 +193,7 @@
"AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework", "AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework",
"CommunitySlogan": "A unique community platform for <span class=\"{0}\">ABP Lovers</span>", "CommunitySlogan": "A unique community platform for <span class=\"{0}\">ABP Lovers</span>",
"RaffleIsNotActive": "Raffle is not active", "RaffleIsNotActive": "Raffle is not active",
"YouAreAlreadyJoinedToThisRaffle": "You already joined to this raffle!", "YouAreAlreadyJoinedToThisRaffle": "You already joined this raffle!",
"InvalidSubscriptionCode": "Invalid subscription code", "InvalidSubscriptionCode": "Invalid subscription code",
"Raffle:{0}": "Raffle: {0}", "Raffle:{0}": "Raffle: {0}",
"Join": "Join", "Join": "Join",
@ -266,4 +266,4 @@
"DailyPostCreateLimitation": "You have reached the daily post creation limit. You can create a new post in {0}.", "DailyPostCreateLimitation": "You have reached the daily post creation limit. You can create a new post in {0}.",
"YourAccountDisabled": "Your user account is disabled!" "YourAccountDisabled": "Your user account is disabled!"
} }
} }

4
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json

@ -158,7 +158,7 @@
"IndexPageHeroSection": "<span class=\"first-line shine\"><strong>open source</strong></span><span class=\"second-line text-uppercase\">Web Application<br />Framework</span><span class=\"third-line shine2\"><strong>for asp.net core</strong></span>", "IndexPageHeroSection": "<span class=\"first-line shine\"><strong>open source</strong></span><span class=\"second-line text-uppercase\">Web Application<br />Framework</span><span class=\"third-line shine2\"><strong>for asp.net core</strong></span>",
"UiFramework": "UI框架", "UiFramework": "UI框架",
"EmailAddress": "电子邮件地址", "EmailAddress": "电子邮件地址",
"Mobile": "移动电话", "Mobile": "选择移动应用程序框架",
"ReactNative": "React Native", "ReactNative": "React Native",
"Strong": "强大", "Strong": "强大",
"Complete": "完整", "Complete": "完整",
@ -476,4 +476,4 @@
"ABPVideoCoursesPageDescription": "通过ABP团队创建的视频课程学习ABP框架的基础知识。在本视频系列中,您将学习ABP框架的基本主题。每个视频上的数字都是根据学习流程编写的。", "ABPVideoCoursesPageDescription": "通过ABP团队创建的视频课程学习ABP框架的基础知识。在本视频系列中,您将学习ABP框架的基本主题。每个视频上的数字都是根据学习流程编写的。",
"ABPVideoCoursesTitle": "ABP 基本视频" "ABPVideoCoursesTitle": "ABP 基本视频"
} }
} }

4
docs/en/CLI.md

@ -131,7 +131,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers: * `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core. * `ef`: Entity Framework Core.
* `mongodb`: MongoDB. * `mongodb`: MongoDB.
* `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes: * `--theme`: Specifies the theme. Default theme is `leptonx-lite`. Available themes:
* `leptonx-lite`: [LeptonX Lite Theme](Themes/LeptonXLite/AspNetCore.md). * `leptonx-lite`: [LeptonX Lite Theme](Themes/LeptonXLite/AspNetCore.md).
* `basic`: [Basic Theme](UI/AspNetCore/Basic-Theme.md). * `basic`: [Basic Theme](UI/AspNetCore/Basic-Theme.md).
* **`module`**: [Module template](Startup-Templates/Module.md). Additional options: * **`module`**: [Module template](Startup-Templates/Module.md). Additional options:
@ -147,7 +147,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers: * `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core. * `ef`: Entity Framework Core.
* `mongodb`: MongoDB. * `mongodb`: MongoDB.
* `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes: * `--theme`: Specifies the theme. Default theme is `leptonx-lite`. Available themes:
* `leptonx-lite`: [LeptonX Lite Theme](Themes/LeptonXLite/AspNetCore.md). * `leptonx-lite`: [LeptonX Lite Theme](Themes/LeptonXLite/AspNetCore.md).
* `basic`: [Basic Theme](UI/AspNetCore/Basic-Theme.md). * `basic`: [Basic Theme](UI/AspNetCore/Basic-Theme.md).
* **`maui`**: .NET MAUI. A minimalist .NET MAUI application will be created if you specify this option. * **`maui`**: .NET MAUI. A minimalist .NET MAUI application will be created if you specify this option.

83
docs/en/Data-Filtering.md

@ -217,17 +217,14 @@ protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityTyp
return base.ShouldFilterEntity<TEntity>(entityType); return base.ShouldFilterEntity<TEntity>(entityType);
} }
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>() protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
{ {
var expression = base.CreateFilterExpression<TEntity>(); var expression = base.CreateFilterExpression<TEntity>(modelBuilder);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{ {
Expression<Func<TEntity, bool>> isActiveFilter = Expression<Func<TEntity, bool>> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive");
e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive"); expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
expression = expression == null
? isActiveFilter
: QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
} }
return expression; return expression;
@ -251,6 +248,78 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
} }
```` ````
#### Using User-defined function mapping for global filters
Using [User-defined function mapping](https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping) for global filters will gain performance improvements.
To use this feature, you need to change your DbContext like below:
````csharp
protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled<IIsActive>() ?? false;
protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return base.ShouldFilterEntity<TEntity>(entityType);
}
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
{
var expression = base.CreateFilterExpression<TEntity>(modelBuilder);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive");
if (UseDbFunction())
{
isActiveFilter = e => IsActiveFilter(((IIsActive)e).IsActive, true);
var abpEfCoreCurrentDbContext = this.GetService<AbpEfCoreCurrentDbContext>();
modelBuilder.HasDbFunction(typeof(MyProjectNameDbContext).GetMethod(nameof(IsActiveFilter))!)
.HasTranslation(args =>
{
// (bool isActive, bool boolParam)
var isActive = args[0];
var boolParam = args[1];
if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled<IIsActive>() == true)
{
// isActive == true
return new SqlBinaryExpression(
ExpressionType.Equal,
isActive,
new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping),
boolParam.Type,
boolParam.TypeMapping);
}
// empty where sql
return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping);
});
}
expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
}
return expression;
}
public static bool IsActiveFilter(bool isActive, bool boolParam)
{
throw new NotSupportedException(AbpEfCoreDataFilterDbFunctionMethods.NotSupportedExceptionMessage);
}
public override string GetCompiledQueryCacheKey()
{
return $"{base.GetCompiledQueryCacheKey()}:{IsActiveFilterEnabled}";
}
````
### MongoDB ### MongoDB
ABP abstracts the `IMongoDbRepositoryFilterer` interface to implement data filtering for the [MongoDB Integration](MongoDB.md), it works only if you use the repositories properly. Otherwise, you should manually filter the data. ABP abstracts the `IMongoDbRepositoryFilterer` interface to implement data filtering for the [MongoDB Integration](MongoDB.md), it works only if you use the repositories properly. Otherwise, you should manually filter the data.

7
docs/en/Local-Event-Bus.md

@ -235,6 +235,13 @@ Pre-build events are published when you save changes to the database;
* For EF Core, they are published on `DbContext.SaveChanges`. * For EF Core, they are published on `DbContext.SaveChanges`.
* For MongoDB, they are published when you call repository's `InsertAsync`, `UpdateAsync` or `DeleteAsync` methods (since MongoDB has not a change tracking system). * For MongoDB, they are published when you call repository's `InsertAsync`, `UpdateAsync` or `DeleteAsync` methods (since MongoDB has not a change tracking system).
#### AbpEntityChangeOptions
There is a `PublishEntityUpdatedEventWhenNavigationChanges` option in the `AbpEntityChangeOptions` class with a default value of `true`.
If you set it to `false`, the `EntityUpdatedEventData<T>` will not be published when a navigation property changes.
> This option is only used for the EF Core.
## See Also ## See Also
* [Distributed Event Bus](Distributed-Event-Bus.md) * [Distributed Event Bus](Distributed-Event-Bus.md)

6
docs/en/Modules/Cms-Kit/Comments.md

@ -80,6 +80,12 @@ You can also view and manage replies on this page.
![comments-detail](../../images/cmskit-module-comments-detail.png) ![comments-detail](../../images/cmskit-module-comments-detail.png)
## Settings
You can configure the approval status of comments using the "Comment" tab under the "Cms" section on the Settings page. When this feature is enabled, you can approve and reject comments. In this way, users can only see the comments that you approve. By default, this feature is set to "false."
![comments-settings](../../images/cmskit-module-comments-settings.png)
## Internals ## Internals
### Domain Layer ### Domain Layer

112
docs/en/Multi-Tenancy.md

@ -1,6 +1,6 @@
# Multi-Tenancy # Multi-Tenancy
Multi-Tenancy is a widely used architecture to create **SaaS applications** where the hardware and software **resources are shared by the customers** (tenants). ABP Framework provides all the base functionalities to create **multi tenant applications**. Multi-Tenancy is a widely used architecture to create **SaaS applications** where the hardware and software **resources are shared by the customers** (tenants). ABP Framework provides all the base functionalities to create **multi tenant applications**.
Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) the multi-tenancy as like that: Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) the multi-tenancy as like that:
@ -10,8 +10,8 @@ Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) the multi-tenanc
There are two main side of a typical SaaS / Multi-tenant application: There are two main side of a typical SaaS / Multi-tenant application:
* A **Tenant** is a customer of the SaaS application that pays money to use the service. - A **Tenant** is a customer of the SaaS application that pays money to use the service.
* **Host** is the company that owns the SaaS application and manages the system. - **Host** is the company that owns the SaaS application and manages the system.
The Host and the Tenant terms will be used for that purpose in the rest of the document. The Host and the Tenant terms will be used for that purpose in the rest of the document.
@ -36,9 +36,9 @@ Configure<AbpMultiTenancyOptions>(options =>
ABP Framework supports all the following approaches to store the tenant data in the database; ABP Framework supports all the following approaches to store the tenant data in the database;
* **Single Database**: All tenants are stored in a single database. - **Single Database**: All tenants are stored in a single database.
* **Database per Tenant**: Every tenant has a separate, dedicated database to store the data related to that tenant. - **Database per Tenant**: Every tenant has a separate, dedicated database to store the data related to that tenant.
* **Hybrid**: Some tenants share a single databases while some tenants may have their own databases. - **Hybrid**: Some tenants share a single database while some tenants may have their own databases.
[Tenant management module](Modules/Tenant-Management.md) (which comes pre-installed with the startup projects) allows you to set a connection string for any tenant (as optional), so you can achieve any of the approaches. [Tenant management module](Modules/Tenant-Management.md) (which comes pre-installed with the startup projects) allows you to set a connection string for any tenant (as optional), so you can achieve any of the approaches.
@ -48,11 +48,11 @@ Multi-tenancy system is designed to **work seamlessly** and make your applicatio
### IMultiTenant ### IMultiTenant
You should implement the `IMultiTenant` interface for your [entities](Entities.md) to make them **multi-tenancy ready**. You should implement the `IMultiTenant` interface for your [entities](Entities.md) to make them **multi-tenancy ready**.
**Example: A multi-tenant *Product* entity** **Example: A multi-tenant _Product_ entity**
````csharp ```csharp
using System; using System;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
@ -68,7 +68,7 @@ namespace MultiTenancyDemo.Products
public float Price { get; set; } public float Price { get; set; }
} }
} }
```` ```
`IMultiTenant` interface just defines a `TenantId` property. When you implement this interface, ABP Framework **automatically** [filters](Data-Filtering.md) entities for the current tenant when you query from database. So, you don't need to manually add `TenantId` condition while performing queries. A tenant can not access to data of another tenant by default. `IMultiTenant` interface just defines a `TenantId` property. When you implement this interface, ABP Framework **automatically** [filters](Data-Filtering.md) entities for the current tenant when you query from database. So, you don't need to manually add `TenantId` condition while performing queries. A tenant can not access to data of another tenant by default.
@ -96,9 +96,9 @@ If you set the `TenantId` value for a specific entity object, it will override t
`ICurrentTenant` defines the following properties; `ICurrentTenant` defines the following properties;
* `Id` (`Guid`): Id of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request. - `Id` (`Guid`): Id of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request.
* `Name` (`string`): Name of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request. - `Name` (`string`): Name of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request.
* `IsAvailable` (`bool`): Returns `true` if the `Id` is not `null`. - `IsAvailable` (`bool`): Returns `true` if the `Id` is not `null`.
#### Change the Current Tenant #### Change the Current Tenant
@ -108,7 +108,7 @@ ABP Framework automatically filters the resources (database, cache...) based on
**Example: Get product count of a specific tenant** **Example: Get product count of a specific tenant**
````csharp ```csharp
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -134,11 +134,11 @@ namespace MultiTenancyDemo.Products
} }
} }
} }
```` ```
* `Change` method can be used in a **nested way**. It restores the `CurrentTenant.Id` to the previous value after the `using` statement. - `Change` method can be used in a **nested way**. It restores the `CurrentTenant.Id` to the previous value after the `using` statement.
* When you use `CurrentTenant.Id` inside the `Change` scope, you get the `tenantId` provided to the `Change` method. So, the repository also get this `tenantId` and can filter the database query accordingly. - When you use `CurrentTenant.Id` inside the `Change` scope, you get the `tenantId` provided to the `Change` method. So, the repository also get this `tenantId` and can filter the database query accordingly.
* Use `CurrentTenant.Change(null)` to change scope to the host context. - Use `CurrentTenant.Change(null)` to change scope to the host context.
> Always use the `Change` method with a `using` statement like done in this example. > Always use the `Change` method with a `using` statement like done in this example.
@ -148,7 +148,7 @@ As mentioned before, ABP Framework handles data isolation between tenants using
**Example: Get count of products in the database, including all the products of all the tenants.** **Example: Get count of products in the database, including all the products of all the tenants.**
````csharp ```csharp
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Data; using Volo.Abp.Data;
@ -181,7 +181,7 @@ namespace MultiTenancyDemo.Products
} }
} }
```` ```
See the [Data Filtering document](Data-Filtering.md) for more. See the [Data Filtering document](Data-Filtering.md) for more.
@ -201,15 +201,15 @@ ABP Framework provides an extensible **Tenant Resolving** system for that purpos
The following resolvers are provided and configured by default; The following resolvers are provided and configured by default;
* `CurrentUserTenantResolveContributor`: Gets the tenant id from claims of the current user, if the current user has logged in. **This should always be the first contributor for the security**. - `CurrentUserTenantResolveContributor`: Gets the tenant id from claims of the current user, if the current user has logged in. **This should always be the first contributor for the security**.
* `QueryStringTenantResolveContributor`: Tries to find current tenant id from query string parameters. The parameter name is `__tenant` by default. - `QueryStringTenantResolveContributor`: Tries to find current tenant id from query string parameters. The parameter name is `__tenant` by default.
* `RouteTenantResolveContributor`: Tries to find current tenant id from route (URL path). The variable name is `__tenant` by default. If you defined a route with this variable, then it can determine the current tenant from the route. - `RouteTenantResolveContributor`: Tries to find current tenant id from route (URL path). The variable name is `__tenant` by default. If you defined a route with this variable, then it can determine the current tenant from the route.
* `HeaderTenantResolveContributor`: Tries to find current tenant id from HTTP headers. The header name is `__tenant` by default. - `HeaderTenantResolveContributor`: Tries to find current tenant id from HTTP headers. The header name is `__tenant` by default.
* `CookieTenantResolveContributor`: Tries to find current tenant id from cookie values. The cookie name is `__tenant` by default. - `CookieTenantResolveContributor`: Tries to find current tenant id from cookie values. The cookie name is `__tenant` by default.
###### Problems with the NGINX ###### Problems with the NGINX
You may have problems with the `__tenant` in the HTTP Headers if you're using the [nginx](https://www.nginx.com/) as the reverse proxy server. Because it doesn't allow to use underscore and some other special characters in the HTTP headers and you may need to manually configure it. See the following documents please: You may have problems with the `__tenant` in the HTTP Headers if you're using the [nginx](https://www.nginx.com/) as the reverse proxy server. Because it doesn't allow to use underscore and some other special characters in the HTTP headers and you may need to manually configure it. See the following documents please:
http://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers http://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers
http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
@ -219,22 +219,24 @@ http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
**Example:** **Example:**
````csharp ```csharp
services.Configure<AbpAspNetCoreMultiTenancyOptions>(options => services.Configure<AbpAspNetCoreMultiTenancyOptions>(options =>
{ {
options.TenantKey = "MyTenantKey"; options.TenantKey = "MyTenantKey";
}); });
```` ```
If you change the `TenantKey`, make sure to pass it to `CoreModule` in the Angular client as follows: If you change the `TenantKey`, make sure to pass it to `provideAbpCore` via `withOptions` method in the Angular client as follows:
```js ```js
@NgModule({ @NgModule({
imports: [ providers: [
CoreModule.forRoot({ provideAbpCore(
// ... withOptions({
tenantKey: 'MyTenantKey' // ...
}), tenantKey: "MyTenantKey",
})
),
], ],
// ... // ...
}) })
@ -249,7 +251,7 @@ import { TENANT_KEY } from '@abp/ng.core';
class SomeComponent { class SomeComponent {
constructor(@Inject(TENANT_KEY) private tenantKey: string) {} constructor(@Inject(TENANT_KEY) private tenantKey: string) {}
} }
``` ```
> However, we don't suggest to change this value since some clients may assume the the `__tenant` as the parameter name and they might need to manually configure then. > However, we don't suggest to change this value since some clients may assume the the `__tenant` as the parameter name and they might need to manually configure then.
@ -277,30 +279,30 @@ In a real application, most of times you will want to determine the current tena
**Example: Add a subdomain resolver** **Example: Add a subdomain resolver**
````csharp ```csharp
Configure<AbpTenantResolveOptions>(options => Configure<AbpTenantResolveOptions>(options =>
{ {
options.AddDomainTenantResolver("{0}.mydomain.com"); options.AddDomainTenantResolver("{0}.mydomain.com");
}); });
```` ```
* `{0}` is the placeholder to determine the current tenant's unique name. - `{0}` is the placeholder to determine the current tenant's unique name.
* Add this code to the `ConfigureServices` method of your [module](Module-Development-Basics.md). - Add this code to the `ConfigureServices` method of your [module](Module-Development-Basics.md).
* This should be done in the *Web/API Layer* since the URL is a web related stuff. - This should be done in the _Web/API Layer_ since the URL is a web related stuff.
Openiddict is the default Auth Server in ABP (since v6.0). When you use OpenIddict, you must add this code to the `PreConfigure` method as well. Openiddict is the default Auth Server in ABP (since v6.0). When you use OpenIddict, you must add this code to the `PreConfigure` method as well.
```csharp ```csharp
// using Volo.Abp.OpenIddict.WildcardDomains // using Volo.Abp.OpenIddict.WildcardDomains
PreConfigure<AbpOpenIddictWildcardDomainOptions>(options => PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
{ {
options.EnableWildcardDomainSupport = true; options.EnableWildcardDomainSupport = true;
options.WildcardDomainsFormat.Add("https://{0}.mydomain.com"); options.WildcardDomainsFormat.Add("https://{0}.mydomain.com");
}); });
``` ```
You must add this code to the `Configure` method as well. You must add this code to the `Configure` method as well.
```csharp ```csharp
// using Volo.Abp.MultiTenancy; // using Volo.Abp.MultiTenancy;
@ -312,7 +314,7 @@ Configure<AbpTenantResolveOptions>(options =>
``` ```
> There is an [example](https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver) that uses the subdomain to determine the current tenant. > There is an [example](https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver) that uses the subdomain to determine the current tenant.
If you use a sepereted Auth server, you must install `[Owl.TokenWildcardIssuerValidator](https://www.nuget.org/packages/Owl.TokenWildcardIssuerValidator)` on the `HTTPApi.Host` project If you use a sepereted Auth server, you must install `[Owl.TokenWildcardIssuerValidator](https://www.nuget.org/packages/Owl.TokenWildcardIssuerValidator)` on the `HTTPApi.Host` project
@ -332,7 +334,7 @@ context.Services
options.Authority = configuration["AuthServer:Authority"]; options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.Audience = "ExampleProjectName"; options.Audience = "ExampleProjectName";
// start of added block // start of added block
options.TokenValidationParameters.IssuerValidator = TokenWildcardIssuerValidator.IssuerValidator; options.TokenValidationParameters.IssuerValidator = TokenWildcardIssuerValidator.IssuerValidator;
options.TokenValidationParameters.ValidIssuers = new[] options.TokenValidationParameters.ValidIssuers = new[]
@ -348,16 +350,16 @@ context.Services
You can add implement your custom tenant resolver and configure the `AbpTenantResolveOptions` in your module's `ConfigureServices` method as like below: You can add implement your custom tenant resolver and configure the `AbpTenantResolveOptions` in your module's `ConfigureServices` method as like below:
````csharp ```csharp
Configure<AbpTenantResolveOptions>(options => Configure<AbpTenantResolveOptions>(options =>
{ {
options.TenantResolvers.Add(new MyCustomTenantResolveContributor()); options.TenantResolvers.Add(new MyCustomTenantResolveContributor());
}); });
```` ```
`MyCustomTenantResolveContributor` must inherit from the `TenantResolveContributorBase` (or implement the `ITenantResolveContributor`) as shown below: `MyCustomTenantResolveContributor` must inherit from the `TenantResolveContributorBase` (or implement the `ITenantResolveContributor`) as shown below:
````csharp ```csharp
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
@ -373,10 +375,10 @@ namespace MultiTenancyDemo.Web
} }
} }
} }
```` ```
* A tenant resolver should set `context.TenantIdOrName` if it can determine it. If not, just leave it as is to allow the next resolver to determine it. - A tenant resolver should set `context.TenantIdOrName` if it can determine it. If not, just leave it as is to allow the next resolver to determine it.
* `context.ServiceProvider` can be used if you need to additional services to resolve from the [dependency injection](Dependency-Injection.md) system. - `context.ServiceProvider` can be used if you need to additional services to resolve from the [dependency injection](Dependency-Injection.md) system.
#### Multi-Tenancy Middleware #### Multi-Tenancy Middleware
@ -384,9 +386,9 @@ Multi-Tenancy middleware is an ASP.NET Core request pipeline [middleware](https:
Multi-Tenancy middleware is typically placed just under the [authentication](https://docs.microsoft.com/en-us/aspnet/core/security/authentication) middleware (`app.UseAuthentication()`): Multi-Tenancy middleware is typically placed just under the [authentication](https://docs.microsoft.com/en-us/aspnet/core/security/authentication) middleware (`app.UseAuthentication()`):
````csharp ```csharp
app.UseMultiTenancy(); app.UseMultiTenancy();
```` ```
> This middleware is already configured in the startup templates, so you normally don't need to manually add it. > This middleware is already configured in the startup templates, so you normally don't need to manually add it.
@ -406,7 +408,7 @@ The [tenant management module](Modules/Tenant-Management) is **included in the s
**Example: Define tenants in appsettings.json** **Example: Define tenants in appsettings.json**
````json ```json
"Tenants": [ "Tenants": [
{ {
"Id": "446a5211-3d72-4339-9adc-845151f8ada0", "Id": "446a5211-3d72-4339-9adc-845151f8ada0",
@ -422,7 +424,7 @@ The [tenant management module](Modules/Tenant-Management) is **included in the s
} }
} }
] ]
```` ```
> It is recommended to **use the Tenant Management module**, which is already pre-configured when you create a new application with the ABP startup templates. > It is recommended to **use the Tenant Management module**, which is already pre-configured when you create a new application with the ABP startup templates.
@ -440,4 +442,4 @@ The [Tenant Management module](Modules/Tenant-Management.md) provides a basic UI
## See Also ## See Also
* [Features](Features.md) - [Features](Features.md)

13
docs/en/Themes/LeptonXLite/Angular.md

@ -31,20 +31,21 @@ yarn add bootstrap-icons
Note: You should remove the old theme styles from "angular.json" if you are switching from "ThemeBasic" or "Lepton." Note: You should remove the old theme styles from "angular.json" if you are switching from "ThemeBasic" or "Lepton."
Look at the [Theme Configurations](../../UI/Angular/Theme-Configurations) list of styles. Depending on your theme, you can alter your styles in angular.json. Look at the [Theme Configurations](../../UI/Angular/Theme-Configurations) list of styles. Depending on your theme, you can alter your styles in angular.json.
- Finally, remove `ThemeBasicModule` from `app.module.ts`, and import the related modules in `app.module.ts` - Finally, remove `ThemeBasicModule`, `provideThemeBasicConfig` from `app.module.ts`, and import the related modules in `app.module.ts`
```js ```js
import { ThemeLeptonXModule } from "@abp/ng.theme.lepton-x"; import { ThemeLeptonXModule } from "@abp/ng.theme.lepton-x";
import { SideMenuLayoutModule } from "@abp/ng.theme.lepton-x/layouts";
@NgModule({ @NgModule({
imports: [ imports: [
// ... // ...
// do not forget to remove ThemeBasicModule or other old theme module // do not forget to remove ThemeBasicModule or other old theme module
// ThemeBasicModule.forRoot(), // ThemeBasicModule
ThemeLeptonXModule.forRoot(), ThemeLeptonXModule.forRoot()
SideMenuLayoutModule.forRoot(), ],
providers: [
// do not forget to remove provideThemeBasicConfig or other old theme providers
// provideThemeBasicConfig
], ],
// ... // ...
}) })

19
docs/en/UI/Angular/Account-Module.md

@ -7,7 +7,6 @@ If you add the account module to your project;
- "My account" link in the current user dropdown on the top bar will redirect the user to a page in the account module. - "My account" link in the current user dropdown on the top bar will redirect the user to a page in the account module.
- You can switch the authentication flow to the resource owner password flow. - You can switch the authentication flow to the resource owner password flow.
### Account Module Implementation ### Account Module Implementation
Install the `@abp/ng.account` NPM package by running the below command: Install the `@abp/ng.account` NPM package by running the below command:
@ -18,18 +17,18 @@ npm install @abp/ng.account
> Make sure v4.3 or higher version is installed. > Make sure v4.3 or higher version is installed.
Open the `app.module.ts` and add `AccountConfigModule.forRoot()` to the imports array as shown below: Open the `app.module.ts` and add `provideAccountConfig()` to the providers array as shown below:
```js ```js
// app.module.ts // app.module.ts
import { AccountConfigModule } from '@abp/ng.account/config'; import { provideAccountConfig } from "@abp/ng.account/config";
//... //...
@NgModule({ @NgModule({
imports: [ providers: [
//... //...
AccountConfigModule.forRoot() provideAccountConfig(),
], ],
//... //...
}) })
@ -57,19 +56,19 @@ The pro startup template comes with `@volo/abp.ng.account` package. You should u
```bash ```bash
npm install @volo/abp.ng.account npm install @volo/abp.ng.account
``` ```
> Make sure v4.3 or higher version is installed. > Make sure v4.3 or higher version is installed.
Open the `app.module.ts` and add `AccountPublicConfigModule.forRoot()` to the imports array as shown below: Open the `app.module.ts` and add `AccountPublicConfigModule.forRoot()` to the imports array as shown below:
> Ensure that the `Account Layout Module` has been added if you are using the Lepton X theme. If you miss the step, you will get an error message that says `Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "AccountLayoutModule.forRoot()" to your app.module configuration.` when you try to access the account pages. Otherwise, you can skip adding the `AccountLayoutModule` step. > Ensure that the `Account Layout Module` has been added if you are using the Lepton X theme. If you miss the step, you will get an error message that says `Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "AccountLayoutModule.forRoot()" to your app.module configuration.` when you try to access the account pages. Otherwise, you can skip adding the `AccountLayoutModule` step.
```js ```js
// app.module.ts // app.module.ts
import { AccountPublicConfigModule } from '@volo/abp.ng.account/public/config'; import { AccountPublicConfigModule } from "@volo/abp.ng.account/public/config";
// if you are using or want to use Lepton X, you should add AccountLayoutModule // if you are using or want to use Lepton X, you should add AccountLayoutModule
// import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account' // import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account'
//... //...
@ -104,9 +103,9 @@ Before v4.3, the "My account" link in the current user dropdown on the top bar r
### Personal Info Page Confirm Message ### Personal Info Page Confirm Message
When the user changes their own data on the personal settings tab in My Account, The data can not update the CurrentUser key of Application-Configuration. The information of the user is stored in claims. The only way to apply this information to the CurrentUser of Application-Configuration is user should log out and log in. When the Refresh-Token feature is implemented, it will be fixed. So We've added a confirmation alert. When the user changes their own data on the personal settings tab in My Account, The data can not update the CurrentUser key of Application-Configuration. The information of the user is stored in claims. The only way to apply this information to the CurrentUser of Application-Configuration is user should log out and log in. When the Refresh-Token feature is implemented, it will be fixed. So We've added a confirmation alert.
If you want to disable these warning, You should set `isPersonalSettingsChangedConfirmationActive` false If you want to disable these warning, You should set `isPersonalSettingsChangedConfirmationActive` false
```js ```js
// app-routing.module.ts // app-routing.module.ts

2
docs/en/UI/Angular/Basic-Theme.md

@ -11,7 +11,7 @@ The Basic Theme is a theme implementation for the Angular UI. It is a minimalist
If you need to manually this theme, follow the steps below: If you need to manually this theme, follow the steps below:
* Install the [@abp/ng.theme.basic](https://www.npmjs.com/package/@abp/ng.theme.basic) NPM package to your Angular project. * Install the [@abp/ng.theme.basic](https://www.npmjs.com/package/@abp/ng.theme.basic) NPM package to your Angular project.
* Open the `src/app/app.module.ts` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule.forRoot()` to the `imports` array. * Open the `src/app/app.module.ts` file, import `ThemeBasicModule`,`provideThemeBasicConfig` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` array and provide `provideThemeBasicConfig()` to the providers array.
* Open the `src/app/shared/shared.module` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` and `exports` array. * Open the `src/app/shared/shared.module` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` and `exports` array.
The `ThemeBasicModule` is registered own layouts (`ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`) to a service which is exposed by `@abp/ng.core` package on application initialization. The `ThemeBasicModule` is registered own layouts (`ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`) to a service which is exposed by `@abp/ng.core` package on application initialization.

117
docs/en/UI/Angular/Component-Replacement.md

@ -30,7 +30,6 @@ export class AppComponent {
![Example Usage](./images/component-replacement.gif) ![Example Usage](./images/component-replacement.gif)
## How to Replace a Layout ## How to Replace a Layout
Each ABP theme module has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced the same way. Each ABP theme module has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced the same way.
@ -88,11 +87,13 @@ This component should have a 'router-outlet' for dynamic content loading. You ca
```bash ```bash
ng generate component new-layout ng generate component new-layout
``` ```
This command will create a new component named `new-layout`. Now, open the new-layout.component.html file and add a `router-outlet` to it: This command will create a new component named `new-layout`. Now, open the new-layout.component.html file and add a `router-outlet` to it:
```html ```html
<router-outlet></router-outlet> <router-outlet></router-outlet>
``` ```
This 'router-outlet' will act as a placeholder that Angular dynamically fills based on the current router state. This 'router-outlet' will act as a placeholder that Angular dynamically fills based on the current router state.
note: (don't forget: you should add the app in the app.module.ts file) note: (don't forget: you should add the app in the app.module.ts file)
@ -103,10 +104,11 @@ Although this step is optional, it can be useful if you're going to use the layo
```javascript ```javascript
export const eCustomLayout = { export const eCustomLayout = {
key: 'CustomLayout', key: "CustomLayout",
component: 'CustomLayoutComponent', component: "CustomLayoutComponent",
}; };
``` ```
In this variable, `key` is a unique identifier for the layout component, and `component` is the name of the layout component. In this variable, `key` is a unique identifier for the layout component, and `component` is the name of the layout component.
You can use this variable when you need to refer to the layout component. You can use this variable when you need to refer to the layout component.
@ -120,19 +122,24 @@ Here's how you can do it:
```javascript ```javascript
export const CUSTOM_LAYOUT_PROVIDERS = [ export const CUSTOM_LAYOUT_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureLayoutFn, deps: [ReplaceableComponentsService], multi: true }, {
provide: APP_INITIALIZER,
useFactory: configureLayoutFn,
deps: [ReplaceableComponentsService],
multi: true,
},
]; ];
function configureLayoutFn() { function configureLayoutFn() {
const service= inject( ReplaceableComponentsService) const service = inject(ReplaceableComponentsService);
return () =>{ return () => {
service.add({ service.add({
key: eCustomLayout.component, key: eCustomLayout.component,
component: CustomLayoutComponent, component: CustomLayoutComponent,
}) });
} };
} }
``` ```
In this code, `configureLayoutFn` is a factory function that adds the new layout component to the `ReplaceableComponentsService`. The `APP_INITIALIZER` provider runs this function when the application starts. In this code, `configureLayoutFn` is a factory function that adds the new layout component to the `ReplaceableComponentsService`. The `APP_INITIALIZER` provider runs this function when the application starts.
note: (don't forget: you should add the CUSTOM_LAYOUT_PROVIDERS in the app.module.ts file) note: (don't forget: you should add the CUSTOM_LAYOUT_PROVIDERS in the app.module.ts file)
@ -149,34 +156,31 @@ export const myDynamicLayouts = new Map<string, string>([...DEFAULT_DYNAMIC_LAYO
#### Step 5: Pass the Dynamic Layouts to the CoreModule #### Step 5: Pass the Dynamic Layouts to the CoreModule
The final step is to pass the dynamic layouts to the `CoreModule` using the `forRoot` method. This method allows you to configure the module with a static method. The final step is to pass the dynamic layouts to the `provideAbpCore` using the `withOptions` method. This method allows you to configure the module with a static method.
Here's how you can do it: Here's how you can do it:
```javascript ```ts
@NgModule({ @NgModule({
declarations: [AppComponent], providers: [
imports: [ // ...
// other imports... provideAbpCore(
CoreModule.forRoot({ withOptions({
dynamicLayouts: myDynamicLayouts, dynamicLayouts: myDynamicLayouts,
environment, environment,
registerLocaleFn: registerLocale(), registerLocaleFn: registerLocale(),
}), }),
// other imports... ),
NewLayoutComponent
], ],
providers: [APP_ROUTE_PROVIDER, CUSTOM_LAYOUT_PROVIDERS],
bootstrap: [AppComponent],
}) })
export class AppModule {} export class AppModule {}
``` ```
In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `CoreModule` using the `forRoot` method.
In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `provideAbpCore` using the `withOptions` method.
Now that you have defined the new layout, you can use it in the router definition. You do this by adding a new route that uses the new layout. Now that you have defined the new layout, you can use it in the router definition. You do this by adding a new route that uses the new layout.
Here's how you can do it: Here's how you can do it:
```javascript ```javascript
// route.provider.ts // route.provider.ts
@ -221,14 +225,13 @@ Run the following command in `angular` folder to create a new component called `
yarn ng generate component logo --inlineTemplate --inlineStyle yarn ng generate component logo --inlineTemplate --inlineStyle
``` ```
Open the generated `logo.component.ts` in `src/app/logo` folder and replace its content with the following: Open the generated `logo.component.ts` in `src/app/logo` folder and replace its content with the following:
```js ```js
import { Component } from '@angular/core'; import { Component } from "@angular/core";
@Component({ @Component({
selector: 'app-logo', selector: "app-logo",
template: ` template: `
<a class="navbar-brand" routerLink="/"> <a class="navbar-brand" routerLink="/">
<!-- Change the img src --> <!-- Change the img src -->
@ -284,14 +287,14 @@ yarn ng generate component routes
Open the generated `routes.component.ts` in `src/app/routes` folder and replace its content with the following: Open the generated `routes.component.ts` in `src/app/routes` folder and replace its content with the following:
```js ```js
import { Component, HostBinding } from '@angular/core'; import { Component, HostBinding } from "@angular/core";
@Component({ @Component({
selector: 'app-routes', selector: "app-routes",
templateUrl: 'routes.component.html', templateUrl: "routes.component.html",
}) })
export class RoutesComponent { export class RoutesComponent {
@HostBinding('class.mx-auto') @HostBinding("class.mx-auto")
marginAuto = true; marginAuto = true;
get smallScreen() { get smallScreen() {
@ -321,11 +324,14 @@ Open the generated `routes.component.html` in `src/app/routes` folder and replac
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" routerLink="/" <a class="nav-link" routerLink="/"
><i class="fas fa-home"></i> {%{{{ '::Menu:Home' | abpLocalization }}}%}</a ><i class="fas fa-home"></i> {%{{{ '::Menu:Home' | abpLocalization
}}}%}</a
> >
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" routerLink="/my-page"><i class="fas fa-newspaper mr-1"></i>My Page</a> <a class="nav-link" routerLink="/my-page"
><i class="fas fa-newspaper mr-1"></i>My Page</a
>
</li> </li>
<li <li
#navbarRootDropdown #navbarRootDropdown
@ -338,7 +344,11 @@ Open the generated `routes.component.html` in `src/app/routes` folder and replac
: (navbarRootDropdown.expand = true) : (navbarRootDropdown.expand = true)
" "
> >
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)"> <a
class="nav-link dropdown-toggle"
data-toggle="dropdown"
href="javascript:void(0)"
>
<i class="fas fa-wrench"></i> <i class="fas fa-wrench"></i>
{%{{{ 'AbpUiNavigation::Menu:Administration' | abpLocalization }}}%} {%{{{ 'AbpUiNavigation::Menu:Administration' | abpLocalization }}}%}
</a> </a>
@ -401,7 +411,8 @@ Open the generated `routes.component.html` in `src/app/routes` folder and replac
class="btn d-block text-start dropdown-toggle" class="btn d-block text-start dropdown-toggle"
> >
<i class="fa fa-users"></i> <i class="fa fa-users"></i>
{%{{{ 'AbpTenantManagement::Menu:TenantManagement' | abpLocalization }}}%} {%{{{ 'AbpTenantManagement::Menu:TenantManagement' | abpLocalization
}}}%}
</a> </a>
</div> </div>
<div <div
@ -409,7 +420,10 @@ Open the generated `routes.component.html` in `src/app/routes` folder and replac
class="dropdown-menu border-0 shadow-sm" class="dropdown-menu border-0 shadow-sm"
[class.d-block]="smallScreen && dropdownSubmenu.isOpen()" [class.d-block]="smallScreen && dropdownSubmenu.isOpen()"
> >
<div class="dropdown-submenu" *abpPermission="'AbpTenantManagement.Tenants'"> <div
class="dropdown-submenu"
*abpPermission="'AbpTenantManagement.Tenants'"
>
<a class="dropdown-item" routerLink="/tenant-management/tenants"> <a class="dropdown-item" routerLink="/tenant-management/tenants">
{%{{{ 'AbpTenantManagement::Tenants' | abpLocalization }}}%}</a {%{{{ 'AbpTenantManagement::Tenants' | abpLocalization }}}%}</a
> >
@ -554,7 +568,11 @@ Open the generated `nav-items.component.html` in `src/app/nav-items` folder and
```html ```html
<ul class="navbar-nav"> <ul class="navbar-nav">
<input type="search" placeholder="Search" class="bg-transparent border-0 text-white" /> <input
type="search"
placeholder="Search"
class="bg-transparent border-0 text-white"
/>
<li class="nav-item d-flex align-items-center"> <li class="nav-item d-flex align-items-center">
<div <div
*ngIf="(dropdownLanguages$ | async)?.length > 0" *ngIf="(dropdownLanguages$ | async)?.length > 0"
@ -592,9 +610,9 @@ Open the generated `nav-items.component.html` in `src/app/nav-items` folder and
</li> </li>
<li class="nav-item d-flex align-items-center"> <li class="nav-item d-flex align-items-center">
<ng-template #loginBtn> <ng-template #loginBtn>
<a role="button" class="nav-link pointer" (click)="navigateToLogin()">{%{{{ <a role="button" class="nav-link pointer" (click)="navigateToLogin()"
'AbpAccount::Login' | abpLocalization >{%{{{ 'AbpAccount::Login' | abpLocalization }}}%}</a
}}}%}</a> >
</ng-template> </ng-template>
<div <div
*ngIf="(currentUser$ | async)?.isAuthenticated; else loginBtn" *ngIf="(currentUser$ | async)?.isAuthenticated; else loginBtn"
@ -614,8 +632,7 @@ Open the generated `nav-items.component.html` in `src/app/nav-items` folder and
aria-expanded="false" aria-expanded="false"
> >
<small *ngIf="(selectedTenant$ | async)?.name as tenantName" <small *ngIf="(selectedTenant$ | async)?.name as tenantName"
><i>{%{{{ tenantName }}}%}</i ><i>{%{{{ tenantName }}}%}</i>\</small
>\</small
> >
<strong>{%{{{ (currentUser$ | async)?.userName }}}%}</strong> <strong>{%{{{ (currentUser$ | async)?.userName }}}%}</strong>
</a> </a>
@ -625,10 +642,12 @@ Open the generated `nav-items.component.html` in `src/app/nav-items` folder and
[class.d-block]="smallScreen && currentUserDropdown.isOpen()" [class.d-block]="smallScreen && currentUserDropdown.isOpen()"
> >
<a class="dropdown-item pointer" (click)="navigateToManageProfile()" <a class="dropdown-item pointer" (click)="navigateToManageProfile()"
><i class="fa fa-cog mr-1"></i>{%{{{ 'AbpAccount::MyAccount' | abpLocalization }}}%}</a ><i class="fa fa-cog mr-1"></i>{%{{{ 'AbpAccount::MyAccount' |
abpLocalization }}}%}</a
> >
<a class="dropdown-item" href="javascript:void(0)" (click)="logout()" <a class="dropdown-item" href="javascript:void(0)" (click)="logout()"
><i class="fa fa-power-off mr-1"></i>{%{{{ 'AbpUi::Logout' | abpLocalization }}}%}</a ><i class="fa fa-power-off mr-1"></i>{%{{{ 'AbpUi::Logout' |
abpLocalization }}}%}</a
> >
</div> </div>
</div> </div>

37
docs/en/UI/Angular/Confirmation-Service.md

@ -71,10 +71,10 @@ const options: Partial<Confirmation.Options> = {
yesText: "Confirm", yesText: "Confirm",
messageLocalizationParams: ["Demo"], messageLocalizationParams: ["Demo"],
titleLocalizationParams: [], titleLocalizationParams: [],
// You can customize icon // You can customize icon
// icon: 'fa fa-exclamation-triangle', // or // icon: 'fa fa-exclamation-triangle', // or
// iconTemplate : '<img src="custom-image-path.jpg" alt=""/>' // iconTemplate : '<img src="custom-image-path.jpg" alt=""/>'
} };
this.confirmation.warn( this.confirmation.warn(
"AbpIdentity::RoleDeletionConfirmationMessage", "AbpIdentity::RoleDeletionConfirmationMessage",
@ -129,23 +129,26 @@ this.confirmation.clear();
### How to Change Icons of The Confirmation Popup ### How to Change Icons of The Confirmation Popup
You can change icons with the token of "confirmationIcons" in ThemeSharedModule in the app.module.ts. The changes will affect all confirmation popup in the project. You can change icons with the `withConfirmationIcon()` method of `provideAbpThemeShared` function in the app.module.ts. The changes will affect all confirmation popup in the project.
```js ```ts
... import { provideAbpThemeShared, withConfirmationIcon } from '@abp/ng.theme.shared';
ThemeSharedModule.forRoot({
confirmationIcons: { @NgModule({
info: 'fa fa-info-circle', providers: [
success: 'fa fa-check-circle', // ...
warning: 'fa fa-exclamation-triangle', provideAbpThemeShared(withConfirmationIcon({
error: 'fa fa-times-circle', info: 'fa fa-info-circle',
default: 'fa fa-question-circle', success: 'fa fa-check-circle',
}, warning: 'fa fa-exclamation-triangle',
}), error: 'fa fa-times-circle',
... default: 'fa fa-question-circle',
})),
],
})
export class AppModule {}
``` ```
## API ## API
### success ### success

8
docs/en/UI/Angular/Feature-Libraries.md

@ -41,13 +41,13 @@ yarn add @abp/ng.identity
As of ABP v3.0, every lazy-loaded module has a config module available via a secondary entry point on the same package. Importing them in your root module looks like this: As of ABP v3.0, every lazy-loaded module has a config module available via a secondary entry point on the same package. Importing them in your root module looks like this:
```js ```ts
import { IdentityConfigModule } from "@abp/ng.identity/config"; import { provideIdentityConfig } from "@abp/ng.identity/config";
@NgModule({ @NgModule({
imports: [ providers: [
// other imports // other imports
IdentityConfigModule.forRoot(), provideIdentityConfig(),
], ],
// providers, declarations, and bootstrap // providers, declarations, and bootstrap
}) })

52
docs/en/UI/Angular/Form-Validation.md

@ -6,28 +6,20 @@ Reactive forms in ABP Angular UI are validated by [ngx-validate](https://www.npm
## How to Add New Error Messages ## How to Add New Error Messages
You can add a new error message by passing validation options to the `ThemeSharedModule` in your root module. You can add a new error message by passing validation options to the `withValidationBluePrint` method of `provideAbpThemeShared` function in your root module.
```js ```ts
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared';
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({ @NgModule({
imports: [ providers: [
ThemeSharedModule.forRoot({ provideAbpThemeShared(
validation: { withValidationBluePrint({
blueprints: { uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]"
uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]", })
}, ),
}, ...
// rest of theme shared config
}),
// other imports
], ],
// rest of the module metadata
}) })
export class AppModule {} export class AppModule {}
``` ```
@ -77,26 +69,16 @@ You can overwrite an existing error message by passing validation options to the
To use this instead of the built-in required input message, all you need to do is the following. To use this instead of the built-in required input message, all you need to do is the following.
```js ```ts
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared';
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({ @NgModule({
imports: [ providers: [
ThemeSharedModule.forRoot({ provideAbpThemeShared(withValidationBluePrint({
validation: { required: "::RequiredInput",
blueprints: { })),
required: "::RequiredInput", ...
},
},
// rest of theme shared config
}),
// other imports
], ],
// rest of the module metadata
}) })
export class AppModule {} export class AppModule {}
``` ```

22
docs/en/UI/Angular/HTTP-Error-Handling.md

@ -5,22 +5,20 @@
ABP offers a configurations for errors handling like below ABP offers a configurations for errors handling like below
```ts ```ts
import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { provideAbpThemeShared, withHttpErrorConfig } from '@abp/ng.theme.shared';
import { MyCustomRouteErrorComponent } from './my-custom-route.component'; import { MyCustomRouteErrorComponent } from './my-custom-route.component';
@NgModule({ @NgModule({
imports: [ providers: [
ThemeSharedModule.forRoot({ // ...
httpErrorConfig: { provideAbpThemeShared(withHttpErrorConfig({
skipHandledErrorCodes: [403], skipHandledErrorCodes: [403],
errorScreen: { errorScreen: {
forWhichErrors: [404], forWhichErrors: [404],
component: CustomErrorComponent, component: MyCustomRouteErrorComponent,
hideCloseIcon: false hideCloseIcon: false
}
} }
}), })),
...
], ],
}) })
export class AppModule {} export class AppModule {}

183
docs/en/UI/Angular/Localization.md

@ -11,7 +11,7 @@ The Localization key format consists of 2 sections which are **Resource Name** a
const environment = { const environment = {
//... //...
localization: { localization: {
defaultResourceName: 'MyProjectName', defaultResourceName: "MyProjectName",
}, },
}; };
``` ```
@ -38,7 +38,8 @@ You can also specify a default value as shown below:
```html ```html
<h1> <h1>
{%{{{ { key: 'Resource::Key', defaultValue: 'Default Value' } | abpLocalization }}}%} {%{{{ { key: 'Resource::Key', defaultValue: 'Default Value' } |
abpLocalization }}}%}
</h1> </h1>
``` ```
@ -82,17 +83,17 @@ After that, you are able to use localization service.
```js ```js
this.localizationService.instant( this.localizationService.instant(
'AbpIdentity::UserDeletionConfirmation', "AbpIdentity::UserDeletionConfirmation",
'John' "John"
); );
// with fallback value // with fallback value
this.localizationService.instant( this.localizationService.instant(
{ {
key: 'AbpIdentity::UserDeletionConfirmation', key: "AbpIdentity::UserDeletionConfirmation",
defaultValue: 'Default Value', defaultValue: "Default Value",
}, },
'John' "John"
); );
// Output // Output
@ -102,12 +103,12 @@ this.localizationService.instant(
To get a localized text as [_Observable_](https://rxjs.dev/guide/observable) use `get` method instead of `instant`: To get a localized text as [_Observable_](https://rxjs.dev/guide/observable) use `get` method instead of `instant`:
```js ```js
this.localizationService.get('Resource::Key'); this.localizationService.get("Resource::Key");
// with fallback value // with fallback value
this.localizationService.get({ this.localizationService.get({
key: 'Resource::Key', key: "Resource::Key",
defaultValue: 'Default Value', defaultValue: "Default Value",
}); });
``` ```
@ -118,41 +119,46 @@ Localizations can be determined on backend side. Angular UI gets the localizatio
See an example: See an example:
```ts ```ts
// app.module.ts import { provideAbpCore, withOptions } from '@abp/ng.core';
@NgModule({ @NgModule({
imports: [ providers: [
//...other imports // ...
CoreModule.forRoot({ provideAbpCore(
localizations: [ withOptions({
{ ...,
culture: 'en', localizations: [
resources: [ {
{ culture: 'en',
resourceName: 'MyProjectName', resources: [
texts: { {
Administration: 'Administration', resourceName: 'MyProjectName',
HomePage: 'Home', texts: {
Administration: 'Administration',
HomePage: 'Home',
},
}, },
}, ],
], },
}, {
{ culture: 'de',
culture: 'de', resources: [
resources: [ {
{ resourceName: 'MyProjectName',
resourceName: 'MyProjectName', texts: {
texts: { Administration: 'Verwaltung',
Administration: 'Verwaltung', HomePage: 'Startseite',
HomePage: 'Startseite', },
}, },
}, ],
], },
}, ],
], }),
}), ),
] ...
],
}) })
export class AppModule {}
``` ```
...or, you can determine the localizations in a feature module: ...or, you can determine the localizations in a feature module:
@ -256,10 +262,10 @@ Find [styles configuration in angular.json](https://angular.io/guide/workspace-c
If you have created and injected chunks for Fontawesome as seen above, you no longer need the lazy loading in the `AppComponent` which was implemented before v2.9. Simply remove them. The `AppComponent` in the template of the new version looks like this: If you have created and injected chunks for Fontawesome as seen above, you no longer need the lazy loading in the `AppComponent` which was implemented before v2.9. Simply remove them. The `AppComponent` in the template of the new version looks like this:
```js ```js
import { Component } from '@angular/core'; import { Component } from "@angular/core";
@Component({ @Component({
selector: 'app-root', selector: "app-root",
template: ` template: `
<abp-loader-bar></abp-loader-bar> <abp-loader-bar></abp-loader-bar>
<router-outlet></router-outlet> <router-outlet></router-outlet>
@ -274,33 +280,32 @@ Since ABP has more than one language, Angular locale files loads lazily using [W
### registerLocaleFn ### registerLocaleFn
`registerLocale` function that exported from `@abp/ng.core/locale` package is a higher order function that accepts `cultureNameLocaleFileMap` object and `errorHandlerFn` function as params and returns Webpack `import` function. A `registerLocale` function must be passed to the `forRoot` of the `CoreModule` as shown below: `registerLocale` function that exported from `@abp/ng.core/locale` package is a higher order function that accepts `cultureNameLocaleFileMap` object and `errorHandlerFn` function as params and returns Webpack `import` function. A `registerLocale` function must be passed to the `withOptions` of the `provideAbpCore` as shown below:
```js
// app.module.ts
```ts
import { provideAbpCore, withOptions } from '@abp/ng.core';
import { registerLocale } from '@abp/ng.core/locale'; import { registerLocale } from '@abp/ng.core/locale';
// if you have commercial license and the language management module, add the below import
// import { registerLocale } from '@volo/abp.ng.language-management/locale';
@NgModule({ @NgModule({
imports: [ providers: [
// ... provideAbpCore(
CoreModule.forRoot({ withOptions({
// ...other options, ...,
registerLocaleFn: registerLocale( registerLocaleFn: registerLocale(
// you can pass the cultureNameLocaleFileMap and errorHandlerFn as optionally // you can pass the cultureNameLocaleFileMap and errorHandlerFn as optionally
{ {
cultureNameLocaleFileMap: { 'pt-BR': 'pt' }, cultureNameLocaleFileMap: { 'pt-BR': 'pt' },
errorHandlerFn: ({ resolve, reject, locale, error }) => { errorHandlerFn: ({ resolve, reject, locale, error }) => {
// the error can be handled here // the error can be handled here
},
}, },
}, ),
) }),
}), ),
//... ...
] ],
})
export class AppModule {}
``` ```
### Mapping of Culture Name to Angular Locale File Name ### Mapping of Culture Name to Angular Locale File Name
@ -320,20 +325,23 @@ import { registerLocale } from '@abp/ng.core/locale';
@NgModule({ @NgModule({
imports: [ providers: [
// ... // ...
CoreModule.forRoot({ provideAbpCore(
// ...other options, withOptions({
registerLocaleFn: registerLocale( ...,
{ registerLocaleFn: registerLocale(
cultureNameLocaleFileMap: { {
"DotnetCultureName": "AngularLocaleFileName", cultureNameLocaleFileMap: {
"pt-BR": "pt" // example "DotnetCultureName": "AngularLocaleFileName",
"pt-BR": "pt" // example
},
}, },
}, )
) }),
}), ),
//... ]
})
``` ```
See [all locale files in Angular](https://github.com/angular/angular/tree/master/packages/common/locales). See [all locale files in Angular](https://github.com/angular/angular/tree/master/packages/common/locales).
@ -345,12 +353,12 @@ Add the below code to the `app.module.ts` by replacing `your-locale` placeholder
```js ```js
//app.module.ts //app.module.ts
import { storeLocaleData } from '@abp/ng.core/locale'; import { storeLocaleData } from "@abp/ng.core/locale";
import( import(
/* webpackChunkName: "_locale-your-locale-js"*/ /* webpackChunkName: "_locale-your-locale-js"*/
/* webpackMode: "eager" */ /* webpackMode: "eager" */
'@angular/common/locales/your-locale.js' "@angular/common/locales/your-locale.js"
).then((m) => storeLocaleData(m.default, 'your-locale')); ).then((m) => storeLocaleData(m.default, "your-locale"));
``` ```
...or a custom `registerLocale` function can be passed to the `CoreModule`: ...or a custom `registerLocale` function can be passed to the `CoreModule`:
@ -373,14 +381,17 @@ export function registerLocale(locale: string) {
import { registerLocale } from './register-locale'; import { registerLocale } from './register-locale';
@NgModule({ @NgModule({
imports: [ providers: [
// ... // ...
CoreModule.forRoot({ provideAbpCore(
// ...other options, withOptions({
registerLocaleFn: registerLocale ...,
}), registerLocaleFn: registerLocale,
}),
),
//... //...
] ]
})
``` ```
After this custom `registerLocale` function, since the en and fr added to the `webpackInclude`, only en and fr locale files will be created as chunks: After this custom `registerLocale` function, since the en and fr added to the `webpackInclude`, only en and fr locale files will be created as chunks:
@ -391,5 +402,5 @@ Which locale files you add to `webpackInclude` magic comment, they will be inclu
## See Also ## See Also
* [Localization in ASP.NET Core](../../Localization.md) - [Localization in ASP.NET Core](../../Localization.md)
* [Video tutorial](https://abp.io/video-courses/essentials/localization) - [Video tutorial](https://abp.io/video-courses/essentials/localization)

9
docs/en/UI/Angular/OAuth-Module.md

@ -1,9 +1,12 @@
# ABP OAuth Package # ABP OAuth Package
The authentication functionality has been moved from @abp/ng.core to @abp/ng.ouath since v7.0. The authentication functionality has been moved from @abp/ng.core to @abp/ng.ouath since v7.0.
If your app is version 7.0 or higher, you should include "AbpOAuthModule.forRoot()" in your app.module.ts as an import after "CoreModule.forRoot(...)". If your app is version 8.3 or higher, you should include "provideAbpOAuth()" in your app.module.ts as an providers after "provideAbpCore()
".
Those abstractions can be found in the @abp/ng-core packages. Those abstractions can be found in the @abp/ng-core packages.
- `AuthService` (the class that implements the IAuthService interface). - `AuthService` (the class that implements the IAuthService interface).
- `NAVIGATE_TO_MANAGE_PROFILE` Inject token. - `NAVIGATE_TO_MANAGE_PROFILE` Inject token.
- `ApiInterceptor` (the class that implements the IApiInterceptor interface). - `ApiInterceptor` (the class that implements the IApiInterceptor interface).
@ -11,9 +14,9 @@ Those abstractions can be found in the @abp/ng-core packages.
Those base classes are overridden by the "AbpOAuthModule" for oAuth. There are also three functions provided with AbpOAuthModule. Those base classes are overridden by the "AbpOAuthModule" for oAuth. There are also three functions provided with AbpOAuthModule.
- `PIPE_TO_LOGIN_FN_KEY` a provide that calls a function when the user is not authenticated. The function should be PipeToLoginFn type. - `PIPE_TO_LOGIN_FN_KEY` a provide that calls a function when the user is not authenticated. The function should be PipeToLoginFn type.
- `SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY` a provide that calls a function when the user is authenticated. The function should be SetTokenResponseToStorageFn type. - `SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY` a provide that calls a function when the user is authenticated. The function should be SetTokenResponseToStorageFn type.
- `CHECK_AUTHENTICATION_STATE_FN_KEY` a provide that calls a function when the user is authenticated and stores the auth state. The function should be CheckAuthenticationStateFn type. - `CHECK_AUTHENTICATION_STATE_FN_KEY` a provide that calls a function when the user is authenticated and stores the auth state. The function should be CheckAuthenticationStateFn type.
The tokens and interfaces are in the `@abp/ng.core` package but the implementation of these interfaces is in the `@abp/ng.oauth` package. The tokens and interfaces are in the `@abp/ng.core` package but the implementation of these interfaces is in the `@abp/ng.oauth` package.
If you want to make your own authentication system, you must also change these 'abstract' classes. If you want to make your own authentication system, you must also change these 'abstract' classes.

4
docs/en/UI/AspNetCore/Static-JavaScript-Proxies.md

@ -66,7 +66,7 @@ acme.bookStore.authors.author.get = function(id, ajaxParams) {
}; };
```` ````
> `generate-proxy` command generates proxies for only the APIs you've defined in your application (assumes `app` as the module name). If you are developing a modular application, you can specify the `-m` (or `--module`) parameter to specify the module you want to generate proxies. See the *generate-proxy* section in the [ABP CLI](../CLI.md) documentation for other options. > `generate-proxy` command generates proxies for only the APIs you've defined in your application (assumes `app` as the module name). If you are developing a modular application, you can specify the `-m` (or `--module`) parameter to specify the module you want to generate proxies. See the *generate-proxy* section in the [ABP CLI](../../CLI.md) documentation for other options.
### Using the Proxy Functions ### Using the Proxy Functions
@ -154,4 +154,4 @@ See the [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) documentation for all
* [Dynamic JavaScript API Client Proxies](Dynamic-JavaScript-Proxies.md) * [Dynamic JavaScript API Client Proxies](Dynamic-JavaScript-Proxies.md)
* [Auto API Controllers](../../API/Auto-API-Controllers.md) * [Auto API Controllers](../../API/Auto-API-Controllers.md)
* [Web Application Development Tutorial](../../Tutorials/Part-1.md) * [Web Application Development Tutorial](../../Tutorials/Part-1.md)

4
docs/en/docs-nav.json

@ -1165,6 +1165,10 @@
"text": "Ellipsis", "text": "Ellipsis",
"path": "UI/Angular/Ellipsis-Directive.md" "path": "UI/Angular/Ellipsis-Directive.md"
}, },
{
"text": "Projection Strategy",
"path": "UI/Angular/Projection-Strategy.md"
},
{ {
"text": "Context Strategy", "text": "Context Strategy",
"path": "UI/Angular/Context-Strategy.md" "path": "UI/Angular/Context-Strategy.md"

BIN
docs/en/images/book-mastering-abp-framework.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 74 KiB

BIN
docs/en/images/cmskit-module-comments-settings.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/images/db-options.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/en/images/ddd-microservice-simple.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 84 KiB

BIN
docs/en/images/ui-options.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 41 KiB

83
docs/zh-Hans/Data-Filtering.md

@ -166,17 +166,14 @@ protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityTyp
return base.ShouldFilterEntity<TEntity>(entityType); return base.ShouldFilterEntity<TEntity>(entityType);
} }
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>() protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
{ {
var expression = base.CreateFilterExpression<TEntity>(); var expression = base.CreateFilterExpression<TEntity>(modelBuilder);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{ {
Expression<Func<TEntity, bool>> isActiveFilter = Expression<Func<TEntity, bool>> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive");
e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive"); expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
expression = expression == null
? isActiveFilter
: QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
} }
return expression; return expression;
@ -186,6 +183,78 @@ protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntit
* 添加 `IsActiveFilterEnabled` 属性用于检查是否启用了 `IIsActive` . 内部使用了之前介绍到的 `IDataFilter` 服务. * 添加 `IsActiveFilterEnabled` 属性用于检查是否启用了 `IIsActive` . 内部使用了之前介绍到的 `IDataFilter` 服务.
* 重写 `ShouldFilterEntity` 和 `CreateFilterExpression` 方法检查给定实体是否实现 `IIsActive` 接口,在必要时组合表达式. * 重写 `ShouldFilterEntity` 和 `CreateFilterExpression` 方法检查给定实体是否实现 `IIsActive` 接口,在必要时组合表达式.
#### 使用用户定义的函数映射
使用[用户定义的函数映射](https://learn.microsoft.com/zh-cnn/ef/core/querying/user-defined-function-mapping) 可以获取性能提升.
要使用此功能,请更改DbContext如下所示:
````csharp
protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled<IIsActive>() ?? false;
protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return base.ShouldFilterEntity<TEntity>(entityType);
}
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
{
var expression = base.CreateFilterExpression<TEntity>(modelBuilder);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive");
if (UseDbFunction())
{
isActiveFilter = e => IsActiveFilter(((IIsActive)e).IsActive, true);
var abpEfCoreCurrentDbContext = this.GetService<AbpEfCoreCurrentDbContext>();
modelBuilder.HasDbFunction(typeof(MyProjectNameDbContext).GetMethod(nameof(IsActiveFilter))!)
.HasTranslation(args =>
{
// (bool isActive, bool boolParam)
var isActive = args[0];
var boolParam = args[1];
if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled<IIsActive>() == true)
{
// isActive == true
return new SqlBinaryExpression(
ExpressionType.Equal,
isActive,
new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping),
boolParam.Type,
boolParam.TypeMapping);
}
// empty where sql
return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping);
});
}
expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
}
return expression;
}
public static bool IsActiveFilter(bool isActive, bool boolParam)
{
throw new NotSupportedException(AbpEfCoreDataFilterDbFunctionMethods.NotSupportedExceptionMessage);
}
public override string GetCompiledQueryCacheKey()
{
return $"{base.GetCompiledQueryCacheKey()}:{IsActiveFilterEnabled}";
}
````
### MongoDB ### MongoDB
ABP抽象了 `IMongoDbRepositoryFilterer` 接口为[MongoDB 集成](MongoDB.md)实现数据过滤, 只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据. ABP抽象了 `IMongoDbRepositoryFilterer` 接口为[MongoDB 集成](MongoDB.md)实现数据过滤, 只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据.

8
docs/zh-Hans/Local-Event-Bus.md

@ -211,6 +211,14 @@ namespace AbpDemo
* 对于 EF Core, 他们在 `DbContext.SaveChanges` 发布. * 对于 EF Core, 他们在 `DbContext.SaveChanges` 发布.
* 对于 MongoDB, 在你调用仓储的 `InsertAsync`, `UpdateAsync` 或 `DeleteAsync` 方法发布(因为MongoDB没有更改追踪系统). * 对于 MongoDB, 在你调用仓储的 `InsertAsync`, `UpdateAsync` 或 `DeleteAsync` 方法发布(因为MongoDB没有更改追踪系统).
#### AbpEntityChangeOptions
`AbpEntityChangeOptions`类中有一个`PublishEntityUpdatedEventWhenNavigationChanges`选项,默认值为`true`。
如果将其设置为`false`,则当导航属性更改时,将不会发布`EntityUpdatedEventData<T>`事件。
> 此选项仅用于EF Core
## 另请参阅 ## 另请参阅
* [分布式事件总线](Distributed-Event-Bus.md) * [分布式事件总线](Distributed-Event-Bus.md)

27
docs/zh-Hans/UI/Angular/Localization.md

@ -205,16 +205,23 @@ export class AppComponent {}
// app.module.ts // app.module.ts
@NgModule({ @NgModule({
imports: [ providers: [
// other imports // ...
CoreModule.forRoot({ provideAbpCore(
// other options withOptions({
cultureNameLocaleFileMap: { ...,
"DotnetCultureName": "AngularLocaleFileName", registerLocaleFn: registerLocale(
"pt-BR": "pt" // example {
} cultureNameLocaleFileMap: {
}) "DotnetCultureName": "AngularLocaleFileName",
//... "pt-BR": "pt" // example
},
},
)
}),
),
]
})
``` ```
查看 [Angular中所有的语言环境文件](https://github.com/angular/angular/tree/master/packages/common/locales). 查看 [Angular中所有的语言环境文件](https://github.com/angular/angular/tree/master/packages/common/locales).

1
framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling; namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling;

2
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs

@ -2,7 +2,7 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.AspNetCore.Components.DependencyInjection; using Volo.Abp.AspNetCore.Components.DependencyInjection;
using Volo.Abp.AspNetCore.Components.Server; using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.UI; using Volo.Abp.UI;

2
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebOptions.cs

@ -1,4 +1,4 @@
namespace Volo.Abp.AspNetCore.Components.Server; namespace Volo.Abp.AspNetCore.Components.Web;
public class AbpAspNetCoreComponentsWebOptions public class AbpAspNetCoreComponentsWebOptions
{ {

1
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs

@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Volo.Abp.AspNetCore.Components.Server;
using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Components.Web.ExceptionHandling; using Volo.Abp.AspNetCore.Components.Web.ExceptionHandling;
using Volo.Abp.AspNetCore.Components.Web.Security; using Volo.Abp.AspNetCore.Components.Web.Security;

27
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ClientProxyExceptionEventHandler.cs

@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.JSInterop; using Microsoft.JSInterop;
using Volo.Abp.AspNetCore.Components.Server;
using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
@ -26,31 +25,19 @@ public class ClientProxyExceptionEventHandler : ILocalEventHandler<ClientProxyEx
{ {
using (var scope = ServiceProvider.CreateScope()) using (var scope = ServiceProvider.CreateScope())
{ {
switch (eventData.StatusCode) if (eventData.StatusCode == 401)
{ {
case 401: var options = scope.ServiceProvider.GetRequiredService<IOptions<AbpAspNetCoreComponentsWebOptions>>();
if (!options.Value.IsBlazorWebApp)
{ {
var options = scope.ServiceProvider.GetRequiredService<IOptions<AbpAspNetCoreComponentsWebOptions>>(); var authenticationOptions = scope.ServiceProvider.GetRequiredService<IOptions<AbpAuthenticationOptions>>();
if (!options.Value.IsBlazorWebApp) var navigationManager = scope.ServiceProvider.GetRequiredService<NavigationManager>();
{ navigationManager.NavigateToLogout(authenticationOptions.Value.LogoutUrl, "/");
var authenticationOptions = scope.ServiceProvider.GetRequiredService<IOptions<AbpAuthenticationOptions>>();
var navigationManager = scope.ServiceProvider.GetRequiredService<NavigationManager>();
navigationManager.NavigateToLogout(authenticationOptions.Value.LogoutUrl, "/");
}
else
{
var jsRuntime = scope.ServiceProvider.GetRequiredService<IJSRuntime>();
await jsRuntime.InvokeVoidAsync("eval", "setTimeout(function(){location.assign('/')}, 2000)");
}
break;
} }
case 403: else
{ {
var jsRuntime = scope.ServiceProvider.GetRequiredService<IJSRuntime>(); var jsRuntime = scope.ServiceProvider.GetRequiredService<IJSRuntime>();
await jsRuntime.InvokeVoidAsync("eval", "setTimeout(function(){location.assign('/')}, 2000)"); await jsRuntime.InvokeVoidAsync("eval", "setTimeout(function(){location.assign('/')}, 2000)");
break;
} }
} }
} }

57
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/CachedBundleDynamicFileProvider.cs

@ -0,0 +1,57 @@
using System;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
[Dependency(ReplaceServices = true)]
public class CachedBundleDynamicFileProvider : DynamicFileProvider
{
protected IDistributedCache<InMemoryFileInfoCacheItem> Cache { get; }
protected IOptions<AbpBundlingOptions> BundlingOptions { get; }
public CachedBundleDynamicFileProvider(
IDistributedCache<InMemoryFileInfoCacheItem> cache,
IOptions<AbpBundlingOptions> bundlingOptions)
{
Cache = cache;
BundlingOptions = bundlingOptions;
}
public override IFileInfo GetFileInfo(string? subpath)
{
var fileInfo = base.GetFileInfo(subpath);
if (!subpath.IsNullOrWhiteSpace() && fileInfo is NotFoundFileInfo &&
subpath.Contains(BundlingOptions.Value.BundleFolderName, StringComparison.OrdinalIgnoreCase))
{
var filePath = NormalizePath(subpath);
var cacheItem = Cache.Get(filePath);
if (cacheItem == null)
{
return fileInfo;
}
fileInfo = new InMemoryFileInfo(filePath, cacheItem.FileContent, cacheItem.Name);
DynamicFiles.AddOrUpdate(filePath, fileInfo, (key, value) => fileInfo);
}
return fileInfo;
}
public override void AddOrUpdate(IFileInfo fileInfo)
{
var filePath = fileInfo.GetVirtualOrPhysicalPathOrNull();
Cache.GetOrAdd(filePath!, () => new InMemoryFileInfoCacheItem(filePath!, fileInfo.ReadBytes(), fileInfo.Name));
base.AddOrUpdate(fileInfo);
}
public override bool Delete(string filePath)
{
Cache.Remove(filePath);
return base.Delete(filePath);
}
}

22
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/InMemoryFileInfoCacheItem.cs

@ -0,0 +1,22 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
[Serializable]
[IgnoreMultiTenancy]
public class InMemoryFileInfoCacheItem
{
public InMemoryFileInfoCacheItem(string dynamicPath, byte[] fileContent, string name)
{
DynamicPath = dynamicPath;
Name = name;
FileContent = fileContent;
}
public string DynamicPath { get; set; }
public string Name { get; set; }
public byte[] FileContent { get; set; }
}

5
framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs

@ -22,8 +22,9 @@ public abstract class BackgroundWorkerBase : IBackgroundWorker
protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName!) ?? NullLogger.Instance); protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName!) ?? NullLogger.Instance);
protected CancellationTokenSource StoppingTokenSource { get; } protected CancellationTokenSource StoppingTokenSource { get; set; }
protected CancellationToken StoppingToken { get; }
protected CancellationToken StoppingToken { get; set; }
public BackgroundWorkerBase() public BackgroundWorkerBase()
{ {

14
framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs

@ -46,6 +46,12 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions
public static string? GetDateEditInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property) public static string? GetDateEditInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property)
{ {
var dataFormatString = property.GetDataFormatStringOrNull();
if (dataFormatString != null)
{
return dataFormatString;
}
if (property.IsDate()) if (property.IsDate())
{ {
return "{0:yyyy-MM-dd}"; return "{0:yyyy-MM-dd}";
@ -59,6 +65,14 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions
return null; return null;
} }
public static string? GetDataFormatStringOrNull(this IBasicObjectExtensionPropertyInfo property)
{
return property
.Attributes
.OfType<DisplayFormatAttribute>()
.FirstOrDefault()?.DataFormatString;
}
public static string? GetTextInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object? value) public static string? GetTextInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object? value)
{ {
if (value == null) if (value == null)

9
framework/src/Volo.Abp.BlazoriseUI/Components/UiPageProgress.razor.cs

@ -7,7 +7,7 @@ namespace Volo.Abp.BlazoriseUI.Components;
public partial class UiPageProgress : ComponentBase, IDisposable public partial class UiPageProgress : ComponentBase, IDisposable
{ {
protected PageProgress PageProgressRef { get; set; } = default!; protected PageProgress? PageProgressRef { get; set; }
protected int? Percentage { get; set; } protected int? Percentage { get; set; }
@ -33,8 +33,11 @@ public partial class UiPageProgress : ComponentBase, IDisposable
Visible = e.Percentage == null || (e.Percentage >= 0 && e.Percentage <= 100); Visible = e.Percentage == null || (e.Percentage >= 0 && e.Percentage <= 100);
Color = GetColor(e.Options.Type); Color = GetColor(e.Options.Type);
await PageProgressRef.SetValueAsync(e.Percentage); if(PageProgressRef != null)
{
await PageProgressRef.SetValueAsync(e.Percentage);
}
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }

172
framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
@ -19,6 +20,8 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
protected static readonly string SlidingExpirationKey; protected static readonly string SlidingExpirationKey;
protected static readonly string DataKey; protected static readonly string DataKey;
protected static readonly long NotPresent; protected static readonly long NotPresent;
protected static readonly RedisValue[] HashMembersAbsoluteExpirationSlidingExpirationData;
protected static readonly RedisValue[] HashMembersAbsoluteExpirationSlidingExpiration;
private readonly static FieldInfo SetScriptField; private readonly static FieldInfo SetScriptField;
private readonly static FieldInfo RedisDatabaseField; private readonly static FieldInfo RedisDatabaseField;
@ -27,29 +30,29 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
private readonly static MethodInfo MapMetadataMethod; private readonly static MethodInfo MapMetadataMethod;
private readonly static MethodInfo GetAbsoluteExpirationMethod; private readonly static MethodInfo GetAbsoluteExpirationMethod;
private readonly static MethodInfo GetExpirationInSecondsMethod; private readonly static MethodInfo GetExpirationInSecondsMethod;
private readonly static MethodInfo OnRedisErrorMethod;
protected IDatabase RedisDatabase => GetRedisDatabase()!; protected RedisKey InstancePrefix { get; }
private IDatabase? _redisDatabase;
protected string Instance { get; }
static AbpRedisCache() static AbpRedisCache()
{ {
var type = typeof(RedisCache); var type = typeof(RedisCache);
RedisDatabaseField = Check.NotNull(type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic), nameof(RedisDatabaseField))!; RedisDatabaseField = Check.NotNull(type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic), nameof(RedisDatabaseField));
SetScriptField = Check.NotNull(type.GetField("_setScript", BindingFlags.Instance | BindingFlags.NonPublic), nameof(SetScriptField))!; SetScriptField = Check.NotNull(type.GetField("_setScript", BindingFlags.Instance | BindingFlags.NonPublic), nameof(SetScriptField));
ConnectMethod = Check.NotNull(type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectMethod))!; ConnectMethod = Check.NotNull(type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectMethod));
ConnectAsyncMethod = Check.NotNull(type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectAsyncMethod))!; ConnectAsyncMethod = Check.NotNull(type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectAsyncMethod));
MapMetadataMethod = Check.NotNull(type.GetMethod("MapMetadata", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static), nameof(MapMetadataMethod))!; MapMetadataMethod = Check.NotNull(type.GetMethod("MapMetadata", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static), nameof(MapMetadataMethod));
GetAbsoluteExpirationMethod = Check.NotNull(type.GetMethod("GetAbsoluteExpiration", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetAbsoluteExpirationMethod))!; GetAbsoluteExpirationMethod = Check.NotNull(type.GetMethod("GetAbsoluteExpiration", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetAbsoluteExpirationMethod));
GetExpirationInSecondsMethod = Check.NotNull(type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetExpirationInSecondsMethod))!; GetExpirationInSecondsMethod = Check.NotNull(type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetExpirationInSecondsMethod));
OnRedisErrorMethod = Check.NotNull(type.GetMethod("OnRedisError", BindingFlags.Instance | BindingFlags.NonPublic), nameof(OnRedisErrorMethod));
AbsoluteExpirationKey = type.GetField("AbsoluteExpirationKey", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.ToString()!; AbsoluteExpirationKey = type.GetField("AbsoluteExpirationKey", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.ToString()!;
@ -58,32 +61,30 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
DataKey = type.GetField("DataKey", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.ToString()!; DataKey = type.GetField("DataKey", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.ToString()!;
NotPresent = type.GetField("NotPresent", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.To<int>(); NotPresent = type.GetField("NotPresent", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.To<int>();
HashMembersAbsoluteExpirationSlidingExpirationData = [AbsoluteExpirationKey, SlidingExpirationKey, DataKey];
HashMembersAbsoluteExpirationSlidingExpiration = [AbsoluteExpirationKey, SlidingExpirationKey];
} }
public AbpRedisCache(IOptions<RedisCacheOptions> optionsAccessor) public AbpRedisCache(IOptions<RedisCacheOptions> optionsAccessor)
: base(optionsAccessor) : base(optionsAccessor)
{ {
Instance = optionsAccessor.Value.InstanceName ?? string.Empty; var instanceName = optionsAccessor.Value.InstanceName;
} if (!string.IsNullOrEmpty(instanceName))
protected virtual void Connect()
{
if (GetRedisDatabase() != null)
{ {
return; InstancePrefix = (RedisKey)Encoding.UTF8.GetBytes(instanceName);
} }
}
ConnectMethod.Invoke(this, Array.Empty<object>()); protected virtual IDatabase Connect()
{
return (IDatabase)ConnectMethod.Invoke(this, Array.Empty<object>())!;
} }
protected virtual async Task ConnectAsync(CancellationToken token = default) protected virtual async ValueTask<IDatabase> ConnectAsync(CancellationToken token = default)
{ {
if (GetRedisDatabase() != null) return await (ValueTask<IDatabase>)ConnectAsyncMethod.Invoke(this, new object[] { token })!;
{
return;
}
await (Task)ConnectAsyncMethod.Invoke(this, new object[] { token })!;
} }
public byte[]?[] GetMany( public byte[]?[] GetMany(
@ -107,9 +108,17 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
IEnumerable<KeyValuePair<string, byte[]>> items, IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options) DistributedCacheEntryOptions options)
{ {
Connect(); var cache = Connect();
Task.WaitAll(PipelineSetMany(items, options)); try
{
Task.WaitAll(PipelineSetMany(cache, items, options));
}
catch (Exception ex)
{
OnRedisError(ex, cache);
throw;
}
} }
public async Task SetManyAsync( public async Task SetManyAsync(
@ -119,9 +128,17 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
{ {
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
await ConnectAsync(token); var cache = await ConnectAsync(token);
await Task.WhenAll(PipelineSetMany(items, options)); try
{
await Task.WhenAll(PipelineSetMany(cache, items, options));
}
catch (Exception ex)
{
OnRedisError(ex, cache);
throw;
}
} }
public void RefreshMany( public void RefreshMany(
@ -145,9 +162,17 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
{ {
keys = Check.NotNull(keys, nameof(keys)); keys = Check.NotNull(keys, nameof(keys));
Connect(); var cache = Connect();
RedisDatabase.KeyDelete(keys.Select(key => (RedisKey)(Instance + key)).ToArray()); try
{
cache.KeyDelete(keys.Select(key => InstancePrefix.Append(key)).ToArray());
}
catch (Exception ex)
{
OnRedisError(ex, cache);
throw;
}
} }
public async Task RemoveManyAsync(IEnumerable<string> keys, CancellationToken token = default) public async Task RemoveManyAsync(IEnumerable<string> keys, CancellationToken token = default)
@ -155,33 +180,40 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
keys = Check.NotNull(keys, nameof(keys)); keys = Check.NotNull(keys, nameof(keys));
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
await ConnectAsync(token); var cache = await ConnectAsync(token);
await RedisDatabase.KeyDeleteAsync(keys.Select(key => (RedisKey)(Instance + key)).ToArray()); try
{
await cache.KeyDeleteAsync(keys.Select(key => InstancePrefix.Append(key)).ToArray());
}
catch (Exception ex)
{
OnRedisError(ex, cache);
throw;
}
} }
protected virtual byte[]?[] GetAndRefreshMany( protected virtual byte[]?[] GetAndRefreshMany(
IEnumerable<string> keys, IEnumerable<string> keys,
bool getData) bool getData)
{ {
Connect(); var cache = Connect();
var keyArray = keys.Select(key => Instance + key).ToArray(); var keyArray = keys.Select(key => InstancePrefix.Append( key)).ToArray();
RedisValue[][] results; byte[]?[] bytes;
if (getData) try
{ {
results = RedisDatabase.HashMemberGetMany(keyArray, AbsoluteExpirationKey, var results = cache.HashMemberGetMany(keyArray, GetHashFields(getData));
SlidingExpirationKey, DataKey);
Task.WaitAll(PipelineRefreshManyAndOutData(cache, keyArray, results, out bytes));
} }
else catch (Exception ex)
{ {
results = RedisDatabase.HashMemberGetMany(keyArray, AbsoluteExpirationKey, OnRedisError(ex, cache);
SlidingExpirationKey); throw;
} }
Task.WaitAll(PipelineRefreshManyAndOutData(keyArray, results, out var bytes));
return bytes; return bytes;
} }
@ -192,29 +224,28 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
{ {
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
await ConnectAsync(token); var cache = await ConnectAsync(token);
var keyArray = keys.Select(key => Instance + key).ToArray(); var keyArray = keys.Select(key => InstancePrefix.Append(key)).ToArray();
RedisValue[][] results; byte[]?[] bytes;
if (getData) try
{ {
results = await RedisDatabase.HashMemberGetManyAsync(keyArray, AbsoluteExpirationKey, var results = await cache.HashMemberGetManyAsync(keyArray, GetHashFields(getData));
SlidingExpirationKey, DataKey); await Task.WhenAll(PipelineRefreshManyAndOutData(cache, keyArray, results, out bytes));
} }
else catch (Exception ex)
{ {
results = await RedisDatabase.HashMemberGetManyAsync(keyArray, AbsoluteExpirationKey, OnRedisError(ex, cache);
SlidingExpirationKey); throw;
} }
await Task.WhenAll(PipelineRefreshManyAndOutData(keyArray, results, out var bytes));
return bytes; return bytes;
} }
protected virtual Task[] PipelineRefreshManyAndOutData( protected virtual Task[] PipelineRefreshManyAndOutData(
string[] keys, IDatabase cache,
RedisKey[] keys,
RedisValue[][] results, RedisValue[][] results,
out byte[]?[] bytes) out byte[]?[] bytes)
{ {
@ -241,7 +272,7 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
expr = sldExpr; expr = sldExpr;
} }
tasks[i] = RedisDatabase.KeyExpireAsync(keys[i], expr); tasks[i] = cache.KeyExpireAsync(keys[i], expr);
} }
else else
{ {
@ -263,6 +294,7 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
} }
protected virtual Task[] PipelineSetMany( protected virtual Task[] PipelineSetMany(
IDatabase cache,
IEnumerable<KeyValuePair<string, byte[]>> items, IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options) DistributedCacheEntryOptions options)
{ {
@ -276,14 +308,13 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
for (var i = 0; i < itemArray.Length; i++) for (var i = 0; i < itemArray.Length; i++)
{ {
tasks[i] = RedisDatabase.ScriptEvaluateAsync(GetSetScript(), new RedisKey[] { Instance + itemArray[i].Key }, tasks[i] = cache.ScriptEvaluateAsync(GetSetScript(), new RedisKey[] { InstancePrefix.Append(itemArray[i].Key) },
new RedisValue[] [
{ absoluteExpiration?.Ticks ?? NotPresent,
absoluteExpiration?.Ticks ?? NotPresent,
options.SlidingExpiration?.Ticks ?? NotPresent, options.SlidingExpiration?.Ticks ?? NotPresent,
GetExpirationInSeconds(creationTime, absoluteExpiration, options) ?? NotPresent, GetExpirationInSeconds(creationTime, absoluteExpiration, options) ?? NotPresent,
itemArray[i].Value itemArray[i].Value
}); ]);
} }
return tasks; return tasks;
@ -316,14 +347,21 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
{ {
return (DateTimeOffset?)GetAbsoluteExpirationMethod.Invoke(null, new object[] { creationTime, options }); return (DateTimeOffset?)GetAbsoluteExpirationMethod.Invoke(null, new object[] { creationTime, options });
} }
private IDatabase? GetRedisDatabase() protected virtual void OnRedisError(Exception ex, IDatabase cache)
{ {
return _redisDatabase ??= RedisDatabaseField.GetValue(this) as IDatabase; OnRedisErrorMethod.Invoke(this, [ex, cache]);
} }
private string GetSetScript() private string GetSetScript()
{ {
return SetScriptField.GetValue(this)!.ToString()!; return SetScriptField.GetValue(this)!.ToString()!;
} }
private static RedisValue[] GetHashFields(bool getData)
{
return getData
? HashMembersAbsoluteExpirationSlidingExpirationData
: HashMembersAbsoluteExpirationSlidingExpiration;
}
} }

16
framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisExtensions.cs

@ -8,16 +8,15 @@ public static class AbpRedisExtensions
{ {
public static RedisValue[][] HashMemberGetMany( public static RedisValue[][] HashMemberGetMany(
this IDatabase cache, this IDatabase cache,
string[] keys, RedisKey[] keys,
params string[] members) RedisValue[] fields)
{ {
var tasks = new Task<RedisValue[]>[keys.Length]; var tasks = new Task<RedisValue[]>[keys.Length];
var fields = members.Select(member => (RedisValue)member).ToArray();
var results = new RedisValue[keys.Length][]; var results = new RedisValue[keys.Length][];
for (var i = 0; i < keys.Length; i++) for (var i = 0; i < keys.Length; i++)
{ {
tasks[i] = cache.HashGetAsync((RedisKey)keys[i], fields); tasks[i] = cache.HashGetAsync(keys[i], fields);
} }
for (var i = 0; i < tasks.Length; i++) for (var i = 0; i < tasks.Length; i++)
@ -28,17 +27,16 @@ public static class AbpRedisExtensions
return results; return results;
} }
public static async Task<RedisValue[][]> HashMemberGetManyAsync( public async static Task<RedisValue[][]> HashMemberGetManyAsync(
this IDatabase cache, this IDatabase cache,
string[] keys, RedisKey[] keys,
params string[] members) RedisValue[] fields)
{ {
var tasks = new Task<RedisValue[]>[keys.Length]; var tasks = new Task<RedisValue[]>[keys.Length];
var fields = members.Select(member => (RedisValue)member).ToArray();
for (var i = 0; i < keys.Length; i++) for (var i = 0; i < keys.Length; i++)
{ {
tasks[i] = cache.HashGetAsync((RedisKey)keys[i], fields); tasks[i] = cache.HashGetAsync(keys[i], fields);
} }
return await Task.WhenAll(tasks); return await Task.WhenAll(tasks);

18
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingService.cs

@ -13,6 +13,7 @@ using Volo.Abp.Cli.Build;
using Volo.Abp.Cli.Bundling.Scripts; using Volo.Abp.Cli.Bundling.Scripts;
using Volo.Abp.Cli.Bundling.Styles; using Volo.Abp.Cli.Bundling.Styles;
using Volo.Abp.Cli.Configuration; using Volo.Abp.Cli.Configuration;
using Volo.Abp.Cli.Version;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Minify.Scripts; using Volo.Abp.Minify.Scripts;
using Volo.Abp.Minify.Styles; using Volo.Abp.Minify.Styles;
@ -29,6 +30,7 @@ public class BundlingService : IBundlingService, ITransientDependency
public IScriptBundler ScriptBundler { get; set; } public IScriptBundler ScriptBundler { get; set; }
public IStyleBundler StyleBundler { get; set; } public IStyleBundler StyleBundler { get; set; }
public IConfigReader ConfigReader { get; set; } public IConfigReader ConfigReader { get; set; }
public CliVersionService CliVersionService { get; set; }
public async Task BundleAsync(string directory, bool forceBuild, string projectType = BundlingConsts.WebAssembly) public async Task BundleAsync(string directory, bool forceBuild, string projectType = BundlingConsts.WebAssembly)
{ {
@ -47,7 +49,7 @@ public class BundlingService : IBundlingService, ITransientDependency
var projectFilePath = projectFiles[0]; var projectFilePath = projectFiles[0];
CheckProjectIsSupportedType(projectFilePath, projectType); await CheckProjectIsSupportedTypeAsync(projectFilePath, projectType);
var config = projectType == BundlingConsts.WebAssembly? ConfigReader.Read(PathHelper.GetWwwRootPath(directory)): ConfigReader.Read(directory); var config = projectType == BundlingConsts.WebAssembly? ConfigReader.Read(PathHelper.GetWwwRootPath(directory)): ConfigReader.Read(directory);
var bundleConfig = config.Bundle; var bundleConfig = config.Bundle;
@ -318,7 +320,7 @@ public class BundlingService : IBundlingService, ITransientDependency
}; };
} }
private void CheckProjectIsSupportedType(string projectFilePath, string projectType) private async Task CheckProjectIsSupportedTypeAsync(string projectFilePath, string projectType)
{ {
var document = new XmlDocument(); var document = new XmlDocument();
document.Load(projectFilePath); document.Load(projectFilePath);
@ -342,5 +344,17 @@ public class BundlingService : IBundlingService, ITransientDependency
} }
break; break;
} }
var targetFramework = document.SelectSingleNode("//TargetFramework")?.InnerText ??
document.SelectNodes("//TargetFrameworks")[0].InnerText;
var currentCliVersion = await CliVersionService.GetCurrentCliVersionAsync();
if (targetFramework.IsNullOrWhiteSpace() ||
targetFramework.IndexOf($"net{currentCliVersion.Major}.0", StringComparison.OrdinalIgnoreCase) < 0)
{
throw new BundlingException($"Your project({projectFilePath}) target framework is {targetFramework}. " + Environment.NewLine +
$"But ABP CLI version is {currentCliVersion}. " + Environment.NewLine +
$"Please use the ABP CLI that is compatible with your project target framework.");
}
} }
} }

1
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs

@ -83,6 +83,7 @@ public class CliService : ITransientDependency
catch (CliUsageException usageException) catch (CliUsageException usageException)
{ {
Logger.LogWarning(usageException.Message); Logger.LogWarning(usageException.Message);
Environment.ExitCode = 1;
} }
catch (Exception ex) catch (Exception ex)
{ {

16
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BundleCommand.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.Cli.Commands;
public class BundleCommand : IConsoleCommand, ITransientDependency public class BundleCommand : IConsoleCommand, ITransientDependency
{ {
public const string Name = "bundle"; public const string Name = "bundle";
public ILogger<BundleCommand> Logger { get; set; } public ILogger<BundleCommand> Logger { get; set; }
public IBundlingService BundlingService { get; set; } public IBundlingService BundlingService { get; set; }
@ -30,7 +30,7 @@ public class BundleCommand : IConsoleCommand, ITransientDependency
var forceBuild = commandLineArgs.Options.ContainsKey(Options.ForceBuild.Short) || var forceBuild = commandLineArgs.Options.ContainsKey(Options.ForceBuild.Short) ||
commandLineArgs.Options.ContainsKey(Options.ForceBuild.Long); commandLineArgs.Options.ContainsKey(Options.ForceBuild.Long);
var projectType = GetProjectType(commandLineArgs); var projectType = GetProjectType(commandLineArgs);
if (!Directory.Exists(workingDirectory)) if (!Directory.Exists(workingDirectory))
@ -42,15 +42,7 @@ public class BundleCommand : IConsoleCommand, ITransientDependency
); );
} }
try await BundlingService.BundleAsync(workingDirectory, forceBuild, projectType);
{
await BundlingService.BundleAsync(workingDirectory, forceBuild, projectType);
}
catch (BundlingException ex)
{
Logger.LogError(ex.Message);
throw;
}
} }
public string GetShortDescription() public string GetShortDescription()
@ -77,7 +69,7 @@ public class BundleCommand : IConsoleCommand, ITransientDependency
return sb.ToString(); return sb.ToString();
} }
private string GetProjectType(CommandLineArgs commandLineArgs) private string GetProjectType(CommandLineArgs commandLineArgs)
{ {
var projectType = commandLineArgs.Options.GetOrNull(Options.ProjectType.Short, Options.ProjectType.Long); var projectType = commandLineArgs.Options.GetOrNull(Options.ProjectType.Short, Options.ProjectType.Long);

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs

@ -84,7 +84,7 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency
return; return;
} }
var project = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.csproj").FirstOrDefault(); var project = Directory.GetFiles(directory, "*.csproj").FirstOrDefault();
if (project != null) if (project != null)
{ {

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ModuleInfo.cs

@ -4,6 +4,8 @@ public class ModuleInfo
{ {
public string Name { get; set; } public string Name { get; set; }
public string AbpStudioName { get; set; }
public string Namespace { get; set; } public string Namespace { get; set; }
public string DocumentUrl { get; set; } public string DocumentUrl { get; set; }

13
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs

@ -37,7 +37,9 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
{ {
var defaultThemeName = context.BuildArgs.TemplateName is AppTemplate.TemplateName or AppNoLayersTemplate.TemplateName var defaultThemeName = context.BuildArgs.TemplateName is AppTemplate.TemplateName or AppNoLayersTemplate.TemplateName
? LeptonXLite : LeptonX; ? LeptonXLite : LeptonX;
new RemoveFilesStep($"/Themes/{defaultThemeName}").Execute(context);
ChangeThemeToBasicForMvcProjects(context, defaultThemeName); ChangeThemeToBasicForMvcProjects(context, defaultThemeName);
ChangeThemeToBasicForBlazorProjects(context, defaultThemeName); ChangeThemeToBasicForBlazorProjects(context, defaultThemeName);
ChangeThemeToBasicForBlazorServerProjects(context, defaultThemeName); ChangeThemeToBasicForBlazorServerProjects(context, defaultThemeName);
@ -627,11 +629,16 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
private static void ChangeThemeToBasicForMvcProjects(ProjectBuildContext context, string defaultThemeName) private static void ChangeThemeToBasicForMvcProjects(ProjectBuildContext context, string defaultThemeName)
{ {
var projectNames = new[] var projectNames = new List<string>
{ {
".Web", ".HttpApi.Host", ".AuthServer", ".Web.Public", ".Web.Public.Host", ".Web", ".AuthServer", ".Web.Public", ".Web.Public.Host",
"" //for app-nolayers-mvc "" //for app-nolayers-mvc
}; };
if(!context.Symbols.Contains("tiered"))
{
projectNames.Add(".HttpApi.Host");
}
foreach (var projectName in projectNames) foreach (var projectName in projectNames)
{ {

13
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveFileStep.cs

@ -1,18 +1,21 @@
using System; namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps;
public class RemoveFileStep : ProjectBuildPipelineStep public class RemoveFileStep : ProjectBuildPipelineStep
{ {
private readonly string _filePath; private readonly string _filePath;
public RemoveFileStep(string filePath) private readonly bool _fullPath;
public RemoveFileStep(string filePath, bool fullPath = true)
{ {
_filePath = filePath; _filePath = filePath;
_fullPath = fullPath;
} }
public override void Execute(ProjectBuildContext context) public override void Execute(ProjectBuildContext context)
{ {
var fileToRemove = context.Files.Find(x => x.Name == _filePath);; var fileToRemove = _fullPath
? context.Files.Find(x => x.Name == _filePath)
: context.Files.Find(x => x.Name.EndsWith(_filePath));
if (fileToRemove != null) if (fileToRemove != null)
{ {
context.Files.Remove(fileToRemove); context.Files.Remove(fileToRemove);

5
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppNoLayersTemplateBase.cs

@ -249,6 +249,11 @@ public abstract class AppNoLayersTemplateBase : TemplateInfo
steps.Add(new ChangeThemeStyleStep()); steps.Add(new ChangeThemeStyleStep());
} }
if (context.BuildArgs.Theme != Theme.LeptonX)
{
steps.Add(new RemoveFileStep("LeptonXFooter.razor", false));
}
RemoveThemeLogoFolders(context, steps); RemoveThemeLogoFolders(context, steps);
if (IsDefaultThemeForTemplate(context.BuildArgs)) if (IsDefaultThemeForTemplate(context.BuildArgs))

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs

@ -235,6 +235,10 @@ public abstract class AppTemplateBase : TemplateInfo
{ {
steps.Add(new ChangeThemeStyleStep()); steps.Add(new ChangeThemeStyleStep());
} }
else
{
steps.Add(new RemoveFileStep("LeptonXFooter.razor", false));
}
RemoveThemeLogoFolders(context, steps); RemoveThemeLogoFolders(context, steps);

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs

@ -49,6 +49,10 @@ public abstract class MicroserviceTemplateBase : TemplateInfo
steps.Add(new ChangeThemeStyleStep()); steps.Add(new ChangeThemeStyleStep());
return; return;
} }
else
{
steps.Add(new RemoveFileStep("LeptonXFooter.razor", false));
}
steps.Add(new ChangeThemeStep()); steps.Add(new ChangeThemeStep());
ReplaceLeptonXThemePackagesFromPackageJsonFiles(steps, uiFramework: context.BuildArgs.UiFramework, theme: context.BuildArgs.Theme, version: context.BuildArgs.Version ?? context.TemplateFile.Version); ReplaceLeptonXThemePackagesFromPackageJsonFiles(steps, uiFramework: context.BuildArgs.UiFramework, theme: context.BuildArgs.Theme, version: context.BuildArgs.Version ?? context.TemplateFile.Version);

11
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs

@ -250,6 +250,17 @@ public class NpmPackagesUpdater : ITransientDependency
return false; return false;
} }
var prefix = string.Empty;
if (package.Value.ToString().StartsWith("~"))
{
prefix = "~";
}
else if (package.Value.ToString().StartsWith("^"))
{
prefix = "^";
}
version = prefix + version.RemovePreFix("~", "^");
package.Value.Replace(version); package.Value.Replace(version);
Logger.LogInformation( Logger.LogInformation(

10
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs

@ -12,12 +12,12 @@ public class CmdHelper : ICmdHelper, ITransientDependency
private const int SuccessfulExitCode = 0; private const int SuccessfulExitCode = 0;
protected AbpCliOptions CliOptions { get; } protected AbpCliOptions CliOptions { get; }
public CmdHelper(IOptionsSnapshot<AbpCliOptions> cliOptions) public CmdHelper(IOptionsSnapshot<AbpCliOptions> cliOptions)
{ {
CliOptions = cliOptions.Value; CliOptions = cliOptions.Value;
} }
public void Open(string pathOrUrl) public void Open(string pathOrUrl)
{ {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@ -43,7 +43,7 @@ public class CmdHelper : ICmdHelper, ITransientDependency
{ {
HideNewCommandWindow(procStartInfo); HideNewCommandWindow(procStartInfo);
} }
Process.Start(procStartInfo)?.WaitForExit(); Process.Start(procStartInfo)?.WaitForExit();
} }
@ -74,6 +74,7 @@ public class CmdHelper : ICmdHelper, ITransientDependency
process?.WaitForExit(); process?.WaitForExit();
exitCode = process.ExitCode; exitCode = process.ExitCode;
Environment.ExitCode = exitCode;
} }
} }
@ -144,6 +145,7 @@ public class CmdHelper : ICmdHelper, ITransientDependency
process.WaitForExit(); process.WaitForExit();
exitCode = process.ExitCode; exitCode = process.ExitCode;
Environment.ExitCode = exitCode;
} }
return output.Trim(); return output.Trim();
@ -160,7 +162,7 @@ public class CmdHelper : ICmdHelper, ITransientDependency
{ {
procStartInfo.WorkingDirectory = workingDirectory; procStartInfo.WorkingDirectory = workingDirectory;
} }
if (CliOptions.AlwaysHideExternalCommandOutput) if (CliOptions.AlwaysHideExternalCommandOutput)
{ {
HideNewCommandWindow(procStartInfo); HideNewCommandWindow(procStartInfo);

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/PackageVersionCheckerService.cs

@ -62,7 +62,7 @@ public class PackageVersionCheckerService : ITransientDependency
public async Task<LatestVersionInfo> GetLatestVersionOrNullAsync(string packageId, bool includeNightly = false, bool includeReleaseCandidates = false) public async Task<LatestVersionInfo> GetLatestVersionOrNullAsync(string packageId, bool includeNightly = false, bool includeReleaseCandidates = false)
{ {
if (!includeNightly && !includeReleaseCandidates && !packageId.Contains("LeptonX")) if (!includeNightly && !includeReleaseCandidates && !packageId.Contains("LeptonX") && !packageId.StartsWith("Volo.Abp.Studio."))
{ {
return await GetLatestStableVersionFromGithubAsync(); return await GetLatestStableVersionFromGithubAsync();
} }

16
framework/src/Volo.Abp.Core/Volo/Abp/Check.cs

@ -10,7 +10,7 @@ public static class Check
{ {
[ContractAnnotation("value:null => halt")] [ContractAnnotation("value:null => halt")]
public static T NotNull<T>( public static T NotNull<T>(
T? value, [System.Diagnostics.CodeAnalysis.NotNull] T? value,
[InvokerParameterName][NotNull] string parameterName) [InvokerParameterName][NotNull] string parameterName)
{ {
if (value == null) if (value == null)
@ -23,7 +23,7 @@ public static class Check
[ContractAnnotation("value:null => halt")] [ContractAnnotation("value:null => halt")]
public static T NotNull<T>( public static T NotNull<T>(
T? value, [System.Diagnostics.CodeAnalysis.NotNull] T? value,
[InvokerParameterName][NotNull] string parameterName, [InvokerParameterName][NotNull] string parameterName,
string message) string message)
{ {
@ -37,7 +37,7 @@ public static class Check
[ContractAnnotation("value:null => halt")] [ContractAnnotation("value:null => halt")]
public static string NotNull( public static string NotNull(
string? value, [System.Diagnostics.CodeAnalysis.NotNull] string? value,
[InvokerParameterName][NotNull] string parameterName, [InvokerParameterName][NotNull] string parameterName,
int maxLength = int.MaxValue, int maxLength = int.MaxValue,
int minLength = 0) int minLength = 0)
@ -62,7 +62,7 @@ public static class Check
[ContractAnnotation("value:null => halt")] [ContractAnnotation("value:null => halt")]
public static string NotNullOrWhiteSpace( public static string NotNullOrWhiteSpace(
string? value, [System.Diagnostics.CodeAnalysis.NotNull] string? value,
[InvokerParameterName][NotNull] string parameterName, [InvokerParameterName][NotNull] string parameterName,
int maxLength = int.MaxValue, int maxLength = int.MaxValue,
int minLength = 0) int minLength = 0)
@ -87,7 +87,7 @@ public static class Check
[ContractAnnotation("value:null => halt")] [ContractAnnotation("value:null => halt")]
public static string NotNullOrEmpty( public static string NotNullOrEmpty(
string? value, [System.Diagnostics.CodeAnalysis.NotNull] string? value,
[InvokerParameterName][NotNull] string parameterName, [InvokerParameterName][NotNull] string parameterName,
int maxLength = int.MaxValue, int maxLength = int.MaxValue,
int minLength = 0) int minLength = 0)
@ -111,7 +111,9 @@ public static class Check
} }
[ContractAnnotation("value:null => halt")] [ContractAnnotation("value:null => halt")]
public static ICollection<T> NotNullOrEmpty<T>(ICollection<T>? value, [InvokerParameterName][NotNull] string parameterName) public static ICollection<T> NotNullOrEmpty<T>(
[System.Diagnostics.CodeAnalysis.NotNull] ICollection<T>? value,
[InvokerParameterName][NotNull] string parameterName)
{ {
if (value == null || value.Count <= 0) if (value == null || value.Count <= 0)
{ {
@ -339,7 +341,7 @@ public static class Check
} }
public static T NotDefaultOrNull<T>( public static T NotDefaultOrNull<T>(
T? value, [System.Diagnostics.CodeAnalysis.NotNull] T? value,
[InvokerParameterName][NotNull] string parameterName) [InvokerParameterName][NotNull] string parameterName)
where T : struct where T : struct
{ {

2
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ExposeServicesAttribute.cs

@ -60,7 +60,7 @@ public class ExposeServicesAttribute : Attribute, IExposedServiceTypesProvider
interfaceName = interfaceName.Right(interfaceName.Length - 1); interfaceName = interfaceName.Right(interfaceName.Length - 1);
} }
if (type.Name.EndsWith(interfaceName)) if (type.Name.EndsWith(interfaceName, StringComparison.OrdinalIgnoreCase))
{ {
serviceTypes.Add(interfaceType); serviceTypes.Add(interfaceType);
} }

8
framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/MySQL/AbpEntityFrameworkCoreMySQLModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Guids; using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.Guids;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.EntityFrameworkCore.MySQL; namespace Volo.Abp.EntityFrameworkCore.MySQL;
@ -17,5 +18,10 @@ public class AbpEntityFrameworkCoreMySQLModule : AbpModule
options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString; options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString;
} }
}); });
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
} }
} }

6
framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/Oracle/Devart/AbpEntityFrameworkCoreOracleDevartModule.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -18,5 +19,10 @@ public class AbpEntityFrameworkCoreOracleDevartModule : AbpModule
options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary; options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
} }
}); });
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
} }
} }

6
framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/Oracle/AbpEntityFrameworkCoreOracleModule.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -16,5 +17,10 @@ public class AbpEntityFrameworkCoreOracleModule : AbpModule
options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary; options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
} }
}); });
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
} }
} }

8
framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/PostgreSql/AbpEntityFrameworkCorePostgreSqlModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Guids; using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.Guids;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.EntityFrameworkCore.PostgreSql; namespace Volo.Abp.EntityFrameworkCore.PostgreSql;
@ -17,5 +18,10 @@ public class AbpEntityFrameworkCorePostgreSqlModule : AbpModule
options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString; options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString;
} }
}); });
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
} }
} }

8
framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/SqlServer/AbpEntityFrameworkCoreSqlServerModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Guids; using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.Guids;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.EntityFrameworkCore.SqlServer; namespace Volo.Abp.EntityFrameworkCore.SqlServer;
@ -17,5 +18,10 @@ public class AbpEntityFrameworkCoreSqlServerModule : AbpModule
options.DefaultSequentialGuidType = SequentialGuidType.SequentialAtEnd; options.DefaultSequentialGuidType = SequentialGuidType.SequentialAtEnd;
} }
}); });
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
} }
} }

9
framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/Sqlite/AbpEntityFrameworkCoreSqliteModule.cs

@ -1,3 +1,4 @@
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.EntityFrameworkCore.Sqlite; namespace Volo.Abp.EntityFrameworkCore.Sqlite;
@ -7,5 +8,11 @@ namespace Volo.Abp.EntityFrameworkCore.Sqlite;
)] )]
public class AbpEntityFrameworkCoreSqliteModule : AbpModule public class AbpEntityFrameworkCoreSqliteModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpEfCoreGlobalFilterOptions>(options =>
{
options.UseDbFunction = true;
});
}
} }

21
framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreDbContextOptionsBuilderExtensions.cs

@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Volo.Abp.EntityFrameworkCore;
namespace Microsoft.Extensions.DependencyInjection;
public static class AbpEfCoreDbContextOptionsBuilderExtensions
{
public static DbContextOptionsBuilder AddAbpDbContextOptionsExtension(this DbContextOptionsBuilder optionsBuilder)
{
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(new AbpDbContextOptionsExtension());
return optionsBuilder;
}
public static DbContextOptionsBuilder<TContext> AddAbpDbContextOptionsExtension<TContext>(this DbContextOptionsBuilder<TContext> optionsBuilder)
where TContext : DbContext
{
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(new AbpDbContextOptionsExtension());
return optionsBuilder;
}
}

68
framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreModelBuilderExtensions.cs

@ -0,0 +1,68 @@
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.MultiTenancy;
namespace Microsoft.Extensions.DependencyInjection;
public static class AbpEfCoreModelBuilderExtensions
{
public static ModelBuilder ConfigureSoftDeleteDbFunction(this ModelBuilder modelBuilder, MethodInfo methodInfo, AbpEfCoreCurrentDbContext abpEfCoreCurrentDbContext)
{
modelBuilder.HasDbFunction(methodInfo)
.HasTranslation(args =>
{
// (bool isDeleted, bool boolParam)
var isDeleted = args[0];
var boolParam = args[1];
if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled<ISoftDelete>() == true)
{
// IsDeleted == false
return new SqlBinaryExpression(
ExpressionType.Equal,
isDeleted,
new SqlConstantExpression(Expression.Constant(false), boolParam.TypeMapping),
boolParam.Type,
boolParam.TypeMapping);
}
// empty where sql
return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping);
});
return modelBuilder;
}
public static ModelBuilder ConfigureMultiTenantDbFunction(this ModelBuilder modelBuilder, MethodInfo methodInfo, AbpEfCoreCurrentDbContext abpEfCoreCurrentDbContext)
{
modelBuilder.HasDbFunction(methodInfo)
.HasTranslation(args =>
{
// (Guid? tenantId, int? currentTenantId)
var tenantId = args[0];
var currentTenantId = args[1];
var boolParam = args[2];
if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled<IMultiTenant>() == true)
{
// TenantId == CurrentTenantId
return new SqlBinaryExpression(
ExpressionType.Equal,
tenantId,
currentTenantId,
boolParam.Type,
boolParam.TypeMapping);
}
// empty where sql
return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping);
});
return modelBuilder;
}
}

38
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -11,11 +11,12 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -24,6 +25,7 @@ using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.EntityFrameworkCore.ChangeTrackers; using Volo.Abp.EntityFrameworkCore.ChangeTrackers;
using Volo.Abp.EntityFrameworkCore.EntityHistory; using Volo.Abp.EntityFrameworkCore.EntityHistory;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
@ -37,7 +39,7 @@ using Volo.Abp.Uow;
namespace Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.EntityFrameworkCore;
public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext, ITransientDependency public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext, IAbpEfCoreDbFunctionContext, ITransientDependency
where TDbContext : DbContext where TDbContext : DbContext
{ {
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!;
@ -78,6 +80,8 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
public IOptions<AbpDbContextOptions> Options => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpDbContextOptions>>(); public IOptions<AbpDbContextOptions> Options => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpDbContextOptions>>();
public IOptions<AbpEfCoreGlobalFilterOptions> GlobalFilterOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpEfCoreGlobalFilterOptions>>();
private static readonly MethodInfo ConfigureBasePropertiesMethodInfo private static readonly MethodInfo ConfigureBasePropertiesMethodInfo
= typeof(AbpDbContext<TDbContext>) = typeof(AbpDbContext<TDbContext>)
.GetMethod( .GetMethod(
@ -99,9 +103,12 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
BindingFlags.Instance | BindingFlags.NonPublic BindingFlags.Instance | BindingFlags.NonPublic
)!; )!;
protected readonly DbContextOptions DbContextOptions;
protected AbpDbContext(DbContextOptions<TDbContext> options) protected AbpDbContext(DbContextOptions<TDbContext> options)
: base(options) : base(options)
{ {
DbContextOptions = options;
} }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
@ -713,7 +720,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
{ {
if (mutableEntityType.BaseType == null && ShouldFilterEntity<TEntity>(mutableEntityType)) if (mutableEntityType.BaseType == null && ShouldFilterEntity<TEntity>(mutableEntityType))
{ {
var filterExpression = CreateFilterExpression<TEntity>(); var filterExpression = CreateFilterExpression<TEntity>(modelBuilder);
if (filterExpression != null) if (filterExpression != null)
{ {
modelBuilder.Entity<TEntity>().HasAbpQueryFilter(filterExpression); modelBuilder.Entity<TEntity>().HasAbpQueryFilter(filterExpression);
@ -782,7 +789,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
return false; return false;
} }
protected virtual Expression<Func<TEntity, bool>>? CreateFilterExpression<TEntity>() protected virtual Expression<Func<TEntity, bool>>? CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
where TEntity : class where TEntity : class
{ {
Expression<Func<TEntity, bool>>? expression = null; Expression<Func<TEntity, bool>>? expression = null;
@ -790,14 +797,37 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{ {
expression = e => !IsSoftDeleteFilterEnabled || !EF.Property<bool>(e, "IsDeleted"); expression = e => !IsSoftDeleteFilterEnabled || !EF.Property<bool>(e, "IsDeleted");
if (UseDbFunction())
{
expression = e => AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilter(((ISoftDelete)e).IsDeleted, true);
modelBuilder.ConfigureSoftDeleteDbFunction(AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilterMethodInfo, this.GetService<AbpEfCoreCurrentDbContext>());
}
} }
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity))) if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{ {
Expression<Func<TEntity, bool>> multiTenantFilter = e => !IsMultiTenantFilterEnabled || EF.Property<Guid>(e, "TenantId") == CurrentTenantId; Expression<Func<TEntity, bool>> multiTenantFilter = e => !IsMultiTenantFilterEnabled || EF.Property<Guid>(e, "TenantId") == CurrentTenantId;
if (UseDbFunction())
{
multiTenantFilter = e => AbpEfCoreDataFilterDbFunctionMethods.MultiTenantFilter(((IMultiTenant)e).TenantId, CurrentTenantId, true);
modelBuilder.ConfigureMultiTenantDbFunction(AbpEfCoreDataFilterDbFunctionMethods.MultiTenantFilterMethodInfo, this.GetService<AbpEfCoreCurrentDbContext>());
}
expression = expression == null ? multiTenantFilter : QueryFilterExpressionHelper.CombineExpressions(expression, multiTenantFilter); expression = expression == null ? multiTenantFilter : QueryFilterExpressionHelper.CombineExpressions(expression, multiTenantFilter);
} }
return expression; return expression;
} }
protected virtual bool UseDbFunction()
{
return LazyServiceProvider != null && GlobalFilterOptions.Value.UseDbFunction && DbContextOptions.FindExtension<AbpDbContextOptionsExtension>() != null;
}
public virtual string GetCompiledQueryCacheKey()
{
return $"{CurrentTenantId?.ToString() ?? "Null"}:{IsSoftDeleteFilterEnabled}:{IsMultiTenantFilterEnabled}";
}
} }

62
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsExtension.cs

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
namespace Volo.Abp.EntityFrameworkCore;
public class AbpDbContextOptionsExtension : IDbContextOptionsExtension
{
public void ApplyServices(IServiceCollection services)
{
var serviceDescriptor = services.FirstOrDefault(x => x.ServiceType == typeof(ICompiledQueryCacheKeyGenerator));
if (serviceDescriptor != null && serviceDescriptor.ImplementationType != null)
{
services.Remove(serviceDescriptor);
services.AddScoped(serviceDescriptor.ImplementationType);
services.Add(ServiceDescriptor.Scoped<ICompiledQueryCacheKeyGenerator>(provider =>
ActivatorUtilities.CreateInstance<AbpCompiledQueryCacheKeyGenerator>(provider,
provider.GetRequiredService(serviceDescriptor.ImplementationType)
.As<ICompiledQueryCacheKeyGenerator>())));
}
services.Replace(ServiceDescriptor.Scoped<IAsyncQueryProvider, AbpEntityQueryProvider>());
services.AddSingleton(typeof(AbpEfCoreCurrentDbContext));
}
public void Validate(IDbContextOptions options)
{
}
public DbContextOptionsExtensionInfo Info => new AbpOptionsExtensionInfo(this);
private class AbpOptionsExtensionInfo : DbContextOptionsExtensionInfo
{
public AbpOptionsExtensionInfo(IDbContextOptionsExtension extension)
: base(extension)
{
}
public override bool IsDatabaseProvider => false;
public override int GetServiceProviderHashCode()
{
return 0;
}
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other)
{
return other is AbpOptionsExtensionInfo;
}
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
{
}
public override string LogFragment => "AbpOptionsExtension";
}
}

49
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityQueryProvider.cs

@ -0,0 +1,49 @@
using System.Linq.Expressions;
using System.Threading;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
namespace Volo.Abp.EntityFrameworkCore;
#pragma warning disable EF1001
public class AbpEntityQueryProvider : EntityQueryProvider
{
protected AbpEfCoreCurrentDbContext AbpEfCoreCurrentDbContext { get; }
protected ICurrentDbContext CurrentDbContext { get; }
public AbpEntityQueryProvider(
IQueryCompiler queryCompiler,
AbpEfCoreCurrentDbContext abpEfCoreCurrentDbContext,
ICurrentDbContext currentDbContext)
: base(queryCompiler)
{
AbpEfCoreCurrentDbContext = abpEfCoreCurrentDbContext;
CurrentDbContext = currentDbContext;
}
public override object Execute(Expression expression)
{
using (AbpEfCoreCurrentDbContext.Use(CurrentDbContext.Context as IAbpEfCoreDbFunctionContext))
{
return base.Execute(expression);
}
}
public override TResult Execute<TResult>(Expression expression)
{
using (AbpEfCoreCurrentDbContext.Use(CurrentDbContext.Context as IAbpEfCoreDbFunctionContext))
{
return base.Execute<TResult>(expression);
}
}
public override TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = new CancellationToken())
{
using (AbpEfCoreCurrentDbContext.Use(CurrentDbContext.Context as IAbpEfCoreDbFunctionContext))
{
return base.ExecuteAsync<TResult>(expression, cancellationToken);
}
}
}
#pragma warning restore EF1001

6
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs

@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore.GlobalFilters;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace Volo.Abp.EntityFrameworkCore.DependencyInjection; namespace Volo.Abp.EntityFrameworkCore.DependencyInjection;
@ -27,6 +28,11 @@ public static class DbContextOptionsFactory
PreConfigure(options, context); PreConfigure(options, context);
Configure(options, context); Configure(options, context);
if (serviceProvider.GetRequiredService<IOptions<AbpEfCoreGlobalFilterOptions>>().Value.UseDbFunction)
{
context.DbContextOptions.AddAbpDbContextOptionsExtension();
}
return context.DbContextOptions.Options; return context.DbContextOptions.Options;
} }

59
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpCompiledQueryCacheKeyGenerator.cs

@ -0,0 +1,59 @@
using System;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters;
public class AbpCompiledQueryCacheKeyGenerator : ICompiledQueryCacheKeyGenerator
{
protected ICompiledQueryCacheKeyGenerator InnerCompiledQueryCacheKeyGenerator { get; }
protected ICurrentDbContext CurrentContext { get; }
public AbpCompiledQueryCacheKeyGenerator(
ICompiledQueryCacheKeyGenerator innerCompiledQueryCacheKeyGenerator,
ICurrentDbContext currentContext)
{
InnerCompiledQueryCacheKeyGenerator = innerCompiledQueryCacheKeyGenerator;
CurrentContext = currentContext;
}
public virtual object GenerateCacheKey(Expression query, bool async)
{
var cacheKey = InnerCompiledQueryCacheKeyGenerator.GenerateCacheKey(query, async);
if (CurrentContext.Context is IAbpEfCoreDbFunctionContext abpEfCoreDbFunctionContext)
{
return new AbpCompiledQueryCacheKey(cacheKey, abpEfCoreDbFunctionContext.GetCompiledQueryCacheKey());
}
return cacheKey;
}
private readonly struct AbpCompiledQueryCacheKey : IEquatable<AbpCompiledQueryCacheKey>
{
private readonly object _compiledQueryCacheKey;
private readonly string _currentFilterCacheKey;
public AbpCompiledQueryCacheKey(object compiledQueryCacheKey, string currentFilterCacheKey)
{
_compiledQueryCacheKey = compiledQueryCacheKey;
_currentFilterCacheKey = currentFilterCacheKey;
}
public override bool Equals(object? obj)
{
return obj is AbpCompiledQueryCacheKey key && Equals(key);
}
public bool Equals(AbpCompiledQueryCacheKey other)
{
return _compiledQueryCacheKey.Equals(other._compiledQueryCacheKey) &&
_currentFilterCacheKey == other._currentFilterCacheKey;
}
public override int GetHashCode()
{
return HashCode.Combine(_compiledQueryCacheKey, _currentFilterCacheKey);
}
}
}

21
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpEfCoreCurrentDbContext.cs

@ -0,0 +1,21 @@
using System;
using System.Threading;
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters;
public class AbpEfCoreCurrentDbContext
{
private readonly AsyncLocal<IAbpEfCoreDbFunctionContext?> _current = new AsyncLocal<IAbpEfCoreDbFunctionContext?>();
public IAbpEfCoreDbFunctionContext? Context => _current.Value;
public IDisposable Use(IAbpEfCoreDbFunctionContext? context)
{
var previousValue = Context;
_current.Value = context;
return new DisposeAction(() =>
{
_current.Value = previousValue;
});
}
}

25
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpEfCoreDataFilterDbFunctionMethods.cs

@ -0,0 +1,25 @@
using System;
using System.Reflection;
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters;
public static class AbpEfCoreDataFilterDbFunctionMethods
{
public const string NotSupportedExceptionMessage = "Your EF Core database provider does not support 'User-defined function mapping'." +
"Please set 'UseDbFunction' of 'AbpEfCoreGlobalFilterOptions' to false to disable it." +
"See https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping for more information." ;
public static bool SoftDeleteFilter(bool isDeleted, bool boolParam)
{
throw new NotSupportedException(NotSupportedExceptionMessage);
}
public static MethodInfo SoftDeleteFilterMethodInfo => typeof(AbpEfCoreDataFilterDbFunctionMethods).GetMethod(nameof(SoftDeleteFilter))!;
public static bool MultiTenantFilter(Guid? tenantId, Guid? currentTenantId, bool boolParam)
{
throw new NotSupportedException(NotSupportedExceptionMessage);
}
public static MethodInfo MultiTenantFilterMethodInfo => typeof(AbpEfCoreDataFilterDbFunctionMethods).GetMethod(nameof(MultiTenantFilter))!;
}

10
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/AbpEfCoreGlobalFilterOptions.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters;
public class AbpEfCoreGlobalFilterOptions
{
/// <summary>
/// Use User-defined function mapping to filter data.
/// https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping
/// </summary>
public bool UseDbFunction { get; set; }
}

16
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/GlobalFilters/IAbpEfCoreDbFunctionContext.cs

@ -0,0 +1,16 @@
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters;
public interface IAbpEfCoreDbFunctionContext
{
IAbpLazyServiceProvider LazyServiceProvider { get; set; }
ICurrentTenant CurrentTenant { get; }
IDataFilter DataFilter { get; }
string GetCompiledQueryCacheKey();
}

18
framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs

@ -5,6 +5,7 @@ using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI; using Swashbuckle.AspNetCore.SwaggerUI;
using Volo.Abp.Content; using Volo.Abp.Content;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle; using Volo.Abp.Swashbuckle;
namespace Microsoft.Extensions.DependencyInjection; namespace Microsoft.Extensions.DependencyInjection;
@ -89,16 +90,15 @@ public static class AbpSwaggerGenServiceCollectionExtensions
Action<SwaggerGenOptions>? setupAction = null) Action<SwaggerGenOptions>? setupAction = null)
{ {
var discoveryUrl = discoveryEndpoint != null ? var discoveryUrl = discoveryEndpoint != null ?
new Uri($"{discoveryEndpoint.TrimEnd('/')}/.well-known/openid-configuration") : $"{discoveryEndpoint.TrimEnd('/')}/.well-known/openid-configuration":
new Uri($"{authority.TrimEnd('/')}/.well-known/openid-configuration"); $"{authority.TrimEnd('/')}/.well-known/openid-configuration";
flows ??= new [] { AbpSwaggerOidcFlows.AuthorizationCode }; flows ??= new [] { AbpSwaggerOidcFlows.AuthorizationCode };
services.Configure<SwaggerUIOptions>(swaggerUiOptions => services.Configure<SwaggerUIOptions>(swaggerUiOptions =>
{ {
swaggerUiOptions.ConfigObject.AdditionalItems["oidcSupportedFlows"] = flows; swaggerUiOptions.ConfigObject.AdditionalItems["oidcSupportedFlows"] = flows;
swaggerUiOptions.ConfigObject.AdditionalItems["oidcSupportedScopes"] = scopes; swaggerUiOptions.ConfigObject.AdditionalItems["oidcSupportedScopes"] = scopes;
swaggerUiOptions.ConfigObject.AdditionalItems["oidcDiscoveryEndpoint"] = discoveryEndpoint; swaggerUiOptions.ConfigObject.AdditionalItems["oidcDiscoveryEndpoint"] = discoveryUrl;
}); });
return services return services
@ -109,7 +109,7 @@ public static class AbpSwaggerGenServiceCollectionExtensions
options.AddSecurityDefinition("oidc", new OpenApiSecurityScheme options.AddSecurityDefinition("oidc", new OpenApiSecurityScheme
{ {
Type = SecuritySchemeType.OpenIdConnect, Type = SecuritySchemeType.OpenIdConnect,
OpenIdConnectUrl = discoveryUrl OpenIdConnectUrl = new Uri(RemoveTenantPlaceholders(discoveryUrl))
}); });
options.AddSecurityRequirement(new OpenApiSecurityRequirement options.AddSecurityRequirement(new OpenApiSecurityRequirement
@ -129,4 +129,12 @@ public static class AbpSwaggerGenServiceCollectionExtensions
setupAction?.Invoke(options); setupAction?.Invoke(options);
}); });
} }
private static string RemoveTenantPlaceholders(string url)
{
return url
.Replace(MultiTenantUrlProvider.TenantPlaceHolder + ".", string.Empty)
.Replace(MultiTenantUrlProvider.TenantIdPlaceHolder + ".", string.Empty)
.Replace(MultiTenantUrlProvider.TenantNamePlaceHolder + ".", string.Empty);
}
} }

65
framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.swagger.js

@ -9,12 +9,12 @@ var abp = abp || {};
var oidcSupportedFlows = configObject.oidcSupportedFlows || []; var oidcSupportedFlows = configObject.oidcSupportedFlows || [];
var oidcSupportedScopes = configObject.oidcSupportedScopes || []; var oidcSupportedScopes = configObject.oidcSupportedScopes || [];
var oidcDiscoveryEndpoint = configObject.oidcDiscoveryEndpoint || []; var oidcDiscoveryEndpoint = configObject.oidcDiscoveryEndpoint || [];
var tenantPlaceHolders = ["{{tenantId}}", "{{tenantName}}" , "{0}"] var tenantPlaceHolders = ["{{tenantId}}", "{{tenantName}}", "{0}"]
abp.appPath = configObject.baseUrl || abp.appPath; abp.appPath = configObject.baseUrl || abp.appPath;
var requestInterceptor = configObject.requestInterceptor; var requestInterceptor = configObject.requestInterceptor;
var responseInterceptor = configObject.responseInterceptor; var responseInterceptor = configObject.responseInterceptor;
configObject.requestInterceptor = async function (request) { configObject.requestInterceptor = async function (request) {
if (request.url.includes(excludeUrl[1])) { if (request.url.includes(excludeUrl[1])) {
@ -27,22 +27,6 @@ var abp = abp || {};
}); });
firstRequest = false; firstRequest = false;
} }
// Intercept .well-known request when the discoveryEndpoint is provided
if (!firstRequest && oidcDiscoveryEndpoint.length !== 0 && request.url.includes(".well-known/openid-configuration")) {
if (oidcDiscoveryEndpoint.endsWith(".well-known/openid-configuration")) {
request.url = await replaceTenantPlaceHolder(oidcDiscoveryEndpoint);
console.log(request.url);
return;
}
if (!oidcDiscoveryEndpoint.endsWith("/")) {
oidcDiscoveryEndpoint += "/"
}
request.url = await replaceTenantPlaceHolder(oidcDiscoveryEndpoint) + ".well-known/openid-configuration";
console.log(request.url);
}
var antiForgeryToken = abp.security.antiForgery.getToken(); var antiForgeryToken = abp.security.antiForgery.getToken();
if (antiForgeryToken) { if (antiForgeryToken) {
@ -78,33 +62,50 @@ var abp = abp || {};
response.text = JSON.stringify(openIdConnectData); response.text = JSON.stringify(openIdConnectData);
} }
// Intercept .well-known request when the discoveryEndpoint is provided
if (response.url.endsWith("swagger.json") && response.status === 200 && oidcDiscoveryEndpoint.length !== 0) {
var swaggerData = JSON.parse(response.text);
if (swaggerData.components.securitySchemes && swaggerData.components.securitySchemes.oidc) {
swaggerData.components.securitySchemes.oidc.openIdConnectUrl = await replaceTenantPlaceHolder(oidcDiscoveryEndpoint);
}
response.text = JSON.stringify(swaggerData);
}
if (responseInterceptor) { if (responseInterceptor) {
responseInterceptor(response); responseInterceptor(response);
} }
return response; return response;
}; };
async function replaceTenantPlaceHolder(url) { async function replaceTenantPlaceHolder(url) {
if(!abp.currentTenant){ if (!abp.currentTenant) {
await getAbpApplicationConfiguration(); await getAbpApplicationConfiguration();
} }
url.replace(tenantPlaceHolders[0], abp.currentTenant.id); if (abp.currentTenant.id == null && abp.currentTenant.name == null) {
url.replace(tenantPlaceHolders[1], abp.currentTenant.name); return url
.replace(tenantPlaceHolders[0] + ".", "")
if(abp.currentTenant.name != null){ .replace(tenantPlaceHolders[1] + ".", "")
url.replace(tenantPlaceHolders[2], abp.currentTenant.name); .replace(tenantPlaceHolders[2] + ".", "");
}else if (abp.currentTenant.id != null){
url.replace(tenantPlaceHolders[2], abp.currentTenant.id);
} }
url = url.replace(tenantPlaceHolders[0], abp.currentTenant.id).replace(tenantPlaceHolders[1], abp.currentTenant.name);
if (abp.currentTenant.name != null) {
url = url.replace(tenantPlaceHolders[2], abp.currentTenant.name);
} else if (abp.currentTenant.id != null) {
url = url.replace(tenantPlaceHolders[2], abp.currentTenant.id);
}
return url; return url;
} }
function getAbpApplicationConfiguration() { function getAbpApplicationConfiguration() {
return fetch(`${abp.appPath}api/abp/application-configuration`).then(response => response.json()).then(data => { return fetch(`${abp.appPath}api/abp/application-configuration`).then(response => response.json()).then(data => {
abp.currentTenant = data.currentTenant; abp.currentTenant = data.currentTenant;
}); });
} }

6
framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DynamicFileProvider.cs

@ -29,14 +29,14 @@ public class DynamicFileProvider : DictionaryBasedFileProvider, IDynamicFileProv
DynamicFiles = new ConcurrentDictionary<string, IFileInfo>(); DynamicFiles = new ConcurrentDictionary<string, IFileInfo>();
} }
public void AddOrUpdate(IFileInfo fileInfo) public virtual void AddOrUpdate(IFileInfo fileInfo)
{ {
var filePath = fileInfo.GetVirtualOrPhysicalPathOrNull(); var filePath = fileInfo.GetVirtualOrPhysicalPathOrNull();
DynamicFiles.AddOrUpdate(filePath!, fileInfo, (key, value) => fileInfo); DynamicFiles.AddOrUpdate(filePath!, fileInfo, (key, value) => fileInfo);
ReportChange(filePath!); ReportChange(filePath!);
} }
public bool Delete(string filePath) public virtual bool Delete(string filePath)
{ {
if (!DynamicFiles.TryRemove(filePath, out _)) if (!DynamicFiles.TryRemove(filePath, out _))
{ {
@ -65,7 +65,7 @@ public class DynamicFileProvider : DictionaryBasedFileProvider, IDynamicFileProv
return tokenInfo.ChangeToken; return tokenInfo.ChangeToken;
} }
private void ReportChange(string filePath) protected virtual void ReportChange(string filePath)
{ {
if (FilePathTokenLookup.TryRemove(filePath, out var tokenInfo)) if (FilePathTokenLookup.TryRemove(filePath, out var tokenInfo))
{ {

2
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingTestModule.cs

@ -70,7 +70,7 @@ public class AbpAuditingTestModule : AbpModule
connection.Open(); connection.Open();
using (var context = new AbpAuditingTestDbContext(new DbContextOptionsBuilder<AbpAuditingTestDbContext>() using (var context = new AbpAuditingTestDbContext(new DbContextOptionsBuilder<AbpAuditingTestDbContext>()
.UseSqlite(connection).Options)) .UseSqlite(connection).AddAbpDbContextOptionsExtension().Options))
{ {
context.GetService<IRelationalDatabaseCreator>().CreateTables(); context.GetService<IRelationalDatabaseCreator>().CreateTables();
} }

20
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AutoRegistrationHelper_Tests.cs

@ -20,6 +20,22 @@ public class AutoRegistrationHelper_Tests
exposedServices.ShouldContain(typeof(IDerivedService)); exposedServices.ShouldContain(typeof(IDerivedService));
} }
[Fact]
public void Should_Get_Conventional_Exposed_Types_By_Default_Case_Insensitive()
{
//Act
var exposedServices = ExposedServiceExplorer.GetExposedServices(typeof(defaultderivedservice));
//Assert
exposedServices.Count.ShouldBe(3);
exposedServices.ShouldContain(typeof(defaultderivedservice));
exposedServices.ShouldContain(typeof(IService));
exposedServices.ShouldContain(typeof(IDerivedService));
}
[Fact] [Fact]
public void Should_Get_Custom_Exposed_Types_If_Available() public void Should_Get_Custom_Exposed_Types_If_Available()
{ {
@ -52,6 +68,10 @@ public class AutoRegistrationHelper_Tests
{ {
} }
public class defaultderivedservice : IDerivedService
{
}
public interface IService public interface IService
{ {
} }

4
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs

@ -72,7 +72,7 @@ public class AbpEntityFrameworkCoreTestModule : AbpModule
{ {
options.Configure(abpDbContextConfigurationContext => options.Configure(abpDbContextConfigurationContext =>
{ {
abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection); abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection).AddAbpDbContextOptionsExtension();
}); });
}); });
} }
@ -101,7 +101,7 @@ public class AbpEntityFrameworkCoreTestModule : AbpModule
var connection = new AbpUnitTestSqliteConnection("Data Source=:memory:"); var connection = new AbpUnitTestSqliteConnection("Data Source=:memory:");
connection.Open(); connection.Open();
using (var context = new TestMigrationsDbContext(new DbContextOptionsBuilder<TestMigrationsDbContext>().UseSqlite(connection).Options)) using (var context = new TestMigrationsDbContext(new DbContextOptionsBuilder<TestMigrationsDbContext>().UseSqlite(connection).AddAbpDbContextOptionsExtension().Options))
{ {
context.GetService<IRelationalDatabaseCreator>().CreateTables(); context.GetService<IRelationalDatabaseCreator>().CreateTables();
context.Database.ExecuteSqlRaw( context.Database.ExecuteSqlRaw(

2
latest-versions.json

@ -1,6 +1,6 @@
[ [
{ {
"version": "8.1.3", "version": "8.1.4",
"releaseDate": "", "releaseDate": "",
"type": "stable", "type": "stable",
"message": "" "message": ""

14
modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.js

@ -1,6 +1,12 @@
document.addEventListener('DOMContentLoaded', function (event) { document.addEventListener("DOMContentLoaded", function (event) {
setTimeout(function () { setTimeout(function () {
window.clientName = document.getElementById("redirectButton").getAttribute("cname"); var redirectButton = document.getElementById("redirectButton");
window.location = document.getElementById('redirectButton').getAttribute('href');
}, 3000); if(!redirectButton){
return;
}
redirectButton.getAttribute("cname");
redirectButton.getAttribute("href");
}, 3000)
}); });

2
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/AbpAspNetCoreComponentsWebAssemblyBasicThemeModule.cs

@ -1,5 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Components.Server; using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Components.Web.BasicTheme; using Volo.Abp.AspNetCore.Components.Web.BasicTheme;
using Volo.Abp.AspNetCore.Components.Web.Theming.Routing; using Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
using Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars; using Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;

2
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor

@ -1,7 +1,7 @@
@using Microsoft.Extensions.Localization @using Microsoft.Extensions.Localization
@using global::Localization.Resources.AbpUi @using global::Localization.Resources.AbpUi
@using Microsoft.Extensions.Options @using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Components.Server @using Volo.Abp.AspNetCore.Components.Web
@inherits AbpComponentBase @inherits AbpComponentBase
@inject IJSRuntime JsRuntime @inject IJSRuntime JsRuntime
@inject NavigationManager Navigation @inject NavigationManager Navigation

2
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/WebAssemblyRedirectToLogin.razor

@ -3,7 +3,7 @@
@using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic @using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.Extensions.Options @using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Components.Server @using Volo.Abp.AspNetCore.Components.Web
@inherits RedirectToLogin @inherits RedirectToLogin
@attribute [ExposeServices(typeof(RedirectToLogin))] @attribute [ExposeServices(typeof(RedirectToLogin))]
@attribute [Dependency(ReplaceServices = true)] @attribute [Dependency(ReplaceServices = true)]

6
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json

@ -3,8 +3,8 @@
"name": "asp.net", "name": "asp.net",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.shared": "~8.2.0-rc.3", "@abp/aspnetcore.mvc.ui.theme.shared": "~8.2.0-rc.5",
"@abp/prismjs": "~8.2.0-rc.3", "@abp/prismjs": "~8.2.0-rc.5",
"@abp/highlight.js": "~8.2.0-rc.3" "@abp/highlight.js": "~8.2.0-rc.5"
} }
} }

276
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock

@ -2,212 +2,212 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.3.tgz#39591ad57565941fef36eec043b3c77f370bfa03" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.5.tgz#97b86ea4daf4392a1067e2a7e7c03b4c381ccc82"
integrity sha512-fE0Eevh7Y3pVHh6sbUTJaguCJMIiIhXkfRcVDYEkY+UZ33hfsodAzhKH7byb8AV6xWD/kfacsrtXpMP5zb6hPA== integrity sha512-lR3XbbNct+8QH1dRhED5s/CHCgkANVyNBrWCQbo4BwBFJ27d3wuJDVt39VxQUsgNfxEmyoJdVZNDRUKDv6fTOw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui" "~8.2.0-rc.5"
"@abp/bootstrap" "~8.2.0-rc.3" "@abp/bootstrap" "~8.2.0-rc.5"
"@abp/bootstrap-datepicker" "~8.2.0-rc.3" "@abp/bootstrap-datepicker" "~8.2.0-rc.5"
"@abp/bootstrap-daterangepicker" "~8.2.0-rc.3" "@abp/bootstrap-daterangepicker" "~8.2.0-rc.5"
"@abp/datatables.net-bs5" "~8.2.0-rc.3" "@abp/datatables.net-bs5" "~8.2.0-rc.5"
"@abp/font-awesome" "~8.2.0-rc.3" "@abp/font-awesome" "~8.2.0-rc.5"
"@abp/jquery-form" "~8.2.0-rc.3" "@abp/jquery-form" "~8.2.0-rc.5"
"@abp/jquery-validation-unobtrusive" "~8.2.0-rc.3" "@abp/jquery-validation-unobtrusive" "~8.2.0-rc.5"
"@abp/lodash" "~8.2.0-rc.3" "@abp/lodash" "~8.2.0-rc.5"
"@abp/luxon" "~8.2.0-rc.3" "@abp/luxon" "~8.2.0-rc.5"
"@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.3" "@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.5"
"@abp/moment" "~8.2.0-rc.3" "@abp/moment" "~8.2.0-rc.5"
"@abp/select2" "~8.2.0-rc.3" "@abp/select2" "~8.2.0-rc.5"
"@abp/sweetalert2" "~8.2.0-rc.3" "@abp/sweetalert2" "~8.2.0-rc.5"
"@abp/timeago" "~8.2.0-rc.3" "@abp/timeago" "~8.2.0-rc.5"
"@abp/toastr" "~8.2.0-rc.3" "@abp/toastr" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.3.tgz#f4ee679bdc6151b0e91b74c3d249963507cc3ecf" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.5.tgz#4a845ebd4b6465b9ac04641d7479b449ca9e1c5f"
integrity sha512-3dROllA2K9DGngy+hvTTpZUwvCjDEZy/3ec1X07TgIcioYKDis6vN+nDP4QcSAu3Fa4VEJderxizSCAJejbURQ== integrity sha512-l3brGHAD2jnlAWwITGNAY5zOtmc0WItVabYCTvKrYyNuKIPEtW9getUNFp9BFMT9x0KZiGnkkrRkvxH+DzIcug==
dependencies: dependencies:
ansi-colors "^4.1.1" ansi-colors "^4.1.1"
"@abp/bootstrap-datepicker@~8.2.0-rc.3": "@abp/bootstrap-datepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.3.tgz#79ffeb35b9c46bc609d0341af83b463951f1c75a" resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.5.tgz#0e8755a51d7a691837951f7a071a9e59a2e9e6cf"
integrity sha512-PNLefHKC07GDAZy9TI8J6S/4+0bYJ7ajlZjjG3zAO248lG5RvRb6q2Mza0uMpNpVmh2mvowxpveS/s5iFMy4hA== integrity sha512-bLt8l6kYbVblThd2iuXcp6Ydss8TefpnZXHyXrQCxZGmVb79I/vf48CekJo1OWY/WcyEi/bm0m4LEI8Q0Y/LZQ==
dependencies: dependencies:
bootstrap-datepicker "^1.9.0" bootstrap-datepicker "^1.9.0"
"@abp/bootstrap-daterangepicker@~8.2.0-rc.3": "@abp/bootstrap-daterangepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.3.tgz#00d685f8c568713da9faf9d1f9a29a2cf81399c4" resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.5.tgz#e37792f24c3c8a8643e5ba5744967505e54f836c"
integrity sha512-2SQii4h9YbkvbkDU4HXBSjIXGlfISMnNweQju7R/HsvwHmSeMYs/UpjQyBjQalJnsl/arYH++bQamUb6QkgTzg== integrity sha512-dN02S1g9sVgACMz+A5FJw0uz4u5lXTFd/7xjE+cmhj0p5AcGvDD3gTbes6d3QNKiwvsPge063lG9pisdn3uEjg==
dependencies: dependencies:
bootstrap-daterangepicker "^3.1.0" bootstrap-daterangepicker "^3.1.0"
"@abp/bootstrap@~8.2.0-rc.3": "@abp/bootstrap@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.3.tgz#518319bd863e24c69c147f57e5b08ba51598098d" resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.5.tgz#1acc191f8156d81e1794bc161bfb394ae8f7372e"
integrity sha512-Q1S8MF44BjIHO0zCLq6tQ97SfGZ0AmucnSvjEA2QaYG+t6vcLulgVqOC+YhaiLVIz72nOZ6n822c5nnI+PvsAA== integrity sha512-FacgSrDlS3QSR+5WdOy06Qw0qF7OoqoBwAGqro2WOfY5sFR5OwEiqXHXUF95+a/q9B9NuYKXBjBfOPhljdiuuA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
bootstrap "^5.1.3" bootstrap "^5.1.3"
"@abp/clipboard@~8.2.0-rc.3": "@abp/clipboard@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-8.2.0-rc.3.tgz#dccbed56abc365aa8a1347b38ce4d33b77335d5c" resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-8.2.0-rc.5.tgz#5cec3d9c89bdad8d50f41807b3be68d4cdecb003"
integrity sha512-jqD48p4N3DR46v3eo8v/+Y7olOr3QcrFvv3QIbjEIGywYGepOv1W4nhmVQSwHRZqyOCSXr7E/vJZZahfsGKeQg== integrity sha512-cBaMy8A1CIU00X6SoGyuMTVf6z9iyEaR6smVRWCVmkf2VayAHFES981+iE+VmT2bezgbCidA2GXtkBZ/kunbJg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
clipboard "^2.0.8" clipboard "^2.0.8"
"@abp/core@~8.2.0-rc.3": "@abp/core@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.3.tgz#7f78600e91d2a5f4d7ea75ce4be541d9c23d5db8" resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.5.tgz#67eb75df046f8997f6af14e86bf8dbf249388a8d"
integrity sha512-0jBUCt6Q7ZoaZ1tciliIYfVZE75qZtkFZ/unkz1MeToo+djFGt8oyXhoZ/0vG2t6yG0BzN+TajAbcZ81F+isKQ== integrity sha512-XVunQMbK/MApkfnpL+8WsVqsJxARBl6W0TZwKfPyfm1QzPWE75P4oW3CIdNis0+Ob5HfhSFFp78tVrbSoEdzYQ==
dependencies: dependencies:
"@abp/utils" "~8.2.0-rc.3" "@abp/utils" "~8.2.0-rc.5"
"@abp/datatables.net-bs5@~8.2.0-rc.3": "@abp/datatables.net-bs5@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.3.tgz#4b56059400e53acb7f6ae74fc3a0c07c8de74413" resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.5.tgz#fe04af4b14530545a05c4c58361aadfdddd8e8c2"
integrity sha512-fcw9KNyfdPj6s3AjyoHvrXQLYHajrollnPitO0jLLiaYjTf8DkWaCQY/yAwcJqzZlvv9P3A56VlWpBye1iHowQ== integrity sha512-yZKC111JVxcOkDz/WxJyQ0lw3JpbBBWr21LVNjyhEiN62w8tJN1Gwo7CjL+7WFm7RPnAUUf/qwitRWmWl7M4YA==
dependencies: dependencies:
"@abp/datatables.net" "~8.2.0-rc.3" "@abp/datatables.net" "~8.2.0-rc.5"
datatables.net-bs5 "^1.11.4" datatables.net-bs5 "^1.11.4"
"@abp/datatables.net@~8.2.0-rc.3": "@abp/datatables.net@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.3.tgz#e701ed17dcbe799d227606638c99e7c120ad714e" resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.5.tgz#94e4b933750332732eeef02119a6cdfca67811e7"
integrity sha512-C1yvafNg5LtnWVqDX7Z9lyhRrWVntymdI0BfP2V4SDVeqoSTLwf859vWn2/WYyDAgtiuqGyW7YdUTHWq+aSppw== integrity sha512-IAXbC29eiHvA3unVMsFh2sNfiw+Jlgah0D++IUKOlz1eAzHMrpwP5KE4jmF6GESF7Al95NkgqH7cd6MUst+UlA==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
datatables.net "^1.11.4" datatables.net "^1.11.4"
"@abp/font-awesome@~8.2.0-rc.3": "@abp/font-awesome@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.3.tgz#091403b45dc310cdf71537e79cfdfb081a6ab90b" resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.5.tgz#5ae19305a373a6dd083944bd825ccea84aadf40b"
integrity sha512-kIVENG5e/WyIr63q6ka6sedmF+kTNSZKr0TUt7mUntJPoY8HQAizcC6SF6/w/xJAgNyVVrOe4+2LPpIkbwLK6g== integrity sha512-VbcM80e9KrZzY6TJ9l/eW42CTpdQ0eBr5gOEW+/UWGTRalCLdGve9YVJZJA55bD1VtcgaR1sV342jw2B1XeN8w==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
"@fortawesome/fontawesome-free" "^6.5.1" "@fortawesome/fontawesome-free" "^6.5.1"
"@abp/highlight.js@~8.2.0-rc.3": "@abp/highlight.js@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/highlight.js/-/highlight.js-8.2.0-rc.3.tgz#ad6765d8d65275ba8e2dcae6c19f23ae657a1265" resolved "https://registry.yarnpkg.com/@abp/highlight.js/-/highlight.js-8.2.0-rc.5.tgz#24c329217ad4092172cba3e9e23a67814f9a164f"
integrity sha512-CXz9BCbOf+xMs14TEtjWiNfkf8j1jR9ycSzSrYF+BLA85Z0cUDseAP7Q5suKwhylMw6xKWVDZF6gzyYEHU9u+w== integrity sha512-NHoUAVrGDV+BQ1rtC4orZ0xYX/4VkjZgouIktpuCAEs8wiP6/5Ddjzf2uYFv8c6XVqBm1Mx9Bufxx7aYo2O/Uw==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
"@highlightjs/cdn-assets" "~11.4.0" "@highlightjs/cdn-assets" "~11.4.0"
"@abp/jquery-form@~8.2.0-rc.3": "@abp/jquery-form@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.3.tgz#30fe28736094fa44d22df7fc65ffbcf8f33c671d" resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.5.tgz#b955fe2c226f1f35a3736aa3b2170f265a797552"
integrity sha512-LfiY4EaDHGQAHjF9i92KLDpc5HH7LUNo+pEEv9JQEvSsTH+JuN1aUf85bxX8GkY63BJbS+vVKGe2YmZJeQjGlA== integrity sha512-M9fUUYywljudem/K7aYlcIG2W+KTzUJPviSeOLo5KNxvVrScWr+Jf4M8Nbj6uWX1saYWmm5kYnfsDs+nOUcmDg==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-form "^4.3.0" jquery-form "^4.3.0"
"@abp/jquery-validation-unobtrusive@~8.2.0-rc.3": "@abp/jquery-validation-unobtrusive@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.3.tgz#6829a9022d9d759e7b2c8719f0c44f70a369f618" resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.5.tgz#c790dc1b707ee7d24fe99c2b7be6bc558af09667"
integrity sha512-C1NEsXZW6SFBo5zYaMv5GGAF6kUh1StVVnCy+AMeHOu2MffucxMQP+EdXFoWgaG+8bdcJAImHVaMUxBmi8OtDA== integrity sha512-sUkfb17cR2zM669U83R8dviv+p+uGNl5nmOV0AP4ch6CzLfnTOYzKsqV7ESGVxqB8oVHO/Wnr8sXaaLdsoQzJw==
dependencies: dependencies:
"@abp/jquery-validation" "~8.2.0-rc.3" "@abp/jquery-validation" "~8.2.0-rc.5"
jquery-validation-unobtrusive "^3.2.12" jquery-validation-unobtrusive "^3.2.12"
"@abp/jquery-validation@~8.2.0-rc.3": "@abp/jquery-validation@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.3.tgz#91e3158189c83dd94da358d4cb86acde751512f7" resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.5.tgz#294254556e804d641d3bf4ea50d1c3eb42f191d1"
integrity sha512-kigDjMUZ/n+1d3THZW5fH0RhfP79+LtqnmATwpACERDdJUBKDSJ7O6sY3Zu8HqTHB8vAuNuYBpYpkIaAg+KocA== integrity sha512-C7sOuSShkX5Ba6LiSBGuxlrORcxiYczZtsxyjRZzNzATYwEBHcLqMxDvgAsWeWtvtkMotkbB2k99vD93nlGuCQ==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-validation "^1.19.3" jquery-validation "^1.19.3"
"@abp/jquery@~8.2.0-rc.3": "@abp/jquery@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.3.tgz#329f18570fb090d059b10aee79ae7a9e6a324c97" resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.5.tgz#9b01156a80d8da6407abb6d51541cb89624cb906"
integrity sha512-j2GByw2EDpQZfWkuJkQ8aGIvtP3rAkIfXiz0KG/lAn6WhmQpQSuE7x6tkmGBaGKp+TP7KrTb6FZraOdVQzWoWA== integrity sha512-KcRVhxEmUuJHd4JNBSeJV+3Ush4w9ambKxwPi3+q1fqdePekrLk9jKNud5HkP6JredBoESJ+TkeVFFQ5HnYPVg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
jquery "~3.6.0" jquery "~3.6.0"
"@abp/lodash@~8.2.0-rc.3": "@abp/lodash@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.3.tgz#2a9d4f0cce96509d1547e57f499402128b080607" resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.5.tgz#b6fa8754258dd2db59b0df65fb9f7d90c8611af6"
integrity sha512-/4ZdVFTTLkzHEtpmIg9f8obLfyfAOLyXGXmfyklclvr14TxIINUjsDdvSKnVNYsT8R8vZkRqkuGYvk21ccE8tg== integrity sha512-LvK03DSk9lDNGEFrjMdiaAkaH58ll+PIn663KJk0kVZvtNLy/egCOMCc6EBuE5DUsjwebLi6YZYzgRQRRKirgw==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
lodash "^4.17.21" lodash "^4.17.21"
"@abp/luxon@~8.2.0-rc.3": "@abp/luxon@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.3.tgz#5cff88da204f5b7737519a31c5e683f88a9b3ac8" resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.5.tgz#e4300d1deebab16432737c831cfae0025b7c5891"
integrity sha512-b4h0uMIChqnvq2/U1gqirdgxvL3kQlQWoFMzhX/ahIKL8rXzh0v+Db8Cd6VV0eRIT6JowviYAqfqz5l0fWDPRg== integrity sha512-UdAToIlS0CwmavErMtd5dwyssKNPa6oqlHrll5h7T26nHDPEdXzSi9rP8RvwqBkrt+BFPMctRSv6DYk8OwoWzA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
luxon "^2.3.0" luxon "^2.3.0"
"@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.3": "@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.3.tgz#c6db0bdc0cc64c7f95b35c030828db7d2d8b989b" resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.5.tgz#8f39683e55fbc5487de08b9209a552cf32ea8087"
integrity sha512-SwBQlS6FYemkJXvdadT9sQiGXz8Fz9PRAjAD00MBUObqT2/RtvB82ssaNT5E1+HikveZ0p75yq7nOLh2zWhn9Q== integrity sha512-e20kLUvnu6tD5GBjzGLQjTMeyeco4q5wO4H4mMuahJpCHue+EUrL0tT1IbWiE+eEmbePw/lAn7Yfhfwjq/+Eeg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
malihu-custom-scrollbar-plugin "^3.1.5" malihu-custom-scrollbar-plugin "^3.1.5"
"@abp/moment@~8.2.0-rc.3": "@abp/moment@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.3.tgz#1bab0a10d131664e7151c2be5f41fddf4c2859f0" resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.5.tgz#e38c7e66ee383a986c7972f4ba2b19d79a43f60e"
integrity sha512-2qrczEiKg2H1ObT3md5TSRtufbvy5nsm7RxUmBLhh1TrUCsUN6YHw9ROTGkzIST686Ew3j4GgZGdJuelZteqWA== integrity sha512-F//4TZySaFBTfWgBxzwTFLeStrS0nklmKcTMU+MOtb/7Zx3QtscJpNm4CmxiBpB8pLwK8xiJQGoiuMQdoTuq+g==
dependencies: dependencies:
moment "^2.9.0" moment "^2.9.0"
"@abp/prismjs@~8.2.0-rc.3": "@abp/prismjs@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-8.2.0-rc.3.tgz#635335a1606e8f3c0e0353598a438f851be754b0" resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-8.2.0-rc.5.tgz#7a7428bb2f118cef5121a196bc45cc5d1a5a8e93"
integrity sha512-KR4xmoAwtsuQTXl4HrfC9ODmaAd/9ehrkrwXkduXid/+i79DuCILLUxdpz/lQG6axAbTwhagmfdJQuqDgsvM1w== integrity sha512-lNPqRvisf8jAxyL/05ppH26ZH4DEEzZUKqO7zqqS+yl7sBTpR/Wh8xX09spQl+wBQTLWAz2z+MouBZnMQIYKjg==
dependencies: dependencies:
"@abp/clipboard" "~8.2.0-rc.3" "@abp/clipboard" "~8.2.0-rc.5"
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
prismjs "^1.26.0" prismjs "^1.26.0"
"@abp/select2@~8.2.0-rc.3": "@abp/select2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.3.tgz#ae182953d45aca5f5ab5ddb5dded5efea23c6400" resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.5.tgz#5fc1dfa4bb871961db0ce9eb68a2c655c38b32d0"
integrity sha512-V8Hzdw1kGaR3K11//iCU+nRV81NPmAR1ZeIPgeZrS9C+9835O/yVhYI4QZk8OdLOIStiJbkVU7bOOt9mhFO8tw== integrity sha512-fT5L+mgiEOBtf2mmXNv6GtXVNjv22qQlgWp1UjI7c0jLtNPHa7P8idVTaP3g6d8b7VCP5zxIUGgjf6sZMxhADg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
select2 "^4.0.13" select2 "^4.0.13"
"@abp/sweetalert2@~8.2.0-rc.3": "@abp/sweetalert2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.3.tgz#dffe9862d7836ceaf5a057014acca28b756167f3" resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.5.tgz#502d6dbaf2c5296f67722e085e52dd0fe62e8dde"
integrity sha512-MgvA8sojsr8QH/ERBw+tZjiPu+6Kj1yozyaQ7r8je6wCWt0CUv+X6AFHp0WAaREssDclArF5h4b1GD6mP33w7g== integrity sha512-S0LTMU0a9SPdSA3ezEpo03ZGfrr7XtouEs0O5c4fA0kWYsddNkalighy3CYTgZZwaR9oWNnY6t4pyka3WXAaqg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
sweetalert2 "^11.3.6" sweetalert2 "^11.3.6"
"@abp/timeago@~8.2.0-rc.3": "@abp/timeago@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.3.tgz#00d463fb890b1e41268c0599039b0a4318848569" resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.5.tgz#8bd78f2ee6b27b8ffd77e75a2851b61013e481ee"
integrity sha512-RpoEKExLhnZlqFvYgsUFpyFpHCrrO17tSf+iLRNokMPQHp0BXT0sV2UFg0Cw51XQg5NKWp9cL+bY2IEOe1qwIA== integrity sha512-eLG9WFtP1dOoYHaNxyV8gOx1xnKmqSTwgviTU45qUFSNsgQHH1n0bpBxUXSSvaFw5mWRbF3R/JJQHql+Dl6Cow==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
timeago "^1.6.7" timeago "^1.6.7"
"@abp/toastr@~8.2.0-rc.3": "@abp/toastr@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.3.tgz#1a3b85b23a352f3b6e0480185a0ca91ab142a251" resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.5.tgz#baecda4e6fed5676f58de2228bf8d1c6ae66d49e"
integrity sha512-EC9EOio5ObgsjYa2fB8v4pgBPKiJ8Lbb7K+lKSQPxZSuqLrw+hEixgqZ0S9bBz5jxNRyqMFBdWAmYU6Vt5zzig== integrity sha512-y7aOY1LF62yRwXRSrvimtqIilrsOgSAM8lHcp2RogZAFdmw7yU1R5a6fJlLDGeRBIgjdcIlSpaOuoi6T2hCjFw==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
toastr "^2.1.4" toastr "^2.1.4"
"@abp/utils@~8.2.0-rc.3": "@abp/utils@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.3.tgz#94c9708e7af563a55a163fd4b57d1b276db61da3" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.5.tgz#526d64aa3e059d2f6e595b22e35dda2d652377e4"
integrity sha512-SAfmjq5MXW32IlXxkN9zZhOtgSgoAhE2OENYPk9eAHsEtkJ7f9+Q+vOE3oJPBI7lFv0K/lee3FrEbDQBsB5XHA== integrity sha512-ZU7jHFpDh7jDYgCrX6aXqy/v4LrMGgYJN+siyWUMpVddg2lTTO2MsxI+KmSxJwD7H01Mqj1sZ+LBAOVxGR3hsw==
dependencies: dependencies:
just-compare "^2.3.0" just-compare "^2.3.0"

4
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json

@ -3,8 +3,8 @@
"name": "asp.net", "name": "asp.net",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "~8.2.0-rc.3", "@abp/aspnetcore.mvc.ui.theme.basic": "~8.2.0-rc.5",
"@abp/prismjs": "~8.2.0-rc.3" "@abp/prismjs": "~8.2.0-rc.5"
}, },
"devDependencies": {} "devDependencies": {}
} }

280
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock

@ -2,211 +2,211 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/aspnetcore.mvc.ui.theme.basic@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.basic@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-8.2.0-rc.3.tgz#ade99976f35ceddd814db8c3e5e376e8664f22eb" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-8.2.0-rc.5.tgz#5cc3231d27e9e12e6fdc3e4fc5eb3e6f2019cf13"
integrity sha512-IaBP/R/lMY5KNP8NIny4ydjJTqlWu1z2lM0lkWoNFhhBq9dmLEVKDJjzaeU4/UOhM8bHqEhvrWt2wh4me/SYIQ== integrity sha512-SKr5Zm6k2SxrRBW2gqJAsTag4KacVzuVG3sTCD5P5BZLYn5OvknwSeky4tg/wzCodWp20wf89hWyET4E0iKExg==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.3.tgz#39591ad57565941fef36eec043b3c77f370bfa03" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.5.tgz#97b86ea4daf4392a1067e2a7e7c03b4c381ccc82"
integrity sha512-fE0Eevh7Y3pVHh6sbUTJaguCJMIiIhXkfRcVDYEkY+UZ33hfsodAzhKH7byb8AV6xWD/kfacsrtXpMP5zb6hPA== integrity sha512-lR3XbbNct+8QH1dRhED5s/CHCgkANVyNBrWCQbo4BwBFJ27d3wuJDVt39VxQUsgNfxEmyoJdVZNDRUKDv6fTOw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui" "~8.2.0-rc.5"
"@abp/bootstrap" "~8.2.0-rc.3" "@abp/bootstrap" "~8.2.0-rc.5"
"@abp/bootstrap-datepicker" "~8.2.0-rc.3" "@abp/bootstrap-datepicker" "~8.2.0-rc.5"
"@abp/bootstrap-daterangepicker" "~8.2.0-rc.3" "@abp/bootstrap-daterangepicker" "~8.2.0-rc.5"
"@abp/datatables.net-bs5" "~8.2.0-rc.3" "@abp/datatables.net-bs5" "~8.2.0-rc.5"
"@abp/font-awesome" "~8.2.0-rc.3" "@abp/font-awesome" "~8.2.0-rc.5"
"@abp/jquery-form" "~8.2.0-rc.3" "@abp/jquery-form" "~8.2.0-rc.5"
"@abp/jquery-validation-unobtrusive" "~8.2.0-rc.3" "@abp/jquery-validation-unobtrusive" "~8.2.0-rc.5"
"@abp/lodash" "~8.2.0-rc.3" "@abp/lodash" "~8.2.0-rc.5"
"@abp/luxon" "~8.2.0-rc.3" "@abp/luxon" "~8.2.0-rc.5"
"@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.3" "@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.5"
"@abp/moment" "~8.2.0-rc.3" "@abp/moment" "~8.2.0-rc.5"
"@abp/select2" "~8.2.0-rc.3" "@abp/select2" "~8.2.0-rc.5"
"@abp/sweetalert2" "~8.2.0-rc.3" "@abp/sweetalert2" "~8.2.0-rc.5"
"@abp/timeago" "~8.2.0-rc.3" "@abp/timeago" "~8.2.0-rc.5"
"@abp/toastr" "~8.2.0-rc.3" "@abp/toastr" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.3.tgz#f4ee679bdc6151b0e91b74c3d249963507cc3ecf" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.5.tgz#4a845ebd4b6465b9ac04641d7479b449ca9e1c5f"
integrity sha512-3dROllA2K9DGngy+hvTTpZUwvCjDEZy/3ec1X07TgIcioYKDis6vN+nDP4QcSAu3Fa4VEJderxizSCAJejbURQ== integrity sha512-l3brGHAD2jnlAWwITGNAY5zOtmc0WItVabYCTvKrYyNuKIPEtW9getUNFp9BFMT9x0KZiGnkkrRkvxH+DzIcug==
dependencies: dependencies:
ansi-colors "^4.1.1" ansi-colors "^4.1.1"
"@abp/bootstrap-datepicker@~8.2.0-rc.3": "@abp/bootstrap-datepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.3.tgz#79ffeb35b9c46bc609d0341af83b463951f1c75a" resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.5.tgz#0e8755a51d7a691837951f7a071a9e59a2e9e6cf"
integrity sha512-PNLefHKC07GDAZy9TI8J6S/4+0bYJ7ajlZjjG3zAO248lG5RvRb6q2Mza0uMpNpVmh2mvowxpveS/s5iFMy4hA== integrity sha512-bLt8l6kYbVblThd2iuXcp6Ydss8TefpnZXHyXrQCxZGmVb79I/vf48CekJo1OWY/WcyEi/bm0m4LEI8Q0Y/LZQ==
dependencies: dependencies:
bootstrap-datepicker "^1.9.0" bootstrap-datepicker "^1.9.0"
"@abp/bootstrap-daterangepicker@~8.2.0-rc.3": "@abp/bootstrap-daterangepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.3.tgz#00d685f8c568713da9faf9d1f9a29a2cf81399c4" resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.5.tgz#e37792f24c3c8a8643e5ba5744967505e54f836c"
integrity sha512-2SQii4h9YbkvbkDU4HXBSjIXGlfISMnNweQju7R/HsvwHmSeMYs/UpjQyBjQalJnsl/arYH++bQamUb6QkgTzg== integrity sha512-dN02S1g9sVgACMz+A5FJw0uz4u5lXTFd/7xjE+cmhj0p5AcGvDD3gTbes6d3QNKiwvsPge063lG9pisdn3uEjg==
dependencies: dependencies:
bootstrap-daterangepicker "^3.1.0" bootstrap-daterangepicker "^3.1.0"
"@abp/bootstrap@~8.2.0-rc.3": "@abp/bootstrap@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.3.tgz#518319bd863e24c69c147f57e5b08ba51598098d" resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.5.tgz#1acc191f8156d81e1794bc161bfb394ae8f7372e"
integrity sha512-Q1S8MF44BjIHO0zCLq6tQ97SfGZ0AmucnSvjEA2QaYG+t6vcLulgVqOC+YhaiLVIz72nOZ6n822c5nnI+PvsAA== integrity sha512-FacgSrDlS3QSR+5WdOy06Qw0qF7OoqoBwAGqro2WOfY5sFR5OwEiqXHXUF95+a/q9B9NuYKXBjBfOPhljdiuuA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
bootstrap "^5.1.3" bootstrap "^5.1.3"
"@abp/clipboard@~8.2.0-rc.3": "@abp/clipboard@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-8.2.0-rc.3.tgz#dccbed56abc365aa8a1347b38ce4d33b77335d5c" resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-8.2.0-rc.5.tgz#5cec3d9c89bdad8d50f41807b3be68d4cdecb003"
integrity sha512-jqD48p4N3DR46v3eo8v/+Y7olOr3QcrFvv3QIbjEIGywYGepOv1W4nhmVQSwHRZqyOCSXr7E/vJZZahfsGKeQg== integrity sha512-cBaMy8A1CIU00X6SoGyuMTVf6z9iyEaR6smVRWCVmkf2VayAHFES981+iE+VmT2bezgbCidA2GXtkBZ/kunbJg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
clipboard "^2.0.8" clipboard "^2.0.8"
"@abp/core@~8.2.0-rc.3": "@abp/core@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.3.tgz#7f78600e91d2a5f4d7ea75ce4be541d9c23d5db8" resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.5.tgz#67eb75df046f8997f6af14e86bf8dbf249388a8d"
integrity sha512-0jBUCt6Q7ZoaZ1tciliIYfVZE75qZtkFZ/unkz1MeToo+djFGt8oyXhoZ/0vG2t6yG0BzN+TajAbcZ81F+isKQ== integrity sha512-XVunQMbK/MApkfnpL+8WsVqsJxARBl6W0TZwKfPyfm1QzPWE75P4oW3CIdNis0+Ob5HfhSFFp78tVrbSoEdzYQ==
dependencies: dependencies:
"@abp/utils" "~8.2.0-rc.3" "@abp/utils" "~8.2.0-rc.5"
"@abp/datatables.net-bs5@~8.2.0-rc.3": "@abp/datatables.net-bs5@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.3.tgz#4b56059400e53acb7f6ae74fc3a0c07c8de74413" resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.5.tgz#fe04af4b14530545a05c4c58361aadfdddd8e8c2"
integrity sha512-fcw9KNyfdPj6s3AjyoHvrXQLYHajrollnPitO0jLLiaYjTf8DkWaCQY/yAwcJqzZlvv9P3A56VlWpBye1iHowQ== integrity sha512-yZKC111JVxcOkDz/WxJyQ0lw3JpbBBWr21LVNjyhEiN62w8tJN1Gwo7CjL+7WFm7RPnAUUf/qwitRWmWl7M4YA==
dependencies: dependencies:
"@abp/datatables.net" "~8.2.0-rc.3" "@abp/datatables.net" "~8.2.0-rc.5"
datatables.net-bs5 "^1.11.4" datatables.net-bs5 "^1.11.4"
"@abp/datatables.net@~8.2.0-rc.3": "@abp/datatables.net@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.3.tgz#e701ed17dcbe799d227606638c99e7c120ad714e" resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.5.tgz#94e4b933750332732eeef02119a6cdfca67811e7"
integrity sha512-C1yvafNg5LtnWVqDX7Z9lyhRrWVntymdI0BfP2V4SDVeqoSTLwf859vWn2/WYyDAgtiuqGyW7YdUTHWq+aSppw== integrity sha512-IAXbC29eiHvA3unVMsFh2sNfiw+Jlgah0D++IUKOlz1eAzHMrpwP5KE4jmF6GESF7Al95NkgqH7cd6MUst+UlA==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
datatables.net "^1.11.4" datatables.net "^1.11.4"
"@abp/font-awesome@~8.2.0-rc.3": "@abp/font-awesome@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.3.tgz#091403b45dc310cdf71537e79cfdfb081a6ab90b" resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.5.tgz#5ae19305a373a6dd083944bd825ccea84aadf40b"
integrity sha512-kIVENG5e/WyIr63q6ka6sedmF+kTNSZKr0TUt7mUntJPoY8HQAizcC6SF6/w/xJAgNyVVrOe4+2LPpIkbwLK6g== integrity sha512-VbcM80e9KrZzY6TJ9l/eW42CTpdQ0eBr5gOEW+/UWGTRalCLdGve9YVJZJA55bD1VtcgaR1sV342jw2B1XeN8w==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
"@fortawesome/fontawesome-free" "^6.5.1" "@fortawesome/fontawesome-free" "^6.5.1"
"@abp/jquery-form@~8.2.0-rc.3": "@abp/jquery-form@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.3.tgz#30fe28736094fa44d22df7fc65ffbcf8f33c671d" resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.5.tgz#b955fe2c226f1f35a3736aa3b2170f265a797552"
integrity sha512-LfiY4EaDHGQAHjF9i92KLDpc5HH7LUNo+pEEv9JQEvSsTH+JuN1aUf85bxX8GkY63BJbS+vVKGe2YmZJeQjGlA== integrity sha512-M9fUUYywljudem/K7aYlcIG2W+KTzUJPviSeOLo5KNxvVrScWr+Jf4M8Nbj6uWX1saYWmm5kYnfsDs+nOUcmDg==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-form "^4.3.0" jquery-form "^4.3.0"
"@abp/jquery-validation-unobtrusive@~8.2.0-rc.3": "@abp/jquery-validation-unobtrusive@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.3.tgz#6829a9022d9d759e7b2c8719f0c44f70a369f618" resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.5.tgz#c790dc1b707ee7d24fe99c2b7be6bc558af09667"
integrity sha512-C1NEsXZW6SFBo5zYaMv5GGAF6kUh1StVVnCy+AMeHOu2MffucxMQP+EdXFoWgaG+8bdcJAImHVaMUxBmi8OtDA== integrity sha512-sUkfb17cR2zM669U83R8dviv+p+uGNl5nmOV0AP4ch6CzLfnTOYzKsqV7ESGVxqB8oVHO/Wnr8sXaaLdsoQzJw==
dependencies: dependencies:
"@abp/jquery-validation" "~8.2.0-rc.3" "@abp/jquery-validation" "~8.2.0-rc.5"
jquery-validation-unobtrusive "^3.2.12" jquery-validation-unobtrusive "^3.2.12"
"@abp/jquery-validation@~8.2.0-rc.3": "@abp/jquery-validation@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.3.tgz#91e3158189c83dd94da358d4cb86acde751512f7" resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.5.tgz#294254556e804d641d3bf4ea50d1c3eb42f191d1"
integrity sha512-kigDjMUZ/n+1d3THZW5fH0RhfP79+LtqnmATwpACERDdJUBKDSJ7O6sY3Zu8HqTHB8vAuNuYBpYpkIaAg+KocA== integrity sha512-C7sOuSShkX5Ba6LiSBGuxlrORcxiYczZtsxyjRZzNzATYwEBHcLqMxDvgAsWeWtvtkMotkbB2k99vD93nlGuCQ==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-validation "^1.19.3" jquery-validation "^1.19.3"
"@abp/jquery@~8.2.0-rc.3": "@abp/jquery@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.3.tgz#329f18570fb090d059b10aee79ae7a9e6a324c97" resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.5.tgz#9b01156a80d8da6407abb6d51541cb89624cb906"
integrity sha512-j2GByw2EDpQZfWkuJkQ8aGIvtP3rAkIfXiz0KG/lAn6WhmQpQSuE7x6tkmGBaGKp+TP7KrTb6FZraOdVQzWoWA== integrity sha512-KcRVhxEmUuJHd4JNBSeJV+3Ush4w9ambKxwPi3+q1fqdePekrLk9jKNud5HkP6JredBoESJ+TkeVFFQ5HnYPVg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
jquery "~3.6.0" jquery "~3.6.0"
"@abp/lodash@~8.2.0-rc.3": "@abp/lodash@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.3.tgz#2a9d4f0cce96509d1547e57f499402128b080607" resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.5.tgz#b6fa8754258dd2db59b0df65fb9f7d90c8611af6"
integrity sha512-/4ZdVFTTLkzHEtpmIg9f8obLfyfAOLyXGXmfyklclvr14TxIINUjsDdvSKnVNYsT8R8vZkRqkuGYvk21ccE8tg== integrity sha512-LvK03DSk9lDNGEFrjMdiaAkaH58ll+PIn663KJk0kVZvtNLy/egCOMCc6EBuE5DUsjwebLi6YZYzgRQRRKirgw==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
lodash "^4.17.21" lodash "^4.17.21"
"@abp/luxon@~8.2.0-rc.3": "@abp/luxon@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.3.tgz#5cff88da204f5b7737519a31c5e683f88a9b3ac8" resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.5.tgz#e4300d1deebab16432737c831cfae0025b7c5891"
integrity sha512-b4h0uMIChqnvq2/U1gqirdgxvL3kQlQWoFMzhX/ahIKL8rXzh0v+Db8Cd6VV0eRIT6JowviYAqfqz5l0fWDPRg== integrity sha512-UdAToIlS0CwmavErMtd5dwyssKNPa6oqlHrll5h7T26nHDPEdXzSi9rP8RvwqBkrt+BFPMctRSv6DYk8OwoWzA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
luxon "^2.3.0" luxon "^2.3.0"
"@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.3": "@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.3.tgz#c6db0bdc0cc64c7f95b35c030828db7d2d8b989b" resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.5.tgz#8f39683e55fbc5487de08b9209a552cf32ea8087"
integrity sha512-SwBQlS6FYemkJXvdadT9sQiGXz8Fz9PRAjAD00MBUObqT2/RtvB82ssaNT5E1+HikveZ0p75yq7nOLh2zWhn9Q== integrity sha512-e20kLUvnu6tD5GBjzGLQjTMeyeco4q5wO4H4mMuahJpCHue+EUrL0tT1IbWiE+eEmbePw/lAn7Yfhfwjq/+Eeg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
malihu-custom-scrollbar-plugin "^3.1.5" malihu-custom-scrollbar-plugin "^3.1.5"
"@abp/moment@~8.2.0-rc.3": "@abp/moment@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.3.tgz#1bab0a10d131664e7151c2be5f41fddf4c2859f0" resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.5.tgz#e38c7e66ee383a986c7972f4ba2b19d79a43f60e"
integrity sha512-2qrczEiKg2H1ObT3md5TSRtufbvy5nsm7RxUmBLhh1TrUCsUN6YHw9ROTGkzIST686Ew3j4GgZGdJuelZteqWA== integrity sha512-F//4TZySaFBTfWgBxzwTFLeStrS0nklmKcTMU+MOtb/7Zx3QtscJpNm4CmxiBpB8pLwK8xiJQGoiuMQdoTuq+g==
dependencies: dependencies:
moment "^2.9.0" moment "^2.9.0"
"@abp/prismjs@~8.2.0-rc.3": "@abp/prismjs@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-8.2.0-rc.3.tgz#635335a1606e8f3c0e0353598a438f851be754b0" resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-8.2.0-rc.5.tgz#7a7428bb2f118cef5121a196bc45cc5d1a5a8e93"
integrity sha512-KR4xmoAwtsuQTXl4HrfC9ODmaAd/9ehrkrwXkduXid/+i79DuCILLUxdpz/lQG6axAbTwhagmfdJQuqDgsvM1w== integrity sha512-lNPqRvisf8jAxyL/05ppH26ZH4DEEzZUKqO7zqqS+yl7sBTpR/Wh8xX09spQl+wBQTLWAz2z+MouBZnMQIYKjg==
dependencies: dependencies:
"@abp/clipboard" "~8.2.0-rc.3" "@abp/clipboard" "~8.2.0-rc.5"
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
prismjs "^1.26.0" prismjs "^1.26.0"
"@abp/select2@~8.2.0-rc.3": "@abp/select2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.3.tgz#ae182953d45aca5f5ab5ddb5dded5efea23c6400" resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.5.tgz#5fc1dfa4bb871961db0ce9eb68a2c655c38b32d0"
integrity sha512-V8Hzdw1kGaR3K11//iCU+nRV81NPmAR1ZeIPgeZrS9C+9835O/yVhYI4QZk8OdLOIStiJbkVU7bOOt9mhFO8tw== integrity sha512-fT5L+mgiEOBtf2mmXNv6GtXVNjv22qQlgWp1UjI7c0jLtNPHa7P8idVTaP3g6d8b7VCP5zxIUGgjf6sZMxhADg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
select2 "^4.0.13" select2 "^4.0.13"
"@abp/sweetalert2@~8.2.0-rc.3": "@abp/sweetalert2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.3.tgz#dffe9862d7836ceaf5a057014acca28b756167f3" resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.5.tgz#502d6dbaf2c5296f67722e085e52dd0fe62e8dde"
integrity sha512-MgvA8sojsr8QH/ERBw+tZjiPu+6Kj1yozyaQ7r8je6wCWt0CUv+X6AFHp0WAaREssDclArF5h4b1GD6mP33w7g== integrity sha512-S0LTMU0a9SPdSA3ezEpo03ZGfrr7XtouEs0O5c4fA0kWYsddNkalighy3CYTgZZwaR9oWNnY6t4pyka3WXAaqg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
sweetalert2 "^11.3.6" sweetalert2 "^11.3.6"
"@abp/timeago@~8.2.0-rc.3": "@abp/timeago@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.3.tgz#00d463fb890b1e41268c0599039b0a4318848569" resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.5.tgz#8bd78f2ee6b27b8ffd77e75a2851b61013e481ee"
integrity sha512-RpoEKExLhnZlqFvYgsUFpyFpHCrrO17tSf+iLRNokMPQHp0BXT0sV2UFg0Cw51XQg5NKWp9cL+bY2IEOe1qwIA== integrity sha512-eLG9WFtP1dOoYHaNxyV8gOx1xnKmqSTwgviTU45qUFSNsgQHH1n0bpBxUXSSvaFw5mWRbF3R/JJQHql+Dl6Cow==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
timeago "^1.6.7" timeago "^1.6.7"
"@abp/toastr@~8.2.0-rc.3": "@abp/toastr@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.3.tgz#1a3b85b23a352f3b6e0480185a0ca91ab142a251" resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.5.tgz#baecda4e6fed5676f58de2228bf8d1c6ae66d49e"
integrity sha512-EC9EOio5ObgsjYa2fB8v4pgBPKiJ8Lbb7K+lKSQPxZSuqLrw+hEixgqZ0S9bBz5jxNRyqMFBdWAmYU6Vt5zzig== integrity sha512-y7aOY1LF62yRwXRSrvimtqIilrsOgSAM8lHcp2RogZAFdmw7yU1R5a6fJlLDGeRBIgjdcIlSpaOuoi6T2hCjFw==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
toastr "^2.1.4" toastr "^2.1.4"
"@abp/utils@~8.2.0-rc.3": "@abp/utils@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.3.tgz#94c9708e7af563a55a163fd4b57d1b276db61da3" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.5.tgz#526d64aa3e059d2f6e595b22e35dda2d652377e4"
integrity sha512-SAfmjq5MXW32IlXxkN9zZhOtgSgoAhE2OENYPk9eAHsEtkJ7f9+Q+vOE3oJPBI7lFv0K/lee3FrEbDQBsB5XHA== integrity sha512-ZU7jHFpDh7jDYgCrX6aXqy/v4LrMGgYJN+siyWUMpVddg2lTTO2MsxI+KmSxJwD7H01Mqj1sZ+LBAOVxGR3hsw==
dependencies: dependencies:
just-compare "^2.3.0" just-compare "^2.3.0"

1
modules/blogging/app/Volo.BloggingTestApp/Program.cs

@ -16,6 +16,7 @@ namespace Volo.BloggingTestApp
.MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext() .Enrich.FromLogContext()
.WriteTo.File("Logs/logs.txt") .WriteTo.File("Logs/logs.txt")
.WriteTo.Console()
.CreateLogger(); .CreateLogger();
try try

4
modules/blogging/app/Volo.BloggingTestApp/package.json

@ -3,7 +3,7 @@
"name": "volo.blogtestapp", "name": "volo.blogtestapp",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "~8.2.0-rc.3", "@abp/aspnetcore.mvc.ui.theme.basic": "~8.2.0-rc.5",
"@abp/blogging": "~8.2.0-rc.3" "@abp/blogging": "~8.2.0-rc.5"
} }
} }

318
modules/blogging/app/Volo.BloggingTestApp/yarn.lock

@ -2,237 +2,237 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/aspnetcore.mvc.ui.theme.basic@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.basic@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-8.2.0-rc.3.tgz#ade99976f35ceddd814db8c3e5e376e8664f22eb" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-8.2.0-rc.5.tgz#5cc3231d27e9e12e6fdc3e4fc5eb3e6f2019cf13"
integrity sha512-IaBP/R/lMY5KNP8NIny4ydjJTqlWu1z2lM0lkWoNFhhBq9dmLEVKDJjzaeU4/UOhM8bHqEhvrWt2wh4me/SYIQ== integrity sha512-SKr5Zm6k2SxrRBW2gqJAsTag4KacVzuVG3sTCD5P5BZLYn5OvknwSeky4tg/wzCodWp20wf89hWyET4E0iKExg==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.3.tgz#39591ad57565941fef36eec043b3c77f370bfa03" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.5.tgz#97b86ea4daf4392a1067e2a7e7c03b4c381ccc82"
integrity sha512-fE0Eevh7Y3pVHh6sbUTJaguCJMIiIhXkfRcVDYEkY+UZ33hfsodAzhKH7byb8AV6xWD/kfacsrtXpMP5zb6hPA== integrity sha512-lR3XbbNct+8QH1dRhED5s/CHCgkANVyNBrWCQbo4BwBFJ27d3wuJDVt39VxQUsgNfxEmyoJdVZNDRUKDv6fTOw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui" "~8.2.0-rc.5"
"@abp/bootstrap" "~8.2.0-rc.3" "@abp/bootstrap" "~8.2.0-rc.5"
"@abp/bootstrap-datepicker" "~8.2.0-rc.3" "@abp/bootstrap-datepicker" "~8.2.0-rc.5"
"@abp/bootstrap-daterangepicker" "~8.2.0-rc.3" "@abp/bootstrap-daterangepicker" "~8.2.0-rc.5"
"@abp/datatables.net-bs5" "~8.2.0-rc.3" "@abp/datatables.net-bs5" "~8.2.0-rc.5"
"@abp/font-awesome" "~8.2.0-rc.3" "@abp/font-awesome" "~8.2.0-rc.5"
"@abp/jquery-form" "~8.2.0-rc.3" "@abp/jquery-form" "~8.2.0-rc.5"
"@abp/jquery-validation-unobtrusive" "~8.2.0-rc.3" "@abp/jquery-validation-unobtrusive" "~8.2.0-rc.5"
"@abp/lodash" "~8.2.0-rc.3" "@abp/lodash" "~8.2.0-rc.5"
"@abp/luxon" "~8.2.0-rc.3" "@abp/luxon" "~8.2.0-rc.5"
"@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.3" "@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.5"
"@abp/moment" "~8.2.0-rc.3" "@abp/moment" "~8.2.0-rc.5"
"@abp/select2" "~8.2.0-rc.3" "@abp/select2" "~8.2.0-rc.5"
"@abp/sweetalert2" "~8.2.0-rc.3" "@abp/sweetalert2" "~8.2.0-rc.5"
"@abp/timeago" "~8.2.0-rc.3" "@abp/timeago" "~8.2.0-rc.5"
"@abp/toastr" "~8.2.0-rc.3" "@abp/toastr" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.3.tgz#f4ee679bdc6151b0e91b74c3d249963507cc3ecf" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.5.tgz#4a845ebd4b6465b9ac04641d7479b449ca9e1c5f"
integrity sha512-3dROllA2K9DGngy+hvTTpZUwvCjDEZy/3ec1X07TgIcioYKDis6vN+nDP4QcSAu3Fa4VEJderxizSCAJejbURQ== integrity sha512-l3brGHAD2jnlAWwITGNAY5zOtmc0WItVabYCTvKrYyNuKIPEtW9getUNFp9BFMT9x0KZiGnkkrRkvxH+DzIcug==
dependencies: dependencies:
ansi-colors "^4.1.1" ansi-colors "^4.1.1"
"@abp/blogging@~8.2.0-rc.3": "@abp/blogging@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/blogging/-/blogging-8.2.0-rc.3.tgz#a9117ded297f0dc1412c2d56846fa69b94801fb4" resolved "https://registry.yarnpkg.com/@abp/blogging/-/blogging-8.2.0-rc.5.tgz#821d5b01862d896591892e97e435adadcda07108"
integrity sha512-245u6RttYpI9TVWGBDUps2Bx0lxzmCyTIPDok1htp1bAJEapYIGAA/RWraWNbYeWpTMQbQ/MnMRI9e+yJxQXTA== integrity sha512-l6tbuaAkFTLv8BMcLFMLUE4ioYyuUmQecmnadDTE47DxZskIasyk7gvbpx8qDYwXr5IHAXgA7A7tTZX5K+tJAw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.5"
"@abp/owl.carousel" "~8.2.0-rc.3" "@abp/owl.carousel" "~8.2.0-rc.5"
"@abp/prismjs" "~8.2.0-rc.3" "@abp/prismjs" "~8.2.0-rc.5"
"@abp/tui-editor" "~8.2.0-rc.3" "@abp/tui-editor" "~8.2.0-rc.5"
"@abp/bootstrap-datepicker@~8.2.0-rc.3": "@abp/bootstrap-datepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.3.tgz#79ffeb35b9c46bc609d0341af83b463951f1c75a" resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.5.tgz#0e8755a51d7a691837951f7a071a9e59a2e9e6cf"
integrity sha512-PNLefHKC07GDAZy9TI8J6S/4+0bYJ7ajlZjjG3zAO248lG5RvRb6q2Mza0uMpNpVmh2mvowxpveS/s5iFMy4hA== integrity sha512-bLt8l6kYbVblThd2iuXcp6Ydss8TefpnZXHyXrQCxZGmVb79I/vf48CekJo1OWY/WcyEi/bm0m4LEI8Q0Y/LZQ==
dependencies: dependencies:
bootstrap-datepicker "^1.9.0" bootstrap-datepicker "^1.9.0"
"@abp/bootstrap-daterangepicker@~8.2.0-rc.3": "@abp/bootstrap-daterangepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.3.tgz#00d685f8c568713da9faf9d1f9a29a2cf81399c4" resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.5.tgz#e37792f24c3c8a8643e5ba5744967505e54f836c"
integrity sha512-2SQii4h9YbkvbkDU4HXBSjIXGlfISMnNweQju7R/HsvwHmSeMYs/UpjQyBjQalJnsl/arYH++bQamUb6QkgTzg== integrity sha512-dN02S1g9sVgACMz+A5FJw0uz4u5lXTFd/7xjE+cmhj0p5AcGvDD3gTbes6d3QNKiwvsPge063lG9pisdn3uEjg==
dependencies: dependencies:
bootstrap-daterangepicker "^3.1.0" bootstrap-daterangepicker "^3.1.0"
"@abp/bootstrap@~8.2.0-rc.3": "@abp/bootstrap@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.3.tgz#518319bd863e24c69c147f57e5b08ba51598098d" resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.5.tgz#1acc191f8156d81e1794bc161bfb394ae8f7372e"
integrity sha512-Q1S8MF44BjIHO0zCLq6tQ97SfGZ0AmucnSvjEA2QaYG+t6vcLulgVqOC+YhaiLVIz72nOZ6n822c5nnI+PvsAA== integrity sha512-FacgSrDlS3QSR+5WdOy06Qw0qF7OoqoBwAGqro2WOfY5sFR5OwEiqXHXUF95+a/q9B9NuYKXBjBfOPhljdiuuA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
bootstrap "^5.1.3" bootstrap "^5.1.3"
"@abp/clipboard@~8.2.0-rc.3": "@abp/clipboard@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-8.2.0-rc.3.tgz#dccbed56abc365aa8a1347b38ce4d33b77335d5c" resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-8.2.0-rc.5.tgz#5cec3d9c89bdad8d50f41807b3be68d4cdecb003"
integrity sha512-jqD48p4N3DR46v3eo8v/+Y7olOr3QcrFvv3QIbjEIGywYGepOv1W4nhmVQSwHRZqyOCSXr7E/vJZZahfsGKeQg== integrity sha512-cBaMy8A1CIU00X6SoGyuMTVf6z9iyEaR6smVRWCVmkf2VayAHFES981+iE+VmT2bezgbCidA2GXtkBZ/kunbJg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
clipboard "^2.0.8" clipboard "^2.0.8"
"@abp/core@~8.2.0-rc.3": "@abp/core@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.3.tgz#7f78600e91d2a5f4d7ea75ce4be541d9c23d5db8" resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.5.tgz#67eb75df046f8997f6af14e86bf8dbf249388a8d"
integrity sha512-0jBUCt6Q7ZoaZ1tciliIYfVZE75qZtkFZ/unkz1MeToo+djFGt8oyXhoZ/0vG2t6yG0BzN+TajAbcZ81F+isKQ== integrity sha512-XVunQMbK/MApkfnpL+8WsVqsJxARBl6W0TZwKfPyfm1QzPWE75P4oW3CIdNis0+Ob5HfhSFFp78tVrbSoEdzYQ==
dependencies: dependencies:
"@abp/utils" "~8.2.0-rc.3" "@abp/utils" "~8.2.0-rc.5"
"@abp/datatables.net-bs5@~8.2.0-rc.3": "@abp/datatables.net-bs5@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.3.tgz#4b56059400e53acb7f6ae74fc3a0c07c8de74413" resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.5.tgz#fe04af4b14530545a05c4c58361aadfdddd8e8c2"
integrity sha512-fcw9KNyfdPj6s3AjyoHvrXQLYHajrollnPitO0jLLiaYjTf8DkWaCQY/yAwcJqzZlvv9P3A56VlWpBye1iHowQ== integrity sha512-yZKC111JVxcOkDz/WxJyQ0lw3JpbBBWr21LVNjyhEiN62w8tJN1Gwo7CjL+7WFm7RPnAUUf/qwitRWmWl7M4YA==
dependencies: dependencies:
"@abp/datatables.net" "~8.2.0-rc.3" "@abp/datatables.net" "~8.2.0-rc.5"
datatables.net-bs5 "^1.11.4" datatables.net-bs5 "^1.11.4"
"@abp/datatables.net@~8.2.0-rc.3": "@abp/datatables.net@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.3.tgz#e701ed17dcbe799d227606638c99e7c120ad714e" resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.5.tgz#94e4b933750332732eeef02119a6cdfca67811e7"
integrity sha512-C1yvafNg5LtnWVqDX7Z9lyhRrWVntymdI0BfP2V4SDVeqoSTLwf859vWn2/WYyDAgtiuqGyW7YdUTHWq+aSppw== integrity sha512-IAXbC29eiHvA3unVMsFh2sNfiw+Jlgah0D++IUKOlz1eAzHMrpwP5KE4jmF6GESF7Al95NkgqH7cd6MUst+UlA==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
datatables.net "^1.11.4" datatables.net "^1.11.4"
"@abp/font-awesome@~8.2.0-rc.3": "@abp/font-awesome@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.3.tgz#091403b45dc310cdf71537e79cfdfb081a6ab90b" resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.5.tgz#5ae19305a373a6dd083944bd825ccea84aadf40b"
integrity sha512-kIVENG5e/WyIr63q6ka6sedmF+kTNSZKr0TUt7mUntJPoY8HQAizcC6SF6/w/xJAgNyVVrOe4+2LPpIkbwLK6g== integrity sha512-VbcM80e9KrZzY6TJ9l/eW42CTpdQ0eBr5gOEW+/UWGTRalCLdGve9YVJZJA55bD1VtcgaR1sV342jw2B1XeN8w==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
"@fortawesome/fontawesome-free" "^6.5.1" "@fortawesome/fontawesome-free" "^6.5.1"
"@abp/jquery-form@~8.2.0-rc.3": "@abp/jquery-form@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.3.tgz#30fe28736094fa44d22df7fc65ffbcf8f33c671d" resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.5.tgz#b955fe2c226f1f35a3736aa3b2170f265a797552"
integrity sha512-LfiY4EaDHGQAHjF9i92KLDpc5HH7LUNo+pEEv9JQEvSsTH+JuN1aUf85bxX8GkY63BJbS+vVKGe2YmZJeQjGlA== integrity sha512-M9fUUYywljudem/K7aYlcIG2W+KTzUJPviSeOLo5KNxvVrScWr+Jf4M8Nbj6uWX1saYWmm5kYnfsDs+nOUcmDg==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-form "^4.3.0" jquery-form "^4.3.0"
"@abp/jquery-validation-unobtrusive@~8.2.0-rc.3": "@abp/jquery-validation-unobtrusive@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.3.tgz#6829a9022d9d759e7b2c8719f0c44f70a369f618" resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.5.tgz#c790dc1b707ee7d24fe99c2b7be6bc558af09667"
integrity sha512-C1NEsXZW6SFBo5zYaMv5GGAF6kUh1StVVnCy+AMeHOu2MffucxMQP+EdXFoWgaG+8bdcJAImHVaMUxBmi8OtDA== integrity sha512-sUkfb17cR2zM669U83R8dviv+p+uGNl5nmOV0AP4ch6CzLfnTOYzKsqV7ESGVxqB8oVHO/Wnr8sXaaLdsoQzJw==
dependencies: dependencies:
"@abp/jquery-validation" "~8.2.0-rc.3" "@abp/jquery-validation" "~8.2.0-rc.5"
jquery-validation-unobtrusive "^3.2.12" jquery-validation-unobtrusive "^3.2.12"
"@abp/jquery-validation@~8.2.0-rc.3": "@abp/jquery-validation@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.3.tgz#91e3158189c83dd94da358d4cb86acde751512f7" resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.5.tgz#294254556e804d641d3bf4ea50d1c3eb42f191d1"
integrity sha512-kigDjMUZ/n+1d3THZW5fH0RhfP79+LtqnmATwpACERDdJUBKDSJ7O6sY3Zu8HqTHB8vAuNuYBpYpkIaAg+KocA== integrity sha512-C7sOuSShkX5Ba6LiSBGuxlrORcxiYczZtsxyjRZzNzATYwEBHcLqMxDvgAsWeWtvtkMotkbB2k99vD93nlGuCQ==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-validation "^1.19.3" jquery-validation "^1.19.3"
"@abp/jquery@~8.2.0-rc.3": "@abp/jquery@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.3.tgz#329f18570fb090d059b10aee79ae7a9e6a324c97" resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.5.tgz#9b01156a80d8da6407abb6d51541cb89624cb906"
integrity sha512-j2GByw2EDpQZfWkuJkQ8aGIvtP3rAkIfXiz0KG/lAn6WhmQpQSuE7x6tkmGBaGKp+TP7KrTb6FZraOdVQzWoWA== integrity sha512-KcRVhxEmUuJHd4JNBSeJV+3Ush4w9ambKxwPi3+q1fqdePekrLk9jKNud5HkP6JredBoESJ+TkeVFFQ5HnYPVg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
jquery "~3.6.0" jquery "~3.6.0"
"@abp/lodash@~8.2.0-rc.3": "@abp/lodash@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.3.tgz#2a9d4f0cce96509d1547e57f499402128b080607" resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.5.tgz#b6fa8754258dd2db59b0df65fb9f7d90c8611af6"
integrity sha512-/4ZdVFTTLkzHEtpmIg9f8obLfyfAOLyXGXmfyklclvr14TxIINUjsDdvSKnVNYsT8R8vZkRqkuGYvk21ccE8tg== integrity sha512-LvK03DSk9lDNGEFrjMdiaAkaH58ll+PIn663KJk0kVZvtNLy/egCOMCc6EBuE5DUsjwebLi6YZYzgRQRRKirgw==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
lodash "^4.17.21" lodash "^4.17.21"
"@abp/luxon@~8.2.0-rc.3": "@abp/luxon@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.3.tgz#5cff88da204f5b7737519a31c5e683f88a9b3ac8" resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.5.tgz#e4300d1deebab16432737c831cfae0025b7c5891"
integrity sha512-b4h0uMIChqnvq2/U1gqirdgxvL3kQlQWoFMzhX/ahIKL8rXzh0v+Db8Cd6VV0eRIT6JowviYAqfqz5l0fWDPRg== integrity sha512-UdAToIlS0CwmavErMtd5dwyssKNPa6oqlHrll5h7T26nHDPEdXzSi9rP8RvwqBkrt+BFPMctRSv6DYk8OwoWzA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
luxon "^2.3.0" luxon "^2.3.0"
"@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.3": "@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.3.tgz#c6db0bdc0cc64c7f95b35c030828db7d2d8b989b" resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.5.tgz#8f39683e55fbc5487de08b9209a552cf32ea8087"
integrity sha512-SwBQlS6FYemkJXvdadT9sQiGXz8Fz9PRAjAD00MBUObqT2/RtvB82ssaNT5E1+HikveZ0p75yq7nOLh2zWhn9Q== integrity sha512-e20kLUvnu6tD5GBjzGLQjTMeyeco4q5wO4H4mMuahJpCHue+EUrL0tT1IbWiE+eEmbePw/lAn7Yfhfwjq/+Eeg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
malihu-custom-scrollbar-plugin "^3.1.5" malihu-custom-scrollbar-plugin "^3.1.5"
"@abp/moment@~8.2.0-rc.3": "@abp/moment@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.3.tgz#1bab0a10d131664e7151c2be5f41fddf4c2859f0" resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.5.tgz#e38c7e66ee383a986c7972f4ba2b19d79a43f60e"
integrity sha512-2qrczEiKg2H1ObT3md5TSRtufbvy5nsm7RxUmBLhh1TrUCsUN6YHw9ROTGkzIST686Ew3j4GgZGdJuelZteqWA== integrity sha512-F//4TZySaFBTfWgBxzwTFLeStrS0nklmKcTMU+MOtb/7Zx3QtscJpNm4CmxiBpB8pLwK8xiJQGoiuMQdoTuq+g==
dependencies: dependencies:
moment "^2.9.0" moment "^2.9.0"
"@abp/owl.carousel@~8.2.0-rc.3": "@abp/owl.carousel@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/owl.carousel/-/owl.carousel-8.2.0-rc.3.tgz#d508f01bc22b00c57ffda57cb6df2afba1e05997" resolved "https://registry.yarnpkg.com/@abp/owl.carousel/-/owl.carousel-8.2.0-rc.5.tgz#4f0dc2ebf8aa4120ae33136fc9fa20544ce36f73"
integrity sha512-9c9USkocAN5LfTomqAmGThmLhNbAxGu0ik8L1n0EOTY+E3QCLHutmAao0x6mF+LSf2r7kVzBES/VBBWaZ1ulww== integrity sha512-eaYUpSsLvlmAovXPtmXHiP11xFkOgmiw6fbIl8JpyTRn/xS9I5wNVawr6vVXbL6JK90H7ZbKI/GY0KzsbDeWDQ==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
owl.carousel "^2.3.4" owl.carousel "^2.3.4"
"@abp/prismjs@~8.2.0-rc.3": "@abp/prismjs@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-8.2.0-rc.3.tgz#635335a1606e8f3c0e0353598a438f851be754b0" resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-8.2.0-rc.5.tgz#7a7428bb2f118cef5121a196bc45cc5d1a5a8e93"
integrity sha512-KR4xmoAwtsuQTXl4HrfC9ODmaAd/9ehrkrwXkduXid/+i79DuCILLUxdpz/lQG6axAbTwhagmfdJQuqDgsvM1w== integrity sha512-lNPqRvisf8jAxyL/05ppH26ZH4DEEzZUKqO7zqqS+yl7sBTpR/Wh8xX09spQl+wBQTLWAz2z+MouBZnMQIYKjg==
dependencies: dependencies:
"@abp/clipboard" "~8.2.0-rc.3" "@abp/clipboard" "~8.2.0-rc.5"
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
prismjs "^1.26.0" prismjs "^1.26.0"
"@abp/select2@~8.2.0-rc.3": "@abp/select2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.3.tgz#ae182953d45aca5f5ab5ddb5dded5efea23c6400" resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.5.tgz#5fc1dfa4bb871961db0ce9eb68a2c655c38b32d0"
integrity sha512-V8Hzdw1kGaR3K11//iCU+nRV81NPmAR1ZeIPgeZrS9C+9835O/yVhYI4QZk8OdLOIStiJbkVU7bOOt9mhFO8tw== integrity sha512-fT5L+mgiEOBtf2mmXNv6GtXVNjv22qQlgWp1UjI7c0jLtNPHa7P8idVTaP3g6d8b7VCP5zxIUGgjf6sZMxhADg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
select2 "^4.0.13" select2 "^4.0.13"
"@abp/sweetalert2@~8.2.0-rc.3": "@abp/sweetalert2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.3.tgz#dffe9862d7836ceaf5a057014acca28b756167f3" resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.5.tgz#502d6dbaf2c5296f67722e085e52dd0fe62e8dde"
integrity sha512-MgvA8sojsr8QH/ERBw+tZjiPu+6Kj1yozyaQ7r8je6wCWt0CUv+X6AFHp0WAaREssDclArF5h4b1GD6mP33w7g== integrity sha512-S0LTMU0a9SPdSA3ezEpo03ZGfrr7XtouEs0O5c4fA0kWYsddNkalighy3CYTgZZwaR9oWNnY6t4pyka3WXAaqg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
sweetalert2 "^11.3.6" sweetalert2 "^11.3.6"
"@abp/timeago@~8.2.0-rc.3": "@abp/timeago@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.3.tgz#00d463fb890b1e41268c0599039b0a4318848569" resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.5.tgz#8bd78f2ee6b27b8ffd77e75a2851b61013e481ee"
integrity sha512-RpoEKExLhnZlqFvYgsUFpyFpHCrrO17tSf+iLRNokMPQHp0BXT0sV2UFg0Cw51XQg5NKWp9cL+bY2IEOe1qwIA== integrity sha512-eLG9WFtP1dOoYHaNxyV8gOx1xnKmqSTwgviTU45qUFSNsgQHH1n0bpBxUXSSvaFw5mWRbF3R/JJQHql+Dl6Cow==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
timeago "^1.6.7" timeago "^1.6.7"
"@abp/toastr@~8.2.0-rc.3": "@abp/toastr@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.3.tgz#1a3b85b23a352f3b6e0480185a0ca91ab142a251" resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.5.tgz#baecda4e6fed5676f58de2228bf8d1c6ae66d49e"
integrity sha512-EC9EOio5ObgsjYa2fB8v4pgBPKiJ8Lbb7K+lKSQPxZSuqLrw+hEixgqZ0S9bBz5jxNRyqMFBdWAmYU6Vt5zzig== integrity sha512-y7aOY1LF62yRwXRSrvimtqIilrsOgSAM8lHcp2RogZAFdmw7yU1R5a6fJlLDGeRBIgjdcIlSpaOuoi6T2hCjFw==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
toastr "^2.1.4" toastr "^2.1.4"
"@abp/tui-editor@~8.2.0-rc.3": "@abp/tui-editor@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/tui-editor/-/tui-editor-8.2.0-rc.3.tgz#1507a673a0fc4591b8c6aa458922f6bfc36805b5" resolved "https://registry.yarnpkg.com/@abp/tui-editor/-/tui-editor-8.2.0-rc.5.tgz#809ef1bb0f90576d2ad7e67b13e707fe889a7e27"
integrity sha512-zDFBI7wN6jqez8wYSlQhot5GZM50RWBeQfSUWsRpbD5a4cvOTEnqJL3HeRAPwIp4hdgdctlNJolMJ/fmiM5kqg== integrity sha512-M1rKE0IhOmj6b/RopK2zDLSe0c7uSngWTv7MYEQjmGwHBG1+M0CEBSXVZWEJQ+LZjB+83oc4Z4UOW+yUW0suXg==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
"@abp/prismjs" "~8.2.0-rc.3" "@abp/prismjs" "~8.2.0-rc.5"
"@abp/utils@~8.2.0-rc.3": "@abp/utils@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.3.tgz#94c9708e7af563a55a163fd4b57d1b276db61da3" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.5.tgz#526d64aa3e059d2f6e595b22e35dda2d652377e4"
integrity sha512-SAfmjq5MXW32IlXxkN9zZhOtgSgoAhE2OENYPk9eAHsEtkJ7f9+Q+vOE3oJPBI7lFv0K/lee3FrEbDQBsB5XHA== integrity sha512-ZU7jHFpDh7jDYgCrX6aXqy/v4LrMGgYJN+siyWUMpVddg2lTTO2MsxI+KmSxJwD7H01Mqj1sZ+LBAOVxGR3hsw==
dependencies: dependencies:
just-compare "^2.3.0" just-compare "^2.3.0"

2
modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json

@ -85,7 +85,7 @@
"MoreFromUser": "More From {0}", "MoreFromUser": "More From {0}",
"BlogPosts": "Posts", "BlogPosts": "Posts",
"Views": "views", "Views": "views",
"Biography": "biography", "Biography": "Biography",
"Social": "Social", "Social": "Social",
"NewBlogPost" : "New Blog Post" "NewBlogPost" : "New Blog Post"
} }

2
modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/tr.json

@ -83,7 +83,7 @@
"EditProfile": "Profili Düzenle", "EditProfile": "Profili Düzenle",
"MoreFromBlog": "Daha Fazla Blog", "MoreFromBlog": "Daha Fazla Blog",
"MoreFromUser": "{0}'dan Daha Fazla", "MoreFromUser": "{0}'dan Daha Fazla",
"Biography": "biyografi", "Biography": "Biyografi",
"Social": "Sosyal", "Social": "Sosyal",
"BlogPosts": "Gönderiler", "BlogPosts": "Gönderiler",
"NewBlogPost": "Yeni Blog Gönderisi" "NewBlogPost": "Yeni Blog Gönderisi"

45
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.cshtml

@ -107,9 +107,10 @@
@if (CurrentUser.Id == Model.User.Id) @if (CurrentUser.Id == Model.User.Id)
{ {
<abp-tabs> <abp-tabs>
@if (Model.Posts is not null && Model.Posts.Any())
{ <abp-tab name="all-posts" title="@L["Posts"]">
<abp-tab name="all-posts" title="@L["Posts"]"> @if (Model.Posts is not null && Model.Posts.Any())
{
<div class="mt-4 pt-3"> <div class="mt-4 pt-3">
@foreach (var post in Model.Posts) @foreach (var post in Model.Posts)
{ {
@ -117,7 +118,7 @@
<div class="post-type-cont" style="text-align: center;"> <div class="post-type-cont" style="text-align: center;">
<a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none"> <a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none">
<img gravatar-email="@Model.User.Email" default-image="Identicon" id="gravatar" class="post-member-img rounded-circle d-block" /> <img gravatar-email="@Model.User.Email" default-image="Identicon" id="gravatar" class="post-member-img rounded-circle d-block"/>
</a> </a>
</div> </div>
@ -149,39 +150,39 @@
</div> </div>
} }
</div> </div>
</abp-tab> }
} else
else {
{ <div class="col-md-8">
<div class="col-md-8"> <div class="mt-5 pt-6">
<div class="mt-5 pt-6"> <p>@L["MemberNotPublishedPostYet"]</p>
<p>@L["MemberNotPublishedPostYet"]</p> </div>
</div> </div>
</div> }
} </abp-tab>
<abp-tab name="edit-profile" title="Edit Profile"> <abp-tab name="edit-profile" title="Edit Profile">
<div class="mt-4 mb-3 pt-3"> <div class="mt-4 mb-3 pt-3">
<form method="post"> <form method="post">
<abp-row> <abp-row>
<abp-column size="_12" v-align="Center"> <abp-column size="_12" v-align="Center">
<abp-input class="form-control" asp-for="CustomUserUpdate.Name" required-symbol="false" label="@($"{L["Name"].Value} ({L["Optional"].Value})")" value="@Model.User.Name"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.Name" required-symbol="false" label="@($"{L["Name"].Value}")" value="@Model.User.Name"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.Surname" required-symbol="false" label="@($"{L["Surname"].Value} ({L["Optional"].Value})")" value="@Model.User.Surname"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.Surname" required-symbol="false" label="@($"{L["Surname"].Value}")" value="@Model.User.Surname"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.WebSite" required-symbol="false" label="@($"{L["WebSite"].Value} ({L["Optional"].Value})")" value="@Model.User.WebSite" info="@L["UpdateUserWebSiteInfo"].Value"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.WebSite" required-symbol="false" label="@($"{L["WebSite"].Value}")" value="@Model.User.WebSite" info="@L["UpdateUserWebSiteInfo"].Value"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.Twitter" required-symbol="false" label="Twitter @($"{L["UserName"].Value} ({L["Optional"].Value})")" value="@Model.User.Twitter" info="@L["UpdateUserTwitterInfo"].Value"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.Twitter" required-symbol="false" label="Twitter @($"{L["UserName"].Value}")" value="@Model.User.Twitter" info="@L["UpdateUserTwitterInfo"].Value"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.Github" required-symbol="false" label="Github @($"{L["UserName"].Value} ({L["Optional"].Value})")" value="@Model.User.Github" info="@L["UpdateUserGithubInfo"].Value"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.Github" required-symbol="false" label="GitHub @($"{L["UserName"].Value}")" value="@Model.User.Github" info="@L["UpdateUserGithubInfo"].Value"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.Linkedin" required-symbol="false" label="Linkedin @($"{L["FullURL"].Value} ({L["Optional"].Value})")" value="@Model.User.Linkedin" info="@L["UpdateUserLinkedinInfo"].Value"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.Linkedin" required-symbol="false" label="Linkedin @($"{L["FullURL"].Value}")" value="@Model.User.Linkedin" info="@L["UpdateUserLinkedinInfo"].Value"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.Company" required-symbol="false" label="@($"{L["Company"].Value} ({L["Optional"].Value})")" value="@Model.User.Company" info="@L["UpdateUserCompanyInfo"].Value"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.Company" required-symbol="false" label="@($"{L["Company"].Value}")" value="@Model.User.Company" info="@L["UpdateUserCompanyInfo"].Value"></abp-input>
<abp-input class="form-control" asp-for="CustomUserUpdate.JobTitle" required-symbol="false" label="@($"{L["JobTitle"].Value} ({L["Optional"].Value})")" value="@Model.User.JobTitle" info="@L["UpdateUserJobTitleInfo"].Value"></abp-input> <abp-input class="form-control" asp-for="CustomUserUpdate.JobTitle" required-symbol="false" label="@($"{L["JobTitle"].Value}")" value="@Model.User.JobTitle" info="@L["UpdateUserJobTitleInfo"].Value"></abp-input>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">@L["Biography"] (@L["Optional"])</label> <label class="form-label">@L["Biography"]</label>
<textarea id="CustomUserUpdate_Biography" name="CustomUserUpdate.Biography" class="form-control " rows="7" data-val-length="The field Biography must be a string with a maximum length of 1000." data-val-length-max="1000" maxlength="1000">@Model.User.Biography</textarea> <textarea id="CustomUserUpdate_Biography" name="CustomUserUpdate.Biography" class="form-control " rows="7" data-val-length="The field Biography must be a string with a maximum length of 1000." data-val-length-max="1000" maxlength="1000">@Model.User.Biography</textarea>
</div> </div>
</abp-column> </abp-column>

6
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml

@ -194,14 +194,14 @@
{ {
<div class="row"> <div class="row">
<div class="col-auto pe-1"> <div class="col-auto pe-1">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})" aria-label="Go to user profile"> <a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})" aria-label="Go to user profile">
<img gravatar-email="@post.Writer.Email" default-image="Identicon" class="last-post-image" alt="User Avatar"/> <img gravatar-email="@post.Writer.Email" default-image="Identicon" class="last-post-image" alt="User Avatar"/>
</a> </a>
</div> </div>
<div class="col"> <div class="col">
<h5 class="last-post-name"> <h5 class="last-post-name">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})"> <a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})">
@(post.Writer!.UserName) @(post.Writer!.UserName)
</a> </a>
</h5> </h5>
@ -212,7 +212,7 @@
</div> </div>
<div class="col mt-2"> <div class="col mt-2">
<p> <p>
<a class="last-post-title" asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a> <a class="last-post-title" asp-page="./Detail" asp-route-postUrl="@post.Url">@post.Title</a>
</p> </p>
</div> </div>
</div> </div>

2
modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json

@ -3,6 +3,6 @@
"name": "client-simulation-web", "name": "client-simulation-web",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui.theme.basic": "~8.2.0-rc.5"
} }
} }

258
modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock

@ -2,194 +2,194 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/aspnetcore.mvc.ui.theme.basic@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.basic@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-8.2.0-rc.3.tgz#ade99976f35ceddd814db8c3e5e376e8664f22eb" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-8.2.0-rc.5.tgz#5cc3231d27e9e12e6fdc3e4fc5eb3e6f2019cf13"
integrity sha512-IaBP/R/lMY5KNP8NIny4ydjJTqlWu1z2lM0lkWoNFhhBq9dmLEVKDJjzaeU4/UOhM8bHqEhvrWt2wh4me/SYIQ== integrity sha512-SKr5Zm6k2SxrRBW2gqJAsTag4KacVzuVG3sTCD5P5BZLYn5OvknwSeky4tg/wzCodWp20wf89hWyET4E0iKExg==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui.theme.shared" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui.theme.shared@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.3.tgz#39591ad57565941fef36eec043b3c77f370bfa03" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-8.2.0-rc.5.tgz#97b86ea4daf4392a1067e2a7e7c03b4c381ccc82"
integrity sha512-fE0Eevh7Y3pVHh6sbUTJaguCJMIiIhXkfRcVDYEkY+UZ33hfsodAzhKH7byb8AV6xWD/kfacsrtXpMP5zb6hPA== integrity sha512-lR3XbbNct+8QH1dRhED5s/CHCgkANVyNBrWCQbo4BwBFJ27d3wuJDVt39VxQUsgNfxEmyoJdVZNDRUKDv6fTOw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui" "~8.2.0-rc.3" "@abp/aspnetcore.mvc.ui" "~8.2.0-rc.5"
"@abp/bootstrap" "~8.2.0-rc.3" "@abp/bootstrap" "~8.2.0-rc.5"
"@abp/bootstrap-datepicker" "~8.2.0-rc.3" "@abp/bootstrap-datepicker" "~8.2.0-rc.5"
"@abp/bootstrap-daterangepicker" "~8.2.0-rc.3" "@abp/bootstrap-daterangepicker" "~8.2.0-rc.5"
"@abp/datatables.net-bs5" "~8.2.0-rc.3" "@abp/datatables.net-bs5" "~8.2.0-rc.5"
"@abp/font-awesome" "~8.2.0-rc.3" "@abp/font-awesome" "~8.2.0-rc.5"
"@abp/jquery-form" "~8.2.0-rc.3" "@abp/jquery-form" "~8.2.0-rc.5"
"@abp/jquery-validation-unobtrusive" "~8.2.0-rc.3" "@abp/jquery-validation-unobtrusive" "~8.2.0-rc.5"
"@abp/lodash" "~8.2.0-rc.3" "@abp/lodash" "~8.2.0-rc.5"
"@abp/luxon" "~8.2.0-rc.3" "@abp/luxon" "~8.2.0-rc.5"
"@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.3" "@abp/malihu-custom-scrollbar-plugin" "~8.2.0-rc.5"
"@abp/moment" "~8.2.0-rc.3" "@abp/moment" "~8.2.0-rc.5"
"@abp/select2" "~8.2.0-rc.3" "@abp/select2" "~8.2.0-rc.5"
"@abp/sweetalert2" "~8.2.0-rc.3" "@abp/sweetalert2" "~8.2.0-rc.5"
"@abp/timeago" "~8.2.0-rc.3" "@abp/timeago" "~8.2.0-rc.5"
"@abp/toastr" "~8.2.0-rc.3" "@abp/toastr" "~8.2.0-rc.5"
"@abp/aspnetcore.mvc.ui@~8.2.0-rc.3": "@abp/aspnetcore.mvc.ui@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.3.tgz#f4ee679bdc6151b0e91b74c3d249963507cc3ecf" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-8.2.0-rc.5.tgz#4a845ebd4b6465b9ac04641d7479b449ca9e1c5f"
integrity sha512-3dROllA2K9DGngy+hvTTpZUwvCjDEZy/3ec1X07TgIcioYKDis6vN+nDP4QcSAu3Fa4VEJderxizSCAJejbURQ== integrity sha512-l3brGHAD2jnlAWwITGNAY5zOtmc0WItVabYCTvKrYyNuKIPEtW9getUNFp9BFMT9x0KZiGnkkrRkvxH+DzIcug==
dependencies: dependencies:
ansi-colors "^4.1.1" ansi-colors "^4.1.1"
"@abp/bootstrap-datepicker@~8.2.0-rc.3": "@abp/bootstrap-datepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.3.tgz#79ffeb35b9c46bc609d0341af83b463951f1c75a" resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-8.2.0-rc.5.tgz#0e8755a51d7a691837951f7a071a9e59a2e9e6cf"
integrity sha512-PNLefHKC07GDAZy9TI8J6S/4+0bYJ7ajlZjjG3zAO248lG5RvRb6q2Mza0uMpNpVmh2mvowxpveS/s5iFMy4hA== integrity sha512-bLt8l6kYbVblThd2iuXcp6Ydss8TefpnZXHyXrQCxZGmVb79I/vf48CekJo1OWY/WcyEi/bm0m4LEI8Q0Y/LZQ==
dependencies: dependencies:
bootstrap-datepicker "^1.9.0" bootstrap-datepicker "^1.9.0"
"@abp/bootstrap-daterangepicker@~8.2.0-rc.3": "@abp/bootstrap-daterangepicker@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.3.tgz#00d685f8c568713da9faf9d1f9a29a2cf81399c4" resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-8.2.0-rc.5.tgz#e37792f24c3c8a8643e5ba5744967505e54f836c"
integrity sha512-2SQii4h9YbkvbkDU4HXBSjIXGlfISMnNweQju7R/HsvwHmSeMYs/UpjQyBjQalJnsl/arYH++bQamUb6QkgTzg== integrity sha512-dN02S1g9sVgACMz+A5FJw0uz4u5lXTFd/7xjE+cmhj0p5AcGvDD3gTbes6d3QNKiwvsPge063lG9pisdn3uEjg==
dependencies: dependencies:
bootstrap-daterangepicker "^3.1.0" bootstrap-daterangepicker "^3.1.0"
"@abp/bootstrap@~8.2.0-rc.3": "@abp/bootstrap@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.3.tgz#518319bd863e24c69c147f57e5b08ba51598098d" resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-8.2.0-rc.5.tgz#1acc191f8156d81e1794bc161bfb394ae8f7372e"
integrity sha512-Q1S8MF44BjIHO0zCLq6tQ97SfGZ0AmucnSvjEA2QaYG+t6vcLulgVqOC+YhaiLVIz72nOZ6n822c5nnI+PvsAA== integrity sha512-FacgSrDlS3QSR+5WdOy06Qw0qF7OoqoBwAGqro2WOfY5sFR5OwEiqXHXUF95+a/q9B9NuYKXBjBfOPhljdiuuA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
bootstrap "^5.1.3" bootstrap "^5.1.3"
"@abp/core@~8.2.0-rc.3": "@abp/core@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.3.tgz#7f78600e91d2a5f4d7ea75ce4be541d9c23d5db8" resolved "https://registry.yarnpkg.com/@abp/core/-/core-8.2.0-rc.5.tgz#67eb75df046f8997f6af14e86bf8dbf249388a8d"
integrity sha512-0jBUCt6Q7ZoaZ1tciliIYfVZE75qZtkFZ/unkz1MeToo+djFGt8oyXhoZ/0vG2t6yG0BzN+TajAbcZ81F+isKQ== integrity sha512-XVunQMbK/MApkfnpL+8WsVqsJxARBl6W0TZwKfPyfm1QzPWE75P4oW3CIdNis0+Ob5HfhSFFp78tVrbSoEdzYQ==
dependencies: dependencies:
"@abp/utils" "~8.2.0-rc.3" "@abp/utils" "~8.2.0-rc.5"
"@abp/datatables.net-bs5@~8.2.0-rc.3": "@abp/datatables.net-bs5@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.3.tgz#4b56059400e53acb7f6ae74fc3a0c07c8de74413" resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-8.2.0-rc.5.tgz#fe04af4b14530545a05c4c58361aadfdddd8e8c2"
integrity sha512-fcw9KNyfdPj6s3AjyoHvrXQLYHajrollnPitO0jLLiaYjTf8DkWaCQY/yAwcJqzZlvv9P3A56VlWpBye1iHowQ== integrity sha512-yZKC111JVxcOkDz/WxJyQ0lw3JpbBBWr21LVNjyhEiN62w8tJN1Gwo7CjL+7WFm7RPnAUUf/qwitRWmWl7M4YA==
dependencies: dependencies:
"@abp/datatables.net" "~8.2.0-rc.3" "@abp/datatables.net" "~8.2.0-rc.5"
datatables.net-bs5 "^1.11.4" datatables.net-bs5 "^1.11.4"
"@abp/datatables.net@~8.2.0-rc.3": "@abp/datatables.net@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.3.tgz#e701ed17dcbe799d227606638c99e7c120ad714e" resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-8.2.0-rc.5.tgz#94e4b933750332732eeef02119a6cdfca67811e7"
integrity sha512-C1yvafNg5LtnWVqDX7Z9lyhRrWVntymdI0BfP2V4SDVeqoSTLwf859vWn2/WYyDAgtiuqGyW7YdUTHWq+aSppw== integrity sha512-IAXbC29eiHvA3unVMsFh2sNfiw+Jlgah0D++IUKOlz1eAzHMrpwP5KE4jmF6GESF7Al95NkgqH7cd6MUst+UlA==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
datatables.net "^1.11.4" datatables.net "^1.11.4"
"@abp/font-awesome@~8.2.0-rc.3": "@abp/font-awesome@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.3.tgz#091403b45dc310cdf71537e79cfdfb081a6ab90b" resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-8.2.0-rc.5.tgz#5ae19305a373a6dd083944bd825ccea84aadf40b"
integrity sha512-kIVENG5e/WyIr63q6ka6sedmF+kTNSZKr0TUt7mUntJPoY8HQAizcC6SF6/w/xJAgNyVVrOe4+2LPpIkbwLK6g== integrity sha512-VbcM80e9KrZzY6TJ9l/eW42CTpdQ0eBr5gOEW+/UWGTRalCLdGve9YVJZJA55bD1VtcgaR1sV342jw2B1XeN8w==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
"@fortawesome/fontawesome-free" "^6.5.1" "@fortawesome/fontawesome-free" "^6.5.1"
"@abp/jquery-form@~8.2.0-rc.3": "@abp/jquery-form@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.3.tgz#30fe28736094fa44d22df7fc65ffbcf8f33c671d" resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-8.2.0-rc.5.tgz#b955fe2c226f1f35a3736aa3b2170f265a797552"
integrity sha512-LfiY4EaDHGQAHjF9i92KLDpc5HH7LUNo+pEEv9JQEvSsTH+JuN1aUf85bxX8GkY63BJbS+vVKGe2YmZJeQjGlA== integrity sha512-M9fUUYywljudem/K7aYlcIG2W+KTzUJPviSeOLo5KNxvVrScWr+Jf4M8Nbj6uWX1saYWmm5kYnfsDs+nOUcmDg==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-form "^4.3.0" jquery-form "^4.3.0"
"@abp/jquery-validation-unobtrusive@~8.2.0-rc.3": "@abp/jquery-validation-unobtrusive@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.3.tgz#6829a9022d9d759e7b2c8719f0c44f70a369f618" resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-8.2.0-rc.5.tgz#c790dc1b707ee7d24fe99c2b7be6bc558af09667"
integrity sha512-C1NEsXZW6SFBo5zYaMv5GGAF6kUh1StVVnCy+AMeHOu2MffucxMQP+EdXFoWgaG+8bdcJAImHVaMUxBmi8OtDA== integrity sha512-sUkfb17cR2zM669U83R8dviv+p+uGNl5nmOV0AP4ch6CzLfnTOYzKsqV7ESGVxqB8oVHO/Wnr8sXaaLdsoQzJw==
dependencies: dependencies:
"@abp/jquery-validation" "~8.2.0-rc.3" "@abp/jquery-validation" "~8.2.0-rc.5"
jquery-validation-unobtrusive "^3.2.12" jquery-validation-unobtrusive "^3.2.12"
"@abp/jquery-validation@~8.2.0-rc.3": "@abp/jquery-validation@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.3.tgz#91e3158189c83dd94da358d4cb86acde751512f7" resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-8.2.0-rc.5.tgz#294254556e804d641d3bf4ea50d1c3eb42f191d1"
integrity sha512-kigDjMUZ/n+1d3THZW5fH0RhfP79+LtqnmATwpACERDdJUBKDSJ7O6sY3Zu8HqTHB8vAuNuYBpYpkIaAg+KocA== integrity sha512-C7sOuSShkX5Ba6LiSBGuxlrORcxiYczZtsxyjRZzNzATYwEBHcLqMxDvgAsWeWtvtkMotkbB2k99vD93nlGuCQ==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
jquery-validation "^1.19.3" jquery-validation "^1.19.3"
"@abp/jquery@~8.2.0-rc.3": "@abp/jquery@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.3.tgz#329f18570fb090d059b10aee79ae7a9e6a324c97" resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-8.2.0-rc.5.tgz#9b01156a80d8da6407abb6d51541cb89624cb906"
integrity sha512-j2GByw2EDpQZfWkuJkQ8aGIvtP3rAkIfXiz0KG/lAn6WhmQpQSuE7x6tkmGBaGKp+TP7KrTb6FZraOdVQzWoWA== integrity sha512-KcRVhxEmUuJHd4JNBSeJV+3Ush4w9ambKxwPi3+q1fqdePekrLk9jKNud5HkP6JredBoESJ+TkeVFFQ5HnYPVg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
jquery "~3.6.0" jquery "~3.6.0"
"@abp/lodash@~8.2.0-rc.3": "@abp/lodash@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.3.tgz#2a9d4f0cce96509d1547e57f499402128b080607" resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-8.2.0-rc.5.tgz#b6fa8754258dd2db59b0df65fb9f7d90c8611af6"
integrity sha512-/4ZdVFTTLkzHEtpmIg9f8obLfyfAOLyXGXmfyklclvr14TxIINUjsDdvSKnVNYsT8R8vZkRqkuGYvk21ccE8tg== integrity sha512-LvK03DSk9lDNGEFrjMdiaAkaH58ll+PIn663KJk0kVZvtNLy/egCOMCc6EBuE5DUsjwebLi6YZYzgRQRRKirgw==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
lodash "^4.17.21" lodash "^4.17.21"
"@abp/luxon@~8.2.0-rc.3": "@abp/luxon@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.3.tgz#5cff88da204f5b7737519a31c5e683f88a9b3ac8" resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-8.2.0-rc.5.tgz#e4300d1deebab16432737c831cfae0025b7c5891"
integrity sha512-b4h0uMIChqnvq2/U1gqirdgxvL3kQlQWoFMzhX/ahIKL8rXzh0v+Db8Cd6VV0eRIT6JowviYAqfqz5l0fWDPRg== integrity sha512-UdAToIlS0CwmavErMtd5dwyssKNPa6oqlHrll5h7T26nHDPEdXzSi9rP8RvwqBkrt+BFPMctRSv6DYk8OwoWzA==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
luxon "^2.3.0" luxon "^2.3.0"
"@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.3": "@abp/malihu-custom-scrollbar-plugin@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.3.tgz#c6db0bdc0cc64c7f95b35c030828db7d2d8b989b" resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-8.2.0-rc.5.tgz#8f39683e55fbc5487de08b9209a552cf32ea8087"
integrity sha512-SwBQlS6FYemkJXvdadT9sQiGXz8Fz9PRAjAD00MBUObqT2/RtvB82ssaNT5E1+HikveZ0p75yq7nOLh2zWhn9Q== integrity sha512-e20kLUvnu6tD5GBjzGLQjTMeyeco4q5wO4H4mMuahJpCHue+EUrL0tT1IbWiE+eEmbePw/lAn7Yfhfwjq/+Eeg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
malihu-custom-scrollbar-plugin "^3.1.5" malihu-custom-scrollbar-plugin "^3.1.5"
"@abp/moment@~8.2.0-rc.3": "@abp/moment@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.3.tgz#1bab0a10d131664e7151c2be5f41fddf4c2859f0" resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-8.2.0-rc.5.tgz#e38c7e66ee383a986c7972f4ba2b19d79a43f60e"
integrity sha512-2qrczEiKg2H1ObT3md5TSRtufbvy5nsm7RxUmBLhh1TrUCsUN6YHw9ROTGkzIST686Ew3j4GgZGdJuelZteqWA== integrity sha512-F//4TZySaFBTfWgBxzwTFLeStrS0nklmKcTMU+MOtb/7Zx3QtscJpNm4CmxiBpB8pLwK8xiJQGoiuMQdoTuq+g==
dependencies: dependencies:
moment "^2.9.0" moment "^2.9.0"
"@abp/select2@~8.2.0-rc.3": "@abp/select2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.3.tgz#ae182953d45aca5f5ab5ddb5dded5efea23c6400" resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-8.2.0-rc.5.tgz#5fc1dfa4bb871961db0ce9eb68a2c655c38b32d0"
integrity sha512-V8Hzdw1kGaR3K11//iCU+nRV81NPmAR1ZeIPgeZrS9C+9835O/yVhYI4QZk8OdLOIStiJbkVU7bOOt9mhFO8tw== integrity sha512-fT5L+mgiEOBtf2mmXNv6GtXVNjv22qQlgWp1UjI7c0jLtNPHa7P8idVTaP3g6d8b7VCP5zxIUGgjf6sZMxhADg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
select2 "^4.0.13" select2 "^4.0.13"
"@abp/sweetalert2@~8.2.0-rc.3": "@abp/sweetalert2@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.3.tgz#dffe9862d7836ceaf5a057014acca28b756167f3" resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-8.2.0-rc.5.tgz#502d6dbaf2c5296f67722e085e52dd0fe62e8dde"
integrity sha512-MgvA8sojsr8QH/ERBw+tZjiPu+6Kj1yozyaQ7r8je6wCWt0CUv+X6AFHp0WAaREssDclArF5h4b1GD6mP33w7g== integrity sha512-S0LTMU0a9SPdSA3ezEpo03ZGfrr7XtouEs0O5c4fA0kWYsddNkalighy3CYTgZZwaR9oWNnY6t4pyka3WXAaqg==
dependencies: dependencies:
"@abp/core" "~8.2.0-rc.3" "@abp/core" "~8.2.0-rc.5"
sweetalert2 "^11.3.6" sweetalert2 "^11.3.6"
"@abp/timeago@~8.2.0-rc.3": "@abp/timeago@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.3.tgz#00d463fb890b1e41268c0599039b0a4318848569" resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-8.2.0-rc.5.tgz#8bd78f2ee6b27b8ffd77e75a2851b61013e481ee"
integrity sha512-RpoEKExLhnZlqFvYgsUFpyFpHCrrO17tSf+iLRNokMPQHp0BXT0sV2UFg0Cw51XQg5NKWp9cL+bY2IEOe1qwIA== integrity sha512-eLG9WFtP1dOoYHaNxyV8gOx1xnKmqSTwgviTU45qUFSNsgQHH1n0bpBxUXSSvaFw5mWRbF3R/JJQHql+Dl6Cow==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
timeago "^1.6.7" timeago "^1.6.7"
"@abp/toastr@~8.2.0-rc.3": "@abp/toastr@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.3.tgz#1a3b85b23a352f3b6e0480185a0ca91ab142a251" resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-8.2.0-rc.5.tgz#baecda4e6fed5676f58de2228bf8d1c6ae66d49e"
integrity sha512-EC9EOio5ObgsjYa2fB8v4pgBPKiJ8Lbb7K+lKSQPxZSuqLrw+hEixgqZ0S9bBz5jxNRyqMFBdWAmYU6Vt5zzig== integrity sha512-y7aOY1LF62yRwXRSrvimtqIilrsOgSAM8lHcp2RogZAFdmw7yU1R5a6fJlLDGeRBIgjdcIlSpaOuoi6T2hCjFw==
dependencies: dependencies:
"@abp/jquery" "~8.2.0-rc.3" "@abp/jquery" "~8.2.0-rc.5"
toastr "^2.1.4" toastr "^2.1.4"
"@abp/utils@~8.2.0-rc.3": "@abp/utils@~8.2.0-rc.5":
version "8.2.0-rc.3" version "8.2.0-rc.5"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.3.tgz#94c9708e7af563a55a163fd4b57d1b276db61da3" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-8.2.0-rc.5.tgz#526d64aa3e059d2f6e595b22e35dda2d652377e4"
integrity sha512-SAfmjq5MXW32IlXxkN9zZhOtgSgoAhE2OENYPk9eAHsEtkJ7f9+Q+vOE3oJPBI7lFv0K/lee3FrEbDQBsB5XHA== integrity sha512-ZU7jHFpDh7jDYgCrX6aXqy/v4LrMGgYJN+siyWUMpVddg2lTTO2MsxI+KmSxJwD7H01Mqj1sZ+LBAOVxGR3hsw==
dependencies: dependencies:
just-compare "^2.3.0" just-compare "^2.3.0"

2
modules/cms-kit/.gitignore

@ -257,4 +257,4 @@ host/Volo.CmsKit.HttpApi.Host/Logs/logs.txt
host/Volo.CmsKit.Web.Host/Logs/logs.txt host/Volo.CmsKit.Web.Host/Logs/logs.txt
host/Volo.CmsKit.Web.Unified/Logs/logs.txt host/Volo.CmsKit.Web.Unified/Logs/logs.txt
**/wwwroot/libs/** **/wwwroot/libs/**

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

Loading…
Cancel
Save