From d025f880b31e55aa3a14289fafea45afbe1e86d5 Mon Sep 17 00:00:00 2001
From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com>
Date: Tue, 17 Mar 2026 15:46:13 +0000
Subject: [PATCH 1/2] Initial plan
From 1928902eecb76b7e20811aba61ebb509100bdce7 Mon Sep 17 00:00:00 2001
From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com>
Date: Tue, 17 Mar 2026 15:54:37 +0000
Subject: [PATCH 2/2] Implement ERP/Inventory hierarchical grid sample
- Add hierarchical data models (Order, OrderDetails, DeliveryDetails, OrderStatus, DataPoint)
- Update InventoryData model to support nested Orders collection
- Update InventoryService to calculate derived fields (UnitsSold, TotalNetProfit)
- Convert ERPInventoryComponent to use IgbHierarchicalGrid with IgbRowIsland
- Add parent grid columns: SKU, Product Name, Category, Rating, Units Sold, Gross Price, Net Price, Net Profit
- Add child grid (IgbRowIsland) showing Order details with collapsible column groups
- Implement Delivery column group (Date Ordered, Date Shipped, Date Delivered)
- Implement Order Information column group (Country, City, Zip Code, Street)
- Add grid toolbar with Hiding and Pinning actions for both grids
- Enable filtering, sorting, and multiple row selection on both grid levels
- Maintain live data updates every 3 seconds
Co-authored-by: dkamburov <1182001+dkamburov@users.noreply.github.com>
---
.../ERPInventoryComponent.razor | 67 ++++++++++++++-----
.../ERPInventory.Library/Models/DataPoint.cs | 9 +++
.../Models/DeliveryDetails.cs | 15 +++++
.../Models/InventoryData.cs | 56 ++++++++--------
.../ERPInventory.Library/Models/Order.cs | 18 +++++
.../Models/OrderDetails.cs | 21 ++++++
.../Models/OrderStatus.cs | 9 +++
.../Services/InventoryService.cs | 24 ++++---
8 files changed, 165 insertions(+), 54 deletions(-)
create mode 100644 src/samples/ERPInventory.Library/Models/DataPoint.cs
create mode 100644 src/samples/ERPInventory.Library/Models/DeliveryDetails.cs
create mode 100644 src/samples/ERPInventory.Library/Models/Order.cs
create mode 100644 src/samples/ERPInventory.Library/Models/OrderDetails.cs
create mode 100644 src/samples/ERPInventory.Library/Models/OrderStatus.cs
diff --git a/src/samples/ERPInventory.Library/ERPInventoryComponent.razor b/src/samples/ERPInventory.Library/ERPInventoryComponent.razor
index 81f9afd..7446325 100644
--- a/src/samples/ERPInventory.Library/ERPInventoryComponent.razor
+++ b/src/samples/ERPInventory.Library/ERPInventoryComponent.razor
@@ -22,22 +22,55 @@
}
else
{
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Inventory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sales data for the last month
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Data updates every 3 seconds to simulate live inventory data
@@ -49,7 +82,7 @@
@code {
private bool isLoading = true;
private System.Timers.Timer? updateTimer;
- private IgbGrid? grid;
+ private IgbHierarchicalGrid? grid;
protected override async Task OnInitializedAsync()
{
diff --git a/src/samples/ERPInventory.Library/Models/DataPoint.cs b/src/samples/ERPInventory.Library/Models/DataPoint.cs
new file mode 100644
index 0000000..82dbd0a
--- /dev/null
+++ b/src/samples/ERPInventory.Library/Models/DataPoint.cs
@@ -0,0 +1,9 @@
+using System.Text.Json.Serialization;
+
+namespace ERPInventory.Library.Models;
+
+public class DataPoint
+{
+ [JsonPropertyName("unitsSold")]
+ public int UnitsSold { get; set; }
+}
diff --git a/src/samples/ERPInventory.Library/Models/DeliveryDetails.cs b/src/samples/ERPInventory.Library/Models/DeliveryDetails.cs
new file mode 100644
index 0000000..ab716bf
--- /dev/null
+++ b/src/samples/ERPInventory.Library/Models/DeliveryDetails.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+
+namespace ERPInventory.Library.Models;
+
+public class DeliveryDetails
+{
+ [JsonPropertyName("dateOrdered")]
+ public string? DateOrdered { get; set; }
+
+ [JsonPropertyName("dateShipped")]
+ public string? DateShipped { get; set; }
+
+ [JsonPropertyName("dateDelivered")]
+ public string? DateDelivered { get; set; }
+}
diff --git a/src/samples/ERPInventory.Library/Models/InventoryData.cs b/src/samples/ERPInventory.Library/Models/InventoryData.cs
index 00805dc..4d385b9 100644
--- a/src/samples/ERPInventory.Library/Models/InventoryData.cs
+++ b/src/samples/ERPInventory.Library/Models/InventoryData.cs
@@ -4,36 +4,36 @@ namespace ERPInventory.Library.Models;
public class InventoryData
{
- [JsonPropertyName("id")]
- public string? Id { get; set; }
-
+ [JsonPropertyName("sku")]
+ public string? Sku { get; set; }
+
+ [JsonPropertyName("imageUrl")]
+ public string? ImageUrl { get; set; }
+
[JsonPropertyName("productName")]
public string? ProductName { get; set; }
-
+
[JsonPropertyName("category")]
public string? Category { get; set; }
-
- [JsonPropertyName("sku")]
- public string? Sku { get; set; }
-
- [JsonPropertyName("quantity")]
- public int Quantity { get; set; }
-
- [JsonPropertyName("unitPrice")]
- public double UnitPrice { get; set; }
-
- [JsonPropertyName("totalValue")]
- public double TotalValue { get; set; }
-
- [JsonPropertyName("supplier")]
- public string? Supplier { get; set; }
-
- [JsonPropertyName("warehouse")]
- public string? Warehouse { get; set; }
-
- [JsonPropertyName("status")]
- public string? Status { get; set; }
-
- [JsonPropertyName("lastUpdated")]
- public DateTime LastUpdated { get; set; }
+
+ [JsonPropertyName("rating")]
+ public double Rating { get; set; }
+
+ [JsonPropertyName("unitsSold")]
+ public int UnitsSold { get; set; }
+
+ [JsonPropertyName("grossPrice")]
+ public double GrossPrice { get; set; }
+
+ [JsonPropertyName("netPrice")]
+ public double NetPrice { get; set; }
+
+ [JsonPropertyName("totalNetProfit")]
+ public double TotalNetProfit { get; set; }
+
+ [JsonPropertyName("salesTrendData")]
+ public List SalesTrendData { get; set; } = new();
+
+ [JsonPropertyName("orders")]
+ public List Orders { get; set; } = new();
}
diff --git a/src/samples/ERPInventory.Library/Models/Order.cs b/src/samples/ERPInventory.Library/Models/Order.cs
new file mode 100644
index 0000000..23da2e6
--- /dev/null
+++ b/src/samples/ERPInventory.Library/Models/Order.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace ERPInventory.Library.Models;
+
+public class Order
+{
+ [JsonPropertyName("orderId")]
+ public int OrderId { get; set; }
+
+ [JsonPropertyName("status")]
+ public string? Status { get; set; }
+
+ [JsonPropertyName("delivery")]
+ public DeliveryDetails Delivery { get; set; } = new();
+
+ [JsonPropertyName("orderInformation")]
+ public OrderDetails OrderInformation { get; set; } = new();
+}
diff --git a/src/samples/ERPInventory.Library/Models/OrderDetails.cs b/src/samples/ERPInventory.Library/Models/OrderDetails.cs
new file mode 100644
index 0000000..e560245
--- /dev/null
+++ b/src/samples/ERPInventory.Library/Models/OrderDetails.cs
@@ -0,0 +1,21 @@
+using System.Text.Json.Serialization;
+
+namespace ERPInventory.Library.Models;
+
+public class OrderDetails
+{
+ [JsonPropertyName("country")]
+ public string? Country { get; set; }
+
+ [JsonPropertyName("city")]
+ public string? City { get; set; }
+
+ [JsonPropertyName("zipCode")]
+ public int ZipCode { get; set; }
+
+ [JsonPropertyName("streetName")]
+ public string? StreetName { get; set; }
+
+ [JsonPropertyName("streetNumber")]
+ public string? StreetNumber { get; set; }
+}
diff --git a/src/samples/ERPInventory.Library/Models/OrderStatus.cs b/src/samples/ERPInventory.Library/Models/OrderStatus.cs
new file mode 100644
index 0000000..acddd39
--- /dev/null
+++ b/src/samples/ERPInventory.Library/Models/OrderStatus.cs
@@ -0,0 +1,9 @@
+namespace ERPInventory.Library.Models;
+
+public static class OrderStatus
+{
+ public const string Packed = "Packed";
+ public const string InTransit = "In Transit";
+ public const string Customs = "Customs";
+ public const string Delivered = "Delivered";
+}
diff --git a/src/samples/ERPInventory.Library/Services/InventoryService.cs b/src/samples/ERPInventory.Library/Services/InventoryService.cs
index f58d43b..5d1c9fc 100644
--- a/src/samples/ERPInventory.Library/Services/InventoryService.cs
+++ b/src/samples/ERPInventory.Library/Services/InventoryService.cs
@@ -27,11 +27,18 @@ public async Task LoadDataAsync()
{
var jsonText = await _httpClient.GetStringAsync(DataUrl);
Data = JsonSerializer.Deserialize>(jsonText, options) ?? new();
-
+
// Calculate derived fields
foreach (var record in Data)
{
- record.TotalValue = Math.Round(record.Quantity * record.UnitPrice, 2);
+ // Set unitsSold from last month's sales data
+ if (record.SalesTrendData.Count > 0)
+ {
+ record.UnitsSold = record.SalesTrendData[^1].UnitsSold;
+ }
+
+ // Calculate totalNetProfit
+ record.TotalNetProfit = Math.Round(record.UnitsSold * record.NetPrice, 2);
}
OnDataChanged?.Invoke();
@@ -46,7 +53,7 @@ public void UpdateAllData()
{
foreach (var dataRow in Data)
{
- // Simulate live data updates - randomly adjust quantity
+ // Simulate live data updates - randomly adjust units sold
var volatility = 0.05;
var rnd = Math.Round(Random.Shared.NextDouble(), 2);
var changePercent = 2 * volatility * rnd;
@@ -55,12 +62,11 @@ public void UpdateAllData()
changePercent -= 2 * volatility;
}
- var changeAmount = dataRow.Quantity * changePercent;
- var newQuantity = dataRow.Quantity + (int)Math.Round(changeAmount);
- dataRow.Quantity = Math.Max(0, newQuantity);
-
- dataRow.TotalValue = Math.Round(dataRow.Quantity * dataRow.UnitPrice, 2);
- dataRow.LastUpdated = DateTime.Now;
+ var changeAmount = dataRow.UnitsSold * changePercent;
+ var newUnitsSold = dataRow.UnitsSold + (int)Math.Round(changeAmount);
+ dataRow.UnitsSold = Math.Max(0, newUnitsSold);
+
+ dataRow.TotalNetProfit = Math.Round(dataRow.UnitsSold * dataRow.NetPrice, 2);
}
OnDataChanged?.Invoke();