diff --git a/FasdCockpitCommunicationDemo/Config/F4SD-CopyTemplate-Configuration.xml b/FasdCockpitCommunicationDemo/Config/F4SD-CopyTemplate-Configuration.xml index 5a5daa9..3269cff 100644 --- a/FasdCockpitCommunicationDemo/Config/F4SD-CopyTemplate-Configuration.xml +++ b/FasdCockpitCommunicationDemo/Config/F4SD-CopyTemplate-Configuration.xml @@ -1,59 +1,69 @@  - - - Ticket Information + + + Ticket-Information-Computer Transfers the relevant information for ticket creation to the clipboard. Überträgt die relevanten Informationen für eine Ticket Erstellung in den Zwischenspeicher. - %DeviceName.Label% %DeviceName.Value% -%UserFullName.Label% %UserFullName.Value% -%UserAccount.Label% %UserAccount.Value% -%DeviceModel.Label% %DeviceModel.Value% -%OsInfo.Label% %OsInfo.Value% -%IpAddress.Label% %IpAddress.Value% -%LastSeenCalc.Label% %LastSeenCalc.Value% - <table border="1" cellpadding="5,1,5,1"><tbody> -<tr><td><em>%DeviceName.Label%</em></td><td style="color: #0000ff;">%DeviceName.Value%</td></tr> -<tr><td><em>%UserFullName.Label%</em></td><td>%UserFullName.Value%</td></tr> -<tr><td><em>%UserAccount.Label%</em></td><td>%UserAccount.Value%</td></tr> -<tr><td><em>%OsInfo.Label%</em></td><td>%OsInfo.Value%</td></tr> -<tr><td><em>%IpAddress.Label%</em></td><td>%IpAddress.Value%</td></tr> -<tr><td><em>%LastSeenCalc.Label%</em></td><td>%LastSeenCalc.Value%</td></tr> -</tbody></table> + + %DeviceName.Label% %DeviceName.Value% + %UserFullName.Label% %UserFullName.Value% + %UserAccount.Label% %UserAccount.Value% + %DeviceModel.Label% %DeviceModel.Value% + %OsInfo.Label% %OsInfo.Value% + %IpAddress.Label% %IpAddress.Value% + %LastBoot.Label% %LastBoot.Value% + %LastSeen.Label% %LastSeen.Value% + + + <table border="1" cellpadding="5,1,5,1"><tbody> + <tr><td><em>%DeviceName.Label%</em></td><td style="color: #0000ff;">%DeviceName.Value%</td></tr> + <tr><td><em>%UserFullName.Label%</em></td><td>%UserFullName.Value%</td></tr> + <tr><td><em>%UserAccount.Label%</em></td><td>%UserAccount.Value%</td></tr> + <tr><td><em>%OsInfo.Label%</em></td><td>%OsInfo.Value%</td></tr> + <tr><td><em>%IpAddress.Label%</em></td><td>%IpAddress.Value%</td></tr> + <tr><td><em>%LastBoot.Label%</em></td><td>%LastBoot.Value%</td></tr> + <tr><td><em>%LastSeen.Label%</em></td><td>%LastSeen.Value%</td></tr> + </tbody></table> + + + + Ticket Information-VM + Transfers the relevant information for ticket creation to the clipboard. + Überträgt die relevanten Informationen für eine Ticket Erstellung in den Zwischenspeicher. + + + %VirtualSessionName.Label% %VirtualSessionName.Value% + %DNSName.Label% %DNSName.Value% + %DomainName.Label% %DomainName.Value% + %HostedMachine.Label% %HostedMachine.Value% + + + + <table border="1" cellpadding="5,1,5,1"><tbody> + <tr><td><em>%VirtualSessionName.Label%</em></td><td style="color: #0000ff;">%VirtualSessionName.Value%</td></tr> + <tr><td><em>%DNSName.Label%</em></td><td>%DNSName.Value%</td></tr> + <tr><td><em>%DomainName.Label%</em></td><td>%DomainName.Value%</td></tr> + <tr><td><em>%HostedMachine.Label%</em></td><td>%HostedMachine.Value%</td></tr> + </tbody></table> + Computer Name
DemoActions
- %DeviceName.Value% + %DeviceName.Label% %DeviceName.Value%
Anwendername - %UserFullName.Value% + %UserFullName.Label% %UserFullName.Value% Anwender Account - %UserAccount.Value% + %UserAccount.Label% %UserAccount.Value% - - - Letzte Quick Action kopieren -
Ticket
- - %F4SD_QuickActionProtocolLast.Value% - %F4SD_QuickActionProtocolLast.Value% -
- - - Quick Action Historie kopieren -
Ticket
- - %F4SD_QuickActionProtocol.Value% - %F4SD_QuickActionProtocol.Value% -
-
\ No newline at end of file diff --git a/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml b/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml index e97b810..6696585 100644 --- a/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml +++ b/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml @@ -567,7 +567,7 @@ Hauptbenutzer - + Letzte Synchronisation @@ -1289,10 +1289,10 @@ Sessionname - + Startdatum - + Enddatum diff --git a/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs b/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs index edf5cc9..84116d5 100644 --- a/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs +++ b/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs @@ -1237,7 +1237,7 @@ namespace C4IT.FASD.Cockpit.Communication public override async Task GetHealthCardData(Guid healthCardId) { - cF4SDHealthCardRawData output = null; + cF4SDHealthCardRawData healthcardData = null; try { @@ -1245,25 +1245,16 @@ namespace C4IT.FASD.Cockpit.Communication lock (CachedHealthCardRawData) { - if (CachedHealthCardRawData.TryGetValue(healthCardId, out output)) - { - CachedHealthCardRawData.Remove(healthCardId); - return output; - } + if (CachedHealthCardRawData.TryGetValue(healthCardId, out healthcardData)) + return healthcardData; } - - return null; } catch (Exception E) { LogException(E); } - finally - { - } - await Task.CompletedTask; - return output; + return healthcardData; } public override async Task> GetDetailsData(cF4sdHealthCardRawDataRequest requestData) diff --git a/FasdDesktopUi/App.xaml.cs b/FasdDesktopUi/App.xaml.cs index 1a7a220..1b49613 100644 --- a/FasdDesktopUi/App.xaml.cs +++ b/FasdDesktopUi/App.xaml.cs @@ -479,7 +479,16 @@ namespace FasdDesktopUi private async void Application_Exit(object sender, ExitEventArgs e) { - var closeUserSessionTask = cFasdCockpitCommunicationBase.Instance?.CloseUserSession(cFasdCockpitConfig.SessionId).ConfigureAwait(false); + cF4sdUserInfo userInfo = null; + ConfiguredTaskAwaitable? closeUserSessionTask = null; + lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock) + { + userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo; + } + if (userInfo?.Id.Equals(Guid.Empty) is false) + { + closeUserSessionTask = cFasdCockpitCommunicationBase.Instance?.CloseUserSession(cFasdCockpitConfig.SessionId).ConfigureAwait(false); + } await cFasdCockpitCommunicationBase.Instance.TerminateAsync(); diff --git a/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs b/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs index ad284b4..7b69f19 100644 --- a/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs +++ b/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs @@ -886,8 +886,8 @@ namespace FasdDesktopUi.Basics.Helper public string GetInformationObjectHeadingName(enumFasdInformationClass InfoClass) { - if (HeadingData.TryGetValue(enumFasdInformationClass.Computer, out var computerHeadingData)) - return computerHeadingData.HeadingText; + if (HeadingData.TryGetValue(InfoClass, out var infoClassHeadingData)) + return infoClassHeadingData.HeadingText; return null; } @@ -1086,7 +1086,7 @@ namespace FasdDesktopUi.Basics.Helper return output; } - private void UpdateNamedParameterEntries() + internal void UpdateNamedParameterEntries() { try { @@ -1978,7 +1978,7 @@ namespace FasdDesktopUi.Basics.Helper parent.dataProvider.Identities = identities; if (newHealthCardRawData != null) - parent.HealthCardRawData = HealthCardRawData.Combine(newHealthCardRawData); + parent.HealthCardRawData = newHealthCardRawData; parent.UpdateNamedParameterEntries(); @@ -2021,12 +2021,12 @@ namespace FasdDesktopUi.Basics.Helper if (oldTable.StartingIndex != newTable.StartingIndex) return true; - foreach (var oldTableColumn in oldTable.Columns.Values) + foreach (var oldTableColumn in oldTable.Columns) { - if (!newTable.Columns.TryGetValue(oldTableColumn.ColumnName, out var newTableColumn)) + if (!newTable.Columns.TryGetValue(oldTableColumn.Key, out var newTableColumn)) continue; - if (oldTableColumn.Values.Count != newTableColumn.Values.Count) + if (oldTableColumn.Value.Values.Count != newTableColumn.Values.Count) return true; } } diff --git a/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs b/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs index f8633ba..ea53820 100644 --- a/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs +++ b/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs @@ -1,11 +1,13 @@ using C4IT.F4SD.SupportCaseProtocoll.Models; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using C4IT.F4SD.DisplayFormatting; using C4IT.FASD.Base; using C4IT.MultiLanguage; using FasdDesktopUi.Basics.Models; using FasdDesktopUi.Basics.UserControls; -using System; -using System.Collections.Generic; -using System.Globalization; using static C4IT.Logging.cLogManager; using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor; @@ -43,8 +45,8 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService quickActionCopyData.Name = quickActionDefinition.Names.GetValue(); quickActionCopyData.ExecutionTime = DateTime.UtcNow; - - quickActionCopyData.AffectedDeviceName = dataProvider.HealthCardDataHelper.GetInformationObjectHeadingName(enumFasdInformationClass.Computer); + var infoClass = dataProvider.HealthCardDataHelper.SelectedHealthCard.InformationClasses.FirstOrDefault(); + quickActionCopyData.AffectedDeviceName = dataProvider.HealthCardDataHelper.GetInformationObjectHeadingName(infoClass); quickActionCopyData.WasRunningOnAffectedDevice = wasRunningOnAffectedDevice; quickActionCopyData.QuickActionOutput = quickActionOutput; @@ -91,7 +93,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService { string ascii = string.Empty; - ascii += GetQuickActionAsciiDescription(copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode); + ascii += GetQuickActionAsciiDescription(quickActionDefinition,copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode); ascii += GetQuickActionAsciiError(copyData.QuickActionOutput?.ErrorDescription); ascii += GetQuickActionAsciiOutput(quickActionDefinition, copyData.QuickActionOutput); ascii += GetQuickActionAsciiValueComparisonString(copyData.MeasureValues); @@ -99,7 +101,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return ascii; } - private static string GetQuickActionAsciiDescription(string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) + private static string GetQuickActionAsciiDescription(cFasdQuickAction quickActionDefinition,string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) { string asciiDescription = string.Empty; try @@ -118,6 +120,12 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService } var rawDescription = wasRunningOnAffectedDevice ? cMultiLanguageSupport.GetItem("QuickAction.Remote.Copy.Description") : cMultiLanguageSupport.GetItem("QuickAction.Local.Copy.Description"); + if (quickActionDefinition.Section == enumDataHistoryOrigin.Citrix.ToString()) + { + rawDescription = cMultiLanguageSupport.GetItem("QuickAction.RemoteSession.Copy.Description"); + + } + asciiDescription = string.Format(rawDescription, quickActionName, deviceName, executionTime.ToString("g", new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)), quickActionStatusString); } catch (Exception E) @@ -291,7 +299,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService try { - output += GetQuickActionHtmlDescription(copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode); + output += GetQuickActionHtmlDescription(quickActionDefinition,copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode); output += GetQuickActionHtmlError(copyData.QuickActionOutput?.ErrorDescription); output += GetQuickActionHtmlOutput(quickActionDefinition, copyData.QuickActionOutput); output += GetQuickActionHtmlValueComparison(copyData.MeasureValues); @@ -304,7 +312,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return output; } - private static string GetQuickActionHtmlDescription(string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) + private static string GetQuickActionHtmlDescription(cFasdQuickAction quickActionDefinition, string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) { string output = string.Empty; try @@ -323,6 +331,11 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService } var rawDescription = wasRunningOnAffectedDevice ? cMultiLanguageSupport.GetItem("QuickAction.Remote.Copy.Description.Html") : cMultiLanguageSupport.GetItem("QuickAction.Local.Copy.Description.Html"); + if(quickActionDefinition.Section == enumDataHistoryOrigin.Citrix.ToString()) + { + rawDescription = cMultiLanguageSupport.GetItem("QuickAction.RemoteSession.Copy.Description.Html"); + + } output = string.Format(rawDescription, quickActionName, deviceName, executionTime.ToString("g", new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)), quickActionStatusString); } catch (Exception E) diff --git a/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs b/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs index 29cad06..19c56ce 100644 --- a/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs +++ b/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs @@ -81,8 +81,8 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers } } - private void HandleAvailableCaseRelationsAdded(object sender, RelationEventArgs e) - => AvailableCaseRelationsAdded?.Invoke(this, e); + private void HandleAvailableCaseRelationsAdded(object sender, RelationEventArgs e) + => AvailableCaseRelationsAdded?.Invoke(this, e); private void HandleCaseDataChanged(object sender, SupportCaseDataEventArgs e) { @@ -127,13 +127,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers SupportCaseDataProviderArtifact.HealthCardDataHelper.TrySetSelectedHealthcard(requiredInformationClasses); - _focusedRelation = relation; - - if (!_selectedRelations.Values.Contains(relation)) - _hasDirectionConnection = false; - - _selectedRelations[cF4sdIdentityEntry.GetFromSearchResult(relation.Type)] = relation; - _ = Task.Run(async () => await UpdateStatusOfSelectedRelations()); + _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() @@ -147,7 +147,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers } } - private async Task UpdateStatusOfSelectedRelations() + private async Task UpdateStatusOfSelectedRelations() { const string StatusString = "Status"; @@ -197,6 +197,11 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers statusValue = isUserOnline ? "Online" : "Offline"; break; case enumFasdInformationClass.Ticket: + if (relationEntry.Value.Infos != null && relationEntry.Value.Infos.TryGetValue("StatusId", out var statusIdValue)) + if (Enum.TryParse(statusIdValue, out var ticketStatus)) + statusValue = ticketStatus.ToString(); + break; + case enumFasdInformationClass.VirtualSession: case enumFasdInformationClass.MobileDevice: default: @@ -215,11 +220,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers catch (Exception ex) { LogException(ex); - } - } + } + } + public async Task RefreshDataForCurrentlyFocusedRelationAsync() { + SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.LastDataRequest = DateTime.Now; await _supportCaseProcessor.UpdateLatestCaseDataFor(_focusedRelation); } diff --git a/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs b/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs index 3dde9b5..8804e59 100644 --- a/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs +++ b/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs @@ -14,6 +14,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase { private readonly Dictionary> _caseRelations = new Dictionary>(); private readonly Dictionary> _supportCaseDataCache = new Dictionary>(); + private readonly Dictionary _rawDataCache = new Dictionary(); // todo remove, currently only used for SupportCaseDataProviderArtifact internal readonly Guid Id; private readonly IRelationService _relationService; @@ -93,11 +94,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase // 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) - ); + bool isDataComplete = IsRawDataCacheComplete() && IsSupportCaseDataCacheComplete(); + + if (isDataComplete) + { + await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.SetHealthCardRawData(_rawDataCache[relation], relation.Identities); + return; + } var rawDataRequest = new cF4sdHealthCardRawDataRequest() { @@ -111,11 +114,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase if (rawData is null) { rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawDataRequest); + _rawDataCache[relation] = rawData; await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.SetHealthCardRawData(rawData, rawDataRequest.Identities); } else { rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawData.Id); + _rawDataCache[relation] = _rawDataCache[relation].Combine(rawData); await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.UpdateHealthcardRawData(rawData); } @@ -130,6 +135,24 @@ namespace FasdDesktopUi.Basics.Services.SupportCase { LogException(ex); } + + bool IsRawDataCacheComplete() + { + return tablesToLoad.All(t => + _rawDataCache.TryGetValue(relation, out var cachedRawData) + && cachedRawData.Tables.TryGetValue(t, out var cachedTable) + && !cachedTable.IsIncomplete && !cachedTable.Columns.Values.Any(c => c.IsIncomplete) + ); + } + + bool IsSupportCaseDataCacheComplete() + { + return tablesToLoad.Any(t => + _supportCaseDataCache.TryGetValue(t, out var cachedTables) + && cachedTables.TryGetValue(relation, out var table) + && !table.IsIncomplete && !table.Columns.Values.Any(c => c.IsIncomplete) + ); + } } public void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable tables) @@ -151,7 +174,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase if (!_supportCaseDataCache[table.Name].ContainsKey(relation)) _supportCaseDataCache[table.Name][relation] = table; - else + else if (_supportCaseDataCache[table.Name][relation].IsIncomplete) MergeTable(_supportCaseDataCache[table.Name][relation], table); } @@ -164,9 +187,18 @@ namespace FasdDesktopUi.Basics.Services.SupportCase void MergeTable(cF4SDHealthCardRawData.cHealthCardTable existingTable, cF4SDHealthCardRawData.cHealthCardTable newTable) { - foreach (var newColumn in newTable.Columns) + try { - existingTable.Columns[newColumn.Key] = newColumn.Value; + existingTable.IsIncomplete = newTable.IsIncomplete; + + foreach (var newColumn in newTable.Columns) + { + existingTable.Columns[newColumn.Key] = newColumn.Value; + } + } + catch (Exception ex) + { + LogException(ex); } } } @@ -175,6 +207,8 @@ namespace FasdDesktopUi.Basics.Services.SupportCase { try { + _rawDataCache.Remove(relation); + foreach (var tableCache in _supportCaseDataCache.Values) { tableCache.Remove(relation); @@ -209,6 +243,20 @@ namespace FasdDesktopUi.Basics.Services.SupportCase invalidatedTables.Add(table); } + + if (!_rawDataCache.TryGetValue(relation, out var cachedRawData) || cachedRawData?.Tables is null) + return; + + foreach (var table in cachedRawData.Tables.Values) + { + table.IsIncomplete = true; + + foreach (var column in table.Columns.Values) + { + column.Values[0] = null; + column.IsIncomplete = true; + } + } } catch (Exception ex) { diff --git a/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs index 8f8a8c3..8f55dfa 100644 --- a/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs +++ b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs @@ -110,6 +110,10 @@ namespace FasdDesktopUi.Basics.Services.SupportCase detailsData = await _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataAsync(); _detailsPageDataCache.Add(relation, detailsData); } + else + { + _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.UpdateNamedParameterEntries(); + } CaseDataChanged?.Invoke(this, new SupportCaseDataEventArgs()); } @@ -124,7 +128,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase await ActualizeDataAsync(agentUserId, agentDeviceId); _supportCase.InvalidateLatestCaseDataCacheFor(relation, out var invalidatedTables); _detailsPageDataCache.Remove(relation); - await _supportCase.LoadSupportCaseDataAsync(relation, invalidatedTables.Select(t => t.Name)); + await _supportCase.LoadSupportCaseDataAsync(relation, invalidatedTables.Where(t => !t.Name.StartsWith("Computation_")).Select(t => t.Name)); } catch (Exception ex) { diff --git a/FasdDesktopUi/Basics/SupportCaseDataProvider.cs b/FasdDesktopUi/Basics/SupportCaseDataProvider.cs index 70b4bb5..c7c57de 100644 --- a/FasdDesktopUi/Basics/SupportCaseDataProvider.cs +++ b/FasdDesktopUi/Basics/SupportCaseDataProvider.cs @@ -107,15 +107,17 @@ namespace FasdDesktopUi.Basics { try { - if (selectedRelation == null) - { - Debug.Assert(true, "The selected relation must not be null here!"); - LogEntry("The selected relation must not be null here!", LogLevels.Error); - return null; - } - - // get the identities of the selected relation - var Identities = selectedRelation.Identities.Clone(); + if (selectedRelation == null) + { + Debug.Assert(true, "The selected relation must not be null here!"); + LogEntry("The selected relation must not be null here!", LogLevels.Error); + return null; + } + + await EnsureUserIdentityForTicketAsync(selectedRelation); + + // get the identities of the selected relation + var Identities = selectedRelation.Identities.Clone(); // get the main indentities from all identites (normally this is the user, in a special case, where a computer was searched and found without any user activities, it could be the computer) var MainIdentity = Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.User); @@ -312,6 +314,87 @@ namespace FasdDesktopUi.Basics detailsPage = new Pages.DetailsPage.DetailsPageView(); }, DispatcherPriority.Normal); } + + private static async Task EnsureUserIdentityForTicketAsync(cF4sdApiSearchResultRelation relation) + { + if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket) + return; + + if (relation.Identities == null) + relation.Identities = new cF4sdIdentityList(); + + var existingUsers = relation.Identities + .Where(identity => identity.Class == enumFasdInformationClass.User) + .ToList(); + + Guid userId = Guid.Empty; + if (relation.Infos != null) + { + if (relation.Infos.TryGetValue("Sids", out var sidsValue) || + relation.Infos.TryGetValue("UserSid", out sidsValue)) + { + var sids = sidsValue?.Split(',') + .Select(v => v.Trim()) + .Where(v => !string.IsNullOrWhiteSpace(v)) + .ToList(); + + if (sids != null && sids.Count > 0) + { + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication != null) + { + relation.Infos.TryGetValue("UserDisplayName", out var userDisplayName); + var result = await communication.GetUserSearchResults(userDisplayName, sids); + var user = result?.Values?.FirstOrDefault()?.FirstOrDefault(); + if (user != null) + userId = user.id; + } + } + } + + if (userId == Guid.Empty && relation.Infos.TryGetValue("UserAccount", out var userAccount)) + { + relation.Infos.TryGetValue("UserDomain", out var userDomain); + if (!string.IsNullOrWhiteSpace(userAccount)) + { + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication != null) + { + userId = await communication.GetUserIdByAccount(userAccount, userDomain ?? string.Empty); + } + } + } + + if (userId == Guid.Empty) + { + if (relation.Infos.TryGetValue("UserId", out var userIdString) || + relation.Infos.TryGetValue("UserGuid", out userIdString) || + relation.Infos.TryGetValue("UserIdentityId", out userIdString)) + { + Guid.TryParse(userIdString, out userId); + } + } + } + + if (userId == Guid.Empty) + return; + + if (existingUsers.Count == 0 || existingUsers.Any(identity => identity.Id != userId)) + { + relation.Identities.RemoveAll(identity => identity.Class == enumFasdInformationClass.User); + relation.Identities.Add(new cF4sdIdentityEntry + { + Class = enumFasdInformationClass.User, + Id = userId + }); + } + + if (relation.Infos == null) + relation.Infos = new Dictionary(StringComparer.OrdinalIgnoreCase); + + relation.Infos["UserId"] = userId.ToString(); + relation.Infos["UserGuid"] = userId.ToString(); + } public async Task CloseCaseAsync() { diff --git a/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs b/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs index 62b0ff8..1a5ed82 100644 --- a/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs @@ -4,8 +4,8 @@ using C4IT.MultiLanguage; using FasdDesktopUi.Basics.Services.RelationService; using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; +using System.Diagnostics; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -92,9 +92,9 @@ namespace FasdDesktopUi.Basics.UiActions // get the new data provider for the support call informations (get it from the cache or create a new one) dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(_selectedRelation, _relationService); - bool shouldLoadRelationsForSelectedRelation = _selectedRelation.Type == enumF4sdSearchResultClass.User; - if (shouldLoadRelationsForSelectedRelation) - StartLoadingRelationsFor(_selectedRelation); + bool shouldLoadRelationsForSelectedRelation = _selectedRelation.Type == enumF4sdSearchResultClass.User; + if (shouldLoadRelationsForSelectedRelation) + StartLoadingRelationsFor(_selectedRelation); if (dataProvider is null) { diff --git a/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs b/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs index aaf555d..8975793 100644 --- a/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs @@ -91,12 +91,12 @@ namespace FasdDesktopUi.Basics.UiActions Mouse.OverrideCursor = null; - if (MatchPreselectedSearchRelation(_loadedRelations)) - return await ProcessSearchResultRelationAsync(_searchResults.First().Name, _loadedRelations, PreSelectedSearchRelation); - if (await _isSearchUnambigous.Task) return await ProcessSearchResultRelationAsync(_searchResults.First().Name, _loadedRelations, _loadedRelations.FirstOrDefault()); + if (MatchPreselectedSearchRelation(_loadedRelations)) + return await ProcessSearchResultRelationAsync(_searchResults.First().Name, _loadedRelations, PreSelectedSearchRelation); + return true; } catch (Exception ex) diff --git a/FasdDesktopUi/Basics/UiActions/UiProcessTicketOverviewRelationAction.cs b/FasdDesktopUi/Basics/UiActions/UiProcessTicketOverviewRelationAction.cs new file mode 100644 index 0000000..4e36815 --- /dev/null +++ b/FasdDesktopUi/Basics/UiActions/UiProcessTicketOverviewRelationAction.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; +using System.Windows; +using C4IT.FASD.Base; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.UiActions +{ + public sealed class cUiProcessTicketOverviewRelationAction : cUiActionBase + { + private readonly Func _runAsync; + + public cUiProcessTicketOverviewRelationAction(string name, Func runAsync) + { + Name = name; + _runAsync = runAsync; + } + + public override async Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) + { + try + { + if (_runAsync != null) + await _runAsync(); + } + catch (Exception ex) + { + LogException(ex); + } + + return false; + } + } +} diff --git a/FasdDesktopUi/Basics/UserControls/CustomMenuItem.xaml.cs b/FasdDesktopUi/Basics/UserControls/CustomMenuItem.xaml.cs index 9c7b33a..5a3b61a 100644 --- a/FasdDesktopUi/Basics/UserControls/CustomMenuItem.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/CustomMenuItem.xaml.cs @@ -169,20 +169,38 @@ namespace FasdDesktopUi.Basics.UserControls { SearchRelationGrid.Visibility = Visibility.Visible; - var lastUsedTimeSpan = DateTime.UtcNow - searchRelationMenuData.LastUsed; - LanguageDefinitionsConverter valueConverter = new LanguageDefinitionsConverter(); - string lastSeenText = null; + if (searchRelationMenuData.LastUsed == DateTime.MinValue) + { + LessThanTextBlock.Text= string.Empty; + LessThanTextBlock.Visibility = Visibility.Collapsed; + LastSeenTextBox.Visibility = Visibility.Collapsed; - if (Math.Floor(lastUsedTimeSpan.TotalHours) > 24) - lastSeenText = valueConverter.Convert(Math.Ceiling(lastUsedTimeSpan.TotalDays), null, "Searchbar.LessThan.Days", null) as string; - else if (Math.Floor(lastUsedTimeSpan.TotalHours) >= 1) - lastSeenText = valueConverter.Convert(Math.Ceiling(lastUsedTimeSpan.TotalHours), null, "Searchbar.LessThan.Hours", null) as string; - else - lastSeenText = valueConverter.Convert(Math.Ceiling(lastUsedTimeSpan.TotalMinutes), null, "Searchbar.LessThan.Min", null) as string; + ActivityIndicator.Width = 0; + ActivityIndicator.Visibility = Visibility.Collapsed; + ActivityTextBlock.Visibility = Visibility.Collapsed; + } + else + { + var lastUsedTimeSpan = DateTime.UtcNow - searchRelationMenuData.LastUsed; + LanguageDefinitionsConverter valueConverter = new LanguageDefinitionsConverter(); + string lastSeenText = null; + + if (Math.Floor(lastUsedTimeSpan.TotalHours) > 24) + lastSeenText = valueConverter.Convert(Math.Ceiling(lastUsedTimeSpan.TotalDays), null, "Searchbar.LessThan.Days", null) as string; + else if (Math.Floor(lastUsedTimeSpan.TotalHours) >= 1) + lastSeenText = valueConverter.Convert(Math.Ceiling(lastUsedTimeSpan.TotalHours), null, "Searchbar.LessThan.Hours", null) as string; + else + lastSeenText = valueConverter.Convert(Math.Ceiling(lastUsedTimeSpan.TotalMinutes), null, "Searchbar.LessThan.Min", null) as string; + + LessThanTextBlock.Text = lastSeenText; + LessThanTextBlock.Visibility = Visibility.Visible; + LastSeenTextBox.Visibility = Visibility.Visible; - LessThanTextBlock.Text = lastSeenText; + ActivityIndicator.Width = Math.Max(ActivityIndicator.Width * relationData.UsingLevel, ActivityIndicator.Width * 0.1); + ActivityIndicator.Visibility = Visibility.Visible; + ActivityTextBlock.Visibility = Visibility.Visible; + } - ActivityIndicator.Width = Math.Max(ActivityIndicator.Width * relationData.UsingLevel, ActivityIndicator.Width * 0.1); } } diff --git a/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs b/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs index c3de5d1..21af975 100644 --- a/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs @@ -157,7 +157,7 @@ namespace FasdDesktopUi.Basics.UserControls Dispatcher.Invoke(() => SearchSpinner.Visibility = visibility); } - public async Task SetFixedSearchResultAsync(enumF4sdSearchResultClass Class, string search, cFilteredResults _result) + public async Task SetFixedSearchResultAsync(enumF4sdSearchResultClass Class, string search, cFilteredResults result) { SearchStatus = eSearchStatus.fixedResult; SearchTextBox.IsEnabled = false; @@ -173,8 +173,8 @@ namespace FasdDesktopUi.Basics.UserControls } SearchTextBox.Text = search; - await ChangedSearchValue?.Invoke(_result); - + if (ChangedSearchValue != null) + await ChangedSearchValue.Invoke(result); } public void SetApiStatus() diff --git a/FasdDesktopUi/Config/LanguageDefinitions.xml b/FasdDesktopUi/Config/LanguageDefinitions.xml index 4056781..f87a9b1 100644 --- a/FasdDesktopUi/Config/LanguageDefinitions.xml +++ b/FasdDesktopUi/Config/LanguageDefinitions.xml @@ -894,6 +894,16 @@ Die Quick Action <b>"{0}"</b> wurde durch F4SD remote auf dem Gerät <b>"{1}"</b> am {2} <b>{3}</b>ausgeführt. + + The Quick Action '{0}' was {3}executed remotely by F4SD for the session '{1}' at {2}. + Die Quick Action "{0}" wurde durch F4SD remote für die Session "{1}" am {2} {3}ausgeführt. + + + + The Quick Action <b>'{0}'</b> was <b>{3}</b>executed remotely by F4SD on the session <b>'{1}'</b> at {2}. + Die Quick Action <b>"{0}"</b> wurde durch F4SD remote für die Session <b>"{1}"</b> am {2} <b>{3}</b>ausgeführt. + + The Quick Action '{0}' was {3}executed local by F4SD for the device '{1}' at {2}. Die Quick Action "{0}" wurde durch F4SD lokal für das Gerät "{1}" am {2} {3}ausgeführt. diff --git a/FasdDesktopUi/F4SD-Cockpit-Client.csproj b/FasdDesktopUi/F4SD-Cockpit-Client.csproj index 7933e7b..bff7afc 100644 --- a/FasdDesktopUi/F4SD-Cockpit-Client.csproj +++ b/FasdDesktopUi/F4SD-Cockpit-Client.csproj @@ -259,7 +259,8 @@ - + + diff --git a/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml.cs b/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml.cs index 80dda84..d6214af 100644 --- a/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml.cs +++ b/FasdDesktopUi/Pages/AdvancedSearchPage/AdvancedSearchPageView.xaml.cs @@ -399,7 +399,7 @@ namespace FasdDesktopUi.Pages.AdvancedSearchPage { await SearchBarUc.SetFixedSearchResultAsync(Class, strInfo, result); - if (result.AutoContinue && result.Results?.Count == 1) + if (result.AutoContinue && result.Results?.Count == 1) { ResultMenu.IndexOfSelectedResultItem = 0; ResultMenu.SelectCurrentResultItem(); diff --git a/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs b/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs index 4c6a9dc..dcaa1ef 100644 --- a/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs +++ b/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs @@ -55,19 +55,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.ViewModels #region Details Properties - #region TimeSinceLastRefresh property - private TimeSpan timeSinceLastRefresh; - public TimeSpan TimeSinceLastRefresh - { - get { return timeSinceLastRefresh; } - set - { - timeSinceLastRefresh = value; - OnPropertyChanged(); - } - } - #endregion - #region DetailsGeometry property private DetailsPageDataHistoryCollectionGeometryModel detailsGeometry; diff --git a/FasdDesktopUi/Pages/DetailsPage/Models/DetailsPageBase.cs b/FasdDesktopUi/Pages/DetailsPage/Models/DetailsPageBase.cs index 61b6fd7..70bb11e 100644 --- a/FasdDesktopUi/Pages/DetailsPage/Models/DetailsPageBase.cs +++ b/FasdDesktopUi/Pages/DetailsPage/Models/DetailsPageBase.cs @@ -31,8 +31,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.Models //Widget public List> WidgetData { get; set; } - //Details - public TimeSpan TimeSinceLastRefresh { get; set; } = new TimeSpan(0, 1, 0); public cDetailsPageDataHistoryDataModel DataHistoryList { get; set; } public int ShownValueColumnsCount { get; set; } diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs index 1094b8d..08082d4 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs @@ -306,8 +306,8 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls if (MobileDeviceStack.Parent is UIElement mobileParent) mobileParent.Visibility = Visibility.Collapsed; - if (VirtualSessionStack.Parent is UIElement virtualParent) - virtualParent.Visibility = Visibility.Collapsed; + //if (VirtualSessionStack.Parent is UIElement virtualParent) + // virtualParent.Visibility = Visibility.Collapsed; } ResetSelectors(); diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageRefreshControl.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageRefreshControl.xaml.cs index 10d56ec..10d8b16 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageRefreshControl.xaml.cs +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageRefreshControl.xaml.cs @@ -1,21 +1,9 @@ -using C4IT.Logging; -using C4IT.MultiLanguage; +using C4IT.MultiLanguage; using FasdDesktopUi.Basics; using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; using System.Windows.Threading; using static C4IT.Logging.cLogManager; diff --git a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs index 7b180e1..5ac2548 100644 --- a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs +++ b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs @@ -64,13 +64,15 @@ namespace FasdDesktopUi.Pages.SearchPage // Aktueller Zustand der Checkbox public bool IsFilterChecked => FilterCheckbox.IsChecked == true; - public SupportCaseSearchService SearchService { get; } = new SupportCaseSearchService(new RelationService()); + private readonly IRelationService _relationService = new RelationService(); + public SupportCaseSearchService SearchService { get; } private SearchPageView() { try { - InitializeComponent(); + InitializeComponent(); + SearchService = new SupportCaseSearchService(_relationService); Visibility = Visibility.Visible; _instance = this; @@ -420,7 +422,7 @@ namespace FasdDesktopUi.Pages.SearchPage { await SearchBarUc.SetFixedSearchResultAsync(Class, strInfo, result); - if (result.AutoContinue && result.Results?.Count == 1) + if (result.AutoContinue && result.Results?.Count == 1) { ResultMenu.IndexOfSelectedResultItem = 0; ResultMenu.SelectCurrentResultItem(); @@ -561,67 +563,20 @@ namespace FasdDesktopUi.Pages.SearchPage } - private void TicketSearch(cTicketSearchParameters searchInfo) - { - var CM = MethodBase.GetCurrentMethod(); - LogMethodBegin(CM); - try - { - if (!Guid.TryParse(searchInfo.ticketId, out var _ticketId)) - return; - - var _h = Task.Run(async () => - { - try - { - var lstSids = searchInfo.sids?.Split(',').Select((v) => v.Trim()).ToList(); - var _result = await cFasdCockpitCommunicationBase.Instance.GetUserSearchResults(searchInfo.userName, lstSids); - - if (_result is null || _result.Count == 0 || _result.First().Value.Count == 0) - { - LogEntry($"No corresponding user could be found for ticket '{searchInfo.ticketName}'", LogLevels.Warning); - return; - } - - var UserId = _result.Values.First().First().id; - var _ticketRelation = new cF4sdApiSearchResultRelation() - { - Type = enumF4sdSearchResultClass.Ticket, - DisplayName = searchInfo.ticketName, - id = _ticketId, - Status = enumF4sdSearchResultStatus.Active, - Identities = new cF4sdIdentityList - { - { new cF4sdIdentityEntry() - { - Class = enumFasdInformationClass.User, - Id = UserId - } - }, - { new cF4sdIdentityEntry() - { - Class = enumFasdInformationClass.Ticket, - Id = _ticketId - } - }, - } - }; - - var filteredResults = new cFilteredResults(_result) { AutoContinue = true, PreSelectedRelation = _ticketRelation }; - - var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.TicketSearch.Info"), searchInfo.ticketName); - var _t = ShowExternalSearchInfoAsync(strInfo, filteredResults, enumF4sdSearchResultClass.Ticket); - } - catch (Exception E) - { - LogException(E); - } - }); - } - catch (Exception E) - { - LogException(E); - } + private void TicketSearch(cTicketSearchParameters searchInfo) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + try + { + if (!Guid.TryParse(searchInfo.ticketId, out var _ticketId)) + return; + _ = RunTicketSearchAsync(searchInfo.ticketName, _ticketId, searchInfo.userName, searchInfo.sids); + } + catch (Exception E) + { + LogException(E); + } finally { LogMethodEnd(CM); @@ -889,6 +844,12 @@ namespace FasdDesktopUi.Pages.SearchPage new TicketOverviewSelectionRequestedEventHandler(TicketOverview_SelectionRequested), true); cFasdCockpitConfig.Instance.UiSettingsChanged += UiSettingsChanged; + SearchBarUc.ChangedSearchValue = filteredResults => + { + UpdateSearchResults(filteredResults); + return Task.CompletedTask; + }; + SearchBarUc.SearchValueChanged += HandleSearchValueChanged; SearchService.RelationsFound += HandleRelationsFound; } @@ -1011,6 +972,83 @@ namespace FasdDesktopUi.Pages.SearchPage } } + private Task TicketSearchFromOverviewRelationAsync(cF4sdApiSearchResultRelation relation) + { + if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket) + return Task.CompletedTask; + + var ticketName = string.IsNullOrWhiteSpace(relation.DisplayName) ? relation.Name : relation.DisplayName; + var ticketId = relation.id; + if (ticketId == Guid.Empty) + return Task.CompletedTask; + + string userName = null; + string sids = null; + + if (relation.Infos != null) + { + if (!relation.Infos.TryGetValue("UserDisplayName", out userName)) + relation.Infos.TryGetValue("UserAccount", out userName); + + if (!relation.Infos.TryGetValue("Sids", out sids)) + relation.Infos.TryGetValue("UserSid", out sids); + } + + return RunTicketSearchAsync(ticketName, ticketId, userName, sids); + } + + private Task RunTicketSearchAsync(string ticketName, Guid ticketId, string userName, string sids) + { + if (ticketId == Guid.Empty) + return Task.CompletedTask; + + return Task.Run(async () => + { + try + { + var lstSids = sids?.Split(',').Select((v) => v.Trim()).ToList(); + var _result = await cFasdCockpitCommunicationBase.Instance.GetUserSearchResults(userName, lstSids); + + if (_result is null || _result.Count == 0 || _result.First().Value.Count == 0) + { + LogEntry($"No corresponding user could be found for ticket '{ticketName}'", LogLevels.Warning); + return; + } + + var userId = _result.Values.First().First().id; + var _ticketRelation = new cF4sdApiSearchResultRelation() + { + Type = enumF4sdSearchResultClass.Ticket, + DisplayName = ticketName, + id = ticketId, + Status = enumF4sdSearchResultStatus.Active, + Identities = new cF4sdIdentityList + { + new cF4sdIdentityEntry() + { + Class = enumFasdInformationClass.User, + Id = userId + }, + new cF4sdIdentityEntry() + { + Class = enumFasdInformationClass.Ticket, + Id = ticketId + }, + } + }; + + var filteredResults = new cFilteredResults(_result) { AutoContinue = true, PreSelectedRelation = _ticketRelation }; + + var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.TicketSearch.Info"), ticketName); + await ShowExternalSearchInfoAsync(strInfo, filteredResults, enumF4sdSearchResultClass.Ticket); + } + catch (Exception E) + { + LogException(E); + } + }); + } + private void PrimeTicketOverviewScope(TileScope scope) { if (_ticketOverviewNotificationScopesPrimed.Add(scope)) @@ -1329,8 +1367,8 @@ namespace FasdDesktopUi.Pages.SearchPage SetPendingInformationClasses(new HashSet { enumFasdInformationClass.Ticket }); var relations = await LoadRelationsForTileAsync(e.Key, e.UseRoleScope, Math.Max(0, e.Count)); + await PopulateTicketOverviewRelationUsersAsync(relations); Debug.WriteLine($"[TicketOverview] Relations loaded: {relations?.Count ?? 0}"); - var ticketOverviewRelationService = new RelationService(); var firstRelation = relations.FirstOrDefault(); string displayText = header; if (firstRelation != null) @@ -1356,13 +1394,13 @@ namespace FasdDesktopUi.Pages.SearchPage { isSeen = true }; _ticketOverviewHistoryEntries.Add(entry); - var lookup = relations.ToLookup( - r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), - r => - { - var required = new List { cF4sdIdentityEntry.GetFromSearchResult(r.Type) }; - bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required); - string disabledReason = null; + var lookup = relations.ToLookup( + r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), + r => + { + var required = new List { cF4sdIdentityEntry.GetFromSearchResult(r.Type) }; + bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required); + string disabledReason = null; if (!isEnabled) { disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty; @@ -1372,24 +1410,24 @@ namespace FasdDesktopUi.Pages.SearchPage isEnabled = false; disabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty; } - string trailingUser = null; - if (_renderTicketOverviewUserNames && r.Infos != null && r.Infos.TryGetValue("UserDisplayName", out var userDisplayName)) - { - trailingUser = userDisplayName; - } + string trailingUser = null; + if (_renderTicketOverviewUserNames && r.Infos != null && r.Infos.TryGetValue("UserDisplayName", out var userDisplayName)) + { + trailingUser = userDisplayName; + } return (cMenuDataBase)new cMenuDataSearchRelation(r) { MenuText = r.DisplayName, TrailingText = trailingUser, - UiAction = new cUiProcessSearchRelationAction(entry, r, ticketOverviewRelationService, this) + UiAction = new cUiProcessTicketOverviewRelationAction(r.DisplayName, () => TicketSearchFromOverviewRelationAsync(r)) { DisplayType = isEnabled ? enumActionDisplayType.enabled : enumActionDisplayType.disabled, Description = isEnabled ? string.Empty : disabledReason, AlternativeDescription = isEnabled ? string.Empty : disabledReason } - }; - } - ); + }; + } + ); ResultMenu.UpdateSearchRelations(lookup); ResultMenu.SetHeaderText(header, hideDetailsCheckbox: true); @@ -1491,11 +1529,11 @@ namespace FasdDesktopUi.Pages.SearchPage return true; } - private async Task> LoadRelationsForTileAsync(string key, bool useRoleScope, int count) - { - var communication = cFasdCockpitCommunicationBase.Instance; - if (communication == null) - return new List(); + private async Task> LoadRelationsForTileAsync(string key, bool useRoleScope, int count) + { + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication == null) + return new List(); try { var relations = await communication.GetTicketOverviewRelations(key, useRoleScope, Math.Max(0, count)).ConfigureAwait(false); @@ -1515,7 +1553,107 @@ namespace FasdDesktopUi.Pages.SearchPage LogException(ex); return new List(); } - } + } + + private async Task PopulateTicketOverviewRelationUsersAsync(List relations) + { + if (relations == null || relations.Count == 0) + return; + + foreach (var relation in relations) + { + if (relation == null || relation.Type != enumF4sdSearchResultClass.Ticket) + continue; + + if (relation.Identities == null) + relation.Identities = new cF4sdIdentityList(); + + var existingUsers = relation.Identities + .Where(identity => identity.Class == enumFasdInformationClass.User) + .ToList(); + + Guid userId = Guid.Empty; + if (relation.Infos != null) + { + if (relation.Infos.TryGetValue("Sids", out var sidsValue) || + relation.Infos.TryGetValue("UserSid", out sidsValue)) + { + var sids = sidsValue?.Split(',') + .Select(v => v.Trim()) + .Where(v => !string.IsNullOrWhiteSpace(v)) + .ToList(); + + if (sids != null && sids.Count > 0) + { + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication != null) + { + relation.Infos.TryGetValue("UserDisplayName", out var userDisplayName); + var result = await communication.GetUserSearchResults(userDisplayName, sids); + var user = result?.Values?.FirstOrDefault()?.FirstOrDefault(); + if (user != null) + userId = user.id; + } + } + } + + if (userId == Guid.Empty && relation.Infos.TryGetValue("UserAccount", out var userAccount)) + { + relation.Infos.TryGetValue("UserDomain", out var userDomain); + if (!string.IsNullOrWhiteSpace(userAccount)) + { + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication != null) + { + userId = await communication.GetUserIdByAccount(userAccount, userDomain ?? string.Empty); + } + } + } + + if (userId == Guid.Empty) + { + if (relation.Infos.TryGetValue("UserId", out var userIdString) || + relation.Infos.TryGetValue("UserGuid", out userIdString) || + relation.Infos.TryGetValue("UserIdentityId", out userIdString)) + { + Guid.TryParse(userIdString, out userId); + } + } + } + + if (userId == Guid.Empty) + { + if (existingUsers.Count == 0) + continue; + + if (relation.Infos != null) + { + if (!relation.Infos.ContainsKey("UserId")) + relation.Infos["UserId"] = existingUsers[0].Id.ToString(); + if (!relation.Infos.ContainsKey("UserGuid")) + relation.Infos["UserGuid"] = existingUsers[0].Id.ToString(); + } + + continue; + } + + if (existingUsers.Count == 0 || existingUsers.Any(identity => identity.Id != userId)) + { + relation.Identities.RemoveAll(identity => identity.Class == enumFasdInformationClass.User); + relation.Identities.Add(new cF4sdIdentityEntry + { + Class = enumFasdInformationClass.User, + Id = userId + }); + } + + if (relation.Infos == null) + relation.Infos = new Dictionary(StringComparer.OrdinalIgnoreCase); + + relation.Infos["UserId"] = userId.ToString(); + relation.Infos["UserGuid"] = userId.ToString(); + } + } private void UpdateSearchResults(cFilteredResults filteredResults) { @@ -1533,6 +1671,20 @@ namespace FasdDesktopUi.Pages.SearchPage } string menuHeaderText = filteredResults?.PreSelectedRelation?.DisplayName; + + if (filteredResults?.PreSelectedRelation != null) + { + List selectedResult = filteredResults.Results.Values.FirstOrDefault(); + var processSearchResult = new cUiProcessSearchResultAction(selectedResult.FirstOrDefault()?.DisplayName, this, selectedResult) { PreSelectedSearchRelation = filteredResults.PreSelectedRelation }; + Dispatcher.Invoke(async () => + { + bool isSearchOngoing = await processSearchResult.RunUiActionAsync(this, this, false, null); + if (!isSearchOngoing) + Hide(); + }); + return; + } + ResultMenu.ShowSearchResults(filteredResults, menuHeaderText, this); preSelectedRelation = filteredResults.PreSelectedRelation; @@ -1546,8 +1698,6 @@ namespace FasdDesktopUi.Pages.SearchPage })); } - - private void CancledSearchAction() { _renderTicketOverviewUserNames = false; @@ -1573,25 +1723,27 @@ namespace FasdDesktopUi.Pages.SearchPage Mouse.OverrideCursor = Cursors.Wait; - switch (e.UiAction) - { - case cUiProcessSearchResultAction searchResultAction: - searchResultAction.PreSelectedSearchRelation = preSelectedRelation; - break; - case cUiProcessSearchRelationAction _: - case cUiProcessSearchHistoryEntry _: - break; - default: - var _t = e.UiAction?.GetType().Name; - Debug.Assert(true, $"The UI action '{_t}' is not supported in detailed page"); - CancledSearchAction(); + switch (e.UiAction) + { + case cUiProcessSearchResultAction searchResultAction: + searchResultAction.PreSelectedSearchRelation = preSelectedRelation; + break; + case cUiProcessSearchRelationAction _: + case cUiProcessSearchHistoryEntry _: + case cUiProcessTicketOverviewRelationAction _: + break; + default: + var _t = e.UiAction?.GetType().Name; + Debug.Assert(true, $"The UI action '{_t}' is not supported in detailed page"); + CancledSearchAction(); return; } SetSearchResultVisibility(true); - if (!await e.UiAction.RunUiActionAsync(sender, null, false, null)) - CancledSearchAction(); - } + var actionResult = await e.UiAction.RunUiActionAsync(sender, null, false, null); + if (!(e.UiAction is cUiProcessTicketOverviewRelationAction) && !actionResult) + CancledSearchAction(); + } catch (Exception E) { LogException(E); diff --git a/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml b/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml index 79aa64b..45aa344 100644 --- a/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml +++ b/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml @@ -139,7 +139,7 @@