diff --git a/F4SD-ActionConnector/Enumerations/ActionResultStatus.cs b/F4SD-ActionConnector/Enumerations/ActionResultStatus.cs
new file mode 100644
index 0000000..38353a3
--- /dev/null
+++ b/F4SD-ActionConnector/Enumerations/ActionResultStatus.cs
@@ -0,0 +1,9 @@
+namespace F4SD.ActionConnector.Enumerations
+{
+ public enum ActionResultStatus
+ {
+ Success,
+ Failure,
+ Skipped
+ }
+}
diff --git a/F4SD-ActionConnector/Enumerations/ActionType.cs b/F4SD-ActionConnector/Enumerations/ActionType.cs
new file mode 100644
index 0000000..380c4df
--- /dev/null
+++ b/F4SD-ActionConnector/Enumerations/ActionType.cs
@@ -0,0 +1,10 @@
+namespace F4SD.ActionConnector.Enumerations
+{
+ public enum ActionType
+ {
+ Unknown,
+ QuickAction,
+ HttpCall,
+ Webhook,
+ }
+}
diff --git a/F4SD-ActionConnector/Enumerations/TriggerEvent.cs b/F4SD-ActionConnector/Enumerations/TriggerEvent.cs
new file mode 100644
index 0000000..e4d1069
--- /dev/null
+++ b/F4SD-ActionConnector/Enumerations/TriggerEvent.cs
@@ -0,0 +1,10 @@
+namespace F4SD.ActionConnector.Enumerations
+{
+ public enum TriggerEvent
+ {
+ Unknown,
+ ApplicationStartup,
+ CaseClosed,
+ CaseCreated,
+ }
+}
diff --git a/F4SD-ActionConnector/Events/ActionCompletedEventArgs.cs b/F4SD-ActionConnector/Events/ActionCompletedEventArgs.cs
new file mode 100644
index 0000000..2c87c3d
--- /dev/null
+++ b/F4SD-ActionConnector/Events/ActionCompletedEventArgs.cs
@@ -0,0 +1,21 @@
+using System;
+using F4SD.ActionConnector.Models;
+using F4SD.ActionConnector.Payloads;
+
+namespace F4SD.ActionConnector.Events
+{
+ ///
+ /// Raised after a sync action finishes. Carries the result for Cockpit integration.
+ ///
+ public sealed class ActionCompletedEventArgs : EventArgs
+ {
+ public ActionResult Result { get; }
+ public ActionContext Context { get; }
+
+ public ActionCompletedEventArgs(ActionResult result, ActionContext context)
+ {
+ Result = result;
+ Context = context;
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/Events/ActionConnectorEvents.cs b/F4SD-ActionConnector/Events/ActionConnectorEvents.cs
new file mode 100644
index 0000000..3938321
--- /dev/null
+++ b/F4SD-ActionConnector/Events/ActionConnectorEvents.cs
@@ -0,0 +1,40 @@
+using System;
+using F4SD.ActionConnector.Payloads;
+
+namespace F4SD.ActionConnector.Events
+{
+ ///
+ /// Static event bus. F4SD calls the methods after a business event occurs.
+ /// The connector engine subscribes to the corresponding events and dispatches configured actions.
+ ///
+ public static class ActionConnectorEvents
+ {
+ /// Raised when a support case is closed.
+ public static event EventHandler> CaseClosed;
+
+ /// Raised when a new support case is created.
+ public static event EventHandler> CaseCreated;
+
+ /// Raised once during application startup, after configuration is loaded.
+ public static event EventHandler> ApplicationStartup;
+
+ ///
+ /// Raised after every sync action completes. The Cockpit Client subscribes here
+ /// to display results without coupling to specific trigger types.
+ ///
+ public static event EventHandler ActionCompleted;
+
+
+ public static void RaiseCaseClosed(object sender, CaseClosedPayload payload)
+ => CaseClosed?.Invoke(sender, new TriggerEventArgs(payload));
+
+ public static void RaiseCaseCreated(object sender, CaseCreatedPayload payload)
+ => CaseCreated?.Invoke(sender, new TriggerEventArgs(payload));
+
+ public static void RaiseApplicationStartup(object sender, ApplicationStartupPayload payload)
+ => ApplicationStartup?.Invoke(sender, new TriggerEventArgs(payload));
+
+ public static void RaiseActionCompleted(object sender, ActionCompletedEventArgs args)
+ => ActionCompleted?.Invoke(sender, args);
+ }
+}
diff --git a/F4SD-ActionConnector/Events/TriggerEventArgs.cs b/F4SD-ActionConnector/Events/TriggerEventArgs.cs
new file mode 100644
index 0000000..6a0482c
--- /dev/null
+++ b/F4SD-ActionConnector/Events/TriggerEventArgs.cs
@@ -0,0 +1,15 @@
+using System;
+using F4SD.ActionConnector.Payloads;
+
+namespace F4SD.ActionConnector.Events
+{
+ public sealed class TriggerEventArgs : EventArgs where TPayload : PayloadBase
+ {
+ public TPayload Payload { get; }
+
+ public TriggerEventArgs(TPayload payload)
+ {
+ Payload = payload;
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/F4SD-ActionConnector.csproj b/F4SD-ActionConnector/F4SD-ActionConnector.csproj
new file mode 100644
index 0000000..c316ba7
--- /dev/null
+++ b/F4SD-ActionConnector/F4SD-ActionConnector.csproj
@@ -0,0 +1,16 @@
+
+
+
+ netstandard2.0
+ F4SD.ActionConnector
+ F4SD-ActionConnector
+ disable
+ 7.3
+
+
+
+
+
+
+
+
diff --git a/F4SD-ActionConnector/Models/ActionContext.cs b/F4SD-ActionConnector/Models/ActionContext.cs
new file mode 100644
index 0000000..5487625
--- /dev/null
+++ b/F4SD-ActionConnector/Models/ActionContext.cs
@@ -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; }
+ }
+}
diff --git a/F4SD-ActionConnector/Models/ActionDefinitionBase.cs b/F4SD-ActionConnector/Models/ActionDefinitionBase.cs
new file mode 100644
index 0000000..48e7f09
--- /dev/null
+++ b/F4SD-ActionConnector/Models/ActionDefinitionBase.cs
@@ -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);
+ }
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/Models/ActionResult.cs b/F4SD-ActionConnector/Models/ActionResult.cs
new file mode 100644
index 0000000..3b9559d
--- /dev/null
+++ b/F4SD-ActionConnector/Models/ActionResult.cs
@@ -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; }
+
+ ///
+ /// HTTP status code for HttpCall actions; null for other types.
+ ///
+ public int? HttpStatusCode { get; set; }
+
+ ///
+ /// Raw response body (HttpCall) or serialized output (QuickAction).
+ ///
+ public string RawResponse { get; set; }
+
+ ///
+ /// Named fields extracted from the response via jsonPath mappings.
+ /// Populated when DisplayInCockpit is true.
+ ///
+ public IDictionary MappedFields { get; set; } = new Dictionary();
+
+ ///
+ /// Human-readable error message; set when Status is Failure.
+ ///
+ 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 };
+ }
+}
diff --git a/F4SD-ActionConnector/Models/ExternalCommunicationConfiguration.cs b/F4SD-ActionConnector/Models/ExternalCommunicationConfiguration.cs
new file mode 100644
index 0000000..87d5708
--- /dev/null
+++ b/F4SD-ActionConnector/Models/ExternalCommunicationConfiguration.cs
@@ -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 Triggers { get; } = new Dictionary();
+
+
+ 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);
+ }
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/Models/HttpCallDefinition.cs b/F4SD-ActionConnector/Models/HttpCallDefinition.cs
new file mode 100644
index 0000000..2d0e4d2
--- /dev/null
+++ b/F4SD-ActionConnector/Models/HttpCallDefinition.cs
@@ -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 Headers { get; set; } = new Dictionary();
+ public string Body { get; set; }
+
+ ///
+ /// jsonPath expressions keyed by field name, used to extract values from the response.
+ ///
+ public IDictionary MappedFieldJsonPaths { get; set; } = new Dictionary();
+
+ internal HttpCallDefinition(XmlElement xNode, cXmlParser parser) : base(xNode, parser)
+ {
+
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/Models/QuickActionDefinition.cs b/F4SD-ActionConnector/Models/QuickActionDefinition.cs
new file mode 100644
index 0000000..33df28f
--- /dev/null
+++ b/F4SD-ActionConnector/Models/QuickActionDefinition.cs
@@ -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;
+
+ ///
+ /// Reference to the Quick Action to invoke, e.g. "Protocol case in JIRA".
+ ///
+ public string QuickActionRef { get; set; }
+
+ public IDictionary Parameters { get; private set; } = new Dictionary();
+
+ 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();
+ }
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/Models/Trigger.cs b/F4SD-ActionConnector/Models/Trigger.cs
new file mode 100644
index 0000000..8f54af1
--- /dev/null
+++ b/F4SD-ActionConnector/Models/Trigger.cs
@@ -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 Actions { get; } = new Dictionary();
+
+ 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);
+ }
+ }
+ }
+}
diff --git a/F4SD-ActionConnector/Payloads/ApplicationStartupPayload.cs b/F4SD-ActionConnector/Payloads/ApplicationStartupPayload.cs
new file mode 100644
index 0000000..a4e4cc6
--- /dev/null
+++ b/F4SD-ActionConnector/Payloads/ApplicationStartupPayload.cs
@@ -0,0 +1,9 @@
+using F4SD.ActionConnector.Enumerations;
+
+namespace F4SD.ActionConnector.Payloads
+{
+ public sealed class ApplicationStartupPayload : PayloadBase
+ {
+ public override TriggerEvent Event => TriggerEvent.ApplicationStartup;
+ }
+}
diff --git a/F4SD-ActionConnector/Payloads/CaseClosedPayload.cs b/F4SD-ActionConnector/Payloads/CaseClosedPayload.cs
new file mode 100644
index 0000000..95c6c07
--- /dev/null
+++ b/F4SD-ActionConnector/Payloads/CaseClosedPayload.cs
@@ -0,0 +1,17 @@
+using System;
+using F4SD.ActionConnector.Enumerations;
+
+namespace F4SD.ActionConnector.Payloads
+{
+ public sealed class CaseClosedPayload : PayloadBase
+ {
+ public override TriggerEvent Event => TriggerEvent.CaseClosed;
+
+ public string Id { get; set; }
+ public string Subject { get; set; }
+ public string Priority { get; set; }
+ public Guid UserId { get; set; }
+ public string ClosedByUserName { get; set; }
+ public DateTime ClosedAt { get; set; }
+ }
+}
diff --git a/F4SD-ActionConnector/Payloads/CaseCreatedPayload.cs b/F4SD-ActionConnector/Payloads/CaseCreatedPayload.cs
new file mode 100644
index 0000000..fe6b8da
--- /dev/null
+++ b/F4SD-ActionConnector/Payloads/CaseCreatedPayload.cs
@@ -0,0 +1,14 @@
+using System;
+using F4SD.ActionConnector.Enumerations;
+
+namespace F4SD.ActionConnector.Payloads
+{
+ public sealed class CaseCreatedPayload : PayloadBase
+ {
+ public override TriggerEvent Event => TriggerEvent.CaseCreated;
+
+ public string Id { get; set; }
+ public string UserId { get; set; }
+ public DateTime CreatedAt { get; set; }
+ }
+}
diff --git a/F4SD-ActionConnector/Payloads/PayloadBase.cs b/F4SD-ActionConnector/Payloads/PayloadBase.cs
new file mode 100644
index 0000000..202f702
--- /dev/null
+++ b/F4SD-ActionConnector/Payloads/PayloadBase.cs
@@ -0,0 +1,9 @@
+using F4SD.ActionConnector.Enumerations;
+
+namespace F4SD.ActionConnector.Payloads
+{
+ public abstract class PayloadBase
+ {
+ public abstract TriggerEvent Event { get; }
+ }
+}
diff --git a/F4SD-AdaptableIcon/Enums/InternIcon.cs b/F4SD-AdaptableIcon/Enums/InternIcon.cs
index bcc180b..8e00db7 100644
--- a/F4SD-AdaptableIcon/Enums/InternIcon.cs
+++ b/F4SD-AdaptableIcon/Enums/InternIcon.cs
@@ -59,6 +59,7 @@ namespace F4SD_AdaptableIcon.Enums
misc_tool,
misc_user,
misc_user_disabled,
+ misc_disabledOverlay,
//StatusIcons
status_bad,
diff --git a/F4SD-AdaptableIcon/IconPainter.cs b/F4SD-AdaptableIcon/IconPainter.cs
index 53f4efc..cac0d69 100644
--- a/F4SD-AdaptableIcon/IconPainter.cs
+++ b/F4SD-AdaptableIcon/IconPainter.cs
@@ -519,6 +519,13 @@ namespace FasdDesktopUi.Basics.UserControls.AdaptableIcon
null
}
},
+ { enumInternIcons.misc_disabledOverlay,
+ new PathGeometry[]
+ {
+ PathGeometry.CreateFromGeometry(Geometry.Parse("F1 M7.8133 5.364l-.844-.62L1.1307.4627c-.5307-.4014-1.1307.4013-.5987.8026L6.1253 5.364l.844.62 5.8387 4.2813c.536.396 1.1307-.412.5933-.808 Z")),
+ null
+ }
+ },
#endregion
diff --git a/F4SD-Docu-Engine/DocuEngine.cs b/F4SD-Docu-Engine/DocuEngine.cs
new file mode 100644
index 0000000..1c12042
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngine.cs
@@ -0,0 +1,41 @@
+using F4SD.DocuEngine.DocuEngineDataProvider;
+using F4SD.DocuEngine.DocuEngineParser;
+using F4SD.DocuEngine.DocuEngineParser.ContentBlock;
+using F4SD.DocuEngine.DocuEngineParser.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace F4SD.DocuEngine
+{
+ public class DocuEngine
+ {
+ public string DocuTemplate { get; private set; }
+ public IDocuEngineDataContainer Container { get; private set; }
+ private ParsingContext parsingContext;
+
+ public DocuEngine(string docuTemplate, IDocuEngineDataContainer container)
+ {
+ DocuTemplate = docuTemplate;
+ Container = container;
+ }
+
+ public string ParseTemplate()
+ {
+ var index = 0;
+ parsingContext = new ParsingContext();
+ ContentBlock contentBlock = new ContentBlock(DocuTemplate, Container);
+ try
+ {
+ parsingContext.Append(contentBlock.ParseContentBlock(ref index));
+ }
+ catch (DocuEngineParser.Exceptions.DocuEngineParserException parserException)
+ {
+ parsingContext.Append(parserException.CurrentText);
+ parsingContext.Append(parserException.PrintedErrorMessage);
+ return parsingContext.GetFinalText();
+ }
+ return parsingContext.GetFinalText();
+ }
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineDataProvider/DocuEngineDataProvider.cs b/F4SD-Docu-Engine/DocuEngineDataProvider/DocuEngineDataProvider.cs
new file mode 100644
index 0000000..acffa61
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineDataProvider/DocuEngineDataProvider.cs
@@ -0,0 +1,93 @@
+using C4IT.F4SD.DisplayFormatting;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace F4SD.DocuEngine.DocuEngineDataProvider
+{
+ public class DocuEngineDataProperty : IDocuEngineDataProperty
+ {
+ public object Value { get; set; }
+ public RawValueType? ValueType { get; set; }
+ }
+
+ public class DocuEngineDataContainer : Dictionary, IDocuEngineDataContainer
+ {
+ public IDocuEngineDataToken GetByName(string tokenName)
+ {
+ var tokenTree = tokenName.Split('.');
+ if (this.TryGetValue(tokenTree[0], out IDocuEngineDataToken token))
+ {
+ if (tokenTree.Length > 1)
+ {
+ switch (token)
+ {
+ case IDocuEngineDataContainer container:
+ return container.GetByName(string.Join(".", tokenTree.Skip(1)));
+ case IDocuEngineDataProperty property:
+ return property;
+ case IDocuEngineDataEnumeration enumeration:
+ return new DocuEngineDataProperty() { Value = tokenTree[0] };
+ default:
+ //Syntax Error
+ break;
+ }
+ }
+ else
+ {
+ switch (token)
+ {
+ case IDocuEngineDataContainer container:
+ return container;
+ case IDocuEngineDataProperty property:
+ return property;
+ case IDocuEngineDataEnumeration enumeration:
+ return enumeration;
+ default:
+ //Syntax Error
+ break;
+ }
+ }
+ return null;
+ }
+ else
+ {
+ //Syntax Error
+ return null;
+ }
+ }
+
+ public IDocuEngineDataContainer GetContainerByName(string containerName)
+ {
+ var token = GetByName(containerName);
+ if (token is IDocuEngineDataContainer container)
+ {
+ return container;
+ }
+ return null;
+ }
+
+ public IDocuEngineDataProperty GetPropertyByName(string propertyName)
+ {
+ var token = GetByName(propertyName);
+ if (token is IDocuEngineDataProperty property)
+ {
+ return property;
+ }
+ return null;
+ }
+
+ public IDocuEngineDataEnumeration GetEnumerationByName(string enumName)
+ {
+ var token = GetByName(enumName);
+ if (token is IDocuEngineDataEnumeration enumeration)
+ {
+ return enumeration;
+ }
+ return null;
+ }
+ }
+
+ public class DocuEngineDataEnumeration : List, IDocuEngineDataEnumeration
+ {
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineDataProvider/IDocuEngineDataToken.cs b/F4SD-Docu-Engine/DocuEngineDataProvider/IDocuEngineDataToken.cs
new file mode 100644
index 0000000..3d8dae8
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineDataProvider/IDocuEngineDataToken.cs
@@ -0,0 +1,31 @@
+using C4IT.F4SD.DisplayFormatting;
+using System.Collections.Generic;
+
+namespace F4SD.DocuEngine.DocuEngineDataProvider
+{
+ public interface IDocuEngineDataToken
+ {
+ }
+
+ public interface IDocuEngineDataIllegal : IDocuEngineDataToken
+ {
+ }
+
+ public interface IDocuEngineDataProperty : IDocuEngineDataToken
+ {
+ object Value { get; set; }
+ RawValueType? ValueType { get; set; }
+ }
+
+ public interface IDocuEngineDataContainer : IDocuEngineDataToken
+ {
+ IDocuEngineDataToken GetByName(string name);
+ IDocuEngineDataContainer GetContainerByName(string containerName);
+ IDocuEngineDataEnumeration GetEnumerationByName(string enumName);
+ IDocuEngineDataProperty GetPropertyByName(string propertyName);
+ }
+
+ public interface IDocuEngineDataEnumeration : IEnumerable, IDocuEngineDataToken
+ {
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlock.cs b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlock.cs
new file mode 100644
index 0000000..96bfbc5
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlock.cs
@@ -0,0 +1,227 @@
+using C4IT.F4SD.DisplayFormatting;
+using F4SD.DocuEngine.DocuEngineDataProvider;
+using F4SD.DocuEngine.DocuEngineParser.Exceptions;
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace F4SD.DocuEngine.DocuEngineParser.ContentBlock
+{
+ internal partial class ContentBlock
+ {
+ public string DocuTemplate { get; private set; }
+ public IDocuEngineDataContainer Container { get; private set; }
+ private ParsingContext parsingContext;
+ public ContentBlock(string DocuTemplate, IDocuEngineDataContainer Container)
+ {
+ this.DocuTemplate = DocuTemplate;
+ this.Container = Container;
+ parsingContext = new ParsingContext();
+ }
+
+ public string ParseContentBlock(ref int index)
+ {
+ bool isContentBlockFinished = false;
+ try
+ {
+ while (!isContentBlockFinished)
+ {
+ ParseTextBlock(ref index, out var finished);
+ if (finished)
+ {
+ isContentBlockFinished = true;
+ }
+ else
+ {
+ ParseCommandBlock(ref index);
+ }
+ }
+ }
+ catch (DocuEngineParserException parserException)
+ {
+ parsingContext.Append(parserException.CurrentText);
+ parserException.AddToCurrentText(parsingContext.GetFinalText());
+ throw;
+ }
+ return parsingContext.GetFinalText();
+ }
+
+ private void ParseTextBlock(ref int index, out bool isContextBlockFinished)
+ {
+ bool foundTrigger = false;
+ string[] keywords = { "@@", "[[", "]]", "{{", "}}" };
+ string pattern = string.Join("|", keywords.Select(Regex.Escape));
+ Regex regex = new Regex(pattern);
+ isContextBlockFinished = false;
+
+ while (!foundTrigger)
+ {
+ Match match = regex.Match(DocuTemplate, index);
+ if (match.Success)
+ {
+ parsingContext.Append(DocuTemplate.Substring(index, match.Index - index));
+ index = match.Index;
+ switch (match.Value)
+ {
+ case "@@":
+ if (DocuTemplate.Substring(index, 3).Equals("@@@"))
+ {
+ parsingContext.Append("@@");
+ index += 3;
+ }
+ else
+ {
+ foundTrigger = true;
+ index += 2;
+ }
+ break;
+ case "[[":
+ if (DocuTemplate.Substring(index, 3).Equals("[[["))
+ {
+ parsingContext.Append("[[");
+ index += 3;
+ }
+ else
+ {
+ index += 2;
+ SkipWhiteSpace(ref index);
+ string variableName = ParseVariableName(ref index);
+ SkipWhiteSpace(ref index);
+ if (DocuTemplate.ElementAtOrDefault(index).Equals(';'))
+ {
+ index++;
+ SkipWhiteSpace(ref index);
+ string displayTypeString = ParseDisplayType(ref index);
+ RawValueType? displayType = null;
+ if (Enum.TryParse(displayTypeString, true, out RawValueType parseDisplayType))
+ {
+ displayType = parseDisplayType;
+ }
+ parsingContext.Append(SubstituteVariable(variableName, displayType));
+ SkipWhiteSpace(ref index);
+ if (DocuTemplate.Substring(index, 2).Equals("]]") && !(DocuTemplate.Substring(index, 3).Equals("]]]")))
+ {
+ index += 2;
+ continue;
+ }
+ else
+ {
+ throw new SyntaxErrorException("]]", DocuTemplate.Substring(index, 3));
+ }
+ }
+ else if (DocuTemplate.Substring(index, 2).Equals("]]"))
+ {
+ parsingContext.Append(SubstituteVariable(variableName, null));
+ index += 2;
+ continue;
+ }
+ else
+ {
+ throw new SyntaxErrorException("]]\" / \";", DocuTemplate.Substring(index, 3));
+ }
+ }
+ break;
+ case "]]":
+ if (DocuTemplate.Substring(index, 3).Equals("]]]"))
+ {
+ parsingContext.Append("]]");
+ index += 3;
+ }
+ else
+ {
+ throw new SyntaxErrorException("]]]", "]]");
+ }
+ break;
+ case "{{":
+ if (DocuTemplate.Substring(index, 3).Equals("{{{"))
+ {
+ parsingContext.Append("{{");
+ index += 3;
+ }
+ else
+ {
+ throw new SyntaxErrorException("{{{", "{{");
+ }
+ break;
+ case "}}":
+ if (DocuTemplate.Substring(index, 3).Equals("}}}"))
+ {
+ parsingContext.Append("}}");
+ index += 3;
+ }
+ else if (DocuTemplate.Substring(index, 3).Equals("}};"))
+ {
+ foundTrigger = true;
+ isContextBlockFinished = true;
+ index += 3;
+ }
+ else
+ {
+ foundTrigger = true;
+ isContextBlockFinished = true;
+ index += 2;
+ }
+ break;
+ }
+ }
+ else
+ {
+ int length = DocuTemplate.Length - index;
+ if (length < 0)
+ {
+ length = 0;
+ }
+ else if (length > 15)
+ {
+ length = 15;
+ }
+ throw new SyntaxErrorException("}};", DocuTemplate.Substring(index, length));
+ }
+ }
+ }
+
+ private void ParseCommandBlock(ref int index)
+ {
+ string[] keywords = { "(" };
+ string pattern = string.Join("|", keywords.Select(Regex.Escape));
+ Regex regex = new Regex(pattern);
+
+ Match match = regex.Match(DocuTemplate, index);
+ if (match.Success)
+ {
+ string commandName = "";
+ commandName = DocuTemplate.Substring(index, match.Index - index);
+ index = match.Index + 1;
+
+ switch (commandName)
+ {
+ case "if":
+ ParseIfCommand(ref index);
+ break;
+ case "switch":
+ ParseSwitchCommand(ref index);
+ break;
+ case "foreach":
+ ParseForeachCommand(ref index);
+ break;
+ case "include":
+ //TODO
+ break;
+ }
+ }
+ else
+ {
+ int length = DocuTemplate.Length - index;
+ if (length < 0)
+ {
+ length = 0;
+ }
+ else if (length > 15)
+ {
+ length = 15;
+ }
+ throw new SyntaxErrorException("if\" / \"switch\" / \"foreach", DocuTemplate.Substring(index, length));
+ }
+ }
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockForeachCommand.cs b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockForeachCommand.cs
new file mode 100644
index 0000000..51a6eda
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockForeachCommand.cs
@@ -0,0 +1,52 @@
+using F4SD.DocuEngine.DocuEngineDataProvider;
+using F4SD.DocuEngine.DocuEngineParser.Exceptions;
+using System.ComponentModel;
+using System.Linq;
+
+namespace F4SD.DocuEngine.DocuEngineParser.ContentBlock
+{
+ internal partial class ContentBlock
+ {
+ private void ParseForeachCommand(ref int index)
+ {
+ string variableName = "";
+ string enumName = "";
+ int tempIndex = 0;
+
+ SkipWhiteSpace(ref index);
+ variableName += ParseVariableName(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ enumName += ParseVariableName(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(')')))
+ {
+ throw new SyntaxErrorException(")", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ IDocuEngineDataEnumeration enumeration = Container.GetEnumerationByName(enumName);
+ if (enumeration == null)
+ {
+ //Syntax Error
+ }
+ tempIndex = index;
+ foreach (var token in enumeration)
+ {
+ index = tempIndex;
+ ContentBlock foreachBlock = new ContentBlock(DocuTemplate, new DocuEngineDataContainer() { { variableName, token } });
+ parsingContext.Append(foreachBlock.ParseContentBlock(ref index));
+ }
+ }
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockHelperMethods.cs b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockHelperMethods.cs
new file mode 100644
index 0000000..e2ec143
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockHelperMethods.cs
@@ -0,0 +1,291 @@
+using C4IT.F4SD.DisplayFormatting;
+using F4SD.DocuEngine.DocuEngineParser.Exceptions;
+using System.ComponentModel;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace F4SD.DocuEngine.DocuEngineParser.ContentBlock
+{
+ internal partial class ContentBlock
+ {
+ private string ParseVariableType(ref int index)
+ {
+ bool foundTypeEnd = false;
+ string variableType = "";
+ while (!foundTypeEnd)
+ {
+ char c = DocuTemplate.ElementAt(index);
+ if (char.IsLetter(c))
+ {
+ variableType += c;
+ index++;
+ }
+ else
+ {
+ foundTypeEnd = true;
+ }
+ }
+ return variableType;
+ }
+
+ private string ParseVariableName(ref int index)
+ {
+ bool foundVariableEnd = false;
+ string variableName = "";
+ while (!foundVariableEnd)
+ {
+ char c = DocuTemplate.ElementAt(index);
+ if (char.IsLetterOrDigit(c) || c == '.')
+ {
+ variableName += c;
+ index++;
+ }
+ else
+ {
+ foundVariableEnd = true;
+ }
+ }
+ return variableName;
+ }
+
+ private void SkipWhiteSpace(ref int index)
+ {
+ bool foundNonWhiteSpace = false;
+ while (!foundNonWhiteSpace)
+ {
+ char c = DocuTemplate.ElementAt(index);
+ if (char.IsWhiteSpace(c))
+ {
+ index++;
+ }
+ else
+ {
+ foundNonWhiteSpace = true;
+ }
+ }
+ }
+
+ private string ParseDisplayType(ref int index)
+ {
+ bool foundDisplayTypeEnd = false;
+ string displayType = "";
+ while (!foundDisplayTypeEnd)
+ {
+ char c = DocuTemplate.ElementAt(index);
+ if (char.IsLetterOrDigit(c))
+ {
+ displayType += c;
+ index++;
+ }
+ else
+ {
+ foundDisplayTypeEnd = true;
+ }
+ }
+ return displayType;
+ }
+
+ private string SubstituteVariable(string variableName, RawValueType? displayType)
+ {
+ IRawValueFormatter rawValueFormatter = new RawValueFormatter();
+
+ var property = Container.GetPropertyByName(variableName);
+ if (property == null)
+ {
+ //Syntax Error
+ }
+ if (displayType != null)
+ {
+ return rawValueFormatter.GetDisplayValue(property.Value, (RawValueType)displayType, null);
+ }
+ else if (property.ValueType != null)
+ {
+ return rawValueFormatter.GetDisplayValue(property.Value, (RawValueType)property.ValueType, null);
+ }
+ else
+ {
+ return property.Value.ToString();
+ }
+ }
+
+ private char ParseComparator(ref int index)
+ {
+ char comparator = DocuTemplate.ElementAtOrDefault(index);
+ if (!(comparator == '<' || comparator == '>' || comparator == '=' || comparator == '!'))
+ {
+ throw new SyntaxErrorException("<\" / \">\" / \"=\" / \"!", comparator.ToString());
+ }
+ index++;
+ return comparator;
+ }
+
+ private string ParseValue(ref int index)
+ {
+ string value = "";
+ string pattern = @"("")(.*?)(""\s*\))";
+ Regex regex = new Regex(pattern);
+ Match match = regex.Match(DocuTemplate, index);
+ if (match.Success)
+ {
+ value = match.Groups[2].Value;
+ string wholeMatch = match.Value.ToString();
+ index += wholeMatch.Length;
+ }
+ else
+ {
+ throw new SyntaxErrorException("\"VariableName\")", "");
+ }
+ return value;
+ }
+
+ private bool CheckCondition(string variableType, string variableName, char comparator, string value)
+ {
+ string stringVariable = "";
+ var property = Container.GetPropertyByName(variableName);
+ if (property == null)
+ {
+ //Syntax Error
+ }
+ stringVariable = property.Value.ToString();
+ switch (variableType)
+ {
+ case "string":
+ if (!(comparator == '=' || comparator == '!'))
+ {
+ throw new SyntaxErrorException("=\" / \"!", comparator.ToString());
+ }
+ return CompareStrings(stringVariable, comparator, value);
+ case "int":
+ if (!(comparator == '<' || comparator == '>' || comparator == '=' || comparator == '!'))
+ {
+ throw new SyntaxErrorException("<\" / \">\" / \"=\" / \"!", comparator.ToString());
+ }
+ if (!(int.TryParse(value, out var intValue)))
+ {
+ throw new VariableErrorException(value, "int");
+ }
+ stringVariable = stringVariable.Replace("\"", "");
+ if (!(int.TryParse(stringVariable, out var intVariable)))
+ {
+ throw new VariableErrorException(stringVariable, "int");
+ }
+ return CompareIntegers(intVariable, comparator, intValue);
+ case "bool":
+ if (!(comparator == '=' || comparator == '!'))
+ {
+ throw new SyntaxErrorException("=\" / \"!", comparator.ToString());
+ }
+ if (!(bool.TryParse(value, out var boolValue)))
+ {
+ throw new VariableErrorException(value, "bool");
+ }
+ if (!(bool.TryParse(stringVariable, out var boolVariable)))
+ {
+ throw new VariableErrorException(stringVariable, "bool");
+ }
+ return CompareBooleans(boolVariable, comparator, boolValue);
+ default:
+ throw new SyntaxErrorException("string\" / \"int\" / \"bool", variableType);
+ }
+ }
+
+ private bool CompareStrings(string variable, char comparator, string value)
+ {
+ switch (comparator)
+ {
+ case '=':
+ if (variable == value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ case '!':
+ if (variable != value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+
+ private bool CompareIntegers(int variable, char comparator, int value)
+ {
+ switch (comparator)
+ {
+ case '=':
+ if (variable == value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ case '!':
+ if (variable != value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ case '>':
+ if (variable > value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ case '<':
+ if (variable < value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+
+ private bool CompareBooleans(bool variable, char comparator, bool value)
+ {
+ switch (comparator)
+ {
+ case '=':
+ if (variable == value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ case '!':
+ if (variable != value)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockIfCommand.cs b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockIfCommand.cs
new file mode 100644
index 0000000..6fa459e
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockIfCommand.cs
@@ -0,0 +1,175 @@
+using F4SD.DocuEngine.DocuEngineParser.Exceptions;
+using System.ComponentModel;
+using System.Linq;
+
+namespace F4SD.DocuEngine.DocuEngineParser.ContentBlock
+{
+ internal partial class ContentBlock
+ {
+ private void ParseIfCommand(ref int index)
+ {
+ string tempString = "";
+ bool foundTrueCondition = false;
+ bool foundAllElseIf = false;
+ int tempIndex = 0;
+
+ tempString = ParseIfBlock(ref index, out var isIfConditionTrue);
+ if (isIfConditionTrue)
+ {
+ foundTrueCondition = true;
+ parsingContext.Append(tempString);
+ }
+ tempString = "";
+ while (!foundAllElseIf)
+ {
+ tempIndex = index;
+ SkipWhiteSpace(ref index);
+ if (DocuTemplate.Substring(index, 7).Equals("else-if"))
+ {
+ index += 7;
+ tempString += ParseElseIfBlock(ref index, out var isElseIfConditionTrue);
+ if (isElseIfConditionTrue && !foundTrueCondition)
+ {
+ foundTrueCondition = true;
+ parsingContext.Append(tempString);
+ }
+ tempString = "";
+ }
+ else
+ {
+ foundAllElseIf = true;
+ index = tempIndex;
+ }
+ }
+ tempIndex = index;
+ SkipWhiteSpace(ref index);
+ if (DocuTemplate.Substring(index, 4).Equals("else"))
+ {
+ index += 4;
+ tempString += ParseElseBlock(ref index);
+ if (!foundTrueCondition)
+ {
+ foundTrueCondition = true;
+ parsingContext.Append(tempString);
+ tempString = "";
+ }
+ }
+ else
+ {
+ index = tempIndex;
+ }
+ }
+
+ private string ParseIfBlock(ref int index, out bool isConditionTrue)
+ {
+ string returnString = "";
+ string variableType = "";
+ string variableName = "";
+ char comparator;
+ string value = "";
+ SkipWhiteSpace(ref index);
+ variableType += ParseVariableType(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ variableName += ParseVariableName(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ comparator = ParseComparator(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ value += ParseValue(ref index);
+ SkipWhiteSpace(ref index);
+ isConditionTrue = CheckCondition(variableType, variableName, comparator, value);
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ ContentBlock contentBlock = new ContentBlock(DocuTemplate, Container);
+ returnString += contentBlock.ParseContentBlock(ref index);
+ return returnString;
+ }
+
+ private string ParseElseIfBlock(ref int index, out bool isConditionTrue)
+ {
+ string returnString = "";
+ string variableType = "";
+ string variableName = "";
+ char comparator;
+ string value = "";
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAt(index).Equals('(')))
+ {
+ throw new SyntaxErrorException("(", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ variableType += ParseVariableType(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ variableName += ParseVariableName(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ comparator = ParseComparator(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ value += ParseValue(ref index);
+ SkipWhiteSpace(ref index);
+ isConditionTrue = CheckCondition(variableType, variableName, comparator, value);
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ ContentBlock contentBlock = new ContentBlock(DocuTemplate, Container);
+ returnString += contentBlock.ParseContentBlock(ref index);
+ return returnString;
+ }
+
+ private string ParseElseBlock(ref int index)
+ {
+ string returnString = "";
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ ContentBlock contentBlock = new ContentBlock(DocuTemplate, Container);
+ returnString += contentBlock.ParseContentBlock(ref index);
+ return returnString;
+ }
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockSwitchCommand.cs b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockSwitchCommand.cs
new file mode 100644
index 0000000..ec4b07b
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/ContentBlock/ContentBlockSwitchCommand.cs
@@ -0,0 +1,127 @@
+using F4SD.DocuEngine.DocuEngineParser.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+
+namespace F4SD.DocuEngine.DocuEngineParser.ContentBlock
+{
+ internal partial class ContentBlock
+ {
+ private void ParseSwitchCommand(ref int index)
+ {
+ string tempString = "";
+ bool foundTrueCase = false;
+ bool foundAllCases = false;
+ int tempIndex = 0;
+ (string VariableType, string VariableName) switchVariable = ParseSwitchBlock(ref index);
+ while (!foundAllCases)
+ {
+ tempIndex = index;
+ SkipWhiteSpace(ref index);
+ if (DocuTemplate.Substring(index, 4).Equals("case"))
+ {
+ index += 4;
+ tempString += ParseCaseBlock(ref index, switchVariable, out var isCaseTrue);
+ if (isCaseTrue && !foundTrueCase)
+ {
+ foundTrueCase = true;
+ parsingContext.Append(tempString);
+ }
+ tempString = "";
+ }
+ else
+ {
+ foundAllCases = true;
+ index = tempIndex;
+ }
+ }
+ tempIndex = index;
+ SkipWhiteSpace(ref index);
+ if (DocuTemplate.Substring(index, 7).Equals("default"))
+ {
+ index += 7;
+ tempString += ParseDefaultBlock(ref index);
+ if (!foundTrueCase)
+ {
+ foundTrueCase = true;
+ parsingContext.Append(tempString);
+ tempString = "";
+ }
+ }
+ else
+ {
+ index = tempIndex;
+ }
+ }
+
+ private (string VariableType, string VariableName) ParseSwitchBlock(ref int index)
+ {
+ string variableName = "";
+ string variableType = "";
+ SkipWhiteSpace(ref index);
+ variableType = ParseVariableType(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(';')))
+ {
+ throw new SyntaxErrorException(";", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ variableName = ParseVariableName(ref index);
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals(')')))
+ {
+ throw new SyntaxErrorException(")", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ return (variableType, variableName);
+ }
+
+ private string ParseCaseBlock(ref int index, (string VariableType, string VariableName) switchVariable, out bool isCaseTrue)
+ {
+ string returnString = "";
+ isCaseTrue = false;
+ string value = "";
+ SkipWhiteSpace(ref index);
+ if (!(DocuTemplate.ElementAtOrDefault(index).Equals('(')))
+ {
+ throw new SyntaxErrorException("(", DocuTemplate.ElementAtOrDefault(index).ToString());
+ }
+ index++;
+ SkipWhiteSpace(ref index);
+ value = ParseValue(ref index);
+ isCaseTrue = CheckCondition(switchVariable.VariableType, switchVariable.VariableName, '=', value);
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ ContentBlock contentBlock = new ContentBlock(DocuTemplate, Container);
+ returnString += contentBlock.ParseContentBlock(ref index);
+ return returnString;
+ }
+
+ private string ParseDefaultBlock(ref int index)
+ {
+ string returnString = "";
+ SkipWhiteSpace(ref index);
+ if (!DocuTemplate.Substring(index, 2).Equals("{{"))
+ {
+ throw new SyntaxErrorException("{{", DocuTemplate.Substring(index, 2));
+ }
+ index += 2;
+ ContentBlock contentBlock = new ContentBlock(DocuTemplate, Container);
+ returnString += contentBlock.ParseContentBlock(ref index);
+ return returnString;
+ }
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineParser/DocuEngineParserException.cs b/F4SD-Docu-Engine/DocuEngineParser/DocuEngineParserException.cs
new file mode 100644
index 0000000..3c294a8
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/DocuEngineParserException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace F4SD.DocuEngine.DocuEngineParser
+{
+ internal abstract class DocuEngineParserException : Exception
+ {
+ public string CurrentText { get; protected set; }
+ public string PrintedErrorMessage { get; protected set; }
+ public DocuEngineParserException(string message) : base(message)
+ {
+
+ }
+ public abstract void AddToCurrentText(string text);
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineParser/Exceptions/DocuEngineParserException.cs b/F4SD-Docu-Engine/DocuEngineParser/Exceptions/DocuEngineParserException.cs
new file mode 100644
index 0000000..f7068d0
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/Exceptions/DocuEngineParserException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace F4SD.DocuEngine.DocuEngineParser.Exceptions
+{
+ internal abstract class DocuEngineParserException : Exception
+ {
+ public string CurrentText { get; protected set; }
+ public string PrintedErrorMessage { get; protected set; }
+ public DocuEngineParserException(string message) : base(message)
+ {
+
+ }
+ public abstract void AddToCurrentText(string text);
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineParser/Exceptions/SyntaxErrorException.cs b/F4SD-Docu-Engine/DocuEngineParser/Exceptions/SyntaxErrorException.cs
new file mode 100644
index 0000000..b1d740c
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/Exceptions/SyntaxErrorException.cs
@@ -0,0 +1,26 @@
+namespace F4SD.DocuEngine.DocuEngineParser.Exceptions
+{
+ internal class SyntaxErrorException : DocuEngineParserException
+ {
+ private const string errorMessageTemplate = "<>";
+ private const string defaultMessage = "You're syntax is wrong. Get good.";
+
+ public SyntaxErrorException(string currentText) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ }
+ public SyntaxErrorException(string expected, string actual) : base(defaultMessage)
+ {
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public SyntaxErrorException(string currentText, string expected, string actual) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public override void AddToCurrentText(string text)
+ {
+ CurrentText = text + CurrentText;
+ }
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineParser/Exceptions/VariableErrorException.cs b/F4SD-Docu-Engine/DocuEngineParser/Exceptions/VariableErrorException.cs
new file mode 100644
index 0000000..840723a
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/Exceptions/VariableErrorException.cs
@@ -0,0 +1,25 @@
+namespace F4SD.DocuEngine.DocuEngineParser.Exceptions
+{
+ internal class VariableErrorException : DocuEngineParserException
+ {
+ private const string errorMessageTemplate = "<>";
+ private const string defaultMessage = "Your variable is the wrong type. Get good.";
+ public VariableErrorException(string currentText) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ }
+ public VariableErrorException(string expected, string actual) : base(defaultMessage)
+ {
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public VariableErrorException(string currentText, string expected, string actual) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public override void AddToCurrentText(string text)
+ {
+ CurrentText = text + CurrentText;
+ }
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineParser/ParsingContext.cs b/F4SD-Docu-Engine/DocuEngineParser/ParsingContext.cs
new file mode 100644
index 0000000..d02ab7f
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/ParsingContext.cs
@@ -0,0 +1,13 @@
+using System.Text;
+
+namespace F4SD.DocuEngine.DocuEngineParser
+{
+ internal class ParsingContext
+ {
+ private readonly StringBuilder _stringBuilder = new StringBuilder();
+
+ public void Append(string text) => _stringBuilder.Append(text);
+
+ public string GetFinalText() => _stringBuilder.ToString();
+ }
+}
diff --git a/F4SD-Docu-Engine/DocuEngineParser/SyntaxErrorException.cs b/F4SD-Docu-Engine/DocuEngineParser/SyntaxErrorException.cs
new file mode 100644
index 0000000..d6ac138
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/SyntaxErrorException.cs
@@ -0,0 +1,26 @@
+namespace F4SD.DocuEngine.DocuEngineParser
+{
+ internal class SyntaxErrorException : DocuEngineParserException
+ {
+ private const string errorMessageTemplate = "<>";
+ private const string defaultMessage = "You're syntax is wrong. Get good.";
+
+ public SyntaxErrorException(string currentText) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ }
+ public SyntaxErrorException(string expected, string actual) : base(defaultMessage)
+ {
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public SyntaxErrorException(string currentText, string expected, string actual) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public override void AddToCurrentText(string text)
+ {
+ CurrentText = text + CurrentText;
+ }
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/DocuEngineParser/VariableErrorException.cs b/F4SD-Docu-Engine/DocuEngineParser/VariableErrorException.cs
new file mode 100644
index 0000000..2e1a403
--- /dev/null
+++ b/F4SD-Docu-Engine/DocuEngineParser/VariableErrorException.cs
@@ -0,0 +1,25 @@
+namespace F4SD.DocuEngine.DocuEngineParser
+{
+ internal class VariableErrorException : DocuEngineParserException
+ {
+ private const string errorMessageTemplate = "<>";
+ private const string defaultMessage = "Your variable is the wrong type. Get good.";
+ public VariableErrorException(string currentText) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ }
+ public VariableErrorException(string expected, string actual) : base(defaultMessage)
+ {
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public VariableErrorException(string currentText, string expected, string actual) : base(defaultMessage)
+ {
+ CurrentText = currentText;
+ PrintedErrorMessage = string.Format(errorMessageTemplate, expected, actual);
+ }
+ public override void AddToCurrentText(string text)
+ {
+ CurrentText = text + CurrentText;
+ }
+ }
+}
\ No newline at end of file
diff --git a/F4SD-Docu-Engine/F4SD-Docu-Engine.csproj b/F4SD-Docu-Engine/F4SD-Docu-Engine.csproj
new file mode 100644
index 0000000..f4ab581
--- /dev/null
+++ b/F4SD-Docu-Engine/F4SD-Docu-Engine.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netstandard2.0
+ F4SD.DocuEngine
+
+
+
+
+
+
+
diff --git a/F4SD-Gamification/CockpitAction.cs b/F4SD-Gamification/CockpitAction.cs
new file mode 100644
index 0000000..0103274
--- /dev/null
+++ b/F4SD-Gamification/CockpitAction.cs
@@ -0,0 +1,13 @@
+namespace F4SD.Gamification
+{
+ public enum CockpitAction
+ {
+ CaseOpened,
+ CaseClosed,
+ QuickActionExecuted,
+ CopyTemplateClicked,
+ BuiltDirectConnection,
+ AddNotes,
+ StartRemoteConnection,
+ }
+}
diff --git a/F4SD-Gamification/F4SD-Gamification.csproj b/F4SD-Gamification/F4SD-Gamification.csproj
new file mode 100644
index 0000000..8641537
--- /dev/null
+++ b/F4SD-Gamification/F4SD-Gamification.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netstandard2.0
+ F4SD.Gamification
+
+
+
+ 9.0
+
+
+
diff --git a/F4SD-Gamification/LevelEventArgs.cs b/F4SD-Gamification/LevelEventArgs.cs
new file mode 100644
index 0000000..c54fbe3
--- /dev/null
+++ b/F4SD-Gamification/LevelEventArgs.cs
@@ -0,0 +1,10 @@
+namespace F4SD.Gamification
+{
+ public class LevelEventArgs
+ {
+ public int CurrentLevel { get; set; }
+ public string LevelTitle { get; set; }
+ public int CurrentXp { get; set; }
+ public int XpRequiredForLevelUp { get; set; }
+ }
+}
diff --git a/F4SD-Gamification/Services/GamificationService.cs b/F4SD-Gamification/Services/GamificationService.cs
new file mode 100644
index 0000000..46692d2
--- /dev/null
+++ b/F4SD-Gamification/Services/GamificationService.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace F4SD.Gamification.Services
+{
+ public static class GamificationService
+ {
+ private static readonly LevelService _levelService = new();
+
+ public static void Initialize()
+ {
+ PersistenceService.Initialize();
+
+ foreach (var action in PersistenceService.GetActions())
+ {
+ _levelService.InitializeAction(action.Action);
+ }
+ }
+
+ public static void TrackAction(CockpitAction action, params object[] args)
+ {
+ PersistenceService.Persist(action);
+ _levelService.TrackAction(action);
+ }
+ }
+}
diff --git a/F4SD-Gamification/Services/LevelService.cs b/F4SD-Gamification/Services/LevelService.cs
new file mode 100644
index 0000000..13536ad
--- /dev/null
+++ b/F4SD-Gamification/Services/LevelService.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Numerics;
+using System.Security.Cryptography;
+
+namespace F4SD.Gamification.Services
+{
+ public class LevelService
+ {
+ private static readonly List<(int MinimumTotalExperiencePoints, int Level)> _experienceToLevelMap = new()
+ {
+ (0,1),
+ (1128,2),
+ (2400,3),
+ (3832,4),
+ (5440,5),
+ (7240,6),
+ (9248,7),
+ (11480,8),
+ (13952,9),
+ (16680,10),
+ (19680,11),
+ (22968,12),
+ (26560,13),
+ (30472,14),
+ (34720,15),
+ (39320,16),
+ (44288,17),
+ (49640,18),
+ (55392,19),
+ (61560,20),
+ (68160,21),
+ (75208,22),
+ (82720,23),
+ (90712,24),
+ (99200,25),
+ (108200,26),
+ (117728,27),
+ (127800,28),
+ (138432,29),
+ (149640,30),
+ (161440,31),
+ (173848,32),
+ (186880,33),
+ (200552,34),
+ (214880,35),
+ (229880,36),
+ (245568,37),
+ (261960,38),
+ (279072,39),
+ (296920,40),
+ (315520,41),
+ (334888,42),
+ (355040,43),
+ (375992,44),
+ (397760,45),
+ (420360,46),
+ (443808,47),
+ (468120,48),
+ (493312,49),
+ (519400,50),
+ };
+
+ private int _totalExperiencePoints = 0;
+ private int _currentExperiencePoints;
+
+ private int _level;
+
+ internal void InitializeAction(CockpitAction action)
+ {
+ AddExperiencePoints(GetExperiencePointsFor(action), true);
+ }
+
+ internal void TrackAction(CockpitAction type, params object[] args)
+ {
+ AddExperiencePoints(GetExperiencePointsFor(type));
+ }
+
+ private void AddExperiencePoints(int points, bool isInitialization = false)
+ {
+ _totalExperiencePoints += points;
+ UpdateLevel(isInitialization);
+ UpdateCurrentExperiencePoints();
+
+ if (isInitialization)
+ return;
+
+ ExperiencePointsChanged?.Invoke(null, new LevelEventArgs()
+ {
+ CurrentLevel = _level,
+ LevelTitle = GetTitle(_level),
+ CurrentXp = _currentExperiencePoints,
+ XpRequiredForLevelUp = GetXpRequiredForNextLevel()
+ });
+ }
+
+ private void UpdateCurrentExperiencePoints()
+ {
+ int xpForCurrentLevel = _experienceToLevelMap.FirstOrDefault(mapEntry => mapEntry.Level == _level).MinimumTotalExperiencePoints;
+ _currentExperiencePoints = _totalExperiencePoints - xpForCurrentLevel;
+ }
+
+ private void UpdateLevel(bool isInitialization)
+ {
+ int previousLevel = _level;
+ _level = _experienceToLevelMap.FirstOrDefault(mapEntry => _totalExperiencePoints < mapEntry.MinimumTotalExperiencePoints).Level - 1;
+
+ if (!isInitialization && previousLevel < _level)
+ LevelChanged?.Invoke(null, new LevelEventArgs() { CurrentLevel = _level, LevelTitle = GetTitle(_level) });
+ }
+
+ private int GetXpRequiredForNextLevel()
+ {
+ int totalXpForNextLevel = _experienceToLevelMap.FirstOrDefault(mapEntry => mapEntry.Level == _level + 1).MinimumTotalExperiencePoints;
+ int totalXpForCurrentLevel = _experienceToLevelMap.FirstOrDefault(mapEntry => mapEntry.Level == _level).MinimumTotalExperiencePoints;
+ return totalXpForNextLevel - totalXpForCurrentLevel;
+ }
+
+ private int GetExperiencePointsFor(CockpitAction action)
+ {
+ switch (action)
+ {
+ case CockpitAction.CaseOpened:
+ break;
+ case CockpitAction.CaseClosed:
+ return 10;
+ case CockpitAction.QuickActionExecuted:
+ return 20;
+ case CockpitAction.CopyTemplateClicked:
+ return 5;
+ case CockpitAction.BuiltDirectConnection:
+ break;
+ case CockpitAction.AddNotes:
+ break;
+ case CockpitAction.StartRemoteConnection:
+ return 50;
+ default:
+ break;
+ }
+
+ return 1;
+ }
+
+ private static string GetTitle(int level)
+ {
+ switch (level)
+ {
+ case <= 5:
+ return "Support Trainee";
+ case <= 10:
+ return "Response Assistant";
+ case <= 15:
+ return "Service Aider";
+ case <= 20:
+ return "Ticket Resolver";
+ case <= 25:
+ return "Customer Navigator";
+ case <= 30:
+ return "Incident Coordinator";
+ case <= 35:
+ return "IT Guy";
+ case <= 40:
+ return "Support Specialist";
+ case <= 45:
+ return "Service Mentor";
+ case <= 49:
+ return "Operations Lead";
+ case > 49:
+ return "Ticket Titan";
+ }
+ }
+
+ public static event EventHandler ExperiencePointsChanged;
+ public static event EventHandler LevelChanged;
+ }
+}
diff --git a/F4SD-Gamification/Services/PersistenceService.cs b/F4SD-Gamification/Services/PersistenceService.cs
new file mode 100644
index 0000000..aa9e182
--- /dev/null
+++ b/F4SD-Gamification/Services/PersistenceService.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace F4SD.Gamification.Services
+{
+ internal static class PersistenceService
+ {
+ private static readonly string _databaseName = "F4SD-gmfc.txt";
+ private static readonly string _directory = $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\Consulting4IT GmbH\C4IT First Aid Service Desk";
+
+ private static string GetConnectionString()
+ {
+ return Path.Combine(_directory, _databaseName);
+ }
+
+ internal static void Persist(CockpitAction action)
+ {
+ Initialize();
+
+ using var writer = File.AppendText(GetConnectionString());
+ string actionLine = $"{DateTime.UtcNow},{action}";
+ string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(actionLine));
+ writer.WriteLine(base64);
+ }
+
+ internal static void Initialize()
+ {
+ Directory.CreateDirectory(_directory);
+
+ if (!File.Exists(GetConnectionString()))
+ {
+ FileStream createdFile = File.Create(GetConnectionString());
+ File.SetAttributes(GetConnectionString(), FileAttributes.Hidden);
+ createdFile.Close();
+ }
+ }
+
+ internal static IEnumerable<(DateTime Time, CockpitAction Action)> GetActions()
+ {
+ using StreamReader reader = new(GetConnectionString());
+
+ string line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ string encodedLine = string.Empty;
+
+ try { encodedLine = Encoding.UTF8.GetString(Convert.FromBase64String(line)); }
+ catch { continue; }
+
+ if (string.IsNullOrWhiteSpace(encodedLine))
+ continue;
+
+ string[] splittedLine = encodedLine.Split(',');
+
+ if (splittedLine.Length < 2)
+ continue;
+
+ if (!DateTime.TryParse(splittedLine[0], out var date))
+ continue;
+
+ if (!(Enum.TryParse(splittedLine[1], out CockpitAction action)))
+ continue;
+
+ yield return new(date, action);
+ }
+ }
+ }
+}
diff --git a/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj b/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj
index 15eac1a..78f9499 100644
--- a/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj
+++ b/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj
@@ -67,7 +67,7 @@
.\Interop.CLMgr.dll
- ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
diff --git a/F4SD-PhoneMonitor/packages.config b/F4SD-PhoneMonitor/packages.config
index 17ab3be..fef83be 100644
--- a/F4SD-PhoneMonitor/packages.config
+++ b/F4SD-PhoneMonitor/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/Controllers/MenuDataFactoryTest.cs b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/Controllers/MenuDataFactoryTest.cs
new file mode 100644
index 0000000..ed3a6bb
--- /dev/null
+++ b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/Controllers/MenuDataFactoryTest.cs
@@ -0,0 +1,44 @@
+using C4IT.FASD.Base;
+using C4IT.MultiLanguage;
+using FasdDesktopUi.Basics;
+using FasdDesktopUi.Basics.Models;
+using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
+using FasdDesktopUi.Basics.UiActions;
+
+namespace F4SD.Cockpit.Client.Test.Basics.Sevices.SupportCase.Controllers;
+
+public class MenuDataFactoryTest
+{
+ public MenuDataFactoryTest()
+ {
+ cMultiLanguageSupport.CurrentLanguage = "EN";
+ }
+
+ [Fact]
+ public async Task Create_From_QuickActionDefinition()
+ {
+ cF4sdQuickActionRemoteComputer menuDataDefinition = new()
+ {
+ Id = Guid.NewGuid(),
+ Names = new() { ["EN"] = "Foo EN", ["DE"] = "Foo DE" },
+ Icon = { IconType = enumIconType.intern, Name = nameof(enumInternIcon.misc_computer) },
+ Descriptions = new() { ["EN"] = "Bar EN", ["DE"] = "Bar DE" },
+ AlternativeDescriptions = new() { ["EN"] = "FooBar EN", ["DE"] = "FooBar DE" },
+ Section = "Section 1",
+ Sections = ["Section 2", "Section 3"],
+ IsHidden = false
+ };
+
+ cMenuDataBase expected = new()
+ {
+ MenuText = "Foo EN",
+ MenuIcon = new cMenuDataBase.MenuIconInfo(new(F4SD_AdaptableIcon.Enums.enumInternIcons.misc_computer), null, false, null),
+ MenuSections = ["Section 1", "Section 2", "Section 3"],
+ UiAction = new cUiRemoteQuickAction(menuDataDefinition) { DisplayType = FasdDesktopUi.Basics.Enums.enumActionDisplayType.enabled }
+ };
+
+ cMenuDataBase actual = MenuDataFactory.Create(menuDataDefinition, [], []);
+
+ Assert.Equivalent(expected, actual);
+ }
+}
diff --git a/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseProcessorTest.cs b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseProcessorTest.cs
new file mode 100644
index 0000000..d1e49d0
--- /dev/null
+++ b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseProcessorTest.cs
@@ -0,0 +1,224 @@
+using C4IT.FASD.Base;
+using C4IT.MultiLanguage;
+using FasdDesktopUi.Basics.Services.Models;
+using FasdDesktopUi.Basics.Services.SupportCase;
+using FasdDesktopUi.Basics.Services.SupportCase.Processors;
+using FasdDesktopUi.Basics.UiActions;
+using NSubstitute;
+using System.Globalization;
+
+namespace F4SD.Cockpit.Client.Test.Basics.Sevices.SupportCase;
+
+public class SupportCaseProcessorTest
+{
+ private readonly SupportCaseProcessor _supportCaseProcessor;
+ private readonly ISupportCase _mockSupportCase = Substitute.For();
+
+ private static readonly cMultiLanguageDictionary _stateTitle = new() { ["EN"] = "Bar", ["DE"] = "Bar (DE)" };
+
+ public SupportCaseProcessorTest()
+ {
+ _supportCaseProcessor = new SupportCaseProcessor();
+ _supportCaseProcessor.SetSupportCase(_mockSupportCase);
+ cMultiLanguageSupport.CurrentLanguage = "EN";
+ cF4SDCockpitXmlConfig.Instance = new() { HealthCardConfig = new() { SearchResultAge = 14 } };
+ }
+
+ [Theory]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateInfo))]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateLevel))]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateTranslation))]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateDateTime))]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateVersion))]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateDetails))]
+ public void Test_CockpitValueDisplayData(MockState mockState, CockpitValueDisplayData expected)
+ {
+ _mockSupportCase.GetSupportCaseHealthcardData(default, default, Arg.Any()).ReturnsForAnyArgs([mockState.RawData]);
+
+ CockpitValueDisplayData actual = _supportCaseProcessor.GetCockpitValueDisplayData(mockState.StateDefinition, default, default);
+
+ Assert.Equivalent(expected, actual);
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateInfo()
+ {
+ yield return (new(new cHealthCardStateInfo() { Names = _stateTitle, IsNotTransparent = false }, "Foo"), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateInfo() { Names = _stateTitle, IsNotTransparent = true }, "Foo"), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.Info] });
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateLevel()
+ {
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 6, Error = 7, IsDirectionUp = true, IsNotTransparent = false }, 5), new() { Title = "Bar", Values = ["5"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 6, Error = 7, IsDirectionUp = true, IsNotTransparent = true }, 5), new() { Title = "Bar", Values = ["5"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 6, Error = 7, IsDirectionUp = true, IsNotTransparent = true }, 6), new() { Title = "Bar", Values = ["6"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 6, Error = 7, IsDirectionUp = true, IsNotTransparent = true }, 7), new() { Title = "Bar", Values = ["7"], Levels = [enumHealthCardStateLevel.Error] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 4, Error = 2, IsDirectionUp = false, IsNotTransparent = false }, 5), new() { Title = "Bar", Values = ["5"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 4, Error = 2, IsDirectionUp = false, IsNotTransparent = true }, 5), new() { Title = "Bar", Values = ["5"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 4, Error = 2, IsDirectionUp = false, IsNotTransparent = true }, 4), new() { Title = "Bar", Values = ["4"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateLevel() { Names = _stateTitle, Warning = 4, Error = 2, IsDirectionUp = false, IsNotTransparent = true }, 2), new() { Title = "Bar", Values = ["2"], Levels = [enumHealthCardStateLevel.Error] });
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateTranslation()
+ {
+ cF4SDCockpitXmlConfig translationConfigNode = new() { HealthCardConfig = new cF4SDHealthCardConfig() };
+ translationConfigNode.Translations.Add("MyTranslation", new cHealthCardTranslator()
+ {
+ DefaultTranslation = new() { Translation = new() { ["EN"] = "Foo translated" }, StateLevel = enumHealthCardStateLevel.Error },
+ Translations = [
+ new() { Translation = new() { ["EN"] = "Foo Info translated"}, Values = ["Foo Info"], StateLevel = enumHealthCardStateLevel.Info},
+ new() { Translation = new() { ["EN"] = "Foo Ok translated"}, Values = ["Foo Ok"], StateLevel = enumHealthCardStateLevel.Ok},
+ new() { Translation = new() { ["EN"] = "Foo Warning translated"}, Values = ["Foo Warning"], StateLevel = enumHealthCardStateLevel.Warning},
+ new() { Translation = new() { ["EN"] = "Foo Error translated"}, Values = ["Foo Error"], StateLevel = enumHealthCardStateLevel.Error},
+ ]
+ });
+
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = false }, "Foo"), new() { Title = "Bar", Values = ["Foo translated"], Levels = [enumHealthCardStateLevel.Error] });
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = false }, "Foo Ok"), new() { Title = "Bar", Values = ["Foo Ok translated"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = true }, "Foo Ok"), new() { Title = "Bar", Values = ["Foo Ok translated"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = false }, "Foo Info"), new() { Title = "Bar", Values = ["Foo Info translated"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = true }, "Foo Info"), new() { Title = "Bar", Values = ["Foo Info translated"], Levels = [enumHealthCardStateLevel.Info] });
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = true }, "Foo Warning"), new() { Title = "Bar", Values = ["Foo Warning translated"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "MyTranslation", IsNotTransparent = true }, "Foo Error"), new() { Title = "Bar", Values = ["Foo Error translated"], Levels = [enumHealthCardStateLevel.Error] });
+
+ yield return (new(new cHealthCardStateTranslation(translationConfigNode) { Names = _stateTitle, Translation = "NoTranslation", IsNotTransparent = false }, "Foo Ok"), new() { Title = "Bar", Values = [null], Levels = [enumHealthCardStateLevel.None] });
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateDateTime()
+ {
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 6, ErrorHours = 7, IsDirectionUp = true, IsNotTransparent = false }, DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 6, ErrorHours = 7, IsDirectionUp = true, IsNotTransparent = true }, DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 6, ErrorHours = 7, IsDirectionUp = true, IsNotTransparent = true }, DateTime.UtcNow.AddHours(-6).ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.AddHours(-6).ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 6, ErrorHours = 7, IsDirectionUp = true, IsNotTransparent = true }, DateTime.UtcNow.AddHours(-7).ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.AddHours(-7).ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.Error] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 4, ErrorHours = 2, IsDirectionUp = false, IsNotTransparent = false }, DateTime.UtcNow.AddHours(-5).ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.AddHours(-5).ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 4, ErrorHours = 2, IsDirectionUp = false, IsNotTransparent = true }, DateTime.UtcNow.AddHours(-5).ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.AddHours(-5).ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 4, ErrorHours = 2, IsDirectionUp = false, IsNotTransparent = true }, DateTime.UtcNow.AddHours(-4).ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.AddHours(-4).ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateDateTime() { Names = _stateTitle, WarningHours = 4, ErrorHours = 2, IsDirectionUp = false, IsNotTransparent = true }, DateTime.UtcNow.AddHours(-2).ToString(CultureInfo.CurrentCulture)), new() { Title = "Bar", Values = [DateTime.UtcNow.AddHours(-2).ToString(CultureInfo.CurrentCulture)], Levels = [enumHealthCardStateLevel.Error] });
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateVersion()
+ {
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = false }, "4.2.4.1"), new() { Title = "Bar", Values = ["4.2.4.1"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = true }, "4.2.4.1"), new() { Title = "Bar", Values = ["4.2.4.1"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = true }, "4.2.4.2"), new() { Title = "Bar", Values = ["4.2.4.2"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = true }, "6.7.6.7"), new() { Title = "Bar", Values = ["6.7.6.7"], Levels = [enumHealthCardStateLevel.Error] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = false }, "6.7.6.8"), new() { Title = "Bar", Values = ["6.7.6.8"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = true }, "6.7.6.8"), new() { Title = "Bar", Values = ["6.7.6.8"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = true }, "6.7.6.7"), new() { Title = "Bar", Values = ["6.7.6.7"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = true }, "4.2.4.2"), new() { Title = "Bar", Values = ["4.2.4.2"], Levels = [enumHealthCardStateLevel.Error] });
+
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = false }, Version.Parse("4.2.4.1")), new() { Title = "Bar", Values = ["4.2.4.1"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = true }, Version.Parse("4.2.4.1")), new() { Title = "Bar", Values = ["4.2.4.1"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = true }, Version.Parse("4.2.4.2")), new() { Title = "Bar", Values = ["4.2.4.2"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("4.2.4.2"), Error = Version.Parse("6.7.6.7"), IsDirectionUp = true, IsNotTransparent = true }, Version.Parse("6.7.6.7")), new() { Title = "Bar", Values = ["6.7.6.7"], Levels = [enumHealthCardStateLevel.Error] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = false }, Version.Parse("6.7.6.8")), new() { Title = "Bar", Values = ["6.7.6.8"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = true }, Version.Parse("6.7.6.8")), new() { Title = "Bar", Values = ["6.7.6.8"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = true }, Version.Parse("6.7.6.7")), new() { Title = "Bar", Values = ["6.7.6.7"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateVersion() { Names = _stateTitle, Warning = Version.Parse("6.7.6.7"), Error = Version.Parse("4.2.4.2"), IsDirectionUp = false, IsNotTransparent = true }, Version.Parse("4.2.4.2")), new() { Title = "Bar", Values = ["4.2.4.2"], Levels = [enumHealthCardStateLevel.Error] });
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateDetails()
+ {
+ cMultiLanguageSupport.CurrentLanguage = "EN";
+
+ cHealthCardStateInfo stateDefinitionWithDetails = new() { Names = _stateTitle };
+ stateDefinitionWithDetails.Details = new cHealthCardDetailsValued(stateDefinitionWithDetails) { Format = cHealthCardDetailsValued.ValuedFormat.csv, RowSeparator = ',', ColSeparator = null };
+ yield return (new(stateDefinitionWithDetails, "42:42:42:42:42:42,67:67:67:67:67:67,69:69:69:69:69:69,,C0:FE:C0:FE:C0:FE"), new() { Title = "Bar", Values = ["4"], Levels = [enumHealthCardStateLevel.None], UiActions = [new cShowDetailedDataAction(stateDefinitionWithDetails, 0, null) { DisplayType = FasdDesktopUi.Basics.Enums.enumActionDisplayType.enabled }] });
+
+ stateDefinitionWithDetails = new() { Names = _stateTitle };
+ stateDefinitionWithDetails.Details = new cHealthCardDetailsValued(stateDefinitionWithDetails) { Format = cHealthCardDetailsValued.ValuedFormat.json, RowSeparator = ',', ColSeparator = null };
+ stateDefinitionWithDetails.Details.Add(new cHealthCardDetailsColumn() { Names = _stateTitle, Column = "Status" });
+ stateDefinitionWithDetails.Details.Add(new cHealthCardDetailsColumn() { Names = new() { ["EN"] = "Hello" }, Column = "Name" });
+ yield return (new(stateDefinitionWithDetails, "[{\"Availability\":2,\"BatteryStatus\":2,\"Caption\":\"Interner Akku\",\"Description\":\"Interner Akku\",\"EstimatedRunTime\":71582788,\"Name\":\"DELL 803W64C7\",\"Status\":\"OK\"}]"), new() { Title = "Bar", Values = ["OK"], Levels = [enumHealthCardStateLevel.None], UiActions = [new cShowDetailedDataAction(stateDefinitionWithDetails, 0, null) { DisplayType = FasdDesktopUi.Basics.Enums.enumActionDisplayType.enabled }] });
+ }
+
+ [Theory]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateRefLink))]
+ public void Test_CockpitValueDisplayData_RefLink(MockState mockState, MockState referencedMockState, CockpitValueDisplayData expected)
+ {
+ _mockSupportCase.GetSupportCaseHealthcardData(default, Arg.Is(referencedMockState.StateDefinition.DatabaseInfo), Arg.Any()).Returns([referencedMockState.RawData]);
+
+ if (referencedMockState.StateDefinition is cHealthCardStateAggregation aggregation)
+ {
+ foreach (var state in aggregation.States)
+ {
+ _mockSupportCase.GetSupportCaseHealthcardData(default, Arg.Is(state.DatabaseInfo), Arg.Any()).Returns([42]);
+ }
+ }
+
+ _mockSupportCase.GetSupportCaseHealthcardData(default, Arg.Is(mockState.StateDefinition.DatabaseInfo), Arg.Any()).Returns([mockState.RawData]);
+
+ CockpitValueDisplayData actual = _supportCaseProcessor.GetCockpitValueDisplayData(mockState.StateDefinition, default, default);
+
+ Assert.Equivalent(expected, actual);
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateRefLink()
+ {
+ const int referenceValue = 42;
+
+ var levelNoneStateDefinition = new cHealthCardStateLevel() { Name = "MyReferenceNone", DatabaseInfo = new() { ValueTable = "Foo", ValueColumn = "BarNone" }, Warning = referenceValue + 1, Error = referenceValue + 2, IsDirectionUp = true, IsNotTransparent = false };
+ var levelInfoStateDefinition = new cHealthCardStateInfo() { Name = "MyReferenceInfo", DatabaseInfo = new() { ValueTable = "Foo", ValueColumn = "BarInfo" }, IsNotTransparent = true };
+ var levelOkStateDefinition = new cHealthCardStateLevel() { Name = "MyReferenceOk", DatabaseInfo = new() { ValueTable = "Foo", ValueColumn = "BarOk" }, Warning = referenceValue + 1, Error = referenceValue + 2, IsDirectionUp = true, IsNotTransparent = true };
+ var levelWarningStateDefinition = new cHealthCardStateLevel() { Name = "MyReferenceWarning", DatabaseInfo = new() { ValueTable = "Foo", ValueColumn = "BarWarning" }, Warning = referenceValue, Error = referenceValue + 1, IsDirectionUp = true, IsNotTransparent = true };
+ var levelErrorStateDefinition = new cHealthCardStateLevel() { Name = "MyReferenceError", DatabaseInfo = new() { ValueTable = "Foo", ValueColumn = "BarError" }, Warning = referenceValue, Error = referenceValue, IsDirectionUp = true, IsNotTransparent = true };
+ var levelWarningAggregationDefinition = new cHealthCardStateAggregation() { Name = "MyReferenceAggregation", States = [levelOkStateDefinition, levelWarningStateDefinition] };
+
+ var stateConfigNode = new cF4SDHealthCardConfig();
+ stateConfigNode.Prerequisites.ReferencableStates.Add(levelNoneStateDefinition.Name, levelNoneStateDefinition);
+ stateConfigNode.Prerequisites.ReferencableStates.Add(levelInfoStateDefinition.Name, levelInfoStateDefinition);
+ stateConfigNode.Prerequisites.ReferencableStates.Add(levelOkStateDefinition.Name, levelOkStateDefinition);
+ stateConfigNode.Prerequisites.ReferencableStates.Add(levelWarningStateDefinition.Name, levelWarningStateDefinition);
+ stateConfigNode.Prerequisites.ReferencableStates.Add(levelErrorStateDefinition.Name, levelErrorStateDefinition);
+ stateConfigNode.Prerequisites.ReferencableStates.Add(levelWarningAggregationDefinition.Name, levelWarningAggregationDefinition);
+
+ yield return (new(new cHealthCardStateRefLink(stateConfigNode) { Names = _stateTitle, DatabaseInfo = new() { ValueTable = "Bar", ValueColumn = "Foo" }, Reference = levelNoneStateDefinition.Name }, "Foo"), new(levelNoneStateDefinition, referenceValue), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.None] });
+ yield return (new(new cHealthCardStateRefLink(stateConfigNode) { Names = _stateTitle, DatabaseInfo = new() { ValueTable = "Bar", ValueColumn = "Foo" }, Reference = levelInfoStateDefinition.Name }, "Foo"), new(levelInfoStateDefinition, referenceValue), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.Info] });
+ yield return (new(new cHealthCardStateRefLink(stateConfigNode) { Names = _stateTitle, DatabaseInfo = new() { ValueTable = "Bar", ValueColumn = "Foo" }, Reference = levelOkStateDefinition.Name, IsNotTransparent = true }, "Foo"), new(levelOkStateDefinition, referenceValue), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.Ok] });
+ yield return (new(new cHealthCardStateRefLink(stateConfigNode) { Names = _stateTitle, DatabaseInfo = new() { ValueTable = "Bar", ValueColumn = "Foo" }, Reference = levelWarningStateDefinition.Name }, "Foo"), new(levelWarningStateDefinition, referenceValue), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.Warning] });
+ yield return (new(new cHealthCardStateRefLink(stateConfigNode) { Names = _stateTitle, DatabaseInfo = new() { ValueTable = "Bar", ValueColumn = "Foo" }, Reference = levelErrorStateDefinition.Name }, "Foo"), new(levelErrorStateDefinition, referenceValue), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.Error] });
+ yield return (new(new cHealthCardStateRefLink(stateConfigNode) { Names = _stateTitle, DatabaseInfo = new() { ValueTable = "Bar", ValueColumn = "Foo" }, Reference = levelWarningAggregationDefinition.Name }, "Foo"), new(levelWarningAggregationDefinition, referenceValue), new() { Title = "Bar", Values = ["Foo"], Levels = [enumHealthCardStateLevel.Warning] });
+ }
+
+ [Theory]
+ [MemberData(nameof(GetCockpitValueDisplayDataTestData_StateAggregation))]
+ public void Test_CockpitValueDisplayData_Aggregation(MockState mockState, CockpitValueDisplayData expected, params MockState[] aggregatedStates)
+ {
+ foreach (var aggregatedState in aggregatedStates)
+ {
+ _mockSupportCase.GetSupportCaseHealthcardData(default, Arg.Is(aggregatedState.StateDefinition.DatabaseInfo), Arg.Any()).Returns([aggregatedState.RawData]);
+
+ if (mockState.StateDefinition is cHealthCardStateAggregation stateAggreagtion)
+ stateAggreagtion.States.Add(aggregatedState.StateDefinition);
+ }
+
+ _mockSupportCase.GetSupportCaseHealthcardData(default, Arg.Is(mockState.StateDefinition.DatabaseInfo), Arg.Any()).Returns([mockState.RawData]);
+
+ CockpitValueDisplayData actual = _supportCaseProcessor.GetCockpitValueDisplayData(mockState.StateDefinition, default, default);
+
+ Assert.Equivalent(expected, actual);
+ }
+
+ public static IEnumerable> GetCockpitValueDisplayDataTestData_StateAggregation()
+ {
+ MockState stateOk = new(new cHealthCardStateLevel() { DatabaseInfo = new() { ValueTable = "MyAggregated", ValueColumn = "Ok" }, Warning = 43, Error = 44, IsDirectionUp = true }, 42);
+ MockState stateWarning = new(new cHealthCardStateLevel() { DatabaseInfo = new() { ValueTable = "MyAggregated", ValueColumn = "Warning" }, Warning = 42, Error = 43, IsDirectionUp = true }, 42);
+ MockState stateError = new(new cHealthCardStateLevel() { DatabaseInfo = new() { ValueTable = "MyAggregated", ValueColumn = "Error" }, Warning = 41, Error = 42, IsDirectionUp = true }, 42);
+
+ yield return (new(new cHealthCardStateAggregation() { Names = _stateTitle, IsNotTransparent = false }, null), new() { Title = "Bar", Values = ["Ø"], Levels = [enumHealthCardStateLevel.None] }, [stateOk]);
+ yield return (new(new cHealthCardStateAggregation() { Names = _stateTitle, IsNotTransparent = true }, null), new() { Title = "Bar", Values = ["Ø"], Levels = [enumHealthCardStateLevel.Ok] }, [stateOk]);
+ yield return (new(new cHealthCardStateAggregation() { Names = _stateTitle, IsNotTransparent = true }, null), new() { Title = "Bar", Values = ["Ø"], Levels = [enumHealthCardStateLevel.Warning] }, [stateOk, stateWarning]);
+ yield return (new(new cHealthCardStateAggregation() { Names = _stateTitle, IsNotTransparent = true }, null), new() { Title = "Bar", Values = ["Ø"], Levels = [enumHealthCardStateLevel.Error] }, [stateOk, stateWarning, stateError]);
+ }
+
+ public record MockState
+ {
+ public cHealthCardStateBase StateDefinition { get; set; }
+ public object? RawData { get; set; }
+
+ public MockState(cHealthCardStateBase stateDefinition, object? rawData)
+ {
+ StateDefinition = stateDefinition;
+ RawData = rawData;
+ }
+ }
+}
diff --git a/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs
index f7a23d3..b4e0c52 100644
--- a/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs
+++ b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs
@@ -126,7 +126,7 @@ public class SupportCaseTest
_supportCase.UpdateSupportCaseDataCache(relation, [dataTable]);
// Assert
- var actual = _supportCase.GetSupportCaseHealthcardData(relation, new cValueAddress() { ValueTable = tableName, ValueColumn = columnName });
+ var actual = _supportCase.GetSupportCaseHealthcardData(relation, new cValueAddress() { ValueTable = tableName, ValueColumn = columnName }, default);
Assert.Equal(expected, actual);
}
@@ -145,7 +145,7 @@ public class SupportCaseTest
]
};
// Act
- var actual = _supportCase.GetSupportCaseHealthcardData(relation, new cValueAddress() { ValueTable = "NonExistentTable", ValueColumn = "NonExistentColumn" });
+ var actual = _supportCase.GetSupportCaseHealthcardData(relation, new cValueAddress() { ValueTable = "NonExistentTable", ValueColumn = "NonExistentColumn" }, default);
// Assert
Assert.Null(actual);
}
diff --git a/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj b/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj
index 4d0cc30..8bd807d 100644
--- a/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj
+++ b/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj
@@ -5,7 +5,8 @@
enable
Exe
F4SD.Cockpit.Client.Test
- net10.0
+ net10.0-windows
+ true
-
+
-
-
+
+
-
-
+ MouseLeftButtonUp="Border_Click"
+ TouchDown="Border_Click">
-
-
-
+
diff --git a/FasdDesktopUi/Basics/UserControls/TimerView.xaml.cs b/FasdDesktopUi/Basics/UserControls/TimerView.xaml.cs
index 94e221a..6e79f42 100644
--- a/FasdDesktopUi/Basics/UserControls/TimerView.xaml.cs
+++ b/FasdDesktopUi/Basics/UserControls/TimerView.xaml.cs
@@ -15,18 +15,18 @@ namespace FasdDesktopUi.Basics.UserControls
public event EventHandler OnPauseStarted;
- private static List startTimes = new List();
- private static List endTimes = new List();
- private static List pausedTimesStart = new List();
- private static List pausedTimesEnd = new List();
+ private static readonly List _startTimes = new List();
+ private static readonly List _endTimes = new List();
+ private static readonly List _pausedTimesStart = new List();
+ private static readonly List _pausedTimesEnd = new List();
- public static List caseTimes = new List();
- private static Dictionary finalWorkingTimes = new Dictionary();
+ public static List CaseTimes = new List();
+ private static Dictionary _finalWorkingTimes = new Dictionary();
- private static DispatcherTimer timer;
- private static TimeSpan elapsedTime;
- private static TimeSpan totalPausedTime = TimeSpan.Zero;
- private static TimeSpan pauseDuration;
+ private static DispatcherTimer _timer;
+ private static TimeSpan _elapsedTime;
+ private static TimeSpan _totalPausedTime = TimeSpan.Zero;
+ private static TimeSpan _pauseDuration;
#endregion
@@ -39,13 +39,13 @@ namespace FasdDesktopUi.Basics.UserControls
public static void ResetTimer()
{
- startTimes.Clear();
- endTimes.Clear();
- pausedTimesEnd.Clear();
- pausedTimesStart.Clear();
- finalWorkingTimes.Clear();
- elapsedTime = TimeSpan.Zero;
- caseTimes.Clear();
+ _startTimes.Clear();
+ _endTimes.Clear();
+ _pausedTimesEnd.Clear();
+ _pausedTimesStart.Clear();
+ _finalWorkingTimes.Clear();
+ _elapsedTime = TimeSpan.Zero;
+ CaseTimes.Clear();
StartTimer();
}
@@ -54,8 +54,8 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
- startTimes?.Add(DateTime.UtcNow);
- timer?.Start();
+ _startTimes?.Add(DateTime.UtcNow);
+ _timer?.Start();
}
catch (Exception E)
{
@@ -67,8 +67,8 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
- endTimes?.Add(DateTime.UtcNow);
- timer?.Stop();
+ _endTimes?.Add(DateTime.UtcNow);
+ _timer?.Stop();
UpdateTimerControl();
}
catch (Exception E)
@@ -83,7 +83,7 @@ namespace FasdDesktopUi.Basics.UserControls
{
ResetTimer();
- timer = new DispatcherTimer(TimeSpan.FromSeconds(1.0), DispatcherPriority.Loaded, new EventHandler((s, args) =>
+ _timer = new DispatcherTimer(TimeSpan.FromSeconds(1.0), DispatcherPriority.Loaded, new EventHandler((s, args) =>
{
try { UpdateTimerControl(); }
catch { }
@@ -100,8 +100,8 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
- TimerControl.Text = elapsedTime.ToString(@"hh\:mm\:ss");
- elapsedTime = elapsedTime.Add(TimeSpan.FromSeconds(1.0));
+ TimerControl.Text = _elapsedTime.ToString(@"hh\:mm\:ss");
+ _elapsedTime = _elapsedTime.Add(TimeSpan.FromSeconds(1.0));
}
catch (Exception E)
{
@@ -113,44 +113,44 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
- var currentDate = DateTime.Now.Date.ToString("d");
- var startDateTime = startTimes.First();
+ var currentDate = DateTime.UtcNow.Date.ToString("d");
+ var startDateTime = _startTimes.First();
var endDateTime = DateTime.UtcNow;
var bruttoWorkingTime = TimeSpan.Zero;
var nettoWorkingTime = TimeSpan.Zero;
- if (pausedTimesStart.Count == 0)
+ if (_pausedTimesStart.Count == 0)
{
- totalPausedTime = TimeSpan.Zero;
+ _totalPausedTime = TimeSpan.Zero;
}
- if (pausedTimesEnd.Count > 0)
+ if (_pausedTimesEnd.Count > 0)
{
- totalPausedTime = TimeSpan.Zero;
+ _totalPausedTime = TimeSpan.Zero;
- for (int i = 0; i < pausedTimesStart.Count; i++)
+ for (int i = 0; i < _pausedTimesStart.Count; i++)
{
- var start = pausedTimesStart[i];
- var end = pausedTimesEnd[i];
+ var start = _pausedTimesStart[i];
+ var end = _pausedTimesEnd[i];
- pauseDuration = end - start;
+ _pauseDuration = end - start;
- totalPausedTime += pauseDuration;
+ _totalPausedTime += _pauseDuration;
}
}
bruttoWorkingTime = endDateTime - startDateTime;
- nettoWorkingTime = bruttoWorkingTime - totalPausedTime;
+ nettoWorkingTime = bruttoWorkingTime - _totalPausedTime;
- finalWorkingTimes = new Dictionary()
+ _finalWorkingTimes = new Dictionary()
{
{"CurrentDate", currentDate},
- {"StartTime", startTimes.First()},
+ {"StartTime", _startTimes.First()},
{"EndTime", endDateTime },
{"BruttoWorkingTime", bruttoWorkingTime },
{"NettoWorkingTime", nettoWorkingTime.TotalSeconds },
- {"TotalPausedTime", totalPausedTime }
+ {"TotalPausedTime", _totalPausedTime }
};
}
catch (Exception E)
@@ -158,7 +158,7 @@ namespace FasdDesktopUi.Basics.UserControls
LogException(E);
}
- return finalWorkingTimes;
+ return _finalWorkingTimes;
}
#endregion
@@ -169,13 +169,13 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
- if (timer?.IsEnabled == true)
+ if (_timer?.IsEnabled == true)
return;
- timer?.Start();
- pausedTimesEnd?.Add(DateTime.UtcNow);
+ _timer?.Start();
+ _pausedTimesEnd?.Add(DateTime.UtcNow);
- caseTimes.Add(new cF4SDCaseTime()
+ CaseTimes.Add(new cF4SDCaseTime()
{
StatusId = CaseStatus.InProgress,
CaseTime = DateTime.UtcNow
@@ -191,10 +191,10 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
- timer?.Stop();
- pausedTimesStart?.Add(DateTime.UtcNow);
+ _timer?.Stop();
+ _pausedTimesStart?.Add(DateTime.UtcNow);
- caseTimes.Add(new cF4SDCaseTime()
+ CaseTimes.Add(new cF4SDCaseTime()
{
StatusId = CaseStatus.OnHold,
CaseTime = DateTime.UtcNow
@@ -209,17 +209,9 @@ namespace FasdDesktopUi.Basics.UserControls
}
}
-
- private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
- {
- PauseButton_Click();
- }
+ private void Border_Click(object sender, InputEventArgs e)
+ => PauseButton_Click();
#endregion
-
- private void Border_TouchDown(object sender, TouchEventArgs e)
- {
- PauseButton_Click();
- }
}
}
diff --git a/FasdDesktopUi/Basics/cUtility.cs b/FasdDesktopUi/Basics/cUtility.cs
index 2252060..d1d55e3 100644
--- a/FasdDesktopUi/Basics/cUtility.cs
+++ b/FasdDesktopUi/Basics/cUtility.cs
@@ -1,15 +1,13 @@
using C4IT.F4SD.DisplayFormatting;
using C4IT.FASD.Base;
-using C4IT.MultiLanguage;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UserControls;
using FasdDesktopUi.Basics.UserControls.AdaptableIcon;
using System;
-using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -362,7 +360,7 @@ namespace FasdDesktopUi.Basics
try
{
FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.AddDays(_v.ReferenceDays), TimeZone = TimeZoneInfo.Local };
- RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
+ RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
var _strVal = RawValueFormatter.GetDisplayValue(_v.Value, _v.StateDefinition.DisplayType, options);
@@ -468,5 +466,11 @@ namespace FasdDesktopUi.Basics
#endregion
+ public static string GetShortDatePattern()
+ {
+ string datePattern = cFasdCockpitConfig.Instance.SelectedCulture.DateTimeFormat.ShortDatePattern;
+ datePattern = Regex.Replace(datePattern, @"(^|[/.\-\s])y{1,4}($|[/.\-\s]?)", "");
+ return datePattern.Trim('/', '.', '-', ' ');
+ }
}
}
diff --git a/FasdDesktopUi/Config/LanguageDefinitions.xml b/FasdDesktopUi/Config/LanguageDefinitions.xml
index 3159dfb..739ae53 100644
--- a/FasdDesktopUi/Config/LanguageDefinitions.xml
+++ b/FasdDesktopUi/Config/LanguageDefinitions.xml
@@ -192,15 +192,15 @@
Auswählen
-
- Select
- Auswählen
-
+
+ Select
+ Auswählen
+
-
- Select
- Auswählen
-
+
+ Select
+ Auswählen
+
Create ticket
@@ -237,15 +237,15 @@
Es wurden keine Session für diesen Fall gefunden.
-
- There were no mobile device found for this case.
- Es wurden keine mobilen Geräte für diesen Fall gefunden.
-
+
+ There were no mobile device found for this case.
+ Es wurden keine mobilen Geräte für diesen Fall gefunden.
+
-
- There were no tickets found for this case.
- Es wurden keine Tickets für diesen Fall gefunden.
-
+
+ There were no tickets found for this case.
+ Es wurden keine Tickets für diesen Fall gefunden.
+
@@ -334,14 +334,10 @@
-
- You currently have an open support case.
- How would you like to proceed?
-
-
- Sie haben aktuell einen noch nicht abgeschlossenen Support Fall.
- Wie möchten Sie fortfahren?
-
+ You currently have an open support case.
+How would you like to proceed?
+ Sie haben aktuell einen noch nicht abgeschlossenen Support Fall.
+Wie möchten Sie fortfahren?
@@ -473,7 +469,48 @@
Geschlossen
-
+
+ Ticket
+ Ticket
+
+
+
+ Closed ticket
+ geschlossenes Ticket
+
+
+
+ Ticket (not classified)
+ Ticket (nicht klassifiziert)
+
+
+
+ Closed ticket (not classified)
+ geschlossenes Ticket (nicht klassifiziert)
+
+
+
+ Incident
+ Störung
+
+
+
+ Closed incident
+ geschlossene Störung
+
+
+
+ Service request
+ Serviceanfrage
+
+
+
+ Closed service request
+ geschlossene Serviceanfrage
+
+
+
+
Ticket overview updated
Ticketübersicht aktualisiert
@@ -503,30 +540,30 @@
Eigene Tickets
-
- My incidents
- Eigene Störungen
-
-
-
- My unassigned
- Eigener Eingang
-
-
-
- Role tickets
- Rollentickets
-
+
+ My incidents
+ Eigene Störungen
+
-
- Role incidents
- Rollenstörungen
-
-
-
- Role unassigned
- Rolleneingang
-
+
+ My unassigned
+ Eigener Eingang
+
+
+
+ Role tickets
+ Rollentickets
+
+
+
+ Role incidents
+ Rollenstörungen
+
+
+
+ Role unassigned
+ Rolleneingang
+
@@ -555,14 +592,10 @@
-
- Do you really want to restart the F4SD Cockpit?
- All open cases will be closed.
-
-
- Wollen Sie das F4SD Cockpit wirklich schließen?
- Alle offenen Fälle werden dabei geschlossen.
-
+ Do you really want to restart the F4SD Cockpit?
+All open cases will be closed.
+ Wollen Sie das F4SD Cockpit wirklich schließen?
+Alle offenen Fälle werden dabei geschlossen.
@@ -581,16 +614,12 @@
-
- Changes to the language settings will not take effect until the environment is restarted. All open sessions will be lost.
+ Changes to the language settings will not take effect until the environment is restarted. All open sessions will be lost.
- Do you want to restart the F4SD Cockpit now?
-
-
- Änderungen an den Spracheinstellungen treten erst in Kraft, nachdem die Umgebung neu gestartet wurde. Alle offenen Fälle gehen dabei verloren.
+Do you want to restart the F4SD Cockpit now?
+ Änderungen an den Spracheinstellungen treten erst in Kraft, nachdem die Umgebung neu gestartet wurde. Alle offenen Fälle gehen dabei verloren.
- Wollen Sie das F4SD Cockpit jetzt neu starten?
-
+Wollen Sie das F4SD Cockpit jetzt neu starten?
@@ -613,15 +642,16 @@
Position der Favoriten Leiste
+
+ Use level progression system
+ Levelfortschritts-System verwenden
+
+
-
- F4SD® is a registered word mark of Consulting4IT GmbH.
- All rights, including but not limited to, ownership, intellectual property, and exclusive usage of the trademark, are fully held by Consulting4IT GmbH. Any unauthorized use or imitation of the mark is legally prohibited and may lead to civil and criminal penalties.
-
-
- F4SD® ist eine eingetragene Wortmarke der Consulting4IT GmbH.
- Alle Rechte, einschließlich, aber nicht beschränkt auf, das Eigentum, das geistige Eigentum und die exklusive Nutzung der Marke, liegen vollständig bei der Consulting4IT GmbH. Jegliche unautorisierte Nutzung oder Nachahmung der Marke ist gesetzlich verboten und kann zu zivil- und strafrechtlichen Sanktionen führen.
-
+ F4SD® is a registered word mark of Consulting4IT GmbH.
+All rights, including but not limited to, ownership, intellectual property, and exclusive usage of the trademark, are fully held by Consulting4IT GmbH. Any unauthorized use or imitation of the mark is legally prohibited and may lead to civil and criminal penalties.
+ F4SD® ist eine eingetragene Wortmarke der Consulting4IT GmbH.
+Alle Rechte, einschließlich, aber nicht beschränkt auf, das Eigentum, das geistige Eigentum und die exklusive Nutzung der Marke, liegen vollständig bei der Consulting4IT GmbH. Jegliche unautorisierte Nutzung oder Nachahmung der Marke ist gesetzlich verboten und kann zu zivil- und strafrechtlichen Sanktionen führen.
@@ -718,6 +748,11 @@
Führe Quick Action aus.
+
+ Start F4SD phoenix viewer.
+ Starte F4SD Phoenix Viewer.
+
+
Load and run local script.
Lade und führe lokales Skript aus.
@@ -889,15 +924,15 @@
Die Quick Action <b>"{0}"</b> wurde durch F4SD remote auf dem Gerät <b>"{1}"</b> am {2} UTC <b>{3}</b>ausgeführt.
-
- The Quick Action '{0}' was {3}executed remotely by F4SD for the session '{1}' at {2} UTC.
- Die Quick Action "{0}" wurde durch F4SD remote für die Session "{1}" am {2} UTC {3}ausgeführt.
-
+
+ The Quick Action '{0}' was {3}executed remotely by F4SD for the session '{1}' at {2} UTC.
+ Die Quick Action "{0}" wurde durch F4SD remote für die Session "{1}" am {2} UTC {3}ausgeführt.
+
-
- The Quick Action <b>'{0}'</b> was <b>{3}</b>executed remotely by F4SD on the session <b>'{1}'</b> at {2} UTC.
- Die Quick Action <b>"{0}"</b> wurde durch F4SD remote für die Session <b>"{1}"</b> am {2} UTC <b>{3}</b>ausgeführt.
-
+
+ The Quick Action <b>'{0}'</b> was <b>{3}</b>executed remotely by F4SD on the session <b>'{1}'</b> at {2} UTC.
+ Die Quick Action <b>"{0}"</b> wurde durch F4SD remote für die Session <b>"{1}"</b> am {2} UTC <b>{3}</b>ausgeführt.
+
The Quick Action '{0}' was {3}executed local by F4SD for the device '{1}' at {2} UTC.
@@ -1131,25 +1166,17 @@
-
- Phone support was disabled.
- Enable phone support first.
-
-
- Telefonie-Unterstützung wurde deaktiviert.
- Aktivieren Sie zuerst die Telefon-Unterstützung.
-
+ Phone support was disabled.
+Enable phone support first.
+ Telefonie-Unterstützung wurde deaktiviert.
+Aktivieren Sie zuerst die Telefon-Unterstützung.
-
- SwyxIt! native was enabled.
- Disable SwyxIt! native first.
-
-
- Natives SwyxIt! wurde aktiviert.
- Deaktivieren Sie zuerst natives SwyxIt!.
-
+ SwyxIt! native was enabled.
+Disable SwyxIt! native first.
+ Natives SwyxIt! wurde aktiviert.
+Deaktivieren Sie zuerst natives SwyxIt!.
@@ -1163,16 +1190,12 @@
-
- Changes to the phone support will not take effect until the environment is restarted. All open sessions will be lost.
+ Changes to the phone support will not take effect until the environment is restarted. All open sessions will be lost.
- Do you want to restart the F4SD Cockpit now?
-
-
- Änderungen an Telefonie-Unterstützung treten erst in Kraft, nachdem die Umgebung neu gestartet wurde. Alle offenen Fälle gehen dabei verloren.
+Do you want to restart the F4SD Cockpit now?
+ Änderungen an Telefonie-Unterstützung treten erst in Kraft, nachdem die Umgebung neu gestartet wurde. Alle offenen Fälle gehen dabei verloren.
- Wollen Sie das F4SD Cockpit jetzt neu starten?
-
+Wollen Sie das F4SD Cockpit jetzt neu starten?
@@ -1223,16 +1246,12 @@
-
- Changes in the Matrix42 authentification will not take effect until the environment is restarted. All open sessions will be lost.
+ Changes in the Matrix42 authentification will not take effect until the environment is restarted. All open sessions will be lost.
- Do you want to restart the F4SD Cockpit now?
-
-
- Die Änderungen bei der Matrix42 Anmeldung treten erst in Kraft, nachdem die Umgebung neu gestartet wurde. Alle offenen Fälle gehen dabei verloren.
+Do you want to restart the F4SD Cockpit now?
+ Die Änderungen bei der Matrix42 Anmeldung treten erst in Kraft, nachdem die Umgebung neu gestartet wurde. Alle offenen Fälle gehen dabei verloren.
- Wollen Sie das F4SD Cockpit jetzt neu starten?
-
+Wollen Sie das F4SD Cockpit jetzt neu starten?
@@ -1359,8 +1378,8 @@
- Close case
- Fall abschließen
+ Document case
+ Fall dokumentieren
@@ -1715,13 +1734,36 @@
Tickets
-
- Incidents
- Störungen
-
-
-
- Unassigned
- Eingang
-
-
+
+ Incidents
+ Störungen
+
+
+
+ Unassigned
+ Eingang
+
+
+
+ Let's continue!
+ Weiter geht's!
+
+
+
+ Remote connection is currenlty only available for computers
+ Remote Verbindung wird derzeit nur für Computer unterstützt
+
+
+
+ Remote connection services are currently unavailable
+ Die Dienste für Remote Verbindung sind derzeit gestört
+
+
+ Logoff Pending
+ Abmeldung bevorstehend
+
+
+ Urgent maintenance required. You will be logged out shortly. Please save your data.
+ Eine dringende Wartung muss durchgeführt werden. Sie werden in Kürze abgemeldet. Bitte speichern Sie Ihre Daten.
+
+
diff --git a/FasdDesktopUi/F4SD-Cockpit-Client.csproj b/FasdDesktopUi/F4SD-Cockpit-Client.csproj
index d4079b7..d184b92 100644
--- a/FasdDesktopUi/F4SD-Cockpit-Client.csproj
+++ b/FasdDesktopUi/F4SD-Cockpit-Client.csproj
@@ -94,40 +94,40 @@
..\packages\C4IT.F4SD.DisplayFormatting.1.0.0\lib\netstandard2.0\C4IT.F4SD.DisplayFormatting.dll
-
- ..\packages\C4IT.F4SD.SupportCaseProtocoll.1.0.0\lib\netstandard2.0\C4IT.F4SD.SupportCaseProtocoll.dll
+
+ ..\packages\C4IT.F4SD.SupportCaseProtocoll.1.0.1\lib\netstandard2.0\C4IT.F4SD.SupportCaseProtocoll.dll
..\packages\MaterialIcons.1.0.3\lib\MaterialIcons.dll
-
- ..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll
+
+ ..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.3\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll
-
- ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll
+
+ ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.3\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll
-
- ..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.2\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll
+
+ ..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.3\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll
-
- ..\packages\Microsoft.Web.WebView2.1.0.3650.58\lib\net462\Microsoft.Web.WebView2.Core.dll
+
+ ..\packages\Microsoft.Web.WebView2.1.0.3800.47\lib\net462\Microsoft.Web.WebView2.Core.dll
-
- ..\packages\Microsoft.Web.WebView2.1.0.3650.58\lib\net462\Microsoft.Web.WebView2.WinForms.dll
+
+ ..\packages\Microsoft.Web.WebView2.1.0.3800.47\lib\net462\Microsoft.Web.WebView2.WinForms.dll
-
- ..\packages\Microsoft.Web.WebView2.1.0.3650.58\lib\net462\Microsoft.Web.WebView2.Wpf.dll
+
+ ..\packages\Microsoft.Web.WebView2.1.0.3800.47\lib\net462\Microsoft.Web.WebView2.Wpf.dll
- ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll
-
- ..\packages\System.Diagnostics.DiagnosticSource.10.0.2\lib\net462\System.Diagnostics.DiagnosticSource.dll
+
+ ..\packages\System.Diagnostics.DiagnosticSource.10.0.3\lib\net462\System.Diagnostics.DiagnosticSource.dll
@@ -177,7 +177,12 @@
+
+
+
+
+
@@ -209,12 +214,15 @@
+
+
+
-
-
+
+
@@ -244,6 +252,7 @@
+
@@ -252,6 +261,7 @@
+
@@ -281,6 +291,18 @@
ComboBoxPageAble.xaml
+
+ CustomMenuItemToolTipTemplate.xaml
+
+
+ LevelTracker.xaml
+
+
+ FooterButton.xaml
+
+
+ InformationClassSearchBar.xaml
+
DesktopWidgetPageView.xaml
@@ -383,6 +405,9 @@
CustomMessageBox.xaml
+
+ LevelUpPage.xaml
+
RawHealthCardValuesPage.xaml
@@ -501,10 +526,26 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -751,6 +792,10 @@
FunctionMarker.xaml
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
@@ -971,6 +1016,10 @@
{bab63a6a-1524-435d-9f96-7a30b6ee0624}
F4SD-AdaptableIcon
+
+ {b59e7dfd-81c8-4d98-ace5-a8f1fc51f7a8}
+ F4SD-Gamification
+
{7793f281-b226-4e20-b6f6-5d53d70f1dc1}
F4SD-Logging
@@ -1058,11 +1107,21 @@ taskkill -im "F4SD-Cockpit-Client.exe" -f -FI "STATUS eq RUNNING"
copy "$(ProjectDir)..\..\C4IT FASD\_Common\XmlSchemas\LanguageDefinitions.xsd" "$(ProjectDir)Config"
-
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml b/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml
index c7c50b5..df8f12b 100644
--- a/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml
+++ b/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml
@@ -28,15 +28,15 @@
-
+
MultiButtonText, string Caption = null, enumHealthCardStateLevel Level = enumHealthCardStateLevel.None, Window Owner = null, bool TopMost = false, bool CenterScreen = false, int MaxWidth = -1)
- {
- var messageBox = InitializeMessageBox(Message, Caption, Level, Owner, false, false, MultiButtonText, TopMost, CenterScreen);
- if (messageBox == null)
- return -1;
- if (MaxWidth > 0)
- messageBox.MaxWidth = MaxWidth;
- messageBox.ShowDialog();
- return messageBox.ResultIndex;
- }
+ public static int Show(string Message, List MultiButtonText, string Caption = null, enumHealthCardStateLevel Level = enumHealthCardStateLevel.None, Window Owner = null, bool TopMost = false, bool CenterScreen = false, int MaxWidth = -1)
+ {
+ var messageBox = InitializeMessageBox(Message, Caption, Level, Owner, false, false, MultiButtonText, TopMost, CenterScreen);
+ if (messageBox == null)
+ return -1;
+ if (MaxWidth > 0)
+ messageBox.MaxWidth = MaxWidth;
+ messageBox.ShowDialog();
+ return messageBox.ResultIndex;
+ }
public static bool? Show(string Message, string Caption = null, enumHealthCardStateLevel Level = enumHealthCardStateLevel.None, Window Owner = null, bool HasYesNoButtons = false, bool HasYesNoText = false, bool TopMost = false, bool CenterScreen = false)
{
diff --git a/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml b/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml
index d585357..4a6190f 100644
--- a/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml
+++ b/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml
@@ -8,6 +8,7 @@
xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon"
xmlns:uc="clr-namespace:FasdDesktopUi.Pages.DetailsPage.UserControls"
xmlns:buc="clr-namespace:FasdDesktopUi.Basics.UserControls"
+ xmlns:bucg="clr-namespace:FasdDesktopUi.Basics.UserControls.Gamification"
xmlns:quc="clr-namespace:FasdDesktopUi.Basics.UserControls.QuickTip"
xmlns:vm="clr-namespace:FasdDesktopUi.Pages.DetailsPage.ViewModels"
xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter"
@@ -84,93 +85,99 @@
Grid.Row="0"
Panel.ZIndex="2"
PreviewMouseLeftButtonDown="Header_PreviewMouseLeftButtonDown">
-
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+ Panel.ZIndex="1" />
+ IsVisibleChanged="DynamicElement_IsVisibleChanged"
+ SearchValueChanged="QuickActionSelectorUc_SearchValueChanged" />
@@ -246,13 +254,6 @@
Visibility="Collapsed"
IsVisibleChanged="DynamicElement_IsVisibleChanged" />
-
-
+
+
-
+
+
+
-
diff --git a/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml.cs
index 72e53ec..eeff376 100644
--- a/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml.cs
+++ b/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml.cs
@@ -1,37 +1,37 @@
-using System;
+using C4IT.FASD.Base;
+using C4IT.FASD.Cockpit.Communication;
+using C4IT.MultiLanguage;
+using FasdDesktopUi.Basics;
+using FasdDesktopUi.Basics.Converter;
+using FasdDesktopUi.Basics.CustomEvents;
+using FasdDesktopUi.Basics.Helper;
+using FasdDesktopUi.Basics.Models;
+using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
+using FasdDesktopUi.Basics.UiActions;
+using FasdDesktopUi.Basics.UserControls;
+using FasdDesktopUi.Basics.UserControls.QuickTip;
+using FasdDesktopUi.Pages.DetailsPage.Models;
+using FasdDesktopUi.Pages.DetailsPage.UserControls;
+using FasdDesktopUi.Pages.DetailsPage.ViewModels;
+using FasdDesktopUi.Pages.SettingsPage;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
-using System.Windows.Media.Effects;
-using System.Windows.Controls;
-using System.Threading.Tasks;
-using System.Windows.Media.Animation;
-using System.Windows.Threading;
-using System.Windows.Documents;
using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Effects;
using System.Windows.Shell;
-
-using FasdDesktopUi.Basics;
-using FasdDesktopUi.Basics.UiActions;
-using FasdDesktopUi.Basics.UserControls;
-using FasdDesktopUi.Basics.Models;
-using FasdDesktopUi.Basics.Helper;
-using FasdDesktopUi.Pages.SettingsPage;
-using FasdDesktopUi.Pages.DetailsPage.Models;
-using FasdDesktopUi.Pages.DetailsPage.ViewModels;
-using FasdDesktopUi.Pages.DetailsPage.UserControls;
-
-using C4IT.FASD.Base;
-using C4IT.MultiLanguage;
-
+using System.Windows.Threading;
using static C4IT.Logging.cLogManager;
-using F4SD_AdaptableIcon.Enums;
-using FasdDesktopUi.Basics.CustomEvents;
-using FasdDesktopUi.Basics.Converter;
-using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
+using static System.Windows.Forms.AxHost;
namespace FasdDesktopUi.Pages.DetailsPage
{
@@ -107,7 +107,7 @@ namespace FasdDesktopUi.Pages.DetailsPage
case SettingsPageBase _:
case CustomMessageBox.CustomMessageBox _:
case TicketCompletion.TicketCompletion _:
- case SearchBar _:
+ case InformationClassSearchBar _:
case SuccessPage.SuccessPage _:
case BlurInvokerContainer _:
return true;
@@ -201,8 +201,8 @@ namespace FasdDesktopUi.Pages.DetailsPage
}
private void HandleAvailableRelationsAdded(object sender, RelationEventArgs e)
- {
- }
+ => Dispatcher.Invoke(() => NavigationHeadingUc.HeadingData = _supportCaseController.GetHeadingData().ToList());
+
private void HandleFocusedRelationsChanged(object sender, RelationEventArgs e)
{
@@ -234,15 +234,15 @@ namespace FasdDesktopUi.Pages.DetailsPage
isDataChangedEventRunning = true;
- Dispatcher.Invoke(() =>
+ Dispatcher.Invoke(async () =>
{
if (QuickActionDecorator.Child is DataCanvas dataCanvas)
- Dispatcher.Invoke(async () => await dataCanvas.UpdateDataAsync());
+ _ = Dispatcher.Invoke(async () => await dataCanvas.UpdateDataAsync());
if (WidgetCollection.WidgetDataList is null || WidgetCollection.WidgetDataList.Count == 0)
- WidgetCollection.WidgetDataList = _supportCaseController?.GetWidgetData();
+ WidgetCollection.WidgetDataList = _supportCaseController?.GetWidgetsData();
- WidgetCollection.UpdateWidgetData(_supportCaseController?.GetWidgetData());
+ WidgetCollection.UpdateWidgetData(_supportCaseController?.GetWidgetsData());
if (DataHistoryCollectionUserControl.HistoryDataList is null || DataHistoryCollectionUserControl.HistoryDataList.Count == 0)
DataHistoryCollectionUserControl.HistoryDataList = _supportCaseController?.GetHistoryData();
@@ -255,7 +255,9 @@ namespace FasdDesktopUi.Pages.DetailsPage
CustomizableSectionUc.UpdateContainerCollection(_supportCaseController?.GetContainerData());
if (this.DataContext is DetailsPageViewModel viewModel)
- viewModel.MenuBarData = _supportCaseController?.GetMenuBarData();
+ viewModel.MenuBarData = _supportCaseController?.GetMenuData().ToList();
+
+ UpdateQuickActionSelectorVisibility();
if (_lastDesiredHeightOfWidgetCollection != WidgetCollection.DesiredSize.Height)
{
@@ -263,6 +265,10 @@ namespace FasdDesktopUi.Pages.DetailsPage
MainGrid.InvalidateMeasure();
MainGrid.UpdateLayout();
}
+
+ var footerMenuData = _supportCaseController.GetMenuData().FirstOrDefault(data => data.UiAction is UiNativeQuickAction);
+ FooterBtn.QuickAction = footerMenuData?.UiAction as cUiQuickAction;
+ FooterBtn.LabelText = footerMenuData?.MenuText;
});
if (shouldReRunDataChangedEvent)
@@ -275,6 +281,41 @@ namespace FasdDesktopUi.Pages.DetailsPage
}
}
+ private void UpdateQuickActionSelectorVisibility()
+ {
+ try
+ {
+ cHealthCard selectedHealthcard = _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.SelectedHealthCard;
+ bool showHistorySection = selectedHealthcard.CategoriesHistory?.StateCategories != null && selectedHealthcard.CategoriesHistory.StateCategories.Count > 0;
+
+ if (showHistorySection && cFasdCockpitConfig.Instance.IsHistoryQuickActionSelectorVisible)
+ {
+ QuickActionSelectorUc.IsLocked = cFasdCockpitConfig.Instance.IsHistoryQuickActionSelectorVisible;
+ MoreButtonClickedAction();
+ }
+ else if (!showHistorySection && cFasdCockpitConfig.Instance.IsCustomizableQuickActionSelectorVisible)
+ {
+ var ticketMenuData = _supportCaseController.GetMenuData().FirstOrDefault(menuData => menuData.MenuText == "Ticket");
+
+ if (ticketMenuData != null)
+ if (ticketMenuData is cMenuDataContainer containerMenuData)
+ {
+ QuickActionSelectorUc.QuickActionSelectorHeading = containerMenuData.MenuText;
+ QuickActionSelectorUc.QuickActionList = containerMenuData.SubMenuData;
+ }
+
+ QuickActionSelectorUc.IsLocked = cFasdCockpitConfig.Instance.IsCustomizableQuickActionSelectorVisible;
+
+ if (cFasdCockpitConfig.Instance.IsCustomizableQuickActionSelectorVisible)
+ QuickActionSelectorUc.Visibility = Visibility.Visible;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogException(ex);
+ }
+ }
+
///
/// Sets the visibility of History and Customizable Section based on the currently selected Healthcard.
///
@@ -597,6 +638,7 @@ namespace FasdDesktopUi.Pages.DetailsPage
// define drawing area
UIElement drawingArea = this;
+
switch (e.UiAction)
{
case cChangeHealthCardAction _:
@@ -604,6 +646,11 @@ namespace FasdDesktopUi.Pages.DetailsPage
case UiShowRawHealthcardValues _:
break;
case cUiQuickAction _:
+ if (!(e.OriginalSource is QuickTipStep) && QuickTipStatusMonitorUc.IsVisible && !QuickTipStatusMonitorUc.TryCancelQuickTip())
+ return;
+ drawingArea = QuickActionDecorator;
+ ToggleHorizontalCollapse(true, true);
+ break;
case cShowRecommendationAction _:
case cShowDetailedDataAction _:
drawingArea = QuickActionDecorator;
@@ -678,7 +725,7 @@ namespace FasdDesktopUi.Pages.DetailsPage
{
IconTimerPanel.HorizontalAlignment = HorizontalAlignment.Right;
IconTimerPanel.Children.Remove(F4SDIcon);
- IconTimerPanel.Children.Insert(1, F4SDIcon);
+ IconTimerPanel.Children.Insert(IconTimerPanel.Children.Count, F4SDIcon);
}
else
{
@@ -687,6 +734,7 @@ namespace FasdDesktopUi.Pages.DetailsPage
IconTimerPanel.Children.Insert(0, F4SDIcon);
}
+ FooterBtn.HorizontalAlignment = cFasdCockpitConfig.Instance.Global.FavouriteBarAlignment == enumF4sdHorizontalAlignment.Center ? HorizontalAlignment.Right : HorizontalAlignment.Center;
MenuBarUserControl.HorizontalAlignment = InternalEnumConverter.GetHorizontalAlignment(cFasdCockpitConfig.Instance.Global.FavouriteBarAlignment);
}
catch (Exception E)
@@ -699,6 +747,7 @@ namespace FasdDesktopUi.Pages.DetailsPage
{
UpdateHistoryWidth();
UpdateFooterPositions();
+ LevelTrackerUc.Visibility = cFasdCockpitConfig.Instance.Global.UseGamification ? Visibility.Visible : Visibility.Collapsed;
}
private void ApiConnectionStatusChanged(cConnectionStatusHelper.enumOnlineStatus? Status)
@@ -923,13 +972,27 @@ namespace FasdDesktopUi.Pages.DetailsPage
break;
}
+ return;
+ }
+
+ // Close Quick Action Section
+ if (e.Key == Key.Escape && QuickActionSelectorUc.Visibility == Visibility.Visible)
+ {
+ CloseQuickActionSelector();
return;
}
- if (FocusManager.GetFocusedElement(this) is TextBox)
- return;
+ bool isTextInputFocused = FocusManager.GetFocusedElement(this) is TextBox || FocusManager.GetFocusedElement(this) is RichTextBox;
- if (FocusManager.GetFocusedElement(this) is RichTextBox)
+ // Open Quick Action Section
+ if (e.Key == Key.Q && !isTextInputFocused)
+ {
+ MoreButtonClickedAction();
+ e.Handled = true;
+ return;
+ }
+
+ if (isTextInputFocused)
return;
List unpinnedDataHistories = DataHistoryCollectionUserControl.HistorySectionControls.Where(x => !x.IsVerticalExpandLocked).ToList();
@@ -970,9 +1033,6 @@ namespace FasdDesktopUi.Pages.DetailsPage
if (Keyboard.Modifiers == ModifierKeys.Control)
SearchButtonClickedAction();
break;
- case Key.Q:
- MoreButtonClickedAction();
- break;
case Key.NumPad0:
case Key.D0:
if (Keyboard.Modifiers != ModifierKeys.Control)
@@ -1177,8 +1237,6 @@ namespace FasdDesktopUi.Pages.DetailsPage
{
tempSubMenuList.Add(new cMenuDataBase(copyTemplate.Value));
}
-
- tempMoreQuickActionList.Insert(0, new cMenuDataContainer() { MenuText = cMultiLanguageSupport.GetItem("QuickAction.CopyContent"), MenuIcon = new F4SD_AdaptableIcon.IconData(enumInternIcons.menuBar_copy), UiAction = new cSubMenuAction(true) { Name = cMultiLanguageSupport.GetItem("QuickAction.CopyContent"), SubMenuData = tempSubMenuList }, SubMenuData = tempSubMenuList });
}
QuickActionSelectorUc.QuickActionList = tempMoreQuickActionList;
@@ -1187,6 +1245,10 @@ namespace FasdDesktopUi.Pages.DetailsPage
ToggleHorizontalCollapse(true);
QuickActionSelectorUc.Visibility = Visibility.Visible;
QuickActionSelectorUc.CloseButtonClickedAction = BlurBorder_Click;
+ QuickActionSelectorUc.Search.ActivateManualSearch();
+ QuickActionSelectorUc.Search.FocusInput();
+ QuickActionSelectorUc.Search.Clear();
+
}
catch (Exception E)
{
@@ -1256,6 +1318,7 @@ namespace FasdDesktopUi.Pages.DetailsPage
notepad.Visibility = Visibility.Collapsed;
NotepadVisibility = false;
+ ResetWindowFocus();
ChangeNotepadNotification();
}
else
@@ -1451,6 +1514,29 @@ namespace FasdDesktopUi.Pages.DetailsPage
ReinitializeNotepad();
DataHistoryCollectionUserControl.ToggleVerticalCollapseDetails(true);
UpdateHistoryWidth();
+
+ Task.Run(async () =>
+ {
+ if (await cFasdCockpitCommunicationBase.Instance.RemoteDesktopManager.IsRemoteDesktopCommunicationAvailable())
+ Dispatcher.Invoke(() => FooterBtn.Visibility = Visibility.Visible);
+ });
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ }
+
+ private void ResetWindowFocus()
+ {
+ try
+ {
+ Window window = Window.GetWindow(this);
+ if (window == null)
+ return;
+
+ FocusManager.SetFocusedElement(window, window);
+ Keyboard.Focus(window);
}
catch (Exception E)
{
@@ -1701,5 +1787,30 @@ namespace FasdDesktopUi.Pages.DetailsPage
QuickActionDecorator.Visibility = Visibility.Collapsed;
}
+ private void QuickActionSelectorUc_SearchValueChanged(object sender, string e)
+ {
+ if (string.IsNullOrWhiteSpace(e))
+ {
+ QuickActionSelectorUc.QuickActionList = _supportCaseController.GetMenuData().ToList();
+ QuickActionSelectorUc.QuickActionSelectorHeading = "Quick Actions";
+ return;
+ }
+
+ QuickActionSelectorUc.QuickActionList = _supportCaseController.GetFilteredMenuData(new MenuDataFilter(e)).ToList();
+
+ }
+
+ private void CloseQuickActionSelector()
+ {
+ try
+ {
+ QuickActionSelectorUc.CloseButton_Click();
+ QuickActionSelectorUc.Search.Clear();
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ }
}
}
diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryValueColumn.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryValueColumn.xaml.cs
index 544c234..87c7626 100644
--- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryValueColumn.xaml.cs
+++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryValueColumn.xaml.cs
@@ -72,7 +72,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
var updatedColumnValues = (DetailsPageDataHistoryColumnModel)e.NewValue;
_me.UpdateColumnSize(updatedColumnValues.ColumnValues.Count - _me.MainGrid.RowDefinitions.Count);
- _me.RefreshColumnHeader(updatedColumnValues.Content);
+ _me.ColumnHeaderTextBlock.Text = updatedColumnValues.Content;
_me.RefreshColumnStatusIcon(updatedColumnValues.HighlightColor);
_me.RefreshValueSection(updatedColumnValues);
}
@@ -155,7 +155,8 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
border.ClearValue(TagProperty);
border.SetResourceReference(StyleProperty, "DetailsPage.DataHistory.ValueBorder");
break;
- };
+ }
+ ;
border.Tag = valueInfo?.ThresholdValues;
}
@@ -163,7 +164,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
{
LogException(E);
}
-
+
}
#region Initialize Controls
@@ -276,22 +277,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
#region Refresh Values
- private void RefreshColumnHeader(string columnHeader)
- {
- string headerContent;
-
- if (int.TryParse(columnHeader, out int dayIndex))
- {
- CultureInfo culture = new CultureInfo(cMultiLanguageSupport.CurrentLanguage);
- string customDateFormat = cMultiLanguageSupport.GetItem("Global.Date.Format.ShortDateWithDay", "ddd. dd.MM.");
- headerContent = dayIndex == 0 ? cMultiLanguageSupport.GetItem("Global.Date.Today", DateTime.Now.ToString(customDateFormat, culture)) : DateTime.Today.AddDays(-dayIndex).ToString(customDateFormat, culture);
- }
- else
- headerContent = columnHeader;
-
- ColumnHeaderTextBlock.Text = headerContent;
- }
-
private void RefreshColumnStatusIcon(enumHighlightColor? statusColor)
{
ColumnStatusIcon.IconWidth = 25;
@@ -386,7 +371,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
default:
valueRowTextBlock.SetResourceReference(ForegroundProperty, "FontColor.DetailsPage.DataHistory.Value");
break;
- };
+ }
valueRow.Visibility = Visibility.Visible;
valueRow.Opacity = 1;
diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs
index 4da9f4f..7fba7dc 100644
--- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs
+++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs
@@ -18,7 +18,6 @@ using C4IT.MultiLanguage;
using C4IT.FASD.Base;
using static C4IT.Logging.cLogManager;
-using C4IT.FASD.Cockpit.Communication;
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
namespace FasdDesktopUi.Pages.DetailsPage.UserControls
@@ -37,7 +36,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
if (value != null)
{
UpdateHeaderHighlights();
- SetHeadingVisibility();
+ _ = SetHeadingVisibilityAsync();
}
}
}
@@ -110,7 +109,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
}
}
- private async Task SetHeadingVisibility()
+ private async Task SetHeadingVisibilityAsync()
{
try
{
@@ -667,19 +666,17 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
List quickActionList = new List();
- if (dataProvider.CaseRelations != null && dataProvider.CaseRelations.TryGetValue(swapCaseData.SelectedCaseInformationClass, out var storedRelations))
+ foreach (var storedRelation in SupportCaseController.GetRelationsOf(swapCaseData.SelectedCaseInformationClass))
{
- foreach (var storedRelation in storedRelations)
+ bool isMatchingRelation = IsMatchingRelation(storedRelation, swapCaseData.HeadingDatas);
+ quickActionList.Add(new cMenuDataSearchRelation(storedRelation)
{
- bool isMatchingRelation = IsMatchingRelation(storedRelation, swapCaseData.HeadingDatas);
- quickActionList.Add(new cMenuDataSearchRelation(storedRelation)
- {
- IsMatchingRelation = isMatchingRelation,
- IsUsedForCaseEnrichment = true,
- UiAction = new cChangeHealthCardAction(storedRelation, supportCaseController)
- });
- }
+ IsMatchingRelation = isMatchingRelation,
+ IsUsedForCaseEnrichment = true,
+ UiAction = new cChangeHealthCardAction(storedRelation, supportCaseController)
+ });
}
+
if (quickActionList.Count > 0)
customMenu.MenuDataList = quickActionList;
}
diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidget.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidget.xaml.cs
index 4791ec0..8c30c04 100644
--- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidget.xaml.cs
+++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidget.xaml.cs
@@ -414,7 +414,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls
if (Data.UiActionTitle is cShowDetailedDataAction)
functionMarkerEntry.SelectedIcon = enumInternIcons.misc_dot;
- else if (Data.UiActionTitle is cUiQuickAction || Data.UiActionTitle is cSubMenuAction)
+ else if (Data.UiActionTitle is cUiQuickAction || Data.UiActionTitle is cSubMenuAction || Data.UiActionTitle is cUiQuickTipAction)
functionMarkerEntry.SelectedIcon = enumInternIcons.misc_functionBolt;
}
else
diff --git a/FasdDesktopUi/Pages/LevelUpPage/LevelUpPage.xaml b/FasdDesktopUi/Pages/LevelUpPage/LevelUpPage.xaml
new file mode 100644
index 0000000..034b6d8
--- /dev/null
+++ b/FasdDesktopUi/Pages/LevelUpPage/LevelUpPage.xaml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level Up!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FasdDesktopUi/Pages/LevelUpPage/LevelUpPage.xaml.cs b/FasdDesktopUi/Pages/LevelUpPage/LevelUpPage.xaml.cs
new file mode 100644
index 0000000..2173f6e
--- /dev/null
+++ b/FasdDesktopUi/Pages/LevelUpPage/LevelUpPage.xaml.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+
+namespace FasdDesktopUi.Pages.LevelUpPage
+{
+ public partial class LevelUpPage : Window
+ {
+ public int NewLevel
+ {
+ get { return (int)GetValue(NewLevelProperty); }
+ set { SetValue(NewLevelProperty, value); }
+ }
+
+ public static readonly DependencyProperty NewLevelProperty =
+ DependencyProperty.Register(nameof(NewLevel), typeof(int), typeof(LevelUpPage), new PropertyMetadata(0, new PropertyChangedCallback(HandleLevelChanged)));
+
+ private static void HandleLevelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (!(d is LevelUpPage levelupPage))
+ return;
+
+ levelupPage.LastLevelTextBlock.Text = (levelupPage.NewLevel - 1).ToString();
+ levelupPage.NewLevelTextBlock.Text = levelupPage.NewLevel.ToString();
+ }
+
+ public string LevelTitle
+ {
+ get { return (string)GetValue(LevelTitleProperty); }
+ set { SetValue(LevelTitleProperty, value); }
+ }
+
+ public static readonly DependencyProperty LevelTitleProperty =
+ DependencyProperty.Register(nameof(LevelTitle), typeof(string), typeof(LevelUpPage), new PropertyMetadata("string.Empty"));
+
+
+ public LevelUpPage()
+ {
+ InitializeComponent();
+ }
+
+ private async Task AnimateText()
+ {
+ await Task.Delay(900);
+
+ double animationDistance = NewLevelTextBlock.ActualHeight + NewLevelTextBlock.Margin.Top + NewLevelTextBlock.Margin.Bottom;
+
+ Duration duration = TimeSpan.FromMilliseconds(500);
+
+ DoubleAnimation lowerAnimation = new DoubleAnimation
+ {
+ From = 0,
+ To = -animationDistance,
+ Duration = duration,
+ EasingFunction = new CubicEase
+ {
+ EasingMode = EasingMode.EaseInOut
+ }
+ };
+
+ DoubleAnimation upperAnimation = new DoubleAnimation
+ {
+ From = 0,
+ To = -animationDistance,
+ Duration = duration,
+ EasingFunction = new CubicEase
+ {
+ EasingMode = EasingMode.EaseInOut
+ }
+ };
+
+ LowerTransform.BeginAnimation(TranslateTransform.YProperty, lowerAnimation);
+ UpperTransform.BeginAnimation(TranslateTransform.YProperty, upperAnimation);
+ }
+
+ private async void HandleVisibilityChanged(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ if (Visibility != Visibility.Visible)
+ return;
+
+ await AnimateText();
+ }
+
+ private void Continue_Click(object sender, RoutedEventArgs e)
+ {
+ Close();
+ }
+ }
+}
diff --git a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml
index 5dfda04..d8ab02a 100644
--- a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml
+++ b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml
@@ -183,12 +183,12 @@
-
+
diff --git a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs
index 7fd337f..2f9df92 100644
--- a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs
+++ b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs
@@ -197,8 +197,8 @@ namespace FasdDesktopUi.Pages.SearchPage
cSearchManager.ResolveRelations(searchHistoryEntry.Relations);
ILookup relationsLookup = searchHistoryEntry.Relations
- .OrderBy(r => r.UsingLevel)
- .ThenBy(r => r.LastUsed)
+ .OrderBy(r => r.LastUsed)
+ .ThenBy(r => r.UsingLevel)
.ToLookup(GetInformationClass, r => GetMenuData(r, relationService));
Dispatcher.Invoke(() =>
@@ -799,7 +799,7 @@ namespace FasdDesktopUi.Pages.SearchPage
Dispatcher.Invoke(() =>
{
var first = e.RelatedTo.FirstOrDefault();
- var relationSearchResult = new cSearchHistorySearchResultEntry(first.DisplayName, first.DisplayName, e.RelatedTo.ToList(), e.StagedResultRelations.Relations.ToList(), this);
+ var relationSearchResult = new cSearchHistorySearchResultEntry(first.DisplayName, first.Name, e.RelatedTo.ToList(), e.StagedResultRelations.Relations.ToList(), this, _relationService);
ShowSearchRelations(relationSearchResult, e.RelationService, this);
UpdatePendingInformationClasses(e.StagedResultRelations.PendingInformationClasses);
@@ -1033,7 +1033,7 @@ namespace FasdDesktopUi.Pages.SearchPage
private bool TryOpenTicketOverviewRelationExternally(cF4sdApiSearchResultRelation relation)
{
- return TicketDeepLinkHelper.TryOpenTicketRelationExternally(relation);
+ return TicketExternalLinkHelper.TryOpenTicketRelationExternally(relation);
}
private Task RunTicketSearchAsync(string ticketName, Guid ticketId, string userName, string sids, bool suppressUi = false)
@@ -1461,7 +1461,8 @@ namespace FasdDesktopUi.Pages.SearchPage
header,
new List(),
relations,
- this
+ this,
+ _relationService
)
{ isSeen = true };
_ticketOverviewHistoryEntries.Add(entry);
@@ -1695,7 +1696,7 @@ namespace FasdDesktopUi.Pages.SearchPage
if (filteredResults?.PreSelectedRelation != null)
{
List selectedResult = filteredResults.Results.Values.FirstOrDefault();
- var processSearchResult = new cUiProcessSearchResultAction(selectedResult.FirstOrDefault()?.DisplayName, this, selectedResult) { PreSelectedSearchRelation = filteredResults.PreSelectedRelation };
+ var processSearchResult = new cUiProcessSearchResultAction(selectedResult.FirstOrDefault()?.Name, this, selectedResult) { PreSelectedSearchRelation = filteredResults.PreSelectedRelation };
Dispatcher.Invoke(async () =>
{
bool isSearchOngoing = await processSearchResult.RunUiActionAsync(this, this, false, null);
diff --git a/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml b/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml
index 770ae8d..0916b2c 100644
--- a/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml
+++ b/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml
@@ -103,13 +103,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -604,7 +604,7 @@
+
+
+
+
+
+
+
+
diff --git a/FasdDesktopUi/Pages/SettingsPage/SettingsPageView.xaml.cs b/FasdDesktopUi/Pages/SettingsPage/SettingsPageView.xaml.cs
index 011ea21..da2bc21 100644
--- a/FasdDesktopUi/Pages/SettingsPage/SettingsPageView.xaml.cs
+++ b/FasdDesktopUi/Pages/SettingsPage/SettingsPageView.xaml.cs
@@ -1,34 +1,19 @@
-using C4IT.MultiLanguage;
+using C4IT.Configuration;
using C4IT.FASD.Base;
+using C4IT.MultiLanguage;
+using F4SD_AdaptableIcon.Enums;
+using FasdDesktopUi.Basics;
using FasdDesktopUi.Basics.Enums;
-using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UserControls.AdaptableIcon;
-using FasdDesktopUi.Pages.DetailsPage;
-using FasdDesktopUi.Pages.SlimPage;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Shapes;
-
using static C4IT.Logging.cLogManager;
-using System.Reflection;
-using C4IT.Logging;
-using System.Windows.Navigation;
-using F4SD_AdaptableIcon.Enums;
-using FasdDesktopUi.Basics;
-using System.Diagnostics;
-using C4IT.Configuration;
namespace FasdDesktopUi.Pages.SettingsPage
{
@@ -36,11 +21,10 @@ namespace FasdDesktopUi.Pages.SettingsPage
{
#region Properties
- private static SettingsPageView _Instance = null;
- public static SettingsPageView Instance { get
- {
- return _Instance ?? (_Instance = new SettingsPageView());
- }
+ private static SettingsPageView _instance = null;
+ public static SettingsPageView Instance
+ {
+ get { return _instance ?? (_instance = new SettingsPageView()); }
}
private Dictionary highlightColorActivationStatus;
@@ -104,7 +88,8 @@ namespace FasdDesktopUi.Pages.SettingsPage
public int PositionOfSmallViews
{
- get {
+ get
+ {
return cF4sdGlobalConfig.ConvertHorizontalAlignmentToPosition(cFasdCockpitConfig.Instance.Global.SmallViewAlignment, 0);
}
set
@@ -152,6 +137,18 @@ namespace FasdDesktopUi.Pages.SettingsPage
}
}
+ public bool UseGamification
+ {
+ get => cFasdCockpitConfig.Instance.Global.UseGamification;
+ set
+ {
+ cFasdCockpitConfig.Instance.Global.UseGamification = value;
+ cFasdCockpitConfig.Instance.Global.Save(nameof(cFasdCockpitConfig.Instance.Global.UseGamification));
+ cFasdCockpitConfig.Instance.OnUiSettingsChanged();
+ OnPropertyChanged(nameof(UseGamification));
+ }
+ }
+
#endregion
public static SettingsPageView Create()
@@ -184,7 +181,7 @@ namespace FasdDesktopUi.Pages.SettingsPage
FavouritePositionRightTextBlock.ClearValue(ForegroundProperty);
FavouritePositionSlider.SetResourceReference(BackgroundProperty, "Color.FunctionMarker");
break;
- case 2:
+ case 2:
FavouritePositionRightTextBlock.SetResourceReference(ForegroundProperty, "Color.FunctionMarker");
FavouritePositionLeftTextBlock.ClearValue(ForegroundProperty);
break;
@@ -233,86 +230,30 @@ namespace FasdDesktopUi.Pages.SettingsPage
ZoomDetailsPageInPecent = cFasdCockpitConfig.Instance.DetailsPageZoom;
ZoomSlimPageInPercent = cFasdCockpitConfig.Instance.SlimPageZoom;
- // hide or deactivate ShouldSkipSlimView options due to the policies
- var _policy = cFasdCockpitConfig.Instance.Global.GetPropertyPolicy("ShouldSkipSlimView");
- if (_policy == enumConfigPolicy.Hidden)
- {
- ShouldSkipSlimViewLabel.Visibility = Visibility.Collapsed;
- ShouldSkipSlimViewCheckBox.Visibility = Visibility.Collapsed;
- }
- else
- {
- ShouldSkipSlimViewLabel.Visibility = Visibility.Visible;
- ShouldSkipSlimViewCheckBox.Visibility = Visibility.Visible;
- }
- if (_policy == enumConfigPolicy.Default)
- {
- ShouldSkipSlimViewCheckBox.IsEnabled = true;
- ShouldSkipSlimViewPolicy.Visibility = Visibility.Collapsed;
- ShouldSkipSlimViewCheckBox.ToolTip = null;
- ShouldSkipSlimViewPolicy.ToolTip = null;
- }
- else
- {
- ShouldSkipSlimViewCheckBox.IsEnabled = false;
- ShouldSkipSlimViewPolicy.Visibility = Visibility.Visible;
- ShouldSkipSlimViewCheckBox.ToolTip = cMultiLanguageSupport.GetItem("Settings.Global.PolicyTooltip");
- ShouldSkipSlimViewPolicy.ToolTip = cMultiLanguageSupport.GetItem("Settings.Global.PolicyTooltip");
- }
+ UpdatePolicyElements("ShouldSkipSlimView", ShouldSkipSlimViewLabel, ShouldSkipSlimViewCheckBox, ShouldSkipSlimViewPolicy);
OnPropertyChanged(nameof(ShouldSkipSlimView));
- // hide or deactivate SmallViewAlignment options due to the policies
- _policy = cFasdCockpitConfig.Instance.Global.GetPropertyPolicy("SmallViewAlignment");
- if (_policy == enumConfigPolicy.Hidden)
- {
- PositionOfSmallViewsLabel.Visibility = Visibility.Collapsed;
- PositionOfSmallViewsInput.Visibility = Visibility.Collapsed;
- }
- else
- {
- PositionOfSmallViewsLabel.Visibility = Visibility.Visible;
- PositionOfSmallViewsInput.Visibility = Visibility.Visible;
- }
- if (_policy == enumConfigPolicy.Default)
- {
- PositionOfSmallViewsInput.IsEnabled = true;
- PositionOfSmallViewsPolicy.Visibility = Visibility.Collapsed;
- PositionOfSmallViewsPolicy.ToolTip = null;
- }
- else
- {
- PositionOfSmallViewsInput.IsEnabled = false;
- PositionOfSmallViewsPolicy.Visibility = Visibility.Visible;
- PositionOfSmallViewsPolicy.ToolTip = cMultiLanguageSupport.GetItem("Settings.Global.PolicyTooltip");
- }
+ UpdatePolicyElements("SmallViewAlignment", PositionOfSmallViewsLabel, PositionOfSmallViewsInput, PositionOfSmallViewsPolicy);
OnPropertyChanged(nameof(PositionOfSmallViews));
- // hide or deactivate FavouriteBarAlignment options due to the policies
- _policy = cFasdCockpitConfig.Instance.Global.GetPropertyPolicy("FavouriteBarAlignment");
- if (_policy == enumConfigPolicy.Hidden)
- {
- PositionOfFavouriteBarLabel.Visibility = Visibility.Collapsed;
- PositionOfFavouriteBarInput.Visibility = Visibility.Collapsed;
- }
- else
- {
- PositionOfFavouriteBarLabel.Visibility = Visibility.Visible;
- PositionOfFavouriteBarInput.Visibility = Visibility.Visible;
- }
- if (_policy == enumConfigPolicy.Default)
- {
- PositionOfFavouriteBarInput.IsEnabled = true;
- PositionOfFavouriteBarPolicy.Visibility = Visibility.Collapsed;
- PositionOfFavouriteBarPolicy.ToolTip = null;
- }
- else
- {
- PositionOfFavouriteBarInput.IsEnabled = false;
- PositionOfFavouriteBarPolicy.Visibility = Visibility.Visible;
- PositionOfFavouriteBarPolicy.ToolTip = cMultiLanguageSupport.GetItem("Settings.Global.PolicyTooltip");
- }
+ UpdatePolicyElements("FavouriteBarAlignment", PositionOfFavouriteBarLabel, PositionOfFavouriteBarInput, PositionOfFavouriteBarPolicy);
OnPropertyChanged(nameof(PositionOfFavouriteBar));
+ UpdatePolicyElements(nameof(cFasdCockpitConfig.Instance.Global.UseGamification), UseGamificationLabel, UseGamificationCheckBox, UseGamifictationPolicy);
+ OnPropertyChanged(nameof(cFasdCockpitConfig.Instance.Global.UseGamification));
+
+ void UpdatePolicyElements(string policyName, FrameworkElement label, FrameworkElement control, FrameworkElement policyElement)
+ {
+ enumConfigPolicy policy = cFasdCockpitConfig.Instance.Global.GetPropertyPolicy(policyName);
+
+ label.Visibility = policy == enumConfigPolicy.Hidden ? Visibility.Collapsed : Visibility.Visible;
+ control.Visibility = policy == enumConfigPolicy.Hidden ? Visibility.Collapsed : Visibility.Visible;
+ control.IsEnabled = policy == enumConfigPolicy.Default;
+
+
+ policyElement.Visibility = policy == enumConfigPolicy.Default ? Visibility.Collapsed : Visibility.Visible;
+ policyElement.ToolTip = policy == enumConfigPolicy.Default ? null : cMultiLanguageSupport.GetItem("Settings.Global.PolicyTooltip");
+ }
}
public void SetUpSettingsControls()
@@ -872,7 +813,7 @@ namespace FasdDesktopUi.Pages.SettingsPage
{
try
{
- _Instance = null;
+ _instance = null;
if (cSupportCaseDataProvider.detailsPage?.Visibility == Visibility.Visible)
await cSupportCaseDataProvider.detailsPage.AdjustWindowSizeAsync();
}
diff --git a/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml b/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml
index aeae58b..f490ec0 100644
--- a/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml
+++ b/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml
@@ -101,9 +101,9 @@
Padding="10">
-
+
diff --git a/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs b/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs
index 7b307c4..2f4d02e 100644
--- a/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs
+++ b/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs
@@ -45,8 +45,8 @@ namespace FasdDesktopUi.Pages.SlimPage
{
switch (invoker)
{
- case SearchBar searchBar:
- if (!searchBar.IsVisible || searchBar.SearchStatus != SearchBar.eSearchStatus.message)
+ case InformationClassSearchBar searchBar:
+ if (!searchBar.IsVisible || searchBar.SearchStatus != InformationClassSearchBar.eSearchStatus.message)
return true;
break;
case QuickActionSelector _:
@@ -256,7 +256,7 @@ namespace FasdDesktopUi.Pages.SlimPage
tempSubMenuList.Add(new cMenuDataBase(copyTemplate.Value));
}
- tempMoreQuickActionList.Insert(0, new cMenuDataContainer() { MenuText = cMultiLanguageSupport.GetItem("QuickAction.CopyContent"), MenuIcon = new F4SD_AdaptableIcon.IconData(enumInternIcons.menuBar_copy), UiAction = new cSubMenuAction(true) { Name = cMultiLanguageSupport.GetItem("QuickAction.CopyContent"), SubMenuData = tempSubMenuList }, SubMenuData = tempSubMenuList });
+ tempMoreQuickActionList.Insert(0, new cMenuDataContainer() { MenuText = cMultiLanguageSupport.GetItem("QuickAction.CopyContent"), MenuIcon = new cMenuDataBase.MenuIconInfo(new F4SD_AdaptableIcon.IconData(enumInternIcons.menuBar_copy)), UiAction = new cSubMenuAction(true) { Name = cMultiLanguageSupport.GetItem("QuickAction.CopyContent"), SubMenuData = tempSubMenuList }, SubMenuData = tempSubMenuList });
}
var quickActionSelector = new QuickActionSelector()
@@ -403,7 +403,7 @@ namespace FasdDesktopUi.Pages.SlimPage
if (!(DataContext is SlimPageViewModel viewModel))
return;
- if (SearchBarUserControl.SearchStatus != SearchBar.eSearchStatus.message)
+ if (SearchBarUserControl.SearchStatus != InformationClassSearchBar.eSearchStatus.message)
{
SearchBarUserControl.Visibility = Visibility.Collapsed;
MenuBarUc.Visibility = Visibility.Visible;
diff --git a/FasdDesktopUi/Pages/SplashScreenView/SplashScreenView.xaml b/FasdDesktopUi/Pages/SplashScreenView/SplashScreenView.xaml
index c3cd852..a72768e 100644
--- a/FasdDesktopUi/Pages/SplashScreenView/SplashScreenView.xaml
+++ b/FasdDesktopUi/Pages/SplashScreenView/SplashScreenView.xaml
@@ -15,6 +15,20 @@
WindowStyle="None"
IsVisibleChanged="Window_IsVisibleChanged">
+
+
+
@@ -30,31 +44,26 @@
-
+
-
-
-
-
- window_minimize
-
-
+ TouchDown="MinimizeButton_TouchDown"
+ SelectedInternIcon="window_minimize"
+ >
+
+
+
+ MouseLeftButtonDown="F4SDLogo_MouseLeftButtonDown"
+ TouchDown="F4SDLogo_TouchDown"
+ />
identity.Class == enumFasdInformationClass.User).Id);
- if (closedSuccessfull)
- {
- SuccessPage.SuccessPage successPage = new SuccessPage.SuccessPage();
- successPage.Show();
- await _dataProvider?.CloseCaseAsync();
- TrySetDialogResult(true);
- Close();
- }
- }
+ if (closedSuccessfull)
+ {
+ SuccessPage.SuccessPage successPage = new SuccessPage.SuccessPage();
+ successPage.Show();
+ GamificationService.TrackAction(F4SD.Gamification.CockpitAction.CaseClosed);
+ await _dataProvider?.CloseCaseAsync();
+ TrySetDialogResult(true);
+ Close();
+ }
+ }
catch (Exception E)
{
LogException(E);
diff --git a/FasdDesktopUi/ResourceDictionaries/DarkModeResources.xaml b/FasdDesktopUi/ResourceDictionaries/DarkModeResources.xaml
index d94acf9..20344fb 100644
--- a/FasdDesktopUi/ResourceDictionaries/DarkModeResources.xaml
+++ b/FasdDesktopUi/ResourceDictionaries/DarkModeResources.xaml
@@ -74,13 +74,13 @@
#414141
- #303030
- #303030
- #303030
+ #5A5A5A
+ #5A5A5A
+ #5A5A5A
#404040
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/FasdDesktopUi/ResourceDictionaries/DetailsPageResources/CustomizableResources.xaml b/FasdDesktopUi/ResourceDictionaries/DetailsPageResources/CustomizableResources.xaml
index 6335400..dd96013 100644
--- a/FasdDesktopUi/ResourceDictionaries/DetailsPageResources/CustomizableResources.xaml
+++ b/FasdDesktopUi/ResourceDictionaries/DetailsPageResources/CustomizableResources.xaml
@@ -1,5 +1,10 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:base="clr-namespace:C4IT.FASD.Base;assembly=F4SD-Cockpit-Client-Base"
+ xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter">
+
+
+
-
-