From 1eb917b4501f5bde9df54e4b2d6eb413efa37acc Mon Sep 17 00:00:00 2001 From: Ankitkumar Satapara Date: Sat, 18 Apr 2026 23:55:40 +0530 Subject: [PATCH] Added group for the right side panel and improved get post patch delete ui for requests --- Examples/Nodify.Calculator/EditorView.xaml | 129 ++++++++++++++---- Examples/Nodify.Calculator/EditorView.xaml.cs | 9 ++ .../Models/SwaggerGroupViewModel.cs | 8 ++ .../Models/SwaggerNodeModel.cs | 1 + .../OperationInfoViewModel.cs | 1 + .../OperationsMenuViewModel.cs | 60 +++++++- .../Nodify.Calculator/UpperCaseConverter.cs | 19 +++ 7 files changed, 194 insertions(+), 33 deletions(-) create mode 100644 Examples/Nodify.Calculator/Models/SwaggerGroupViewModel.cs create mode 100644 Examples/Nodify.Calculator/UpperCaseConverter.cs diff --git a/Examples/Nodify.Calculator/EditorView.xaml b/Examples/Nodify.Calculator/EditorView.xaml index 6ec3c7a..f6cf966 100644 --- a/Examples/Nodify.Calculator/EditorView.xaml +++ b/Examples/Nodify.Calculator/EditorView.xaml @@ -91,6 +91,7 @@ + @@ -590,8 +591,8 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Nodify.Calculator/EditorView.xaml.cs b/Examples/Nodify.Calculator/EditorView.xaml.cs index 82e1907..90224a5 100644 --- a/Examples/Nodify.Calculator/EditorView.xaml.cs +++ b/Examples/Nodify.Calculator/EditorView.xaml.cs @@ -83,6 +83,15 @@ namespace Nodify.Calculator } } + private void OnSwaggerItemDrag(object sender, MouseEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed && sender is FrameworkElement fe && fe.Tag is OperationInfoViewModel operation) + { + var data = new DataObject(typeof(OperationInfoViewModel), operation); + DragDrop.DoDragDrop(this, data, DragDropEffects.Copy); + } + } + private void OpenContextMenu_Executed(object sender, ExecutedRoutedEventArgs e) { if (e.Source is NodifyEditor editor && editor.DataContext is CalculatorViewModel calculator) diff --git a/Examples/Nodify.Calculator/Models/SwaggerGroupViewModel.cs b/Examples/Nodify.Calculator/Models/SwaggerGroupViewModel.cs new file mode 100644 index 0000000..16a937b --- /dev/null +++ b/Examples/Nodify.Calculator/Models/SwaggerGroupViewModel.cs @@ -0,0 +1,8 @@ +namespace Nodify.Calculator +{ + public class SwaggerGroupViewModel + { + public string GroupName { get; set; } = string.Empty; + public NodifyObservableCollection Operations { get; set; } = new NodifyObservableCollection(); + } +} diff --git a/Examples/Nodify.Calculator/Models/SwaggerNodeModel.cs b/Examples/Nodify.Calculator/Models/SwaggerNodeModel.cs index dfb969b..2c8efc0 100644 --- a/Examples/Nodify.Calculator/Models/SwaggerNodeModel.cs +++ b/Examples/Nodify.Calculator/Models/SwaggerNodeModel.cs @@ -10,5 +10,6 @@ namespace Nodify.Calculator.Models public List InputNames { get; set; } = new List(); public string SwaggerFileName { get; set; } = string.Empty; public string ResponseModelClassName { get; set; } = string.Empty; + public string SwaggerGroup { get; set; } = string.Empty; } } diff --git a/Examples/Nodify.Calculator/OperationInfoViewModel.cs b/Examples/Nodify.Calculator/OperationInfoViewModel.cs index 50b0a25..d784c0e 100644 --- a/Examples/Nodify.Calculator/OperationInfoViewModel.cs +++ b/Examples/Nodify.Calculator/OperationInfoViewModel.cs @@ -36,5 +36,6 @@ namespace Nodify.Calculator public List FunctionInputs { get; set; } = new List(); public List FunctionOutputs { get; set; } = new List(); public string ResponseModelClassName { get; set; } = string.Empty; + public string SwaggerGroup { get; set; } = string.Empty; } } diff --git a/Examples/Nodify.Calculator/OperationsMenuViewModel.cs b/Examples/Nodify.Calculator/OperationsMenuViewModel.cs index 7053583..95f072a 100644 --- a/Examples/Nodify.Calculator/OperationsMenuViewModel.cs +++ b/Examples/Nodify.Calculator/OperationsMenuViewModel.cs @@ -114,6 +114,12 @@ namespace Nodify.Calculator public NodifyObservableCollection AvailableModels { get; } public NodifyObservableCollection AvailableVariables { get; } public NodifyObservableCollection AvailableFunctions { get; } + + /// Swagger operations grouped by SwaggerGroup (tag), for the right-side panel. + public NodifyObservableCollection GroupedSwaggerOperations { get; } = new NodifyObservableCollection(); + + /// Non-API system nodes for the right-side panel. + public NodifyObservableCollection SystemNodes { get; } = new NodifyObservableCollection(); public INodifyCommand CreateOperationCommand { get; } [Newtonsoft.Json.JsonIgnore] @@ -150,8 +156,13 @@ namespace Nodify.Calculator operations.AddRange(OperationFactory.GetSystemNodes()); //operations.AddRange(OperationFactory.GetOperationsInfo(typeof(OperationsContainer))); + // Populate system-only nodes for the right panel + foreach (var sysNode in operations) + SystemNodes.Add(sysNode); + SwaggerOperations = new NodifyObservableCollection(); LoadSwaggerNodesFromDb(); + RebuildGroupedSwaggerOperations(); operations.AddRange(SwaggerOperations); @@ -344,6 +355,8 @@ namespace Nodify.Calculator MenuAvailableOperations.Add(node); } + RebuildGroupedSwaggerOperations(); + MessageBox.Show($"Successfully imported {nodes.Count} API endpoints from Swagger.", "Import Swagger", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) @@ -362,11 +375,18 @@ namespace Nodify.Calculator { foreach (var method in path.Value) { + // Determine swagger group from operation tags or path segments + var tag = method.Value.Tags?.FirstOrDefault(); + var group = !string.IsNullOrEmpty(tag) + ? tag + : ExtractGroupFromPath(path.Key); + var ovmodel = new OperationInfoViewModel { Title = path.Key, OPType = method.Key, - Type = OperationType.API + Type = OperationType.API, + SwaggerGroup = group }; var addedParams = new HashSet(); @@ -522,6 +542,38 @@ namespace Nodify.Calculator return new string(name.Where(c => char.IsLetterOrDigit(c) || c == '_').ToArray()); } + private static string ExtractGroupFromPath(string path) + { + // Extract group from path like "/api/Pizza/{id}" -> "Pizza" + var segments = path.Split('/', System.StringSplitOptions.RemoveEmptyEntries); + // Skip "api" prefix if present, take the first meaningful segment + foreach (var seg in segments) + { + if (seg.StartsWith("{") || string.Equals(seg, "api", System.StringComparison.OrdinalIgnoreCase)) + continue; + // Capitalize first letter + return char.ToUpper(seg[0]) + seg.Substring(1); + } + return "Other"; + } + + private void RebuildGroupedSwaggerOperations() + { + GroupedSwaggerOperations.Clear(); + var groups = SwaggerOperations + .GroupBy(op => string.IsNullOrEmpty(op.SwaggerGroup) ? "Other" : op.SwaggerGroup) + .OrderBy(g => g.Key); + + foreach (var group in groups) + { + GroupedSwaggerOperations.Add(new SwaggerGroupViewModel + { + GroupName = group.Key, + Operations = new NodifyObservableCollection(group.ToList()) + }); + } + } + private void SaveSwaggerNodesToDb(List nodes, string swaggerFileName) { using var db = new LiteDbHelper("SwaggerNodes"); @@ -535,7 +587,8 @@ namespace Nodify.Calculator OPType = node.OPType ?? string.Empty, InputNames = new List(node.Input), SwaggerFileName = swaggerFileName, - ResponseModelClassName = node.ResponseModelClassName ?? string.Empty + ResponseModelClassName = node.ResponseModelClassName ?? string.Empty, + SwaggerGroup = node.SwaggerGroup ?? string.Empty }); } } @@ -553,7 +606,8 @@ namespace Nodify.Calculator { Title = saved.Title, OPType = saved.OPType, - Type = OperationType.API + Type = OperationType.API, + SwaggerGroup = saved.SwaggerGroup ?? string.Empty }; foreach (var inputName in saved.InputNames) diff --git a/Examples/Nodify.Calculator/UpperCaseConverter.cs b/Examples/Nodify.Calculator/UpperCaseConverter.cs new file mode 100644 index 0000000..a994502 --- /dev/null +++ b/Examples/Nodify.Calculator/UpperCaseConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace Nodify.Calculator +{ + public class UpperCaseConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value is string s ? s.ToUpper() : value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +}