Skip to content

Commit

Permalink
Cherry-picks (#14733)
Browse files Browse the repository at this point in the history
* DYN-6524 Packages Tour Regression (#14721)

I did several updates for the Packages guide:
I've splitted the functionality of collapseExpandPackage so now we will have one method for collapse and another one for expand, so the function collapseExpandPackage was renamed to expandPackageDiv.
Some Steps in the dynamo_guides.json were modified to stick to the functionality of expanding the package when passing from Step8 to Step9.
Finally I added a validation in the function that highlight a div so if the div is already highlighted when we don't add the functionality ( this will prevent showing the orange rectangle when closing the guide ).

* DYN-6055 Lucene Search Category Based. (#14663)

* DYN-6055 Lucene Search Category Based.

I've updated the Lucene Search in a way that if the user type the "." character then the search will be "category based" (e.g. the search criteria "list.r" will find all the nodes which belong to the list category and the node name starts with r).
For this implementation I've indexed two new fields: NameSplitted and CategorySplitted. For NameSplitted when the node name contains the Category (like List.Shop) then we will be using the last part (after the "." character), the same case for CategorySplitted, we will be using the last part after the "." character.

* DYN-6055 Lucene Search Category Based Code Review

I've added more comments
I've changed the validation for always taking the last two sections (the NameSplitted can be empty due that later there is a validation) so if the search criteria use a large category like "Core.File.FileSystem.A". it will take only the last two sections.

* DYN-6055 Lucene Search Category Based Code Review

Adding a unit test that will validate category search based.

* Fixing Search Regressions (#14738)

For the test SearchingForACategoryReturnsAllItsChildren now with my changes related to category based search the term "Category.Child" will be searching the nodes with Category = Category and Name=Child so that's why was not returning results adding an extra "." in the search term fixed it.

The same case for the test LuceneSearchNodesByCategoryValidation, was expecting all the nodes under the category "Core.Input" so we have to add an extra "." in the search term.

For the test LuceneSearchNodesOrderingValidation I have to change a node due that with my changes the order changed and now is one position below (for the search term "list.join" we only guarante that the items at the top will be Category = list and the name starts with "join").

* mark test failure

* Add selection handler after binding. (#14744)

---------

Co-authored-by: Roberto T <[email protected]>
Co-authored-by: Trygve Wastvedt <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2023
1 parent 39988f5 commit ecf811d
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ internal void CollapseExpandPackage(string section)

object[] jsParameters = new object[] { breadBrumbsArray[i], sectionType, "true" };
//Create the array for the paramateres that will be sent to the WebBrowser.InvokeScript Method
object[] parametersInvokeScript = new object[] { "collapseExpandPackage", jsParameters };
object[] parametersInvokeScript = new object[] { "expandPackageDiv", jsParameters };

ResourceUtilities.ExecuteJSFunction(DynamoView, parametersInvokeScript);

Expand Down
12 changes: 12 additions & 0 deletions src/DynamoCore/Configuration/LuceneConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,21 @@ public enum NodeFieldsEnum
/// </summary>
Name,

/// <summary>
/// NameSplitted - The name of the node splitted using just the last part (e.g. List.Chop we will be using just Chop)
/// </summary>
NameSplitted,

/// <summary>
/// FullCategoryName - The category of the node
/// </summary>
FullCategoryName,

/// <summary>
/// CategorySplitted - For this case we will be using just the last Category (the last word after the dot separator in FullCategoryName)
/// </summary>
CategorySplitted,

/// <summary>
/// Description - The description of the node
/// </summary>
Expand Down Expand Up @@ -182,7 +192,9 @@ public enum NodeFieldsEnum
/// Nodes Fields to be indexed by Lucene Search
/// </summary>
public static string[] NodeIndexFields = { nameof(NodeFieldsEnum.Name),
nameof(NodeFieldsEnum.NameSplitted),
nameof(NodeFieldsEnum.FullCategoryName),
nameof(NodeFieldsEnum.CategorySplitted),
nameof(NodeFieldsEnum.Description),
nameof(NodeFieldsEnum.SearchKeywords),
nameof(NodeFieldsEnum.DocName),
Expand Down
76 changes: 71 additions & 5 deletions src/DynamoCore/Utilities/LuceneSearchUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ internal Document InitializeIndexDocumentForNodes()
if (DynamoModel.IsTestMode && startConfig.StorageType == LuceneStorage.FILE_SYSTEM) return null;

var name = new TextField(nameof(LuceneConfig.NodeFieldsEnum.Name), string.Empty, Field.Store.YES);
var nameSplitted = new TextField(nameof(LuceneConfig.NodeFieldsEnum.NameSplitted), string.Empty, Field.Store.YES);
var fullCategory = new TextField(nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName), string.Empty, Field.Store.YES);
var categorySplitted = new TextField(nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted), string.Empty, Field.Store.YES);
var description = new TextField(nameof(LuceneConfig.NodeFieldsEnum.Description), string.Empty, Field.Store.YES);
var keywords = new TextField(nameof(LuceneConfig.NodeFieldsEnum.SearchKeywords), string.Empty, Field.Store.YES);
var docName = new StringField(nameof(LuceneConfig.NodeFieldsEnum.DocName), string.Empty, Field.Store.YES);
Expand All @@ -172,8 +174,10 @@ internal Document InitializeIndexDocumentForNodes()

var d = new Document()
{
fullCategory,
name,
nameSplitted,
fullCategory,
categorySplitted,
description,
keywords,
fullDoc,
Expand Down Expand Up @@ -269,23 +273,61 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm)

var booleanQuery = new BooleanQuery();
string searchTerm = QueryParser.Escape(SearchTerm);
var bCategoryBasedSearch = searchTerm.Contains('.') ? true : false;

foreach (string f in fields)
{
//Needs to be again due that now a query can contain different values per field (e.g. CategorySplitted:list, Name:tr)
searchTerm = QueryParser.Escape(SearchTerm);
if (bCategoryBasedSearch == true)
{
//This code section should be only executed if the search criteria is CategoryBased like "category.nodename"
if (f != nameof(LuceneConfig.NodeFieldsEnum.NameSplitted) &&
f != nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted))
continue;

var categorySearchBased = searchTerm.Split('.');
//In the case the search criteria is like "Core.File.FileSystem.a" it will take only the last two sections Category=FileSystem and Name=a*
if (categorySearchBased.Length > 1 && !string.IsNullOrEmpty(categorySearchBased[categorySearchBased.Length - 2]))
{
if (f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted))
searchTerm = categorySearchBased[categorySearchBased.Length - 2];
else
searchTerm = categorySearchBased[categorySearchBased.Length - 1];
}
}

FuzzyQuery fuzzyQuery;
if (searchTerm.Length > LuceneConfig.FuzzySearchMinimalTermLength)
{
fuzzyQuery = new FuzzyQuery(new Term(f, searchTerm), fuzzyLogicMaxEdits);
booleanQuery.Add(fuzzyQuery, Occur.SHOULD);
}

//For normal search we don't consider the fields NameSplitted and CategorySplitted
if ((f == nameof(LuceneConfig.NodeFieldsEnum.NameSplitted) ||
f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted)) && bCategoryBasedSearch == false)
continue;

//This case is for when the user type something like "list.", I mean, not specifying the node name or part of it
if (string.IsNullOrEmpty(searchTerm))
continue;

var fieldQuery = CalculateFieldWeight(f, searchTerm);
var wildcardQuery = CalculateFieldWeight(f, searchTerm, true);

booleanQuery.Add(fieldQuery, Occur.SHOULD);
booleanQuery.Add(wildcardQuery, Occur.SHOULD);
if (bCategoryBasedSearch && f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted))
{
booleanQuery.Add(fieldQuery, Occur.MUST);
booleanQuery.Add(wildcardQuery, Occur.MUST);
}
else
{
booleanQuery.Add(fieldQuery, Occur.SHOULD);
booleanQuery.Add(wildcardQuery, Occur.SHOULD);
}

if (searchTerm.Contains(' ') || searchTerm.Contains('.'))
if (searchTerm.Contains(' '))
{
foreach (string s in searchTerm.Split(' ', '.'))
{
Expand Down Expand Up @@ -317,19 +359,32 @@ private WildcardQuery CalculateFieldWeight(string fieldName, string searchTerm,
{
WildcardQuery query;

//In case we are weighting the NameSplitted field then means that is a search based on Category of the type "cat.node" so we will be using the wilcard "category.node*" otherwise will be the normal wildcard
var termText = fieldName == nameof(LuceneConfig.NodeFieldsEnum.NameSplitted) ? searchTerm + "*" : "*" + searchTerm + "*";

query = isWildcard == false ?
new WildcardQuery(new Term(fieldName, searchTerm)) : new WildcardQuery(new Term(fieldName, "*" + searchTerm + "*"));
new WildcardQuery(new Term(fieldName, searchTerm)) : new WildcardQuery(new Term(fieldName, termText));

switch (fieldName)
{
case nameof(LuceneConfig.NodeFieldsEnum.Name):
query.Boost = isWildcard == false?
LuceneConfig.SearchNameWeight : LuceneConfig.WildcardsSearchNameWeight;
break;
case nameof(LuceneConfig.NodeFieldsEnum.NameSplitted):
//Under this case the NameSplitted field will have less weight than CategorySplitted
query.Boost = isWildcard == false ?
LuceneConfig.SearchCategoryWeight : LuceneConfig.WildcardsSearchCategoryWeight;
break;
case nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName):
query.Boost = isWildcard == false?
LuceneConfig.SearchCategoryWeight : LuceneConfig.WildcardsSearchCategoryWeight;
break;
case nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted):
//Under this case the CategorySplitted field will have more weight than NameSplitted
query.Boost = isWildcard == false ?
LuceneConfig.SearchNameWeight : LuceneConfig.WildcardsSearchNameWeight;
break;
case nameof(LuceneConfig.NodeFieldsEnum.Description):
query.Boost = isWildcard == false ?
LuceneConfig.SearchDescriptionWeight : LuceneConfig.WildcardsSearchDescriptionWeight;
Expand Down Expand Up @@ -431,7 +486,18 @@ internal void AddNodeTypeToSearchIndex(NodeSearchElement node, Document doc)
if (writer == null) return;

SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName), node.FullCategoryName);

var categoryParts = node.FullCategoryName.Split('.');
string categoryParsed = categoryParts.Length > 1 ? categoryParts[categoryParts.Length - 1] : node.FullCategoryName;
//In case the search criteria is like "filesystem.replace" we will be storing the value "filesystem" inside the CategorySplitted field
SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted), categoryParsed);

SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.Name), node.Name);

var nameParts = node.Name.Split('.');
string nameParsed = nameParts.Length > 1 ? nameParts[nameParts.Length - 1] : node.Name;
SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.NameSplitted), nameParsed);

SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.Description), node.Description);
if (node.SearchKeywords.Count > 0)
{
Expand Down
46 changes: 39 additions & 7 deletions src/DynamoCoreWpf/UI/GuidedTour/GuidesValidationMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Dynamo.PackageManager.ViewModels;
using Dynamo.Utilities;
using Dynamo.ViewModels;
using Dynamo.Wpf.ViewModels.GuidedTour;
using Dynamo.Wpf.Views.GuidedTour;
using Newtonsoft.Json.Linq;
using static Dynamo.PackageManager.PackageManagerSearchViewModel;
Expand Down Expand Up @@ -495,18 +496,30 @@ internal static void SubscribeNextButtonClickEvent(Step stepInfo, StepUIAutomati
/// <param name="e">Event Arguments</param>
internal void ExecuteAutomaticPackage_Click(object sender, RoutedEventArgs e)
{
CollapseExpandPackage(CurrentExecutingStep);
var nextButton = (sender as Button);
if (nextButton == null) return;

var popupVM = (nextButton.DataContext as PopupWindowViewModel);
if(popupVM == null) return;

if (popupVM.Step == null) return;
ExpandPackage(popupVM.Step);
}

/// <summary>
/// This method will call the collapseExpandPackage javascript method with reflection, so the package expander in LibraryView will be clicked
/// This method will call the expandPackageDiv javascript method with reflection, so the package expander in LibraryView will be clicked
/// </summary>
internal static void CollapseExpandPackage(Step stepInfo)
internal static void ExpandPackage(Step stepInfo)
{
CurrentExecutingStep = stepInfo;
var firstUIAutomation = stepInfo.UIAutomation.FirstOrDefault();
if (firstUIAutomation == null || firstUIAutomation.JSParameters.Count == 0) return;
object[] parametersInvokeScript = new object[] { firstUIAutomation.JSFunctionName, new object[] { firstUIAutomation.JSParameters.FirstOrDefault() } };
var expandUIAutomation = stepInfo.UIAutomation.Where(automation => automation.JSFunctionName == "expandPackageDiv").FirstOrDefault();
if (expandUIAutomation == null || expandUIAutomation.JSParameters.Count == 0) return;

//Expand the Sample Package Div when clicking the next button in Step8
object[] parametersInvokeScript = new object[] { expandUIAutomation.JSFunctionName, new object[] { expandUIAutomation.JSParameters[0], expandUIAutomation.JSParameters[1] } };
ResourceUtilities.ExecuteJSFunction(stepInfo.MainWindow, stepInfo.HostPopupInfo, parametersInvokeScript);

//Expand the Package nodes when clicking the next button in Step8
parametersInvokeScript = new object[] { expandUIAutomation.JSFunctionName, new object[] { "Examples", "LibraryItemGroupText" } };
ResourceUtilities.ExecuteJSFunction(stepInfo.MainWindow, stepInfo.HostPopupInfo, parametersInvokeScript);
}

Expand Down Expand Up @@ -976,5 +989,24 @@ private static void RunButton_Click(object sender, RoutedEventArgs e)
{
CurrentExecutingGuide.NextStep(CurrentExecutingStep.Sequence);
}

/// <summary>
/// In the the Package is expanded this method will call a js method that will collapse the <div></div>
/// </summary>
internal static void CollapsePackageDiv(Step stepInfo, StepUIAutomation uiAutomationData, bool enableFunction, GuideFlow currentFlow)
{
CurrentExecutingStep = stepInfo;
if (uiAutomationData == null) return;
string jsFunctionName = uiAutomationData.JSFunctionName;
//Create the array for the paramateres that will be sent to the WebBrowser.InvokeScript Method
object[] parametersInvokeScript = new object[] { jsFunctionName, new object[] { uiAutomationData.JSParameters[0], uiAutomationData.JSParameters[1] } };

//Only will be executed when entering to the Step8 (when leaving Step8 the div should be expanded)
if(enableFunction == true)
{
//Execute the JS function with the provided parameters
ResourceUtilities.ExecuteJSFunction(CurrentExecutingStep.MainWindow, CurrentExecutingStep.HostPopupInfo, parametersInvokeScript);
}
}
}
}
52 changes: 26 additions & 26 deletions src/DynamoCoreWpf/UI/GuidedTour/dynamo_guides.json
Original file line number Diff line number Diff line change
Expand Up @@ -738,10 +738,18 @@
{
"Sequence": 1,
"ControlType": "function",
"Name": "CollapsePackageDiv",
"JSFunctionName": "collapsePackageDiv",
"JSParameters": [ "SampleLibraryUI", "LibraryItemText" ],
"Action": "execute"
},
{
"Sequence": 2,
"ControlType": "function",
"WindowName": "PopupWindow",
"Name": "SubscribeNextButtonClickEvent",
"Action": "execute",
"JSFunctionName": "collapseExpandPackage",
"JSFunctionName": "expandPackageDiv",
"JSParameters": [ "SampleLibraryUI", "LibraryItemText" ],
"AutomaticHandlers": [
{
Expand All @@ -752,39 +760,39 @@
]
},
{
"Sequence": 2,
"Sequence": 3,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"JSFunctionName": "setOverlay",
"JSParameters": [],
"Action": "execute"
},
{
"Sequence": 3,
"Sequence": 4,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"JSFunctionName": "subscribePackageClickedEvent",
"JSParameters": [ "SampleLibraryUI" ],
"Action": "execute"
},
{
"Sequence": 4,
"Sequence": 5,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"JSFunctionName": "getDocumentClientRect",
"JSParameters": [ "SampleLibraryUI" ],
"Action": "execute"
},
{
"Sequence": 5,
"Sequence": 6,
"ControlType": "function",
"Name": "LibraryScrollToBottom",
"JSFunctionName": "scrollToBottom",
"JSParameters": [],
"Action": "execute"
},
{
"Sequence": 6,
"Sequence": 7,
"ControlType": "function",
"Name": "CalculateLibraryItemLocation",
"JSFunctionName": "getDocumentClientRect",
Expand Down Expand Up @@ -821,36 +829,28 @@
},
"UIAutomation": [
{
"Sequence": 0,
"Sequence": 1,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"JSFunctionName": "setOverlay",
"JSParameters": [],
"Action": "execute"
},
{
"Sequence": 1,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"Action": "execute",
"JSFunctionName": "collapseExpandPackage",
"JSParameters": [ "SampleLibraryUI", "LibraryItemText" ]
},
{
"Sequence": 2,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"Action": "execute",
"JSFunctionName": "collapseExpandPackage",
"JSParameters": [ "Examples", "LibraryItemGroupText" ]
},
{
"Sequence": 3,
"ControlType": "function",
"Name": "LibraryScrollToBottom",
"JSFunctionName": "scrollToBottom",
"JSParameters": [],
"Action": "execute"
},
{
"Sequence": 3,
"ControlType": "JSFunction",
"Name": "InvokeJSFunction",
"JSFunctionName": "expandPackageDiv",
"JSParameters": [ "Examples", "LibraryItemGroupText" ],
"Action": "execute"
}
]
},
Expand Down Expand Up @@ -998,7 +998,7 @@
"WindowName": "LibraryView",
"Name": "InvokeJSFunction",
"Action": "execute",
"JSFunctionName": "collapseExpandPackage",
"JSFunctionName": "expandPackageDiv",
"JSParameters": [ "Geometry", "LibraryItemText" ]
},
{
Expand All @@ -1007,7 +1007,7 @@
"WindowName": "LibraryView",
"Name": "InvokeJSFunction",
"Action": "execute",
"JSFunctionName": "collapseExpandPackage",
"JSFunctionName": "expandPackageDiv",
"JSParameters": [ "Abstract", "LibraryItemGroupText" ]
},
{
Expand All @@ -1016,7 +1016,7 @@
"WindowName": "LibraryView",
"Name": "InvokeJSFunction",
"Action": "execute",
"JSFunctionName": "collapseExpandPackage",
"JSFunctionName": "expandPackageDiv",
"JSParameters": [ "CoordinateSystem", "LibraryItemGroupText" ]
},
{
Expand Down
Loading

0 comments on commit ecf811d

Please sign in to comment.