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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user