Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
13 changes: 7 additions & 6 deletions playground/Stress/Stress.AppHost/InteractionCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -796,8 +796,8 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
var interactionService = commandContext.Services.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptProgressAsync(
"Please wait while resources are being downloaded...",
"Downloading resources",
"Please wait while resources are being downloaded...",
new ProgressInteractionOptions
{
PrimaryButtonText = "Cancel",
Expand Down Expand Up @@ -825,8 +825,8 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
var interactionService = commandContext.Services.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptProgressAsync(
null,
"Please wait while resources are being downloaded...",
title: null,
options: new ProgressInteractionOptions
{
Work = async ctx =>
Expand Down Expand Up @@ -855,8 +855,8 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
using var cts = CancellationTokenSource.CreateLinkedTokenSource(commandContext.CancellationToken);

var progressTask = interactionService.PromptProgressAsync(
"This dialog has no cancel button. It will close automatically.",
"Processing",
"This dialog has no cancel button. It will close automatically.",
cancellationToken: cts.Token);

// Simulate background work, then close the dialog.
Expand All @@ -877,8 +877,8 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
var interactionService = commandContext.Services.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptProgressAsync(
"Please wait while data is being loaded...",
"Loading",
"Please wait while data is being loaded...",
new ProgressInteractionOptions
{
Work = async ctx =>
Expand All @@ -900,6 +900,7 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
var interactionService = commandContext.Services.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptProgressAsync(
null,
"Please wait...",
options: new ProgressInteractionOptions
{
Expand All @@ -923,8 +924,8 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
var interactionService = commandContext.Services.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptProgressAsync(
"Provisioning resources for **MyApp**.\n\nThis may take several minutes.",
"Deploying to Azure",
"Provisioning resources for **MyApp**.\n\nThis may take several minutes.",
new ProgressInteractionOptions
{
PrimaryButtonText = "Abort deployment",
Expand All @@ -948,8 +949,8 @@ public static IResourceBuilder<T> AddInteractionCommands<T>(this IResourceBuilde
var interactionService = commandContext.Services.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptProgressAsync(
"Building and pushing container images to registry. This will take approximately 30 seconds.",
"Building container images",
"Building and pushing container images to registry. This will take approximately 30 seconds.",
new ProgressInteractionOptions
{
PrimaryButtonText = "Cancel build"
Expand Down
12 changes: 5 additions & 7 deletions playground/TypeScriptAppHost/apphost.mts
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,13 @@ await cache.withCommand(
}

const result = await interactionService.promptProgress(
"Processing",
"Please wait while data is being processed...",
{
title: "Processing",
options: {
primaryButtonText: "Cancel",
work: async () => {
// Simulate a long-running operation.
await new Promise<void>(resolve => setTimeout(resolve, 10000));
}
primaryButtonText: "Cancel",
work: async () => {
// Simulate a long-running operation.
await new Promise<void>(resolve => setTimeout(resolve, 10000));
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ private async Task<ExecuteCommandResult> ExecuteCommandWithOptionalProgressAsync
options.PrimaryButtonText = InteractionStrings.CommandProgressCancelButtonText;
}

var progressResult = await interactionService.PromptProgressAsync(progressOptions.Message, title: progressOptions.Title, options: options, cancellationToken: cancellationToken).ConfigureAwait(false);
var progressResult = await interactionService.PromptProgressAsync(progressOptions.Title, progressOptions.Message, options: options, cancellationToken: cancellationToken).ConfigureAwait(false);

if (progressResult.Canceled)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Aspire.Hosting/Ats/InteractionExports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ public static async Task<BoolInteractionResult> PromptNotification(
[AspireExport(RunSyncOnBackgroundThread = true)]
public static async Task<BoolInteractionResult> PromptProgress(
this IInteractionService interactionService,
string? title,
string message,
Comment thread
JamesNK marked this conversation as resolved.
Outdated
string? title = null,
InteractionProgressOptions? options = null,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(interactionService);

var result = await interactionService.PromptProgressAsync(message, title, options?.ToOptions(), cancellationToken).ConfigureAwait(false);
var result = await interactionService.PromptProgressAsync(title, message, options?.ToOptions(), cancellationToken).ConfigureAwait(false);
return BoolInteractionResult.From(result);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Aspire.Hosting/IInteractionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,16 @@ public interface IInteractionService
/// through the <see cref="ProgressContext.CancellationToken"/> provided to the work callback.
/// </para>
/// </remarks>
/// <param name="message">The message to display in the progress dialog.</param>
/// <param name="title">The optional title of the progress dialog.</param>
/// <param name="message">The message to display in the progress dialog.</param>
/// <param name="options">Optional configuration for the progress interaction.</param>
/// <param name="cancellationToken">A token to cancel the operation and close the dialog.</param>
/// <returns>
/// An <see cref="InteractionResult{T}"/> containing <c>true</c> if the operation completed successfully,
/// or a canceled result if the user clicked the cancel button.
/// </returns>
[Experimental("ASPIREINTERACTION001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
Task<InteractionResult<bool>> PromptProgressAsync(string message, string? title = null, ProgressInteractionOptions? options = null, CancellationToken cancellationToken = default);
Task<InteractionResult<bool>> PromptProgressAsync(string? title, string message, ProgressInteractionOptions? options = null, CancellationToken cancellationToken = default);
}

internal record QueueLoadOptions(
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Hosting/InteractionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ public async Task<InteractionResult<bool>> PromptNotificationAsync(string title,
}
}

public async Task<InteractionResult<bool>> PromptProgressAsync(string message, string? title = null, ProgressInteractionOptions? options = null, CancellationToken cancellationToken = default)
public async Task<InteractionResult<bool>> PromptProgressAsync(string? title, string message, ProgressInteractionOptions? options = null, CancellationToken cancellationToken = default)
{
EnsureServiceAvailable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1648,12 +1648,6 @@ export interface GetValueAsyncOptions {
cancellationToken?: AbortSignal | CancellationToken;
}

export interface PromptProgressOptions {
title?: string;
options?: InteractionProgressOptions;
cancellationToken?: AbortSignal | CancellationToken;
}

export interface PublishAsDockerFileOptions {
/** Optional action to configure the container resource */
configure?: (obj: ContainerResource) => Promise<void>;
Expand Down Expand Up @@ -12765,7 +12759,7 @@ export interface InteractionService {
* Displays a progress dialog with an indeterminate progress indicator.
* @param options Additional options.
*/
promptProgress(message: string, options?: PromptProgressOptions): Promise<BoolInteractionResult>;
promptProgress(title: string, message: string, options?: InteractionProgressOptions, cancellationToken?: AbortSignal | CancellationToken): Promise<BoolInteractionResult>;
Comment thread
JamesNK marked this conversation as resolved.
Outdated
/**
* Prompts the user for a single input.
* @param options Additional options.
Expand Down Expand Up @@ -12834,7 +12828,7 @@ export interface InteractionServicePromise extends PromiseLike<InteractionServic
* Displays a progress dialog with an indeterminate progress indicator.
* @param options Additional options.
*/
promptProgress(message: string, options?: PromptProgressOptions): Promise<BoolInteractionResult>;
promptProgress(title: string, message: string, options?: InteractionProgressOptions, cancellationToken?: AbortSignal | CancellationToken): Promise<BoolInteractionResult>;
/**
* Prompts the user for a single input.
* @param options Additional options.
Expand Down Expand Up @@ -12945,12 +12939,9 @@ class InteractionServiceImpl implements InteractionService {

/**
* Displays a progress dialog with an indeterminate progress indicator.
* @param optionsBag Additional options.
* @param options Additional options.
*/
async promptProgress(message: string, optionsBag?: PromptProgressOptions): Promise<BoolInteractionResult> {
const title = optionsBag?.title;
const options = optionsBag?.options;
const cancellationToken = optionsBag?.cancellationToken;
async promptProgress(title: string, message: string, options?: InteractionProgressOptions, cancellationToken?: AbortSignal | CancellationToken): Promise<BoolInteractionResult> {
const __optionsForRpc = options === undefined || options === null ? options : { ...options };
if (__optionsForRpc !== undefined && __optionsForRpc !== null) {
const __optionsForRpcData = __optionsForRpc as Record<string, unknown>;
Expand All @@ -12964,8 +12955,7 @@ class InteractionServiceImpl implements InteractionService {
__optionsForRpcData["work"] = ____optionsForRpcWorkId;
}
}
const rpcArgs: Record<string, unknown> = { interactionService: this._handle, message };
if (title !== undefined) rpcArgs.title = title;
const rpcArgs: Record<string, unknown> = { interactionService: this._handle, title, message };
if (options !== undefined) rpcArgs.options = __optionsForRpc;
if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken);
return await this._client.invokeCapability<BoolInteractionResult>(
Expand Down Expand Up @@ -13186,8 +13176,8 @@ class InteractionServicePromiseImpl implements InteractionServicePromise {
return this._promise.then(obj => obj.promptNotification(title, message, options, cancellationToken));
}

promptProgress(message: string, options?: PromptProgressOptions): Promise<BoolInteractionResult> {
return this._promise.then(obj => obj.promptProgress(message, options));
promptProgress(title: string, message: string, options?: InteractionProgressOptions, cancellationToken?: AbortSignal | CancellationToken): Promise<BoolInteractionResult> {
return this._promise.then(obj => obj.promptProgress(title, message, options, cancellationToken));
}

promptInput(title: string, message: string, input: Awaitable<InteractionInputBuilder>, options?: InteractionInputsDialogOptions, cancellationToken?: AbortSignal | CancellationToken): Promise<InputInteractionResult> {
Expand Down
16 changes: 8 additions & 8 deletions tests/Aspire.Hosting.Tests/InteractionServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ await Assert.ThrowsAsync<InvalidOperationException>(
await Assert.ThrowsAsync<InvalidOperationException>(
() => interactionService.PromptMessageBoxAsync("Are you sure?", "Confirmation")).DefaultTimeout();
await Assert.ThrowsAsync<InvalidOperationException>(
() => interactionService.PromptProgressAsync("Please wait", "Working...")).DefaultTimeout();
() => interactionService.PromptProgressAsync("Working...", "Please wait")).DefaultTimeout();
}

[Fact]
Expand Down Expand Up @@ -1132,7 +1132,7 @@ public async Task PromptProgressAsync_WithWork_CompletesSuccessfully()
var interactionService = CreateInteractionService();

var workExecuted = false;
var result = await interactionService.PromptProgressAsync("Please wait", "Working...", new ProgressInteractionOptions
var result = await interactionService.PromptProgressAsync("Working...", "Please wait", new ProgressInteractionOptions
{
Work = async ctx =>
{
Expand All @@ -1153,7 +1153,7 @@ public async Task PromptProgressAsync_WithWork_CancelledViaButton_ReturnsCancele
var interactionService = CreateInteractionService();

var tcs = new TaskCompletionSource();
var resultTask = interactionService.PromptProgressAsync("Please wait", "Working...", new ProgressInteractionOptions
var resultTask = interactionService.PromptProgressAsync("Working...", "Please wait", new ProgressInteractionOptions
{
PrimaryButtonText = "Cancel",
Work = async ctx =>
Expand Down Expand Up @@ -1185,7 +1185,7 @@ public async Task PromptProgressAsync_WithWorkThatHandlesCancellation_CancelledV
// thread. Inlining would run the cancellation below before the callback returns, so the prompt task could
// never complete and the test would deadlock until the timeout.
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var resultTask = interactionService.PromptProgressAsync("Please wait", "Working...", new ProgressInteractionOptions
var resultTask = interactionService.PromptProgressAsync("Working...", "Please wait", new ProgressInteractionOptions
{
PrimaryButtonText = "Cancel",
Work = async ctx =>
Expand Down Expand Up @@ -1218,7 +1218,7 @@ public async Task PromptProgressAsync_WithWorkThatHandlesCancellation_Externally

using var cts = new CancellationTokenSource();
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var resultTask = interactionService.PromptProgressAsync("Please wait", "Working...", new ProgressInteractionOptions
var resultTask = interactionService.PromptProgressAsync("Working...", "Please wait", new ProgressInteractionOptions
{
Work = async ctx =>
{
Expand Down Expand Up @@ -1250,7 +1250,7 @@ public async Task PromptProgressAsync_WithoutWork_Cancellation_ClosesDialog()
var interactionService = CreateInteractionService();

var cts = new CancellationTokenSource();
var resultTask = interactionService.PromptProgressAsync("Please wait", "Working...", cancellationToken: cts.Token);
var resultTask = interactionService.PromptProgressAsync("Working...", "Please wait", cancellationToken: cts.Token);

var interaction = Assert.Single(interactionService.GetCurrentInteractions());
Assert.Equal(Interaction.InteractionState.InProgress, interaction.State);
Expand All @@ -1267,7 +1267,7 @@ public async Task PromptProgressAsync_WithoutWork_ButtonClick_ReturnsCanceled()
{
var interactionService = CreateInteractionService();

var resultTask = interactionService.PromptProgressAsync("Please wait", "Working...", new ProgressInteractionOptions
var resultTask = interactionService.PromptProgressAsync("Working...", "Please wait", new ProgressInteractionOptions
{
PrimaryButtonText = "Cancel"
});
Expand All @@ -1288,7 +1288,7 @@ public async Task PromptProgressAsync_NullTitle_CreatesInteraction()
var interactionService = CreateInteractionService();

var cts = new CancellationTokenSource();
var resultTask = interactionService.PromptProgressAsync("Please wait...", cancellationToken: cts.Token);
var resultTask = interactionService.PromptProgressAsync(null, "Please wait...", cancellationToken: cts.Token);

var interaction = Assert.Single(interactionService.GetCurrentInteractions());
Assert.Equal(string.Empty, interaction.Title);
Expand Down
13 changes: 5 additions & 8 deletions tests/PolyglotAppHosts/Aspire.Hosting/TypeScript/apphost.mts
Original file line number Diff line number Diff line change
Expand Up @@ -869,14 +869,11 @@ await container.withCommand("interaction-showcase", "Interaction Showcase", asyn
showDismiss: true
});

const progress = await interactionService.promptProgress("Completing **work**...", {
title: "Progress",
options: {
primaryButtonText: "Cancel",
enableMessageMarkdown: true,
work: async (progressContext) => {
await progressContext.cancellationToken();
}
const progress = await interactionService.promptProgress("Progress", "Completing **work**...", {
primaryButtonText: "Cancel",
enableMessageMarkdown: true,
work: async (progressContext) => {
await progressContext.cancellationToken();
}
});

Expand Down
2 changes: 1 addition & 1 deletion tests/Shared/TestInteractionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public async Task<InteractionResult<bool>> PromptMessageBoxAsync(string title, s

public bool PromptProgressCalled { get; private set; }

public async Task<InteractionResult<bool>> PromptProgressAsync(string message, string? title = null, ProgressInteractionOptions? options = null, CancellationToken cancellationToken = default)
public async Task<InteractionResult<bool>> PromptProgressAsync(string? title, string message, ProgressInteractionOptions? options = null, CancellationToken cancellationToken = default)
{
PromptProgressCalled = true;

Expand Down
Loading