aktueller Stand
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
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.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to manage the <see cref="ISupportCase"/> for the UI via the <see cref="SupportCaseProcessor"/>"
|
||||
/// </summary>
|
||||
public class SupportCaseController
|
||||
{
|
||||
private SupportCaseProcessor _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)
|
||||
{
|
||||
IEnumerable<cF4sdApiSearchResultRelation> preselectedRelations = GetPreselectedRelations(supportCaseProcessor.GetCaseRelations(), preselectedIdentities);
|
||||
|
||||
ResetSelectedRelations(preselectedRelations);
|
||||
_hasDirectionConnection = false;
|
||||
|
||||
if (_supportCaseProcessor != null)
|
||||
{
|
||||
_supportCaseProcessor.AvailableCaseRelationsAdded -= HandleAvailableCaseRelationsAdded;
|
||||
_supportCaseProcessor.CaseDataChanged -= HandleCaseDataChanged;
|
||||
_supportCaseProcessor.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged -= HandleDirectConnectionChanged;
|
||||
}
|
||||
|
||||
_supportCaseProcessor = supportCaseProcessor;
|
||||
|
||||
_supportCaseProcessor.AvailableCaseRelationsAdded += HandleAvailableCaseRelationsAdded;
|
||||
_supportCaseProcessor.CaseDataChanged += HandleCaseDataChanged;
|
||||
_supportCaseProcessor.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged += HandleDirectConnectionChanged;
|
||||
}
|
||||
|
||||
private IEnumerable<cF4sdApiSearchResultRelation> GetPreselectedRelations
|
||||
(ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> loadedRelations, IEnumerable<cF4sdIdentityEntry> preselectedIdentities)
|
||||
{
|
||||
List<cF4sdApiSearchResultRelation> preselectedRelations = new List<cF4sdApiSearchResultRelation>();
|
||||
|
||||
foreach (var relationType in loadedRelations)
|
||||
{
|
||||
foreach (var relation in relationType)
|
||||
{
|
||||
if (relation.Identities.All(ri => preselectedIdentities.Any(i => i.Id == ri.Id)))
|
||||
preselectedRelations.Add(relation);
|
||||
}
|
||||
}
|
||||
|
||||
return preselectedRelations;
|
||||
}
|
||||
|
||||
private void ResetSelectedRelations(IEnumerable<cF4sdApiSearchResultRelation> preselectedRelations)
|
||||
{
|
||||
try
|
||||
{
|
||||
_selectedRelations.Clear();
|
||||
|
||||
if (preselectedRelations is null)
|
||||
return;
|
||||
|
||||
foreach (var relation in preselectedRelations)
|
||||
{
|
||||
_selectedRelations[cF4sdIdentityEntry.GetFromSearchResult(relation.Type)] = relation;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAvailableCaseRelationsAdded(object sender, RelationEventArgs e)
|
||||
=> AvailableCaseRelationsAdded?.Invoke(this, e);
|
||||
|
||||
private void HandleCaseDataChanged(object sender, SupportCaseDataEventArgs e)
|
||||
{
|
||||
CaseDataChanged?.Invoke(this, e);
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await UpdateStatusOfSelectedRelations();
|
||||
|
||||
if (!_hasDirectionConnection)
|
||||
await SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionStartAsync();
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleDirectConnectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
_hasDirectionConnection = SupportCaseDataProviderArtifact.DirectConnectionHelper.IsDirectConnectionActive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the currently for a support case relevant and shown relation.
|
||||
/// </summary>
|
||||
/// <remarks>Raises <see cref="FocusedRelationsChanged"/></remarks>
|
||||
internal void UpdateFocusedCaseRelation(cF4sdApiSearchResultRelation relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
_selectedHealthcard = _supportCaseProcessor.GetHealthcardFor(relation);
|
||||
HashSet<string> requiredTables = cHealthCard.GetRequiredTables(_selectedHealthcard);
|
||||
_ = Task.Run(async () => await _supportCaseProcessor.LoadSupportCaseDataAsync(relation, requiredTables));
|
||||
|
||||
List<enumFasdInformationClass> requiredInformationClasses = relation.Identities
|
||||
.Where(i => i.Class != enumFasdInformationClass.User)
|
||||
.Select(i => i.Class)
|
||||
.ToList();
|
||||
|
||||
if (relation.Type == enumF4sdSearchResultClass.User)
|
||||
requiredInformationClasses = new List<enumFasdInformationClass>() { enumFasdInformationClass.User };
|
||||
|
||||
if (requiredInformationClasses.Count == 0)
|
||||
requiredInformationClasses.Add(enumFasdInformationClass.User);
|
||||
|
||||
SupportCaseDataProviderArtifact.HealthCardDataHelper.TrySetSelectedHealthcard(requiredInformationClasses);
|
||||
|
||||
_focusedRelation = relation;
|
||||
|
||||
if (!_selectedRelations.Values.Contains(relation))
|
||||
_hasDirectionConnection = false;
|
||||
|
||||
_selectedRelations[cF4sdIdentityEntry.GetFromSearchResult(relation.Type)] = relation;
|
||||
_ = Task.Run(async () => await UpdateStatusOfSelectedRelations());
|
||||
|
||||
var focusedRelations = new cF4sdApiSearchResultRelation[1] { _focusedRelation };
|
||||
FocusedRelationsChanged?.Invoke(this, new RelationEventArgs()
|
||||
{
|
||||
Relations = focusedRelations.ToLookup(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), r => r)
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateStatusOfSelectedRelations()
|
||||
{
|
||||
const string StatusString = "Status";
|
||||
|
||||
try
|
||||
{
|
||||
int? agentUserId = null;
|
||||
int? agentDeviceId = null;
|
||||
|
||||
// todo these values should not be recieved from the NamedParameters, instead from the relation it self
|
||||
if (SupportCaseDataProviderArtifact.NamedParameterEntries.TryGetValue("AgentUserId", out var userNamedParameter))
|
||||
{
|
||||
var value = userNamedParameter.GetValue();
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
agentUserId = int.Parse(value);
|
||||
}
|
||||
|
||||
|
||||
// todo these values should not be recieved from the NamedParameters, instead from the relation it self
|
||||
if (SupportCaseDataProviderArtifact.NamedParameterEntries.TryGetValue("AgentDeviceId", out var deviceNamedParameter))
|
||||
{
|
||||
var value = deviceNamedParameter.GetValue();
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
agentDeviceId = int.Parse(deviceNamedParameter.GetValue());
|
||||
}
|
||||
|
||||
foreach (var relationEntry in _selectedRelations)
|
||||
{
|
||||
if (relationEntry.Value is null)
|
||||
continue;
|
||||
|
||||
string statusValue = "Unknown";
|
||||
|
||||
switch (relationEntry.Key)
|
||||
{
|
||||
case enumFasdInformationClass.Computer:
|
||||
if (!agentDeviceId.HasValue)
|
||||
continue;
|
||||
|
||||
bool isDeviceOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId.Value);
|
||||
statusValue = isDeviceOnline ? "Online" : "Offline";
|
||||
break;
|
||||
case enumFasdInformationClass.User:
|
||||
if (!agentDeviceId.HasValue || !agentUserId.HasValue)
|
||||
continue;
|
||||
|
||||
bool isUserOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId.Value, agentUserId.Value);
|
||||
statusValue = isUserOnline ? "Online" : "Offline";
|
||||
break;
|
||||
case enumFasdInformationClass.Ticket:
|
||||
case enumFasdInformationClass.VirtualSession:
|
||||
case enumFasdInformationClass.MobileDevice:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (relationEntry.Value.Infos is null)
|
||||
relationEntry.Value.Infos = new Dictionary<string, string>();
|
||||
|
||||
relationEntry.Value.Infos[StatusString] = statusValue;
|
||||
}
|
||||
|
||||
IEnumerable<cHeadingDataModel> newHeadingData = SupportCaseHeadingController.GetHeadingData(_selectedRelations);
|
||||
HeadingDataChanged?.Invoke(this, new HeadingDataEventArgs(newHeadingData));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RefreshDataForCurrentlyFocusedRelationAsync()
|
||||
{
|
||||
await _supportCaseProcessor.UpdateLatestCaseDataFor(_focusedRelation);
|
||||
}
|
||||
|
||||
public List<List<cWidgetValueModel>> GetWidgetData()
|
||||
=> _supportCaseProcessor.GetWidgetData(_focusedRelation);
|
||||
|
||||
public cDetailsPageDataHistoryDataModel GetHistoryData()
|
||||
=> _supportCaseProcessor.GetHistoryData(_focusedRelation);
|
||||
|
||||
public List<cContainerCollectionData> GetContainerData()
|
||||
=> _supportCaseProcessor.GetContainerData(_focusedRelation);
|
||||
|
||||
public List<cMenuDataBase> GetMenuBarData()
|
||||
=> _supportCaseProcessor.GetMenuBarData(_focusedRelation);
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the currently for a support case relevant and shown relations have been updated.
|
||||
/// </summary>
|
||||
public event EventHandler<RelationEventArgs> FocusedRelationsChanged;
|
||||
|
||||
/// <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;
|
||||
|
||||
public event EventHandler<HeadingDataEventArgs> HeadingDataChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.MultiLanguage;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers
|
||||
{
|
||||
internal class SupportCaseHeadingController
|
||||
{
|
||||
internal static IEnumerable<cHeadingDataModel> GetHeadingData(Dictionary<enumFasdInformationClass, cF4sdApiSearchResultRelation> relations)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Enum.GetValues(typeof(enumFasdInformationClass))
|
||||
.Cast<enumFasdInformationClass>()
|
||||
.Select(informationClass =>
|
||||
{
|
||||
if (relations.TryGetValue(informationClass, out var relation) && relation != null)
|
||||
return GetHeadingDataFor(relation);
|
||||
else
|
||||
return GetEmptyHeadingDataFor(informationClass);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<cHeadingDataModel>();
|
||||
}
|
||||
|
||||
private static cHeadingDataModel GetEmptyHeadingDataFor(enumFasdInformationClass informationClass)
|
||||
{
|
||||
string headingText = string.Empty;
|
||||
|
||||
switch (informationClass)
|
||||
{
|
||||
case enumFasdInformationClass.Computer:
|
||||
headingText = cMultiLanguageSupport.GetItem("Header.Select.Computer");
|
||||
break;
|
||||
case enumFasdInformationClass.Ticket:
|
||||
headingText = cMultiLanguageSupport.GetItem("Header.Select.Ticket");
|
||||
break;
|
||||
case enumFasdInformationClass.VirtualSession:
|
||||
headingText = cMultiLanguageSupport.GetItem("Header.Select.VirtualSession");
|
||||
break;
|
||||
case enumFasdInformationClass.MobileDevice:
|
||||
headingText = cMultiLanguageSupport.GetItem("Header.Select.MobileDevice");
|
||||
break;
|
||||
}
|
||||
|
||||
return new cHeadingDataModel() { InformationClass = informationClass, HeadingText = headingText };
|
||||
}
|
||||
|
||||
private static cHeadingDataModel GetHeadingDataFor(cF4sdApiSearchResultRelation relation)
|
||||
{
|
||||
const string StatusString = "Status";
|
||||
bool isOnline = false;
|
||||
|
||||
string statusValue = "Unknown";
|
||||
if (relation?.Infos?.TryGetValue(StatusString, out var statusValueFromDictionary) ?? false)
|
||||
statusValue = statusValueFromDictionary;
|
||||
|
||||
switch (relation.Type)
|
||||
{
|
||||
case enumF4sdSearchResultClass.Computer:
|
||||
case enumF4sdSearchResultClass.User:
|
||||
isOnline = string.Equals(statusValue, "Online", StringComparison.InvariantCultureIgnoreCase);
|
||||
break;
|
||||
case enumF4sdSearchResultClass.Ticket:
|
||||
isOnline = !string.Equals(statusValue, nameof(enumTicketStatus.Closed));
|
||||
break;
|
||||
case enumF4sdSearchResultClass.VirtualSession:
|
||||
isOnline = string.Equals(statusValue, nameof(enumCitrixSessionStatus.Active));
|
||||
break;
|
||||
case enumF4sdSearchResultClass.MobileDevice:
|
||||
break;
|
||||
}
|
||||
|
||||
return new cHeadingDataModel()
|
||||
{
|
||||
HeadingText = string.IsNullOrEmpty(relation.Name) ? relation.DisplayName : relation.Name,
|
||||
InformationClass = cF4sdIdentityEntry.GetFromSearchResult(relation.Type),
|
||||
IsOnline = isOnline,
|
||||
Identities = relation.Identities,
|
||||
Realtion = relation
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
using C4IT.FASD.Base;
|
||||
using FasdDesktopUi.Basics.Services.RelationService;
|
||||
using FasdDesktopUi.Basics.CustomEvents;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
{
|
||||
@@ -12,10 +13,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
void Initialize();
|
||||
void AddCaseRelations(ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> relations);
|
||||
ILookup<enumFasdInformationClass, cF4sdApiSearchResultRelation> GetCaseRelations();
|
||||
IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> GetSupportCaseHealthcardData(object identities, object valueAddress);
|
||||
void UpdateSupportCaseDataCache();
|
||||
Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable<string> tablesToLoad);
|
||||
IEnumerable<object> GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress);
|
||||
void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> tables);
|
||||
void InvalidateCaseDataCacheFor(cF4sdApiSearchResultRelation relation);
|
||||
void InvalidateLatestCaseDataCacheFor(cF4sdApiSearchResultRelation relation, out ICollection<cF4SDHealthCardRawData.cHealthCardTable> invalidatedTables);
|
||||
|
||||
event EventHandler<RelationEventArgs> CaseRelationsAdded;
|
||||
event EventHandler<object> SupportCaseDataCacheHasChanged;
|
||||
event EventHandler<SupportCaseDataEventArgs> SupportCaseDataCacheHasChanged;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using FasdDesktopUi.Basics.CustomEvents;
|
||||
using FasdDesktopUi.Basics.Services.RelationService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
public class SupportCase : ISupportCase
|
||||
{
|
||||
private readonly Dictionary<enumFasdInformationClass, IList<cF4sdApiSearchResultRelation>> _caseRelations = new Dictionary<enumFasdInformationClass, IList<cF4sdApiSearchResultRelation>>();
|
||||
//private readonly Lookup<IdentitySet, cF4SDHealthCardRawData.cHealthCardTable> _supportCaseDataCache;
|
||||
private readonly Dictionary<string, Dictionary<cF4sdApiSearchResultRelation, cF4SDHealthCardRawData.cHealthCardTable>> _supportCaseDataCache = new Dictionary<string, Dictionary<cF4sdApiSearchResultRelation, cF4SDHealthCardRawData.cHealthCardTable>>();
|
||||
|
||||
internal readonly Guid Id;
|
||||
private readonly IRelationService _relationService;
|
||||
@@ -67,12 +67,12 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
foreach (var relationType in relations)
|
||||
{
|
||||
if (_caseRelations.TryGetValue(relationType.Key, out var caseRelation))
|
||||
caseRelation = caseRelation.Union(relationType, new SearchResultRelationEqualityComparer()).ToList();
|
||||
caseRelation = caseRelation.Union(relationType).ToList();
|
||||
else
|
||||
_caseRelations.Add(relationType.Key, relationType.ToList());
|
||||
|
||||
if (SupportCaseDataProviderArtifact?.CaseRelations?.TryGetValue(relationType.Key, out var caseRelations) ?? false)
|
||||
caseRelations = caseRelations.Union(relationType, new SearchResultRelationEqualityComparer()).ToList();
|
||||
caseRelations = caseRelations.Union(relationType).ToList();
|
||||
else
|
||||
SupportCaseDataProviderArtifact?.CaseRelations?.Add(relationType.Key, relationType.ToList());
|
||||
}
|
||||
@@ -85,14 +85,158 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSupportCaseDataCache()
|
||||
public async Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable<string> tablesToLoad)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
try
|
||||
{
|
||||
cF4SDHealthCardRawData rawData = null;
|
||||
|
||||
// todo this is only a temporary fix. Currently the tablesToLoad contain also detail tables
|
||||
// and tables won't be loaded e.g. the QuickActionHistory
|
||||
bool isDataComplete = tablesToLoad.Any(t =>
|
||||
_supportCaseDataCache.TryGetValue(t, out var cachedTables)
|
||||
&& cachedTables.TryGetValue(relation, out var table)
|
||||
&& !table.IsIncomplete && !table.Columns.Values.Any(c => c.IsIncomplete)
|
||||
);
|
||||
|
||||
var rawDataRequest = new cF4sdHealthCardRawDataRequest()
|
||||
{
|
||||
Identities = relation.Identities,
|
||||
Tables = tablesToLoad.ToList(),
|
||||
MaxAge = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.SearchResultAge ?? 14
|
||||
};
|
||||
|
||||
while (!isDataComplete)
|
||||
{
|
||||
if (rawData is null)
|
||||
{
|
||||
rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawDataRequest);
|
||||
await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.SetHealthCardRawData(rawData, rawDataRequest.Identities);
|
||||
}
|
||||
else
|
||||
{
|
||||
rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawData.Id);
|
||||
await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.UpdateHealthcardRawData(rawData);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> GetSupportCaseHealthcardData(object identities, object valueAddress)
|
||||
public void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable<cF4SDHealthCardRawData.cHealthCardTable> tables)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
try
|
||||
{
|
||||
if (tables is null)
|
||||
return;
|
||||
|
||||
List<cF4SDHealthCardRawData.cHealthCardTable> dataTables = tables?.ToList();
|
||||
|
||||
foreach (var table in dataTables)
|
||||
{
|
||||
if (string.IsNullOrEmpty(table.Name))
|
||||
continue;
|
||||
|
||||
if (!_supportCaseDataCache.ContainsKey(table.Name))
|
||||
_supportCaseDataCache.Add(table.Name, new Dictionary<cF4sdApiSearchResultRelation, cF4SDHealthCardRawData.cHealthCardTable>());
|
||||
|
||||
if (!_supportCaseDataCache[table.Name].ContainsKey(relation))
|
||||
_supportCaseDataCache[table.Name][relation] = table;
|
||||
else
|
||||
MergeTable(_supportCaseDataCache[table.Name][relation], table);
|
||||
}
|
||||
|
||||
SupportCaseDataCacheHasChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation, DataTables = dataTables });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
void MergeTable(cF4SDHealthCardRawData.cHealthCardTable existingTable, cF4SDHealthCardRawData.cHealthCardTable newTable)
|
||||
{
|
||||
foreach (var newColumn in newTable.Columns)
|
||||
{
|
||||
existingTable.Columns[newColumn.Key] = newColumn.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InvalidateCaseDataCacheFor(cF4sdApiSearchResultRelation relation)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var tableCache in _supportCaseDataCache.Values)
|
||||
{
|
||||
tableCache.Remove(relation);
|
||||
}
|
||||
|
||||
// todo: invoke SupportCaseDataChache with empty tables
|
||||
// SupportCaseDataCacheHasChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void InvalidateLatestCaseDataCacheFor(cF4sdApiSearchResultRelation relation, out ICollection<cF4SDHealthCardRawData.cHealthCardTable> invalidatedTables)
|
||||
{
|
||||
invalidatedTables = new HashSet<cF4SDHealthCardRawData.cHealthCardTable>();
|
||||
try
|
||||
{
|
||||
foreach (var tableCache in _supportCaseDataCache.Values)
|
||||
{
|
||||
if (!tableCache.TryGetValue(relation, out cF4SDHealthCardRawData.cHealthCardTable table))
|
||||
continue;
|
||||
|
||||
table.IsIncomplete = true;
|
||||
|
||||
foreach (var column in table.Columns.Values)
|
||||
{
|
||||
column.Values[0] = null;
|
||||
column.IsIncomplete = true;
|
||||
}
|
||||
|
||||
invalidatedTables.Add(table);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<object> GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_supportCaseDataCache.TryGetValue(valueAddress.ValueTable, out var tables))
|
||||
return null;
|
||||
|
||||
if (!tables.TryGetValue(relation, out var table))
|
||||
return null;
|
||||
|
||||
if (!table.Columns.TryGetValue(valueAddress.ValueColumn, out var column))
|
||||
return null;
|
||||
|
||||
return column.Values;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e)
|
||||
@@ -107,19 +251,6 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
=> AddCaseRelations(relations?.ToLookup(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), r => r));
|
||||
|
||||
public event EventHandler<RelationEventArgs> CaseRelationsAdded;
|
||||
public event EventHandler<object> SupportCaseDataCacheHasChanged; // Lookup for IdentitySet and tables which has been updated
|
||||
|
||||
private class SearchResultRelationEqualityComparer : IEqualityComparer<cF4sdApiSearchResultRelation>
|
||||
{
|
||||
public bool Equals(cF4sdApiSearchResultRelation x, cF4sdApiSearchResultRelation y)
|
||||
{
|
||||
return x.isEqual(y);
|
||||
}
|
||||
|
||||
public int GetHashCode(cF4sdApiSearchResultRelation obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
public event EventHandler<SupportCaseDataEventArgs> SupportCaseDataCacheHasChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,6 @@ namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
if (primaryIdentity is null)
|
||||
throw new InvalidEnumArgumentException($"{nameof(primaryIdentity)} must not be null.");
|
||||
|
||||
if (primaryIdentity.Class != enumFasdInformationClass.User)
|
||||
throw new InvalidEnumArgumentException($"{nameof(primaryIdentity)} must be of class {nameof(enumFasdInformationClass.User)}.");
|
||||
|
||||
if (_supportCases.TryGetValue(primaryIdentity.Id, out var supportCase))
|
||||
{
|
||||
supportCase.Initialize();
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
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);
|
||||
}
|
||||
|
||||
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.Select(t => t.Name));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<enumActualizeStatus> ActualizeDataAsync(int? agentUserId, int? agentDeviceId)
|
||||
{
|
||||
var status = enumActualizeStatus.unknown;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.SupportCase
|
||||
{
|
||||
internal class SupportCaseProcessorFactory
|
||||
{
|
||||
private readonly static Dictionary<Guid, SupportCaseProcessor> _supportCaseProccesors = new Dictionary<Guid, SupportCaseProcessor>();
|
||||
|
||||
internal static SupportCaseProcessor Get(Guid id)
|
||||
{
|
||||
if (!_supportCaseProccesors.ContainsKey(id))
|
||||
_supportCaseProccesors.Add(id, new SupportCaseProcessor());
|
||||
|
||||
return _supportCaseProccesors[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user