Compare commits
19 Commits
0b52999b1d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffcfc85a4e | ||
|
|
2d3460574e | ||
|
|
bdff275da9 | ||
|
|
bb5d7c1d2a | ||
|
|
9bd3896ba0 | ||
|
|
fb45f1c42b | ||
|
|
1a3bef9eeb | ||
|
|
21e9b85be7 | ||
|
|
30cc7a0482 | ||
|
|
4ed75c6e82 | ||
|
|
791e53062e | ||
|
|
b88b325d02 | ||
|
|
2fbf2e2d2d | ||
|
|
62a5c97cbd | ||
|
|
0fef3ad49c | ||
|
|
1db0da9a40 | ||
|
|
7ea13f60a7 | ||
|
|
b3520f8865 | ||
|
|
997dcee78f |
159
F4SD-ActionConnector/Bus/ActionBus.cs
Normal file
159
F4SD-ActionConnector/Bus/ActionBus.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using F4SD.ActionConnector.Events;
|
||||
using F4SD.ActionConnector.Execution;
|
||||
using F4SD.ActionConnector.Models;
|
||||
using F4SD.ActionConnector.Payloads;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Bus
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry point for the ActionConnector.
|
||||
/// Subscribes to <see cref="ActionConnectorEvents"/>, reads the configuration once,
|
||||
/// and dispatches actions whenever a trigger event fires.
|
||||
///
|
||||
/// Usage from the host application:
|
||||
/// <code>
|
||||
/// var bus = new ActionBus(new ActionBusOptions
|
||||
/// {
|
||||
/// ConfigurationFilePath = @"C:\Config\F4SD-ExternalCommunication-Configuration.xml",
|
||||
/// QuickActionExecutor = async request =>
|
||||
/// {
|
||||
/// await myJiraClient.CreateTicketAsync(request.QuickActionRef, request.Parameters);
|
||||
/// return ActionResult.Ok(request.ActionId);
|
||||
/// }
|
||||
/// });
|
||||
///
|
||||
/// bus.Start();
|
||||
/// // later:
|
||||
/// bus.Stop();
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public sealed class ActionBus : IDisposable
|
||||
{
|
||||
private readonly ActionBusOptions _options;
|
||||
private readonly ActionDispatcher _dispatcher;
|
||||
private ExternalCommunicationConfiguration _configuration;
|
||||
private bool _running;
|
||||
|
||||
public ActionBus(ActionBusOptions options)
|
||||
{
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_dispatcher = new ActionDispatcher(options.QuickActionExecutor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the configuration and subscribes to all trigger events.
|
||||
/// Call once during application startup.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
_configuration = new ExternalCommunicationConfiguration();
|
||||
_configuration.Initiate(_options.ConfigRootElement, _options.Parser);
|
||||
|
||||
ActionConnectorEvents.CaseClosed += OnCaseClosed;
|
||||
ActionConnectorEvents.CaseCreated += OnCaseCreated;
|
||||
ActionConnectorEvents.ApplicationStartup += OnApplicationStartup;
|
||||
|
||||
_running = true;
|
||||
LogEntry("ActionBus started.", C4IT.Logging.LogLevels.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from all trigger events.
|
||||
/// Call during application shutdown.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
ActionConnectorEvents.CaseClosed -= OnCaseClosed;
|
||||
ActionConnectorEvents.CaseCreated -= OnCaseCreated;
|
||||
ActionConnectorEvents.ApplicationStartup -= OnApplicationStartup;
|
||||
|
||||
_running = false;
|
||||
LogEntry("ActionBus stopped.", C4IT.Logging.LogLevels.Info);
|
||||
}
|
||||
|
||||
public void Dispose() => Stop();
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
// Event handlers — each one creates a typed ActionContext and fires dispatch
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private void OnCaseClosed(object sender, TriggerEventArgs<CaseClosedPayload> args)
|
||||
=> DispatchTrigger(TriggerEvent.CaseClosed, args.Payload, sender);
|
||||
|
||||
private void OnCaseCreated(object sender, TriggerEventArgs<CaseCreatedPayload> args)
|
||||
=> DispatchTrigger(TriggerEvent.CaseCreated, args.Payload, sender);
|
||||
|
||||
private void OnApplicationStartup(object sender, TriggerEventArgs<ApplicationStartupPayload> args)
|
||||
=> DispatchTrigger(TriggerEvent.ApplicationStartup, args.Payload, sender);
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
// Core dispatch — fire-and-forget wrapper that surfaces results via events
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private void DispatchTrigger(TriggerEvent triggerEvent, PayloadBase payload, object sender)
|
||||
{
|
||||
if (!_running) return;
|
||||
if (!_configuration.Triggers.TryGetValue(triggerEvent, out Trigger trigger)) return;
|
||||
|
||||
// Run async dispatch on the thread pool; do not block the caller.
|
||||
Task.Run(() => DispatchActionsAsync(trigger.Actions, triggerEvent, payload, sender));
|
||||
}
|
||||
|
||||
private async Task DispatchActionsAsync(
|
||||
IDictionary<string, ActionDefinitionBase> actions,
|
||||
TriggerEvent triggerEvent,
|
||||
PayloadBase payload,
|
||||
object sender)
|
||||
{
|
||||
foreach (var pair in actions)
|
||||
{
|
||||
ActionDefinitionBase action = pair.Value;
|
||||
|
||||
var context = new ActionContext
|
||||
{
|
||||
TriggerEvent = triggerEvent,
|
||||
AwaitResult = action.AwaitResult,
|
||||
Payload = payload,
|
||||
};
|
||||
|
||||
ActionResult result = await ExecuteSafeAsync(action, context);
|
||||
|
||||
ActionConnectorEvents.RaiseActionCompleted(
|
||||
sender,
|
||||
new ActionCompletedEventArgs(result, context));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ActionResult> ExecuteSafeAsync(ActionDefinitionBase action, ActionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _dispatcher.DispatchAsync(action, context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return ActionResult.Fail(action.Id, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
F4SD-ActionConnector/Bus/ActionBusOptions.cs
Normal file
23
F4SD-ActionConnector/Bus/ActionBusOptions.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Execution;
|
||||
using F4SD.ActionConnector.Models;
|
||||
|
||||
namespace F4SD.ActionConnector.Bus
|
||||
{
|
||||
public sealed class ActionBusOptions
|
||||
{
|
||||
public XmlElement ConfigRootElement { get; set; }
|
||||
public cXmlParser Parser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called for every QuickAction that fires.
|
||||
/// Template variables in <see cref="QuickActionRequest.Parameters"/> are already
|
||||
/// resolved against the event payload before this delegate is invoked.
|
||||
/// Must be set when any QuickAction is configured.
|
||||
/// </summary>
|
||||
public Func<QuickActionRequest, Task<ActionResult>> QuickActionExecutor { get; set; }
|
||||
}
|
||||
}
|
||||
62
F4SD-ActionConnector/Execution/ActionDispatcher.cs
Normal file
62
F4SD-ActionConnector/Execution/ActionDispatcher.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using F4SD.ActionConnector.Enumerations;
|
||||
using F4SD.ActionConnector.Models;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Execution
|
||||
{
|
||||
/// <summary>
|
||||
/// Routes a single action definition to the correct executor based on its <see cref="ActionType"/>.
|
||||
/// </summary>
|
||||
internal sealed class ActionDispatcher
|
||||
{
|
||||
private readonly Func<QuickActionRequest, Task<ActionResult>> _quickActionExecutor;
|
||||
|
||||
internal ActionDispatcher(Func<QuickActionRequest, Task<ActionResult>> quickActionExecutor)
|
||||
{
|
||||
_quickActionExecutor = quickActionExecutor;
|
||||
}
|
||||
|
||||
internal async Task<ActionResult> DispatchAsync(ActionDefinitionBase action, ActionContext context)
|
||||
{
|
||||
if (!action.IsEnabled)
|
||||
return ActionResult.Skip(action.Id);
|
||||
|
||||
switch (action.Type)
|
||||
{
|
||||
case ActionType.QuickAction:
|
||||
return await ExecuteQuickActionAsync((QuickActionDefinition)action, context);
|
||||
|
||||
case ActionType.HttpCall:
|
||||
case ActionType.Webhook:
|
||||
throw new NotImplementedException(
|
||||
$"ActionType '{action.Type}' is not yet implemented.");
|
||||
|
||||
default:
|
||||
LogEntry($"ActionDispatcher: unknown ActionType '{action.Type}' for action '{action.Id}'.",
|
||||
C4IT.Logging.LogLevels.Warning);
|
||||
return ActionResult.Skip(action.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ActionResult> ExecuteQuickActionAsync(QuickActionDefinition definition, ActionContext context)
|
||||
{
|
||||
if (_quickActionExecutor == null)
|
||||
throw new InvalidOperationException(
|
||||
$"A QuickAction ('{definition.Id}') was triggered but no {nameof(Bus.ActionBusOptions.QuickActionExecutor)} was registered.");
|
||||
|
||||
var resolvedParameters = PayloadVariableResolver.Resolve(definition.Parameters, context.Payload);
|
||||
|
||||
var request = new QuickActionRequest
|
||||
{
|
||||
ActionId = definition.Id,
|
||||
QuickActionRef = definition.QuickActionRef,
|
||||
Parameters = resolvedParameters,
|
||||
Context = context,
|
||||
};
|
||||
|
||||
return await _quickActionExecutor(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
94
F4SD-ActionConnector/Execution/PayloadVariableResolver.cs
Normal file
94
F4SD-ActionConnector/Execution/PayloadVariableResolver.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using F4SD.ActionConnector.Payloads;
|
||||
|
||||
namespace F4SD.ActionConnector.Execution
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves template variables such as {{Case.Id}} or {{Case.ClosedAt:yyyy-MM-ddTHH:mm:ssZ}}
|
||||
/// against a payload object.
|
||||
///
|
||||
/// Variable format: {{ObjectName.PropertyName[:FormatSpecifier]}}
|
||||
/// </summary>
|
||||
internal static class PayloadVariableResolver
|
||||
{
|
||||
private static readonly Regex VariablePattern =
|
||||
new Regex(@"\{\{(?<obj>[^.}]+)\.(?<prop>[^:}]+)(?::(?<fmt>[^}]+))?\}\}",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new dictionary with every value in <paramref name="rawParameters"/> having
|
||||
/// its template variables replaced by the corresponding payload property values.
|
||||
/// Pure single-variable templates (e.g. <c>{{Case.ClosedAt}}</c>) yield the raw typed
|
||||
/// object; mixed or formatted templates yield a resolved string.
|
||||
/// </summary>
|
||||
internal static IDictionary<string, object> Resolve(
|
||||
IDictionary<string, string> rawParameters,
|
||||
PayloadBase payload)
|
||||
{
|
||||
var resolved = new Dictionary<string, object>(rawParameters.Count);
|
||||
|
||||
foreach (var pair in rawParameters)
|
||||
resolved[pair.Key] = ResolveValue(pair.Value, payload);
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private static object ResolveValue(string template, PayloadBase payload)
|
||||
{
|
||||
var match = VariablePattern.Match(template);
|
||||
|
||||
// Pure single variable with no format specifier → return raw object
|
||||
if (match.Success && match.Value == template && !match.Groups["fmt"].Success)
|
||||
return ResolveRawProperty(match, payload);
|
||||
|
||||
// Mixed template, literal, or explicit format specifier → return resolved string
|
||||
return ResolveString(template, payload);
|
||||
}
|
||||
|
||||
private static object ResolveRawProperty(Match match, PayloadBase payload)
|
||||
{
|
||||
string propertyName = match.Groups["prop"].Value;
|
||||
|
||||
PropertyInfo property = payload.GetType().GetProperty(
|
||||
propertyName,
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||
|
||||
if (property == null)
|
||||
return match.Value;
|
||||
|
||||
return property.GetValue(payload);
|
||||
}
|
||||
|
||||
private static string ResolveString(string template, PayloadBase payload)
|
||||
{
|
||||
return VariablePattern.Replace(template, match => ResolveMatch(match, payload));
|
||||
}
|
||||
|
||||
private static string ResolveMatch(Match match, PayloadBase payload)
|
||||
{
|
||||
string propertyName = match.Groups["prop"].Value;
|
||||
string formatSpecifier = match.Groups["fmt"].Success ? match.Groups["fmt"].Value : null;
|
||||
|
||||
PropertyInfo property = payload.GetType().GetProperty(
|
||||
propertyName,
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||
|
||||
if (property == null)
|
||||
return match.Value;
|
||||
|
||||
object value = property.GetValue(payload);
|
||||
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
if (formatSpecifier != null && value is IFormattable formattable)
|
||||
return formattable.ToString(formatSpecifier, CultureInfo.InvariantCulture);
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
F4SD-ActionConnector/Execution/QuickActionRequest.cs
Normal file
29
F4SD-ActionConnector/Execution/QuickActionRequest.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using F4SD.ActionConnector.Models;
|
||||
|
||||
namespace F4SD.ActionConnector.Execution
|
||||
{
|
||||
public sealed class QuickActionRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Matches <see cref="QuickActionDefinition.Id"/> from the configuration.
|
||||
/// </summary>
|
||||
public string ActionId { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the Quick Action to invoke, e.g. "Document case in JIRA".
|
||||
/// </summary>
|
||||
public string QuickActionRef { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Template variables resolved against the event payload.
|
||||
/// Values are the raw payload values; callers are responsible for casting.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> Parameters { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Full context of the triggering event.
|
||||
/// </summary>
|
||||
public ActionContext Context { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public sealed class ActionContext
|
||||
{
|
||||
public TriggerEvent TriggerEvent { get; set; }
|
||||
public bool AwaitResult { get; set; }
|
||||
public PayloadBase Payload { get; set; }
|
||||
public TriggerEvent TriggerEvent { get; internal set; }
|
||||
public bool AwaitResult { get; internal set; }
|
||||
public PayloadBase Payload { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public abstract class ActionDefinitionBase
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Id { get; internal set; }
|
||||
public abstract ActionType Type { get; }
|
||||
public bool AwaitResult { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool AwaitResult { get; internal set; }
|
||||
public bool IsEnabled { get; internal set; }
|
||||
public string Description { get; internal set; }
|
||||
public bool IsValid { get; private protected set; }
|
||||
|
||||
protected ActionDefinitionBase(XmlElement xNode, cXmlParser parser)
|
||||
|
||||
@@ -5,29 +5,29 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public sealed class ActionResult
|
||||
{
|
||||
public string ActionId { get; set; }
|
||||
public ActionResultStatus Status { get; set; }
|
||||
public string ActionId { get; private set; }
|
||||
public ActionResultStatus Status { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP status code for HttpCall actions; null for other types.
|
||||
/// </summary>
|
||||
public int? HttpStatusCode { get; set; }
|
||||
public int? HttpStatusCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw response body (HttpCall) or serialized output (QuickAction).
|
||||
/// </summary>
|
||||
public string RawResponse { get; set; }
|
||||
public string RawResponse { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Named fields extracted from the response via jsonPath mappings.
|
||||
/// Populated when DisplayInCockpit is true.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> MappedFields { get; set; } = new Dictionary<string, string>();
|
||||
public IDictionary<string, string> MappedFields { get; private set; } = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable error message; set when Status is Failure.
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public static ActionResult Ok(string actionId, string rawResponse = null)
|
||||
=> new ActionResult { ActionId = actionId, Status = ActionResultStatus.Success, RawResponse = rawResponse };
|
||||
|
||||
@@ -3,17 +3,16 @@ 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
|
||||
public 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 const string ConfigRootElement = "F4SD-ExternalCommunication-Configuration";
|
||||
|
||||
public IDictionary<TriggerEvent, Trigger> Triggers { get; } = new Dictionary<TriggerEvent, Trigger>();
|
||||
|
||||
@@ -43,7 +42,7 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
Trigger trigger = new Trigger(triggerNodeElement, parser);
|
||||
|
||||
if (trigger is null || !Triggers.ContainsKey(trigger.Event))
|
||||
if (trigger is null || !trigger.IsValid || Triggers.ContainsKey(trigger.Event))
|
||||
continue;
|
||||
|
||||
Triggers.Add(trigger.Event, trigger);
|
||||
|
||||
@@ -11,16 +11,16 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
public override ActionType Type => ActionType.HttpCall;
|
||||
|
||||
public string Url { get; set; }
|
||||
public HttpMethod Method { get; set; } = HttpMethod.Post;
|
||||
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
|
||||
public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
|
||||
public string Body { get; set; }
|
||||
public string Url { get; internal set; }
|
||||
public HttpMethod Method { get; internal set; } = HttpMethod.Post;
|
||||
public TimeSpan Timeout { get; internal set; } = TimeSpan.FromSeconds(30);
|
||||
public IDictionary<string, string> Headers { get; internal set; } = new Dictionary<string, string>();
|
||||
public string Body { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// jsonPath expressions keyed by field name, used to extract values from the response.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> MappedFieldJsonPaths { get; set; } = new Dictionary<string, string>();
|
||||
public IDictionary<string, string> MappedFieldJsonPaths { get; internal set; } = new Dictionary<string, string>();
|
||||
|
||||
internal HttpCallDefinition(XmlElement xNode, cXmlParser parser) : base(xNode, parser)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace F4SD.ActionConnector.Models
|
||||
/// <summary>
|
||||
/// Reference to the Quick Action to invoke, e.g. "Protocol case in JIRA".
|
||||
/// </summary>
|
||||
public string QuickActionRef { get; set; }
|
||||
public string QuickActionRef { get; internal set; }
|
||||
|
||||
public IDictionary<string, string> Parameters { get; private set; } = new Dictionary<string, string>();
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
string parameterName = cXmlParser.GetStringFromXmlAttribute(parameterNode, "name");
|
||||
string parameterName = cXmlParser.GetStringFromXmlAttribute(parameterNode, "Name");
|
||||
string parameterVariable = cXmlParser.GetInnerTextFromXmlElement(parameterNode);
|
||||
|
||||
if (string.IsNullOrEmpty(parameterName) || string.IsNullOrEmpty(parameterVariable))
|
||||
|
||||
@@ -8,7 +8,7 @@ using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
internal class Trigger
|
||||
public class Trigger
|
||||
{
|
||||
public TriggerEvent Event { get; set; }
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
Event = cXmlParser.GetEnumFromAttribute(xNode, "action", TriggerEvent.Unknown);
|
||||
Event = cXmlParser.GetEnumFromAttribute(xNode, "event", TriggerEvent.Unknown);
|
||||
|
||||
XmlNode actionsNode = xNode.SelectSingleNode(ActionsNodeName);
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace F4SD.ActionConnector.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
ActionType type = cXmlParser.GetEnumFromAttribute(actionNode, "type", ActionType.Unknown);
|
||||
ActionType type = cXmlParser.GetEnumFromAttribute(actionNode, "Type", ActionType.Unknown);
|
||||
|
||||
ActionDefinitionBase actionDefinition = null;
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace F4SD.DocuEngine.DocuEngineParser
|
||||
{
|
||||
internal class SyntaxErrorException : DocuEngineParserException
|
||||
{
|
||||
private const string errorMessageTemplate = "<<Syntax Error | Expected Characters: \"{0}\" | Actual Characters: \"{1}\">>";
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace F4SD.DocuEngine.DocuEngineParser
|
||||
{
|
||||
internal class VariableErrorException : DocuEngineParserException
|
||||
{
|
||||
private const string errorMessageTemplate = "<<Variable Error | \"{0}\" can't be converted to type \"{1}\">>";
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
using C4IT.FASD.Base;
|
||||
using FasdDesktopUi.Basics.Helper;
|
||||
|
||||
namespace F4SD.Cockpit.Client.Test.Basics.Helper;
|
||||
|
||||
public class TicketExternalLinkHelperTest
|
||||
{
|
||||
[Fact]
|
||||
public void HasValidUserIdentity_NullIdentities_ReturnsFalse()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
|
||||
Assert.False(TicketExternalLinkHelper.HasValidUserIdentity(relation));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasValidUserIdentity_EmptyUserId_ReturnsFalse()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
relation.Identities =
|
||||
[
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = relation.id },
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = Guid.Empty }
|
||||
];
|
||||
|
||||
Assert.False(TicketExternalLinkHelper.HasValidUserIdentity(relation));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasValidUserIdentity_ValidUserId_ReturnsTrue()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
relation.Identities =
|
||||
[
|
||||
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = Guid.NewGuid() }
|
||||
];
|
||||
|
||||
Assert.True(TicketExternalLinkHelper.HasValidUserIdentity(relation));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetTicketLink_UsesProvidedPreviewLink()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
relation.Infos = new Dictionary<string, string>
|
||||
{
|
||||
["DirectLinkPreview"] = "https://m42.example/wm/ticket/preview"
|
||||
};
|
||||
|
||||
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, null, out var ticketLink);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Equal("https://m42.example/wm/ticket/preview", ticketLink.TrimEnd('/'));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetTicketLink_PreservesConfiguredTicketLink()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
relation.Infos = new Dictionary<string, string>
|
||||
{
|
||||
["TicketLink"] = "matrix42-client://ticket/TCK00001"
|
||||
};
|
||||
|
||||
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, null, out var ticketLink);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Equal("matrix42-client://ticket/TCK00001", ticketLink);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetTicketLink_BuildsPreviewLinkForOverviewRelation()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
relation.Infos = new Dictionary<string, string>
|
||||
{
|
||||
["ActivityType"] = "SPSActivityTypeIncident"
|
||||
};
|
||||
|
||||
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, "m42.example", out var ticketLink);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Equal(
|
||||
$"https://m42.example/wm/app-ServiceDesk/notSet/preview-object/SPSActivityTypeIncident/{relation.id:D}/0/",
|
||||
ticketLink);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetTicketLink_UsesDefaultTicketActivityType()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
|
||||
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, "https://m42.example/", out var ticketLink);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Contains("/SPSActivityTypeTicket/", ticketLink);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetTicketLink_MissingTicketId_ReturnsFalse()
|
||||
{
|
||||
var relation = CreateTicketRelation();
|
||||
relation.id = Guid.Empty;
|
||||
|
||||
var result = TicketExternalLinkHelper.TryGetTicketLink(relation, "https://m42.example", out var ticketLink);
|
||||
|
||||
Assert.False(result);
|
||||
Assert.Null(ticketLink);
|
||||
}
|
||||
|
||||
private static cF4sdApiSearchResultRelation CreateTicketRelation()
|
||||
{
|
||||
return new cF4sdApiSearchResultRelation
|
||||
{
|
||||
Type = enumF4sdSearchResultClass.Ticket,
|
||||
Name = "TCK00001",
|
||||
DisplayName = "TCK00001",
|
||||
id = Guid.NewGuid()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using FasdDesktopUi.Basics.Services;
|
||||
using FasdDesktopUi.Basics.Services.Models;
|
||||
|
||||
@@ -110,6 +111,52 @@ public class TicketOverviewUpdateServiceTest
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FetchAsync_TicketAndServiceRequestsCapability_UsesEnabledDefaultAndIsSeparatedFromCounts()
|
||||
{
|
||||
// Arrange
|
||||
var communication = new FakeCommunication();
|
||||
communication.SetCounts(TileScope.Personal, new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["ServiceRequestsNew"] = 2
|
||||
});
|
||||
communication.SetCounts(TileScope.Role, new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["ServiceRequestsNew"] = 4
|
||||
});
|
||||
|
||||
var service = CreateService(communication, out _);
|
||||
var availabilityChanges = 0;
|
||||
service.TicketAndServiceRequestsAvailabilityChanged += (_, _) => availabilityChanges++;
|
||||
Assert.True(service.TicketAndServiceRequestsEnabled);
|
||||
|
||||
// Act
|
||||
service.UpdateAvailability(true);
|
||||
await WaitUntilAsync(() => service.AreAllScopesInitialized);
|
||||
|
||||
// Assert
|
||||
Assert.True(service.TicketAndServiceRequestsEnabled);
|
||||
Assert.Equal(0, availabilityChanges);
|
||||
Assert.Equal(2, service.CurrentCounts["ServiceRequestsNew"].Personal);
|
||||
Assert.Equal(4, service.CurrentCounts["ServiceRequestsNew"].Role);
|
||||
Assert.DoesNotContain("TicketAndServiceRequestsEnabled", service.CurrentCounts.Keys);
|
||||
|
||||
communication.SetCounts(TileScope.Personal, new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["ServiceRequestsNew"] = 3
|
||||
});
|
||||
await service.FetchAsync(TileScope.Personal);
|
||||
|
||||
Assert.True(service.TicketAndServiceRequestsEnabled);
|
||||
Assert.Equal(0, availabilityChanges);
|
||||
|
||||
communication.SetCapability(TileScope.Personal, false);
|
||||
await service.FetchAsync(TileScope.Personal);
|
||||
|
||||
Assert.False(service.TicketAndServiceRequestsEnabled);
|
||||
Assert.Equal(1, availabilityChanges);
|
||||
}
|
||||
|
||||
private static TicketOverviewUpdateService CreateService(FakeCommunication communication, out FakeDispatcher dispatcher)
|
||||
{
|
||||
dispatcher = new FakeDispatcher();
|
||||
@@ -149,18 +196,27 @@ public class TicketOverviewUpdateServiceTest
|
||||
|
||||
private sealed class FakeCommunication : ITicketOverviewCommunication
|
||||
{
|
||||
private Dictionary<string, int> _personalCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
private Dictionary<string, int> _roleCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
private cF4sdTicketOverviewCountsResult _personalResult = new cF4sdTicketOverviewCountsResult();
|
||||
private cF4sdTicketOverviewCountsResult _roleResult = new cF4sdTicketOverviewCountsResult();
|
||||
|
||||
public bool IsDemo()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public Task<Dictionary<string, int>> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope)
|
||||
public Task<cF4sdTicketOverviewCountsResult> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope)
|
||||
{
|
||||
var source = useRoleScope ? _roleCounts : _personalCounts;
|
||||
return Task.FromResult(new Dictionary<string, int>(source, StringComparer.OrdinalIgnoreCase));
|
||||
var source = useRoleScope ? _roleResult : _personalResult;
|
||||
return Task.FromResult(new cF4sdTicketOverviewCountsResult
|
||||
{
|
||||
Counts = new Dictionary<string, int>(source.Counts, StringComparer.OrdinalIgnoreCase),
|
||||
Capabilities = source.Capabilities == null
|
||||
? null
|
||||
: new cF4sdTicketOverviewCapabilities
|
||||
{
|
||||
TicketAndServiceRequestsEnabled = source.Capabilities.TicketAndServiceRequestsEnabled
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void RegisterGeneratedTicket(FasdCockpitCommunicationDemo.DemoTicketRecord record)
|
||||
@@ -175,13 +231,22 @@ public class TicketOverviewUpdateServiceTest
|
||||
|
||||
if (scope == TileScope.Role)
|
||||
{
|
||||
_roleCounts = copy;
|
||||
_roleResult.Counts = copy;
|
||||
}
|
||||
else
|
||||
{
|
||||
_personalCounts = copy;
|
||||
_personalResult.Counts = copy;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCapability(TileScope scope, bool enabled)
|
||||
{
|
||||
var result = scope == TileScope.Role ? _roleResult : _personalResult;
|
||||
result.Capabilities = new cF4sdTicketOverviewCapabilities
|
||||
{
|
||||
TicketAndServiceRequestsEnabled = enabled
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FakeDispatcher : ITicketOverviewDispatcher
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
</Compile>
|
||||
<Compile Include="Models\RemoteDesktopConnection\IRemoteDesktopClientInfo.cs" />
|
||||
<Compile Include="Models\RemoteDesktopConnection\RemoteDesktopConnectionStatusResult.cs" />
|
||||
<Compile Include="Models\TicketOverview\TicketOverviewCountsResult.cs" />
|
||||
<Compile Include="RemoteDesktopCommunicationBase.cs" />
|
||||
<Compile Include="ExternalToolExecutor.cs" />
|
||||
<Compile Include="F4sdCockpitCommunicationM42Base.cs" />
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
#region Ticketübersicht
|
||||
|
||||
public abstract Task<List<cF4sdApiSearchResultRelation>> GetTicketOverviewRelations(string key, bool useRoleScope, int count);
|
||||
public abstract Task<Dictionary<string, int>> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope);
|
||||
public abstract Task<cF4sdTicketOverviewCountsResult> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -90,6 +90,29 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
public abstract Task<bool> UpdateHealthcardTableData(cF4SDWriteParameters dataParameter);
|
||||
public abstract Task<bool> Matrix42TicketFinalization(cApiM42Ticket ticketData);
|
||||
|
||||
public virtual async Task<cTicketFinalizationResult> FinalizeTicketAsync(cApiM42Ticket ticketData)
|
||||
{
|
||||
var success = await Matrix42TicketFinalization(ticketData);
|
||||
var ticketId = ticketData?.Ticket;
|
||||
if (ticketId == Guid.Empty)
|
||||
ticketId = null;
|
||||
|
||||
return new cTicketFinalizationResult
|
||||
{
|
||||
Success = success,
|
||||
TicketId = ticketId
|
||||
};
|
||||
}
|
||||
|
||||
public virtual Task<cTicketExternalLinkResult> GetTicketExternalLinkAsync(Guid ticketId, enumTicketExternalOpenMode mode)
|
||||
{
|
||||
return Task.FromResult(new cTicketExternalLinkResult
|
||||
{
|
||||
Success = false,
|
||||
Mode = enumTicketExternalOpenMode.None
|
||||
});
|
||||
}
|
||||
|
||||
public abstract Task<List<List<object>>> GetQuickActionHistory(string QuickActionName, int OrgId, int DeviceId, int? UserId);
|
||||
|
||||
public abstract Task<bool> GetAgentApiAccessInfo();
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace C4IT.FASD.Cockpit.Communication
|
||||
{
|
||||
public sealed class cF4sdTicketOverviewCountsResult
|
||||
{
|
||||
public Dictionary<string, int> Counts { get; set; } = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public cF4sdTicketOverviewCapabilities Capabilities { get; set; } = new cF4sdTicketOverviewCapabilities();
|
||||
}
|
||||
|
||||
public sealed class cF4sdTicketOverviewCapabilities
|
||||
{
|
||||
public bool TicketAndServiceRequestsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -1147,7 +1147,7 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
|
||||
#region Ticketübersicht
|
||||
|
||||
public override async Task<Dictionary<string, int>> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope)
|
||||
public override async Task<cF4sdTicketOverviewCountsResult> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
@@ -1182,13 +1182,13 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
await CheckConnectionStatus.Invoke();
|
||||
|
||||
LogEntry($"Error on requesting ticket overview counts ({scope}). Status: {result.Status}", LogLevels.Warning);
|
||||
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
return new cF4sdTicketOverviewCountsResult();
|
||||
}
|
||||
|
||||
if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetCounts", result.Result, url);
|
||||
|
||||
var response = JsonConvert.DeserializeObject<TicketOverviewCountsResponse>(result.Result);
|
||||
return response?.ToDictionary(normalizedKeys) ?? new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
return response?.ToResult(normalizedKeys) ?? new cF4sdTicketOverviewCountsResult();
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
@@ -1204,7 +1204,7 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
return new cF4sdTicketOverviewCountsResult();
|
||||
}
|
||||
|
||||
public override async Task<List<cF4sdApiSearchResultRelation>> GetTicketOverviewRelations(string key, bool useRoleScope, int count)
|
||||
@@ -1515,6 +1515,12 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
return output;
|
||||
}
|
||||
public override async Task<bool> Matrix42TicketFinalization(cApiM42Ticket ticketData)
|
||||
{
|
||||
var result = await FinalizeTicketAsync(ticketData);
|
||||
return result?.Success == true;
|
||||
}
|
||||
|
||||
public override async Task<cTicketFinalizationResult> FinalizeTicketAsync(cApiM42Ticket ticketData)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
@@ -1522,7 +1528,6 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
var apiError = 0;
|
||||
var timeStart = DateTime.UtcNow;
|
||||
|
||||
bool output = false;
|
||||
try
|
||||
{
|
||||
var http = GetHttpHelper(true);
|
||||
@@ -1532,7 +1537,7 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
var result = await http.PostJsonAsync(url, payload, 20000, CancellationToken.None);
|
||||
|
||||
if (result.IsOk)
|
||||
return true;
|
||||
return ParseTicketFinalizationResult(result.Result, ticketData?.Ticket);
|
||||
else
|
||||
apiError = (int)result.Status;
|
||||
}
|
||||
@@ -1547,7 +1552,102 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return output;
|
||||
return new cTicketFinalizationResult { Success = false };
|
||||
}
|
||||
|
||||
internal static cTicketFinalizationResult ParseTicketFinalizationResult(string response, Guid? fallbackTicketId)
|
||||
{
|
||||
if (fallbackTicketId == Guid.Empty)
|
||||
fallbackTicketId = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(response))
|
||||
{
|
||||
try
|
||||
{
|
||||
var token = JToken.Parse(response);
|
||||
if (token.Type == JTokenType.Object)
|
||||
{
|
||||
var result = token.ToObject<cTicketFinalizationResult>();
|
||||
if (result != null)
|
||||
{
|
||||
if (result.Success && (!result.TicketId.HasValue || result.TicketId.Value == Guid.Empty))
|
||||
result.TicketId = fallbackTicketId;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (token.Type == JTokenType.String &&
|
||||
Guid.TryParse(token.Value<string>(), out var createdTicketId))
|
||||
{
|
||||
return new cTicketFinalizationResult
|
||||
{
|
||||
Success = true,
|
||||
TicketId = createdTicketId
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
if (Guid.TryParse(response.Trim().Trim('"'), out var createdTicketId))
|
||||
{
|
||||
return new cTicketFinalizationResult
|
||||
{
|
||||
Success = true,
|
||||
TicketId = createdTicketId
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Older providers returned an empty JSON value for successful updates.
|
||||
return new cTicketFinalizationResult
|
||||
{
|
||||
Success = true,
|
||||
TicketId = fallbackTicketId
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<cTicketExternalLinkResult> GetTicketExternalLinkAsync(Guid ticketId, enumTicketExternalOpenMode mode)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
|
||||
var apiError = 0;
|
||||
var timeStart = DateTime.UtcNow;
|
||||
|
||||
try
|
||||
{
|
||||
if (ticketId == Guid.Empty || mode == enumTicketExternalOpenMode.None)
|
||||
return new cTicketExternalLinkResult { Success = false, Mode = enumTicketExternalOpenMode.None };
|
||||
|
||||
var http = GetHttpHelper(true);
|
||||
var url = $"api/Ticketing/GetExternalLink?ticketId={ticketId:D}&mode={Uri.EscapeDataString(mode.ToString())}";
|
||||
var result = await http.GetHttpJson(url, 20000, CancellationToken.None);
|
||||
|
||||
if (result.IsOk)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<cTicketExternalLinkResult>(result.Result)
|
||||
?? new cTicketExternalLinkResult { Success = false, Mode = enumTicketExternalOpenMode.None };
|
||||
}
|
||||
|
||||
apiError = (int)result.Status;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
apiError = E.HResult;
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Debug_apiTiming) SaveApiTimingEntry("Ticketing-GetExternalLink", timeStart, apiError);
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return new cTicketExternalLinkResult
|
||||
{
|
||||
Success = false,
|
||||
Mode = enumTicketExternalOpenMode.None
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<bool> GetAgentApiAccessInfo()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace FasdCockpitCommunication.TicketOverview
|
||||
@@ -10,7 +11,10 @@ namespace FasdCockpitCommunication.TicketOverview
|
||||
[JsonProperty("counts")]
|
||||
public Dictionary<string, int> Counts { get; set; } = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public Dictionary<string, int> ToDictionary(IEnumerable<string> expectedKeys)
|
||||
[JsonProperty("capabilities")]
|
||||
public TicketOverviewCapabilitiesResponse Capabilities { get; set; } = new TicketOverviewCapabilitiesResponse();
|
||||
|
||||
public cF4sdTicketOverviewCountsResult ToResult(IEnumerable<string> expectedKeys)
|
||||
{
|
||||
var comparer = StringComparer.OrdinalIgnoreCase;
|
||||
var output = new Dictionary<string, int>(comparer);
|
||||
@@ -28,7 +32,7 @@ namespace FasdCockpitCommunication.TicketOverview
|
||||
output[key] = 0;
|
||||
}
|
||||
|
||||
return output;
|
||||
return CreateResult(output);
|
||||
}
|
||||
|
||||
if (Counts != null)
|
||||
@@ -42,7 +46,25 @@ namespace FasdCockpitCommunication.TicketOverview
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
return CreateResult(output);
|
||||
}
|
||||
|
||||
private cF4sdTicketOverviewCountsResult CreateResult(Dictionary<string, int> counts)
|
||||
{
|
||||
return new cF4sdTicketOverviewCountsResult
|
||||
{
|
||||
Counts = counts,
|
||||
Capabilities = new cF4sdTicketOverviewCapabilities
|
||||
{
|
||||
TicketAndServiceRequestsEnabled = Capabilities?.TicketAndServiceRequestsEnabled ?? true
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TicketOverviewCapabilitiesResponse
|
||||
{
|
||||
[JsonProperty("ticketAndServiceRequestsEnabled")]
|
||||
public bool TicketAndServiceRequestsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,31 @@
|
||||
<TicketConfiguration>
|
||||
<DisableAutomaticTimeTracking Policy="Mandatory" Value="true" />
|
||||
<CompletitionPolicy Policy="Mandatory" Value="IfRequired" />
|
||||
<UseSimplifiedCaseCompletionDialog Policy="Mandatory" Value="false" />
|
||||
<SimplifiedCaseCompletionTicketOpenMode Policy="Default" Value="Preview" />
|
||||
<NotesMandatory Policy="Mandatory" Value="true" />
|
||||
<ShowOverview Policy="Mandatory" Value="true" />
|
||||
<OpenActivitiesExternally Policy="Mandatory" Value="false">
|
||||
<OpenActivityOverride ActivityType="SPSActivityTypeTicket" Value="false" />
|
||||
<OpenActivityOverride ActivityType="SPSActivityTypeServiceRequest" Value="true" />
|
||||
</OpenActivitiesExternally>
|
||||
<TicketProcessing Policy="Mandatory" Value="both">
|
||||
<TicketTypeProcessing Type="Ticket" Value="intern" />
|
||||
<TicketTypeProcessing Type="UnclassifiedTicket" Value="intern" />
|
||||
<TicketTypeProcessing Type="Incident" Value="intern" />
|
||||
</TicketProcessing>
|
||||
<TicketFilters>
|
||||
<Filter Provider="Matrix42" Field="Queue" Enabled="false" Match="include" EmptyHandling="include">
|
||||
<Value ID="2a7e8099-3d57-f011-1988-00155d320605" Name="HR" />
|
||||
<Value ID="2a7a8099-3d47-f011-1988-00155d320505" Name="FM" />
|
||||
</Filter>
|
||||
<Filter Field="AssignmentGroup" Enabled="false" Match="include" EmptyHandling="exclude">
|
||||
<Value ID="0a76de08-136c-764a-b410-5610e8076712" Name="HR Service Desk Agent" />
|
||||
<Value ID="0b76de08-8668-a026-b410-5610e8076f95" Name="HR-Manager" />
|
||||
<Value ID="0a76de08-d589-4c94-b410-5610e8076919" Name="HR-Spezialist" />
|
||||
<Value ID="e87dde08-235c-04e5-b410-562b64035575" Name="Facility-Koordinator" />
|
||||
</Filter>
|
||||
<Filter Provider="Matrix42" Field="Workspace" Enabled="false" Match="include" EmptyHandling="exclude">
|
||||
<Value ID="1676de08-27f3-550c-b410-5610e807aa02" Name="HR Service Management" />
|
||||
<Value ID="ed7dde08-199e-c27b-b410-562b64037aa1" Name="Gebäudemanagement" />
|
||||
</Filter>
|
||||
</TicketFilters>
|
||||
<OverviewPollingPersonal Policy="Mandatory" Value="10" />
|
||||
<OverviewPollingRole Policy="Mandatory" Value="5" />
|
||||
</TicketConfiguration>
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
return ticket;
|
||||
}
|
||||
|
||||
public override Task<Dictionary<string, int>> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope)
|
||||
public override Task<cF4sdTicketOverviewCountsResult> GetTicketOverviewCounts(IEnumerable<string> keys, bool useRoleScope)
|
||||
{
|
||||
var scopeKey = useRoleScope ? "Role" : "Personal";
|
||||
var comparer = StringComparer.OrdinalIgnoreCase;
|
||||
@@ -299,7 +299,10 @@ namespace C4IT.FASD.Cockpit.Communication
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(result);
|
||||
return Task.FromResult(new cF4sdTicketOverviewCountsResult
|
||||
{
|
||||
Counts = result
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task<List<cF4sdApiSearchResultRelation>> GetTicketOverviewRelations(string key, bool useRoleScope, int count)
|
||||
|
||||
@@ -308,6 +308,58 @@
|
||||
}
|
||||
],
|
||||
"Tickets": [
|
||||
{
|
||||
"TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61",
|
||||
"UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a",
|
||||
"TileKey": "ServiceRequestsNew",
|
||||
"UseRoleScope": false,
|
||||
"ActivityType": "SPSActivityTypeServiceRequest",
|
||||
"DisplayName": "SRQ00001",
|
||||
"Summary": "Neue Software fuer den Arbeitsplatz bereitstellen",
|
||||
"StatusId": "New",
|
||||
"UserDisplayName": "Busch, Andrea",
|
||||
"UserAccount": "AB014",
|
||||
"UserDomain": "CONTOSO"
|
||||
},
|
||||
{
|
||||
"TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61",
|
||||
"UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a",
|
||||
"TileKey": "ServiceRequestsActive",
|
||||
"UseRoleScope": false,
|
||||
"ActivityType": "SPSActivityTypeServiceRequest",
|
||||
"DisplayName": "SRQ00001",
|
||||
"Summary": "Neue Software fuer den Arbeitsplatz bereitstellen",
|
||||
"StatusId": "InProgress",
|
||||
"UserDisplayName": "Busch, Andrea",
|
||||
"UserAccount": "AB014",
|
||||
"UserDomain": "CONTOSO"
|
||||
},
|
||||
{
|
||||
"TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61",
|
||||
"UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a",
|
||||
"TileKey": "ServiceRequestsCritical",
|
||||
"UseRoleScope": false,
|
||||
"ActivityType": "SPSActivityTypeServiceRequest",
|
||||
"DisplayName": "SRQ00001",
|
||||
"Summary": "Neue Software fuer den Arbeitsplatz bereitstellen",
|
||||
"StatusId": "InProgress",
|
||||
"UserDisplayName": "Busch, Andrea",
|
||||
"UserAccount": "AB014",
|
||||
"UserDomain": "CONTOSO"
|
||||
},
|
||||
{
|
||||
"TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61",
|
||||
"UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a",
|
||||
"TileKey": "ServiceRequestsNewInfo",
|
||||
"UseRoleScope": false,
|
||||
"ActivityType": "SPSActivityTypeServiceRequest",
|
||||
"DisplayName": "SRQ00001",
|
||||
"Summary": "Neue Software fuer den Arbeitsplatz bereitstellen",
|
||||
"StatusId": "OnHold",
|
||||
"UserDisplayName": "Busch, Andrea",
|
||||
"UserAccount": "AB014",
|
||||
"UserDomain": "CONTOSO"
|
||||
},
|
||||
{
|
||||
"TicketId": "7e852bb9-420b-4caa-b79a-9178d793fc06",
|
||||
"UserId": "a2c35ad1-7cc7-4b2b-9aa5-d03fdaecd155",
|
||||
|
||||
@@ -4,10 +4,14 @@ using C4IT.FASD.Security;
|
||||
using C4IT.Graphics;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using C4IT.XML;
|
||||
using F4SD.ActionConnector.Bus;
|
||||
using F4SD.ActionConnector.Models;
|
||||
using FasdDesktopUi.Basics;
|
||||
using FasdDesktopUi.Basics.Helper;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services.Models;
|
||||
using FasdDesktopUi.Basics.UiActions.NativeActions;
|
||||
using FasdDesktopUi.Pages.CustomMessageBox;
|
||||
using FasdDesktopUi.Pages.PhoneSettingsPage;
|
||||
using FasdDesktopUi.Pages.SearchPage;
|
||||
@@ -46,6 +50,8 @@ namespace FasdDesktopUi
|
||||
|
||||
#endregion
|
||||
|
||||
private ActionBus _actionBus;
|
||||
|
||||
private async void Application_Startup(object sender, StartupEventArgs e)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
@@ -127,7 +133,24 @@ namespace FasdDesktopUi
|
||||
|
||||
InitializeNotifyIcon();
|
||||
|
||||
//CustomMessageBox.ShowCustomContent("Close case", enumHealthCardStateLevel.None, null, true, new CloseCaseDialogWithTicket());
|
||||
try
|
||||
{
|
||||
//_actionBus = new ActionBus(new ActionBusOptions()
|
||||
//{
|
||||
// ConfigRootElement = cXmlParser.OpenXmlDocument(new List<cXmlFileLocation>() { new cXmlFileLocation()
|
||||
// {
|
||||
// LocationType = cXmlFileLocation.enumXmlLocationType.StringContent,
|
||||
// StringContent = string.Empty
|
||||
// } }, out cXmlParser parser, ExternalCommunicationConfiguration.ConfigRootElement),
|
||||
// Parser = parser,
|
||||
// QuickActionExecutor = QuickActionExecutor.RunAction
|
||||
//});
|
||||
//_actionBus.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
await cAppStartUp.StartAsync(e.Args);
|
||||
notifyIcon.Visible = true;
|
||||
@@ -545,6 +568,8 @@ namespace FasdDesktopUi
|
||||
}
|
||||
catch { }
|
||||
|
||||
_actionBus?.Stop();
|
||||
|
||||
if (closeUserSessionTask is ConfiguredTaskAwaitable _t)
|
||||
await _t;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Helper
|
||||
{
|
||||
@@ -20,7 +13,7 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
{
|
||||
#region Unicode
|
||||
|
||||
public static void TraverseBlockAsUnicode(BlockCollection blocks, StringBuilder stringBuilder, bool isBlockFromList = false)
|
||||
public static void TraverseBlockAsUnicode(BlockCollection blocks, StringBuilder stringBuilder)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -54,17 +47,13 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
|
||||
private static void TraverseParagraphAsUnicode(Paragraph paragraph, StringBuilder stringBuilder)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var inline in paragraph.Inlines)
|
||||
{
|
||||
if (inline is Run run)
|
||||
foreach (Run run in paragraph.Inlines.OfType<Run>())
|
||||
{
|
||||
stringBuilder.Append(run.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
@@ -73,32 +62,24 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
|
||||
private static void TraverseListAsUnicode(List list, StringBuilder stringBuilder)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (list.MarkerStyle == TextMarkerStyle.Decimal)
|
||||
{
|
||||
|
||||
for (int i = 0; i < list.ListItems.Count; i++)
|
||||
{
|
||||
|
||||
stringBuilder.Append(i + 1 + ". ");
|
||||
TraverseBlockAsUnicode(list.ListItems.ElementAt(i).Blocks, stringBuilder, true);
|
||||
|
||||
TraverseBlockAsUnicode(list.ListItems.ElementAt(i).Blocks, stringBuilder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in list.ListItems)
|
||||
{
|
||||
|
||||
stringBuilder.Append("- ");
|
||||
TraverseBlockAsUnicode(item.Blocks, stringBuilder, true);
|
||||
|
||||
TraverseBlockAsUnicode(item.Blocks, stringBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
@@ -108,18 +89,14 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
|
||||
private static void TraverseImageAsUnicode(System.Windows.Controls.Image image, StringBuilder stringBuilder)
|
||||
{
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
stringBuilder.Append("[Image]");
|
||||
stringBuilder.Append($"[Image:\"{image.Name}\"]");
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -151,12 +128,7 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
else if (block is BlockUIContainer container)
|
||||
{
|
||||
if (container.Child is System.Windows.Controls.Image image)
|
||||
{
|
||||
|
||||
TraverseImageAsHtml(image, stringBuilder);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +195,6 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
byte[] arr;
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
@@ -242,7 +213,6 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void TraverseRunAsHtml(Run run, StringBuilder stringBuilder)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.Logging;
|
||||
|
||||
using FasdDesktopUi.Basics;
|
||||
@@ -13,7 +15,36 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
{
|
||||
internal static class TicketExternalLinkHelper
|
||||
{
|
||||
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation)
|
||||
private const string DefaultTicketActivityType = "SPSActivityTypeTicket";
|
||||
|
||||
internal static async Task<bool> TryOpenFinalizedTicketExternallyAsync(Guid ticketId, enumTicketExternalOpenMode mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ticketId == Guid.Empty || mode == enumTicketExternalOpenMode.None)
|
||||
return false;
|
||||
|
||||
var linkResult = await cFasdCockpitCommunicationBase.Instance.GetTicketExternalLinkAsync(ticketId, mode);
|
||||
if (linkResult?.Success != true ||
|
||||
!Uri.TryCreate(linkResult.Url, UriKind.Absolute, out var ticketUri) ||
|
||||
(ticketUri.Scheme != Uri.UriSchemeHttp && ticketUri.Scheme != Uri.UriSchemeHttps))
|
||||
{
|
||||
LogEntry($"Could not resolve an external link for ticket '{ticketId:D}'.", LogLevels.Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
new cBrowsers().Start("default", ticketUri.AbsoluteUri);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation, bool forceExternal = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -25,14 +56,20 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
var processing = ShouldOpenExternally(ticketType);
|
||||
|
||||
// check if we have a valid user id in the id list => if not we could open this ticket only extern.
|
||||
var hasUser = relation.Identities.Any(e => (e.Class == enumFasdInformationClass.User && e.Id != null && e.Id != Guid.Empty));
|
||||
if (!hasUser)
|
||||
var hasUser = HasValidUserIdentity(relation);
|
||||
if (forceExternal || !hasUser)
|
||||
processing = enumTicketProcessing.Extern;
|
||||
|
||||
if (processing == enumTicketProcessing.Intern)
|
||||
return false;
|
||||
|
||||
if (relation?.Infos?.TryGetValue("TicketLink", out var ticketLink) == true && !string.IsNullOrWhiteSpace(ticketLink))
|
||||
var m42Server = cCockpitConfiguration.Instance?.m42ServerConfiguration?.Server;
|
||||
if (!TryGetTicketLink(relation, m42Server, out var ticketLink))
|
||||
{
|
||||
LogEntry($"Could not resolve an external Matrix42 link for ticket '{relation.DisplayName ?? relation.Name}'.", LogLevels.Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
new cBrowsers().Start("default", ticketLink);
|
||||
|
||||
return processing == enumTicketProcessing.Extern;
|
||||
@@ -45,6 +82,73 @@ namespace FasdDesktopUi.Basics.Helper
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool HasValidUserIdentity(cF4sdApiSearchResultRelation relation)
|
||||
{
|
||||
return relation?.Identities?.Any(identity =>
|
||||
identity.Class == enumFasdInformationClass.User && identity.Id != Guid.Empty) == true;
|
||||
}
|
||||
|
||||
internal static bool TryGetTicketLink(cF4sdApiSearchResultRelation relation, string m42Server, out string ticketLink)
|
||||
{
|
||||
ticketLink = null;
|
||||
if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket)
|
||||
return false;
|
||||
|
||||
if (TryGetConfiguredLink(relation, "TicketLink", out ticketLink) ||
|
||||
TryGetConfiguredLink(relation, "DirectLinkPreview", out ticketLink))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (relation.id == Guid.Empty || string.IsNullOrWhiteSpace(m42Server))
|
||||
return false;
|
||||
|
||||
var server = m42Server.Trim();
|
||||
if (!server.Contains("://"))
|
||||
server = $"https://{server}";
|
||||
|
||||
if (!Uri.TryCreate(server, UriKind.Absolute, out var serverUri) ||
|
||||
(serverUri.Scheme != Uri.UriSchemeHttp && serverUri.Scheme != Uri.UriSchemeHttps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var activityType = GetActivityType(relation);
|
||||
var encodedActivityType = Uri.EscapeDataString(activityType);
|
||||
ticketLink = $"{serverUri.Scheme}://{serverUri.Authority}/wm/app-ServiceDesk/notSet/preview-object/{encodedActivityType}/{relation.id:D}/0/";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryGetConfiguredLink(cF4sdApiSearchResultRelation relation, string key, out string ticketLink)
|
||||
{
|
||||
ticketLink = null;
|
||||
if (relation?.Infos?.TryGetValue(key, out var configuredLink) != true || string.IsNullOrWhiteSpace(configuredLink))
|
||||
return false;
|
||||
|
||||
ticketLink = configuredLink;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string GetActivityType(cF4sdApiSearchResultRelation relation)
|
||||
{
|
||||
if (relation?.Infos?.TryGetValue("ActivityType", out var activityType) == true && !string.IsNullOrWhiteSpace(activityType))
|
||||
return activityType.Trim();
|
||||
|
||||
if (relation?.Infos?.TryGetValue("TicketType", out var ticketTypeValue) == true &&
|
||||
Enum.TryParse(ticketTypeValue, true, out enumTicketType ticketType))
|
||||
{
|
||||
switch (ticketType)
|
||||
{
|
||||
case enumTicketType.Incident:
|
||||
return "SPSActivityTypeIncident";
|
||||
case enumTicketType.ServiceRequest:
|
||||
return "SPSActivityTypeServiceRequest";
|
||||
}
|
||||
}
|
||||
|
||||
return DefaultTicketActivityType;
|
||||
}
|
||||
|
||||
private static enumTicketType GetTicketType(cF4sdApiSearchResultRelation relation)
|
||||
{
|
||||
if (relation?.Infos != null && relation.Infos.TryGetValue("TicketType", out var ticketTypeValue))
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.F4SD.SupportCaseProtocoll.Models;
|
||||
using C4IT.FASD.Base;
|
||||
|
||||
using FasdCockpitBase;
|
||||
using FasdDesktopUi.Basics.Helper;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Processors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models
|
||||
@@ -193,6 +195,33 @@ namespace FasdDesktopUi.Basics.Models
|
||||
}
|
||||
}
|
||||
|
||||
public class cNamedParameterEntryCaseNotes : cNamedParameterEntryBase
|
||||
{
|
||||
private readonly bool _getHtmlAsDefaultValue;
|
||||
|
||||
public cNamedParameterEntryCaseNotes(cSupportCaseDataProvider dataProvider, bool getHtmlAsDefaultValue) : base(dataProvider)
|
||||
{
|
||||
_getHtmlAsDefaultValue = getHtmlAsDefaultValue;
|
||||
}
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
if (_getHtmlAsDefaultValue)
|
||||
return GetHtmlValue();
|
||||
|
||||
StringBuilder caseNotesStringBuilder = new StringBuilder();
|
||||
cRichTextBoxHelper.TraverseBlockAsUnicode(dataProvider.CaseNotes.Blocks, caseNotesStringBuilder);
|
||||
return caseNotesStringBuilder.ToString();
|
||||
}
|
||||
|
||||
public override string GetHtmlValue()
|
||||
{
|
||||
StringBuilder caseNotesHtmlStringBuilder = new StringBuilder();
|
||||
cRichTextBoxHelper.TraverseBlockAsHtml(dataProvider.CaseNotes.Blocks, caseNotesHtmlStringBuilder);
|
||||
return caseNotesHtmlStringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class cNamedParameterList : Dictionary<string, cNamedParameterEntryBase>
|
||||
{
|
||||
public cNamedParameterList()
|
||||
@@ -204,8 +233,11 @@ namespace FasdDesktopUi.Basics.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
Add("F4SD_QuickActionProtocolLast", new cNamedParameterEntryQuickActionResult(dataProvider));
|
||||
Add("F4SD_QuickActionProtocol", new cNamedParameterEntryQuickActionResultProtocol(dataProvider));
|
||||
Add(SupportCaseProcessor.QuickActionProtocolLastNamedParameterName, new cNamedParameterEntryQuickActionResult(dataProvider));
|
||||
Add(SupportCaseProcessor.QuickActionProtocolNamedParameterName, new cNamedParameterEntryQuickActionResultProtocol(dataProvider));
|
||||
|
||||
Add(SupportCaseProcessor.CaseNotesNamedParameterName, new cNamedParameterEntryCaseNotes(dataProvider, false));
|
||||
Add(SupportCaseProcessor.CaseNotesHtmlNamedParameterName, new cNamedParameterEntryCaseNotes(dataProvider, true));
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models
|
||||
{
|
||||
@@ -13,7 +10,7 @@ namespace FasdDesktopUi.Basics.Models
|
||||
public string Name { get; set; }
|
||||
public string AffectedDeviceName { get; set; }
|
||||
public bool WasRunningOnAffectedDevice { get; set; }
|
||||
public QuickActionStatusMonitor.cQuickActionOutput QuickActionOutput { get; set; }
|
||||
public List<QuickActionStatusMonitor.cQuickActionMeasureValue> MeasureValues { get; set; }
|
||||
public cQuickActionOutput QuickActionOutput { get; set; }
|
||||
public List<cQuickActionMeasureValue> MeasureValues { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.MultiLanguage;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models.QuickActionOutput
|
||||
{
|
||||
|
||||
public class cQuickActionMeasureValue
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public cMultiLanguageDictionary Names { get; set; }
|
||||
public object Value { get; set; }
|
||||
public object PostValue { get; set; }
|
||||
|
||||
public object Difference
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Display)
|
||||
{
|
||||
case RawValueType.INTEGER:
|
||||
case RawValueType.PERCENT:
|
||||
case RawValueType.PERCENT100:
|
||||
case RawValueType.PERCENT1000:
|
||||
case RawValueType.BYTES:
|
||||
var valueDouble = cF4SDHealthCardRawData.GetDouble(Value);
|
||||
var postValueDouble = cF4SDHealthCardRawData.GetDouble(PostValue);
|
||||
|
||||
if (valueDouble != null && postValueDouble != null)
|
||||
return postValueDouble - valueDouble;
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public RawValueType Display { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models.QuickActionOutput
|
||||
{
|
||||
public abstract class cQuickActionOutput
|
||||
{
|
||||
protected const string veiledText = "********";
|
||||
|
||||
protected readonly IRawValueFormatter _rawValueFormatter = new RawValueFormatter();
|
||||
|
||||
public cQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
_rawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
|
||||
_rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
|
||||
ErrorCode = scriptOutput.ErrorCode;
|
||||
ErrorDescription = scriptOutput.ErrorDescription;
|
||||
ResultCode = scriptOutput.ResultCode.GetValueOrDefault();
|
||||
IsError = HasError(scriptOutput);
|
||||
}
|
||||
|
||||
public cSupportCaseDataProvider DataProvider { get; private set; }
|
||||
public enumQuickActionSuccess? ResultCode { get; set; }
|
||||
public int? ErrorCode { get; set; }
|
||||
public string ErrorDescription { get; set; }
|
||||
|
||||
public bool IsError { get; private set; }
|
||||
|
||||
internal static KeyValuePair<string, RawValueType> GetDisplayType(dynamic columnTypeObject)
|
||||
{
|
||||
var output = new KeyValuePair<string, RawValueType>();
|
||||
|
||||
try
|
||||
{
|
||||
var columnType = columnTypeObject.ToObject<dynamic>();
|
||||
string name = string.Empty;
|
||||
RawValueType type = RawValueType.STRING;
|
||||
|
||||
|
||||
if (columnType.Name != null)
|
||||
if (columnType.Name is Newtonsoft.Json.Linq.JValue nameJValue)
|
||||
name = nameJValue.Value.ToString();
|
||||
|
||||
if (columnType.Type != null)
|
||||
if (columnType.Type is Newtonsoft.Json.Linq.JValue typeJValue)
|
||||
if (Enum.TryParse(typeJValue.Value.ToString(), out RawValueType typeJValueType))
|
||||
type = typeJValueType;
|
||||
|
||||
output = new KeyValuePair<string, RawValueType>(name, type);
|
||||
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static cQuickActionOutput GetQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput, cSupportCaseDataProvider dataProvider)
|
||||
{
|
||||
if (scriptOutput == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
if (scriptOutput?.Values == null)
|
||||
{
|
||||
var output = new cQuickActionOutputSingle(scriptOutput) { DataProvider = dataProvider };
|
||||
return output;
|
||||
}
|
||||
else if (scriptOutput.Values is JArray scriptValueJArray)
|
||||
{
|
||||
var scriptValues = scriptValueJArray.ToObject<List<dynamic>>();
|
||||
if (scriptValues != null && scriptValues.Count > 0)
|
||||
{
|
||||
var output = new cQuickActionOutputList(scriptOutput) { DataProvider = dataProvider };
|
||||
|
||||
foreach (var scriptValue in scriptValues)
|
||||
{
|
||||
if (scriptValue is JObject scriptValueJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var scriptValueHelperDictionary = scriptValueJObject.ToObject<Dictionary<string, object>>();
|
||||
output.Values.Add(scriptValueHelperDictionary.ToList());
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
else if (scriptOutput.Values is JObject scriptValueJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var output = new cQuickActionOutputObject(scriptOutput) { DataProvider = dataProvider };
|
||||
return output;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new cQuickActionOutputSingle(scriptOutput) { DataProvider = dataProvider };
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool HasError(cF4sdQuickActionRevision.cOutput quickActionOutput)
|
||||
{
|
||||
if ((quickActionOutput?.ResultCode == null || quickActionOutput?.ResultCode == enumQuickActionSuccess.finished || quickActionOutput?.ResultCode == enumQuickActionSuccess.successfull)
|
||||
&& (quickActionOutput?.ErrorCode == null || quickActionOutput?.ErrorCode == 0)
|
||||
&& string.IsNullOrEmpty(quickActionOutput?.ErrorDescription))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models.QuickActionOutput
|
||||
{
|
||||
public class cQuickActionOutputList : cQuickActionOutput
|
||||
{
|
||||
public cQuickActionOutputList(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
|
||||
{
|
||||
InstantiateDisplayTypes(scriptOutput);
|
||||
}
|
||||
|
||||
public Dictionary<string, RawValueType> DisplayTypes { get; set; } = new Dictionary<string, RawValueType>();
|
||||
public List<List<KeyValuePair<string, object>>> Values { get; set; } = new List<List<KeyValuePair<string, object>>>();
|
||||
|
||||
private void InstantiateDisplayTypes(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JArray columnTypeJArray)
|
||||
{
|
||||
var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
|
||||
if (columnTypes != null && columnTypes.Count > 0)
|
||||
{
|
||||
foreach (var columnTypeObject in columnTypes)
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeObject);
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JObject columnTypeJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeJObject);
|
||||
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayValue(int row, int column, Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
|
||||
{
|
||||
string output = null;
|
||||
|
||||
try
|
||||
{
|
||||
RawValueType displayType = RawValueType.STRING;
|
||||
DisplayTypes.TryGetValue(Values[row][column].Key, out displayType);
|
||||
output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, displayType);
|
||||
|
||||
if (columnOutputFormattings != null && columnOutputFormattings.TryGetValue(Values[row][column].Key, out var outputFormatting))
|
||||
{
|
||||
if (outputFormatting.Hidden)
|
||||
return string.Empty;
|
||||
|
||||
if (outputFormatting.IsSecret && !getSecretValue)
|
||||
return veiledText;
|
||||
|
||||
if (outputFormatting.DisplayType != null)
|
||||
output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, outputFormatting.DisplayType.Value);
|
||||
|
||||
if (outputFormatting.Translation != null)
|
||||
{
|
||||
var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
|
||||
if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
|
||||
{
|
||||
output = translator.DefaultTranslation?.Translation.GetValue() ?? Values[row].ToList()[column].Value.ToString();
|
||||
|
||||
foreach (var translation in translator.Translations)
|
||||
{
|
||||
if (translation.Values.Any(value => value.Equals(Values[row].ToList()[column].Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
|
||||
output = translation.Translation.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models.QuickActionOutput
|
||||
{
|
||||
public class cQuickActionOutputObject : cQuickActionOutput
|
||||
{
|
||||
public Dictionary<string, RawValueType> DisplayTypes { get; set; } = new Dictionary<string, RawValueType>();
|
||||
public List<KeyValuePair<string, object>> Values { get; set; } = new List<KeyValuePair<string, object>>();
|
||||
|
||||
public cQuickActionOutputObject(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
InstantiateDisplayTypes(scriptOutput);
|
||||
InstantiateValues(scriptOutput);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstantiateDisplayTypes(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JArray columnTypeJArray)
|
||||
{
|
||||
var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
|
||||
if (columnTypes != null && columnTypes.Count > 0)
|
||||
{
|
||||
foreach (var columnTypeObject in columnTypes)
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeObject);
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JObject columnTypeJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeJObject);
|
||||
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstantiateValues(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(scriptOutput.Values is JObject valuesJObject))
|
||||
return;
|
||||
|
||||
if (valuesJObject.Properties() == null)
|
||||
return;
|
||||
|
||||
foreach (var property in valuesJObject.Properties())
|
||||
{
|
||||
Values.Add(new KeyValuePair<string, object>(property.Name, property.Value));
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayValue(int index, Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
|
||||
{
|
||||
string output = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (Values.Count <= index)
|
||||
return null;
|
||||
|
||||
var selectedItem = Values[index];
|
||||
|
||||
RawValueType displayType = RawValueType.STRING;
|
||||
DisplayTypes.TryGetValue(selectedItem.Key, out displayType);
|
||||
output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, displayType);
|
||||
|
||||
if (columnOutputFormattings != null && columnOutputFormattings.TryGetValue(selectedItem.Key, out var outputFormatting))
|
||||
{
|
||||
if (outputFormatting.Hidden)
|
||||
return string.Empty;
|
||||
|
||||
if (outputFormatting.IsSecret && !getSecretValue)
|
||||
return veiledText;
|
||||
|
||||
if (outputFormatting.DisplayType != null)
|
||||
output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, outputFormatting.DisplayType.Value);
|
||||
|
||||
if (outputFormatting.Translation != null)
|
||||
{
|
||||
var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
|
||||
if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
|
||||
{
|
||||
output = translator.DefaultTranslation?.Translation.GetValue() ?? selectedItem.Value.ToString();
|
||||
|
||||
foreach (var translation in translator.Translations)
|
||||
{
|
||||
if (translation.Values.Any(value => value.Equals(selectedItem.Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
|
||||
output = translation.Translation.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Models.QuickActionOutput
|
||||
{
|
||||
public class cQuickActionOutputSingle : cQuickActionOutput
|
||||
{
|
||||
public cQuickActionOutputSingle(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
|
||||
{
|
||||
Instantiate(scriptOutput);
|
||||
}
|
||||
|
||||
|
||||
public RawValueType DisplayType { get; set; }
|
||||
public string Key { get; set; }
|
||||
public object Value { get; set; }
|
||||
|
||||
private void Instantiate(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value = scriptOutput.Values;
|
||||
|
||||
if (scriptOutput.Values is JObject scriptValueJObject)
|
||||
{
|
||||
string scriptValueKey = null;
|
||||
|
||||
try
|
||||
{
|
||||
var scriptValueHelperDictionary = scriptValueJObject.ToObject<Dictionary<string, object>>();
|
||||
scriptValueKey = scriptValueHelperDictionary.Keys.ToList()[0];
|
||||
|
||||
Key = scriptValueKey;
|
||||
Value = scriptValueHelperDictionary[scriptValueKey];
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
if (scriptOutput.ColumnTypes is JArray columnTypeJArray)
|
||||
{
|
||||
var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
|
||||
if (columnTypes != null && columnTypes.Count > 0)
|
||||
{
|
||||
foreach (var columnTypeObject in columnTypes)
|
||||
{
|
||||
var displayType = cQuickActionOutput.GetDisplayType(columnTypeObject);
|
||||
|
||||
if (displayType.Key == scriptValueKey)
|
||||
DisplayType = displayType.Value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (scriptOutput.ColumnTypes is JObject columnTypeJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dispayType = cQuickActionOutput.GetDisplayType(columnTypeJObject);
|
||||
DisplayType = dispayType.Value;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayValue(Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
|
||||
{
|
||||
string output = null;
|
||||
|
||||
try
|
||||
{
|
||||
output = _rawValueFormatter.GetDisplayValue(Value, DisplayType);
|
||||
|
||||
cColumnOutputFormatting outputFormatting = null;
|
||||
|
||||
if (string.IsNullOrEmpty(Key))
|
||||
outputFormatting = columnOutputFormattings?.Values.FirstOrDefault();
|
||||
else
|
||||
columnOutputFormattings?.TryGetValue(Key, out outputFormatting);
|
||||
|
||||
if (outputFormatting != null)
|
||||
{
|
||||
if (outputFormatting.IsSecret && !getSecretValue)
|
||||
return veiledText;
|
||||
|
||||
if (outputFormatting.DisplayType != null)
|
||||
output = _rawValueFormatter.GetDisplayValue(Value, outputFormatting.DisplayType.Value);
|
||||
|
||||
if (outputFormatting.Translation != null)
|
||||
{
|
||||
var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
|
||||
if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
|
||||
{
|
||||
output = translator.DefaultTranslation?.Translation.GetValue() ?? Value.ToString();
|
||||
|
||||
foreach (var translation in translator.Translations)
|
||||
{
|
||||
if (translation.Values.Any(value => value.Equals(Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
|
||||
output = translation.Translation.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,34 @@ namespace FasdDesktopUi.Basics.Models
|
||||
set { if (_incidentNewInfoSelected != value) { _incidentNewInfoSelected = value; OnPropertyChanged(nameof(IncidentNewInfoSelected)); } }
|
||||
}
|
||||
|
||||
private bool _serviceRequestsNewSelected;
|
||||
public bool ServiceRequestsNewSelected
|
||||
{
|
||||
get => _serviceRequestsNewSelected;
|
||||
set { if (_serviceRequestsNewSelected != value) { _serviceRequestsNewSelected = value; OnPropertyChanged(nameof(ServiceRequestsNewSelected)); } }
|
||||
}
|
||||
|
||||
private bool _serviceRequestsActiveSelected;
|
||||
public bool ServiceRequestsActiveSelected
|
||||
{
|
||||
get => _serviceRequestsActiveSelected;
|
||||
set { if (_serviceRequestsActiveSelected != value) { _serviceRequestsActiveSelected = value; OnPropertyChanged(nameof(ServiceRequestsActiveSelected)); } }
|
||||
}
|
||||
|
||||
private bool _serviceRequestsCriticalSelected;
|
||||
public bool ServiceRequestsCriticalSelected
|
||||
{
|
||||
get => _serviceRequestsCriticalSelected;
|
||||
set { if (_serviceRequestsCriticalSelected != value) { _serviceRequestsCriticalSelected = value; OnPropertyChanged(nameof(ServiceRequestsCriticalSelected)); } }
|
||||
}
|
||||
|
||||
private bool _serviceRequestsNewInfoSelected;
|
||||
public bool ServiceRequestsNewInfoSelected
|
||||
{
|
||||
get => _serviceRequestsNewInfoSelected;
|
||||
set { if (_serviceRequestsNewInfoSelected != value) { _serviceRequestsNewInfoSelected = value; OnPropertyChanged(nameof(ServiceRequestsNewInfoSelected)); } }
|
||||
}
|
||||
|
||||
private bool _unassignedTicketsSelected;
|
||||
public bool UnassignedTicketsSelected
|
||||
{
|
||||
@@ -102,6 +130,18 @@ namespace FasdDesktopUi.Basics.Models
|
||||
private bool _incidentNewInfoHighlighted;
|
||||
public bool IncidentNewInfoHighlighted { get => _incidentNewInfoHighlighted; set { if (_incidentNewInfoHighlighted != value) { _incidentNewInfoHighlighted = value; OnPropertyChanged(nameof(IncidentNewInfoHighlighted)); } } }
|
||||
|
||||
private bool _serviceRequestsNewHighlighted;
|
||||
public bool ServiceRequestsNewHighlighted { get => _serviceRequestsNewHighlighted; set { if (_serviceRequestsNewHighlighted != value) { _serviceRequestsNewHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsNewHighlighted)); } } }
|
||||
|
||||
private bool _serviceRequestsActiveHighlighted;
|
||||
public bool ServiceRequestsActiveHighlighted { get => _serviceRequestsActiveHighlighted; set { if (_serviceRequestsActiveHighlighted != value) { _serviceRequestsActiveHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsActiveHighlighted)); } } }
|
||||
|
||||
private bool _serviceRequestsCriticalHighlighted;
|
||||
public bool ServiceRequestsCriticalHighlighted { get => _serviceRequestsCriticalHighlighted; set { if (_serviceRequestsCriticalHighlighted != value) { _serviceRequestsCriticalHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsCriticalHighlighted)); } } }
|
||||
|
||||
private bool _serviceRequestsNewInfoHighlighted;
|
||||
public bool ServiceRequestsNewInfoHighlighted { get => _serviceRequestsNewInfoHighlighted; set { if (_serviceRequestsNewInfoHighlighted != value) { _serviceRequestsNewInfoHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsNewInfoHighlighted)); } } }
|
||||
|
||||
private bool _unassignedTicketsHighlighted;
|
||||
public bool UnassignedTicketsHighlighted { get => _unassignedTicketsHighlighted; set { if (_unassignedTicketsHighlighted != value) { _unassignedTicketsHighlighted = value; OnPropertyChanged(nameof(UnassignedTicketsHighlighted)); } } }
|
||||
|
||||
@@ -134,6 +174,18 @@ namespace FasdDesktopUi.Basics.Models
|
||||
private string _incidentNewInfoChangeHint;
|
||||
public string IncidentNewInfoChangeHint { get => _incidentNewInfoChangeHint; set { if (_incidentNewInfoChangeHint != value) { _incidentNewInfoChangeHint = value; OnPropertyChanged(nameof(IncidentNewInfoChangeHint)); } } }
|
||||
|
||||
private string _serviceRequestsNewChangeHint;
|
||||
public string ServiceRequestsNewChangeHint { get => _serviceRequestsNewChangeHint; set { if (_serviceRequestsNewChangeHint != value) { _serviceRequestsNewChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsNewChangeHint)); } } }
|
||||
|
||||
private string _serviceRequestsActiveChangeHint;
|
||||
public string ServiceRequestsActiveChangeHint { get => _serviceRequestsActiveChangeHint; set { if (_serviceRequestsActiveChangeHint != value) { _serviceRequestsActiveChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsActiveChangeHint)); } } }
|
||||
|
||||
private string _serviceRequestsCriticalChangeHint;
|
||||
public string ServiceRequestsCriticalChangeHint { get => _serviceRequestsCriticalChangeHint; set { if (_serviceRequestsCriticalChangeHint != value) { _serviceRequestsCriticalChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsCriticalChangeHint)); } } }
|
||||
|
||||
private string _serviceRequestsNewInfoChangeHint;
|
||||
public string ServiceRequestsNewInfoChangeHint { get => _serviceRequestsNewInfoChangeHint; set { if (_serviceRequestsNewInfoChangeHint != value) { _serviceRequestsNewInfoChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsNewInfoChangeHint)); } } }
|
||||
|
||||
private string _unassignedTicketsChangeHint;
|
||||
public string UnassignedTicketsChangeHint { get => _unassignedTicketsChangeHint; set { if (_unassignedTicketsChangeHint != value) { _unassignedTicketsChangeHint = value; OnPropertyChanged(nameof(UnassignedTicketsChangeHint)); } } }
|
||||
|
||||
@@ -169,6 +221,19 @@ namespace FasdDesktopUi.Basics.Models
|
||||
private int _incidentNewInfo;
|
||||
public int IncidentNewInfo { get => _incidentNewInfo; set { _incidentNewInfo = value; OnPropertyChanged(nameof(IncidentNewInfo)); } }
|
||||
|
||||
// Service Request Properties
|
||||
private int _serviceRequestsNew;
|
||||
public int ServiceRequestsNew { get => _serviceRequestsNew; set { _serviceRequestsNew = value; OnPropertyChanged(nameof(ServiceRequestsNew)); } }
|
||||
|
||||
private int _serviceRequestsActive;
|
||||
public int ServiceRequestsActive { get => _serviceRequestsActive; set { _serviceRequestsActive = value; OnPropertyChanged(nameof(ServiceRequestsActive)); } }
|
||||
|
||||
private int _serviceRequestsCritical;
|
||||
public int ServiceRequestsCritical { get => _serviceRequestsCritical; set { _serviceRequestsCritical = value; OnPropertyChanged(nameof(ServiceRequestsCritical)); } }
|
||||
|
||||
private int _serviceRequestsNewInfo;
|
||||
public int ServiceRequestsNewInfo { get => _serviceRequestsNewInfo; set { _serviceRequestsNewInfo = value; OnPropertyChanged(nameof(ServiceRequestsNewInfo)); } }
|
||||
|
||||
// Unassigned Ticket Properties
|
||||
private int _unassignedTickets;
|
||||
public int UnassignedTickets { get => _unassignedTickets; set { _unassignedTickets = value; OnPropertyChanged(nameof(UnassignedTickets)); } }
|
||||
@@ -196,6 +261,11 @@ namespace FasdDesktopUi.Basics.Models
|
||||
IncidentCriticalSelected = false;
|
||||
IncidentNewInfoSelected = false;
|
||||
|
||||
ServiceRequestsNewSelected = false;
|
||||
ServiceRequestsActiveSelected = false;
|
||||
ServiceRequestsCriticalSelected = false;
|
||||
ServiceRequestsNewInfoSelected = false;
|
||||
|
||||
UnassignedTicketsSelected = false;
|
||||
UnassignedTicketsCriticalSelected = false;
|
||||
}
|
||||
@@ -212,6 +282,11 @@ namespace FasdDesktopUi.Basics.Models
|
||||
IncidentCriticalHighlighted = false;
|
||||
IncidentNewInfoHighlighted = false;
|
||||
|
||||
ServiceRequestsNewHighlighted = false;
|
||||
ServiceRequestsActiveHighlighted = false;
|
||||
ServiceRequestsCriticalHighlighted = false;
|
||||
ServiceRequestsNewInfoHighlighted = false;
|
||||
|
||||
UnassignedTicketsHighlighted = false;
|
||||
UnassignedTicketsCriticalHighlighted = false;
|
||||
|
||||
@@ -225,6 +300,11 @@ namespace FasdDesktopUi.Basics.Models
|
||||
IncidentCriticalChangeHint = null;
|
||||
IncidentNewInfoChangeHint = null;
|
||||
|
||||
ServiceRequestsNewChangeHint = null;
|
||||
ServiceRequestsActiveChangeHint = null;
|
||||
ServiceRequestsCriticalChangeHint = null;
|
||||
ServiceRequestsNewInfoChangeHint = null;
|
||||
|
||||
UnassignedTicketsChangeHint = null;
|
||||
UnassignedTicketsCriticalChangeHint = null;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace FasdDesktopUi.Basics.Services.Models
|
||||
{
|
||||
bool IsDemo();
|
||||
|
||||
Task<Dictionary<string, int>> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope);
|
||||
Task<cF4sdTicketOverviewCountsResult> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope);
|
||||
|
||||
#if isDemo
|
||||
void RegisterGeneratedTicket(DemoTicketRecord record);
|
||||
@@ -47,12 +47,15 @@ namespace FasdDesktopUi.Basics.Services.Models
|
||||
return _communication.IsDemo();
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, int>> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope)
|
||||
public async Task<cF4sdTicketOverviewCountsResult> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope)
|
||||
{
|
||||
var rawCounts = await _communication.GetTicketOverviewCounts(overviewKeys, useRoleScope).ConfigureAwait(false);
|
||||
return rawCounts == null
|
||||
var result = await _communication.GetTicketOverviewCounts(overviewKeys, useRoleScope).ConfigureAwait(false)
|
||||
?? new cF4sdTicketOverviewCountsResult();
|
||||
result.Counts = result.Counts == null
|
||||
? new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
: new Dictionary<string, int>(rawCounts, StringComparer.OrdinalIgnoreCase);
|
||||
: new Dictionary<string, int>(result.Counts, StringComparer.OrdinalIgnoreCase);
|
||||
result.Capabilities = result.Capabilities ?? new cF4sdTicketOverviewCapabilities();
|
||||
return result;
|
||||
}
|
||||
|
||||
#if isDemo
|
||||
|
||||
@@ -3,13 +3,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
{
|
||||
@@ -155,7 +153,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
private static string GetQuickActionAsciiOutput(cFasdQuickAction quickActionDefinition, QuickActionStatusMonitor.cQuickActionOutput quickActionOutput)
|
||||
private static string GetQuickActionAsciiOutput(cFasdQuickAction quickActionDefinition, cQuickActionOutput quickActionOutput)
|
||||
{
|
||||
string output = string.Empty;
|
||||
|
||||
@@ -166,7 +164,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
|
||||
switch (quickActionOutput)
|
||||
{
|
||||
case QuickActionStatusMonitor.cQuickActionOutputSingle singleOutput:
|
||||
case cQuickActionOutputSingle singleOutput:
|
||||
{
|
||||
if (singleOutput.Value is null)
|
||||
return output;
|
||||
@@ -177,7 +175,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
|
||||
break;
|
||||
}
|
||||
case QuickActionStatusMonitor.cQuickActionOutputList listOutput:
|
||||
case cQuickActionOutputList listOutput:
|
||||
{
|
||||
output += AsciiSeperator;
|
||||
output += cMultiLanguageSupport.GetItem("QuickAction.Copy.Output") + "\n";
|
||||
@@ -219,7 +217,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
|
||||
break;
|
||||
}
|
||||
case QuickActionStatusMonitor.cQuickActionOutputObject objectOutput:
|
||||
case cQuickActionOutputObject objectOutput:
|
||||
{
|
||||
output += AsciiSeperator;
|
||||
output += cMultiLanguageSupport.GetItem("QuickAction.Copy.Output") + "\n";
|
||||
@@ -259,7 +257,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
return output;
|
||||
}
|
||||
|
||||
private static string GetQuickActionAsciiValueComparisonString(List<QuickActionStatusMonitor.cQuickActionMeasureValue> measureValues)
|
||||
private static string GetQuickActionAsciiValueComparisonString(List<cQuickActionMeasureValue> measureValues)
|
||||
{
|
||||
string output = string.Empty;
|
||||
|
||||
@@ -365,7 +363,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
private static string GetQuickActionHtmlOutput(cFasdQuickAction quickActionDefinition, QuickActionStatusMonitor.cQuickActionOutput quickActionOutput)
|
||||
private static string GetQuickActionHtmlOutput(cFasdQuickAction quickActionDefinition, cQuickActionOutput quickActionOutput)
|
||||
{
|
||||
string output = string.Empty;
|
||||
|
||||
@@ -378,7 +376,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
|
||||
switch (quickActionOutput)
|
||||
{
|
||||
case QuickActionStatusMonitor.cQuickActionOutputSingle singleOutput:
|
||||
case cQuickActionOutputSingle singleOutput:
|
||||
{
|
||||
if (singleOutput.Value is null)
|
||||
return output;
|
||||
@@ -387,7 +385,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
output += "<p>" + cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Html") + " " + displayValue + "</p>";
|
||||
break;
|
||||
}
|
||||
case QuickActionStatusMonitor.cQuickActionOutputList listOutput:
|
||||
case cQuickActionOutputList listOutput:
|
||||
{
|
||||
output += "<p>" + cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Html") + "</p>";
|
||||
|
||||
@@ -436,7 +434,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
output += "</table>";
|
||||
break;
|
||||
}
|
||||
case QuickActionStatusMonitor.cQuickActionOutputObject objectOutput:
|
||||
case cQuickActionOutputObject objectOutput:
|
||||
{
|
||||
output += "<p>" + cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Html") + "</p>";
|
||||
|
||||
@@ -479,7 +477,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
|
||||
return output;
|
||||
}
|
||||
|
||||
private static string GetQuickActionHtmlValueComparison(List<QuickActionStatusMonitor.cQuickActionMeasureValue> measureValues)
|
||||
private static string GetQuickActionHtmlValueComparison(List<cQuickActionMeasureValue> measureValues)
|
||||
{
|
||||
string output = string.Empty;
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace FasdDesktopUi.Basics.Services.RemoteDesktop
|
||||
{
|
||||
ProcessStartInfo info = new ProcessStartInfo(GetViewerPath())
|
||||
{
|
||||
Arguments = $"-connectionId {connectionDetails.ConnectionId} -phoenixServiceUrl {connectionDetails.PhoenixServiceUrl} -secret {connectionDetails.Secret}"
|
||||
Arguments = $"-connectionId {connectionDetails.ConnectionId} -phoenixServiceUrl {connectionDetails.PhoenixServiceUrl} -secret {connectionDetails.Secret} -hideAi {!cFasdCockpitConfig.Instance.Global.UseAiAnalyzer}"
|
||||
};
|
||||
|
||||
Process process = Process.Start(info);
|
||||
|
||||
@@ -3,6 +3,7 @@ using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.Logging;
|
||||
using FasdDesktopUi.Basics.CustomEvents;
|
||||
using FasdDesktopUi.Basics.Enums;
|
||||
using FasdDesktopUi.Basics.Helper;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services.Models;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
|
||||
@@ -11,6 +12,7 @@ using FasdDesktopUi.Pages.DetailsPage.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
@@ -24,6 +26,11 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
|
||||
internal const string AgentDeviceIdNamedParameterName = "F4SD_Agent_DeviceId";
|
||||
internal const string AgentUserIdNamedParameterName = "F4SD_Agent_UserId";
|
||||
internal const string AgentOrganisationCodeNamedParameterName = "F4SD_Agent_OrganisationId";
|
||||
internal const string CaseNotesNamedParameterName = "F4SD_CaseNotes";
|
||||
internal const string CaseNotesHtmlNamedParameterName = "F4SD_CaseNotesHtml";
|
||||
internal const string QuickActionProtocolNamedParameterName = "F4SD_QuickActionProtocol";
|
||||
internal const string QuickActionProtocolLastNamedParameterName = "F4SD_QuickActionProtocolLast";
|
||||
|
||||
|
||||
private ISupportCase _supportCase;
|
||||
public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get => _supportCase?.SupportCaseDataProviderArtifact; }
|
||||
@@ -134,6 +141,16 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
|
||||
}
|
||||
|
||||
_namedParameterCache[relation][AgentOrganisationCodeNamedParameterName] = cCockpitConfiguration.Instance.agentApiConfiguration.OrganizationCode;
|
||||
|
||||
// todo insert quick action protocoll
|
||||
|
||||
StringBuilder caseNotesStringBuilder = new StringBuilder();
|
||||
cRichTextBoxHelper.TraverseBlockAsUnicode(SupportCaseDataProviderArtifact.CaseNotes.Blocks, caseNotesStringBuilder);
|
||||
_namedParameterCache[relation][CaseNotesNamedParameterName] = caseNotesStringBuilder.ToString();
|
||||
|
||||
StringBuilder caseNotesHtmlStringBuilder = new StringBuilder();
|
||||
cRichTextBoxHelper.TraverseBlockAsHtml(SupportCaseDataProviderArtifact.CaseNotes.Blocks, caseNotesHtmlStringBuilder);
|
||||
_namedParameterCache[relation][CaseNotesHtmlNamedParameterName] = caseNotesHtmlStringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using FasdDesktopUi.Basics.UiActions.NativeActions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
|
||||
@@ -12,6 +13,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
|
||||
if (!_supportCaseProccesors.ContainsKey(id))
|
||||
_supportCaseProccesors.Add(id, new SupportCaseProcessor());
|
||||
|
||||
QuickActionExecutor.SetSupportCaseProcessor(_supportCaseProccesors[id]);
|
||||
return _supportCaseProccesors[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FasdDesktopUi.Basics.Services
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const bool TicketAndServiceRequestsEnabledDefault = true;
|
||||
private readonly ITicketOverviewCommunicationSource _communicationSource;
|
||||
private static readonly string[] OverviewKeys = new[]
|
||||
{
|
||||
@@ -35,6 +36,10 @@ namespace FasdDesktopUi.Basics.Services
|
||||
"IncidentActive",
|
||||
"IncidentCritical",
|
||||
"IncidentNewInfo",
|
||||
"ServiceRequestsNew",
|
||||
"ServiceRequestsActive",
|
||||
"ServiceRequestsCritical",
|
||||
"ServiceRequestsNewInfo",
|
||||
"UnassignedTickets",
|
||||
"UnassignedTicketsCritical"
|
||||
};
|
||||
@@ -53,6 +58,7 @@ namespace FasdDesktopUi.Basics.Services
|
||||
private bool _isDemo;
|
||||
private bool _initialized;
|
||||
private bool _isEnabled;
|
||||
private bool _ticketAndServiceRequestsEnabled = TicketAndServiceRequestsEnabledDefault;
|
||||
private readonly Random _random = new Random();
|
||||
#if isDemo
|
||||
private readonly List<DemoTicketRecord> _persistedDemoTickets = new List<DemoTicketRecord>();
|
||||
@@ -109,8 +115,10 @@ namespace FasdDesktopUi.Basics.Services
|
||||
#region Public API
|
||||
|
||||
public event EventHandler<TicketOverviewCountsChangedEventArgs> OverviewCountsChanged;
|
||||
public event EventHandler TicketAndServiceRequestsAvailabilityChanged;
|
||||
|
||||
public IReadOnlyDictionary<string, TileCounts> CurrentCounts => _currentCounts;
|
||||
public bool TicketAndServiceRequestsEnabled => _ticketAndServiceRequestsEnabled;
|
||||
|
||||
public bool IsScopeInitialized(TileScope scope)
|
||||
{
|
||||
@@ -215,6 +223,8 @@ namespace FasdDesktopUi.Basics.Services
|
||||
{
|
||||
_currentCounts[key] = TileCounts.Empty;
|
||||
}
|
||||
|
||||
UpdateTicketAndServiceRequestsAvailability(false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -328,8 +338,11 @@ namespace FasdDesktopUi.Basics.Services
|
||||
|
||||
_isDemo = communication.IsDemo();
|
||||
|
||||
var rawCounts = await communication.GetTicketOverviewCounts(OverviewKeys, scope == TileScope.Role).ConfigureAwait(false);
|
||||
var result = await communication.GetTicketOverviewCounts(OverviewKeys, scope == TileScope.Role).ConfigureAwait(false);
|
||||
var rawCounts = result?.Counts;
|
||||
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
var ticketAndServiceRequestsEnabled =
|
||||
result?.Capabilities?.TicketAndServiceRequestsEnabled ?? TicketAndServiceRequestsEnabledDefault;
|
||||
|
||||
if (rawCounts != null)
|
||||
{
|
||||
@@ -345,7 +358,13 @@ namespace FasdDesktopUi.Basics.Services
|
||||
if (!_isEnabled)
|
||||
return;
|
||||
|
||||
await _dispatcher.InvokeAsync(() => ProcessScopeCounts(scope, counts));
|
||||
await _dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
if (scope == TileScope.Personal)
|
||||
UpdateTicketAndServiceRequestsAvailability(ticketAndServiceRequestsEnabled);
|
||||
|
||||
ProcessScopeCounts(scope, counts);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -362,6 +381,15 @@ namespace FasdDesktopUi.Basics.Services
|
||||
|
||||
#region Count Processing
|
||||
|
||||
private void UpdateTicketAndServiceRequestsAvailability(bool isEnabled)
|
||||
{
|
||||
if (_ticketAndServiceRequestsEnabled == isEnabled)
|
||||
return;
|
||||
|
||||
_ticketAndServiceRequestsEnabled = isEnabled;
|
||||
TicketAndServiceRequestsAvailabilityChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void RefreshTimerIntervals()
|
||||
{
|
||||
_ = _dispatcher.InvokeAsync(() =>
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
using System;
|
||||
using C4IT.F4SD.SupportCaseProtocoll.Models;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using F4SD.ActionConnector.Bus;
|
||||
using F4SD.ActionConnector.Events;
|
||||
using F4SD.ActionConnector.Payloads;
|
||||
using F4SD.Gamification;
|
||||
using F4SD.Gamification.Services;
|
||||
using FasdDesktopUi.Basics.Helper;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using FasdDesktopUi.Basics.Services.RelationService;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Processors;
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
using FasdDesktopUi.Config;
|
||||
using FasdDesktopUi.Pages;
|
||||
using FasdDesktopUi.Pages.CustomMessageBox;
|
||||
using FasdDesktopUi.Pages.SearchPage;
|
||||
using FasdDesktopUi.Pages.TicketCompletion;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using System.Diagnostics;
|
||||
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.MultiLanguage;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
using FasdDesktopUi.Basics.Helper;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
using FasdDesktopUi.Pages;
|
||||
using FasdDesktopUi.Pages.CustomMessageBox;
|
||||
using FasdDesktopUi.Config;
|
||||
using FasdDesktopUi.Pages.SearchPage;
|
||||
using FasdDesktopUi.Pages.TicketCompletion;
|
||||
using Newtonsoft.Json;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase;
|
||||
using FasdDesktopUi.Basics.Services.RelationService;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
|
||||
using C4IT.F4SD.SupportCaseProtocoll.Models;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Processors;
|
||||
using F4SD.Gamification;
|
||||
using F4SD.Gamification.Services;
|
||||
|
||||
|
||||
namespace FasdDesktopUi.Basics
|
||||
{
|
||||
@@ -303,6 +304,8 @@ namespace FasdDesktopUi.Basics
|
||||
|
||||
detailsPage?.EndPause();
|
||||
|
||||
ActionConnectorEvents.RaiseCaseClosed(this, new CaseClosedPayload() { ClosedAt = DateTime.UtcNow });
|
||||
|
||||
List<Task> tasks = new List<Task>();
|
||||
tasks.Add(DirectConnectionHelper.DirectConnectionStopAsync());
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
using C4IT.FASD.Base;
|
||||
using F4SD.ActionConnector.Execution;
|
||||
using F4SD.ActionConnector.Models;
|
||||
using F4SD.ActionConnector.Payloads;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
|
||||
using FasdDesktopUi.Basics.Services.SupportCase.Processors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.UiActions.NativeActions
|
||||
{
|
||||
internal static class QuickActionExecutor
|
||||
{
|
||||
private static ISupportCaseProcessor _supportCaseProcessor;
|
||||
|
||||
internal static void SetSupportCaseProcessor(ISupportCaseProcessor supportCaseProcessor)
|
||||
{
|
||||
_supportCaseProcessor = supportCaseProcessor ?? throw new ArgumentNullException(nameof(supportCaseProcessor));
|
||||
}
|
||||
|
||||
internal static async Task<ActionResult> RunAction(QuickActionRequest quickActionRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_supportCaseProcessor is null)
|
||||
return ActionResult.Fail(quickActionRequest.ActionId, "No valid SupportCase processor was found.");
|
||||
|
||||
if (!(quickActionRequest.Context.Payload is CaseClosedPayload payload))
|
||||
return ActionResult.Fail(quickActionRequest.ActionId, $"Payload is not of type '{typeof(CaseClosedPayload)}'. It is of type '{quickActionRequest.Context.Payload.GetType()}'");
|
||||
|
||||
cMenuDataBase menuData = MenuDataFactory.GetByName(quickActionRequest.QuickActionRef, _supportCaseProcessor.SupportCaseDataProviderArtifact.NamedParameterEntries, _supportCaseProcessor.SupportCaseDataProviderArtifact.CaseRelations.Select(r => r.Key));
|
||||
|
||||
// Till there is a clear picture of what object belongs to a case and what doesn't
|
||||
// we do not want to make remote Quick Actions available
|
||||
if (menuData is null || !(menuData.UiAction is cUiLocalQuickAction quickAction))
|
||||
{
|
||||
LogEntry($"'{quickActionRequest.QuickActionRef}' is no valid Local QuickAction and was therefore skipped.", C4IT.Logging.LogLevels.Error);
|
||||
return ActionResult.Skip(quickActionRequest.ActionId);
|
||||
}
|
||||
|
||||
await quickAction.RunUiActionAsync(null, null, false, _supportCaseProcessor.SupportCaseDataProviderArtifact);
|
||||
await quickAction.ProcessActionAsync(CancellationToken.None, GetParameterDictionaryFrom(quickActionRequest.Parameters));
|
||||
|
||||
return ActionResult.Ok(quickActionRequest.ActionId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return ActionResult.Fail(quickActionRequest.ActionId, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<cAdjustableParameter, object> GetParameterDictionaryFrom(IDictionary<string, object> requestParameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
return requestParameters.ToDictionary(p => new cAdjustableParameterString() { ParameterName = p.Key } as cAdjustableParameter, p => p.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return new Dictionary<cAdjustableParameter, object>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.F4SD.SupportCaseProtocoll.Models;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
|
||||
using FasdCockpitBase.Models;
|
||||
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
|
||||
using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor;
|
||||
|
||||
namespace FasdDesktopUi.Basics.UiActions
|
||||
{
|
||||
@@ -139,7 +132,7 @@ namespace FasdDesktopUi.Basics.UiActions
|
||||
catch { }
|
||||
|
||||
StatusMonitor.QuickActionOutputs.Add(_ref.Output);
|
||||
quickActionOutput = QuickActionStatusMonitor.cQuickActionOutput.GetQuickActionOutput(_ref.Output, DataProvider);
|
||||
quickActionOutput = cQuickActionOutput.GetQuickActionOutput(_ref.Output, DataProvider);
|
||||
|
||||
cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(quickActionDemo, DataProvider, true, quickActionOutput, StatusMonitor.MeasureValues);
|
||||
QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(quickActionDemo, copyData);
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdCockpitBase.Models;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.UiActions
|
||||
{
|
||||
@@ -39,7 +32,7 @@ namespace FasdDesktopUi.Basics.UiActions
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<QuickActionStatusMonitor.cQuickActionMeasureValue> GetStatusMonitorMeasureValues(List<cF4sdQuickActionRevision.cMeasure> measures)
|
||||
private List<cQuickActionMeasureValue> GetStatusMonitorMeasureValues(List<cF4sdQuickActionRevision.cMeasure> measures)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
@@ -11,12 +9,11 @@ using C4IT.FASD.Base;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdCockpitBase.Models;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using Newtonsoft.Json;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor;
|
||||
|
||||
namespace FasdDesktopUi.Basics.UiActions
|
||||
{
|
||||
@@ -140,7 +137,7 @@ namespace FasdDesktopUi.Basics.UiActions
|
||||
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.finished });
|
||||
else
|
||||
{
|
||||
StatusMonitor.QuickActionOutputs.Add(ResultRevision.Output);
|
||||
StatusMonitor?.QuickActionOutputs?.Add(ResultRevision.Output);
|
||||
quickActionOutput = cQuickActionOutput.GetQuickActionOutput(ResultRevision.Output, DataProvider);
|
||||
}
|
||||
|
||||
@@ -155,7 +152,7 @@ namespace FasdDesktopUi.Basics.UiActions
|
||||
cMultiLanguageSupport.CurrentLanguage = tempLang;
|
||||
}
|
||||
|
||||
cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues);
|
||||
cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor?.MeasureValues);
|
||||
QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData);
|
||||
|
||||
F4SDProtocoll.Instance.Add(protocollEntry);
|
||||
@@ -195,7 +192,7 @@ namespace FasdDesktopUi.Basics.UiActions
|
||||
cMultiLanguageSupport.CurrentLanguage = tempLang;
|
||||
}
|
||||
|
||||
cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues);
|
||||
cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor?.MeasureValues);
|
||||
QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData);
|
||||
|
||||
F4SDProtocoll.Instance.Add(protocollEntry);
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.F4SD.SupportCaseProtocoll.Models;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdCockpitBase.Models;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor;
|
||||
|
||||
namespace FasdDesktopUi.Basics.UiActions
|
||||
{
|
||||
|
||||
@@ -85,6 +85,9 @@ namespace FasdDesktopUi.Basics.UiActions
|
||||
|
||||
cF4sdStagedSearchResultRelationTaskId gatherRelationTask = await _searchUiProvider.SearchService.LoadRelationsAsync(_searchResults, token);
|
||||
|
||||
if (gatherRelationTask == null)
|
||||
return false;
|
||||
|
||||
HashSet<enumFasdInformationClass> orderedPendingInfoClasses
|
||||
= GetInformationClassOrderedByPriority(gatherRelationTask.PendingInformationClasses, cF4sdIdentityEntry.GetFromSearchResult(_searchResults.FirstOrDefault()?.Type ?? enumF4sdSearchResultClass.Unknown));
|
||||
_searchUiProvider.SetPendingInformationClasses(orderedPendingInfoClasses);
|
||||
|
||||
@@ -6,6 +6,7 @@ using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdCockpitBase.Models;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
@@ -6,6 +6,7 @@ using C4IT.Logging;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdCockpitBase.Models;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using FasdDesktopUi.Basics.UserControls;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
using C4IT.F4SD.DisplayFormatting;
|
||||
using C4IT.F4SD.SupportCaseProtocoll.Models;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.MultiLanguage;
|
||||
using F4SD_AdaptableIcon.Enums;
|
||||
using F4SD.Gamification;
|
||||
using FasdDesktopUi.Basics.Converter;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services.ProtocollService;
|
||||
using FasdDesktopUi.Basics.UiActions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -23,12 +20,12 @@ using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using F4SD.Gamification.Services;
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
|
||||
namespace FasdDesktopUi.Basics.UserControls
|
||||
{
|
||||
public partial class QuickActionStatusMonitor : UserControl, IBlurInvoker
|
||||
{
|
||||
private const string veiledText = "********";
|
||||
private bool secretsAreShown = false;
|
||||
private readonly IRawValueFormatter _rawValueFormatter = new RawValueFormatter();
|
||||
|
||||
@@ -42,503 +39,6 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
set { lock (_currentQuickActionLock) { _currentRunningQuickActionId = value; } }
|
||||
}
|
||||
|
||||
#region Helperclasses QuickAction Output
|
||||
|
||||
public abstract class cQuickActionOutput
|
||||
{
|
||||
protected readonly IRawValueFormatter _rawValueFormatter = new RawValueFormatter();
|
||||
|
||||
public cQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
_rawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
|
||||
_rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
|
||||
ErrorCode = scriptOutput.ErrorCode;
|
||||
ErrorDescription = scriptOutput.ErrorDescription;
|
||||
ResultCode = scriptOutput.ResultCode.GetValueOrDefault();
|
||||
IsError = HasError(scriptOutput);
|
||||
}
|
||||
|
||||
public cSupportCaseDataProvider DataProvider { get; private set; }
|
||||
public enumQuickActionSuccess? ResultCode { get; set; }
|
||||
public int? ErrorCode { get; set; }
|
||||
public string ErrorDescription { get; set; }
|
||||
|
||||
public bool IsError { get; private set; }
|
||||
|
||||
internal static KeyValuePair<string, RawValueType> GetDisplayType(dynamic columnTypeObject)
|
||||
{
|
||||
var output = new KeyValuePair<string, RawValueType>();
|
||||
|
||||
try
|
||||
{
|
||||
var columnType = columnTypeObject.ToObject<dynamic>();
|
||||
string name = string.Empty;
|
||||
RawValueType type = RawValueType.STRING;
|
||||
|
||||
|
||||
if (columnType.Name != null)
|
||||
if (columnType.Name is Newtonsoft.Json.Linq.JValue nameJValue)
|
||||
name = nameJValue.Value.ToString();
|
||||
|
||||
if (columnType.Type != null)
|
||||
if (columnType.Type is Newtonsoft.Json.Linq.JValue typeJValue)
|
||||
if (Enum.TryParse(typeJValue.Value.ToString(), out RawValueType typeJValueType))
|
||||
type = typeJValueType;
|
||||
|
||||
output = new KeyValuePair<string, RawValueType>(name, type);
|
||||
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static cQuickActionOutput GetQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput, cSupportCaseDataProvider dataProvider)
|
||||
{
|
||||
if (scriptOutput == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
if (scriptOutput?.Values == null)
|
||||
{
|
||||
var output = new cQuickActionOutputSingle(scriptOutput) { DataProvider = dataProvider };
|
||||
return output;
|
||||
}
|
||||
else if (scriptOutput.Values is JArray scriptValueJArray)
|
||||
{
|
||||
var scriptValues = scriptValueJArray.ToObject<List<dynamic>>();
|
||||
if (scriptValues != null && scriptValues.Count > 0)
|
||||
{
|
||||
var output = new cQuickActionOutputList(scriptOutput) { DataProvider = dataProvider };
|
||||
|
||||
foreach (var scriptValue in scriptValues)
|
||||
{
|
||||
if (scriptValue is JObject scriptValueJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var scriptValueHelperDictionary = scriptValueJObject.ToObject<Dictionary<string, object>>();
|
||||
output.Values.Add(scriptValueHelperDictionary.ToList());
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
else if (scriptOutput.Values is JObject scriptValueJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var output = new cQuickActionOutputObject(scriptOutput) { DataProvider = dataProvider };
|
||||
return output;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new cQuickActionOutputSingle(scriptOutput) { DataProvider = dataProvider };
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool HasError(cF4sdQuickActionRevision.cOutput quickActionOutput)
|
||||
{
|
||||
if ((quickActionOutput?.ResultCode == null || quickActionOutput?.ResultCode == enumQuickActionSuccess.finished || quickActionOutput?.ResultCode == enumQuickActionSuccess.successfull)
|
||||
&& (quickActionOutput?.ErrorCode == null || quickActionOutput?.ErrorCode == 0)
|
||||
&& string.IsNullOrEmpty(quickActionOutput?.ErrorDescription))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class cQuickActionOutputSingle : cQuickActionOutput
|
||||
{
|
||||
public cQuickActionOutputSingle(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
|
||||
{
|
||||
Instantiate(scriptOutput);
|
||||
}
|
||||
|
||||
|
||||
public RawValueType DisplayType { get; set; }
|
||||
public string Key { get; set; }
|
||||
public object Value { get; set; }
|
||||
|
||||
private void Instantiate(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value = scriptOutput.Values;
|
||||
|
||||
if (scriptOutput.Values is JObject scriptValueJObject)
|
||||
{
|
||||
string scriptValueKey = null;
|
||||
|
||||
try
|
||||
{
|
||||
var scriptValueHelperDictionary = scriptValueJObject.ToObject<Dictionary<string, object>>();
|
||||
scriptValueKey = scriptValueHelperDictionary.Keys.ToList()[0];
|
||||
|
||||
Key = scriptValueKey;
|
||||
Value = scriptValueHelperDictionary[scriptValueKey];
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
if (scriptOutput.ColumnTypes is JArray columnTypeJArray)
|
||||
{
|
||||
var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
|
||||
if (columnTypes != null && columnTypes.Count > 0)
|
||||
{
|
||||
foreach (var columnTypeObject in columnTypes)
|
||||
{
|
||||
var displayType = cQuickActionOutput.GetDisplayType(columnTypeObject);
|
||||
|
||||
if (displayType.Key == scriptValueKey)
|
||||
DisplayType = displayType.Value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (scriptOutput.ColumnTypes is JObject columnTypeJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dispayType = cQuickActionOutput.GetDisplayType(columnTypeJObject);
|
||||
DisplayType = dispayType.Value;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayValue(Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
|
||||
{
|
||||
string output = null;
|
||||
|
||||
try
|
||||
{
|
||||
output = _rawValueFormatter.GetDisplayValue(Value, DisplayType);
|
||||
|
||||
cColumnOutputFormatting outputFormatting = null;
|
||||
|
||||
if (string.IsNullOrEmpty(Key))
|
||||
outputFormatting = columnOutputFormattings?.Values.FirstOrDefault();
|
||||
else
|
||||
columnOutputFormattings?.TryGetValue(Key, out outputFormatting);
|
||||
|
||||
if (outputFormatting != null)
|
||||
{
|
||||
if (outputFormatting.IsSecret && !getSecretValue)
|
||||
return veiledText;
|
||||
|
||||
if (outputFormatting.DisplayType != null)
|
||||
output = _rawValueFormatter.GetDisplayValue(Value, outputFormatting.DisplayType.Value);
|
||||
|
||||
if (outputFormatting.Translation != null)
|
||||
{
|
||||
var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
|
||||
if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
|
||||
{
|
||||
output = translator.DefaultTranslation?.Translation.GetValue() ?? Value.ToString();
|
||||
|
||||
foreach (var translation in translator.Translations)
|
||||
{
|
||||
if (translation.Values.Any(value => value.Equals(Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
|
||||
output = translation.Translation.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public class cQuickActionOutputObject : cQuickActionOutput
|
||||
{
|
||||
public Dictionary<string, RawValueType> DisplayTypes { get; set; } = new Dictionary<string, RawValueType>();
|
||||
public List<KeyValuePair<string, object>> Values { get; set; } = new List<KeyValuePair<string, object>>();
|
||||
|
||||
public cQuickActionOutputObject(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
InstantiateDisplayTypes(scriptOutput);
|
||||
InstantiateValues(scriptOutput);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstantiateDisplayTypes(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JArray columnTypeJArray)
|
||||
{
|
||||
var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
|
||||
if (columnTypes != null && columnTypes.Count > 0)
|
||||
{
|
||||
foreach (var columnTypeObject in columnTypes)
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeObject);
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JObject columnTypeJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeJObject);
|
||||
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstantiateValues(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(scriptOutput.Values is JObject valuesJObject))
|
||||
return;
|
||||
|
||||
if (valuesJObject.Properties() == null)
|
||||
return;
|
||||
|
||||
foreach (var property in valuesJObject.Properties())
|
||||
{
|
||||
Values.Add(new KeyValuePair<string, object>(property.Name, property.Value));
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayValue(int index, Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
|
||||
{
|
||||
string output = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (Values.Count <= index)
|
||||
return null;
|
||||
|
||||
var selectedItem = Values[index];
|
||||
|
||||
RawValueType displayType = RawValueType.STRING;
|
||||
DisplayTypes.TryGetValue(selectedItem.Key, out displayType);
|
||||
output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, displayType);
|
||||
|
||||
if (columnOutputFormattings != null && columnOutputFormattings.TryGetValue(selectedItem.Key, out var outputFormatting))
|
||||
{
|
||||
if (outputFormatting.Hidden)
|
||||
return string.Empty;
|
||||
|
||||
if (outputFormatting.IsSecret && !getSecretValue)
|
||||
return veiledText;
|
||||
|
||||
if (outputFormatting.DisplayType != null)
|
||||
output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, outputFormatting.DisplayType.Value);
|
||||
|
||||
if (outputFormatting.Translation != null)
|
||||
{
|
||||
var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
|
||||
if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
|
||||
{
|
||||
output = translator.DefaultTranslation?.Translation.GetValue() ?? selectedItem.Value.ToString();
|
||||
|
||||
foreach (var translation in translator.Translations)
|
||||
{
|
||||
if (translation.Values.Any(value => value.Equals(selectedItem.Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
|
||||
output = translation.Translation.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public class cQuickActionOutputList : cQuickActionOutput
|
||||
{
|
||||
public cQuickActionOutputList(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
|
||||
{
|
||||
InstantiateDisplayTypes(scriptOutput);
|
||||
}
|
||||
|
||||
public Dictionary<string, RawValueType> DisplayTypes { get; set; } = new Dictionary<string, RawValueType>();
|
||||
public List<List<KeyValuePair<string, object>>> Values { get; set; } = new List<List<KeyValuePair<string, object>>>();
|
||||
|
||||
private void InstantiateDisplayTypes(cF4sdQuickActionRevision.cOutput scriptOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JArray columnTypeJArray)
|
||||
{
|
||||
var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
|
||||
if (columnTypes != null && columnTypes.Count > 0)
|
||||
{
|
||||
foreach (var columnTypeObject in columnTypes)
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeObject);
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JObject columnTypeJObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var displayType = GetDisplayType(columnTypeJObject);
|
||||
|
||||
DisplayTypes[displayType.Key] = displayType.Value;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayValue(int row, int column, Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
|
||||
{
|
||||
string output = null;
|
||||
|
||||
try
|
||||
{
|
||||
RawValueType displayType = RawValueType.STRING;
|
||||
DisplayTypes.TryGetValue(Values[row][column].Key, out displayType);
|
||||
output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, displayType);
|
||||
|
||||
if (columnOutputFormattings != null && columnOutputFormattings.TryGetValue(Values[row][column].Key, out var outputFormatting))
|
||||
{
|
||||
if (outputFormatting.Hidden)
|
||||
return string.Empty;
|
||||
|
||||
if (outputFormatting.IsSecret && !getSecretValue)
|
||||
return veiledText;
|
||||
|
||||
if (outputFormatting.DisplayType != null)
|
||||
output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, outputFormatting.DisplayType.Value);
|
||||
|
||||
if (outputFormatting.Translation != null)
|
||||
{
|
||||
var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
|
||||
if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
|
||||
{
|
||||
output = translator.DefaultTranslation?.Translation.GetValue() ?? Values[row].ToList()[column].Value.ToString();
|
||||
|
||||
foreach (var translation in translator.Translations)
|
||||
{
|
||||
if (translation.Values.Any(value => value.Equals(Values[row].ToList()[column].Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
|
||||
output = translation.Translation.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public class cQuickActionMeasureValue
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public cMultiLanguageDictionary Names { get; set; }
|
||||
public object Value { get; set; }
|
||||
public object PostValue { get; set; }
|
||||
|
||||
public object Difference
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Display)
|
||||
{
|
||||
case RawValueType.INTEGER:
|
||||
case RawValueType.PERCENT:
|
||||
case RawValueType.PERCENT100:
|
||||
case RawValueType.PERCENT1000:
|
||||
case RawValueType.BYTES:
|
||||
var valueDouble = cF4SDHealthCardRawData.GetDouble(Value);
|
||||
var postValueDouble = cF4SDHealthCardRawData.GetDouble(PostValue);
|
||||
|
||||
if (valueDouble != null && postValueDouble != null)
|
||||
return postValueDouble - valueDouble;
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public RawValueType Display { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
private CancellationTokenSource tokenSource;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using C4IT.FASD.Base;
|
||||
|
||||
using FasdDesktopUi.Basics.Models.QuickActionOutput;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -38,52 +38,26 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<DockPanel>
|
||||
|
||||
<!--<DockPanel.Resources>
|
||||
<Style TargetType="ico:AdaptableIcon">
|
||||
<Setter Property="IconWidth"
|
||||
Value="20" />
|
||||
<Setter Property="IconHeight"
|
||||
Value="20" />
|
||||
<Setter Property="BorderPadding"
|
||||
Value="5" />
|
||||
<Setter Property="IconBackgroundColor"
|
||||
Value="Transparent" />
|
||||
<Setter Property="Margin"
|
||||
Value="0, 0, 10, 0" />
|
||||
<Setter Property="PrimaryIconColor"
|
||||
Value="{DynamicResource Color.Menu.Icon}" />
|
||||
<Setter Property="Cursor"
|
||||
Value="Hand" />
|
||||
<Setter Property="WindowChrome.IsHitTestVisibleInChrome"
|
||||
Value="True" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver"
|
||||
Value="True">
|
||||
<Setter Property="PrimaryIconColor"
|
||||
Value="{DynamicResource Color.Menu.Icon.Hover}" />
|
||||
<Setter Property="IconBackgroundColor"
|
||||
Value="{DynamicResource Background.Menu.Icon.Hover}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
|
||||
</Style>
|
||||
</DockPanel.Resources>-->
|
||||
|
||||
<ico:AdaptableIcon x:Name="CloseNotepadIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="CloseNotepadIcon"
|
||||
x:FieldModifier="private"
|
||||
DockPanel.Dock="Right"
|
||||
SelectedInternIcon="window_minimize"
|
||||
Style="{DynamicResource SettingsPage.Close.Icon}"
|
||||
WindowChrome.IsHitTestVisibleInChrome="True"
|
||||
Margin="0 8 0 0"
|
||||
Tag="close" MouseUp="CloseNotepadIcon_MouseUp" TouchDown="CloseNotepadIcon_TouchDown"/>
|
||||
Tag="close"
|
||||
MouseLeftButtonUp="CloseNotepadIcon_Click"
|
||||
TouchDown="CloseNotepadIcon_Click" />
|
||||
|
||||
<ico:AdaptableIcon x:Name="LockNotepadIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="LockNotepadIcon"
|
||||
x:FieldModifier="private"
|
||||
DockPanel.Dock="Right"
|
||||
Style="{DynamicResource Menu.Notepad.Icon.Lock}"
|
||||
MouseLeave="LockNotepadIcon_MouseLeave"
|
||||
WindowChrome.IsHitTestVisibleInChrome="True"
|
||||
Tag="lock" MouseUp="LockNotepadIcon_MouseUp" TouchDown="LockNotepadIcon_TouchDown"/>
|
||||
Tag="lock"
|
||||
MouseLeftButtonUp="LockNotepadIcon_Click"
|
||||
TouchDown="LockNotepadIcon_Click" />
|
||||
|
||||
<ico:AdaptableIcon DockPanel.Dock="Left"
|
||||
VerticalAlignment="Center"
|
||||
@@ -116,42 +90,50 @@
|
||||
CornerRadius="7.5">
|
||||
<DockPanel>
|
||||
|
||||
<ico:AdaptableIcon x:Name="ToggleDockButton" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="ToggleDockButton"
|
||||
x:FieldModifier="private"
|
||||
DockPanel.Dock="Right"
|
||||
SelectedMaterialIcon="ic_zoom_out_map"
|
||||
MouseLeftButtonUp="ToggleDockButton_MouseLeftButtonUp"
|
||||
TouchDown="ToggleDockButton_TouchDown" />
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ico:AdaptableIcon x:Name="UndoIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="UndoIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_undo"
|
||||
Command="ApplicationCommands.Undo"
|
||||
Style="{DynamicResource Menu.MenuBar.PinnedIcon.Disabled}" />
|
||||
<ico:AdaptableIcon x:Name="RedoIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="RedoIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_redo"
|
||||
Command="ApplicationCommands.Redo"
|
||||
Style="{DynamicResource Menu.MenuBar.PinnedIcon.Disabled}" />
|
||||
<ico:AdaptableIcon x:Name="CopyIcon"
|
||||
SelectedInternIcon="menuBar_copy"
|
||||
TouchDown="CopyIcon_TouchDown"
|
||||
MouseLeftButtonUp="CopyIcon_MouseLeftButtonUp" />
|
||||
<ico:AdaptableIcon x:Name="BoldIcon" x:FieldModifier="private"
|
||||
TouchDown="CopyIcon_Click"
|
||||
MouseLeftButtonUp="CopyIcon_Click" />
|
||||
<ico:AdaptableIcon x:Name="BoldIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_format_bold"
|
||||
Command="EditingCommands.ToggleBold"
|
||||
MouseLeftButtonUp="TextBoxIcon_MouseLeftButtonUp" />
|
||||
<ico:AdaptableIcon x:Name="ItalicIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="ItalicIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_format_italic"
|
||||
Command="EditingCommands.ToggleItalic"
|
||||
MouseLeftButtonUp="TextBoxIcon_MouseLeftButtonUp" />
|
||||
<ico:AdaptableIcon x:Name="UnderlineIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="UnderlineIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_format_underlined"
|
||||
Command="EditingCommands.ToggleUnderline"
|
||||
MouseLeftButtonUp="TextBoxIcon_MouseLeftButtonUp" />
|
||||
<ico:AdaptableIcon x:Name="BulletsIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="BulletsIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_format_list_bulleted"
|
||||
Command="EditingCommands.ToggleBullets"
|
||||
MouseLeftButtonUp="TextBoxIcon_MouseLeftButtonUp" />
|
||||
<ico:AdaptableIcon x:Name="NumberingIcon" x:FieldModifier="private"
|
||||
<ico:AdaptableIcon x:Name="NumberingIcon"
|
||||
x:FieldModifier="private"
|
||||
SelectedMaterialIcon="ic_format_list_numbered"
|
||||
Command="EditingCommands.ToggleNumbering"
|
||||
MouseLeftButtonUp="TextBoxIcon_MouseLeftButtonUp" />
|
||||
@@ -161,7 +143,8 @@
|
||||
</Border>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<RichTextBox x:Name="NotepadRichTextBox" x:FieldModifier="private"
|
||||
<RichTextBox x:Name="NotepadRichTextBox"
|
||||
x:FieldModifier="private"
|
||||
VerticalAlignment="Stretch"
|
||||
Padding="2.5 5"
|
||||
TextChanged="NotepadRichTextBox_TextChanged"
|
||||
@@ -169,8 +152,7 @@
|
||||
Background="{DynamicResource BackgroundColor.DetailsPage.Widget.Title}"
|
||||
SpellCheck.IsEnabled="True"
|
||||
SelectionChanged="NotepadRichTextBox_SelectionChanged"
|
||||
IsVisibleChanged="NotepadRichTextBox_IsVisibleChanged"
|
||||
GotKeyboardFocus="NotepadRichTextBox_GotKeyboardFocus">
|
||||
IsVisibleChanged="NotepadRichTextBox_IsVisibleChanged">
|
||||
<RichTextBox.Resources>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="CornerRadius"
|
||||
|
||||
@@ -42,21 +42,7 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
#region DataProvider
|
||||
|
||||
private cSupportCaseDataProvider DataProvider;
|
||||
|
||||
/*
|
||||
{
|
||||
get { return (cDataProviderBase)GetValue(DataProviderProperty); }
|
||||
set {
|
||||
SetValue(DataProviderProperty, value);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
private static readonly DependencyProperty DataProviderProperty =
|
||||
DependencyProperty.Register("DataProvider", typeof(cDataProviderBase), typeof(Notepad), new PropertyMetadata(null));
|
||||
*/
|
||||
private readonly cSupportCaseDataProvider _dataProvider;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -102,24 +88,18 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
private static void HandleLockedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
if (!(d is Notepad _me))
|
||||
{
|
||||
if (!(d is Notepad notepad))
|
||||
return;
|
||||
}
|
||||
|
||||
_me.LockNotepadIcon.SelectedInternIcon = _me.IsLocked ? F4SD_AdaptableIcon.Enums.enumInternIcons.lock_closed : F4SD_AdaptableIcon.Enums.enumInternIcons.lock_open;
|
||||
|
||||
_me.CloseNotepadIcon.IsEnabled = _me.IsLocked ? false : true;
|
||||
|
||||
notepad.LockNotepadIcon.SelectedInternIcon = notepad.IsLocked ? enumInternIcons.lock_closed : enumInternIcons.lock_open;
|
||||
notepad.CloseNotepadIcon.IsEnabled = !notepad.IsLocked;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -165,7 +145,7 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
public Notepad(cSupportCaseDataProvider dataProvider)
|
||||
{
|
||||
DataProvider = dataProvider;
|
||||
_dataProvider = dataProvider;
|
||||
InitializeComponent();
|
||||
saveTimer = new DispatcherTimer(TimeSpan.FromSeconds(0.75), DispatcherPriority.Render, SaveNotes, Dispatcher.CurrentDispatcher);
|
||||
IsLocked = cFasdCockpitConfig.Instance.IsNotepadVisibleDocked;
|
||||
@@ -175,29 +155,6 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
#region Methods
|
||||
|
||||
|
||||
private void NotepadRichTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DataProvider is null)
|
||||
return;
|
||||
|
||||
if (DataProvider?.CaseNotes?.Parent is RichTextBox parentBox)
|
||||
parentBox.Document = new FlowDocument();
|
||||
|
||||
if (!(sender is RichTextBox senderElement))
|
||||
return;
|
||||
|
||||
senderElement.Document = DataProvider.CaseNotes;
|
||||
senderElement.CaretPosition = senderElement.CaretPosition.DocumentEnd;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
}
|
||||
|
||||
private async void NotepadRichTextBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -205,11 +162,15 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
if (!(e.NewValue is bool isVisible && isVisible))
|
||||
return;
|
||||
|
||||
await Task.Delay(50);
|
||||
NotepadRichTextBox.Focus();
|
||||
Keyboard.Focus(NotepadRichTextBox);
|
||||
if (!(sender is RichTextBox senderElement))
|
||||
return;
|
||||
|
||||
NotepadRichTextBox_GotKeyboardFocus(sender, null);
|
||||
senderElement.Document = _dataProvider.CaseNotes;
|
||||
senderElement.CaretPosition = senderElement.CaretPosition.DocumentEnd;
|
||||
|
||||
await Task.Delay(50);
|
||||
senderElement.Focus();
|
||||
Keyboard.Focus(senderElement);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
@@ -221,7 +182,7 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
#region CopyIcon Click
|
||||
|
||||
private async void CopyIcon_Click(object sender)
|
||||
private async void CopyIcon_Click(object sender, InputEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -254,16 +215,6 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyIcon_TouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
CopyIcon_Click(sender);
|
||||
}
|
||||
|
||||
private void CopyIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
CopyIcon_Click(sender);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Popout
|
||||
@@ -308,13 +259,13 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
{
|
||||
saveTimer?.Stop();
|
||||
|
||||
if (DataProvider is null)
|
||||
if (_dataProvider is null)
|
||||
return;
|
||||
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
SetLanguageOfDocument();
|
||||
DataProvider.SaveCaseNotes();
|
||||
_dataProvider.SaveCaseNotes();
|
||||
});
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -642,7 +593,7 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
{
|
||||
ToggleDockButton.Visibility = IsUndocked ? Visibility.Collapsed : Visibility.Visible;
|
||||
LockNotepadIcon.Visibility = IsUndocked ? Visibility.Collapsed : Visibility.Visible;
|
||||
CloseNotepadIcon.IsEnabled = IsUndocked ? true : !IsLocked;
|
||||
CloseNotepadIcon.IsEnabled = IsUndocked || !IsLocked;
|
||||
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -680,23 +631,12 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseNotepadIcon_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
private void CloseNotepadIcon_TouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
CloseNotepad();
|
||||
}
|
||||
private void CloseNotepadIcon_Click(object sender, InputEventArgs e) => CloseNotepad();
|
||||
|
||||
private void LockNotepad()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (IsLocked)
|
||||
{
|
||||
LockNotepadIcon.SetResourceReference(AdaptableIcon.AdaptableIcon.PrimaryIconColorProperty, "Color.SoftContrast");
|
||||
@@ -717,19 +657,9 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void LockNotepadIcon_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
LockNotepad();
|
||||
}
|
||||
|
||||
private void LockNotepadIcon_TouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
LockNotepad();
|
||||
}
|
||||
private void LockNotepadIcon_Click(object sender, InputEventArgs e) => LockNotepad();
|
||||
|
||||
private void LockNotepadIcon_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
|
||||
@@ -78,14 +78,15 @@
|
||||
<local:SearchBar x:Name="Search"
|
||||
DockPanel.Dock="Top"
|
||||
PlaceholderText="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=Searchbar.Placeholder}"
|
||||
ShowCloseButton="False"
|
||||
ShowCloseButton="True"
|
||||
SearchButtonSize="26"
|
||||
DebounceInterval="0"
|
||||
SearchBackground="{DynamicResource BackgroundColor.DetailsPage.Widget.Title}"
|
||||
SearchValueChanged="SearchBar_SearchValueChanged"
|
||||
Margin="0 0 0 10"
|
||||
Focusable="True"
|
||||
Height="26" />
|
||||
Height="26"
|
||||
CancelledSearch="Search_CancelledSearch" />
|
||||
|
||||
<local:CustomMenu x:Name="SubMenuUc"
|
||||
DockPanel.Dock="Top"
|
||||
|
||||
@@ -238,5 +238,12 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
private void SearchBar_SearchValueChanged(object sender, string e)
|
||||
=> SearchValueChanged?.Invoke(this, e);
|
||||
|
||||
#region ClearSearch
|
||||
private void Search_CancelledSearch(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Search.Clear();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Timers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
@@ -9,7 +10,7 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
{
|
||||
public partial class SearchBar : UserControl
|
||||
{
|
||||
private readonly DispatcherTimer _searchTimer = new DispatcherTimer();
|
||||
private readonly Timer _searchTimer = new Timer();
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
@@ -70,7 +71,8 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
private static void OnDebounceIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((SearchBar)d)._searchTimer.Interval = (TimeSpan)e.NewValue;
|
||||
TimeSpan interval = (TimeSpan)e.NewValue;
|
||||
((SearchBar)d)._searchTimer.Interval = Math.Max(interval.TotalMilliseconds, 10);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsInputEnabledProperty =
|
||||
@@ -158,7 +160,7 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
private void HandleSearchValueChanged()
|
||||
{
|
||||
if (_searchTimer.IsEnabled)
|
||||
if (_searchTimer.Enabled)
|
||||
_searchTimer.Stop();
|
||||
|
||||
_searchTimer.Start();
|
||||
@@ -183,8 +185,8 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
private void SearchBar_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_searchTimer.Stop();
|
||||
_searchTimer.Interval = DebounceInterval;
|
||||
_searchTimer.Tick += SearchTimerTick;
|
||||
_searchTimer.Interval = Math.Max(DebounceInterval.TotalMilliseconds, 10);
|
||||
_searchTimer.Elapsed += SearchTimerTick;
|
||||
BackgroundBorder.CornerRadius = new CornerRadius(BackgroundBorder.ActualHeight / 2.0);
|
||||
}
|
||||
|
||||
|
||||
@@ -422,9 +422,28 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
foreach (var informationClass in informationClasses.Reverse())
|
||||
{
|
||||
string _title = string.Empty;
|
||||
switch (informationClass)
|
||||
{
|
||||
case enumFasdInformationClass.Computer:
|
||||
_title = "Searchbar.Relations.SearchFor.Computer";
|
||||
break;
|
||||
case enumFasdInformationClass.User:
|
||||
_title = "Searchbar.Relations.SearchFor.User";
|
||||
break;
|
||||
case enumFasdInformationClass.Ticket:
|
||||
_title = "Searchbar.Relations.SearchFor.Ticket";
|
||||
break;
|
||||
case enumFasdInformationClass.VirtualSession:
|
||||
_title = "Searchbar.Relations.SearchFor.VirtualSession";
|
||||
break;
|
||||
}
|
||||
if (string.IsNullOrEmpty(_title))
|
||||
continue;
|
||||
|
||||
var searchResultCategory = new SearchResultCategory()
|
||||
{
|
||||
Title = string.Format(cMultiLanguageSupport.GetItem("Searchbar.Relations.SearchFor"), informationClass),
|
||||
Title = cMultiLanguageSupport.GetItem(_title),
|
||||
IsPending = true,
|
||||
TitleIcon = GetIconFrom(informationClass),
|
||||
Margin = new Thickness(0, 7.5, 0, 0)
|
||||
|
||||
@@ -104,6 +104,13 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
public bool AreCaseNotesMandatory =>
|
||||
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.NotesMandatory ?? false;
|
||||
|
||||
private bool UseSimplifiedCaseCompletionDialog =>
|
||||
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.UseSimplifiedCaseCompletionDialog == true;
|
||||
|
||||
private enumTicketExternalOpenMode SimplifiedCaseCompletionTicketOpenMode =>
|
||||
cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.SimplifiedCaseCompletionTicketOpenMode
|
||||
?? enumTicketExternalOpenMode.Preview;
|
||||
|
||||
private static class TicketInfoKeys
|
||||
{
|
||||
public const string ActivityType = "ActivityType";
|
||||
@@ -531,6 +538,8 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
|
||||
private void CloseCaseDialogWithTicket_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateTicketComponentVisibility();
|
||||
|
||||
Window _parentWindow = Window.GetWindow(this);
|
||||
|
||||
if (!(_parentWindow is TicketCompletion _msgBox))
|
||||
@@ -623,10 +632,17 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
return;
|
||||
|
||||
var _isVisible = checkTicketActive() && !_skipTicketPillSelected;
|
||||
var useSimplifiedDialog = _isVisible && UseSimplifiedCaseCompletionDialog;
|
||||
|
||||
if (useSimplifiedDialog)
|
||||
SelectSaveTicketAction();
|
||||
|
||||
TicketSelectionCategory.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||
StatusSelectionBorder.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||
StatusSelectionBorder.Visibility = _isVisible && !useSimplifiedDialog ? Visibility.Visible : Visibility.Collapsed;
|
||||
CopyDisclaimerTextBox.Visibility = _isVisible ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
if (!_isVisible || useSimplifiedDialog)
|
||||
DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
@@ -634,6 +650,21 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectSaveTicketAction()
|
||||
{
|
||||
var saveItem = TicketStatusCombobox.Items
|
||||
.OfType<ComboBoxItem>()
|
||||
.FirstOrDefault(item =>
|
||||
Enum.TryParse(item.Tag?.ToString(), out enumCloseCaseTicketStatus action) &&
|
||||
action == enumCloseCaseTicketStatus.Save);
|
||||
|
||||
if (saveItem != null && !ReferenceEquals(TicketStatusCombobox.SelectedItem, saveItem))
|
||||
TicketStatusCombobox.SelectedItem = saveItem;
|
||||
|
||||
DynamicStatusAdditionBorder.Child = null;
|
||||
DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private UIElement GetTicketUiElement(cF4sdApiSearchResultRelation ticketRelation)
|
||||
{
|
||||
try
|
||||
@@ -2011,7 +2042,20 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
ticketData.AdditionalValues.Add("Dialog.CloseCase.AssetNotFoundInMatrix42", cMultiLanguageSupport.GetItem("Dialog.CloseCase.AssetNotFoundInMatrix42"));
|
||||
ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonText", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonText"));
|
||||
ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonTextHtml", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonTextHtml"));
|
||||
var _res = await cFasdCockpitCommunicationBase.Instance.Matrix42TicketFinalization(ticketData);
|
||||
var finalizationResult = await cFasdCockpitCommunicationBase.Instance.FinalizeTicketAsync(ticketData);
|
||||
if (finalizationResult?.Success != true)
|
||||
return false;
|
||||
|
||||
if (UseSimplifiedCaseCompletionDialog &&
|
||||
SimplifiedCaseCompletionTicketOpenMode != enumTicketExternalOpenMode.None &&
|
||||
finalizationResult.TicketId is Guid finalizedTicketId &&
|
||||
finalizedTicketId != Guid.Empty)
|
||||
{
|
||||
await TicketExternalLinkHelper.TryOpenFinalizedTicketExternallyAsync(
|
||||
finalizedTicketId,
|
||||
SimplifiedCaseCompletionTicketOpenMode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -15,6 +15,44 @@
|
||||
<UserControl.Resources>
|
||||
<vc:LanguageDefinitionsConverter x:Key="LanguageConverter" />
|
||||
|
||||
<Style x:Key="TicketOverviewRowHeadingStyle"
|
||||
TargetType="Label">
|
||||
<Setter Property="HorizontalContentAlignment"
|
||||
Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment"
|
||||
Value="Center" />
|
||||
<EventSetter Event="MouseEnter"
|
||||
Handler="RowHeading_MouseEnter" />
|
||||
<EventSetter Event="MouseLeave"
|
||||
Handler="RowHeading_MouseLeave" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Label">
|
||||
<!-- Padding stays outside the ticker viewport so the animation uses the actual visible text width.
|
||||
The small right-side reserve prevents marginal overflows from triggering the marquee. -->
|
||||
<Border Background="Transparent"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<Border x:Name="PART_TickerContainer"
|
||||
Background="Transparent"
|
||||
ClipToBounds="True"
|
||||
Margin="0,0,-2,0">
|
||||
<TextBlock x:Name="PART_TickerText"
|
||||
Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
FontFamily="{TemplateBinding FontFamily}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontStretch="{TemplateBinding FontStretch}"
|
||||
FontStyle="{TemplateBinding FontStyle}"
|
||||
FontWeight="{TemplateBinding FontWeight}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
VerticalAlignment="Center" />
|
||||
</Border>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Style für Labels mit Auswahlzustand -->
|
||||
<Style x:Key="RoundedSelectedLabelStyle"
|
||||
TargetType="Label">
|
||||
@@ -82,8 +120,11 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition x:Name="TicketsRow"
|
||||
Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition x:Name="ServiceRequestsRow"
|
||||
Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -128,6 +169,7 @@
|
||||
<!-- Tickets -->
|
||||
<Label Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource TicketOverviewRowHeadingStyle}"
|
||||
Foreground="{DynamicResource FontColor.DetailsPage.TitleSection.Header}"
|
||||
Content="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=TicketOverview.Row.Heading.Tickets}"
|
||||
FontWeight="Bold"
|
||||
@@ -200,6 +242,7 @@
|
||||
<!-- Incidents -->
|
||||
<Label Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource TicketOverviewRowHeadingStyle}"
|
||||
Foreground="{DynamicResource FontColor.DetailsPage.TitleSection.Header}"
|
||||
Content="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=TicketOverview.Row.Heading.Incidents}"
|
||||
FontWeight="Bold"
|
||||
@@ -269,15 +312,89 @@
|
||||
HorizontalAlignment="Center"
|
||||
Cursor="Hand" />
|
||||
|
||||
<!-- Unassigned -->
|
||||
<!-- Service Requests -->
|
||||
<Label Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource TicketOverviewRowHeadingStyle}"
|
||||
Foreground="{DynamicResource FontColor.DetailsPage.TitleSection.Header}"
|
||||
Content="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=TicketOverview.Row.Heading.ServiceRequests}"
|
||||
FontWeight="Bold"
|
||||
FontSize="12" />
|
||||
|
||||
<Label Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Content="{Binding ServiceRequestsNew}"
|
||||
Style="{StaticResource RoundedSelectedLabelStyle}"
|
||||
local:TicketOverview.IsSelected="{Binding ServiceRequestsNewSelected, Mode=TwoWay}"
|
||||
local:TicketOverview.IsHighlighted="{Binding ServiceRequestsNewHighlighted}"
|
||||
ToolTip="{Binding ServiceRequestsNewChangeHint}"
|
||||
Tag="ServiceRequestsNewSelected"
|
||||
MouseLeftButtonUp="Label_MouseLeftButtonUp"
|
||||
FontWeight="Medium"
|
||||
Foreground="{DynamicResource Color.Green}"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Cursor="Hand" />
|
||||
|
||||
<Label Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Content="{Binding ServiceRequestsActive}"
|
||||
Style="{StaticResource RoundedSelectedLabelStyle}"
|
||||
local:TicketOverview.IsSelected="{Binding ServiceRequestsActiveSelected, Mode=TwoWay}"
|
||||
local:TicketOverview.IsHighlighted="{Binding ServiceRequestsActiveHighlighted}"
|
||||
ToolTip="{Binding ServiceRequestsActiveChangeHint}"
|
||||
Tag="ServiceRequestsActiveSelected"
|
||||
MouseLeftButtonUp="Label_MouseLeftButtonUp"
|
||||
FontWeight="Medium"
|
||||
Foreground="{DynamicResource Color.Green}"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Cursor="Hand" />
|
||||
|
||||
<Label Grid.Row="4"
|
||||
Grid.Column="3"
|
||||
Content="{Binding ServiceRequestsCritical}"
|
||||
Style="{StaticResource RoundedSelectedLabelStyle}"
|
||||
local:TicketOverview.IsSelected="{Binding ServiceRequestsCriticalSelected, Mode=TwoWay}"
|
||||
local:TicketOverview.IsHighlighted="{Binding ServiceRequestsCriticalHighlighted}"
|
||||
ToolTip="{Binding ServiceRequestsCriticalChangeHint}"
|
||||
Tag="ServiceRequestsCriticalSelected"
|
||||
MouseLeftButtonUp="Label_MouseLeftButtonUp"
|
||||
FontWeight="Medium"
|
||||
Foreground="{DynamicResource Color.Red}"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Cursor="Hand" />
|
||||
|
||||
<Label Grid.Row="4"
|
||||
Grid.Column="4"
|
||||
Content="{Binding ServiceRequestsNewInfo}"
|
||||
Style="{StaticResource RoundedSelectedLabelStyle}"
|
||||
local:TicketOverview.IsSelected="{Binding ServiceRequestsNewInfoSelected, Mode=TwoWay}"
|
||||
local:TicketOverview.IsHighlighted="{Binding ServiceRequestsNewInfoHighlighted}"
|
||||
ToolTip="{Binding ServiceRequestsNewInfoChangeHint}"
|
||||
Tag="ServiceRequestsNewInfoSelected"
|
||||
MouseLeftButtonUp="Label_MouseLeftButtonUp"
|
||||
FontWeight="Medium"
|
||||
Foreground="{DynamicResource Color.Orange}"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Cursor="Hand" />
|
||||
|
||||
<!-- Unassigned -->
|
||||
<Label Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource TicketOverviewRowHeadingStyle}"
|
||||
Foreground="{DynamicResource FontColor.DetailsPage.TitleSection.Header}"
|
||||
Content="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=TicketOverview.Row.Heading.UnassignedTickets}"
|
||||
FontWeight="Bold"
|
||||
FontSize="12" />
|
||||
|
||||
<Label Grid.Row="4"
|
||||
<Label Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Content="{Binding UnassignedTickets}"
|
||||
Style="{StaticResource RoundedSelectedLabelStyle}"
|
||||
@@ -293,7 +410,7 @@
|
||||
HorizontalAlignment="Center"
|
||||
Cursor="Hand" />
|
||||
|
||||
<Label Grid.Row="4"
|
||||
<Label Grid.Row="5"
|
||||
Grid.Column="3"
|
||||
Content="{Binding UnassignedTicketsCritical}"
|
||||
Style="{StaticResource RoundedSelectedLabelStyle}"
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Windows.Threading;
|
||||
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using C4IT.Logging;
|
||||
using FasdDesktopUi.Basics;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services;
|
||||
using FasdDesktopUi.Basics.Services.Models;
|
||||
@@ -31,6 +32,10 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
("IncidentActive", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentActive = value; })),
|
||||
("IncidentCritical", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentCritical = value; })),
|
||||
("IncidentNewInfo", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentNewInfo = value; })),
|
||||
("ServiceRequestsNew", new Action<TicketOverviewModel, int>((vm, value) => { vm.ServiceRequestsNew = value; })),
|
||||
("ServiceRequestsActive", new Action<TicketOverviewModel, int>((vm, value) => { vm.ServiceRequestsActive = value; })),
|
||||
("ServiceRequestsCritical", new Action<TicketOverviewModel, int>((vm, value) => { vm.ServiceRequestsCritical = value; })),
|
||||
("ServiceRequestsNewInfo", new Action<TicketOverviewModel, int>((vm, value) => { vm.ServiceRequestsNewInfo = value; })),
|
||||
("UnassignedTickets", new Action<TicketOverviewModel, int>((vm, value) => { vm.UnassignedTickets = value; })),
|
||||
("UnassignedTicketsCritical", new Action<TicketOverviewModel, int>((vm, value) => { vm.UnassignedTicketsCritical = value; }))
|
||||
};
|
||||
@@ -44,6 +49,10 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
("IncidentActive", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentActiveHighlighted = value; })),
|
||||
("IncidentCritical", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentCriticalHighlighted = value; })),
|
||||
("IncidentNewInfo", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentNewInfoHighlighted = value; })),
|
||||
("ServiceRequestsNew", new Action<TicketOverviewModel, bool>((vm, value) => { vm.ServiceRequestsNewHighlighted = value; })),
|
||||
("ServiceRequestsActive", new Action<TicketOverviewModel, bool>((vm, value) => { vm.ServiceRequestsActiveHighlighted = value; })),
|
||||
("ServiceRequestsCritical", new Action<TicketOverviewModel, bool>((vm, value) => { vm.ServiceRequestsCriticalHighlighted = value; })),
|
||||
("ServiceRequestsNewInfo", new Action<TicketOverviewModel, bool>((vm, value) => { vm.ServiceRequestsNewInfoHighlighted = value; })),
|
||||
("UnassignedTickets", new Action<TicketOverviewModel, bool>((vm, value) => { vm.UnassignedTicketsHighlighted = value; })),
|
||||
("UnassignedTicketsCritical", new Action<TicketOverviewModel, bool>((vm, value) => { vm.UnassignedTicketsCriticalHighlighted = value; }))
|
||||
};
|
||||
@@ -57,6 +66,10 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
("IncidentActive", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentActiveChangeHint = value; })),
|
||||
("IncidentCritical", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentCriticalChangeHint = value; })),
|
||||
("IncidentNewInfo", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentNewInfoChangeHint = value; })),
|
||||
("ServiceRequestsNew", new Action<TicketOverviewModel, string>((vm, value) => { vm.ServiceRequestsNewChangeHint = value; })),
|
||||
("ServiceRequestsActive", new Action<TicketOverviewModel, string>((vm, value) => { vm.ServiceRequestsActiveChangeHint = value; })),
|
||||
("ServiceRequestsCritical", new Action<TicketOverviewModel, string>((vm, value) => { vm.ServiceRequestsCriticalChangeHint = value; })),
|
||||
("ServiceRequestsNewInfo", new Action<TicketOverviewModel, string>((vm, value) => { vm.ServiceRequestsNewInfoChangeHint = value; })),
|
||||
("UnassignedTickets", new Action<TicketOverviewModel, string>((vm, value) => { vm.UnassignedTicketsChangeHint = value; })),
|
||||
("UnassignedTicketsCritical", new Action<TicketOverviewModel, string>((vm, value) => { vm.UnassignedTicketsCriticalChangeHint = value; }))
|
||||
};
|
||||
@@ -175,6 +188,41 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Row Heading Ticker
|
||||
|
||||
private void RowHeading_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!TryGetRowHeadingTickerParts(sender, out var textBlock, out var container))
|
||||
return;
|
||||
|
||||
cUtility.SetTickerTextAnimation(textBlock, container);
|
||||
}
|
||||
|
||||
private void RowHeading_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!TryGetRowHeadingTickerParts(sender, out var textBlock, out var container))
|
||||
return;
|
||||
|
||||
textBlock.TextTrimming = TextTrimming.CharacterEllipsis;
|
||||
textBlock.BeginAnimation(MarginProperty, null);
|
||||
container.ClearValue(WidthProperty);
|
||||
}
|
||||
|
||||
private static bool TryGetRowHeadingTickerParts(object sender, out TextBlock textBlock, out Border container)
|
||||
{
|
||||
textBlock = null;
|
||||
container = null;
|
||||
|
||||
if (!(sender is Label label) || label.Template == null)
|
||||
return false;
|
||||
|
||||
textBlock = label.Template.FindName("PART_TickerText", label) as TextBlock;
|
||||
container = label.Template.FindName("PART_TickerContainer", label) as Border;
|
||||
return textBlock != null && container != null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
private async void TicketOverview_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -225,6 +273,15 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
if (DataContext is TicketOverviewModel vm)
|
||||
vm.ResetSelection();
|
||||
}
|
||||
|
||||
public void SetTicketAndServiceRequestsVisibility(bool isVisible)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
TicketsRow.Height = isVisible ? GridLength.Auto : new GridLength(0);
|
||||
ServiceRequestsRow.Height = isVisible ? GridLength.Auto : new GridLength(0);
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// Prüft welche Daten für die Ansicht geladen werden sollen
|
||||
/// Wenn UseRoledTickets = true dann Rolebased Tickets und Incidents laden
|
||||
@@ -268,6 +325,8 @@ namespace FasdDesktopUi.Basics.UserControls
|
||||
if (counts == null || counts.Count == 0)
|
||||
counts = await LoadCountsFallbackAsync(useRoleTickets).ConfigureAwait(false);
|
||||
|
||||
SetTicketAndServiceRequestsVisibility(TicketOverviewUpdateService.Instance?.TicketAndServiceRequestsEnabled == true);
|
||||
|
||||
await Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
foreach (var (key, setter) in CategorySetters)
|
||||
|
||||
@@ -399,9 +399,24 @@ Wie möchten Sie fortfahren?</Language>
|
||||
<Language Lang="DE">Letzte Suchanfragen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Searchbar.Relations.SearchFor">
|
||||
<Language Lang="EN">Search {0}</Language>
|
||||
<Language Lang="DE">Suche {0}</Language>
|
||||
<UIItem Name="Searchbar.Relations.SearchFor.Computer">
|
||||
<Language Lang="EN">Search Computers</Language>
|
||||
<Language Lang="DE">Suche Computer</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Searchbar.Relations.SearchFor.User">
|
||||
<Language Lang="EN">Search users</Language>
|
||||
<Language Lang="DE">Suche Anwender</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Searchbar.Relations.SearchFor.Ticket">
|
||||
<Language Lang="EN">Search tickets</Language>
|
||||
<Language Lang="DE">Suche Tickets</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Searchbar.Relations.SearchFor.VirtualSession">
|
||||
<Language Lang="EN">Search virtual sessions</Language>
|
||||
<Language Lang="DE">Suche virtuelle Sitzungen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Searchbar.Header.Template">
|
||||
@@ -545,6 +560,11 @@ Wie möchten Sie fortfahren?</Language>
|
||||
<Language Lang="DE">Eigene Störungen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="TicketOverview.ScopeRow.Personal.ServiceRequests">
|
||||
<Language Lang="EN">My service requests</Language>
|
||||
<Language Lang="DE">Eigene Serviceanfragen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="TicketOverview.ScopeRow.Personal.UnassignedTickets">
|
||||
<Language Lang="EN">My unassigned</Language>
|
||||
<Language Lang="DE">Eigener Eingang</Language>
|
||||
@@ -560,6 +580,11 @@ Wie möchten Sie fortfahren?</Language>
|
||||
<Language Lang="DE">Rollenstörungen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="TicketOverview.ScopeRow.Role.ServiceRequests">
|
||||
<Language Lang="EN">Role service requests</Language>
|
||||
<Language Lang="DE">Rollen-Serviceanfragen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="TicketOverview.ScopeRow.Role.UnassignedTickets">
|
||||
<Language Lang="EN">Role unassigned</Language>
|
||||
<Language Lang="DE">Rolleneingang</Language>
|
||||
@@ -604,8 +629,8 @@ Alle offenen Fälle werden dabei geschlossen.</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Menu.SelectLanguage">
|
||||
<Language Lang="EN">Select language</Language>
|
||||
<Language Lang="DE">Sprache festlegen</Language>
|
||||
<Language Lang="EN">Select language & Format</Language>
|
||||
<Language Lang="DE">Sprache & Format festlegen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="Menu.SelectLanguage.RestartDialog.Caption">
|
||||
@@ -1739,6 +1764,11 @@ Wollen Sie das F4SD Cockpit jetzt neu starten?</Language>
|
||||
<Language Lang="DE">Störungen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="TicketOverview.Row.Heading.ServiceRequests">
|
||||
<Language Lang="EN">Service requests</Language>
|
||||
<Language Lang="DE">Serviceanfragen</Language>
|
||||
</UIItem>
|
||||
|
||||
<UIItem Name="TicketOverview.Row.Heading.UnassignedTickets">
|
||||
<Language Lang="EN">Unassigned</Language>
|
||||
<Language Lang="DE">Eingang</Language>
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
<Compile Include="Basics\PrivateSecurePassword.cs" />
|
||||
<Compile Include="Basics\UiActions\ChangeHealthCardAction.cs" />
|
||||
<Compile Include="Basics\UiActions\CopyQuickActionProtocolAction.cs" />
|
||||
<Compile Include="Basics\UiActions\NativeActions\QuickActionExecutor.cs" />
|
||||
<Compile Include="Basics\UiActions\NativeActions\RemoteConnectionAction.cs" />
|
||||
<Compile Include="Basics\UiActions\UiCopyDetailsTableContent.cs" />
|
||||
<Compile Include="Basics\UiActions\UiDummyQuickAction.cs" />
|
||||
@@ -294,6 +295,11 @@
|
||||
<Compile Include="Basics\UserControls\CustomMenuItemToolTipTemplate.xaml.cs">
|
||||
<DependentUpon>CustomMenuItemToolTipTemplate.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Basics\Models\QuickActionOutput\cQuickActionMeasureValue.cs" />
|
||||
<Compile Include="Basics\Models\QuickActionOutput\cQuickActionOutput.cs" />
|
||||
<Compile Include="Basics\Models\QuickActionOutput\cQuickActionOutputList.cs" />
|
||||
<Compile Include="Basics\Models\QuickActionOutput\cQuickActionOutputObject.cs" />
|
||||
<Compile Include="Basics\Models\QuickActionOutput\cQuickActionOutputSingle.cs" />
|
||||
<Compile Include="Basics\UserControls\Gamification\LevelTracker.xaml.cs">
|
||||
<DependentUpon>LevelTracker.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -1012,6 +1018,10 @@
|
||||
<EmbeddedResource Include="Config\LanguageDefinitions.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\F4SD-ActionConnector\F4SD-ActionConnector.csproj">
|
||||
<Project>{887c6721-b9f3-c83a-3d55-5e684ca19592}</Project>
|
||||
<Name>F4SD-ActionConnector</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\F4SD-AdaptableIcon\F4SD-AdaptableIcon.csproj">
|
||||
<Project>{bab63a6a-1524-435d-9f96-7a30b6ee0624}</Project>
|
||||
<Name>F4SD-AdaptableIcon</Name>
|
||||
@@ -1119,9 +1129,6 @@ taskkill -im "F4SD-Cockpit-Client.exe" -f -FI "STATUS eq RUNNING"
|
||||
<PhoenixFiles Include="$(SolutionDir)PhoenixViewer\*" />
|
||||
</ItemGroup>
|
||||
<MakeDir Directories="$(TargetDir)Phoenix" />
|
||||
<Copy
|
||||
SourceFiles="@(PhoenixFiles)"
|
||||
DestinationFolder="$(TargetDir)Phoenix"
|
||||
SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="@(PhoenixFiles)" DestinationFolder="$(TargetDir)Phoenix" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -105,6 +105,7 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
if (TicketOverviewUpdateService.Instance != null)
|
||||
{
|
||||
TicketOverviewUpdateService.Instance.OverviewCountsChanged += TicketOverviewUpdateService_OverviewCountsChanged;
|
||||
TicketOverviewUpdateService.Instance.TicketAndServiceRequestsAvailabilityChanged += TicketOverviewUpdateService_TicketAndServiceRequestsAvailabilityChanged;
|
||||
}
|
||||
|
||||
UiSettingsChanged(null, null);
|
||||
@@ -732,7 +733,10 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
try
|
||||
{
|
||||
if (TicketOverviewUpdateService.Instance != null)
|
||||
{
|
||||
TicketOverviewUpdateService.Instance.OverviewCountsChanged -= TicketOverviewUpdateService_OverviewCountsChanged;
|
||||
TicketOverviewUpdateService.Instance.TicketAndServiceRequestsAvailabilityChanged -= TicketOverviewUpdateService_TicketAndServiceRequestsAvailabilityChanged;
|
||||
}
|
||||
_pipeServer?.Dispose();
|
||||
}
|
||||
catch { }
|
||||
@@ -1008,8 +1012,11 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (TryOpenTicketOverviewRelationExternally(relation))
|
||||
if (!TicketExternalLinkHelper.HasValidUserIdentity(relation))
|
||||
{
|
||||
TryOpenTicketOverviewRelationExternally(relation, forceExternal: true);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var ticketName = string.IsNullOrWhiteSpace(relation.DisplayName) ? relation.Name : relation.DisplayName;
|
||||
var ticketId = relation.id;
|
||||
@@ -1028,22 +1035,19 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
relation.Infos.TryGetValue("UserSid", out sids);
|
||||
}
|
||||
|
||||
return RunTicketSearchAsync(ticketName, ticketId, userName, sids, suppressUi: true);
|
||||
return RunTicketSearchAsync(ticketName, ticketId, userName, sids, suppressUi: true, ticketOverviewRelation: relation);
|
||||
}
|
||||
|
||||
private bool TryOpenTicketOverviewRelationExternally(cF4sdApiSearchResultRelation relation)
|
||||
private bool TryOpenTicketOverviewRelationExternally(cF4sdApiSearchResultRelation relation, bool forceExternal = false)
|
||||
{
|
||||
return TicketExternalLinkHelper.TryOpenTicketRelationExternally(relation);
|
||||
return TicketExternalLinkHelper.TryOpenTicketRelationExternally(relation, forceExternal);
|
||||
}
|
||||
|
||||
private Task RunTicketSearchAsync(string ticketName, Guid ticketId, string userName, string sids, bool suppressUi = false)
|
||||
private Task RunTicketSearchAsync(string ticketName, Guid ticketId, string userName, string sids, bool suppressUi = false, cF4sdApiSearchResultRelation ticketOverviewRelation = null)
|
||||
{
|
||||
if (ticketId == Guid.Empty)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (suppressUi)
|
||||
BeginTicketOverviewAutoContinue(TimeSpan.FromSeconds(6));
|
||||
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
@@ -1054,6 +1058,7 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
if (_result is null || _result.Count == 0 || _result.First().Value.Count == 0)
|
||||
{
|
||||
LogEntry($"No corresponding user could be found for ticket '{ticketName}'", LogLevels.Warning);
|
||||
TryOpenTicketOverviewRelationExternally(ticketOverviewRelation, forceExternal: true);
|
||||
if (suppressUi)
|
||||
EndTicketOverviewAutoContinue(showSearch: true);
|
||||
return;
|
||||
@@ -1063,6 +1068,7 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
LogEntry($"No valid user id could be found for ticket '{ticketName}'", LogLevels.Warning);
|
||||
TryOpenTicketOverviewRelationExternally(ticketOverviewRelation, forceExternal: true);
|
||||
if (suppressUi)
|
||||
EndTicketOverviewAutoContinue(showSearch: true);
|
||||
return;
|
||||
@@ -1074,6 +1080,9 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
DisplayName = ticketName,
|
||||
id = ticketId,
|
||||
Status = enumF4sdSearchResultStatus.Active,
|
||||
Infos = ticketOverviewRelation?.Infos == null
|
||||
? null
|
||||
: new Dictionary<string, string>(ticketOverviewRelation.Infos),
|
||||
Identities = new cF4sdIdentityList
|
||||
{
|
||||
new cF4sdIdentityEntry()
|
||||
@@ -1092,6 +1101,9 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
var filteredResults = new cFilteredResults(_result) { AutoContinue = true, PreSelectedRelation = _ticketRelation };
|
||||
|
||||
var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.TicketSearch.Info"), ticketName);
|
||||
if (suppressUi)
|
||||
BeginTicketOverviewAutoContinue(TimeSpan.FromSeconds(6));
|
||||
|
||||
await ShowExternalSearchInfoAsync(strInfo, filteredResults, enumF4sdSearchResultClass.Ticket, suppressUi);
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -1291,6 +1303,8 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
var service = TicketOverviewUpdateService.Instance;
|
||||
if (service == null)
|
||||
return;
|
||||
|
||||
TicketOverviewUc?.SetTicketAndServiceRequestsVisibility(service.TicketAndServiceRequestsEnabled);
|
||||
var counts = service.GetCountsForScope(IsFilterChecked);
|
||||
if (counts == null || counts.Count == 0)
|
||||
return;
|
||||
@@ -1299,6 +1313,13 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
TicketOverviewUc?.RefreshHighlightState(IsFilterChecked);
|
||||
}
|
||||
|
||||
private void TicketOverviewUpdateService_TicketAndServiceRequestsAvailabilityChanged(object sender, EventArgs e)
|
||||
{
|
||||
var isVisible = TicketOverviewUpdateService.Instance?.TicketAndServiceRequestsEnabled == true;
|
||||
TicketOverviewUc?.SetTicketAndServiceRequestsVisibility(isVisible);
|
||||
ScheduleSearchResultMaxHeightUpdate();
|
||||
}
|
||||
|
||||
private string BuildNotificationMessage(IReadOnlyList<TileCountChange> changes)
|
||||
{
|
||||
if (changes == null || changes.Count == 0)
|
||||
@@ -1362,6 +1383,8 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
rowKey = "TicketOverview.Row.Heading.Tickets";
|
||||
else if (normalized.StartsWith("incident"))
|
||||
rowKey = "TicketOverview.Row.Heading.Incidents";
|
||||
else if (normalized.StartsWith("servicerequests"))
|
||||
rowKey = "TicketOverview.Row.Heading.ServiceRequests";
|
||||
else if (normalized.StartsWith("unassigned"))
|
||||
rowKey = "TicketOverview.Row.Heading.UnassignedTickets";
|
||||
else
|
||||
@@ -1389,6 +1412,8 @@ namespace FasdDesktopUi.Pages.SearchPage
|
||||
suffix = "Tickets";
|
||||
else if (string.Equals(rowKey, "TicketOverview.Row.Heading.Incidents", StringComparison.OrdinalIgnoreCase))
|
||||
suffix = "Incidents";
|
||||
else if (string.Equals(rowKey, "TicketOverview.Row.Heading.ServiceRequests", StringComparison.OrdinalIgnoreCase))
|
||||
suffix = "ServiceRequests";
|
||||
else if (string.Equals(rowKey, "TicketOverview.Row.Heading.UnassignedTickets", StringComparison.OrdinalIgnoreCase))
|
||||
suffix = "UnassignedTickets";
|
||||
|
||||
|
||||
@@ -173,10 +173,11 @@ namespace FasdDesktopUi.Pages.ShortCutPage
|
||||
{
|
||||
Names = new C4IT.MultiLanguage.cMultiLanguageDictionary()
|
||||
{
|
||||
["EN"] = "Open Quick Action menu",
|
||||
["DE"] = "Quick Action Menü öffnen"
|
||||
["EN"] = "Open Quick Action menu/close",
|
||||
["DE"] = "Quick Action Menü öffnen/schließen"
|
||||
},
|
||||
HotKey = Key.Q,
|
||||
AlternativeKey = Key.Escape
|
||||
},
|
||||
new cHotKeyInformation()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user