feat: expand cockpit integrations and support workflows
Add Phoenix remote desktop, action connector, documentation engine, and gamification support. Refactor support-case processing and search/action UI, and update installer assets and dependencies.
This commit is contained in:
12
F4SD-ActionConnector/Models/ActionContext.cs
Normal file
12
F4SD-ActionConnector/Models/ActionContext.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using F4SD.ActionConnector.Payloads;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public sealed class ActionContext
|
||||
{
|
||||
public TriggerEvent TriggerEvent { get; set; }
|
||||
public bool AwaitResult { get; set; }
|
||||
public PayloadBase Payload { get; set; }
|
||||
}
|
||||
}
|
||||
38
F4SD-ActionConnector/Models/ActionDefinitionBase.cs
Normal file
38
F4SD-ActionConnector/Models/ActionDefinitionBase.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using System;
|
||||
using System.Xml;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public abstract class ActionDefinitionBase
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public abstract ActionType Type { get; }
|
||||
public bool AwaitResult { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool IsValid { get; private protected set; }
|
||||
|
||||
protected ActionDefinitionBase(XmlElement xNode, cXmlParser parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
Id = cXmlParser.GetStringFromXmlAttribute(xNode, "Id");
|
||||
AwaitResult = cXmlParser.GetBoolFromXmlAttribute(xNode, "AwaitResult");
|
||||
IsEnabled = cXmlParser.GetBoolFromXmlAttribute(xNode, "IsEnabled");
|
||||
|
||||
XmlNode descriptionNode = xNode.SelectSingleNode("Description");
|
||||
if (descriptionNode != null)
|
||||
Description = cXmlParser.GetInnerTextFromXmlElement(descriptionNode);
|
||||
|
||||
IsValid = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
F4SD-ActionConnector/Models/ActionResult.cs
Normal file
41
F4SD-ActionConnector/Models/ActionResult.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public sealed class ActionResult
|
||||
{
|
||||
public string ActionId { get; set; }
|
||||
public ActionResultStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP status code for HttpCall actions; null for other types.
|
||||
/// </summary>
|
||||
public int? HttpStatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw response body (HttpCall) or serialized output (QuickAction).
|
||||
/// </summary>
|
||||
public string RawResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Named fields extracted from the response via jsonPath mappings.
|
||||
/// Populated when DisplayInCockpit is true.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> MappedFields { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable error message; set when Status is Failure.
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public static ActionResult Ok(string actionId, string rawResponse = null)
|
||||
=> new ActionResult { ActionId = actionId, Status = ActionResultStatus.Success, RawResponse = rawResponse };
|
||||
|
||||
public static ActionResult Fail(string actionId, string errorMessage)
|
||||
=> new ActionResult { ActionId = actionId, Status = ActionResultStatus.Failure, ErrorMessage = errorMessage };
|
||||
|
||||
public static ActionResult Skip(string actionId)
|
||||
=> new ActionResult { ActionId = actionId, Status = ActionResultStatus.Skipped };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
internal class ExternalCommunicationConfiguration
|
||||
{
|
||||
private const string FileNameConfig = "F4SD-ExternalCommunication-Configuration.xml";
|
||||
private const string FileNameConfigSchema = "F4SD-ExternalCommunication-Configuration.xsd";
|
||||
private const string ConfigRootElement = "F4SD-ExternalCommunication-Configuration";
|
||||
|
||||
public IDictionary<TriggerEvent, Trigger> Triggers { get; } = new Dictionary<TriggerEvent, Trigger>();
|
||||
|
||||
|
||||
private const string TriggersNodeName = "Triggers";
|
||||
private const string TriggerNodeName = "Trigger";
|
||||
|
||||
public void Initiate(XmlElement rootElement, cXmlParser parser)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var triggersNode = rootElement.SelectSingleNode(TriggersNodeName);
|
||||
parser.EnterElement(TriggersNodeName);
|
||||
|
||||
var triggerNodes = triggersNode.SelectNodes(TriggerNodeName);
|
||||
|
||||
if (triggerNodes is null || triggerNodes.Count == 0)
|
||||
return;
|
||||
|
||||
parser.EnterElement(TriggerNodeName);
|
||||
|
||||
foreach (XmlElement triggerNodeElement in triggerNodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
Trigger trigger = new Trigger(triggerNodeElement, parser);
|
||||
|
||||
if (trigger is null || !Triggers.ContainsKey(trigger.Event))
|
||||
continue;
|
||||
|
||||
Triggers.Add(trigger.Event, trigger);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.SelectElementNext();
|
||||
}
|
||||
}
|
||||
|
||||
parser.LeaveElement(TriggerNodeName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.LeaveElement(TriggersNodeName);
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
F4SD-ActionConnector/Models/HttpCallDefinition.cs
Normal file
30
F4SD-ActionConnector/Models/HttpCallDefinition.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Xml;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public sealed class HttpCallDefinition : ActionDefinitionBase
|
||||
{
|
||||
public override ActionType Type => ActionType.HttpCall;
|
||||
|
||||
public string Url { get; set; }
|
||||
public HttpMethod Method { get; set; } = HttpMethod.Post;
|
||||
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
|
||||
public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
|
||||
public string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// jsonPath expressions keyed by field name, used to extract values from the response.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> MappedFieldJsonPaths { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
internal HttpCallDefinition(XmlElement xNode, cXmlParser parser) : base(xNode, parser)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
105
F4SD-ActionConnector/Models/QuickActionDefinition.cs
Normal file
105
F4SD-ActionConnector/Models/QuickActionDefinition.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public sealed class QuickActionDefinition : ActionDefinitionBase
|
||||
{
|
||||
private const string ParametersNodeName = "Parameters";
|
||||
private const string ParameterNodeName = "Parameter";
|
||||
|
||||
public override ActionType Type => ActionType.QuickAction;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the Quick Action to invoke, e.g. "Protocol case in JIRA".
|
||||
/// </summary>
|
||||
public string QuickActionRef { get; set; }
|
||||
|
||||
public IDictionary<string, string> Parameters { get; private set; } = new Dictionary<string, string>();
|
||||
|
||||
internal QuickActionDefinition(XmlElement xNode, cXmlParser parser) : base(xNode, parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsValid) return; else IsValid = false;
|
||||
|
||||
XmlNode quickActionRefNode = xNode.SelectSingleNode("QuickActionRef");
|
||||
if (quickActionRefNode is null)
|
||||
return;
|
||||
|
||||
QuickActionRef = cXmlParser.GetInnerTextFromXmlElement(quickActionRefNode);
|
||||
|
||||
if (QuickActionRef is null)
|
||||
return;
|
||||
|
||||
XmlNode parametersNode = xNode.SelectSingleNode(ParametersNodeName);
|
||||
if (parametersNode != null && parametersNode is XmlElement paramtersNodeElement)
|
||||
ParseParametersElement(paramtersNodeElement, parser);
|
||||
|
||||
IsValid = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseParametersElement(XmlElement parametersNodeElement, cXmlParser parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
parser.EnterElement(ParametersNodeName);
|
||||
|
||||
XmlNodeList parameterNodes = parametersNodeElement.SelectNodes(ParameterNodeName);
|
||||
|
||||
if (parameterNodes?.Count > 0)
|
||||
parser.EnterElement(ParameterNodeName);
|
||||
|
||||
foreach (XmlElement parameterNode in parameterNodes)
|
||||
{
|
||||
ParseParameterElement(parameterNode, parser);
|
||||
}
|
||||
|
||||
if (parameterNodes?.Count > 0)
|
||||
parser.LeaveElement(ParameterNodeName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.LeaveElement(ParametersNodeName);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseParameterElement(XmlElement parameterNode, cXmlParser parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
string parameterName = cXmlParser.GetStringFromXmlAttribute(parameterNode, "name");
|
||||
string parameterVariable = cXmlParser.GetInnerTextFromXmlElement(parameterNode);
|
||||
|
||||
if (string.IsNullOrEmpty(parameterName) || string.IsNullOrEmpty(parameterVariable))
|
||||
return;
|
||||
|
||||
if (Parameters.ContainsKey(parameterName))
|
||||
LogEntry($"A paramter with name '{parameterName}' does allready exist.", C4IT.Logging.LogLevels.Warning);
|
||||
else
|
||||
Parameters.Add(parameterName, parameterVariable);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.SelectElementNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
F4SD-ActionConnector/Models/Trigger.cs
Normal file
101
F4SD-ActionConnector/Models/Trigger.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
internal class Trigger
|
||||
{
|
||||
public TriggerEvent Event { get; set; }
|
||||
|
||||
public IDictionary<string, ActionDefinitionBase> Actions { get; } = new Dictionary<string, ActionDefinitionBase>();
|
||||
|
||||
public bool IsValid { get; private set; }
|
||||
|
||||
private const string ActionsNodeName = "Actions";
|
||||
private const string ActionNodeName = "Action";
|
||||
|
||||
internal Trigger(XmlElement xNode, cXmlParser parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
Event = cXmlParser.GetEnumFromAttribute(xNode, "action", TriggerEvent.Unknown);
|
||||
|
||||
XmlNode actionsNode = xNode.SelectSingleNode(ActionsNodeName);
|
||||
|
||||
if (actionsNode is null || !(actionsNode is XmlElement actionsNodeElement))
|
||||
return;
|
||||
|
||||
ParseActionsNode(actionsNodeElement, parser);
|
||||
|
||||
IsValid = true; ;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseActionsNode(XmlElement actionsNode, cXmlParser parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
parser.EnterElement(ActionsNodeName);
|
||||
|
||||
var actionNodes = actionsNode.SelectNodes(ActionNodeName);
|
||||
if (actionNodes is null || actionNodes.Count == 0)
|
||||
return;
|
||||
|
||||
parser.EnterElement(ActionNodeName);
|
||||
|
||||
foreach (XmlElement actionNode in actionNodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
ActionType type = cXmlParser.GetEnumFromAttribute(actionNode, "type", ActionType.Unknown);
|
||||
|
||||
ActionDefinitionBase actionDefinition = null;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ActionType.QuickAction:
|
||||
actionDefinition = new QuickActionDefinition(actionNode, parser);
|
||||
break;
|
||||
case ActionType.HttpCall:
|
||||
break;
|
||||
case ActionType.Unknown:
|
||||
case ActionType.Webhook:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (actionDefinition?.Id != null && !Actions.ContainsKey(actionDefinition.Id))
|
||||
Actions.Add(actionDefinition.Id, actionDefinition);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.SelectElementNext();
|
||||
}
|
||||
}
|
||||
|
||||
parser.LeaveElement(ActionNodeName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.LeaveElement(ActionsNodeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user