aktueller Stand

This commit is contained in:
Meik
2026-01-28 12:08:39 +01:00
parent 1283750829
commit ee1f54675e
104 changed files with 6797 additions and 1867 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();

View File

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

View File

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