Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions Source/Cli/Commands/Chronicle/Workbench/views/ReadModelsView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,42 @@ public void OpenDetailOverlay(WorkbenchReadModel rm)
$"[{mut}]Queryable[/] [{queryableColor}]{(rm.IsQueryable ? "Yes" : "No")}[/]",
$"[{mut}]Identifier[/] {rm.Identifier}");

var instancesContent = BuildInstancesContent(rm);
// Open immediately with a placeholder for the Instances tab, then fetch off the UI thread so
// activating a row never blocks (or deadlocks) the render loop. The fetched content is pushed
// back into the tab editor on the UI thread once it arrives.
const string instancesTab = "Instances";
var loadingContent = OnFetchInstances is null
? $"[{mut}](No instance loader configured)[/]"
: $"[{mut}]Loading instances…[/]";

List<(string TabName, string Content)> tabs =
[
("Info", infoContent),
("Instances", instancesContent)
(instancesTab, loadingContent)
];

var overlay = new DetailOverlayWindow();
var window = overlay.Build(_windowSystem, $" {rm.ContainerName} ", tabs, []);
_windowSystem.AddWindow(window, activateWindow: true);

if (OnFetchInstances is null)
{
return;
}

var windowSystem = _windowSystem;
_ = Task.Run(async () =>
{
var content = await FetchInstancesContentAsync(rm).ConfigureAwait(false);
windowSystem.EnqueueOnUIThread(() =>
{
if (overlay.TabEditors.TryGetValue(instancesTab, out var editor))
{
// The overlay strips markup to plain text for its read-only editors.
editor.SetContent(Markup.Remove(content));
}
});
});
}

/// <inheritdoc/>
Expand Down Expand Up @@ -154,7 +179,7 @@ protected override IEnumerable<string> GetCompletions(string input) =>
/// <inheritdoc/>
protected override void OnRowActivated(WorkbenchReadModel item) => OpenDetailOverlay(item);

string BuildInstancesContent(WorkbenchReadModel rm)
async Task<string> FetchInstancesContentAsync(WorkbenchReadModel rm)
{
var mut = WorkbenchColors.Muted.ToMarkup();
var dan = WorkbenchColors.Danger.ToMarkup();
Expand All @@ -166,8 +191,8 @@ string BuildInstancesContent(WorkbenchReadModel rm)

try
{
var data = OnFetchInstances(rm.ContainerName, CancellationToken.None)
.GetAwaiter().GetResult();
var data = await OnFetchInstances(rm.ContainerName, CancellationToken.None)
.ConfigureAwait(false);

if (data.ReadModelInstancesError is not null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ namespace Cratis.Cli.Commands.Chronicle.Workbench;
/// </summary>
public class DetailOverlayWindow
{
readonly Dictionary<string, MultilineEditControl> _tabEditors = [];
Window? _window;

/// <summary>
/// Gets the read-only editors backing each tab, keyed by tab name. Lets callers update a tab's
/// content after <see cref="Build"/> (for example, when a tab is populated by an async fetch).
/// </summary>
public IReadOnlyDictionary<string, MultilineEditControl> TabEditors => _tabEditors;

/// <summary>
/// Builds a detail overlay window with the specified title, tabbed content, and action buttons.
/// </summary>
Expand Down Expand Up @@ -49,6 +56,7 @@ public Window Build(
.Build();

tabBuilder.AddTab(tabName, editor);
_tabEditors[tabName] = editor;
}

var tabControl = tabBuilder.Fill().Build();
Expand Down
Loading