diff --git a/.github/workflows/angular.yml b/.github/workflows/angular.yml
index ee66fbcf2c..cd48c0448a 100644
--- a/.github/workflows/angular.yml
+++ b/.github/workflows/angular.yml
@@ -27,12 +27,12 @@ jobs:
with:
fetch-depth: 0
- - uses: actions/cache@v2
+ - uses: actions/cache@v4
with:
path: 'npm/ng-packs/node_modules'
key: ${{ runner.os }}-${{ hashFiles('npm/ng-packs/yarn.lock') }}
- - uses: actions/cache@v2
+ - uses: actions/cache@v4
with:
path: 'templates/app/angular/node_modules'
key: ${{ runner.os }}-${{ hashFiles('templates/app/angular/yarn.lock') }}
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 0a243a3067..e76cb94b80 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -119,7 +119,7 @@
-
+
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
index 18b1cf1064..3fc052783f 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
@@ -695,7 +695,8 @@
"ModuleMainImage": "Module Main Image",
"ModuleImageInfo1": "Accepted file types : JPEG, JPG, PNG ",
"ModuleImageInfo2": "Max file size : 1 MB ",
- "ModuleImageInfo3": " Download a sample cover image ",
+ "ModuleImageInfo3": "Image Proportion : 1:1 ",
+ "ModuleImageInfo4": " Download a sample cover image ",
"AreYouSureToDeleteImage": "Are you sure you want to delete this image?"
}
}
diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md
index b6a99a8997..e59e75f44a 100644
--- a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md
+++ b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md
@@ -25,6 +25,7 @@ Here is a brief list of titles explained in the next sections:
* Docs Module: Added "Alternative Words" to Filter Items
* Introducing the Bunny BLOB Storage Provider
* Upgraded `MongoDB.Driver` to v3.1.0
+* Using Timezone Settings to Display Datetime
* Identity Pro Module: Require Email Verification to Register
* Switching users during OAuth login
@@ -114,6 +115,49 @@ The upgrade provides:
We have prepared a [migration guide](https://abp.io/docs/9.2/release-info/migration-guides/MongoDB-Driver-2-to-3) for this upgrade. Please refer to it to learn more about the changes and how to migrate your application.
+### Using Timezone Settings to Display Datetime
+
+A significant enhancement in ABP v9.2 is the ability to use timezone settings to display `DateTime` values according to the user's or application's configured timezone. Introduced in `v9.2.0-rc.2`, this feature addresses the common challenge of ensuring users see accurate time information, regardless of their geographical location.
+
+Previously, `DateTime` values were often shown in the server's timezone or in UTC, which could cause confusion for users in different timezones. With this new feature, ABP applications can now respect the configured timezone and automatically convert and display datetime values accordingly.
+
+**Before setting the timezone:**
+
+Consider a scenario where you have a list of books, and the `CreationTime` property is displayed without any timezone consideration. It may appear in the server's default timezone:
+
+
+*(Screenshot of a Books page showing the CreationTime in a default timezone.)*
+
+**Setting the timezone:**
+
+To set the timezone, start by configuring the `AbpClockOptions` in your module's `ConfigureServices` method:
+
+```csharp
+Configure(options =>
+{
+ options.Kind = DateTimeKind.Utc;
+});
+```
+
+> By setting the `Kind` property of `AbpClockOptions` to `DateTimeKind.Utc`, ABP will normalize all datetime values. Times stored in the database and returned to the frontend will be in UTC. Additionally, the `SupportsMultipleTimezone` property of the `IClock` service will be **true**, and you’ll be able to configure the timezone from the UI under the _Settings_ page.
+
+After setting the `Kind` property, you can run your application and configure the timezone from the UI under the _Settings_ page. For example, set the timezone to "Asia/Tokyo (+09:00)":
+
+
+*(Screenshot showing the configuration setting for Abp.Timing.TimeZone, set to "Asia/Tokyo (+09:00)".)*
+
+> ABP provides the `Abp.Timing.TimeZone` setting, which allows you to configure the desired timezone at the application, tenant, or user level and this setting can be configured in the UI under the _Settings_ page, inside of the _Time Zone_ tab.
+
+**After setting the timezone:**
+
+Once the timezone is configured, ABP automatically handles the conversion and display of `DateTime` values. The `CreationTime` on the _Books_ page will now be shown in the **"Asia/Tokyo"** timezone.
+
+
+*(Screenshot of the _Books_ page after setting the timezone, showing the `CreationTime` adjusted to the "Asia/Tokyo" timezone.)*
+
+This feature utilizes the `IClock` service, which provides methods like `ConvertToUserTime` and `ConvertToUtc` to facilitate timezone conversions. By configuring the `Abp.Timing.TimeZone` setting, developers can ensure a consistent and user-friendly experience across applications with a global user base.
+> For a more detailed guide on implementing and using this feature, refer to the article: [Developing a Multi-Timezone Application Using the ABP Framework](https://abp.io/community/articles/developing-a-multitimezone-application-using-the-abp-framework-zk7fnrdq). It offers step-by-step instructions and examples for handling multi-timezone scenarios in ABP applications.
+
### Identity Pro Module: Require Email Verification to Register
[ABP Identity Pro module](https://abp.io/docs/9.2/modules/identity-pro) has been enhanced with a new feature that allows administrators to require email verification during the registration process. This security improvement ensures that users must verify their email addresses before their registration is considered complete. Enabling this feature is especially important for applications that want to prevent spam registrations.
diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/after.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/after.png
new file mode 100644
index 0000000000..f9f72302a5
Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/after.png differ
diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/before.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/before.png
new file mode 100644
index 0000000000..14340f91ee
Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/before.png differ
diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/configure-timezone.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/configure-timezone.png
new file mode 100644
index 0000000000..d383eee6f6
Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/configure-timezone.png differ
diff --git a/docs/en/cli/index.md b/docs/en/cli/index.md
index 44cab0caa4..02521e72cb 100644
--- a/docs/en/cli/index.md
+++ b/docs/en/cli/index.md
@@ -342,6 +342,7 @@ Note that this command can upgrade your solution from a previous version, and al
* `--solution-name` or `-sn`: Specify the solution name. Search `*.sln` files in the directory by default.
* `--check-all`: Check the new version of each package separately. Default is `false`.
* `--version` or `-v`: Specifies the version to use for update. If not specified, latest version is used.
+* * `--leptonx-version` or `-lv`: Specifies the LeptonX version to use for update. If not specified, latest version or the version that is compatible with `--version` argument is used.
### clean
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpBlazorWebAppServiceCollectionExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpBlazorWebAppServiceCollectionExtensions.cs
index 1bcc1c1f45..2027ac1e69 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpBlazorWebAppServiceCollectionExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpBlazorWebAppServiceCollectionExtensions.cs
@@ -1,3 +1,4 @@
+using System;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -19,10 +20,14 @@ public static class AbpBlazorWebAppServiceCollectionExtensions
return services;
}
+ [Obsolete("Use AddBlazorWebAppServices instead. See https://github.com/abpframework/abp/issues/22622")]
public static IServiceCollection AddBlazorWebAppTieredServices([NotNull] this IServiceCollection services)
{
Check.NotNull(services, nameof(services));
+ // Compatibility with old template code
+ services.AddTransient();
+
services.AddScoped();
services.Replace(ServiceDescriptor.Singleton());
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProvider.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProvider.cs
index b35960f071..d3f05820b0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProvider.cs
@@ -1,5 +1,7 @@
+using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Components.WebAssembly.WebApp;
@@ -8,21 +10,26 @@ public class RemoteAuthenticationStateProvider : AuthenticationStateProvider
{
protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; }
protected WebAssemblyCachedApplicationConfigurationClient WebAssemblyCachedApplicationConfigurationClient { get; }
+ protected IServiceProvider ServiceProvider { get; }
public RemoteAuthenticationStateProvider(
ICurrentPrincipalAccessor currentPrincipalAccessor,
- WebAssemblyCachedApplicationConfigurationClient webAssemblyCachedApplicationConfigurationClient)
+ WebAssemblyCachedApplicationConfigurationClient webAssemblyCachedApplicationConfigurationClient,
+ IServiceProvider serviceProvider)
{
CurrentPrincipalAccessor = currentPrincipalAccessor;
WebAssemblyCachedApplicationConfigurationClient = webAssemblyCachedApplicationConfigurationClient;
+ ServiceProvider = serviceProvider;
}
public async override Task GetAuthenticationStateAsync()
{
- if (CurrentPrincipalAccessor.Principal.Identity == null ||
- !CurrentPrincipalAccessor.Principal.Identity.IsAuthenticated)
+ if (ServiceProvider.GetService() != null)
{
- await WebAssemblyCachedApplicationConfigurationClient.InitializeAsync();
+ if (CurrentPrincipalAccessor.Principal.Identity == null || !CurrentPrincipalAccessor.Principal.Identity.IsAuthenticated)
+ {
+ await WebAssemblyCachedApplicationConfigurationClient.InitializeAsync();
+ }
}
return new AuthenticationState(CurrentPrincipalAccessor.Principal);
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProviderCompatible.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProviderCompatible.cs
new file mode 100644
index 0000000000..780f96c631
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProviderCompatible.cs
@@ -0,0 +1,8 @@
+namespace Volo.Abp.AspNetCore.Components.WebAssembly.WebApp;
+
+///
+/// This class is used to indicate that the AddBlazorWebAppTieredServices method has been called for compatibility with the old template code
+///
+internal sealed class AddBlazorWebAppTieredServicesHasBeenCalled
+{
+}
diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
index d042bb6026..b9142b5aed 100644
--- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
@@ -115,7 +115,7 @@ public static class AbpApplicationBuilderExtensions
return app.UseMiddleware();
}
- [Obsolete("Replace with AbpClaimsTransformation")]
+ [Obsolete("Use the TransformAbpClaims extension method from IServiceCollection instead.")]
public static IApplicationBuilder UseAbpClaimsMap(this IApplicationBuilder app)
{
return app.UseMiddleware();
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs
index 2104edab0a..70fad0d19e 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs
@@ -11,7 +11,7 @@ using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Security.Claims;
-[Obsolete("Replace with AbpClaimsTransformation")]
+[Obsolete("Use the TransformAbpClaims extension method from IServiceCollection instead.")]
public class AbpClaimsMapMiddleware : AbpMiddlewareBase, ITransientDependency
{
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs
index 9fb647806b..cc13e9d187 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs
@@ -68,7 +68,7 @@ public class HelpCommand : IConsoleCommand, ITransientDependency
sb.AppendLine("Command List:");
sb.AppendLine("");
- foreach (var command in AbpCliOptions.Commands.ToArray().Where(NotHiddenFromCommandList))
+ foreach (var command in AbpCliOptions.Commands.ToArray().Where(NotHiddenFromCommandList).OrderBy(x => x.Key))
{
var method = command.Value.GetMethod("GetShortDescription", BindingFlags.Static | BindingFlags.Public);
if (method == null)
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs
index ad0992af4e..8c6df3b0b9 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs
@@ -38,24 +38,25 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency
var directory = commandLineArgs.Options.GetOrNull(Options.SolutionPath.Short, Options.SolutionPath.Long) ??
Directory.GetCurrentDirectory();
var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
+ var leptonXVersion = commandLineArgs.Options.GetOrNull(Options.LeptonXVersion.Short, Options.LeptonXVersion.Long);
if (updateNuget || !updateNpm)
{
- await UpdateNugetPackages(commandLineArgs, directory, version);
+ await UpdateNugetPackages(commandLineArgs, directory, version, leptonXVersion);
}
if (updateNpm || !updateNuget)
{
- await UpdateNpmPackages(directory, version);
+ await UpdateNpmPackages(directory, version, leptonXVersion);
}
}
- private async Task UpdateNpmPackages(string directory, string version)
+ private async Task UpdateNpmPackages(string directory, string version, string leptonXVersion)
{
- await _npmPackagesUpdater.Update(directory, version: version);
+ await _npmPackagesUpdater.Update(directory, version: version, leptonXVersion: leptonXVersion);
}
- private async Task UpdateNugetPackages(CommandLineArgs commandLineArgs, string directory, string version)
+ private async Task UpdateNugetPackages(CommandLineArgs commandLineArgs, string directory, string version, string leptonXVersion)
{
var solutions = new List();
var givenSolution = commandLineArgs.Options.GetOrNull(Options.SolutionName.Short, Options.SolutionName.Long);
@@ -77,7 +78,7 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency
{
var solutionName = Path.GetFileName(solution).RemovePostFix(".sln");
- await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, checkAll: checkAll, version: version);
+ await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, checkAll: checkAll, version: version, leptonXVersion: leptonXVersion);
Logger.LogInformation("Volo packages are updated in {SolutionName} solution", solutionName);
}
@@ -90,7 +91,7 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency
{
var projectName = Path.GetFileName(project).RemovePostFix(".csproj");
- await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, checkAll: checkAll, version: version);
+ await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, checkAll: checkAll, version: version, leptonXVersion: leptonXVersion);
Logger.LogInformation("Volo packages are updated in {ProjectName} project", projectName);
return;
@@ -120,6 +121,7 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency
sb.AppendLine("-sn|--solution-name (Specify the solution name)");
sb.AppendLine("--check-all (Check the new version of each package separately)");
sb.AppendLine("-v|--version (default: latest version)");
+ sb.AppendLine("-lv|--leptonx-version (default: latest LeptonX version)");
sb.AppendLine("");
sb.AppendLine("Some examples:");
sb.AppendLine("");
@@ -167,5 +169,11 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency
public const string Short = "v";
public const string Long = "version";
}
+
+ public static class LeptonXVersion
+ {
+ public const string Short = "lv";
+ public const string Long = "leptonx-version";
+ }
}
}
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
index 2c88f1e8c5..d543b43d65 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
@@ -50,7 +50,7 @@ public class NpmPackagesUpdater : ITransientDependency
public async Task Update(string rootDirectory, bool includePreviews = false,
bool includeReleaseCandidates = false,
- bool switchToStable = false, string version = null, bool includePreRc = false)
+ bool switchToStable = false, string version = null, string leptonXVersion = null, bool includePreRc = false)
{
var fileList = _packageJsonFileFinder.Find(rootDirectory);
@@ -80,6 +80,7 @@ public class NpmPackagesUpdater : ITransientDependency
var updated = await UpdatePackagesInFile(file, includePreviews, includeReleaseCandidates,
switchToStable,
version,
+ leptonXVersion,
includePreRc);
packagesUpdated.TryAdd(file, updated);
@@ -162,6 +163,7 @@ public class NpmPackagesUpdater : ITransientDependency
bool includeReleaseCandidates = false,
bool switchToStable = false,
string specifiedVersion = null,
+ string specifiedLeptonXVersion = null,
bool includePreRc = false)
{
var packagesUpdated = false;
@@ -177,7 +179,7 @@ public class NpmPackagesUpdater : ITransientDependency
foreach (var abpPackage in abpPackages)
{
var updated = await TryUpdatingPackage(filePath, abpPackage, includePreviews, includeReleaseCandidates,
- switchToStable, specifiedVersion, includePreRc);
+ switchToStable, specifiedVersion, specifiedLeptonXVersion, includePreRc);
if (updated)
{
@@ -188,7 +190,7 @@ public class NpmPackagesUpdater : ITransientDependency
var updatedContent = packageJson.ToString(Formatting.Indented);
File.WriteAllText(filePath, updatedContent);
-
+
return packagesUpdated;
}
@@ -199,6 +201,7 @@ public class NpmPackagesUpdater : ITransientDependency
bool includeReleaseCandidates = false,
bool switchToStable = false,
string specifiedVersion = null,
+ string specifiedLeptonXVersion = null,
bool includePreRc = false)
{
var currentVersion = (string)package.Value;
@@ -207,18 +210,36 @@ public class NpmPackagesUpdater : ITransientDependency
if (!specifiedVersion.IsNullOrWhiteSpace())
{
- if (!SpecifiedVersionExists(specifiedVersion, package))
+ if (package.Name.IndexOf("leptonx", StringComparison.InvariantCultureIgnoreCase) > 0 && !specifiedLeptonXVersion.IsNullOrWhiteSpace())
{
- return false;
- }
+ if (!SpecifiedVersionExists(specifiedLeptonXVersion, package))
+ {
+ return false;
+ }
- if (SemanticVersion.Parse(specifiedVersion) <=
- SemanticVersion.Parse(currentVersion.RemovePreFix("~", "^")))
- {
- return false;
+ if (SemanticVersion.Parse(specifiedLeptonXVersion) <=
+ SemanticVersion.Parse(currentVersion.RemovePreFix("~", "^")))
+ {
+ return false;
+ }
+
+ version = specifiedLeptonXVersion.EnsureStartsWith('^');
}
+ else
+ {
+ if (!SpecifiedVersionExists(specifiedVersion, package))
+ {
+ return false;
+ }
- version = specifiedVersion.EnsureStartsWith('^');
+ if (SemanticVersion.Parse(specifiedVersion) <=
+ SemanticVersion.Parse(currentVersion.RemovePreFix("~", "^")))
+ {
+ return false;
+ }
+
+ version = specifiedVersion.EnsureStartsWith('^');
+ }
}
else
{
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs
index 4ece393913..924d6041b1 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs
@@ -27,7 +27,14 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
Logger = NullLogger.Instance;
}
- public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false, string version = null)
+ public async Task UpdateSolutionAsync(
+ string solutionPath,
+ bool includePreviews = false,
+ bool includeReleaseCandidates = false,
+ bool switchToStable = false,
+ bool checkAll = false,
+ string version = null,
+ string leptonXVersion = null)
{
var projectPaths = ProjectFinder.GetProjectFiles(solutionPath);
@@ -58,6 +65,7 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
latestReleaseCandidateVersionInfo.Version,
latestVersionFromMyGet,
version,
+ leptonXVersion,
latestStableVersions: latestStableVersions);
fs.Seek(0, SeekOrigin.Begin);
@@ -75,7 +83,14 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
}
}
- public async Task UpdateProjectAsync(string projectPath, bool includeNightlyPreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false, string version = null)
+ public async Task UpdateProjectAsync(
+ string projectPath,
+ bool includeNightlyPreviews = false,
+ bool includeReleaseCandidates = false,
+ bool switchToStable = false,
+ bool checkAll = false,
+ string version = null,
+ string leptonXVersion = null)
{
if (checkAll && version.IsNullOrWhiteSpace())
{
@@ -102,6 +117,7 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
latestReleaseCandidateVersionInfo.Version,
latestVersionFromMyGet,
version,
+ leptonXVersion,
latestStableVersions: latestStableVersions);
fs.Seek(0, SeekOrigin.Begin);
@@ -166,6 +182,7 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
SemanticVersion latestNugetReleaseCandidateVersion = null,
string latestMyGetVersion = null,
string specifiedVersion = null,
+ string specifiedLeptonXVersion = null,
List latestStableVersions = null)
{
string packageId = null;
@@ -222,21 +239,35 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
var leptonXPackageVersion = latestStableVersions?
.FirstOrDefault(v => v.Version.Equals(specifiedVersion, StringComparison.InvariantCultureIgnoreCase))?.LeptonX?.Version;
- if ((isLeptonXPackage && string.IsNullOrWhiteSpace(leptonXPackageVersion)) || isStudioPackage)
+ if ((isLeptonXPackage && string.IsNullOrWhiteSpace(leptonXPackageVersion) && specifiedLeptonXVersion.IsNullOrWhiteSpace()) || isStudioPackage)
{
Logger.LogWarning("Package: {PackageId} could not be updated. Please manually update the package version yourself to prevent version mismatches!", packageId);
continue;
}
- var isLeptonXPackageWithVersion = isLeptonXPackage && !string.IsNullOrWhiteSpace(leptonXPackageVersion);
-
- if (isLeptonXPackageWithVersion || await SpecifiedVersionExists(specifiedVersion, packageId))
+ if (isLeptonXPackage)
{
- TryUpdatingPackage(isLeptonXPackageWithVersion ? leptonXPackageVersion : specifiedVersion);
+ var isLeptonXPackageWithVersion = isLeptonXPackage && !string.IsNullOrWhiteSpace(leptonXPackageVersion);
+
+ if (isLeptonXPackageWithVersion || await SpecifiedVersionExists(specifiedLeptonXVersion, packageId))
+ {
+ TryUpdatingPackage(specifiedLeptonXVersion ?? leptonXPackageVersion);
+ }
+ else
+ {
+ Logger.LogWarning($"Package \"{packageId}\" specified version v{specifiedLeptonXVersion} does not exist!");
+ }
}
else
{
- Logger.LogWarning("Package \"{PackageId}\" specified version v{SpecifiedVersion} does not exist!", packageId, specifiedVersion);
+ if (await SpecifiedVersionExists(specifiedVersion, packageId))
+ {
+ TryUpdatingPackage(specifiedVersion);
+ }
+ else
+ {
+ Logger.LogWarning($"Package \"{packageId}\" specified version v{specifiedVersion} does not exist!");
+ }
}
void TryUpdatingPackage(string versionToUpdate)
diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpGuidCustomBsonTypeMapper.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpGuidCustomBsonTypeMapper.cs
new file mode 100644
index 0000000000..4cfacc39fd
--- /dev/null
+++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpGuidCustomBsonTypeMapper.cs
@@ -0,0 +1,13 @@
+using System;
+using MongoDB.Bson;
+
+namespace Volo.Abp.MongoDB;
+
+public class AbpGuidCustomBsonTypeMapper : ICustomBsonTypeMapper
+{
+ public bool TryMapToBsonValue(object value, out BsonValue bsonValue)
+ {
+ bsonValue = new BsonBinaryData((Guid)value, GuidRepresentation.Standard);
+ return true;
+ }
+}
diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs
index 8e8ad345fc..195491d989 100644
--- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs
+++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.DependencyInjection;
+using System;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
@@ -16,6 +17,12 @@ namespace Volo.Abp.MongoDB;
[DependsOn(typeof(AbpDddDomainModule))]
public class AbpMongoDbModule : AbpModule
{
+ static AbpMongoDbModule()
+ {
+ BsonSerializer.TryRegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
+ BsonTypeMapper.RegisterCustomTypeMapper(typeof(Guid), new AbpGuidCustomBsonTypeMapper());
+ }
+
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddConventionalRegistrar(new AbpMongoDbConventionalRegistrar());
@@ -23,8 +30,6 @@ public class AbpMongoDbModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
- BsonSerializer.TryRegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
-
context.Services.TryAddTransient(
typeof(IMongoDbContextProvider<>),
typeof(UnitOfWorkMongoDbContextProvider<>)
diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs
index e2ad9088cb..3df8699f6d 100644
--- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs
+++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using MongoDB.Driver.Linq;
using Shouldly;
+using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.TestApp;
using Volo.Abp.TestApp.Domain;
@@ -52,10 +53,12 @@ public class Repository_Basic_Tests : Repository_Basic_Tests p.PersonId == person.Id && p.Number == "1234567890").ShouldBeTrue();
+ person.GetProperty("test-guid-property").ShouldBe(person.Id);
+ person.GetProperty("test-nullable-guid-property").ShouldBe(person.Id);
}
-
+
[Fact]
public async Task Filter_Case_Insensitive()
{
(await CityRepository.GetQueryableAsync()).FirstOrDefault(c => c.Name == "ISTANBUL").ShouldBeNull();
(await CityRepository.GetQueryableAsync()).FirstOrDefault(c => c.Name == "istanbul").ShouldBeNull();
(await CityRepository.GetQueryableAsync()).FirstOrDefault(c => c.Name == "Istanbul").ShouldNotBeNull();
-
+
(await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "douglas").ShouldNotBeNull();
(await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "DOUGLAS").ShouldNotBeNull();
(await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "Douglas").ShouldNotBeNull();
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs
index ad3a39c746..ac9601cda3 100644
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs
+++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs
@@ -1,31 +1,42 @@
using System;
-using System.IO;
-using Microsoft.AspNetCore.Hosting;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
-using Serilog.Events;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo;
public class Program
{
- public static int Main(string[] args)
+ public async static Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Debug() //TODO: Should be configurable!
- .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
+ .MinimumLevel.Debug()
.Enrich.FromLogContext()
- .WriteTo.File("Logs/logs.txt")
+ .WriteTo.Async(c => c.Console())
.CreateLogger();
try
{
Log.Information("Starting web host.");
- CreateHostBuilder(args).Build().Run();
+ var builder = WebApplication.CreateBuilder(args);
+ builder.Host.AddAppSettingsSecretsJson()
+ .UseAutofac()
+ .UseSerilog();
+ await builder.AddApplicationAsync();
+ var app = builder.Build();
+ await app.InitializeApplicationAsync();
+ await app.RunAsync();
return 0;
}
catch (Exception ex)
{
+ if (ex is HostAbortedException)
+ {
+ throw;
+ }
+
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
@@ -34,14 +45,4 @@ public class Program
Log.CloseAndFlush();
}
}
-
-
- internal static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- })
- .UseAutofac()
- .UseSerilog();
}
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json
index 07a310a660..7ad9d24119 100644
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json
+++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json
@@ -1,27 +1,12 @@
{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:51339",
- "sslPort": 0
- }
- },
"profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.AbpIo.Commercial.Web": {
+ "Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo": {
"commandName": "Project",
"launchBrowser": true,
- "applicationUrl": "http://localhost:5000",
+ "applicationUrl": "https://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs
deleted file mode 100644
index 838cf43402..0000000000
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-
-namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo;
-
-public class Startup
-{
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddApplication();
- }
-
- public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
- {
- app.InitializeApplication();
- }
-}
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj
index f8202b97ec..9aa8142fda 100644
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj
+++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj
@@ -10,7 +10,7 @@
-
+
@@ -23,5 +23,5 @@
Always
-
+
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs
index 4ebeb18498..c887825b2b 100644
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs
+++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs
@@ -55,8 +55,8 @@ public class AbpAspNetCoreMvcUiThemeBasicDemoModule : AbpModule
app.UseDeveloperExceptionPage();
}
- app.MapAbpStaticAssets();
app.UseRouting();
+ app.MapAbpStaticAssets();
app.UseConfiguredEndpoints();
}
}
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs
index a27f797715..d2ca3053b8 100644
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs
+++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs
@@ -1,30 +1,42 @@
using System;
-using Microsoft.AspNetCore.Hosting;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
-using Serilog.Events;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo;
public class Program
{
- public static int Main(string[] args)
+ public async static Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.FromLogContext()
- .WriteTo.Async(c => c.File("Logs/logs.txt"))
.WriteTo.Async(c => c.Console())
.CreateLogger();
try
{
Log.Information("Starting web host.");
- CreateHostBuilder(args).Build().Run();
+ var builder = WebApplication.CreateBuilder(args);
+ builder.Host.AddAppSettingsSecretsJson()
+ .UseAutofac()
+ .UseSerilog();
+ await builder.AddApplicationAsync();
+ var app = builder.Build();
+ await app.InitializeApplicationAsync();
+ await app.RunAsync();
return 0;
}
catch (Exception ex)
{
+ if (ex is HostAbortedException)
+ {
+ throw;
+ }
+
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
@@ -33,14 +45,4 @@ public class Program
Log.CloseAndFlush();
}
}
-
-
- internal static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- })
- .UseAutofac()
- .UseSerilog();
}
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json
index 9bee4298ff..4ae3999794 100644
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json
+++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json
@@ -1,24 +1,9 @@
{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:61659",
- "sslPort": 0
- }
- },
"profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo": {
"commandName": "Project",
"launchBrowser": true,
- "applicationUrl": "http://localhost:5000",
+ "applicationUrl": "https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs
deleted file mode 100644
index a11ca855da..0000000000
--- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-
-namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo;
-
-public class Startup
-{
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddApplication();
- }
-
- public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
- {
- app.InitializeApplication();
- }
-}
diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor
index 87c2c0db91..7992764c00 100644
--- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor
+++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor
@@ -37,22 +37,25 @@
@if (_groups != null && _groups.Any())
{
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
index dfdca734a6..dc6b797446 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
@@ -2,6 +2,7 @@ import { ABP, RoutesService, TreeNode } from '@abp/ng.core';
import {
Component,
ElementRef,
+ inject,
Input,
QueryList,
Renderer2,
@@ -15,6 +16,9 @@ import {
templateUrl: 'routes.component.html',
})
export class RoutesComponent {
+ public readonly routesService = inject(RoutesService);
+ protected renderer = inject(Renderer2);
+
@Input() smallScreen?: boolean;
@ViewChildren('childrenContainer') childrenContainers!: QueryList>;
@@ -23,11 +27,6 @@ export class RoutesComponent {
trackByFn: TrackByFunction> = (_, item) => item.name;
- constructor(
- public readonly routesService: RoutesService,
- protected renderer: Renderer2,
- ) {}
-
isDropdown(node: TreeNode) {
return !node?.isLeaf || this.routesService.hasChildren(node.name);
}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/pipes/index.ts b/npm/ng-packs/packages/theme-basic/src/lib/pipes/index.ts
new file mode 100644
index 0000000000..0bde64d742
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/pipes/index.ts
@@ -0,0 +1 @@
+export * from './lazy-translate.pipe';
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/pipes/lazy-translate.pipe.ts b/npm/ng-packs/packages/theme-basic/src/lib/pipes/lazy-translate.pipe.ts
new file mode 100644
index 0000000000..d7b36a0c32
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/pipes/lazy-translate.pipe.ts
@@ -0,0 +1,20 @@
+import { LocalizationService, ConfigStateService } from '@abp/ng.core';
+import { inject, Pipe, PipeTransform } from '@angular/core';
+import { Observable, filter, take, switchMap, shareReplay } from 'rxjs';
+
+@Pipe({
+ name: 'abpLazyTranslate',
+})
+export class LazyTranslatePipe implements PipeTransform {
+ private localizationService = inject(LocalizationService);
+ private configStateService = inject(ConfigStateService);
+
+ transform(key: string): Observable {
+ return this.configStateService.getAll$().pipe(
+ filter(config => !!config.localization),
+ take(1),
+ switchMap(() => this.localizationService.get(key)),
+ shareReplay({ bufferSize: 1, refCount: true }),
+ );
+ }
+}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
index d959509dfd..d68d112ac5 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
+++ b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
@@ -16,6 +16,7 @@ import { PageAlertContainerComponent } from './components/page-alert-container/p
import { RoutesComponent } from './components/routes/routes.component';
import { ValidationErrorComponent } from './components/validation-error/validation-error.component';
import { provideThemeBasicConfig } from './providers';
+import { LazyTranslatePipe } from './pipes';
export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent];
@@ -48,6 +49,7 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
NgbCollapseModule,
NgbDropdownModule,
NgxValidateCoreModule,
+ LazyTranslatePipe,
],
})
export class BaseThemeBasicModule {}
diff --git a/npm/ng-packs/packages/theme-basic/src/public-api.ts b/npm/ng-packs/packages/theme-basic/src/public-api.ts
index 5c607ca06d..ec57cc892e 100644
--- a/npm/ng-packs/packages/theme-basic/src/public-api.ts
+++ b/npm/ng-packs/packages/theme-basic/src/public-api.ts
@@ -6,6 +6,7 @@ export * from './lib/components';
export * from './lib/enums';
export * from './lib/handlers';
export * from './lib/models';
+export * from './lib/pipes';
export * from './lib/providers';
export * from './lib/theme-basic.module';
export * from './lib/tokens';