feat: expand cockpit integrations and support workflows

Add Phoenix remote desktop, action connector, documentation engine, and gamification support. Refactor support-case processing and search/action UI, and update installer assets and dependencies.
This commit is contained in:
Meik
2026-07-13 11:16:53 +02:00
parent bbedbf71c8
commit 0b52999b1d
303 changed files with 11235 additions and 3580 deletions

View File

@@ -0,0 +1,27 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace FasdDesktopUi.Basics.Converter
{
[ValueConversion(typeof(string), typeof(XmlLanguage))]
internal class LanguageCultureConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is string tag))
return Binding.DoNothing;
return XmlLanguage.GetLanguage(tag);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is XmlLanguage lang))
return Binding.DoNothing;
return lang.IetfLanguageTag;
}
}
}

View File

@@ -31,7 +31,7 @@ namespace FasdDesktopUi.Basics
var http = GetHttpHelper(false);
var searchResultInfoClass = cF4sdIdentityEntry.GetFromSearchResult(enumF4sdSearchResultClass.Computer);
var parameter = new cF4SDServerQuickActionParameters() { Action = ServerAction.Action, Category = ServerAction.Category, ParamaterType = ServerAction.ParameterType, Identities = dataProvider.Identities, AdjustableParameter = ParameterDictionary };
var parameter = new cF4SDServerQuickActionParameters() { Action = ServerAction.Action, Category = ServerAction.Category, ParameterType = ServerAction.ParameterType, Identities = dataProvider.Identities, AdjustableParameter = ParameterDictionary };
var payload = JsonConvert.SerializeObject(parameter);
var result = await http.PostJsonAsync("api/QuickAction/Run", payload, 15000, CancellationToken.None);

View File

@@ -0,0 +1,126 @@
using C4IT.FASD.Base;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Helper
{
internal static class ActionDisplayTypeInspector
{
internal static enumActionDisplayType GetDisplayType(cFasdBaseConfigMenuItem menuDataDefinition, cNamedParameterList namedParameterEntries, IEnumerable<enumFasdInformationClass> availableInformationClasses)
{
if (menuDataDefinition.IsHidden)
return enumActionDisplayType.hidden;
else if (IsEnabled(menuDataDefinition, namedParameterEntries, availableInformationClasses))
return enumActionDisplayType.enabled;
else
return enumActionDisplayType.disabled;
}
private static bool IsEnabled(cFasdBaseConfigMenuItem menuDataDefinition, cNamedParameterList namedParameterEntries, IEnumerable<enumFasdInformationClass> availableInformationClasses)
{
if (!HasRequiredInformationClasses(menuDataDefinition, availableInformationClasses))
return false;
if (menuDataDefinition is cFasdQuickAction quickActionDefinition && !IsQuickActionEnabled(quickActionDefinition, namedParameterEntries))
return false;
else
return true;
}
private static bool IsQuickActionEnabled(cFasdQuickAction quickActionDefinition, cNamedParameterList namedParameterEntries)
{
if (!string.IsNullOrEmpty(quickActionDefinition.CheckFilePath) && !FileExists(quickActionDefinition.CheckFilePath))
return false;
if (!string.IsNullOrEmpty(quickActionDefinition.CheckRegistryEntry) && !RegistryEntryExists(quickActionDefinition.CheckRegistryEntry))
return false;
if (namedParameterEntries is null)
return true;
cNamedParameterEntryBase namedParameterValue = null;
if (!string.IsNullOrEmpty(quickActionDefinition.CheckNamedParameter) && !namedParameterEntries.TryGetValue(quickActionDefinition.CheckNamedParameter, out namedParameterValue))
return false;
if (namedParameterValue != null && quickActionDefinition.CheckNamedParameterValues != null && !quickActionDefinition.CheckNamedParameterValues.Contains(namedParameterValue.GetValue()))
return false;
return true;
}
private static bool HasRequiredInformationClasses(cFasdBaseConfigMenuItem definition, IEnumerable<enumFasdInformationClass> availableInformationClasses)
{
if (definition?.InformationClasses is null)
return true;
if (definition.InformationClasses.Count == 0)
return true;
if (definition.InformationClasses.Any(i => !availableInformationClasses.Contains(i)))
return false;
return true;
}
private static bool FileExists(string path)
{
try
{
if (string.IsNullOrWhiteSpace(path))
return true;
var specialFolders = Enum.GetValues(typeof(Environment.SpecialFolder)).Cast<Environment.SpecialFolder>();
foreach (var specialFolder in specialFolders)
{
string specialFolderName = $"%{specialFolder}%";
string specialFolderPath = Environment.GetFolderPath(specialFolder);
path = path.Replace(specialFolderName, specialFolderPath);
}
path = Environment.ExpandEnvironmentVariables(path);
return File.Exists(path);
}
catch (Exception E)
{
LogException(E);
return false;
}
}
private static bool RegistryEntryExists(string entry)
{
try
{
if (string.IsNullOrWhiteSpace(entry))
return true;
string rootPath = entry.Split('\\')[0];
entry = entry.Replace(rootPath, "").Remove(0, 1);
switch (rootPath)
{
case "HKEY_LOCAL_MACHINE":
case "HKLM":
return Registry.LocalMachine.OpenSubKey(entry) != null;
case "HKEY_CURRENT_USER":
case "HKCU":
return Registry.CurrentUser.OpenSubKey(entry) != null;
default:
return false;
}
}
catch (Exception E)
{
LogException(E);
return false;
}
}
}
}

View File

@@ -7,7 +7,6 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using C4IT.Configuration;
using C4IT.F4SD.DisplayFormatting;
@@ -27,7 +26,6 @@ using FasdDesktopUi.Pages.SlimPage.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using static C4IT.FASD.Base.cF4SDHealthCardRawData;
using static C4IT.Logging.cLogManager;
@@ -80,7 +78,7 @@ namespace FasdDesktopUi.Basics.Helper
{
this.dataProvider = dataProvider;
_menuDataProvider = new MenuItemDataProvider(dataProvider);
cUtility.RawValueFormatter.SetDefaultCulture(new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
cUtility.RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
HistoryData = new cHealthCardHistoryDataHelper(this);
@@ -149,7 +147,7 @@ namespace FasdDesktopUi.Basics.Helper
if (informationClasses is null)
return null;
foreach (var healthCard in cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.HealthCards.Values)
foreach (var healthCard in cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.HealthCards?.Values)
{
bool found = true;
@@ -250,7 +248,7 @@ namespace FasdDesktopUi.Basics.Helper
{
List<object> output = new List<object>();
if (healthCardColumn?.Values == null)
if (healthCardColumn?.Values == null || startingIndex < 0)
return output;
try
@@ -453,13 +451,9 @@ namespace FasdDesktopUi.Basics.Helper
var stateValue = GetStateValueAt(stateDefinition.DatabaseInfo, dayIndex, isStatic);
enumHighlightColor? tempColor = null;
if (stateValue != null)
{
tempColor = GetHighlightColor(stateValue, stateDefinition, dayIndex, isStatic);
if (tempColor == enumHighlightColor.none && stateValue != null)
tempColor = enumHighlightColor.green;
}
enumHighlightColor? tempColor = GetHighlightColor(stateValue, stateDefinition, dayIndex, isStatic);
if (tempColor == enumHighlightColor.none && stateValue != null)
tempColor = enumHighlightColor.green;
if (output == null)
output = tempColor;
@@ -492,7 +486,7 @@ namespace FasdDesktopUi.Basics.Helper
}
else
{
FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.Date.AddDays(columnIndex), TimeZone = TimeZoneInfo.Local };
FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.Date.AddDays(-columnIndex), TimeZone = TimeZoneInfo.Local };
var _c = cUtility.RawValueFormatter.GetDisplayValue(value, Requirements.valueState.DisplayType, options);
if (!string.IsNullOrWhiteSpace(_c))
cellContent.Content = _c;
@@ -689,11 +683,19 @@ namespace FasdDesktopUi.Basics.Helper
{
if (NamedParameters == null)
return false;
var _invert = false;
if (namedParameter.StartsWith("!"))
{
_invert = true;
namedParameter = namedParameter.Remove(0, 1);
}
if (!NamedParameters.TryGetValue(namedParameter, out var entry))
return false;
return _invert;
var entryValue = entry.GetValue();
cConfigRegistryHelper.ReadFromStringBoolean(entryValue, out var result);
if (_invert)
result = !result;
return result;
}
@@ -1113,11 +1115,14 @@ namespace FasdDesktopUi.Basics.Helper
}
}
const string defaultCopyTemplateParameterName = "Copy_default";
if (!dataProvider.NamedParameterEntries.ContainsKey(defaultCopyTemplateParameterName))
{
string defaultCopyTemplate = cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.DefaultTemplate.Name;
dataProvider.NamedParameterEntries.Add(defaultCopyTemplateParameterName, new cNamedParameterEntryCopyTemplate(dataProvider, defaultCopyTemplate));
dataProvider.NamedParameterEntries.Add(defaultCopyTemplateParameterName, new cNamedParameterEntryCopyTemplate(dataProvider, SelectedHealthCard.DefaultCopyTemplate != null ? SelectedHealthCard.DefaultCopyTemplate : defaultCopyTemplate));
}
foreach (var copyTemplate in cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.CopyTemplates)
@@ -1202,8 +1207,8 @@ namespace FasdDesktopUi.Basics.Helper
var historySectionValueColumns = new List<DetailsPageDataHistoryColumnModel>(valueColumnCount);
for (int i = 0; i < valueColumnCount; i++)
{
CultureInfo culture = new CultureInfo(cMultiLanguageSupport.CurrentLanguage);
var valueColumnHeader = i != 0 ? DateTime.Today.AddDays(-i).ToString(cMultiLanguageSupport.GetItem("Global.Date.Format.ShortDateWithDay", "ddd. dd.MM."), culture) : cMultiLanguageSupport.GetItem("Global.Date.Today");
CultureInfo culture = cFasdCockpitConfig.Instance.SelectedCulture;
var valueColumnHeader = i != 0 ? DateTime.Today.AddDays(-i).ToString($"ddd. {cUtility.GetShortDatePattern()}") : cMultiLanguageSupport.GetItem("Global.Date.Today");
var summaryStatusColor = parent.GetSummaryStatusColor(stateCategoryDefinition.States, false, i);
var valueColumn = new DetailsPageDataHistoryColumnModel() { ColumnValues = new List<cDataHistoryValueModel>(), Content = valueColumnHeader, HighlightColor = summaryStatusColor ?? enumHighlightColor.none };
historySectionValueColumns.Add(valueColumn);
@@ -2165,6 +2170,7 @@ namespace FasdDesktopUi.Basics.Helper
bool isDataIncomplete = true;
await LoadingRawDataCriticalSection.EnterAsync();
try
{
lock (HealthCardRawData)

View File

@@ -1,6 +1,7 @@
using C4IT.FASD.Base;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.SupportCase.Processors;
using FasdDesktopUi.Basics.UiActions;
using Microsoft.Win32;
using System;
@@ -15,7 +16,6 @@ namespace FasdDesktopUi.Basics.Helper
internal class MenuItemDataProvider
{
private readonly cSupportCaseDataProvider _dataProvider;
private const int defaultPinnedActionCount = 3; //search, notepad, copyTicketInformation
public MenuItemDataProvider(cSupportCaseDataProvider dataProvider)
@@ -58,7 +58,7 @@ namespace FasdDesktopUi.Basics.Helper
return menuItemData;
}
private cMenuDataBase GetMenuItem(cFasdBaseConfigMenuItem menuItemConfig)
internal cMenuDataBase GetMenuItem(cFasdBaseConfigMenuItem menuItemConfig)
{
try
{
@@ -81,7 +81,7 @@ namespace FasdDesktopUi.Basics.Helper
if (menuItem != null)
{
if (!cHealthCardDataHelper.IsUiVisible(menuItemConfig, _dataProvider.NamedParameterEntries))
if (_dataProvider != null && !cHealthCardDataHelper.IsUiVisible(menuItemConfig, _dataProvider.NamedParameterEntries))
menuItem.SetUiActionDisplayType(enumActionDisplayType.hidden);
}
return menuItem;
@@ -129,7 +129,7 @@ namespace FasdDesktopUi.Basics.Helper
}
private bool HasAllRequirements(cFasdQuickAction quickAction)
internal bool HasAllRequirements(cFasdQuickAction quickAction)
{
try
{
@@ -137,9 +137,14 @@ namespace FasdDesktopUi.Basics.Helper
return false;
// if CheckNamedParamter the value of NamedParameter is set and if required equals one of the necessary values
bool hasRequiredNamedParameter = quickAction.CheckNamedParameter is null
|| (_dataProvider.NamedParameterEntries.TryGetValue(quickAction.CheckNamedParameter, out var namedParameterEntry)
&& (quickAction.CheckNamedParameterValues is null || quickAction.CheckNamedParameterValues.Count == 0 || quickAction.CheckNamedParameterValues.Contains(namedParameterEntry.GetValue())));
bool hasRequiredNamedParameter = true;
if (_dataProvider != null)
{
hasRequiredNamedParameter = quickAction.CheckNamedParameter is null
|| (_dataProvider.NamedParameterEntries.TryGetValue(quickAction.CheckNamedParameter, out var namedParameterEntry)
&& (quickAction.CheckNamedParameterValues is null || quickAction.CheckNamedParameterValues.Count == 0 || quickAction.CheckNamedParameterValues.Contains(namedParameterEntry.GetValue())));
}
if (!hasRequiredNamedParameter)
return false;

View File

@@ -1,13 +1,17 @@
using System;
using System.Collections.Generic;
using C4IT.FASD.Base;
using C4IT.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using C4IT.FASD.Base;
using C4IT.Logging;
using FasdDesktopUi.Basics;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Helper
{
internal static class TicketDeepLinkHelper
internal static class TicketExternalLinkHelper
{
internal static bool TryOpenTicketRelationExternally(cF4sdApiSearchResultRelation relation)
{
@@ -16,127 +20,51 @@ namespace FasdDesktopUi.Basics.Helper
if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket)
return false;
var ticketConfig = cFasdCockpitConfig.Instance?.Global?.TicketConfiguration;
if (ticketConfig == null)
// check how we should open this ticket (intern, extern or both)
var ticketType = GetTicketType(relation);
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)
processing = enumTicketProcessing.Extern;
if (processing == enumTicketProcessing.Intern)
return false;
var activityType = GetActivityType(relation);
var openExternally = ShouldOpenExternally(ticketConfig, activityType);
if (!openExternally)
return false;
var url = BuildTicketDeepLink(relation.id, activityType);
if (string.IsNullOrWhiteSpace(url))
return false;
if (relation?.Infos?.TryGetValue("TicketLink", out var ticketLink) == true && !string.IsNullOrWhiteSpace(ticketLink))
new cBrowsers().Start("default", ticketLink);
new cBrowsers().Start("default", url);
return true;
return processing == enumTicketProcessing.Extern;
}
catch (Exception ex)
{
LogException(ex);
}
return false;
}
private static string GetActivityType(cF4sdApiSearchResultRelation relation)
{
if (relation?.Infos != null && relation.Infos.TryGetValue("ActivityType", out var activityTypeValue))
return activityTypeValue;
return null;
}
private static bool ShouldOpenExternally(cF4sdTicketConfig ticketConfig, string activityType)
{
if (ticketConfig == null)
return false;
if (TryGetOverride(ticketConfig.OpenActivitiesExternallyOverrides, activityType, out var overrideValue))
return overrideValue;
return ticketConfig.OpenActivitiesExternally;
}
private static bool TryGetOverride(IEnumerable<string> overrides, string activityType, out bool value)
{
value = false;
if (string.IsNullOrWhiteSpace(activityType) || overrides == null)
return false;
foreach (var entry in overrides)
{
if (string.IsNullOrWhiteSpace(entry))
continue;
var parts = entry.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
continue;
var typeName = parts[0].Trim();
if (!string.Equals(typeName, activityType, StringComparison.OrdinalIgnoreCase))
continue;
if (!TryParseBool(parts[1], out value))
return false;
return true;
}
return false;
}
private static bool TryParseBool(string value, out bool result)
{
result = false;
if (string.IsNullOrWhiteSpace(value))
return false;
switch (value.Trim().ToLowerInvariant())
{
case "true":
case "1":
case "yes":
result = true;
return true;
case "false":
case "0":
case "no":
result = false;
return true;
default:
return bool.TryParse(value, out result);
}
}
return false;
}
internal static string BuildTicketDeepLink(Guid ticketId, string activityType)
private static enumTicketType GetTicketType(cF4sdApiSearchResultRelation relation)
{
if (ticketId == Guid.Empty)
return null;
var server = cCockpitConfiguration.Instance?.m42ServerConfiguration?.Server;
if (string.IsNullOrWhiteSpace(server))
return null;
var baseUrl = server.TrimEnd('/');
if (!baseUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
!baseUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
if (relation?.Infos != null && relation.Infos.TryGetValue("TicketType", out var ticketTypeValue))
{
baseUrl = "https://" + baseUrl;
if (Enum.TryParse<enumTicketType>(ticketTypeValue, true, out var ticketType))
return ticketType;
}
if (!baseUrl.EndsWith("/wm", StringComparison.OrdinalIgnoreCase))
baseUrl += "/wm";
return enumTicketType.Ticket;
}
if (string.IsNullOrWhiteSpace(activityType))
return null;
private static enumTicketProcessing ShouldOpenExternally(enumTicketType ticketType)
{
var ticketConfig = cFasdCockpitConfig.Instance?.Global?.TicketConfiguration;
if (ticketConfig == null)
return enumTicketProcessing.Extern;
var viewOptionsJson = $"{{\"embedded\":false,\"objectId\":\"{ticketId}\",\"type\":\"{activityType}\",\"viewType\":\"preview\",\"archived\":0}}";
var viewOptionsEncoded = Uri.EscapeDataString(viewOptionsJson);
if (ticketConfig.TicketProcessing?.TryGetValue(ticketType, out var processing) == true)
return processing;
return $"{baseUrl}/app-ServiceDesk/?view-options={viewOptionsEncoded}";
return ticketConfig.DefaultProcessing;
}
}
}

View File

@@ -48,7 +48,9 @@ namespace FasdDesktopUi.Basics.Models
heartBeat
}
public bool IsActive = true;
public enumOnlineStatus ApiConnectionStatus { get; private set; } = enumOnlineStatus.notSpecified;
public bool ApplicationIsExiting { get; set; } = false;
public readonly Version MinServerVersion = new Version("0.0.0.0");
@@ -64,16 +66,15 @@ namespace FasdDesktopUi.Basics.Models
public static cConnectionStatusHelper Instance { get; set; }
public bool IsAuthorizationSupported { get; private set; } = false;
private bool IsAuthorizationSupported { get; set; } = false;
private System.Timers.Timer timer;
#region Lock Elements Connecion Status
private readonly object connectionStatusCheckLock = new object();
private enumCheckRunning IsConnectionStatusCheckRunning = enumCheckRunning.no;
private int OnlineCheckCounter = 0;
#endregion
public enumOnlineStatus ApiConnectionStatus = enumOnlineStatus.notSpecified;
public cConnectionStatusHelper()
{
ApiConnectionStatus = enumOnlineStatus.offline;
@@ -125,44 +126,47 @@ namespace FasdDesktopUi.Basics.Models
return (timerInterval, shortInterval);
}
private void HandleConnectionStatus(enumConnectionStatus status, ref int timerInterval, int timerInteralShort)
private enumOnlineStatus HandleConnectionStatus(enumConnectionStatus status, ref int timerInterval, int timerInteralShort)
{
var newStatus = ApiConnectionStatus;
switch (status)
{
case enumConnectionStatus.unknown:
case enumConnectionStatus.serverNotFound:
if (ApiConnectionStatus != enumOnlineStatus.offline)
ApiConnectionStatus = enumOnlineStatus.offline;
if (newStatus != enumOnlineStatus.offline)
newStatus = enumOnlineStatus.offline;
timerInterval = timerInteralShort;
LogEntry("RunConnectionStatusCheckAsync: Exit due to status 'serverNotFound'");
break;
case enumConnectionStatus.serverResponseError:
ApiConnectionStatus = enumOnlineStatus.connectionError;
newStatus = enumOnlineStatus.connectionError;
timerInterval = timerInteralShort;
LogEntry("RunConnectionStatusCheckAsync: Exit due to status 'serverResponseError'");
break;
case enumConnectionStatus.incompatibleServerVersion:
LogEntry("RunConnectionStatusCheckAsync: Exit due to status 'incompatibleServerVersion'");
ApiConnectionStatus = enumOnlineStatus.incompatibleServerVersion;
newStatus = enumOnlineStatus.incompatibleServerVersion;
break;
case enumConnectionStatus.serverStarting:
ApiConnectionStatus = enumOnlineStatus.serverStarting;
newStatus = enumOnlineStatus.serverStarting;
break;
case enumConnectionStatus.serverNotConfigured:
ApiConnectionStatus = enumOnlineStatus.serverNotConfigured;
newStatus = enumOnlineStatus.serverNotConfigured;
break;
case enumConnectionStatus.connected:
if (cCockpitConfiguration.Instance == null || cF4SDCockpitXmlConfig.Instance == null)
ApiConnectionStatus = enumOnlineStatus.illegalConfig;
newStatus = enumOnlineStatus.illegalConfig;
else if (ApiConnectionStatus != enumOnlineStatus.online)
ApiConnectionStatus = enumOnlineStatus.online;
newStatus = enumOnlineStatus.online;
break;
}
return newStatus;
}
public async Task RunConnectionStatusCheckAsync(SplashScreenView splashScreen)
{
if (!IsActive)
if (ApplicationIsExiting)
return;
var CM = MethodBase.GetCurrentMethod();
@@ -195,7 +199,7 @@ namespace FasdDesktopUi.Basics.Models
cCheckConnectionResult connectionResult = await cFasdCockpitCommunicationBase.Instance.CheckConnection(MinServerVersion);
IsAuthorizationSupported = connectionResult?.ApiConnectionInfo?.SupportAuthorisation ?? false;
HandleConnectionStatus(connectionResult.ConnectionStatus, ref timerInterval, shortTimerInterval);
ApiConnectionStatus = HandleConnectionStatus(connectionResult.ConnectionStatus, ref timerInterval, shortTimerInterval);
if (connectionResult.ConnectionStatus != enumConnectionStatus.connected)
return;
@@ -210,7 +214,12 @@ namespace FasdDesktopUi.Basics.Models
var configTasks = await Task.WhenAll(loadConfigFilesTask, getCockpitConfig);
if (configTasks.Any(t => t == false))
{
LogEntry("Connection status check wasn't successfull. Could not retrieve all configurations.", LogLevels.Warning);
await Task.Delay(TimeSpan.FromSeconds(5));
await RunConnectionStatusCheckAsync(splashScreen);
return;
}
if (cFasdCockpitConfig.Instance?.Global != null && cCockpitConfiguration.Instance?.GlobalConfig != null)
{
cFasdCockpitConfig.Instance.Global.Load(cCockpitConfiguration.Instance.GlobalConfig);
@@ -225,33 +234,34 @@ namespace FasdDesktopUi.Basics.Models
}
if (IsAuthorizationSupported)
{
if (userInfo is null || DateTime.UtcNow > userInfo.RenewUntil)
{
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.AuthenticateUser")));
ApiConnectionStatus = enumOnlineStatus.unauthorized;
const string cockpitUserRole = "Cockpit.User";
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.AuthenticateUser")));
ApiConnectionStatus = enumOnlineStatus.unauthorized;
const string cockpitUserRole = "Cockpit.User";
#if isNewFeature
const string cockpitTicketAgentRole = "Cockpit.TicketAgent";
#endif
if (userInfo is null || DateTime.UtcNow > userInfo.RenewUntil)
{
userInfo = await cFasdCockpitCommunicationBase.Instance.WinLogon();
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
{
cFasdCockpitCommunicationBase.CockpitUserInfo = userInfo;
}
if (userInfo?.Roles is null || !userInfo.Roles.Contains(cockpitUserRole))
{
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.NoAuthorization")));
LogEntry($"Cockpit User ({userInfo?.Name} with Id {userInfo?.Id}, has not the required permissions.", LogLevels.Error);
}
else
{
await Task.Run(async () => await cFasdCockpitConfig.Instance.InstantiateAnalyticsAsync(cFasdCockpitConfig.SessionId));
ApiConnectionStatus = enumOnlineStatus.online;
}
if (userInfo?.Roles is null || !userInfo.Roles.Contains(cockpitUserRole))
{
Dispatcher.CurrentDispatcher.Invoke(() => splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.NoAuthorization")));
LogEntry($"Cockpit User ({userInfo?.Name} with Id {userInfo?.Id}, has not the required permissions.", LogLevels.Error);
}
else
{
await Task.Run(async () => await cFasdCockpitConfig.Instance.InstantiateAnalyticsAsync(cFasdCockpitConfig.SessionId));
ApiConnectionStatus = enumOnlineStatus.online;
#if isNewFeature
if (userInfo.Roles.Contains(cockpitTicketAgentRole))
cCockpitConfiguration.Instance.ticketSupport.EditTicket = true;
#endif
}
}
}
else
@@ -280,9 +290,9 @@ namespace FasdDesktopUi.Basics.Models
}
if (App.M42OptionMenuItem != null)
App.Current.MainWindow.Dispatcher.Invoke(() =>
Dispatcher.CurrentDispatcher.Invoke(() =>
{
App.M42OptionMenuItem.Enabled = userInfo != null;
App.M42OptionMenuItem.Enabled = userInfo != null;
});
// check, if the are logons needed
@@ -291,6 +301,7 @@ namespace FasdDesktopUi.Basics.Models
await cFasdCockpitConfig.Instance.CheckServerQuickActionAvailabilityAsync();
await cFasdCockpitCommunicationBase.Instance.InitializeAfterOnlineAsync();
cFasdCockpitConfig.Instance.OnUiSettingsChanged();
await Task.Run(async () => await cFasdCockpitConfig.Instance.InstantiateAnalyticsAsync(cFasdCockpitConfig.SessionId));
}
catch (Exception E)
{
@@ -312,7 +323,7 @@ namespace FasdDesktopUi.Basics.Models
LogException(E);
}
if (IsActive)
if (!ApplicationIsExiting)
{
if (ApiConnectionStatus == enumOnlineStatus.online)
NotifyerSupport.SetNotifyIcon("Default", null, NotifyerSupport.enumIconAlignment.BottomRight);
@@ -334,6 +345,7 @@ namespace FasdDesktopUi.Basics.Models
}
finally
{
OnlineCheckCounter++;
LogMethodEnd(CM);
}
}

View File

@@ -0,0 +1,175 @@
using C4IT.FASD.Base;
using F4SD_AdaptableIcon;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.UiActions;
using System;
using System.Collections.Generic;
namespace FasdDesktopUi.Basics.Models.DTOs
{
// __ __ ____ ____
// | |__| || || \
// | | | | | | | o )
// | | | | | | | _/
// | ` ' | | | | |
// \ / | | | |
// \_/\_/ |____||__|
// the following classes are work in Progress and shouldn't been used
[Obsolete]
internal readonly struct IconInfo
{
public IconData? Overlay { get; }
public double IconScale { get; }
public bool IsInactive { get; }
public string Description { get; }
public IconInfo(bool isInactive = default, string description = null, IconData? overlay = null, double iconScale = 1.0)
{
Overlay = overlay;
IsInactive = isInactive;
Description = description;
IconScale = iconScale;
}
}
[Obsolete]
internal abstract class MenuDataBaseDto
{
private readonly IconData _icon;
public string Title { get; set; }
public string SubTitle { get; set; }
public cUiActionBase Action { get; set; }
public IconInfo IconInformation { get; set; }
public int PositoinIndex { get; set; }
protected MenuDataBaseDto() { }
protected MenuDataBaseDto(cFasdBaseConfigMenuItem menuItemDefinition)
{
_icon = IconDataConverter.Convert(menuItemDefinition.Icon);
Title = menuItemDefinition.Names.GetValue();
}
internal virtual IconData GetIcon() => _icon;
}
[Obsolete]
internal sealed class ContainerMenuDataDto : MenuDataBaseDto
{
public IList<MenuDataBaseDto> SubMenuData { get; set; } = new List<MenuDataBaseDto>();
public ContainerMenuDataDto(cFasdMenuSection sectionDefintion) : base(sectionDefintion)
{
Action = new cSubMenuAction(true); // todo rework subMenuAction
}
}
[Obsolete]
internal sealed class LoadingMenuDataDto : MenuDataBaseDto
{
private readonly IconData _icon = new IconData(enumInternGif.loadingSpinner);
public LoadingMenuDataDto(string loadingText)
{
Title = loadingText;
}
internal override IconData GetIcon() => _icon;
}
[Obsolete]
internal sealed class SearchResultMenuDataDto : MenuDataBaseDto
{
private readonly cFasdApiSearchResultEntry _searchResultEntry;
public enumF4sdSearchResultClass Type { get => _searchResultEntry.Type; }
public SearchResultMenuDataDto(cFasdApiSearchResultEntry searchResultEntry)
{
_searchResultEntry = searchResultEntry;
//Action = new cUiProcessSearchRelationAction()
}
internal override IconData GetIcon()
{
switch (Type)
{
case enumF4sdSearchResultClass.Computer:
return new IconData(enumInternIcons.misc_computer);
case enumF4sdSearchResultClass.User:
return new IconData(enumInternIcons.misc_user);
case enumF4sdSearchResultClass.Phone:
return new IconData(MaterialIcons.MaterialIconType.ic_phone);
case enumF4sdSearchResultClass.Ticket:
break;
case enumF4sdSearchResultClass.VirtualSession:
break;
case enumF4sdSearchResultClass.MobileDevice:
break;
default:
break;
}
throw new NotImplementedException();
}
}
[Obsolete]
internal sealed class SearchRelationMenuDataDto : MenuDataBaseDto
{
private readonly cF4sdApiSearchResultRelation _searchRelation;
public enumF4sdSearchResultClass Type { get => _searchRelation.Type; }
public DateTime LastUsed { get; private set; }
public double UsingFactor { get; private set; }
public Dictionary<string, string> AdditionalInfos { get; private set; } // todo check
public bool IsUsedForCaseEnrichtment { get; set; } // todo check
public string TrailingText { get; set; }
public SearchRelationMenuDataDto(cF4sdApiSearchResultRelation searchRelation)
{
_searchRelation = searchRelation;
//Action = new cUiProcessSearchRelationAction()
}
internal override IconData GetIcon()
{
throw new NotImplementedException();
}
}
[Obsolete]
internal sealed class QuickActionMenuDataDto : MenuDataBaseDto
{
public QuickActionMenuDataDto(cFasdQuickAction quickActionDefinition) : base(quickActionDefinition)
{
Action = cUiActionBase.GetUiAction(quickActionDefinition);
}
}
[Obsolete]
internal sealed class QuickTipMenuDataDto : MenuDataBaseDto
{
public QuickTipMenuDataDto(cFasdQuickTip quickTipDefinition) : base(quickTipDefinition)
{
Title = quickTipDefinition.Names.GetValue();
Action = new cUiQuickTipAction(quickTipDefinition);
}
}
[Obsolete]
internal sealed class CopyTemplateMenuDataDto : MenuDataBaseDto
{
public CopyTemplateMenuDataDto(cCopyTemplate copyActionDefintion) : base(copyActionDefintion)
{
Action = new cUiCopyAction(copyActionDefintion);
}
}
}

View File

@@ -119,6 +119,9 @@ namespace FasdDesktopUi.Basics.Models
{
try
{
if (actionSteps is null)
return;
foreach (var step in actionSteps)
{
if (step.StepType.Equals(type) && step.QuickActionName.Equals(quickActionName))

View File

@@ -1,199 +1,292 @@
using System;
using System.Collections.Generic;
using System.Linq;
using C4IT.FASD.Base;
using F4SD_AdaptableIcon;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.UiActions;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Models
{
//todo: check what properties can/should be set via constructor
public class cMenuDataBase
{
public string MenuText { get; set; }
public string SubMenuText { get; set; }
public string TrailingText { get; set; }
public IconData MenuIcon { get; set; }
public double MenuIconSize { get; set; } = 1.0;
public int IconPositionIndex { get; set; }
public object Data { get; set; }
public List<string> MenuSections { get; set; }
public cUiActionBase UiAction { get; set; }
public cMenuDataBase()
{
}
public cMenuDataBase(cFasdBaseConfigMenuItem menuItem)
{
MenuText = menuItem.Names.GetValue(Default: null);
MenuIcon = IconDataConverter.Convert(menuItem.Icon);
MenuSections = menuItem.Sections;
}
public cMenuDataBase(cFasdQuickAction quickAction, Enums.enumActionDisplayType display) : this(quickAction)
{
SetUiActionDisplayType(display);
}
public cMenuDataBase(cFasdQuickAction quickAction) : this((cFasdBaseConfigMenuItem)quickAction)
{
var tempUiAction = cUiActionBase.GetUiAction(quickAction);
tempUiAction.Name = quickAction.Name;
tempUiAction.Description = quickAction.Descriptions?.GetValue(Default: null);
tempUiAction.AlternativeDescription = quickAction.AlternativeDescriptions?.GetValue(Default: null);
UiAction = tempUiAction;
}
public cMenuDataBase(cCopyTemplate copyTemplate) : this((cFasdBaseConfigMenuItem)copyTemplate)
{
UiAction = new cUiCopyAction(copyTemplate) { Name = copyTemplate.Name, Description = copyTemplate.Descriptions.GetValue(Default: null), DisplayType = Enums.enumActionDisplayType.enabled };
}
public cMenuDataBase(cFasdMenuSection menuSection) : this((cFasdBaseConfigMenuItem)menuSection)
{
IconPositionIndex = -1;
}
public cMenuDataBase(cFasdQuickTip quickTip) : this((cFasdBaseConfigMenuItem)quickTip)
{
UiAction = new cUiQuickTipAction(quickTip) { DisplayType = Enums.enumActionDisplayType.enabled };
}
public void SetUiActionDisplayType(Enums.enumActionDisplayType display)
{
if (this.UiAction != null)
this.UiAction.DisplayType = display;
}
}
public class cMenuDataContainer : cMenuDataBase
{
public string ContainerName { get; private set; }
public List<cMenuDataBase> SubMenuData { get; set; }
public cMenuDataContainer()
{
UiAction = new cSubMenuAction(true) { Name = MenuText, DisplayType = Enums.enumActionDisplayType.enabled };
}
public cMenuDataContainer(cFasdMenuSection menuSection) : base(menuSection)
{
ContainerName = menuSection.TechName;
UiAction = new cSubMenuAction(true) { Name = MenuText, DisplayType = Enums.enumActionDisplayType.enabled };
}
}
public class cMenuDataSearchResult : cMenuDataBase
{
public cMenuDataSearchResult(string menuText, ISearchUiProvider SearchUiProvider, List<cFasdApiSearchResultEntry> searchResults) : base()
{
if (searchResults?.Count <= 0)
return;
MenuText = menuText;
UiAction = new cUiProcessSearchResultAction(menuText, SearchUiProvider, searchResults);
var firstSearchResult = searchResults.First();
MenuIcon = GetMenuIcon(firstSearchResult.Type, firstSearchResult.Infos);
}
static public IconData GetMenuIcon(enumF4sdSearchResultClass searchResultClass, Dictionary<string, string> infos)
{
switch (searchResultClass)
{
case enumF4sdSearchResultClass.Computer:
return new IconData(enumInternIcons.misc_computer);
case enumF4sdSearchResultClass.User:
return new IconData(enumInternIcons.misc_user);
case enumF4sdSearchResultClass.Phone:
return new IconData(MaterialIcons.MaterialIconType.ic_phone);
case enumF4sdSearchResultClass.Ticket:
return new IconData(enumInternIcons.misc_ticket);
case enumF4sdSearchResultClass.MobileDevice:
return new IconData(MaterialIcons.MaterialIconType.ic_smartphone);
case enumF4sdSearchResultClass.VirtualSession:
if (!infos.TryGetValue("Status", out string status))
return new IconData(MaterialIcons.MaterialIconType.ic_cloud_off);
else if (status == nameof(enumCitrixSessionStatus.Active))
return new IconData(MaterialIcons.MaterialIconType.ic_cloud_queue);
else
return new IconData(MaterialIcons.MaterialIconType.ic_cloud_off);
default:
return new IconData(MaterialIcons.MaterialIconType.ic_more_vert);
}
}
}
public sealed class cMenuDataSearchRelation : cMenuDataBase
{
public readonly DateTime LastUsed;
public readonly double UsingLevel = 0;
public readonly Dictionary<string, string> Infos = null;
public bool IsMatchingRelation = false;
public bool IsUsedForCaseEnrichment = false;
public readonly cF4sdApiSearchResultRelation searchResultRelation = null;
public cMenuDataSearchRelation(cF4sdApiSearchResultRelation searchResultRelation)
{
try
{
UiAction = null;
if (searchResultRelation is null)
return;
this.searchResultRelation = searchResultRelation;
MenuText = searchResultRelation.DisplayName;
Data = searchResultRelation;
LastUsed = searchResultRelation.LastUsed;
UsingLevel = searchResultRelation.UsingLevel;
Infos = searchResultRelation.Infos;
MenuIcon = cMenuDataSearchResult.GetMenuIcon(searchResultRelation.Type, searchResultRelation.Infos);
}
catch (Exception E)
{
LogException(E);
}
}
}
public sealed class cMenuDataLoading : cMenuDataBase
{
public cMenuDataLoading(string LoadingText)
{
MenuText = LoadingText;
}
}
public class cFilteredResults
{
public bool AutoContinue { get; set; } = false;
public cFasdApiSearchResultCollection Results { get; set; }
public cF4sdApiSearchResultRelation PreSelectedRelation { get; set; }
public cFilteredResults()
{
}
public cFilteredResults(cFasdApiSearchResultCollection _results)
{
Results = _results ?? new cFasdApiSearchResultCollection();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using C4IT.FASD.Base;
using C4IT.MultiLanguage;
using F4SD_AdaptableIcon;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.UiActions;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Models
{
//todo: check what properties can/should be set via constructor
public class cMenuDataBase
{
public string MenuText { get; set; }
public string SubMenuText { get; set; }
public string TrailingText { get; set; }
public MenuIconInfo MenuIcon { get; set; }
public double MenuIconSize { get; set; } = 1.0;
public int IconPositionIndex { get; set; }
public object Data { get; set; }
public List<string> MenuSections { get; set; }
public cUiActionBase UiAction { get; set; }
public class MenuIconInfo
{
public readonly IconData Icon;
public readonly IconData? Overlay;
public readonly bool IsInactive;
public readonly string Description;
public MenuIconInfo(IconData icon, string Description = null, bool isInactive = false, IconData? overlay = null)
{
Icon = icon;
IsInactive = isInactive;
this.Description = Description;
Overlay = overlay;
}
}
public cMenuDataBase()
{
}
public cMenuDataBase(cFasdBaseConfigMenuItem menuItem)
{
MenuText = menuItem.Names.GetValue(Default: null);
MenuIcon = new MenuIconInfo(IconDataConverter.Convert(menuItem.Icon));
MenuSections = menuItem.Sections;
if (!string.IsNullOrEmpty(menuItem.Section))
MenuSections.Add(menuItem.Section);
MenuSections = MenuSections.Distinct().ToList();
}
public cMenuDataBase(cFasdQuickAction quickAction, Enums.enumActionDisplayType display) : this(quickAction)
{
SetUiActionDisplayType(display);
}
public cMenuDataBase(cFasdQuickAction quickAction) : this((cFasdBaseConfigMenuItem)quickAction)
{
var tempUiAction = cUiActionBase.GetUiAction(quickAction);
tempUiAction.Name = quickAction.Name;
tempUiAction.Description = quickAction.Descriptions?.GetValue(Default: null);
tempUiAction.AlternativeDescription = quickAction.AlternativeDescriptions?.GetValue(Default: null);
UiAction = tempUiAction;
}
public cMenuDataBase(cCopyTemplate copyTemplate) : this((cFasdBaseConfigMenuItem)copyTemplate)
{
UiAction = new cUiCopyAction(copyTemplate) { Name = copyTemplate.Name, Description = copyTemplate.Descriptions.GetValue(Default: null), DisplayType = Enums.enumActionDisplayType.enabled };
}
public cMenuDataBase(cFasdMenuSection menuSection) : this((cFasdBaseConfigMenuItem)menuSection)
{
IconPositionIndex = -1;
}
public cMenuDataBase(cFasdQuickTip quickTip) : this((cFasdBaseConfigMenuItem)quickTip)
{
UiAction = new cUiQuickTipAction(quickTip) { DisplayType = Enums.enumActionDisplayType.enabled, Name = quickTip.Name };
}
public void SetUiActionDisplayType(Enums.enumActionDisplayType display)
{
if (this.UiAction != null)
this.UiAction.DisplayType = display;
}
}
public class cMenuDataContainer : cMenuDataBase
{
public string ContainerName { get; private set; }
public List<cMenuDataBase> SubMenuData { get; set; } = new List<cMenuDataBase>();
public cMenuDataContainer()
{
UiAction = new cSubMenuAction(true) { Name = MenuText, DisplayType = Enums.enumActionDisplayType.enabled };
}
public cMenuDataContainer(cFasdMenuSection menuSection) : base(menuSection)
{
ContainerName = menuSection.TechName;
UiAction = new cSubMenuAction(true) { Name = MenuText, DisplayType = Enums.enumActionDisplayType.enabled };
}
}
public class cMenuDataSearchResult : cMenuDataBase
{
public cMenuDataSearchResult(string menuText, ISearchUiProvider SearchUiProvider, List<cFasdApiSearchResultEntry> searchResults) : base()
{
if (searchResults?.Count <= 0)
return;
MenuText = menuText;
UiAction = new cUiProcessSearchResultAction(menuText, SearchUiProvider, searchResults);
var firstSearchResult = searchResults.First();
MenuIcon = GetMenuIcon(firstSearchResult.Type, firstSearchResult.Infos);
}
static private MenuIconInfo GetTicketIcon(Dictionary<string, string> infos)
{
bool isInactive = false;
if (infos.TryGetValue("StatusId", out var ticketStatusId))
{
if (Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus))
{
switch (ticketStatus)
{
case enumTicketStatus.Closed:
isInactive = true;
break;
default:
break;
}
}
}
string description = null;
var overlay = isInactive ? (IconData?)new IconData(enumInternIcons.misc_disabledOverlay) : null;
if (isInactive)
{
}
if (infos.TryGetValue("TicketType", out var ticketType))
{
if (Enum.TryParse(ticketType, true, out enumTicketType parsedTicketType))
{
switch (parsedTicketType)
{
case enumTicketType.Incident:
if (isInactive)
description = cMultiLanguageSupport.GetItem("Searchbar.Item.Incident.Closed");
else
description = cMultiLanguageSupport.GetItem("Searchbar.Item.Incident.Active");
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_bug_report), description, isInactive, overlay);
case enumTicketType.ServiceRequest:
if (isInactive)
description = cMultiLanguageSupport.GetItem("Searchbar.Item.ServiceRequest.Closed");
else
description = cMultiLanguageSupport.GetItem("Searchbar.Item.ServiceRequest.Active");
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_room_service), description, isInactive, overlay);
case enumTicketType.UnclassifiedTicket:
if (isInactive)
description = cMultiLanguageSupport.GetItem("Searchbar.Item.Unclassified.Closed");
else
description = cMultiLanguageSupport.GetItem("Searchbar.Item.Unclassified.Active");
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_confirmation_number), description, isInactive, overlay);
default:
break;
}
}
}
if (isInactive)
description = cMultiLanguageSupport.GetItem("Searchbar.Item.Ticket.Closed");
else
description = cMultiLanguageSupport.GetItem("Searchbar.Item.Ticket.Active");
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_mail_outline), description, isInactive, overlay);
}
static private MenuIconInfo GetVirtualSessionIcon(Dictionary<string, string> infos)
{
if (infos.TryGetValue("Status", out string status))
{
if (status == nameof(enumCitrixSessionStatus.Active))
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_cloud_queue));
}
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_cloud_off));
}
static public MenuIconInfo GetMenuIcon(enumF4sdSearchResultClass searchResultClass, Dictionary<string, string> infos)
{
switch (searchResultClass)
{
case enumF4sdSearchResultClass.Computer:
return new MenuIconInfo(new IconData(enumInternIcons.misc_computer));
case enumF4sdSearchResultClass.User:
return new MenuIconInfo(new IconData(enumInternIcons.misc_user));
case enumF4sdSearchResultClass.Phone:
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_phone));
case enumF4sdSearchResultClass.Ticket:
return GetTicketIcon(infos);
case enumF4sdSearchResultClass.MobileDevice:
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_smartphone));
case enumF4sdSearchResultClass.VirtualSession:
return GetVirtualSessionIcon(infos);
default:
return new MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_more_vert));
}
}
}
public sealed class cMenuDataSearchRelation : cMenuDataBase
{
public readonly DateTime LastUsed;
public readonly double UsingLevel = 0;
public readonly Dictionary<string, string> Infos = null;
public bool IsMatchingRelation = false;
public bool IsUsedForCaseEnrichment = false;
public readonly cF4sdApiSearchResultRelation searchResultRelation = null;
public cMenuDataSearchRelation(cF4sdApiSearchResultRelation searchResultRelation)
{
try
{
UiAction = null;
if (searchResultRelation is null)
return;
this.searchResultRelation = searchResultRelation;
MenuText = searchResultRelation.DisplayName;
Data = searchResultRelation;
LastUsed = searchResultRelation.LastUsed;
UsingLevel = searchResultRelation.UsingLevel;
Infos = searchResultRelation.Infos;
MenuIcon = cMenuDataSearchResult.GetMenuIcon(searchResultRelation.Type, searchResultRelation.Infos);
}
catch (Exception E)
{
LogException(E);
}
}
}
public sealed class cMenuDataLoading : cMenuDataBase
{
public cMenuDataLoading(string LoadingText)
{
MenuText = LoadingText;
}
}
public class cFilteredResults
{
public bool AutoContinue { get; set; } = false;
public cFasdApiSearchResultCollection Results { get; set; }
public cF4sdApiSearchResultRelation PreSelectedRelation { get; set; }
public cFilteredResults()
{
}
public cFilteredResults(cFasdApiSearchResultCollection _results)
{
Results = _results ?? new cFasdApiSearchResultCollection();
}
}
}

