Browse Source

Merge branch 'dev' into issue-6542

pull/22922/head
SALİH ÖZKARA 1 year ago
parent
commit
9c3e205174
  1. 20
      Directory.Packages.props
  2. BIN
      docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg
  3. 93
      docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md
  4. 4
      docs/en/release-info/release-notes.md
  5. 1
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs
  6. 2
      framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj
  7. 3
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs
  8. 36
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs
  9. 2
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs
  10. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationScheme.cs
  11. 8
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/WebClientInfoProvider/WebClientInfoProviderDto.cs
  12. 26
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/WebClientInfoProvider/WebClientInfoProviderTestController.cs
  13. 36
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/WebClientInfoProvider/WebClientInfoProviderTestController_Tests.cs
  14. 18
      npm/ng-packs/packages/components/extensible/src/lib/components/multi-select/extensible-form-multiselect.component.ts
  15. 34
      npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html
  16. 4
      npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts

20
Directory.Packages.props

@ -29,7 +29,7 @@
<PackageVersion Include="Dapper" Version="2.1.66" />
<PackageVersion Include="Dapr.AspNetCore" Version="1.15.4" />
<PackageVersion Include="Dapr.Client" Version="1.15.4" />
<PackageVersion Include="DeviceDetector.NET" Version="6.4.2" />
<PackageVersion Include="MyCSharp.HttpUserAgentParser" Version="3.0.25" />
<PackageVersion Include="Devart.Data.Oracle.EFCore" Version="10.4.235.9" />
<PackageVersion Include="DistributedLock.Core" Version="1.0.8" />
<PackageVersion Include="DistributedLock.Redis" Version="1.0.3" />
@ -113,10 +113,10 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.9.0" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.9.0" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.9.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.9.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.12.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.12.0" />
<PackageVersion Include="Minio" Version="6.0.4" />
<PackageVersion Include="MongoDB.Driver" Version="3.3.0" />
<PackageVersion Include="NEST" Version="7.17.5" />
@ -128,11 +128,11 @@
<PackageVersion Include="NUglify" Version="1.21.15" />
<PackageVersion Include="Nullable" Version="1.3.1" />
<PackageVersion Include="Octokit" Version="14.0.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="6.2.1" />
<PackageVersion Include="OpenIddict.Core" Version="6.2.1" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="6.2.1" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="6.2.1" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="6.2.1" />
<PackageVersion Include="OpenIddict.Abstractions" Version="6.4.0" />
<PackageVersion Include="OpenIddict.Core" Version="6.4.0" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="6.4.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="6.4.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="6.4.0" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="9.23.80" />
<PackageVersion Include="Polly" Version="8.5.2" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />

BIN
docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

93
docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md

