Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R&D - New Repository Serializer #3543

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Ginger/Ginger.sln
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GingerTest", "GingerTest\Gi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GingerATS", "GingerATS\GingerATS.csproj", "{2FE010E3-F1BD-4F8D-91BA-E3C452FD62BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RepositorySerializerBenchmarks", "RepositorySerializerBenchmarks\RepositorySerializerBenchmarks.csproj", "{236F653A-5243-41C2-972A-4A503D4579E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -224,6 +226,12 @@ Global
{2FE010E3-F1BD-4F8D-91BA-E3C452FD62BD}.Release|Any CPU.Build.0 = Release|Any CPU
{2FE010E3-F1BD-4F8D-91BA-E3C452FD62BD}.RemoteDebug|Any CPU.ActiveCfg = Debug|Any CPU
{2FE010E3-F1BD-4F8D-91BA-E3C452FD62BD}.RemoteDebug|Any CPU.Build.0 = Debug|Any CPU
{236F653A-5243-41C2-972A-4A503D4579E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{236F653A-5243-41C2-972A-4A503D4579E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{236F653A-5243-41C2-972A-4A503D4579E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{236F653A-5243-41C2-972A-4A503D4579E5}.Release|Any CPU.Build.0 = Release|Any CPU
{236F653A-5243-41C2-972A-4A503D4579E5}.RemoteDebug|Any CPU.ActiveCfg = Release|Any CPU
{236F653A-5243-41C2-972A-4A503D4579E5}.RemoteDebug|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ protected List<ITreeViewItem> GetChildrentGeneric<T>(RepositoryFolder<T> RF)
CollectionChangedEventManager.RemoveHandler(source: subFolders, handler: TreeFolderItems_CollectionChanged); // track sub folders
CollectionChangedEventManager.AddHandler(source: subFolders, handler: TreeFolderItems_CollectionChanged); // track sub folders

//Add direct children's
//Add direct children's
ObservableList<T> folderItems = RF.GetFolderItems();
// why we need -? in case we did refresh and reloaded the item TODO: research, make children called once
CollectionChangedEventManager.RemoveHandler(source: folderItems, handler: TreeFolderItems_CollectionChanged);
Expand Down
62 changes: 47 additions & 15 deletions Ginger/Ginger/UserControlsLib/UCTreeView/UCTreeView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,15 @@ private async Task LoadChildItems(TreeViewItem treeViewItem)
if (hadDummyNode)
{
SetRepositoryFolderIsExpanded(treeViewItem, isExpanded: true);
Stopwatch stopwatch = new();
stopwatch.Start();
await SetTreeNodeItemChilds(treeViewItem);
stopwatch.Stop();
System.Diagnostics.Debug.WriteLine($"All BusinessFlow UI Item loaded in {new DateTime(stopwatch.Elapsed.Ticks).ToString("ss:fff")}s");
Dispatcher.Invoke(() =>
{
Reporter.ToUser(eUserMsgKey.AllBusinessFlowLoadTime, new DateTime(stopwatch.Elapsed.Ticks).ToString("ss.fff"));
});
Comment on lines +277 to +285
Copy link
Contributor

Choose a reason for hiding this comment

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

The implementation of the Stopwatch to measure the loading time of UI items and the use of Dispatcher.Invoke for UI updates are good practices for optimizing UI performance. However, consider the following improvements:

  • Logging Strategy: Directly writing to System.Diagnostics.Debug (line 281) is useful during development but consider using a more flexible logging framework for production. This allows for easier control over logging levels and destinations.
  • Time Formatting: The use of new DateTime(stopwatch.Elapsed.Ticks).ToString("ss:fff") for formatting the elapsed time is a bit unconventional. Instead, you can directly use stopwatch.Elapsed.ToString("ss\\.fff") to achieve the same result with clearer intent.
  • UI Feedback: The call to Reporter.ToUser within the Dispatcher.Invoke block (lines 282-285) is a good way to provide feedback to the user. Ensure that this feedback mechanism is consistent with the rest of the application and that it does not disrupt the user experience with excessive notifications.
- System.Diagnostics.Debug.WriteLine($"All BusinessFlow UI Item loaded in {new DateTime(stopwatch.Elapsed.Ticks).ToString("ss:fff")}s");
+ Debug.WriteLine($"All BusinessFlow UI Item loaded in {stopwatch.Elapsed.ToString("ss\\.fff")}s");

- Dispatcher.Invoke(() =>
- {
-     Reporter.ToUser(eUserMsgKey.AllBusinessFlowLoadTime, new DateTime(stopwatch.Elapsed.Ticks).ToString("ss.fff"));
- });
+ // Consider a more user-friendly way to report loading times, or ensure this fits the application's logging strategy.

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.

Suggested change
Stopwatch stopwatch = new();
stopwatch.Start();
await SetTreeNodeItemChilds(treeViewItem);
stopwatch.Stop();
System.Diagnostics.Debug.WriteLine($"All BusinessFlow UI Item loaded in {new DateTime(stopwatch.Elapsed.Ticks).ToString("ss:fff")}s");
Dispatcher.Invoke(() =>
{
Reporter.ToUser(eUserMsgKey.AllBusinessFlowLoadTime, new DateTime(stopwatch.Elapsed.Ticks).ToString("ss.fff"));
});
Stopwatch stopwatch = new();
stopwatch.Start();
await SetTreeNodeItemChilds(treeViewItem);
stopwatch.Stop();
Debug.WriteLine($"All BusinessFlow UI Item loaded in {stopwatch.Elapsed.ToString("ss\\.fff")}s");
// Consider a more user-friendly way to report loading times, or ensure this fits the application's logging strategy.

GingerCore.General.DoEvents();
// remove the handler as expand data is cached now on tree
WeakEventManager<TreeViewItem, RoutedEventArgs>.RemoveHandler(treeViewItem, nameof(TreeViewItem.Expanded), TVI_Expanded);
Expand Down Expand Up @@ -315,7 +323,11 @@ private Task SetTreeNodeItemChilds(TreeViewItem TVI)

if (TVI.Tag is ITreeViewItem ITVI)
{
Stopwatch stopwatch = new();
stopwatch.Start();
List<ITreeViewItem> Childs = ITVI.Childrens();
stopwatch.Stop();
Debug.WriteLine($"All BusinessFlow TreeViewItems loaded in {new DateTime(stopwatch.Elapsed.Ticks).ToString("ss.fff")}s");

TVI.Items.Clear();
if (Childs != null)
Expand All @@ -325,26 +337,46 @@ private Task SetTreeNodeItemChilds(TreeViewItem TVI)
try
{
mSetTreeNodeItemChildsEvent = new AutoResetEvent(false);
foreach (ITreeViewItem item in Childs)
Stopwatch stopwatch2 = new();
stopwatch2.Start();
Dispatcher.Invoke(() =>
{

if (TreeChildFolderOnly == true && item.IsExpandable() == false)
//Stopwatch stopwatch3 = new();
//stopwatch3.Start();
foreach (ITreeViewItem item in Childs)
{
continue;
}
if (TreeNodesFilterByField != null)
{
if (IsTreeItemFitsFilter(item))
//Stopwatch stopwatch4 = new();
//stopwatch4.Start();
if (TreeChildFolderOnly == true && item.IsExpandable() == false)
{
Dispatcher.Invoke(() => AddItem(item, TVI));
continue;
}
if (TreeNodesFilterByField != null)
{
if (IsTreeItemFitsFilter(item))
{
//Dispatcher.Invoke(() =>
//{
AddItem(item, TVI);
//});
}
}
else
{
//Dispatcher.Invoke(() =>
//{
AddItem(item, TVI);
//});
}
//Thread.Sleep(5);
//stopwatch4.Stop();
//Debug.WriteLine($"BusinessFlow TVI Item added to Tree in {stopwatch4.Elapsed.TotalMilliseconds}ms");
}
else
{
Dispatcher.Invoke(() => AddItem(item, TVI));
}
Thread.Sleep(5);
}
//stopwatch3.Stop();
//Debug.WriteLine($"All BusinessFlow TVI Items added to Tree from Dispatcher in {stopwatch3.Elapsed.TotalSeconds}s");
});
stopwatch2.Stop();
Debug.WriteLine($"All BusinessFlow TVI Items added to Tree in {stopwatch2.Elapsed.TotalSeconds}s");
mSetTreeNodeItemChildsEvent.Set();
if (tviChildNodesLoadTaskMap.ContainsKey(TVI))
{
Comment on lines 337 to 382
Copy link
Contributor

Choose a reason for hiding this comment

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

📝 NOTE
This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [326-379]

The use of a Stopwatch to measure the time taken to load TreeViewItems (lines 326-330) and the subsequent addition of items to the TreeView within a Dispatcher.Invoke block (lines 342-377) are well-implemented for performance measurement and UI thread safety. However, there are areas for refinement:

  • Repeated Code: The pattern of starting a Stopwatch, performing operations, and then stopping it is repeated. Consider abstracting this pattern into a utility method to reduce code duplication and improve readability.
  • Performance Consideration: While measuring performance is crucial, ensure that the debug logging does not become a performance bottleneck itself, especially when processing a large number of items.
  • UI Updates: The use of Dispatcher.Invoke for adding items to the TreeView is necessary for thread safety. However, adding items one by one in a loop can be inefficient. Investigate if there's a way to batch these updates or minimize the number of UI thread invocations.
- Stopwatch stopwatch2 = new();
- stopwatch2.Start();
+ // Consider abstracting the Stopwatch usage into a utility method for better code reuse and readability.

- Dispatcher.Invoke(() =>
- {
-     foreach (ITreeViewItem item in Childs)
-     {
-         AddItem(item, TVI);
-     }
- });
+ // Explore optimizing the Dispatcher.Invoke usage for batch updates to improve performance.

Expand Down
38 changes: 36 additions & 2 deletions Ginger/GingerCoreCommon/Actions/Act.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,18 @@
using System.Drawing;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml;
using Amdocs.Ginger.Common;
using Amdocs.Ginger.Common.Actions;
using Amdocs.Ginger.Common.Enums;
using Amdocs.Ginger.Common.GeneralLib;
using Amdocs.Ginger.Common.InterfacesLib;
using Amdocs.Ginger.Common.Repository;
using Amdocs.Ginger.Common.Repository.Serialization;
using Amdocs.Ginger.Common.SourceControlLib;
using Amdocs.Ginger.Common.UIElement;
using Amdocs.Ginger.Repository;
using GingerCore.Actions.Common;
Expand Down Expand Up @@ -696,6 +701,37 @@ public ObservableList<FlowControl> ActFlowControls
}
}

private static Dictionary<string, Act> _nameToActMap = new();
private static readonly IEnumerable<string> ActAssemblyNames = new List<string>()
{
"GingerCoreCommon",
"GingerCoreNET"
};
Comment on lines +704 to +709
Copy link
Contributor

Choose a reason for hiding this comment

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

The introduction of a static dictionary _nameToActMap and a static readonly IEnumerable<string> ActAssemblyNames suggests enhancements related to action mapping and assembly name management. It's crucial to ensure that these properties are accessed and modified in a thread-safe manner, especially _nameToActMap, given its mutable nature. Consider using ConcurrentDictionary if concurrent access is expected.

- private static Dictionary<string, Act> _nameToActMap = new();
+ private static ConcurrentDictionary<string, Act> _nameToActMap = new ConcurrentDictionary<string, Act>();

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.

Suggested change
private static Dictionary<string, Act> _nameToActMap = new();
private static readonly IEnumerable<string> ActAssemblyNames = new List<string>()
{
"GingerCoreCommon",
"GingerCoreNET"
};
private static ConcurrentDictionary<string, Act> _nameToActMap = new ConcurrentDictionary<string, Act>();
private static readonly IEnumerable<string> ActAssemblyNames = new List<string>()
{
"GingerCoreCommon",
"GingerCoreNET"
};


public Act() { }

public Act(DeserializedSnapshot snapshot) : base(snapshot)
{
Active = snapshot.GetValueAsBool(nameof(Active));
Description = snapshot.GetValue(nameof(Description));
Platform = snapshot.GetValueAsEnum<ePlatformType>(nameof(Platform));
RetryMechanismInterval = snapshot.GetValueAsInt(nameof(RetryMechanismInterval));
StatusConverter = snapshot.GetValueAsEnum<eStatusConverterOptions>(nameof(StatusConverter));
WindowsToCapture = snapshot.GetValueAsEnum<eWindowsToCapture>(nameof(WindowsToCapture));
InputValues = new(snapshot.GetValues<ActInputValue>(nameof(InputValues)));
}

protected override SerializedSnapshot.Builder WriteSnapshotProperties(SerializedSnapshot.Builder snapshotBuilder)
{
return base.WriteSnapshotProperties(snapshotBuilder)
.WithValue(nameof(Active), Active.ToString())
.WithValue(nameof(Description), Description)
.WithValue(nameof(Platform), Platform.ToString())
.WithValue(nameof(RetryMechanismInterval), RetryMechanismInterval.ToString())
.WithValue(nameof(StatusConverter), StatusConverter.ToString())
.WithValue(nameof(WindowsToCapture), WindowsToCapture.ToString())
.WithValues(nameof(InputValues), InputValues.Cast<RepositoryItemBase>());
}

#region ActInputValues
public void AddInputValueParam(string ParamName)
Expand Down Expand Up @@ -2016,7 +2052,5 @@ public override string GetItemType()
{
return "Action";
}


}
}
16 changes: 16 additions & 0 deletions Ginger/GingerCoreCommon/Actions/ActInputValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Amdocs.Ginger.Common;
using Amdocs.Ginger.Common.Repository;
using Amdocs.Ginger.Common.Repository.Serialization;
using Ginger.UserControlsLib.ActionInputValueUserControlLib;
using Newtonsoft.Json;

Expand Down Expand Up @@ -224,5 +228,17 @@ public override string ItemNameField
}
}

public ActInputValue() { }

public ActInputValue(DeserializedSnapshot snapshot) : base(snapshot)
{
Param = snapshot.GetValue(nameof(Param));
}

protected override SerializedSnapshot.Builder WriteSnapshotProperties(SerializedSnapshot.Builder snapshotBuilder)
{
return base.WriteSnapshotProperties(snapshotBuilder)
.WithValue(nameof(Param), Param);
}
}
}
5 changes: 5 additions & 0 deletions Ginger/GingerCoreCommon/Actions/ActLogAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Amdocs.Ginger.Common;
using Amdocs.Ginger.Common.Enums;
using Amdocs.Ginger.Common.InterfacesLib;
using Amdocs.Ginger.Common.Repository.Serialization;
using Amdocs.Ginger.Repository;
using GingerCoreNET.SolutionRepositoryLib.RepositoryObjectsLib.PlatformsLib;