View File

@@ -49,7 +49,7 @@ namespace FasdDesktopUi.Basics.Models
try
{
cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
cUtility.RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
var outputTable = dataProvider.HealthCardDataHelper.HealthCardRawData.GetTableByName(valueAdress.ValueTable, true);

View File

@@ -1,6 +1,7 @@
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Services.Models;
using FasdDesktopUi.Basics.UiActions;
using System.Linq;
using static C4IT.FASD.Base.cF4SDHealthCardRawData;
namespace FasdDesktopUi.Basics.Models
@@ -17,5 +18,17 @@ namespace FasdDesktopUi.Basics.Models
public cUiActionBase UiActionTitle { get; set; } = null;
public cUiActionBase UiActionValue { get; set; } = null;
public cHealthCardDetailsTable ValuedDetails { get; set; } = null;
public cWidgetValueModel() { }
public cWidgetValueModel(CockpitValueDisplayData displayData, enumHighlightColor highlightColor, cUiActionBase titleUiAction)
{
Title = displayData?.Title;
Value = displayData?.Values?.FirstOrDefault() ?? (displayData.IsLoading ? "..." : null);
HighlightIn = highlightColor;
IsLoading = displayData?.IsLoading ?? true;
UiActionTitle = titleUiAction;
UiActionValue = displayData?.UiActions?.FirstOrDefault();
}
}
}

View File

@@ -286,18 +286,20 @@ namespace FasdDesktopUi.Basics
public bool isSeen { get; set; } = false;
protected DateTime LastRefresh = DateTime.MinValue;
public IRelationService RelationService { get; private set; }
public List<cFasdApiSearchResultEntry> SelectedSearchResult { get; private set; }
public List<cF4sdApiSearchResultRelation> Relations { get; protected set; }
public ISearchUiProvider SearchUiProvider { get; private set; }
public cSearchHistoryEntryBase(string DisplayText, List<cFasdApiSearchResultEntry> selectedSearchResult, List<cF4sdApiSearchResultRelation> relations, ISearchUiProvider SearchUiProvider)
public cSearchHistoryEntryBase(string DisplayText, List<cFasdApiSearchResultEntry> selectedSearchResult, List<cF4sdApiSearchResultRelation> relations, ISearchUiProvider SearchUiProvider, IRelationService relationService)
{
this.DisplayText = DisplayText;
this.isSeen = isSeen;
this.SelectedSearchResult = selectedSearchResult;
this.Relations = relations;
this.SearchUiProvider = SearchUiProvider;
RelationService = relationService;
LastRefresh = DateTime.UtcNow;
}
@@ -313,7 +315,7 @@ namespace FasdDesktopUi.Basics
{
public string HeaderText { get; private set; }
public cSearchHistorySearchResultEntry(string DisplayText, string HeaderText, List<cFasdApiSearchResultEntry> selectedSearchResult, List<cF4sdApiSearchResultRelation> relations, ISearchUiProvider SearchUiProvider) : base(DisplayText, selectedSearchResult, relations, SearchUiProvider)
public cSearchHistorySearchResultEntry(string DisplayText, string HeaderText, List<cFasdApiSearchResultEntry> selectedSearchResult, List<cF4sdApiSearchResultRelation> relations, ISearchUiProvider SearchUiProvider, IRelationService relationService) : base(DisplayText, selectedSearchResult, relations, SearchUiProvider, relationService)
{
this.HeaderText = HeaderText;
LastRefresh = DateTime.UtcNow;
@@ -337,7 +339,7 @@ namespace FasdDesktopUi.Basics
{
public cF4sdApiSearchResultRelation SelectedRelation { get; private set; }
public cSearchHistoryRelationEntry(string DisplayText, List<cFasdApiSearchResultEntry> selectedSearchResult, List<cF4sdApiSearchResultRelation> relations, cF4sdApiSearchResultRelation selectedRealtion, ISearchUiProvider SearchUiProvider) : base(DisplayText, selectedSearchResult, relations, SearchUiProvider)
public cSearchHistoryRelationEntry(string DisplayText, List<cFasdApiSearchResultEntry> selectedSearchResult, List<cF4sdApiSearchResultRelation> relations, cF4sdApiSearchResultRelation selectedRealtion, ISearchUiProvider SearchUiProvider, IRelationService relationService) : base(DisplayText, selectedSearchResult, relations, SearchUiProvider, relationService)
{
SelectedRelation = selectedRealtion;
}

View File

@@ -0,0 +1,15 @@
using C4IT.FASD.Base;
using FasdDesktopUi.Basics.UiActions;
using System.Collections.Generic;
namespace FasdDesktopUi.Basics.Services.Models
{
public class CockpitValueDisplayData
{
public string Title { get; set; }
public IList<string> Values { get; set; }
public IList<enumHealthCardStateLevel> Levels { get; set; }
public bool IsLoading { get; set; }
public IList<cUiActionBase> UiActions { get; set; }
}
}

View File

@@ -19,20 +19,31 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
public static QuickActionProtocollEntry GetQuickActionProtocollEntry(cFasdQuickAction quickActionDefinition, cQuickActionCopyData quickActionCopyData)
{
string ascii = GetAscii(quickActionDefinition, quickActionCopyData);
string html = GetHtml(quickActionDefinition, quickActionCopyData);
string currentLanguage = cMultiLanguageSupport.CurrentLanguage;
return new QuickActionProtocollEntry(ascii, html)
try
{
Id = quickActionDefinition.Id,
Name = quickActionDefinition.Name,
ExecutionTypeId = (int)quickActionDefinition.ExecutionType,
WasRunningOnAffectedDevice = quickActionCopyData.WasRunningOnAffectedDevice,
AffectedDeviceName = quickActionCopyData.AffectedDeviceName,
ResultCode = (int?)quickActionCopyData.QuickActionOutput?.ResultCode,
ErrorMessage = quickActionCopyData.QuickActionOutput?.ErrorDescription,
MeasureValues = GetQuickActionHtmlValueComparison(quickActionCopyData.MeasureValues)
};
cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage ?? currentLanguage;
string ascii = GetAscii(quickActionDefinition, quickActionCopyData);
string html = GetHtml(quickActionDefinition, quickActionCopyData);
return new QuickActionProtocollEntry(ascii, html)
{
Id = quickActionDefinition.Id,
Name = quickActionDefinition.Name,
ExecutionTypeId = (int)quickActionDefinition.ExecutionType,
WasRunningOnAffectedDevice = quickActionCopyData.WasRunningOnAffectedDevice,
AffectedDeviceName = quickActionCopyData.AffectedDeviceName,
ResultCode = (int?)quickActionCopyData.QuickActionOutput?.ResultCode,
ErrorMessage = quickActionCopyData.QuickActionOutput?.ErrorDescription,
MeasureValues = GetQuickActionHtmlValueComparison(quickActionCopyData.MeasureValues)
};
}
finally
{
cMultiLanguageSupport.CurrentLanguage = currentLanguage;
}
}
internal static cQuickActionCopyData GetCopyData(cFasdQuickAction quickActionDefinition, cSupportCaseDataProvider dataProvider, bool wasRunningOnAffectedDevice, cQuickActionOutput quickActionOutput, List<cQuickActionMeasureValue> measureValues)
@@ -93,7 +104,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
{
string ascii = string.Empty;
ascii += GetQuickActionAsciiDescription(quickActionDefinition,copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode);
ascii += GetQuickActionAsciiDescription(quickActionDefinition, copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode);
ascii += GetQuickActionAsciiError(copyData.QuickActionOutput?.ErrorDescription);
ascii += GetQuickActionAsciiOutput(quickActionDefinition, copyData.QuickActionOutput);
ascii += GetQuickActionAsciiValueComparisonString(copyData.MeasureValues);
@@ -101,7 +112,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
return ascii;
}
private static string GetQuickActionAsciiDescription(cFasdQuickAction quickActionDefinition,string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus)
private static string GetQuickActionAsciiDescription(cFasdQuickAction quickActionDefinition, string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus)
{
string asciiDescription = string.Empty;
try
@@ -125,7 +136,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
rawDescription = cMultiLanguageSupport.GetItem("QuickAction.RemoteSession.Copy.Description");
}
asciiDescription = string.Format(rawDescription, quickActionName, deviceName, executionTime.ToString("g", new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)), quickActionStatusString);
}
catch (Exception E)
@@ -259,7 +270,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
output += AsciiSeperator + cMultiLanguageSupport.GetItem("QuickAction.Copy.Measure");
cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
cUtility.RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
foreach (var measureValue in measureValues)
@@ -299,7 +310,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
try
{
output += GetQuickActionHtmlDescription(quickActionDefinition,copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode);
output += GetQuickActionHtmlDescription(quickActionDefinition, copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode);
output += GetQuickActionHtmlError(copyData.QuickActionOutput?.ErrorDescription);
output += GetQuickActionHtmlOutput(quickActionDefinition, copyData.QuickActionOutput);
output += GetQuickActionHtmlValueComparison(copyData.MeasureValues);
@@ -331,7 +342,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
}
var rawDescription = wasRunningOnAffectedDevice ? cMultiLanguageSupport.GetItem("QuickAction.Remote.Copy.Description.Html") : cMultiLanguageSupport.GetItem("QuickAction.Local.Copy.Description.Html");
if(quickActionDefinition.Section == enumDataHistoryOrigin.Citrix.ToString())
if (quickActionDefinition.Section == enumDataHistoryOrigin.Citrix.ToString())
{
rawDescription = cMultiLanguageSupport.GetItem("QuickAction.RemoteSession.Copy.Description.Html");
@@ -479,7 +490,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService
output += "<p>" + cMultiLanguageSupport.GetItem("QuickAction.Copy.Measure.Html") + "</p>";
cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
cUtility.RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
foreach (var measureValue in measureValues)

View File

@@ -9,8 +9,10 @@ namespace FasdDesktopUi.Basics.Services.RelationService
public interface IRelationService
{
event EventHandler<StagedSearchResultRelationsEventArgs> RelationsFound;
event EventHandler RelationsReset;
IEnumerable<cF4sdApiSearchResultRelation> GetLoadedRelations();
void Reset();
IReadOnlyList<cF4sdApiSearchResultRelation> GetLoadedRelations();
Task<cF4sdStagedSearchResultRelationTaskId> LoadRelationsAsync(IEnumerable<cFasdApiSearchResultEntry> relatedTo, CancellationToken token = default);
IRelationService Clone();
}

View File

@@ -14,8 +14,17 @@ namespace FasdDesktopUi.Basics.Services.RelationService
{
internal class RelationService : IRelationService
{
private readonly object _relationsLock = new object();
private IEnumerable<cF4sdApiSearchResultRelation> _relations = new List<cF4sdApiSearchResultRelation>();
public void Reset()
{
lock (_relationsLock)
_relations = _relations.Where(r => r.Type == enumF4sdSearchResultClass.User).ToList();
RelationsReset?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Asynchronously loads relations for the specified search results.
/// </summary>
@@ -27,24 +36,14 @@ namespace FasdDesktopUi.Basics.Services.RelationService
{
try
{
_relations = relatedTo?.Select(searchResult => new cF4sdApiSearchResultRelation(searchResult)).ToList() ?? new List<cF4sdApiSearchResultRelation>();
lock (_relationsLock)
_relations = relatedTo?.Select(searchResult => new cF4sdApiSearchResultRelation(searchResult)).ToList() ?? new List<cF4sdApiSearchResultRelation>();
cF4sdStagedSearchResultRelationTaskId gatherRelationTask = await cFasdCockpitCommunicationBase.Instance.StartGatheringRelations(relatedTo, token);
_ = Task.Run(async () =>
{
const int maxRetryCount = 10;
for (int i = 0; i < maxRetryCount; i++)
{
cF4sdStagedSearchResultRelations stagedRelations = await cFasdCockpitCommunicationBase.Instance.GetStagedRelations(gatherRelationTask.Id, token);
stagedRelations.MergeAsRelationInfosWith(relatedTo);
if (gatherRelationTask is null)
return null;
_relations = _relations.Union(stagedRelations.Relations);
RelationsFound?.Invoke(this, new StagedSearchResultRelationsEventArgs() { RelatedTo = relatedTo, StagedResultRelations = stagedRelations, RelationService = this });
if (stagedRelations?.IsComplete ?? false)
break;
}
});
_ = Task.Run(async () => await GatherRelationsAsync(gatherRelationTask.Id, relatedTo, token));
return gatherRelationTask;
}
@@ -56,15 +55,56 @@ namespace FasdDesktopUi.Basics.Services.RelationService
return null;
}
public IEnumerable<cF4sdApiSearchResultRelation> GetLoadedRelations() => _relations;
private async Task GatherRelationsAsync(Guid gatherTaskId, IEnumerable<cFasdApiSearchResultEntry> relatedTo, CancellationToken token = default)
{
try
{
const int maxRetryCount = 10;
for (int i = 0; i < maxRetryCount; i++)
{
if (token.IsCancellationRequested)
{
await cFasdCockpitCommunicationBase.Instance.StopGatheringRelations(gatherTaskId, CancellationToken.None);
return;
}
cF4sdStagedSearchResultRelations stagedRelations = await cFasdCockpitCommunicationBase.Instance.GetStagedRelations(gatherTaskId, token);
if (stagedRelations is null)
continue;
stagedRelations.MergeAsRelationInfosWith(relatedTo);
lock (_relationsLock)
_relations = _relations.Union(stagedRelations.Relations).ToList();
RelationsFound?.Invoke(this, new StagedSearchResultRelationsEventArgs() { RelatedTo = relatedTo, StagedResultRelations = stagedRelations, RelationService = this });
if (stagedRelations?.IsComplete ?? false)
break;
}
}
catch (Exception ex)
{
LogException(ex);
}
}
public IReadOnlyList<cF4sdApiSearchResultRelation> GetLoadedRelations()
{
lock (_relationsLock)
return _relations.ToList();
}
public IRelationService Clone()
{
RelationService copy = (RelationService)MemberwiseClone();
copy._relations = _relations.Select(r => r).ToList();
RelationService copy = new RelationService();
lock (_relationsLock)
copy._relations = _relations.ToList();
return copy;
}
public event EventHandler RelationsReset;
public event EventHandler<StagedSearchResultRelationsEventArgs> RelationsFound;
}
}

View File

@@ -0,0 +1,136 @@
using C4IT.FASD.Cockpit.Communication;
using F4SD.Gamification.Services;
using FasdCockpitBase.Models.RemoteDesktopConnection;
using FasdCockpitCommunication.RemoteDesktopCommunication;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Services.RemoteDesktop
{
internal static class AgentRemoteDesktopService
{
private static readonly Dictionary<Guid, Process> _viewerProcesses = new Dictionary<Guid, Process>();
internal static async Task<RemoteDesktopConnectionStatusResult> StartRemoteDesktopConnectionAsync(AgentRemoteClientInfo clientInfo, bool isElevated, CancellationToken token = default)
{
const int maxRetryCount = 20;
TimeSpan baseDelay = TimeSpan.FromSeconds(0.5);
AgentRemoteDesktopConnecitonDetails connectionDetails = await cFasdCockpitCommunicationBase.Instance.RemoteDesktopManager.InitiateConnection<AgentRemoteDesktopConnecitonDetails>(clientInfo, isElevated, token);
RemoteConnetionStatusChanged?.Invoke(null, RemoteDesktopConnectionStatus.Initiated);
if (token.IsCancellationRequested)
{
RemoteConnetionStatusChanged?.Invoke(null, RemoteDesktopConnectionStatus.Canceled);
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Canceled);
}
if (connectionDetails is null)
{
LogEntry("Could not initiate remote connection.", C4IT.Logging.LogLevels.Warning);
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Unknown);
}
if (connectionDetails.Errors != null && connectionDetails.Errors.Count > 0)
{
RemoteConnetionStatusChanged?.Invoke(null, RemoteDesktopConnectionStatus.Error);
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Error) { Errors = connectionDetails.Errors.Select(e => e.Message).ToArray() };
}
RemoteDesktopConnectionStatusResult connectionStatus = null;
for (int i = 0; i < maxRetryCount; i++)
{
try
{
connectionStatus = await cFasdCockpitCommunicationBase.Instance.RemoteDesktopManager.GetConnectionStatus(connectionDetails.ConnectionId, token);
LogEntry($"Update {i} RemoteDesktop connection status: {connectionStatus}", C4IT.Logging.LogLevels.Debug);
if (token.IsCancellationRequested || IsRemoteConnectionEstablished(connectionStatus.Status))
break;
await Task.Delay(TimeSpan.FromTicks(baseDelay.Ticks * i));
}
catch (Exception ex)
{
LogException(ex);
}
}
if (token.IsCancellationRequested)
{
RemoteConnetionStatusChanged?.Invoke(null, RemoteDesktopConnectionStatus.Canceled);
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Canceled);
}
RemoteConnetionStatusChanged?.Invoke(null, connectionStatus.Status);
if (connectionStatus.Status != RemoteDesktopConnectionStatus.Accepted)
{
LogEntry($"Could not connect to remote desktop. Status: {connectionStatus}", C4IT.Logging.LogLevels.Warning);
return new RemoteDesktopConnectionStatusResult(connectionStatus.Status);
}
StartViewer(connectionDetails);
GamificationService.TrackAction(F4SD.Gamification.CockpitAction.StartRemoteConnection);
return new RemoteDesktopConnectionStatusResult(RemoteDesktopConnectionStatus.Connected);
}
private static bool IsRemoteConnectionEstablished(RemoteDesktopConnectionStatus status)
{
switch (status)
{
case RemoteDesktopConnectionStatus.Accepted:
case RemoteDesktopConnectionStatus.Connected:
case RemoteDesktopConnectionStatus.Finished:
case RemoteDesktopConnectionStatus.Canceled:
return true;
case RemoteDesktopConnectionStatus.Unknown:
case RemoteDesktopConnectionStatus.Initiated:
default:
return false;
}
}
private static void StartViewer(AgentRemoteDesktopConnecitonDetails connectionDetails)
{
try
{
ProcessStartInfo info = new ProcessStartInfo(GetViewerPath())
{
Arguments = $"-connectionId {connectionDetails.ConnectionId} -phoenixServiceUrl {connectionDetails.PhoenixServiceUrl} -secret {connectionDetails.Secret}"
};
Process process = Process.Start(info);
_viewerProcesses.Add(connectionDetails.ConnectionId, process);
RemoteConnetionStatusChanged?.Invoke(null, RemoteDesktopConnectionStatus.Connected);
}
catch (Exception ex)
{
LogException(ex);
}
}
internal static async Task StopRemoteDesktopConnection(Guid connectionId, CancellationToken token = default)
{
await cFasdCockpitCommunicationBase.Instance.RemoteDesktopManager.StopConnection(connectionId, token);
if (_viewerProcesses.TryGetValue(connectionId, out var process))
process.Close();
}
internal static string GetViewerPath()
{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Phoenix\Phoenix.Viewer.exe").ToString();
}
internal static EventHandler<RemoteDesktopConnectionStatus> RemoteConnetionStatusChanged;
}
}

