-
Notifications
You must be signed in to change notification settings - Fork 769
Add viewer for long strings in GridValue #5018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
9b9eb28
1aeb0de
10f7cd2
1714da7
eebf7a4
86c1a5c
ce36464
633250a
2b9ebab
fa0b2ea
7a6336e
3afba4c
8cbdad8
987c800
1c618f2
fd2dc69
e7ebf22
1b8d8be
813cb75
665b30b
681789f
78eac50
68edbfa
729889c
4b262ab
6cd0349
1593d0d
1892bc8
bb2d8d9
d52819f
18cdf6c
e29961f
bdedc1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| @using Aspire.Dashboard.Model | ||
| @using Aspire.Dashboard.Resources | ||
|
|
||
| @inject IStringLocalizer<Dialogs> Loc | ||
| @implements IDialogContentComponent<Aspire.Dashboard.Model.TextVisualizerDialogViewModel> | ||
|
|
||
| <FluentDialogHeader ShowDismiss="true"> | ||
| <FluentStack VerticalAlignment="VerticalAlignment.Center"> | ||
| <FluentIcon Value="@(new Icons.Regular.Size24.SlideSearch())" /> | ||
| <FluentLabel Typo="Typography.PaneHeader"> | ||
| @Content.Description | ||
| </FluentLabel> | ||
|
|
||
| <FluentButton id="@_openSelectFormatButtonId" slot="end" | ||
| Style="margin-left: auto" | ||
| Appearance="Appearance.Accent" | ||
| IconEnd="@(new Icons.Regular.Size24.Filter())" | ||
| @onclick="() => _isSelectFormatPopupOpen = !_isSelectFormatPopupOpen" | ||
| Title="@Loc[nameof(Dialogs.TextVisualizerSelectFormatType)]" | ||
| aria-label="@Loc[nameof(Dialogs.TextVisualizerSelectFormatType)]"/> | ||
|
|
||
| <FluentPopover AnchorId="@_openSelectFormatButtonId" | ||
| @bind-Open="@_isSelectFormatPopupOpen" | ||
| AutoFocus="true"> | ||
| <Body> | ||
| <FluentRadioGroup aria-labelledby="@_openSelectFormatButtonId" | ||
| @bind-Value="_selectedOption" | ||
| @bind-Value:after="@OnFormatOptionChanged" | ||
| Orientation="Orientation.Vertical"> | ||
| @foreach (var option in _options) | ||
| { | ||
| <FluentRadio Value="@option.Id">@option.Name</FluentRadio> | ||
| } | ||
| </FluentRadioGroup> | ||
| </Body> | ||
| </FluentPopover> | ||
| </FluentStack> | ||
| </FluentDialogHeader> | ||
|
|
||
| <FluentDialogBody> | ||
| <pre style="white-space: pre-wrap; overflow-wrap: break-word"> | ||
| @_formattedText | ||
| </pre> | ||
| </FluentDialogBody> | ||
|
|
||
| <FluentDialogFooter Visible="false" /> | ||
|
|
||
| @code { | ||
| [Parameter, EditorRequired] | ||
| public required TextVisualizerDialogViewModel Content { get; set; } | ||
adamint marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Text; | ||
| using System.Text.Json; | ||
| using System.Xml; | ||
| using System.Xml.Linq; | ||
| using Aspire.Dashboard.Model.Otlp; | ||
| using Microsoft.AspNetCore.Components; | ||
|
|
||
| namespace Aspire.Dashboard.Components.Dialogs; | ||
|
|
||
| public partial class TextVisualizerDialog : ComponentBase | ||
| { | ||
| private const string XmlFormat = "xml"; | ||
| private const string JsonFormat = "json"; | ||
| private const string PlaintextFormat = "text"; | ||
|
|
||
| private List<SelectViewModel<string>> _options = null!; | ||
| private string _selectedOption = null!; | ||
|
|
||
| private string _formattedText = string.Empty; | ||
|
|
||
| private readonly string _openSelectFormatButtonId = $"select-format-{Guid.NewGuid():N}"; | ||
| private bool _isSelectFormatPopupOpen; | ||
|
|
||
| protected override void OnInitialized() | ||
| { | ||
| _options = | ||
| [ | ||
| new SelectViewModel<string> { Id = PlaintextFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogPlaintextFormat)] }, | ||
adamint marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| new SelectViewModel<string> { Id = JsonFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogJsonFormat)] }, | ||
| new SelectViewModel<string> { Id = XmlFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogXmlFormat)] }, | ||
| ]; | ||
| } | ||
|
|
||
| protected override void OnParametersSet() | ||
| { | ||
| // We don't know what format the string is in, but we can guess | ||
| if (TryFormatXml()) | ||
| { | ||
| _selectedOption = XmlFormat; | ||
| return; | ||
| } | ||
|
|
||
| if (TryFormatJson()) | ||
| { | ||
| _selectedOption = JsonFormat; | ||
| return; | ||
| } | ||
|
|
||
| _selectedOption = PlaintextFormat; | ||
| _formattedText = Content.Text; | ||
| } | ||
|
|
||
| private bool TryFormatXml() | ||
| { | ||
| try | ||
| { | ||
| _formattedText = XElement.Parse(Content.Text).ToString(); | ||
adamint marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return true; | ||
| } | ||
| catch (XmlException) | ||
| { | ||
| // If the XML is invalid, just show the original text | ||
| _formattedText = Content.Text; | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| private bool TryFormatJson() | ||
| { | ||
| try | ||
| { | ||
| using var doc = JsonDocument.Parse( | ||
| Content.Text, | ||
| new JsonDocumentOptions | ||
| { | ||
| AllowTrailingCommas = true, | ||
| CommentHandling = JsonCommentHandling.Skip | ||
adamint marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| ); | ||
|
|
||
| var memoryStream = new MemoryStream(); | ||
| using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, new JsonWriterOptions { Indented = true }); | ||
| doc.WriteTo(utf8JsonWriter); | ||
| utf8JsonWriter.Flush(); | ||
|
|
||
| _formattedText = Encoding.Default.GetString(memoryStream.ToArray()); | ||
|
||
| return true; | ||
| } | ||
| catch (JsonException) | ||
| { | ||
| // If the JSON is invalid, just show the original text | ||
| _formattedText = Content.Text; | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| private void OnFormatOptionChanged() | ||
| { | ||
| if (_selectedOption == XmlFormat) | ||
| { | ||
| TryFormatXml(); | ||
| } | ||
| else if (_selectedOption == JsonFormat) | ||
| { | ||
| TryFormatJson(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If these "try" operations fail, should we set
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. The 'JSON' view for a non-JSON string is just the same as the unformatted view.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if you have invalid JSON or xml? Is it only going to format if its valid? I almost want the errors if the user explicitly selects json, but it's not valid json. |
||
| } | ||
| else | ||
| { | ||
| _formattedText = Content.Text; | ||
| } | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.