aktueller Stand

This commit is contained in:
Meik
2026-02-09 19:36:39 +01:00
parent 825ddf05d4
commit d6cbbe1ef1
6 changed files with 510 additions and 186 deletions

View File

@@ -35,7 +35,6 @@ namespace C4IT.FASD.Cockpit.Communication
new Dictionary<string, Dictionary<string, List<TicketOverviewRelationDefinition>>>(StringComparer.OrdinalIgnoreCase); new Dictionary<string, Dictionary<string, List<TicketOverviewRelationDefinition>>>(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<Guid> _generatedTicketIds = new HashSet<Guid>(); private readonly HashSet<Guid> _generatedTicketIds = new HashSet<Guid>();
private readonly object _demoTicketSync = new object(); private readonly object _demoTicketSync = new object();
private const string DemoTicketHasDetailsInfoKey = "Demo.HasTicketDetails";
#endregion #endregion
public cFasdCockpitCommunicationDemo() public cFasdCockpitCommunicationDemo()
@@ -47,6 +46,7 @@ namespace C4IT.FASD.Cockpit.Communication
BuildCategoryLookup(); BuildCategoryLookup();
LoadTicketOverviewRelations(); LoadTicketOverviewRelations();
LoadGeneratedTickets(); LoadGeneratedTickets();
EnsureOverviewTicketJournalEntries();
} }
public override bool IsDemo() => true; public override bool IsDemo() => true;
@@ -193,11 +193,11 @@ namespace C4IT.FASD.Cockpit.Communication
} }
} }
private void LoadGeneratedTickets() private void LoadGeneratedTickets()
{ {
try try
{ {
var records = TicketOverviewDataStore.LoadTickets(); var records = TicketOverviewDataStore.LoadTickets();
foreach (var record in records) foreach (var record in records)
{ {
AppendDemoTicket(record); AppendDemoTicket(record);
@@ -268,9 +268,112 @@ namespace C4IT.FASD.Cockpit.Communication
return; return;
var generatedTicket = ConvertToTicket(record); var generatedTicket = ConvertToTicket(record);
targetSample.Tickets.Add(generatedTicket); targetSample.Tickets.Add(generatedTicket);
} EnsureTicketHasMinimumDemoJournalEntries(generatedTicket);
} }
}
private void EnsureOverviewTicketJournalEntries()
{
try
{
var overviewTicketIds = TicketOverviewRelations.Values
.Where(scopeMap => scopeMap != null)
.SelectMany(scopeMap => scopeMap.Values)
.Where(definitions => definitions != null)
.SelectMany(definitions => definitions)
.Where(definition => definition != null && definition.TicketId != Guid.Empty)
.Select(definition => definition.TicketId)
.Distinct()
.ToList();
foreach (var ticketId in overviewTicketIds)
{
var ticket = MockupData
.FirstOrDefault(data => data != null && data.Tickets != null && data.Tickets.Any(t => t.Id == ticketId))
?.Tickets
.FirstOrDefault(t => t.Id == ticketId);
if (ticket == null)
continue;
EnsureTicketHasMinimumDemoJournalEntries(ticket);
}
}
catch (Exception E)
{
LogException(E);
}
}
private void EnsureTicketHasMinimumDemoJournalEntries(cF4SDTicket ticket)
{
if (ticket == null)
return;
if (ticket.JournalItems == null)
ticket.JournalItems = new List<cF4SDTicket.cTicketJournalItem>();
if (ticket.JournalItems.Count >= 2)
return;
bool isIncident = (ticket.Name ?? string.Empty).StartsWith("INC", StringComparison.OrdinalIgnoreCase);
var baseTime = ticket.CreationDate == default ? DateTime.Now.AddHours(-2) : ticket.CreationDate;
if (ticket.JournalItems.Count == 0)
{
ticket.JournalItems.Add(CreateDemoJournalItem(
baseTime,
isIncident ? "Incident erfasst" : "Ticket erfasst",
"Der Vorgang wurde in der Ticketuebersicht erfasst und priorisiert."));
}
if (ticket.JournalItems.Count < 2)
{
string header;
string text;
switch (ticket.Status)
{
case enumTicketStatus.InProgress:
header = "Bearbeitung aufgenommen";
text = "Der Vorgang wurde einem Bearbeiter zugeordnet und die Analyse gestartet.";
break;
case enumTicketStatus.OnHold:
header = "Warte auf Rueckmeldung";
text = "Fuer die weitere Bearbeitung werden zusaetzliche Informationen vom Anwender erwartet.";
break;
case enumTicketStatus.New:
header = "Sichtung durch Service Desk";
text = "Der Vorgang wurde gesichtet und zur Bearbeitung vorbereitet.";
break;
case enumTicketStatus.Closed:
header = "Abschluss dokumentiert";
text = "Loesung und Abschluss wurden fuer den Vorgang dokumentiert.";
break;
default:
header = "Status aktualisiert";
text = "Der aktuelle Bearbeitungsstand wurde im Vorgang aktualisiert.";
break;
}
ticket.JournalItems.Add(CreateDemoJournalItem(baseTime.AddMinutes(15), header, text));
}
}
private static cF4SDTicket.cTicketJournalItem CreateDemoJournalItem(DateTime timestamp, string header, string text)
{
var creationTime = timestamp == default ? DateTime.Now : timestamp;
return new cF4SDTicket.cTicketJournalItem
{
Header = header ?? string.Empty,
Description = text ?? string.Empty,
DescriptionHtml = $"<p>{text ?? string.Empty}</p>",
IsVisibleForUser = true,
CreationDate = creationTime,
CreationDaysSinceNow = Math.Max(0, (int)(DateTime.Now - creationTime).TotalDays)
};
}
private static cF4SDTicket ConvertToTicket(DemoTicketRecord record) private static cF4SDTicket ConvertToTicket(DemoTicketRecord record)
{ {
@@ -378,27 +481,31 @@ namespace C4IT.FASD.Cockpit.Communication
await SimulateTicketOverviewLatencyAsync(count); await SimulateTicketOverviewLatencyAsync(count);
return new List<cF4sdApiSearchResultRelation>(); return new List<cF4sdApiSearchResultRelation>();
} }
int requestedCount = count <= 0 ? definitions.Count : Math.Min(count, definitions.Count); int requestedCount = count <= 0 ? definitions.Count : Math.Min(count, definitions.Count);
await SimulateTicketOverviewLatencyAsync(requestedCount); await SimulateTicketOverviewLatencyAsync(requestedCount);
var relations = new List<cF4sdApiSearchResultRelation>(requestedCount); var relations = new List<cF4sdApiSearchResultRelation>(requestedCount);
foreach (var definition in definitions.Take(requestedCount)) foreach (var definition in definitions.Take(requestedCount))
{ {
var relation = new cF4sdApiSearchResultRelation var detailTicket = FindTicketForOverviewRelation(definition);
{ var summary = definition.Summary ?? string.Empty;
Type = enumF4sdSearchResultClass.Ticket, if (detailTicket != null && !string.IsNullOrWhiteSpace(detailTicket.Summary))
DisplayName = definition.DisplayName ?? string.Empty, summary = detailTicket.Summary;
Name = definition.DisplayName ?? string.Empty,
var relation = new cF4sdApiSearchResultRelation
{
Type = enumF4sdSearchResultClass.Ticket,
DisplayName = definition.DisplayName ?? string.Empty,
Name = definition.DisplayName ?? string.Empty,
id = definition.TicketId, id = definition.TicketId,
Status = enumF4sdSearchResultStatus.Active, Status = enumF4sdSearchResultStatus.Active,
Infos = new Dictionary<string, string> Infos = new Dictionary<string, string>
{ {
["Summary"] = definition.Summary ?? string.Empty, ["Summary"] = summary,
["StatusId"] = definition.StatusId ?? string.Empty, ["StatusId"] = definition.StatusId ?? string.Empty,
["UserDisplayName"] = definition.UserDisplayName ?? string.Empty, ["UserDisplayName"] = definition.UserDisplayName ?? string.Empty,
["UserAccount"] = definition.UserAccount ?? string.Empty, ["UserAccount"] = definition.UserAccount ?? string.Empty,
["UserDomain"] = definition.UserDomain ?? string.Empty, ["UserDomain"] = definition.UserDomain ?? string.Empty
[DemoTicketHasDetailsInfoKey] = HasTicketDetails(definition.TicketId).ToString() },
},
Identities = new cF4sdIdentityList Identities = new cF4sdIdentityList
{ {
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = definition.TicketId }, new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = definition.TicketId },
@@ -416,32 +523,40 @@ namespace C4IT.FASD.Cockpit.Communication
} }
finally finally
{ {
LogMethodEnd(CM); LogMethodEnd(CM);
} }
} }
private bool HasTicketDetails(Guid ticketId) private cF4SDTicket FindTicketForOverviewRelation(TicketOverviewRelationDefinition definition)
{ {
if (ticketId == Guid.Empty) if (definition == null || definition.TicketId == Guid.Empty)
return false; return null;
foreach (var sample in MockupData) cF4SDTicket selectedTicket = null;
{
var tickets = sample?.Tickets; if (definition.UserId != Guid.Empty)
if (tickets == null) {
continue; var selectedData = MockupData.FirstOrDefault(data => data.SampleDataId == definition.UserId);
if (selectedData != null && selectedData.Tickets != null)
foreach (var ticket in tickets) selectedTicket = selectedData.Tickets.FirstOrDefault(ticket => ticket.Id == definition.TicketId);
{ }
if (ticket?.Id == ticketId)
return true; if (selectedTicket != null)
} return selectedTicket;
}
var fallbackData = MockupData.FirstOrDefault(data =>
return false; data != null &&
} data.Tickets != null &&
private static Task SimulateTicketOverviewLatencyAsync(int count) data.Tickets.Any(ticket => ticket.Id == definition.TicketId));
{
if (fallbackData == null || fallbackData.Tickets == null)
return null;
return fallbackData.Tickets.FirstOrDefault(ticket => ticket.Id == definition.TicketId);
}
private static Task SimulateTicketOverviewLatencyAsync(int count)
{
int baseMs = 420; int baseMs = 420;
int perItem = 100; int perItem = 100;
int capped = Math.Max(0, Math.Min(count, 5)); int capped = Math.Max(0, Math.Min(count, 5));
@@ -714,21 +829,115 @@ namespace C4IT.FASD.Cockpit.Communication
return output; return output;
} }
public override async Task<cFasdApiSearchResultCollection> GetUserSearchResults(string Name, List<string> SIDs) public override async Task<cFasdApiSearchResultCollection> GetUserSearchResults(string Name, List<string> SIDs)
{ {
var output = new cFasdApiSearchResultCollection(); var output = new cFasdApiSearchResultCollection();
try try
{ {
foreach (var data in MockupData) bool IsNameMatch(string sourceName, string requestName)
{ {
if (data.SampleDataName.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) if (string.IsNullOrWhiteSpace(sourceName) || string.IsNullOrWhiteSpace(requestName))
{ return false;
//todo: add a field in demo data
var searchResultClass = enumF4sdSearchResultClass.User; if (sourceName.Equals(requestName, StringComparison.InvariantCultureIgnoreCase))
output[data.SampleDataName] = new List<cFasdApiSearchResultEntry>() { new cFasdApiSearchResultEntry() { id = data.SampleDataId, Name = data.SampleDataName, DisplayName = data.SampleDataName, Type = searchResultClass } }; return true;
}
} string Normalize(string value)
{
return string.Join(" ", (value ?? string.Empty)
.ToLowerInvariant()
.Replace(",", " ")
.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
}
int LevenshteinDistance(string left, string right)
{
if (string.IsNullOrEmpty(left))
return right?.Length ?? 0;
if (string.IsNullOrEmpty(right))
return left.Length;
int[] previous = new int[right.Length + 1];
int[] current = new int[right.Length + 1];
for (int j = 0; j <= right.Length; j++)
previous[j] = j;
for (int i = 1; i <= left.Length; i++)
{
current[0] = i;
for (int j = 1; j <= right.Length; j++)
{
int cost = left[i - 1] == right[j - 1] ? 0 : 1;
current[j] = Math.Min(
Math.Min(current[j - 1] + 1, previous[j] + 1),
previous[j - 1] + cost);
}
var temp = previous;
previous = current;
current = temp;
}
return previous[right.Length];
}
bool IsTokenMatch(string leftToken, string rightToken)
{
if (leftToken == rightToken)
return true;
int sharedLength = Math.Min(Math.Min(leftToken.Length, rightToken.Length), 5);
if (sharedLength >= 4 && leftToken.Substring(0, sharedLength) == rightToken.Substring(0, sharedLength))
return true;
return LevenshteinDistance(leftToken, rightToken) <= 2;
}
var normalizedSource = Normalize(sourceName);
var normalizedRequest = Normalize(requestName);
if (normalizedSource == normalizedRequest)
return true;
var sourceTokens = normalizedSource.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
var requestTokens = normalizedRequest.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
if (sourceTokens.Count == 0 || requestTokens.Count == 0 || sourceTokens.Count != requestTokens.Count)
return false;
var remaining = new List<string>(sourceTokens);
foreach (var token in requestTokens)
{
int index = remaining.FindIndex(candidate => IsTokenMatch(candidate, token));
if (index < 0)
return false;
remaining.RemoveAt(index);
}
return remaining.Count == 0;
}
foreach (var data in MockupData)
{
if (!IsNameMatch(data.SampleDataName, Name))
continue;
//todo: add a field in demo data
var searchResultClass = enumF4sdSearchResultClass.User;
if (!output.ContainsKey(data.SampleDataName))
{
output[data.SampleDataName] = new List<cFasdApiSearchResultEntry>()
{
new cFasdApiSearchResultEntry()
{
id = data.SampleDataId,
Name = data.SampleDataName,
DisplayName = data.SampleDataName,
Type = searchResultClass
}
};
}
}
await Task.CompletedTask; await Task.CompletedTask;
} }
catch (Exception E) catch (Exception E)
@@ -758,8 +967,8 @@ namespace C4IT.FASD.Cockpit.Communication
var output = new List<cF4sdApiSearchResultRelation>(); var output = new List<cF4sdApiSearchResultRelation>();
switch (resultIds.First().ToString()) switch (resultIds.First().ToString())
{ {
case constGuidOlliOffline: // Olli Offline case constGuidOlliOffline: // Olli Offline
output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4-NB005", DisplayName = "C4-NB005", Infos = new Dictionary<string, string>() { ["UserAccountType"] = "AD", ["UserAccount"] = "C4-NB005", ["UserDomain"] = "C4IT" }, LastUsed = DateTime.UtcNow.AddDays(-10), Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.Parse(constGuidOlliOffline) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } }); output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4-NB005", DisplayName = "C4-NB005", Infos = new Dictionary<string, string>() { ["UserAccountType"] = "AD", ["UserAccount"] = "C4-NB005", ["UserDomain"] = "C4IT" }, LastUsed = DateTime.UtcNow.AddDays(-10), Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.Parse(constGuidOlliOffline) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } });
@@ -930,18 +1139,67 @@ namespace C4IT.FASD.Cockpit.Communication
case constGuidComputer: // Computer case constGuidComputer: // Computer
break; break;
default: default:
output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4IT-007", DisplayName = "C4IT-007", LastUsed = DateTime.UtcNow, Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = resultIds.First() }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } }); output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4IT-007", DisplayName = "C4IT-007", LastUsed = DateTime.UtcNow, Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = resultIds.First() }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } });
break; break;
} }
await Task.CompletedTask; if (resultType == enumF4sdSearchResultClass.User)
{
output = output.OrderByDescending(relation => relation.LastUsed).ToList(); foreach (var userId in resultIds)
return output; {
} AppendDemoTicketRelationsForUser(userId, output);
}
public override async Task<cF4SDHealthCardRawData> GetHealthCardData(cF4sdHealthCardRawDataRequest requestData) }
{
await Task.CompletedTask;
output = output.OrderByDescending(relation => relation.LastUsed).ToList();
return output;
}
private void AppendDemoTicketRelationsForUser(Guid userId, List<cF4sdApiSearchResultRelation> output)
{
if (userId == Guid.Empty || output == null)
return;
var selectedData = MockupData.FirstOrDefault(data => data?.SampleDataId == userId);
if (selectedData?.Tickets == null)
return;
foreach (var demoTicket in selectedData.Tickets)
{
if (demoTicket == null || demoTicket.Id == Guid.Empty)
continue;
if (output.Any(relation => relation.Type == enumF4sdSearchResultClass.Ticket && relation.id == demoTicket.Id))
continue;
output.Add(new cF4sdApiSearchResultRelation()
{
id = demoTicket.Id,
Name = demoTicket.Name,
DisplayName = demoTicket.Name,
LastUsed = demoTicket.CreationDate == default ? DateTime.UtcNow : demoTicket.CreationDate.ToUniversalTime(),
Type = enumF4sdSearchResultClass.Ticket,
UsingLevel = 1,
Infos = new Dictionary<string, string>()
{
["Summary"] = demoTicket.Summary ?? string.Empty,
["Status"] = demoTicket.Status.ToString(),
["StatusId"] = ((int)demoTicket.Status).ToString(),
["Asset"] = demoTicket.Asset ?? string.Empty
},
Identities = new cF4sdIdentityList()
{
new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = userId },
new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Ticket, Id = demoTicket.Id }
}
});
}
}
public override async Task<cF4SDHealthCardRawData> GetHealthCardData(cF4sdHealthCardRawDataRequest requestData)
{
var CM = MethodBase.GetCurrentMethod(); var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM); LogMethodBegin(CM);
@@ -968,14 +1226,29 @@ namespace C4IT.FASD.Cockpit.Communication
if (selectedData is null) if (selectedData is null)
return output; return output;
output = selectedData.GetHealthCardData(); output = selectedData.GetHealthCardData();
var ticketRequest = requestData.Identities.FirstOrDefault(data => data.Class is enumFasdInformationClass.Ticket); var ticketRequest = requestData.Identities.FirstOrDefault(data => data.Class is enumFasdInformationClass.Ticket);
if (ticketRequest != null) if (ticketRequest != null)
{ {
var selectedTicket = selectedData.Tickets.FirstOrDefault(ticket => ticket.Id == ticketRequest.Id); var selectedTicket = selectedData.Tickets.FirstOrDefault(ticket => ticket.Id == ticketRequest.Id);
if (selectedTicket != null)
{ // Some demo users share the same SampleDataId; resolve by TicketId if the first user match has no ticket details.
string ticketStatusString = string.Empty; if (selectedTicket == null)
{
var fallbackData = MockupData.FirstOrDefault(data =>
data?.Tickets != null && data.Tickets.Any(ticket => ticket?.Id == ticketRequest.Id));
if (fallbackData != null)
{
selectedData = fallbackData;
output = selectedData.GetHealthCardData();
selectedTicket = selectedData.Tickets.FirstOrDefault(ticket => ticket.Id == ticketRequest.Id);
}
}
if (selectedTicket != null)
{
string ticketStatusString = string.Empty;
switch (selectedTicket.Status) switch (selectedTicket.Status)
{ {
case enumTicketStatus.Unknown: case enumTicketStatus.Unknown:

View File

@@ -108,9 +108,6 @@
] ]
} }
}, },
/* --- Ab hier: 5 neue Klassiker --- */
{ {
"TileKey": "TicketsNew", "TileKey": "TicketsNew",
"UseRoleScope": false, "UseRoleScope": false,
@@ -247,5 +244,118 @@
} }
} }
], ],
"Tickets": [] "Tickets": [
{
"TicketId": "e2e49f85-1a81-47e8-935b-d76898c155f6",
"UserId": "916db36b-fb6e-4212-81c1-e72acdab77d2",
"TileKey": "UnassignedTickets",
"UseRoleScope": false,
"DisplayName": "TCK00414",
"Summary": "Pool Notebook fuer Schulungsteilnehmer fehlt",
"StatusId": "New",
"UserDisplayName": "Virtual, Vera",
"UserAccount": "VV004",
"UserDomain": "CONTOSO",
"Detail": {
"AffectedUser": "Virtual, Vera",
"Asset": "C4-NB02014",
"Category": "42b49002-fed3-4c9b-9532-cf351df038cf",
"Description": "Ein Pool-Notebook fuer die morgige Schulung ist nicht auffindbar. Das Ticket wurde noch keinem Bearbeiter zugewiesen.",
"DescriptionHtml": "<p>Ein Pool-Notebook fuer die morgige Schulung ist nicht auffindbar. Das Ticket wurde noch keinem Bearbeiter zugewiesen.</p>",
"Priority": 2,
"Journal": [
{
"Header": "Ticket erstellt",
"Description": "Demodatensatz fuer Ticketuebersicht (Eingang).",
"DescriptionHtml": "<p>Demodatensatz fuer Ticketuebersicht (Eingang).</p>",
"IsVisibleForUser": true
}
]
}
},
{
"TicketId": "ebe8818e-b197-411e-b56e-40b77b623ae2",
"UserId": "436e8d67-1b9b-4b1a-83e9-0b1e8fa0173b",
"TileKey": "UnassignedTickets",
"UseRoleScope": false,
"DisplayName": "TCK00415",
"Summary": "Etikettendrucker im Lager meldet Papierstau",
"StatusId": "New",
"UserDisplayName": "Anwender, Peter",
"UserAccount": "PA010",
"UserDomain": "CONTOSO",
"Detail": {
"AffectedUser": "Anwender, Peter",
"Asset": "PRN-LAGER-03",
"Category": "42b49002-fed3-4c9b-9532-cf351df038cf",
"Description": "Der Etikettendrucker im Lager zeigt permanent Papierstau, obwohl kein Papier klemmt. Ticket ist neu und noch unzugewiesen.",
"DescriptionHtml": "<p>Der Etikettendrucker im Lager zeigt permanent Papierstau, obwohl kein Papier klemmt. Ticket ist neu und noch unzugewiesen.</p>",
"Priority": 2,
"Journal": [
{
"Header": "Ticket erstellt",
"Description": "Demodatensatz fuer Ticketuebersicht (Eingang).",
"DescriptionHtml": "<p>Demodatensatz fuer Ticketuebersicht (Eingang).</p>",
"IsVisibleForUser": true
}
]
}
},
{
"TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab",
"UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec",
"TileKey": "UnassignedTicketsCritical",
"UseRoleScope": false,
"DisplayName": "TCK00416",
"Summary": "WLAN Controller im Werk startet zyklisch neu",
"StatusId": "InProgress",
"UserDisplayName": "Seifert, Dominik",
"UserAccount": "DS014",
"UserDomain": "CONTOSO",
"Detail": {
"AffectedUser": "Seifert, Dominik",
"Asset": "NET-WLC-01",
"Category": "42b49002-fed3-4c9b-9532-cf351df038cf",
"Description": "Der WLAN-Controller im Werk rebootet im 5-Minuten-Takt. Das Ticket ist kritisch markiert und noch nicht personell zugewiesen.",
"DescriptionHtml": "<p>Der WLAN-Controller im Werk rebootet im 5-Minuten-Takt. Das Ticket ist kritisch markiert und noch nicht personell zugewiesen.</p>",
"Priority": 1,
"Journal": [
{
"Header": "Stoerung eingegangen",
"Description": "Demodatensatz fuer Ticketuebersicht (Eingang Kritisch).",
"DescriptionHtml": "<p>Demodatensatz fuer Ticketuebersicht (Eingang Kritisch).</p>",
"IsVisibleForUser": true
}
]
}
},
{
"TicketId": "d427dc61-9842-4464-b37a-612878d3de0f",
"UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a",
"TileKey": "UnassignedTicketsCritical",
"UseRoleScope": false,
"DisplayName": "TCK00417",
"Summary": "SAP Buchungsjob bricht nachts wiederholt ab",
"StatusId": "InProgress",
"UserDisplayName": "Boss, Bernd",
"UserAccount": "BB003",
"UserDomain": "CONTOSO",
"Detail": {
"AffectedUser": "Boss, Bernd",
"Asset": "SAP-PRD-APP02",
"Category": "42b49002-fed3-4c9b-9532-cf351df038cf",
"Description": "Naechtlicher Buchungsjob endet mit Fehlercode. Ticket ist kritisch und liegt im Eingang zur Erstzuweisung.",
"DescriptionHtml": "<p>Naechtlicher Buchungsjob endet mit Fehlercode. Ticket ist kritisch und liegt im Eingang zur Erstzuweisung.</p>",
"Priority": 1,
"Journal": [
{
"Header": "Stoerung eingegangen",
"Description": "Demodatensatz fuer Ticketuebersicht (Eingang Kritisch).",
"DescriptionHtml": "<p>Demodatensatz fuer Ticketuebersicht (Eingang Kritisch).</p>",
"IsVisibleForUser": true
}
]
}
}
]
} }

