Merge branch 'feature/virtual-properties' into 'dev'
Resolve "Fully virtual properties" Closes #24 See merge request leon.hoppe/hopframe!32
This commit was merged in pull request #70.
This commit is contained in:
63
.idea/.idea.HopFrame/.idea/workspace.xml
generated
63
.idea/.idea.HopFrame/.idea/workspace.xml
generated
@@ -12,10 +12,17 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="0648788e-7696-4e60-bf12-5d5601f33d8c" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/docs/Dockerfile" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docs/Writerside/hopframe.tree" beforeDir="false" afterPath="$PROJECT_DIR$/docs/Writerside/hopframe.tree" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docs/Writerside/topics/starter.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/Writerside/topics/Overview.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/HopFrameConfiguratorExtensions.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/HopFrameConfiguratorExtensions.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/HopFrameConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/HopFrameConfig.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfig.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/TableManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/TableManager.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Config/TableConfiguratorTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Config/TableConfiguratorTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Services/DisplayPropertyTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Services/DisplayPropertyTests.cs" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -35,7 +42,7 @@
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="feature/plugins" />
|
||||
<entry key="$PROJECT_DIR$" value="dev" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
@@ -74,6 +81,7 @@
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/558c1d46e1e21d2e78ee2ab67a674f6927bf95355b2f245f35d74bb5ec0f92/CancellationTokenSource.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/5a69b82eed595b731b82667db08722b69b82482e275cf32dfb219190e3dc49/CollectionEntry.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/60e7b22380df80ef6fefe43138047f49ec6eff4b25c12b42ce3d6ed5aac/MethodInvokerCommon.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/6354a7b35d7821629924d3676acd7e67a6f7f94343e0e66ec439aa2bd6ed5/ThrowHelper.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/642391624bd5c30b3411a11434588aba4906207335166b784bf3a4325f6c7/NavigationEntry.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/6d1d64f05e7045295fa180276a8c2aef0302c9e96eb53b3431ab13db4579/FluentAppBarItem.razor.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/6fe785cceb29ca2d1da78e157315815a7c4372b582a20a71c28b210f9d56e/IconsExtensions.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
@@ -97,8 +105,6 @@
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/fd57398b7dc3a8ce7da2786f2c67289c3d974658a9e90d0c1e84db3d965fbf1/Console.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ff37d54b3bf4d2756237fb789635831532603376e940f63d634b869d26d74c/Regular16.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Web/Components/Pages/HopFrameTablePage.razor" root0="SKIP_HIGHLIGHTING" root1="FORCE_HIGHLIGHTING" root2="FORCE_HIGHLIGHTING" />
|
||||
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Web/Plugins/Events/SearchEvent.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="KubernetesApiPersistence">{}</component>
|
||||
<component name="KubernetesApiProvider">{
|
||||
@@ -117,28 +123,28 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.HopFrame.Testing.Api: https.executor": "Run",
|
||||
".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
|
||||
".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
|
||||
".NET Project.HopFrame.Testing.executor": "Run",
|
||||
"72b118b0-a6fc-4561-acdf-74f0b454dbb8.executor": "Debug",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"b5f11219-dfc4-47a1-b02c-90ab603034fb.executor": "Debug",
|
||||
"dcdf1689-dc07-47e4-8824-2e60a4fbf301.executor": "Debug",
|
||||
"git-widget-placeholder": "!31 on feature/docs",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.HopFrame.Testing.Api: https.executor": "Run",
|
||||
".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
|
||||
".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
|
||||
".NET Project.HopFrame.Testing.executor": "Run",
|
||||
"72b118b0-a6fc-4561-acdf-74f0b454dbb8.executor": "Debug",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"b5f11219-dfc4-47a1-b02c-90ab603034fb.executor": "Debug",
|
||||
"dcdf1689-dc07-47e4-8824-2e60a4fbf301.executor": "Debug",
|
||||
"git-widget-placeholder": "!32 on feature/virtual-properties",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
}]]></component>
|
||||
<component name="RunManager" selected=".NET Launch Settings Profile.HopFrame.Testing: https">
|
||||
<configuration name="HopFrame.Testing: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/testing/HopFrame.Testing/HopFrame.Testing.csproj" />
|
||||
@@ -248,6 +254,7 @@
|
||||
<workItem from="1739352479748" duration="3047000" />
|
||||
<workItem from="1739369355001" duration="1751000" />
|
||||
<workItem from="1739461452173" duration="5533000" />
|
||||
<workItem from="1739550750776" duration="3388000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Added basic configuration">
|
||||
<option name="closed" value="true" />
|
||||
|
||||
@@ -26,7 +26,7 @@ public class DbContextConfig {
|
||||
/// <summary>
|
||||
/// A helper class for editing the <see cref="DbContextConfig"/>
|
||||
/// </summary>
|
||||
public class DbContextConfigurator<TDbContext>(DbContextConfig config) {
|
||||
public sealed class DbContextConfigurator<TDbContext>(DbContextConfig config) {
|
||||
|
||||
/// <summary>
|
||||
/// The Internal DbContext configuration that's modified by the helper functions
|
||||
|
||||
@@ -15,7 +15,7 @@ public class HopFrameConfig {
|
||||
/// <summary>
|
||||
/// A helper class for editing the <see cref="HopFrameConfig"/>
|
||||
/// </summary>
|
||||
public class HopFrameConfigurator(HopFrameConfig config, IServiceCollection collection = null!) {
|
||||
public sealed class HopFrameConfigurator(HopFrameConfig config, IServiceCollection collection = null!) {
|
||||
|
||||
/// <summary>
|
||||
/// The Internal HopFrame configuration that's modified by the helper functions
|
||||
|
||||
@@ -23,9 +23,37 @@ public class PropertyConfig(PropertyInfo info, TableConfig table, int nthPropert
|
||||
public bool IsRelation { get; internal set; }
|
||||
public bool IsRequired { get; internal set; }
|
||||
public bool IsEnumerable { get; internal set; }
|
||||
public bool IsListingProperty { get; set; }
|
||||
public bool IsVirtualProperty { get; set; }
|
||||
public int Order { get; set; } = nthProperty;
|
||||
public int DisplayLength { get; set; } = 32;
|
||||
|
||||
public virtual object? GetValue(object? source, IServiceProvider provider) {
|
||||
return Info.GetValue(source);
|
||||
}
|
||||
|
||||
public virtual void SetValue(object? source, object? value, IServiceProvider provider) {
|
||||
Info.SetValue(source, value);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VirtualPropertyConfig(TableConfig table, int nthProperty) : PropertyConfig(GetDummyProperty(), table, nthProperty) {
|
||||
public string? DummyProperty { get; set; } = null;
|
||||
|
||||
public Func<object, string, IServiceProvider, Task>? VirtualParser { get; set; }
|
||||
|
||||
public override object? GetValue(object? source, IServiceProvider provider) {
|
||||
return Formatter!.Invoke(source!, provider).Result;
|
||||
}
|
||||
|
||||
public override void SetValue(object? source, object? value, IServiceProvider provider) {
|
||||
VirtualParser?.Invoke(source!, (string)value!, provider).Wait();
|
||||
}
|
||||
|
||||
private static PropertyInfo GetDummyProperty() {
|
||||
return typeof(VirtualPropertyConfig)
|
||||
.GetProperties()
|
||||
.First(prop => prop.Name == nameof(DummyProperty));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,3 +241,28 @@ public class PropertyConfigurator<TProp>(PropertyConfig config) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VirtualPropertyConfigurator<TModel>(VirtualPropertyConfig config) : PropertyConfigurator<string>(config) {
|
||||
/// <summary>
|
||||
/// Determines the function used for parsing the value provided in the editor dialog to the actual model value
|
||||
/// </summary>
|
||||
public VirtualPropertyConfigurator<TModel> SetVirtualParser(Action<TModel, string, IServiceProvider> parser) {
|
||||
var cfg = InnerConfig as VirtualPropertyConfig;
|
||||
|
||||
cfg!.VirtualParser = (model, input, services) => {
|
||||
parser.Invoke((TModel)model, input, services);
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="SetVirtualParser{TModel}(System.Action{TModel,string,System.IServiceProvider})"/>
|
||||
public VirtualPropertyConfigurator<TModel> SetVirtualParser(Func<TModel, string, IServiceProvider, Task> parser) {
|
||||
var cfg = InnerConfig as VirtualPropertyConfig;
|
||||
|
||||
cfg!.VirtualParser = (model, input, services) => parser.Invoke((TModel)model, input, services);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class TableConfig {
|
||||
/// <summary>
|
||||
/// A helper class for editing the <see cref="TableConfig"/>
|
||||
/// </summary>
|
||||
public class TableConfigurator<TModel>(TableConfig config) {
|
||||
public sealed class TableConfigurator<TModel>(TableConfig config) {
|
||||
|
||||
/// <summary>
|
||||
/// The Internal property configuration that's modified by the helper functions
|
||||
@@ -76,7 +76,7 @@ public class TableConfigurator<TModel>(TableConfig config) {
|
||||
public PropertyConfigurator<TProp> Property<TProp>(Expression<Func<TModel, TProp>> propertyExpression) {
|
||||
var info = GetPropertyInfo(propertyExpression);
|
||||
var prop = InnerConfig.Properties
|
||||
.Single(prop => prop.Info.Name == info.Name);
|
||||
.Single(prop => prop.Info == info);
|
||||
return new PropertyConfigurator<TProp>(prop);
|
||||
}
|
||||
|
||||
@@ -99,25 +99,25 @@ public class TableConfigurator<TModel>(TableConfig config) {
|
||||
/// <param name="template">The template used for generating the property value</param>
|
||||
/// <returns>The configurator for the virtual property</returns>
|
||||
/// <seealso cref="PropertyConfigurator{TProp}"/>
|
||||
public PropertyConfigurator<string> AddVirtualProperty(string name, Func<TModel, IServiceProvider, string> template) {
|
||||
var prop = new PropertyConfig(InnerConfig.Properties.First().Info, InnerConfig, InnerConfig.Properties.Count) {
|
||||
public VirtualPropertyConfigurator<TModel> AddVirtualProperty(string name, Func<TModel, IServiceProvider, string> template) {
|
||||
var prop = new VirtualPropertyConfig(InnerConfig, InnerConfig.Properties.Count) {
|
||||
Name = name,
|
||||
IsListingProperty = true,
|
||||
IsVirtualProperty = true,
|
||||
Formatter = (obj, provider) => Task.FromResult(template.Invoke((TModel)obj, provider))
|
||||
};
|
||||
InnerConfig.Properties.Add(prop);
|
||||
return new PropertyConfigurator<string>(prop);
|
||||
return new VirtualPropertyConfigurator<TModel>(prop);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="AddVirtualProperty(string,System.Func{TModel,System.IServiceProvider,string})"/>
|
||||
public PropertyConfigurator<string> AddVirtualProperty(string name, Func<TModel, IServiceProvider, Task<string>> template) {
|
||||
var prop = new PropertyConfig(InnerConfig.Properties.First().Info, InnerConfig, InnerConfig.Properties.Count) {
|
||||
public VirtualPropertyConfigurator<TModel> AddVirtualProperty(string name, Func<TModel, IServiceProvider, Task<string>> template) {
|
||||
var prop = new VirtualPropertyConfig(InnerConfig, InnerConfig.Properties.Count) {
|
||||
Name = name,
|
||||
IsListingProperty = true,
|
||||
IsVirtualProperty = true,
|
||||
Formatter = (obj, provider) => template.Invoke((TModel)obj, provider)
|
||||
};
|
||||
InnerConfig.Properties.Add(prop);
|
||||
return new PropertyConfigurator<string>(prop);
|
||||
return new VirtualPropertyConfigurator<TModel>(prop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -229,7 +229,7 @@ public class TableConfigurator<TModel>(TableConfig config) {
|
||||
throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property.");
|
||||
}
|
||||
|
||||
Type type = typeof(TSource);
|
||||
var type = typeof(TSource);
|
||||
if (propInfo.ReflectedType != null && type != propInfo.ReflectedType &&
|
||||
!type.IsSubclassOf(propInfo.ReflectedType)) {
|
||||
throw new ArgumentException($"Expression '{propertyLambda}' refers to a property that is not from type {type}.");
|
||||
|
||||
@@ -61,7 +61,7 @@ internal sealed class ContextExplorer(HopFrameConfig config, IServiceProvider pr
|
||||
var entity = dbContext.Model.FindEntityType(table.TableType)!;
|
||||
|
||||
foreach (var propertyConfig in table.Properties) {
|
||||
if (propertyConfig.IsListingProperty) continue;
|
||||
if (propertyConfig.IsVirtualProperty) continue;
|
||||
if (propertyConfig.IsRelation) continue;
|
||||
|
||||
var prop = entity.FindProperty(propertyConfig.Info.Name);
|
||||
@@ -93,7 +93,7 @@ internal sealed class ContextExplorer(HopFrameConfig config, IServiceProvider pr
|
||||
|
||||
foreach (var property in entity.GetProperties()) {
|
||||
var propConfig = table.Properties
|
||||
.Where(prop => !prop.IsListingProperty)
|
||||
.Where(prop => !prop.IsVirtualProperty)
|
||||
.SingleOrDefault(prop => prop.Info == property.PropertyInfo);
|
||||
if (propConfig is null || propConfig.IsRequired) continue;
|
||||
propConfig.IsRequired = !property.IsNullable;
|
||||
|
||||
@@ -63,7 +63,7 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
private bool ItemSearched(TModel item, string searchTerm) {
|
||||
foreach (var property in config.Properties) {
|
||||
if (!property.Searchable) continue;
|
||||
var value = property.Info.GetValue(item);
|
||||
var value = property.GetValue(item, provider);
|
||||
if (value is null) continue;
|
||||
|
||||
var strValue = value.ToString();
|
||||
@@ -77,10 +77,10 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
public async Task<string> DisplayProperty(object? item, PropertyConfig prop, object? value = null, object? enumerableValue = null) {
|
||||
if (item is null) return string.Empty;
|
||||
|
||||
if (prop.IsListingProperty)
|
||||
if (prop.IsVirtualProperty)
|
||||
return await prop.Formatter!.Invoke(item, provider);
|
||||
|
||||
var propValue = value ?? prop.Info.GetValue(item);
|
||||
var propValue = value ?? prop.GetValue(item, provider);
|
||||
if (propValue is null)
|
||||
return string.Empty;
|
||||
|
||||
@@ -112,7 +112,7 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
if (innerConfig is null) return propValue.ToString()!;
|
||||
|
||||
var innerProp = innerConfig.Properties
|
||||
.SingleOrDefault(p => p.Info == prop.DisplayedProperty && !p.IsListingProperty);
|
||||
.SingleOrDefault(p => p.Info == prop.DisplayedProperty && !p.IsVirtualProperty);
|
||||
|
||||
if (innerProp is null) return propValue.ToString() ?? string.Empty;
|
||||
return await DisplayProperty(propValue, innerProp);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@using HopFrame.Web.Plugins.Events
|
||||
|
||||
<FluentDialogBody>
|
||||
@foreach (var property in Content.Config.Properties.Where(prop => !prop.IsListingProperty).OrderBy(prop => prop.Order)) {
|
||||
@foreach (var property in GetEditorProperties()) {
|
||||
if (!_currentlyEditing && !property.Creatable) continue;
|
||||
|
||||
<div style="margin-bottom: 20px">
|
||||
@@ -158,7 +158,7 @@
|
||||
ValueChanged="@(async v => await SetPropertyValue(property, v, InputType.Text))" />
|
||||
}
|
||||
|
||||
@foreach (var error in _validationErrors[property.Info.Name]) {
|
||||
@foreach (var error in _validationErrors[property.Name]) {
|
||||
<FluentLabel Color="@Color.Error">@error</FluentLabel>
|
||||
}
|
||||
</div>
|
||||
@@ -197,11 +197,16 @@
|
||||
Content.CurrentObject ??= Activator.CreateInstance(Content.Config.TableType);
|
||||
|
||||
foreach (var property in Content.Config.Properties) {
|
||||
if (property.IsListingProperty) continue;
|
||||
_validationErrors.Add(property.Info.Name, []);
|
||||
_validationErrors.Add(property.Name, []);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<PropertyConfig> GetEditorProperties() {
|
||||
return Content.Config.Properties
|
||||
.Where(prop => prop is not VirtualPropertyConfig { VirtualParser: null })
|
||||
.OrderBy(prop => prop.Order);
|
||||
}
|
||||
|
||||
private TValue? GetPropertyValue<TValue>(PropertyConfig config, object? listItem = null) {
|
||||
if (!config.DisplayValue) return default;
|
||||
if (Content.CurrentObject is null) return default;
|
||||
@@ -315,12 +320,12 @@
|
||||
private void ApplyChanges(object entry) {
|
||||
foreach (var prop in Content.Config.Properties) {
|
||||
var newValue = GetNewestValue(prop);
|
||||
prop.Info.SetValue(entry, newValue);
|
||||
prop.SetValue(entry, newValue, Provider);
|
||||
}
|
||||
}
|
||||
|
||||
private object? GetNewestValue(PropertyConfig config) {
|
||||
var value = config.Info.GetValue(Content.CurrentObject);
|
||||
var value = config.GetValue(Content.CurrentObject, Provider);
|
||||
|
||||
var change = _changes.LastOrDefault(c => c.Property == config.Info);
|
||||
if (change is not null)
|
||||
@@ -366,9 +371,9 @@
|
||||
return false;
|
||||
|
||||
foreach (var property in Content.Config.Properties) {
|
||||
if (property.IsListingProperty) continue;
|
||||
if (property.IsVirtualProperty) continue;
|
||||
|
||||
var errorList = _validationErrors[property.Info.Name];
|
||||
var errorList = _validationErrors[property.Name];
|
||||
errorList.Clear();
|
||||
var value = GetNewestValue(property);
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@ builder.Services.AddHopFrame(options => {
|
||||
.SetOrderIndex(3);
|
||||
|
||||
table.AddVirtualProperty("Name", (user, _) => $"{user.FirstName} {user.LastName}")
|
||||
/*.SetVirtualParser((model, input, _) => {
|
||||
var split = input.Split(' ');
|
||||
model.FirstName = split.FirstOrDefault();
|
||||
model.LastName = split.LastOrDefault();
|
||||
})*/
|
||||
.SetOrderIndex(2);
|
||||
|
||||
table.SetDisplayName("Benutzer");
|
||||
|
||||
@@ -63,7 +63,7 @@ public class TableConfiguratorTests {
|
||||
var virtualProperty = tableConfig.Properties.SingleOrDefault(p => p.Name == "VirtualName");
|
||||
Assert.NotNull(virtualProperty);
|
||||
Assert.NotNull(propertyConfigurator);
|
||||
Assert.True(virtualProperty.IsListingProperty);
|
||||
Assert.True(virtualProperty.IsVirtualProperty);
|
||||
Assert.Equal("VirtualName", virtualProperty.Name);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class TableConfiguratorTests {
|
||||
var virtualProperty = tableConfig.Properties.SingleOrDefault(p => p.Name == "VirtualName");
|
||||
Assert.NotNull(virtualProperty);
|
||||
Assert.NotNull(propertyConfigurator);
|
||||
Assert.True(virtualProperty.IsListingProperty);
|
||||
Assert.True(virtualProperty.IsVirtualProperty);
|
||||
Assert.Equal("VirtualName", virtualProperty.Name);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class DisplayPropertyTests {
|
||||
// Arrange
|
||||
var item = "test";
|
||||
var prop = new PropertyConfig(typeof(string).GetProperty("Length")!, _config, 0) {
|
||||
IsListingProperty = true,
|
||||
IsVirtualProperty = true,
|
||||
Formatter = (obj, provider) => Task.FromResult(((string)obj).ToUpper())
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user