Add action row support#1484
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds support for exporting Discord action rows with button components to both HTML and JSON export formats. The implementation follows Discord's component structure and styling conventions, allowing exported chat logs to display interactive buttons (though they're rendered as static or disabled elements in the export).
Changes:
- New data models for button components and action rows with JSON parsing support
- HTML rendering with Discord-style button CSS including 6 button styles (Primary, Secondary, Success, Danger, Link, Premium)
- JSON export serialization for components structure
- Basic test coverage for component parsing and JSON array existence
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| DiscordChatExporter.Core/Discord/Data/Components/ButtonStyle.cs | Defines enum for 6 Discord button styles matching API specification |
| DiscordChatExporter.Core/Discord/Data/Components/ButtonComponent.cs | Button component model with parsing logic for style, label, emoji, URL, and other properties |
| DiscordChatExporter.Core/Discord/Data/Components/ActionRowComponent.cs | Action row container for button components with filtering for button type |
| DiscordChatExporter.Core/Discord/Data/Message.cs | Integrates components into Message model and IsEmpty logic |
| DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml | Adds CSS styles for button components and action rows |
| DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml | Renders buttons as anchor tags (for URL buttons) or disabled button elements |
| DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs | Serializes components to JSON format with button and action row structures |
| DiscordChatExporter.Cli.Tests/Specs/ComponentParsingSpecs.cs | Tests parsing of link button from message payload |
| DiscordChatExporter.Cli.Tests/Specs/JsonContentSpecs.cs | Verifies components array exists in JSON export |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
this adds support for exporting the action rows sometimes found in embeds. Only was able to test with single button action rows. I used copilot to draft up a proof of concept and tweaked to get it working 100% and fixed the colors to match discord styling Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
cbeec1a to
1a671b3
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@solareon thank you. Please see updated review comments above. |
This should improve buffer performance for the JsonWriter. I guess that the others in this file are probably redundant as well but out of scope for this PR.
This respects the disabled state of buttons and fixes a few styling and performance tweaks to the loop.
| bool IsDisabled | ||
| ) | ||
| { | ||
| public bool IsUrlButton => !string.IsNullOrWhiteSpace(Url); |
There was a problem hiding this comment.
| public bool IsUrlButton => !string.IsNullOrWhiteSpace(Url); | |
| public bool IsLink => !string.IsNullOrWhiteSpace(Url); |
| if (!Enum.IsDefined(typeof(MessageComponentType), type)) | ||
| return null; |
There was a problem hiding this comment.
Are you sure this check is necessary? If that value is not defined in the enum, your current logic would flow through to ParseDefault anyway. Is ParseDefault not meant to act as a fallback?
| json.GetPropertyOrNull("style") | ||
| ?.GetInt32OrNull() | ||
| ?.Pipe(s => | ||
| Enum.IsDefined(typeof(ButtonStyle), s) ? (ButtonStyle)s : (ButtonStyle?)null |
There was a problem hiding this comment.
I think we can just do Enum.ParseOrNull<ButtonStyle>(s) here (you may need to merge latest prime to get access to this method via PowerKit.Extensions). We will handle unknown styles during rendering (which your code already does by falling back to secondary style).
| namespace DiscordChatExporter.Core.Discord.Data.Components; | ||
|
|
||
| // https://docs.discord.com/developers/components/reference#component-object | ||
| public partial record MessageComponent( |
There was a problem hiding this comment.
The design I was thinking about was more like this:
MessageComponent:abstract class, essentially a marker (basically a union in other languages). Has aParse(JsonElement)method that checks therawTypeand calls actual components' ownParse(JsonElement)methods.ButtonMessageComponent: inherits fromMessageComponent, has its ownParse(JsonElement), and the properties that are inherent to a button.ActionRowComponent: inherits fromMessageComponent, has its ownParse(JsonElement)(that recursively calls intoMessageComponent.Parseto parse children), and the properties that are inherent to an action row (i.e.Children).
There was a problem hiding this comment.
The rendering code would then pattern match via:
component switch
{
ButtonMessageComponent button => ...
ActionRowComponent actionRow => ...
}
this adds support for exporting the action rows sometimes found in embeds. Only was able to test with single button action rows. I used copilot to draft up a proof of concept and tweaked to get it working 100% and fixed the colors to match discord styling
No issues closed by this. This adds support for action rows in exports for html and json