View File

@@ -73,7 +73,7 @@
"TicketId": "2e9cb83d-ecb7-c93b-e8e4-08daaa97265f", "TicketId": "2e9cb83d-ecb7-c93b-e8e4-08daaa97265f",
"UserId": "42c760d6-90e8-469f-b2fe-ac7d4cc6cb0a", "UserId": "42c760d6-90e8-469f-b2fe-ac7d4cc6cb0a",
"DisplayName": "TCK00405", "DisplayName": "TCK00405",
"Summary": "OneDrive Synchronisation bleibt haengen", "Summary": "Mein OneDrive synchronisiert nicht mehr",
"UserDisplayName": "Ticket, Timo", "UserDisplayName": "Ticket, Timo",
"UserAccount": "TT007", "UserAccount": "TT007",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",
@@ -153,7 +153,7 @@
"TicketId": "de403992-98cb-4476-9e04-d645ab22e6de", "TicketId": "de403992-98cb-4476-9e04-d645ab22e6de",
"UserId": "42c760d6-90e8-469f-b2fe-ac7d4cc6cb0a", "UserId": "42c760d6-90e8-469f-b2fe-ac7d4cc6cb0a",
"DisplayName": "TCK00411", "DisplayName": "TCK00411",
"Summary": "Rueckfrage zur Passwort Ruecksetzung beantworten", "Summary": "Passwort muss zur\u00fcckgesetzt werden",
"UserDisplayName": "Ticket, Timo", "UserDisplayName": "Ticket, Timo",
"UserAccount": "TT007", "UserAccount": "TT007",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",
@@ -175,7 +175,7 @@
"TicketId": "de403992-98cb-4476-9e04-d645ab22e6de", "TicketId": "de403992-98cb-4476-9e04-d645ab22e6de",
"UserId": "42c760d6-90e8-469f-b2fe-ac7d4cc6cb0a", "UserId": "42c760d6-90e8-469f-b2fe-ac7d4cc6cb0a",
"DisplayName": "TCK00411", "DisplayName": "TCK00411",
"Summary": "Rueckfrage zur Passwort Ruecksetzung beantworten", "Summary": "Passwort muss zur\u00fcckgesetzt werden",
"UserDisplayName": "Ticket, Timo", "UserDisplayName": "Ticket, Timo",
"UserAccount": "TT007", "UserAccount": "TT007",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",
@@ -207,7 +207,7 @@
}, },
{ {
"TicketId": "a8deb50d-9f15-4371-9ebc-a28791f27d5c", "TicketId": "a8deb50d-9f15-4371-9ebc-a28791f27d5c",
"UserId": "76f86d28-862c-4fa2-9062-8367be7fbd92", "UserId": "916db36b-fb6e-4212-81c1-e72acdab77d2",
"DisplayName": "INC00402", "DisplayName": "INC00402",
"Summary": "SharePoint Bereich Vertrieb laedt extrem langsam", "Summary": "SharePoint Bereich Vertrieb laedt extrem langsam",
"UserDisplayName": "Virtual, Vera", "UserDisplayName": "Virtual, Vera",
@@ -381,7 +381,7 @@
"Personal": [ "Personal": [
{ {
"TicketId": "e2e49f85-1a81-47e8-935b-d76898c155f6", "TicketId": "e2e49f85-1a81-47e8-935b-d76898c155f6",
"UserId": "76f86d28-862c-4fa2-9062-8367be7fbd92", "UserId": "916db36b-fb6e-4212-81c1-e72acdab77d2",
"DisplayName": "TCK00414", "DisplayName": "TCK00414",
"Summary": "Pool Notebook fuer Schulungsteilnehmer fehlt", "Summary": "Pool Notebook fuer Schulungsteilnehmer fehlt",
"UserDisplayName": "Virtual, Vera", "UserDisplayName": "Virtual, Vera",
@@ -403,7 +403,7 @@
"Role": [ "Role": [
{ {
"TicketId": "e2e49f85-1a81-47e8-935b-d76898c155f6", "TicketId": "e2e49f85-1a81-47e8-935b-d76898c155f6",
"UserId": "76f86d28-862c-4fa2-9062-8367be7fbd92", "UserId": "916db36b-fb6e-4212-81c1-e72acdab77d2",
"DisplayName": "TCK00414", "DisplayName": "TCK00414",
"Summary": "Pool Notebook fuer Schulungsteilnehmer fehlt", "Summary": "Pool Notebook fuer Schulungsteilnehmer fehlt",
"UserDisplayName": "Virtual, Vera", "UserDisplayName": "Virtual, Vera",
@@ -425,7 +425,7 @@
"TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab", "TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab",
"UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec", "UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec",
"DisplayName": "TCK00416", "DisplayName": "TCK00416",
"Summary": "Ueberwachung meldet sporadische Alarme", "Summary": "WLAN Controller im Werk startet zyklisch neu",
"UserDisplayName": "Seifert, Dominik", "UserDisplayName": "Seifert, Dominik",
"UserAccount": "DS014", "UserAccount": "DS014",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",
@@ -439,7 +439,7 @@
"TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab", "TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab",
"UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec", "UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec",
"DisplayName": "TCK00416", "DisplayName": "TCK00416",
"Summary": "Ueberwachung meldet sporadische Alarme", "Summary": "WLAN Controller im Werk startet zyklisch neu",
"UserDisplayName": "Seifert, Dominik", "UserDisplayName": "Seifert, Dominik",
"UserAccount": "DS014", "UserAccount": "DS014",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",
@@ -451,7 +451,7 @@
"TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab", "TicketId": "9e1d5d1b-5a22-430e-99ea-59840257caab",
"UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec", "UserId": "deece196-d8b6-4a9c-a2b9-3c2ae9c6d4ec",
"DisplayName": "TCK00416", "DisplayName": "TCK00416",
"Summary": "Ueberwachung meldet sporadische Alarme", "Summary": "WLAN Controller im Werk startet zyklisch neu",
"UserDisplayName": "Seifert, Dominik", "UserDisplayName": "Seifert, Dominik",
"UserAccount": "DS014", "UserAccount": "DS014",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",
@@ -461,7 +461,7 @@
"TicketId": "d427dc61-9842-4464-b37a-612878d3de0f", "TicketId": "d427dc61-9842-4464-b37a-612878d3de0f",
"UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a", "UserId": "a2164ecd-791f-482c-bea3-f089f14bec8a",
"DisplayName": "TCK00417", "DisplayName": "TCK00417",
"Summary": "Produktionsroboter steht nach Not Aus", "Summary": "SAP Buchungsjob bricht nachts wiederholt ab",
"UserDisplayName": "Boss, Bernd", "UserDisplayName": "Boss, Bernd",
"UserAccount": "BB003", "UserAccount": "BB003",
"UserDomain": "CONTOSO", "UserDomain": "CONTOSO",

View File

@@ -33,7 +33,6 @@ namespace FasdDesktopUi.Basics.Services
"UnassignedTickets", "UnassignedTickets",
"UnassignedTicketsCritical" "UnassignedTicketsCritical"
}; };
private const string DemoTicketDetailsKey = "Demo.HasTicketDetails";
private readonly Dispatcher _dispatcher; private readonly Dispatcher _dispatcher;
private readonly Dictionary<string, TileCounts> _currentCounts = new Dictionary<string, TileCounts>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, TileCounts> _currentCounts = new Dictionary<string, TileCounts>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<(string Key, bool UseRoleScope), List<cF4sdApiSearchResultRelation>> _demoRelations = new Dictionary<(string, bool), List<cF4sdApiSearchResultRelation>>(); private readonly Dictionary<(string Key, bool UseRoleScope), List<cF4sdApiSearchResultRelation>> _demoRelations = new Dictionary<(string, bool), List<cF4sdApiSearchResultRelation>>();
@@ -317,18 +316,6 @@ namespace FasdDesktopUi.Basics.Services
} }
} }
if (_isDemo)
{
foreach (var key in OverviewKeys)
{
var extras = GetDemoRelationCount(key, scope == TileScope.Role);
if (counts.ContainsKey(key))
counts[key] += extras;
else
counts[key] = extras;
}
}
if (!_isEnabled) if (!_isEnabled)
return; return;
@@ -560,15 +547,14 @@ namespace FasdDesktopUi.Basics.Services
Name = record.DisplayName, Name = record.DisplayName,
id = record.TicketId, id = record.TicketId,
Status = enumF4sdSearchResultStatus.Active, Status = enumF4sdSearchResultStatus.Active,
Infos = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) Infos = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
["Summary"] = record.Summary ?? string.Empty, ["Summary"] = record.Summary ?? string.Empty,
["StatusId"] = record.StatusId ?? string.Empty, ["StatusId"] = record.StatusId ?? string.Empty,
["UserDisplayName"] = record.UserDisplayName ?? string.Empty, ["UserDisplayName"] = record.UserDisplayName ?? string.Empty,
["UserAccount"] = record.UserAccount ?? string.Empty, ["UserAccount"] = record.UserAccount ?? string.Empty,
["UserDomain"] = record.UserDomain ?? string.Empty, ["UserDomain"] = record.UserDomain ?? string.Empty
[DemoTicketDetailsKey] = bool.TrueString },
},
Identities = new cF4sdIdentityList Identities = new cF4sdIdentityList
{ {
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = record.TicketId }, new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = record.TicketId },

View File

@@ -473,12 +473,7 @@
<Language Lang="DE">Geschlossen</Language> <Language Lang="DE">Geschlossen</Language>
</UIItem> </UIItem>
<UIItem Name="Searchbar.Demo.NoTicketDetails"> <UIItem Name="TicketOverview.Notification.Title">
<Language Lang="EN">No demo ticket details available</Language>
<Language Lang="DE">Keine Demo-Ticketdetails verfügbar</Language>
</UIItem>
<UIItem Name="TicketOverview.Notification.Title">
<Language Lang="EN">Ticket overview updated</Language> <Language Lang="EN">Ticket overview updated</Language>
<Language Lang="DE">Ticketübersicht aktualisiert</Language> <Language Lang="DE">Ticketübersicht aktualisiert</Language>
</UIItem> </UIItem>

View File

@@ -47,7 +47,6 @@ namespace FasdDesktopUi.Pages.SearchPage
private EventHandler _ticketOverviewAutoContinueCaseChangedHandler; private EventHandler _ticketOverviewAutoContinueCaseChangedHandler;
private bool _renderTicketOverviewUserNames = false; private bool _renderTicketOverviewUserNames = false;
private readonly HashSet<cSearchHistorySearchResultEntry> _ticketOverviewHistoryEntries = new HashSet<cSearchHistorySearchResultEntry>(); private readonly HashSet<cSearchHistorySearchResultEntry> _ticketOverviewHistoryEntries = new HashSet<cSearchHistorySearchResultEntry>();
private const string DemoTicketHasDetailsInfoKey = "Demo.HasTicketDetails";
// Event zum auslösen wenn Toggle geändert wird // Event zum auslösen wenn Toggle geändert wird
public event EventHandler<bool> FilterToggleCheckedChanged; public event EventHandler<bool> FilterToggleCheckedChanged;
@@ -216,15 +215,10 @@ namespace FasdDesktopUi.Pages.SearchPage
bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(requiredInformationClasses); bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(requiredInformationClasses);
string disabledReason = null; string disabledReason = null;
if (!isEnabled) if (!isEnabled)
{ {
disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty; disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty;
} }
else if (ShouldDisableTicketRelationForDemo(relation))
{
isEnabled = false;
disabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty;
}
string trailingText = null; string trailingText = null;
if (_renderTicketOverviewUserNames && relation.Infos != null && relation.Infos.TryGetValue("UserDisplayName", out var relationUserDisplayName)) if (_renderTicketOverviewUserNames && relation.Infos != null && relation.Infos.TryGetValue("UserDisplayName", out var relationUserDisplayName))
{ {
@@ -268,15 +262,10 @@ namespace FasdDesktopUi.Pages.SearchPage
{ {
var required = new List<enumFasdInformationClass> { cF4sdIdentityEntry.GetFromSearchResult(relation.Type) }; var required = new List<enumFasdInformationClass> { cF4sdIdentityEntry.GetFromSearchResult(relation.Type) };
fallbackIsEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required); fallbackIsEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required);
if (!fallbackIsEnabled) if (!fallbackIsEnabled)
{ {
fallbackDisabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty; fallbackDisabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty;
} }
else if (ShouldDisableTicketRelationForDemo(relation))
{
fallbackIsEnabled = false;
fallbackDisabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty;
}
} }
catch catch
{ {
@@ -1470,15 +1459,10 @@ namespace FasdDesktopUi.Pages.SearchPage
var required = new List<enumFasdInformationClass> { cF4sdIdentityEntry.GetFromSearchResult(r.Type) }; var required = new List<enumFasdInformationClass> { cF4sdIdentityEntry.GetFromSearchResult(r.Type) };
bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required); bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required);
string disabledReason = null; string disabledReason = null;
if (!isEnabled) if (!isEnabled)
{ {
disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty; disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty;
} }
else if (ShouldDisableTicketRelationForDemo(r))
{
isEnabled = false;
disabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty;
}
string trailingUser = null; string trailingUser = null;
if (_renderTicketOverviewUserNames && r.Infos != null && r.Infos.TryGetValue("UserDisplayName", out var userDisplayName)) if (_renderTicketOverviewUserNames && r.Infos != null && r.Infos.TryGetValue("UserDisplayName", out var userDisplayName))
{ {
@@ -1574,30 +1558,6 @@ namespace FasdDesktopUi.Pages.SearchPage
return "Searchbar.Header.Filter.Overview"; return "Searchbar.Header.Filter.Overview";
} }
private bool ShouldDisableTicketRelationForDemo(cF4sdApiSearchResultRelation relation)
{
if (relation == null)
return false;
var communication = cFasdCockpitCommunicationBase.Instance;
if (communication?.IsDemo() != true)
return false;
if (relation.Type != enumF4sdSearchResultClass.Ticket)
return false;
if (relation.Infos == null)
return false;
if (!relation.Infos.TryGetValue(DemoTicketHasDetailsInfoKey, out var hasDetailsValue))
return false;
if (bool.TryParse(hasDetailsValue, out var hasDetails))
return !hasDetails;
return true;
}
private async Task<List<cF4sdApiSearchResultRelation>> LoadRelationsForTileAsync(string key, bool useRoleScope, int count) private async Task<List<cF4sdApiSearchResultRelation>> LoadRelationsForTileAsync(string key, bool useRoleScope, int count)
{ {
var communication = cFasdCockpitCommunicationBase.Instance; var communication = cFasdCockpitCommunicationBase.Instance;