mirror of https://github.com/abpframework/abp.git
188 changed files with 3634 additions and 693 deletions
@ -0,0 +1,178 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
using Volo.Abp.ObjectExtending.Modularity; |
||||
|
using Volo.Abp.Reflection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
public class CachedObjectExtensionsDtoService : ICachedObjectExtensionsDtoService, ISingletonDependency |
||||
|
{ |
||||
|
private volatile ObjectExtensionsDto _cachedValue; |
||||
|
private readonly object _syncLock = new object(); |
||||
|
|
||||
|
public virtual ObjectExtensionsDto Get() |
||||
|
{ |
||||
|
if (_cachedValue == null) |
||||
|
{ |
||||
|
lock (_syncLock) |
||||
|
{ |
||||
|
if (_cachedValue == null) |
||||
|
{ |
||||
|
_cachedValue = GenerateCacheValue(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return _cachedValue; |
||||
|
} |
||||
|
|
||||
|
protected virtual ObjectExtensionsDto GenerateCacheValue() |
||||
|
{ |
||||
|
var objectExtensionsDto = new ObjectExtensionsDto |
||||
|
{ |
||||
|
Modules = new Dictionary<string, ModuleExtensionDto>() |
||||
|
}; |
||||
|
|
||||
|
foreach (var moduleConfig in ObjectExtensionManager.Instance.Modules()) |
||||
|
{ |
||||
|
objectExtensionsDto.Modules[moduleConfig.Key] = CreateModuleExtensionDto(moduleConfig.Value); |
||||
|
} |
||||
|
|
||||
|
return objectExtensionsDto; |
||||
|
} |
||||
|
|
||||
|
protected virtual ModuleExtensionDto CreateModuleExtensionDto( |
||||
|
ModuleExtensionConfiguration moduleConfig) |
||||
|
{ |
||||
|
var moduleExtensionDto = new ModuleExtensionDto |
||||
|
{ |
||||
|
Entities = new Dictionary<string, EntityExtensionDto>() |
||||
|
}; |
||||
|
|
||||
|
foreach (var objectConfig in moduleConfig.Entities) |
||||
|
{ |
||||
|
moduleExtensionDto.Entities[objectConfig.Key] = GetEntityExtensionDto(objectConfig.Value); |
||||
|
} |
||||
|
|
||||
|
foreach (var customConfig in moduleConfig.Configuration.Where(c => !c.Key.StartsWith("_"))) |
||||
|
{ |
||||
|
moduleExtensionDto.Configuration[customConfig.Key] = customConfig.Value; |
||||
|
} |
||||
|
|
||||
|
return moduleExtensionDto; |
||||
|
} |
||||
|
|
||||
|
protected virtual EntityExtensionDto GetEntityExtensionDto( |
||||
|
EntityExtensionConfiguration entityConfig) |
||||
|
{ |
||||
|
var entityExtensionDto = new EntityExtensionDto |
||||
|
{ |
||||
|
Properties = new Dictionary<string, ExtensionPropertyDto>(), |
||||
|
Configuration = new Dictionary<string, object>() |
||||
|
}; |
||||
|
|
||||
|
foreach (var propertyConfig in entityConfig.GetProperties()) |
||||
|
{ |
||||
|
if (!propertyConfig.IsAvailableToClients) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
entityExtensionDto.Properties[propertyConfig.Name] = CreateExtensionPropertyDto(propertyConfig); |
||||
|
} |
||||
|
|
||||
|
foreach (var customConfig in entityConfig.Configuration.Where(c => !c.Key.StartsWith("_"))) |
||||
|
{ |
||||
|
entityExtensionDto.Configuration[customConfig.Key] = customConfig.Value; |
||||
|
} |
||||
|
|
||||
|
return entityExtensionDto; |
||||
|
} |
||||
|
|
||||
|
protected virtual ExtensionPropertyDto CreateExtensionPropertyDto( |
||||
|
ExtensionPropertyConfiguration propertyConfig) |
||||
|
{ |
||||
|
var extensionPropertyDto = new ExtensionPropertyDto |
||||
|
{ |
||||
|
Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(propertyConfig.Type), |
||||
|
TypeSimple = TypeHelper.GetSimplifiedName(propertyConfig.Type), |
||||
|
Attributes = new List<ExtensionPropertyAttributeDto>(), |
||||
|
DisplayName = CreateDisplayNameDto(propertyConfig), |
||||
|
Configuration = new Dictionary<string, object>(), |
||||
|
Api = new ExtensionPropertyApiDto |
||||
|
{ |
||||
|
OnGet = new ExtensionPropertyApiGetDto |
||||
|
{ |
||||
|
IsAvailable = propertyConfig.Api.OnGet.IsAvailable |
||||
|
}, |
||||
|
OnCreate = new ExtensionPropertyApiCreateDto |
||||
|
{ |
||||
|
IsAvailable = propertyConfig.Api.OnCreate.IsAvailable |
||||
|
}, |
||||
|
OnUpdate = new ExtensionPropertyApiUpdateDto |
||||
|
{ |
||||
|
IsAvailable = propertyConfig.Api.OnUpdate.IsAvailable |
||||
|
} |
||||
|
}, |
||||
|
Ui = new ExtensionPropertyUiDto |
||||
|
{ |
||||
|
OnCreateForm = new ExtensionPropertyUiFormDto |
||||
|
{ |
||||
|
IsVisible = propertyConfig.UI.OnCreateForm.IsVisible |
||||
|
}, |
||||
|
OnEditForm = new ExtensionPropertyUiFormDto |
||||
|
{ |
||||
|
IsVisible = propertyConfig.UI.OnEditForm.IsVisible |
||||
|
}, |
||||
|
OnTable = new ExtensionPropertyUiTableDto |
||||
|
{ |
||||
|
IsVisible = propertyConfig.UI.OnTable.IsVisible |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
foreach (var attribute in propertyConfig.Attributes) |
||||
|
{ |
||||
|
extensionPropertyDto.Attributes.Add( |
||||
|
ExtensionPropertyAttributeDto.Create(attribute) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
foreach (var customConfig in propertyConfig.Configuration.Where(c => !c.Key.StartsWith("_"))) |
||||
|
{ |
||||
|
extensionPropertyDto.Configuration[customConfig.Key] = customConfig.Value; |
||||
|
} |
||||
|
|
||||
|
return extensionPropertyDto; |
||||
|
} |
||||
|
|
||||
|
protected virtual LocalizableStringDto CreateDisplayNameDto(ExtensionPropertyConfiguration propertyConfig) |
||||
|
{ |
||||
|
if (propertyConfig.DisplayName == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (propertyConfig.DisplayName is LocalizableString localizableStringInstance) |
||||
|
{ |
||||
|
return new LocalizableStringDto( |
||||
|
localizableStringInstance.Name, |
||||
|
localizableStringInstance.ResourceType != null |
||||
|
? LocalizationResourceNameAttribute.GetName(localizableStringInstance.ResourceType) |
||||
|
: null |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
if (propertyConfig.DisplayName is FixedLocalizableString fixedLocalizableString) |
||||
|
{ |
||||
|
// "_" means don't use the default resource, but directly use the name.
|
||||
|
return new LocalizableStringDto(fixedLocalizableString.Value, "_"); |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class EntityExtensionDto |
||||
|
{ |
||||
|
public Dictionary<string, ExtensionPropertyDto> Properties { get; set; } |
||||
|
|
||||
|
public Dictionary<string, object> Configuration { get; set; } |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyApiCreateDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailable { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
public class ExtensionPropertyApiDto |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiGetDto OnGet { get; set; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiCreateDto OnCreate { get; set; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiUpdateDto OnUpdate { get; set; } |
||||
|
|
||||
|
public ExtensionPropertyApiDto() |
||||
|
{ |
||||
|
OnGet = new ExtensionPropertyApiGetDto(); |
||||
|
OnCreate = new ExtensionPropertyApiCreateDto(); |
||||
|
OnUpdate = new ExtensionPropertyApiUpdateDto(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyApiGetDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailable { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyApiUpdateDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailable { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Reflection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyAttributeDto |
||||
|
{ |
||||
|
public string Type { get; set; } |
||||
|
public string TypeSimple { get; set; } |
||||
|
public Dictionary<string, object> Configuration { get; set; } |
||||
|
|
||||
|
public static ExtensionPropertyAttributeDto Create(Attribute attribute) |
||||
|
{ |
||||
|
var attributeType = attribute.GetType(); |
||||
|
var dto = new ExtensionPropertyAttributeDto |
||||
|
{ |
||||
|
Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(attributeType), |
||||
|
TypeSimple = TypeHelper.GetSimplifiedName(attributeType), |
||||
|
Configuration = new Dictionary<string, object>() |
||||
|
}; |
||||
|
|
||||
|
if (attribute is StringLengthAttribute stringLengthAttribute) |
||||
|
{ |
||||
|
dto.Configuration["MaximumLength"] = stringLengthAttribute.MaximumLength; |
||||
|
dto.Configuration["MinimumLength"] = stringLengthAttribute.MinimumLength; |
||||
|
} |
||||
|
|
||||
|
//TODO: Others!
|
||||
|
|
||||
|
return dto; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyDto |
||||
|
{ |
||||
|
public string Type { get; set; } |
||||
|
|
||||
|
public string TypeSimple { get; set; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public LocalizableStringDto DisplayName { get; set; } |
||||
|
|
||||
|
public ExtensionPropertyApiDto Api { get; set; } |
||||
|
|
||||
|
public ExtensionPropertyUiDto Ui { get; set; } |
||||
|
|
||||
|
public List<ExtensionPropertyAttributeDto> Attributes { get; set; } |
||||
|
|
||||
|
public Dictionary<string, object> Configuration { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyUiDto |
||||
|
{ |
||||
|
public ExtensionPropertyUiTableDto OnTable { get; set; } |
||||
|
public ExtensionPropertyUiFormDto OnCreateForm { get; set; } |
||||
|
public ExtensionPropertyUiFormDto OnEditForm { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyUiFormDto |
||||
|
{ |
||||
|
public bool IsVisible { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionPropertyUiTableDto |
||||
|
{ |
||||
|
public bool IsVisible { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
public interface ICachedObjectExtensionsDtoService |
||||
|
{ |
||||
|
ObjectExtensionsDto Get(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class LocalizableStringDto |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string Name { get; private set; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public string Resource { get; set; } |
||||
|
|
||||
|
public LocalizableStringDto([NotNull] string name, string resource = null) |
||||
|
{ |
||||
|
Name = Check.NotNullOrEmpty(name, nameof(name)); |
||||
|
Resource = resource; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ModuleExtensionDto |
||||
|
{ |
||||
|
public Dictionary<string, EntityExtensionDto> Entities { get; set; } |
||||
|
|
||||
|
public Dictionary<string, object> Configuration { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ObjectExtensionsDto |
||||
|
{ |
||||
|
public Dictionary<string, ModuleExtensionDto> Modules { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class AbpPageToolbarOptions |
||||
|
{ |
||||
|
public PageToolbarDictionary Toolbars { get; } |
||||
|
|
||||
|
public AbpPageToolbarOptions() |
||||
|
{ |
||||
|
Toolbars = new PageToolbarDictionary(); |
||||
|
} |
||||
|
|
||||
|
public void Configure<TPage>([NotNull] Action<PageToolbar> configureAction) |
||||
|
{ |
||||
|
// ReSharper disable once AssignNullToNotNullAttribute
|
||||
|
Configure(typeof(TPage).FullName, configureAction); |
||||
|
} |
||||
|
|
||||
|
public void Configure([NotNull]string pageName, [NotNull]Action<PageToolbar> configureAction) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(pageName, nameof(pageName)); |
||||
|
Check.NotNull(configureAction, nameof(configureAction)); |
||||
|
|
||||
|
var toolbar = Toolbars.GetOrAdd(pageName, () => new PageToolbar(pageName)); |
||||
|
configureAction(toolbar); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public interface IPageToolbarContributor |
||||
|
{ |
||||
|
Task ContributeAsync(PageToolbarContributionContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public interface IPageToolbarManager |
||||
|
{ |
||||
|
Task<PageToolbarItem[]> GetItemsAsync(string pageName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbar |
||||
|
{ |
||||
|
public string PageName { get; } |
||||
|
|
||||
|
public PageToolbarContributorList Contributors { get; set; } |
||||
|
|
||||
|
public PageToolbar([NotNull] string pageName) |
||||
|
{ |
||||
|
PageName = Check.NotNullOrEmpty(pageName, nameof(pageName)); |
||||
|
Contributors = new PageToolbarContributorList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbarContributionContext |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string PageName { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public PageToolbarItemList Items { get; } |
||||
|
|
||||
|
public PageToolbarContributionContext( |
||||
|
[NotNull] string pageName, |
||||
|
[NotNull] IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
PageName = Check.NotNull(pageName, nameof(pageName)); |
||||
|
ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider)); |
||||
|
|
||||
|
Items = new PageToolbarItemList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public abstract class PageToolbarContributor : IPageToolbarContributor |
||||
|
{ |
||||
|
public abstract Task ContributeAsync(PageToolbarContributionContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbarContributorList : List<IPageToolbarContributor> |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbarDictionary : Dictionary<string, PageToolbar> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
using System; |
||||
|
using Localization.Resources.AbpUi; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar.Button; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public static class PageToolbarExtensions |
||||
|
{ |
||||
|
public static PageToolbar AddComponent<TComponent>( |
||||
|
this PageToolbar toolbar, |
||||
|
object argument = null, |
||||
|
int order = 0, |
||||
|
string requiredPolicyName = null) |
||||
|
{ |
||||
|
return toolbar.AddComponent( |
||||
|
typeof(TComponent), |
||||
|
argument, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public static PageToolbar AddComponent( |
||||
|
this PageToolbar toolbar, |
||||
|
Type componentType, |
||||
|
object argument = null, |
||||
|
int order = 0, |
||||
|
string requiredPolicyName = null) |
||||
|
{ |
||||
|
toolbar.Contributors.Add( |
||||
|
new SimplePageToolbarContributor( |
||||
|
componentType, |
||||
|
argument, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
return toolbar; |
||||
|
} |
||||
|
|
||||
|
public static PageToolbar AddButton( |
||||
|
this PageToolbar toolbar, |
||||
|
ILocalizableString text, |
||||
|
string icon = null, |
||||
|
string name = null, |
||||
|
string id = null, |
||||
|
ILocalizableString busyText = null, |
||||
|
FontIconType iconType = FontIconType.FontAwesome, |
||||
|
AbpButtonType type = AbpButtonType.Primary, |
||||
|
AbpButtonSize size = AbpButtonSize.Small, |
||||
|
bool disabled = false, |
||||
|
int order = 0, |
||||
|
string requiredPolicyName = null) |
||||
|
{ |
||||
|
if (busyText == null) |
||||
|
{ |
||||
|
busyText = new LocalizableString(typeof(AbpUiResource), "ProcessingWithThreeDot"); |
||||
|
} |
||||
|
|
||||
|
toolbar.AddComponent<AbpPageToolbarButtonViewComponent>( |
||||
|
new |
||||
|
{ |
||||
|
text, |
||||
|
icon, |
||||
|
name, |
||||
|
id, |
||||
|
busyText, |
||||
|
iconType, |
||||
|
type, |
||||
|
size, |
||||
|
disabled |
||||
|
}, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
); |
||||
|
|
||||
|
return toolbar; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbarItem |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public Type ComponentType { get; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public object Arguments { get; set; } |
||||
|
|
||||
|
public int Order { get; set; } |
||||
|
|
||||
|
public PageToolbarItem( |
||||
|
[NotNull] Type componentType, |
||||
|
[CanBeNull] object arguments = null, |
||||
|
int order = 0) |
||||
|
{ |
||||
|
ComponentType = Check.NotNull(componentType, nameof(componentType)); |
||||
|
Arguments = arguments; |
||||
|
Order = order; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbarItemList : List<PageToolbarItem> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class PageToolbarManager : IPageToolbarManager, ITransientDependency |
||||
|
{ |
||||
|
protected AbpPageToolbarOptions Options { get; } |
||||
|
protected IHybridServiceScopeFactory ServiceScopeFactory { get; } |
||||
|
|
||||
|
public PageToolbarManager( |
||||
|
IOptions<AbpPageToolbarOptions> options, |
||||
|
IHybridServiceScopeFactory serviceScopeFactory) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
ServiceScopeFactory = serviceScopeFactory; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<PageToolbarItem[]> GetItemsAsync(string pageName) |
||||
|
{ |
||||
|
var toolbar = Options.Toolbars.GetOrDefault(pageName); |
||||
|
if (toolbar == null || !toolbar.Contributors.Any()) |
||||
|
{ |
||||
|
return Array.Empty<PageToolbarItem>(); |
||||
|
} |
||||
|
|
||||
|
using (var scope = ServiceScopeFactory.CreateScope()) |
||||
|
{ |
||||
|
var context = new PageToolbarContributionContext(pageName, scope.ServiceProvider); |
||||
|
|
||||
|
foreach (var contributor in toolbar.Contributors) |
||||
|
{ |
||||
|
await contributor.ContributeAsync(context); |
||||
|
} |
||||
|
|
||||
|
return context.Items.OrderBy(i => i.Order).ToArray(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars |
||||
|
{ |
||||
|
public class SimplePageToolbarContributor : IPageToolbarContributor |
||||
|
{ |
||||
|
public Type ComponentType { get; } |
||||
|
|
||||
|
public object Argument { get; set; } |
||||
|
|
||||
|
public int Order { get; } |
||||
|
|
||||
|
public string RequiredPolicyName { get; } |
||||
|
|
||||
|
public SimplePageToolbarContributor( |
||||
|
Type componentType, |
||||
|
object argument = null, |
||||
|
int order = 0, |
||||
|
string requiredPolicyName = null) |
||||
|
{ |
||||
|
ComponentType = componentType; |
||||
|
Argument = argument; |
||||
|
Order = order; |
||||
|
RequiredPolicyName = requiredPolicyName; |
||||
|
} |
||||
|
|
||||
|
public async Task ContributeAsync(PageToolbarContributionContext context) |
||||
|
{ |
||||
|
if(await ShouldAddComponentAsync(context)) |
||||
|
{ |
||||
|
context.Items.Add(new PageToolbarItem(ComponentType, Argument, Order)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<bool> ShouldAddComponentAsync(PageToolbarContributionContext context) |
||||
|
{ |
||||
|
if (RequiredPolicyName != null) |
||||
|
{ |
||||
|
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>(); |
||||
|
if (!await authorizationService.IsGrantedAsync(RequiredPolicyName)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
||||
|
{ |
||||
|
public class AbpPageToolbarViewComponent : AbpViewComponent |
||||
|
{ |
||||
|
private readonly IPageToolbarManager _toolbarManager; |
||||
|
|
||||
|
public AbpPageToolbarViewComponent(IPageToolbarManager toolbarManager) |
||||
|
{ |
||||
|
_toolbarManager = toolbarManager; |
||||
|
} |
||||
|
|
||||
|
public async Task<IViewComponentResult> InvokeAsync(string pageName) |
||||
|
{ |
||||
|
var items = await _toolbarManager.GetItemsAsync(pageName); |
||||
|
return View("~/Pages/Shared/Components/AbpPageToolbar/Default.cshtml", items); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar.Button |
||||
|
{ |
||||
|
public class AbpPageToolbarButtonViewComponent : AbpViewComponent |
||||
|
{ |
||||
|
protected IStringLocalizerFactory StringLocalizerFactory { get; } |
||||
|
|
||||
|
public AbpPageToolbarButtonViewComponent(IStringLocalizerFactory stringLocalizerFactory) |
||||
|
{ |
||||
|
StringLocalizerFactory = stringLocalizerFactory; |
||||
|
} |
||||
|
|
||||
|
public IViewComponentResult Invoke( |
||||
|
ILocalizableString text, |
||||
|
string name, |
||||
|
string icon, |
||||
|
string id, |
||||
|
ILocalizableString busyText, |
||||
|
FontIconType iconType, |
||||
|
AbpButtonType type, |
||||
|
AbpButtonSize size, |
||||
|
bool disabled) |
||||
|
{ |
||||
|
Check.NotNull(text, nameof(text)); |
||||
|
|
||||
|
return View( |
||||
|
"~/Pages/Shared/Components/AbpPageToolbar/Button/Default.cshtml", |
||||
|
new AbpPageToolbarButtonViewModel( |
||||
|
text.Localize(StringLocalizerFactory), |
||||
|
name, |
||||
|
icon, |
||||
|
id, |
||||
|
busyText?.Localize(StringLocalizerFactory), |
||||
|
iconType, |
||||
|
type, |
||||
|
size, |
||||
|
disabled |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public class AbpPageToolbarButtonViewModel |
||||
|
{ |
||||
|
public string Text { get; } |
||||
|
public string Name { get; } |
||||
|
public string Icon { get; } |
||||
|
public string Id { get; } |
||||
|
public string BusyText { get; } |
||||
|
public FontIconType IconType { get; } |
||||
|
public AbpButtonType Type { get; } |
||||
|
public AbpButtonSize Size { get; } |
||||
|
public bool Disabled { get; } |
||||
|
|
||||
|
public AbpPageToolbarButtonViewModel( |
||||
|
string text, |
||||
|
string name, |
||||
|
string icon, |
||||
|
string id, |
||||
|
string busyText, |
||||
|
FontIconType iconType, |
||||
|
AbpButtonType type, |
||||
|
AbpButtonSize size, |
||||
|
bool disabled) |
||||
|
{ |
||||
|
Text = text; |
||||
|
Name = name; |
||||
|
Icon = icon; |
||||
|
Id = id; |
||||
|
BusyText = busyText; |
||||
|
IconType = iconType; |
||||
|
Type = type; |
||||
|
Size = size; |
||||
|
Disabled = disabled; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
@model Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar.Button.AbpPageToolbarButtonViewComponent.AbpPageToolbarButtonViewModel |
||||
|
<abp-button |
||||
|
text="@Model.Text" |
||||
|
name="@Model.Name" |
||||
|
icon="@Model.Icon" |
||||
|
id="@Model.Id" |
||||
|
busy-text="@Model.BusyText" |
||||
|
icon-type="@Model.IconType" |
||||
|
button-type="@Model.Type" |
||||
|
size="@Model.Size" |
||||
|
disabled="@Model.Disabled" |
||||
|
class="mx-1" |
||||
|
/> |
||||
@ -0,0 +1,5 @@ |
|||||
|
@model Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars.PageToolbarItem[] |
||||
|
@foreach (var toolbarItem in Model) |
||||
|
{ |
||||
|
@(await Component.InvokeAsync(toolbarItem.ComponentType, toolbarItem.Arguments)) |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
||||
|
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
||||
|
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
||||
|
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
@ -0,0 +1,192 @@ |
|||||
|
var abp = abp || {}; |
||||
|
(function () { |
||||
|
abp.ui = abp.ui || {}; |
||||
|
abp.ui.extensions = abp.ui.extensions || {}; |
||||
|
|
||||
|
abp.ui.extensions.ActionList = function () { |
||||
|
return new abp.utils.common.LinkedList(); |
||||
|
}; |
||||
|
|
||||
|
abp.ui.extensions.ColumnList = function () { |
||||
|
return new abp.utils.common.LinkedList(); |
||||
|
}; |
||||
|
|
||||
|
abp.ui.extensions.entityActions = (function () { |
||||
|
var _callbackLists = {}; |
||||
|
|
||||
|
function _get(name) { |
||||
|
var callbackList = _callbackLists[name]; |
||||
|
|
||||
|
if (!callbackList) { |
||||
|
callbackList = _callbackLists[name] = []; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
addContributor: _addContributor, |
||||
|
get actions() { |
||||
|
return _getActions(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function _addContributor(contributeCallback, order) { |
||||
|
if (order === undefined || order >= callbackList.length) { |
||||
|
callbackList.push(contributeCallback); |
||||
|
} else if (order === 0) { |
||||
|
callbackList.unshift(contributeCallback); |
||||
|
} else { |
||||
|
callbackList.splice(order, 0, contributeCallback); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function _getActions() { |
||||
|
var actionList = new abp.ui.extensions.ActionList(); |
||||
|
|
||||
|
callbackList.forEach(function (callback) { |
||||
|
callback(actionList); |
||||
|
}); |
||||
|
|
||||
|
return actionList; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
get: _get |
||||
|
}; |
||||
|
})(); |
||||
|
|
||||
|
abp.ui.extensions.tableColumns = (function () { |
||||
|
var _callbackLists = {}; |
||||
|
|
||||
|
function _get(name) { |
||||
|
var callbackList = _callbackLists[name]; |
||||
|
|
||||
|
if (!callbackList) { |
||||
|
callbackList = _callbackLists[name] = []; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
addContributor: _addContributor, |
||||
|
get columns() { |
||||
|
return _getColumns(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function _addContributor(contributeCallback, order) { |
||||
|
if (order === undefined || order >= callbackList.length) { |
||||
|
callbackList.push(contributeCallback); |
||||
|
} else if (order === 0) { |
||||
|
callbackList.unshift(contributeCallback); |
||||
|
} else { |
||||
|
callbackList.splice(order, 0, contributeCallback); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function _getColumns() { |
||||
|
var columnList = new abp.ui.extensions.ColumnList(); |
||||
|
|
||||
|
callbackList.forEach(function (callback) { |
||||
|
callback(columnList); |
||||
|
}); |
||||
|
|
||||
|
return columnList; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
get: _get |
||||
|
}; |
||||
|
})(); |
||||
|
|
||||
|
function initializeObjectExtensions() { |
||||
|
|
||||
|
function localizeDisplayName(propertyName, displayName) { |
||||
|
if (displayName && displayName.name) { |
||||
|
return abp.localization.localize(displayName.name, displayName.resource); |
||||
|
} |
||||
|
|
||||
|
if (abp.localization.isLocalized('DisplayName:' + propertyName)) { |
||||
|
return abp.localization.localize('DisplayName:' + propertyName); |
||||
|
} |
||||
|
|
||||
|
return abp.localization.localize(propertyName); |
||||
|
} |
||||
|
|
||||
|
function configureTableColumns(tableName, columnConfigs) { |
||||
|
abp.ui.extensions.tableColumns.get(tableName) |
||||
|
.addContributor( |
||||
|
function (columnList) { |
||||
|
columnList.addManyTail(columnConfigs); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
function getTableProperties(objectConfig) { |
||||
|
var propertyNames = Object.keys(objectConfig.properties); |
||||
|
var tableProperties = []; |
||||
|
for (var i = 0; i < propertyNames.length; i++) { |
||||
|
var propertyName = propertyNames[i]; |
||||
|
var propertyConfig = objectConfig.properties[propertyName]; |
||||
|
if (propertyConfig.ui.onTable.isVisible) { |
||||
|
tableProperties.push({ |
||||
|
name: propertyName, |
||||
|
config: propertyConfig |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return tableProperties; |
||||
|
} |
||||
|
|
||||
|
function convertPropertiesToColumnConfigs(properties) { |
||||
|
var columnConfigs = []; |
||||
|
|
||||
|
for (var i = 0; i < properties.length; i++) { |
||||
|
var tableProperty = properties[i]; |
||||
|
columnConfigs.push({ |
||||
|
title: localizeDisplayName(tableProperty.name, tableProperty.config.displayName), |
||||
|
data: "extraProperties." + tableProperty.name |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return columnConfigs; |
||||
|
} |
||||
|
|
||||
|
function configureEntity(moduleName, entityName, entityConfig) { |
||||
|
var tableProperties = getTableProperties(entityConfig); |
||||
|
|
||||
|
if (tableProperties.length > 0) { |
||||
|
var tableName = abp.utils.toCamelCase(moduleName) + "." + abp.utils.toCamelCase(entityName); |
||||
|
var columnConfigs = convertPropertiesToColumnConfigs(tableProperties); |
||||
|
configureTableColumns( |
||||
|
tableName, |
||||
|
columnConfigs |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function configureModule(moduleName, moduleConfig) { |
||||
|
var entityNames = Object.keys(moduleConfig.entities); |
||||
|
for (var i = 0; i < entityNames.length; i++) { |
||||
|
configureEntity( |
||||
|
moduleName, |
||||
|
entityNames[i], |
||||
|
moduleConfig.entities[entityNames[i]] |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var moduleNames = Object.keys(abp.objectExtensions.modules); |
||||
|
|
||||
|
for (var i = 0; i < moduleNames.length; i++) { |
||||
|
configureModule( |
||||
|
moduleNames[i], |
||||
|
abp.objectExtensions.modules[moduleNames[i]] |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
abp.event.on('abp.configurationInitialized', function () { |
||||
|
initializeObjectExtensions(); |
||||
|
}); |
||||
|
|
||||
|
})(); |
||||
@ -1,26 +0,0 @@ |
|||||
using System; |
|
||||
using System.Globalization; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Localization |
|
||||
{ |
|
||||
internal static class GlobalizationHelper |
|
||||
{ |
|
||||
public static bool IsValidCultureCode(string cultureCode) |
|
||||
{ |
|
||||
if (cultureCode.IsNullOrWhiteSpace()) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
CultureInfo.GetCultureInfo(cultureCode); |
|
||||
return true; |
|
||||
} |
|
||||
catch (CultureNotFoundException) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
||||
|
{ |
||||
|
public class AbpExtraPropertiesDictionaryModelBinderProvider : IModelBinderProvider |
||||
|
{ |
||||
|
public IModelBinder GetBinder(ModelBinderProviderContext context) |
||||
|
{ |
||||
|
if (context == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(context)); |
||||
|
} |
||||
|
|
||||
|
if (context.Metadata.ModelType != typeof(Dictionary<string, object>)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (!context.Metadata.ContainerType.IsAssignableTo<IHasExtraProperties>()) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var binderType = typeof(DictionaryModelBinder<string, object>); |
||||
|
var keyBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(typeof(string))); |
||||
|
var valueBinder = new AbpExtraPropertyModelBinder(context.Metadata.ContainerType); |
||||
|
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>(); |
||||
|
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value; |
||||
|
|
||||
|
return (IModelBinder)Activator.CreateInstance( |
||||
|
binderType, |
||||
|
keyBinder, |
||||
|
valueBinder, |
||||
|
loggerFactory, |
||||
|
true /* allowValidatingTopLevelNodes */, |
||||
|
mvcOptions); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
||||
|
{ |
||||
|
public class AbpExtraPropertyModelBinder : IModelBinder |
||||
|
{ |
||||
|
public Type ExtensibleObjectType { get; } |
||||
|
|
||||
|
public AbpExtraPropertyModelBinder(Type extensibleObjectType) |
||||
|
{ |
||||
|
ExtensibleObjectType = extensibleObjectType; |
||||
|
} |
||||
|
|
||||
|
public virtual Task BindModelAsync(ModelBindingContext bindingContext) |
||||
|
{ |
||||
|
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); |
||||
|
if (valueProviderResult == ValueProviderResult.None) |
||||
|
{ |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); |
||||
|
|
||||
|
var model = ConvertStringToPropertyType( |
||||
|
bindingContext, |
||||
|
valueProviderResult.FirstValue |
||||
|
); |
||||
|
|
||||
|
bindingContext.Result = ModelBindingResult.Success(model); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
protected virtual object ConvertStringToPropertyType(ModelBindingContext bindingContext, string value) |
||||
|
{ |
||||
|
if (bindingContext.ModelMetadata.ConvertEmptyStringToNull && string.IsNullOrWhiteSpace(value)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var extensionInfo = ObjectExtensionManager.Instance.GetOrNull(ExtensibleObjectType); |
||||
|
if (extensionInfo == null) |
||||
|
{ |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
var propertyName = ExtraPropertyBindingHelper.ExtractExtraPropertyName(bindingContext.ModelName); |
||||
|
if (propertyName == null) |
||||
|
{ |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
var propertyInfo = extensionInfo.GetPropertyOrNull(propertyName); |
||||
|
if (propertyInfo == null) |
||||
|
{ |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
return Convert.ChangeType(value, propertyInfo.Type); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
||||
|
{ |
||||
|
public static class ExtraPropertyBindingHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// <paramref name="expression"/> is a string like "UserInfo.ExtraProperties[SocialSecurityNumber]"
|
||||
|
/// This method returns "SocialSecurityNumber" for this example. */
|
||||
|
/// </summary>
|
||||
|
public static string ExtractExtraPropertyName(string expression) |
||||
|
{ |
||||
|
var index = expression.IndexOf("ExtraProperties[", StringComparison.Ordinal); |
||||
|
if (index < 0) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return expression.Substring(index + 16, expression.Length - index - 17); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// <paramref name="expression"/> is a string like "UserInfo.ExtraProperties[SocialSecurityNumber]"
|
||||
|
/// This method returns "UserInfo" for this example.
|
||||
|
/// </summary>
|
||||
|
public static string ExtractContainerName(string expression) |
||||
|
{ |
||||
|
var index = expression.IndexOf("ExtraProperties[", StringComparison.Ordinal); |
||||
|
if (index < 0) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return expression.Left(index).TrimEnd('.'); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.Reflection; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.Validation |
||||
|
{ |
||||
|
public static class ValidationAttributeHelper |
||||
|
{ |
||||
|
private static readonly PropertyInfo ValidationAttributeErrorMessageStringProperty = typeof(ValidationAttribute) |
||||
|
.GetProperty("ErrorMessageString", BindingFlags.Instance | BindingFlags.NonPublic); |
||||
|
|
||||
|
public static void SetDefaultErrorMessage(ValidationAttribute validationAttribute) |
||||
|
{ |
||||
|
validationAttribute.ErrorMessage = |
||||
|
ValidationAttributeErrorMessageStringProperty.GetValue(validationAttribute) as string; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,132 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.Reflection; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.DataAnnotations; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; |
||||
|
using Microsoft.AspNetCore.Mvc.Rendering; |
||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.AspNetCore.Mvc.ModelBinding; |
||||
|
using Volo.Abp.AspNetCore.Mvc.Validation; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
using Volo.Abp.Validation.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ViewFeatures |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices(typeof(ValidationHtmlAttributeProvider))] |
||||
|
public class AbpValidationHtmlAttributeProvider |
||||
|
: DefaultValidationHtmlAttributeProvider, ISingletonDependency |
||||
|
{ |
||||
|
private readonly IModelMetadataProvider _metadataProvider; |
||||
|
private readonly IStringLocalizerFactory _stringLocalizerFactory; |
||||
|
private readonly IStringLocalizer<AbpValidationResource> _validationStringLocalizer; |
||||
|
private readonly IValidationAttributeAdapterProvider _validationAttributeAdapterProvider; |
||||
|
|
||||
|
public AbpValidationHtmlAttributeProvider( |
||||
|
IOptions<MvcViewOptions> optionsAccessor, |
||||
|
IModelMetadataProvider metadataProvider, |
||||
|
ClientValidatorCache clientValidatorCache, |
||||
|
IValidationAttributeAdapterProvider validationAttributeAdapterProvider, |
||||
|
IStringLocalizerFactory stringLocalizerFactory, |
||||
|
IStringLocalizer<AbpValidationResource> validationStringLocalizer) |
||||
|
: base( |
||||
|
optionsAccessor, |
||||
|
metadataProvider, |
||||
|
clientValidatorCache) |
||||
|
{ |
||||
|
_metadataProvider = metadataProvider; |
||||
|
_validationAttributeAdapterProvider = validationAttributeAdapterProvider; |
||||
|
_stringLocalizerFactory = stringLocalizerFactory; |
||||
|
_validationStringLocalizer = validationStringLocalizer; |
||||
|
} |
||||
|
|
||||
|
public override void AddValidationAttributes( |
||||
|
ViewContext viewContext, |
||||
|
ModelExplorer modelExplorer, |
||||
|
IDictionary<string, string> attributes) |
||||
|
{ |
||||
|
base.AddValidationAttributes(viewContext, modelExplorer, attributes); |
||||
|
AddExtraPropertyValidationsAttributes(viewContext, modelExplorer, attributes); |
||||
|
} |
||||
|
|
||||
|
protected virtual void AddExtraPropertyValidationsAttributes(ViewContext viewContext, ModelExplorer modelExplorer, IDictionary<string, string> attributes) |
||||
|
{ |
||||
|
var nameAttribute = attributes.GetOrDefault("name"); |
||||
|
if (nameAttribute == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var extraPropertyName = ExtraPropertyBindingHelper.ExtractExtraPropertyName(nameAttribute); |
||||
|
if (extraPropertyName == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
//TODO: containerName can be null on controller actions..?
|
||||
|
var containerName = ExtraPropertyBindingHelper.ExtractContainerName(nameAttribute); |
||||
|
if (containerName == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (modelExplorer.Container?.ModelType == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var extensibleObjectType = modelExplorer.Container.ModelType |
||||
|
.GetProperty(containerName, BindingFlags.Instance | BindingFlags.Public) |
||||
|
?.PropertyType; |
||||
|
if (extensibleObjectType == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var extensionPropertyInfo = ObjectExtensionManager.Instance.GetPropertyOrNull( |
||||
|
extensibleObjectType, |
||||
|
extraPropertyName |
||||
|
); |
||||
|
|
||||
|
if (extensionPropertyInfo == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (modelExplorer.Metadata is DefaultModelMetadata metadata) |
||||
|
{ |
||||
|
metadata.DisplayMetadata.DisplayName = |
||||
|
() => extensionPropertyInfo.GetLocalizedDisplayName(_stringLocalizerFactory); |
||||
|
} |
||||
|
|
||||
|
foreach (var validationAttribute in extensionPropertyInfo.GetValidationAttributes()) |
||||
|
{ |
||||
|
var validationContext = new ClientModelValidationContext( |
||||
|
viewContext, |
||||
|
modelExplorer.Metadata, |
||||
|
_metadataProvider, |
||||
|
attributes |
||||
|
); |
||||
|
|
||||
|
if (validationAttribute.ErrorMessage == null) |
||||
|
{ |
||||
|
ValidationAttributeHelper.SetDefaultErrorMessage(validationAttribute); |
||||
|
} |
||||
|
|
||||
|
var validationAttributeAdapter = _validationAttributeAdapterProvider.GetAttributeAdapter( |
||||
|
validationAttribute, |
||||
|
_validationStringLocalizer |
||||
|
); |
||||
|
|
||||
|
validationAttributeAdapter?.AddValidation(validationContext); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending |
||||
|
{ |
||||
|
public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions |
||||
|
{ |
||||
|
public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) |
||||
|
{ |
||||
|
foreach (var attribute in propertyInfo.Attributes) |
||||
|
{ |
||||
|
var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); |
||||
|
if (inputTypeByAttribute != null) |
||||
|
{ |
||||
|
return inputTypeByAttribute; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return GetInputTypeFromTypeOrNull(propertyInfo.Type) |
||||
|
?? "text"; //default
|
||||
|
} |
||||
|
|
||||
|
private static string GetInputTypeFromAttributeOrNull(Attribute attribute) |
||||
|
{ |
||||
|
if (attribute is EmailAddressAttribute) |
||||
|
{ |
||||
|
return "email"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is UrlAttribute) |
||||
|
{ |
||||
|
return "url"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is HiddenInputAttribute) |
||||
|
{ |
||||
|
return "hidden"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is PhoneAttribute) |
||||
|
{ |
||||
|
return "tel"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is DataTypeAttribute dataTypeAttribute) |
||||
|
{ |
||||
|
switch (dataTypeAttribute.DataType) |
||||
|
{ |
||||
|
case DataType.Password: |
||||
|
return "password"; |
||||
|
case DataType.Date: |
||||
|
return "date"; |
||||
|
case DataType.Time: |
||||
|
return "time"; |
||||
|
case DataType.EmailAddress: |
||||
|
return "email"; |
||||
|
case DataType.Url: |
||||
|
return "url"; |
||||
|
case DataType.PhoneNumber: |
||||
|
return "tel"; |
||||
|
case DataType.DateTime: |
||||
|
return "datetime-local"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private static string GetInputTypeFromTypeOrNull(Type type) |
||||
|
{ |
||||
|
if (type == typeof(bool)) |
||||
|
{ |
||||
|
return "checkbox"; |
||||
|
} |
||||
|
|
||||
|
if (type == typeof(DateTime)) |
||||
|
{ |
||||
|
return "datetime-local"; |
||||
|
} |
||||
|
|
||||
|
if (type == typeof(int) || |
||||
|
type == typeof(long) || |
||||
|
type == typeof(byte) || |
||||
|
type == typeof(sbyte) || |
||||
|
type == typeof(short) || |
||||
|
type == typeof(ushort) || |
||||
|
type == typeof(uint) || |
||||
|
type == typeof(long) || |
||||
|
type == typeof(ulong)) |
||||
|
{ |
||||
|
return "number"; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
{ |
||||
|
"culture": "tr", |
||||
|
"texts": { |
||||
|
"DisplayName:Abp.Mailing.DefaultFromAddress": "Varsayılan gönderici adresi", |
||||
|
"DisplayName:Abp.Mailing.DefaultFromDisplayName": "Varsayılan gönderici adı", |
||||
|
"DisplayName:Abp.Mailing.Smtp.Host": "Sunucu", |
||||
|
"DisplayName:Abp.Mailing.Smtp.Port": "Port", |
||||
|
"DisplayName:Abp.Mailing.Smtp.UserName": "Kullanıcı adı", |
||||
|
"DisplayName:Abp.Mailing.Smtp.Password": "Şifre", |
||||
|
"DisplayName:Abp.Mailing.Smtp.Domain": "Domain", |
||||
|
"DisplayName:Abp.Mailing.Smtp.EnableSsl": "SSL aktif", |
||||
|
"DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "Varsayılan kimlik kullan", |
||||
|
"Description:Abp.Mailing.DefaultFromAddress": "Varsayılan gönderici adresi", |
||||
|
"Description:Abp.Mailing.DefaultFromDisplayName": "Varsayılan gönderici adı", |
||||
|
"Description:Abp.Mailing.Smtp.Host": "SMTP üzerinden e-posta göndermek için kullanılacak sunucunun IP adresi ya da adı.", |
||||
|
"Description:Abp.Mailing.Smtp.Port": "Sunucunun SMTP portu.", |
||||
|
"Description:Abp.Mailing.Smtp.UserName": "Varsayılan kimlik kullanılmaması durumunda kullanılacak kullanıcı adı.", |
||||
|
"Description:Abp.Mailing.Smtp.Password": "Varsayılan kimlik kullanılmaması durumunda kullanılacak şifre.", |
||||
|
"Description:Abp.Mailing.Smtp.Domain": "Kimlik bilgilerinin doğrulanacağı sunucu/domain.", |
||||
|
"Description:Abp.Mailing.Smtp.EnableSsl": "Email gönderiminde SSL kullanılıp kullanılmayacağı.", |
||||
|
"Description:Abp.Mailing.Smtp.UseDefaultCredentials": "Varsayılan kimlik bilgilerinin kullanılıp kullanılmayacağı.", |
||||
|
"TextTemplate:StandardEmailTemplates.Layout": "Varsayılan e-posta layout şablonu", |
||||
|
"TextTemplate:StandardEmailTemplates.Message": "Basit bir mesaj göndermek için e-posta şablonu" |
||||
|
} |
||||
|
} |
||||
@ -1,25 +1,27 @@ |
|||||
using Volo.Abp.TextTemplating; |
using Volo.Abp.Emailing.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
namespace Volo.Abp.Emailing.Templates |
namespace Volo.Abp.Emailing.Templates |
||||
{ |
{ |
||||
public class DefaultEmailTemplateProvider : TemplateDefinitionProvider |
public class StandardEmailTemplateDefinitionProvider : TemplateDefinitionProvider |
||||
{ |
{ |
||||
public override void Define(ITemplateDefinitionContext context) |
public override void Define(ITemplateDefinitionContext context) |
||||
{ |
{ |
||||
context.Add( |
context.Add( |
||||
new TemplateDefinition( |
new TemplateDefinition( |
||||
StandardEmailTemplates.Layout, |
StandardEmailTemplates.Layout, |
||||
defaultCultureName: "en", |
displayName: LocalizableString.Create<EmailingResource>("TextTemplate:StandardEmailTemplates.Layout"), |
||||
isLayout: true |
isLayout: true |
||||
).WithVirtualFilePath("/Volo/Abp/Emailing/Templates/Layout") |
).WithVirtualFilePath("/Volo/Abp/Emailing/Templates/Layout.tpl", true) |
||||
); |
); |
||||
|
|
||||
context.Add( |
context.Add( |
||||
new TemplateDefinition( |
new TemplateDefinition( |
||||
StandardEmailTemplates.Message, |
StandardEmailTemplates.Message, |
||||
defaultCultureName: "en", |
displayName: LocalizableString.Create<EmailingResource>("TextTemplate:StandardEmailTemplates.Message"), |
||||
layout: StandardEmailTemplates.Layout |
layout: StandardEmailTemplates.Layout |
||||
).WithVirtualFilePath("/Volo/Abp/Emailing/Templates/Message") |
).WithVirtualFilePath("/Volo/Abp/Emailing/Templates/Message.tpl", true) |
||||
); |
); |
||||
} |
} |
||||
} |
} |
||||
@ -1,127 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using JetBrains.Annotations; |
|
||||
|
|
||||
namespace Volo.Abp.Http.Modeling |
|
||||
{ |
|
||||
public static class ModelingTypeHelper |
|
||||
{ |
|
||||
public static string GetFullNameHandlingNullableAndGenerics([NotNull] Type type) |
|
||||
{ |
|
||||
Check.NotNull(type, nameof(type)); |
|
||||
|
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) |
|
||||
{ |
|
||||
return type.GenericTypeArguments[0].FullName + "?"; |
|
||||
} |
|
||||
|
|
||||
if (type.IsGenericType) |
|
||||
{ |
|
||||
var genericType = type.GetGenericTypeDefinition(); |
|
||||
return $"{genericType.FullName.Left(genericType.FullName.IndexOf('`'))}<{type.GenericTypeArguments.Select(GetFullNameHandlingNullableAndGenerics).JoinAsString(",")}>"; |
|
||||
} |
|
||||
|
|
||||
return type.FullName; |
|
||||
} |
|
||||
|
|
||||
public static string GetSimplifiedName([NotNull] Type type) |
|
||||
{ |
|
||||
Check.NotNull(type, nameof(type)); |
|
||||
|
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) |
|
||||
{ |
|
||||
return GetSimplifiedName(type.GenericTypeArguments[0]) + "?"; |
|
||||
} |
|
||||
|
|
||||
if (type.IsGenericType) |
|
||||
{ |
|
||||
var genericType = type.GetGenericTypeDefinition(); |
|
||||
return $"{genericType.FullName.Left(genericType.FullName.IndexOf('`'))}<{type.GenericTypeArguments.Select(GetSimplifiedName).JoinAsString(",")}>"; |
|
||||
} |
|
||||
|
|
||||
if (type == typeof(string)) |
|
||||
{ |
|
||||
return "string"; |
|
||||
} |
|
||||
else if (type == typeof(int)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(long)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(bool)) |
|
||||
{ |
|
||||
return "boolean"; |
|
||||
} |
|
||||
else if (type == typeof(char)) |
|
||||
{ |
|
||||
return "string"; |
|
||||
} |
|
||||
else if (type == typeof(double)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(float)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(decimal)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(DateTime)) |
|
||||
{ |
|
||||
return "string"; |
|
||||
} |
|
||||
else if (type == typeof(DateTimeOffset)) |
|
||||
{ |
|
||||
return "string"; |
|
||||
} |
|
||||
else if (type == typeof(TimeSpan)) |
|
||||
{ |
|
||||
return "string"; |
|
||||
} |
|
||||
else if (type == typeof(Guid)) |
|
||||
{ |
|
||||
return "string"; |
|
||||
} |
|
||||
else if (type == typeof(byte)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(sbyte)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(short)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(ushort)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(uint)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(ulong)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(IntPtr)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
else if (type == typeof(UIntPtr)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
|
|
||||
return type.FullName; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace Microsoft.Extensions.Localization |
||||
|
{ |
||||
|
public static class AbpStringLocalizerFactoryExtensions |
||||
|
{ |
||||
|
public static IStringLocalizer CreateDefaultOrNull(this IStringLocalizerFactory localizerFactory) |
||||
|
{ |
||||
|
return (localizerFactory as IAbpStringLocalizerFactoryWithDefaultResourceSupport) |
||||
|
?.CreateDefaultOrNull(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Microsoft.Extensions.Localization |
||||
|
{ |
||||
|
public interface IAbpStringLocalizerFactoryWithDefaultResourceSupport |
||||
|
{ |
||||
|
[CanBeNull] |
||||
|
IStringLocalizer CreateDefaultOrNull(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Localization |
||||
|
{ |
||||
|
public static class HasNameWithLocalizableDisplayNameExtensions |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public static string GetLocalizedDisplayName( |
||||
|
[NotNull] this IHasNameWithLocalizableDisplayName source, |
||||
|
[NotNull] IStringLocalizerFactory stringLocalizerFactory, |
||||
|
[CanBeNull] string localizationNamePrefix = "DisplayName:") |
||||
|
{ |
||||
|
if (source.DisplayName != null) |
||||
|
{ |
||||
|
return source.DisplayName.Localize(stringLocalizerFactory); |
||||
|
} |
||||
|
|
||||
|
var defaultStringLocalizer = stringLocalizerFactory.CreateDefaultOrNull(); |
||||
|
if (defaultStringLocalizer == null) |
||||
|
{ |
||||
|
return source.Name; |
||||
|
} |
||||
|
|
||||
|
var localizedString = defaultStringLocalizer[$"{localizationNamePrefix}{source.Name}"]; |
||||
|
if (!localizedString.ResourceNotFound || |
||||
|
localizationNamePrefix.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return localizedString; |
||||
|
} |
||||
|
|
||||
|
return defaultStringLocalizer[source.Name]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.Localization |
||||
|
{ |
||||
|
public interface IHasNameWithLocalizableDisplayName |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string Name { get; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public ILocalizableString DisplayName { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class EntityExtensionConfiguration |
||||
|
{ |
||||
|
[NotNull] |
||||
|
protected ExtensionPropertyConfigurationDictionary Properties { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public List<Action<ObjectExtensionValidationContext>> Validators { get; } |
||||
|
|
||||
|
public Dictionary<string, object> Configuration { get; } |
||||
|
|
||||
|
public EntityExtensionConfiguration() |
||||
|
{ |
||||
|
Properties = new ExtensionPropertyConfigurationDictionary(); |
||||
|
Validators = new List<Action<ObjectExtensionValidationContext>>(); |
||||
|
Configuration = new Dictionary<string, object>(); |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public virtual EntityExtensionConfiguration AddOrUpdateProperty<TProperty>( |
||||
|
[NotNull] string propertyName, |
||||
|
[CanBeNull] Action<ExtensionPropertyConfiguration> configureAction = null) |
||||
|
{ |
||||
|
return AddOrUpdateProperty( |
||||
|
typeof(TProperty), |
||||
|
propertyName, |
||||
|
configureAction |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public virtual EntityExtensionConfiguration AddOrUpdateProperty( |
||||
|
[NotNull] Type propertyType, |
||||
|
[NotNull] string propertyName, |
||||
|
[CanBeNull] Action<ExtensionPropertyConfiguration> configureAction = null) |
||||
|
{ |
||||
|
Check.NotNull(propertyType, nameof(propertyType)); |
||||
|
Check.NotNull(propertyName, nameof(propertyName)); |
||||
|
|
||||
|
var propertyInfo = Properties.GetOrAdd( |
||||
|
propertyName, |
||||
|
() => new ExtensionPropertyConfiguration(this, propertyType, propertyName) |
||||
|
); |
||||
|
|
||||
|
configureAction?.Invoke(propertyInfo); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public virtual ImmutableList<ExtensionPropertyConfiguration> GetProperties() |
||||
|
{ |
||||
|
return Properties.Values.ToImmutableList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class EntityExtensionConfigurationDictionary : Dictionary<string, EntityExtensionConfiguration> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class ExtensionPropertyApiConfiguration |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiGetConfiguration OnGet { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiCreateConfiguration OnCreate { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiUpdateConfiguration OnUpdate { get; } |
||||
|
|
||||
|
public ExtensionPropertyApiConfiguration() |
||||
|
{ |
||||
|
OnGet = new ExtensionPropertyApiGetConfiguration(); |
||||
|
OnCreate = new ExtensionPropertyApiCreateConfiguration(); |
||||
|
OnUpdate = new ExtensionPropertyApiUpdateConfiguration(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class ExtensionPropertyApiCreateConfiguration |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailable { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class ExtensionPropertyApiGetConfiguration |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailable { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class ExtensionPropertyApiUpdateConfiguration |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailable { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class ExtensionPropertyConfiguration : IHasNameWithLocalizableDisplayName |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public EntityExtensionConfiguration EntityExtensionConfiguration { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public string Name { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public Type Type { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public List<Attribute> Attributes { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public List<Action<ObjectExtensionPropertyValidationContext>> Validators { get; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public ILocalizableString DisplayName { get; set; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public Dictionary<string, object> Configuration { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Single point to enable/disable this property for the clients (UI and API).
|
||||
|
/// If this is false, the configuration made in the <see cref="UI"/> and the <see cref="Api"/>
|
||||
|
/// properties are not used.
|
||||
|
/// Default: true.
|
||||
|
/// </summary>
|
||||
|
public bool IsAvailableToClients { get; set; } = true; |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyEntityConfiguration Entity { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyUiConfiguration UI { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public ExtensionPropertyApiConfiguration Api { get; } |
||||
|
|
||||
|
public ExtensionPropertyConfiguration( |
||||
|
[NotNull] EntityExtensionConfiguration entityExtensionConfiguration, |
||||
|
[NotNull] Type type, |
||||
|
[NotNull] string name) |
||||
|
{ |
||||
|
EntityExtensionConfiguration = Check.NotNull(entityExtensionConfiguration, nameof(entityExtensionConfiguration)); |
||||
|
Type = Check.NotNull(type, nameof(type)); |
||||
|
Name = Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
Configuration = new Dictionary<string, object>(); |
||||
|
Attributes = new List<Attribute>(); |
||||
|
Validators = new List<Action<ObjectExtensionPropertyValidationContext>>(); |
||||
|
|
||||
|
Entity = new ExtensionPropertyEntityConfiguration(); |
||||
|
UI = new ExtensionPropertyUiConfiguration(); |
||||
|
Api = new ExtensionPropertyApiConfiguration(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public class ExtensionPropertyConfigurationDictionary : Dictionary<string, ExtensionPropertyConfiguration> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue