diff --git a/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs b/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs index 586b94b2757..28af9aa22cb 100644 --- a/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs +++ b/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs @@ -1442,8 +1442,8 @@ private void GenerateOptionsOverloads( { var requiredParameterList = string.Join(", ", requiredParameters.Select(parameter => $"{MapParameterToJava(parameter)} {ToCamelCase(parameter.Name)}")); var publicParameterList = string.IsNullOrEmpty(requiredParameterList) - ? $"{optionsClassName} options" - : $"{requiredParameterList}, {optionsClassName} options"; + ? $"{optionsClassName} optionsBag" + : $"{requiredParameterList}, {optionsClassName} optionsBag"; if (!string.IsNullOrEmpty(capability.Description)) { @@ -1454,7 +1454,7 @@ private void GenerateOptionsOverloads( foreach (var parameter in optionalParameters) { var paramName = ToCamelCase(parameter.Name); - WriteLine($" var {paramName} = options == null ? null : options.{GetOptionGetterName(parameter)}();"); + WriteLine($" var {paramName} = optionsBag == null ? null : optionsBag.{GetOptionGetterName(parameter)}();"); } var implementationArguments = requiredParameters diff --git a/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs b/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs index c0d06ad92b8..c4703ef6080 100644 --- a/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs +++ b/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs @@ -183,22 +183,22 @@ private string MapTypeRefToTypeScript(AtsTypeRef? typeRef) // ReferenceExpression is a value type defined in base.mts, not a handle-based wrapper if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId) { - return GetReferenceExpressionInterfaceName(); + return ApplyNullableType(typeRef, GetReferenceExpressionInterfaceName()); } if (typeRef.TypeId == InputTypeTypeId) { - return GetInputTypeEnumName(); + return ApplyNullableType(typeRef, GetInputTypeEnumName()); } if (typeRef.TypeId == InteractionInputTypeId) { - return GetInteractionInputInterfaceName(); + return ApplyNullableType(typeRef, GetInteractionInputInterfaceName()); } if (typeRef.TypeId == InteractionInputCollectionTypeId) { - return GetInteractionInputCollectionClassName(); + return ApplyNullableType(typeRef, GetInteractionInputCollectionClassName()); } // Check for wrapper class first (handles custom types like resource builders) @@ -228,7 +228,7 @@ private string MapTypeRefToTypeScript(AtsTypeRef? typeRef) private static string ApplyNullableType(AtsTypeRef typeRef, string mappedType) { - if (typeRef.IsNullable != true || typeRef.Category is not (AtsTypeCategory.Primitive or AtsTypeCategory.Enum)) + if (typeRef.IsNullable != true) { return mappedType; } @@ -247,9 +247,9 @@ private string MapDtoPropertyTypeToTypeScript(AtsTypeRef? typeRef) return typeRef.Category switch { - AtsTypeCategory.Array or AtsTypeCategory.List => $"{MapDtoPropertyTypeToTypeScript(typeRef.ElementType)}[]", - AtsTypeCategory.Dict => $"Record<{MapDtoPropertyTypeToTypeScript(typeRef.KeyType)}, {MapDtoPropertyTypeToTypeScript(typeRef.ValueType)}>", - AtsTypeCategory.Union => MapDtoUnionTypeToTypeScript(typeRef), + AtsTypeCategory.Array or AtsTypeCategory.List => ApplyNullableType(typeRef, $"{MapDtoPropertyTypeToTypeScript(typeRef.ElementType)}[]"), + AtsTypeCategory.Dict => ApplyNullableType(typeRef, $"Record<{MapDtoPropertyTypeToTypeScript(typeRef.KeyType)}, {MapDtoPropertyTypeToTypeScript(typeRef.ValueType)}>"), + AtsTypeCategory.Union => ApplyNullableType(typeRef, MapDtoUnionTypeToTypeScript(typeRef)), _ => MapTypeRefToTypeScript(typeRef) }; } diff --git a/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs b/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs index 3560a24daff..753d763a0ed 100644 --- a/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs +++ b/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs @@ -432,7 +432,6 @@ public sealed class ExecuteCommandContext /// /// The service provider. /// - [AspireExportIgnore(Reason = "IServiceProvider is not usable from polyglot command callbacks.")] public required IServiceProvider ServiceProvider { get; init; } /// diff --git a/src/Aspire.Hosting/Ats/AtsTypeMappings.cs b/src/Aspire.Hosting/Ats/AtsTypeMappings.cs index 00882748bfb..920c1a24c8b 100644 --- a/src/Aspire.Hosting/Ats/AtsTypeMappings.cs +++ b/src/Aspire.Hosting/Ats/AtsTypeMappings.cs @@ -1,3 +1,4 @@ +#pragma warning disable ASPIREINTERACTION001 #pragma warning disable ASPIREPIPELINES001 // Licensed to the .NET Foundation under one or more agreements. @@ -53,6 +54,7 @@ // Service types [assembly: AspireExport(typeof(IServiceProvider))] +[assembly: AspireExport(typeof(IInteractionService))] [assembly: AspireExport(typeof(ResourceNotificationService))] [assembly: AspireExport(typeof(ResourceLoggerService))] [assembly: AspireExport(typeof(ResourceCommandService))] diff --git a/src/Aspire.Hosting/Ats/InteractionExports.cs b/src/Aspire.Hosting/Ats/InteractionExports.cs new file mode 100644 index 00000000000..489ec78befc --- /dev/null +++ b/src/Aspire.Hosting/Ats/InteractionExports.cs @@ -0,0 +1,424 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma warning disable ASPIREINTERACTION001 + +using Microsoft.Extensions.DependencyInjection; +using PublicInputsDialogInteractionOptions = Aspire.Hosting.InputsDialogInteractionOptions; +using PublicInteractionOptions = Aspire.Hosting.InteractionOptions; +using PublicMessageBoxInteractionOptions = Aspire.Hosting.MessageBoxInteractionOptions; +using PublicNotificationInteractionOptions = Aspire.Hosting.NotificationInteractionOptions; + +namespace Aspire.Hosting.Ats; + +/// +/// ATS exports for interaction service operations. +/// +internal static class InteractionExports +{ + /// + /// Gets the interaction service from the service provider. + /// + /// The service provider handle. + /// An interaction service handle. + [AspireExport] + public static IInteractionService GetInteractionService(this IServiceProvider serviceProvider) + { + ArgumentNullException.ThrowIfNull(serviceProvider); + + return serviceProvider.GetRequiredService(); + } + + /// + /// Gets a value indicating whether the interaction service is available. + /// + /// The interaction service handle. + /// when the interaction service can interact with the user; otherwise, . + [AspireExport("interactionServiceIsAvailable", MethodName = "isAvailable")] + public static bool IsAvailable(this IInteractionService interactionService) + { + ArgumentNullException.ThrowIfNull(interactionService); + + return interactionService.IsAvailable; + } + + /// + /// Prompts the user for confirmation with a dialog. + /// + /// The interaction service handle. + /// The title of the dialog. + /// The message to display in the dialog. + /// Optional configuration for the message box interaction. + /// A token to cancel the operation. + /// The confirmation interaction result. + [AspireExport] + public static async Task PromptConfirmationAsync( + this IInteractionService interactionService, + string title, + string message, + MessageBoxInteractionOptions? options = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(interactionService); + + var result = await interactionService.PromptConfirmationAsync( + title, + message, + options?.ToMessageBoxInteractionOptions(), + cancellationToken).ConfigureAwait(false); + + return BooleanInteractionResult.FromInteractionResult(result); + } + + /// + /// Prompts the user with a message box dialog. + /// + /// The interaction service handle. + /// The title of the message box. + /// The message to display in the message box. + /// Optional configuration for the message box interaction. + /// A token to cancel the operation. + /// The message box interaction result. + [AspireExport] + public static async Task PromptMessageBoxAsync( + this IInteractionService interactionService, + string title, + string message, + MessageBoxInteractionOptions? options = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(interactionService); + + var result = await interactionService.PromptMessageBoxAsync( + title, + message, + options?.ToMessageBoxInteractionOptions(), + cancellationToken).ConfigureAwait(false); + + return BooleanInteractionResult.FromInteractionResult(result); + } + + /// + /// Prompts the user for a single text input. + /// + /// The interaction service handle. + /// The title of the input dialog. + /// The message to display in the dialog. + /// The label for the input field. + /// The placeholder text for the input field. + /// Optional configuration for the input dialog interaction. + /// A token to cancel the operation. + /// The input interaction result. + [AspireExport] + public static async Task PromptInputAsync( + this IInteractionService interactionService, + string title, + string? message, + string inputLabel, + string placeHolder, + InputsDialogInteractionOptions? options = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(interactionService); + + var result = await interactionService.PromptInputAsync( + title, + message, + inputLabel, + placeHolder, + options?.ToInputsDialogInteractionOptions(), + cancellationToken).ConfigureAwait(false); + + return InputInteractionResult.FromInteractionResult(result); + } + + /// + /// Prompts the user for a single input using a specified . + /// + /// The interaction service handle. + /// The title of the input dialog. + /// The message to display in the dialog. + /// The input configuration. + /// Optional configuration for the input dialog interaction. + /// A token to cancel the operation. + /// The input interaction result. + [AspireExport("promptInputWithInput", MethodName = "promptInputWithInputAsync")] + public static async Task PromptInputWithInputAsync( + this IInteractionService interactionService, + string title, + string? message, + InteractionInput input, + InputsDialogInteractionOptions? options = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(interactionService); + + var result = await interactionService.PromptInputAsync( + title, + message, + input, + options?.ToInputsDialogInteractionOptions(), + cancellationToken).ConfigureAwait(false); + + return InputInteractionResult.FromInteractionResult(result); + } + + /// + /// Prompts the user for multiple inputs. + /// + /// The interaction service handle. + /// The title of the input dialog. + /// The message to display in the dialog. + /// The input configurations. + /// Optional configuration for the input dialog interaction. + /// A token to cancel the operation. + /// The inputs interaction result. + [AspireExport] + public static async Task PromptInputsAsync( + this IInteractionService interactionService, + string title, + string? message, + IReadOnlyList inputs, + InputsDialogInteractionOptions? options = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(interactionService); + + var result = await interactionService.PromptInputsAsync( + title, + message, + inputs, + options?.ToInputsDialogInteractionOptions(), + cancellationToken).ConfigureAwait(false); + + return InputsInteractionResult.FromInteractionResult(result); + } + + /// + /// Prompts the user with a notification. + /// + /// The interaction service handle. + /// The title of the notification. + /// The message to display in the notification. + /// Optional configuration for the notification interaction. + /// A token to cancel the operation. + /// The notification interaction result. + [AspireExport] + public static async Task PromptNotificationAsync( + this IInteractionService interactionService, + string title, + string message, + NotificationInteractionOptions? options = null, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(interactionService); + + var result = await interactionService.PromptNotificationAsync( + title, + message, + options?.ToNotificationInteractionOptions(), + cancellationToken).ConfigureAwait(false); + + return BooleanInteractionResult.FromInteractionResult(result); + } +} + +/// +/// Shared polyglot options for interaction prompts. +/// +[AspireDto] +internal class InteractionOptions +{ + /// + /// Optional primary button text to override the default text. + /// + public string? PrimaryButtonText { get; init; } + + /// + /// Optional secondary button text to override the default text. + /// + public string? SecondaryButtonText { get; init; } + + /// + /// Gets a value indicating whether to show the secondary button. + /// + public bool? ShowSecondaryButton { get; init; } + + /// + /// Gets a value indicating whether to show the dismiss button. + /// + public bool? ShowDismiss { get; init; } + + /// + /// Gets a value indicating whether Markdown in the message is rendered. + /// + public bool? EnableMessageMarkdown { get; init; } + + internal void ApplyTo(PublicInteractionOptions options) + { + options.PrimaryButtonText = PrimaryButtonText; + options.SecondaryButtonText = SecondaryButtonText; + options.ShowSecondaryButton = ShowSecondaryButton; + options.ShowDismiss = ShowDismiss; + options.EnableMessageMarkdown = EnableMessageMarkdown; + } +} + +/// +/// Polyglot options for message box interactions. +/// +[AspireDto] +internal sealed class MessageBoxInteractionOptions : InteractionOptions +{ + /// + /// Gets the intent of the message box. + /// + public MessageIntent? Intent { get; init; } + + internal PublicMessageBoxInteractionOptions ToMessageBoxInteractionOptions() + { + var options = new PublicMessageBoxInteractionOptions + { + Intent = Intent + }; + + ApplyTo(options); + return options; + } +} + +/// +/// Polyglot options for inputs dialog interactions. +/// +[AspireDto] +internal sealed class InputsDialogInteractionOptions : InteractionOptions +{ + /// + /// Gets the validation callback for the inputs dialog. + /// + public Func? ValidationCallback { get; init; } + + internal PublicInputsDialogInteractionOptions ToInputsDialogInteractionOptions() + { + var options = new PublicInputsDialogInteractionOptions + { + ValidationCallback = ValidationCallback + }; + + ApplyTo(options); + return options; + } +} + +/// +/// Polyglot options for notification interactions. +/// +[AspireDto] +internal sealed class NotificationInteractionOptions : InteractionOptions +{ + /// + /// Gets the intent of the notification. + /// + public MessageIntent? Intent { get; init; } + + /// + /// Gets the text for a link in the notification. + /// + public string? LinkText { get; init; } + + /// + /// Gets the URL for the link in the notification. + /// + public string? LinkUrl { get; init; } + + internal PublicNotificationInteractionOptions ToNotificationInteractionOptions() + { + var options = new PublicNotificationInteractionOptions + { + Intent = Intent, + LinkText = LinkText, + LinkUrl = LinkUrl + }; + + ApplyTo(options); + return options; + } +} + +/// +/// The result of a boolean interaction prompt. +/// +[AspireDto] +internal sealed class BooleanInteractionResult +{ + /// + /// The data returned from the interaction. The value is when the interaction was canceled. + /// + public bool? Data { get; init; } + + /// + /// A flag indicating whether the interaction was canceled by the user. + /// + public required bool Canceled { get; init; } + + internal static BooleanInteractionResult FromInteractionResult(InteractionResult result) + { + return new BooleanInteractionResult + { + Data = result.Canceled ? null : result.Data, + Canceled = result.Canceled + }; + } +} + +/// +/// The result of a single input interaction prompt. +/// +[AspireDto] +internal sealed class InputInteractionResult +{ + /// + /// The data returned from the interaction. The value is when the interaction was canceled. + /// + public InteractionInput? Data { get; init; } + + /// + /// A flag indicating whether the interaction was canceled by the user. + /// + public required bool Canceled { get; init; } + + internal static InputInteractionResult FromInteractionResult(InteractionResult result) + { + return new InputInteractionResult + { + Data = result.Canceled ? null : result.Data, + Canceled = result.Canceled + }; + } +} + +/// +/// The result of a multi-input interaction prompt. +/// +[AspireDto] +internal sealed class InputsInteractionResult +{ + /// + /// The data returned from the interaction. The value is when the interaction was canceled. + /// + public InteractionInputCollection? Data { get; init; } + + /// + /// A flag indicating whether the interaction was canceled by the user. + /// + public required bool Canceled { get; init; } + + internal static InputsInteractionResult FromInteractionResult(InteractionResult result) + { + return new InputsInteractionResult + { + Data = result.Canceled ? null : result.Data, + Canceled = result.Canceled + }; + } +} diff --git a/src/Aspire.Hosting/IInteractionService.cs b/src/Aspire.Hosting/IInteractionService.cs index 9dc6643c925..f8e15d48d35 100644 --- a/src/Aspire.Hosting/IInteractionService.cs +++ b/src/Aspire.Hosting/IInteractionService.cs @@ -203,6 +203,7 @@ await _options.LoadCallback(new LoadInputContext /// scenarios where input loading behavior must be customized. /// [Experimental(InteractionService.DiagnosticId, UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] +[AspireDto] public sealed class InputLoadOptions { /// @@ -230,6 +231,7 @@ public sealed class InputLoadOptions /// The context for dynamic input loading. Used with . /// [Experimental(InteractionService.DiagnosticId, UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] +[AspireExport(ExposeProperties = true)] public sealed class LoadInputContext { /// @@ -245,12 +247,25 @@ public sealed class LoadInputContext /// /// Gets the service provider. /// + [AspireExportIgnore(Reason = "IServiceProvider is not part of the polyglot dynamic loading surface.")] public required IServiceProvider Services { get; init; } /// /// Gets the . /// public required CancellationToken CancellationToken { get; init; } + + /// + /// Sets the available options for the loading input. + /// + /// The choice options to display for the loading input, keyed by submitted value. + [AspireExport("LoadInputContext.setOptions", MethodName = "setOptions")] + internal void SetOptions(IReadOnlyDictionary options) + { + ArgumentNullException.ThrowIfNull(options); + + Input.Options = options.ToArray(); + } } /// diff --git a/src/Aspire.Hosting/api/Aspire.Hosting.ats.txt b/src/Aspire.Hosting/api/Aspire.Hosting.ats.txt index dd82a3d3772..e1354cd86d8 100644 --- a/src/Aspire.Hosting/api/Aspire.Hosting.ats.txt +++ b/src/Aspire.Hosting/api/Aspire.Hosting.ats.txt @@ -67,10 +67,12 @@ Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing [interfac Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationResourceEvent [interface] Aspire.Hosting/Aspire.Hosting.ExternalServiceResource Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder [interface] +Aspire.Hosting/Aspire.Hosting.IInteractionService [interface] Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext [ExposeProperties] Aspire.Hosting/Aspire.Hosting.InteractionInputCollection Aspire.Hosting/Aspire.Hosting.IResourceWithContainerFiles [interface] Aspire.Hosting/Aspire.Hosting.IUserSecretsManager [interface, ExposeProperties, ExposeMethods] +Aspire.Hosting/Aspire.Hosting.LoadInputContext [ExposeProperties] Aspire.Hosting/Aspire.Hosting.Pipelines.IDistributedApplicationPipeline [interface] Aspire.Hosting/Aspire.Hosting.Pipelines.IReportingStep [interface] Aspire.Hosting/Aspire.Hosting.Pipelines.IReportingTask [interface] @@ -182,6 +184,9 @@ Aspire.Hosting/Aspire.Hosting.ApplicationModel.UpdateCommandStateResourceSnapsho Aspire.Hosting/Aspire.Hosting.Ats.AddContainerOptions # Options for configuring a container image in polyglot apphosts. Image: string # The container image name. Tag?: string # The container image tag. +Aspire.Hosting/Aspire.Hosting.Ats.BooleanInteractionResult # The result of a boolean interaction prompt. + Canceled: boolean # A flag indicating whether the interaction was canceled by the user. + Data?: boolean # The data returned from the interaction. The value is `null` when the interaction was canceled. Aspire.Hosting/Aspire.Hosting.Ats.CertificateTrustExecutionConfigurationExportData # ATS-friendly certificate trust data returned from an execution-configuration result. CertificateSubjects: string[] # The certificate subjects included in the trust configuration. CustomBundlePaths: string[] # The relative custom bundle paths. @@ -207,6 +212,41 @@ Aspire.Hosting/Aspire.Hosting.Ats.HttpsCertificateInfo # ATS-friendly certificat Issuer: string # The certificate issuer. Subject: string # The certificate subject. Thumbprint?: string # The certificate thumbprint. +Aspire.Hosting/Aspire.Hosting.Ats.InputInteractionResult # The result of a single input interaction prompt. + Canceled: boolean # A flag indicating whether the interaction was canceled by the user. + Data?: Aspire.Hosting/Aspire.Hosting.InteractionInput # The data returned from the interaction. The value is `null` when the interaction was canceled. +Aspire.Hosting/Aspire.Hosting.Ats.InputsDialogInteractionOptions # Polyglot options for inputs dialog interactions. + EnableMessageMarkdown?: boolean # Gets a value indicating whether Markdown in the message is rendered. + PrimaryButtonText?: string # Optional primary button text to override the default text. + SecondaryButtonText?: string # Optional secondary button text to override the default text. + ShowDismiss?: boolean # Gets a value indicating whether to show the dismiss button. + ShowSecondaryButton?: boolean # Gets a value indicating whether to show the secondary button. + ValidationCallback?: callback # Gets the validation callback for the inputs dialog. +Aspire.Hosting/Aspire.Hosting.Ats.InputsInteractionResult # The result of a multi-input interaction prompt. + Canceled: boolean # A flag indicating whether the interaction was canceled by the user. + Data?: Aspire.Hosting/Aspire.Hosting.InteractionInputCollection # The data returned from the interaction. The value is `null` when the interaction was canceled. +Aspire.Hosting/Aspire.Hosting.Ats.InteractionOptions # Shared polyglot options for interaction prompts. + EnableMessageMarkdown?: boolean # Gets a value indicating whether Markdown in the message is rendered. + PrimaryButtonText?: string # Optional primary button text to override the default text. + SecondaryButtonText?: string # Optional secondary button text to override the default text. + ShowDismiss?: boolean # Gets a value indicating whether to show the dismiss button. + ShowSecondaryButton?: boolean # Gets a value indicating whether to show the secondary button. +Aspire.Hosting/Aspire.Hosting.Ats.MessageBoxInteractionOptions # Polyglot options for message box interactions. + EnableMessageMarkdown?: boolean # Gets a value indicating whether Markdown in the message is rendered. + Intent?: enum:Aspire.Hosting.MessageIntent # Gets the intent of the message box. + PrimaryButtonText?: string # Optional primary button text to override the default text. + SecondaryButtonText?: string # Optional secondary button text to override the default text. + ShowDismiss?: boolean # Gets a value indicating whether to show the dismiss button. + ShowSecondaryButton?: boolean # Gets a value indicating whether to show the secondary button. +Aspire.Hosting/Aspire.Hosting.Ats.NotificationInteractionOptions # Polyglot options for notification interactions. + EnableMessageMarkdown?: boolean # Gets a value indicating whether Markdown in the message is rendered. + Intent?: enum:Aspire.Hosting.MessageIntent # Gets the intent of the notification. + LinkText?: string # Gets the text for a link in the notification. + LinkUrl?: string # Gets the URL for the link in the notification. + PrimaryButtonText?: string # Optional primary button text to override the default text. + SecondaryButtonText?: string # Optional secondary button text to override the default text. + ShowDismiss?: boolean # Gets a value indicating whether to show the dismiss button. + ShowSecondaryButton?: boolean # Gets a value indicating whether to show the secondary button. Aspire.Hosting/Aspire.Hosting.Ats.ParameterCustomInputOptions # Options for customizing parameter inputs from polyglot app hosts. AllowCustomChoice?: boolean # Gets or sets whether custom choices are allowed. Description: string # Gets or sets the description for the input. @@ -230,6 +270,10 @@ Aspire.Hosting/Aspire.Hosting.Ats.ResourceEventDto # DTO for resource events ret ResourceName: string # The resource name. State?: string # The current state text. StateStyle?: string # The state style (e.g., "success", "warn", "error"). +Aspire.Hosting/Aspire.Hosting.InputLoadOptions # Represents configuration options for dynamically loading input data. + AlwaysLoadOnStart?: boolean # Gets a value indicating whether `LoadCallback` should always be executed at the start of the input prompt. + DependsOnInputs?: string[] # Gets the list of input names that this input depends on. `LoadCallback` is executed whenever any of the specified inputs change. + LoadCallback: callback # Gets the callback function that is invoked to perform a load operation using the specified input context. Aspire.Hosting/Aspire.Hosting.InteractionInput # Represents an input for an interaction. AllowCustomChoice?: boolean # Gets a value indicating whether a custom choice is allowed. Only used by `Choice` inputs. Description?: string # Gets or sets the description for the input. @@ -261,6 +305,7 @@ enum:Aspire.Hosting.ApplicationModel.UrlDisplayLocation = SummaryAndDetails | De enum:Aspire.Hosting.ApplicationModel.WaitBehavior = WaitOnResourceUnavailable | StopOnResourceUnavailable enum:Aspire.Hosting.DistributedApplicationOperation = Run | Publish enum:Aspire.Hosting.InputType = Text | SecretText | Choice | Boolean | Number +enum:Aspire.Hosting.MessageIntent = None | Success | Warning | Error | Information | Confirmation enum:Aspire.Hosting.OtlpProtocol = Grpc | HttpProtobuf | HttpJson enum:Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus = Unhealthy | Degraded | Healthy enum:System.Net.Sockets.ProtocolType = IP | IPv6HopByHopOptions | Unspecified | Icmp | Igmp | Ggp | IPv4 | Tcp | Pup | Udp | Idp | IPv6 | IPv6RoutingHeader | IPv6FragmentHeader | IPSecEncapsulatingSecurityPayload | IPSecAuthenticationHeader | IcmpV6 | IPv6NoNextHeader | IPv6DestinationOptions | ND | Raw | Ipx | Spx | SpxII | Unknown @@ -376,6 +421,7 @@ Aspire.Hosting.ApplicationModel/ExecuteCommandContext.arguments(context: Aspire. Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> cancellationToken Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> string +Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> System.ComponentModel/System.IServiceProvider Aspire.Hosting.ApplicationModel/getEndpoint(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext, name: string) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference Aspire.Hosting.ApplicationModel/getValueAsync(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression, cancellationToken: cancellationToken) -> string Aspire.Hosting.ApplicationModel/IAspireStore.basePath(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.IAspireStore) -> string @@ -525,6 +571,7 @@ Aspire.Hosting/getEndpoint(name: string) -> Aspire.Hosting/Aspire.Hosting.Applic Aspire.Hosting/getEventing() -> Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing Aspire.Hosting/getFileNameWithContent(filenameTemplate: string, sourceFilename: string) -> string Aspire.Hosting/getHttpsCertificateData() -> Aspire.Hosting/Aspire.Hosting.Ats.HttpsCertificateExecutionConfigurationExportData +Aspire.Hosting/getInteractionService() -> Aspire.Hosting/Aspire.Hosting.IInteractionService Aspire.Hosting/getLoggerFactory() -> Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILoggerFactory Aspire.Hosting/getOrSetSecret(resourceBuilder: Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource, name: string, value: string) -> void Aspire.Hosting/getResourceCommandService() -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceCommandService @@ -544,6 +591,7 @@ Aspire.Hosting/InputsDialogValidationContext.addValidationError(context: Aspire. Aspire.Hosting/InputsDialogValidationContext.cancellationToken(context: Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext) -> cancellationToken Aspire.Hosting/InputsDialogValidationContext.inputs(context: Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext) -> Aspire.Hosting/Aspire.Hosting.InteractionInputCollection Aspire.Hosting/InteractionInputCollection.toArray(context: Aspire.Hosting/Aspire.Hosting.InteractionInputCollection) -> Aspire.Hosting/Aspire.Hosting.InteractionInput[] +Aspire.Hosting/interactionServiceIsAvailable() -> boolean Aspire.Hosting/isDevelopment() -> boolean Aspire.Hosting/isEnvironment(environmentName: string) -> boolean Aspire.Hosting/isProduction() -> boolean @@ -561,6 +609,10 @@ Aspire.Hosting/List.length() -> number Aspire.Hosting/List.removeAt(index: number) -> boolean Aspire.Hosting/List.set(index: number, value: any) -> void Aspire.Hosting/List.toArray() -> any[] +Aspire.Hosting/LoadInputContext.allInputs(context: Aspire.Hosting/Aspire.Hosting.LoadInputContext) -> Aspire.Hosting/Aspire.Hosting.InteractionInputCollection +Aspire.Hosting/LoadInputContext.cancellationToken(context: Aspire.Hosting/Aspire.Hosting.LoadInputContext) -> cancellationToken +Aspire.Hosting/LoadInputContext.input(context: Aspire.Hosting/Aspire.Hosting.LoadInputContext) -> Aspire.Hosting/Aspire.Hosting.InteractionInput +Aspire.Hosting/LoadInputContext.setOptions(context: Aspire.Hosting/Aspire.Hosting.LoadInputContext, options: Aspire.Hosting/Dict) -> void Aspire.Hosting/log(level: string, message: string) -> void Aspire.Hosting/logDebug(message: string) -> void Aspire.Hosting/logError(message: string) -> void @@ -580,6 +632,12 @@ Aspire.Hosting/ProjectResourceOptions.launchProfileName(context: Aspire.Hosting/ Aspire.Hosting/ProjectResourceOptions.setExcludeKestrelEndpoints(context: Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions, value: boolean) -> Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions Aspire.Hosting/ProjectResourceOptions.setExcludeLaunchProfile(context: Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions, value: boolean) -> Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions Aspire.Hosting/ProjectResourceOptions.setLaunchProfileName(context: Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions, value: string) -> Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions +Aspire.Hosting/promptConfirmationAsync(title: string, message: string, options?: Aspire.Hosting/Aspire.Hosting.Ats.MessageBoxInteractionOptions, cancellationToken?: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.Ats.BooleanInteractionResult +Aspire.Hosting/promptInputAsync(title: string, message: string, inputLabel: string, placeHolder: string, options?: Aspire.Hosting/Aspire.Hosting.Ats.InputsDialogInteractionOptions, cancellationToken?: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.Ats.InputInteractionResult +Aspire.Hosting/promptInputsAsync(title: string, message: string, inputs: Aspire.Hosting/Aspire.Hosting.InteractionInput[], options?: Aspire.Hosting/Aspire.Hosting.Ats.InputsDialogInteractionOptions, cancellationToken?: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.Ats.InputsInteractionResult +Aspire.Hosting/promptInputWithInput(title: string, message: string, input: Aspire.Hosting/Aspire.Hosting.InteractionInput, options?: Aspire.Hosting/Aspire.Hosting.Ats.InputsDialogInteractionOptions, cancellationToken?: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.Ats.InputInteractionResult +Aspire.Hosting/promptMessageBoxAsync(title: string, message: string, options?: Aspire.Hosting/Aspire.Hosting.Ats.MessageBoxInteractionOptions, cancellationToken?: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.Ats.BooleanInteractionResult +Aspire.Hosting/promptNotificationAsync(title: string, message: string, options?: Aspire.Hosting/Aspire.Hosting.Ats.NotificationInteractionOptions, cancellationToken?: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.Ats.BooleanInteractionResult Aspire.Hosting/publishAsConnectionString() -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource Aspire.Hosting/publishAsContainer() -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource Aspire.Hosting/publishAsDockerFile(configure: callback) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource diff --git a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go index 5414dfb283e..981ae5b4c21 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go +++ b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go @@ -157,6 +157,18 @@ const ( InputTypeNumber InputType = "Number" ) +// MessageIntent represents MessageIntent. +type MessageIntent string + +const ( + MessageIntentNone MessageIntent = "None" + MessageIntentSuccess MessageIntent = "Success" + MessageIntentWarning MessageIntent = "Warning" + MessageIntentError MessageIntent = "Error" + MessageIntentInformation MessageIntent = "Information" + MessageIntentConfirmation MessageIntent = "Confirmation" +) + // ResourceCommandVisibility represents ResourceCommandVisibility. type ResourceCommandVisibility string @@ -234,6 +246,22 @@ const ( // DTOs // ============================================================================ +// InputLoadOptions represents InputLoadOptions. +type InputLoadOptions struct { + LoadCallback func(...any) any `json:"LoadCallback,omitempty"` + AlwaysLoadOnStart *bool `json:"AlwaysLoadOnStart,omitempty"` + DependsOnInputs []string `json:"DependsOnInputs,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *InputLoadOptions) ToMap() map[string]any { + m := map[string]any{} + if d.LoadCallback != nil { m["LoadCallback"] = serializeValue(d.LoadCallback) } + if d.AlwaysLoadOnStart != nil { m["AlwaysLoadOnStart"] = serializeValue(d.AlwaysLoadOnStart) } + if d.DependsOnInputs != nil { m["DependsOnInputs"] = serializeValue(d.DependsOnInputs) } + return m +} + // InteractionInput represents InteractionInput. type InteractionInput struct { Name string `json:"Name,omitempty"` @@ -243,7 +271,7 @@ type InteractionInput struct { InputType InputType `json:"InputType,omitempty"` Required *bool `json:"Required,omitempty"` Options []any `json:"Options,omitempty"` - DynamicLoading any `json:"DynamicLoading,omitempty"` + DynamicLoading *InputLoadOptions `json:"DynamicLoading,omitempty"` Value string `json:"Value,omitempty"` Placeholder *string `json:"Placeholder,omitempty"` AllowCustomChoice *bool `json:"AllowCustomChoice,omitempty"` @@ -366,6 +394,138 @@ func (d *HttpsCertificateExecutionConfigurationExportData) ToMap() map[string]an return m } +// InteractionOptions represents InteractionOptions. +type InteractionOptions struct { + PrimaryButtonText *string `json:"PrimaryButtonText,omitempty"` + SecondaryButtonText *string `json:"SecondaryButtonText,omitempty"` + ShowSecondaryButton *bool `json:"ShowSecondaryButton,omitempty"` + ShowDismiss *bool `json:"ShowDismiss,omitempty"` + EnableMessageMarkdown *bool `json:"EnableMessageMarkdown,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *InteractionOptions) ToMap() map[string]any { + m := map[string]any{} + if d.PrimaryButtonText != nil { m["PrimaryButtonText"] = serializeValue(d.PrimaryButtonText) } + if d.SecondaryButtonText != nil { m["SecondaryButtonText"] = serializeValue(d.SecondaryButtonText) } + if d.ShowSecondaryButton != nil { m["ShowSecondaryButton"] = serializeValue(d.ShowSecondaryButton) } + if d.ShowDismiss != nil { m["ShowDismiss"] = serializeValue(d.ShowDismiss) } + if d.EnableMessageMarkdown != nil { m["EnableMessageMarkdown"] = serializeValue(d.EnableMessageMarkdown) } + return m +} + +// MessageBoxInteractionOptions represents MessageBoxInteractionOptions. +type MessageBoxInteractionOptions struct { + Intent *MessageIntent `json:"Intent,omitempty"` + PrimaryButtonText *string `json:"PrimaryButtonText,omitempty"` + SecondaryButtonText *string `json:"SecondaryButtonText,omitempty"` + ShowSecondaryButton *bool `json:"ShowSecondaryButton,omitempty"` + ShowDismiss *bool `json:"ShowDismiss,omitempty"` + EnableMessageMarkdown *bool `json:"EnableMessageMarkdown,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *MessageBoxInteractionOptions) ToMap() map[string]any { + m := map[string]any{} + if d.Intent != nil { m["Intent"] = serializeValue(d.Intent) } + if d.PrimaryButtonText != nil { m["PrimaryButtonText"] = serializeValue(d.PrimaryButtonText) } + if d.SecondaryButtonText != nil { m["SecondaryButtonText"] = serializeValue(d.SecondaryButtonText) } + if d.ShowSecondaryButton != nil { m["ShowSecondaryButton"] = serializeValue(d.ShowSecondaryButton) } + if d.ShowDismiss != nil { m["ShowDismiss"] = serializeValue(d.ShowDismiss) } + if d.EnableMessageMarkdown != nil { m["EnableMessageMarkdown"] = serializeValue(d.EnableMessageMarkdown) } + return m +} + +// InputsDialogInteractionOptions represents InputsDialogInteractionOptions. +type InputsDialogInteractionOptions struct { + ValidationCallback func(...any) any `json:"ValidationCallback,omitempty"` + PrimaryButtonText *string `json:"PrimaryButtonText,omitempty"` + SecondaryButtonText *string `json:"SecondaryButtonText,omitempty"` + ShowSecondaryButton *bool `json:"ShowSecondaryButton,omitempty"` + ShowDismiss *bool `json:"ShowDismiss,omitempty"` + EnableMessageMarkdown *bool `json:"EnableMessageMarkdown,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *InputsDialogInteractionOptions) ToMap() map[string]any { + m := map[string]any{} + if d.ValidationCallback != nil { m["ValidationCallback"] = serializeValue(d.ValidationCallback) } + if d.PrimaryButtonText != nil { m["PrimaryButtonText"] = serializeValue(d.PrimaryButtonText) } + if d.SecondaryButtonText != nil { m["SecondaryButtonText"] = serializeValue(d.SecondaryButtonText) } + if d.ShowSecondaryButton != nil { m["ShowSecondaryButton"] = serializeValue(d.ShowSecondaryButton) } + if d.ShowDismiss != nil { m["ShowDismiss"] = serializeValue(d.ShowDismiss) } + if d.EnableMessageMarkdown != nil { m["EnableMessageMarkdown"] = serializeValue(d.EnableMessageMarkdown) } + return m +} + +// NotificationInteractionOptions represents NotificationInteractionOptions. +type NotificationInteractionOptions struct { + Intent *MessageIntent `json:"Intent,omitempty"` + LinkText *string `json:"LinkText,omitempty"` + LinkUrl *string `json:"LinkUrl,omitempty"` + PrimaryButtonText *string `json:"PrimaryButtonText,omitempty"` + SecondaryButtonText *string `json:"SecondaryButtonText,omitempty"` + ShowSecondaryButton *bool `json:"ShowSecondaryButton,omitempty"` + ShowDismiss *bool `json:"ShowDismiss,omitempty"` + EnableMessageMarkdown *bool `json:"EnableMessageMarkdown,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *NotificationInteractionOptions) ToMap() map[string]any { + m := map[string]any{} + if d.Intent != nil { m["Intent"] = serializeValue(d.Intent) } + if d.LinkText != nil { m["LinkText"] = serializeValue(d.LinkText) } + if d.LinkUrl != nil { m["LinkUrl"] = serializeValue(d.LinkUrl) } + if d.PrimaryButtonText != nil { m["PrimaryButtonText"] = serializeValue(d.PrimaryButtonText) } + if d.SecondaryButtonText != nil { m["SecondaryButtonText"] = serializeValue(d.SecondaryButtonText) } + if d.ShowSecondaryButton != nil { m["ShowSecondaryButton"] = serializeValue(d.ShowSecondaryButton) } + if d.ShowDismiss != nil { m["ShowDismiss"] = serializeValue(d.ShowDismiss) } + if d.EnableMessageMarkdown != nil { m["EnableMessageMarkdown"] = serializeValue(d.EnableMessageMarkdown) } + return m +} + +// BooleanInteractionResult represents BooleanInteractionResult. +type BooleanInteractionResult struct { + Data *bool `json:"Data,omitempty"` + Canceled bool `json:"Canceled,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *BooleanInteractionResult) ToMap() map[string]any { + m := map[string]any{} + if d.Data != nil { m["Data"] = serializeValue(d.Data) } + m["Canceled"] = serializeValue(d.Canceled) + return m +} + +// InputInteractionResult represents InputInteractionResult. +type InputInteractionResult struct { + Data *InteractionInput `json:"Data,omitempty"` + Canceled bool `json:"Canceled,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *InputInteractionResult) ToMap() map[string]any { + m := map[string]any{} + if d.Data != nil { m["Data"] = serializeValue(d.Data) } + m["Canceled"] = serializeValue(d.Canceled) + return m +} + +// InputsInteractionResult represents InputsInteractionResult. +type InputsInteractionResult struct { + Data *InteractionInputCollection `json:"Data,omitempty"` + Canceled bool `json:"Canceled,omitempty"` +} + +// ToMap converts the DTO to a map for JSON serialization. +func (d *InputsInteractionResult) ToMap() map[string]any { + m := map[string]any{} + if d.Data != nil { m["Data"] = serializeValue(d.Data) } + m["Canceled"] = serializeValue(d.Canceled) + return m +} + // ResourceEventDto represents ResourceEventDto. type ResourceEventDto struct { ResourceName string `json:"ResourceName,omitempty"` @@ -14166,6 +14326,7 @@ type ExecuteCommandContext interface { CancellationToken() (*CancellationToken, error) Logger() Logger ResourceName() (string, error) + ServiceProvider() ServiceProvider Err() error } @@ -14247,6 +14408,25 @@ func (s *executeCommandContext) ResourceName() (string, error) { return decodeAs[string](result) } +// ServiceProvider the service provider. +func (s *executeCommandContext) ServiceProvider() ServiceProvider { + if s.err != nil { return &serviceProvider{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)} } + ctx := context.Background() + reqArgs := map[string]any{ + "context": s.handle.ToJSON(), + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider", reqArgs) + if err != nil { + return &serviceProvider{resourceBuilderBase: newErroredResourceBuilder(err, s.client)} + } + href, ok := result.(handleReference) + if !ok { + err := fmt.Errorf("aspire: Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider returned unexpected type %T", result) + return &serviceProvider{resourceBuilderBase: newErroredResourceBuilder(err, s.client)} + } + return &serviceProvider{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)} +} + // ExecutionConfigurationBuilder is the public interface for handle type ExecutionConfigurationBuilder. type ExecutionConfigurationBuilder interface { handleReference @@ -15762,6 +15942,309 @@ func (s *interactionInputCollection) ToArray() ([]*InteractionInput, error) { return decodeAs[[]*InteractionInput](result) } +// InteractionService is the public interface for handle type InteractionService. +type InteractionService interface { + handleReference + IsAvailable() (bool, error) + PromptConfirmationAsync(title string, message string, options ...*PromptConfirmationAsyncOptions) (*BooleanInteractionResult, error) + PromptInputAsync(title string, message string, inputLabel string, placeHolder string, options ...*PromptInputAsyncOptions) (*InputInteractionResult, error) + PromptInputWithInputAsync(title string, message string, input *InteractionInput, options ...*PromptInputWithInputAsyncOptions) (*InputInteractionResult, error) + PromptInputsAsync(title string, message string, inputs []*InteractionInput, options ...*PromptInputsAsyncOptions) (*InputsInteractionResult, error) + PromptMessageBoxAsync(title string, message string, options ...*PromptMessageBoxAsyncOptions) (*BooleanInteractionResult, error) + PromptNotificationAsync(title string, message string, options ...*PromptNotificationAsyncOptions) (*BooleanInteractionResult, error) + Err() error +} + +// interactionService is the unexported impl of InteractionService. +type interactionService struct { + *resourceBuilderBase +} + +// newInteractionServiceFromHandle wraps an existing handle as InteractionService. +func newInteractionServiceFromHandle(h *handle, c *client) InteractionService { + return &interactionService{resourceBuilderBase: newResourceBuilderBase(h, c)} +} + +// IsAvailable gets a value indicating whether the interaction service is available. +func (s *interactionService) IsAvailable() (bool, error) { + if s.err != nil { var zero bool; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/interactionServiceIsAvailable", reqArgs) + if err != nil { + var zero bool + return zero, err + } + return decodeAs[bool](result) +} + +// PromptConfirmationAsync prompts the user for confirmation with a dialog. +func (s *interactionService) PromptConfirmationAsync(title string, message string, options ...*PromptConfirmationAsyncOptions) (*BooleanInteractionResult, error) { + if s.err != nil { var zero *BooleanInteractionResult; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + reqArgs["title"] = serializeValue(title) + reqArgs["message"] = serializeValue(message) + if len(options) > 0 { + merged := &PromptConfirmationAsyncOptions{} + for _, opt := range options { + if opt != nil { merged = deepUpdate(merged, opt) } + } + for k, v := range merged.ToMap() { reqArgs[k] = v } + if merged.CancellationToken != nil { + ctx = merged.CancellationToken.Context() + if id := s.client.registerCancellation(merged.CancellationToken); id != "" { + reqArgs["cancellationToken"] = id + } + } + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/promptConfirmationAsync", reqArgs) + if err != nil { + var zero *BooleanInteractionResult + return zero, err + } + return decodeAs[*BooleanInteractionResult](result) +} + +// PromptInputAsync prompts the user for a single text input. +func (s *interactionService) PromptInputAsync(title string, message string, inputLabel string, placeHolder string, options ...*PromptInputAsyncOptions) (*InputInteractionResult, error) { + if s.err != nil { var zero *InputInteractionResult; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + reqArgs["title"] = serializeValue(title) + reqArgs["message"] = serializeValue(message) + reqArgs["inputLabel"] = serializeValue(inputLabel) + reqArgs["placeHolder"] = serializeValue(placeHolder) + if len(options) > 0 { + merged := &PromptInputAsyncOptions{} + for _, opt := range options { + if opt != nil { merged = deepUpdate(merged, opt) } + } + for k, v := range merged.ToMap() { reqArgs[k] = v } + if merged.CancellationToken != nil { + ctx = merged.CancellationToken.Context() + if id := s.client.registerCancellation(merged.CancellationToken); id != "" { + reqArgs["cancellationToken"] = id + } + } + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/promptInputAsync", reqArgs) + if err != nil { + var zero *InputInteractionResult + return zero, err + } + return decodeAs[*InputInteractionResult](result) +} + +// PromptInputWithInputAsync prompts the user for a single input using a specified `InteractionInput`. +func (s *interactionService) PromptInputWithInputAsync(title string, message string, input *InteractionInput, options ...*PromptInputWithInputAsyncOptions) (*InputInteractionResult, error) { + if s.err != nil { var zero *InputInteractionResult; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + reqArgs["title"] = serializeValue(title) + reqArgs["message"] = serializeValue(message) + if input != nil { reqArgs["input"] = serializeValue(input) } + if len(options) > 0 { + merged := &PromptInputWithInputAsyncOptions{} + for _, opt := range options { + if opt != nil { merged = deepUpdate(merged, opt) } + } + for k, v := range merged.ToMap() { reqArgs[k] = v } + if merged.CancellationToken != nil { + ctx = merged.CancellationToken.Context() + if id := s.client.registerCancellation(merged.CancellationToken); id != "" { + reqArgs["cancellationToken"] = id + } + } + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/promptInputWithInput", reqArgs) + if err != nil { + var zero *InputInteractionResult + return zero, err + } + return decodeAs[*InputInteractionResult](result) +} + +// PromptInputsAsync prompts the user for multiple inputs. +func (s *interactionService) PromptInputsAsync(title string, message string, inputs []*InteractionInput, options ...*PromptInputsAsyncOptions) (*InputsInteractionResult, error) { + if s.err != nil { var zero *InputsInteractionResult; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + reqArgs["title"] = serializeValue(title) + reqArgs["message"] = serializeValue(message) + if inputs != nil { reqArgs["inputs"] = serializeValue(inputs) } + if len(options) > 0 { + merged := &PromptInputsAsyncOptions{} + for _, opt := range options { + if opt != nil { merged = deepUpdate(merged, opt) } + } + for k, v := range merged.ToMap() { reqArgs[k] = v } + if merged.CancellationToken != nil { + ctx = merged.CancellationToken.Context() + if id := s.client.registerCancellation(merged.CancellationToken); id != "" { + reqArgs["cancellationToken"] = id + } + } + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/promptInputsAsync", reqArgs) + if err != nil { + var zero *InputsInteractionResult + return zero, err + } + return decodeAs[*InputsInteractionResult](result) +} + +// PromptMessageBoxAsync prompts the user with a message box dialog. +func (s *interactionService) PromptMessageBoxAsync(title string, message string, options ...*PromptMessageBoxAsyncOptions) (*BooleanInteractionResult, error) { + if s.err != nil { var zero *BooleanInteractionResult; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + reqArgs["title"] = serializeValue(title) + reqArgs["message"] = serializeValue(message) + if len(options) > 0 { + merged := &PromptMessageBoxAsyncOptions{} + for _, opt := range options { + if opt != nil { merged = deepUpdate(merged, opt) } + } + for k, v := range merged.ToMap() { reqArgs[k] = v } + if merged.CancellationToken != nil { + ctx = merged.CancellationToken.Context() + if id := s.client.registerCancellation(merged.CancellationToken); id != "" { + reqArgs["cancellationToken"] = id + } + } + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/promptMessageBoxAsync", reqArgs) + if err != nil { + var zero *BooleanInteractionResult + return zero, err + } + return decodeAs[*BooleanInteractionResult](result) +} + +// PromptNotificationAsync prompts the user with a notification. +func (s *interactionService) PromptNotificationAsync(title string, message string, options ...*PromptNotificationAsyncOptions) (*BooleanInteractionResult, error) { + if s.err != nil { var zero *BooleanInteractionResult; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "interactionService": s.handle.ToJSON(), + } + reqArgs["title"] = serializeValue(title) + reqArgs["message"] = serializeValue(message) + if len(options) > 0 { + merged := &PromptNotificationAsyncOptions{} + for _, opt := range options { + if opt != nil { merged = deepUpdate(merged, opt) } + } + for k, v := range merged.ToMap() { reqArgs[k] = v } + if merged.CancellationToken != nil { + ctx = merged.CancellationToken.Context() + if id := s.client.registerCancellation(merged.CancellationToken); id != "" { + reqArgs["cancellationToken"] = id + } + } + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/promptNotificationAsync", reqArgs) + if err != nil { + var zero *BooleanInteractionResult + return zero, err + } + return decodeAs[*BooleanInteractionResult](result) +} + +// LoadInputContext is the public interface for handle type LoadInputContext. +type LoadInputContext interface { + handleReference + AllInputs() InteractionInputCollection + CancellationToken() (*CancellationToken, error) + Input() (*InteractionInput, error) + SetOptions(options map[string]string) error + Err() error +} + +// loadInputContext is the unexported impl of LoadInputContext. +type loadInputContext struct { + *resourceBuilderBase +} + +// newLoadInputContextFromHandle wraps an existing handle as LoadInputContext. +func newLoadInputContextFromHandle(h *handle, c *client) LoadInputContext { + return &loadInputContext{resourceBuilderBase: newResourceBuilderBase(h, c)} +} + +// AllInputs gets the collection of all `InteractionInput` in this prompt. +func (s *loadInputContext) AllInputs() InteractionInputCollection { + if s.err != nil { return &interactionInputCollection{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)} } + ctx := context.Background() + reqArgs := map[string]any{ + "context": s.handle.ToJSON(), + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/LoadInputContext.allInputs", reqArgs) + if err != nil { + return &interactionInputCollection{resourceBuilderBase: newErroredResourceBuilder(err, s.client)} + } + href, ok := result.(handleReference) + if !ok { + err := fmt.Errorf("aspire: Aspire.Hosting/LoadInputContext.allInputs returned unexpected type %T", result) + return &interactionInputCollection{resourceBuilderBase: newErroredResourceBuilder(err, s.client)} + } + return &interactionInputCollection{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)} +} + +// CancellationToken gets the `CancellationToken`. +func (s *loadInputContext) CancellationToken() (*CancellationToken, error) { + if s.err != nil { var zero *CancellationToken; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "context": s.handle.ToJSON(), + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/LoadInputContext.cancellationToken", reqArgs) + if err != nil { + var zero *CancellationToken + return zero, err + } + return decodeAs[*CancellationToken](result) +} + +// Input gets the loading input. This is the target of `InputLoadOptions`. +func (s *loadInputContext) Input() (*InteractionInput, error) { + if s.err != nil { var zero *InteractionInput; return zero, s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "context": s.handle.ToJSON(), + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/LoadInputContext.input", reqArgs) + if err != nil { + var zero *InteractionInput + return zero, err + } + return decodeAs[*InteractionInput](result) +} + +// SetOptions sets the available options for the loading input. +func (s *loadInputContext) SetOptions(options map[string]string) error { + if s.err != nil { return s.err } + ctx := context.Background() + reqArgs := map[string]any{ + "context": s.handle.ToJSON(), + } + if options != nil { reqArgs["options"] = serializeValue(options) } + _, err := s.client.invokeCapability(ctx, "Aspire.Hosting/LoadInputContext.setOptions", reqArgs) + return err +} + // LogFacade is the public interface for handle type LogFacade. type LogFacade interface { handleReference @@ -20329,6 +20812,7 @@ type ServiceProvider interface { GetAspireStore() AspireStore GetDistributedApplicationModel() DistributedApplicationModel GetEventing() DistributedApplicationEventing + GetInteractionService() InteractionService GetLoggerFactory() LoggerFactory GetResourceCommandService() ResourceCommandService GetResourceLoggerService() ResourceLoggerService @@ -20404,6 +20888,25 @@ func (s *serviceProvider) GetEventing() DistributedApplicationEventing { return &distributedApplicationEventing{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)} } +// GetInteractionService gets the interaction service from the service provider. +func (s *serviceProvider) GetInteractionService() InteractionService { + if s.err != nil { return &interactionService{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)} } + ctx := context.Background() + reqArgs := map[string]any{ + "serviceProvider": s.handle.ToJSON(), + } + result, err := s.client.invokeCapability(ctx, "Aspire.Hosting/getInteractionService", reqArgs) + if err != nil { + return &interactionService{resourceBuilderBase: newErroredResourceBuilder(err, s.client)} + } + href, ok := result.(handleReference) + if !ok { + err := fmt.Errorf("aspire: Aspire.Hosting/getInteractionService returned unexpected type %T", result) + return &interactionService{resourceBuilderBase: newErroredResourceBuilder(err, s.client)} + } + return &interactionService{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)} +} + // GetLoggerFactory gets the logger factory from the service provider. func (s *serviceProvider) GetLoggerFactory() LoggerFactory { if s.err != nil { return &loggerFactory{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)} } @@ -25874,6 +26377,84 @@ func (o *BuildOptions) ToMap() map[string]any { return m } +// PromptConfirmationAsyncOptions carries optional parameters for PromptConfirmationAsync. +type PromptConfirmationAsyncOptions struct { + Options *MessageBoxInteractionOptions `json:"options,omitempty"` + CancellationToken *CancellationToken `json:"-"` +} + +func (o *PromptConfirmationAsyncOptions) ToMap() map[string]any { + m := map[string]any{} + if o == nil { return m } + if o.Options != nil { m["options"] = serializeValue(o.Options) } + return m +} + +// PromptMessageBoxAsyncOptions carries optional parameters for PromptMessageBoxAsync. +type PromptMessageBoxAsyncOptions struct { + Options *MessageBoxInteractionOptions `json:"options,omitempty"` + CancellationToken *CancellationToken `json:"-"` +} + +func (o *PromptMessageBoxAsyncOptions) ToMap() map[string]any { + m := map[string]any{} + if o == nil { return m } + if o.Options != nil { m["options"] = serializeValue(o.Options) } + return m +} + +// PromptInputAsyncOptions carries optional parameters for PromptInputAsync. +type PromptInputAsyncOptions struct { + Options *InputsDialogInteractionOptions `json:"options,omitempty"` + CancellationToken *CancellationToken `json:"-"` +} + +func (o *PromptInputAsyncOptions) ToMap() map[string]any { + m := map[string]any{} + if o == nil { return m } + if o.Options != nil { m["options"] = serializeValue(o.Options) } + return m +} + +// PromptInputWithInputAsyncOptions carries optional parameters for PromptInputWithInputAsync. +type PromptInputWithInputAsyncOptions struct { + Options *InputsDialogInteractionOptions `json:"options,omitempty"` + CancellationToken *CancellationToken `json:"-"` +} + +func (o *PromptInputWithInputAsyncOptions) ToMap() map[string]any { + m := map[string]any{} + if o == nil { return m } + if o.Options != nil { m["options"] = serializeValue(o.Options) } + return m +} + +// PromptInputsAsyncOptions carries optional parameters for PromptInputsAsync. +type PromptInputsAsyncOptions struct { + Options *InputsDialogInteractionOptions `json:"options,omitempty"` + CancellationToken *CancellationToken `json:"-"` +} + +func (o *PromptInputsAsyncOptions) ToMap() map[string]any { + m := map[string]any{} + if o == nil { return m } + if o.Options != nil { m["options"] = serializeValue(o.Options) } + return m +} + +// PromptNotificationAsyncOptions carries optional parameters for PromptNotificationAsync. +type PromptNotificationAsyncOptions struct { + Options *NotificationInteractionOptions `json:"options,omitempty"` + CancellationToken *CancellationToken `json:"-"` +} + +func (o *PromptNotificationAsyncOptions) ToMap() map[string]any { + m := map[string]any{} + if o == nil { return m } + if o.Options != nil { m["options"] = serializeValue(o.Options) } + return m +} + // WaitForResourceStateOptions carries optional parameters for WaitForResourceState. type WaitForResourceStateOptions struct { TargetState *string `json:"targetState,omitempty"` @@ -26381,6 +26962,12 @@ func registerWrappers(c *client) { c.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.InteractionInputCollection", func(h *handle, c *client) any { return newInteractionInputCollectionFromHandle(h, c) }) + c.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.IInteractionService", func(h *handle, c *client) any { + return newInteractionServiceFromHandle(h, c) + }) + c.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.LoadInputContext", func(h *handle, c *client) any { + return newLoadInputContextFromHandle(h, c) + }) c.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.LogFacade", func(h *handle, c *client) any { return newLogFacadeFromHandle(h, c) }) diff --git a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java index 1511e3911c8..72f71bf9a16 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java +++ b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java @@ -1791,9 +1791,9 @@ public class TestDatabaseResource extends ResourceBuilderBase { } /** Adds an optional string parameter */ - public TestDatabaseResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public TestDatabaseResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -2002,8 +2002,8 @@ public TestDatabaseResource withCancellableOperation(AspireAction1 new ContainerImageReference(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerPortReference", (h, c) -> new ContainerPortReference(h, c)); AspireClient.registerHandleWrapper("System.ComponentModel/System.IServiceProvider", (h, c) -> new IServiceProvider(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.IInteractionService", (h, c) -> new IInteractionService(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService", (h, c) -> new ResourceNotificationService(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService", (h, c) -> new ResourceLoggerService(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceCommandService", (h, c) -> new ResourceCommandService(h, c)); @@ -1353,6 +1354,7 @@ public class AspireRegistrations { AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription", (h, c) -> new DistributedApplicationEventSubscription(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext", (h, c) -> new DistributedApplicationExecutionContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContextOptions", (h, c) -> new DistributedApplicationExecutionContextOptions(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.LoadInputContext", (h, c) -> new LoadInputContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.InteractionInputCollection", (h, c) -> new InteractionInputCollection(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext", (h, c) -> new InputsDialogValidationContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions", (h, c) -> new ProjectResourceOptions(h, c)); @@ -1595,6 +1597,42 @@ public DistributedApplicationModel model() { } +// ===== BooleanInteractionResult.java ===== +// BooleanInteractionResult.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** BooleanInteractionResult DTO. */ +public class BooleanInteractionResult implements JsonSerializable { + private Boolean data; + private boolean canceled; + + public Boolean getData() { return data; } + public void setData(Boolean value) { this.data = value; } + public boolean getCanceled() { return canceled; } + public void setCanceled(boolean value) { this.canceled = value; } + + @SuppressWarnings("unchecked") + public static BooleanInteractionResult fromMap(Map map) { + var value = new BooleanInteractionResult(); + var dataValue = map.get("Data"); + value.setData(dataValue == null ? null : (Boolean) dataValue); + var canceledValue = map.get("Canceled"); + value.setCanceled((Boolean) canceledValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("Data", AspireClient.serializeValue(data)); + map.put("Canceled", AspireClient.serializeValue(canceled)); + return map; + } +} + // ===== BuildOptions.java ===== // BuildOptions.java - GENERATED CODE - DO NOT EDIT @@ -1650,9 +1688,9 @@ public CSharpAppResource withContainerRegistry(ResourceBuilderBase registry) { } /** Configures custom base images for generated Dockerfiles. */ - public CSharpAppResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public CSharpAppResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -1675,9 +1713,9 @@ private CSharpAppResource withDockerfileBaseImageImpl(String buildImage, String } /** Marks the resource as hosting a Model Context Protocol (MCP) server on the specified endpoint. */ - public CSharpAppResource withMcpServer(WithMcpServerOptions options) { - var path = options == null ? null : options.getPath(); - var endpointName = options == null ? null : options.getEndpointName(); + public CSharpAppResource withMcpServer(WithMcpServerOptions optionsBag) { + var path = optionsBag == null ? null : optionsBag.getPath(); + var endpointName = optionsBag == null ? null : optionsBag.getEndpointName(); return withMcpServerImpl(path, endpointName); } @@ -1930,10 +1968,10 @@ public CSharpAppResource withReference(String source) { } /** Adds a reference to another resource */ - public CSharpAppResource withReference(AspireUnion source, WithReferenceOptions options) { - var connectionName = options == null ? null : options.getConnectionName(); - var optional = options == null ? null : options.getOptional(); - var name = options == null ? null : options.getName(); + public CSharpAppResource withReference(AspireUnion source, WithReferenceOptions optionsBag) { + var connectionName = optionsBag == null ? null : optionsBag.getConnectionName(); + var optional = optionsBag == null ? null : optionsBag.getOptional(); + var name = optionsBag == null ? null : optionsBag.getName(); return withReferenceImpl(source, connectionName, optional, name); } @@ -1984,9 +2022,9 @@ public CSharpAppResource withEndpointCallback(String endpointName, AspireAction1 } /** Updates an HTTP endpoint via callback */ - public CSharpAppResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public CSharpAppResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -2017,9 +2055,9 @@ private CSharpAppResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public CSharpAppResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -2050,15 +2088,15 @@ private CSharpAppResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public CSharpAppResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -2865,9 +2903,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public CSharpAppResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public CSharpAppResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -3116,9 +3154,9 @@ public CSharpAppResource withMergeEndpointScheme(String endpointName, double por } /** Configures resource logging */ - public CSharpAppResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public CSharpAppResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -3142,9 +3180,9 @@ private CSharpAppResource withMergeLoggingImpl(String logLevel, Boolean enableCo } /** Configures resource logging with file path */ - public CSharpAppResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public CSharpAppResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -4078,9 +4116,9 @@ public ContainerRegistryResource withContainerRegistry(ResourceBuilderBase regis } /** Configures custom base images for generated Dockerfiles. */ - public ContainerRegistryResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public ContainerRegistryResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -4370,9 +4408,9 @@ public ContainerRegistryResource withHidden() { } /** Hides the resource from default resource lists after successful completion */ - public ContainerRegistryResource withHiddenOnCompletion(WithHiddenOnCompletionOptions options) { - var exitCode = options == null ? null : options.getExitCode(); - var exitCodes = options == null ? null : options.getExitCodes(); + public ContainerRegistryResource withHiddenOnCompletion(WithHiddenOnCompletionOptions optionsBag) { + var exitCode = optionsBag == null ? null : optionsBag.getExitCode(); + var exitCodes = optionsBag == null ? null : optionsBag.getExitCodes(); return withHiddenOnCompletionImpl(exitCode, exitCodes); } @@ -4395,11 +4433,11 @@ private ContainerRegistryResource withHiddenOnCompletionImpl(Double exitCode, do } /** Adds a pipeline step to the resource that will be executed during deployment. */ - public ContainerRegistryResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public ContainerRegistryResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -4533,9 +4571,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public ContainerRegistryResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public ContainerRegistryResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -4759,9 +4797,9 @@ public ContainerRegistryResource withMergeEndpointScheme(String endpointName, do } /** Configures resource logging */ - public ContainerRegistryResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ContainerRegistryResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -4785,9 +4823,9 @@ private ContainerRegistryResource withMergeLoggingImpl(String logLevel, Boolean } /** Configures resource logging with file path */ - public ContainerRegistryResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ContainerRegistryResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -4970,9 +5008,9 @@ public ContainerResource publishAsContainer() { } /** Causes Aspire to build the specified container image from a Dockerfile. */ - public ContainerResource withDockerfile(String contextPath, WithDockerfileOptions options) { - var dockerfilePath = options == null ? null : options.getDockerfilePath(); - var stage = options == null ? null : options.getStage(); + public ContainerResource withDockerfile(String contextPath, WithDockerfileOptions optionsBag) { + var dockerfilePath = optionsBag == null ? null : optionsBag.getDockerfilePath(); + var stage = optionsBag == null ? null : optionsBag.getStage(); return withDockerfileImpl(contextPath, dockerfilePath, stage); } @@ -5056,10 +5094,10 @@ public ContainerResource withBuildSecret(String name, ParameterResource value) { } /** Adds container certificate path overrides used for certificate trust at run time. */ - public ContainerResource withContainerCertificatePaths(WithContainerCertificatePathsOptions options) { - var customCertificatesDestination = options == null ? null : options.getCustomCertificatesDestination(); - var defaultCertificateBundlePaths = options == null ? null : options.getDefaultCertificateBundlePaths(); - var defaultCertificateDirectoryPaths = options == null ? null : options.getDefaultCertificateDirectoryPaths(); + public ContainerResource withContainerCertificatePaths(WithContainerCertificatePathsOptions optionsBag) { + var customCertificatesDestination = optionsBag == null ? null : optionsBag.getCustomCertificatesDestination(); + var defaultCertificateBundlePaths = optionsBag == null ? null : optionsBag.getDefaultCertificateBundlePaths(); + var defaultCertificateDirectoryPaths = optionsBag == null ? null : optionsBag.getDefaultCertificateDirectoryPaths(); return withContainerCertificatePathsImpl(customCertificatesDestination, defaultCertificateBundlePaths, defaultCertificateDirectoryPaths); } @@ -5109,9 +5147,9 @@ public ContainerResource withDockerfileBuilder(String contextPath, AspireAction1 } /** Configures custom base images for generated Dockerfiles. */ - public ContainerResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public ContainerResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -5143,9 +5181,9 @@ public ContainerResource withContainerNetworkAlias(String alias) { } /** Marks the resource as hosting a Model Context Protocol (MCP) server on the specified endpoint. */ - public ContainerResource withMcpServer(WithMcpServerOptions options) { - var path = options == null ? null : options.getPath(); - var endpointName = options == null ? null : options.getEndpointName(); + public ContainerResource withMcpServer(WithMcpServerOptions optionsBag) { + var path = optionsBag == null ? null : optionsBag.getPath(); + var endpointName = optionsBag == null ? null : optionsBag.getEndpointName(); return withMcpServerImpl(path, endpointName); } @@ -5369,10 +5407,10 @@ public ContainerResource withReference(String source) { } /** Adds a reference to another resource */ - public ContainerResource withReference(AspireUnion source, WithReferenceOptions options) { - var connectionName = options == null ? null : options.getConnectionName(); - var optional = options == null ? null : options.getOptional(); - var name = options == null ? null : options.getName(); + public ContainerResource withReference(AspireUnion source, WithReferenceOptions optionsBag) { + var connectionName = optionsBag == null ? null : optionsBag.getConnectionName(); + var optional = optionsBag == null ? null : optionsBag.getOptional(); + var name = optionsBag == null ? null : optionsBag.getName(); return withReferenceImpl(source, connectionName, optional, name); } @@ -5423,9 +5461,9 @@ public ContainerResource withEndpointCallback(String endpointName, AspireAction1 } /** Updates an HTTP endpoint via callback */ - public ContainerResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public ContainerResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -5456,9 +5494,9 @@ private ContainerResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public ContainerResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -5489,15 +5527,15 @@ private ContainerResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public ContainerResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -6194,9 +6232,9 @@ public ContainerResource withPipelineConfiguration(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public DotnetToolResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -7728,9 +7766,9 @@ private DotnetToolResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public DotnetToolResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -7761,15 +7799,15 @@ private DotnetToolResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public DotnetToolResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -8562,9 +8600,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public DotnetToolResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public DotnetToolResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -8813,9 +8851,9 @@ public DotnetToolResource withMergeEndpointScheme(String endpointName, double po } /** Configures resource logging */ - public DotnetToolResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public DotnetToolResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -8839,9 +8877,9 @@ private DotnetToolResource withMergeLoggingImpl(String logLevel, Boolean enableC } /** Configures resource logging with file path */ - public DotnetToolResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public DotnetToolResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -9560,9 +9598,9 @@ public ExecutableResource withContainerRegistry(ResourceBuilderBase registry) { } /** Configures custom base images for generated Dockerfiles. */ - public ExecutableResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public ExecutableResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -9619,9 +9657,9 @@ public ExecutableResource withWorkingDirectory(String workingDirectory) { } /** Marks the resource as hosting a Model Context Protocol (MCP) server on the specified endpoint. */ - public ExecutableResource withMcpServer(WithMcpServerOptions options) { - var path = options == null ? null : options.getPath(); - var endpointName = options == null ? null : options.getEndpointName(); + public ExecutableResource withMcpServer(WithMcpServerOptions optionsBag) { + var path = optionsBag == null ? null : optionsBag.getPath(); + var endpointName = optionsBag == null ? null : optionsBag.getEndpointName(); return withMcpServerImpl(path, endpointName); } @@ -9837,10 +9875,10 @@ public ExecutableResource withReference(String source) { } /** Adds a reference to another resource */ - public ExecutableResource withReference(AspireUnion source, WithReferenceOptions options) { - var connectionName = options == null ? null : options.getConnectionName(); - var optional = options == null ? null : options.getOptional(); - var name = options == null ? null : options.getName(); + public ExecutableResource withReference(AspireUnion source, WithReferenceOptions optionsBag) { + var connectionName = optionsBag == null ? null : optionsBag.getConnectionName(); + var optional = optionsBag == null ? null : optionsBag.getOptional(); + var name = optionsBag == null ? null : optionsBag.getName(); return withReferenceImpl(source, connectionName, optional, name); } @@ -9891,9 +9929,9 @@ public ExecutableResource withEndpointCallback(String endpointName, AspireAction } /** Updates an HTTP endpoint via callback */ - public ExecutableResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public ExecutableResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -9924,9 +9962,9 @@ private ExecutableResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public ExecutableResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -9957,15 +9995,15 @@ private ExecutableResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public ExecutableResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -10758,9 +10796,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public ExecutableResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public ExecutableResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -11009,9 +11047,9 @@ public ExecutableResource withMergeEndpointScheme(String endpointName, double po } /** Configures resource logging */ - public ExecutableResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ExecutableResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -11035,9 +11073,9 @@ private ExecutableResource withMergeLoggingImpl(String logLevel, Boolean enableC } /** Configures resource logging with file path */ - public ExecutableResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ExecutableResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -11129,6 +11167,14 @@ public class ExecuteCommandContext extends HandleWrapperBase { super(handle, client); } + /** The service provider. */ + public IServiceProvider serviceProvider() { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + var result = getClient().invokeCapability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider", reqArgs); + return (IServiceProvider) result; + } + /** The resource name. */ public String resourceName() { Map reqArgs = new HashMap<>(); @@ -11245,9 +11291,9 @@ public ExternalServiceResource withContainerRegistry(ResourceBuilderBase registr } /** Configures custom base images for generated Dockerfiles. */ - public ExternalServiceResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public ExternalServiceResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -11270,10 +11316,10 @@ private ExternalServiceResource withDockerfileBaseImageImpl(String buildImage, S } /** Adds an HTTP health check to the external service for polyglot app hosts. */ - public ExternalServiceResource withHttpHealthCheck(WithHttpHealthCheckOptions options) { - var path = options == null ? null : options.getPath(); - var statusCode = options == null ? null : options.getStatusCode(); - var endpointName = options == null ? null : options.getEndpointName(); + public ExternalServiceResource withHttpHealthCheck(WithHttpHealthCheckOptions optionsBag) { + var path = optionsBag == null ? null : optionsBag.getPath(); + var statusCode = optionsBag == null ? null : optionsBag.getStatusCode(); + var endpointName = optionsBag == null ? null : optionsBag.getEndpointName(); return withHttpHealthCheckImpl(path, statusCode, endpointName); } @@ -11566,9 +11612,9 @@ public ExternalServiceResource withHidden() { } /** Hides the resource from default resource lists after successful completion */ - public ExternalServiceResource withHiddenOnCompletion(WithHiddenOnCompletionOptions options) { - var exitCode = options == null ? null : options.getExitCode(); - var exitCodes = options == null ? null : options.getExitCodes(); + public ExternalServiceResource withHiddenOnCompletion(WithHiddenOnCompletionOptions optionsBag) { + var exitCode = optionsBag == null ? null : optionsBag.getExitCode(); + var exitCodes = optionsBag == null ? null : optionsBag.getExitCodes(); return withHiddenOnCompletionImpl(exitCode, exitCodes); } @@ -11591,11 +11637,11 @@ private ExternalServiceResource withHiddenOnCompletionImpl(Double exitCode, doub } /** Adds a pipeline step to the resource that will be executed during deployment. */ - public ExternalServiceResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public ExternalServiceResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -11729,9 +11775,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public ExternalServiceResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public ExternalServiceResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -11955,9 +12001,9 @@ public ExternalServiceResource withMergeEndpointScheme(String endpointName, doub } /** Configures resource logging */ - public ExternalServiceResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ExternalServiceResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -11981,9 +12027,9 @@ private ExternalServiceResource withMergeLoggingImpl(String logLevel, Boolean en } /** Configures resource logging with file path */ - public ExternalServiceResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ExternalServiceResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -12727,9 +12773,9 @@ public ContainerResource addContainer(String name, AspireUnion image) { } /** Adds a Dockerfile to the application model that can be treated like a container resource. */ - public ContainerResource addDockerfile(String name, String contextPath, AddDockerfileOptions options) { - var dockerfilePath = options == null ? null : options.getDockerfilePath(); - var stage = options == null ? null : options.getStage(); + public ContainerResource addDockerfile(String name, String contextPath, AddDockerfileOptions optionsBag) { + var dockerfilePath = optionsBag == null ? null : optionsBag.getDockerfilePath(); + var stage = optionsBag == null ? null : optionsBag.getStage(); return addDockerfileImpl(name, contextPath, dockerfilePath, stage); } @@ -12899,10 +12945,10 @@ public DistributedApplication build() { } /** Adds a parameter resource */ - public ParameterResource addParameter(String name, AddParameterOptions options) { - var value = options == null ? null : options.getValue(); - var publishValueAsDefault = options == null ? null : options.getPublishValueAsDefault(); - var secret = options == null ? null : options.getSecret(); + public ParameterResource addParameter(String name, AddParameterOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var publishValueAsDefault = optionsBag == null ? null : optionsBag.getPublishValueAsDefault(); + var secret = optionsBag == null ? null : optionsBag.getSecret(); return addParameterImpl(name, value, publishValueAsDefault, secret); } @@ -12946,9 +12992,9 @@ public ParameterResource addParameterFromConfiguration(String name, String confi } /** Adds a parameter with a generated default value */ - public ParameterResource addParameterWithGeneratedValue(String name, GenerateParameterDefault value, AddParameterWithGeneratedValueOptions options) { - var secret = options == null ? null : options.getSecret(); - var persist = options == null ? null : options.getPersist(); + public ParameterResource addParameterWithGeneratedValue(String name, GenerateParameterDefault value, AddParameterWithGeneratedValueOptions optionsBag) { + var secret = optionsBag == null ? null : optionsBag.getSecret(); + var persist = optionsBag == null ? null : optionsBag.getPersist(); return addParameterWithGeneratedValueImpl(name, value, secret, persist); } @@ -13230,9 +13276,9 @@ public IDistributedApplicationPipeline disableBuildOnlyContainerValidation() { } /** Adds an application-level pipeline step in a TypeScript-friendly shape. */ - public void addStep(String stepName, AspireAction1 callback, AddStepOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); + public void addStep(String stepName, AspireAction1 callback, AddStepOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); addStepImpl(stepName, callback, dependsOn, requiredBy); } @@ -13310,9 +13356,9 @@ public class IExecutionConfigurationBuilder extends HandleWrapperBase { } /** Builds the execution configuration for the specified builder. */ - public IExecutionConfigurationResult build(DistributedApplicationExecutionContext executionContext, BuildOptions options) { - var resourceLogger = options == null ? null : options.getResourceLogger(); - var cancellationToken = options == null ? null : options.getCancellationToken(); + public IExecutionConfigurationResult build(DistributedApplicationExecutionContext executionContext, BuildOptions optionsBag) { + var resourceLogger = optionsBag == null ? null : optionsBag.getResourceLogger(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); return buildImpl(executionContext, resourceLogger, cancellationToken); } @@ -13531,6 +13577,196 @@ public boolean isEnvironment(String environmentName) { } +// ===== IInteractionService.java ===== +// IInteractionService.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Wrapper for Aspire.Hosting/Aspire.Hosting.IInteractionService. */ +public class IInteractionService extends HandleWrapperBase { + IInteractionService(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Gets a value indicating whether the interaction service is available. */ + public boolean isAvailable() { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + var result = getClient().invokeCapability("Aspire.Hosting/interactionServiceIsAvailable", reqArgs); + return (Boolean) result; + } + + /** Prompts the user for confirmation with a dialog. */ + public BooleanInteractionResult promptConfirmationAsync(String title, String message, PromptConfirmationAsyncOptions optionsBag) { + var options = optionsBag == null ? null : optionsBag.getOptions(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); + return promptConfirmationAsyncImpl(title, message, options, cancellationToken); + } + + public BooleanInteractionResult promptConfirmationAsync(String title, String message) { + return promptConfirmationAsync(title, message, null); + } + + /** Prompts the user for confirmation with a dialog. */ + private BooleanInteractionResult promptConfirmationAsyncImpl(String title, String message, MessageBoxInteractionOptions options, CancellationToken cancellationToken) { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + reqArgs.put("title", AspireClient.serializeValue(title)); + reqArgs.put("message", AspireClient.serializeValue(message)); + if (options != null) { + reqArgs.put("options", AspireClient.serializeValue(options)); + } + if (cancellationToken != null) { + reqArgs.put("cancellationToken", getClient().registerCancellation(cancellationToken)); + } + var result = getClient().invokeCapability("Aspire.Hosting/promptConfirmationAsync", reqArgs); + return BooleanInteractionResult.fromMap((Map) result); + } + + /** Prompts the user with a message box dialog. */ + public BooleanInteractionResult promptMessageBoxAsync(String title, String message, PromptMessageBoxAsyncOptions optionsBag) { + var options = optionsBag == null ? null : optionsBag.getOptions(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); + return promptMessageBoxAsyncImpl(title, message, options, cancellationToken); + } + + public BooleanInteractionResult promptMessageBoxAsync(String title, String message) { + return promptMessageBoxAsync(title, message, null); + } + + /** Prompts the user with a message box dialog. */ + private BooleanInteractionResult promptMessageBoxAsyncImpl(String title, String message, MessageBoxInteractionOptions options, CancellationToken cancellationToken) { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + reqArgs.put("title", AspireClient.serializeValue(title)); + reqArgs.put("message", AspireClient.serializeValue(message)); + if (options != null) { + reqArgs.put("options", AspireClient.serializeValue(options)); + } + if (cancellationToken != null) { + reqArgs.put("cancellationToken", getClient().registerCancellation(cancellationToken)); + } + var result = getClient().invokeCapability("Aspire.Hosting/promptMessageBoxAsync", reqArgs); + return BooleanInteractionResult.fromMap((Map) result); + } + + /** Prompts the user for a single text input. */ + public InputInteractionResult promptInputAsync(String title, String message, String inputLabel, String placeHolder, PromptInputAsyncOptions optionsBag) { + var options = optionsBag == null ? null : optionsBag.getOptions(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); + return promptInputAsyncImpl(title, message, inputLabel, placeHolder, options, cancellationToken); + } + + public InputInteractionResult promptInputAsync(String title, String message, String inputLabel, String placeHolder) { + return promptInputAsync(title, message, inputLabel, placeHolder, null); + } + + /** Prompts the user for a single text input. */ + private InputInteractionResult promptInputAsyncImpl(String title, String message, String inputLabel, String placeHolder, InputsDialogInteractionOptions options, CancellationToken cancellationToken) { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + reqArgs.put("title", AspireClient.serializeValue(title)); + reqArgs.put("message", AspireClient.serializeValue(message)); + reqArgs.put("inputLabel", AspireClient.serializeValue(inputLabel)); + reqArgs.put("placeHolder", AspireClient.serializeValue(placeHolder)); + if (options != null) { + reqArgs.put("options", AspireClient.serializeValue(options)); + } + if (cancellationToken != null) { + reqArgs.put("cancellationToken", getClient().registerCancellation(cancellationToken)); + } + var result = getClient().invokeCapability("Aspire.Hosting/promptInputAsync", reqArgs); + return InputInteractionResult.fromMap((Map) result); + } + + /** Prompts the user for a single input using a specified `InteractionInput`. */ + public InputInteractionResult promptInputWithInputAsync(String title, String message, InteractionInput input, PromptInputWithInputAsyncOptions optionsBag) { + var options = optionsBag == null ? null : optionsBag.getOptions(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); + return promptInputWithInputAsyncImpl(title, message, input, options, cancellationToken); + } + + public InputInteractionResult promptInputWithInputAsync(String title, String message, InteractionInput input) { + return promptInputWithInputAsync(title, message, input, null); + } + + /** Prompts the user for a single input using a specified `InteractionInput`. */ + private InputInteractionResult promptInputWithInputAsyncImpl(String title, String message, InteractionInput input, InputsDialogInteractionOptions options, CancellationToken cancellationToken) { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + reqArgs.put("title", AspireClient.serializeValue(title)); + reqArgs.put("message", AspireClient.serializeValue(message)); + reqArgs.put("input", AspireClient.serializeValue(input)); + if (options != null) { + reqArgs.put("options", AspireClient.serializeValue(options)); + } + if (cancellationToken != null) { + reqArgs.put("cancellationToken", getClient().registerCancellation(cancellationToken)); + } + var result = getClient().invokeCapability("Aspire.Hosting/promptInputWithInput", reqArgs); + return InputInteractionResult.fromMap((Map) result); + } + + /** Prompts the user for multiple inputs. */ + public InputsInteractionResult promptInputsAsync(String title, String message, InteractionInput[] inputs, PromptInputsAsyncOptions optionsBag) { + var options = optionsBag == null ? null : optionsBag.getOptions(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); + return promptInputsAsyncImpl(title, message, inputs, options, cancellationToken); + } + + public InputsInteractionResult promptInputsAsync(String title, String message, InteractionInput[] inputs) { + return promptInputsAsync(title, message, inputs, null); + } + + /** Prompts the user for multiple inputs. */ + private InputsInteractionResult promptInputsAsyncImpl(String title, String message, InteractionInput[] inputs, InputsDialogInteractionOptions options, CancellationToken cancellationToken) { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + reqArgs.put("title", AspireClient.serializeValue(title)); + reqArgs.put("message", AspireClient.serializeValue(message)); + reqArgs.put("inputs", AspireClient.serializeValue(inputs)); + if (options != null) { + reqArgs.put("options", AspireClient.serializeValue(options)); + } + if (cancellationToken != null) { + reqArgs.put("cancellationToken", getClient().registerCancellation(cancellationToken)); + } + var result = getClient().invokeCapability("Aspire.Hosting/promptInputsAsync", reqArgs); + return InputsInteractionResult.fromMap((Map) result); + } + + /** Prompts the user with a notification. */ + public BooleanInteractionResult promptNotificationAsync(String title, String message, PromptNotificationAsyncOptions optionsBag) { + var options = optionsBag == null ? null : optionsBag.getOptions(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); + return promptNotificationAsyncImpl(title, message, options, cancellationToken); + } + + public BooleanInteractionResult promptNotificationAsync(String title, String message) { + return promptNotificationAsync(title, message, null); + } + + /** Prompts the user with a notification. */ + private BooleanInteractionResult promptNotificationAsyncImpl(String title, String message, NotificationInteractionOptions options, CancellationToken cancellationToken) { + Map reqArgs = new HashMap<>(); + reqArgs.put("interactionService", AspireClient.serializeValue(getHandle())); + reqArgs.put("title", AspireClient.serializeValue(title)); + reqArgs.put("message", AspireClient.serializeValue(message)); + if (options != null) { + reqArgs.put("options", AspireClient.serializeValue(options)); + } + if (cancellationToken != null) { + reqArgs.put("cancellationToken", getClient().registerCancellation(cancellationToken)); + } + var result = getClient().invokeCapability("Aspire.Hosting/promptNotificationAsync", reqArgs); + return BooleanInteractionResult.fromMap((Map) result); + } + +} + // ===== ILogger.java ===== // ILogger.java - GENERATED CODE - DO NOT EDIT @@ -13678,9 +13914,9 @@ public void logStepMarkdown(String level, String markdownString) { } /** Completes the reporting step with plain-text completion text. */ - public void completeStep(String completionText, CompleteStepOptions options) { - var completionState = options == null ? null : options.getCompletionState(); - var cancellationToken = options == null ? null : options.getCancellationToken(); + public void completeStep(String completionText, CompleteStepOptions optionsBag) { + var completionState = optionsBag == null ? null : optionsBag.getCompletionState(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); completeStepImpl(completionText, completionState, cancellationToken); } @@ -13703,9 +13939,9 @@ private void completeStepImpl(String completionText, String completionState, Can } /** Completes the reporting step with Markdown-formatted completion text. */ - public void completeStepMarkdown(String markdownString, CompleteStepMarkdownOptions options) { - var completionState = options == null ? null : options.getCompletionState(); - var cancellationToken = options == null ? null : options.getCancellationToken(); + public void completeStepMarkdown(String markdownString, CompleteStepMarkdownOptions optionsBag) { + var completionState = optionsBag == null ? null : optionsBag.getCompletionState(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); completeStepMarkdownImpl(markdownString, completionState, cancellationToken); } @@ -13774,10 +14010,10 @@ public void updateTaskMarkdown(String markdownString, CancellationToken cancella } /** Completes the reporting task with plain-text completion text. */ - public void completeTask(CompleteTaskOptions options) { - var completionMessage = options == null ? null : options.getCompletionMessage(); - var completionState = options == null ? null : options.getCompletionState(); - var cancellationToken = options == null ? null : options.getCancellationToken(); + public void completeTask(CompleteTaskOptions optionsBag) { + var completionMessage = optionsBag == null ? null : optionsBag.getCompletionMessage(); + var completionState = optionsBag == null ? null : optionsBag.getCompletionState(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); completeTaskImpl(completionMessage, completionState, cancellationToken); } @@ -13802,9 +14038,9 @@ private void completeTaskImpl(String completionMessage, String completionState, } /** Completes the reporting task with Markdown-formatted completion text. */ - public void completeTaskMarkdown(String markdownString, CompleteTaskMarkdownOptions options) { - var completionState = options == null ? null : options.getCompletionState(); - var cancellationToken = options == null ? null : options.getCancellationToken(); + public void completeTaskMarkdown(String markdownString, CompleteTaskMarkdownOptions optionsBag) { + var completionState = optionsBag == null ? null : optionsBag.getCompletionState(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); completeTaskMarkdownImpl(markdownString, completionState, cancellationToken); } @@ -13995,6 +14231,14 @@ public IDistributedApplicationEventing getEventing() { return (IDistributedApplicationEventing) result; } + /** Gets the interaction service from the service provider. */ + public IInteractionService getInteractionService() { + Map reqArgs = new HashMap<>(); + reqArgs.put("serviceProvider", AspireClient.serializeValue(getHandle())); + var result = getClient().invokeCapability("Aspire.Hosting/getInteractionService", reqArgs); + return (IInteractionService) result; + } + /** Gets the logger factory from the service provider. */ public ILoggerFactory getLoggerFactory() { Map reqArgs = new HashMap<>(); @@ -14265,6 +14509,84 @@ public IServiceProvider services() { } +// ===== InputInteractionResult.java ===== +// InputInteractionResult.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** InputInteractionResult DTO. */ +public class InputInteractionResult implements JsonSerializable { + private InteractionInput data; + private boolean canceled; + + public InteractionInput getData() { return data; } + public void setData(InteractionInput value) { this.data = value; } + public boolean getCanceled() { return canceled; } + public void setCanceled(boolean value) { this.canceled = value; } + + @SuppressWarnings("unchecked") + public static InputInteractionResult fromMap(Map map) { + var value = new InputInteractionResult(); + var dataValue = map.get("Data"); + value.setData(dataValue == null ? null : InteractionInput.fromMap((Map) dataValue)); + var canceledValue = map.get("Canceled"); + value.setCanceled((Boolean) canceledValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("Data", AspireClient.serializeValue(data)); + map.put("Canceled", AspireClient.serializeValue(canceled)); + return map; + } +} + +// ===== InputLoadOptions.java ===== +// InputLoadOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** InputLoadOptions DTO. */ +public class InputLoadOptions implements JsonSerializable { + private Object loadCallback; + private Boolean alwaysLoadOnStart; + private String[] dependsOnInputs; + + public Object getLoadCallback() { return loadCallback; } + public void setLoadCallback(Object value) { this.loadCallback = value; } + public Boolean getAlwaysLoadOnStart() { return alwaysLoadOnStart; } + public void setAlwaysLoadOnStart(Boolean value) { this.alwaysLoadOnStart = value; } + public String[] getDependsOnInputs() { return dependsOnInputs; } + public void setDependsOnInputs(String[] value) { this.dependsOnInputs = value; } + + @SuppressWarnings("unchecked") + public static InputLoadOptions fromMap(Map map) { + var value = new InputLoadOptions(); + var loadCallbackValue = map.get("LoadCallback"); + value.setLoadCallback(loadCallbackValue); + var alwaysLoadOnStartValue = map.get("AlwaysLoadOnStart"); + value.setAlwaysLoadOnStart(alwaysLoadOnStartValue == null ? null : (Boolean) alwaysLoadOnStartValue); + var dependsOnInputsValue = map.get("DependsOnInputs"); + value.setDependsOnInputs((String[]) dependsOnInputsValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("LoadCallback", AspireClient.serializeValue(loadCallback)); + map.put("AlwaysLoadOnStart", AspireClient.serializeValue(alwaysLoadOnStart)); + map.put("DependsOnInputs", AspireClient.serializeValue(dependsOnInputs)); + return map; + } +} + // ===== InputType.java ===== // InputType.java - GENERATED CODE - DO NOT EDIT @@ -14297,6 +14619,66 @@ public static InputType fromValue(String value) { } } +// ===== InputsDialogInteractionOptions.java ===== +// InputsDialogInteractionOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** InputsDialogInteractionOptions DTO. */ +public class InputsDialogInteractionOptions implements JsonSerializable { + private Object validationCallback; + private String primaryButtonText; + private String secondaryButtonText; + private Boolean showSecondaryButton; + private Boolean showDismiss; + private Boolean enableMessageMarkdown; + + public Object getValidationCallback() { return validationCallback; } + public void setValidationCallback(Object value) { this.validationCallback = value; } + public String getPrimaryButtonText() { return primaryButtonText; } + public void setPrimaryButtonText(String value) { this.primaryButtonText = value; } + public String getSecondaryButtonText() { return secondaryButtonText; } + public void setSecondaryButtonText(String value) { this.secondaryButtonText = value; } + public Boolean getShowSecondaryButton() { return showSecondaryButton; } + public void setShowSecondaryButton(Boolean value) { this.showSecondaryButton = value; } + public Boolean getShowDismiss() { return showDismiss; } + public void setShowDismiss(Boolean value) { this.showDismiss = value; } + public Boolean getEnableMessageMarkdown() { return enableMessageMarkdown; } + public void setEnableMessageMarkdown(Boolean value) { this.enableMessageMarkdown = value; } + + @SuppressWarnings("unchecked") + public static InputsDialogInteractionOptions fromMap(Map map) { + var value = new InputsDialogInteractionOptions(); + var validationCallbackValue = map.get("ValidationCallback"); + value.setValidationCallback(validationCallbackValue); + var primaryButtonTextValue = map.get("PrimaryButtonText"); + value.setPrimaryButtonText(primaryButtonTextValue == null ? null : (String) primaryButtonTextValue); + var secondaryButtonTextValue = map.get("SecondaryButtonText"); + value.setSecondaryButtonText(secondaryButtonTextValue == null ? null : (String) secondaryButtonTextValue); + var showSecondaryButtonValue = map.get("ShowSecondaryButton"); + value.setShowSecondaryButton(showSecondaryButtonValue == null ? null : (Boolean) showSecondaryButtonValue); + var showDismissValue = map.get("ShowDismiss"); + value.setShowDismiss(showDismissValue == null ? null : (Boolean) showDismissValue); + var enableMessageMarkdownValue = map.get("EnableMessageMarkdown"); + value.setEnableMessageMarkdown(enableMessageMarkdownValue == null ? null : (Boolean) enableMessageMarkdownValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("ValidationCallback", AspireClient.serializeValue(validationCallback)); + map.put("PrimaryButtonText", AspireClient.serializeValue(primaryButtonText)); + map.put("SecondaryButtonText", AspireClient.serializeValue(secondaryButtonText)); + map.put("ShowSecondaryButton", AspireClient.serializeValue(showSecondaryButton)); + map.put("ShowDismiss", AspireClient.serializeValue(showDismiss)); + map.put("EnableMessageMarkdown", AspireClient.serializeValue(enableMessageMarkdown)); + return map; + } +} + // ===== InputsDialogValidationContext.java ===== // InputsDialogValidationContext.java - GENERATED CODE - DO NOT EDIT @@ -14338,6 +14720,42 @@ public void addValidationError(String inputName, String errorMessage) { } +// ===== InputsInteractionResult.java ===== +// InputsInteractionResult.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** InputsInteractionResult DTO. */ +public class InputsInteractionResult implements JsonSerializable { + private InteractionInputCollection data; + private boolean canceled; + + public InteractionInputCollection getData() { return data; } + public void setData(InteractionInputCollection value) { this.data = value; } + public boolean getCanceled() { return canceled; } + public void setCanceled(boolean value) { this.canceled = value; } + + @SuppressWarnings("unchecked") + public static InputsInteractionResult fromMap(Map map) { + var value = new InputsInteractionResult(); + var dataValue = map.get("Data"); + value.setData((InteractionInputCollection) dataValue); + var canceledValue = map.get("Canceled"); + value.setCanceled((Boolean) canceledValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("Data", AspireClient.serializeValue(data)); + map.put("Canceled", AspireClient.serializeValue(canceled)); + return map; + } +} + // ===== InteractionInput.java ===== // InteractionInput.java - GENERATED CODE - DO NOT EDIT @@ -14355,7 +14773,7 @@ public class InteractionInput implements JsonSerializable { private InputType inputType; private Boolean required; private Object[] options; - private Object dynamicLoading; + private InputLoadOptions dynamicLoading; private String value; private String placeholder; private Boolean allowCustomChoice; @@ -14376,8 +14794,8 @@ public class InteractionInput implements JsonSerializable { public void setRequired(Boolean value) { this.required = value; } public Object[] getOptions() { return options; } public void setOptions(Object[] value) { this.options = value; } - public Object getDynamicLoading() { return dynamicLoading; } - public void setDynamicLoading(Object value) { this.dynamicLoading = value; } + public InputLoadOptions getDynamicLoading() { return dynamicLoading; } + public void setDynamicLoading(InputLoadOptions value) { this.dynamicLoading = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getPlaceholder() { return placeholder; } @@ -14407,7 +14825,7 @@ public static InteractionInput fromMap(Map map) { var optionsValue = map.get("Options"); value.setOptions((Object[]) optionsValue); var dynamicLoadingValue = map.get("DynamicLoading"); - value.setDynamicLoading(dynamicLoadingValue); + value.setDynamicLoading(dynamicLoadingValue == null ? null : InputLoadOptions.fromMap((Map) dynamicLoadingValue)); var valueValue = map.get("Value"); value.setValue(valueValue == null ? null : (String) valueValue); var placeholderValue = map.get("Placeholder"); @@ -14464,6 +14882,60 @@ public InteractionInput[] toArray() { } +// ===== InteractionOptions.java ===== +// InteractionOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** InteractionOptions DTO. */ +public class InteractionOptions implements JsonSerializable { + private String primaryButtonText; + private String secondaryButtonText; + private Boolean showSecondaryButton; + private Boolean showDismiss; + private Boolean enableMessageMarkdown; + + public String getPrimaryButtonText() { return primaryButtonText; } + public void setPrimaryButtonText(String value) { this.primaryButtonText = value; } + public String getSecondaryButtonText() { return secondaryButtonText; } + public void setSecondaryButtonText(String value) { this.secondaryButtonText = value; } + public Boolean getShowSecondaryButton() { return showSecondaryButton; } + public void setShowSecondaryButton(Boolean value) { this.showSecondaryButton = value; } + public Boolean getShowDismiss() { return showDismiss; } + public void setShowDismiss(Boolean value) { this.showDismiss = value; } + public Boolean getEnableMessageMarkdown() { return enableMessageMarkdown; } + public void setEnableMessageMarkdown(Boolean value) { this.enableMessageMarkdown = value; } + + @SuppressWarnings("unchecked") + public static InteractionOptions fromMap(Map map) { + var value = new InteractionOptions(); + var primaryButtonTextValue = map.get("PrimaryButtonText"); + value.setPrimaryButtonText(primaryButtonTextValue == null ? null : (String) primaryButtonTextValue); + var secondaryButtonTextValue = map.get("SecondaryButtonText"); + value.setSecondaryButtonText(secondaryButtonTextValue == null ? null : (String) secondaryButtonTextValue); + var showSecondaryButtonValue = map.get("ShowSecondaryButton"); + value.setShowSecondaryButton(showSecondaryButtonValue == null ? null : (Boolean) showSecondaryButtonValue); + var showDismissValue = map.get("ShowDismiss"); + value.setShowDismiss(showDismissValue == null ? null : (Boolean) showDismissValue); + var enableMessageMarkdownValue = map.get("EnableMessageMarkdown"); + value.setEnableMessageMarkdown(enableMessageMarkdownValue == null ? null : (Boolean) enableMessageMarkdownValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("PrimaryButtonText", AspireClient.serializeValue(primaryButtonText)); + map.put("SecondaryButtonText", AspireClient.serializeValue(secondaryButtonText)); + map.put("ShowSecondaryButton", AspireClient.serializeValue(showSecondaryButton)); + map.put("ShowDismiss", AspireClient.serializeValue(showDismiss)); + map.put("EnableMessageMarkdown", AspireClient.serializeValue(enableMessageMarkdown)); + return map; + } +} + // ===== JsonSerializable.java ===== // JsonSerializable.java - GENERATED CODE - DO NOT EDIT @@ -14481,6 +14953,54 @@ public interface JsonSerializable { Map toMap(); } +// ===== LoadInputContext.java ===== +// LoadInputContext.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Wrapper for Aspire.Hosting/Aspire.Hosting.LoadInputContext. */ +public class LoadInputContext extends HandleWrapperBase { + LoadInputContext(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Gets the loading input. This is the target of `InputLoadOptions`. */ + public InteractionInput input() { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + var result = getClient().invokeCapability("Aspire.Hosting/LoadInputContext.input", reqArgs); + return InteractionInput.fromMap((Map) result); + } + + /** Gets the collection of all `InteractionInput` in this prompt. */ + public InteractionInputCollection allInputs() { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + var result = getClient().invokeCapability("Aspire.Hosting/LoadInputContext.allInputs", reqArgs); + return (InteractionInputCollection) result; + } + + /** Gets the `CancellationToken`. */ + public CancellationToken cancellationToken() { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + var result = getClient().invokeCapability("Aspire.Hosting/LoadInputContext.cancellationToken", reqArgs); + return (CancellationToken) result; + } + + /** Sets the available options for the loading input. */ + public void setOptions(Map options) { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + reqArgs.put("options", AspireClient.serializeValue(options)); + getClient().invokeCapability("Aspire.Hosting/LoadInputContext.setOptions", reqArgs); + } + +} + // ===== LogFacade.java ===== // LogFacade.java - GENERATED CODE - DO NOT EDIT @@ -14529,6 +15049,171 @@ public void debug(String message) { } +// ===== MessageBoxInteractionOptions.java ===== +// MessageBoxInteractionOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** MessageBoxInteractionOptions DTO. */ +public class MessageBoxInteractionOptions implements JsonSerializable { + private MessageIntent intent; + private String primaryButtonText; + private String secondaryButtonText; + private Boolean showSecondaryButton; + private Boolean showDismiss; + private Boolean enableMessageMarkdown; + + public MessageIntent getIntent() { return intent; } + public void setIntent(MessageIntent value) { this.intent = value; } + public String getPrimaryButtonText() { return primaryButtonText; } + public void setPrimaryButtonText(String value) { this.primaryButtonText = value; } + public String getSecondaryButtonText() { return secondaryButtonText; } + public void setSecondaryButtonText(String value) { this.secondaryButtonText = value; } + public Boolean getShowSecondaryButton() { return showSecondaryButton; } + public void setShowSecondaryButton(Boolean value) { this.showSecondaryButton = value; } + public Boolean getShowDismiss() { return showDismiss; } + public void setShowDismiss(Boolean value) { this.showDismiss = value; } + public Boolean getEnableMessageMarkdown() { return enableMessageMarkdown; } + public void setEnableMessageMarkdown(Boolean value) { this.enableMessageMarkdown = value; } + + @SuppressWarnings("unchecked") + public static MessageBoxInteractionOptions fromMap(Map map) { + var value = new MessageBoxInteractionOptions(); + var intentValue = map.get("Intent"); + value.setIntent(intentValue == null ? null : MessageIntent.fromValue((String) intentValue)); + var primaryButtonTextValue = map.get("PrimaryButtonText"); + value.setPrimaryButtonText(primaryButtonTextValue == null ? null : (String) primaryButtonTextValue); + var secondaryButtonTextValue = map.get("SecondaryButtonText"); + value.setSecondaryButtonText(secondaryButtonTextValue == null ? null : (String) secondaryButtonTextValue); + var showSecondaryButtonValue = map.get("ShowSecondaryButton"); + value.setShowSecondaryButton(showSecondaryButtonValue == null ? null : (Boolean) showSecondaryButtonValue); + var showDismissValue = map.get("ShowDismiss"); + value.setShowDismiss(showDismissValue == null ? null : (Boolean) showDismissValue); + var enableMessageMarkdownValue = map.get("EnableMessageMarkdown"); + value.setEnableMessageMarkdown(enableMessageMarkdownValue == null ? null : (Boolean) enableMessageMarkdownValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("Intent", AspireClient.serializeValue(intent)); + map.put("PrimaryButtonText", AspireClient.serializeValue(primaryButtonText)); + map.put("SecondaryButtonText", AspireClient.serializeValue(secondaryButtonText)); + map.put("ShowSecondaryButton", AspireClient.serializeValue(showSecondaryButton)); + map.put("ShowDismiss", AspireClient.serializeValue(showDismiss)); + map.put("EnableMessageMarkdown", AspireClient.serializeValue(enableMessageMarkdown)); + return map; + } +} + +// ===== MessageIntent.java ===== +// MessageIntent.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** MessageIntent enum. */ +public enum MessageIntent implements WireValueEnum { + NONE("None"), + SUCCESS("Success"), + WARNING("Warning"), + ERROR("Error"), + INFORMATION("Information"), + CONFIRMATION("Confirmation"); + + private final String value; + + MessageIntent(String value) { + this.value = value; + } + + public String getValue() { return value; } + + public static MessageIntent fromValue(String value) { + for (MessageIntent e : values()) { + if (e.value.equals(value)) return e; + } + throw new IllegalArgumentException("Unknown value: " + value); + } +} + +// ===== NotificationInteractionOptions.java ===== +// NotificationInteractionOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** NotificationInteractionOptions DTO. */ +public class NotificationInteractionOptions implements JsonSerializable { + private MessageIntent intent; + private String linkText; + private String linkUrl; + private String primaryButtonText; + private String secondaryButtonText; + private Boolean showSecondaryButton; + private Boolean showDismiss; + private Boolean enableMessageMarkdown; + + public MessageIntent getIntent() { return intent; } + public void setIntent(MessageIntent value) { this.intent = value; } + public String getLinkText() { return linkText; } + public void setLinkText(String value) { this.linkText = value; } + public String getLinkUrl() { return linkUrl; } + public void setLinkUrl(String value) { this.linkUrl = value; } + public String getPrimaryButtonText() { return primaryButtonText; } + public void setPrimaryButtonText(String value) { this.primaryButtonText = value; } + public String getSecondaryButtonText() { return secondaryButtonText; } + public void setSecondaryButtonText(String value) { this.secondaryButtonText = value; } + public Boolean getShowSecondaryButton() { return showSecondaryButton; } + public void setShowSecondaryButton(Boolean value) { this.showSecondaryButton = value; } + public Boolean getShowDismiss() { return showDismiss; } + public void setShowDismiss(Boolean value) { this.showDismiss = value; } + public Boolean getEnableMessageMarkdown() { return enableMessageMarkdown; } + public void setEnableMessageMarkdown(Boolean value) { this.enableMessageMarkdown = value; } + + @SuppressWarnings("unchecked") + public static NotificationInteractionOptions fromMap(Map map) { + var value = new NotificationInteractionOptions(); + var intentValue = map.get("Intent"); + value.setIntent(intentValue == null ? null : MessageIntent.fromValue((String) intentValue)); + var linkTextValue = map.get("LinkText"); + value.setLinkText(linkTextValue == null ? null : (String) linkTextValue); + var linkUrlValue = map.get("LinkUrl"); + value.setLinkUrl(linkUrlValue == null ? null : (String) linkUrlValue); + var primaryButtonTextValue = map.get("PrimaryButtonText"); + value.setPrimaryButtonText(primaryButtonTextValue == null ? null : (String) primaryButtonTextValue); + var secondaryButtonTextValue = map.get("SecondaryButtonText"); + value.setSecondaryButtonText(secondaryButtonTextValue == null ? null : (String) secondaryButtonTextValue); + var showSecondaryButtonValue = map.get("ShowSecondaryButton"); + value.setShowSecondaryButton(showSecondaryButtonValue == null ? null : (Boolean) showSecondaryButtonValue); + var showDismissValue = map.get("ShowDismiss"); + value.setShowDismiss(showDismissValue == null ? null : (Boolean) showDismissValue); + var enableMessageMarkdownValue = map.get("EnableMessageMarkdown"); + value.setEnableMessageMarkdown(enableMessageMarkdownValue == null ? null : (Boolean) enableMessageMarkdownValue); + return value; + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("Intent", AspireClient.serializeValue(intent)); + map.put("LinkText", AspireClient.serializeValue(linkText)); + map.put("LinkUrl", AspireClient.serializeValue(linkUrl)); + map.put("PrimaryButtonText", AspireClient.serializeValue(primaryButtonText)); + map.put("SecondaryButtonText", AspireClient.serializeValue(secondaryButtonText)); + map.put("ShowSecondaryButton", AspireClient.serializeValue(showSecondaryButton)); + map.put("ShowDismiss", AspireClient.serializeValue(showDismiss)); + map.put("EnableMessageMarkdown", AspireClient.serializeValue(enableMessageMarkdown)); + return map; + } +} + // ===== OtlpProtocol.java ===== // OtlpProtocol.java - GENERATED CODE - DO NOT EDIT @@ -14671,9 +15356,9 @@ public ParameterResource withContainerRegistry(ResourceBuilderBase registry) { } /** Configures custom base images for generated Dockerfiles. */ - public ParameterResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public ParameterResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -14988,9 +15673,9 @@ public ParameterResource withHidden() { } /** Hides the resource from default resource lists after successful completion */ - public ParameterResource withHiddenOnCompletion(WithHiddenOnCompletionOptions options) { - var exitCode = options == null ? null : options.getExitCode(); - var exitCodes = options == null ? null : options.getExitCodes(); + public ParameterResource withHiddenOnCompletion(WithHiddenOnCompletionOptions optionsBag) { + var exitCode = optionsBag == null ? null : optionsBag.getExitCode(); + var exitCodes = optionsBag == null ? null : optionsBag.getExitCodes(); return withHiddenOnCompletionImpl(exitCode, exitCodes); } @@ -15013,11 +15698,11 @@ private ParameterResource withHiddenOnCompletionImpl(Double exitCode, double[] e } /** Adds a pipeline step to the resource that will be executed during deployment. */ - public ParameterResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public ParameterResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -15151,9 +15836,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public ParameterResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public ParameterResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -15377,9 +16062,9 @@ public ParameterResource withMergeEndpointScheme(String endpointName, double por } /** Configures resource logging */ - public ParameterResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ParameterResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -15403,9 +16088,9 @@ private ParameterResource withMergeLoggingImpl(String logLevel, Boolean enableCo } /** Configures resource logging with file path */ - public ParameterResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ParameterResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -16096,9 +16781,9 @@ public ProjectResource withContainerRegistry(ResourceBuilderBase registry) { } /** Configures custom base images for generated Dockerfiles. */ - public ProjectResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public ProjectResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -16121,9 +16806,9 @@ private ProjectResource withDockerfileBaseImageImpl(String buildImage, String ru } /** Marks the resource as hosting a Model Context Protocol (MCP) server on the specified endpoint. */ - public ProjectResource withMcpServer(WithMcpServerOptions options) { - var path = options == null ? null : options.getPath(); - var endpointName = options == null ? null : options.getEndpointName(); + public ProjectResource withMcpServer(WithMcpServerOptions optionsBag) { + var path = optionsBag == null ? null : optionsBag.getPath(); + var endpointName = optionsBag == null ? null : optionsBag.getEndpointName(); return withMcpServerImpl(path, endpointName); } @@ -16376,10 +17061,10 @@ public ProjectResource withReference(String source) { } /** Adds a reference to another resource */ - public ProjectResource withReference(AspireUnion source, WithReferenceOptions options) { - var connectionName = options == null ? null : options.getConnectionName(); - var optional = options == null ? null : options.getOptional(); - var name = options == null ? null : options.getName(); + public ProjectResource withReference(AspireUnion source, WithReferenceOptions optionsBag) { + var connectionName = optionsBag == null ? null : optionsBag.getConnectionName(); + var optional = optionsBag == null ? null : optionsBag.getOptional(); + var name = optionsBag == null ? null : optionsBag.getName(); return withReferenceImpl(source, connectionName, optional, name); } @@ -16430,9 +17115,9 @@ public ProjectResource withEndpointCallback(String endpointName, AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public ProjectResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -16463,9 +17148,9 @@ private ProjectResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public ProjectResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -16496,15 +17181,15 @@ private ProjectResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public ProjectResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -17311,9 +17996,9 @@ public IExecutionConfigurationBuilder createExecutionConfiguration() { } /** Adds an optional string parameter */ - public ProjectResource withOptionalString(WithOptionalStringOptions options) { - var value = options == null ? null : options.getValue(); - var enabled = options == null ? null : options.getEnabled(); + public ProjectResource withOptionalString(WithOptionalStringOptions optionsBag) { + var value = optionsBag == null ? null : optionsBag.getValue(); + var enabled = optionsBag == null ? null : optionsBag.getEnabled(); return withOptionalStringImpl(value, enabled); } @@ -17562,9 +18247,9 @@ public ProjectResource withMergeEndpointScheme(String endpointName, double port, } /** Configures resource logging */ - public ProjectResource withMergeLogging(String logLevel, WithMergeLoggingOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ProjectResource withMergeLogging(String logLevel, WithMergeLoggingOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingImpl(logLevel, enableConsole, maxFiles); } @@ -17588,9 +18273,9 @@ private ProjectResource withMergeLoggingImpl(String logLevel, Boolean enableCons } /** Configures resource logging with file path */ - public ProjectResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions options) { - var enableConsole = options == null ? null : options.getEnableConsole(); - var maxFiles = options == null ? null : options.getMaxFiles(); + public ProjectResource withMergeLoggingPath(String logLevel, String logPath, WithMergeLoggingPathOptions optionsBag) { + var enableConsole = optionsBag == null ? null : optionsBag.getEnableConsole(); + var maxFiles = optionsBag == null ? null : optionsBag.getMaxFiles(); return withMergeLoggingPathImpl(logLevel, logPath, enableConsole, maxFiles); } @@ -17708,6 +18393,168 @@ public ProjectResourceOptions setExcludeKestrelEndpoints(boolean value) { } +// ===== PromptConfirmationAsyncOptions.java ===== +// PromptConfirmationAsyncOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Options for PromptConfirmationAsync. */ +public final class PromptConfirmationAsyncOptions { + private MessageBoxInteractionOptions options; + private CancellationToken cancellationToken; + + public MessageBoxInteractionOptions getOptions() { return options; } + public PromptConfirmationAsyncOptions options(MessageBoxInteractionOptions value) { + this.options = value; + return this; + } + + public CancellationToken getCancellationToken() { return cancellationToken; } + public PromptConfirmationAsyncOptions cancellationToken(CancellationToken value) { + this.cancellationToken = value; + return this; + } + +} + +// ===== PromptInputAsyncOptions.java ===== +// PromptInputAsyncOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Options for PromptInputAsync. */ +public final class PromptInputAsyncOptions { + private InputsDialogInteractionOptions options; + private CancellationToken cancellationToken; + + public InputsDialogInteractionOptions getOptions() { return options; } + public PromptInputAsyncOptions options(InputsDialogInteractionOptions value) { + this.options = value; + return this; + } + + public CancellationToken getCancellationToken() { return cancellationToken; } + public PromptInputAsyncOptions cancellationToken(CancellationToken value) { + this.cancellationToken = value; + return this; + } + +} + +// ===== PromptInputWithInputAsyncOptions.java ===== +// PromptInputWithInputAsyncOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Options for PromptInputWithInputAsync. */ +public final class PromptInputWithInputAsyncOptions { + private InputsDialogInteractionOptions options; + private CancellationToken cancellationToken; + + public InputsDialogInteractionOptions getOptions() { return options; } + public PromptInputWithInputAsyncOptions options(InputsDialogInteractionOptions value) { + this.options = value; + return this; + } + + public CancellationToken getCancellationToken() { return cancellationToken; } + public PromptInputWithInputAsyncOptions cancellationToken(CancellationToken value) { + this.cancellationToken = value; + return this; + } + +} + +// ===== PromptInputsAsyncOptions.java ===== +// PromptInputsAsyncOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Options for PromptInputsAsync. */ +public final class PromptInputsAsyncOptions { + private InputsDialogInteractionOptions options; + private CancellationToken cancellationToken; + + public InputsDialogInteractionOptions getOptions() { return options; } + public PromptInputsAsyncOptions options(InputsDialogInteractionOptions value) { + this.options = value; + return this; + } + + public CancellationToken getCancellationToken() { return cancellationToken; } + public PromptInputsAsyncOptions cancellationToken(CancellationToken value) { + this.cancellationToken = value; + return this; + } + +} + +// ===== PromptMessageBoxAsyncOptions.java ===== +// PromptMessageBoxAsyncOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Options for PromptMessageBoxAsync. */ +public final class PromptMessageBoxAsyncOptions { + private MessageBoxInteractionOptions options; + private CancellationToken cancellationToken; + + public MessageBoxInteractionOptions getOptions() { return options; } + public PromptMessageBoxAsyncOptions options(MessageBoxInteractionOptions value) { + this.options = value; + return this; + } + + public CancellationToken getCancellationToken() { return cancellationToken; } + public PromptMessageBoxAsyncOptions cancellationToken(CancellationToken value) { + this.cancellationToken = value; + return this; + } + +} + +// ===== PromptNotificationAsyncOptions.java ===== +// PromptNotificationAsyncOptions.java - GENERATED CODE - DO NOT EDIT + +package aspire; + +import java.util.*; +import java.util.function.*; + +/** Options for PromptNotificationAsync. */ +public final class PromptNotificationAsyncOptions { + private NotificationInteractionOptions options; + private CancellationToken cancellationToken; + + public NotificationInteractionOptions getOptions() { return options; } + public PromptNotificationAsyncOptions options(NotificationInteractionOptions value) { + this.options = value; + return this; + } + + public CancellationToken getCancellationToken() { return cancellationToken; } + public PromptNotificationAsyncOptions cancellationToken(CancellationToken value) { + this.cancellationToken = value; + return this; + } + +} + // ===== ProtocolType.java ===== // ProtocolType.java - GENERATED CODE - DO NOT EDIT @@ -18084,9 +18931,9 @@ public ExecuteCommandResult executeCommandAsync(IResource resource, String comma } /** Executes a command for the specified resource. */ - public ExecuteCommandResult executeCommandAsync(AspireUnion resource, String commandName, ExecuteCommandAsyncOptions options) { - var arguments = options == null ? null : options.getArguments(); - var cancellationToken = options == null ? null : options.getCancellationToken(); + public ExecuteCommandResult executeCommandAsync(AspireUnion resource, String commandName, ExecuteCommandAsyncOptions optionsBag) { + var arguments = optionsBag == null ? null : optionsBag.getArguments(); + var cancellationToken = optionsBag == null ? null : optionsBag.getCancellationToken(); return executeCommandAsyncImpl(resource, commandName, arguments, cancellationToken); } @@ -18370,9 +19217,9 @@ public ResourceEventDto tryGetResourceState(String resourceName) { } /** Publishes an update for a resource's state. */ - public void publishResourceUpdate(IResource resource, PublishResourceUpdateOptions options) { - var state = options == null ? null : options.getState(); - var stateStyle = options == null ? null : options.getStateStyle(); + public void publishResourceUpdate(IResource resource, PublishResourceUpdateOptions optionsBag) { + var state = optionsBag == null ? null : optionsBag.getState(); + var stateStyle = optionsBag == null ? null : optionsBag.getStateStyle(); publishResourceUpdateImpl(resource, state, stateStyle); } @@ -18953,9 +19800,9 @@ public TestDatabaseResource publishAsContainer() { } /** Causes Aspire to build the specified container image from a Dockerfile. */ - public TestDatabaseResource withDockerfile(String contextPath, WithDockerfileOptions options) { - var dockerfilePath = options == null ? null : options.getDockerfilePath(); - var stage = options == null ? null : options.getStage(); + public TestDatabaseResource withDockerfile(String contextPath, WithDockerfileOptions optionsBag) { + var dockerfilePath = optionsBag == null ? null : optionsBag.getDockerfilePath(); + var stage = optionsBag == null ? null : optionsBag.getStage(); return withDockerfileImpl(contextPath, dockerfilePath, stage); } @@ -19039,10 +19886,10 @@ public TestDatabaseResource withBuildSecret(String name, ParameterResource value } /** Adds container certificate path overrides used for certificate trust at run time. */ - public TestDatabaseResource withContainerCertificatePaths(WithContainerCertificatePathsOptions options) { - var customCertificatesDestination = options == null ? null : options.getCustomCertificatesDestination(); - var defaultCertificateBundlePaths = options == null ? null : options.getDefaultCertificateBundlePaths(); - var defaultCertificateDirectoryPaths = options == null ? null : options.getDefaultCertificateDirectoryPaths(); + public TestDatabaseResource withContainerCertificatePaths(WithContainerCertificatePathsOptions optionsBag) { + var customCertificatesDestination = optionsBag == null ? null : optionsBag.getCustomCertificatesDestination(); + var defaultCertificateBundlePaths = optionsBag == null ? null : optionsBag.getDefaultCertificateBundlePaths(); + var defaultCertificateDirectoryPaths = optionsBag == null ? null : optionsBag.getDefaultCertificateDirectoryPaths(); return withContainerCertificatePathsImpl(customCertificatesDestination, defaultCertificateBundlePaths, defaultCertificateDirectoryPaths); } @@ -19092,9 +19939,9 @@ public TestDatabaseResource withDockerfileBuilder(String contextPath, AspireActi } /** Configures custom base images for generated Dockerfiles. */ - public TestDatabaseResource withDockerfileBaseImage(WithDockerfileBaseImageOptions options) { - var buildImage = options == null ? null : options.getBuildImage(); - var runtimeImage = options == null ? null : options.getRuntimeImage(); + public TestDatabaseResource withDockerfileBaseImage(WithDockerfileBaseImageOptions optionsBag) { + var buildImage = optionsBag == null ? null : optionsBag.getBuildImage(); + var runtimeImage = optionsBag == null ? null : optionsBag.getRuntimeImage(); return withDockerfileBaseImageImpl(buildImage, runtimeImage); } @@ -19126,9 +19973,9 @@ public TestDatabaseResource withContainerNetworkAlias(String alias) { } /** Marks the resource as hosting a Model Context Protocol (MCP) server on the specified endpoint. */ - public TestDatabaseResource withMcpServer(WithMcpServerOptions options) { - var path = options == null ? null : options.getPath(); - var endpointName = options == null ? null : options.getEndpointName(); + public TestDatabaseResource withMcpServer(WithMcpServerOptions optionsBag) { + var path = optionsBag == null ? null : optionsBag.getPath(); + var endpointName = optionsBag == null ? null : optionsBag.getEndpointName(); return withMcpServerImpl(path, endpointName); } @@ -19352,10 +20199,10 @@ public TestDatabaseResource withReference(String source) { } /** Adds a reference to another resource */ - public TestDatabaseResource withReference(AspireUnion source, WithReferenceOptions options) { - var connectionName = options == null ? null : options.getConnectionName(); - var optional = options == null ? null : options.getOptional(); - var name = options == null ? null : options.getName(); + public TestDatabaseResource withReference(AspireUnion source, WithReferenceOptions optionsBag) { + var connectionName = optionsBag == null ? null : optionsBag.getConnectionName(); + var optional = optionsBag == null ? null : optionsBag.getOptional(); + var name = optionsBag == null ? null : optionsBag.getName(); return withReferenceImpl(source, connectionName, optional, name); } @@ -19406,9 +20253,9 @@ public TestDatabaseResource withEndpointCallback(String endpointName, AspireActi } /** Updates an HTTP endpoint via callback */ - public TestDatabaseResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public TestDatabaseResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -19439,9 +20286,9 @@ private TestDatabaseResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public TestDatabaseResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -19472,15 +20319,15 @@ private TestDatabaseResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public TestDatabaseResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -20177,9 +21024,9 @@ public TestDatabaseResource withPipelineConfiguration(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public TestRedisResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -21507,9 +22354,9 @@ private TestRedisResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public TestRedisResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -21540,15 +22387,15 @@ private TestRedisResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public TestRedisResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -22245,9 +23092,9 @@ public TestRedisResource withPipelineConfiguration(AspireAction1 callback, WithHttpEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public TestVaultResource withHttpEndpointCallback(AspireAction1 callback, WithHttpEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -23593,9 +24440,9 @@ private TestVaultResource withHttpEndpointCallbackImpl(AspireAction1 callback, WithHttpsEndpointCallbackOptions options) { - var name = options == null ? null : options.getName(); - var createIfNotExists = options == null ? null : options.getCreateIfNotExists(); + public TestVaultResource withHttpsEndpointCallback(AspireAction1 callback, WithHttpsEndpointCallbackOptions optionsBag) { + var name = optionsBag == null ? null : optionsBag.getName(); + var createIfNotExists = optionsBag == null ? null : optionsBag.getCreateIfNotExists(); return withHttpsEndpointCallbackImpl(callback, name, createIfNotExists); } @@ -23626,15 +24473,15 @@ private TestVaultResource withHttpsEndpointCallbackImpl(AspireAction1 callback, WithPipelineStepFactoryOptions options) { - var dependsOn = options == null ? null : options.getDependsOn(); - var requiredBy = options == null ? null : options.getRequiredBy(); - var tags = options == null ? null : options.getTags(); - var description = options == null ? null : options.getDescription(); + public TestVaultResource withPipelineStepFactory(String stepName, AspireAction1 callback, WithPipelineStepFactoryOptions optionsBag) { + var dependsOn = optionsBag == null ? null : optionsBag.getDependsOn(); + var requiredBy = optionsBag == null ? null : optionsBag.getRequiredBy(); + var tags = optionsBag == null ? null : optionsBag.getTags(); + var description = optionsBag == null ? null : optionsBag.getDescription(); return withPipelineStepFactoryImpl(stepName, callback, dependsOn, requiredBy, tags, description); } @@ -24331,9 +25178,9 @@ public TestVaultResource withPipelineConfiguration(AspireAction1 bool: InputType = typing.Literal["Text", "SecretText", "Choice", "Boolean", "Number"] +MessageIntent = typing.Literal["None", "Success", "Warning", "Error", "Information", "Confirmation"] + OtlpProtocol = typing.Literal["Grpc", "HttpProtobuf", "HttpJson"] ProbeType = typing.Literal["Startup", "Readiness", "Liveness"] @@ -1737,6 +1739,10 @@ class AddContainerOptions(typing.TypedDict, total=False): Image: str Tag: str | None +class BooleanInteractionResult(typing.TypedDict, total=False): + Data: bool | None + Canceled: bool + class CertificateTrustExecutionConfigurationContext(typing.TypedDict, total=False): CertificateBundlePath: ReferenceExpression CertificateDirectoriesPath: ReferenceExpression @@ -1823,6 +1829,27 @@ class HttpsCertificateInfo(typing.TypedDict, total=False): Issuer: str Thumbprint: str | None +class InputInteractionResult(typing.TypedDict, total=False): + Data: InteractionInput + Canceled: bool + +class InputLoadOptions(typing.TypedDict, total=False): + LoadCallback: typing.Callable + AlwaysLoadOnStart: bool + DependsOnInputs: typing.Iterable[str] + +class InputsDialogInteractionOptions(typing.TypedDict, total=False): + ValidationCallback: typing.Callable + PrimaryButtonText: str | None + SecondaryButtonText: str | None + ShowSecondaryButton: bool | None + ShowDismiss: bool | None + EnableMessageMarkdown: bool | None + +class InputsInteractionResult(typing.TypedDict, total=False): + Data: InteractionInputCollection + Canceled: bool + class InteractionInput(typing.TypedDict, total=False): Name: str Label: str | None @@ -1831,13 +1858,38 @@ class InteractionInput(typing.TypedDict, total=False): InputType: InputType Required: bool Options: typing.Iterable[typing.Any] - DynamicLoading: typing.Any + DynamicLoading: InputLoadOptions Value: str | None Placeholder: str | None AllowCustomChoice: bool Disabled: bool MaxLength: int | None +class InteractionOptions(typing.TypedDict, total=False): + PrimaryButtonText: str | None + SecondaryButtonText: str | None + ShowSecondaryButton: bool | None + ShowDismiss: bool | None + EnableMessageMarkdown: bool | None + +class MessageBoxInteractionOptions(typing.TypedDict, total=False): + Intent: MessageIntent | None + PrimaryButtonText: str | None + SecondaryButtonText: str | None + ShowSecondaryButton: bool | None + ShowDismiss: bool | None + EnableMessageMarkdown: bool | None + +class NotificationInteractionOptions(typing.TypedDict, total=False): + Intent: MessageIntent | None + LinkText: str | None + LinkUrl: str | None + PrimaryButtonText: str | None + SecondaryButtonText: str | None + ShowSecondaryButton: bool | None + ShowDismiss: bool | None + EnableMessageMarkdown: bool | None + class ParameterCustomInputOptions(typing.TypedDict, total=False): InputType: InputType | None Label: str | None @@ -2817,6 +2869,125 @@ def is_env(self, env_name: str) -> bool: return result +class AbstractInteractionService: + """Type class for AbstractInteractionService.""" + + def __init__(self, handle: Handle, client: AspireClient) -> None: + self._handle = handle + self._client = client + + def __repr__(self) -> str: + return f"AbstractInteractionService(handle={self._handle.handle_id})" + + @_uncached_property + def handle(self) -> Handle: + """The underlying object reference handle.""" + return self._handle + + def is_available(self) -> bool: + """Gets a value indicating whether the interaction service is available.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + result = self._client.invoke_capability( + 'Aspire.Hosting/interactionServiceIsAvailable', + rpc_args, + ) + return result + + def prompt_confirmation(self, title: str, message: str, *, options: MessageBoxInteractionOptions | None = None, timeout: int | None = None) -> BooleanInteractionResult: + """Prompts the user for confirmation with a dialog.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + rpc_args['title'] = title + rpc_args['message'] = message + if options is not None: + rpc_args['options'] = options + if timeout is not None: + rpc_args['cancellationToken'] = self._client.register_cancellation_token(timeout) + result = self._client.invoke_capability( + 'Aspire.Hosting/promptConfirmationAsync', + rpc_args, + ) + return typing.cast(BooleanInteractionResult, result) + + def prompt_message_box(self, title: str, message: str, *, options: MessageBoxInteractionOptions | None = None, timeout: int | None = None) -> BooleanInteractionResult: + """Prompts the user with a message box dialog.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + rpc_args['title'] = title + rpc_args['message'] = message + if options is not None: + rpc_args['options'] = options + if timeout is not None: + rpc_args['cancellationToken'] = self._client.register_cancellation_token(timeout) + result = self._client.invoke_capability( + 'Aspire.Hosting/promptMessageBoxAsync', + rpc_args, + ) + return typing.cast(BooleanInteractionResult, result) + + def prompt_input(self, title: str, message: str, input_label: str, place_holder: str, *, options: InputsDialogInteractionOptions | None = None, timeout: int | None = None) -> InputInteractionResult: + """Prompts the user for a single text input.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + rpc_args['title'] = title + rpc_args['message'] = message + rpc_args['inputLabel'] = input_label + rpc_args['placeHolder'] = place_holder + if options is not None: + rpc_args['options'] = options + if timeout is not None: + rpc_args['cancellationToken'] = self._client.register_cancellation_token(timeout) + result = self._client.invoke_capability( + 'Aspire.Hosting/promptInputAsync', + rpc_args, + ) + return typing.cast(InputInteractionResult, result) + + def prompt_input_with_input(self, title: str, message: str, input: InteractionInput, *, options: InputsDialogInteractionOptions | None = None, timeout: int | None = None) -> InputInteractionResult: + """Prompts the user for a single input using a specified `InteractionInput`.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + rpc_args['title'] = title + rpc_args['message'] = message + rpc_args['input'] = input + if options is not None: + rpc_args['options'] = options + if timeout is not None: + rpc_args['cancellationToken'] = self._client.register_cancellation_token(timeout) + result = self._client.invoke_capability( + 'Aspire.Hosting/promptInputWithInput', + rpc_args, + ) + return typing.cast(InputInteractionResult, result) + + def prompt_inputs(self, title: str, message: str, inputs: typing.Iterable[InteractionInput], *, options: InputsDialogInteractionOptions | None = None, timeout: int | None = None) -> InputsInteractionResult: + """Prompts the user for multiple inputs.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + rpc_args['title'] = title + rpc_args['message'] = message + rpc_args['inputs'] = inputs + if options is not None: + rpc_args['options'] = options + if timeout is not None: + rpc_args['cancellationToken'] = self._client.register_cancellation_token(timeout) + result = self._client.invoke_capability( + 'Aspire.Hosting/promptInputsAsync', + rpc_args, + ) + return typing.cast(InputsInteractionResult, result) + + def prompt_notification(self, title: str, message: str, *, options: NotificationInteractionOptions | None = None, timeout: int | None = None) -> BooleanInteractionResult: + """Prompts the user with a notification.""" + rpc_args: dict[str, typing.Any] = {'interactionService': self._handle} + rpc_args['title'] = title + rpc_args['message'] = message + if options is not None: + rpc_args['options'] = options + if timeout is not None: + rpc_args['cancellationToken'] = self._client.register_cancellation_token(timeout) + result = self._client.invoke_capability( + 'Aspire.Hosting/promptNotificationAsync', + rpc_args, + ) + return typing.cast(BooleanInteractionResult, result) + + class AbstractLogger: """Type class for AbstractLogger.""" @@ -3092,6 +3263,15 @@ def get_eventing(self) -> AbstractDistributedApplicationEventing: ) return typing.cast(AbstractDistributedApplicationEventing, result) + def get_interaction_service(self) -> AbstractInteractionService: + """Gets the interaction service from the service provider.""" + rpc_args: dict[str, typing.Any] = {'serviceProvider': self._handle} + result = self._client.invoke_capability( + 'Aspire.Hosting/getInteractionService', + rpc_args, + ) + return typing.cast(AbstractInteractionService, result) + def get_logger_factory(self) -> AbstractLoggerFactory: """Gets the logger factory from the service provider.""" rpc_args: dict[str, typing.Any] = {'serviceProvider': self._handle} @@ -4756,6 +4936,15 @@ def handle(self) -> Handle: """The underlying object reference handle.""" return self._handle + @_cached_property + def service_provider(self) -> AbstractServiceProvider: + """The service provider.""" + result = self._client.invoke_capability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider', + {'context': self._handle} + ) + return typing.cast(AbstractServiceProvider, result) + @_cached_property def resource_name(self) -> str: """The resource name.""" @@ -4921,6 +5110,57 @@ def to_array(self) -> typing.Iterable[InteractionInput]: return result +class LoadInputContext: + """Type class for LoadInputContext.""" + + def __init__(self, handle: Handle, client: AspireClient) -> None: + self._handle = handle + self._client = client + + def __repr__(self) -> str: + return f"LoadInputContext(handle={self._handle.handle_id})" + + @_uncached_property + def handle(self) -> Handle: + """The underlying object reference handle.""" + return self._handle + + @_cached_property + def input(self) -> InteractionInput: + """Gets the loading input. This is the target of `InputLoadOptions`.""" + result = self._client.invoke_capability( + 'Aspire.Hosting/LoadInputContext.input', + {'context': self._handle} + ) + return typing.cast(InteractionInput, result) + + @_cached_property + def all_inputs(self) -> InteractionInputCollection: + """Gets the collection of all `InteractionInput` in this prompt.""" + result = self._client.invoke_capability( + 'Aspire.Hosting/LoadInputContext.allInputs', + {'context': self._handle} + ) + return typing.cast(InteractionInputCollection, result) + + def cancel(self) -> None: + """Cancel the operation.""" + token: CancellationToken = self._client.invoke_capability( + 'Aspire.Hosting/LoadInputContext.cancellationToken', + {'context': self._handle} + ) + token.cancel() + + def set_options(self, options: typing.Mapping[str, str]) -> None: + """Sets the available options for the loading input.""" + rpc_args: dict[str, typing.Any] = {'context': self._handle} + rpc_args['options'] = options + self._client.invoke_capability( + 'Aspire.Hosting/LoadInputContext.setOptions', + rpc_args + ) + + class LogFacade: """Type class for LogFacade.""" @@ -11448,9 +11688,9 @@ def create_builder( _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression", lambda handle, _: ReferenceExpression(handle)) _register_handle_wrapper("System.Private.CoreLib/System.Threading.CancellationToken", CancellationToken) +_register_handle_wrapper("Aspire.Hosting/Dict", AspireDict) _register_handle_wrapper("Aspire.Hosting/List", AspireList) _register_handle_wrapper("Aspire.Hosting/Dict", AspireDict) -_register_handle_wrapper("Aspire.Hosting/Dict", AspireDict) _register_handle_wrapper("Aspire.Hosting/Dict", AspireDict) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IAspireStore", AbstractAspireStore) _register_handle_wrapper("Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration", AbstractConfiguration) @@ -11460,6 +11700,7 @@ def create_builder( _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IExecutionConfigurationBuilder", AbstractExecutionConfigurationBuilder) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IExecutionConfigurationResult", AbstractExecutionConfigurationResult) _register_handle_wrapper("Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment", AbstractHostEnvironment) +_register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.IInteractionService", AbstractInteractionService) _register_handle_wrapper("Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger", AbstractLogger) _register_handle_wrapper("Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILoggerFactory", AbstractLoggerFactory) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Pipelines.IReportingStep", AbstractReportingStep) @@ -11497,6 +11738,7 @@ def create_builder( _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.InitializeResourceEvent", InitializeResourceEvent) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext", InputsDialogValidationContext) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.InteractionInputCollection", InteractionInputCollection) +_register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.LoadInputContext", LoadInputContext) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.LogFacade", LogFacade) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Pipelines.PipelineConfigurationContext", PipelineConfigurationContext) _register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Pipelines.PipelineContext", PipelineContext) diff --git a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs index 89453a8b76e..51dcc555628 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs +++ b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs @@ -362,6 +362,37 @@ impl std::fmt::Display for InputType { } } +/// MessageIntent +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum MessageIntent { + #[default] + #[serde(rename = "None")] + None, + #[serde(rename = "Success")] + Success, + #[serde(rename = "Warning")] + Warning, + #[serde(rename = "Error")] + Error, + #[serde(rename = "Information")] + Information, + #[serde(rename = "Confirmation")] + Confirmation, +} + +impl std::fmt::Display for MessageIntent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::None => write!(f, "None"), + Self::Success => write!(f, "Success"), + Self::Warning => write!(f, "Warning"), + Self::Error => write!(f, "Error"), + Self::Information => write!(f, "Information"), + Self::Confirmation => write!(f, "Confirmation"), + } + } +} + /// ResourceCommandVisibility #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ResourceCommandVisibility { @@ -545,6 +576,31 @@ impl std::fmt::Display for TestResourceStatus { // DTOs // ============================================================================ +/// InputLoadOptions +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct InputLoadOptions { + #[serde(rename = "LoadCallback")] + pub load_callback: Value, + #[serde(rename = "AlwaysLoadOnStart", skip_serializing_if = "Option::is_none")] + pub always_load_on_start: Option, + #[serde(rename = "DependsOnInputs", skip_serializing_if = "Option::is_none")] + pub depends_on_inputs: Option>, +} + +impl InputLoadOptions { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + map.insert("LoadCallback".to_string(), serde_json::to_value(&self.load_callback).unwrap_or(Value::Null)); + if let Some(ref v) = self.always_load_on_start { + map.insert("AlwaysLoadOnStart".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.depends_on_inputs { + map.insert("DependsOnInputs".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map + } +} + /// InteractionInput #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct InteractionInput { @@ -563,7 +619,7 @@ pub struct InteractionInput { #[serde(rename = "Options")] pub options: Vec, #[serde(rename = "DynamicLoading", skip_serializing_if = "Option::is_none")] - pub dynamic_loading: Option, + pub dynamic_loading: Option, #[serde(rename = "Value")] pub value: String, #[serde(rename = "Placeholder", skip_serializing_if = "Option::is_none")] @@ -749,6 +805,239 @@ impl HttpsCertificateExecutionConfigurationExportData { } } +/// InteractionOptions +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct InteractionOptions { + #[serde(rename = "PrimaryButtonText", skip_serializing_if = "Option::is_none")] + pub primary_button_text: Option, + #[serde(rename = "SecondaryButtonText", skip_serializing_if = "Option::is_none")] + pub secondary_button_text: Option, + #[serde(rename = "ShowSecondaryButton", skip_serializing_if = "Option::is_none")] + pub show_secondary_button: Option, + #[serde(rename = "ShowDismiss", skip_serializing_if = "Option::is_none")] + pub show_dismiss: Option, + #[serde(rename = "EnableMessageMarkdown", skip_serializing_if = "Option::is_none")] + pub enable_message_markdown: Option, +} + +impl InteractionOptions { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.primary_button_text { + map.insert("PrimaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.secondary_button_text { + map.insert("SecondaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_secondary_button { + map.insert("ShowSecondaryButton".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_dismiss { + map.insert("ShowDismiss".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.enable_message_markdown { + map.insert("EnableMessageMarkdown".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map + } +} + +/// MessageBoxInteractionOptions +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct MessageBoxInteractionOptions { + #[serde(rename = "Intent", skip_serializing_if = "Option::is_none")] + pub intent: Option, + #[serde(rename = "PrimaryButtonText", skip_serializing_if = "Option::is_none")] + pub primary_button_text: Option, + #[serde(rename = "SecondaryButtonText", skip_serializing_if = "Option::is_none")] + pub secondary_button_text: Option, + #[serde(rename = "ShowSecondaryButton", skip_serializing_if = "Option::is_none")] + pub show_secondary_button: Option, + #[serde(rename = "ShowDismiss", skip_serializing_if = "Option::is_none")] + pub show_dismiss: Option, + #[serde(rename = "EnableMessageMarkdown", skip_serializing_if = "Option::is_none")] + pub enable_message_markdown: Option, +} + +impl MessageBoxInteractionOptions { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.intent { + map.insert("Intent".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.primary_button_text { + map.insert("PrimaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.secondary_button_text { + map.insert("SecondaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_secondary_button { + map.insert("ShowSecondaryButton".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_dismiss { + map.insert("ShowDismiss".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.enable_message_markdown { + map.insert("EnableMessageMarkdown".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map + } +} + +/// InputsDialogInteractionOptions +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct InputsDialogInteractionOptions { + #[serde(rename = "ValidationCallback", skip_serializing_if = "Option::is_none")] + pub validation_callback: Option, + #[serde(rename = "PrimaryButtonText", skip_serializing_if = "Option::is_none")] + pub primary_button_text: Option, + #[serde(rename = "SecondaryButtonText", skip_serializing_if = "Option::is_none")] + pub secondary_button_text: Option, + #[serde(rename = "ShowSecondaryButton", skip_serializing_if = "Option::is_none")] + pub show_secondary_button: Option, + #[serde(rename = "ShowDismiss", skip_serializing_if = "Option::is_none")] + pub show_dismiss: Option, + #[serde(rename = "EnableMessageMarkdown", skip_serializing_if = "Option::is_none")] + pub enable_message_markdown: Option, +} + +impl InputsDialogInteractionOptions { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.validation_callback { + map.insert("ValidationCallback".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.primary_button_text { + map.insert("PrimaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.secondary_button_text { + map.insert("SecondaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_secondary_button { + map.insert("ShowSecondaryButton".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_dismiss { + map.insert("ShowDismiss".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.enable_message_markdown { + map.insert("EnableMessageMarkdown".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map + } +} + +/// NotificationInteractionOptions +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct NotificationInteractionOptions { + #[serde(rename = "Intent", skip_serializing_if = "Option::is_none")] + pub intent: Option, + #[serde(rename = "LinkText", skip_serializing_if = "Option::is_none")] + pub link_text: Option, + #[serde(rename = "LinkUrl", skip_serializing_if = "Option::is_none")] + pub link_url: Option, + #[serde(rename = "PrimaryButtonText", skip_serializing_if = "Option::is_none")] + pub primary_button_text: Option, + #[serde(rename = "SecondaryButtonText", skip_serializing_if = "Option::is_none")] + pub secondary_button_text: Option, + #[serde(rename = "ShowSecondaryButton", skip_serializing_if = "Option::is_none")] + pub show_secondary_button: Option, + #[serde(rename = "ShowDismiss", skip_serializing_if = "Option::is_none")] + pub show_dismiss: Option, + #[serde(rename = "EnableMessageMarkdown", skip_serializing_if = "Option::is_none")] + pub enable_message_markdown: Option, +} + +impl NotificationInteractionOptions { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.intent { + map.insert("Intent".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.link_text { + map.insert("LinkText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.link_url { + map.insert("LinkUrl".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.primary_button_text { + map.insert("PrimaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.secondary_button_text { + map.insert("SecondaryButtonText".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_secondary_button { + map.insert("ShowSecondaryButton".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.show_dismiss { + map.insert("ShowDismiss".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = self.enable_message_markdown { + map.insert("EnableMessageMarkdown".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map + } +} + +/// BooleanInteractionResult +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct BooleanInteractionResult { + #[serde(rename = "Data", skip_serializing_if = "Option::is_none")] + pub data: Option, + #[serde(rename = "Canceled")] + pub canceled: bool, +} + +impl BooleanInteractionResult { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.data { + map.insert("Data".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map.insert("Canceled".to_string(), serde_json::to_value(&self.canceled).unwrap_or(Value::Null)); + map + } +} + +/// InputInteractionResult +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct InputInteractionResult { + #[serde(rename = "Data", skip_serializing_if = "Option::is_none")] + pub data: Option, + #[serde(rename = "Canceled")] + pub canceled: bool, +} + +impl InputInteractionResult { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.data { + map.insert("Data".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map.insert("Canceled".to_string(), serde_json::to_value(&self.canceled).unwrap_or(Value::Null)); + map + } +} + +/// InputsInteractionResult +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct InputsInteractionResult { + #[serde(rename = "Data", skip_serializing_if = "Option::is_none")] + pub data: Option, + #[serde(rename = "Canceled")] + pub canceled: bool, +} + +impl InputsInteractionResult { + pub fn to_map(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(ref v) = self.data { + map.insert("Data".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + map.insert("Canceled".to_string(), serde_json::to_value(&self.canceled).unwrap_or(Value::Null)); + map + } +} + /// ResourceEventDto #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct ResourceEventDto { @@ -8839,6 +9128,15 @@ impl ExecuteCommandContext { &self.client } + /// The service provider. + pub fn service_provider(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(IServiceProvider::new(handle, self.client.clone())) + } + /// The resource name. pub fn resource_name(&self) -> Result> { let mut args: HashMap = HashMap::new(); @@ -10579,6 +10877,146 @@ impl IHostEnvironment { } } +/// Wrapper for Aspire.Hosting/Aspire.Hosting.IInteractionService +pub struct IInteractionService { + handle: Handle, + client: Arc, +} + +impl HasHandle for IInteractionService { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl IInteractionService { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Gets a value indicating whether the interaction service is available. + pub fn is_available(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/interactionServiceIsAvailable", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Prompts the user for confirmation with a dialog. + pub fn prompt_confirmation_async(&self, title: &str, message: &str, options: Option, cancellation_token: Option<&CancellationToken>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + args.insert("title".to_string(), serde_json::to_value(&title).unwrap_or(Value::Null)); + args.insert("message".to_string(), serde_json::to_value(&message).unwrap_or(Value::Null)); + if let Some(ref v) = options { + args.insert("options".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(token) = cancellation_token { + let token_id = register_cancellation(token, self.client.clone()); + args.insert("cancellationToken".to_string(), Value::String(token_id)); + } + let result = self.client.invoke_capability("Aspire.Hosting/promptConfirmationAsync", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Prompts the user with a message box dialog. + pub fn prompt_message_box_async(&self, title: &str, message: &str, options: Option, cancellation_token: Option<&CancellationToken>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + args.insert("title".to_string(), serde_json::to_value(&title).unwrap_or(Value::Null)); + args.insert("message".to_string(), serde_json::to_value(&message).unwrap_or(Value::Null)); + if let Some(ref v) = options { + args.insert("options".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(token) = cancellation_token { + let token_id = register_cancellation(token, self.client.clone()); + args.insert("cancellationToken".to_string(), Value::String(token_id)); + } + let result = self.client.invoke_capability("Aspire.Hosting/promptMessageBoxAsync", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Prompts the user for a single text input. + pub fn prompt_input_async(&self, title: &str, message: &str, input_label: &str, place_holder: &str, options: Option, cancellation_token: Option<&CancellationToken>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + args.insert("title".to_string(), serde_json::to_value(&title).unwrap_or(Value::Null)); + args.insert("message".to_string(), serde_json::to_value(&message).unwrap_or(Value::Null)); + args.insert("inputLabel".to_string(), serde_json::to_value(&input_label).unwrap_or(Value::Null)); + args.insert("placeHolder".to_string(), serde_json::to_value(&place_holder).unwrap_or(Value::Null)); + if let Some(ref v) = options { + args.insert("options".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(token) = cancellation_token { + let token_id = register_cancellation(token, self.client.clone()); + args.insert("cancellationToken".to_string(), Value::String(token_id)); + } + let result = self.client.invoke_capability("Aspire.Hosting/promptInputAsync", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Prompts the user for a single input using a specified `InteractionInput`. + pub fn prompt_input_with_input_async(&self, title: &str, message: &str, input: InteractionInput, options: Option, cancellation_token: Option<&CancellationToken>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + args.insert("title".to_string(), serde_json::to_value(&title).unwrap_or(Value::Null)); + args.insert("message".to_string(), serde_json::to_value(&message).unwrap_or(Value::Null)); + args.insert("input".to_string(), serde_json::to_value(&input).unwrap_or(Value::Null)); + if let Some(ref v) = options { + args.insert("options".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(token) = cancellation_token { + let token_id = register_cancellation(token, self.client.clone()); + args.insert("cancellationToken".to_string(), Value::String(token_id)); + } + let result = self.client.invoke_capability("Aspire.Hosting/promptInputWithInput", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Prompts the user for multiple inputs. + pub fn prompt_inputs_async(&self, title: &str, message: &str, inputs: Vec, options: Option, cancellation_token: Option<&CancellationToken>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + args.insert("title".to_string(), serde_json::to_value(&title).unwrap_or(Value::Null)); + args.insert("message".to_string(), serde_json::to_value(&message).unwrap_or(Value::Null)); + args.insert("inputs".to_string(), serde_json::to_value(&inputs).unwrap_or(Value::Null)); + if let Some(ref v) = options { + args.insert("options".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(token) = cancellation_token { + let token_id = register_cancellation(token, self.client.clone()); + args.insert("cancellationToken".to_string(), Value::String(token_id)); + } + let result = self.client.invoke_capability("Aspire.Hosting/promptInputsAsync", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Prompts the user with a notification. + pub fn prompt_notification_async(&self, title: &str, message: &str, options: Option, cancellation_token: Option<&CancellationToken>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("interactionService".to_string(), self.handle.to_json()); + args.insert("title".to_string(), serde_json::to_value(&title).unwrap_or(Value::Null)); + args.insert("message".to_string(), serde_json::to_value(&message).unwrap_or(Value::Null)); + if let Some(ref v) = options { + args.insert("options".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(token) = cancellation_token { + let token_id = register_cancellation(token, self.client.clone()); + args.insert("cancellationToken".to_string(), Value::String(token_id)); + } + let result = self.client.invoke_capability("Aspire.Hosting/promptNotificationAsync", args)?; + Ok(serde_json::from_value(result)?) + } +} + /// Wrapper for Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger pub struct ILogger { handle: Handle, @@ -11140,6 +11578,15 @@ impl IServiceProvider { Ok(IDistributedApplicationEventing::new(handle, self.client.clone())) } + /// Gets the interaction service from the service provider. + pub fn get_interaction_service(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("serviceProvider".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/getInteractionService", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(IInteractionService::new(handle, self.client.clone())) + } + /// Gets the logger factory from the service provider. pub fn get_logger_factory(&self) -> Result> { let mut args: HashMap = HashMap::new(); @@ -11474,6 +11921,67 @@ impl InteractionInputCollection { } } +/// Wrapper for Aspire.Hosting/Aspire.Hosting.LoadInputContext +pub struct LoadInputContext { + handle: Handle, + client: Arc, +} + +impl HasHandle for LoadInputContext { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl LoadInputContext { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Gets the loading input. This is the target of `InputLoadOptions`. + pub fn input(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/LoadInputContext.input", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Gets the collection of all `InteractionInput` in this prompt. + pub fn all_inputs(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/LoadInputContext.allInputs", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(InteractionInputCollection::new(handle, self.client.clone())) + } + + /// Gets the `CancellationToken`. + pub fn cancellation_token(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/LoadInputContext.cancellationToken", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(CancellationToken::new(handle, self.client.clone())) + } + + /// Sets the available options for the loading input. + pub fn set_options(&self, options: HashMap) -> Result<(), Box> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + args.insert("options".to_string(), serde_json::to_value(&options).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/LoadInputContext.setOptions", args)?; + Ok(()) + } +} + /// Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.LogFacade pub struct LogFacade { handle: Handle, diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts index 214adcf2ddb..f94f70688f1 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts @@ -141,7 +141,7 @@ export interface TestDeeplyNestedDto { /** Test DTO with complex nested types. */ export interface TestNestedDto { id?: string; - config?: TestConfigDto; + config?: TestConfigDto | null; tags?: string[]; counts?: Record; } diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts index e7a67d4916e..6f770680b06 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts @@ -327,6 +327,9 @@ type ExternalServiceResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Exter /** A builder for creating instances of {@link DistributedApplication}. */ type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; +/** A service to interact with the current development environment. */ +type IInteractionServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IInteractionService'>; + /** Represents the context for validating inputs in an inputs dialog interaction. */ type InputsDialogValidationContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext'>; @@ -339,6 +342,9 @@ type IResourceWithContainerFilesHandle = Handle<'Aspire.Hosting/Aspire.Hosting.I /** Defines an interface for managing user secrets with support for read and write operations. */ type IUserSecretsManagerHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IUserSecretsManager'>; +/** The context for dynamic input loading. Used with `LoadCallback`. */ +type LoadInputContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.LoadInputContext'>; + /** Represents a pipeline for executing deployment steps in a distributed application. */ type IDistributedApplicationPipelineHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Pipelines.IDistributedApplicationPipeline'>; @@ -530,6 +536,22 @@ export enum ImagePullPolicy { Never = "Never", } +/** Specifies the intent or purpose of a message in an interaction. */ +export enum MessageIntent { + /** No specific intent. */ + None = "None", + /** Indicates a successful operation. */ + Success = "Success", + /** Indicates a warning. */ + Warning = "Warning", + /** Indicates an error. */ + Error = "Error", + /** Provides informational content. */ + Information = "Information", + /** Requests confirmation from the user. */ + Confirmation = "Confirmation", +} + /** Protocols available for OTLP exporters. */ export enum OtlpProtocol { /** A gRPC-based OTLP exporter. */ @@ -646,6 +668,14 @@ export interface AddContainerOptions { tag?: string | null; } +/** The result of a boolean interaction prompt. */ +export interface BooleanInteractionResult { + /** The data returned from the interaction. The value is `null` when the interaction was canceled. */ + data?: boolean | null; + /** A flag indicating whether the interaction was canceled by the user. */ + canceled?: boolean; +} + /** Context for configuring certificate trust configuration properties. */ export interface CertificateTrustExecutionConfigurationContext { /** The path to the PEM certificate bundle file in the resource context (e.g., container filesystem). */ @@ -725,7 +755,7 @@ export interface CommandResultData { /** Options for creating a distributed application builder from polyglot apphosts. */ export interface CreateBuilderOptions { /** The command line arguments. */ - args?: string[]; + args?: string[] | null; /** The directory containing the AppHost project file. */ projectDirectory?: string | null; /** The full path to the AppHost file (e.g., apphost.ts, apphost.py). Used for consistent socket path computation across CLI and AppHost. */ @@ -755,7 +785,7 @@ export interface ExecuteCommandResult { /** An optional message associated with the command result. */ message?: string | null; /** An optional value produced by the command. */ - data?: CommandResultData; + data?: CommandResultData | null; } /** @@ -865,10 +895,112 @@ export interface HttpsCertificateInfo { thumbprint?: string | null; } +/** The result of a single input interaction prompt. */ +export interface InputInteractionResult { + /** The data returned from the interaction. The value is `null` when the interaction was canceled. */ + data?: InteractionInput | null; + /** A flag indicating whether the interaction was canceled by the user. */ + canceled?: boolean; +} + +/** + * Represents configuration options for dynamically loading input data. + * + * Use this class to specify how and when dynamic input data should be loaded. This type is intended for advanced + * scenarios where input loading behavior must be customized. + */ +export interface InputLoadOptions { + /** Gets the callback function that is invoked to perform a load operation using the specified input context. */ + loadCallback?: (arg: LoadInputContext) => Promise; + /** + * Gets a value indicating whether `LoadCallback` should always be executed at the start of the input prompt. + * + * `LoadCallback` is executed at the start of the input prompt except when it depends on other inputs with `DependsOnInputs`. + * Setting this to `true` forces the load to always occur at the start of the prompt, regardless of dependencies. + */ + alwaysLoadOnStart?: boolean; + /** Gets the list of input names that this input depends on. `LoadCallback` is executed whenever any of the specified inputs change. */ + dependsOnInputs?: string[] | null; +} + +/** Polyglot options for inputs dialog interactions. */ +export interface InputsDialogInteractionOptions { + /** Gets the validation callback for the inputs dialog. */ + validationCallback?: (arg: InputsDialogValidationContext) => Promise; + /** Optional primary button text to override the default text. */ + primaryButtonText?: string | null; + /** Optional secondary button text to override the default text. */ + secondaryButtonText?: string | null; + /** Gets a value indicating whether to show the secondary button. */ + showSecondaryButton?: boolean | null; + /** Gets a value indicating whether to show the dismiss button. */ + showDismiss?: boolean | null; + /** Gets a value indicating whether Markdown in the message is rendered. */ + enableMessageMarkdown?: boolean | null; +} + +/** The result of a multi-input interaction prompt. */ +export interface InputsInteractionResult { + /** The data returned from the interaction. The value is `null` when the interaction was canceled. */ + data?: InteractionInputCollection | null; + /** A flag indicating whether the interaction was canceled by the user. */ + canceled?: boolean; +} + +/** Shared polyglot options for interaction prompts. */ +export interface InteractionOptions { + /** Optional primary button text to override the default text. */ + primaryButtonText?: string | null; + /** Optional secondary button text to override the default text. */ + secondaryButtonText?: string | null; + /** Gets a value indicating whether to show the secondary button. */ + showSecondaryButton?: boolean | null; + /** Gets a value indicating whether to show the dismiss button. */ + showDismiss?: boolean | null; + /** Gets a value indicating whether Markdown in the message is rendered. */ + enableMessageMarkdown?: boolean | null; +} + +/** Polyglot options for message box interactions. */ +export interface MessageBoxInteractionOptions { + /** Gets the intent of the message box. */ + intent?: MessageIntent | null; + /** Optional primary button text to override the default text. */ + primaryButtonText?: string | null; + /** Optional secondary button text to override the default text. */ + secondaryButtonText?: string | null; + /** Gets a value indicating whether to show the secondary button. */ + showSecondaryButton?: boolean | null; + /** Gets a value indicating whether to show the dismiss button. */ + showDismiss?: boolean | null; + /** Gets a value indicating whether Markdown in the message is rendered. */ + enableMessageMarkdown?: boolean | null; +} + +/** Polyglot options for notification interactions. */ +export interface NotificationInteractionOptions { + /** Gets the intent of the notification. */ + intent?: MessageIntent | null; + /** Gets the text for a link in the notification. */ + linkText?: string | null; + /** Gets the URL for the link in the notification. */ + linkUrl?: string | null; + /** Optional primary button text to override the default text. */ + primaryButtonText?: string | null; + /** Optional secondary button text to override the default text. */ + secondaryButtonText?: string | null; + /** Gets a value indicating whether to show the secondary button. */ + showSecondaryButton?: boolean | null; + /** Gets a value indicating whether to show the dismiss button. */ + showDismiss?: boolean | null; + /** Gets a value indicating whether Markdown in the message is rendered. */ + enableMessageMarkdown?: boolean | null; +} + /** Options for customizing parameter inputs from polyglot app hosts. */ export interface ParameterCustomInputOptions { /** Gets or sets the type of the input. */ - inputType?: InputType; + inputType?: InputType | null; /** Gets or sets the label for the input. */ label?: string | null; /** Gets or sets the description for the input. */ @@ -876,7 +1008,7 @@ export interface ParameterCustomInputOptions { /** Gets or sets whether the description should be rendered as Markdown. */ enableDescriptionMarkdown?: boolean | null; /** Gets or sets the choice options keyed by submitted value. */ - options?: Record; + options?: Record | null; /** Gets or sets the initial value of the input. */ value?: string | null; /** Gets or sets the placeholder text for the input. */ @@ -894,11 +1026,11 @@ export interface ProcessCommandExportOptions { /** The executable path or command name to start. */ executablePath?: string | null; /** The command-line arguments for the process. */ - arguments?: string[]; + arguments?: string[] | null; /** The working directory for the process. */ workingDirectory?: string | null; /** The environment variables to set for the process. */ - environmentVariables?: Record; + environmentVariables?: Record | null; /** A value indicating whether the process should inherit the current environment variables. */ inheritEnvironmentVariables?: boolean | null; /** Standard input content to write to the process after it starts. */ @@ -906,25 +1038,25 @@ export interface ProcessCommandExportOptions { /** A value indicating whether the entire process tree should be killed when the process is disposed. */ killEntireProcessTree?: boolean | null; /** Optional command configuration. */ - commandOptions?: CommandOptions; + commandOptions?: CommandOptions | null; /** The maximum number of stdout and stderr output lines returned as command result data. */ maxOutputLineCount?: number | null; /** A value indicating whether returned command output should be displayed immediately in the dashboard. */ displayImmediately?: boolean | null; /** The exit codes that are treated as a successful command invocation. */ - successExitCodes?: number[]; + successExitCodes?: number[] | null; } /** ATS-friendly result and command configuration for resource process commands. */ export interface ProcessCommandResultExportOptions { /** Optional command configuration. */ - commandOptions?: CommandOptions; + commandOptions?: CommandOptions | null; /** The maximum number of stdout and stderr output lines returned as command result data. */ maxOutputLineCount?: number | null; /** A value indicating whether returned command output should be displayed immediately in the dashboard. */ displayImmediately?: boolean | null; /** The exit codes that are treated as a successful command invocation. */ - successExitCodes?: number[]; + successExitCodes?: number[] | null; } /** ATS-friendly process specification for resource process command callbacks. */ @@ -932,11 +1064,11 @@ export interface ProcessCommandSpecExportData { /** The executable path or command name to start. */ executablePath?: string | null; /** The command-line arguments for the process. */ - arguments?: string[]; + arguments?: string[] | null; /** The working directory for the process. */ workingDirectory?: string | null; /** The environment variables to set for the process. */ - environmentVariables?: Record; + environmentVariables?: Record | null; /** A value indicating whether the process should inherit the current environment variables. */ inheritEnvironmentVariables?: boolean | null; /** Standard input content to write to the process after it starts. */ @@ -1008,7 +1140,7 @@ export interface TestDeeplyNestedDto { /** Test DTO with complex nested types. */ export interface TestNestedDto { id?: string; - config?: TestConfigDto; + config?: TestConfigDto | null; tags?: string[]; counts?: Record; } @@ -1273,6 +1405,48 @@ export interface GetValueAsyncOptions { cancellationToken?: AbortSignal | CancellationToken; } +export interface PromptConfirmationAsyncOptions { + /** Optional configuration for the message box interaction. */ + options?: MessageBoxInteractionOptions; + /** A token to cancel the operation. */ + cancellationToken?: AbortSignal | CancellationToken; +} + +export interface PromptInputAsyncOptions { + /** Optional configuration for the input dialog interaction. */ + options?: InputsDialogInteractionOptions; + /** A token to cancel the operation. */ + cancellationToken?: AbortSignal | CancellationToken; +} + +export interface PromptInputsAsyncOptions { + /** Optional configuration for the input dialog interaction. */ + options?: InputsDialogInteractionOptions; + /** A token to cancel the operation. */ + cancellationToken?: AbortSignal | CancellationToken; +} + +export interface PromptInputWithInputAsyncOptions { + /** Optional configuration for the input dialog interaction. */ + options?: InputsDialogInteractionOptions; + /** A token to cancel the operation. */ + cancellationToken?: AbortSignal | CancellationToken; +} + +export interface PromptMessageBoxAsyncOptions { + /** Optional configuration for the message box interaction. */ + options?: MessageBoxInteractionOptions; + /** A token to cancel the operation. */ + cancellationToken?: AbortSignal | CancellationToken; +} + +export interface PromptNotificationAsyncOptions { + /** Optional configuration for the notification interaction. */ + options?: NotificationInteractionOptions; + /** A token to cancel the operation. */ + cancellationToken?: AbortSignal | CancellationToken; +} + export interface PublishAsDockerFileOptions { /** Optional action to configure the container resource */ configure?: (obj: ContainerResource) => Promise; @@ -4922,6 +5096,8 @@ class EventingSubscriberRegistrationContextPromiseImpl implements EventingSubscr /** Context for {@link ResourceCommandAnnotation.ExecuteCommand}. */ export interface ExecuteCommandContext { toJSON(): MarshalledHandle; + /** The service provider. */ + serviceProvider(): ServiceProviderPromise; /** The resource name. */ resourceName(): Promise; /** The cancellation token. */ @@ -4939,6 +5115,8 @@ export interface ExecuteCommandContext { } export interface ExecuteCommandContextPromise extends PromiseLike { + /** The service provider. */ + serviceProvider(): ServiceProviderPromise; /** The resource name. */ resourceName(): Promise; /** The cancellation token. */ @@ -4966,6 +5144,17 @@ class ExecuteCommandContextImpl implements ExecuteCommandContext { /** Serialize for JSON-RPC transport */ toJSON(): MarshalledHandle { return this._handle.toJSON(); } + serviceProvider(): ServiceProviderPromise { + const promise = (async () => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.serviceProvider', + { context: this._handle } + ); + return new ServiceProviderImpl(handle, this._client); + })(); + return new ServiceProviderPromiseImpl(promise, this._client, false); + } + async resourceName(): Promise { return await this._client.invokeCapability( 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', @@ -5016,6 +5205,10 @@ class ExecuteCommandContextPromiseImpl implements ExecuteCommandContextPromise { return this._promise.then(onfulfilled, onrejected); } + serviceProvider(): ServiceProviderPromise { + return new ServiceProviderPromiseImpl(this._promise.then(obj => obj.serviceProvider()), this._client, false); + } + resourceName(): Promise { return this._promise.then(obj => obj.resourceName()); } @@ -5289,6 +5482,126 @@ class InputsDialogValidationContextPromiseImpl implements InputsDialogValidation } +// ============================================================================ +// LoadInputContext +// ============================================================================ + +/** The context for dynamic input loading. Used with `LoadCallback`. */ +export interface LoadInputContext { + toJSON(): MarshalledHandle; + /** Gets the loading input. This is the target of `InputLoadOptions`. */ + input(): Promise; + /** Gets the collection of all `InteractionInput` in this prompt. */ + allInputs(): Promise; + /** Gets the `CancellationToken`. */ + cancellationToken(): Promise; + /** + * Sets the available options for the loading input. + * @param options The choice options to display for the loading input, keyed by submitted value. + */ + setOptions(options: Record): LoadInputContextPromise; +} + +export interface LoadInputContextPromise extends PromiseLike { + /** Gets the loading input. This is the target of `InputLoadOptions`. */ + input(): Promise; + /** Gets the collection of all `InteractionInput` in this prompt. */ + allInputs(): Promise; + /** Gets the `CancellationToken`. */ + cancellationToken(): Promise; + /** + * Sets the available options for the loading input. + * @param options The choice options to display for the loading input, keyed by submitted value. + */ + setOptions(options: Record): LoadInputContextPromise; +} + +// ============================================================================ +// LoadInputContextImpl +// ============================================================================ + +/** The context for dynamic input loading. Used with `LoadCallback`. */ +class LoadInputContextImpl implements LoadInputContext { + constructor(private _handle: LoadInputContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + async input(): Promise { + return await this._client.invokeCapability( + 'Aspire.Hosting/LoadInputContext.input', + { context: this._handle } + ); + } + + async allInputs(): Promise { + return await this._client.invokeCapability( + 'Aspire.Hosting/LoadInputContext.allInputs', + { context: this._handle } + ); + } + + async cancellationToken(): Promise { + const result = await this._client.invokeCapability( + 'Aspire.Hosting/LoadInputContext.cancellationToken', + { context: this._handle } + ); + return CancellationToken.fromValue(result); + } + + /** @internal */ + async _setOptionsInternal(options: Record): Promise { + const rpcArgs: Record = { context: this._handle, options }; + await this._client.invokeCapability( + 'Aspire.Hosting/LoadInputContext.setOptions', + rpcArgs + ); + return this; + } + + /** + * Sets the available options for the loading input. + * @param options The choice options to display for the loading input, keyed by submitted value. + */ + setOptions(options: Record): LoadInputContextPromise { + return new LoadInputContextPromiseImpl(this._setOptionsInternal(options), this._client); + } + +} + +/** + * Thenable wrapper for LoadInputContext that enables fluent chaining. + */ +class LoadInputContextPromiseImpl implements LoadInputContextPromise { + constructor(private _promise: Promise, private _client: AspireClientRpc, track = true) { + if (track) { _client.trackPromise(_promise); } + } + + then( + onfulfilled?: ((value: LoadInputContext) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + input(): Promise { + return this._promise.then(obj => obj.input()); + } + + allInputs(): Promise { + return this._promise.then(obj => obj.allInputs()); + } + + cancellationToken(): Promise { + return this._promise.then(obj => obj.cancellationToken()); + } + + setOptions(options: Record): LoadInputContextPromise { + return new LoadInputContextPromiseImpl(this._promise.then(obj => obj.setOptions(options)), this._client); + } + +} + // ============================================================================ // LogFacade // ============================================================================ @@ -10522,6 +10835,320 @@ class HostEnvironmentPromiseImpl implements HostEnvironmentPromise { } +// ============================================================================ +// InteractionService +// ============================================================================ + +/** A service to interact with the current development environment. */ +export interface InteractionService { + toJSON(): MarshalledHandle; + /** + * Gets a value indicating whether the interaction service is available. + * @returns `true` when the interaction service can interact with the user; otherwise, `false`. + */ + isAvailable(): Promise; + /** + * Prompts the user for confirmation with a dialog. + * @param title The title of the dialog. + * @param message The message to display in the dialog. + * @param options Additional options. + * @returns The confirmation interaction result. + */ + promptConfirmationAsync(title: string, message: string, options?: PromptConfirmationAsyncOptions): Promise; + /** + * Prompts the user with a message box dialog. + * @param title The title of the message box. + * @param message The message to display in the message box. + * @param options Additional options. + * @returns The message box interaction result. + */ + promptMessageBoxAsync(title: string, message: string, options?: PromptMessageBoxAsyncOptions): Promise; + /** + * Prompts the user for a single text input. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param inputLabel The label for the input field. + * @param placeHolder The placeholder text for the input field. + * @param options Additional options. + * @returns The input interaction result. + */ + promptInputAsync(title: string, message: string, inputLabel: string, placeHolder: string, options?: PromptInputAsyncOptions): Promise; + /** + * Prompts the user for a single input using a specified `InteractionInput`. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param input The input configuration. + * @param options Additional options. + * @returns The input interaction result. + */ + promptInputWithInputAsync(title: string, message: string, input: InteractionInput, options?: PromptInputWithInputAsyncOptions): Promise; + /** + * Prompts the user for multiple inputs. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param inputs The input configurations. + * @param options Additional options. + * @returns The inputs interaction result. + */ + promptInputsAsync(title: string, message: string, inputs: InteractionInput[], options?: PromptInputsAsyncOptions): Promise; + /** + * Prompts the user with a notification. + * @param title The title of the notification. + * @param message The message to display in the notification. + * @param options Additional options. + * @returns The notification interaction result. + */ + promptNotificationAsync(title: string, message: string, options?: PromptNotificationAsyncOptions): Promise; +} + +export interface InteractionServicePromise extends PromiseLike { + /** + * Gets a value indicating whether the interaction service is available. + * @returns `true` when the interaction service can interact with the user; otherwise, `false`. + */ + isAvailable(): Promise; + /** + * Prompts the user for confirmation with a dialog. + * @param title The title of the dialog. + * @param message The message to display in the dialog. + * @param options Additional options. + * @returns The confirmation interaction result. + */ + promptConfirmationAsync(title: string, message: string, options?: PromptConfirmationAsyncOptions): Promise; + /** + * Prompts the user with a message box dialog. + * @param title The title of the message box. + * @param message The message to display in the message box. + * @param options Additional options. + * @returns The message box interaction result. + */ + promptMessageBoxAsync(title: string, message: string, options?: PromptMessageBoxAsyncOptions): Promise; + /** + * Prompts the user for a single text input. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param inputLabel The label for the input field. + * @param placeHolder The placeholder text for the input field. + * @param options Additional options. + * @returns The input interaction result. + */ + promptInputAsync(title: string, message: string, inputLabel: string, placeHolder: string, options?: PromptInputAsyncOptions): Promise; + /** + * Prompts the user for a single input using a specified `InteractionInput`. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param input The input configuration. + * @param options Additional options. + * @returns The input interaction result. + */ + promptInputWithInputAsync(title: string, message: string, input: InteractionInput, options?: PromptInputWithInputAsyncOptions): Promise; + /** + * Prompts the user for multiple inputs. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param inputs The input configurations. + * @param options Additional options. + * @returns The inputs interaction result. + */ + promptInputsAsync(title: string, message: string, inputs: InteractionInput[], options?: PromptInputsAsyncOptions): Promise; + /** + * Prompts the user with a notification. + * @param title The title of the notification. + * @param message The message to display in the notification. + * @param options Additional options. + * @returns The notification interaction result. + */ + promptNotificationAsync(title: string, message: string, options?: PromptNotificationAsyncOptions): Promise; +} + +// ============================================================================ +// InteractionServiceImpl +// ============================================================================ + +/** A service to interact with the current development environment. */ +class InteractionServiceImpl implements InteractionService { + constructor(private _handle: IInteractionServiceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** + * Gets a value indicating whether the interaction service is available. + * @returns `true` when the interaction service can interact with the user; otherwise, `false`. + */ + async isAvailable(): Promise { + const rpcArgs: Record = { interactionService: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/interactionServiceIsAvailable', + rpcArgs + ); + } + + /** + * Prompts the user for confirmation with a dialog. + * @param title The title of the dialog. + * @param message The message to display in the dialog. + * @param optionsBag Additional options. + * @returns The confirmation interaction result. + */ + async promptConfirmationAsync(title: string, message: string, optionsBag?: PromptConfirmationAsyncOptions): Promise { + const options = optionsBag?.options; + const cancellationToken = optionsBag?.cancellationToken; + const rpcArgs: Record = { interactionService: this._handle, title, message }; + if (options !== undefined) rpcArgs.options = options; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken); + return await this._client.invokeCapability( + 'Aspire.Hosting/promptConfirmationAsync', + rpcArgs + ); + } + + /** + * Prompts the user with a message box dialog. + * @param title The title of the message box. + * @param message The message to display in the message box. + * @param optionsBag Additional options. + * @returns The message box interaction result. + */ + async promptMessageBoxAsync(title: string, message: string, optionsBag?: PromptMessageBoxAsyncOptions): Promise { + const options = optionsBag?.options; + const cancellationToken = optionsBag?.cancellationToken; + const rpcArgs: Record = { interactionService: this._handle, title, message }; + if (options !== undefined) rpcArgs.options = options; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken); + return await this._client.invokeCapability( + 'Aspire.Hosting/promptMessageBoxAsync', + rpcArgs + ); + } + + /** + * Prompts the user for a single text input. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param inputLabel The label for the input field. + * @param placeHolder The placeholder text for the input field. + * @param optionsBag Additional options. + * @returns The input interaction result. + */ + async promptInputAsync(title: string, message: string, inputLabel: string, placeHolder: string, optionsBag?: PromptInputAsyncOptions): Promise { + const options = optionsBag?.options; + const cancellationToken = optionsBag?.cancellationToken; + const rpcArgs: Record = { interactionService: this._handle, title, message, inputLabel, placeHolder }; + if (options !== undefined) rpcArgs.options = options; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken); + return await this._client.invokeCapability( + 'Aspire.Hosting/promptInputAsync', + rpcArgs + ); + } + + /** + * Prompts the user for a single input using a specified `InteractionInput`. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param input The input configuration. + * @param optionsBag Additional options. + * @returns The input interaction result. + */ + async promptInputWithInputAsync(title: string, message: string, input: InteractionInput, optionsBag?: PromptInputWithInputAsyncOptions): Promise { + const options = optionsBag?.options; + const cancellationToken = optionsBag?.cancellationToken; + const rpcArgs: Record = { interactionService: this._handle, title, message, input }; + if (options !== undefined) rpcArgs.options = options; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken); + return await this._client.invokeCapability( + 'Aspire.Hosting/promptInputWithInput', + rpcArgs + ); + } + + /** + * Prompts the user for multiple inputs. + * @param title The title of the input dialog. + * @param message The message to display in the dialog. + * @param inputs The input configurations. + * @param optionsBag Additional options. + * @returns The inputs interaction result. + */ + async promptInputsAsync(title: string, message: string, inputs: InteractionInput[], optionsBag?: PromptInputsAsyncOptions): Promise { + const options = optionsBag?.options; + const cancellationToken = optionsBag?.cancellationToken; + const rpcArgs: Record = { interactionService: this._handle, title, message, inputs }; + if (options !== undefined) rpcArgs.options = options; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken); + return await this._client.invokeCapability( + 'Aspire.Hosting/promptInputsAsync', + rpcArgs + ); + } + + /** + * Prompts the user with a notification. + * @param title The title of the notification. + * @param message The message to display in the notification. + * @param optionsBag Additional options. + * @returns The notification interaction result. + */ + async promptNotificationAsync(title: string, message: string, optionsBag?: PromptNotificationAsyncOptions): Promise { + const options = optionsBag?.options; + const cancellationToken = optionsBag?.cancellationToken; + const rpcArgs: Record = { interactionService: this._handle, title, message }; + if (options !== undefined) rpcArgs.options = options; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = CancellationToken.fromValue(cancellationToken); + return await this._client.invokeCapability( + 'Aspire.Hosting/promptNotificationAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for InteractionService that enables fluent chaining. + */ +class InteractionServicePromiseImpl implements InteractionServicePromise { + constructor(private _promise: Promise, private _client: AspireClientRpc, track = true) { + if (track) { _client.trackPromise(_promise); } + } + + then( + onfulfilled?: ((value: InteractionService) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + isAvailable(): Promise { + return this._promise.then(obj => obj.isAvailable()); + } + + promptConfirmationAsync(title: string, message: string, options?: PromptConfirmationAsyncOptions): Promise { + return this._promise.then(obj => obj.promptConfirmationAsync(title, message, options)); + } + + promptMessageBoxAsync(title: string, message: string, options?: PromptMessageBoxAsyncOptions): Promise { + return this._promise.then(obj => obj.promptMessageBoxAsync(title, message, options)); + } + + promptInputAsync(title: string, message: string, inputLabel: string, placeHolder: string, options?: PromptInputAsyncOptions): Promise { + return this._promise.then(obj => obj.promptInputAsync(title, message, inputLabel, placeHolder, options)); + } + + promptInputWithInputAsync(title: string, message: string, input: InteractionInput, options?: PromptInputWithInputAsyncOptions): Promise { + return this._promise.then(obj => obj.promptInputWithInputAsync(title, message, input, options)); + } + + promptInputsAsync(title: string, message: string, inputs: InteractionInput[], options?: PromptInputsAsyncOptions): Promise { + return this._promise.then(obj => obj.promptInputsAsync(title, message, inputs, options)); + } + + promptNotificationAsync(title: string, message: string, options?: PromptNotificationAsyncOptions): Promise { + return this._promise.then(obj => obj.promptNotificationAsync(title, message, options)); + } + +} + // ============================================================================ // Logger // ============================================================================ @@ -11177,6 +11804,11 @@ export interface ServiceProvider { * @returns The distributed application eventing handle. */ getEventing(): DistributedApplicationEventingPromise; + /** + * Gets the interaction service from the service provider. + * @returns An interaction service handle. + */ + getInteractionService(): InteractionServicePromise; /** * Gets the logger factory from the service provider. * @returns A logger factory handle. @@ -11220,6 +11852,11 @@ export interface ServiceProviderPromise extends PromiseLike { * @returns The distributed application eventing handle. */ getEventing(): DistributedApplicationEventingPromise; + /** + * Gets the interaction service from the service provider. + * @returns An interaction service handle. + */ + getInteractionService(): InteractionServicePromise; /** * Gets the logger factory from the service provider. * @returns A logger factory handle. @@ -11286,6 +11923,24 @@ class ServiceProviderImpl implements ServiceProvider { return new DistributedApplicationEventingPromiseImpl(this._getEventingInternal(), this._client); } + /** @internal */ + async _getInteractionServiceInternal(): Promise { + const rpcArgs: Record = { serviceProvider: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/getInteractionService', + rpcArgs + ); + return new InteractionServiceImpl(result, this._client); + } + + /** + * Gets the interaction service from the service provider. + * @returns An interaction service handle. + */ + getInteractionService(): InteractionServicePromise { + return new InteractionServicePromiseImpl(this._getInteractionServiceInternal(), this._client); + } + /** @internal */ async _getLoggerFactoryInternal(): Promise { const rpcArgs: Record = { serviceProvider: this._handle }; @@ -11433,6 +12088,10 @@ class ServiceProviderPromiseImpl implements ServiceProviderPromise { return new DistributedApplicationEventingPromiseImpl(this._promise.then(obj => obj.getEventing()), this._client); } + getInteractionService(): InteractionServicePromise { + return new InteractionServicePromiseImpl(this._promise.then(obj => obj.getInteractionService()), this._client); + } + getLoggerFactory(): LoggerFactoryPromise { return new LoggerFactoryPromiseImpl(this._promise.then(obj => obj.getLoggerFactory()), this._client); } @@ -53528,6 +54187,7 @@ registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Ats.EventingSubscriberRegis registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContextImpl(handle as ExecuteCommandContextHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.InitializeResourceEvent', (handle, client) => new InitializeResourceEventImpl(handle as InitializeResourceEventHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.InputsDialogValidationContext', (handle, client) => new InputsDialogValidationContextImpl(handle as InputsDialogValidationContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.LoadInputContext', (handle, client) => new LoadInputContextImpl(handle as LoadInputContextHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.LogFacade', (handle, client) => new LogFacadeImpl(handle as LogFacadeHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Pipelines.PipelineConfigurationContext', (handle, client) => new PipelineConfigurationContextImpl(handle as PipelineConfigurationContextHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Pipelines.PipelineContext', (handle, client) => new PipelineContextImpl(handle as PipelineContextHandle, client)); @@ -53561,6 +54221,7 @@ registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Pipelines.IDistributedAppli registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IExecutionConfigurationBuilder', (handle, client) => new ExecutionConfigurationBuilderImpl(handle as IExecutionConfigurationBuilderHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IExecutionConfigurationResult', (handle, client) => new ExecutionConfigurationResultImpl(handle as IExecutionConfigurationResultHandle, client)); registerHandleWrapper('Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment', (handle, client) => new HostEnvironmentImpl(handle as IHostEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IInteractionService', (handle, client) => new InteractionServiceImpl(handle as IInteractionServiceHandle, client)); registerHandleWrapper('Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger', (handle, client) => new LoggerImpl(handle as ILoggerHandle, client)); registerHandleWrapper('Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILoggerFactory', (handle, client) => new LoggerFactoryImpl(handle as ILoggerFactoryHandle, client)); registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Pipelines.IReportingStep', (handle, client) => new ReportingStepImpl(handle as IReportingStepHandle, client)); diff --git a/tests/PolyglotAppHosts/Aspire.Hosting/Go/apphost.go b/tests/PolyglotAppHosts/Aspire.Hosting/Go/apphost.go index dfafb72dfe6..d92ba37d65d 100644 --- a/tests/PolyglotAppHosts/Aspire.Hosting/Go/apphost.go +++ b/tests/PolyglotAppHosts/Aspire.Hosting/Go/apphost.go @@ -2,6 +2,7 @@ package main import ( "log" + "time" "apphost/modules/aspire" ) @@ -381,11 +382,6 @@ ENTRYPOINT ["dotnet", "App.dll"] _, _ = builderConfiguration.GetChildren() _, _ = builderConfiguration.Exists("MyConfig:Key") - builderExecutionContext := builder.ExecutionContext() - executionContextServiceProvider := builderExecutionContext.ServiceProvider() - _ = executionContextServiceProvider.GetDistributedApplicationModel() - resourceCommandService := executionContextServiceProvider.GetResourceCommandService() - // Subscriptions (typed callbacks) beforeStartSub := builder.SubscribeBeforeStart(func(e aspire.BeforeStartEvent) { beforeStartModel := e.Model() @@ -548,8 +544,8 @@ ENTRYPOINT ["dotnet", "App.dll"] UpdateState: updateCommandState, }, }) - _ = container.WithCommand("echo", "Echo", func(ctx aspire.ExecuteCommandContext) *aspire.ExecuteCommandResult { - commandArguments, err := ctx.Arguments().ToArray() + _ = container.WithCommand("echo", "Echo", func(commandContext aspire.ExecuteCommandContext) *aspire.ExecuteCommandResult { + commandArguments, err := commandContext.Arguments().ToArray() if err != nil { return &aspire.ExecuteCommandResult{Success: false, ErrorMessage: aspire.StringPtr(aspire.FormatError(err))} } @@ -565,11 +561,14 @@ ENTRYPOINT ["dotnet", "App.dll"] }, }, }) - _ = container.WithCommand("restart", "Restart", func(ctx aspire.ExecuteCommandContext) *aspire.ExecuteCommandResult { - cancellationToken, err := ctx.CancellationToken() + _ = container.WithCommand("restart", "Restart", func(commandContext aspire.ExecuteCommandContext) *aspire.ExecuteCommandResult { + cancellationToken, err := commandContext.CancellationToken() if err != nil { return &aspire.ExecuteCommandResult{Success: false, ErrorMessage: aspire.StringPtr(aspire.FormatError(err))} } + // Command callbacks run after Build(), when the execution context service provider is populated; accessing it before Build() throws. + serviceProvider := commandContext.ServiceProvider() + resourceCommandService := serviceProvider.GetResourceCommandService() result, err := resourceCommandService.ExecuteCommandAsync(container, "echo", &aspire.ExecuteCommandAsyncOptions{Arguments: map[string]string{"message": "hello"}, CancellationToken: cancellationToken}) if err != nil { return &aspire.ExecuteCommandResult{Success: false, ErrorMessage: aspire.StringPtr(aspire.FormatError(err))} @@ -577,12 +576,144 @@ ENTRYPOINT ["dotnet", "App.dll"] return result }) + _ = container.WithCommand("interaction-validation", "Interaction Validation", func(commandContext aspire.ExecuteCommandContext) *aspire.ExecuteCommandResult { + // Command callbacks run after Build(), when the execution context service provider is populated; accessing it before Build() throws. + interactionService := commandContext.ServiceProvider().GetInteractionService() + isAvailable, _ := interactionService.IsAvailable() + dynamicChoiceValue := validateInteractionServicePromptApis(interactionService) + _ = commandContext.Logger().LogInformation("Dynamic choice selected: " + dynamicChoiceValue) + resultFormat := aspire.CommandResultFormatText + + return &aspire.ExecuteCommandResult{ + Success: isAvailable, + Data: &aspire.CommandResultData{ + Value: dynamicChoiceValue, + Format: &resultFormat, + }, + } + }) app, err := builder.Build() if err != nil { log.Fatalf(aspire.FormatError(err)) } + if err := app.Run(); err != nil { log.Fatalf(aspire.FormatError(err)) } } + +func validateInteractionServicePromptApis(interactionService aspire.InteractionService) string { + confirmationIntent := aspire.MessageIntentConfirmation + informationIntent := aspire.MessageIntentInformation + interactionInput := &aspire.InteractionInput{ + Name: "validation", + InputType: aspire.InputTypeText, + Value: "default", + Disabled: false, + } + dynamicChoiceInput := &aspire.InteractionInput{ + Name: "dynamic-choice", + InputType: aspire.InputTypeChoice, + Placeholder: aspire.StringPtr("Loading choices..."), + Required: aspire.BoolPtr(true), + DynamicLoading: &aspire.InputLoadOptions{ + AlwaysLoadOnStart: aspire.BoolPtr(true), + LoadCallback: func(args ...any) any { + loadContext, ok := args[0].(aspire.LoadInputContext) + if !ok { + return nil + } + + time.Sleep(time.Second) + _ = loadContext.SetOptions(map[string]string{ + "dynamic1": "Dynamic Option 1", + "dynamic2": "Dynamic Option 2", + }) + return nil + }, + }, + } + + _, _ = interactionService.PromptConfirmationAsync("Confirm", "Continue?", &aspire.PromptConfirmationAsyncOptions{ + Options: &aspire.MessageBoxInteractionOptions{ + Intent: &confirmationIntent, + PrimaryButtonText: aspire.StringPtr("Continue"), + }, + }) + _, _ = interactionService.PromptMessageBoxAsync("Message", "Message body", &aspire.PromptMessageBoxAsyncOptions{ + Options: &aspire.MessageBoxInteractionOptions{ + Intent: &informationIntent, + EnableMessageMarkdown: aspire.BoolPtr(true), + }, + }) + _, _ = interactionService.PromptInputAsync("Input", "Input body", "Name", "Placeholder", &aspire.PromptInputAsyncOptions{ + Options: &aspire.InputsDialogInteractionOptions{ + PrimaryButtonText: aspire.StringPtr("Submit"), + }, + }) + _, _ = interactionService.PromptInputWithInputAsync("Input", "Input body", interactionInput, &aspire.PromptInputWithInputAsyncOptions{ + Options: &aspire.InputsDialogInteractionOptions{ + ShowDismiss: aspire.BoolPtr(true), + }, + }) + _, _ = interactionService.PromptInputsAsync("Inputs", "Inputs body", []*aspire.InteractionInput{interactionInput}, &aspire.PromptInputsAsyncOptions{ + Options: &aspire.InputsDialogInteractionOptions{ + ShowSecondaryButton: aspire.BoolPtr(true), + SecondaryButtonText: aspire.StringPtr("Skip"), + }, + }) + dynamicChoiceResult, _ := interactionService.PromptInputsAsync("Dynamic choice", "Select a dynamically loaded option.", []*aspire.InteractionInput{dynamicChoiceInput}, &aspire.PromptInputsAsyncOptions{ + Options: &aspire.InputsDialogInteractionOptions{ + PrimaryButtonText: aspire.StringPtr("Submit"), + ValidationCallback: func(args ...any) any { + validationContext, ok := args[0].(aspire.InputsDialogValidationContext) + if !ok { + return nil + } + + inputs, err := validationContext.Inputs().ToArray() + if err != nil { + _ = validationContext.AddValidationError("dynamic-choice", aspire.FormatError(err)) + return nil + } + + selectedValue := "" + for _, input := range inputs { + if input.Name == "dynamic-choice" { + selectedValue = input.Value + break + } + } + if selectedValue != "dynamic1" && selectedValue != "dynamic2" { + _ = validationContext.AddValidationError("dynamic-choice", "Select a dynamically loaded option.") + } + return nil + }, + }, + }) + _, _ = interactionService.PromptNotificationAsync("Notification", "Notification body", &aspire.PromptNotificationAsyncOptions{ + Options: &aspire.NotificationInteractionOptions{ + Intent: &informationIntent, + LinkText: aspire.StringPtr("Docs"), + LinkUrl: aspire.StringPtr("https://aspire.dev"), + }, + }) + + if dynamicChoiceResult == nil || dynamicChoiceResult.Canceled || dynamicChoiceResult.Data == nil { + return "default" + } + + inputs, err := (*dynamicChoiceResult.Data).ToArray() + if err != nil { + return "default" + } + + for _, input := range inputs { + if input.Name == "dynamic-choice" && input.Value != "" { + return input.Value + } + } + + return "default" +} diff --git a/tests/PolyglotAppHosts/Aspire.Hosting/Java/AppHost.java b/tests/PolyglotAppHosts/Aspire.Hosting/Java/AppHost.java index 5847f19d63b..9b5b76a9b0a 100644 --- a/tests/PolyglotAppHosts/Aspire.Hosting/Java/AppHost.java +++ b/tests/PolyglotAppHosts/Aspire.Hosting/Java/AppHost.java @@ -139,9 +139,6 @@ void main() throws Exception { var _configChildren = builderConfiguration.getChildren(); var _configExists = builderConfiguration.exists("MyConfig:Key"); var builderExecutionContext = builder.executionContext(); - var executionContextServiceProvider = builderExecutionContext.serviceProvider(); - var _distributedApplicationModelFromExecutionContext = executionContextServiceProvider.getDistributedApplicationModel(); - var resourceCommandService = executionContextServiceProvider.getResourceCommandService(); builder.addEventingSubscriber((registrationContext) -> { var subscriberExecutionContext = registrationContext.executionContext(); var _subscriberIsRunMode = subscriberExecutionContext.isRunMode(); @@ -254,8 +251,11 @@ void main() throws Exception { result.setSuccess("hello".equals(commandArguments[0].getValue())); return result; }, echoCommandOptions); - container.withCommand("restart", "Restart", (ctx) -> { - var cancellationToken = ctx.cancellationToken(); + container.withCommand("restart", "Restart", (commandContext) -> { + var cancellationToken = commandContext.cancellationToken(); + // Command callbacks run after build(), when the execution context service provider is populated; accessing it before build() throws. + var serviceProvider = commandContext.serviceProvider(); + var resourceCommandService = serviceProvider.getResourceCommandService(); return resourceCommandService.executeCommandAsync( container, "echo", @@ -263,6 +263,135 @@ void main() throws Exception { .arguments(Map.of("message", "hello")) .cancellationToken(cancellationToken)); }); + container.withCommand("interaction-validation", "Interaction Validation", (commandContext) -> { + // Command callbacks run after build(), when the execution context service provider is populated; accessing it before build() throws. + var interactionService = commandContext.serviceProvider().getInteractionService(); + var interactionServiceAvailable = interactionService.isAvailable(); + var interactionInput = new InteractionInput(); + interactionInput.setName("validation"); + interactionInput.setInputType(InputType.TEXT); + interactionInput.setValue("default"); + interactionInput.setDisabled(false); + var choiceInput = new InteractionInput(); + choiceInput.setName("choice"); + choiceInput.setInputType(InputType.CHOICE); + choiceInput.setPlaceholder("Placeholder!"); + choiceInput.setRequired(true); + choiceInput.setOptions(new Object[] { + Map.of("Value", "option1", "Label", "Option 1"), + Map.of("Value", "option2", "Label", "Option 2"), + Map.of("Value", "option3", "Label", "Option 3") + }); + var dynamicLoading = new InputLoadOptions(); + dynamicLoading.setAlwaysLoadOnStart(true); + dynamicLoading.setLoadCallback((Function) (args) -> { + var loadContext = (LoadInputContext) args[0]; + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ex); + } + + loadContext.setOptions(Map.of( + "dynamic1", "Dynamic Option 1", + "dynamic2", "Dynamic Option 2")); + return null; + }); + var dynamicChoiceInput = new InteractionInput(); + dynamicChoiceInput.setName("dynamic-choice"); + dynamicChoiceInput.setInputType(InputType.CHOICE); + dynamicChoiceInput.setPlaceholder("Loading choices..."); + dynamicChoiceInput.setRequired(true); + dynamicChoiceInput.setDynamicLoading(dynamicLoading); + var confirmationOptions = new MessageBoxInteractionOptions(); + confirmationOptions.setIntent(MessageIntent.CONFIRMATION); + confirmationOptions.setPrimaryButtonText("Continue"); + interactionService.promptConfirmationAsync( + "Confirm", + "Continue?", + new PromptConfirmationAsyncOptions().options(confirmationOptions)); + var messageBoxOptions = new MessageBoxInteractionOptions(); + messageBoxOptions.setIntent(MessageIntent.INFORMATION); + messageBoxOptions.setEnableMessageMarkdown(true); + interactionService.promptMessageBoxAsync( + "Message", + "Message body", + new PromptMessageBoxAsyncOptions().options(messageBoxOptions)); + var inputOptions = new InputsDialogInteractionOptions(); + inputOptions.setPrimaryButtonText("Submit"); + interactionService.promptInputAsync( + "Input", + "Input body", + "Name", + "Placeholder", + new PromptInputAsyncOptions().options(inputOptions)); + var inputWithInputOptions = new InputsDialogInteractionOptions(); + inputWithInputOptions.setPrimaryButtonText("Submit"); + inputWithInputOptions.setSecondaryButtonText("Skip"); + inputWithInputOptions.setShowSecondaryButton(true); + inputWithInputOptions.setEnableMessageMarkdown(true); + inputWithInputOptions.setShowDismiss(true); + interactionService.promptInputWithInputAsync( + "Choice inputs", + "Range of choice inputs", + choiceInput, + new PromptInputWithInputAsyncOptions().options(inputWithInputOptions)); + var inputsOptions = new InputsDialogInteractionOptions(); + inputsOptions.setShowSecondaryButton(true); + inputsOptions.setSecondaryButtonText("Skip"); + interactionService.promptInputsAsync( + "Inputs", + "Inputs body", + new InteractionInput[] { interactionInput, choiceInput }, + new PromptInputsAsyncOptions().options(inputsOptions)); + var dynamicChoiceOptions = new InputsDialogInteractionOptions(); + dynamicChoiceOptions.setPrimaryButtonText("Submit"); + dynamicChoiceOptions.setValidationCallback((Function) (args) -> { + var validationContext = (InputsDialogValidationContext) args[0]; + var selectedValue = ""; + for (var input : validationContext.inputs().toArray()) { + if ("dynamic-choice".equals(input.getName())) { + selectedValue = input.getValue(); + break; + } + } + if (!"dynamic1".equals(selectedValue) && !"dynamic2".equals(selectedValue)) { + validationContext.addValidationError("dynamic-choice", "Select a dynamically loaded option."); + } + return null; + }); + var dynamicChoiceResult = interactionService.promptInputsAsync( + "Dynamic choice", + "Select a dynamically loaded option.", + new InteractionInput[] { dynamicChoiceInput }, + new PromptInputsAsyncOptions().options(dynamicChoiceOptions)); + var notificationOptions = new NotificationInteractionOptions(); + notificationOptions.setIntent(MessageIntent.INFORMATION); + notificationOptions.setLinkText("Docs"); + notificationOptions.setLinkUrl("https://aspire.dev"); + interactionService.promptNotificationAsync( + "Notification", + "Notification body", + new PromptNotificationAsyncOptions().options(notificationOptions)); + var dynamicChoiceValue = "default"; + if (!dynamicChoiceResult.getCanceled() && dynamicChoiceResult.getData() != null) { + for (var input : dynamicChoiceResult.getData().toArray()) { + if ("dynamic-choice".equals(input.getName()) && input.getValue() != null && !input.getValue().isEmpty()) { + dynamicChoiceValue = input.getValue(); + break; + } + } + } + commandContext.logger().logInformation("Dynamic choice selected: " + dynamicChoiceValue); + var data = new CommandResultData(); + data.setValue(dynamicChoiceValue); + data.setFormat(CommandResultFormat.TEXT); + var result = new ExecuteCommandResult(); + result.setSuccess(interactionServiceAvailable); + result.setData(data); + return result; + }); container.withHttpCommand("/health", "Health Check"); var httpCmdOptions = new HttpCommandExportOptions(); httpCmdOptions.setMethodName("POST"); diff --git a/tests/PolyglotAppHosts/Aspire.Hosting/Python/apphost.py b/tests/PolyglotAppHosts/Aspire.Hosting/Python/apphost.py index d0216658da6..b61849ac39e 100644 --- a/tests/PolyglotAppHosts/Aspire.Hosting/Python/apphost.py +++ b/tests/PolyglotAppHosts/Aspire.Hosting/Python/apphost.py @@ -288,9 +288,6 @@ def configure_image_push_options(context): _config_children = builder_configuration.get_children() _config_exists = builder_configuration.exists() builder_execution_context = builder.execution_context - execution_context_service_provider = builder_execution_context.service_provider - _distributed_application_model_from_execution_context = execution_context_service_provider.get_distributed_app_model() - resource_command_service = execution_context_service_provider.get_resource_command_service() def configure_eventing_subscriber(registration_context): _subscriber_execution_context = registration_context.execution_context @@ -413,13 +410,122 @@ def echo_command(ctx): container.with_command( "noop", "Noop", - lambda *_args, **_kwargs: {"success": True}, + lambda command_context: {"success": True}, command_options={"UpdateState": update_command_state} ) - def restart_command(_ctx): + def restart_command(command_context): + # Command callbacks run after build(), when the execution context service provider is populated; accessing it before build() throws. + service_provider = command_context.service_provider + resource_command_service = service_provider.get_resource_command_service() return resource_command_service.execute_command(container, "echo", arguments={"message": "hello"}) + def interaction_validation_command(command_context): + # Command callbacks run after build(), when the execution context service provider is populated; accessing it before build() throws. + service_provider = command_context.service_provider + interaction_service = service_provider.get_interaction_service() + is_available = interaction_service.is_available() + text_input = { + "Name": "validation", + "InputType": "Text", + "Value": "default", + "Disabled": False, + } + choice_input = { + "Name": "choice", + "InputType": "Choice", + "Placeholder": "Placeholder!", + "Required": True, + "Options": [ + {"Key": "option1", "Value": "Option 1"}, + {"Key": "option2", "Value": "Option 2"}, + {"Key": "option3", "Value": "Option 3"}, + ], + } + + def load_dynamic_choices(load_context): + import time + time.sleep(1) + load_context.set_options({ + "dynamic1": "Dynamic Option 1", + "dynamic2": "Dynamic Option 2", + }) + + def validate_dynamic_choice(validation_context): + dynamic_choice = validation_context.inputs.required("dynamic-choice") + if dynamic_choice.get("Value") not in ("dynamic1", "dynamic2"): + validation_context.add_validation_error("dynamic-choice", "Select one of the dynamically loaded values.") + + dynamic_choice_input = { + "Name": "dynamic-choice", + "InputType": "Choice", + "Placeholder": "Choose a dynamically loaded value", + "Required": True, + "DynamicLoading": { + "AlwaysLoadOnStart": True, + "LoadCallback": load_dynamic_choices, + }, + } + interaction_service.prompt_confirmation( + "Confirm", + "Continue?", + options={"Intent": "Confirmation", "PrimaryButtonText": "Continue"}, + ) + interaction_service.prompt_message_box( + "Message", + "Message body", + options={"Intent": "Information", "EnableMessageMarkdown": True}, + ) + input_result = interaction_service.prompt_input( + "Input", + "Input body", + "Name", + "Placeholder", + options={"PrimaryButtonText": "Submit"}, + ) + choice_result = interaction_service.prompt_input_with_input( + "Choice inputs", + "Range of choice inputs", + choice_input, + options={ + "PrimaryButtonText": "Submit", + "SecondaryButtonText": "Skip", + "ShowSecondaryButton": True, + "EnableMessageMarkdown": True, + "ShowDismiss": True, + }, + ) + interaction_service.prompt_inputs( + "Inputs", + "Inputs body", + [text_input, choice_input], + options={"ShowSecondaryButton": True, "SecondaryButtonText": "Skip"}, + ) + dynamic_choice_result = interaction_service.prompt_input_with_input( + "Dynamic choice input", + "Options are loaded after the prompt opens.", + dynamic_choice_input, + options={ + "PrimaryButtonText": "Submit", + "ValidationCallback": validate_dynamic_choice, + }, + ) + dynamic_choice_value = (dynamic_choice_result.get("data") or {}).get("Value", "canceled") + command_context.logger.log_information("Dynamic choice selected: %s", dynamic_choice_value) + interaction_service.prompt_notification( + "Notification", + "Notification body", + options={"Intent": "Information", "LinkText": "Docs", "LinkUrl": "https://aspire.dev"}, + ) + + return { + "success": is_available or input_result.get("canceled") is True or choice_result.get("canceled") is True, + "data": { + "value": dynamic_choice_value, + "format": "Text", + }, + } + container.with_command( "echo", "Echo", @@ -427,6 +533,7 @@ def restart_command(_ctx): command_options={"Arguments": [{"Name": "message", "InputType": "Text", "Required": True}]} ) container.with_command("restart", "Restart", restart_command) + container.with_command("interaction-validation", "Interaction Validation", interaction_validation_command) # withHttpCommand container.with_http_command("/health", "Health Check") container.with_http_command("/api/reset", "Reset", options={"MethodName": "POST", "ConfirmationMessage": "Are you sure?"}) diff --git a/tests/PolyglotAppHosts/Aspire.Hosting/TypeScript/apphost.mts b/tests/PolyglotAppHosts/Aspire.Hosting/TypeScript/apphost.mts index 1791c4773f0..29f8ad6cd4f 100644 --- a/tests/PolyglotAppHosts/Aspire.Hosting/TypeScript/apphost.mts +++ b/tests/PolyglotAppHosts/Aspire.Hosting/TypeScript/apphost.mts @@ -5,16 +5,18 @@ import { WellKnownPipelineTags, createBuilder, CertificateTrustScope, + CommandResultFormat, EndpointProperty, HealthStatus, IconVariant, InputType, + MessageIntent, OtlpProtocol, ProbeType, ResourceCommandState, refExpr, } from './.aspire/modules/aspire.mjs'; -import type { DockerfileBuilderCallbackContext, DockerfileFactoryContext } from './.aspire/modules/aspire.mjs'; +import type { DockerfileBuilderCallbackContext, DockerfileFactoryContext, InputLoadOptions, InteractionInput, LoadInputContext } from './.aspire/modules/aspire.mjs'; import { fileURLToPath } from 'node:url'; const builder = await createBuilder(); @@ -442,9 +444,6 @@ const _configChildren = await builderConfiguration.getChildren(); const _configExists: boolean = await builderConfiguration.exists("MyConfig:Key"); const builderExecutionContext = builder.executionContext(); -const executionContextServiceProvider = await builderExecutionContext.serviceProvider(); -const _distributedApplicationModelFromExecutionContext = await executionContextServiceProvider.getDistributedApplicationModel(); -const resourceCommandService = await executionContextServiceProvider.getResourceCommandService(); await builder.addEventingSubscriber(async (registrationContext) => { const _subscriberIsRunMode: boolean = await registrationContext.executionContext().isRunMode(); @@ -719,8 +718,8 @@ await container.withCommand("noop", "Noop", async () => { }, }, }); -await container.withCommand("echo", "Echo", async (ctx) => { - const commandInputs = await ctx.arguments(); +await container.withCommand("echo", "Echo", async (commandContext) => { + const commandInputs = await commandContext.arguments(); const commandArguments = await commandInputs.toArray(); return { success: commandArguments[0]?.value === "hello" }; @@ -735,14 +734,107 @@ await container.withCommand("echo", "Echo", async (ctx) => { ] } }); -await container.withCommand("restart", "Restart", async (ctx) => { - const cancellationToken = await ctx.cancellationToken(); +await container.withCommand("restart", "Restart", async (commandContext) => { + const cancellationToken = await commandContext.cancellationToken(); + // Command callbacks run after build(), when the execution context service provider is populated; accessing it before build() throws. + const resourceCommandService = await commandContext.serviceProvider().getResourceCommandService(); return await resourceCommandService.executeCommandAsync(container, "echo", { arguments: { message: "hello" }, cancellationToken }); }); +await container.withCommand("interaction-validation", "Interaction Validation", async (commandContext) => { + // Command callbacks run after build(), when the execution context service provider is populated; accessing it before build() throws. + const interactionService = await commandContext.serviceProvider().getInteractionService(); + const interactionServiceAvailable = await interactionService.isAvailable(); + const textInput = { + name: "validation", + inputType: InputType.Text, + value: "default", + disabled: false, + }; + const choiceInput = { + name: "choice", + inputType: InputType.Choice, + placeholder: "Placeholder!", + required: true, + options: [ + { key: "option1", value: "Option 1" }, + { key: "option2", value: "Option 2" }, + { key: "option3", value: "Option 3" }, + ], + }; + const dynamicLoading: InputLoadOptions = { + alwaysLoadOnStart: true, + loadCallback: async (loadContext: LoadInputContext) => { + await new Promise(resolve => setTimeout(resolve, 1000)); + await loadContext.setOptions({ + dynamic1: "Dynamic Option 1", + dynamic2: "Dynamic Option 2", + }); + }, + }; + const dynamicChoiceInput: InteractionInput = { + name: "dynamic-choice", + inputType: InputType.Choice, + placeholder: "Choose a dynamically loaded value", + required: true, + dynamicLoading, + }; + + await interactionService.promptConfirmationAsync("Confirm", "Continue?", { + options: { intent: MessageIntent.Confirmation, primaryButtonText: "Continue" }, + }); + await interactionService.promptMessageBoxAsync("Message", "Message body", { + options: { intent: MessageIntent.Information, enableMessageMarkdown: true }, + }); + await interactionService.promptInputAsync("Input", "Input body", "Name", "Placeholder", { + options: { primaryButtonText: "Submit" }, + }); + await interactionService.promptInputWithInputAsync("Choice inputs", "Range of choice inputs", choiceInput, { + options: { + primaryButtonText: "Submit", + secondaryButtonText: "Skip", + showSecondaryButton: true, + enableMessageMarkdown: true, + showDismiss: true, + }, + }); + await interactionService.promptInputsAsync("Inputs", "Inputs body", [textInput, choiceInput], { + options: { showSecondaryButton: true, secondaryButtonText: "Skip" }, + }); + const dynamicChoiceResult = await interactionService.promptInputWithInputAsync( + "Dynamic choice input", + "Options are loaded after the prompt opens.", + dynamicChoiceInput, + { + options: { + primaryButtonText: "Submit", + validationCallback: async (validationContext) => { + const inputs = await validationContext.inputs(); + const dynamicChoice = await inputs.required("dynamic-choice"); + if (dynamicChoice.value !== "dynamic1" && dynamicChoice.value !== "dynamic2") { + await validationContext.addValidationError("dynamic-choice", "Select one of the dynamically loaded values."); + } + }, + }, + }); + const dynamicChoiceValue = dynamicChoiceResult.data?.value ?? "canceled"; + const commandLogger = await commandContext.logger(); + await commandLogger.logInformation(`Dynamic choice selected: ${dynamicChoiceValue}`); + await interactionService.promptNotificationAsync("Notification", "Notification body", { + options: { intent: MessageIntent.Information, linkText: "Docs", linkUrl: "https://aspire.dev" }, + }); + + return { + success: interactionServiceAvailable, + data: { + value: dynamicChoiceValue, + format: CommandResultFormat.Text, + }, + }; +}); // withProcessCommand await container.withProcessCommand("dotnet-version", "Show .NET version", {