View File

@@ -0,0 +1,48 @@
using C4IT.FASD.Base;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using System.Collections.Generic;
namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
{
internal static class MenuDataFactory
{
internal static cMenuDataBase GetByName(string name, cNamedParameterList namedParameterEntries, IEnumerable<enumFasdInformationClass> availableInformationClasses)
{
if (!cF4SDCockpitXmlConfig.Instance.MenuItems.TryGetValue(name, out var menuDataDefinition))
return null;
return Create(menuDataDefinition, namedParameterEntries, availableInformationClasses);
}
internal static cMenuDataBase Create(cFasdBaseConfigMenuItem definition, cNamedParameterList namedParameterEntries, IEnumerable<enumFasdInformationClass> availableInformationClasses)
{
cMenuDataBase menuData;
switch (definition)
{
case cFasdQuickAction quickActionDefinition:
menuData = new cMenuDataBase(quickActionDefinition);
break;
case cCopyTemplate copyTemplate:
menuData = new cMenuDataBase(copyTemplate);
break;
case cFasdMenuSection sectionDefinition:
menuData = new cMenuDataContainer(sectionDefinition);
break;
case cFasdQuickTip quickTip:
menuData = new cMenuDataBase(quickTip);
break;
default:
menuData = new cMenuDataBase(definition);
break;
}
enumActionDisplayType displayType = ActionDisplayTypeInspector.GetDisplayType(definition, namedParameterEntries, availableInformationClasses);
menuData.SetUiActionDisplayType(displayType);
return menuData;
}
}
}

View File

@@ -1,7 +1,12 @@
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using FasdCockpitCommunication.RemoteDesktopCommunication;
using FasdDesktopUi.Basics.CustomEvents;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.Models;
using FasdDesktopUi.Basics.Services.SupportCase.Processors;
using FasdDesktopUi.Basics.UiActions;
using FasdDesktopUi.Pages.DetailsPage.Models;
using System;
using System.Collections.Generic;
@@ -12,18 +17,18 @@ using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
{
/// <summary>
/// Used to manage the <see cref="ISupportCase"/> for the UI via the <see cref="SupportCaseProcessor"/>
/// Used to manage the <see cref="ISupportCase"/> for the UI via the <see cref="ISupportCaseProcessor"/>
/// </summary>
public class SupportCaseController
{
private SupportCaseProcessor _supportCaseProcessor;
private ISupportCaseProcessor _supportCaseProcessor;
private cF4sdApiSearchResultRelation _focusedRelation;
private readonly Dictionary<enumFasdInformationClass, cF4sdApiSearchResultRelation> _selectedRelations = new Dictionary<enumFasdInformationClass, cF4sdApiSearchResultRelation>();
private cHealthCard _selectedHealthcard = null;
private bool _hasDirectionConnection = false;
public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get => _supportCaseProcessor?.SupportCaseDataProviderArtifact; }
internal void SetSupportCaseProcessor(SupportCaseProcessor supportCaseProcessor, IEnumerable<cF4sdIdentityEntry> preselectedIdentities)
internal void SetSupportCaseProcessor(ISupportCaseProcessor supportCaseProcessor, IEnumerable<cF4sdIdentityEntry> preselectedIdentities)
{
IEnumerable<cF4sdApiSearchResultRelation> preselectedRelations = GetPreselectedRelations(supportCaseProcessor.GetCaseRelations(), preselectedIdentities);
@@ -88,6 +93,9 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
{
CaseDataChanged?.Invoke(this, e);
if (e.DataTables.Any(t => !t.Name.StartsWith("Computation_")))
_supportCaseProcessor.ProcessComputations(e.Relation, _supportCaseProcessor.GetHealthcardFor(e.Relation).Prerequisites.Computations.Values);
_ = Task.Run(async () =>
{
await UpdateStatusOfSelectedRelations();
@@ -220,7 +228,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
relationEntry.Value.Infos[StatusString] = statusValue;
}
IEnumerable<cHeadingDataModel> newHeadingData = SupportCaseHeadingController.GetHeadingData(_selectedRelations);
IEnumerable<cHeadingDataModel> newHeadingData = GetHeadingData();
HeadingDataChanged?.Invoke(this, new HeadingDataEventArgs(newHeadingData));
}
catch (Exception ex)
@@ -234,18 +242,209 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.LastDataRequest = DateTime.Now;
await _supportCaseProcessor.UpdateLatestCaseDataFor(_focusedRelation);
}
public cCopyTemplate GetCopyTemplate()
{
string defaultCopyTemplate = _selectedHealthcard?.DefaultCopyTemplate
?? cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.DefaultTemplate.Name
?? string.Empty;
public List<List<cWidgetValueModel>> GetWidgetData()
=> _supportCaseProcessor.GetWidgetData(_focusedRelation);
Dictionary<string, cCopyTemplate> copyTemplates = cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates?.CopyTemplates;
if (copyTemplates?.TryGetValue(defaultCopyTemplate, out cCopyTemplate _defaultCopyTemplate) ?? false)
return _defaultCopyTemplate;
else
return null;
}
public List<List<cWidgetValueModel>> GetWidgetsData()
{
try
{
List<List<cWidgetValueModel>> widgetsData = new List<List<cWidgetValueModel>>();
cHealthCard currentHealthCard = _supportCaseProcessor.GetHealthcardFor(_focusedRelation);
IEnumerable<cHealthCardStateCategory> widgetsDefinition = currentHealthCard.CategoriesStatic.StateCategories;
foreach (var widgetDefinition in widgetsDefinition)
{
List<cWidgetValueModel> widgetData = new List<cWidgetValueModel>();
foreach (var widgetValueDefinition in widgetDefinition.States)
{
CockpitValueDisplayData displayData = _supportCaseProcessor.GetCockpitValueDisplayData(widgetValueDefinition, _focusedRelation, true);
cUiActionBase uiAction = _supportCaseProcessor.GetUiAction(widgetValueDefinition);
var widgetValue = new cWidgetValueModel(displayData, GetHighlightColor(displayData?.Levels?.FirstOrDefault() ?? enumHealthCardStateLevel.None), uiAction);
if (widgetValue?.UiActionValue != null && ShouldHideUiActionValue(widgetValue.Value))
widgetValue.UiActionValue.DisplayType = enumActionDisplayType.hidden;
widgetData.Add(widgetValue);
}
widgetsData.Add(widgetData);
}
return widgetsData;
}
catch (Exception ex)
{
LogException(ex);
return null;
}
bool ShouldHideUiActionValue(string widgetValue)
=> string.IsNullOrWhiteSpace(widgetValue) || widgetValue == "0";
}
public cDetailsPageDataHistoryDataModel GetHistoryData()
=> _supportCaseProcessor.GetHistoryData(_focusedRelation);
=> ((SupportCaseProcessor)_supportCaseProcessor).GetHistoryData(_focusedRelation);
public List<cContainerCollectionData> GetContainerData()
=> _supportCaseProcessor.GetContainerData(_focusedRelation);
=> ((SupportCaseProcessor)_supportCaseProcessor).GetContainerData(_focusedRelation);
public List<cMenuDataBase> GetMenuBarData()
=> _supportCaseProcessor.GetMenuBarData(_focusedRelation);
public IEnumerable<cMenuDataBase> GetMenuData()
{
var menuBarDatas = cF4SDCockpitXmlConfig.Instance.MenuItems.ToDictionary(config => config.Key, config => (Config: config.Value, MenuValue: MenuDataFactory.Create(config.Value, _supportCaseProcessor.SupportCaseDataProviderArtifact.NamedParameterEntries, _selectedRelations.Values.Select(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type)).ToList())));
try
{
List<string> menuBarDatasAddedToSection = new List<string>();
foreach (var menuBarData in menuBarDatas.Values)
{
bool isPinned = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.QuickActionsPinned.Contains(menuBarData.Config.Name);
menuBarData.MenuValue.IconPositionIndex = isPinned ? cF4SDCockpitXmlConfig.Instance.HealthCardConfig.QuickActionsPinned.IndexOf(menuBarData.Config.Name) : -1;
// Same Logic in GetFilteredMenuData()
bool hasBeenAddedToSection = TryAddMenuDataToSection(ref menuBarDatas, menuBarData.Config.Section, menuBarData.MenuValue);
foreach (var section in menuBarData.Config.Sections)
{
// todo add test for adding to multiple sections
hasBeenAddedToSection = TryAddMenuDataToSection(ref menuBarDatas, section, menuBarData.MenuValue) || hasBeenAddedToSection; // order is relevent, because data has to be added to section
}
if (hasBeenAddedToSection)
menuBarDatasAddedToSection.Add(menuBarData.Config.Name);
}
foreach (var menuBarData in menuBarDatasAddedToSection)
{
if (cF4SDCockpitXmlConfig.Instance.HealthCardConfig.QuickActionsPinned.Contains(menuBarData))
continue;
menuBarDatas.Remove(menuBarData);
}
return menuBarDatas.Values.Select(data => data.MenuValue);
}
catch (Exception ex)
{
LogException(ex);
return new List<cMenuDataBase>();
}
}
public IEnumerable<cMenuDataBase> GetFilteredMenuData(MenuDataFilter filterQuery)
{
Dictionary<string, (cFasdBaseConfigMenuItem Config, cMenuDataBase MenuValue)> menuBarDatas = cF4SDCockpitXmlConfig.Instance.MenuItems.ToDictionary(config => config.Key, config => (Config: config.Value, MenuValue: MenuDataFactory.Create(config.Value, _supportCaseProcessor.SupportCaseDataProviderArtifact.NamedParameterEntries, _selectedRelations.Values.Select(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type)).ToList())));
try
{
foreach (var menuBarData in menuBarDatas.Values)
{
// Same Logic in GetMenuData()
bool hasBeenAddedToSection = TryAddMenuDataToSection(ref menuBarDatas, menuBarData.Config.Section, menuBarData.MenuValue);
foreach (var section in menuBarData.Config.Sections)
{
// todo add test for adding to multiple sections
hasBeenAddedToSection = TryAddMenuDataToSection(ref menuBarDatas, section, menuBarData.MenuValue) || hasBeenAddedToSection; // order is relevent, because data has to be added to section
}
}
return menuBarDatas.Values.Select(data => data.MenuValue)
.Where(md => md.MenuText.ToLower().Contains(filterQuery?.SearchString?.ToLower()));
}
catch (Exception ex)
{
LogException(ex);
return new List<cMenuDataBase>();
}
}
private bool TryAddMenuDataToSection(ref Dictionary<string, (cFasdBaseConfigMenuItem Config, cMenuDataBase MenuValue)> menuBarDatas, string section, cMenuDataBase menuData)
{
if (string.IsNullOrEmpty(section))
return false;
if (!menuBarDatas.TryGetValue(section, out var sectionMenuBar))
return false;
if (!(sectionMenuBar.MenuValue is cMenuDataContainer containerData))
return false;
if (containerData.UiAction is cSubMenuAction subMenuAction)
{
if (!subMenuAction.SubMenuData.Any(item => item.MenuText == menuData.MenuText)) // todo SubMenuData maybe better as Dictionary<Guid, cMenuDataBase>
subMenuAction.SubMenuData.Add(menuData);
if (!containerData.SubMenuData.Any(item => item.MenuText == menuData.MenuText))
containerData.SubMenuData.Add(menuData);
}
return true;
}
internal IEnumerable<cHeadingDataModel> GetHeadingData()
=> SupportCaseHeadingController.GetHeadingData(_selectedRelations);
private static enumHighlightColor GetHighlightColor(enumHealthCardStateLevel level)
{
switch (level)
{
case enumHealthCardStateLevel.None:
return enumHighlightColor.none;
case enumHealthCardStateLevel.Ok:
return enumHighlightColor.green;
case enumHealthCardStateLevel.Warning:
return enumHighlightColor.orange;
case enumHealthCardStateLevel.Error:
return enumHighlightColor.red;
case enumHealthCardStateLevel.Info:
return enumHighlightColor.blue;
default:
return enumHighlightColor.none;
}
}
internal IEnumerable<cF4sdApiSearchResultRelation> GetRelationsOf(enumFasdInformationClass informationClass)
{
return _supportCaseProcessor.GetCaseRelations().FirstOrDefault(r => r.Key == informationClass);
}
internal AgentRemoteClientInfo GetAgentClientInfo()
{
if (_focusedRelation.Type != enumF4sdSearchResultClass.Computer)
return null;
int deviceId = 0;
int userId = 0;
bool hasAllRequiredNamedParameters =
_supportCaseProcessor.TryGetNamedParameterValue(_focusedRelation, SupportCaseProcessor.AgentOrganisationCodeNamedParameterName, out int organisationId)
&& _supportCaseProcessor.TryGetNamedParameterValue(_focusedRelation, SupportCaseProcessor.AgentUserIdNamedParameterName, out userId)
&& _supportCaseProcessor.TryGetNamedParameterValue(_focusedRelation, SupportCaseProcessor.AgentDeviceIdNamedParameterName, out deviceId);
if (!hasAllRequiredNamedParameters)
return null;
return new AgentRemoteClientInfo()
{
DeviceCode = deviceId,
AccountCode = userId,
OrganisationCode = organisationId
};
}
/// <summary>
/// Raised when the currently for a support case relevant and shown relations have been updated.
@@ -264,4 +463,15 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
public event EventHandler<HeadingDataEventArgs> HeadingDataChanged;
}
public class MenuDataFilter
{
public string SearchString { get; set; }
public MenuDataFilter(string searchString = null)
{
SearchString = searchString;
}
}
}

View File

@@ -68,6 +68,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
{
case enumF4sdSearchResultClass.Computer:
case enumF4sdSearchResultClass.User:
case enumF4sdSearchResultClass.Phone:
isOnline = string.Equals(statusValue, "Online", StringComparison.InvariantCultureIgnoreCase);
break;
case enumF4sdSearchResultClass.Ticket:

View File

@@ -14,7 +14,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
void AddCaseRelations(ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> relations);
ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations();
Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable<string> tablesToLoad);
IEnumerable<object> GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress);
IList<object> GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress, bool getStatic);
void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> tables);
void InvalidateCaseDataCacheFor(cF4sdApiSearchResultRelation relation);
void InvalidateLatestCaseDataCacheFor(cF4sdApiSearchResultRelation relation, out ICollection<cF4SDHealthCardRawData.cHealthCardTable> invalidatedTables);

View File

@@ -0,0 +1,29 @@
using C4IT.FASD.Base;
using FasdDesktopUi.Basics.CustomEvents;
using FasdDesktopUi.Basics.Services.Models;
using FasdDesktopUi.Basics.UiActions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
{
internal interface ISupportCaseProcessor
{
cSupportCaseDataProvider SupportCaseDataProviderArtifact { get; }
event EventHandler<RelationEventArgs> AvailableCaseRelationsAdded;
event EventHandler<SupportCaseDataEventArgs> CaseDataChanged;
void SetSupportCase(ISupportCase supportCase);
CockpitValueDisplayData GetCockpitValueDisplayData(cHealthCardStateBase displayValueDefinition, cF4sdApiSearchResultRelation relation, bool getStatic);
Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable<string> tablesToLoad);
void ProcessComputations(cF4sdApiSearchResultRelation relation, IEnumerable<cHealthCardComputationBase> computations);
Task UpdateLatestCaseDataFor(cF4sdApiSearchResultRelation relation);
ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations();
cHealthCard GetHealthcardFor(cF4sdApiSearchResultRelation relation);
cUiActionBase GetUiAction(cHealthCardStateBase stateDefinition);
bool TryGetNamedParameterValue<T>(cF4sdApiSearchResultRelation relation, string parameterName, out T value);
}
}

View File

@@ -0,0 +1,145 @@
using C4IT.F4SD.DisplayFormatting;
using C4IT.FASD.Base;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
{
internal class SupportCaseDetailsValueProcessesor
{
/// <summary>
/// Transform a value to a <seealso cref="cF4SDHealthCardRawData.cHealthCardDetailsTable"/>
/// </summary>
/// <param name="rawValue">Raw value in form of CSV or JSON</param>
/// <param name="stateDetailsValued">Details definition the transformation is based on</param>
/// <returns></returns>
internal static cF4SDHealthCardRawData.cHealthCardDetailsTable GetDetailsTable(object rawValue, cHealthCardDetailsValued stateDetailsValued)
{
try
{
if (rawValue is null)
return null;
var stringValue = cUtility.RawValueFormatter.GetDisplayValue(rawValue, RawValueType.STRING);
if (stringValue is null)
return null;
List<object[]> tableValues = stateDetailsValued.Format == cHealthCardDetailsValued.ValuedFormat.json
? ParseJson(stringValue, stateDetailsValued)
: ParseCsv(stringValue, stateDetailsValued);
tableValues = tableValues ?? new List<object[]>();
var detailedValueTable = new cF4SDHealthCardRawData.cHealthCardDetailsTable()
{
Name = "Details-" + stateDetailsValued.ParentState.Name,
Columns = stateDetailsValued.Select(v => v.Names.GetValue()).ToList(),
Values = new Dictionary<int, List<object[]>>() { { 0, tableValues } }
};
return detailedValueTable;
}
catch (Exception ex)
{
LogException(ex);
}
return null;
}
private static List<object[]> ParseJson(string text, cHealthCardDetailsValued details)
{
try
{
var jObjects = JsonConvert.DeserializeObject<List<JObject>>(text);
if (jObjects == null || jObjects.Count == 0)
return new List<object[]>();
var values = new List<object[]>();
foreach (JObject jObject in jObjects)
{
var valueRow = new object[details.Count];
for (int i = 0; i < details.Count; i++)
valueRow[i] = null;
foreach (var jProp in jObject.Properties())
{
var name = jProp.Name;
var index = details.FindIndex(v => v.Column.Equals(name, StringComparison.InvariantCultureIgnoreCase));
if (index < 0)
continue;
var column = details[index];
if (jProp.Value is JValue jValue)
{
var value = jValue.Value;
valueRow[index] = cUtility.RawValueFormatter.GetDisplayValue(value, column.DisplayType);
}
}
values.Add(valueRow);
}
return values;
}
catch (Exception)
{
return new List<object[]>();
}
}
private static List<object[]> ParseCsv(string text, cHealthCardDetailsValued details)
{
var values = new List<object[]>();
var rows = text.Split(details.RowSeparator);
foreach (var row in rows)
{
if (string.IsNullOrWhiteSpace(row))
continue;
var entry = new List<object>();
if (details.ColSeparator == null)
{
entry.Add(row.Trim());
}
else
{
var columns = row.Split((char)details.ColSeparator);
foreach (var column in columns)
entry.Add(column?.Trim());
}
while (entry.Count < details.Count)
entry.Add(null);
values.Add(entry.ToArray());
}
return values;
}
/// <summary>
/// Get a display string based on StateDetails and its values
/// </summary>
internal static string GetDetailStringValue(cHealthCardDetailsBase details, cF4SDHealthCardRawData.cHealthCardDetailsTable detailTableValueTable)
{
if (detailTableValueTable?.Values is null || detailTableValueTable.Values.Count == 0)
return null;
var tableValues = detailTableValueTable.Values.First().Value;
if (detailTableValueTable.Columns.Count >= 1 && tableValues.Count == 1)
return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.First()?.First(), details.First().DisplayType);
else
return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.Count, RawValueType.STRING);
}
}
}

View File

