Browse Source

Merge branch 'dev' into EditionId

pull/22632/head
maliming 1 year ago
parent
commit
9c8d166700
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 4
      .github/workflows/angular.yml
  2. 2
      Directory.Packages.props
  3. 1
      docs/en/cli/index.md
  4. 5
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpBlazorWebAppServiceCollectionExtensions.cs
  5. 15
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProvider.cs
  6. 8
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebApp/RemoteAuthenticationStateProviderCompatible.cs
  7. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-styles.css
  8. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-styles.min.css
  9. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-styles.scss
  10. 2
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
  11. 2
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs
  12. 20
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliConsts.cs
  13. 25
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs
  14. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs
  15. 22
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs
  16. 43
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
  17. 47
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs
  18. 17
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs
  19. 13
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpGuidCustomBsonTypeMapper.cs
  20. 11
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs
  21. 17
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestBase.cs
  22. 52
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpNewtonsoftSerializerProviderTests.cs
  23. 47
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
  24. 5
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/InputAndOutputDateTimeFormat_Tests.cs
  25. 11
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs
  26. 37
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs
  27. 21
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json
  28. 18
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs
  29. 4
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj
  30. 2
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs
  31. 32
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs
  32. 17
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json
  33. 18
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs
  34. 47
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js
  35. 12
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor
  36. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs
  37. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs
  38. 61
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml
  39. 20
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs
  40. 1
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.css
  41. 17
      modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor
  42. 2
      modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs
  43. 17
      modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.css
  44. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs
  45. 4
      npm/ng-packs/packages/account/config/src/providers/route.provider.ts
  46. 15
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html
  47. 9
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
  48. 1
      npm/ng-packs/packages/theme-basic/src/lib/pipes/index.ts
  49. 20
      npm/ng-packs/packages/theme-basic/src/lib/pipes/lazy-translate.pipe.ts
  50. 2
      npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
  51. 1
      npm/ng-packs/packages/theme-basic/src/public-api.ts

4
.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') }}

2
Directory.Packages.props

@ -119,7 +119,7 @@
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.6.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.6.0" />
<PackageVersion Include="Minio" Version="6.0.3" />
<PackageVersion Include="MongoDB.Driver" Version="3.1.0" />
<PackageVersion Include="MongoDB.Driver" Version="3.3.0" />
<PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />

1
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

5
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<AddBlazorWebAppTieredServicesHasBeenCalled>();
services.AddScoped<AuthenticationStateProvider, RemoteAuthenticationStateProvider>();
services.Replace(ServiceDescriptor.Singleton<IAbpAccessTokenProvider, PersistentComponentStateAbpAccessTokenProvider>());

15
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<AuthenticationState> GetAuthenticationStateAsync()
{
if (CurrentPrincipalAccessor.Principal.Identity == null ||
!CurrentPrincipalAccessor.Principal.Identity.IsAuthenticated)
if (ServiceProvider.GetService<AddBlazorWebAppTieredServicesHasBeenCalled>() != null)
{
await WebAssemblyCachedApplicationConfigurationClient.InitializeAsync();
if (CurrentPrincipalAccessor.Principal.Identity == null || !CurrentPrincipalAccessor.Principal.Identity.IsAuthenticated)
{
await WebAssemblyCachedApplicationConfigurationClient.InitializeAsync();
}
}
return new AuthenticationState(CurrentPrincipalAccessor.Principal);

8
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;
/// <summary>
/// This class is used to indicate that the AddBlazorWebAppTieredServices method has been called for compatibility with the old template code
/// </summary>
internal sealed class AddBlazorWebAppTieredServicesHasBeenCalled
{
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-styles.css

@ -10,3 +10,8 @@
.dataTable tbody tr td div.dropdown ul.dropdown-menu li {
cursor: pointer; }
.abp-action-button ui.dropdown-menu[data-popper-reference-hidden]{
visibility: hidden;
pointer-events: none;
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-styles.min.css

@ -1 +1 @@
.dataTable{width:100% !important;border-spacing:0 !important;}.table td,.table th{padding:8px 10px;}.dataTable tbody tr td button{cursor:pointer;}.dataTable tbody tr td div.dropdown ul.dropdown-menu li{cursor:pointer;}
.dataTable{width:100%!important;border-spacing:0!important}.table td,.table th{padding:8px 10px}.dataTable tbody tr td button{cursor:pointer}.dataTable tbody tr td div.dropdown ul.dropdown-menu li{cursor:pointer}.abp-action-button ui.dropdown-menu[data-popper-reference-hidden]{visibility:hidden;pointer-events:none}

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-styles.scss

@ -27,3 +27,10 @@
}
}
}
.abp-action-button {
ui.dropdown-menu[data-popper-reference-hidden] {
visibility: hidden;
pointer-events: none;
}
}

2
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs

