fc3178cca8
/fleet/diagnostics was reachable only by URL: each driver-role row on /fleet now links to it (FleetDiagnosticsLinks.For escapes the host:port node id). The diagnostics table showed the string instance id because the wire carries no display name; the page now joins the authored DriverInstances.Name from the ConfigDb (enrichment only - a failed lookup falls back to the id) and keeps the id beneath the name. Refs #745 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
47 lines
2.3 KiB
C#
47 lines
2.3 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Clients;
|
|
|
|
/// <summary>
|
|
/// Helpers for the per-node diagnostics page (A-F4 / A-F5). <c>/fleet/diagnostics</c> was reachable only
|
|
/// by URL; <c>/fleet</c> now links each driver node's row to it. The page also showed the driver's
|
|
/// string instance id where the operator expects its authored name — the diagnostics wire carries only
|
|
/// the id (<c>DriverInstanceDiagnostics.Name</c>), so the AdminUI joins the name from the ConfigDb.
|
|
/// </summary>
|
|
public static class FleetDiagnosticsLinks
|
|
{
|
|
/// <summary>The diagnostics page route.</summary>
|
|
public const string PagePath = "/fleet/diagnostics";
|
|
|
|
/// <summary>The diagnostics URL for one node.</summary>
|
|
/// <param name="nodeId">The node id as <c>/fleet</c> shows it (<c>host:port</c>).</param>
|
|
/// <returns>A relative URL with the node escaped.</returns>
|
|
public static string For(string nodeId) => PagePath + "?node=" + Uri.EscapeDataString(nodeId);
|
|
|
|
/// <summary>Loads the authored display names of the given driver instance ids.</summary>
|
|
/// <param name="db">The config DB context.</param>
|
|
/// <param name="driverInstanceIds">The string driver instance ids from the snapshot.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>Id → authored name (ordinal-ignore-case keys); ids with no configured row are absent.</returns>
|
|
public static async Task<IReadOnlyDictionary<string, string>> LoadDisplayNamesAsync(
|
|
OtOpcUaConfigDbContext db, IReadOnlyCollection<string> driverInstanceIds, CancellationToken ct = default)
|
|
{
|
|
if (driverInstanceIds.Count == 0) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
var ids = driverInstanceIds.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
|
var rows = await db.DriverInstances.AsNoTracking()
|
|
.Where(d => ids.Contains(d.DriverInstanceId))
|
|
.Select(d => new { d.DriverInstanceId, d.Name })
|
|
.ToListAsync(ct);
|
|
|
|
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
foreach (var r in rows)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(r.Name)) map[r.DriverInstanceId] = r.Name;
|
|
}
|
|
|
|
return map;
|
|
}
|
|
}
|