Expand All @@ -37,7 +38,7 @@
TBH.AddText("This is Log action which you can use to log any value as per configuration.");
}

public static partial class Fields

Check warning on line 41 in Ginger/GingerCoreCommon/Actions/ActLogAction.cs

View workflow job for this annotation

GitHub Actions / Build Stage / build

'ActLogAction.Fields' hides inherited member 'Act.Fields'. Use the new keyword if hiding was intended.
{
public static string SelectedLogType = "SelectedLogType";
public static string LogText = "LogText";
Expand Down Expand Up @@ -96,6 +97,10 @@

public override eImageType Image { get { return eImageType.File; } }

public ActLogAction() { }

public ActLogAction(DeserializedSnapshot snapshot) : base(snapshot) { }

eLogLevel GetLogLevel(eActionLogLevels loglevel)
{
eLogLevel logLevel;
Expand Down
8 changes: 7 additions & 1 deletion Ginger/GingerCoreCommon/Actions/ActWithoutDriver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#region License
#region License
/*
Copyright © 2014-2024 European Support Limited

Expand All @@ -18,6 +18,7 @@


using Amdocs.Ginger.Common;
using Amdocs.Ginger.Common.Repository.Serialization;
using GingerCore.DataSource;
using GingerCore.Environments;

Expand All @@ -28,6 +29,11 @@ public abstract class ActWithoutDriver : Act
public BusinessFlow RunOnBusinessFlow;
public ProjEnvironment RunOnEnvironment;
public ObservableList<DataSourceBase> DSList;

public ActWithoutDriver() { }

public ActWithoutDriver(DeserializedSnapshot snapshot) : base(snapshot) { }

public abstract void Execute();
}
}
3 changes: 3 additions & 0 deletions Ginger/GingerCoreCommon/FodyWeavers.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<MethodTimer />
</Weavers>
26 changes: 26 additions & 0 deletions Ginger/GingerCoreCommon/FodyWeavers.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="MethodTimer" minOccurs="0" maxOccurs="1" type="xs:anyType" />
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
6 changes: 6 additions & 0 deletions Ginger/GingerCoreCommon/GingerCoreCommon.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
<CodeAnalysisRuleSet>GingerCoreCommon.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Repository\TempSerializers\**" />
<EmbeddedResource Remove="Repository\TempSerializers\**" />
<None Remove="Repository\TempSerializers\**" />
</ItemGroup>
Comment on lines +35 to +39
Copy link
Contributor

Choose a reason for hiding this comment

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

The removal of Repository\TempSerializers\** from compilation, embedding, and non-source file references is a good cleanup step if these serializers are indeed obsolete or have been replaced. Ensure that no other parts of the project depend on these files, as their removal could potentially break functionality if they are still in use elsewhere.


<ItemGroup>
<PackageReference Include="Ginger.External" Version="1.0.0" />
<PackageReference Include="LiteDB" Version="5.0.17" />
Expand Down
3 changes: 3 additions & 0 deletions Ginger/GingerCoreCommon/ReporterLib/UserMsgsPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace Amdocs.Ginger.Common
{
public enum eUserMsgKey
{
AllBusinessFlowLoadTime,
GeneralErrorOccured, MissingImplementation, MissingImplementation2, ApplicationInitError, PageLoadError, UserProfileLoadError, ItemToSaveWasNotSelected, ToSaveChanges, SaveLocalChanges, LooseLocalChanges,
RegistryValuesCheckFailed, AddRegistryValue, AddRegistryValueSucceed, AddRegistryValueFailed,
NoItemWasSelected, AskToAddCheckInComment, FailedToGetProjectsListFromSVN, AskToSelectSolution, UpdateToRevision, CommitedToRevision, GitUpdateState, SourceControlConnFaild, SourceControlRemoteCannotBeAccessed, SourceControlUnlockFaild, SourceControlConnSucss, SourceControlLockSucss, SourceControlUnlockSucss, SourceControlConnMissingConnInputs, SourceControlConnMissingLocalFolderInput,
Expand Down Expand Up @@ -193,6 +194,8 @@ public static void LoadUserMsgsPool()
//Initialize the pool
Reporter.UserMsgsPool = new Dictionary<eUserMsgKey, UserMsg>();

Reporter.UserMsgsPool.Add(eUserMsgKey.AllBusinessFlowLoadTime, new UserMsg(eUserMsgType.INFO, "BusinessFlows Load Time", "All Business Flows loaded in {0}s.", eUserMsgOption.OK, eUserMsgSelection.OK));

//Add user messages to the pool
#region General Application Messages
Reporter.UserMsgsPool.Add(eUserMsgKey.GherkinNotifyFeatureFileExists, new UserMsg(eUserMsgType.ERROR, "Feature File Already Exists", "Feature File with the same name already exist - '{0}'." + Environment.NewLine + "Please select another Feature File to continue.", eUserMsgOption.OK, eUserMsgSelection.None));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Amdocs.Ginger.Common;
using Amdocs.Ginger.Common.Enums;
using Amdocs.Ginger.Common.InterfacesLib;
using Amdocs.Ginger.Common.Repository;
using Amdocs.Ginger.Common.Repository.Serialization;
using Amdocs.Ginger.Common.WorkSpaceLib;
using Amdocs.Ginger.Repository;

Expand All @@ -49,8 +51,19 @@
set { _executionLoggerStatus = value; }
}

public ActivitiesGroup()
public ActivitiesGroup() { }

public ActivitiesGroup(DeserializedSnapshot snapshot) : base(snapshot)
{
Name = snapshot.GetValue(nameof(Name));
ActivitiesIdentifiers = new(snapshot.GetValues<ActivityIdentifiers>(nameof(ActivitiesIdentifiers)));
}
Comment on lines +56 to +60
Copy link
Contributor

Choose a reason for hiding this comment

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

The constructor ActivitiesGroup(DeserializedSnapshot snapshot) correctly initializes the Name and ActivitiesIdentifiers properties from the provided snapshot. This approach ensures that the object is properly initialized with data from a deserialization process. However, it's important to ensure that the snapshot argument is not null before accessing its methods to prevent potential NullReferenceException.

+ if (snapshot == null) throw new ArgumentNullException(nameof(snapshot));

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.

Suggested change
public ActivitiesGroup(DeserializedSnapshot snapshot) : base(snapshot)
{
Name = snapshot.GetValue(nameof(Name));
ActivitiesIdentifiers = new(snapshot.GetValues<ActivityIdentifiers>(nameof(ActivitiesIdentifiers)));
}
public ActivitiesGroup(DeserializedSnapshot snapshot) : base(snapshot)
{
if (snapshot == null) throw new ArgumentNullException(nameof(snapshot));
Name = snapshot.GetValue(nameof(Name));
ActivitiesIdentifiers = new(snapshot.GetValues<ActivityIdentifiers>(nameof(ActivitiesIdentifiers)));
}


protected override SerializedSnapshot.Builder WriteSnapshotProperties(SerializedSnapshot.Builder snapshotBuilder)
{
return base.WriteSnapshotProperties(snapshotBuilder)
.WithValue(nameof(Name), Name)
.WithValues(nameof(ActivitiesIdentifiers), ActivitiesIdentifiers.Cast<RepositoryItemBase>());
}

private string mName;
Expand Down Expand Up @@ -172,7 +185,7 @@
}

[IsSerializedForLocalRepository]
public string ExternalID2 { get; set; } // used to store the actual TC ID when importing it from QC in case the TC type is linked TC

Check warning on line 188 in Ginger/GingerCoreCommon/Repository/BusinessFlowLib/ActivitiesGroup.cs

View workflow job for this annotation

GitHub Actions / Build Stage / build

'ActivitiesGroup.ExternalID2' hides inherited member 'RepositoryItemBase.ExternalID2'. Use the new keyword if hiding was intended.


public string AutomationPrecentage
Expand Down Expand Up @@ -520,6 +533,5 @@
ExternalIdCalculated = ve.ValueCalculated;
}
}

}
}
Loading
Loading