@ -115,7 +115,7 @@ public static class AbpApplicationBuilderExtensions
return app.UseMiddleware<AbpExceptionHandlingMiddleware>();
}
[Obsolete("Replace with AbpClaimsTransformation")]
[Obsolete("Use the TransformAbpClaims extension method from IServiceCollection instead.")]
public static IApplicationBuilder UseAbpClaimsMap(this IApplicationBuilder app)
{
return app.UseMiddleware<AbpClaimsMapMiddleware>();

2
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)

20
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliConsts.cs

@ -2,24 +2,24 @@
public static class CliConsts
{
public const string Command = "AbpCliCommand";
public static string Command = "AbpCliCommand";
public const string BranchPrefix = "branch@";
public static string BranchPrefix = "branch@";
public const string DocsLink = "https://abp.io/docs";
public static string DocsLink = "https://abp.io/docs";
public const string HttpClientName = "AbpHttpClient";
public static string HttpClientName = "AbpHttpClient";
public const string GithubHttpClientName = "GithubHttpClient";
public static string GithubHttpClientName = "GithubHttpClient";
public const string LogoutUrl = CliUrls.WwwAbpIo + "api/license/logout";
public static string LogoutUrl = CliUrls.WwwAbpIo + "api/license/logout";
public const string LicenseCodePlaceHolder = @"<LICENSE_CODE/>";
public static string LicenseCodePlaceHolder = @"<LICENSE_CODE/>";
public const string AppSettingsJsonFileName = "appsettings.json";
public static string AppSettingsJsonFileName = "appsettings.json";
public static string AppSettingsSecretJsonFileName = "appsettings.secrets.json";
public const string AppSettingsSecretJsonFileName = "appsettings.secrets.json";
public static class MemoryKeys
{
public const string LatestCliVersionCheckDate = "LatestCliVersionCheckDate";

25
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs

@ -5,19 +5,18 @@ namespace Volo.Abp.Cli;
public static class CliUrls
{
public const string WwwAbpIo = WwwAbpIoProduction;
public const string AccountAbpIo = AccountAbpIoProduction;
public const string NuGetRootPath = NuGetRootPathProduction;
public const string LatestVersionCheckFullPath =
"https://raw.githubusercontent.com/abpframework/abp/dev/latest-versions.json";
public const string WwwAbpIoProduction = "https://abp.io/";
public const string AccountAbpIoProduction = "https://account.abp.io/";
public const string NuGetRootPathProduction = "https://nuget.abp.io/";
public const string WwwAbpIoDevelopment = "https://localhost:44328/";
public const string AccountAbpIoDevelopment = "https://localhost:44333/";
public const string NuGetRootPathDevelopment = "https://localhost:44373/";
public static string WwwAbpIo = WwwAbpIoProduction;
public static string AccountAbpIo = AccountAbpIoProduction;
public static string NuGetRootPath = NuGetRootPathProduction;
public static string LatestVersionCheckFullPath = "https://raw.githubusercontent.com/abpframework/abp/dev/latest-versions.json";
public static string WwwAbpIoProduction = "https://abp.io/";
public static string AccountAbpIoProduction = "https://account.abp.io/";
public static string NuGetRootPathProduction = "https://nuget.abp.io/";
public static string WwwAbpIoDevelopment = "https://localhost:44328/";
public static string AccountAbpIoDevelopment = "https://localhost:44333/";
public static string NuGetRootPathDevelopment = "https://localhost:44373/";
public static string GetNuGetServiceIndexUrl(string apiKey)
{

2
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)

22
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<string>();
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 <version> (default: latest version)");
sb.AppendLine("-lv|--leptonx-version <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";
}
}
}

43
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
{

47
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs

@ -27,7 +27,14 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
Logger = NullLogger<VoloNugetPackagesVersionUpdater>.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<PackageVersionCheckerService.LatestStableVersionResult> 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)

17
framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs

@ -40,21 +40,10 @@ public class AbpSystemTextJsonSerializer : IJsonSerializer, ITransientDependency
camelCase,
indented,
Options.JsonSerializerOptions
}, _ =>
}, _ => new JsonSerializerOptions(Options.JsonSerializerOptions)
{
var settings = new JsonSerializerOptions(Options.JsonSerializerOptions);
if (camelCase)
{
settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
}
if (indented)
{
settings.WriteIndented = true;
}
return settings;
PropertyNamingPolicy = camelCase ? JsonNamingPolicy.CamelCase : null,
WriteIndented = indented
});
}
}

13
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;
}
}

11
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<>)

17
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestBase.cs

