Skip to content

Feature/pom support web smart sync#3782

Merged
Maheshkale447 merged 8 commits into
masterfrom
Feature/POMSupport_WebSmartSync
Jun 24, 2024
Merged

Feature/pom support web smart sync#3782
Maheshkale447 merged 8 commits into
masterfrom
Feature/POMSupport_WebSmartSync

Conversation

@GokulBothe

@GokulBothe GokulBothe commented Jun 21, 2024

Copy link
Copy Markdown
Collaborator

Thank you for your contribution.
Before submitting this PR, please make sure:

  • PR description and commit message should describe the changes done in this PR
  • Verify the PR is pointing to correct branch i.e. Release or Beta branch if the code fix is for specific release , else point it to master
  • Latest Code from master or specific release branch is merged to your branch
  • No unwanted\commented\junk code is included
  • No new warning upon build solution
  • Code Summary\Comments are added to my code which explains what my code is doing
  • Existing unit test cases are passed
  • New Unit tests are added for your development
  • Sanity Tests are successfully executed for New and Existing Functionality
  • Verify that changes are compatible with all relevant browsers and platforms.
  • After creating pull request there should not be any conflicts
  • Resolve all Codacy comments
  • Builds and checks are passed before PR is sent for review
  • Resolve code review comments
  • Update the Help Library document to match any feature changes

Summary by CodeRabbit

  • New Features

    • Enhanced UI layout and structure in the web synchronization page.
    • Added new properties and methods for element location and visibility handling.
  • Improvements

    • Increased design height for better readability.
    • Updated element locators and synchronization logic for improved web automation.
  • Bug Fixes

    • Improved error handling for missing or invalid input values during synchronization operations.

@coderabbitai

coderabbitai Bot commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Walkthrough

The recent changes primarily focus on refactoring and enhancing the UI and backend functionality of the WebSmartSync feature in the Ginger automation tool. This includes modifications to UI layouts and structures, updating how elements are located and synchronized, and optimizing property handling and visibility logic. The changes aim to improve user experience and ensure more robust synchronization operations.

Changes

File Path Change Summary
.../Actions/ActionEditPage.xaml.cs Refactored LoadOperationSettingsEditPage, removed IActEditPage logic, and commented out ActionEditPage_PropertyChanged.
.../Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml UI layout and structure changes: increased design height, reorganized layout, introduced new elements (xLocaterPnl, LocateValueEditFrame), and adjusted sizes and styles.
.../Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs Removed LocatorVisibility property, added methods for handling element locating and visibility, and removed INotifyPropertyChanged logic.
.../ActionsLib/UI/ActWebSmartSync.cs Updated imports, added Fields static partial class, properties (ElementLocateBy, ElementLocateValue, ElementLocateValueForDriver), added enum value, LocatorTypeManager class.
.../CoreDrivers/Web/Selenium/SeleniumDriver.cs Enhanced element locating and sync handling logic, improved error handling for invalid inputs, and handled Page Object Model (POM) elements.

Poem

🐰
Amid the code, changes bright and bold,
Elements now, no longer untold.
Styles refined, sync operations gleam,
Ginger’s magic, a developer's dream.
For every click and every line,
Rabbit hops, improvements shine. 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@GokulBothe
GokulBothe requested a review from Maheshkale447 June 21, 2024 12:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 7879bdd and b8ae92d.