@ -0,0 +1,93 @@
# Solving MongoDB GUID Issues After an ABP Framework Upgrade
So, you've just upgraded your ABP Framework application to a newer version (like v9.2.0+) and suddenly, your application can't read data from its MongoDB database. You're seeing strange deserialization errors, especially related to `Guid` types. What's going on?
You've likely run into a classic compatibility issue with the MongoDB .NET driver.
### The Problem: Legacy vs. Standard GUIDs
Here's the short version:
* **Old MongoDB Drivers** (used in older ABP versions) stored `Guid` values in a format called `CSharpLegacy`.
* **New MongoDB Drivers** (v3.0+), now default to a universal `Standard` format.
When your newly upgraded app tries to read old data, the new driver expects the `Standard` format but finds `CSharpLegacy`. The byte orders don't match, and... boom. Deserialization fails.
The ABP Framework team has an excellent official guide covering this topic in detail. We highly recommend reading their **[MongoDB Driver 2 to 3 Migration Guide](https://abp.io/docs/latest/release-info/migration-guides/MongoDB-Driver-2-to-3)** for a full understanding.
Our tip below serves as a fast, application-level fix if you need to get your system back online quickly without performing a full data migration.
### The Quick Fix: Tell the Driver to Use the Old Format
Instead of changing your data, you can simply tell the new driver to continue using the old `CSharpLegacy` format for all `Guid` and `Guid?` properties. This provides immediate backward compatibility without touching your database.
It’s a simple, two-step process.
#### Step 1: Create a Custom Convention
First, create this class in your `.MongoDb` project. It tells the serializer how to handle `Guid` types.
```csharp
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.Serializers;
using System;
public class LegacyGuidConvention : ConventionBase, IMemberMapConvention
{
public void Apply(BsonMemberMap memberMap)
{
if (memberMap.MemberType == typeof(Guid))
{
memberMap.SetSerializer(new GuidSerializer(GuidRepresentation.CSharpLegacy));
}
else if (memberMap.MemberType == typeof(Guid?))
{
var guidSerializer = new GuidSerializer(GuidRepresentation.CSharpLegacy);
var nullableGuidSerializer = new NullableSerializer<Guid>(guidSerializer);
memberMap.SetSerializer(nullableGuidSerializer);
}
}
}
```
#### Step 2: Register the Convention at Startup
Now, register this convention in your `YourProjectMongoDbModule.cs` file. Add this code to the top of the `ConfigureServices` method. This ensures your rule is applied globally as soon as the application starts.
```csharp
using Volo.Abp.Modularity;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
public class YourProjectMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Fix Start
var conventionPack = new ConventionPack { new LegacyGuidConvention() };
ConventionRegistry.Register(
"LegacyGuidConvention",
conventionPack,
t => true); // Apply to all types
// Fix End
// ... Your existing ConfigureServices code
}
}
```
### An Alternative to Full Data Migration
It's important to note that the method described here is an **application-level fix**. It's a fantastic alternative to performing a full data migration, which involves writing scripts to convert every legacy GUID in your database.
If you are interested in the more permanent, data-centric approach, the ABP.IO community has a detailed guide on [**Migrating MongoDB GUIDs from Legacy to Standard Format**](https://abp.io/community/articles/migrating-mongodb-guids-from-legacy-to-standard-format-mongodb-v2-to-v3-dqwybdtw).
Our quick fix is ideal for getting a system back online fast or when a database migration is too complex. The full migration is better for long-term standards compliance. Choose the path that best fits your project's needs!
### That's It!
Restart your application, and the errors should be gone. Your app can now correctly read its old `Guid` data, and it will continue to write new data in the same legacy format, ensuring consistency.
This approach is a lifesaver for existing projects, saving you from a risky and time-consuming data migration. For brand-new projects, you might consider starting with the `Standard` representation, but for everything else, this is a clean and effective fix. Happy coding!

4
docs/en/release-info/release-notes.md

@ -8,9 +8,9 @@ Also see the following notes about ABP releases:
* [Change logs for ABP pro packages](https://abp.io/pro-releases)
## 9.2 (2025-03-25)
## 9.2 (2025-06-02)
This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/articles/abp-platform-9.2-rc-has-been-released-jpq072nh)** for the v9.2 release.
See the detailed **[blog post / announcement](https://abp.io/community/articles/announcing-abp-9-2-stable-release-061qmtzb)** for the v9.2 release.
* Added `ApplicationName` Property to Isolate Background Jobs & Background Workers
* Docs Module: Added "Alternative Words" to Filter Items

1
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs

@ -4,7 +4,6 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DeviceDetectorNET;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.DependencyInjection;

2
framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj

@ -31,7 +31,7 @@
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" />
<PackageReference Include="IdentityModel" />
<PackageReference Include="DeviceDetector.NET" />
<PackageReference Include="MyCSharp.HttpUserAgentParser" />
</ItemGroup>
</Project>

3
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.AspNetCore.RequestLocalization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using MyCSharp.HttpUserAgentParser.DependencyInjection;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.Auditing;
@ -59,6 +60,8 @@ public class AbpAspNetCoreModule : AbpModule
context.Services.AddAbpDynamicOptions<RequestLocalizationOptions, AbpRequestLocalizationOptionsManager>();
StaticWebAssetsLoader.UseStaticWebAssets(context.Services.GetHostingEnvironment(), context.Services.GetConfiguration());
context.Services.AddHttpUserAgentCachedParser();
}
private static void AddAspNetServices(IServiceCollection services)

36
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs

@ -1,7 +1,8 @@
using System;
using DeviceDetectorNET;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MyCSharp.HttpUserAgentParser;
using MyCSharp.HttpUserAgentParser.Providers;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.WebClientInfo;
@ -11,13 +12,16 @@ public class HttpContextWebClientInfoProvider : IWebClientInfoProvider, ITransie
{
protected ILogger<HttpContextWebClientInfoProvider> Logger { get; }
protected IHttpContextAccessor HttpContextAccessor { get; }
protected IHttpUserAgentParserProvider HttpUserAgentParser { get; }
public HttpContextWebClientInfoProvider(
ILogger<HttpContextWebClientInfoProvider> logger,
IHttpContextAccessor httpContextAccessor)
IHttpContextAccessor httpContextAccessor,
IHttpUserAgentParserProvider httpUserAgentParser)
{
Logger = logger;
HttpContextAccessor = httpContextAccessor;
HttpUserAgentParser = httpUserAgentParser;
}
public string? BrowserInfo => GetBrowserInfo();
@ -46,27 +50,21 @@ public class HttpContextWebClientInfoProvider : IWebClientInfoProvider, ITransie
protected virtual string? GetDeviceInfo()
{
string? deviceInfo = null;
var deviceDetector = new DeviceDetector(GetBrowserInfo());
deviceDetector.Parse();
if (!deviceDetector.IsParsed())
var browserInfo = GetBrowserInfo();
if (browserInfo.IsNullOrWhiteSpace())
{
return deviceInfo;
}
var osInfo = deviceDetector.GetOs();
if (osInfo.Success)
{
deviceInfo = osInfo.Match.Name;
return null;
}
var clientInfo = deviceDetector.GetClient();
if (clientInfo.Success)
var httpUserAgentInformation = HttpUserAgentParser.Parse(browserInfo);
switch (httpUserAgentInformation.Type)
{
deviceInfo = deviceInfo.IsNullOrWhiteSpace() ? clientInfo.Match.Name : deviceInfo + " " + clientInfo.Match.Name;
case HttpUserAgentType.Browser:
case HttpUserAgentType.Robot:
return (httpUserAgentInformation.Platform.HasValue ? httpUserAgentInformation.Platform.Value.Name + " " : string.Empty) + httpUserAgentInformation.Name;
case HttpUserAgentType.Unknown:
default:
return httpUserAgentInformation.UserAgent;
}
return deviceInfo;
}
}

2
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs

@ -68,7 +68,7 @@ public class AbpBackgroundJobOptions
public void AddJob(Type jobType)
{
AddJob(new BackgroundJobConfiguration(jobType, GetBackgroundJobName(jobType)));
AddJob(new BackgroundJobConfiguration(jobType, GetBackgroundJobName(BackgroundJobArgsHelper.GetJobArgsType(jobType))));
}
public void AddJob(BackgroundJobConfiguration jobConfiguration)

2
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationScheme.cs

@ -1,8 +1,8 @@
using System;
using System.Linq;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using DeviceDetectorNET;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

8
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/WebClientInfoProvider/WebClientInfoProviderDto.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.AspNetCore.Mvc.WebClientInfoProvider;
public class WebClientInfoProviderDto
{
public string BrowserInfo { get; set; }
public string DeviceInfo { get; set; }
}

26
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/WebClientInfoProvider/WebClientInfoProviderTestController.cs

@ -0,0 +1,26 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.WebClientInfo;
namespace Volo.Abp.AspNetCore.Mvc.WebClientInfoProvider;
[Route("api/web-client-info")]
public class WebClientInfoProviderTestController : AbpController
{
private IWebClientInfoProvider _webClientInfoProvider { get; }
public WebClientInfoProviderTestController(IWebClientInfoProvider webClientInfoProvider)
{
_webClientInfoProvider = webClientInfoProvider;
}
[HttpGet]
public Task<WebClientInfoProviderDto> GetAsync()
{
return Task.FromResult(new WebClientInfoProviderDto
{
BrowserInfo = _webClientInfoProvider.BrowserInfo,
DeviceInfo = _webClientInfoProvider.DeviceInfo
});
}
}

36
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/WebClientInfoProvider/WebClientInfoProviderTestController_Tests.cs

@ -0,0 +1,36 @@
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.WebClientInfoProvider;
public class WebClientInfoProviderTestController_Tests : AspNetCoreMvcTestBase
{
[Theory]
[InlineData("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36", "Windows 10 Chrome")]
[InlineData("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36", "Mac OS X Chrome")]
[InlineData("PostmanRuntime/7.43.4", "PostmanRuntime/7.43.4")]
[InlineData("curl/7.64.1", "curl/7.64.1")]
[InlineData("Mozilla/5.0 (compatible; MojeekBot/0.11; +mojeek.com/bot.html)", "MojeekBot")]
public async Task TestAsync(string ua, string device)
{
var clientInfo = await GetWebClientInfoAsync(ua);
clientInfo.ShouldNotBeNull();
clientInfo.BrowserInfo.ShouldBe(ua);
clientInfo.DeviceInfo.ShouldBe(device);
}
private async Task<WebClientInfoProviderDto> GetWebClientInfoAsync(string userAgent )
{
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, "api/web-client-info"))
{
requestMessage.Headers.Add("User-Agent", userAgent);
var response = await Client.SendAsync(requestMessage);
response.StatusCode.ShouldBe(HttpStatusCode.OK);
return JsonSerializer.Deserialize<WebClientInfoProviderDto>(await response.Content.ReadAsStringAsync(), JsonSerializerOptions.Web);
}
}
}