@ -1,4 +1,9 @@
using Volo.Abp.Testing;
using System;
using System.Collections.Concurrent;
using System.Reflection;
using Newtonsoft.Json;
using Volo.Abp.Json.Newtonsoft;
using Volo.Abp.Testing;
namespace Volo.Abp.Json;
@ -12,6 +17,16 @@ public abstract class AbpJsonSystemTextJsonTestBase : AbpIntegratedTest<AbpJsonS
public abstract class AbpJsonNewtonsoftJsonTestBase : AbpIntegratedTest<AbpJsonNewtonsoftTestModule>
{
protected AbpJsonNewtonsoftJsonTestBase()
{
var cache = typeof(AbpNewtonsoftJsonSerializer).GetField("JsonSerializerOptionsCache", BindingFlags.NonPublic | BindingFlags.Static);
if (cache != null)
{
var cacheValue = cache.GetValue(null)?.As<ConcurrentDictionary<object, JsonSerializerSettings>>();
cacheValue?.Clear();
}
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();

52
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpNewtonsoftSerializerProviderTests.cs

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using Shouldly;
using Xunit;
namespace Volo.Abp.Json;
[Collection("AbpJsonNewtonsoftJsonTest")]
public class AbpNewtonsoftSerializerProviderTests : AbpJsonNewtonsoftJsonTestBase
{
protected IJsonSerializer JsonSerializer;
public AbpNewtonsoftSerializerProviderTests()
{
JsonSerializer = GetRequiredService<IJsonSerializer>();
}
public class File
{
public string FileName { get; set; }
public Dictionary<string, int> ExtraProperties { get; set; }
}
[Fact]
public void Serialize_Deserialize_Test()
{
var defaultIndent = " "; // Default indent is 2 spaces
var newLine = Environment.NewLine;
var file = new File()
{
FileName = "abp",
ExtraProperties = new Dictionary<string, int>()
{
{ "One", 1 },
{ "Two", 2 }
}
};
var json = JsonSerializer.Serialize(file, camelCase: true);
json.ShouldBe("{\"fileName\":\"abp\",\"extraProperties\":{\"One\":1,\"Two\":2}}");
json = JsonSerializer.Serialize(file, camelCase: true, indented: true);
json.ShouldBe($"{{{newLine}{defaultIndent}\"fileName\": \"abp\",{newLine}{defaultIndent}\"extraProperties\": {{{newLine}{defaultIndent}{defaultIndent}\"One\": 1,{newLine}{defaultIndent}{defaultIndent}\"Two\": 2{newLine}{defaultIndent}}}{newLine}}}");
json = JsonSerializer.Serialize(file, camelCase: false);
json.ShouldBe("{\"FileName\":\"abp\",\"ExtraProperties\":{\"One\":1,\"Two\":2}}");
json = JsonSerializer.Serialize(file, camelCase: false, indented: true);
json.ShouldBe($"{{{newLine}{defaultIndent}\"FileName\": \"abp\",{newLine}{defaultIndent}\"ExtraProperties\": {{{newLine}{defaultIndent}{defaultIndent}\"One\": 1,{newLine}{defaultIndent}{defaultIndent}\"Two\": 2{newLine}{defaultIndent}}}{newLine}}}");
}
}

47
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Data;
@ -11,11 +13,11 @@ namespace Volo.Abp.Json;
public abstract class AbpSystemTextJsonSerializerProviderTestBase : AbpJsonSystemTextJsonTestBase
{
protected AbpSystemTextJsonSerializer JsonSerializer;
protected IJsonSerializer JsonSerializer;
public AbpSystemTextJsonSerializerProviderTestBase()
{
JsonSerializer = GetRequiredService<AbpSystemTextJsonSerializer>();
JsonSerializer = GetRequiredService<IJsonSerializer>();
}
public class TestExtensibleObjectClass : ExtensibleObject
@ -23,6 +25,13 @@ public abstract class AbpSystemTextJsonSerializerProviderTestBase : AbpJsonSyste
public string Name { get; set; }
}
public class File
{
public string FileName { get; set; }
public Dictionary<string, int> ExtraProperties { get; set; }
}
public class FileWithBoolean
{
public string Name { get; set; }
@ -74,6 +83,34 @@ public abstract class AbpSystemTextJsonSerializerProviderTestBase : AbpJsonSyste
public class AbpSystemTextJsonSerializerProviderTests : AbpSystemTextJsonSerializerProviderTestBase
{
[Fact]
public void Serialize_Deserialize_Test()
{
var defaultIndent = " "; // Default indent is 2 spaces
var newLine = Environment.NewLine;
var file = new File()
{
FileName = "abp",
ExtraProperties = new Dictionary<string, int>()
{
{ "One", 1 },
{ "Two", 2 }
}
};
var json = JsonSerializer.Serialize(file, camelCase: true);
json.ShouldBe("{\"fileName\":\"abp\",\"extraProperties\":{\"One\":1,\"Two\":2}}");
json = JsonSerializer.Serialize(file, camelCase: true, indented: true);
json.ShouldBe($"{{{newLine}{defaultIndent}\"fileName\": \"abp\",{newLine}{defaultIndent}\"extraProperties\": {{{newLine}{defaultIndent}{defaultIndent}\"One\": 1,{newLine}{defaultIndent}{defaultIndent}\"Two\": 2{newLine}{defaultIndent}}}{newLine}}}");
json = JsonSerializer.Serialize(file, camelCase: false);
json.ShouldBe("{\"FileName\":\"abp\",\"ExtraProperties\":{\"One\":1,\"Two\":2}}");
json = JsonSerializer.Serialize(file, camelCase: false, indented: true);
json.ShouldBe($"{{{newLine}{defaultIndent}\"FileName\": \"abp\",{newLine}{defaultIndent}\"ExtraProperties\": {{{newLine}{defaultIndent}{defaultIndent}\"One\": 1,{newLine}{defaultIndent}{defaultIndent}\"Two\": 2{newLine}{defaultIndent}}}{newLine}}}");
}
[Fact]
public void Serialize_Deserialize_With_Boolean()
{
@ -223,6 +260,8 @@ public class AbpSystemTextJsonSerializerProviderDateTimeFormatTests : AbpSystemT
options.InputDateTimeFormats.Add("yyyy*MM*dd");
options.OutputDateTimeFormat = "yyyy*MM*dd HH*mm*ss";
});
base.AfterAddApplication(services);
}
[Fact]
@ -289,6 +328,8 @@ public class AbpSystemTextJsonSerializerProviderDatetimeKindUtcTests : AbpSystem
{
Kind = DateTimeKind.Utc;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.AfterAddApplication(services);
}
}
@ -298,6 +339,8 @@ public class AbpSystemTextJsonSerializerProviderDatetimeKindLocalTests : AbpSyst
{
Kind = DateTimeKind.Local;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.AfterAddApplication(services);
}
}

