Table of Contents

Session Message Panel

Session messages are partitioned by kind into three sinks on LocalProjectService (obtained via dependency injection):

The panel surfaces each sink in its own tab, so one tab holds one message kind.

Layout

  • Tab Bar
    • Shell Tab
    • NC Diagnostics Tab
    • Step Diagnostics Tab
  • Per-Tab Content
    • Message Text Filter Input
    • Message Table

Message Table (per tab)

Each tab renders its sink's message list — Messages, Diagnostics, or Messages — as rows of:

  • Severity (colour-coded via GetSeverity())
  • Anchor — the kind-specific position: the NC sentence index (Sn) for NC diagnostics, the step index for step diagnostics, none for shell messages
  • MessageGetId() and GetNotification()

Only take the last filtered elements (e.g. 500–1000) for user experience. Find the usage example in the code:

internal static void DemoUseSessionMessageHost(LocalProjectService localProjectService)
{
    // Session messages are partitioned by kind into three sinks on LocalProjectService:
    // - ShellProgress: session-level routine / lifecycle messages
    //   (session-scoped: null outside BeginSession/EndSession).
    // - NcDiagnosticProgress: NC-pipeline diagnostics, anchored to the NC source sentence.
    // - StepDiagnosticProgress: diagnostics anchored to a motion step.

    ShellProgress shellProgress = localProjectService.ShellProgress;
    List<IMessage> shellMessages = shellProgress == null
        ? new List<IMessage>() : shellProgress.Messages.ToList();
    foreach (IMessage message in shellMessages)
        Console.WriteLine(
            $"Shell [{message.GetSeverity()}] {message.GetId()}: {message.GetNotification()}");

    foreach (NcDiagnostic diagnostic in
        localProjectService.NcDiagnosticProgress.Diagnostics.ToList())
    {
        var ncLine = diagnostic.SentenceCarrier?.GetSentence()?.FirstIndexedFileLine;
        Console.WriteLine(
            $"NC [{diagnostic.GetSeverity()}] {diagnostic.GetId()}: {diagnostic.GetNotification()}; " +
            $"File: {ncLine?.FilePath}; LineNo: {ncLine?.GetLineNo()}; NC: {ncLine?.Line}");
    }

    foreach (StepDiagnostic diagnostic in
        localProjectService.StepDiagnosticProgress.Messages.ToList())
        Console.WriteLine(
            $"Step {diagnostic.StepIndex} [{diagnostic.GetSeverity()}] " +
            $"{diagnostic.GetId()}: {diagnostic.GetNotification()}");

    File.WriteAllLines("output-session-messages.txt",
        shellMessages.Select(m =>
        $"[{m.GetSeverity()}] {m.GetId()}: {m.GetNotification()}"));
}

Add the update-table event per sink: MessageAdded / MessageAdded, and for the session-scoped shell sink the app-lifetime bridge OnShellMessageAdded (with the matching Cleared events). The updating process has to be called by Loose Manner for user experience.

Tip

On window desktop application (WPF), consider use textarea instead of datagrid to MessageTable for better performance. Use padding to show the different columns. And use the font in the textarea that with consistent width.

Note

The message display should be real-time.

Behavior of Export Button

Export ALL filtered elements of the active tab's sink.

SignalR Implementation (Webapi Only)

One hub per sink — /shellMessageHub, /ncDiagnosticHub, /stepDiagnosticHub — each with a GetMessages(int limit) pull returning MessagesUpdate { messages, totalCount }. A per-sink broadcast service subscribes its sink's MessageAdded/Cleared and raises a coalesced MessagesChanged notification via LooseRunner; the client re-pulls the recent window on each notification (loss-free regardless of how many appends coalesced). The JavaScript components connect to the three hubs to receive real-time updates.

Source Code Path

See this page for git repository.

WPF Application Source Code Path

  • Play/SessionMessagePanel

Web Page Application Source Code Path

  • wwwroot-src/src/components/player/SessionMessagePanel.vue (tabbed panel)
  • wwwroot-src/src/components/player/SessionMessageTab.vue + MessageRow.vue (per-tab list)
  • wwwroot-src/src/composables/useSessionSinkHub.ts (the three hub composables)
  • Players/SessionSinkHub.cs (SignalR hubs for the three sinks)
  • Players/SessionSinkBroadcastService.cs + {Shell,Nc,Step}*BroadcastService.cs (subscribe-and-rebroadcast)
  • Players/SessionSinkDtos.cs (typed DTOs)