Added nodes related to the list and array operations
Some checks failed
Build / build (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
This commit is contained in:
@@ -49,6 +49,9 @@ namespace Nodify.Calculator
|
|||||||
|
|
||||||
// Dynamic Parse Json node: adapt input to match source
|
// Dynamic Parse Json node: adapt input to match source
|
||||||
if (!IsLoading) HandleParseJsonNodeConnected(c);
|
if (!IsLoading) HandleParseJsonNodeConnected(c);
|
||||||
|
|
||||||
|
// Dynamic List nodes: adapt connectors based on connected list type
|
||||||
|
if (!IsLoading) HandleListNodeConnected(c);
|
||||||
})
|
})
|
||||||
.WhenRemoved(c =>
|
.WhenRemoved(c =>
|
||||||
{
|
{
|
||||||
@@ -87,6 +90,9 @@ namespace Nodify.Calculator
|
|||||||
|
|
||||||
// Dynamic Parse Json node: reset input on disconnect
|
// Dynamic Parse Json node: reset input on disconnect
|
||||||
HandleParseJsonNodeDisconnected(c);
|
HandleParseJsonNodeDisconnected(c);
|
||||||
|
|
||||||
|
// Dynamic List nodes: reset on disconnect
|
||||||
|
HandleListNodeDisconnected(c);
|
||||||
});
|
});
|
||||||
|
|
||||||
Operations.WhenAdded(x =>
|
Operations.WhenAdded(x =>
|
||||||
@@ -211,7 +217,16 @@ namespace Nodify.Calculator
|
|||||||
// If either side has no DataType set, allow connection (generic/untyped connector)
|
// If either side has no DataType set, allow connection (generic/untyped connector)
|
||||||
if (string.IsNullOrEmpty(sourceType) || string.IsNullOrEmpty(targetType))
|
if (string.IsNullOrEmpty(sourceType) || string.IsNullOrEmpty(targetType))
|
||||||
return true;
|
return true;
|
||||||
return string.Equals(sourceType, targetType, System.StringComparison.OrdinalIgnoreCase);
|
if (string.Equals(sourceType, targetType, System.StringComparison.OrdinalIgnoreCase))
|
||||||
|
return true;
|
||||||
|
// Generic "list" is compatible with any List<T> or array type
|
||||||
|
var s = sourceType.ToLower();
|
||||||
|
var t = targetType.ToLower();
|
||||||
|
if (s == "list" && (t.StartsWith("list<") || t.EndsWith("[]")))
|
||||||
|
return true;
|
||||||
|
if (t == "list" && (s.StartsWith("list<") || s.EndsWith("[]")))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsTakeListBlockedConnection(ConnectorViewModel source, ConnectorViewModel target)
|
private static bool IsTakeListBlockedConnection(ConnectorViewModel source, ConnectorViewModel target)
|
||||||
@@ -957,6 +972,178 @@ namespace Nodify.Calculator
|
|||||||
parseInput.ConnectorColor = System.Drawing.Color.White;
|
parseInput.ConnectorColor = System.Drawing.Color.White;
|
||||||
parseInput.DataType = string.Empty;
|
parseInput.DataType = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly SystemOperations[] _listOps = new[]
|
||||||
|
{
|
||||||
|
SystemOperations.LIST_ADD, SystemOperations.LIST_REMOVE, SystemOperations.LIST_UPDATE,
|
||||||
|
SystemOperations.LIST_GET, SystemOperations.LIST_COUNT, SystemOperations.LIST_CONTAINS,
|
||||||
|
SystemOperations.LIST_CLEAR
|
||||||
|
};
|
||||||
|
|
||||||
|
private static bool IsListNode(OperationViewModel op, out SystemOperationViewModel sysVm)
|
||||||
|
{
|
||||||
|
sysVm = op as SystemOperationViewModel;
|
||||||
|
return sysVm != null && _listOps.Contains(sysVm.SystemOperationType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleListNodeConnected(ConnectionViewModel c)
|
||||||
|
{
|
||||||
|
// Find the list node's Grid (List) input that was just connected
|
||||||
|
ConnectorViewModel listInput = null;
|
||||||
|
ConnectorViewModel sourceConnector = null;
|
||||||
|
|
||||||
|
if (c.Input.Shape == ConnectorShape.Grid && c.Input.IsInput && IsListNode(c.Input.Operation, out _))
|
||||||
|
{
|
||||||
|
listInput = c.Input;
|
||||||
|
sourceConnector = c.Output;
|
||||||
|
}
|
||||||
|
else if (c.Output.Shape == ConnectorShape.Grid && c.Output.IsInput && IsListNode(c.Output.Operation, out _))
|
||||||
|
{
|
||||||
|
listInput = c.Output;
|
||||||
|
sourceConnector = c.Input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listInput == null || sourceConnector == null) return;
|
||||||
|
|
||||||
|
if (!IsListNode(listInput.Operation, out var sysVm)) return;
|
||||||
|
|
||||||
|
// Determine the full list type and element type from the source
|
||||||
|
var sourceDataType = sourceConnector.DataType ?? "";
|
||||||
|
string elementType;
|
||||||
|
string listType;
|
||||||
|
if (sourceDataType.StartsWith("List<") && sourceDataType.EndsWith(">"))
|
||||||
|
{
|
||||||
|
elementType = sourceDataType.Substring(5, sourceDataType.Length - 6);
|
||||||
|
listType = sourceDataType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elementType = "object";
|
||||||
|
listType = sourceDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapt the List input connector
|
||||||
|
listInput.Title = $"List ({listType})";
|
||||||
|
listInput.ConnectorColor = sourceConnector.RawColor;
|
||||||
|
listInput.DataType = sourceDataType;
|
||||||
|
|
||||||
|
// Adapt all List output connectors (Grid shape)
|
||||||
|
foreach (var outConn in listInput.Operation.Output.Where(o => o.Shape == ConnectorShape.Grid))
|
||||||
|
{
|
||||||
|
outConn.Title = listType;
|
||||||
|
outConn.ConnectorColor = sourceConnector.RawColor;
|
||||||
|
outConn.DataType = sourceDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine element connector properties
|
||||||
|
var primitiveTypes = new[] { "string", "int", "double", "bool", "float", "decimal", "long", "object", "datetime" };
|
||||||
|
bool isModel = !primitiveTypes.Contains(elementType.ToLower())
|
||||||
|
&& File.Exists(Path.Combine(ProjectManager.ProjectDirectory, "CustomModels", $"{elementType}.cs"));
|
||||||
|
|
||||||
|
var elemShape = isModel ? ConnectorShape.Square : ConnectorShape.Circle;
|
||||||
|
var elemColor = isModel ? System.Drawing.Color.FromArgb(255, 150, 80, 220) : ConnectorViewModel.GetColorForType(elementType);
|
||||||
|
|
||||||
|
// Adapt Item input connectors (IsCopyConnector ones) for Add/Update/Contains
|
||||||
|
foreach (var itemConn in listInput.Operation.Input.Where(i => i.IsCopyConnector))
|
||||||
|
{
|
||||||
|
itemConn.Title = $"Item ({elementType})";
|
||||||
|
itemConn.Shape = elemShape;
|
||||||
|
itemConn.ConnectorColor = elemColor;
|
||||||
|
itemConn.DataType = elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapt Item output connector for List Get
|
||||||
|
if (sysVm.SystemOperationType == SystemOperations.LIST_GET)
|
||||||
|
{
|
||||||
|
var itemOut = listInput.Operation.Output.FirstOrDefault(o => o.Shape != ConnectorShape.Triangle && o.Shape != ConnectorShape.Grid);
|
||||||
|
if (itemOut != null)
|
||||||
|
{
|
||||||
|
itemOut.Title = elementType;
|
||||||
|
itemOut.Shape = elemShape;
|
||||||
|
itemOut.ConnectorColor = elemColor;
|
||||||
|
itemOut.DataType = elementType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update node title
|
||||||
|
var baseTitle = sysVm.SystemOperationType switch
|
||||||
|
{
|
||||||
|
SystemOperations.LIST_ADD => "List Add",
|
||||||
|
SystemOperations.LIST_REMOVE => "List Remove",
|
||||||
|
SystemOperations.LIST_UPDATE => "List Update",
|
||||||
|
SystemOperations.LIST_GET => "List Get",
|
||||||
|
SystemOperations.LIST_COUNT => "List Count",
|
||||||
|
SystemOperations.LIST_CONTAINS => "List Contains",
|
||||||
|
SystemOperations.LIST_CLEAR => "List Clear",
|
||||||
|
_ => "List"
|
||||||
|
};
|
||||||
|
sysVm.Title = $"{baseTitle} <{elementType}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleListNodeDisconnected(ConnectionViewModel c)
|
||||||
|
{
|
||||||
|
ConnectorViewModel listInput = null;
|
||||||
|
|
||||||
|
if (c.Input.Shape == ConnectorShape.Grid && c.Input.IsInput && IsListNode(c.Input.Operation, out _))
|
||||||
|
listInput = c.Input;
|
||||||
|
else if (c.Output.Shape == ConnectorShape.Grid && c.Output.IsInput && IsListNode(c.Output.Operation, out _))
|
||||||
|
listInput = c.Output;
|
||||||
|
|
||||||
|
if (listInput == null) return;
|
||||||
|
|
||||||
|
var stillConnected = Connections.Any(con => con.Input == listInput || con.Output == listInput);
|
||||||
|
if (stillConnected) return;
|
||||||
|
|
||||||
|
if (!IsListNode(listInput.Operation, out var sysVm)) return;
|
||||||
|
|
||||||
|
// Reset List input
|
||||||
|
listInput.Title = "List";
|
||||||
|
listInput.ConnectorColor = NodeColors.List;
|
||||||
|
listInput.DataType = "list";
|
||||||
|
|
||||||
|
// Reset List outputs
|
||||||
|
foreach (var outConn in listInput.Operation.Output.Where(o => o.Shape == ConnectorShape.Grid))
|
||||||
|
{
|
||||||
|
outConn.Title = "List";
|
||||||
|
outConn.ConnectorColor = NodeColors.List;
|
||||||
|
outConn.DataType = "list";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Item input connectors
|
||||||
|
foreach (var itemConn in listInput.Operation.Input.Where(i => i.IsCopyConnector))
|
||||||
|
{
|
||||||
|
itemConn.Title = "Item";
|
||||||
|
itemConn.Shape = ConnectorShape.Circle;
|
||||||
|
itemConn.ConnectorColor = NodeColors.Universal;
|
||||||
|
itemConn.DataType = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Item output for List Get
|
||||||
|
if (sysVm.SystemOperationType == SystemOperations.LIST_GET)
|
||||||
|
{
|
||||||
|
var itemOut = listInput.Operation.Output.FirstOrDefault(o => o.Shape != ConnectorShape.Triangle && o.Shape != ConnectorShape.Grid);
|
||||||
|
if (itemOut != null)
|
||||||
|
{
|
||||||
|
itemOut.Title = "Item";
|
||||||
|
itemOut.Shape = ConnectorShape.Circle;
|
||||||
|
itemOut.ConnectorColor = NodeColors.Object;
|
||||||
|
itemOut.DataType = "object";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset title
|
||||||
|
sysVm.Title = sysVm.SystemOperationType switch
|
||||||
|
{
|
||||||
|
SystemOperations.LIST_ADD => "List Add",
|
||||||
|
SystemOperations.LIST_REMOVE => "List Remove",
|
||||||
|
SystemOperations.LIST_UPDATE => "List Update",
|
||||||
|
SystemOperations.LIST_GET => "List Get",
|
||||||
|
SystemOperations.LIST_COUNT => "List Count",
|
||||||
|
SystemOperations.LIST_CONTAINS => "List Contains",
|
||||||
|
SystemOperations.LIST_CLEAR => "List Clear",
|
||||||
|
_ => "List"
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -839,6 +839,34 @@
|
|||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
|
<!-- List / Array Nodes -->
|
||||||
|
<TextBlock Text="📋 List / Array" FontWeight="Bold" FontSize="14"
|
||||||
|
Foreground="{DynamicResource ForegroundBrush}" Margin="5 10 0 4" />
|
||||||
|
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.ListNodes}"
|
||||||
|
Focusable="False">
|
||||||
|
<ItemsControl.ItemContainerStyle>
|
||||||
|
<Style>
|
||||||
|
<Setter Property="FrameworkElement.Margin" Value="5" />
|
||||||
|
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Left" />
|
||||||
|
<Setter Property="FrameworkElement.Cursor" Value="Hand" />
|
||||||
|
<Setter Property="FrameworkElement.ToolTip" Value="Drag and drop into the editor" />
|
||||||
|
</Style>
|
||||||
|
</ItemsControl.ItemContainerStyle>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate DataType="{x:Type local:OperationViewModel}">
|
||||||
|
<nodify:Node Content="{Binding Title}"
|
||||||
|
Input="{Binding Input}"
|
||||||
|
Output="{Binding Output}"
|
||||||
|
BorderBrush="{StaticResource AnimatedBrush}"
|
||||||
|
BorderThickness="2"
|
||||||
|
MouseMove="OnNodeDrag"
|
||||||
|
Focusable="True"
|
||||||
|
KeyboardNavigation.TabNavigation="None">
|
||||||
|
</nodify:Node>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
|
||||||
<!-- Grouped Swagger API operations -->
|
<!-- Grouped Swagger API operations -->
|
||||||
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.GroupedSwaggerOperations}"
|
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.GroupedSwaggerOperations}"
|
||||||
Focusable="False">
|
Focusable="False">
|
||||||
|
|||||||
@@ -340,6 +340,108 @@ namespace Nodify.Calculator.Execution.Handlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// List operation execution handlers
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
internal sealed class ListAddExecutionHandler : INodeExecutionHandler
|
||||||
|
{
|
||||||
|
public bool CanHandle(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_ADD;
|
||||||
|
|
||||||
|
public void Execute(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
{
|
||||||
|
var listJson = ListExecHelper.ReadInput(node, ctx, "List");
|
||||||
|
var itemJson = ListExecHelper.ReadInput(node, ctx, "Item");
|
||||||
|
var list = ListExecHelper.ParseList(listJson);
|
||||||
|
list.Add(itemJson != null ? JToken.Parse(itemJson) : JValue.CreateNull());
|
||||||
|
var result = list.ToString(Formatting.None);
|
||||||
|
ctx.Outputs[node.NodeId] = result;
|
||||||
|
ctx.Variables[node.NodeId] = result;
|
||||||
|
ctx.Log($"[List Add] Added item. Count={list.Count}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class ListRemoveExecutionHandler : INodeExecutionHandler
|
||||||
|
{
|
||||||
|
public bool CanHandle(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_REMOVE;
|
||||||
|
|
||||||
|
public void Execute(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
{
|
||||||
|
var listJson = ListExecHelper.ReadInput(node, ctx, "List");
|
||||||
|
var indexStr = ListExecHelper.ReadInput(node, ctx, "Index");
|
||||||
|
var list = ListExecHelper.ParseList(listJson);
|
||||||
|
int index = int.TryParse(indexStr, out var i) ? i : -1;
|
||||||
|
if (index >= 0 && index < list.Count)
|
||||||
|
list.RemoveAt(index);
|
||||||
|
else
|
||||||
|
ctx.Log($"[List Remove] Index {index} out of range (Count={list.Count})", logType.Warning);
|
||||||
|
var result = list.ToString(Formatting.None);
|
||||||
|
ctx.Outputs[node.NodeId] = result;
|
||||||
|
ctx.Variables[node.NodeId] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class ListUpdateExecutionHandler : INodeExecutionHandler
|
||||||
|
{
|
||||||
|
public bool CanHandle(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_UPDATE;
|
||||||
|
|
||||||
|
public void Execute(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
{
|
||||||
|
var listJson = ListExecHelper.ReadInput(node, ctx, "List");
|
||||||
|
var indexStr = ListExecHelper.ReadInput(node, ctx, "Index");
|
||||||
|
var itemJson = ListExecHelper.ReadInput(node, ctx, "Item");
|
||||||
|
var list = ListExecHelper.ParseList(listJson);
|
||||||
|
int index = int.TryParse(indexStr, out var i) ? i : -1;
|
||||||
|
if (index >= 0 && index < list.Count)
|
||||||
|
list[index] = itemJson != null ? JToken.Parse(itemJson) : JValue.CreateNull();
|
||||||
|
else
|
||||||
|
ctx.Log($"[List Update] Index {index} out of range (Count={list.Count})", logType.Warning);
|
||||||
|
var result = list.ToString(Formatting.None);
|
||||||
|
ctx.Outputs[node.NodeId] = result;
|
||||||
|
ctx.Variables[node.NodeId] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class ListClearExecutionHandler : INodeExecutionHandler
|
||||||
|
{
|
||||||
|
public bool CanHandle(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_CLEAR;
|
||||||
|
|
||||||
|
public void Execute(OperationViewModel node, ExecutionContext ctx)
|
||||||
|
{
|
||||||
|
var result = "[]";
|
||||||
|
ctx.Outputs[node.NodeId] = result;
|
||||||
|
ctx.Variables[node.NodeId] = result;
|
||||||
|
ctx.Log("[List Clear] Cleared list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Helper for reading list node inputs and parsing JSON arrays.</summary>
|
||||||
|
internal static class ListExecHelper
|
||||||
|
{
|
||||||
|
public static string ReadInput(OperationViewModel node, ExecutionContext ctx, string title)
|
||||||
|
{
|
||||||
|
var conn = ctx.Connections.FirstOrDefault(c =>
|
||||||
|
c.Input.Operation == node
|
||||||
|
&& (c.Input.Title ?? "").StartsWith(title, StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& c.Input.Shape != ConnectorShape.Triangle);
|
||||||
|
if (conn == null) return null;
|
||||||
|
if (ctx.Outputs.TryGetValue(conn.OutputNodeId, out var val))
|
||||||
|
return val;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JArray ParseList(string json)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(json)) return new JArray();
|
||||||
|
try { return JArray.Parse(json); }
|
||||||
|
catch { return new JArray(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
// Default / fallback: API call
|
// Default / fallback: API call
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -205,4 +205,88 @@ namespace Nodify.Calculator.Execution.Resolvers
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// LIST GET: pick an element by index from a JSON array (non-flow value node).
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
internal sealed class ListGetValueResolver : INodeValueResolver
|
||||||
|
{
|
||||||
|
public bool CanResolve(OperationViewModel node, ConnectorViewModel c)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_GET;
|
||||||
|
|
||||||
|
public string Resolve(OperationViewModel node, ConnectorViewModel outputConnector, IValueResolutionContext ctx)
|
||||||
|
{
|
||||||
|
var listInput = node.Input.FirstOrDefault(i => i.Shape == ConnectorShape.Grid);
|
||||||
|
var indexInput = node.Input.FirstOrDefault(i => (i.Title ?? "").StartsWith("Index", StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (listInput == null) return null;
|
||||||
|
|
||||||
|
var json = ctx.Read(listInput);
|
||||||
|
var indexStr = indexInput != null ? ctx.Read(indexInput) : "0";
|
||||||
|
int index = int.TryParse(indexStr, out var i) ? i : 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var arr = JArray.Parse(json ?? "[]");
|
||||||
|
if (index >= 0 && index < arr.Count)
|
||||||
|
{
|
||||||
|
var item = arr[index];
|
||||||
|
return item.Type == JTokenType.String ? item.ToString() : item.ToString(Formatting.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// LIST COUNT: returns the length of a JSON array as a string integer.
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
internal sealed class ListCountValueResolver : INodeValueResolver
|
||||||
|
{
|
||||||
|
public bool CanResolve(OperationViewModel node, ConnectorViewModel c)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_COUNT;
|
||||||
|
|
||||||
|
public string Resolve(OperationViewModel node, ConnectorViewModel outputConnector, IValueResolutionContext ctx)
|
||||||
|
{
|
||||||
|
var listInput = node.Input.FirstOrDefault(i => i.Shape == ConnectorShape.Grid);
|
||||||
|
if (listInput == null) return "0";
|
||||||
|
|
||||||
|
var json = ctx.Read(listInput);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var arr = JArray.Parse(json ?? "[]");
|
||||||
|
return arr.Count.ToString();
|
||||||
|
}
|
||||||
|
catch { return "0"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// LIST CONTAINS: checks if item exists in array, returns "true"/"false".
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
internal sealed class ListContainsValueResolver : INodeValueResolver
|
||||||
|
{
|
||||||
|
public bool CanResolve(OperationViewModel node, ConnectorViewModel c)
|
||||||
|
=> node is SystemOperationViewModel sys && sys.SystemOperationType == SystemOperations.LIST_CONTAINS;
|
||||||
|
|
||||||
|
public string Resolve(OperationViewModel node, ConnectorViewModel outputConnector, IValueResolutionContext ctx)
|
||||||
|
{
|
||||||
|
var listInput = node.Input.FirstOrDefault(i => i.Shape == ConnectorShape.Grid);
|
||||||
|
var itemInput = node.Input.FirstOrDefault(i => i.IsCopyConnector);
|
||||||
|
if (listInput == null) return "false";
|
||||||
|
|
||||||
|
var json = ctx.Read(listInput);
|
||||||
|
var itemJson = itemInput != null ? ctx.Read(itemInput) : null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var arr = JArray.Parse(json ?? "[]");
|
||||||
|
if (string.IsNullOrEmpty(itemJson)) return "false";
|
||||||
|
var searchToken = JToken.Parse(itemJson);
|
||||||
|
bool found = arr.Any(t => JToken.DeepEquals(t, searchToken));
|
||||||
|
return found.ToString().ToLower();
|
||||||
|
}
|
||||||
|
catch { return "false"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ namespace Nodify.Calculator
|
|||||||
new AssertHandler(),
|
new AssertHandler(),
|
||||||
new ForEachHandler(),
|
new ForEachHandler(),
|
||||||
new FunctionHandler(),
|
new FunctionHandler(),
|
||||||
|
new ListAddExecutionHandler(),
|
||||||
|
new ListRemoveExecutionHandler(),
|
||||||
|
new ListUpdateExecutionHandler(),
|
||||||
|
new ListClearExecutionHandler(),
|
||||||
new ApiRequestHandler(), // default / fallback
|
new ApiRequestHandler(), // default / fallback
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,6 +75,9 @@ namespace Nodify.Calculator
|
|||||||
new KnotNodeValueResolver(),
|
new KnotNodeValueResolver(),
|
||||||
new TakeNodeValueResolver(),
|
new TakeNodeValueResolver(),
|
||||||
new ParseJsonNodeValueResolver(),
|
new ParseJsonNodeValueResolver(),
|
||||||
|
new ListGetValueResolver(),
|
||||||
|
new ListCountValueResolver(),
|
||||||
|
new ListContainsValueResolver(),
|
||||||
new GetVariableNodeValueResolver(),
|
new GetVariableNodeValueResolver(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
251
Examples/Nodify.Calculator/NodeHandlers/ListNodeHandlers.cs
Normal file
251
Examples/Nodify.Calculator/NodeHandlers/ListNodeHandlers.cs
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
using Nodify.Calculator.Models;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Nodify.Calculator.NodeHandlers
|
||||||
|
{
|
||||||
|
// ─── LIST ADD ───
|
||||||
|
public class ListAddHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_ADD;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_ADD);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Add",
|
||||||
|
SystemOperationType = SystemOperations.LIST_ADD
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "Item", Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Universal, IsCopyConnector = true });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "List", IsInput = false, Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_ADD });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_ADD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── LIST REMOVE ───
|
||||||
|
public class ListRemoveHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_REMOVE;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_REMOVE);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Remove",
|
||||||
|
SystemOperationType = SystemOperations.LIST_REMOVE
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "Index", Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Integer, DataType = "int" });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "List", IsInput = false, Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_REMOVE });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_REMOVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── LIST UPDATE ───
|
||||||
|
public class ListUpdateHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_UPDATE;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_UPDATE);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Update",
|
||||||
|
SystemOperationType = SystemOperations.LIST_UPDATE
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "Index", Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Integer, DataType = "int" });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "Item", Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Universal, IsCopyConnector = true });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "List", IsInput = false, Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_UPDATE });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── LIST GET (non-flow, value node) ───
|
||||||
|
public class ListGetHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_GET;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_GET);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Get",
|
||||||
|
SystemOperationType = SystemOperations.LIST_GET
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "Index", Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Integer, DataType = "int" });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "Item", IsInput = false, Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Object, DataType = "object" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_GET });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_GET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── LIST COUNT (non-flow, value node) ───
|
||||||
|
public class ListCountHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_COUNT;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_COUNT);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Count",
|
||||||
|
SystemOperationType = SystemOperations.LIST_COUNT
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "Count", IsInput = false, Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Integer, DataType = "int" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_COUNT });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_COUNT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── LIST CONTAINS (non-flow, value node) ───
|
||||||
|
public class ListContainsHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_CONTAINS;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_CONTAINS);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Contains",
|
||||||
|
SystemOperationType = SystemOperations.LIST_CONTAINS
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "Item", Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Universal, IsCopyConnector = true });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "Result", IsInput = false, Shape = ConnectorShape.Circle, ConnectorColor = NodeColors.Boolean, DataType = "bool" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_CONTAINS });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_CONTAINS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── LIST CLEAR ───
|
||||||
|
public class ListClearHandler : INodeHandler
|
||||||
|
{
|
||||||
|
public string NodeTypeKey => "System";
|
||||||
|
|
||||||
|
public bool CanCreate(OperationInfoViewModel info)
|
||||||
|
=> info.Type == OperationType.System && info.sysOp == SystemOperations.LIST_CLEAR;
|
||||||
|
|
||||||
|
public bool CanRestore(NodeData data)
|
||||||
|
=> data.NodeType == "System" && data.SystemOp == nameof(SystemOperations.LIST_CLEAR);
|
||||||
|
|
||||||
|
public OperationViewModel Create(OperationInfoViewModel info)
|
||||||
|
{
|
||||||
|
var op = new SystemOperationViewModel
|
||||||
|
{
|
||||||
|
Title = info.Title ?? "List Clear",
|
||||||
|
SystemOperationType = SystemOperations.LIST_CLEAR
|
||||||
|
};
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
|
||||||
|
op.Input.Add(new ConnectorViewModel { Title = "List", Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
op.Output.Add(new ConnectorViewModel { Title = "List", IsInput = false, Shape = ConnectorShape.Grid, ConnectorColor = NodeColors.List, DataType = "list" });
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationViewModel Restore(NodeData data)
|
||||||
|
=> Create(new OperationInfoViewModel { Title = data.Title, Type = OperationType.System, sysOp = SystemOperations.LIST_CLEAR });
|
||||||
|
|
||||||
|
public void Save(OperationViewModel vm, NodeData data)
|
||||||
|
{
|
||||||
|
data.NodeType = "System";
|
||||||
|
data.SystemOp = nameof(SystemOperations.LIST_CLEAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,6 +43,13 @@ namespace Nodify.Calculator.NodeHandlers
|
|||||||
_handlers.Add(new CopyHandler());
|
_handlers.Add(new CopyHandler());
|
||||||
_handlers.Add(new SplitHandler());
|
_handlers.Add(new SplitHandler());
|
||||||
_handlers.Add(new ParseJsonHandler());
|
_handlers.Add(new ParseJsonHandler());
|
||||||
|
_handlers.Add(new ListAddHandler());
|
||||||
|
_handlers.Add(new ListRemoveHandler());
|
||||||
|
_handlers.Add(new ListUpdateHandler());
|
||||||
|
_handlers.Add(new ListGetHandler());
|
||||||
|
_handlers.Add(new ListCountHandler());
|
||||||
|
_handlers.Add(new ListContainsHandler());
|
||||||
|
_handlers.Add(new ListClearHandler());
|
||||||
_handlers.Add(new GetSetVariableHandler());
|
_handlers.Add(new GetSetVariableHandler());
|
||||||
_handlers.Add(new GetSetModelHandler());
|
_handlers.Add(new GetSetModelHandler());
|
||||||
_handlers.Add(new BeginEndHandler());
|
_handlers.Add(new BeginEndHandler());
|
||||||
@@ -108,6 +115,13 @@ namespace Nodify.Calculator.NodeHandlers
|
|||||||
SystemOperations.END => _handlers.OfType<BeginEndHandler>().FirstOrDefault(),
|
SystemOperations.END => _handlers.OfType<BeginEndHandler>().FirstOrDefault(),
|
||||||
SystemOperations.GET_SET when sys.IsSimpleVariable => _handlers.OfType<GetSetVariableHandler>().FirstOrDefault(),
|
SystemOperations.GET_SET when sys.IsSimpleVariable => _handlers.OfType<GetSetVariableHandler>().FirstOrDefault(),
|
||||||
SystemOperations.GET_SET => _handlers.OfType<GetSetModelHandler>().FirstOrDefault(),
|
SystemOperations.GET_SET => _handlers.OfType<GetSetModelHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_ADD => _handlers.OfType<ListAddHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_REMOVE => _handlers.OfType<ListRemoveHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_UPDATE => _handlers.OfType<ListUpdateHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_GET => _handlers.OfType<ListGetHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_COUNT => _handlers.OfType<ListCountHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_CONTAINS => _handlers.OfType<ListContainsHandler>().FirstOrDefault(),
|
||||||
|
SystemOperations.LIST_CLEAR => _handlers.OfType<ListClearHandler>().FirstOrDefault(),
|
||||||
_ => _handlers.OfType<GenericSystemHandler>().FirstOrDefault()
|
_ => _handlers.OfType<GenericSystemHandler>().FirstOrDefault()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,13 +153,116 @@ namespace Nodify.Calculator
|
|||||||
systemNodes.Add(debugAndCreateModels);
|
systemNodes.Add(debugAndCreateModels);
|
||||||
systemNodes.Add(jsonParseNode);
|
systemNodes.Add(jsonParseNode);
|
||||||
systemNodes.Add(splitNode);
|
systemNodes.Add(splitNode);
|
||||||
systemNodes.Add(takeNode);
|
|
||||||
systemNodes.Add(forEachNode);
|
|
||||||
systemNodes.Add(assertNode);
|
systemNodes.Add(assertNode);
|
||||||
systemNodes.Add(stringConcatNode);
|
systemNodes.Add(stringConcatNode);
|
||||||
return systemNodes;
|
return systemNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<OperationInfoViewModel> GetListNodes()
|
||||||
|
{
|
||||||
|
var listNodes = new List<OperationInfoViewModel>();
|
||||||
|
|
||||||
|
var listAdd = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Add",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_ADD,
|
||||||
|
IsFlowNode = true
|
||||||
|
};
|
||||||
|
listAdd.Input.Add("List");
|
||||||
|
listAdd.Input.Add("Item");
|
||||||
|
|
||||||
|
var listRemove = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Remove",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_REMOVE,
|
||||||
|
IsFlowNode = true
|
||||||
|
};
|
||||||
|
listRemove.Input.Add("List");
|
||||||
|
listRemove.Input.Add("Index");
|
||||||
|
|
||||||
|
var listUpdate = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Update",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_UPDATE,
|
||||||
|
IsFlowNode = true
|
||||||
|
};
|
||||||
|
listUpdate.Input.Add("List");
|
||||||
|
listUpdate.Input.Add("Index");
|
||||||
|
listUpdate.Input.Add("Item");
|
||||||
|
|
||||||
|
var listGet = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Get",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_GET,
|
||||||
|
IsFlowNode = false
|
||||||
|
};
|
||||||
|
listGet.Input.Add("List");
|
||||||
|
listGet.Input.Add("Index");
|
||||||
|
|
||||||
|
var listCount = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Count",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_COUNT,
|
||||||
|
IsFlowNode = false
|
||||||
|
};
|
||||||
|
listCount.Input.Add("List");
|
||||||
|
|
||||||
|
var listContains = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Contains",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_CONTAINS,
|
||||||
|
IsFlowNode = false
|
||||||
|
};
|
||||||
|
listContains.Input.Add("List");
|
||||||
|
listContains.Input.Add("Item");
|
||||||
|
|
||||||
|
var listClear = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "List Clear",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.LIST_CLEAR,
|
||||||
|
IsFlowNode = true
|
||||||
|
};
|
||||||
|
listClear.Input.Add("List");
|
||||||
|
|
||||||
|
// Also include existing list-related nodes
|
||||||
|
var takeNode = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "TAKE",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.TAKE,
|
||||||
|
IsFlowNode = false
|
||||||
|
};
|
||||||
|
takeNode.Input.Add("List");
|
||||||
|
|
||||||
|
var forEachNode = new OperationInfoViewModel
|
||||||
|
{
|
||||||
|
Title = "ForEach",
|
||||||
|
Type = OperationType.System,
|
||||||
|
sysOp = SystemOperations.FOREACH,
|
||||||
|
IsFlowNode = true
|
||||||
|
};
|
||||||
|
forEachNode.Input.Add("List");
|
||||||
|
|
||||||
|
listNodes.Add(takeNode);
|
||||||
|
listNodes.Add(forEachNode);
|
||||||
|
listNodes.Add(listAdd);
|
||||||
|
listNodes.Add(listRemove);
|
||||||
|
listNodes.Add(listUpdate);
|
||||||
|
listNodes.Add(listGet);
|
||||||
|
listNodes.Add(listCount);
|
||||||
|
listNodes.Add(listContains);
|
||||||
|
listNodes.Add(listClear);
|
||||||
|
|
||||||
|
return listNodes;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<OperationInfoViewModel> GetOperationsInfo(Type container)
|
public static List<OperationInfoViewModel> GetOperationsInfo(Type container)
|
||||||
{
|
{
|
||||||
List<OperationInfoViewModel> result = new List<OperationInfoViewModel>();
|
List<OperationInfoViewModel> result = new List<OperationInfoViewModel>();
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ namespace Nodify.Calculator
|
|||||||
|
|
||||||
/// <summary>Non-API system nodes for the right-side panel.</summary>
|
/// <summary>Non-API system nodes for the right-side panel.</summary>
|
||||||
public NodifyObservableCollection<OperationInfoViewModel> SystemNodes { get; } = new NodifyObservableCollection<OperationInfoViewModel>();
|
public NodifyObservableCollection<OperationInfoViewModel> SystemNodes { get; } = new NodifyObservableCollection<OperationInfoViewModel>();
|
||||||
|
|
||||||
|
/// <summary>List/Array operation nodes for the right-side panel.</summary>
|
||||||
|
public NodifyObservableCollection<OperationInfoViewModel> ListNodes { get; } = new NodifyObservableCollection<OperationInfoViewModel>();
|
||||||
public INodifyCommand CreateOperationCommand { get; }
|
public INodifyCommand CreateOperationCommand { get; }
|
||||||
|
|
||||||
[Newtonsoft.Json.JsonIgnore]
|
[Newtonsoft.Json.JsonIgnore]
|
||||||
@@ -160,6 +163,12 @@ namespace Nodify.Calculator
|
|||||||
foreach (var sysNode in operations)
|
foreach (var sysNode in operations)
|
||||||
SystemNodes.Add(sysNode);
|
SystemNodes.Add(sysNode);
|
||||||
|
|
||||||
|
// Populate list/array nodes for the right panel
|
||||||
|
var listOps = OperationFactory.GetListNodes();
|
||||||
|
foreach (var listNode in listOps)
|
||||||
|
ListNodes.Add(listNode);
|
||||||
|
operations.AddRange(listOps);
|
||||||
|
|
||||||
SwaggerOperations = new NodifyObservableCollection<OperationInfoViewModel>();
|
SwaggerOperations = new NodifyObservableCollection<OperationInfoViewModel>();
|
||||||
LoadSwaggerNodesFromDb();
|
LoadSwaggerNodesFromDb();
|
||||||
RebuildGroupedSwaggerOperations();
|
RebuildGroupedSwaggerOperations();
|
||||||
|
|||||||
@@ -24,7 +24,14 @@ namespace Nodify.Calculator
|
|||||||
FOREACH,
|
FOREACH,
|
||||||
ASSERT,
|
ASSERT,
|
||||||
KNOT,
|
KNOT,
|
||||||
STRING_CONCAT
|
STRING_CONCAT,
|
||||||
|
LIST_ADD,
|
||||||
|
LIST_REMOVE,
|
||||||
|
LIST_UPDATE,
|
||||||
|
LIST_COUNT,
|
||||||
|
LIST_CONTAINS,
|
||||||
|
LIST_CLEAR,
|
||||||
|
LIST_GET
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemOperationViewModel : OperationViewModel
|
public class SystemOperationViewModel : OperationViewModel
|
||||||
|
|||||||
Reference in New Issue
Block a user