@@ -0,0 +1,643 @@
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using FasdDesktopUi.Basics.CustomEvents;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.Models;
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
using FasdDesktopUi.Basics.UiActions;
using FasdDesktopUi.Pages.DetailsPage.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
{
/// <summary>
/// Used for processing raw data of a <see cref="ISupportCase"/> for the UI in a certain way.
/// </summary>
internal class SupportCaseProcessor : ISupportCaseProcessor
{
internal const string AgentDeviceIdNamedParameterName = "F4SD_Agent_DeviceId";
internal const string AgentUserIdNamedParameterName = "F4SD_Agent_UserId";
internal const string AgentOrganisationCodeNamedParameterName = "F4SD_Agent_OrganisationId";
private ISupportCase _supportCase;
public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get => _supportCase?.SupportCaseDataProviderArtifact; }
private readonly Dictionary<cF4sdApiSearchResultRelation, cDetailsPageData> _detailsPageDataCache = new Dictionary<cF4sdApiSearchResultRelation, cDetailsPageData>();
private readonly Dictionary<cF4sdApiSearchResultRelation, Dictionary<string, object>> _namedParameterCache = new Dictionary<cF4sdApiSearchResultRelation, Dictionary<string, object>>();
private readonly Dictionary<cF4sdApiSearchResultRelation, Dictionary<string, IList<object>>> _computationCache = new Dictionary<cF4sdApiSearchResultRelation, Dictionary<string, IList<object>>>();
public void SetSupportCase(ISupportCase supportCase)
{
if (_supportCase != null)
{
_supportCase.CaseRelationsAdded -= HandleSupportCaseRelationsAdded;
_supportCase.SupportCaseDataCacheHasChanged -= HandleSupportCaseDataCacheHasChanged;
}
_supportCase = supportCase;
_supportCase.CaseRelationsAdded += HandleSupportCaseRelationsAdded;
_supportCase.SupportCaseDataCacheHasChanged += HandleSupportCaseDataCacheHasChanged;
}
private void HandleSupportCaseRelationsAdded(object sender, RelationEventArgs e)
=> AvailableCaseRelationsAdded?.Invoke(this, e);
private async void HandleSupportCaseDataCacheHasChanged(object sender, SupportCaseDataEventArgs e)
{
bool isArtifactShowingCorrectHealthCard
= SupportCaseDataProviderArtifact.HealthCardDataHelper.SelectedHealthCard == GetHealthcardFor(e.Relation);
if (!isArtifactShowingCorrectHealthCard)
{
// todo this can probably be removed, as soon as the last dependency of the SupportCaseDataProviderArtifact is gone.
// till then the detailspageData gets overriden with the detailspageData of the new relation.
// However, the removal shouldn't be much of a problem, due to the fact the Artifact also stores the raw data
_detailsPageDataCache.Remove(e.Relation);
return;
}
await EnsureDetailsPageDataCachedAsync(e.Relation).ConfigureAwait(false);
UpdateNamedParameters(e.Relation, e.DataTables);
CaseDataChanged?.Invoke(this, e);
}
private async Task EnsureDetailsPageDataCachedAsync(cF4sdApiSearchResultRelation relation)
{
if (!_detailsPageDataCache.TryGetValue(relation, out var cachedData))
{
_detailsPageDataCache[relation] = await _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataAsync().ConfigureAwait(false);
return;
}
cDetailsPageData detailData = _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataWithoutHeading();
cachedData.WidgetData = detailData.WidgetData;
cachedData.DataHistoryList = detailData.DataHistoryList;
cachedData.MenuBarData = detailData.MenuBarData;
cachedData.DataContainerCollectionList = detailData.DataContainerCollectionList;
}
private void UpdateNamedParameters(cF4sdApiSearchResultRelation relation, IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> dataTables)
{
try
{
if (!_namedParameterCache.ContainsKey(relation))
_namedParameterCache.Add(relation, new Dictionary<string, object>());
var healthcard = GetHealthcardFor(relation);
foreach (var namedParameter in cHealthCardPrerequisites.GetNamedParameters(healthcard).Values)
{
var table = dataTables.FirstOrDefault(t => t.Name == namedParameter.DatabaseInfo.ValueTable);
if (table is null)
continue;
if (!table.Columns.TryGetValue(namedParameter.DatabaseInfo.ValueColumn, out var column))
continue;
string value = cUtility.RawValueFormatter.GetDisplayValue(column.Values.FirstOrDefault(), namedParameter.Display);
_namedParameterCache[relation][namedParameter.ParameterName] = value;
}
AddDefaultNamedParameters();
}
catch (Exception ex)
{
LogException(ex);
}
void AddDefaultNamedParameters()
{
var table = dataTables.FirstOrDefault(t => t.Name == "agnt-computer");
if (table != null)
{
if (table.Columns.TryGetValue("id", out var agentDeviceIdColumn))
_namedParameterCache[relation][AgentDeviceIdNamedParameterName] = agentDeviceIdColumn.Values.FirstOrDefault();
}
table = dataTables.FirstOrDefault(t => t.Name == "agnt-user");
if (table != null)
{
if (table.Columns.TryGetValue("id", out var agentUserColumn))
_namedParameterCache[relation][AgentUserIdNamedParameterName] = agentUserColumn.Values.FirstOrDefault();
}
_namedParameterCache[relation][AgentOrganisationCodeNamedParameterName] = cCockpitConfiguration.Instance.agentApiConfiguration.OrganizationCode;
}
}
public async Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable<string> tablesToLoad)
{
_ = Task.Run(async () => await _supportCase.LoadSupportCaseDataAsync(relation, tablesToLoad.Where(t => !t.Contains("-details-"))));
await EnsureDetailsPageDataCachedAsync(relation).ConfigureAwait(false);
_supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.UpdateNamedParameterEntries();
CaseDataChanged?.Invoke(this, new SupportCaseDataEventArgs());
}
public void ProcessComputations(cF4sdApiSearchResultRelation relation, IEnumerable<cHealthCardComputationBase> computations)
{
if (!_computationCache.ContainsKey(relation))
_computationCache.Add(relation, new Dictionary<string, IList<object>>());
var cachedComputations = _computationCache[relation];
var computationTables = new List<cF4SDHealthCardRawData.cHealthCardTable>();
foreach (cHealthCardComputationBase computation in computations)
{
AddComputationTable(computation);
AddComputationTableStatic(computation);
}
CaseDataChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation, DataTables = computationTables });
void AddComputationTable(cHealthCardComputationBase computation)
{
var computationTable = new cF4SDHealthCardRawData.cHealthCardTable() { Name = $"Computation_{computation.Name}", AlternateStaticTable = $"Computation_{computation.Name}_latest" };
var computationColumn = new cF4SDHealthCardRawData.cHealthCardTableColumn(computationTable);
for (int i = 0; i < cF4SDCockpitXmlConfig.Instance.HealthCardConfig.SearchResultAge; i++)
{
object[] valuesRequiredToCompute = computation.Values
.Where(v => v.ValueTable != null && v.ValueColumn != null)
.Select(v => _supportCase.GetSupportCaseHealthcardData(relation, v, false)?.ElementAtOrDefault(i))
.ToArray();
object computedValue = computation.Compute(valuesRequiredToCompute);
computationColumn.Values.Add(computedValue);
}
computationTable.Columns = new Dictionary<string, cF4SDHealthCardRawData.cHealthCardTableColumn>() { ["default"] = computationColumn };
computationTables.Add(computationTable);
cachedComputations[computation.Name] = computationColumn.Values;
}
void AddComputationTableStatic(cHealthCardComputationBase computation)
{
var computationTableStatic = new cF4SDHealthCardRawData.cHealthCardTable() { Name = $"Computation_{computation.Name}_latest" };
var computationColumnStatic = new cF4SDHealthCardRawData.cHealthCardTableColumn(computationTableStatic);
object[] staticValuesRequiredToCompute = computation.Values
.Where(v => v.ValueTable != null && v.ValueColumn != null)
.Select(v => _supportCase.GetSupportCaseHealthcardData(relation, v, true)?.ElementAtOrDefault(0))
.ToArray();
object computedStaticValue = computation.Compute(staticValuesRequiredToCompute);
computationColumnStatic.Values.Add(computedStaticValue);
computationTableStatic.Columns = new Dictionary<string, cF4SDHealthCardRawData.cHealthCardTableColumn>() { ["default"] = computationColumnStatic };
computationTables.Add(computationTableStatic);
cachedComputations[$"{computation.Name}_latest"] = computationColumnStatic.Values;
}
}
public async Task UpdateLatestCaseDataFor(cF4sdApiSearchResultRelation relation)
{
try
{
int? agentUserId = relation.Identities.FirstOrDefault(i => i.Class == enumFasdInformationClass.User)?.agentId;
int? agentDeviceId = relation.Identities.FirstOrDefault(i => i.Class == enumFasdInformationClass.Computer)?.agentId;
await ActualizeDataAsync(agentUserId, agentDeviceId);
_supportCase.InvalidateLatestCaseDataCacheFor(relation, out var invalidatedTables);
_detailsPageDataCache.Remove(relation);
await _supportCase.LoadSupportCaseDataAsync(relation, invalidatedTables.Where(t => !t.Name.StartsWith("Computation_")).Select(t => t.Name));
}
catch (Exception ex)
{
LogException(ex);
}
}
private async Task<enumActualizeStatus> ActualizeDataAsync(int? agentUserId, int? agentDeviceId)
{
var status = enumActualizeStatus.unknown;
if (!agentUserId.HasValue && !agentDeviceId.HasValue)
return status;
try
{
TimeSpan refreshDelay = TimeSpan.FromMilliseconds(500);
const int maxPollCount = 20;
if (!agentDeviceId.HasValue)
{
LogEntry("Coudldn't acutalize data. There was no valid AgentDeviceId found.", LogLevels.Error);
return status;
}
var taskId = await cFasdCockpitCommunicationBase.Instance.ActualizeAgentData(agentDeviceId.Value, agentUserId);
if (taskId == Guid.Empty)
return enumActualizeStatus.failed;
enumFasdInformationClass informationClass = agentUserId != null ? enumFasdInformationClass.User : enumFasdInformationClass.Computer;
int pollCount = 0;
do
{
status = await cFasdCockpitCommunicationBase.Instance.GetActualizeAgentDataStatus(taskId, informationClass);
if (status == enumActualizeStatus.unknown)
{
pollCount++;
if (pollCount >= maxPollCount)
return status;
await Task.Delay(refreshDelay);
}
} while (status == enumActualizeStatus.unknown);
}
catch (Exception E)
{
LogException(E);
}
return status;
}
public ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations()
=> _supportCase.GetCaseRelations();
public cHealthCard GetHealthcardFor(cF4sdApiSearchResultRelation relation)
{
var availableHealthCards = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.HealthCards?.Values;
if (availableHealthCards is null || availableHealthCards.Count == 0)
return null;
return availableHealthCards
.FirstOrDefault(hc =>
hc.InformationClasses.All(i => i == cF4sdIdentityEntry.GetFromSearchResult(relation.Type))
&& HasCockpitUserRequiredRoles(hc.RequiredRoles));
}
private static bool HasCockpitUserRequiredRoles(List<string> requiredRoles)
{
try
{
if (requiredRoles is null || requiredRoles.Count == 0)
return true;
List<string> roles = null;
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
{
roles = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles;
}
if (roles is null || roles.Count == 0)
return false;
foreach (var requiredRole in requiredRoles)
{
if (roles.Contains(requiredRole, StringComparer.InvariantCultureIgnoreCase))
return true;
}
}
catch (Exception E)
{
LogException(E);
}
return false;
}
public cDetailsPageDataHistoryDataModel GetHistoryData(cF4sdApiSearchResultRelation relation)
{
cDetailsPageDataHistoryDataModel historyData = null;
if (_detailsPageDataCache.TryGetValue(relation, out var detailsData))
historyData = detailsData?.DataHistoryList;
return historyData ?? new cDetailsPageDataHistoryDataModel();
}
public List<cContainerCollectionData> GetContainerData(cF4sdApiSearchResultRelation relation)
{
List<cContainerCollectionData> containerData = null;
if (_detailsPageDataCache.TryGetValue(relation, out var detailsData))
containerData = detailsData?.DataContainerCollectionList;
return containerData ?? new List<cContainerCollectionData>();
}
public CockpitValueDisplayData GetCockpitValueDisplayData(cHealthCardStateBase displayValueDefinition, cF4sdApiSearchResultRelation relation, bool getStatic)
{
IList<object> rawValues = GetRawValues(displayValueDefinition, relation, getStatic);
cHealthCardStateBase definitionForLevel = GetDefinitionForLevel(displayValueDefinition);
IList<enumHealthCardStateLevel> predefinedLevel = GetPredefinedLevels(displayValueDefinition, relation, getStatic);
cF4SDHealthCardRawData.cHealthCardDetailsTable valueDetailsTable = null;
if (displayValueDefinition?.Details is cHealthCardDetailsValued detailsValued)
valueDetailsTable = SupportCaseDetailsValueProcessesor.GetDetailsTable(rawValues?.FirstOrDefault(), detailsValued);
return new CockpitValueDisplayData()
{
IsLoading = false,
Title = displayValueDefinition?.Names.GetValue(),
Values = rawValues?.Select(raw => GetDisplayValue(raw, displayValueDefinition, valueDetailsTable)).ToList(),
Levels = predefinedLevel ?? rawValues?.Select(raw => GetLevel(raw, definitionForLevel, 0)).ToList(),
UiActions = GetValueUiActions(displayValueDefinition, valueDetailsTable)
};
}
private IList<object> GetRawValues(cHealthCardStateBase stateDefinition, cF4sdApiSearchResultRelation relation, bool getStatic)
{
const string computationPrefix = "Computation_";
if (stateDefinition?.DatabaseInfo?.ValueTable?.StartsWith(computationPrefix) ?? false)
if (_computationCache.TryGetValue(relation, out var cachedComputationValues))
if (cachedComputationValues.TryGetValue(stateDefinition.DatabaseInfo.ValueTable.Substring(computationPrefix.Length) + (getStatic ? "_latest" : string.Empty), out var computedValues))
return computedValues;
return _supportCase.GetSupportCaseHealthcardData(relation, stateDefinition.DatabaseInfo, getStatic);
}
private IList<cUiActionBase> GetValueUiActions(cHealthCardStateBase stateDefinition, cF4SDHealthCardRawData.cHealthCardDetailsTable detailedValueTable)
{
if (stateDefinition.Details is null)
return null;
List<cUiActionBase> uiActions = new List<cUiActionBase>(cF4SDCockpitXmlConfig.Instance.HealthCardConfig.SearchResultAge);
for (int i = 0; i < cF4SDCockpitXmlConfig.Instance.HealthCardConfig.SearchResultAge; i++)
{
uiActions.Add(new cShowDetailedDataAction(stateDefinition, i, detailedValueTable) { DisplayType = enumActionDisplayType.enabled });
}
return uiActions;
}
private IList<enumHealthCardStateLevel> GetHighestLevels(List<IList<enumHealthCardStateLevel>> allLevels, bool isNotTransparent)
{
var highestLevels = new List<enumHealthCardStateLevel>();
int maxLevelCount = allLevels?.Where(l => l != null).Select(l => l.Count).DefaultIfEmpty(0).Max() ?? 0;
for (int i = 0; i < maxLevelCount; i++)
{
enumHealthCardStateLevel highestLevel = enumHealthCardStateLevel.None;
foreach (var levels in allLevels)
{
if (levels == null || levels.Count <= i)
continue;
highestLevel = (enumHealthCardStateLevel)Math.Max((int)highestLevel, (int)levels[i]);
if (highestLevel == enumHealthCardStateLevel.Error)
break;
}
if (highestLevel <= enumHealthCardStateLevel.Ok)
highestLevel = isNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
highestLevels.Add(highestLevel);
}
return highestLevels;
}
private string GetDisplayValue(object rawValue, cHealthCardStateBase displayValueDefinition, cF4SDHealthCardRawData.cHealthCardDetailsTable detailedValueTable)
{
if (displayValueDefinition?.Details != null && detailedValueTable != null)
return SupportCaseDetailsValueProcessesor.GetDetailStringValue(displayValueDefinition.Details, detailedValueTable);
else if (displayValueDefinition is cHealthCardStateTranslation translationDefinition)
return GetTranslationValue(rawValue, translationDefinition);
else if (displayValueDefinition is cHealthCardStateAggregation)
return "Ø";
else
return cUtility.RawValueFormatter.GetDisplayValue(rawValue, displayValueDefinition.DisplayType);
}
private string GetTranslationValue(object rawValue, cHealthCardStateTranslation translationDefinition)
{
ITranslatorObject abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(translationDefinition, translationDefinition.Translation);
if (!(abstractTranslation is cHealthCardTranslator translation))
return null;
if (rawValue is null)
return translation.DefaultTranslation?.Translation?.GetValue();
string defaultValue = translation.DefaultTranslation?.Translation?.GetValue() ?? rawValue.ToString();
foreach (var translationEntry in translation.Translations)
{
if (translationEntry.Values.Any(v => string.Equals(rawValue.ToString(), v, StringComparison.InvariantCultureIgnoreCase)))
return translationEntry.Translation.GetValue();
}
return defaultValue;
}
private static enumHealthCardStateLevel GetLevel(object rawValue, cHealthCardStateBase stateDefinition, int referenceDays)
{
if (stateDefinition is null || rawValue is null)
return enumHealthCardStateLevel.None;
if (stateDefinition is cHealthCardStateAggregation)
throw new NotImplementedException();
try
{
if (stateDefinition is cHealthCardStateLevel levelDefinition)
{
var valueDouble = cF4SDHealthCardRawData.GetDouble(rawValue);
if (valueDouble != null)
{
if (levelDefinition.IsDirectionUp)
return valueDouble >= levelDefinition.Error ? enumHealthCardStateLevel.Error : valueDouble >= levelDefinition.Warning ? enumHealthCardStateLevel.Warning : stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
else
return valueDouble <= levelDefinition.Error ? enumHealthCardStateLevel.Error : valueDouble <= levelDefinition.Warning ? enumHealthCardStateLevel.Warning : stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
}
}
else if (stateDefinition is cHealthCardStateVersion stateVersion)
{
Version valueVersion = cF4SDHealthCardRawData.GetVersion(rawValue);
if (valueVersion is null)
return enumHealthCardStateLevel.None;
if (stateVersion.IsDirectionUp)
return valueVersion >= stateVersion.Error ? enumHealthCardStateLevel.Error : valueVersion >= stateVersion.Warning ? enumHealthCardStateLevel.Warning : stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
else
return valueVersion <= stateVersion.Error ? enumHealthCardStateLevel.Error : valueVersion <= stateVersion.Warning ? enumHealthCardStateLevel.Warning : stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
}
else if (stateDefinition is cHealthCardStateDateTime stateDateTime)
{
DateTime? valueDateTime = cF4SDHealthCardRawData.GetDateTime(rawValue);
if (valueDateTime is null)
return enumHealthCardStateLevel.None;
DateTime tempDateTime = valueDateTime.Value;
double differenceHours = Math.Floor((DateTime.UtcNow.AddDays(-referenceDays) - tempDateTime).TotalHours);
if (stateDateTime.IsDirectionUp)
return differenceHours >= stateDateTime.ErrorHours ? enumHealthCardStateLevel.Error : differenceHours >= stateDateTime.WarningHours ? enumHealthCardStateLevel.Warning : stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
else
return differenceHours <= stateDateTime.ErrorHours ? enumHealthCardStateLevel.Error : differenceHours <= stateDateTime.WarningHours ? enumHealthCardStateLevel.Warning : stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Ok : enumHealthCardStateLevel.None;
}
else if (stateDefinition is cHealthCardStateInfo)
{
return stateDefinition.IsNotTransparent ? enumHealthCardStateLevel.Info : enumHealthCardStateLevel.None;
}
else if (stateDefinition is cHealthCardStateTranslation stateTranslation)
{
ITranslatorObject abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(stateTranslation, stateTranslation.Translation);
if (!(abstractTranslation is cHealthCardTranslator translation))
return enumHealthCardStateLevel.None;
enumHealthCardStateLevel translationStateLevel = translation.DefaultTranslation?.StateLevel ?? enumHealthCardStateLevel.Info;
foreach (var translationEntry in translation.Translations)
{
if (translationEntry.Values.Any(v => string.Equals(rawValue.ToString(), v, StringComparison.InvariantCultureIgnoreCase)))
translationStateLevel = translationEntry.StateLevel;
}
if (!stateTranslation.IsNotTransparent && (translationStateLevel == enumHealthCardStateLevel.Ok || translationStateLevel == enumHealthCardStateLevel.Info))
return enumHealthCardStateLevel.None;
else
return translationStateLevel;
}
else if (stateDefinition is cHealthCardStateRefLink)
{
throw new NotImplementedException();
}
return enumHealthCardStateLevel.None;
}
catch (Exception e)
{
LogException(e);
return enumHealthCardStateLevel.None;
}
}
public cUiActionBase GetUiAction(cHealthCardStateBase stateDefinition)
{
if (stateDefinition?.QuickActions is null || stateDefinition.QuickActions.Count == 0)
return null;
return stateDefinition.QuickActions.Count == 1
? GetSingleUiAction(stateDefinition)
: GetMultipleUiActions(stateDefinition);
}
private cHealthCardStateBase GetDefinitionForLevel(cHealthCardStateBase displayValueDefinition)
{
if (displayValueDefinition is cHealthCardStateRefLink stateRefLink)
return cF4SDHealthCardConfig.GetReferencableStateWithName(stateRefLink, stateRefLink.Reference);
return displayValueDefinition;
}
private IList<enumHealthCardStateLevel> GetPredefinedLevels(cHealthCardStateBase displayValueDefinition, cF4sdApiSearchResultRelation relation, bool getStatic)
{
if (displayValueDefinition is cHealthCardStateRefLink stateRefLink)
{
cHealthCardStateBase definition = cF4SDHealthCardConfig.GetReferencableStateWithName(stateRefLink, stateRefLink.Reference);
CockpitValueDisplayData displayData = GetCockpitValueDisplayData(definition, relation, getStatic);
return GetHighestLevels(new List<IList<enumHealthCardStateLevel>> { displayData.Levels }, stateRefLink.IsNotTransparent);
}
if (displayValueDefinition is cHealthCardStateAggregation stateAggregation)
{
List<IList<enumHealthCardStateLevel>> allLevels = stateAggregation.States.Select(s => GetCockpitValueDisplayData(s, relation, getStatic).Levels).ToList();
return GetHighestLevels(allLevels, stateAggregation.IsNotTransparent);
}
return null;
}
private cUiActionBase GetSingleUiAction(cHealthCardStateBase stateDefinition)
{
string quickActionName = stateDefinition.QuickActions?.FirstOrDefault();
if (string.IsNullOrWhiteSpace(quickActionName))
return null;
cUiActionBase uiAction = MenuDataFactory.GetByName(quickActionName, SupportCaseDataProviderArtifact.NamedParameterEntries, SupportCaseDataProviderArtifact.CaseRelations.Select(r => r.Key))?.UiAction;
if (uiAction is cUiQuickAction uiQuickAction)
uiQuickAction.QuickActionRecommendation = new cRecommendationDataModel { Category = quickActionName, Recommendation = stateDefinition.Descriptions.GetValue() };
return uiAction;
}
private cUiActionBase GetMultipleUiActions(cHealthCardStateBase stateDefinition)
{
List<cMenuDataBase> menuDatas = stateDefinition.QuickActions
.Select(quickActionName => MenuDataFactory.GetByName(quickActionName, SupportCaseDataProviderArtifact.NamedParameterEntries, SupportCaseDataProviderArtifact.CaseRelations.Select(r => r.Key)))
.Where(menuData => menuData?.UiAction != null)
.Select(menuData =>
{
if (menuData.UiAction is cUiQuickAction uiQuickAction)
uiQuickAction.QuickActionRecommendation = new cRecommendationDataModel
{
Category = stateDefinition.Names.GetValue(),
Recommendation = stateDefinition.Descriptions.GetValue()
};
return menuData;
})
.ToList();
if (menuDatas == null || menuDatas.Count == 0)
return null;
if (menuDatas.Count == 1)
return menuDatas[0].UiAction;
return new cSubMenuAction(false)
{
SubMenuData = menuDatas,
Name = stateDefinition.Names.GetValue(),
Description = stateDefinition.Descriptions.GetValue(),
DisplayType = enumActionDisplayType.enabled
};
}
public bool TryGetNamedParameterValue<T>(cF4sdApiSearchResultRelation relation, string parameterName, out T value)
{
value = default;
if (!_namedParameterCache.TryGetValue(relation, out var namedParameters))
return false;
if (!namedParameters.TryGetValue(parameterName, out var namedParameter))
return false;
try
{
value = (T)Convert.ChangeType(namedParameter, typeof(T));
}
catch
{
LogEntry($"Found named parameter, but can not be converted to type: {typeof(T)}. Value: {namedParameter} Actual type: {namedParameter.GetType()}", LogLevels.Info);
return false;
}
return true;
}
/// <summary>
/// Raised when newly available relations for a support case were added.
/// </summary>
public event EventHandler<RelationEventArgs> AvailableCaseRelationsAdded;
/// <summary>
/// Raised when the data set of a support case has changed.
/// </summary>
public event EventHandler<SupportCaseDataEventArgs> CaseDataChanged;
}
}

View File

@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
namespace FasdDesktopUi.Basics.Services.SupportCase
namespace FasdDesktopUi.Basics.Services.SupportCase.Processors
{
internal class SupportCaseProcessorFactory
{
private readonly static Dictionary<Guid, SupportCaseProcessor> _supportCaseProccesors = new Dictionary<Guid, SupportCaseProcessor>();
private readonly static Dictionary<Guid, ISupportCaseProcessor> _supportCaseProccesors = new Dictionary<Guid, ISupportCaseProcessor>();
internal static SupportCaseProcessor Get(Guid id)
internal static ISupportCaseProcessor Get(Guid id)
{
if (!_supportCaseProccesors.ContainsKey(id))
_supportCaseProccesors.Add(id, new SupportCaseProcessor());

View File

@@ -34,13 +34,19 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
~SupportCase()
{
if (_relationService != null)
{
_relationService.RelationsReset -= HandleRelationsReset;
_relationService.RelationsFound -= HandleRelationsFound;
}
}
public void Initialize()
{
if (_relationService != null)
_relationService.RelationsFound += HandleRelationsFound;
if (_relationService is null)
return;
_relationService.RelationsReset += HandleRelationsReset;
_relationService.RelationsFound += HandleRelationsFound;
}
public ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations()
@@ -69,13 +75,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
foreach (var relationType in relations)
{
if (_caseRelations.TryGetValue(relationType.Key, out var caseRelation))
caseRelation = caseRelation.Union(relationType).ToList();
if (_caseRelations.ContainsKey(relationType.Key))
_caseRelations[relationType.Key] = _caseRelations[relationType.Key].Union(relationType).ToList();
else
_caseRelations.Add(relationType.Key, relationType.ToList());
if (SupportCaseDataProviderArtifact?.CaseRelations?.TryGetValue(relationType.Key, out var caseRelations) ?? false)
caseRelations = caseRelations.Union(relationType).ToList();
if (SupportCaseDataProviderArtifact?.CaseRelations?.ContainsKey(relationType.Key) ?? false)
SupportCaseDataProviderArtifact.CaseRelations[relationType.Key] = SupportCaseDataProviderArtifact.CaseRelations[relationType.Key].Union(relationType).ToList();
else
SupportCaseDataProviderArtifact?.CaseRelations?.Add(relationType.Key, relationType.ToList());
}
@@ -134,7 +140,6 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
UpdateSupportCaseDataCache(relation, rawData?.Tables?.Values);
isDataComplete = rawData?.Tables?
.Where(table => table.Key.StartsWith("Computation_") == false)
.All(table => !table.Value.IsIncomplete && !table.Value.Columns.Values.Any(c => c.IsIncomplete)) ?? false;
}
@@ -279,15 +284,25 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
}
}
public IEnumerable<object> GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress)
public IList<object> GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress, bool getStatic)
{
try
{
if (!_supportCaseDataCache.TryGetValue(valueAddress.ValueTable, out var tables))
if (!TryGetTable(relation, valueAddress, out var table))
return null;
if (!tables.TryGetValue(relation, out var table))
return null;
if (getStatic && !string.IsNullOrEmpty(table.AlternateStaticTable))
{
cValueAddress staticValueAdress = new cValueAddress()
{
DayIndex = valueAddress.DayIndex,
ValueTable = table.AlternateStaticTable,
ValueColumn = valueAddress.ValueColumn
};
if (TryGetTable(relation, staticValueAdress, out var staticTable))
table = staticTable;
}
if (!table.Columns.TryGetValue(valueAddress.ValueColumn, out var column))
return null;
@@ -302,6 +317,28 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
return null;
}
private bool TryGetTable(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress, out cF4SDHealthCardRawData.cHealthCardTable table)
{
table = null;
if (valueAddress is null)
return false;
if (!_supportCaseDataCache.TryGetValue(valueAddress.ValueTable, out var tables))
return false;
if (!tables.TryGetValue(relation, out table))
return false;
return true;
}
private void HandleRelationsReset(object sender, EventArgs e)
{
_caseRelations.Clear();
AddCaseRelations(_relationService?.GetLoadedRelations());
}
private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e)
{
AddCaseRelations(e.StagedResultRelations.Relations);

View File

@@ -1,281 +0,0 @@
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using FasdDesktopUi.Basics.CustomEvents;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Pages.DetailsPage.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.Services.SupportCase
{
/// <summary>
/// Used for processing raw data of a <see cref="ISupportCase"/> for the UI in a certain way.
/// </summary>
internal class SupportCaseProcessor
{
private ISupportCase _supportCase;
public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get => _supportCase?.SupportCaseDataProviderArtifact; }
private readonly Dictionary<cF4sdApiSearchResultRelation, cDetailsPageData> _detailsPageDataCache = new Dictionary<cF4sdApiSearchResultRelation, cDetailsPageData>();
private readonly Dictionary<cF4sdApiSearchResultRelation, Dictionary<string, object>> _namedParameterCache = new Dictionary<cF4sdApiSearchResultRelation, Dictionary<string, object>>();
internal void SetSupportCase(ISupportCase supportCase)
{
if (_supportCase != null)
{
_supportCase.CaseRelationsAdded -= HandleSupportCaseRelationsAdded;
_supportCase.SupportCaseDataCacheHasChanged -= HandleSupportCaseDataCacheHasChanged;
}
_supportCase = supportCase;
_supportCase.CaseRelationsAdded += HandleSupportCaseRelationsAdded;
_supportCase.SupportCaseDataCacheHasChanged += HandleSupportCaseDataCacheHasChanged;
}
private void HandleSupportCaseRelationsAdded(object sender, RelationEventArgs e)
=> AvailableCaseRelationsAdded?.Invoke(this, e);
private async void HandleSupportCaseDataCacheHasChanged(object sender, SupportCaseDataEventArgs e)
{
bool isArtifactShowingCorrectHealthCard
= SupportCaseDataProviderArtifact.HealthCardDataHelper.SelectedHealthCard == GetHealthcardFor(e.Relation);
if (!isArtifactShowingCorrectHealthCard)
{
// todo this can probably be removed, as soon as the last dependency of the SupportCaseDataProviderArtifact is gone.
// till then the detailspageData gets overriden with the detailspageData of the new relation.
// However, the removal shouldn't be much of a problem, due to the fact the Artifact also stores the raw data
_detailsPageDataCache.Remove(e.Relation);
return;
}
if (_detailsPageDataCache.TryGetValue(e.Relation, out var cachedData))
{
cDetailsPageData detailData = _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataWithoutHeading();
cachedData.WidgetData = detailData.WidgetData;
cachedData.DataHistoryList = detailData.DataHistoryList;
cachedData.MenuBarData = detailData.MenuBarData;
cachedData.DataContainerCollectionList = detailData.DataContainerCollectionList;
}
else
{
_detailsPageDataCache[e.Relation] = await _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataAsync();
}
UpdateNamedParameters(e.Relation, e.DataTables);
CaseDataChanged?.Invoke(this, e);
}
private void UpdateNamedParameters(cF4sdApiSearchResultRelation relation, IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> dataTables)
{
try
{
if (!_namedParameterCache.ContainsKey(relation))
_namedParameterCache.Add(relation, new Dictionary<string, object>());
var healthcard = GetHealthcardFor(relation);
foreach (var namedParameter in cHealthCardPrerequisites.GetNamedParameters(healthcard).Values)
{
var table = dataTables.FirstOrDefault(t => t.Name == namedParameter.DatabaseInfo.ValueTable);
if (table is null)
continue;
if (!table.Columns.TryGetValue(namedParameter.DatabaseInfo.ValueColumn, out var column))
continue;
string value = cUtility.RawValueFormatter.GetDisplayValue(column.Values.FirstOrDefault(), namedParameter.Display);
_namedParameterCache[relation][namedParameter.ParameterName] = value;
}
}
catch (Exception ex)
{
LogException(ex);
}
}
public async Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable<string> tablesToLoad)
{
_ = Task.Run(async () => await _supportCase.LoadSupportCaseDataAsync(relation, tablesToLoad.Where(t => !t.Contains("-details-"))));
if (!_detailsPageDataCache.TryGetValue(relation, out var detailsData))
{
detailsData = await _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataAsync();
_detailsPageDataCache.Add(relation, detailsData);
}
else
{
_supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.UpdateNamedParameterEntries();
}
CaseDataChanged?.Invoke(this, new SupportCaseDataEventArgs());
}
public async Task UpdateLatestCaseDataFor(cF4sdApiSearchResultRelation relation)
{
try
{
int? agentUserId = relation.Identities.FirstOrDefault(i => i.Class == enumFasdInformationClass.User)?.agentId;
int? agentDeviceId = relation.Identities.FirstOrDefault(i => i.Class == enumFasdInformationClass.Computer)?.agentId;
await ActualizeDataAsync(agentUserId, agentDeviceId);
_supportCase.InvalidateLatestCaseDataCacheFor(relation, out var invalidatedTables);
_detailsPageDataCache.Remove(relation);
await _supportCase.LoadSupportCaseDataAsync(relation, invalidatedTables.Where(t => !t.Name.StartsWith("Computation_")).Select(t => t.Name));
}
catch (Exception ex)
{
LogException(ex);
}
}
private async Task<enumActualizeStatus> ActualizeDataAsync(int? agentUserId, int? agentDeviceId)
{
var status = enumActualizeStatus.unknown;
if (!agentUserId.HasValue && !agentDeviceId.HasValue)
return status;
try
{
TimeSpan refreshDelay = TimeSpan.FromMilliseconds(500);
const int maxPollCount = 20;
if (!agentDeviceId.HasValue)
{
LogEntry("Coudldn't acutalize data. There was no valid AgentDeviceId found.", LogLevels.Error);
return status;
}
var taskId = await cFasdCockpitCommunicationBase.Instance.ActualizeAgentData(agentDeviceId.Value, agentUserId);
if (taskId == Guid.Empty)
return enumActualizeStatus.failed;
enumFasdInformationClass informationClass = agentUserId != null ? enumFasdInformationClass.User : enumFasdInformationClass.Computer;
int pollCount = 0;
do
{
status = await cFasdCockpitCommunicationBase.Instance.GetActualizeAgentDataStatus(taskId, informationClass);
if (status == enumActualizeStatus.unknown)
{
pollCount++;
if (pollCount >= maxPollCount)
return status;
await Task.Delay(refreshDelay);
}
} while (status == enumActualizeStatus.unknown);
}
catch (Exception E)
{
LogException(E);
}
return status;
}
internal ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations()
=> _supportCase.GetCaseRelations();
internal cHealthCard GetHealthcardFor(cF4sdApiSearchResultRelation relation)
{
var availableHealthCards = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.HealthCards?.Values;
if (availableHealthCards is null || availableHealthCards.Count == 0)
return null;
return availableHealthCards
.FirstOrDefault(hc =>
hc.InformationClasses.All(i => i == cF4sdIdentityEntry.GetFromSearchResult(relation.Type))
&& HasCockpitUserRequiredRoles(hc.RequiredRoles));
}
private static bool HasCockpitUserRequiredRoles(List<string> requiredRoles)
{
try
{
if (requiredRoles is null || requiredRoles.Count == 0)
return true;
List<string> roles = null;
lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
{
roles = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles;
}
if (roles is null || roles.Count == 0)
return false;
foreach (var requiredRole in requiredRoles)
{
if (roles.Contains(requiredRole, StringComparer.InvariantCultureIgnoreCase))
return true;
}
}
catch (Exception E)
{
LogException(E);
}
return false;
}
public List<List<cWidgetValueModel>> GetWidgetData(cF4sdApiSearchResultRelation relation)
{
List<List<cWidgetValueModel>> widgetData = null;
if (_detailsPageDataCache.TryGetValue(relation, out var detailsData))
widgetData = detailsData?.WidgetData;
return widgetData ?? new List<List<cWidgetValueModel>>();
}
public cDetailsPageDataHistoryDataModel GetHistoryData(cF4sdApiSearchResultRelation relation)
{
cDetailsPageDataHistoryDataModel historyData = null;
if (_detailsPageDataCache.TryGetValue(relation, out var detailsData))
historyData = detailsData?.DataHistoryList;
return historyData ?? new cDetailsPageDataHistoryDataModel();
}
public List<cContainerCollectionData> GetContainerData(cF4sdApiSearchResultRelation relation)
{
List<cContainerCollectionData> containerData = null;
if (_detailsPageDataCache.TryGetValue(relation, out var detailsData))
containerData = detailsData?.DataContainerCollectionList;
return containerData ?? new List<cContainerCollectionData>();
}
public List<cMenuDataBase> GetMenuBarData(cF4sdApiSearchResultRelation relation)
{
List<cMenuDataBase> menuData = null;
if (_detailsPageDataCache.TryGetValue(relation, out var detailsData))
menuData = detailsData?.MenuBarData;
return menuData ?? new List<cMenuDataBase>();
}
/// <summary>
/// Raised when newly available relations for a support case were added.
/// </summary>
public event EventHandler<RelationEventArgs> AvailableCaseRelationsAdded;
/// <summary>
/// Raised when the data set of a support case has changed.
/// </summary>
public event EventHandler<SupportCaseDataEventArgs> CaseDataChanged;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,9 @@ 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
@@ -178,7 +181,7 @@ namespace FasdDesktopUi.Basics
return null;
HashSet<string> requiredTables = cHealthCard.GetRequiredTables(_result.HealthCardDataHelper.SelectedHealthCard); // todo the healthcard is not selected at this point
detailsPage.WidgetCollection.WidgetDataList = supportCaseController.GetWidgetData();
detailsPage.WidgetCollection.WidgetDataList = supportCaseController.GetWidgetsData();
detailsPage.DataHistoryCollectionUserControl.HistoryDataList = supportCaseController.GetHistoryData();
detailsPage.CustomizableSectionUc.ContainerCollections = supportCaseController.GetContainerData();
@@ -269,6 +272,7 @@ namespace FasdDesktopUi.Basics
TimerView.ResetTimer();
CaseChanged?.Invoke(this, new EventArgs());
GamificationService.TrackAction(CockpitAction.CaseOpened);
}
catch (Exception E)
{
@@ -308,7 +312,7 @@ namespace FasdDesktopUi.Basics
var nettoTime = workTimes["NettoWorkingTime"];
var caseParameter = new cF4SDCaseStatusParameters() { CaseId = tempCaseId, StatusId = CaseStatus.Finished, ActiveTime = (double)nettoTime };
tasks.Add(cFasdCockpitCommunicationBase.Instance.UpdateCase(caseParameter, TimerView.caseTimes));
tasks.Add(cFasdCockpitCommunicationBase.Instance.UpdateCase(caseParameter, TimerView.CaseTimes));
caseAliveTimer?.Stop();
caseAliveTimer?.Dispose();
}