18
npm/ng-packs/packages/components/extensible/src/lib/components/multi-select/extensible-form-multiselect.component.ts

@ -1,8 +1,9 @@
import { Component, ChangeDetectionStrategy, forwardRef, input } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ABP, LocalizationModule } from '@abp/ng.core';
import { ABP, LocalizationPipe } from '@abp/ng.core';
import { FormProp } from '../../models/form-props';
import { NgxValidateCoreModule } from '@ngx-validate/core';
const EXTENSIBLE_FORM_MULTI_SELECT_CONTROL_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
@ -19,21 +20,24 @@ const EXTENSIBLE_FORM_MULTI_SELECT_CONTROL_VALUE_ACCESSOR = {
<input
type="checkbox"
class="form-check-input"
[id]="'checkbox_' + option.value"
[disabled]="disabled"
[checked]="isChecked(option.value)"
(change)="onCheckboxChange(option.value, $event.target.checked)"
/>
@if (prop().isExtra) {
{{ '::' + option.key | abpLocalization }}
} @else {
{{ option.key }}
}
<label [for]="'checkbox_' + option.value">
@if (prop().isExtra) {
{{ '::' + option.key | abpLocalization }}
} @else {
{{ option.key }}
}
</label>
</div>
}
</div>
`,
providers: [EXTENSIBLE_FORM_MULTI_SELECT_CONTROL_VALUE_ACCESSOR],
imports: [LocalizationModule, CommonModule, ReactiveFormsModule],
imports: [LocalizationPipe, CommonModule, ReactiveFormsModule, NgxValidateCoreModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExtensibleFormMultiselectComponent implements ControlValueAccessor {

34
npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html

@ -28,6 +28,10 @@
<hr class="mt-2 mb-3" />
@for (feature of features[group.name]; track feature.id || i; let i = $index) {
@let provider = feature.provider.name;
@let isFeatureDisabled =
provider !== providerName && provider !== defaultProviderName;
<div class="mt-2" [ngStyle]="feature.style" (keyup.enter)="save()">
@switch (feature.valueType?.name) {
@case (valueTypes.ToggleStringValueType) {
@ -38,11 +42,15 @@
[id]="feature.name"
[(ngModel)]="feature.value"
(ngModelChange)="onCheckboxClick($event, feature)"
[disabled]="isFeatureDisabled"
/>
<label class="form-check-label" [htmlFor]="feature.name">{{
feature.displayName
}}</label>
<label class="form-check-label" [htmlFor]="feature.name">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<ng-container
*ngTemplateOutlet="
descTmp;
@ -53,15 +61,19 @@
}
@case (valueTypes.FreeTextStringValueType) {
<div class="mb-3 form-group" [class.px-2]="!!feature.parentName">
<label [htmlFor]="feature.name" class="form-label">{{
feature.displayName
}}</label>
<label [htmlFor]="feature.name" class="form-label">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<input
class="form-control"
type="text"
[id]="feature.name"
[(ngModel)]="feature.value"
[abpFeatureManagementFreeText]="feature"
[disabled]="isFeatureDisabled"
/>
<ng-container
@ -75,13 +87,17 @@
@case (valueTypes.SelectionStringValueType) {
@if (feature.valueType.itemSource?.items?.length) {
<div class="mb-3 form-group" [class.px-2]="!!feature.parentName">
<label [htmlFor]="feature.name" class="form-label">{{
feature.displayName
}}</label>
<label [htmlFor]="feature.name" class="form-label">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<select
class="form-select"
[id]="feature.name"
[(ngModel)]="feature.value"
[disabled]="isFeatureDisabled"
>
@for (
item of feature.valueType.itemSource?.items;

4
npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts

@ -28,6 +28,8 @@ enum ValueTypes {
SelectionStringValueType = 'SelectionStringValueType',
}
const DEFAULT_PROVIDER_NAME = 'D';
@Component({
selector: 'abp-feature-management',
templateUrl: './feature-management.component.html',
@ -74,6 +76,8 @@ export class FeatureManagementComponent
valueTypes = ValueTypes;
defaultProviderName = DEFAULT_PROVIDER_NAME;
protected _visible;
@Input()

Loading…
Cancel
Save