Files selected for processing (5)
  • Ginger/Ginger/Actions/ActionEditPage.xaml.cs (2 hunks)
  • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml (1 hunks)
  • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs (5 hunks)
  • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (4 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (4 hunks)
Additional context used
Learnings (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (4)
User: prashelke
PR: Ginger-Automation/Ginger#3429
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:1581-1616
Timestamp: 2024-01-05T14:23:27.219Z
Learning: The user has implemented the use of `using` statements for `Bitmap` objects and added a `finally` block to clear the `bitmapsToMerge` list. They have also handled exceptions that may occur during bitmap operations.
User: prashelke
PR: Ginger-Automation/Ginger#3429
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:1581-1616
Timestamp: 2024-01-05T14:23:27.219Z
Learning: The user has implemented the use of `using` statements for `Bitmap` objects and added a `finally` block to clear the `bitmapsToMerge` list. They have also handled exceptions that may occur during bitmap operations.
User: manas-droid
PR: Ginger-Automation/Ginger#3436
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:6702-6749
Timestamp: 2024-01-10T08:58:17.226Z
Learning: The user has indicated that the commented `CheckifPageLoaded` method is needed for later use, suggesting a requirement to retain the code within the source files for reference or potential re-implementation.
User: manas-droid
PR: Ginger-Automation/Ginger#3436
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs:6702-6749
Timestamp: 2024-01-10T08:58:17.226Z
Learning: The user has indicated that the commented `CheckifPageLoaded` method is needed for later use, suggesting a requirement to retain the code within the source files for reference or potential re-implementation.
Additional comments not posted (12)
Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml (4)

5-5: Addition of System Namespace:

The addition of xmlns:sys="clr-namespace:System;assembly=mscorlib" is appropriate for utilizing system types directly in XAML, which you have done for defining resource keys like LabelWidth. This is a good use of XAML namespaces to simplify the declarations in the resources section.


8-8: Increase in Design Height:

Changing the d:DesignHeight from 300 to 400 is a UI change that needs to be validated against the intended design specifications. Ensure this change is consistent with the overall UI layout and does not introduce any overflow or clipping issues in different resolutions.


18-27: New UI Elements and Structure:

The introduction of a new panel xLocaterPnl along with associated labels and combo boxes for element location is a significant UI change. Ensure that these UI elements are accessible and properly integrated with the rest of the application. Additionally, validate that all new elements are styled consistently with existing UI components.


30-30: Event Handler for ComboBox:

The addition of an event handler SelectionChanged="ActionNameComboBox_SelectionChanged" to the ComboBox is crucial for dynamic UI interactions. Ensure that the corresponding method in the code-behind handles all edge cases and updates the UI appropriately based on the selection.

Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (4)

22-26: Addition of Using Directives:

The new using directives for Amdocs.Ginger.Common.UIElement and GingerCore.Actions.Common are necessary for the enhancements in element locating and synchronization functionalities. Ensure these namespaces are utilized effectively in the methods and properties where UI element interactions are handled.


69-73: New Static Partial Class Fields:

The introduction of a new static partial class Fields with properties like ElementLocateValue and ValueToSelect is a good encapsulation practice for managing constants. Ensure these fields are used consistently across the project wherever these string literals are needed.


127-157: New Properties for Element Location:

The addition of properties ElementLocateBy, ElementLocateValue, and ElementLocateValueForDriver enhances the configurability of element synchronization actions. Ensure that these properties are integrated correctly with the UI and backend functionalities, and validate their usage across different modules of the application.

Verification successful

Properties Integration Verified

The properties ElementLocateBy, ElementLocateValue, and ElementLocateValueForDriver are extensively used across various modules, including test cases, drivers, and action handlers. This indicates that they are well-integrated with both UI and backend functionalities.

  • Files with usage:
    • Ginger/GingerTest/ActionConversion/ActionConversionTest.cs
    • Ginger/GingerPluginPlatforms/Platform/Web/Execution/WebPlatformActionHandler.cs
    • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
    • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs
    • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs
    • And many others...

The presence of these properties in numerous test cases further confirms their correct integration and usage.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify correct integration and usage of new properties for element location.

echo "Review the integration of `ElementLocateBy`, `ElementLocateValue`, and `ElementLocateValueForDriver` across different modules."

Length of output: 466



Script:

#!/bin/bash
# Search for occurrences of ElementLocateBy in the codebase
rg 'ElementLocateBy'

# Search for occurrences of ElementLocateValue in the codebase
rg 'ElementLocateValue'

# Search for occurrences of ElementLocateValueForDriver in the codebase
rg 'ElementLocateValueForDriver'

Length of output: 120828


52-52: Change in ObjectLocatorConfigsNeeded Property:

The modification from true to false in ObjectLocatorConfigsNeeded suggests a change in how object locators are configured. Confirm that this change aligns with the new functionalities introduced in this PR and does not negatively impact existing features.

Verification successful

Change in ObjectLocatorConfigsNeeded Property:

The modification of ObjectLocatorConfigsNeeded from true to false in ActWebSmartSync.cs aligns with the new functionalities introduced in this PR. The changes in related files (ActWebSmartSyncEditPage.xaml.cs and SeleniumDriver.cs) focus on updating locator types and ensuring compatibility with the new configurations. No negative impact on existing features is evident.

  • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs: Modified ObjectLocatorConfigsNeeded to false.
  • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs: Updated locator types.
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs: Added support for ByRelXPath.
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that the change in `ObjectLocatorConfigsNeeded` aligns with new functionalities.

echo "Review related functionalities to ensure they operate correctly without explicit object locator configurations."

Length of output: 232



Script:

#!/bin/bash
# Search for usage of ObjectLocatorConfigsNeeded in the codebase
rg 'ObjectLocatorConfigsNeeded'

Length of output: 13726



Script:

#!/bin/bash
# List the files changed in this PR to identify new functionalities that might relate to `ObjectLocatorConfigsNeeded`.
git diff --name-only HEAD~1

Length of output: 225



Script:

#!/bin/bash
# Show changes in the files modified in this PR to understand the new functionalities.
git diff HEAD~1 Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs
git diff HEAD~1 Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs
git diff HEAD~1 Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs

Length of output: 9042

Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs (4)

42-43: Initialization of Action Object:

The initialization of mAction with the passed ActWebSmartSync object is crucial for linking the UI with the underlying data model. Ensure that this object is used consistently and safely throughout this class without leading to any null reference exceptions.


93-105: Conditional UI Page Generation:

The method GetLocateValueEditPage generates different pages based on the selected location type. This conditional logic is important for maintaining modularity in the UI. Review the implementation to ensure that it correctly handles all defined cases and integrates seamlessly with the rest of the UI components.


62-75: Dynamic UI Updates Based on Selection:

The method ElementLocateByComboBox_SelectionChanged is designed to clear and reset the location value based on the selection in the combo box. This dynamic behavior is essential for a responsive UI. Ensure that it handles all possible selections and updates the UI without errors.


127-142: Dynamic Locator Type Configuration:

The method setLocateBycombo dynamically configures the locator types available in the xLocateByComboBox. This flexibility is crucial for supporting various locator strategies. Verify that all locator types are correctly handled and that the UI reflects the selections appropriately.

Verification successful

Dynamic Locator Type Configuration Verified:

The method setLocateBycombo dynamically configures the locator types available in the xLocateByComboBox. The verification confirms that all locator types are correctly handled throughout the codebase. Additionally, the BindControl method in ExtensionsMethods.cs ensures that the xLocateByComboBox is correctly bound to the locator types and reflects the selections appropriately in the UI.

  • Locator Types Handled: All locator types (eLocateBy.POMElement, eLocateBy.ByID, eLocateBy.ByName, eLocateBy.ByXPath, eLocateBy.ByClassName, eLocateBy.ByCSSSelector, eLocateBy.ByLinkText, eLocateBy.ByTagName, eLocateBy.ByRelXPath) are valid and used throughout the codebase.
  • UI Binding: The BindControl method properly binds the list of locator types to the xLocateByComboBox, ensuring the UI reflects the selections appropriately.
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify correct handling of locator types in the combo box.

echo "Manually test each locator type in `xLocateByComboBox` to ensure correct behavior and UI updates."

Length of output: 272



Script:

#!/bin/bash
# Verify that all locator types in the setLocateBycombo method are valid and correctly handled.

# Search for the definition of eLocateBy to ensure all locator types are valid
ast-grep --lang csharp --pattern 'enum eLocateBy { $$$ }'

# Search for the usage of each locator type in the codebase to ensure they are correctly handled
ast-grep --lang csharp --pattern 'eLocateBy.POMElement'
ast-grep --lang csharp --pattern 'eLocateBy.ByID'
ast-grep --lang csharp --pattern 'eLocateBy.ByName'
ast-grep --lang csharp --pattern 'eLocateBy.ByXPath'
ast-grep --lang csharp --pattern 'eLocateBy.ByClassName'
ast-grep --lang csharp --pattern 'eLocateBy.ByCSSSelector'
ast-grep --lang csharp --pattern 'eLocateBy.ByLinkText'
ast-grep --lang csharp --pattern 'eLocateBy.ByTagName'
ast-grep --lang csharp --pattern 'eLocateBy.ByRelXPath'

Length of output: 94889



Script:

#!/bin/bash
# Verify that the xLocateByComboBox is correctly bound to the locator types and reflects the selections in the UI.

# Search for the definition of BindControl to ensure it correctly binds the list of locator types to the combo box
ast-grep --lang csharp --pattern 'void BindControl($_, $_, $_, $_)' --debug

# Search for the usage of BindControl to see how it is used with xLocateByComboBox
ast-grep --lang csharp --pattern 'xLocateByComboBox.BindControl($_, $_, $_, $_)'

Length of output: 955



Script:

#!/bin/bash
# Verify that the xLocateByComboBox is correctly bound to the locator types and reflects the selections in the UI.

# Search for the definition of BindControl to ensure it correctly binds the list of locator types to the combo box
ast-grep --lang csharp --pattern 'void BindControl($_, $_, $_, $_)'

# Search for the usage of BindControl to see how it is used with xLocateByComboBox
ast-grep --lang csharp --pattern 'xLocateByComboBox.BindControl($_, $_, $_, $_)'

Length of output: 1126



Script:

#!/bin/bash
# Verify that the xLocateByComboBox is correctly bound to the locator types and reflects the selections in the UI.

# Search for all method definitions to identify the BindControl method
ast-grep --lang csharp --pattern 'void $_($_, $_, $_, $_)'

Length of output: 446



Script:

#!/bin/bash
# Verify that the xLocateByComboBox is correctly bound to the locator types and reflects the selections in the UI.

# Search for the definition of BindControl to ensure it correctly binds the list of locator types to the combo box
rg 'void BindControl\('

Length of output: 1968



Script:

#!/bin/bash
# Display the content of Ginger/Ginger/Extensions/ExtensionsMethods.cs to inspect the BindControl method
cat Ginger/Ginger/Extensions/ExtensionsMethods.cs

Length of output: 19654

PropertyChangedEventManager.RemoveHandler(source: (IActEditPage)actEditPage, ActionEditPage_PropertyChanged, propertyName: allProperties);
PropertyChangedEventManager.AddHandler(source: (IActEditPage)actEditPage, ActionEditPage_PropertyChanged, propertyName: allProperties);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider handling potential null values for actEditPage.

The actEditPage is being checked for null but not handled if it is null. It might be safer to include a null check before setting the content to avoid potential runtime errors.

if (actEditPage != null)
{
    // Load the page
    xActionPrivateConfigsFrame.SetContent(actEditPage);
    xActionPrivateConfigsFrame.Visibility = System.Windows.Visibility.Visible;
}
+else
+{
+    // Handle the null scenario, maybe log it or set a default content
+    xActionPrivateConfigsFrame.Visibility = System.Windows.Visibility.Collapsed;
+}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (actEditPage != null)
{
// Load the page
xActionPrivateConfigsFrame.SetContent(actEditPage);
xActionPrivateConfigsFrame.Visibility = System.Windows.Visibility.Visible;
}
else
{
// Handle the null scenario, maybe log it or set a default content
xActionPrivateConfigsFrame.Visibility = System.Windows.Visibility.Collapsed;
}

Comment on lines +2339 to +2346
if (!String.IsNullOrEmpty(urlMatches))
{
wait.Until(ExpectedConditions.UrlMatches(urlMatches));
}
else
{
throw new ArgumentNullException();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve exception handling for clarity.

For operations like URL matching, providing specific error messages in exceptions can greatly aid in understanding the issues when they occur.

- throw new ArgumentNullException();
+ throw new ArgumentNullException("urlMatches", "URL match string cannot be null or empty.");
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!String.IsNullOrEmpty(urlMatches))
{
wait.Until(ExpectedConditions.UrlMatches(urlMatches));
}
else
{
throw new ArgumentNullException();
}
if (!String.IsNullOrEmpty(urlMatches))
{
wait.Until(ExpectedConditions.UrlMatches(urlMatches));
}
else
{
throw new ArgumentNullException("urlMatches", "URL match string cannot be null or empty.");
}

Comment on lines +2294 to +2316
if (!String.IsNullOrEmpty(textToMatch))
{
wait.Until(ExpectedConditions.TextMatches(elementLocator, textToMatch));
}
else
{
throw new ArgumentNullException();
}
break;
case ActWebSmartSync.eSyncOperation.AttributeMatches:
VE.Value = act.AttributeName;
string attributeName = VE.ValueCalculated;
VE = new ValueExpression(GetCurrentProjectEnvironment(), this.BusinessFlow);
VE.Value = act.AttributeValue;
string attributeValue= VE.ValueCalculated;
wait.Until(ExpectedConditions.AttributeMatches(elementLocator, attributeName, attributeValue));
if (!String.IsNullOrEmpty(attributeValue) || String.IsNullOrEmpty(attributeName))
{
wait.Until(ExpectedConditions.AttributeMatches(elementLocator, attributeName, attributeValue));
}
else
{
throw new ArgumentNullException();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enhance exception handling with specific error messages.

The use of ArgumentNullException should include specific error messages to aid in debugging and maintenance.

- throw new ArgumentNullException();
+ throw new ArgumentNullException("textToMatch", "Text to match cannot be null or empty.");
- throw new ArgumentNullException();
+ throw new ArgumentNullException("attributeValue", "Attribute value cannot be null or empty.");

Committable suggestion was skipped due to low confidence.

Comment on lines +2178 to +2224
eLocateBy locateBy = act.ElementLocateBy;
string locateValue = act.ElementLocateValueForDriver;

if (act.ElementLocateBy == eLocateBy.POMElement)
{
POMExecutionUtils pomExcutionUtil = new(act, act.ElementLocateValue);
if (pomExcutionUtil.GetCurrentPOM() == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"Current POM not found from {nameof(POMExecutionUtils)}");
act.Error = "Relevant POM not found";
return;
}

ElementInfo currentPOMElementInfo = pomExcutionUtil.GetCurrentPOMElementInfo();
if (currentPOMElementInfo == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"{nameof(ElementInfo)} not found for the current POM");
act.Error = "Unable to find details about the POM";
return;
}


ElementLocator firstLocator = currentPOMElementInfo.Locators.Where(l => l.Active &&(l.LocateBy == eLocateBy.ByXPath || l.LocateBy == eLocateBy.ByName || l.LocateBy == eLocateBy.ByID || l.LocateBy == eLocateBy.ByClassName || l.LocateBy == eLocateBy.ByCSSSelector || l.LocateBy == eLocateBy.ByLinkText || l.LocateBy == eLocateBy.ByTagName || l.LocateBy == eLocateBy.ByRelXPath)).FirstOrDefault();
if (firstLocator == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"No active or supported locator found in the current POM");
act.Error = "No active or supported locators found in the current POM";
return;
}

locateBy = firstLocator.LocateBy;
locateValue = firstLocator.LocateValue;
}
try
{
if (String.IsNullOrEmpty(locateValue))
{
throw new ArgumentNullException();

}
}
catch (ArgumentNullException ex)
{
act.Error = $"For {act.SyncOperations} operation Locate value is missing or invalid input.";
Reporter.ToLog(eLogLevel.ERROR, act.Error, ex);
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor for improved readability and maintainability.

The method contains complex nested conditions and multiple return statements that can be refactored for better clarity. Additionally, the exception handling for ArgumentNullException should provide more specific error messages to aid in debugging.

- if (String.IsNullOrEmpty(locateValue))
- { 
-     throw new ArgumentNullException();
- }
+ if (String.IsNullOrEmpty(locateValue))
+ { 
+     throw new ArgumentNullException("locateValue", "Locate value cannot be null or empty.");
+ }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
eLocateBy locateBy = act.ElementLocateBy;
string locateValue = act.ElementLocateValueForDriver;
if (act.ElementLocateBy == eLocateBy.POMElement)
{
POMExecutionUtils pomExcutionUtil = new(act, act.ElementLocateValue);
if (pomExcutionUtil.GetCurrentPOM() == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"Current POM not found from {nameof(POMExecutionUtils)}");
act.Error = "Relevant POM not found";
return;
}
ElementInfo currentPOMElementInfo = pomExcutionUtil.GetCurrentPOMElementInfo();
if (currentPOMElementInfo == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"{nameof(ElementInfo)} not found for the current POM");
act.Error = "Unable to find details about the POM";
return;
}
ElementLocator firstLocator = currentPOMElementInfo.Locators.Where(l => l.Active &&(l.LocateBy == eLocateBy.ByXPath || l.LocateBy == eLocateBy.ByName || l.LocateBy == eLocateBy.ByID || l.LocateBy == eLocateBy.ByClassName || l.LocateBy == eLocateBy.ByCSSSelector || l.LocateBy == eLocateBy.ByLinkText || l.LocateBy == eLocateBy.ByTagName || l.LocateBy == eLocateBy.ByRelXPath)).FirstOrDefault();
if (firstLocator == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"No active or supported locator found in the current POM");
act.Error = "No active or supported locators found in the current POM";
return;
}
locateBy = firstLocator.LocateBy;
locateValue = firstLocator.LocateValue;
}
try
{
if (String.IsNullOrEmpty(locateValue))
{
throw new ArgumentNullException();
}
}
catch (ArgumentNullException ex)
{
act.Error = $"For {act.SyncOperations} operation Locate value is missing or invalid input.";
Reporter.ToLog(eLogLevel.ERROR, act.Error, ex);
return;
}
eLocateBy locateBy = act.ElementLocateBy;
string locateValue = act.ElementLocateValueForDriver;
if (act.ElementLocateBy == eLocateBy.POMElement)
{
POMExecutionUtils pomExcutionUtil = new(act, act.ElementLocateValue);
if (pomExcutionUtil.GetCurrentPOM() == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"Current POM not found from {nameof(POMExecutionUtils)}");
act.Error = "Relevant POM not found";
return;
}
ElementInfo currentPOMElementInfo = pomExcutionUtil.GetCurrentPOMElementInfo();
if (currentPOMElementInfo == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"{nameof(ElementInfo)} not found for the current POM");
act.Error = "Unable to find details about the POM";
return;
}
ElementLocator firstLocator = currentPOMElementInfo.Locators.Where(l => l.Active &&(l.LocateBy == eLocateBy.ByXPath || l.LocateBy == eLocateBy.ByName || l.LocateBy == eLocateBy.ByID || l.LocateBy == eLocateBy.ByClassName || l.LocateBy == eLocateBy.ByCSSSelector || l.LocateBy == eLocateBy.ByLinkText || l.LocateBy == eLocateBy.ByTagName || l.LocateBy == eLocateBy.ByRelXPath)).FirstOrDefault();
if (firstLocator == null)
{
Reporter.ToLog(eLogLevel.ERROR, $"No active or supported locator found in the current POM");
act.Error = "No active or supported locators found in the current POM";
return;
}
locateBy = firstLocator.LocateBy;
locateValue = firstLocator.LocateValue;
}
try
{
if (String.IsNullOrEmpty(locateValue))
{
throw new ArgumentNullException("locateValue", "Locate value cannot be null or empty.");
}
}
catch (ArgumentNullException ex)
{
act.Error = $"For {act.SyncOperations} operation Locate value is missing or invalid input.";
Reporter.ToLog(eLogLevel.ERROR, act.Error, ex);
return;
}

