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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/Aspire.Cli/Backchannel/AppHostAuxiliaryBackchannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ public async Task<GetResourcesResponse> GetResourcesV2Async(GetResourcesRequest?
{
// Fall back to v1
var snapshots = await GetResourceSnapshotsAsync(cancellationToken).ConfigureAwait(false);
var includeHidden = request?.IncludeHidden is true;

// Apply filter if specified
if (!string.IsNullOrEmpty(request?.Filter))
Expand All @@ -472,6 +473,11 @@ public async Task<GetResourcesResponse> GetResourcesV2Async(GetResourcesRequest?
snapshots = snapshots.Where(s => s.Name.Contains(filter, StringComparison.OrdinalIgnoreCase)).ToList();
}

if (!includeHidden)
{
snapshots = snapshots.Where(s => !s.IsHidden).ToList();
}

return new GetResourcesResponse
{
Resources = snapshots.ToArray()
Expand Down Expand Up @@ -503,12 +509,19 @@ public async IAsyncEnumerable<ResourceSnapshot> WatchResourcesV2Async(
{
// Fall back to v1
var filter = request?.Filter;
var includeHidden = request?.IncludeHidden is true;
await foreach (var snapshot in WatchResourceSnapshotsAsync(cancellationToken).ConfigureAwait(false))
{
if (!string.IsNullOrEmpty(filter) && !snapshot.Name.Contains(filter, StringComparison.OrdinalIgnoreCase))
{
continue;
}

if (!includeHidden && snapshot.IsHidden)
{
continue;
}

yield return snapshot;
}
yield break;
Expand Down
16 changes: 16 additions & 0 deletions src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,29 @@ internal interface IAppHostAuxiliaryBackchannel : IDisposable
/// <returns>A list of resource snapshots representing current state.</returns>
Task<List<ResourceSnapshot>> GetResourceSnapshotsAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Gets resources using the v2 API.
/// </summary>
/// <param name="request">The request with optional filtering and hidden-resource inclusion.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The resources response.</returns>
Task<GetResourcesResponse> GetResourcesV2Async(GetResourcesRequest? request = null, CancellationToken cancellationToken = default);

/// <summary>
/// Watches for resource snapshot changes and streams them from the AppHost.
/// </summary>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>An async enumerable of resource snapshots as they change.</returns>
IAsyncEnumerable<ResourceSnapshot> WatchResourceSnapshotsAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Watches resources using the v2 API.
/// </summary>
/// <param name="request">The request with optional filtering and hidden-resource inclusion.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>An async enumerable of resource snapshots.</returns>
IAsyncEnumerable<ResourceSnapshot> WatchResourcesV2Async(WatchResourcesRequest? request = null, CancellationToken cancellationToken = default);

/// <summary>
/// Gets resource log lines from the AppHost.
/// </summary>
Expand Down
22 changes: 17 additions & 5 deletions src/Aspire.Cli/Commands/DescribeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ internal sealed class DescribeCommand : BaseCommand
{
Description = DescribeCommandStrings.JsonOptionDescription
};
private static readonly Option<bool> s_includeHiddenOption = new("--include-hidden")
{
Description = DescribeCommandStrings.IncludeHiddenOptionDescription
};

public DescribeCommand(
IInteractionService interactionService,
Expand All @@ -109,6 +113,7 @@ public DescribeCommand(
Options.Add(s_appHostOption);
Options.Add(s_followOption);
Options.Add(s_formatOption);
Options.Add(s_includeHiddenOption);
}

protected override async Task<int> ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken)
Expand All @@ -119,6 +124,7 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
var passedAppHostProjectFile = parseResult.GetValue(s_appHostOption);
var follow = parseResult.GetValue(s_followOption);
var format = parseResult.GetValue(s_formatOption);
var includeHidden = parseResult.GetValue(s_includeHiddenOption);

var result = await _connectionResolver.ResolveConnectionAsync(
passedAppHostProjectFile,
Expand All @@ -139,20 +145,23 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
// Get dashboard URL and resource snapshots in parallel before
// dispatching to the snapshot or watch path.
var dashboardUrlsTask = connection.GetDashboardUrlsAsync(cancellationToken);
var snapshotsTask = connection.GetResourceSnapshotsAsync(cancellationToken);
var snapshotsTask = connection.GetResourcesV2Async(new GetResourcesRequest
{
IncludeHidden = includeHidden
}, cancellationToken);

await Task.WhenAll(dashboardUrlsTask, snapshotsTask).ConfigureAwait(false);

var dashboardBaseUrl = TelemetryCommandHelpers.ExtractDashboardBaseUrl((await dashboardUrlsTask.ConfigureAwait(false))?.BaseUrlWithLoginToken);
var snapshots = await snapshotsTask.ConfigureAwait(false);
var snapshots = (await snapshotsTask.ConfigureAwait(false)).Resources;

// Pre-resolve colors for all resource names so that assignment is
// deterministic regardless of which resources are displayed.
_resourceColorMap.ResolveAll(snapshots.Select(s => ResourceSnapshotMapper.GetResourceName(s, snapshots)));

if (follow)
{
return await ExecuteWatchAsync(connection, snapshots, dashboardBaseUrl, resourceName, format, cancellationToken);
return await ExecuteWatchAsync(connection, snapshots, dashboardBaseUrl, resourceName, format, includeHidden, cancellationToken);
}
else
{
Expand Down Expand Up @@ -192,7 +201,7 @@ private int ExecuteSnapshot(IReadOnlyList<ResourceSnapshot> snapshots, string? d
return ExitCodeConstants.Success;
}

private async Task<int> ExecuteWatchAsync(IAppHostAuxiliaryBackchannel connection, IReadOnlyList<ResourceSnapshot> initialSnapshots, string? dashboardBaseUrl, string? resourceName, OutputFormat format, CancellationToken cancellationToken)
private async Task<int> ExecuteWatchAsync(IAppHostAuxiliaryBackchannel connection, IReadOnlyList<ResourceSnapshot> initialSnapshots, string? dashboardBaseUrl, string? resourceName, OutputFormat format, bool includeHidden, CancellationToken cancellationToken)
{
// Maintain a dictionary of the current state per resource for relationship resolution
// and display name deduplication. Keyed by snapshot.Name so each resource has exactly
Expand All @@ -208,7 +217,10 @@ private async Task<int> ExecuteWatchAsync(IAppHostAuxiliaryBackchannel connectio
var lastDisplayedContent = new Dictionary<string, object>(StringComparers.ResourceName);

// Stream resource snapshots
await foreach (var snapshot in connection.WatchResourceSnapshotsAsync(cancellationToken).ConfigureAwait(false))
await foreach (var snapshot in connection.WatchResourcesV2Async(new WatchResourcesRequest
{
IncludeHidden = includeHidden
}, cancellationToken).ConfigureAwait(false))
{
// Update the dictionary with the latest state for this resource
allResources[snapshot.Name] = snapshot;
Expand Down
6 changes: 6 additions & 0 deletions src/Aspire.Cli/Resources/DescribeCommandStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Aspire.Cli/Resources/DescribeCommandStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@
<data name="JsonOptionDescription" xml:space="preserve">
<value>Output format (Table or Json)</value>
</data>
<data name="IncludeHiddenOptionDescription" xml:space="preserve">
<value>Include hidden resources in the output</value>
</data>
<data name="NoAppHostFound" xml:space="preserve">
<value>No AppHost project found.</value>
</data>
Expand Down
5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DescribeCommandStrings.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading