Implemented reading input from the textbox instead of connectors
Some checks failed
Build / build (push) Successful in 34s
CodeQL / Analyze (csharp) (push) Has been cancelled

This commit is contained in:
Ankitkumar Satapara
2026-04-29 19:20:37 +05:30
parent 1463d5b3a8
commit bc373d291e
3 changed files with 80 additions and 10 deletions

View File

@@ -31,6 +31,19 @@ namespace Nodify.Calculator
.Then(() => ValueObservers.ForEach(o => o.Value = value));
}
private string _userInput = string.Empty;
/// <summary>
/// Free-form text the user types directly into the connector's input textbox
/// (visible only when the connector is not connected). Used by handlers like
/// NEW_OBJECT to read non-numeric values (strings, bools, JSON snippets, ...)
/// that <see cref="Value"/> (a double) cannot represent.
/// </summary>
public string UserInput
{
get => _userInput;
set => SetProperty(ref _userInput, value);
}
private ConnectorShape _shape;
public ConnectorShape Shape
{

View File

@@ -273,7 +273,8 @@
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}"
Margin="0 0 5 0" />
<TextBox Text="{Binding Value}"
<TextBox Text="{Binding UserInput, UpdateSourceTrigger=PropertyChanged}"
MinWidth="60"
Visibility="{Binding IsConnected, Converter={shared:BooleanToVisibilityConverter Negate=True}}" />
</StackPanel>
</DataTemplate>

View File

@@ -95,10 +95,23 @@ namespace Nodify.Calculator.Execution.Handlers
var propPath = parenIdx > 0 ? title.Substring(0, parenIdx).Trim() : title.Trim();
if (string.IsNullOrEmpty(propPath)) continue;
var val = ctx.ReadInput(inp);
// If a wire is connected → read from upstream node.
// Otherwise fall back to whatever the user typed in the inline TextBox (UserInput).
// If neither is provided, skip the field so the JSON only carries explicit values.
string val;
if (inp.IsConnected)
{
val = ctx.ReadInput(inp);
}
else
{
if (string.IsNullOrWhiteSpace(inp.UserInput)) continue;
val = inp.UserInput;
}
ctx.Log($"[NEW OBJECT] {propPath} = {(val?.Length > 80 ? val.Substring(0, 80) + "..." : val ?? "null")}");
SetNestedValue(root, propPath, val);
SetNestedValue(root, propPath, val, inp.DataType);
}
var json = root.ToString(Formatting.None);
@@ -109,9 +122,10 @@ namespace Nodify.Calculator.Execution.Handlers
/// <summary>
/// Sets a value at a dot-notation path in a JObject, creating intermediate objects as needed.
/// e.g., "Address.Street" with value "Main St" → { "Address": { "Street": "Main St" } }
/// The leaf token is coerced according to <paramref name="dataType"/> so that string fields
/// remain JSON strings, numeric fields remain JSON numbers, etc.
/// </summary>
private static void SetNestedValue(JObject root, string path, string val)
private static void SetNestedValue(JObject root, string path, string val, string dataType)
{
var parts = path.Split('.');
var current = root;
@@ -129,14 +143,56 @@ namespace Nodify.Calculator.Execution.Handlers
}
var leaf = parts[parts.Length - 1];
if (val != null)
{
try { current[leaf] = JToken.Parse(val); }
catch { current[leaf] = val; }
current[leaf] = CoerceValue(val, dataType);
}
else
private static JToken CoerceValue(string val, string dataType)
{
current[leaf] = null;
if (val == null) return JValue.CreateNull();
var dt = (dataType ?? "").Trim().ToLowerInvariant();
// Lists / nested objects / unspecified — try JSON parse first, fall back to string.
if (dt.StartsWith("list<") || dt == "object" || string.IsNullOrEmpty(dt))
{
try { return JToken.Parse(val); }
catch { return new JValue(val); }
}
switch (dt)
{
case "string":
case "char":
case "guid":
case "datetime":
return new JValue(val);
case "bool":
case "boolean":
if (bool.TryParse(val, out var b)) return new JValue(b);
return new JValue(val);
case "int":
case "long":
case "short":
case "byte":
if (long.TryParse(val, System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out var l))
return new JValue(l);
return new JValue(val);
case "double":
case "float":
case "decimal":
if (double.TryParse(val, System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out var d))
return new JValue(d);
return new JValue(val);
default:
// Custom model type referenced by name → expect a JSON object string.
try { return JToken.Parse(val); }
catch { return new JValue(val); }
}
}
}