Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 6, 2025

Adding Custom Icon Support for Resources

Implements support for custom icons in Aspire resources, allowing hosting integrations to specify SVG content, data URIs, or file-based icons for display in the dashboard.

Implementation Complete ✅

  • Extend ResourceIconAnnotation to support custom icon data (SVG content or data URIs)
  • Add new properties to track icon source type (FluentUI name vs custom data)
  • Update proto file to include custom icon data field
  • Modify ResourceSnapshot to include custom icon data
  • Update Dashboard to handle custom icon data with proper Icon base class
  • Update ResourceIconHelpers to use custom icons when available
  • Add extension methods for file path and data URI scenarios
  • Add tests for custom icon functionality
  • Update existing tests as needed
  • Address PR feedback

API Surface

Two methods for setting icons:

// 1. FluentUI icon name (existing WithIconName method)
builder.AddContainer("foo", "foo")
    .WithIconName("Database", IconVariant.Filled);

// 2. Custom icon data - SVG or data URI (new WithIconName overload)
// SVG example:
var svgContent = "<svg width='24' height='24'><circle cx='12' cy='12' r='10'/></svg>";
builder.AddContainer("foo", "foo")
    .WithIconName(svgContent, "MyIcon");

// PNG from embedded resource example:
var iconBytes = Resources.MyIcon;
var dataUri = $"data:image/png;base64,{Convert.ToBase64String(iconBytes)}";
builder.AddContainer("foo", "foo")
    .WithIconName(dataUri, "MyIcon");

// 3. File-based icon (WithResourceIcon for files only)
builder.AddContainer("foo", "foo")
    .WithResourceIcon("./myicon.svg");

Changes from Feedback

  1. ✅ Changed default iconName from "CustomIcon" to empty string in ResourceIconAnnotation
  2. ✅ Updated documentation to include SVG example
  3. ✅ Removed duplicate WithResourceIcon(iconName, iconVariant) - use existing WithIconName instead
  4. ✅ Renamed WithResourceIcon(iconData, iconName) to WithIconName and moved next to existing method
  5. ✅ Created CustomResourceIcon class extending Icon base class (FluentUI's CustomIcon caused conflict)
  6. ✅ Kept WithResourceIcon(iconPath) for file-based loading

Build Status

✅ Aspire.Hosting builds successfully
✅ Aspire.Dashboard builds successfully
✅ Aspire.Hosting.Tests builds successfully

Original prompt

This section details on the original issue you should resolve

<issue_title>Allow resources to specify custom icons to use when displayed in the dashboard</issue_title>
<issue_description>In 9.2 we added resource icons to the resources table and graph views. We should go further and enable resources to specify their own custom icons to be used when displayed in the dashboard. This should be done in such a way that hosting integrations can specify custom icons for their resources, so that, e.g., the Redis resource could show up with the Redis icon in the dashboard.

The icon itself would need to be sent from the app host resource server to the dashboard process so would need to be serializable. I imagine we'd want to support SVG which has the advantage of being vector and text-based. We could support bitmap-based formats like PNG, ICO, JPG, etc., by encoding them as data-uris.

I imagine an API kinda like the following for using a file on disk:

builder.AddContainer("foo", "foo")
    .WithResourceIcon("./myicon.svg");

And perhaps something like this for something embedded, e.g. in a hosting integration:

builder.AddContainer("foo", "foo")
    .WithResourceIcon(EncodeAsDataUri(Resources.MyIcon), ImageFormat.Png);
```</issue_description>

<agent_instructions>Do not break any existing code.</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@maddymontaquila</author><body>
@copilot can you take a look at this but start by extending it to a known list of Blazor fluent UI icons that an integration can set? 

Keep in mind that currently we are using this helper and we do _not_ want to break it. These should be the fallbacks and still the default.
https://github.com/dotnet/aspire/blob/main/src/Aspire.Dashboard/Model/ResourceIconHelpers.cs#L13

</body></comment_new>
<comment_new><author>@DamianEdwards</author><body>
Re-opening as the PR added support for specifying the name of a known icon, but not setting custom icons.</body></comment_new>
</comments>
Fixes #8684

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

{
ArgumentException.ThrowIfNullOrWhiteSpace(customIconData);
CustomIconData = customIconData;
IconName = iconName ?? "CustomIcon";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this an empty string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to empty string in commit 6ce6e93.

/// - Raw SVG content (e.g., "&lt;svg...&gt;...&lt;/svg&gt;")
/// - A data URI (e.g., "data:image/png;base64,...")
/// </remarks>
public string? CustomIconData { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure this supports svgs, and update to include an svg example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated documentation with SVG example in commit 6ce6e93.

/// </code>
/// </example>
/// </remarks>
public static IResourceBuilder<T> WithResourceIcon<T>(this IResourceBuilder<T> builder, string iconPath) where T : IResource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a function WithIconName already exists, don't duplicate

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must get rid of this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the duplicate method in commit 6ce6e93.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in commit 6ce6e93.

/// </code>
/// </example>
/// </remarks>
public static IResourceBuilder<T> WithResourceIcon<T>(this IResourceBuilder<T> builder, string iconData, string? iconName) where T : IResource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should also be named WithIconName and placed next to the existing method

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must rename this and move to the correct location

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to WithIconName and moved next to existing method in commit 6ce6e93.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to WithIconName and moved in commit 6ce6e93.

@dotnet-policy-service dotnet-policy-service bot added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 6, 2025
/// <summary>
/// Represents a custom icon using SVG content or data URI.
/// </summary>
internal sealed class CustomDataIcon : Icon
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, you should use the CustomIcon class that already exists

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must use the existing custom icon class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created CustomResourceIcon class extending Icon base class in commit 6ce6e93.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created CustomResourceIcon class extending Icon base class in commit 6ce6e93. Named it CustomResourceIcon to avoid conflict with FluentUI's existing CustomIcon class.

@adamint adamint requested a review from JamesNK October 6, 2025 18:54
@Copilot Copilot AI changed the title [WIP] Allow resources to specify custom icons to use when displayed in the dashboard Add support for custom icons in resources beyond FluentUI icon names Oct 6, 2025
@Copilot Copilot AI requested a review from adamint October 6, 2025 18:58
Copilot finished work on behalf of adamint October 6, 2025 18:58
/// <summary>
/// Represents a custom icon using SVG content or data URI.
/// </summary>
internal sealed class CustomDataIcon : Icon
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must use the existing custom icon class

/// </code>
/// </example>
/// </remarks>
public static IResourceBuilder<T> WithResourceIcon<T>(this IResourceBuilder<T> builder, string iconPath) where T : IResource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must get rid of this

/// </code>
/// </example>
/// </remarks>
public static IResourceBuilder<T> WithResourceIcon<T>(this IResourceBuilder<T> builder, string iconData, string? iconName) where T : IResource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must rename this and move to the correct location

@adamint
Copy link
Member

adamint commented Oct 6, 2025

@copilot you need to make new changes based on the comments

@dotnet-policy-service dotnet-policy-service bot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 6, 2025
@Copilot Copilot AI requested a review from adamint October 6, 2025 19:29
Copilot finished work on behalf of adamint October 6, 2025 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow resources to specify custom icons to use when displayed in the dashboard

2 participants