diff --git a/src/MxGateway.Server/Dashboard/DashboardMxValueFormatter.cs b/src/MxGateway.Server/Dashboard/DashboardMxValueFormatter.cs
index 545fdea..1fde4c1 100644
--- a/src/MxGateway.Server/Dashboard/DashboardMxValueFormatter.cs
+++ b/src/MxGateway.Server/Dashboard/DashboardMxValueFormatter.cs
@@ -10,6 +10,9 @@ namespace MxGateway.Server.Dashboard;
///
public static class DashboardMxValueFormatter
{
+ /// Maximum array elements rendered inline before the value is truncated.
+ private const int MaxArrayElements = 24;
+
/// Formats the value payload of an .
/// The value to format; may be null.
/// A display string — never null.
@@ -37,7 +40,7 @@ public static class DashboardMxValueFormatter
.ToDateTimeOffset()
.UtcDateTime
.ToString("yyyy-MM-dd HH:mm:ss.fff 'UTC'", CultureInfo.InvariantCulture),
- MxValue.KindOneofCase.ArrayValue => "(array)",
+ MxValue.KindOneofCase.ArrayValue => FormatArray(value.ArrayValue),
MxValue.KindOneofCase.RawValue => $"({value.RawValue.Length} bytes)",
_ => "-",
};
@@ -45,9 +48,63 @@ public static class DashboardMxValueFormatter
/// Formats the MXAccess data type of an .
/// The value whose data type to describe; may be null.
- /// The data-type name — never null.
+ /// The data-type name — never null. Arrays render as Element[dims].
public static string FormatDataType(MxValue? value)
{
- return value is null ? "-" : value.DataType.ToString();
+ if (value is null)
+ {
+ return "-";
+ }
+
+ // A scalar carries its type in MxValue.DataType, but an array leaves
+ // that Unspecified and carries the element type on the MxArray itself.
+ return value.KindCase == MxValue.KindOneofCase.ArrayValue
+ ? FormatArrayDataType(value.ArrayValue)
+ : value.DataType.ToString();
+ }
+
+ private static string FormatArrayDataType(MxArray array)
+ {
+ string dimensions = array.Dimensions.Count > 0
+ ? string.Join(",", array.Dimensions)
+ : string.Empty;
+ return $"{array.ElementDataType}[{dimensions}]";
+ }
+
+ private static string FormatArray(MxArray array)
+ {
+ IReadOnlyList elements = array.ValuesCase switch
+ {
+ MxArray.ValuesOneofCase.BoolValues =>
+ array.BoolValues.Values.Select(item => item ? "true" : "false").ToArray(),
+ MxArray.ValuesOneofCase.Int32Values =>
+ array.Int32Values.Values.Select(item => item.ToString(CultureInfo.InvariantCulture)).ToArray(),
+ MxArray.ValuesOneofCase.Int64Values =>
+ array.Int64Values.Values.Select(item => item.ToString(CultureInfo.InvariantCulture)).ToArray(),
+ MxArray.ValuesOneofCase.FloatValues =>
+ array.FloatValues.Values.Select(item => item.ToString("G7", CultureInfo.InvariantCulture)).ToArray(),
+ MxArray.ValuesOneofCase.DoubleValues =>
+ array.DoubleValues.Values.Select(item => item.ToString("G15", CultureInfo.InvariantCulture)).ToArray(),
+ MxArray.ValuesOneofCase.StringValues =>
+ array.StringValues.Values.Select(item => $"\"{item}\"").ToArray(),
+ MxArray.ValuesOneofCase.TimestampValues =>
+ array.TimestampValues.Values
+ .Select(item => item.ToDateTimeOffset().UtcDateTime
+ .ToString("yyyy-MM-dd HH:mm:ss 'UTC'", CultureInfo.InvariantCulture))
+ .ToArray(),
+ MxArray.ValuesOneofCase.RawValues =>
+ array.RawValues.Values.Select(item => $"({item.Length} bytes)").ToArray(),
+ _ => [],
+ };
+
+ if (elements.Count == 0)
+ {
+ return "[]";
+ }
+
+ string body = string.Join(", ", elements.Take(MaxArrayElements));
+ return elements.Count > MaxArrayElements
+ ? $"[{body}, … {elements.Count} total]"
+ : $"[{body}]";
}
}
diff --git a/src/MxGateway.Tests/Gateway/Dashboard/DashboardBrowseAndAlarmModelTests.cs b/src/MxGateway.Tests/Gateway/Dashboard/DashboardBrowseAndAlarmModelTests.cs
index e226f10..88aa7ff 100644
--- a/src/MxGateway.Tests/Gateway/Dashboard/DashboardBrowseAndAlarmModelTests.cs
+++ b/src/MxGateway.Tests/Gateway/Dashboard/DashboardBrowseAndAlarmModelTests.cs
@@ -126,4 +126,17 @@ public sealed class DashboardBrowseAndAlarmModelTests
Assert.True(unackedRow.IsUnacknowledged);
Assert.False(ackedRow.IsUnacknowledged);
}
+
+ [Fact]
+ public void FormatValue_AndDataType_RenderArrayElementsAndElementType()
+ {
+ MxArray array = new() { ElementDataType = MxDataType.Double };
+ array.Dimensions.Add(3u);
+ array.DoubleValues = new DoubleArray();
+ array.DoubleValues.Values.Add(new[] { 1.5, 2.25, 3.0 });
+ MxValue value = new() { ArrayValue = array };
+
+ Assert.Equal("[1.5, 2.25, 3]", DashboardMxValueFormatter.FormatValue(value));
+ Assert.Equal("Double[3]", DashboardMxValueFormatter.FormatDataType(value));
+ }
}