View File

@@ -0,0 +1,171 @@
using C4IT.F4SD.DisplayFormatting;
using C4IT.FASD.Base;
using C4IT.MultiLanguage;
using FasdCockpitBase.Models.RemoteDesktopConnection;
using FasdCockpitCommunication.RemoteDesktopCommunication;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.RemoteDesktop;
using FasdDesktopUi.Basics.UserControls;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.UiActions.NativeActions
{
internal class RemoteConnectionAction
{
internal const string NativeActionName = "StartAgentRemoteConnection";
internal static void UpdatePrerequesites(FasdNativeQuickAction nativeQuickAction)
{
nativeQuickAction.CheckFilePath = AgentRemoteDesktopService.GetViewerPath();
}
internal static cDataCanvasDataModel GetQuickActionData(cFasdQuickAction quickActionConfig, cQuickActionStatusMonitorModel.RunQuickActionDelegate quickAction)
{
var detailedDataQuickActionHistory = new cDetailedDataModel()
{
Heading = cMultiLanguageSupport.GetItem("DetailsPage.History"),
FullDetailedData = new List<object>() { new List<object>() { "Status", cMultiLanguageSupport.GetItem("QuickAction.Revision.ExecutionTime") } }
};
return new cDataCanvasDataModel()
{
RecommendationData = null,
QuickActionStatusMonitorData = new cQuickActionStatusMonitorModel()
{
ActionName = quickActionConfig.Names.GetValue(),
ActionSteps = new List<cQuickActionStatusMonitorModel.cQuickActionStep>()
{
new cQuickActionStatusMonitorModel.cQuickActionStep(cMultiLanguageSupport.GetItem("QuickAction.Remote.UserAcceptance"), quickActionConfig.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.waitingForUserAcceptance),
new cQuickActionStatusMonitorModel.cQuickActionStep(cMultiLanguageSupport.GetItem("QuickAction.Phoenix.StartViewer"), quickActionConfig.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running)
},
QuickActionDefinition = quickActionConfig,
RunQuickAction = quickAction
},
DetailedData = detailedDataQuickActionHistory,
};
}
private static bool TryGetNamedParameterValue(cNamedParameterList namedParameters, string namedParameterName, string quickActionName, QuickActionStatusMonitor statusMonitor, out int namedParameterValue)
{
namedParameterValue = -1;
bool hasNamedParameterValue = true;
if (!namedParameters.TryGetValue(namedParameterName, out var namedParameter))
{
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(statusMonitor.QuickActionData.ActionSteps);
statusMonitor.QuickActionOutputs.Add(new cF4sdQuickActionRevision.cOutput() { Values = $"Named parameter \"{namedParameterName}\" is missing. Try to refresh data." });
hasNamedParameterValue = false;
}
if (!int.TryParse(namedParameter.GetValue(), out namedParameterValue))
{
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(statusMonitor.QuickActionData.ActionSteps);
statusMonitor.QuickActionOutputs.Add(new cF4sdQuickActionRevision.cOutput() { Values = $"Named parameter \"{namedParameterName}\" is missing. Try to refresh data." });
hasNamedParameterValue = false;
}
return hasNamedParameterValue;
}
private static bool TryGetClientInfo(string quickActionName, QuickActionStatusMonitor statusMonitor, cNamedParameterList namedParameters, out AgentRemoteClientInfo clientInfo)
{
clientInfo = null;
try
{
bool hasClientInfo = true;
if (!TryGetNamedParameterValue(namedParameters, "AgentUserId", quickActionName, statusMonitor, out var userId))
hasClientInfo = false;
if (!TryGetNamedParameterValue(namedParameters, "AgentDeviceId", quickActionName, statusMonitor, out var deviceId))
hasClientInfo = false;
int? organizationId = cCockpitConfiguration.Instance?.agentApiConfiguration?.OrganizationCode;
if (organizationId is null)
{
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(statusMonitor.QuickActionData.ActionSteps);
hasClientInfo = false;
}
clientInfo = new AgentRemoteClientInfo() { AccountCode = userId, DeviceCode = deviceId, OrganisationCode = organizationId.Value };
return hasClientInfo;
}
catch (Exception ex)
{
LogException(ex);
return false;
}
}
internal static async Task<List<object>> RunQuickAction(string quickActionName, QuickActionStatusMonitor statusMonitor, cNamedParameterList namedParameters, CancellationToken token)
{
try
{
statusMonitor.QuickActionOutputs.Clear();
var errorOutput = new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedWithError"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
if (!TryGetClientInfo(quickActionName, statusMonitor, namedParameters, out var clientInfo))
return errorOutput;
AgentRemoteDesktopService.RemoteConnetionStatusChanged += HandleConnectionStatusChanged;
RemoteDesktopConnectionStatusResult connectionStatus = await AgentRemoteDesktopService.StartRemoteDesktopConnectionAsync(clientInfo, true, token);
switch (connectionStatus.Status)
{
case RemoteDesktopConnectionStatus.Accepted:
case RemoteDesktopConnectionStatus.Connected:
case RemoteDesktopConnectionStatus.Finished:
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(statusMonitor?.QuickActionData?.ActionSteps, quickActionName, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.waitingForUserAcceptance, enumQuickActionRevisionStatus.finishedSuccessfull);
return new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedSuccessfull"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
case RemoteDesktopConnectionStatus.Canceled:
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(statusMonitor?.QuickActionData?.ActionSteps);
return new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
case RemoteDesktopConnectionStatus.Error:
foreach (var error in connectionStatus.Errors)
{
var quickactionOutput = new cF4sdQuickActionRevision.cOutput() { Values = error };
statusMonitor.QuickActionOutputs.Add(quickactionOutput);
}
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(statusMonitor?.QuickActionData?.ActionSteps, quickActionName, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.waitingForUserAcceptance, enumQuickActionRevisionStatus.finishedWithError);
return new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedWithError"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
default:
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(statusMonitor?.QuickActionData?.ActionSteps, quickActionName, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.waitingForUserAcceptance, enumQuickActionRevisionStatus.finishedWithError);
return errorOutput;
}
}
finally
{
AgentRemoteDesktopService.RemoteConnetionStatusChanged -= HandleConnectionStatusChanged;
}
void HandleConnectionStatusChanged(object sender, RemoteDesktopConnectionStatus e)
{
switch (e)
{
case RemoteDesktopConnectionStatus.Accepted:
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(statusMonitor?.QuickActionData?.ActionSteps, quickActionName, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.waitingForUserAcceptance, enumQuickActionRevisionStatus.finishedSuccessfull);
break;
case RemoteDesktopConnectionStatus.Connected:
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(statusMonitor?.QuickActionData?.ActionSteps, quickActionName, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
break;
case RemoteDesktopConnectionStatus.Canceled:
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(statusMonitor?.QuickActionData?.ActionSteps);
break;
default:
break;
}
}
}
}
}

View File

@@ -337,7 +337,7 @@ namespace FasdDesktopUi.Basics.UiActions
shouldHideRow = true;
}
cUtility.RawValueFormatter.SetDefaultCulture(new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
cUtility.RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
foreach (var index in rawColumnIndexes)

View File

@@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using C4IT.Logging;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UserControls;
@@ -19,7 +13,7 @@ namespace FasdDesktopUi.Basics.UiActions
public class cSubMenuAction : cUiActionBase
{
public bool UseTempData { get; private set; }
public List<cMenuDataBase> SubMenuData { get; set; }
public List<cMenuDataBase> SubMenuData { get; set; } = new List<cMenuDataBase>();
public cSubMenuAction(bool UseTempData)
{

View File

@@ -30,6 +30,8 @@ namespace FasdDesktopUi.Basics.UiActions
return new cUiDemoQuickAction(QuickActionDemo);
else if (quickAction is cF4sdQuickActionServer serverQuickAction)
return new cUiServerQuickAction(serverQuickAction);
else if (quickAction is FasdNativeQuickAction nativeQuickAction)
return new UiNativeQuickAction(nativeQuickAction);
else
return new cUiDummyQuickAction(quickAction);
}

View File

@@ -6,6 +6,8 @@ using System.Windows;
using FasdDesktopUi.Basics.UserControls;
using C4IT.FASD.Base;
using static C4IT.Logging.cLogManager;
using F4SD.Gamification;
using F4SD.Gamification.Services;
namespace FasdDesktopUi.Basics.UiActions
{
@@ -36,6 +38,8 @@ namespace FasdDesktopUi.Basics.UiActions
if (sender is CustomMenuItem senderElement)
await cUtility.ChangeIconToCheckAsync(senderElement.MenuItemIcon);
GamificationService.TrackAction(CockpitAction.CopyTemplateClicked);
return true;
}
catch (Exception E)

View File

@@ -78,6 +78,9 @@ namespace FasdDesktopUi.Basics.UiActions
public override async Task<List<object>> ProcessActionAsync(CancellationToken token, Dictionary<cAdjustableParameter, object> ParameterDictionary = null)
{
var runningId = Guid.NewGuid();
StatusMonitor.CurrentRunningQuickActionId = runningId;
var _finshedStatus = enumQuickActionRevisionStatus.finishedSuccessfull;
if (quickActionDemo.SimulatedClientConnect > 0)
{
@@ -86,7 +89,7 @@ namespace FasdDesktopUi.Basics.UiActions
if (token.IsCancellationRequested)
_finshedStatus = enumQuickActionRevisionStatus.canceled;
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, quickActionDemo.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.connectingToClient, _finshedStatus);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, quickActionDemo.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.connectingToClient, _finshedStatus);
}
if (quickActionDemo.SimulatedRuntime > 0)
@@ -98,14 +101,16 @@ namespace FasdDesktopUi.Basics.UiActions
if (token.IsCancellationRequested)
_finshedStatus = enumQuickActionRevisionStatus.canceled;
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, quickActionDemo.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, _finshedStatus);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, quickActionDemo.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, _finshedStatus);
}
string _msg;
if (_finshedStatus == enumQuickActionRevisionStatus.canceled)
{
_msg = cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled");
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(StatusMonitor.QuickActionData.ActionSteps);
if (StatusMonitor.CurrentRunningQuickActionId == runningId)
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(StatusMonitor.QuickActionData.ActionSteps);
}
else
{

View File

@@ -133,8 +133,8 @@ namespace FasdDesktopUi.Basics.UiActions
{
var ResultRevision = GetRevisionOutput(_actionResult);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);
if (ResultRevision.Output == null)
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.finished });
@@ -182,8 +182,8 @@ namespace FasdDesktopUi.Basics.UiActions
}
else
{
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") });

View File

@@ -100,8 +100,8 @@ namespace FasdDesktopUi.Basics.UiActions
if (string.IsNullOrEmpty(webRequestUrl))
{
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
return new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedWithError"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
}
@@ -112,8 +112,8 @@ namespace FasdDesktopUi.Basics.UiActions
if (!token.IsCancellationRequested)
{
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.finished });
@@ -134,8 +134,8 @@ namespace FasdDesktopUi.Basics.UiActions
}
else
{
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") });

View File

@@ -0,0 +1,49 @@
using C4IT.FASD.Base;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions.NativeActions;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace FasdDesktopUi.Basics.UiActions
{
internal class UiNativeQuickAction : cUiQuickAction
{
private readonly string _nativeActionName;
public UiNativeQuickAction(FasdNativeQuickAction quickActionConfig) : base(quickActionConfig)
{
_nativeActionName = quickActionConfig.NativeName;
}
public override Task<cDataCanvasDataModel> GetQuickActionDataAsync(cSupportCaseDataProvider dataProvider, bool isDetailedLayout)
{
DataProvider = dataProvider;
switch (_nativeActionName)
{
case RemoteConnectionAction.NativeActionName:
return Task.FromResult(RemoteConnectionAction.GetQuickActionData(QuickActionConfig, ProcessActionAsync));
default:
throw new NotImplementedException();
}
}
public override async Task<List<object>> ProcessActionAsync(CancellationToken token, Dictionary<cAdjustableParameter, object> parameterDictionary = null)
{
return await RunNativeAction(_nativeActionName, token);
}
private async Task<List<object>> RunNativeAction(string actionName, CancellationToken token)
{
switch (actionName)
{
case RemoteConnectionAction.NativeActionName:
return await RemoteConnectionAction.RunQuickAction(QuickActionConfig.Name, StatusMonitor, DataProvider?.NamedParameterEntries, token);
default:
throw new NotImplementedException();
}
}
}
}

View File

@@ -33,14 +33,11 @@ namespace FasdDesktopUi.Basics.UiActions
await HistoryEntry.RefreshAsync();
}
// todo set relationService
IRelationService relationService = new RelationService();
switch (HistoryEntry)
{
case cSearchHistorySearchResultEntry SearchEntry:
HistoryEntry.SearchUiProvider.SetSearchHistoryVisibility(true);
HistoryEntry.SearchUiProvider.ShowSearchRelations(SearchEntry, relationService, HistoryEntry.SearchUiProvider);
HistoryEntry.SearchUiProvider.ShowSearchRelations(SearchEntry, HistoryEntry.RelationService, HistoryEntry.SearchUiProvider);
return true;
case cSearchHistoryRelationEntry RelationEntry:
string caseObjectName = RelationEntry.SelectedRelation.DisplayName;
@@ -58,7 +55,7 @@ namespace FasdDesktopUi.Basics.UiActions
}
}
HistoryEntry.isSeen = true;
dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(RelationEntry.SelectedRelation, relationService);
dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(RelationEntry.SelectedRelation, HistoryEntry.RelationService);
if (dataProvider is null)
{
Debug.Assert(true, "Could not start a data provider for the selected criterias.");

View File

@@ -1,12 +1,12 @@
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT.MultiLanguage;
using FasdDesktopUi.Basics.Helper;
using C4IT.MultiLanguage;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Services.RelationService;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -61,21 +61,21 @@ namespace FasdDesktopUi.Basics.UiActions
return false;
}
if (_selectedRelation == null)
{
Debug.Assert(true, "A new support case can't be opend, if we have no selected relation or seach result");
LogEntry("A new support case can't be opend, if we have no sselected relation or seach result", LogLevels.Error);
return false;
}
if (TicketDeepLinkHelper.TryOpenTicketRelationExternally(_selectedRelation))
return false;
// check, if have an active support case
var supportCaseActive = dataProvider?.IsActive ?? false;
if (_selectedRelation == null)
{
Debug.Assert(true, "A new support case can't be opend, if we have no selected relation or seach result");
LogEntry("A new support case can't be opend, if we have no sselected relation or seach result", LogLevels.Error);
return false;
}
if (TicketExternalLinkHelper.TryOpenTicketRelationExternally(_selectedRelation))
return false;
// check, if have an active support case
var supportCaseActive = dataProvider?.IsActive ?? false;
// create the search histroy entry
var _seachHistoryEntry = new cSearchHistoryRelationEntry(Name, _selectedSearchResult, _relations, _selectedRelation, _searchUiProvider);
var _seachHistoryEntry = new cSearchHistoryRelationEntry(Name, _selectedSearchResult, _relations, _selectedRelation, _searchUiProvider, _relationService);
cSearchManager.Instance.ReplaceEntry(_seachHistoryEntry, _searchHistoryEntry);
// show the loading information
@@ -96,9 +96,12 @@ namespace FasdDesktopUi.Basics.UiActions
// get the new data provider for the support call informations (get it from the cache or create a new one)
dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(_selectedRelation, _relationService);
bool shouldLoadRelationsForSelectedRelation = _selectedRelation.Type == enumF4sdSearchResultClass.User;
if (shouldLoadRelationsForSelectedRelation)
StartLoadingRelationsFor(_selectedRelation);
bool shouldLoadRelationsForSelectedRelation = _selectedRelation.Type == enumF4sdSearchResultClass.User;
if (shouldLoadRelationsForSelectedRelation)
{
_relationService.Reset();
StartLoadingRelationsFor(_selectedRelation);
}
if (dataProvider is null)
{

View File

@@ -116,7 +116,7 @@ namespace FasdDesktopUi.Basics.UiActions
private async Task<bool> ProcessSearchResultRelationAsync(string name, List<cF4sdApiSearchResultRelation> caseRelations, cF4sdApiSearchResultRelation selectedRelation)
{
var relationSearchResult = new cSearchHistorySearchResultEntry(_searchResults.FirstOrDefault().DisplayName, _searchResults.FirstOrDefault().DisplayName, _searchResults, caseRelations, _searchUiProvider);
var relationSearchResult = new cSearchHistorySearchResultEntry(_searchResults.FirstOrDefault().DisplayName, _searchResults.FirstOrDefault().Name, _searchResults, caseRelations, _searchUiProvider, _relationService);
string displayName = !string.IsNullOrWhiteSpace(selectedRelation?.Name) ? $"{name} → {selectedRelation.Name}" : name;
cUiProcessSearchRelationAction action

View File

@@ -44,7 +44,7 @@ namespace FasdDesktopUi.Basics.UiActions
if (QuickActionConfig is null)
return;
cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
cUtility.RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
shouldRunImmidiate = QuickActionConfig.RunImmediate;

View File

@@ -85,6 +85,9 @@ namespace FasdDesktopUi.Basics.UiActions
{
try
{
var runningId = Guid.NewGuid();
StatusMonitor.CurrentRunningQuickActionId = runningId;
int agentDeviceId = int.MinValue;
int? agentUserIdNullable = null;
var startTime = DateTime.UtcNow;
@@ -132,11 +135,12 @@ namespace FasdDesktopUi.Basics.UiActions
if (!token.IsCancellationRequested)
{
StatusMonitor.QuickActionOutputs.Add(QuickActionResult.Output);
if (StatusMonitor.CurrentRunningQuickActionId == runningId)
StatusMonitor.QuickActionOutputs.Add(QuickActionResult.Output);
var status = quickActionOutput?.IsError == true ? enumQuickActionRevisionStatus.finishedWithError : QuickActionResult.Status;
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, RemoteQuickAction.Name, enumActionStepType.running, status);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, RemoteQuickAction.Name, enumActionStepType.main, status);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, RemoteQuickAction.Name, enumActionStepType.running, status);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, RemoteQuickAction.Name, enumActionStepType.main, status);
cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(RemoteQuickAction, DataProvider, true, protocollOutput, StatusMonitor.MeasureValues);
QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(RemoteQuickAction, copyData);
@@ -145,7 +149,8 @@ namespace FasdDesktopUi.Basics.UiActions
}
else
{
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(StatusMonitor.QuickActionData.ActionSteps);
if (StatusMonitor.CurrentRunningQuickActionId == runningId)
cQuickActionStatusMonitorModel.cQuickActionStep.CancelRemainingQuickActionSteps(StatusMonitor.QuickActionData.ActionSteps);
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") });
@@ -303,7 +308,7 @@ namespace FasdDesktopUi.Basics.UiActions
foreach (var actionStepToUpdate in actionStepsToUpdate)
{
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, RemoteQuickAction.Name, actionStepToUpdate, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, RemoteQuickAction.Name, actionStepToUpdate, enumQuickActionRevisionStatus.finishedSuccessfull);
}
if (quickActionStatus == enumQuickActionStatus.Finished || quickActionStatus == enumQuickActionStatus.Cancelled)

View File

@@ -134,8 +134,8 @@ namespace FasdDesktopUi.Basics.UiActions
{
var ResultRevision = GetRevisionOutput(_actionResult);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);
if (!string.IsNullOrEmpty(_actionResult.StandardOutput))
try
@@ -198,8 +198,8 @@ namespace FasdDesktopUi.Basics.UiActions
}
else
{
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor?.QuickActionData?.ActionSteps, ServerQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);
quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") });

View File

@@ -21,7 +21,8 @@
MouseLeftButtonUp="MenuItemBorder_Click"
TouchDown="MenuItemBorder_Click"
MouseEnter="MenuItemBorder_MouseEnter"
MouseLeave="MenuItemBorder_MouseLeave">
MouseLeave="MenuItemBorder_MouseLeave"
>
<Grid x:Name="MenuItemContent">
<Grid.ColumnDefinitions>
@@ -31,12 +32,14 @@
</Grid.ColumnDefinitions>
<ico:AdaptableIcon x:Name="MenuItemIcon"
Grid.Column="0" />
Grid.Column="0"
/>
<ico:AdaptableIcon x:Name="MenuItemOverlayIcon"
Grid.Column="0"
BorderPadding="10 10 0 0"
Margin="0 0 -5 -5"/>
Visibility="Collapsed"
IsHitTestVisible="False"
/>
<StackPanel Grid.Column="1"
Margin="15 0 15 0"

View File