5
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/InputAndOutputDateTimeFormat_Tests.cs

@ -31,6 +31,8 @@ public class InputAndOutputDateTimeFormatSystemTextJsonTests : AbpJsonSystemText
{
options.Kind = DateTimeKind.Utc;
});
base.AfterAddApplication(services);
}
[Fact]
@ -59,6 +61,7 @@ public class InputAndOutputDateTimeFormatSystemTextJsonTests : AbpJsonSystemText
}
}
[Collection("AbpJsonNewtonsoftJsonTest")]
public class InputAndOutputDateTimeFormatNewtonsoftTests : AbpJsonNewtonsoftJsonTestBase
{
private readonly IJsonSerializer _jsonSerializer;
@ -83,6 +86,8 @@ public class InputAndOutputDateTimeFormatNewtonsoftTests : AbpJsonNewtonsoftJson
{
options.Kind = DateTimeKind.Utc;
});
base.AfterAddApplication(services);
}
[Fact]

11
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<AbpMongoDbTestModul
}
[Fact]
public override async Task InsertAsync()
public async override Task InsertAsync()
{
var person = new Person(Guid.NewGuid(), "New Person", 35);
person.Phones.Add(new Phone(person.Id, "1234567890"));
person.SetProperty("test-guid-property", person.Id);
person.SetProperty("test-nullable-guid-property", (Guid?)person.Id);
await PersonRepository.InsertAsync(person);
@ -64,15 +67,17 @@ public class Repository_Basic_Tests : Repository_Basic_Tests<AbpMongoDbTestModul
person.Name.ShouldBe("New Person");
person.Phones.Count.ShouldBe(1);
person.Phones.Any(p => p.PersonId == person.Id && p.Number == "1234567890").ShouldBeTrue();
person.GetProperty<Guid>("test-guid-property").ShouldBe(person.Id);
person.GetProperty<Guid?>("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();

37
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<int> 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<AbpAspNetCoreMvcUiBootstrapDemoModule>();
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<Startup>();
})
.UseAutofac()
.UseSerilog();
}

21
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"
}
}
}
}
}

18
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs

@ -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<AbpAspNetCoreMvcUiBootstrapDemoModule>();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.InitializeApplication();
}
}

4
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj

@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="Serilog.Sinks.Async" />
</ItemGroup>
<ItemGroup>
@ -23,5 +23,5 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

2
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();
}
}

32
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<int> 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<AbpAspNetCoreMvcUiThemeBasicDemoModule>();
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<Startup>();
})
.UseAutofac()
.UseSerilog();
}

17
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"
}

18
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs

@ -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<AbpAspNetCoreMvcUiThemeBasicDemoModule>();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.InitializeApplication();
}
}

47
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js

