diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/App.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/App.razor
index 19ad36db..9961b138 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/App.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/App.razor
@@ -24,16 +24,17 @@
{
try
{
- //Route to the component that contains the QR
- if (args.Path == "mudbarcode" || args.Path == "api")
- {
- var assemblies = await AssemblyLoader
- .LoadAssembliesAsync(new[]
- {
- "zxing.dll",
- });
- _lazyLoadedAssemblies.AddRange(assemblies);
- }
+ //Route to the component that contains the lazy load components
+ // if (args.Path == "mudbarcode" || args.Path == "api")
+ // {
+ // var assemblies = await AssemblyLoader
+ // .LoadAssembliesAsync(new[]
+ // {
+ // "CodeBeam.MudBlazor.Extensions.Qr.dll",
+ // "CodeBeam.MudBlazor.Extensions.CsvMapper.dll"
+ // });
+ // _lazyLoadedAssemblies.AddRange(assemblies);
+ // }
}
catch (Exception ex)
{
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/CodeBeam.MudBlazor.Extensions.Docs.Wasm.csproj b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/CodeBeam.MudBlazor.Extensions.Docs.Wasm.csproj
index c2bc9a4b..6840a4bd 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/CodeBeam.MudBlazor.Extensions.Docs.Wasm.csproj
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/CodeBeam.MudBlazor.Extensions.Docs.Wasm.csproj
@@ -1,25 +1,21 @@
-
- net10.0
- enable
- enable
- MudExtensions.Docs.Wasm
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ net10.0
+ enable
+ enable
+ MudExtensions.Docs.Wasm
+
+
+
+
+
+
+
+
+
+
+
@@ -35,10 +31,10 @@
-
- true
- PreserveNewest
-
-
+
+ true
+ PreserveNewest
+
+
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.Qr.xml b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.Qr.xml
new file mode 100644
index 00000000..dc7a14c0
--- /dev/null
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/CodeBeam.MudBlazor.Extensions.Qr.xml
@@ -0,0 +1,146 @@
+
+
+
+ CodeBeam.MudBlazor.Extensions.Qr
+
+
+
+
+ The result that used in MudBarcode component to show one of the barcode formats.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Determines which barcode format will shown. Default is QR Code.
+
+
+
+
+ The outer div classname.
+
+
+
+
+ The outer div classname.
+
+
+
+
+ The image source shows when the value is null.
+
+
+
+
+ If true, it goes to specified href when click.
+
+
+
+
+ The error content.
+
+
+
+
+ The width value as integer.
+
+
+
+
+ The height value as integer.
+
+
+
+
+ Use this value on not square sized barcode formats like UPC_A and UPC_E.
+
+
+
+
+ Increase the stroke width if readers can not read the barcode easily.
+
+
+
+
+ Determines how user go to href content. Default is open in a new tab.
+
+
+
+
+ The value of the barcode format.
+
+
+
+
+ The color of the barcode as string. Accepts all kinds of CSS property values. (ex. #123456) Default is "black".
+
+
+
+
+ The background color of the barcode as string. Accepts all kinds of CSS property values. (ex. #123456) Default is "white".
+
+
+
+
+ Fires when value changed.
+
+
+
+
+ Shows a component inside the barcode.
+
+
+
+
+ Barcode process that returns BarcodeResult. Returns null if value is also null or empty.
+
+
+
+
+
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Components/DocsApiTable.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Components/DocsApiTable.razor
index 4d9ff7b8..a7704863 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Components/DocsApiTable.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Components/DocsApiTable.razor
@@ -22,7 +22,7 @@
@value
- @(_docReader?.GetSummary(context) ?? "—")
+ @(GetDocReaderFor(context.DeclaringType!)?.GetSummary(context) ?? "—")
@@ -40,7 +40,7 @@
@context.Name
@DocUtilities.GetFriendlyTypeName(context.PropertyType)
- @(_docReader?.GetSummary(context) ?? "—")
+ @(GetDocReaderFor(context.DeclaringType!)?.GetSummary(context) ?? "—")
No specific items.
@@ -57,7 +57,7 @@
@context.Name
@DocUtilities.GetFriendlyTypeName(context.ReturnType)
- @(_docReader?.GetSummary(context) ?? "—")
+ @(GetDocReaderFor(context.DeclaringType!)?.GetSummary(context) ?? "—")
No specific items.
@@ -79,7 +79,8 @@
[Parameter] public Type? Type { get; set; }
[Parameter] public MudExtensionComponentInfo? Component { get; set; }
- private SimpleXmlDocReader? _docReader;
+ // private SimpleXmlDocReader? _docReader;
+ private readonly Dictionary _docReaders = new();
private List _excludedMethods = new()
{
@@ -122,24 +123,55 @@
}
}
- protected override async Task OnInitializedAsync()
+ private SimpleXmlDocReader? GetDocReaderFor(Type memberType)
{
- string? xmlContent = null;
+ var asmName = memberType.Assembly.GetName().Name;
- if (OperatingSystem.IsBrowser())
+ return asmName switch
{
- xmlContent = await Http.GetStringAsync("CodeBeam.MudBlazor.Extensions.xml");
- }
- else
+ "CodeBeam.MudBlazor.Extensions" => _docReaders.GetValueOrDefault("CodeBeam.MudBlazor.Extensions.xml"),
+ "CodeBeam.MudBlazor.Extensions.Qr" => _docReaders.GetValueOrDefault("CodeBeam.MudBlazor.Extensions.Qr.xml"),
+ "CodeBeam.MudBlazor.Extensions.CsvMapper" => _docReaders.GetValueOrDefault("CodeBeam.MudBlazor.Extensions.CsvMapper.xml"),
+ _ => null
+ };
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ var xmlFiles = new[]
{
- var xmlPath = Path.Combine(AppContext.BaseDirectory, "CodeBeam.MudBlazor.Extensions.xml");
- if (File.Exists(xmlPath))
- xmlContent = await File.ReadAllTextAsync(xmlPath);
- }
+ "CodeBeam.MudBlazor.Extensions.xml",
+ "CodeBeam.MudBlazor.Extensions.Qr.xml",
+ "CodeBeam.MudBlazor.Extensions.CsvMapper.xml"
+ };
- if (!string.IsNullOrEmpty(xmlContent))
+ foreach (var file in xmlFiles)
{
- _docReader = new SimpleXmlDocReader(xmlContent);
+ string? xmlContent = null;
+
+ try
+ {
+ if (OperatingSystem.IsBrowser())
+ {
+ xmlContent = await Http.GetStringAsync(file);
+ }
+ else
+ {
+ var xmlPath = Path.Combine(AppContext.BaseDirectory, file);
+ if (File.Exists(xmlPath))
+ xmlContent = await File.ReadAllTextAsync(xmlPath);
+ }
+
+ if (!string.IsNullOrWhiteSpace(xmlContent))
+ {
+ _docReaders[file] = new SimpleXmlDocReader(xmlContent);
+ }
+ }
+ catch
+ {
+
+ }
}
}
+
}
diff --git a/src/CodeBeam.MudBlazor.Extensions.CsvMapper/CodeBeam.MudBlazor.Extensions.CsvMapper.csproj b/src/CodeBeam.MudBlazor.Extensions.CsvMapper/CodeBeam.MudBlazor.Extensions.CsvMapper.csproj
index 3ec6f317..c1019f25 100644
--- a/src/CodeBeam.MudBlazor.Extensions.CsvMapper/CodeBeam.MudBlazor.Extensions.CsvMapper.csproj
+++ b/src/CodeBeam.MudBlazor.Extensions.CsvMapper/CodeBeam.MudBlazor.Extensions.CsvMapper.csproj
@@ -5,7 +5,7 @@
enable
enable
MIT
- 1.0.0
+ 9.0.0-preview.1
CodeBeam.MudBlazor.Extensions.Csv
CodeBeam
CodeBeam
@@ -20,10 +20,11 @@
https://github.com/CodeBeamOrg/CodeBeam.MudBlazor.Extensions
Blazor; MudBlazor; Component; Extension; Csv; Mapper;
MudExtensions
+ True
-
+
diff --git a/src/CodeBeam.MudBlazor.Extensions.CsvMapper/Components/CsvMapper/MudCsvMapper.razor.cs b/src/CodeBeam.MudBlazor.Extensions.CsvMapper/Components/CsvMapper/MudCsvMapper.razor.cs
index b10bc88a..98bbb3a6 100644
--- a/src/CodeBeam.MudBlazor.Extensions.CsvMapper/Components/CsvMapper/MudCsvMapper.razor.cs
+++ b/src/CodeBeam.MudBlazor.Extensions.CsvMapper/Components/CsvMapper/MudCsvMapper.razor.cs
@@ -1,5 +1,4 @@
-using System.ComponentModel;
-using CsvHelper;
+using CsvHelper;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using MudBlazor;
@@ -11,9 +10,19 @@
namespace MudExtensions
{
- internal class ConfirmedDefaultValue
+ ///
+ ///
+ ///
+ public class ConfirmedDefaultValue
{
+ ///
+ ///
+ ///
public string? DefaultValue { get; set; }
+
+ ///
+ ///
+ ///
public bool Confirmed { get; set; }
}
@@ -315,7 +324,7 @@ private async Task OnImport()
await using (var csv = new CsvWriter(writer, config))
{
var dynamicContent = CsvContent?.Cast();
- await csv.WriteRecordsAsync(dynamicContent);
+ await csv.WriteRecordsAsync(dynamicContent ?? Enumerable.Empty());
var str = writer.ToString();
FileContentByte = Encoding.UTF8.GetBytes(str);
diff --git a/src/CodeBeam.MudBlazor.Extensions.Qr/CodeBeam.MudBlazor.Extensions.Qr.csproj b/src/CodeBeam.MudBlazor.Extensions.Qr/CodeBeam.MudBlazor.Extensions.Qr.csproj
index 13fdff1c..24d16b21 100644
--- a/src/CodeBeam.MudBlazor.Extensions.Qr/CodeBeam.MudBlazor.Extensions.Qr.csproj
+++ b/src/CodeBeam.MudBlazor.Extensions.Qr/CodeBeam.MudBlazor.Extensions.Qr.csproj
@@ -5,7 +5,7 @@
enable
enable
MIT
- 1.0.0
+ 9.0.0-preview.1
CodeBeam.MudBlazor.Extensions.Qr
CodeBeam
CodeBeam
@@ -30,7 +30,7 @@
-
+
@@ -39,16 +39,6 @@
-
-
-
-
-
-
-
-
-
-
True
diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/CsvMapperTests.cs b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/CsvMapperTests.cs
new file mode 100644
index 00000000..4688c947
--- /dev/null
+++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/CsvMapperTests.cs
@@ -0,0 +1,188 @@
+using AwesomeAssertions;
+using Bunit;
+using System.Reflection;
+
+namespace MudExtensions.UnitTests.Components
+{
+ [TestFixture]
+ public class CsvMapperTests : BunitTest
+ {
+ [Test]
+ public void MudCsvMapper_Should_Render_With_Minimal_Parameters()
+ {
+ var expectedHeaders = new List
+ {
+ new("Id", required: true),
+ new("Name"),
+ };
+
+ var cut = Context.Render(parameters => parameters.Add(p => p.ExpectedHeaders, expectedHeaders));
+
+ cut.Markup.Should().NotBeNullOrWhiteSpace();
+ cut.FindAll("input").Count.Should().BeGreaterThan(0);
+ }
+
+ [Test]
+ public void MudCsvMapper_Should_Render_With_AllowCreateExpectedHeaders()
+ {
+ var cut = Context.Render(parameters => parameters
+ .Add(p => p.AllowCreateExpectedHeaders, true)
+ .Add(p => p.ExpectedHeaders, new List())
+ );
+
+ cut.Markup.Should().Contain("Create Header");
+ }
+
+ [Test]
+ public void CsvHeaders_Should_Match_ExpectedHeaders_Exactly()
+ {
+ // Arrange
+ var expectedHeaders = new List
+ {
+ new("Id", required: true),
+ new("Name", required: false)
+ };
+
+ var cut = Context.Render(p => p
+ .Add(x => x.ExpectedHeaders, expectedHeaders)
+ );
+
+ var csvContent = new List>
+ {
+ new Dictionary
+ {
+ ["Id"] = 1,
+ ["Name"] = "Test"
+ }
+ };
+
+ cut.Instance.GetType()
+ .GetField("CsvContent", BindingFlags.NonPublic | BindingFlags.Instance)!
+ .SetValue(cut.Instance, csvContent);
+
+ InvokePrivate(cut.Instance, "MatchCsvHeadersWithExpectedHeaders");
+
+ expectedHeaders[0].MatchedFieldCount.Should().Be(1);
+ expectedHeaders[1].MatchedFieldCount.Should().Be(1);
+ }
+
+ [Test]
+ public void Normalize_Should_Lowercase_And_Remove_Spaces_When_Enabled()
+ {
+ var cut = Context.Render(p => p
+ .Add(x => x.NormalizeHeaders, true)
+ );
+
+ var result = cut.Instance.GetType()
+ .GetMethod("Normalize", BindingFlags.NonPublic | BindingFlags.Instance)!
+ .Invoke(cut.Instance, new object[] { "My Header \"Name\"" });
+
+ result.Should().Be("myheadername");
+ }
+
+ [Test]
+ public void AddDefaultValues_Should_Add_Confirmed_Defaults()
+ {
+ var expectedHeaders = new List
+ {
+ new("Age", required: true, allowDefaultValue: true)
+ };
+
+ var cut = Context.Render(p => p
+ .Add(x => x.ExpectedHeaders, expectedHeaders)
+ );
+
+ var csvContent = new List>
+ {
+ new Dictionary()
+ };
+
+ SetPrivateMember(cut.Instance, "CsvContent", csvContent);
+
+ var defaults = new Dictionary
+ {
+ ["Age"] = new ConfirmedDefaultValue
+ {
+ Confirmed = true,
+ DefaultValue = "18"
+ }
+ };
+
+ SetPrivateMember(cut.Instance, "_defaultValueHeaders", defaults);
+
+ InvokePrivate(cut.Instance, "AddDefaultValues");
+
+ csvContent[0].ContainsKey("Age").Should().BeTrue();
+ csvContent[0]["Age"].Should().Be("18");
+ }
+
+
+ [Test]
+ public void RemoveUnmappedData_Should_Remove_Unmapped_Fields()
+ {
+ var cut = Context.Render();
+
+ var headers = new List
+ {
+ new("A", "File"),
+ new("B", "Mapped")
+ };
+
+ SetPrivateMember(cut.Instance, "MudCsvHeaders", headers);
+
+ var csvContent = new List>
+ {
+ new Dictionary
+ {
+ ["A"] = 1,
+ ["B"] = 2
+ }
+ };
+
+ SetPrivateMember(cut.Instance, "CsvContent", csvContent);
+
+ InvokePrivate(cut.Instance, "RemoveUnmappedData");
+
+ csvContent[0].ContainsKey("A").Should().BeFalse();
+ csvContent[0].ContainsKey("B").Should().BeTrue();
+ }
+
+
+
+
+ private static void InvokePrivate(object instance, string methodName)
+ {
+ var method = instance.GetType()
+ .GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
+
+ method.Should().NotBeNull();
+ method!.Invoke(instance, null);
+ }
+
+ private static void SetPrivateMember(object instance, string name, object value)
+ {
+ var type = instance.GetType();
+
+ var prop = type.GetProperty(name,
+ BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (prop != null)
+ {
+ prop.SetValue(instance, value);
+ return;
+ }
+
+ var field = type.GetField(name,
+ BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (field != null)
+ {
+ field.SetValue(instance, value);
+ return;
+ }
+
+ Assert.Fail($"Private member '{name}' not found on {type.Name}");
+ }
+
+ }
+}