@@ -1,186 +1,207 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions;
using C4IT.FASD.Base;
using static C4IT.Logging.cLogManager;
using MaterialIcons;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class CustomMenuItem : UserControl
{
#region Properties
#region MenuData
private cMenuDataBase _menuData = new cMenuDataBase();
private readonly bool _isLean;
public cMenuDataBase MenuData
{
get { return _menuData; }
set
{
if (_menuData != value)
{
_menuData = value;
MenuDataChanged();
}
}
}
private void MenuDataChanged()
{
if (MenuData.MenuIcon.Intern != null)
MenuItemIcon.SelectedInternIcon = MenuData.MenuIcon.Intern;
else if (MenuData.MenuIcon.Material != null)
MenuItemIcon.SelectedMaterialIcon = MenuData.MenuIcon.Material;
MenuItemIcon.IconHeight = MenuData.MenuIconSize * MenuItemIcon.IconHeight;
MenuItemIcon.IconWidth = MenuData.MenuIconSize * MenuItemIcon.IconWidth;
switch (MenuData.UiAction?.DisplayType)
{
case Enums.enumActionDisplayType.hidden:
//todo: add hidden state
break;
case Enums.enumActionDisplayType.disabled:
MenuItemContent.SetValue(OpacityProperty, 0.5);
MenuItemBorder.SetResourceReference(StyleProperty, "Menu.MainCategory.NoHover");
MenuItemBorder.SetValue(ToolTipProperty, string.IsNullOrWhiteSpace(MenuData.UiAction.AlternativeDescription) ? MenuData.UiAction.Description : MenuData.UiAction.AlternativeDescription);
try
{
MenuItemBorder.MouseLeftButtonUp -= MenuItemBorder_Click;
MenuItemBorder.TouchDown -= MenuItemBorder_Click;
}
catch { }
break;
case Enums.enumActionDisplayType.enabled:
MenuItemContent.ClearValue(OpacityProperty);
MenuItemBorder.ClearValue(IsHitTestVisibleProperty);
break;
}
MenuItemBorder.ToolTip = !string.IsNullOrEmpty(MenuData.UiAction?.Description) ? MenuData.UiAction?.Description : null;
ToolTip = !string.IsNullOrEmpty(MenuData.UiAction?.Description) ? MenuData.UiAction?.Description : null;
CustomTextBlock.Text = MenuData.MenuText;
CustomTextBlockBottom.Text = MenuData.MenuText;
if (string.IsNullOrWhiteSpace(MenuData.TrailingText))
{
CustomTrailingTextBlock.Text = string.Empty;
CustomTrailingTextBlock.Visibility = Visibility.Collapsed;
}
else
{
CustomTrailingTextBlock.Text = MenuData.TrailingText;
CustomTrailingTextBlock.Visibility = Visibility.Visible;
}
DrawEnhancedMenuInformation();
}
private void DrawEnhancedMenuInformation()
{
try
{
if (MenuData is cMenuDataContainer containerMenuData)
DrawContainer(containerMenuData);
else if (MenuData is cMenuDataSearchRelation searchRelationMenuData)
DrawSearchRelation(searchRelationMenuData);
else if (MenuData is cMenuDataLoading)
LoadingIcon.Visibility = Visibility.Visible;
else
DrawDefault();
}
catch (Exception E)
{
LogException(E);
}
void DrawContainer(cMenuDataContainer containerMenuData)
{
SubMenuCounterBorder.Visibility = Visibility.Visible;
var count = 0;
foreach (var entry in containerMenuData.SubMenuData)
{
if (entry.UiAction?.DisplayType == null || entry.UiAction?.DisplayType == Enums.enumActionDisplayType.enabled)
count++;
}
if (count == 0)
SubMenuCounterTextBlock.Text = "-";
else
SubMenuCounterTextBlock.Text = count.ToString();
}
void DrawSearchRelation(cMenuDataSearchRelation searchRelationMenuData)
{
if (!(searchRelationMenuData.Data is cF4sdApiSearchResultRelation relationData))
return;
if (searchRelationMenuData.IsMatchingRelation)
{
LoadingIcon.SelectedMaterialIcon = MaterialIconType.ic_link;
LoadingIcon.ClearValue(StyleProperty);
LoadingIcon.Visibility = Visibility.Visible;
}
if (relationData.Type is enumF4sdSearchResultClass.Ticket)
{
if (relationData.Infos is null)
return;
if (relationData.Infos.TryGetValue("Summary", out var ticketSummary))
{
CustomTextBlockBottom.Text = ticketSummary;
CustomTextBlockBorderBottom.Visibility = Visibility.Visible;
}
if (relationData.Infos.TryGetValue("StatusId", out var ticketStatusId))
{
Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus);
switch (ticketStatus)
{
case enumTicketStatus.Unknown:
break;
case enumTicketStatus.New:
case enumTicketStatus.InProgress:
case enumTicketStatus.OnHold:
MenuItemIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts;
break;
case enumTicketStatus.Closed:
MenuItemIcon.SelectedMaterialIcon = MaterialIconType.ic_mail;
break;
default:
break;
}
}
}
else
{
SearchRelationGrid.Visibility = Visibility.Visible;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions;
using C4IT.FASD.Base;
using static C4IT.Logging.cLogManager;
using MaterialIcons;
using F4SD_AdaptableIcon;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class CustomMenuItem : UserControl
{
#region Properties
#region MenuData
private cMenuDataBase _menuData = new cMenuDataBase();
private readonly bool _isLean;
public cMenuDataBase MenuData
{
get { return _menuData; }
set
{
if (_menuData != value)
{
_menuData = value;
MenuDataChanged();
}
}
}
private void setIcon(AdaptableIcon.AdaptableIcon icon, IconData data)
{
var _visibilty = Visibility.Visible;
if (data.Intern != null)
icon.SelectedInternIcon = data.Intern;
else if (data.Material != null)
icon.SelectedMaterialIcon = data.Material;
else
_visibilty = Visibility.Hidden;
icon.IconHeight = MenuData.MenuIconSize * icon.IconHeight;
icon.IconWidth = MenuData.MenuIconSize * icon.IconWidth;
icon.Visibility = _visibilty;
}
private void MenuDataChanged()
{
setIcon(MenuItemIcon, MenuData.MenuIcon?.Icon ?? new IconData());
if (MenuData.MenuIcon?.Overlay != null)
setIcon(MenuItemOverlayIcon, (IconData)MenuData.MenuIcon.Overlay);
else
MenuItemOverlayIcon.Visibility = Visibility.Collapsed;
if (MenuData.MenuIcon?.IsInactive == true)
{
MenuItemIcon.Opacity = 0.7;
MenuItemOverlayIcon.Opacity = 0.7;
}
else
{
MenuItemIcon.Opacity = 1.0;
MenuItemOverlayIcon.Opacity = 1.0;
}
if (MenuData.MenuIcon?.Description != null)
{
MenuItemIcon.ToolTip = new CustomMenuItemToolTipTemplate(MenuData.MenuIcon.Description);
ToolTipService.SetInitialShowDelay(MenuItemIcon, 300);
ToolTipService.SetBetweenShowDelay(MenuItemIcon, 600);
ToolTipService.SetPlacement(MenuItemIcon, System.Windows.Controls.Primitives.PlacementMode.Top);
ToolTipService.SetHorizontalOffset(MenuItemIcon, 20);
ToolTipService.SetVerticalOffset(MenuItemIcon, 20);
}
string toolTip = MenuData.UiAction?.Description;
switch (MenuData.UiAction?.DisplayType)
{
case Enums.enumActionDisplayType.hidden:
//todo: add hidden state
break;
case Enums.enumActionDisplayType.disabled:
MenuItemContent.SetValue(OpacityProperty, 0.5);
MenuItemBorder.SetResourceReference(StyleProperty, "Menu.MainCategory.NoHover");
if (!string.IsNullOrWhiteSpace(MenuData.UiAction.AlternativeDescription))
toolTip = MenuData.UiAction.AlternativeDescription;
try
{
MenuItemBorder.MouseLeftButtonUp -= MenuItemBorder_Click;
MenuItemBorder.TouchDown -= MenuItemBorder_Click;
}
catch { }
break;
case Enums.enumActionDisplayType.enabled:
MenuItemContent.ClearValue(OpacityProperty);
MenuItemBorder.ClearValue(IsHitTestVisibleProperty);
break;
}
if (!string.IsNullOrWhiteSpace(toolTip))
MenuItemBorder.ToolTip = toolTip;
CustomTextBlock.Text = MenuData.MenuText;
CustomTextBlockBottom.Text = MenuData.MenuText;
if (string.IsNullOrWhiteSpace(MenuData.TrailingText))
{
CustomTrailingTextBlock.Text = string.Empty;
CustomTrailingTextBlock.Visibility = Visibility.Collapsed;
}
else
{
CustomTrailingTextBlock.Text = MenuData.TrailingText;
CustomTrailingTextBlock.Visibility = Visibility.Visible;
}
DrawEnhancedMenuInformation();
}
private void DrawEnhancedMenuInformation()
{
try
{
if (MenuData is cMenuDataContainer containerMenuData)
DrawContainer(containerMenuData);
else if (MenuData is cMenuDataSearchRelation searchRelationMenuData)
DrawSearchRelation(searchRelationMenuData);
else if (MenuData is cMenuDataLoading)
LoadingIcon.Visibility = Visibility.Visible;
else
DrawDefault();
}
catch (Exception E)
{
LogException(E);
}
void DrawContainer(cMenuDataContainer containerMenuData)
{
SubMenuCounterBorder.Visibility = Visibility.Visible;
var count = 0;
foreach (var entry in containerMenuData.SubMenuData)
{
if (entry.UiAction?.DisplayType == null || entry.UiAction?.DisplayType == Enums.enumActionDisplayType.enabled)
count++;
}
if (count == 0)
SubMenuCounterTextBlock.Text = "-";
else
SubMenuCounterTextBlock.Text = count.ToString();
}
void DrawSearchRelation(cMenuDataSearchRelation searchRelationMenuData)
{
if (!(searchRelationMenuData.Data is cF4sdApiSearchResultRelation relationData))
return;
if (searchRelationMenuData.IsMatchingRelation)
{
LoadingIcon.SelectedMaterialIcon = MaterialIconType.ic_link;
LoadingIcon.ClearValue(StyleProperty);
LoadingIcon.Visibility = Visibility.Visible;
}
if (relationData.Type is enumF4sdSearchResultClass.Ticket)
{
if (relationData.Infos is null)
return;
if (relationData.Infos.TryGetValue("Summary", out var ticketSummary))
{
CustomTextBlockBottom.Text = ticketSummary;
CustomTextBlockBorderBottom.Visibility = Visibility.Visible;
}
}
else
{
SearchRelationGrid.Visibility = Visibility.Visible;
if (searchRelationMenuData.LastUsed == DateTime.MinValue)
{
LessThanTextBlock.Text= string.Empty;
LessThanTextBlock.Text = string.Empty;
LessThanTextBlock.Visibility = Visibility.Collapsed;
LastSeenTextBox.Visibility = Visibility.Collapsed;
ActivityIndicator.Width = 0;
ActivityIndicator.Visibility = Visibility.Collapsed;
ActivityTextBlock.Visibility = Visibility.Collapsed;
}
LastSeenTextBox.Visibility = Visibility.Collapsed;
ActivityIndicator.Width = 0;
ActivityIndicator.Visibility = Visibility.Collapsed;
ActivityTextBlock.Visibility = Visibility.Collapsed;
}
else
{
{
var lastUsedTimeSpan = DateTime.UtcNow - searchRelationMenuData.LastUsed;
LanguageDefinitionsConverter valueConverter = new LanguageDefinitionsConverter();
string lastSeenText = null;
@@ -194,86 +215,97 @@ namespace FasdDesktopUi.Basics.UserControls
LessThanTextBlock.Text = lastSeenText;
LessThanTextBlock.Visibility = Visibility.Visible;
LastSeenTextBox.Visibility = Visibility.Visible;
ActivityIndicator.Width = Math.Max(ActivityIndicator.Width * relationData.UsingLevel, ActivityIndicator.Width * 0.1);
ActivityIndicator.Visibility = Visibility.Visible;
ActivityTextBlock.Visibility = Visibility.Visible;
}
}
}
void DrawDefault()
{
if (string.IsNullOrWhiteSpace(MenuData.SubMenuText))
return;
CustomTextBlockBottom.Text = MenuData.SubMenuText;
CustomTextBlockBorderBottom.Visibility = Visibility.Visible;
}
}
#endregion
#endregion
public CustomMenuItem(bool isLean)
{
_isLean = isLean;
InitializeComponent();
}
#region Events
private void MenuItemBorder_Click(object sender, InputEventArgs e)
{
if (MenuData.UiAction == null)
return;
cUiActionBase.RaiseEvent(MenuData.UiAction, this, this);
}
#region Hover
private void MenuItemBorder_MouseEnter(object sender, MouseEventArgs e)
{
cUtility.SetTickerTextAnimation(CustomTextBlock, CustomTextBlockBorder);
if (string.IsNullOrWhiteSpace(CustomTextBlockBottom.Text) is false)
cUtility.SetTickerTextAnimation(CustomTextBlockBottom, CustomTextBlockBorderBottom);
}
private void MenuItemBorder_MouseLeave(object sender, MouseEventArgs e)
{
CustomTextBlock.TextTrimming = TextTrimming.CharacterEllipsis;
CustomTextBlock.BeginAnimation(MarginProperty, null);
CustomTextBlockBorder.ClearValue(WidthProperty);
CustomTextBlockBorderBottom.ClearValue(WidthProperty);
if (string.IsNullOrWhiteSpace(CustomTextBlockBottom.Text) is false)
{
CustomTextBlockBottom.TextTrimming = TextTrimming.CharacterEllipsis;
CustomTextBlockBottom.BeginAnimation(MarginProperty, null);
}
}
#endregion
#endregion
public void ShowDetailHeadings(bool showDetails)
{
SearchRelationGrid.ColumnDefinitions[0].Width =
showDetails ? new GridLength(1, GridUnitType.Auto) : new GridLength(0);
}
private void CustomMenuItemUc_Initialized(object sender, EventArgs e)
{
if (_isLean)
MenuItemBorder.Height = 30;
}
}
}
LastSeenTextBox.Visibility = Visibility.Visible;
ActivityIndicator.Width = Math.Max(ActivityIndicator.Width * relationData.UsingLevel, ActivityIndicator.Width * 0.1);
ActivityIndicator.Visibility = Visibility.Visible;
ActivityTextBlock.Visibility = Visibility.Visible;
}
}
}
void DrawDefault()
{
if (string.IsNullOrWhiteSpace(MenuData.SubMenuText))
return;
CustomTextBlockBottom.Text = MenuData.SubMenuText;
CustomTextBlockBorderBottom.Visibility = Visibility.Visible;
}
}
#endregion
#endregion
public CustomMenuItem(bool isLean)
{
_isLean = isLean;
InitializeComponent();
}
#region Events
private void MenuItemBorder_Click(object sender, InputEventArgs e)
{
if (MenuData.UiAction == null)
return;
if (MenuData.UiAction is cSubMenuAction subMenuAction)
{
bool useTempData = subMenuAction.UseTempData;
if (useTempData)
{
QuickActionSelector.Instance.Search.IsEnabled = false;
}
}
cUiActionBase.RaiseEvent(MenuData.UiAction, this, this);
}
#region Hover
private void MenuItemBorder_MouseEnter(object sender, MouseEventArgs e)
{
cUtility.SetTickerTextAnimation(CustomTextBlock, CustomTextBlockBorder);
if (string.IsNullOrWhiteSpace(CustomTextBlockBottom.Text) is false)
cUtility.SetTickerTextAnimation(CustomTextBlockBottom, CustomTextBlockBorderBottom);
}
private void MenuItemBorder_MouseLeave(object sender, MouseEventArgs e)
{
CustomTextBlock.TextTrimming = TextTrimming.CharacterEllipsis;
CustomTextBlock.BeginAnimation(MarginProperty, null);
CustomTextBlockBorder.ClearValue(WidthProperty);
CustomTextBlockBorderBottom.ClearValue(WidthProperty);
if (string.IsNullOrWhiteSpace(CustomTextBlockBottom.Text) is false)
{
CustomTextBlockBottom.TextTrimming = TextTrimming.CharacterEllipsis;
CustomTextBlockBottom.BeginAnimation(MarginProperty, null);
}
}
#endregion
#endregion
public void ShowDetailHeadings(bool showDetails)
{
SearchRelationGrid.ColumnDefinitions[0].Width =
showDetails ? new GridLength(1, GridUnitType.Auto) : new GridLength(0);
}
private void CustomMenuItemUc_Initialized(object sender, EventArgs e)
{
if (_isLean)
MenuItemBorder.Height = 30;
}
}
}

View File

@@ -0,0 +1,23 @@
<ToolTip x:Class="FasdDesktopUi.Basics.UserControls.CustomMenuItemToolTipTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls"
mc:Ignorable="d"
>
<ToolTip.Template>
<ControlTemplate>
<Border BorderBrush="{DynamicResource FontColor.Menu.Categories}" BorderThickness="1" CornerRadius="5"
Background="{DynamicResource BackgroundColor.Menu.Categories}"
>
<TextBlock Text="{Binding Text, RelativeSource={RelativeSource AncestorType=ToolTip}}"
Foreground="{DynamicResource FontColor.Menu.Categories}"
TextWrapping="Wrap"
MaxWidth="300"
Margin="8,3,8,5"
/>
</Border>
</ControlTemplate>
</ToolTip.Template>
</ToolTip>

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class CustomMenuItemToolTipTemplate : ToolTip
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(CustomMenuItemToolTipTemplate), new PropertyMetadata("This is a default popup text."));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public CustomMenuItemToolTipTemplate(string content = null)
{
InitializeComponent();
Text = content;
}
}
}

View File

@@ -26,8 +26,8 @@
Style="{DynamicResource SettingsPage.Close.Icon}"
BorderPadding="5"
SelectedMaterialIcon="ic_remove"
MouseLeftButtonUp="CollapseButton_MouseLeftButtonUp"
TouchDown="CollapseButton_TouchDown" />
MouseLeftButtonUp="CollapseButton_Click"
TouchDown="CollapseButton_Click" />
<TextBlock Style="{DynamicResource DetailsPage.DataHistory.TitleColumn.OverviewTitle}"
Text="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=QuickAction.Parameter}" />

View File

@@ -1,23 +1,12 @@
using C4IT.FASD.Base;
using C4IT.Logging;
using FasdDesktopUi.Basics.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.UserControls
@@ -104,13 +93,13 @@ namespace FasdDesktopUi.Basics.UserControls
switch (parameterValue)
{
case cAdjustableParameterBoolean booleanParameter:
AddBooleanParameter(parameter.Key, booleanParameter);
AddBooleanParameter(booleanParameter);
break;
case cAdjustableParameterNumerical numericalParameter:
AddNumericalParameter(parameter.Key, numericalParameter);
AddNumericalParameter(numericalParameter);
break;
case cAdjustableParameterDropDown dropDownParameter:
AddDropDownParameter(parameter.Key, dropDownParameter);
AddDropDownParameter(dropDownParameter);
break;
default:
break;
@@ -140,7 +129,7 @@ namespace FasdDesktopUi.Basics.UserControls
#region Helper
private void AddBooleanParameter(string parameterKey, cAdjustableParameterBoolean booleanParameter)
private void AddBooleanParameter(cAdjustableParameterBoolean booleanParameter)
{
try
{
@@ -157,7 +146,7 @@ namespace FasdDesktopUi.Basics.UserControls
outerPanel.Children.Add(valueCheckBox);
TextBlock parameterNameTextBlock = new TextBlock() { Text = booleanParameter.Names.GetValue(), Margin = new Thickness(0, 0, 7.5, 0) };
if(!string.IsNullOrEmpty(booleanParameter.Descriptions.GetValue()))
if (!string.IsNullOrEmpty(booleanParameter.Descriptions.GetValue()))
{
parameterNameTextBlock.ToolTip = booleanParameter.Descriptions.GetValue();
}
@@ -172,7 +161,7 @@ namespace FasdDesktopUi.Basics.UserControls
}
}
private void AddNumericalParameter(string parameterKey, cAdjustableParameterNumerical numericalParameter)
private void AddNumericalParameter(cAdjustableParameterNumerical numericalParameter)
{
try
{
@@ -185,20 +174,11 @@ namespace FasdDesktopUi.Basics.UserControls
valueTextBox.SetResourceReference(BackgroundProperty, "BackgroundColor.DetailsPage.DataHistory.TitleColumn");
valueTextBox.SetResourceReference(BorderBrushProperty, "BackgroundColor.DetailsPage.DataHistory.ValueColumn");
valueTextBox.PreviewKeyDown += ((sender, e) =>
valueTextBox.TextChanged += (sender, e) =>
{
if (double.TryParse(valueTextBox.Text, out var parsedValue))
ParameterValues[numericalParameter] = parsedValue;
});
valueTextBox.PreviewTextInput += new TextCompositionEventHandler((sender, e) =>
{
var plannedValue = valueTextBox.Text.Insert(valueTextBox.CaretIndex, e.Text);
if (double.TryParse(plannedValue, out var parsedValue))
ParameterValues[numericalParameter] = parsedValue;
else
e.Handled = true;
});
};
DockPanel.SetDock(valueTextBox, Dock.Right);
outerPanel.Children.Add(valueTextBox);
@@ -219,7 +199,7 @@ namespace FasdDesktopUi.Basics.UserControls
}
}
private void AddDropDownParameter(string parameterKey, cAdjustableParameterDropDown dropDownParameter)
private void AddDropDownParameter(cAdjustableParameterDropDown dropDownParameter)
{
try
{
@@ -227,8 +207,12 @@ namespace FasdDesktopUi.Basics.UserControls
ParameterValues[dropDownParameter] = dropDownParameter.Default;
ComboBox valueComboBox = new ComboBox() { SelectedItem = dropDownParameter.Default, MinWidth = 125 };
valueComboBox.Style = (Style)FindResource("DarkComboBox");
ComboBox valueComboBox = new ComboBox
{
SelectedItem = dropDownParameter.Default,
MinWidth = 125,
Style = (Style)FindResource("DarkComboBox")
};
valueComboBox.DropDownOpened += (sender, e) => cFocusInvoker.InvokeGotFocus(this, e);
valueComboBox.DropDownClosed += (sender, e) => cFocusInvoker.InvokeLostFocus(this, e);
@@ -346,9 +330,7 @@ namespace FasdDesktopUi.Basics.UserControls
}
}
#region CollapseButton_Click
private void CollapseButton_Click()
private void CollapseButton_Click(object sender, InputEventArgs e)
{
try
{
@@ -360,17 +342,5 @@ namespace FasdDesktopUi.Basics.UserControls
LogException(E);
}
}
private void CollapseButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
CollapseButton_Click();
}
private void CollapseButton_TouchDown(object sender, TouchEventArgs e)
{
CollapseButton_Click();
}
#endregion
}
}

View File

@@ -23,12 +23,12 @@
Visibility="{Binding ElementName=DataCanvasUc, Path=IsDetailedLayout, Converter={StaticResource BoolToVisibility}}"
IsCloseButtonVisible="{Binding ElementName=DataCanvasUc, Path=DataCanvasData, Converter={StaticResource IsCloseButtonVisible}, ConverterParameter={x:Static converter:enumDataCanvasTypes.detailedData} }" />
<local:DynamicChart x:Name="DynamicChartUc"
HorizontalAlignment="Stretch"
<local:DynamicChart x:Name="DynamicChartUc"
HorizontalAlignment="Stretch"
Width="385"
Visibility="{Binding ElementName=DataCanvasUc, Path=IsDetailedLayout, Converter={StaticResource BoolToVisibility}}"
IsCloseButtonVisible="{Binding ElementName=DataCanvasUc, Path=DataCanvasData, Converter={StaticResource IsCloseButtonVisible}, ConverterParameter={x:Static converter:enumDataCanvasTypes.detailedData} }" />
<local:DetailedRecommendation x:Name="RecommendationUc"
Width="{Binding ElementName=DetailedDataUc, Path=ActualWidth, UpdateSourceTrigger=PropertyChanged}"
MinWidth="300"

View File

@@ -1,22 +1,9 @@
using C4IT.Logging;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Pages.DetailsPage.Models;
using FasdDesktopUi.Basics.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.UserControls
@@ -63,7 +50,9 @@ namespace FasdDesktopUi.Basics.UserControls
_me.dataProvider.HealthCardDataHelper.LoadingHelper.DataRefreshed += _me.HealthCardDataHelper_DataRefreshed;
}
_me.QuickActionStatusUc.CancelQuickAction();
bool isSameQuickAction = oldData?.QuickActionStatusMonitorData?.QuickActionDefinition?.Id == newData?.QuickActionStatusMonitorData?.QuickActionDefinition?.Id;
if (!isSameQuickAction && newData?.QuickActionStatusMonitorData?.QuickActionDefinition?.RunImmediate != true)
_me.QuickActionStatusUc.CancelQuickAction();
_me.RecommendationUc.RecommendationData = _me.DataCanvasData.RecommendationData;
_me.RecommendationUc.CloseButtonClickedAction = _me.CloseDataCanvas;

View File

@@ -2,21 +2,10 @@
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Pages.DetailsPage.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace FasdDesktopUi.Basics.UserControls
{
@@ -27,7 +16,18 @@ namespace FasdDesktopUi.Basics.UserControls
#region RecommendationData
public static readonly DependencyProperty RecommendationDataProperty =
DependencyProperty.Register("RecommendationData", typeof(cRecommendationDataModel), typeof(DetailedRecommendation), new PropertyMetadata(new cRecommendationDataModel()));
DependencyProperty.Register("RecommendationData", typeof(cRecommendationDataModel), typeof(DetailedRecommendation), new PropertyMetadata(new cRecommendationDataModel(), new PropertyChangedCallback(HandleRecommendationDataChanged)));
private static void HandleRecommendationDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is DetailedRecommendation recommendationUc))
return;
if (string.IsNullOrWhiteSpace(recommendationUc.RecommendationData?.Recommendation))
recommendationUc.Visibility = Visibility.Collapsed;
else
recommendationUc.Visibility = Visibility.Visible;
}
public cRecommendationDataModel RecommendationData
{
@@ -66,7 +66,7 @@ namespace FasdDesktopUi.Basics.UserControls
if (d is DetailedRecommendation recommendation && e.NewValue is IconData iconData)
{
IconHelper.SetIconValue(recommendation.RecommendationIcon, iconData);
}
}
}
public string PrimaryIconColorResourceName
@@ -99,8 +99,7 @@ namespace FasdDesktopUi.Basics.UserControls
private void CloseButton_Click()
{
if (CloseButtonClickedAction != null)
CloseButtonClickedAction.Invoke();
CloseButtonClickedAction?.Invoke();
}
private void CloseButton_MouseUp(object sender, MouseButtonEventArgs e)

View File

@@ -3,6 +3,7 @@ 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;
@@ -21,6 +22,7 @@ using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using static C4IT.Logging.cLogManager;
using F4SD.Gamification.Services;
namespace FasdDesktopUi.Basics.UserControls
{
@@ -30,6 +32,16 @@ namespace FasdDesktopUi.Basics.UserControls
private bool secretsAreShown = false;
private readonly IRawValueFormatter _rawValueFormatter = new RawValueFormatter();
private static object _currentQuickActionLock = new object();
private Guid _currentRunningQuickActionId;
public Guid CurrentRunningQuickActionId
{
get { lock (_currentQuickActionLock) { return _currentRunningQuickActionId; } }
set { lock (_currentQuickActionLock) { _currentRunningQuickActionId = value; } }
}
#region Helperclasses QuickAction Output
public abstract class cQuickActionOutput
@@ -38,7 +50,7 @@ namespace FasdDesktopUi.Basics.UserControls
public cQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput)
{
_rawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
_rawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
_rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
ErrorCode = scriptOutput.ErrorCode;
ErrorDescription = scriptOutput.ErrorDescription;
@@ -804,7 +816,7 @@ namespace FasdDesktopUi.Basics.UserControls
if (measureValues?.Count <= 0)
return;
_rawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
_rawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
_rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
for (int i = 0; i < measureValues.Count; i++)
@@ -1006,7 +1018,7 @@ namespace FasdDesktopUi.Basics.UserControls
else if (QuickActionData.ActionSteps.All(step => step.Status == enumQuickActionRevisionStatus.finishedSuccessfull))
status = enumQuickActionRevisionStatus.finishedSuccessfull;
RaiseEvent(new QuickActionEventArgs(QuickActionFinishedEvent, this) { QuickActionResult = result, QuickActionStatus = status, QuickAction = QuickActionData.QuickActionDefinition});
RaiseEvent(new QuickActionEventArgs(QuickActionFinishedEvent, this) { QuickActionResult = result, QuickActionStatus = status, QuickAction = QuickActionData.QuickActionDefinition });
CopyButton.Visibility = Visibility.Visible;
@@ -1022,6 +1034,7 @@ namespace FasdDesktopUi.Basics.UserControls
finally
{
VisualizeQuickActionFinish(status);
GamificationService.TrackAction(CockpitAction.QuickActionExecuted);
}
}

View File

@@ -0,0 +1,40 @@
<UserControl x:Class="FasdDesktopUi.Basics.UserControls.FooterButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls"
xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon"
xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter"
mc:Ignorable="d"
d:DesignHeight="35"
d:DesignWidth="230"
x:Name="FooterBtn">
<UserControl.Resources>
<vc:LanguageDefinitionsConverter x:Key="LanguageConverter" />
</UserControl.Resources>
<Grid x:Name="MainGrid"
x:FieldModifier="private"
Visibility="Collapsed">
<Border x:Name="MainBorder"
Style="{DynamicResource Menu.MainCategory}"
CornerRadius="7.5"
Height="35"
MouseLeftButtonUp="Button_Click"
TouchDown="Button_Click">
<StackPanel Orientation="Horizontal">
<ico:AdaptableIcon x:Name="ButtonIcon"
Margin="0 0 10 0" />
<TextBlock x:Name="ButtonLabel"
FontSize="16"
Text="{Binding ElementName=FooterBtn, Path=LabelText}" />
</StackPanel>
</Border>
<local:Badge Text="Beta"
Margin="-12.5"
HorizontalAlignment="Right"
VerticalAlignment="Top" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,84 @@
using C4IT.MultiLanguage;
using F4SD_AdaptableIcon;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.UiActions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class FooterButton : UserControl
{
public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register(nameof(LabelText), typeof(string), typeof(FooterButton), new PropertyMetadata(string.Empty));
public cUiQuickAction QuickAction
{
get { return (cUiQuickAction)GetValue(QuickActionProperty); }
set { SetValue(QuickActionProperty, value); }
}
public static readonly DependencyProperty QuickActionProperty =
DependencyProperty.Register(nameof(QuickAction), typeof(cUiQuickAction), typeof(FooterButton), new PropertyMetadata(null, new PropertyChangedCallback(HandleQuickActionChanged)));
private static void HandleQuickActionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is FooterButton button))
return;
button.UpdateButtonProperties();
}
private void UpdateButtonProperties()
{
MainGrid.Visibility = QuickAction is null ? Visibility.Collapsed : Visibility.Visible;
string tooltip = QuickAction != null ? null : cMultiLanguageSupport.GetItem("RemoteConnection.Button.Disabled");
SetEnableButton(QuickAction != null && QuickAction.DisplayType == Enums.enumActionDisplayType.enabled, tooltip);
IconData iconData = IconDataConverter.Convert(QuickAction.QuickActionConfig.Icon);
IconHelper.SetIconValue(ButtonIcon, iconData);
}
public FooterButton()
{
InitializeComponent();
}
private async void Button_Click(object sender, InputEventArgs e)
{
if (QuickAction is null)
return;
SetEnableButton(false);
cUiActionBase.RaiseEvent(QuickAction, this, this);
SetEnableButton(true);
}
internal void SetEnableButton(bool isEnabled, string tooltip = null)
{
if (isEnabled)
{
MainBorder.SetResourceReference(StyleProperty, "Menu.MainCategory");
MainBorder.ClearValue(OpacityProperty);
}
else
{
MainBorder.SetResourceReference(StyleProperty, "Menu.MainCategory.NoHover");
MainBorder.Opacity = 0.5;
}
MainBorder.ToolTip = tooltip;
}
}
}

View File

@@ -0,0 +1,74 @@
<UserControl x:Class="FasdDesktopUi.Basics.UserControls.Gamification.LevelTracker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls.Gamification"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground"
Value="{DynamicResource FontColor.DetailsPage.DataHistory.TitleColumn.MainTitle}" />
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<Grid Margin="10 0">
<Border BorderBrush="{DynamicResource Color.FunctionMarker}"
CornerRadius="50"
BorderThickness="6"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#01010101"
Height="45"
Width="45">
</Border>
<TextBlock x:Name="LevelValueTextBlock"
TextAlignment="Center"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontWeight="Bold"
FontSize="20" />
<Ellipse x:Name="CoverEllipse"
Stroke="{DynamicResource Color.AppBackground}"
Opacity="0.5"
StrokeThickness="7"
Height="46"
Width="46"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<RotateTransform Angle="-90" />
</Ellipse.RenderTransform>
</Ellipse>
</Grid>
<StackPanel VerticalAlignment="Center">
<StackPanel.Resources>
<Style TargetType="StackPanel">
<Setter Property="Visibility"
Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType=FrameworkElement}, Path=IsMouseOver}"
Value="True">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock x:Name="LevelTitelTextBlock"
FontWeight="Bold"
FontSize="18" />
<TextBlock x:Name="XpTextBlock"
FontWeight="Light"
FontSize="14" />
</StackPanel>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,39 @@
using F4SD.Gamification;
using F4SD.Gamification.Services;
using System;
using System.Windows.Controls;
using System.Windows.Media;
namespace FasdDesktopUi.Basics.UserControls.Gamification
{
public partial class LevelTracker : UserControl
{
public LevelTracker()
{
InitializeComponent();
}
private double GetCircumferenceOfCoverEllipse()
{
return (2 * Math.PI * (CoverEllipse.Height / 2.0 - CoverEllipse.StrokeThickness / 2.0)) / CoverEllipse.StrokeThickness;
}
protected override void OnInitialized(EventArgs e)
{
CoverEllipse.StrokeDashArray = new DoubleCollection() { GetCircumferenceOfCoverEllipse() };
LevelService.ExperiencePointsChanged += UpdateExperiencePoints;
base.OnInitialized(e);
}
private void UpdateExperiencePoints(object sender, LevelEventArgs e)
{
LevelValueTextBlock.Text = e.CurrentLevel.ToString();
double relativeProgress = (double)e.CurrentXp / (double)e.XpRequiredForLevelUp;
CoverEllipse.StrokeDashOffset = (GetCircumferenceOfCoverEllipse() * relativeProgress) * -1.0;
LevelTitelTextBlock.Text = e.LevelTitle;
XpTextBlock.Text = $"{e.CurrentXp} / {e.XpRequiredForLevelUp} XP";
}
}
}

View File

@@ -0,0 +1,72 @@
<UserControl x:Class="FasdDesktopUi.Basics.UserControls.InformationClassSearchBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls"
xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon"
xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
Name="_this"
IsVisibleChanged="BlurInvoker_IsActiveChanged">
<UserControl.Resources>
<vc:LanguageDefinitionsConverter x:Key="LanguageConverter" />
</UserControl.Resources>
<Border Background="{DynamicResource BackgroundColor.Menu.Categories}"
CornerRadius="17.5"
Margin="-2.5"
Padding="2.5"
VerticalAlignment="Bottom"
x:Name="BackgroundBorder"
x:FieldModifier="private">
<DockPanel>
<ico:AdaptableIcon x:Name="PhoneCallIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
Visibility="Collapsed"
SelectedMaterialIcon="ic_phone" />
<ico:AdaptableIcon x:Name="ComputerCallIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
Visibility="Collapsed"
SelectedInternIcon="misc_computer" />
<ico:AdaptableIcon x:Name="UserCallIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
Visibility="Collapsed"
SelectedInternIcon="misc_user" />
<ico:AdaptableIcon x:Name="WarningIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
PrimaryIconColor="{DynamicResource HighlightColor.Orange}"
Visibility="Collapsed"
SelectedInternIcon="status_bad" />
<local:SearchBar x:Name="InnerSearchBar"
x:FieldModifier="private"
SearchButtonSize="{Binding SearchButtonSize, ElementName=_this}"
CloseButtonSize="{Binding CloseButtonSize, ElementName=_this}"
PlaceholderText="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=Searchbar.Placeholder.UserName}"
ShowCloseButton="True"
ShowSearchButton="True"
SearchValueChanged="InnerSearchBar_SearchValueChanged"
CancelledSearch="InnerSearchBar_CancelledSearch" />
</DockPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,287 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using FasdDesktopUi.Basics.Models;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using static C4IT.Logging.cLogManager;
using C4IT.MultiLanguage;
using C4IT.FASD.Base;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class InformationClassSearchBar : UserControl, IBlurInvoker
{
#region Properties
public enum eSearchStatus { message, active, fixedResult }
public eSearchStatus SearchStatus { get; private set; } = eSearchStatus.message;
private static CancellationTokenSource _currentSearchTaskToken = null;
private static Guid? _currentSearchTaskId = null;
private static readonly object _currentSearchTaskLock = new object();
private readonly Dictionary<enumF4sdSearchResultClass, UIElement> _searchIcons = null;
public delegate Task ChangedSearchValueDelegate(cFilteredResults results);
public ChangedSearchValueDelegate ChangedSearchValue { get; set; } = null;
public Action CancledSearchAction { get; set; }
public bool BlurInvoker_IsActive => IsVisible;
public string SearchValue => InnerSearchBar.SearchValue;
#endregion
#region Dependency Properties
public static readonly DependencyProperty SearchButtonSizeProperty =
DependencyProperty.Register(nameof(SearchButtonSize), typeof(double), typeof(InformationClassSearchBar), new PropertyMetadata(30.0));
public double SearchButtonSize
{
get => (double)GetValue(SearchButtonSizeProperty);
set => SetValue(SearchButtonSizeProperty, value);
}
public static readonly DependencyProperty CloseButtonSizeProperty =
DependencyProperty.Register(nameof(CloseButtonSize), typeof(double), typeof(InformationClassSearchBar), new PropertyMetadata(30.0));
public double CloseButtonSize
{
get => (double)GetValue(CloseButtonSizeProperty);
set => SetValue(CloseButtonSizeProperty, value);
}
#endregion
public InformationClassSearchBar()
{
InitializeComponent();
_searchIcons = new Dictionary<enumF4sdSearchResultClass, UIElement>
{
{ enumF4sdSearchResultClass.Phone, PhoneCallIndicator },
{ enumF4sdSearchResultClass.User, UserCallIndicator },
{ enumF4sdSearchResultClass.Computer, ComputerCallIndicator }
};
}
public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e)
{
BlurInvoker.InvokeVisibilityChanged(this, new EventArgs());
if (e.NewValue is bool newVisible)
{
if (!newVisible)
{
InnerSearchBar.IsInputEnabled = true;
InnerSearchBar.ShowSearchButton = true;
WarningIndicator.Visibility = Visibility.Collapsed;
TicketOverview.Instance?.ResetSelection();
foreach (var entry in _searchIcons.Values)
entry.Visibility = Visibility.Collapsed;
}
SetApiStatus();
}
if (Visibility == Visibility.Visible)
Dispatcher.BeginInvoke((Action)(() => InnerSearchBar.FocusInput()), DispatcherPriority.Render);
}
public void Clear()
{
SearchStatus = eSearchStatus.message;
InnerSearchBar.Clear();
}
public void ActivateManualSearch()
{
SearchStatus = eSearchStatus.active;
InnerSearchBar.ShowSearchButton = true;
WarningIndicator.Visibility = Visibility.Collapsed;
foreach (var entry in _searchIcons.Values)
entry.Visibility = Visibility.Collapsed;
InnerSearchBar.Clear();
InnerSearchBar.IsInputEnabled = true;
InnerSearchBar.FocusInput();
}
public void SetSearchText(string search)
{
SearchStatus = eSearchStatus.active;
InnerSearchBar.SetSearchText(search);
}
public void SetSpinnerVisibility(Visibility visibility)
{
InnerSearchBar.SetSpinnerVisibility(visibility);
}
public async Task SetFixedSearchResultAsync(enumF4sdSearchResultClass resultClass, string search, cFilteredResults result)
{
SearchStatus = eSearchStatus.fixedResult;
InnerSearchBar.IsInputEnabled = false;
InnerSearchBar.ShowSearchButton = false;
WarningIndicator.Visibility = Visibility.Collapsed;
foreach (var entryIcon in _searchIcons)
entryIcon.Value.Visibility = entryIcon.Key == resultClass ? Visibility.Visible : Visibility.Collapsed;
InnerSearchBar.SetSearchText(search);
if (ChangedSearchValue != null)
await ChangedSearchValue.Invoke(result);
}
public void SetApiStatus()
{
try
{
var status = cConnectionStatusHelper.Instance?.ApiConnectionStatus;
if (status == null)
return;
bool isEnabled = false;
string txt = null;
switch (status)
{
case cConnectionStatusHelper.enumOnlineStatus.online:
isEnabled = true;
break;
case cConnectionStatusHelper.enumOnlineStatus.connectionError:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ConnectError");
break;
case cConnectionStatusHelper.enumOnlineStatus.incompatibleServerVersion:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.IncompatibleVersion");
break;
case cConnectionStatusHelper.enumOnlineStatus.serverStarting:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ServerStarting");
break;
case cConnectionStatusHelper.enumOnlineStatus.serverNotConfigured:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ServerNotConfigured");
break;
case cConnectionStatusHelper.enumOnlineStatus.illegalConfig:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.IllegalConfig");
break;
case cConnectionStatusHelper.enumOnlineStatus.unauthorized:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.Unauthorized");
break;
default:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.Offline");
break;
}
if (!isEnabled)
{
SearchStatus = eSearchStatus.message;
InnerSearchBar.SetSearchText(txt);
InnerSearchBar.IsInputEnabled = false;
WarningIndicator.Visibility = Visibility.Visible;
InnerSearchBar.ShowSearchButton = false;
foreach (var entry in _searchIcons.Values)
entry.Visibility = Visibility.Collapsed;
}
}
catch (Exception e)
{
LogException(e);
}
}
private async Task CancelRunningSearchTaskAsync()
{
lock (_currentSearchTaskLock)
{
if (_currentSearchTaskToken != null)
{
LogEntry("Canceling current running search...");
_currentSearchTaskToken.Cancel(true);
_currentSearchTaskToken = null;
}
}
Guid? currentTaskId = null;
lock (_currentSearchTaskLock)
{
if (_currentSearchTaskId != null)
{
currentTaskId = _currentSearchTaskId;
_currentSearchTaskId = null;
}
}
if (currentTaskId != null)
{
LogEntry("Sending a search stop...");
await cFasdCockpitCommunicationBase.Instance.GetSearchResultsStop((Guid)currentTaskId, CancellationToken.None);
}
}
private async void InnerSearchBar_SearchValueChanged(object sender, string searchValue)
{
MethodBase cm = null;
if (cLogManager.DefaultLogger.IsDebug) { cm = MethodBase.GetCurrentMethod(); LogMethodBegin(cm); }
try
{
await CancelRunningSearchTaskAsync();
lock (_currentSearchTaskLock)
{
LogEntry("Start running new search...");
SearchValueChanged?.Invoke(this, searchValue);
}
}
catch (Exception e)
{
LogException(e);
}
finally
{
if (cm != null) LogMethodEnd(cm);
}
}
private void InnerSearchBar_CancelledSearch(object sender, RoutedEventArgs e)
{
e.Handled = true;
RaiseCancledSearchEvent();
if (cConnectionStatusHelper.Instance?.ApiConnectionStatus == cConnectionStatusHelper.enumOnlineStatus.online)
InnerSearchBar.Clear();
CancledSearchAction?.Invoke();
}
#region Events
public event EventHandler<string> SearchValueChanged;
public static readonly RoutedEvent CancledSearchEvent =
EventManager.RegisterRoutedEvent(nameof(CancledSearch), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InformationClassSearchBar));
public event RoutedEventHandler CancledSearch
{
add => AddHandler(CancledSearchEvent, value);
remove => RemoveHandler(CancledSearchEvent, value);
}
private void RaiseCancledSearchEvent()
{
RaiseEvent(new RoutedEventArgs(CancledSearchEvent));
}
#endregion
}
}

View File

@@ -1,22 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Linq;
using System.Threading.Tasks;
using C4IT.FASD.Base;
using F4SD_AdaptableIcon;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.SupportCase;
using FasdDesktopUi.Basics.Services.SupportCase.Controllers;
using FasdDesktopUi.Basics.UiActions;
using FasdDesktopUi.Pages;
using FasdDesktopUi.Pages.SearchPage;
using C4IT.FASD.Base;
using static C4IT.Logging.cLogManager;
using F4SD_AdaptableIcon;
namespace FasdDesktopUi.Basics.UserControls
{
@@ -26,6 +26,8 @@ namespace FasdDesktopUi.Basics.UserControls
#region PopUpIsVisible
public SupportCaseController SupportCaseController { get; set; }
internal static readonly DependencyPropertyKey PopUpIsVisibleKey = DependencyProperty.RegisterReadOnly("PopUpIsVisible", typeof(bool), typeof(MenuBar), new PropertyMetadata(false));
public static readonly DependencyProperty PopUpIsVisibleProperty = PopUpIsVisibleKey.DependencyProperty;
@@ -109,7 +111,7 @@ namespace FasdDesktopUi.Basics.UserControls
{
AdaptableIcon.AdaptableIcon menuIcon = new AdaptableIcon.AdaptableIcon() { Style = menuPinnedIconStyle };
IconData icon = sortedMenuData[i].MenuIcon;
IconData icon = sortedMenuData[i].MenuIcon.Icon;
if (icon.Intern != null)
menuIcon.SelectedInternIcon = icon.Intern;
else if(icon.Material != null)
@@ -142,17 +144,23 @@ namespace FasdDesktopUi.Basics.UserControls
if (sortedMenuData[i].IconPositionIndex >= 0)
MenuBarStackPanel.Children.Insert(MenuBarStackPanel.Children.Count - 1, menuIcon);
}
if (cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.DefaultTemplate != null)
cCopyTemplate defaultCopyTemplate = null;
defaultCopyTemplate = SupportCaseController?.GetCopyTemplate();
if (defaultCopyTemplate != null)
{
var copyIcon = new AdaptableIcon.AdaptableIcon()
{
Style = menuPinnedIconStyle,
SelectedInternIcon = enumInternIcons.menuBar_copy,
ToolTip = cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.DefaultTemplate.Descriptions.GetValue(Default: null),
ToolTip = defaultCopyTemplate?.Descriptions.GetValue(Default: null),
};
copyIcon.Tag = new cMenuDataBase() { IconPositionIndex = 2, MenuIcon = new F4SD_AdaptableIcon.IconData(enumInternIcons.menuBar_copy), UiAction = new cUiCopyAction(cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.DefaultTemplate) };
copyIcon.Tag = new cMenuDataBase() { IconPositionIndex = 2, MenuIcon = new cMenuDataBase.MenuIconInfo(new F4SD_AdaptableIcon.IconData(enumInternIcons.menuBar_copy)), UiAction = new cUiCopyAction(defaultCopyTemplate) };
copyIcon.MouseLeftButtonUp += MenuItem_MouseUp;
copyIcon.TouchDown += MenuItem_TouchDown;

View File

@@ -167,6 +167,7 @@
TextChanged="NotepadRichTextBox_TextChanged"
Foreground="{DynamicResource FontColor.DetailsPage.Widget}"
Background="{DynamicResource BackgroundColor.DetailsPage.Widget.Title}"
SpellCheck.IsEnabled="True"
SelectionChanged="NotepadRichTextBox_SelectionChanged"
IsVisibleChanged="NotepadRichTextBox_IsVisibleChanged"
GotKeyboardFocus="NotepadRichTextBox_GotKeyboardFocus">

View File

@@ -1,4 +1,5 @@
using F4SD_AdaptableIcon.Enums;
using C4IT.FASD.Base;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Helper;
using System;
using System.IO;
@@ -8,6 +9,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Threading;
using static C4IT.Logging.cLogManager;
@@ -109,7 +111,7 @@ namespace FasdDesktopUi.Basics.UserControls
}
_me.LockNotepadIcon.SelectedInternIcon = _me.IsLocked ? F4SD_AdaptableIcon.Enums.enumInternIcons.lock_closed : F4SD_AdaptableIcon.Enums.enumInternIcons.lock_open;
_me.CloseNotepadIcon.IsEnabled = _me.IsLocked ? false : true;
}
@@ -147,9 +149,9 @@ namespace FasdDesktopUi.Basics.UserControls
{
return;
}
}
catch(Exception E)
catch (Exception E)
{
LogException(E);
}
@@ -172,8 +174,8 @@ namespace FasdDesktopUi.Basics.UserControls
#endregion
#region Methods
private void NotepadRichTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
try
@@ -309,7 +311,11 @@ namespace FasdDesktopUi.Basics.UserControls
if (DataProvider is null)
return;
Dispatcher.Invoke(() => DataProvider.SaveCaseNotes());
Dispatcher.Invoke(() =>
{
SetLanguageOfDocument();
DataProvider.SaveCaseNotes();
});
}
catch (Exception E)
{
@@ -317,9 +323,19 @@ namespace FasdDesktopUi.Basics.UserControls
}
}
private void SetLanguageOfDocument()
{
if (cF4SDCockpitXmlConfig.Instance.HealthCardConfig?.ProtocollLanguage != null)
{
var languageTag = XmlLanguage.GetLanguage(cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage);
TextRange range = new TextRange(NotepadRichTextBox.Document.ContentStart, NotepadRichTextBox.Document.ContentEnd);
range.ApplyPropertyValue(FrameworkElement.LanguageProperty, languageTag);
}
}
private void NotepadRichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
saveTimer?.Stop();
saveTimer?.Start();
@@ -734,7 +750,7 @@ namespace FasdDesktopUi.Basics.UserControls
return;
}
NotepadVisibilityChanged?.Invoke(this, true);
}
catch (Exception E)
{

View File

@@ -15,6 +15,7 @@
<UserControl.Resources>
<converter:NullValueToVisibilityConverter x:Key="NullToVisibility" />
<converter:LanguageDefinitionsConverter x:Key="LanguageConverter" />
</UserControl.Resources>
<Border Padding="10"
@@ -37,7 +38,7 @@
Style="{DynamicResource Menu.Selector.Icon.Lock}"
MouseUp="LockButton_MouseUp"
TouchDown="LockButton_TouchDown"
MouseLeave="LockButton_MouseLeave"/>
MouseLeave="LockButton_MouseLeave" />
<ico:AdaptableIcon x:Name="BackButton"
DockPanel.Dock="Left"
@@ -74,9 +75,22 @@
</DockPanel>
<local:SearchBar x:Name="Search"
DockPanel.Dock="Top"
PlaceholderText="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=Searchbar.Placeholder}"
ShowCloseButton="False"
SearchButtonSize="26"
DebounceInterval="0"
SearchBackground="{DynamicResource BackgroundColor.DetailsPage.Widget.Title}"
SearchValueChanged="SearchBar_SearchValueChanged"
Margin="0 0 0 10"
Focusable="True"
Height="26" />
<local:CustomMenu x:Name="SubMenuUc"
DockPanel.Dock="Top"
MenuDataList="{Binding ElementName=QuickActionSelectorUc, Path=QuickActionList}" />
MenuDataList="{Binding ElementName=QuickActionSelectorUc, Path=QuickActionList}"
Width="270"/>
</DockPanel>

View File

@@ -1,23 +1,13 @@
using System;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using C4IT.FASD.Base;
using C4IT.Logging;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Models;
using static C4IT.Logging.cLogManager;
using static FasdDesktopUi.Basics.UserControls.InformationClassSearchBar;
namespace FasdDesktopUi.Basics.UserControls
{
@@ -25,9 +15,12 @@ namespace FasdDesktopUi.Basics.UserControls
{
#region Properties
public event EventHandler<string> SearchValueChanged;
public Action CloseButtonClickedAction { get; set; }
public Action<bool> LockStatusChanged { get; set; }
public static QuickActionSelector Instance;
#region IsLocked DependencyProperty
public bool IsLocked
@@ -49,7 +42,7 @@ namespace FasdDesktopUi.Basics.UserControls
return;
}
_me.CloseButton.IsEnabled = _me.IsLocked ? false : true;
_me.CloseButton.IsEnabled = !_me.IsLocked;
}
catch (Exception E)
@@ -110,10 +103,13 @@ namespace FasdDesktopUi.Basics.UserControls
public QuickActionSelector()
{
InitializeComponent();
Search.ActivateManualSearch();
Instance = this;
}
public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Search.IsInputEnabled = this.Visibility == Visibility.Visible;
BlurInvoker.InvokeVisibilityChanged(this, new EventArgs());
}
@@ -178,7 +174,7 @@ namespace FasdDesktopUi.Basics.UserControls
#region CloseButton
private void CloseButton_Click()
public void CloseButton_Click()
{
try
{
@@ -187,9 +183,16 @@ namespace FasdDesktopUi.Basics.UserControls
QuickActionList = null;
Visibility = Visibility.Collapsed;
Search.IsEnabled = true;
if (CloseButtonClickedAction != null)
CloseButtonClickedAction.Invoke();
Window window = Window.GetWindow(this);
if (window != null)
{
FocusManager.SetFocusedElement(window, window);
Keyboard.Focus(window);
}
CloseButtonClickedAction?.Invoke();
}
catch (Exception E)
{
@@ -217,6 +220,8 @@ namespace FasdDesktopUi.Basics.UserControls
TempQuickActionSelectorHeading = null;
QuickActionList = TempQuickActionList;
TempQuickActionList = null;
Search.IsEnabled = true;
Search.FocusInput();
}
private void BackButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
@@ -230,5 +235,8 @@ namespace FasdDesktopUi.Basics.UserControls
}
#endregion
private void SearchBar_SearchValueChanged(object sender, string e)
=> SearchValueChanged?.Invoke(this, e);
}
}

View File

@@ -30,7 +30,6 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
set { SetValue(QuickTipNameProperty, value); }
}
// Using a DependencyProperty as the backing store for QuickTipName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty QuickTipNameProperty =
DependencyProperty.Register("QuickTipName", typeof(string), typeof(QuickTipStatusMonitor), new PropertyMetadata("Quick Tip Name"));
@@ -44,7 +43,6 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
set { SetValue(QuickTipIconProperty, value); }
}
// Using a DependencyProperty as the backing store for QuickTipIcon. This enables animation, styling, binding, etc...
public static readonly DependencyProperty QuickTipIconProperty =
DependencyProperty.Register("QuickTipIcon", typeof(IconData), typeof(QuickTipStatusMonitor), new PropertyMetadata(new IconData(enumInternIcons.none)));
@@ -58,7 +56,6 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
set { SetValue(QuickTipElementDataProperty, value); }
}
// Using a DependencyProperty as the backing store for QuickTipElementData. This enables animation, styling, binding, etc...
public static readonly DependencyProperty QuickTipElementDataProperty =
DependencyProperty.Register("QuickTipElementData", typeof(List<cUiQuickTipElement>), typeof(QuickTipStatusMonitor), new PropertyMetadata(new List<cUiQuickTipElement>(), HandleQuickTipElementDataChanged));
@@ -94,20 +91,6 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
#endregion
#region HasFocusIndex
public int HasFocusIndex
{
get { return (int)GetValue(HasFocusIndexProperty); }
set { SetValue(HasFocusIndexProperty, value); }
}
// Using a DependencyProperty as the backing store for HasFocusIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HasFocusIndexProperty =
DependencyProperty.Register("HasFocusIndex", typeof(int), typeof(QuickTipStatusMonitor), new PropertyMetadata(0));
#endregion
#endregion
public QuickTipStatusMonitor()
@@ -255,8 +238,14 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
return;
bool wasSuccessfull = step.SuccessState == enumQuickActionSuccess.finished || step.SuccessState == enumQuickActionSuccess.successfull;
string currentLanguage = cMultiLanguageSupport.CurrentLanguage;
cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage ?? currentLanguage;
ProtocollEntryBase protocollEntry = QuickTipStepProtocollEntryOutput.GetQuickTipStepProtocollEntry(step.StepData.QuickTipElementDefinition, wasSuccessfull);
cMultiLanguageSupport.CurrentLanguage = currentLanguage;
F4SDProtocoll.Instance.Add(protocollEntry);
}
catch (Exception ex)
@@ -331,26 +320,40 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
QuickTipElementData = new List<cUiQuickTipElement>();
}
private void CancelButton_Click(object sender, InputEventArgs args) => CancelQuickTip();
private void CancelButton_Click(object sender, InputEventArgs args) => TryCancelQuickTip();
private void CancelQuickTip()
/// <returns>If QuickTip could be canceled</returns>
internal bool TryCancelQuickTip()
{
if (_stepList.Any(step => step.SuccessState != enumQuickActionSuccess.unknown))
if (CustomMessageBox.Show(cMultiLanguageSupport.GetItem("QuickTips.Dialog.Cancel"), "Quick Tip", enumHealthCardStateLevel.Warning, null, true) != true)
return;
return false;
Visibility = Visibility.Collapsed;
int finishedStepCount = _stepList.Count(step => step.SuccessState == enumQuickActionSuccess.finished);
AddQuickTipEndToProtocoll(QuickTipName, finishedStepCount, _stepList.Count, true);
QuickTipElementData = new List<cUiQuickTipElement>();
return true;
}
private void AddQuickTipEndToProtocoll(string quickTipName, int finishedStepCount, int totalStepCount, bool wasCanceled)
{
string ascii = wasCanceled ? cMultiLanguageSupport.GetItem("QuickTips.Copy.Cancel") : cMultiLanguageSupport.GetItem("QuickTips.Copy.Finish");
ascii = string.Format(ascii, quickTipName, finishedStepCount, totalStepCount);
F4SDProtocoll.Instance.Add(new TextualProtocollEntry(ascii, ascii));
string currentLanguage = cMultiLanguageSupport.CurrentLanguage;
try
{
cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage ?? currentLanguage;
string ascii = wasCanceled ? cMultiLanguageSupport.GetItem("QuickTips.Copy.Cancel") : cMultiLanguageSupport.GetItem("QuickTips.Copy.Finish");
ascii = string.Format(ascii, quickTipName, finishedStepCount, totalStepCount);
F4SDProtocoll.Instance.Add(new TextualProtocollEntry(ascii, ascii));
}
finally
{
cMultiLanguageSupport.CurrentLanguage = currentLanguage;
}
}
private void QuickTipStatusMonitorUc_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
@@ -358,9 +361,21 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip
if (!IsVisible)
return;
string ascii = cMultiLanguageSupport.GetItem("QuickTips.Copy.Start");
ascii = string.Format(ascii, QuickTipName);
F4SDProtocoll.Instance.Add(new TextualProtocollEntry(ascii, ascii));
string currentLanguage = cMultiLanguageSupport.CurrentLanguage;
try
{
cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage ?? currentLanguage;
string ascii = cMultiLanguageSupport.GetItem("QuickTips.Copy.Start");
ascii = string.Format(ascii, QuickTipName);
F4SDProtocoll.Instance.Add(new TextualProtocollEntry(ascii, ascii));
}
finally
{
cMultiLanguageSupport.CurrentLanguage = currentLanguage;
}
}
}
}

View File