@ -2,7 +2,11 @@ $(function () {
var l = abp.localization.getResource('Docs');
var service = window.volo.docs.admin.documentsAdmin;
moment.localeData().preparse = (s)=>s;
var getFormattedDate = function ($datePicker) {
return $datePicker.data('date');
};
moment.localeData().preparse = (s)=>s;
moment.localeData().postformat = (s)=>s;
var singleDatePicker = $('#DocumentsContainer .singledatepicker');
@ -26,7 +30,7 @@ $(function () {
var comboboxItems = [];
service.getFilterItems()
.then(function (result) {
comboboxItems = result;
@ -41,13 +45,13 @@ $(function () {
$projectId.on('change', function () {
fillOptions();
});
var comboboxs = {
version: $('#Version'),
languageCode: $('#LanguageCode'),
format: $('#Format')
};
for (var key in comboboxs) {
comboboxs[key].on('change', function () {
fillOptions();
@ -62,7 +66,7 @@ $(function () {
comboboxs[key].empty();
}
}
function getSelectedItem() {
var item = {};
for (var key in comboboxs) {
@ -70,13 +74,13 @@ $(function () {
}
return item;
}
function SetComboboxsValues(item) {
for (var key in comboboxs) {
comboboxs[key].val(item[key]);
}
}
function addComboboxsEmptyItem() {
for (var key in comboboxs) {
comboboxs[key].append($('<option/>').val('').text(''));
@ -84,17 +88,17 @@ $(function () {
}
function fillOptions() {
selectedItem = getSelectedItem();
var selectedProjectId = $projectId.val();
emptyComboboxs();
addComboboxsEmptyItem();
var selectedProjectItems = comboboxItems.filter((item) => !selectedProjectId || item.projectId === selectedProjectId);
for (var key in selectedItem) {
var item = selectedProjectItems.find((item) => item[key] === selectedItem[key]);
if (item) {
@ -103,14 +107,14 @@ $(function () {
selectedItem[key] = '';
}
}
selectedProjectItems.forEach(function (item) {
for (var key in comboboxs) {
appendComboboxItem(comboboxs[key], item, key);
}
});
SetComboboxsValues(selectedItem);
}
function appendComboboxItem($combobox, item , key) {
@ -128,21 +132,20 @@ $(function () {
var getFilter = function () {
$('#DocumentsContainer').handleDatepicker('.singledatepicker');
return {
projectId: $('#ProjectId').val(),
name: $('#Name').val(),
version: $('#Version').val(),
languageCode: $('#LanguageCode').val(),
format: $('#Format').val(),
creationTimeMin: $('#DocumentsContainer').find('input[name="CreationTimeMin"'),
creationTimeMax: $('#DocumentsContainer').find('input[name="CreationTimeMax"'),
lastUpdatedTimeMin: $('#DocumentsContainer').find('input[name="LastUpdatedTimeMin"'),
lastUpdatedTimeMax: $('#DocumentsContainer').find('input[name="LastUpdatedTimeMax"'),
lastSignificantUpdateTimeMin: $('#DocumentsContainer').find('input[name="LastSignificantUpdateTimeMin"'),
lastSignificantUpdateTimeMax: $('#DocumentsContainer').find('input[name="LastSignificantUpdateTimeMax"'),
lastCachedTimeMin: $('#DocumentsContainer').find('input[name="LastCachedTimeMin"'),
lastCachedTimeMax: $('#DocumentsContainer').find('input[name="LastCachedTimeMax"'),
creationTimeMin: getFormattedDate($('#DocumentsContainer').find('input[name="CreationTimeMin"]')),
creationTimeMax: getFormattedDate($('#DocumentsContainer').find('input[name="CreationTimeMax"]')),
lastUpdatedTimeMin: getFormattedDate($('#DocumentsContainer').find('input[name="LastUpdatedTimeMin"]')),
lastUpdatedTimeMax: getFormattedDate($('#DocumentsContainer').find('input[name="LastUpdatedTimeMax"]')),
lastSignificantUpdateTimeMin: getFormattedDate($('#DocumentsContainer').find('input[name="LastSignificantUpdateTimeMin"]')),
lastSignificantUpdateTimeMax: getFormattedDate($('#DocumentsContainer').find('input[name="LastSignificantUpdateTimeMax"]')),
lastCachedTimeMin: getFormattedDate($('#DocumentsContainer').find('input[name="LastCachedTimeMin"]')),
lastCachedTimeMax: getFormattedDate($('#DocumentsContainer').find('input[name="LastCachedTimeMax"]')),
};
};

12
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor

@ -35,12 +35,12 @@
{
<div class="mt-2">
@{
var disabled = IsDisabled(feature.Provider.Name);
var disabled = IsDisabled(feature);
if (feature.ValueType is FreeTextStringValueType)
{
<Field Style="@GetFeatureStyles(feature)">
<FieldLabel>@feature.DisplayName</FieldLabel>
<FieldLabel>@GetShownName(feature)</FieldLabel>
<TextEdit Disabled="@disabled"
Text="@feature.Value"
TextChanged="@(async (v) => await OnFeatureValueChangedAsync(v, feature))" />
@ -56,8 +56,8 @@
var items = ((SelectionStringValueType)feature.ValueType).ItemSource.Items;
var selectedValue = SelectionStringValues[feature.Name];
<Field Style="@GetFeatureStyles(feature)">
<FieldLabel>@feature.DisplayName</FieldLabel>
<Select TValue="string" SelectedValue="selectedValue" SelectedValueChanged="s => SelectionStringValues[feature.Name] = s">
<FieldLabel>@GetShownName(feature)</FieldLabel>
<Select TValue="string" Disabled="disabled" SelectedValue="selectedValue" SelectedValueChanged="s => SelectionStringValues[feature.Name] = s">
@foreach (var item in items)
{
<SelectItem Value="@item.Value">
@ -75,8 +75,8 @@
if (feature.ValueType is ToggleStringValueType)
{
<Field Style="@GetFeatureStyles(feature)">
<Check TValue="bool" Checked="@ToggleValues[feature.Name]" CheckedChanged="@(async (v) => await OnSelectedValueChangedAsync(v, feature))">
@feature.DisplayName
<Check TValue="bool" Disabled="disabled" Checked="@ToggleValues[feature.Name]" CheckedChanged="@(async (v) => await OnSelectedValueChangedAsync(v, feature))">
@GetShownName(feature)
</Check>
@if (feature.Description != null)
{

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs

@ -150,9 +150,16 @@ public partial class FeatureManagementModal
return $"margin-left: {feature.Depth * 20}px";
}
protected virtual bool IsDisabled(string providerName)
protected virtual bool IsDisabled(FeatureDto feature)
{
return providerName != ProviderName && providerName != DefaultValueFeatureValueProvider.ProviderName;
return feature.Provider.Name != ProviderName && feature.Provider.Name != DefaultValueFeatureValueProvider.ProviderName;
}
public string GetShownName(FeatureDto featureDto)
{
return !IsDisabled(featureDto)
? featureDto.DisplayName
: $"{featureDto.DisplayName} ({featureDto.Provider.Name})";
}
protected virtual async Task OnFeatureValueChangedAsync(string value, FeatureDto feature)

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs

@ -152,7 +152,7 @@ public class FeatureManager : IFeatureManager, ISingletonDependency
await using (await providers[0].HandleContextAsync(providerName, providerKey))
{
var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
if (fallbackValue.Value == value)
if (string.Equals(fallbackValue.Value, value, StringComparison.OrdinalIgnoreCase))
{
//Clear the value if it's same as it's fallback value
value = null;

61
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml

@ -45,44 +45,40 @@
@for (var j = 0; j < featureGroup.Features.Count; j++)
{
var feature = featureGroup.Features[j];
var disabled = Model.IsDisabled(feature);
<div class="mt-2">
<input type="text" abp-id-name="@Model.FeatureGroups[i].Features[j].IsDisabled" value="@(disabled.ToString())" hidden/>
<input type="text" abp-id-name="@Model.FeatureGroups[i].Features[j].Type" value="@feature.ValueType?.Name" hidden/>
@if (feature.ValueType is ToggleStringValueType)
{
<abp-input asp-for="@feature.Value"
type="checkbox"
class="d-inline"
abp-id-name="@Model.FeatureGroups[i].Features[j].BoolValue"
label="@feature.DisplayName"
group-data-feature-name="@feature.Name"
group-data-parent-name="@(feature.ParentName ?? "")"
group-style="margin-inline-start: @(feature.Depth * 20)px"/>
@if (feature.Description != null)
type="checkbox"
class="d-inline"
abp-id-name="@Model.FeatureGroups[i].Features[j].BoolValue"
label="@Model.GetShownName(feature)"
disabled="disabled"
group-data-feature-name="@feature.Name"
group-data-parent-name="@(feature.ParentName ?? "")"
group-style="margin-inline-start: @(feature.Depth * 20)px"/>
if (feature.Description != null)
{
<div class="form-text" style="margin-inline-start: @(feature.Depth * 20)px">@feature.Description</div>
}
}
@if (feature.ValueType is FreeTextStringValueType)
{
var type = "text";
if(feature.ValueType.Validator is NumericValueValidator)
{
type = "number";
}
var type = feature.ValueType.Validator is NumericValueValidator ? "number" : "text";
<abp-input asp-for="@feature.Value"
label="@feature.DisplayName"
abp-id-name="@Model.FeatureGroups[i].Features[j].Value"
type="@type"
group-data-feature-name="@feature.Name"
group-data-parent-name="@(feature.ParentName ?? "")"
group-style="margin-inline-start: @(feature.Depth * 25)px"/>
@if (feature.Description != null)
label="@Model.GetShownName(feature)"
abp-id-name="@Model.FeatureGroups[i].Features[j].Value"
type="@type"
disabled="disabled"
group-data-feature-name="@feature.Name"
group-data-parent-name="@(feature.ParentName ?? "")"
group-style="margin-inline-start: @(feature.Depth * 25)px"/>
if (feature.Description != null)
{
<div class="form-text" style="margin-inline-start: @(feature.Depth * 25)px">@feature.Description</div>
}
@ -91,19 +87,12 @@
@if (feature.ValueType is SelectionStringValueType selectType)
{
<div data-feature-name="@feature.Name" data-parent-name="@(feature.ParentName ?? "")" style="margin-inline-start: @(feature.Depth * 25)px" class="mb-3">
<label class="form-label" for="@feature.Name">@feature.DisplayName</label>
<select id="@feature.Name" name="FeatureGroups[@i].Features[@j].Value" class="form-select">
<label class="form-label" for="@feature.Name">@Model.GetShownName(feature)</label>
<select id="@feature.Name" name="FeatureGroups[@i].Features[@j].Value" class="form-select" @(disabled ? "disabled" : "")>
@foreach (var item in selectType.ItemSource.Items)
{
if (item.Value == feature.Value)
{
<option value="@item.Value" selected="selected"> @CreateHtmlLocalizer(item.DisplayText.ResourceName).GetString(item.DisplayText.Name) </option>
}
else
{
<option value="@item.Value"> @CreateHtmlLocalizer(item.DisplayText.ResourceName).GetString(item.DisplayText.Name) </option>
}
var selected = item.Value == feature.Value ? "selected=\"selected\"" : "";
<!option value="@item.Value" @(selected) >@CreateHtmlLocalizer(item.DisplayText.ResourceName).GetString(item.DisplayText.Name) </!option>
}
</select>
@if (feature.Description != null)
@ -112,8 +101,8 @@
}
</div>
}
<input value="@feature.Name" abp-id-name="@Model.FeatureGroups[i].Features[j].Name" hidden/>
</div>
}
</div>

20
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs

@ -25,9 +25,9 @@ public class FeatureManagementModal : AbpPageModel
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ProviderKey { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
[BindProperty(SupportsGet = true)]
public string ProviderKeyDisplayName { get; set; }
[BindProperty]
@ -69,7 +69,7 @@ public class FeatureManagementModal : AbpPageModel
{
var features = new UpdateFeaturesDto
{
Features = FeatureGroups.SelectMany(g => g.Features).Select(f => new UpdateFeatureDto
Features = FeatureGroups.SelectMany(g => g.Features).Where(x => !x.IsDisabled).Select(f => new UpdateFeatureDto
{
Name = f.Name,
Value = f.Type == nameof(ToggleStringValueType) ? f.BoolValue.ToString() : f.Value
@ -85,6 +85,18 @@ public class FeatureManagementModal : AbpPageModel
return NoContent();
}
public bool IsDisabled(FeatureDto featureDto)
{
return featureDto.Provider.Name != ProviderName && featureDto.Provider.Name != DefaultValueFeatureValueProvider.ProviderName;
}
public string GetShownName(FeatureDto featureDto)
{
return !IsDisabled(featureDto)
? featureDto.DisplayName
: $"{featureDto.DisplayName} ({featureDto.Provider.Name})";
}
public class FeatureGroupViewModel
{
public List<FeatureViewModel> Features { get; set; }
@ -92,6 +104,8 @@ public class FeatureManagementModal : AbpPageModel
public class FeatureViewModel
{
public bool IsDisabled { get; set; }
public string Name { get; set; }
public string Value { get; set; }

1
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.css

@ -2,7 +2,6 @@
max-height: 400px;
}
.custom-scroll-container > .col-md-4 {
max-height: 500px;
}

17
modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor

@ -37,22 +37,25 @@
@if (_groups != null && _groups.Any())
{
<div class="lpx-scroll-pills-container" >
<Tabs @key="_groups" TabPosition="TabPosition.Start" Pills="true" SelectedTab="@_selectedTabName" SelectedTabChanged="@OnSelectedTabChangedAsync">
<Tabs @key="_groups"
VerticalItemsColumnSize="ColumnSize.Is4.OnDesktop"
TabPosition="TabPosition.Start"
Pills="true"
SelectedTab="@_selectedTabName"
SelectedTabChanged="@OnSelectedTabChangedAsync">
<Items>
@foreach (var group in _groups)
{
<Tab Name="@GetNormalizedGroupName(group.Name)">
@if (group.Permissions.Any(x => x.IsGranted))
{
<span>
<b>@group.DisplayName ( @(group.Permissions.Count(x => x.IsGranted)) )</b>
</span>
<b>@group.DisplayName (@(group.Permissions.Count(x => x.IsGranted)))</b>
}
else
{
<span>
@group.DisplayName ( @(group.Permissions.Count(x => x.IsGranted)) )
</span>
<small>
@group.DisplayName (@(group.Permissions.Count(x => x.IsGranted)))
</small>
}
</Tab>
}

2
modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs

@ -58,7 +58,7 @@ public partial class PermissionManagementModal
var result = await PermissionAppService.GetAsync(_providerName, _providerKey);
_entityDisplayName = entityDisplayName ?? result.EntityDisplayName;
_allGroups = result.Groups;
_allGroups = result.Groups.OrderBy(x => x.DisplayName).ToList();
_groups = _allGroups.ToList();
NormalizePermissionGroup();

17
modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.css

@ -15,7 +15,7 @@ fieldset legend {
}
::deep .lpx-scroll-pills-container ul li {
border: 1px solid #e8eef3;
border: 1px solid var(--lpx-border-color);
margin-bottom: 10px;
border-radius: 10px;
}
@ -26,6 +26,15 @@ fieldset legend {
background-color: #6c5dd3 !important;
}
::deep .lpx-theme-dark .lpx-scroll-pills-container ul li {
border: 1px solid #23262a;
}
::deep .nav-pills .nav-link {
background: none;
border: 0;
border-radius: var(--bs-nav-pills-border-radius);
}
::deep .nav-pills .nav-link:disabled {
color: var(--bs-nav-link-disabled-color);
background-color: transparent;
border-color: transparent;
}

2
modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs

@ -136,7 +136,7 @@ public class SettingManager : ISettingManager, ISingletonDependency
if (providers.Count > 1 && !forceToSet && setting.IsInherited && value != null)
{
var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
if (fallbackValue == value)
if (string.Equals(fallbackValue, value, StringComparison.OrdinalIgnoreCase))
{
//Clear the value if it's same as it's fallback value
value = null;

4
npm/ng-packs/packages/account/config/src/providers/route.provider.ts

@ -24,12 +24,14 @@ export function configureRoutes() {
path: '/account/login',
name: eAccountRouteNames.Login,
parentName: eAccountRouteNames.Account,
layout: eLayoutType.account,
order: 1,
},
{
path: '/account/register',
name: eAccountRouteNames.Register,
parentName: eAccountRouteNames.Account,
layout: eLayoutType.account,
order: 2,
},
{
@ -45,12 +47,14 @@ export function configureRoutes() {
path: '/account/forgot-password',
parentName: eAccountRouteNames.Account,
name: eAccountRouteNames.ForgotPassword,
layout: eLayoutType.account,
invisible: true,
},
{
path: '/account/reset-password',
parentName: eAccountRouteNames.Account,
name: eAccountRouteNames.ResetPassword,
layout: eLayoutType.account,
invisible: true,
},
]);

15
npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html

@ -3,8 +3,7 @@
<ng-container
[ngTemplateOutlet]="isDropdown(route) ? dropdownLink : defaultLink"
[ngTemplateOutletContext]="{ $implicit: route }"
>
</ng-container>
/>
}
<ng-template #defaultLink let-route>
@ -13,7 +12,7 @@
@if (route.iconClass) {
<i [ngClass]="route.iconClass"></i>
}
{{ route.name | abpLocalization }}
{{ route.name | abpLazyTranslate | async }}
</a>
</li>
</ng-template>
@ -40,7 +39,7 @@
@if (route.iconClass) {
<i [ngClass]="route.iconClass"></i>
}
{{ route.name | abpLocalization }}
{{ route.name | abpLazyTranslate | async }}
</a>
<div
#routeContainer
@ -48,9 +47,7 @@
(click)="$event.preventDefault(); $event.stopPropagation()"
[class.d-block]="smallScreen && rootDropdownExpand[route.name]"
>
<ng-container
*ngTemplateOutlet="forTemplate; context: { $implicit: route }"
></ng-container>
<ng-container *ngTemplateOutlet="forTemplate; context: { $implicit: route }" />
</div>
</li>
}
@ -61,7 +58,7 @@
<ng-template
[ngTemplateOutlet]="child.children?.length ? dropdownChild : defaultChild"
[ngTemplateOutletContext]="{ $implicit: child }"
></ng-template>
/>
}
</ng-template>
@ -105,7 +102,7 @@
class="dropdown-menu dropdown-menu-start border-0 shadow-sm"
[class.d-block]="smallScreen && dropdownSubmenu.isOpen()"
>
<ng-container *ngTemplateOutlet="forTemplate; context: { $implicit: child }"></ng-container>
<ng-container *ngTemplateOutlet="forTemplate; context: { $implicit: child }" />
</div>
</div>
</ng-template>

9
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<ElementRef<HTMLDivElement>>;
@ -23,11 +27,6 @@ export class RoutesComponent {
trackByFn: TrackByFunction<TreeNode<ABP.Route>> = (_, item) => item.name;
constructor(
public readonly routesService: RoutesService,
protected renderer: Renderer2,
) {}
isDropdown(node: TreeNode<ABP.Route>) {
return !node?.isLeaf || this.routesService.hasChildren(node.name);
}

1
npm/ng-packs/packages/theme-basic/src/lib/pipes/index.ts

@ -0,0 +1 @@
export * from './lazy-translate.pipe';

20
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<string> {
return this.configStateService.getAll$().pipe(
filter(config => !!config.localization),
take(1),
switchMap(() => this.localizationService.get(key)),
shareReplay({ bufferSize: 1, refCount: true }),
);
}
}

2
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 {}

1
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';

Loading…
Cancel
Save