Comment on lines +46 to +47
using Microsoft.Azure.Cosmos.Linq;
using Microsoft.HBase.Client.Internal;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

Verify the usage of new namespaces.

The namespaces Microsoft.Azure.Cosmos.Linq and Microsoft.HBase.Client.Internal are only referenced in the using statements and not actually used in the codebase. Please remove these unnecessary imports to clean up the code.

  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/Database/ActDBValidation.cs
Analysis chain

Verify the usage of new namespaces.

The addition of Microsoft.Azure.Cosmos.Linq and Microsoft.HBase.Client.Internal suggests new functionalities related to Azure Cosmos DB and HBase. Please ensure these libraries are actually used in the project to justify their inclusion.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the usage of the newly added namespaces in the project.

# Test: Search for the usage of the namespaces. Expect: At least one occurrence in the project.
rg --type python 'Microsoft.Azure.Cosmos.Linq|Microsoft.HBase.Client.Internal'

Length of output: 111



Script:

#!/bin/bash
# Description: Verify the usage of the newly added namespaces in the project.

# Test: Search for the usage of the namespaces. Expect: At least one occurrence in the project.
rg 'Microsoft.Azure.Cosmos.Linq|Microsoft.HBase.Client.Internal'

Length of output: 368

@Maheshkale447
Maheshkale447 changed the base branch from Releases/Beta to master June 21, 2024 13:38
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs Outdated
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs Outdated
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs Outdated
@GokulBothe
GokulBothe requested a review from Maheshkale447 June 21, 2024 17:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Outside diff range and nitpick comments (2)
Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (2)