@@ -3,21 +3,19 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls"
xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon"
xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
Name="_this"
IsVisibleChanged="BlurInvoker_IsActiveChanged"
Name="Search"
Loaded="SearchBar_Loaded">
<UserControl.Resources>
<vc:LanguageDefinitionsConverter x:Key="LanguageConverter" />
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</UserControl.Resources>
<Border Background="{DynamicResource BackgroundColor.Menu.Categories}"
<Border Background="{Binding ElementName=Search, Path=SearchBackground}"
CornerRadius="17.5"
Margin="-2.5"
Padding="2.5"
@@ -29,47 +27,15 @@
<ico:AdaptableIcon x:Name="SearchButton"
x:FieldModifier="private"
DockPanel.Dock="Left"
Visibility="{Binding ShowSearchButton, ElementName=Search, Converter={StaticResource BoolToVisibility}}"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
MouseUp="SearchButton_Click"
TouchDown="SearchButton_Click"
IconBackgroundColor="Transparent"
IconHeight="{Binding SearchButtonSize, RelativeSource={RelativeSource AncestorType=UserControl}}"
IconWidth="{Binding SearchButtonSize, RelativeSource={RelativeSource AncestorType=UserControl}}"
IconHeight="{Binding SearchButtonSize, ElementName=Search}"
IconWidth="{Binding SearchButtonSize, ElementName=Search}"
SelectedInternIcon="menuBar_search" />
<ico:AdaptableIcon x:Name="PhoneCallIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
Visibility="Collapsed"
SelectedMaterialIcon="ic_phone" />
<ico:AdaptableIcon x:Name="ComputerCallIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
Visibility="Collapsed"
SelectedInternIcon="misc_computer" />
<ico:AdaptableIcon x:Name="UserCallIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
Visibility="Collapsed"
SelectedInternIcon="misc_user" />
<ico:AdaptableIcon x:Name="WarningIndicator"
x:FieldModifier="private"
DockPanel.Dock="Left"
Style="{DynamicResource Menu.MenuBar.PinnedIcon}"
IconBackgroundColor="Transparent"
PrimaryIconColor="#FFFF8800"
Visibility="Collapsed"
SelectedInternIcon="status_bad" />
<Grid DockPanel.Dock="Left">
<TextBlock IsHitTestVisible="False"
@@ -83,7 +49,7 @@
<DataTrigger Binding="{Binding Text, ElementName=SearchTextBox}"
Value="">
<Setter Property="Text"
Value="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=Searchbar.Placeholder.UserName}" />
Value="{Binding PlaceholderText, ElementName=Search}" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -92,7 +58,8 @@
<TextBox x:Name="SearchTextBox"
x:FieldModifier="private"
Text="{Binding ElementName=_this, Path=SearchValue, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"
IsEnabled="{Binding IsInputEnabled, ElementName=Search}"
Text="{Binding ElementName=Search, Path=SearchValue, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"
Style="{DynamicResource SearchBar.TextBox}" />
<StackPanel Orientation="Horizontal"
@@ -114,11 +81,13 @@
</TransformGroup>
</ico:AdaptableIcon.RenderTransform>
</ico:AdaptableIcon>
<ico:AdaptableIcon x:Name="CloseButton"
x:FieldModifier="private"
Visibility="{Binding ShowCloseButton, ElementName=Search, Converter={StaticResource BoolToVisibility}}"
Style="{DynamicResource SettingsPage.Close.Icon}"
IconHeight="{Binding CloseButtonSize, RelativeSource={RelativeSource AncestorType=UserControl}}"
IconWidth="{Binding CloseButtonSize, RelativeSource={RelativeSource AncestorType=UserControl}}"
IconHeight="{Binding CloseButtonSize, ElementName=Search}"
IconWidth="{Binding CloseButtonSize, ElementName=Search}"
Margin="-3 0 0 0"
Padding="0"
ToolTip="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=Global.NavBar.Close}"

View File

@@ -1,38 +1,99 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using FasdDesktopUi.Basics.Models;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using static C4IT.Logging.cLogManager;
using C4IT.MultiLanguage;
using C4IT.FASD.Base;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class SearchBar : UserControl, IBlurInvoker
public partial class SearchBar : UserControl
{
private const int constTimeBetweenKeystrokes = 250;
#region Propeties
public enum eSearchStatus { message, active, fixedResult };
public eSearchStatus SearchStatus { get; private set; } = eSearchStatus.message;
#region Search Value Property
private readonly DispatcherTimer _searchTimer = new DispatcherTimer();
private static CancellationTokenSource _currentSearchTaskToken = null;
private static Guid? _currentSearchTaskId = null;
private static readonly object _currentSearchTaskLock = new object();
#region Dependency Properties
public static readonly DependencyProperty SearchButtonSizeProperty =
DependencyProperty.Register(nameof(SearchButtonSize), typeof(double), typeof(SearchBar), new PropertyMetadata(30.0));
public double SearchButtonSize
{
get => (double)GetValue(SearchButtonSizeProperty);
set => SetValue(SearchButtonSizeProperty, value);
}
public static readonly DependencyProperty CloseButtonSizeProperty =
DependencyProperty.Register(nameof(CloseButtonSize), typeof(double), typeof(SearchBar), new PropertyMetadata(30.0));
public double CloseButtonSize
{
get => (double)GetValue(CloseButtonSizeProperty);
set => SetValue(CloseButtonSizeProperty, value);
}
public static readonly DependencyProperty ShowCloseButtonProperty =
DependencyProperty.Register(nameof(ShowCloseButton), typeof(bool), typeof(SearchBar), new PropertyMetadata(true));
public bool ShowCloseButton
{
get => (bool)GetValue(ShowCloseButtonProperty);
set => SetValue(ShowCloseButtonProperty, value);
}
public static readonly DependencyProperty ShowSearchButtonProperty =
DependencyProperty.Register(nameof(ShowSearchButton), typeof(bool), typeof(SearchBar), new PropertyMetadata(true));
public bool ShowSearchButton
{
get => (bool)GetValue(ShowSearchButtonProperty);
set => SetValue(ShowSearchButtonProperty, value);
}
public static readonly DependencyProperty PlaceholderTextProperty =
DependencyProperty.Register(nameof(PlaceholderText), typeof(string), typeof(SearchBar), new PropertyMetadata(string.Empty));
public string PlaceholderText
{
get => (string)GetValue(PlaceholderTextProperty);
set => SetValue(PlaceholderTextProperty, value);
}
public static readonly DependencyProperty DebounceIntervalProperty =
DependencyProperty.Register(nameof(DebounceInterval), typeof(TimeSpan), typeof(SearchBar),
new PropertyMetadata(TimeSpan.FromMilliseconds(250), OnDebounceIntervalChanged));
public TimeSpan DebounceInterval
{
get => (TimeSpan)GetValue(DebounceIntervalProperty);
set => SetValue(DebounceIntervalProperty, value);
}
private static void OnDebounceIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((SearchBar)d)._searchTimer.Interval = (TimeSpan)e.NewValue;
}
public static readonly DependencyProperty IsInputEnabledProperty =
DependencyProperty.Register(nameof(IsInputEnabled), typeof(bool), typeof(SearchBar), new PropertyMetadata(true));
public bool IsInputEnabled
{
get => (bool)GetValue(IsInputEnabledProperty);
set => SetValue(IsInputEnabledProperty, value);
}
public SolidColorBrush SearchBackground
{
get { return (SolidColorBrush)GetValue(SearchBackgroundProperty); }
set { SetValue(SearchBackgroundProperty, value); }
}
public static readonly DependencyProperty SearchBackgroundProperty =
DependencyProperty.Register(nameof(SearchBackground), typeof(SolidColorBrush), typeof(SearchBar), new PropertyMetadata(null));
#endregion
#region SearchValue
private string _searchValue = null;
public string SearchValue
@@ -43,111 +104,49 @@ namespace FasdDesktopUi.Basics.UserControls
if (value != _searchValue)
{
_searchValue = value;
if (SearchStatus == eSearchStatus.active)
if (IsInputEnabled)
HandleSearchValueChanged();
}
}
}
private readonly Dictionary<enumF4sdSearchResultClass, UIElement> _searchIcons = null;
#endregion
#region Events
public event EventHandler<string> SearchValueChanged;
public delegate Task ChangedSearchValueDelegate(cFilteredResults results);
public static readonly RoutedEvent CancelledSearchEvent =
EventManager.RegisterRoutedEvent(nameof(CancelledSearch), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SearchBar));
public ChangedSearchValueDelegate ChangedSearchValue { get; set; } = null;
public Action CancledSearchAction { get; set; }
public bool BlurInvoker_IsActive => IsVisible;
#endregion
#region Dependency Propertys
public double SearchButtonSize
public event RoutedEventHandler CancelledSearch
{
get { return (double)GetValue(SearchButtonSizeProperty); }
set { SetValue(SearchButtonSizeProperty, value); }
add => AddHandler(CancelledSearchEvent, value);
remove => RemoveHandler(CancelledSearchEvent, value);
}
public static readonly DependencyProperty SearchButtonSizeProperty =
DependencyProperty.Register("SearchButtonSize", typeof(double), typeof(SearchBar), new PropertyMetadata(30.0));
public double CloseButtonSize
{
get { return (double)GetValue(CloseButtonSizeProperty); }
set { SetValue(CloseButtonSizeProperty, value); }
}
public static readonly DependencyProperty CloseButtonSizeProperty =
DependencyProperty.Register("CloseButtonSize", typeof(double), typeof(SearchBar), new PropertyMetadata(30.0));
#endregion
public SearchBar()
{
InitializeComponent();
_searchIcons = new Dictionary<enumF4sdSearchResultClass, UIElement>()
{
{ enumF4sdSearchResultClass.Phone, PhoneCallIndicator },
{ enumF4sdSearchResultClass.User, UserCallIndicator },
{ enumF4sdSearchResultClass.Computer, ComputerCallIndicator }
};
}
public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e)
{
BlurInvoker.InvokeVisibilityChanged(this, new EventArgs());
if (e.NewValue is bool newVisible)
{
if (newVisible == false)
{
SearchTextBox.IsEnabled = true;
SearchButton.Visibility = Visibility.Visible;
WarningIndicator.Visibility = Visibility.Collapsed;
TicketOverview.Instance?.ResetSelection();
foreach (var Entry in _searchIcons.Values)
Entry.Visibility = Visibility.Collapsed;
}
SetApiStatus();
}
if (Visibility == Visibility.Visible)
{
var _h = Dispatcher.BeginInvoke((Action)delegate { Keyboard.Focus(SearchTextBox); }, DispatcherPriority.Render);
}
}
public void Clear()
{
SearchStatus = eSearchStatus.message;
SearchTextBox.Text = null;
}
public void ActivateManualSearch()
{
SearchStatus = eSearchStatus.active;
SearchButton.Visibility = Visibility.Visible;
WarningIndicator.Visibility = Visibility.Collapsed;
foreach (var Entry in _searchIcons.Values)
Entry.Visibility = Visibility.Collapsed;
SearchTextBox.Text = null;
SearchTextBox.IsEnabled = true;
SearchTextBox.Focus();
Keyboard.Focus(SearchTextBox);
}
public void SetSearchText(string search)
{
SearchStatus = eSearchStatus.active;
SearchTextBox.Text = search;
SearchTextBox.CaretIndex = search.Length;
SearchTextBox.CaretIndex = search?.Length ?? 0;
SearchTextBox.Focus();
Keyboard.Focus(SearchTextBox);
}
public void FocusInput()
{
SearchTextBox.Focus();
Keyboard.Focus(SearchTextBox);
}
@@ -157,165 +156,18 @@ namespace FasdDesktopUi.Basics.UserControls
Dispatcher.Invoke(() => SearchSpinner.Visibility = visibility);
}
public async Task SetFixedSearchResultAsync(enumF4sdSearchResultClass Class, string search, cFilteredResults result)
{
SearchStatus = eSearchStatus.fixedResult;
SearchTextBox.IsEnabled = false;
SearchButton.Visibility = Visibility.Collapsed;
WarningIndicator.Visibility = Visibility.Collapsed;
foreach (var entryIcon in _searchIcons)
{
if (Class == entryIcon.Key)
entryIcon.Value.Visibility = Visibility.Visible;
else
entryIcon.Value.Visibility = Visibility.Collapsed;
}
SearchTextBox.Text = search;
if (ChangedSearchValue != null)
await ChangedSearchValue.Invoke(result);
}
public void SetApiStatus()
{
try
{
var Status = cConnectionStatusHelper.Instance?.ApiConnectionStatus;
if (Status == null)
return;
bool IsEnabled = false;
string txt = null;
switch (Status)
{
case cConnectionStatusHelper.enumOnlineStatus.online:
IsEnabled = true;
break;
case cConnectionStatusHelper.enumOnlineStatus.connectionError:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ConnectError");
break;
case cConnectionStatusHelper.enumOnlineStatus.incompatibleServerVersion:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.IncompatibleVersion");
break;
case cConnectionStatusHelper.enumOnlineStatus.serverStarting:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ServerStarting");
break;
case cConnectionStatusHelper.enumOnlineStatus.serverNotConfigured:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.ServerNotConfigured");
break;
case cConnectionStatusHelper.enumOnlineStatus.illegalConfig:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.IllegalConfig");
break;
case cConnectionStatusHelper.enumOnlineStatus.unauthorized:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.Unauthorized");
break;
default:
txt = cMultiLanguageSupport.GetItem("Searchbar.Status.Offline");
break;
}
if (!IsEnabled)
{
SearchStatus = eSearchStatus.message;
SearchTextBox.Text = txt;
SearchTextBox.IsEnabled = false;
WarningIndicator.Visibility = Visibility.Visible;
SearchButton.Visibility = Visibility.Collapsed;
foreach (var Entry in _searchIcons.Values)
Entry.Visibility = Visibility.Collapsed;
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
}
}
private async Task CancelRunningSearchTaskAsync()
{
// cancel the search task, in case of a running search task
lock (_currentSearchTaskLock)
{
if (_currentSearchTaskToken != null)
{
LogEntry("Canceling current running search...");
_currentSearchTaskToken.Cancel(true);
_currentSearchTaskToken = null;
}
}
// send a stop to the server, in case of a running search task
Guid? currentTaskId = null;
lock (_currentSearchTaskLock)
{
if (_currentSearchTaskId != null)
{
currentTaskId = _currentSearchTaskId;
_currentSearchTaskId = null;
}
}
if (currentTaskId != null)
{
LogEntry("Sending a search stop...");
await cFasdCockpitCommunicationBase.Instance.GetSearchResultsStop((Guid)currentTaskId, CancellationToken.None);
}
}
private async void UpdateSearchResultsTick(object sender, EventArgs e)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
_searchTimer.Stop();
await CancelRunningSearchTaskAsync();
lock (_currentSearchTaskLock)
{
LogEntry("Start running new search...");
SearchValueChanged?.Invoke(this, SearchValue);
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
private void HandleSearchValueChanged()
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
if (_searchTimer.IsEnabled)
_searchTimer.Stop();
try
{
if (!SearchTextBox.IsEnabled)
return;
_searchTimer.Start();
}
if (_searchTimer.IsEnabled)
_searchTimer.Stop();
_searchTimer.Start();
_ = Task.Run(async () => { await CancelRunningSearchTaskAsync(); });
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
private void SearchTimerTick(object sender, EventArgs e)
{
_searchTimer.Stop();
SearchValueChanged?.Invoke(this, SearchValue);
}
private void SearchButton_Click(object sender, InputEventArgs e)
@@ -323,40 +175,28 @@ namespace FasdDesktopUi.Basics.UserControls
SearchTextBox.Focus();
}
#region CancledSearch Event
public static readonly RoutedEvent CancledSearchEvent = EventManager.RegisterRoutedEvent("CancledSearch", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SearchBar));
public event RoutedEventHandler CancledSearch
{
add { AddHandler(CancledSearchEvent, value); }
remove { RemoveHandler(CancledSearchEvent, value); }
}
private void RaiseCancledSearchEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(CancledSearchEvent);
RaiseEvent(newEventArgs);
}
#endregion
private void CloseButton_Click(object sender, InputEventArgs e)
{
RaiseCancledSearchEvent();
if (cConnectionStatusHelper.Instance?.ApiConnectionStatus == cConnectionStatusHelper.enumOnlineStatus.online)
SearchTextBox.Text = null;
CancledSearchAction?.Invoke();
RaiseEvent(new RoutedEventArgs(CancelledSearchEvent));
}
private void SearchBar_Loaded(object sender, RoutedEventArgs e)
{
_searchTimer.Stop();
_searchTimer.Interval = TimeSpan.FromMilliseconds(constTimeBetweenKeystrokes);
_searchTimer.Tick += UpdateSearchResultsTick;
_searchTimer.Interval = DebounceInterval;
_searchTimer.Tick += SearchTimerTick;
BackgroundBorder.CornerRadius = new CornerRadius(BackgroundBorder.ActualHeight / 2.0);
}
internal void ActivateManualSearch()
{
Search.Clear();
Search.IsInputEnabled = true;
Dispatcher.BeginInvoke(new Action(() =>
{
Search.FocusInput();
}), DispatcherPriority.Input);
}
}
}

View File

@@ -197,7 +197,7 @@ namespace FasdDesktopUi.Basics.UserControls
MenuData = new cMenuDataBase()
{
MenuText = cMultiLanguageSupport.GetItem("SearchBar.NoResults"),
MenuIcon = new IconData(enumInternIcons.menuBar_search_noResults)
MenuIcon = new cMenuDataBase.MenuIconInfo(new IconData(enumInternIcons.menuBar_search_noResults))
}
};
MainStackPanel.Children.Add(resultItemControl);
@@ -236,7 +236,7 @@ namespace FasdDesktopUi.Basics.UserControls
var menuData = new cMenuDataBase() { MenuText = historyEntry.DisplayText, UiAction = new cUiProcessSearchHistoryEntry(historyEntry) };
if (historyEntry.isSeen)
{
menuData.MenuIcon = new IconData(MaterialIcons.MaterialIconType.ic_visibility);
menuData.MenuIcon = new cMenuDataBase.MenuIconInfo(new IconData(MaterialIcons.MaterialIconType.ic_visibility));
menuData.MenuIconSize = 0.75;
}

View File

@@ -5,31 +5,33 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FasdDesktopUi.Basics.UserControls"
xmlns:config="clr-namespace:C4IT.FASD.Base;assembly=F4SD-Cockpit-Client-Base"
xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon"
xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon"
xmlns:vd="clr-namespace:FasdDesktopUi.Basics.Converter"
xmlns:vc="clr-namespace:C4IT.MultiLanguage;assembly=F4SD-Cockpit-Client-Base"
mc:Ignorable="d"
Initialized="UserControl_Initialized">
Initialized="UserControl_Initialized">
<UserControl.Resources>
<vd:LanguageDefinitionsConverter x:Key="LanguageConverter"/>
<!-- Style für den Hovereffekt -->
<Style x:Key="PauseButtonHoverStyle" TargetType="Border">
<Setter Property="Background" Value="Transparent"/>
<vd:LanguageDefinitionsConverter x:Key="LanguageConverter" />
<Style x:Key="PauseButtonHoverStyle"
TargetType="Border">
<Setter Property="Background"
Value="Transparent" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource Background.Menu.Icon.Hover}"/>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="{DynamicResource Background.Menu.Icon.Hover}" />
</Trigger>
</Style.Triggers>
</Style>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Padding="8"
@@ -45,71 +47,72 @@
ToolTip="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=TimerView.Time.ToolTip}"
Foreground="{DynamicResource Color.Menu.Icon}" />
</Border>
<Border Padding="20 5 5 5"
<Border Padding="20 5 5 5"
Grid.Column="1"
Width="Auto"
Height="33"
Cursor="Hand"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="5"
CornerRadius="5"
Margin="-5 0 0 0"
ToolTip="{Binding Converter={StaticResource LanguageConverter}, ConverterParameter=TimerView.Pausebutton.ToolTip}"
Style="{DynamicResource PauseButtonHoverStyle}"
MouseLeftButtonUp="Border_MouseLeftButtonUp" TouchDown="Border_TouchDown"
>
MouseLeftButtonUp="Border_Click"
TouchDown="Border_Click">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ico:AdaptableIcon Grid.Column="1"
<ico:AdaptableIcon Grid.Column="1"
x:Name="PauseButton"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="-15 0 5 0"
Margin="-15 0 5 0"
Panel.ZIndex="2"
BorderPadding="0"
IconHeight="22"
IconWidth="22"
SelectedMaterialIcon="ic_pause_circle_outline"
SelectedMaterialIcon="ic_pause_circle_outline"
IconBackgroundColor="Transparent">
<ico:AdaptableIcon.Resources>
<Style TargetType="ico:AdaptableIcon"
BasedOn="{StaticResource Menu.MenuBar.PinnedIcon.Pinned}">
<Setter Property="PrimaryIconColor"
Value="{DynamicResource FontColor.Menu.Categories}"/>
Value="{DynamicResource FontColor.Menu.Categories}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType=Border}, Path=IsMouseOver}"
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType=Border}, Path=IsMouseOver}"
Value="True">
<Setter Property="PrimaryIconColor"
Value="{DynamicResource FontColor.Menu.Categories.Hover}"/>
<Setter Property="PrimaryIconColor"
Value="{DynamicResource Color.FunctionMarker}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ico:AdaptableIcon.Resources>
</ico:AdaptableIcon>
<TextBlock Grid.Column="2" Text="Pause">
<TextBlock Grid.Column="2"
Text="Pause">
<TextBlock.Resources>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment"
Value="Center"/>
Value="Center" />
<Setter Property="HorizontalAlignment"
Value="Center"/>
Value="Center" />
<Setter Property="FontSize"
Value="16"/>
Value="16" />
<Setter Property="Foreground"
Value="{DynamicResource FontColor.Menu.Categories}"/>
Value="{DynamicResource FontColor.Menu.Categories}" />
<Setter Property="Margin"
Value="0 0 0 2"/>
Value="0 0 0 2" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType=Border}, Path=IsMouseOver}"
Value="True">
<Setter Property="Foreground"
Value="{DynamicResource FontColor.Menu.Categories.Hover}"/>
Value="{DynamicResource Color.FunctionMarker}" />
</DataTrigger>
</Style.Triggers>
</Style>

View File

@@ -15,18 +15,18 @@ namespace FasdDesktopUi.Basics.UserControls
public event EventHandler<EventArgs> OnPauseStarted;
private static List<DateTime> startTimes = new List<DateTime>();
private static List<DateTime> endTimes = new List<DateTime>();
private static List<DateTime> pausedTimesStart = new List<DateTime>();
private static List<DateTime> pausedTimesEnd = new List<DateTime>();
private static readonly List<DateTime> _startTimes = new List<DateTime>();
private static readonly List<DateTime> _endTimes = new List<DateTime>();
private static readonly List<DateTime> _pausedTimesStart = new List<DateTime>();
private static readonly List<DateTime> _pausedTimesEnd = new List<DateTime>();
public static List<cF4SDCaseTime> caseTimes = new List<cF4SDCaseTime>();
private static Dictionary<string, object> finalWorkingTimes = new Dictionary<string, object>();
public static List<cF4SDCaseTime> CaseTimes = new List<cF4SDCaseTime>();
private static Dictionary<string, object> _finalWorkingTimes = new Dictionary<string, object>();
private static DispatcherTimer timer;
private static TimeSpan elapsedTime;
private static TimeSpan totalPausedTime = TimeSpan.Zero;
private static TimeSpan pauseDuration;
private static DispatcherTimer _timer;
private static TimeSpan _elapsedTime;
private static TimeSpan _totalPausedTime = TimeSpan.Zero;
private static TimeSpan _pauseDuration;
#endregion
@@ -39,13 +39,13 @@ namespace FasdDesktopUi.Basics.UserControls
public static void ResetTimer()
{
startTimes.Clear();
endTimes.Clear();
pausedTimesEnd.Clear();
pausedTimesStart.Clear();
finalWorkingTimes.Clear();
elapsedTime = TimeSpan.Zero;
caseTimes.Clear();
_startTimes.Clear();
_endTimes.Clear();
_pausedTimesEnd.Clear();
_pausedTimesStart.Clear();
_finalWorkingTimes.Clear();
_elapsedTime = TimeSpan.Zero;
CaseTimes.Clear();
StartTimer();
}
@@ -54,8 +54,8 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
startTimes?.Add(DateTime.UtcNow);
timer?.Start();
_startTimes?.Add(DateTime.UtcNow);
_timer?.Start();
}
catch (Exception E)
{
@@ -67,8 +67,8 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
endTimes?.Add(DateTime.UtcNow);
timer?.Stop();
_endTimes?.Add(DateTime.UtcNow);
_timer?.Stop();
UpdateTimerControl();
}
catch (Exception E)
@@ -83,7 +83,7 @@ namespace FasdDesktopUi.Basics.UserControls
{
ResetTimer();
timer = new DispatcherTimer(TimeSpan.FromSeconds(1.0), DispatcherPriority.Loaded, new EventHandler((s, args) =>
_timer = new DispatcherTimer(TimeSpan.FromSeconds(1.0), DispatcherPriority.Loaded, new EventHandler((s, args) =>
{
try { UpdateTimerControl(); }
catch { }
@@ -100,8 +100,8 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
TimerControl.Text = elapsedTime.ToString(@"hh\:mm\:ss");
elapsedTime = elapsedTime.Add(TimeSpan.FromSeconds(1.0));
TimerControl.Text = _elapsedTime.ToString(@"hh\:mm\:ss");
_elapsedTime = _elapsedTime.Add(TimeSpan.FromSeconds(1.0));
}
catch (Exception E)
{
@@ -113,44 +113,44 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
var currentDate = DateTime.Now.Date.ToString("d");
var startDateTime = startTimes.First();
var currentDate = DateTime.UtcNow.Date.ToString("d");
var startDateTime = _startTimes.First();
var endDateTime = DateTime.UtcNow;
var bruttoWorkingTime = TimeSpan.Zero;
var nettoWorkingTime = TimeSpan.Zero;
if (pausedTimesStart.Count == 0)
if (_pausedTimesStart.Count == 0)
{
totalPausedTime = TimeSpan.Zero;
_totalPausedTime = TimeSpan.Zero;
}
if (pausedTimesEnd.Count > 0)
if (_pausedTimesEnd.Count > 0)
{
totalPausedTime = TimeSpan.Zero;
_totalPausedTime = TimeSpan.Zero;
for (int i = 0; i < pausedTimesStart.Count; i++)
for (int i = 0; i < _pausedTimesStart.Count; i++)
{
var start = pausedTimesStart[i];
var end = pausedTimesEnd[i];
var start = _pausedTimesStart[i];
var end = _pausedTimesEnd[i];
pauseDuration = end - start;
_pauseDuration = end - start;
totalPausedTime += pauseDuration;
_totalPausedTime += _pauseDuration;
}
}
bruttoWorkingTime = endDateTime - startDateTime;
nettoWorkingTime = bruttoWorkingTime - totalPausedTime;
nettoWorkingTime = bruttoWorkingTime - _totalPausedTime;
finalWorkingTimes = new Dictionary<string, object>()
_finalWorkingTimes = new Dictionary<string, object>()
{
{"CurrentDate", currentDate},
{"StartTime", startTimes.First()},
{"StartTime", _startTimes.First()},
{"EndTime", endDateTime },
{"BruttoWorkingTime", bruttoWorkingTime },
{"NettoWorkingTime", nettoWorkingTime.TotalSeconds },
{"TotalPausedTime", totalPausedTime }
{"TotalPausedTime", _totalPausedTime }
};
}
catch (Exception E)
@@ -158,7 +158,7 @@ namespace FasdDesktopUi.Basics.UserControls
LogException(E);
}
return finalWorkingTimes;
return _finalWorkingTimes;
}
#endregion
@@ -169,13 +169,13 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
if (timer?.IsEnabled == true)
if (_timer?.IsEnabled == true)
return;
timer?.Start();
pausedTimesEnd?.Add(DateTime.UtcNow);
_timer?.Start();
_pausedTimesEnd?.Add(DateTime.UtcNow);
caseTimes.Add(new cF4SDCaseTime()
CaseTimes.Add(new cF4SDCaseTime()
{
StatusId = CaseStatus.InProgress,
CaseTime = DateTime.UtcNow
@@ -191,10 +191,10 @@ namespace FasdDesktopUi.Basics.UserControls
{
try
{
timer?.Stop();
pausedTimesStart?.Add(DateTime.UtcNow);
_timer?.Stop();
_pausedTimesStart?.Add(DateTime.UtcNow);
caseTimes.Add(new cF4SDCaseTime()
CaseTimes.Add(new cF4SDCaseTime()
{
StatusId = CaseStatus.OnHold,
CaseTime = DateTime.UtcNow
@@ -209,17 +209,9 @@ namespace FasdDesktopUi.Basics.UserControls
}
}
private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
PauseButton_Click();
}
private void Border_Click(object sender, InputEventArgs e)
=> PauseButton_Click();
#endregion
private void Border_TouchDown(object sender, TouchEventArgs e)
{
PauseButton_Click();
}
}
}

View File

@@ -1,15 +1,13 @@
using C4IT.F4SD.DisplayFormatting;
using C4IT.FASD.Base;
using C4IT.MultiLanguage;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UserControls;
using FasdDesktopUi.Basics.UserControls.AdaptableIcon;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -362,7 +360,7 @@ namespace FasdDesktopUi.Basics
try
{
FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.AddDays(_v.ReferenceDays), TimeZone = TimeZoneInfo.Local };
RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
RawValueFormatter.SetDefaultCulture(cFasdCockpitConfig.Instance.SelectedCulture);
RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
var _strVal = RawValueFormatter.GetDisplayValue(_v.Value, _v.StateDefinition.DisplayType, options);
@@ -468,5 +466,11 @@ namespace FasdDesktopUi.Basics
#endregion
public static string GetShortDatePattern()
{
string datePattern = cFasdCockpitConfig.Instance.SelectedCulture.DateTimeFormat.ShortDatePattern;
datePattern = Regex.Replace(datePattern, @"(^|[/.\-\s])y{1,4}($|[/.\-\s]?)", "");
return datePattern.Trim('/', '.', '-', ' ');
}
}
}