diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000000..33b43cf283
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,122 @@
+# Ginger Automation AI Coding Agent Guide
+
+## Project Overview
+Ginger is a comprehensive automation IDE supporting multiple platforms (Web, Mobile, APIs, Java, Windows, PowerBuilder, Linux/Unix, Mainframe). It uses a drag-and-drop approach enabling users with or without coding skills to create automation flows.
+
+## Core Architecture Concepts
+
+### 1. Execution Hierarchy
+The fundamental execution structure follows this hierarchy:
+```
+Solution → RunSet → Runner → BusinessFlow → Activity → Action (Act)
+```
+
+- **BusinessFlow**: Top-level test scenario container (`GingerCoreCommon/Repository/BusinessFlowLib/BusinessFlow.cs`)
+- **Activity**: Group of related actions within a BusinessFlow (`GingerCoreCommon/Repository/BusinessFlowLib/Activity.cs`)
+- **Act/Action**: Individual executable step (`GingerCoreCommon/Actions/Act.cs`)
+- **Agent**: Driver wrapper that connects to target applications (`GingerCoreCommon/RunLib/Agent.cs`)
+
+### 2. Key Project Structure
+- **Ginger/**: Main WPF application (UI)
+- **GingerCoreCommon/**: Shared models and base classes
+- **GingerCoreNET/**: .NET execution engine and CLI components
+- **GingerRuntime/**: Console application entry point
+- **GingerCore/**: Legacy core components (being migrated to GingerCoreNET)
+
+### 3. Driver Architecture
+Each platform has dedicated drivers under `GingerCore/Drivers/`:
+- `SeleniumDriver` for web automation
+- `JavaDriver` for Java applications
+- `ConsoleDriverLib` for command-line interfaces
+- `WindowsAutomation` for Windows applications
+- Agents (`Agent.cs`) act as wrappers providing unified interface
+
+## Development Workflows
+
+### Building & Testing
+```powershell
+# Main build (Windows)
+dotnet build Ginger/Ginger.sln
+
+# Run tests
+./TestDotNetFramework.ps1 # Framework tests
+./CLITests.ps1 # CLI functionality tests
+
+# Console execution
+cd Ginger/GingerRuntime/bin/Release/net8.0/publish/
+dotnet GingerConsole.dll run -s "path/to/solution" -e "Environment" -r "RunSet"
+```
+
+### CLI Commands
+**Windows:**
+- `ginger.exe help` or `dotnet ginger.dll help` - Show CLI help
+- `ginger.exe run -s -e -r ` - Execute automation
+- `ginger.exe analyze -s ` - Analyze solution
+- `ginger.exe grid --port ` - Start grid mode
+
+**Linux:**
+- `dotnet gingerruntime.dll help` - Show CLI help
+- `dotnet gingerruntime.dll run -s -e -r ` - Execute automation
+- `dotnet gingerruntime.dll analyze -s ` - Analyze solution
+- `dotnet gingerruntime.dll grid --port ` - Start grid mode
+
+## Project Conventions
+
+### 1. File Organization
+- Actions inherit from `Act` class and implement platform-specific logic
+- Repository objects use `[IsSerializedForLocalRepository]` attribute for persistence
+- Test files end with `Test.cs` and use MSTest framework with `[TestClass]` and `[TestMethod]`
+
+### 2. Naming Patterns
+- Actions: `Act{PlatformType}{ActionType}` (e.g., `ActBrowserElement`, `ActConsoleCommand`)
+- Drivers: `{Platform}Driver` (e.g., `SeleniumDriver`, `JavaDriver`)
+- Pages/Windows: `{Feature}Page` or `{Feature}Window`
+
+### 3. Error Handling
+- Use `Reporter.ToLog(eLogLevel.ERROR, message)` for logging
+- Actions set `act.Error` and `act.Status = eRunStatus.Failed` on failure
+- Execution continues based on `Activity.ActionRunOption` setting
+
+## Integration Points
+
+### 1. Solution Structure
+Solutions are XML-based with this folder structure:
+```
+Solution/
+├── BusinessFlows/ # Test scenarios
+├── Activities/ # Reusable activity groups
+├── Actions/ # Shared actions
+├── Agents/ # Driver configurations
+├── Environments/ # Environment settings
+├── DataSources/ # Test data
+└── Applications/ # Target application definitions
+```
+
+### 2. Execution Engine
+- `RunsetExecutor` orchestrates execution (`GingerCoreNET/Run/RunsetExecutor.cs`)
+- `GingerExecutionEngine` handles individual runner execution
+- Execution logging via `ExecutionLogger` implementations
+- Supports parallel execution across multiple agents
+
+### 3. Plugin Architecture
+- Legacy drivers implement `DriverBase`
+- New plugins use `Agent.eAgentType.Service` with `PluginId`/`ServiceId`
+- External integrations via `ALM` (Application Lifecycle Management) connectors
+- Plugin packages defined by `Ginger.PluginPackage.json` manifest
+- Managed through `PluginsManager` (`GingerCoreNET/PlugInsLib/PluginsManager.cs`)
+
+## Critical Development Notes
+
+- **Target Framework**: .NET 8.0 with Windows 10.0.17763.0 compatibility
+- **WPF Dependencies**: Main UI uses WPF; console components are cross-platform
+- **XML Serialization**: Repository objects serialize to XML using custom attributes
+- **Multi-Threading**: Execution engine supports parallel runners; use thread-safe patterns
+- **Memory Management**: Dispose drivers properly; avoid memory leaks in long-running executions
+
+## Testing Strategy
+- Unit tests in `*Test.cs` files use dependency injection patterns
+- Integration tests use `TestResources/Solutions/` for test data
+- CLI tests verify command-line interface functionality
+- Use `mConsoleMessages` pattern for testing CLI output capture
+
+When working with this codebase, focus on the execution hierarchy and understand how Actions flow through Activities within BusinessFlows, executed by Agents that wrap platform-specific drivers.
\ No newline at end of file
diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml
index fabad6ebd7..6863b19c8f 100644
--- a/.github/workflows/Build.yml
+++ b/.github/workflows/Build.yml
@@ -67,8 +67,6 @@ jobs:
echo $save > .\Ginger\GingerCoreCommon/GingerCoreCommon.csproj
$save=(Get-Content .\Ginger\GingerInstallerScript.iss) -replace '#define MyAppVersion "*.*.*.*"','#define MyAppVersion "${{ env.gingernumber}}"'
echo $save > .\Ginger\GingerInstallerScript.iss
- $save=(Get-Content .\Ginger\GingerCore\Drivers\JavaDriverLib\GingerJavaAgent\agent\com\amdocs\ginger\GingerAgent.java) -replace 'public static final String GINGER_JAVA_AGENT_VERSION="*.*.*.*";','public static final String GINGER_JAVA_AGENT_VERSION="${{ env.gingernumber}}";'
- echo $save > .\Ginger\GingerCore\Drivers\JavaDriverLib\GingerJavaAgent\agent\com\amdocs\ginger\GingerAgent.java
$save=(Get-Content .\Ginger\GingerInstallerScriptGithub.iss) -replace '#define MyAppVersion "*.*.*.*"','#define MyAppVersion "${{ env.gingernumber}}"'
echo $save > .\Ginger\GingerInstallerScriptGithub.iss
@@ -77,8 +75,7 @@ jobs:
run: |
sed -i 's/.*<\/AssemblyVersion>/${{ env.gingernumber}}<\/AssemblyVersion>/' ./Ginger/GingerCoreCommon/GingerCoreCommon.csproj
sed -i 's/.*<\/FileVersion>/${{ env.gingernumber}}<\/FileVersion>/' ./Ginger/GingerCoreCommon/GingerCoreCommon.csproj
- sed -i 's/#define MyAppVersion ".*"/#define MyAppVersion "${{ env.gingernumber}}"/' ./Ginger/GingerInstallerScript.iss
- sed -i 's/public static final String GINGER_JAVA_AGENT_VERSION=".*";/public static final String GINGER_JAVA_AGENT_VERSION="${{ env.gingernumber}}";/' ./Ginger/GingerCore/Drivers/JavaDriverLib/GingerJavaAgent/agent/com/amdocs/ginger/GingerAgent.java
+ sed -i 's/#define MyAppVersion ".*"/#define MyAppVersion "${{ env.gingernumber}}"/' ./Ginger/GingerInstallerScript.iss
sed -i 's/#define MyAppVersion ".*"/#define MyAppVersion "${{ env.gingernumber}}"/' ./Ginger/GingerInstallerScriptGithub.iss
- name: 'Update Assembly - macOS'
@@ -86,8 +83,7 @@ jobs:
run: |
sed -i '' 's/.*<\/AssemblyVersion>/${{ env.gingernumber}}<\/AssemblyVersion>/' ./Ginger/GingerCoreCommon/GingerCoreCommon.csproj
sed -i '' 's/.*<\/FileVersion>/${{ env.gingernumber}}<\/FileVersion>/' ./Ginger/GingerCoreCommon/GingerCoreCommon.csproj
- sed -i '' 's/#define MyAppVersion ".*"/#define MyAppVersion "${{ env.gingernumber}}"/' ./Ginger/GingerInstallerScript.iss
- sed -i '' 's/public static final String GINGER_JAVA_AGENT_VERSION=".*";/public static final String GINGER_JAVA_AGENT_VERSION="${{ env.gingernumber}}";/' ./Ginger/GingerCore/Drivers/JavaDriverLib/GingerJavaAgent/agent/com/amdocs/ginger/GingerAgent.java
+ sed -i '' 's/#define MyAppVersion ".*"/#define MyAppVersion "${{ env.gingernumber}}"/' ./Ginger/GingerInstallerScript.iss
sed -i '' 's/#define MyAppVersion ".*"/#define MyAppVersion "${{ env.gingernumber}}"/' ./Ginger/GingerInstallerScriptGithub.iss
- name: 'Print OS type'
diff --git a/.github/workflows/Old/codeql-analysis.yml b/.github/workflows/Old/codeql-analysis.yml
deleted file mode 100644
index a1ed5a8907..0000000000
--- a/.github/workflows/Old/codeql-analysis.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: "CodeQL"
-
-on:
- push:
- branches: [ master, Features/Linux-Migration, Releases/*, Releases/*/* ]
- pull_request:
- # The branches below must be a subset of the branches above
- branches: [ master ]
- schedule:
- - cron: '18 16 * * 3'
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: read
- security-events: write
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'csharp', 'java', 'javascript', 'python' ]
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
- # Learn more about CodeQL language support at https://git.io/codeql-language-support
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v1
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
- # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v1
-
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 https://git.io/JvXDl
-
- # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
-
- #- run: |
- # make bootstrap
- # make release
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000000..2f19062a4a
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,112 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL Security Scan"
+
+
+on:
+ push:
+ branches: [ master, Features/Linux-Migration, Releases/*, Releases/*/*]
+ pull_request:
+ branches: [ master ]
+ schedule:
+ - cron: '0 0 * * 0'
+
+jobs:
+ analyze:
+ name: CodeQL - ${{ matrix.language }} - ${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp', 'javascript' ]
+ os: [windows-latest]
+
+# ------------------------------------------------------------------------------------------------------
+# Checkout Ginger Repository
+# ------------------------------------------------------------------------------------------------------
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+# ------------------------------------------------------------------------------------------------------
+# Initialize CodeQL
+# ------------------------------------------------------------------------------------------------------
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ config-file: ./.github/workflows/codeql-config.yml
+
+# ------------------------------------------------------------------------------------------------------
+# Install .Net core SDK 8.0.100
+# ------------------------------------------------------------------------------------------------------
+
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.100'
+
+# ------------------------------------------------------------------------------------------------------
+# Install Mono - for Ubuntu & macOS as pre-requisite for building Ginger
+# ------------------------------------------------------------------------------------------------------
+
+ - name: Install Mono - Linux
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y mono-complete
+
+ - name: 'Install Mono - macOS'
+ if: runner.os == 'macOS'
+ run: brew install mono
+
+# ------------------------------------------------------------------------------------------------------
+# Build && Publish Ginger Solution
+# ------------------------------------------------------------------------------------------------------
+
+ - name: Setup Nuget
+ uses: Nuget/setup-nuget@v1.0.5
+
+ - name: Restore Nuget Packages
+ run: nuget restore ./Ginger/Ginger.sln
+
+ - name: Add msbuild to PATH
+ if: runner.os == 'windows'
+ uses: microsoft/setup-msbuild@v1.0.2
+
+ - name: Build Windows Ginger Solution
+ if: runner.os == 'windows'
+ run: msbuild ./Ginger/Ginger.sln /p:DebugSymbols=true /p:DebugType=full /p:Configuration=Release
+
+ - name: Publish GingerRuntime - Linux
+ if: runner.os == 'Linux'
+ run: dotnet publish ./Ginger/GingerRuntime/GingerRuntime.csproj --runtime linux-x64 --self-contained true -c Release
+
+ - name: Publish GingerRuntime - macOS
+ if: runner.os == 'macOS'
+ run: dotnet publish ./Ginger/GingerRuntime/GingerRuntime.csproj --runtime osx-x64 --self-contained true -c Release
+
+# ------------------------------------------------------------------------------------------------------
+# Security Scan with CodeQL
+# ------------------------------------------------------------------------------------------------------
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{ matrix.language }}"
diff --git a/.github/workflows/codeql-config.yml b/.github/workflows/codeql-config.yml
new file mode 100644
index 0000000000..d14259082c
--- /dev/null
+++ b/.github/workflows/codeql-config.yml
@@ -0,0 +1,33 @@
+name: "CodeQL Config"
+
+paths:
+ - 'Ginger' # Only scan the Ginger directory for CodeQL
+
+paths-ignore:
+
+ # ignore build outputs
+ - '**/bin/**'
+ - '**/obj/**'
+ - '**/Release/**'
+ - '**/Debug/**'
+
+ # ignore test projects
+ - 'Ginger/GingerAutoPilotTest/**'
+ - 'Ginger/GingerConsoleTest/**'
+ - 'Ginger/GingerCoreCommonTest/**'
+ - 'Ginger/GingerCoreNETUnitTest/**'
+ - 'Ginger/GingerCoreTest/**'
+ - 'Ginger/GingerPluginCoreTest/**'
+ - 'Ginger/GingerTest/**'
+ - 'Ginger/GingerUtilsTest/**'
+ - 'Ginger/GingerWPFDriverWindowTest/**'
+
+ # more optional files to ignore
+# - '**/*.Designer.cs' # Auto-generated designer files
+# - '**/*.g.cs' # Auto-generated files
+# - '**/*.g.i.cs' # Auto-generated intermediate files
+# - '**/AssemblyInfo.cs' # Assembly info files
+# - '**/packages/**' # NuGet packages
+# - '**/node_modules' # JavaScript dependencies
+# - '**/*.min.js' # Minified JavaScript
+# - '**/*.min.css' # Minified CSS
diff --git a/Extensions/DotnetDependencies/aspnetcore-runtime-8.0.0-win-x64.exe b/Extensions/DotnetDependencies/aspnetcore-runtime-8.0.22-win-x64.exe
similarity index 56%
rename from Extensions/DotnetDependencies/aspnetcore-runtime-8.0.0-win-x64.exe
rename to Extensions/DotnetDependencies/aspnetcore-runtime-8.0.22-win-x64.exe
index 6fea7ea066..42f1fca711 100644
Binary files a/Extensions/DotnetDependencies/aspnetcore-runtime-8.0.0-win-x64.exe and b/Extensions/DotnetDependencies/aspnetcore-runtime-8.0.22-win-x64.exe differ
diff --git a/Extensions/DotnetDependencies/windowsdesktop-runtime-8.0.0-win-x64.exe b/Extensions/DotnetDependencies/windowsdesktop-runtime-8.0.22-win-x64.exe
similarity index 80%
rename from Extensions/DotnetDependencies/windowsdesktop-runtime-8.0.0-win-x64.exe
rename to Extensions/DotnetDependencies/windowsdesktop-runtime-8.0.22-win-x64.exe
index 19e4c0a89b..b267bd8b2e 100644
Binary files a/Extensions/DotnetDependencies/windowsdesktop-runtime-8.0.0-win-x64.exe and b/Extensions/DotnetDependencies/windowsdesktop-runtime-8.0.22-win-x64.exe differ
diff --git a/Ginger/Ginger.sln b/Ginger/Ginger.sln
index 0a083df49a..0ba9413e27 100644
--- a/Ginger/Ginger.sln
+++ b/Ginger/Ginger.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.1.32319.34
+# Visual Studio Version 18
+VisualStudioVersion = 18.0.11205.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GingerCoreCommon", "GingerCoreCommon\GingerCoreCommon.csproj", "{9D569B65-EC6C-4677-A59B-CF12C24B5EB0}"
EndProject
diff --git a/Ginger/Ginger/Actions/ActionEditPage.xaml.cs b/Ginger/Ginger/Actions/ActionEditPage.xaml.cs
index cbc3f24449..7ddf2f7ac3 100644
--- a/Ginger/Ginger/Actions/ActionEditPage.xaml.cs
+++ b/Ginger/Ginger/Actions/ActionEditPage.xaml.cs
@@ -23,6 +23,7 @@ limitations under the License.
using Amdocs.Ginger.Common.Expressions;
using Amdocs.Ginger.Common.GeneralLib;
using Amdocs.Ginger.Common.UIElement;
+using Amdocs.Ginger.CoreNET.ActionsLib;
using Amdocs.Ginger.CoreNET.Execution;
using Amdocs.Ginger.Repository;
using Ginger.Actions.UserControls;
diff --git a/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml b/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml
index e0788f79bc..ed154c284c 100644
--- a/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml
+++ b/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml
@@ -1,4 +1,4 @@
-
-
+
@@ -24,18 +24,18 @@
-
+
-
+
-
+
-
+
diff --git a/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml.cs b/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml.cs
index b65f00fe02..e5ce872af0 100644
--- a/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml.cs
+++ b/Ginger/Ginger/Actions/ActionEditPages/ActConsoleCommandEditPage.xaml.cs
@@ -18,15 +18,14 @@ limitations under the License.
using amdocs.ginger.GingerCoreNET;
using Amdocs.Ginger.Common;
-using GingerCore.Actions;
-using GingerCore.GeneralLib;
+using Amdocs.Ginger.CoreNET.ActionsLib;
using GingerCoreNET.SolutionRepositoryLib.RepositoryObjectsLib.PlatformsLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Windows;
using System.Windows.Controls;
-using static GingerCore.Actions.ActConsoleCommand;
namespace Ginger.Actions
{
@@ -41,20 +40,22 @@ public partial class ActConsoleCommandEditPage : Page
string SHFilesPath = System.IO.Path.Combine(WorkSpace.Instance.Solution.Folder, @"Documents\sh\");
+
public ActConsoleCommandEditPage(ActConsoleCommand actConsoleCommand)
{
InitializeComponent();
this.mActConsoleCommand = actConsoleCommand;
+
if (mActConsoleCommand.Context != null)
{
mContext = Context.GetAsContext(mActConsoleCommand.Context);
}
List
diff --git a/Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml b/Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml
index 01cec19e2f..18ce6656f0 100644
--- a/Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml
+++ b/Ginger/Ginger/ApplicationModelsLib/POMModels/POMWizardLib/LearnWizard/POMLearnConfigWizardPage.xaml
@@ -71,7 +71,12 @@
-
+
+
-
-
@@ -94,7 +93,7 @@
x:Name="xLearnPOMByAI"
AutomationProperties.AutomationId="xLearnPOMByAICheckBox AID"
Content="Activate Smart Fine-Tuning Elements"
- Margin="7,10,0,10"
+ Margin="0,10,0,10"
IsChecked="False"
IsEnabled="False"
Visibility="Visible"
diff --git a/Ginger/Ginger/DLLs/Open3270.dll b/Ginger/Ginger/DLLs/Open3270.dll
index 7e1a0e2f18..41662f73c7 100644
Binary files a/Ginger/Ginger/DLLs/Open3270.dll and b/Ginger/Ginger/DLLs/Open3270.dll differ
diff --git a/Ginger/Ginger/DataSource/ImportExcelWizardLib/ImportDataSourceFromExcelWizard.cs b/Ginger/Ginger/DataSource/ImportExcelWizardLib/ImportDataSourceFromExcelWizard.cs
index 261109726c..2ffd9b8510 100644
--- a/Ginger/Ginger/DataSource/ImportExcelWizardLib/ImportDataSourceFromExcelWizard.cs
+++ b/Ginger/Ginger/DataSource/ImportExcelWizardLib/ImportDataSourceFromExcelWizard.cs
@@ -96,6 +96,12 @@ public override void Finish()
}
foreach (DataTable dt in ExcelImportData.Tables)
{
+ if (!IsImportEmptyColumns)
+ {
+ // Removing empty rows
+ RemoveEmptyRows(dt);
+ }
+
string cols = GetColumnNameListForTableCreation(dt);
AddDefaultColumn(dt);
CreateTable(dt.TableName, cols);
@@ -108,6 +114,31 @@ public override void Finish()
}
}
+ private void RemoveEmptyRows(DataTable dt)
+ {
+ var rowsToRemove = new List();
+ foreach (DataRow row in dt.Rows)
+ {
+ bool isEmpty = true;
+ foreach (var item in row.ItemArray)
+ {
+ if (item != null && !string.IsNullOrWhiteSpace(item.ToString()))
+ {
+ isEmpty = false;
+ break;
+ }
+ }
+ if (isEmpty)
+ {
+ rowsToRemove.Add(row);
+ }
+ }
+ foreach (var row in rowsToRemove)
+ {
+ dt.Rows.Remove(row);
+ }
+ }
+
///
/// This method is used to get the columnList for exporting the parameters to datasource
///
diff --git a/Ginger/Ginger/DotNetFrameworkHelper.cs b/Ginger/Ginger/DotNetFrameworkHelper.cs
index 82d9fd2468..0017e22107 100644
--- a/Ginger/Ginger/DotNetFrameworkHelper.cs
+++ b/Ginger/Ginger/DotNetFrameworkHelper.cs
@@ -21,6 +21,7 @@ limitations under the License.
using Amdocs.Ginger.Common.InterfacesLib;
using Amdocs.Ginger.Common.UIElement;
using Amdocs.Ginger.CoreNET;
+using Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Console;
using Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Web.Playwright;
using Amdocs.Ginger.Repository;
using Ginger.ALM;
diff --git a/Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml b/Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml
new file mode 100644
index 0000000000..ba5303f97d
--- /dev/null
+++ b/Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml.cs b/Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml.cs
new file mode 100644
index 0000000000..aa287783ad
--- /dev/null
+++ b/Ginger/Ginger/Drivers/DriversWindows/ConsoleDriverWindow.xaml.cs
@@ -0,0 +1,620 @@
+#region License
+/*
+Copyright © 2014-2025 European Support Limited
+
+Licensed under the Apache License, Version 2.0 (the "License")
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#endregion
+
+using Amdocs.Ginger.Common;
+using Amdocs.Ginger.Common.UIElement;
+using Amdocs.Ginger.CoreNET.ActionsLib;
+using Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Console;
+using GingerCore; // for BusinessFlow and eLocateBy
+using GingerCore.Drivers;
+using System;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls; // added for WPF controls
+using System.Windows.Controls.Primitives; // for ScrollBar
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+
+namespace Ginger.Drivers.DriversWindows
+{
+ ///
+ /// Interaction logic for ConsoleDriverWindow.xaml
+ ///
+ public partial class ConsoleDriverWindow : Window
+ {
+ bool mRecording = false;
+ StringBuilder mConsoleBuffer = new StringBuilder();
+
+ // default brush style
+ Brush ConsoleBackgroundBrush = Brushes.White;
+ Brush ConsoleTextBrush = Brushes.Green;
+ Brush ConsoleCommandBrush = Brushes.Blue;
+ Brush ConsoleErrorBrush = Brushes.Red;
+ BusinessFlow mBusinessFlow;
+
+ ConsoleDriverBase mConsoleDriver;
+ Agent mAgent;
+
+ bool mIsDarkTheme = true;
+
+ private TextBlock _recordText;
+ private TextBlock _newActionText;
+ private TextBlock _themeText;
+
+ private const string CommandPlaceholder = "Command";
+ private static readonly Color PlaceholderColor = Color.FromRgb(120, 120, 130);
+ private static readonly Color DarkThemeTextColor = Color.FromRgb(220, 220, 235);
+ private static readonly Color LightThemeTextColor = Color.FromRgb(0, 221, 0);
+
+ private void InitTextBlocks()
+ {
+ _recordText = (RecordButton.Content as StackPanel)?.Children.OfType().FirstOrDefault();
+ _newActionText = (NewActionButton.Content as StackPanel)?.Children.OfType().FirstOrDefault();
+ _themeText = (ThemeToggleButton.Content as StackPanel)?.Children.OfType().FirstOrDefault();
+ }
+
+ private void SetCommandPlaceholder()
+ {
+ if (string.IsNullOrEmpty(CommandTextBox.Text))
+ {
+ CommandTextBox.Text = CommandPlaceholder;
+ CommandTextBox.Foreground = new SolidColorBrush(PlaceholderColor);
+ }
+ }
+
+ private void RemoveCommandPlaceholder()
+ {
+ if (CommandTextBox.Text == CommandPlaceholder)
+ {
+ CommandTextBox.Text = string.Empty;
+ CommandTextBox.Foreground = mIsDarkTheme ? new SolidColorBrush(DarkThemeTextColor) : new SolidColorBrush(LightThemeTextColor);
+ }
+ }
+
+ private void CommandTextBox_GotFocus(object sender, RoutedEventArgs e) => RemoveCommandPlaceholder();
+ private void CommandTextBox_LostFocus(object sender, RoutedEventArgs e) => SetCommandPlaceholder();
+
+ private void InitializeCommonUI()
+ {
+ InitTextBlocks();
+ ApplyDarkTheme();
+ SetCommandPlaceholder();
+ }
+
+ public ConsoleDriverWindow(BusinessFlow BF)
+ {
+ InitializeComponent();
+ mBusinessFlow = BF;
+ Loaded += (_, _) => InitializeCommonUI();
+ }
+
+ public ConsoleDriverWindow(DriverBase driver, Agent agent)
+ {
+ InitializeComponent();
+ if (driver == null)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is null");
+ }
+
+ if (agent == null)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: agent is null");
+ }
+
+ if (driver is not ConsoleDriverBase)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "ConsoleDriverWindow: driver is null");
+ }
+
+ mConsoleDriver = (ConsoleDriverBase)driver;
+ mAgent = agent;
+ mBusinessFlow = driver.BusinessFlow;
+ Loaded += (_, _) => InitializeCommonUI();
+ ((DriverBase)mConsoleDriver).DriverMessageEvent += ConsoleDriverWindow_DriverMessageEvent;
+ }
+
+ #region Events
+ private async void ConsoleDriverWindow_DriverMessageEvent(object sender, DriverMessageEventArgs e)
+ {
+ switch (e.DriverMessageType)
+ {
+ case DriverBase.eDriverMessageType.DriverStatusChanged:
+ await this.Dispatcher.InvokeAsync(async () =>
+ {
+ bool connected = mConsoleDriver.IsRunning();
+ Title = mConsoleDriver.ConsoleWindowTitle() + (connected ? " (Connected)" : " (Disconnected)");
+ CommandTextBox.IsEnabled = connected;
+ RecordButton.IsEnabled = connected;
+ // Optionally show a status line if a label exists (ignore if not)
+ try
+ {
+ var statusLbl = this.FindName("xStatusLabel") as System.Windows.Controls.ContentControl;
+ if (statusLbl != null)
+ {
+ statusLbl.Content = connected ? "Connected" : "Disconnected";
+ statusLbl.Foreground = connected ? Brushes.Green : Brushes.Red;
+ }
+ }
+ catch(Exception ex)
+ {
+ Reporter.ToLog(eLogLevel.WARN, "Failed to update status label", ex);
+ }
+ });
+ break;
+
+ case DriverBase.eDriverMessageType.CloseDriverWindow:
+ // Driver is closing - close window gracefully
+ await Dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ Reporter.ToLog(eLogLevel.DEBUG, "Closing console window per driver request");
+
+ // Unsubscribe from events to prevent recursive calls
+ if (mConsoleDriver != null)
+ {
+ ((DriverBase)mConsoleDriver).DriverMessageEvent -= ConsoleDriverWindow_DriverMessageEvent;
+ }
+
+ // Close window
+ this.Close();
+ }
+ catch (Exception ex)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "Error closing console window", ex);
+ }
+ });
+ break;
+
+ case DriverBase.eDriverMessageType.ConsoleBufferUpdate:
+ // After a command/action finished, we can auto-scroll or update UI if needed
+ await Dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ if (sender is string)
+ {
+ ConsoleWriteCommand((string)sender);
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "Failed to write console buffer update", ex);
+ }
+ });
+ break;
+
+ case DriverBase.eDriverMessageType.RecordingEvent:
+ // sender carries bool (recording on/off)
+ if (sender is bool recFlag)
+ {
+ await Dispatcher.InvokeAsync(() =>
+ {
+ mRecording = recFlag;
+ RecordButton.Foreground = mRecording ? Brushes.Red : Brushes.Black;
+ });
+ }
+ break;
+
+ }
+ }
+
+ private void ConsoleDriverWindow_Closing(Object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ // Prevent recursive calls
+ if (mConsoleDriver == null)
+ {
+ return;
+ }
+
+ mRecording = false;
+
+ try
+ {
+ // Unsubscribe from events first
+ ((DriverBase)mConsoleDriver).DriverMessageEvent -= ConsoleDriverWindow_DriverMessageEvent;
+
+ // Only disconnect if driver is still running
+ if (mConsoleDriver.IsRunning())
+ {
+ Reporter.ToLog(eLogLevel.DEBUG, "User closed console window - disconnecting driver");
+ mConsoleDriver.Disconnect();
+ mConsoleDriver.CloseDriver();
+ }
+
+ // Clear reference
+ mConsoleDriver = null;
+ }
+ catch (Exception ex)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "Error during console window closing", ex);
+ }
+ }
+
+ private void GoButton_Click(object sender, RoutedEventArgs e)
+ {
+ mConsoleDriver.CleanExpectedString();
+ RunCommand();
+ }
+
+ private void RunCommand()
+ {
+ if (string.IsNullOrEmpty(CommandTextBox.Text))
+ {
+ CommandTextBox.Text = string.Empty;
+ }
+ if (mRecording)
+ {
+ ActConsoleCommand ACC = new ActConsoleCommand
+ {
+ Description = "Command: " + CommandTextBox.Text,
+
+ LocateBy = eLocateBy.NA
+ };
+ ACC.AddOrUpdateInputParamValue("Free Command", CommandTextBox.Text);
+ ACC.ConsoleCommand = ActConsoleCommand.eConsoleCommand.FreeCommand;
+ mBusinessFlow.AddAct(ACC);
+ }
+
+ mConsoleDriver.RunConsoleCommand(CommandTextBox.Text);
+
+ CommandTextBox.Text = "";
+ }
+
+ public void ConsoleWriteCommand(string command)
+ {
+ Paragraph p = new Paragraph();
+ p.Inlines.Add(new Bold(new System.Windows.Documents.Run(command))
+ {
+ Foreground = ConsoleCommandBrush
+ });
+
+ ConsoleTextBox.Document.Blocks.Add(p);
+ ConsoleTextBox.ScrollToEnd();
+ }
+ public void ConsoleWriteText(string txt, bool applyFormat = false)
+ {
+ mConsoleBuffer.Append(txt + Environment.NewLine);
+ Paragraph p = new Paragraph
+ {
+ LineHeight = 10
+ };
+ if (applyFormat == true)
+ {
+ ApplyStyleToText(txt, ref p);
+ }
+ else
+ {
+ p.Inlines.Add(new Bold(new System.Windows.Documents.Run(txt))
+ {
+ Foreground = ConsoleTextBrush
+ });
+ }
+ ConsoleTextBox.Document.Blocks.Add(p);
+ ConsoleTextBox.ScrollToEnd();
+ }
+
+ public void ConsoleWriteError(string txt)
+ {
+ mConsoleBuffer.Append("ERROR:" + txt);
+
+ Paragraph p = new Paragraph();
+ p.Inlines.Add(new System.Windows.Documents.Bold(new System.Windows.Documents.Run("ERROR: " + txt))
+ {
+ Foreground = Foreground = ConsoleErrorBrush
+ });
+
+ ConsoleTextBox.Document.Blocks.Add(p);
+ ConsoleTextBox.ScrollToEnd();
+ }
+ private void RecordButton_Click(object sender, RoutedEventArgs e)
+ {
+ mRecording = !mRecording;
+ // Change only icon color
+ var icon = RecordIcon; // from XAML
+ if (icon != null)
+ {
+ icon.ImageForeground = mRecording ? new SolidColorBrush(Colors.Red) : (mIsDarkTheme ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Colors.Black));
+ }
+ }
+
+
+
+ private void CommandTextBox_KeyUp(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ {
+ mConsoleDriver.CleanExpectedString();
+ RunCommand();
+ }
+ }
+
+ internal string RunConsoleCommand(string Command, string WaitForText = null)
+ {
+ mConsoleBuffer.Clear();
+ CommandTextBox.Text = Command;
+ RunCommand();
+
+ string rc = mConsoleBuffer.ToString();
+ string GingerRCStart = "~~~GINGER_RC_START~~~";
+ string GingerRCEnd = "~~~GINGER_RC_END~~~";
+
+ int i = rc.IndexOf(GingerRCStart);
+ if (i > 0)
+ {
+ int i2 = rc.IndexOf(GingerRCEnd, i);
+ if (i2 > 0)
+ {
+ rc = rc.Substring(i + GingerRCStart.Length + 1, i2 - i - GingerRCEnd.Length - 4);
+ }
+ }
+ mConsoleBuffer.Clear();
+ return rc;
+ }
+
+ private void TopButton_Click(object sender, RoutedEventArgs e)
+ {
+ this.Topmost = !this.Topmost;
+ }
+
+ private void NewActionButton_Click(object sender, RoutedEventArgs e)
+ {
+ ConsoleNewActionPage CNAP = new ConsoleNewActionPage(mConsoleDriver, mBusinessFlow);
+ CNAP.ShowAsWindow(this);
+ }
+
+ private void ApplyStyleToText(string result, ref Paragraph p)
+ {
+ try
+ {
+ if (result == null)
+ {
+ result = string.Empty;
+ }
+
+ string[] splitResult = result.Split(new string[] { "\u001b[" }, StringSplitOptions.None);
+ foreach (string splitLine in splitResult)
+ {
+ if (splitLine.IndexOf("m") != -1)
+ {
+ string format = splitLine[..splitLine.IndexOf('m')];
+ string text = splitLine[(splitLine.IndexOf('m') + 1)..];
+ if (ApplyASCIICodeFormat(text, format, ref p) == false)
+ {
+ p.Inlines.Add(new System.Windows.Documents.Bold(new System.Windows.Documents.Run(splitLine)));
+ }
+ }
+ else
+ {
+ p.Inlines.Add(new System.Windows.Documents.Bold(new System.Windows.Documents.Run(splitLine)));
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "Exception in ApplyStyleToResultAsync", e);
+ }
+ }
+ private bool ApplyASCIICodeFormat(string TargetString, string format, ref Paragraph p)
+ {
+ try
+ {
+ string[] arrFormat = format.Split(';');
+ System.Windows.Documents.Inline txtElem = new System.Windows.Documents.Run(TargetString);
+ foreach (string strformat in arrFormat)
+ {
+ switch (Convert.ToInt32(strformat))
+ {
+ case 0://Reset
+ break;
+ case 1://Bold
+ txtElem = new System.Windows.Documents.Bold(txtElem);
+ break;
+ case 3://Italic
+ txtElem.FontStyle = FontStyles.Italic;
+ break;
+ case 4://Underline
+ p.TextDecorations = System.Windows.TextDecorations.Underline;
+ break;
+ case 7://Reverse foreground & background
+ break;
+ case 9://Strike Through
+ p.TextDecorations = System.Windows.TextDecorations.Strikethrough;
+ break;
+ case 22://Bold Off
+ case 23://Italic Off
+ case 24://Underline off
+ case 27://Inverse off
+ p.FontStyle = FontStyles.Normal;
+ break;
+ case 29://StrikeThrough off
+ p.TextDecorations = null;
+ break;
+ case 30://Foreground Color to Black
+ txtElem.Foreground = System.Windows.Media.Brushes.Black;
+ break;
+ case 31://Foreground Color to Red
+ txtElem.Foreground = System.Windows.Media.Brushes.Red;
+ break;
+ case 32://Foreground Color to Green
+ txtElem.Foreground = System.Windows.Media.Brushes.LightGreen;
+ break;
+ case 33://Foreground Color to Yellow
+ txtElem.Foreground = System.Windows.Media.Brushes.Yellow;
+ break;
+ case 34://Foreground Color to blue
+ txtElem.Foreground = System.Windows.Media.Brushes.LightBlue;
+ break;
+ case 35://Foreground Color to Magenta
+ txtElem.Foreground = System.Windows.Media.Brushes.Magenta;
+ break;
+ case 36://Foreground Color to Cyan
+ txtElem.Foreground = System.Windows.Media.Brushes.Cyan;
+ break;
+ case 37://Foreground Color to White
+ txtElem.Foreground = System.Windows.Media.Brushes.White;
+ break;
+ case 39://Foreground Color to Default (White)
+ txtElem.Foreground = System.Windows.Media.Brushes.White;
+ break;
+ case 40://Foreground Color to Black
+ txtElem.Background = System.Windows.Media.Brushes.Black;
+ break;
+ case 41://Background Color to Red
+ txtElem.Background = System.Windows.Media.Brushes.Red;
+ break;
+ case 42://Background Color to Green
+ txtElem.Background = System.Windows.Media.Brushes.LightGreen;
+ break;
+ case 43://Background Color to Yellow
+ txtElem.Background = System.Windows.Media.Brushes.Yellow;
+ break;
+ case 44://Background Color to Blue
+ txtElem.Background = System.Windows.Media.Brushes.Blue;
+ break;
+ case 45://Background Color to Magenta
+ txtElem.Background = System.Windows.Media.Brushes.Magenta;
+ break;
+ case 46://Background Color to Cyan
+ txtElem.Background = System.Windows.Media.Brushes.Cyan;
+ break;
+ case 47://Background Color to white
+ txtElem.Background = System.Windows.Media.Brushes.White;
+ break;
+ case 49://Background Color to Default (Black)
+ txtElem.Background = System.Windows.Media.Brushes.Black;
+ break;
+ default:
+ break;
+ }
+ }
+ p.Inlines.Add(txtElem);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ private void ThemeToggleButton_Click(object sender, RoutedEventArgs e)
+ {
+ // Toggle based on current flag after applying opposite theme
+ if (mIsDarkTheme)
+ {
+ ApplyLightTheme();
+ }
+ else
+ {
+ ApplyDarkTheme();
+ }
+ }
+
+ private void ApplyDarkTheme()
+ {
+ TopBarBorder.Background = new SolidColorBrush(Color.FromRgb(40, 38, 59));
+ TopBarBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(55, 50, 70));
+ xRootGrid.Background = new SolidColorBrush(Color.FromRgb(12, 11, 18));
+ this.Background = xRootGrid.Background;
+ ConsoleBorder.Background = new SolidColorBrush(Color.FromRgb(18, 17, 24));
+ ConsoleBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(55, 50, 70));
+ ConsoleTextBox.Background = ConsoleBorder.Background;
+ ConsoleTextBox.Foreground = new SolidColorBrush(Color.FromRgb(0, 170, 255));
+ // ScrollBars dark
+ ConsoleTextBox.Resources[typeof(ScrollBar)] = FindResource("DarkScrollBarStyle");
+ CommandBorder.Background = new SolidColorBrush(Color.FromRgb(40, 38, 59));
+ CommandBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(55, 50, 70));
+ CommandTextBox.Background = new SolidColorBrush(Color.FromRgb(20, 18, 29));
+ if (CommandTextBox.Text != CommandPlaceholder)
+ {
+ CommandTextBox.Foreground = new SolidColorBrush(DarkThemeTextColor);
+ }
+ // Command textbox scrollbar
+ CommandTextBox.Resources[typeof(ScrollBar)] = FindResource("DarkScrollBarStyle");
+ CommandLabelIfExists();
+ var btnBG = new SolidColorBrush(Color.FromRgb(40, 38, 59));
+ var btnBorder = new SolidColorBrush(Color.FromRgb(55, 50, 70));
+ var btnText = Brushes.White;
+ Style roundStyle = (Style)FindResource("ThemedRoundButtonStyle");
+ foreach (var b in new[] { RecordButton, NewActionButton, ThemeToggleButton, GoButton, TopButton })
+ {
+ b.Style = roundStyle; b.Background = btnBG; b.BorderBrush = btnBorder; b.Foreground = btnText;
+ }
+ _recordText?.SetValue(TextBlock.ForegroundProperty, mRecording ? Brushes.Red : btnText);
+ _newActionText?.SetValue(TextBlock.ForegroundProperty, btnText);
+ _themeText?.SetValue(TextBlock.ForegroundProperty, btnText);
+ if (xStatusLabel.Content?.ToString() == "Connected")
+ {
+ xStatusLabel.Foreground = new SolidColorBrush(Color.FromRgb(0, 220, 100));
+ }
+ mIsDarkTheme = true;
+ if (CommandTextBox.Text == CommandPlaceholder)
+ {
+ SetCommandPlaceholder();
+ }
+ }
+
+ private void ApplyLightTheme()
+ {
+ TopBarBorder.Background = Brushes.White;
+ TopBarBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(208, 208, 208));
+ xRootGrid.Background = new SolidColorBrush(Color.FromRgb(244, 244, 244));
+ this.Background = xRootGrid.Background;
+ // Keep console background same as dark mode
+ ConsoleBorder.Background = new SolidColorBrush(Color.FromRgb(18, 17, 24));
+ ConsoleBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(208, 208, 208));
+ ConsoleTextBox.Background = ConsoleBorder.Background;
+ // Optionally keep dark mode foreground for better contrast
+ ConsoleTextBox.Foreground = new SolidColorBrush(Color.FromRgb(0, 170, 255));
+ ConsoleTextBox.Resources[typeof(ScrollBar)] = FindResource("DarkScrollBarStyle");
+ CommandBorder.Background = Brushes.White;
+ CommandBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(208, 208, 208));
+ CommandTextBox.Background = new SolidColorBrush(Color.FromRgb(250, 250, 250));
+ if (CommandTextBox.Text != CommandPlaceholder)
+ {
+ CommandTextBox.Foreground = new SolidColorBrush(Color.FromRgb(51, 51, 51));
+ }
+ CommandTextBox.Resources[typeof(ScrollBar)] = FindResource("LightScrollBarStyle");
+ CommandLabelIfExists();
+ Style roundStyle = (Style)FindResource("ThemedRoundButtonStyle");
+ var btnBG = Brushes.White;
+ var btnBorder = new SolidColorBrush(Color.FromRgb(208, 208, 208));
+ var btnText = new SolidColorBrush(Color.FromRgb(51, 51, 51));
+ foreach (var b in new[] { RecordButton, NewActionButton, ThemeToggleButton, GoButton, TopButton })
+ { b.Style = roundStyle; b.Background = btnBG; b.BorderBrush = btnBorder; b.Foreground = btnText; }
+ _recordText?.SetValue(TextBlock.ForegroundProperty, mRecording ? Brushes.Red : btnText);
+ _newActionText?.SetValue(TextBlock.ForegroundProperty, btnText);
+ _themeText?.SetValue(TextBlock.ForegroundProperty, btnText);
+ if (xStatusLabel.Content?.ToString() == "Connected")
+ {
+ xStatusLabel.Foreground = Brushes.Green;
+ }
+ mIsDarkTheme = false;
+ if (CommandTextBox.Text == CommandPlaceholder)
+ {
+ SetCommandPlaceholder();
+ }
+ }
+
+ private void CommandLabelIfExists() { /* placeholder since label removed */ }
+ }
+}
+#endregion
\ No newline at end of file
diff --git a/Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml b/Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml
new file mode 100644
index 0000000000..d20fe6b145
--- /dev/null
+++ b/Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ginger/GingerCore/Drivers/ConsoleDriverLib/ConsoleNewActionPage.xaml.cs b/Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml.cs
similarity index 90%
rename from Ginger/GingerCore/Drivers/ConsoleDriverLib/ConsoleNewActionPage.xaml.cs
rename to Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml.cs
index 07e7d4363e..1622cd4f81 100644
--- a/Ginger/GingerCore/Drivers/ConsoleDriverLib/ConsoleNewActionPage.xaml.cs
+++ b/Ginger/Ginger/Drivers/DriversWindows/ConsoleNewActionPage.xaml.cs
@@ -17,12 +17,15 @@ limitations under the License.
#endregion
using Amdocs.Ginger.Common;
+using Amdocs.Ginger.CoreNET.ActionsLib;
+using Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Console;
using Ginger;
-using GingerCore.Actions;
+using GingerCore; // Added to resolve BusinessFlow reference
using System.Windows;
using System.Windows.Controls;
-namespace GingerCore.Drivers.ConsoleDriverLib
+
+namespace Ginger.Drivers.DriversWindows
{
///
/// Interaction logic for ConsoleNewActionPage.xaml
@@ -42,8 +45,8 @@ public ConsoleNewActionPage(ConsoleDriverBase CDB, BusinessFlow BF)
ACC.AddOrUpdateInputParamValue("Param 2", "");
ACC.AddOrUpdateInputParamValue("Param 3", "");
- ParamsDatGrid.ItemsSource = ACC.InputValues;
- ParamsDatGrid.AutoGenerateColumns = false;
+ ParamsDataGrid.ItemsSource = ACC.InputValues;
+ ParamsDataGrid.AutoGenerateColumns = false;
}
internal void ShowAsWindow(System.Windows.Window owner)
diff --git a/Ginger/Ginger/Drivers/DriversWindows/DriverWindowHandler.cs b/Ginger/Ginger/Drivers/DriversWindows/DriverWindowHandler.cs
index 4635ea403b..b72908940d 100644
--- a/Ginger/Ginger/Drivers/DriversWindows/DriverWindowHandler.cs
+++ b/Ginger/Ginger/Drivers/DriversWindows/DriverWindowHandler.cs
@@ -50,6 +50,7 @@ private static void DriverWindowUtils_DriverWindowEvent(DriverWindowEventArgs ar
{
DriverBase driver = args.Driver;
AgentOperations agentOperations = (AgentOperations)args.DataObject;
+
string classname = "Ginger.Drivers.DriversWindows." + ((IDriverWindow)driver).GetDriverWindowName(agentOperations.Agent.DriverType);
Type t = Assembly.GetExecutingAssembly().GetType(classname);
if (t == null)
diff --git a/Ginger/Ginger/Ginger.csproj b/Ginger/Ginger/Ginger.csproj
index ac23caf7b5..c39d3a9f2b 100644
--- a/Ginger/Ginger/Ginger.csproj
+++ b/Ginger/Ginger/Ginger.csproj
@@ -741,7 +741,7 @@
-
+
@@ -2668,6 +2668,12 @@
Always
+
+ Always
+
+
+ Always
+
Always
diff --git a/Ginger/Ginger/GingerAgentStarter.xml b/Ginger/Ginger/GingerAgentStarter.xml
index 0be4ded7cf..eb472abcba 100644
--- a/Ginger/Ginger/GingerAgentStarter.xml
+++ b/Ginger/Ginger/GingerAgentStarter.xml
@@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/ActionReport.html b/Ginger/Ginger/Reports/GingerExecutionReport/ActionReport.html
deleted file mode 100644
index b4d973cc3b..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/ActionReport.html
+++ /dev/null
@@ -1,246 +0,0 @@
-
-
-
-
-
- Ginger Action Report
-
-
- {css_path}
-
-
-
-
-
-
-
-
-
-
- {ginger_logo}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{ReportCreated}
-
-
-
-
-
-
-
-
- {js_path}
-
-
-
-
×
-
![]()
-
sdafasd asdfasdf
-
-
-
-
-
-
-
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/ActivityGroupReport.html b/Ginger/Ginger/Reports/GingerExecutionReport/ActivityGroupReport.html
deleted file mode 100644
index bb156df749..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/ActivityGroupReport.html
+++ /dev/null
@@ -1,198 +0,0 @@
-
-
-
-
- Ginger Execution Report
-
-
- {css_path}
-
-
-
-
-
-
-
-
-
-
- {ginger_logo}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{ReportCreated}
-
-
-
-
-
-
-
- {js_path}
-
-
-
-
×
-
![]()
-
sdafasd asdfasdf
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/ActivityReport.html b/Ginger/Ginger/Reports/GingerExecutionReport/ActivityReport.html
deleted file mode 100644
index db1b7fe611..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/ActivityReport.html
+++ /dev/null
@@ -1,275 +0,0 @@
-
-
-
-
-
- Ginger Activity Report
-
-
- {css_path}
-
- {js_path}
-
-
-
-
-
-
-
-
-
-
- {ginger_logo}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{ReportCreated}
-
-
-
-
-
-
-
-
-
-
-
-
×
-
![]()
-
sdafasd asdfasdf
-
-
-
-
-
-
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/BusinessFlowReport.html b/Ginger/Ginger/Reports/GingerExecutionReport/BusinessFlowReport.html
deleted file mode 100644
index 06ce6fdecf..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/BusinessFlowReport.html
+++ /dev/null
@@ -1,265 +0,0 @@
-
-
-
-
- Ginger Execution Report
-
-
- {css_path}
-
- {js_path}
-
-
-
-
-
-
-
-
-
-
- {ginger_logo}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{ReportCreated}
-
-
-
-
-
-
-
-
-
-
×
-
![]()
-
sdafasd asdfasdf
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/GingerExecutionReport.html b/Ginger/Ginger/Reports/GingerExecutionReport/GingerExecutionReport.html
deleted file mode 100644
index a1e2b1c8cb..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/GingerExecutionReport.html
+++ /dev/null
@@ -1,325 +0,0 @@
-
-
-
-
-
- Ginger Execution Report
-
-
-
- {css_path}
-
- {canvas_path}
- {js_path}
- {js_path}
-
-
-
-
-
-
-
-
-
-
- {ginger_logo}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{ReportCreated}
-
-
-
-
-
-
-
-
-
-
-
×
-
![]()
-
sdafasd asdfasdf
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/GingerRunnerReport.html b/Ginger/Ginger/Reports/GingerExecutionReport/GingerRunnerReport.html
deleted file mode 100644
index dc405ad27b..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/GingerRunnerReport.html
+++ /dev/null
@@ -1,244 +0,0 @@
-
-
-
-
-
- Ginger Execution Report
-
-
- {css_path}
-
- {js_path}
-
-
-
-
-
-
-
-
-
-
- {ginger_logo}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{ReportCreated}
-
-
-
-
-
-
-
-
-
-
×
-
![]()
-
sdafasd asdfasdf
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Ginger/Ginger/Reports/GingerExecutionReport/HTMLReports/HTMLDetailedReport.cs b/Ginger/Ginger/Reports/GingerExecutionReport/HTMLReports/HTMLDetailedReport.cs
deleted file mode 100644
index 9fae41ad93..0000000000
--- a/Ginger/Ginger/Reports/GingerExecutionReport/HTMLReports/HTMLDetailedReport.cs
+++ /dev/null
@@ -1,898 +0,0 @@
-#region License
-/*
-Copyright © 2014-2018 European Support Limited
-
-Licensed under the Apache License, Version 2.0 (the "License")
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Xml;
-using System.Xml.Linq;
-using GingerCore;
-using GingerCore.GeneralLib;
-using GingerCore.Actions;
-using Ginger.Reports;
-
-namespace Ginger.Reports
-{
- class HTMLDetailedReport : HTMLReportBase
- {
- public override string CreateReport(ReportInfo RI)
- {
- base.RI = RI;
-
- List BizFlows = RI.BusinessFlows;
-
- if (BizFlows.Count == 0)
- {
- return "There are no " + GingerDicser.GetTermResValue(eTermResKey.BusinessFlows) + " to create report";
- }
-
- string BFTableFlows = "";
- string ValFailColor = "#b01318";
- string ActFailColor = "#b01318";
- string AtvFailColor = "#b01318";
- string BFFailColor = "#D9181E";
- double TableSize = 140;
-
- string bftable = "";
-
-
- //set fail color
- if (validationFail == 0) { ValFailColor = "#105b00"; }
- if (ActivityFail == 0) { AtvFailColor = "#105b00"; }
- if (ActionFail == 0) { ActFailColor = "#105b00"; }
- if (Failcount == 0) { BFFailColor = "#109300"; }
-
- foreach (BusinessFlowReport BFR in BizFlows)
- {
- BusinessFlow BF = BFR.GetBusinessFlow();
- bftable = "";
- string runColor = "#00000";
- TableSize = TableSize + 16.7;
- if (BF.RunStatus == BusinessFlow.eBusinessFlowRunStatus.Passed)
- {
- runColor = "#107400";
- }
- else if (BF.RunStatus == BusinessFlow.eBusinessFlowRunStatus.Failed)
- {
- runColor = "#D9181E";
- }
-
- //format BF duration
- string FormatedDuration1 = string.Format("{0:D2}h:{1:D2}m:{2:D2}s", 0, 0, 0); //Added by Preeti as part of resolving defect 2147
- if (BF.Elapsed != null)
- {
- TimeSpan t1 = TimeSpan.FromMilliseconds((double)BF.Elapsed);
- FormatedDuration1 = string.Format("{0:D2}h:{1:D2}m:{2:D2}s", t1.Hours, t1.Minutes, t1.Seconds);
- }
-
- //Added as part of resolving defect 2147
- if (BF.RunStatus == BusinessFlow.eBusinessFlowRunStatus.Running )
- {
- BF.RunStatus = BusinessFlow.eBusinessFlowRunStatus.Stopped;
- }
-
-
- foreach (Activity a in BF.Activities.Where(a => a.GetType() != typeof(ErrorHandler) && a.Active == true).ToList())
- {
- //Added as part of resolving defect 2147
- if (a.Status == Activity.eActivityRunStatus.Pending || a.Status == Activity.eActivityRunStatus.Running) //(a.ElapsedSecs == null)
- {
- a.Status = Activity.eActivityRunStatus.Skipped;
- }
-
- if (a.Status == Activity.eActivityRunStatus.Passed)
- {
- runColor = "#107400";
- }
- else if (a.Status != Activity.eActivityRunStatus.Passed)
- {
- runColor = "#D9181E";
- }
- TableSize = TableSize + 16.7;
- bftable = bftable + @"
- |
- " + a.ActivityName +
- @" |
-
- " + string.Format("{0:00}h:{1:00}m:{2:00}s", a.ElapsedSecs / 3600, (a.ElapsedSecs / 60) % 60, a.ElapsedSecs % 60) +
- @" |
-
- " + a.Status.ToString() +
- @" |
-
";
- }
-
-
- BFTableFlows = BFTableFlows + @"
- |
- " + BFR.Name +
- @" |
-
- " + FormatedDuration1 +
- @" |
-
- " + BF.RunStatus.ToString() +
- @" |
-
";
- BFTableFlows = BFTableFlows + bftable;
- bftable = "";
- }
- TimeSpan t = RI.TotalExecutionTime;
- string FormatedDuration = string.Format("{0:D2}h:{1:D2}m:{2:D2}s", t.Hours, t.Minutes, t.Seconds);
-
- string html = @"
-
-
-
-
-
-
- ![]()
-
- |
-
-
-
-
-
- GINGER Automation Execution Report
-
-
- |
-
-
-
-
-
- |
-
-
-
-
- Detailed Report" +
- @"
-
-
- |
-
-
-
-
- Execution Environment : " + RI.ExecutionEnv +
- @"
-
-
-
-
-
- |
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
- EXECUTION DETAILS
-
-
-
-
-
-
-
- Execution Run Time:
-
-
- " + DateTime.Now.ToString() +
- @"
-
-
- Execution Duration:
-
-
- " + FormatedDuration +
- @"
-
-
- # "+GingerDicser.GetTermResValue(eTermResKey.BusinessFlows)+@":
-
-
- " + BizFlows.Count().ToString() +
- @"
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
- |
- |
-
-
-
-
-
-
-
-
- " +GingerDicser.GetTermResValue(eTermResKey.BusinessFlows, setToUpperCase:true)+@" PASSED
-
-
-
-
-
-
- " + Passcount.ToString() +
- @"
-
- |
-
-
- |
- |
-
-
-
-
-
-
-
-
-
- "+GingerDicser.GetTermResValue(eTermResKey.BusinessFlows, setToUpperCase:true)+ @" FAILED
-
-
-
-
-
-
- " + Failcount.ToString() +
- @"
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
- |
-
- Activities
- |
-
- Actions
- |
-
- Validations
- |
-
-
- |
- Total
- |
-
- " + ActivityCount.ToString() +
- @" |
-
- " + ActionCount.ToString() +
- @" |
-
- " + ValidationCount.ToString() +
- @" |
-
-
- |
- Passed
- |
-
- " + ActivityPass.ToString() +
- @" |
-
- " + ActionPass.ToString() +
- @" |
-
- " + ValidationPass.ToString() +
- @" |
-
-
- |
- Failed
- |
-
- " + ActivityFail.ToString() +
- @" |
-
- " + ActionFail.ToString() +
- @" |
-
- " + validationFail.ToString() +
- @" |
-
-
- |
- Skipped
- |
-
- " + ActivitySkipped.ToString() +
- @" |
-
- " + ActionSkipped.ToString() +
- @" |
-
- " + "N/A" +
- @" |
-
-
- |
- Other
- |
-
- " + ActivityOther.ToString() +
- @" |
-
- " + ActionOther.ToString() +
- @" |
-
- " + "N/A" +
- @" |
-
-
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
- "+GingerDicser.GetTermResValue(eTermResKey.BusinessFlows, setToUpperCase:true)+@" DETAILS
-
- |
-
-
- |
- "+GingerDicser.GetTermResValue(eTermResKey.BusinessFlow)+@" Name
- |
-
- Duration
- |
-
- Status
- |
- "
- + BFTableFlows +
- @"
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
- |
-
-
-
-
- Contact Us:
-
- Ginger@amdocs.com
-
- Amdocs BEAT Ginger Automation
-
-
- |
-
- |
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ![]()
-
- |
-
-
-
-
-
- GINGER Automation Execution Report
-
-
- |
-
-
-
-
-
- |
-
-
-
-
- Report Title - Run Set Long Name of Biz Flow
-
-
- |
-
-
- |
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
- EXECUTION DETAILS
-
-
-
-
-
-
-
- Execution Run Time:
-
-
- 3/26/2015 1:10:29 AM
-
-
-
- Execution Duration:
-
-
- 1234
-
-
-
- # "+GingerDicser.GetTermResValue(eTermResKey.BusinessFlows)+@":
-
-
- 134
-
-
-
-
-
-
-
-
-
-
- |
-
-
- |
- |
-
-
-
-
-
-
-
-
- " + GingerDicser.GetTermResValue(eTermResKey.Activities, setToUpperCase:true) + @" PASSED
-
-
-
-
-
-
- 122
-
-
- |
-
-
- |
- |
-
-
-
-
-
-
-
-
- " + GingerDicser.GetTermResValue(eTermResKey.Activities, setToUpperCase: true) + @" FAILED
-
-
-
-
-
-
- 12
-
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
- " +GingerDicser.GetTermResValue(eTermResKey.BusinessFlow, setToUpperCase:true) + @" DETAILS
-
- |
-
-
- |
- " +GingerDicser.GetTermResValue(eTermResKey.BusinessFlow) + @" Name
- |
-
- Duration
- |
-
- Status
- |
-
-
- |
- SCRM - Create Customer New
- |
-
- 23943
- |
-
- FAILED
- |
-
-
- |
- SCRM - Create Customer Retention Modify Existing
- |
-
- 33641
- |
-
- PASSED
- |
-
-
- |
- SCRM - Create Customer Aqcuistion Flow with Super Duper Long " +GingerDicser.GetTermResValue(eTermResKey.BusinessFlow) + @" Name for Wrapping
- |
-
- 33641
- |
-
- PASSED
- |
-
-
- |
- SCRM - Create Customer Retention Modify Existing
- |
-
- 33641
- |
-
- PASSED
- |
-
-
- |
- SCRM - Create Customer Retention Modify Existing
- |
-
- 33641
- |
-
- PASSED
- |
-
-
- |
- SCRM - Create Customer Retention Modify Existing
- |
-
- 33641
- |
-
- PASSED
- |
-
-
- |
- SCRM - Create Customer Retention Modify Existing
- |
-
- 33641
- |
-
- FAILED
- |
-
-
- |
- SCRM - Create Customer Retention Modify Existing
- |
-
- 33641
- |
-
- PASSED
- |
-
-
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
- |
-
- |
-
-
-
-
- Contact us
-
- Email me
- Sent by GINGER AUTOMATION
- AMDOCS TIS AUTOMATION
-
-
- |
-
- |
-
- |
-
-
-
- |
-
-
-