69-69: Redundant property initialization.

The property ObjectLocatorConfigsNeeded is redundantly initialized to false which is already its default value. Consider removing the explicit setting if the default behavior is intended.


207-208: Ensure consistent documentation.

The documentation for properties like AttributeValue, AttributeName, TxtMatchInput, and UrlMatches is missing. Adding summaries for these properties would improve code readability and maintainability.

Also applies to: 222-223, 239-240, 255-256

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b8ae92d and 4726009.

Files selected for processing (3)
  • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs (4 hunks)
  • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (8 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (4 hunks)
Files not reviewed due to errors (1)
  • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs (no review received)
Files skipped from review as they are similar to previous changes (1)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
Additional context used
GitHub Check: Codacy Static Code Analysis
Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs

[failure] 96-96: Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs#L96
Change the visibility of 'ElementLocateValue' or make it 'const' or 'readonly'.


[failure] 97-97: Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs#L97
Change the visibility of 'ValueToSelect' or make it 'const' or 'readonly'.

Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs

[warning] 44-44: Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs#L44
Remove this commented out code.


[notice] 98-98: Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs#L98
Replace this 'switch' statement with 'if' statements to increase readability.

using Amdocs.Ginger.Common;
using Amdocs.Ginger.Common.Enums;
using Amdocs.Ginger.Common.InterfacesLib;
using Amdocs.Ginger.Common.UIElement;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider grouping related imports.

The imports are scattered and could be grouped for better readability. Grouping related namespaces together helps in maintaining a clean and organized code structure.

+ using Amdocs.Ginger.Common.UIElement;
+ using GingerCore.Actions.Common;
- using Amdocs.Ginger.Common.UIElement;
- using GingerCore.Actions.Common;

Also applies to: 26-26

Comment on lines +170 to +180
public string ElementLocateValue
{
get
{
return GetOrCreateInputParam(nameof(ElementLocateValue)).Value;
}
set
{
GetOrCreateInputParam(nameof(ElementLocateValue)).Value = value;
OnPropertyChanged(nameof(ElementLocateValue));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize property setting for ElementLocateValue.

The setter of ElementLocateValue is redundantly checking and setting values which can be simplified.

- GetOrCreateInputParam(nameof(ElementLocateValue)).Value = value;
+ if (GetOrCreateInputParam(nameof(ElementLocateValue)).Value != value) {
+     GetOrCreateInputParam(nameof(ElementLocateValue)).Value = value;
+     OnPropertyChanged(nameof(ElementLocateValue));
+ }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public string ElementLocateValue
{
get
{
return GetOrCreateInputParam(nameof(ElementLocateValue)).Value;
}
set
{
GetOrCreateInputParam(nameof(ElementLocateValue)).Value = value;
OnPropertyChanged(nameof(ElementLocateValue));
}
public string ElementLocateValue
{
get
{
return GetOrCreateInputParam(nameof(ElementLocateValue)).Value;
}
set
{
if (GetOrCreateInputParam(nameof(ElementLocateValue)).Value != value) {
GetOrCreateInputParam(nameof(ElementLocateValue)).Value = value;
OnPropertyChanged(nameof(ElementLocateValue));
}
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 4726009 and fbc0eba.

Files selected for processing (3)
  • Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs (4 hunks)
  • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (8 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (18 hunks)
Files skipped from review as they are similar to previous changes (1)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
Additional context used
GitHub Check: Codacy Static Code Analysis
Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs

[notice] 94-94: Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs#L94
Replace this 'switch' statement with 'if' statements to increase readability.

Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs

[failure] 111-111: Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs#L111
Change the visibility of 'ElementLocateValue' or make it 'const' or 'readonly'.


[failure] 112-112: Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs#L112
Change the visibility of 'ValueToSelect' or make it 'const' or 'readonly'.

Additional comments not posted (5)
Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs (3)

62-62: Event subscription in constructor.

Subscribing to the SelectionChanged event within the constructor is good practice as it sets up UI behavior early. Ensure that there is a corresponding unsubscribe to prevent memory leaks if the page is disposed.


65-65: Method ElementLocateByComboBox_SelectionChanged properly resets properties.

This method effectively resets multiple properties to an empty string, which seems intended to clear the state when the selection changes. Ensure this aligns with the expected behavior.


43-43: Initialization of mExistingPOMAndElementGuidString.

The variable mExistingPOMAndElementGuidString is initialized to null but is not used elsewhere in the provided code. Please ensure that it is used appropriately or consider removing it if it's redundant.

Verification successful

Initialization of mExistingPOMAndElementGuidString.

The variable mExistingPOMAndElementGuidString is initialized to null and is used in a conditional statement. Therefore, it is not redundant and should be kept.

  • Line 43: string mExistingPOMAndElementGuidString = null;
  • Line 45: if (mExistingPOMAndElementGuidString != mAction.LocateValue)
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Search usage of mExistingPOMAndElementGuidString in the entire file.
rg --type python 'mExistingPOMAndElementGuidString' Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs

Length of output: 152



Script:

#!/bin/bash
# Description: Search usage of mExistingPOMAndElementGuidString in the entire file.
rg --type cs 'mExistingPOMAndElementGuidString' Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs

Length of output: 246

Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (2)

22-26: Improved organization of imports.

The addition of related imports together enhances the maintainability and readability of the code. Good job on organizing these logically.


91-102: List initialization for supported locator types.

The static list SupportedLocatorsTypeList is well-defined, covering all necessary locator types. This ensures that all supported types are explicitly declared and easily maintainable.

Comment on lines +31 to +37
using System.Collections.Generic;
using Amdocs.Ginger.Common.UIElement;
using System.Linq;
using OpenQA.Selenium.Appium;
using Ginger.Actions._Common.ActUIElementLib;
using GingerCore.Actions.Common;
using GingerCore.Helpers;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider organizing imports for better readability.

The imports are scattered and could be grouped to enhance readability and maintainability. Consider grouping all GingerCore related imports together, followed by Amdocs.Ginger.Common and others.

- using GingerCore.Actions;
- using GingerCore.Helpers;
- using GingerCore.GeneralLib;
- using Amdocs.Ginger.Common;
+ using Amdocs.Ginger.Common;
+ using GingerCore.Actions;
+ using GingerCore.GeneralLib;
+ using GingerCore.Helpers;

Committable suggestion was skipped due to low confidence.

/// <returns>The LocateValueEditPage.</returns>
private Page GetLocateValueEditPage(eLocateBy SelectedLocType)
{
switch (SelectedLocType)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace switch statement with if statements.

According to static analysis, replacing this switch statement with if statements could increase readability. Consider this suggestion if it makes the code clearer in your context.

- switch (SelectedLocType)
- {
-     case eLocateBy.POMElement:
-         ...
-     default:
-         ...
- }
+ if (SelectedLocType == eLocateBy.POMElement) {
+     ...
+ } else {
+     ...
+ }

Committable suggestion was skipped due to low confidence.

Tools
GitHub Check: Codacy Static Code Analysis

[notice] 94-94: Ginger/Ginger/Actions/ActionEditPages/ActWebSmartSyncEditPage.xaml.cs#L94
Replace this 'switch' statement with 'if' statements to increase readability.

Comment on lines +75 to +85
private void SetLocateValueFrame()
{
LocateValueEditFrame.ClearAndSetContent(null);
if (xLocateByComboBox.SelectedItem == null)
{
return;
}
eLocateBy SelectedLocType = (eLocateBy)((ComboEnumItem)xLocateByComboBox.SelectedItem).Value;
Page p = GetLocateValueEditPage(SelectedLocType);
LocateValueEditFrame.ClearAndSetContent(p);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor suggestion for SetLocateValueFrame.

The method performs null checks and updates UI content, which is good. However, consider simplifying the logic by encapsulating the content setting into a separate method to enhance readability and maintainability.

- if (xLocateByComboBox.SelectedItem == null)
- {
-     return;
- }
- eLocateBy SelectedLocType = (eLocateBy)((ComboEnumItem)xLocateByComboBox.SelectedItem).Value;
- Page p = GetLocateValueEditPage(SelectedLocType);
- LocateValueEditFrame.ClearAndSetContent(p);
+ UpdateLocateValueFrameContent();

Committable suggestion was skipped due to low confidence.

Comment on lines +111 to +113
public static string ElementLocateValue = "ElementLocateValue";
public static string ValueToSelect = "ValueToSelect";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Visibility and mutability of static fields.

The static fields ElementLocateValue and ValueToSelect are public and mutable. Consider making them readonly if they are not modified after initialization to ensure immutability and thread safety.

- public static string ElementLocateValue = "ElementLocateValue";
- public static string ValueToSelect = "ValueToSelect";
+ public static readonly string ElementLocateValue = "ElementLocateValue";
+ public static readonly string ValueToSelect = "ValueToSelect";
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static string ElementLocateValue = "ElementLocateValue";
public static string ValueToSelect = "ValueToSelect";
}
public static readonly string ElementLocateValue = "ElementLocateValue";
public static readonly string ValueToSelect = "ValueToSelect";
Tools
GitHub Check: Codacy Static Code Analysis

[failure] 111-111: Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs#L111
Change the visibility of 'ElementLocateValue' or make it 'const' or 'readonly'.


[failure] 112-112: Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs#L112
Change the visibility of 'ValueToSelect' or make it 'const' or 'readonly'.

Comment on lines +172 to +179
public eLocateBy ElementLocateBy
{
get { return GetOrCreateInputParam(nameof(ElementLocateBy), eLocateBy.ByID); }
set
{
GetOrCreateInputParam(nameof(ElementLocateBy)).Value = value.ToString();
OnPropertyChanged(nameof(ElementLocateBy));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize property ElementLocateBy with direct enum usage.

The property ElementLocateBy uses string conversion which can be inefficient. Consider using the enum type directly to improve performance and reduce potential bugs.

- GetOrCreateInputParam(nameof(ElementLocateBy)).Value = value.ToString();
+ GetOrCreateInputParam(nameof(ElementLocateBy)).Value = value;
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public eLocateBy ElementLocateBy
{
get { return GetOrCreateInputParam(nameof(ElementLocateBy), eLocateBy.ByID); }
set
{
GetOrCreateInputParam(nameof(ElementLocateBy)).Value = value.ToString();
OnPropertyChanged(nameof(ElementLocateBy));
}
public eLocateBy ElementLocateBy
{
get { return GetOrCreateInputParam(nameof(ElementLocateBy), eLocateBy.ByID); }
set
{
GetOrCreateInputParam(nameof(ElementLocateBy)).Value = value;
OnPropertyChanged(nameof(ElementLocateBy));
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between fbc0eba and 528e527.

Files selected for processing (1)
  • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs (8 hunks)
Files skipped from review as they are similar to previous changes (1)
  • Ginger/GingerCoreNET/ActionsLib/UI/ActWebSmartSync.cs

@coderabbitai coderabbitai Bot mentioned this pull request Feb 11, 2025
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants