-
Notifications
You must be signed in to change notification settings - Fork 850
Add command result support for resource commands #15622
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,13 +59,22 @@ public static async Task<int> ExecuteGenericCommandAsync( | |
| { | ||
| logger.LogDebug("Executing command '{CommandName}' on resource '{ResourceName}'", commandName, resourceName); | ||
|
|
||
| // Route status messages to stderr so command results can be piped (e.g., | jq) | ||
| interactionService.Console = ConsoleOutput.Error; | ||
|
|
||
| var response = await interactionService.ShowStatusAsync( | ||
| $"Executing command '{commandName}' on resource '{resourceName}'...", | ||
| async () => await connection.ExecuteResourceCommandAsync(resourceName, commandName, cancellationToken)); | ||
|
|
||
| if (response.Success) | ||
| { | ||
| interactionService.DisplaySuccess($"Command '{commandName}' executed successfully on resource '{resourceName}'."); | ||
|
|
||
| if (response.Result is not null) | ||
| { | ||
| interactionService.DisplayRawText(response.Result, ConsoleOutput.Standard); | ||
| } | ||
|
Comment on lines
+74
to
+76
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This result handling only exists in |
||
|
|
||
| return ExitCodeConstants.Success; | ||
| } | ||
| else if (response.Canceled) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,9 +74,19 @@ public override async ValueTask<CallToolResult> CallToolAsync(CallToolContext co | |
|
|
||
| if (response.Success) | ||
| { | ||
| var content = new List<TextContentBlock> | ||
| { | ||
| new() { Text = $"Command '{commandName}' executed successfully on resource '{resourceName}'." } | ||
| }; | ||
|
|
||
| if (response.Result is not null) | ||
| { | ||
| content.Add(new TextContentBlock { Text = response.Result }); | ||
| } | ||
|
Comment on lines
+77
to
+85
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As noted in previous comment, result is only available for success result. |
||
|
|
||
| return new CallToolResult | ||
| { | ||
| Content = [new TextContentBlock { Text = $"Command '{commandName}' executed successfully on resource '{resourceName}'." }] | ||
| Content = [.. content] | ||
| }; | ||
| } | ||
| else if (response.Canceled) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Globalization; | ||
| using Aspire.Dashboard.Components.Dialogs; | ||
| using Aspire.Dashboard.Telemetry; | ||
| using Aspire.Dashboard.Utils; | ||
| using Microsoft.AspNetCore.Components; | ||
|
|
@@ -13,7 +14,7 @@ namespace Aspire.Dashboard.Model; | |
|
|
||
| public sealed class DashboardCommandExecutor( | ||
| IDashboardClient dashboardClient, | ||
| IDialogService dialogService, | ||
| IServiceProvider serviceProvider, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not pass in DashboardDialogService directly? It and the containing type have the same lifetime (scoped) so shouldn't it be fine? |
||
| IToastService toastService, | ||
| IStringLocalizer<Dashboard.Resources.Resources> loc, | ||
| NavigationManager navigationManager, | ||
|
|
@@ -86,7 +87,7 @@ public async Task ExecuteAsyncCore(ResourceViewModel resource, CommandViewModel | |
| { | ||
| if (!string.IsNullOrWhiteSpace(command.ConfirmationMessage)) | ||
| { | ||
| var dialogReference = await dialogService.ShowConfirmationAsync(command.ConfirmationMessage).ConfigureAwait(false); | ||
| var dialogReference = await serviceProvider.GetRequiredService<DashboardDialogService>().ShowConfirmationAsync(command.ConfirmationMessage).ConfigureAwait(false); | ||
| var result = await dialogReference.Result.ConfigureAwait(false); | ||
| if (result.Cancelled) | ||
| { | ||
|
|
@@ -148,6 +149,18 @@ public async Task ExecuteAsyncCore(ResourceViewModel resource, CommandViewModel | |
| toastParameters.Title = string.Format(CultureInfo.InvariantCulture, loc[nameof(Dashboard.Resources.Resources.ResourceCommandSuccess)], messageResourceName, command.GetDisplayName()); | ||
| toastParameters.Intent = ToastIntent.Success; | ||
| toastParameters.Icon = GetIntentIcon(ToastIntent.Success); | ||
|
|
||
| if (response.Result is not null) | ||
| { | ||
| var fixedFormat = response.ResultFormat == CommandResultFormat.Json ? DashboardUIHelpers.JsonFormat : null; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the reason there is a resultformat? JSON content is automatically detected by the visualizer dialog so this isn't nessessary.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about this more, and being able to return markdown and displaying HTML would be valuable, and you'd need to specify the content is markdown. Don't need to support this now, but leave the resultformat in to extend in the future. |
||
| await TextVisualizerDialog.OpenDialogAsync(new OpenTextVisualizerDialogOptions | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is ok for an initial PR, but it's not a good user experience. With a long running command you could randomly have a modal dialog open while using the dashboard. And you might not care to look at the result, just care whether it succeeded or failed. I think what we should have long term is a notification icon in the header that opens and displays recent notifications. From here you could choose to look at the result from a command. Basically, copy what Azure Portal (and may other websites) do with notifications for async tasks. |
||
| { | ||
| DialogService = serviceProvider.GetRequiredService<DashboardDialogService>(), | ||
| ValueDescription = command.GetDisplayName(), | ||
| Value = response.Result, | ||
| FixedFormat = fixedFormat | ||
| }).ConfigureAwait(false); | ||
| } | ||
|
Comment on lines
+153
to
+163
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Consider either moving this call to after the toast update block, or fire-and-forgetting the dialog so the toast updates immediately.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested and I didn't see this. And this wouldn't be a concern after switching to accessing result via persistent notification. |
||
| } | ||
| else if (response.Kind == ResourceCommandResponseKind.Cancelled) | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why only display result on success? I can imagine wanting to display output on error.