diff --git a/F4SD.Cockpit.Client.Test/Basics/Sevices/TicketOverview/TicketOverviewUpdateServiceTest.cs b/F4SD.Cockpit.Client.Test/Basics/Sevices/TicketOverview/TicketOverviewUpdateServiceTest.cs index 30bea7d..2c387ed 100644 --- a/F4SD.Cockpit.Client.Test/Basics/Sevices/TicketOverview/TicketOverviewUpdateServiceTest.cs +++ b/F4SD.Cockpit.Client.Test/Basics/Sevices/TicketOverview/TicketOverviewUpdateServiceTest.cs @@ -110,6 +110,37 @@ public class TicketOverviewUpdateServiceTest }); } + [Fact] + public async Task FetchAsync_ServiceRequestsCapability_IsSeparatedFromCounts() + { + // Arrange + var communication = new FakeCommunication(); + communication.SetCounts(TileScope.Personal, new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["ServiceRequestsEnabled"] = 1, + ["ServiceRequestsNew"] = 2 + }); + communication.SetCounts(TileScope.Role, new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["ServiceRequestsNew"] = 4 + }); + + var service = CreateService(communication, out _); + var availabilityChanges = 0; + service.ServiceRequestsAvailabilityChanged += (_, _) => availabilityChanges++; + + // Act + service.UpdateAvailability(true); + await WaitUntilAsync(() => service.AreAllScopesInitialized); + + // Assert + Assert.True(service.ServiceRequestsEnabled); + Assert.Equal(1, availabilityChanges); + Assert.Equal(2, service.CurrentCounts["ServiceRequestsNew"].Personal); + Assert.Equal(4, service.CurrentCounts["ServiceRequestsNew"].Role); + Assert.DoesNotContain("ServiceRequestsEnabled", service.CurrentCounts.Keys); + } + private static TicketOverviewUpdateService CreateService(FakeCommunication communication, out FakeDispatcher dispatcher) { dispatcher = new FakeDispatcher(); diff --git a/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs b/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs index 20e87e1..c7fe1cc 100644 --- a/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs +++ b/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs @@ -286,6 +286,12 @@ namespace C4IT.FASD.Cockpit.Communication if (string.IsNullOrWhiteSpace(key)) continue; + if (string.Equals(key, "ServiceRequestsEnabled", StringComparison.OrdinalIgnoreCase)) + { + result[key] = 1; + continue; + } + if (TicketOverviewRelations.TryGetValue(key, out var scopeDictionary) && scopeDictionary != null && scopeDictionary.TryGetValue(scopeKey, out var definitions) && diff --git a/FasdCockpitCommunicationDemo/MockupTicketOverview/TicketOverviewGeneratedTickets.json b/FasdCockpitCommunicationDemo/MockupTicketOverview/TicketOverviewGeneratedTickets.json index b1765cd..b3d9b3c 100644 --- a/FasdCockpitCommunicationDemo/MockupTicketOverview/TicketOverviewGeneratedTickets.json +++ b/FasdCockpitCommunicationDemo/MockupTicketOverview/TicketOverviewGeneratedTickets.json @@ -308,6 +308,58 @@ } ], "Tickets": [ + { + "TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61", + "UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a", + "TileKey": "ServiceRequestsNew", + "UseRoleScope": false, + "ActivityType": "SPSActivityTypeServiceRequest", + "DisplayName": "SRQ00001", + "Summary": "Neue Software fuer den Arbeitsplatz bereitstellen", + "StatusId": "New", + "UserDisplayName": "Busch, Andrea", + "UserAccount": "AB014", + "UserDomain": "CONTOSO" + }, + { + "TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61", + "UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a", + "TileKey": "ServiceRequestsActive", + "UseRoleScope": false, + "ActivityType": "SPSActivityTypeServiceRequest", + "DisplayName": "SRQ00001", + "Summary": "Neue Software fuer den Arbeitsplatz bereitstellen", + "StatusId": "InProgress", + "UserDisplayName": "Busch, Andrea", + "UserAccount": "AB014", + "UserDomain": "CONTOSO" + }, + { + "TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61", + "UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a", + "TileKey": "ServiceRequestsCritical", + "UseRoleScope": false, + "ActivityType": "SPSActivityTypeServiceRequest", + "DisplayName": "SRQ00001", + "Summary": "Neue Software fuer den Arbeitsplatz bereitstellen", + "StatusId": "InProgress", + "UserDisplayName": "Busch, Andrea", + "UserAccount": "AB014", + "UserDomain": "CONTOSO" + }, + { + "TicketId": "8f3ef61d-6f59-44ee-ae2e-38e7dd9d6f61", + "UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a", + "TileKey": "ServiceRequestsNewInfo", + "UseRoleScope": false, + "ActivityType": "SPSActivityTypeServiceRequest", + "DisplayName": "SRQ00001", + "Summary": "Neue Software fuer den Arbeitsplatz bereitstellen", + "StatusId": "OnHold", + "UserDisplayName": "Busch, Andrea", + "UserAccount": "AB014", + "UserDomain": "CONTOSO" + }, { "TicketId": "7e852bb9-420b-4caa-b79a-9178d793fc06", "UserId": "a2c35ad1-7cc7-4b2b-9aa5-d03fdaecd155", diff --git a/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs b/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs index f30bdfc..89c4857 100644 --- a/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs +++ b/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs @@ -62,6 +62,34 @@ namespace FasdDesktopUi.Basics.Models set { if (_incidentNewInfoSelected != value) { _incidentNewInfoSelected = value; OnPropertyChanged(nameof(IncidentNewInfoSelected)); } } } + private bool _serviceRequestsNewSelected; + public bool ServiceRequestsNewSelected + { + get => _serviceRequestsNewSelected; + set { if (_serviceRequestsNewSelected != value) { _serviceRequestsNewSelected = value; OnPropertyChanged(nameof(ServiceRequestsNewSelected)); } } + } + + private bool _serviceRequestsActiveSelected; + public bool ServiceRequestsActiveSelected + { + get => _serviceRequestsActiveSelected; + set { if (_serviceRequestsActiveSelected != value) { _serviceRequestsActiveSelected = value; OnPropertyChanged(nameof(ServiceRequestsActiveSelected)); } } + } + + private bool _serviceRequestsCriticalSelected; + public bool ServiceRequestsCriticalSelected + { + get => _serviceRequestsCriticalSelected; + set { if (_serviceRequestsCriticalSelected != value) { _serviceRequestsCriticalSelected = value; OnPropertyChanged(nameof(ServiceRequestsCriticalSelected)); } } + } + + private bool _serviceRequestsNewInfoSelected; + public bool ServiceRequestsNewInfoSelected + { + get => _serviceRequestsNewInfoSelected; + set { if (_serviceRequestsNewInfoSelected != value) { _serviceRequestsNewInfoSelected = value; OnPropertyChanged(nameof(ServiceRequestsNewInfoSelected)); } } + } + private bool _unassignedTicketsSelected; public bool UnassignedTicketsSelected { @@ -102,6 +130,18 @@ namespace FasdDesktopUi.Basics.Models private bool _incidentNewInfoHighlighted; public bool IncidentNewInfoHighlighted { get => _incidentNewInfoHighlighted; set { if (_incidentNewInfoHighlighted != value) { _incidentNewInfoHighlighted = value; OnPropertyChanged(nameof(IncidentNewInfoHighlighted)); } } } + private bool _serviceRequestsNewHighlighted; + public bool ServiceRequestsNewHighlighted { get => _serviceRequestsNewHighlighted; set { if (_serviceRequestsNewHighlighted != value) { _serviceRequestsNewHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsNewHighlighted)); } } } + + private bool _serviceRequestsActiveHighlighted; + public bool ServiceRequestsActiveHighlighted { get => _serviceRequestsActiveHighlighted; set { if (_serviceRequestsActiveHighlighted != value) { _serviceRequestsActiveHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsActiveHighlighted)); } } } + + private bool _serviceRequestsCriticalHighlighted; + public bool ServiceRequestsCriticalHighlighted { get => _serviceRequestsCriticalHighlighted; set { if (_serviceRequestsCriticalHighlighted != value) { _serviceRequestsCriticalHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsCriticalHighlighted)); } } } + + private bool _serviceRequestsNewInfoHighlighted; + public bool ServiceRequestsNewInfoHighlighted { get => _serviceRequestsNewInfoHighlighted; set { if (_serviceRequestsNewInfoHighlighted != value) { _serviceRequestsNewInfoHighlighted = value; OnPropertyChanged(nameof(ServiceRequestsNewInfoHighlighted)); } } } + private bool _unassignedTicketsHighlighted; public bool UnassignedTicketsHighlighted { get => _unassignedTicketsHighlighted; set { if (_unassignedTicketsHighlighted != value) { _unassignedTicketsHighlighted = value; OnPropertyChanged(nameof(UnassignedTicketsHighlighted)); } } } @@ -134,6 +174,18 @@ namespace FasdDesktopUi.Basics.Models private string _incidentNewInfoChangeHint; public string IncidentNewInfoChangeHint { get => _incidentNewInfoChangeHint; set { if (_incidentNewInfoChangeHint != value) { _incidentNewInfoChangeHint = value; OnPropertyChanged(nameof(IncidentNewInfoChangeHint)); } } } + private string _serviceRequestsNewChangeHint; + public string ServiceRequestsNewChangeHint { get => _serviceRequestsNewChangeHint; set { if (_serviceRequestsNewChangeHint != value) { _serviceRequestsNewChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsNewChangeHint)); } } } + + private string _serviceRequestsActiveChangeHint; + public string ServiceRequestsActiveChangeHint { get => _serviceRequestsActiveChangeHint; set { if (_serviceRequestsActiveChangeHint != value) { _serviceRequestsActiveChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsActiveChangeHint)); } } } + + private string _serviceRequestsCriticalChangeHint; + public string ServiceRequestsCriticalChangeHint { get => _serviceRequestsCriticalChangeHint; set { if (_serviceRequestsCriticalChangeHint != value) { _serviceRequestsCriticalChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsCriticalChangeHint)); } } } + + private string _serviceRequestsNewInfoChangeHint; + public string ServiceRequestsNewInfoChangeHint { get => _serviceRequestsNewInfoChangeHint; set { if (_serviceRequestsNewInfoChangeHint != value) { _serviceRequestsNewInfoChangeHint = value; OnPropertyChanged(nameof(ServiceRequestsNewInfoChangeHint)); } } } + private string _unassignedTicketsChangeHint; public string UnassignedTicketsChangeHint { get => _unassignedTicketsChangeHint; set { if (_unassignedTicketsChangeHint != value) { _unassignedTicketsChangeHint = value; OnPropertyChanged(nameof(UnassignedTicketsChangeHint)); } } } @@ -169,6 +221,19 @@ namespace FasdDesktopUi.Basics.Models private int _incidentNewInfo; public int IncidentNewInfo { get => _incidentNewInfo; set { _incidentNewInfo = value; OnPropertyChanged(nameof(IncidentNewInfo)); } } + // Service Request Properties + private int _serviceRequestsNew; + public int ServiceRequestsNew { get => _serviceRequestsNew; set { _serviceRequestsNew = value; OnPropertyChanged(nameof(ServiceRequestsNew)); } } + + private int _serviceRequestsActive; + public int ServiceRequestsActive { get => _serviceRequestsActive; set { _serviceRequestsActive = value; OnPropertyChanged(nameof(ServiceRequestsActive)); } } + + private int _serviceRequestsCritical; + public int ServiceRequestsCritical { get => _serviceRequestsCritical; set { _serviceRequestsCritical = value; OnPropertyChanged(nameof(ServiceRequestsCritical)); } } + + private int _serviceRequestsNewInfo; + public int ServiceRequestsNewInfo { get => _serviceRequestsNewInfo; set { _serviceRequestsNewInfo = value; OnPropertyChanged(nameof(ServiceRequestsNewInfo)); } } + // Unassigned Ticket Properties private int _unassignedTickets; public int UnassignedTickets { get => _unassignedTickets; set { _unassignedTickets = value; OnPropertyChanged(nameof(UnassignedTickets)); } } @@ -196,6 +261,11 @@ namespace FasdDesktopUi.Basics.Models IncidentCriticalSelected = false; IncidentNewInfoSelected = false; + ServiceRequestsNewSelected = false; + ServiceRequestsActiveSelected = false; + ServiceRequestsCriticalSelected = false; + ServiceRequestsNewInfoSelected = false; + UnassignedTicketsSelected = false; UnassignedTicketsCriticalSelected = false; } @@ -212,6 +282,11 @@ namespace FasdDesktopUi.Basics.Models IncidentCriticalHighlighted = false; IncidentNewInfoHighlighted = false; + ServiceRequestsNewHighlighted = false; + ServiceRequestsActiveHighlighted = false; + ServiceRequestsCriticalHighlighted = false; + ServiceRequestsNewInfoHighlighted = false; + UnassignedTicketsHighlighted = false; UnassignedTicketsCriticalHighlighted = false; @@ -225,6 +300,11 @@ namespace FasdDesktopUi.Basics.Models IncidentCriticalChangeHint = null; IncidentNewInfoChangeHint = null; + ServiceRequestsNewChangeHint = null; + ServiceRequestsActiveChangeHint = null; + ServiceRequestsCriticalChangeHint = null; + ServiceRequestsNewInfoChangeHint = null; + UnassignedTicketsChangeHint = null; UnassignedTicketsCriticalChangeHint = null; } diff --git a/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs b/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs index 7b46065..a43a0a4 100644 --- a/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs +++ b/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs @@ -24,6 +24,7 @@ namespace FasdDesktopUi.Basics.Services { #region Fields + private const string ServiceRequestsEnabledKey = "ServiceRequestsEnabled"; private readonly ITicketOverviewCommunicationSource _communicationSource; private static readonly string[] OverviewKeys = new[] { @@ -35,6 +36,10 @@ namespace FasdDesktopUi.Basics.Services "IncidentActive", "IncidentCritical", "IncidentNewInfo", + "ServiceRequestsNew", + "ServiceRequestsActive", + "ServiceRequestsCritical", + "ServiceRequestsNewInfo", "UnassignedTickets", "UnassignedTicketsCritical" }; @@ -53,6 +58,7 @@ namespace FasdDesktopUi.Basics.Services private bool _isDemo; private bool _initialized; private bool _isEnabled; + private bool _serviceRequestsEnabled; private readonly Random _random = new Random(); #if isDemo private readonly List _persistedDemoTickets = new List(); @@ -109,8 +115,10 @@ namespace FasdDesktopUi.Basics.Services #region Public API public event EventHandler OverviewCountsChanged; + public event EventHandler ServiceRequestsAvailabilityChanged; public IReadOnlyDictionary CurrentCounts => _currentCounts; + public bool ServiceRequestsEnabled => _serviceRequestsEnabled; public bool IsScopeInitialized(TileScope scope) { @@ -215,6 +223,8 @@ namespace FasdDesktopUi.Basics.Services { _currentCounts[key] = TileCounts.Empty; } + + UpdateServiceRequestsAvailability(false); }); } @@ -328,8 +338,12 @@ namespace FasdDesktopUi.Basics.Services _isDemo = communication.IsDemo(); - var rawCounts = await communication.GetTicketOverviewCounts(OverviewKeys, scope == TileScope.Role).ConfigureAwait(false); + var requestedKeys = scope == TileScope.Personal + ? OverviewKeys.Concat(new[] { ServiceRequestsEnabledKey }).ToArray() + : OverviewKeys; + var rawCounts = await communication.GetTicketOverviewCounts(requestedKeys, scope == TileScope.Role).ConfigureAwait(false); var counts = new Dictionary(StringComparer.OrdinalIgnoreCase); + var serviceRequestsEnabled = _isDemo; if (rawCounts != null) { @@ -338,6 +352,13 @@ namespace FasdDesktopUi.Basics.Services if (string.IsNullOrWhiteSpace(kvp.Key)) continue; + if (string.Equals(kvp.Key, ServiceRequestsEnabledKey, StringComparison.OrdinalIgnoreCase)) + { + if (scope == TileScope.Personal) + serviceRequestsEnabled = _isDemo || kvp.Value > 0; + continue; + } + counts[kvp.Key] = Math.Max(0, kvp.Value); } } @@ -345,7 +366,13 @@ namespace FasdDesktopUi.Basics.Services if (!_isEnabled) return; - await _dispatcher.InvokeAsync(() => ProcessScopeCounts(scope, counts)); + await _dispatcher.InvokeAsync(() => + { + if (scope == TileScope.Personal) + UpdateServiceRequestsAvailability(serviceRequestsEnabled); + + ProcessScopeCounts(scope, counts); + }); } catch (Exception ex) { @@ -362,6 +389,15 @@ namespace FasdDesktopUi.Basics.Services #region Count Processing + private void UpdateServiceRequestsAvailability(bool isEnabled) + { + if (_serviceRequestsEnabled == isEnabled) + return; + + _serviceRequestsEnabled = isEnabled; + ServiceRequestsAvailabilityChanged?.Invoke(this, EventArgs.Empty); + } + private void RefreshTimerIntervals() { _ = _dispatcher.InvokeAsync(() => diff --git a/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml b/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml index 0ec7989..73abb60 100644 --- a/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml +++ b/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml @@ -84,6 +84,8 @@ + @@ -269,15 +271,87 @@ HorizontalAlignment="Center" Cursor="Hand" /> - +