|
|
|
|
@@ -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;
|
|
|
|
|
}
|
|
|
|
|
}
|