Skip to content
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

Add viewer for long strings in GridValue #5018

Merged
merged 33 commits into from
Aug 12, 2024

Conversation

adamint
Copy link
Member

@adamint adamint commented Jul 22, 2024

Fixes #4412, and converts the copy button to a menu where the user can select whether to open a popup viewer or copy the cell text.

Menu appearance:
image

Dialog appearance:
image

Per spec, adds a plaintext, xml, and json formatting option. The initial formatting option is selected by trying to parse the string using an xml/json parser.

image

demo:
https://github.com/user-attachments/assets/5d0ef395-13f3-4e59-9a3f-9b6842469ca2

Normally, we would trigger popup opening just by adding an OnClick listener to the FluentMenuItems, but we are encountering a bug (probably in fluentui-blazor or fluent webcomponents) causing this to be swallowed sometimes when enclosed in PropertyGrid. @vnbaaij is aware, I am looking into this. A workaround is invoking a function from JS similar to how the copy button currently works.

Microsoft Reviewers: Open in CodeFlow

@mitchdenny
Copy link
Member

This is nice. This might be relevant for DevTunnels support where we want to be able to render a QR code associated with a particular endpoint so people can point their mobile device at it.

@tlmii
Copy link
Member

tlmii commented Jul 22, 2024

Just curious: Do we have any indication how common it is that people just want to copy? Are we trading quick one-click access to that most-common task for two-clicks for all tasks? I'm fine accepting either "the two clicks aren't that bad" or "copy isn't that much more common than what we expect visualize will be" or even "we don't know and we'll see if users complain after we do this", I just want to make sure that's an intentional usability decision.

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

This looks good.

I haven't tested it yet, but from my first impression of the screenshots, here are some ideas to make it better:

  1. Add a new, default option, called Auto. When the popup opens, we try to guess the value type. For example, we try to parse it as JSON, and if that succeeds then the value is automatically displayed as JSON. If that doesn't work (catch the exception) then we try to parse it as XML, and so on. If nothing works, then display as plaintext. The default option would say something like "Auto (JSON)", depending on what we end up displaying.
    An auto option makes the user do less work to get a better result.
  2. There should be a copy button on the popup. I could imagine someone options the popup to see the full value, and then decides they want to copy it to the clip board. We don't want to make them close the popup and then choose the copy value. The exception details popup has a copy button. Reuse that design?
    If there is a copy button here, an interesting question is what gets copied? The formatted value (has new lines and indenting), or the original value?
  3. I think line numbers would be useful here. I'm guessing that currently long lines wrap (like they do in the console page) so they would help indicate when content has a new line vs content that is just long. A lot of the CSS from the console page could be reused as all the same display choices apply here.
  4. I think there should be some differentiation in background color between the dialog and the scrollable content area. Lower priority.

@adamint
Copy link
Member Author

adamint commented Jul 23, 2024

Add a new, default option, called Auto. When the popup opens, we try to guess the value type. For example, we try to parse it as JSON, and if that succeeds then the value is automatically displayed as JSON. If that doesn't work (catch the exception) then we try to parse it as XML, and so on. If nothing works, then display as JSON. The default option would say something like "Auto (JSON)", depending on what we end up displaying. An auto option makes the user do less work to get a better result.

This is already done by default when you open the dialog, do you feel that a separate option is important to have rather than preselecting?

There should be a copy button on the popup. I could imagine someone options the popup to see the full value, and then decides they want to copy it to the clip board. We don't want to make them close the popup and then choose the copy value. The exception details popup has a copy button. Reuse that design?
If there is a copy button here, an interesting question is what gets copied? The formatted value (has new lines and indenting), or the original

I would assume the formatted value so as not to confuse the user, or both options?

@adamint
Copy link
Member Author

adamint commented Jul 23, 2024

Just curious: Do we have any indication how common it is that people just want to copy? Are we trading quick one-click access to that most-common task for two-clicks for all tasks? I'm fine accepting either "the two clicks aren't that bad" or "copy isn't that much more common than what we expect visualize will be" or even "we don't know and we'll see if users complain after we do this", I just want to make sure that's an intentional usability decision.

I don’t think we have any information on that. @kvenkatrajan

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

Just curious: Do we have any indication how common it is that people just want to copy? Are we trading quick one-click access to that most-common task for two-clicks for all tasks? I'm fine accepting either "the two clicks aren't that bad" or "copy isn't that much more common than what we expect visualize will be" or even "we don't know and we'll see if users complain after we do this", I just want to make sure that's an intentional usability decision.

I think we can mitigate this issue by only displaying the ... menu option when we think there will be multiple lines. For example, the Source column on the resource grid is always an image name with one line. We should just display the copy button as we did before. But the details view for a resource should display ... for its values because the value could be anything, e.g. JSON in an OTEL span's attribute value.

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

This is already done by default when you open the dialog, do you feel that a separate option is important to have rather than preselecting?

Nice, I didn't know that. I don't know which is best, I'll try it out and see what it's like. Preselecting like is already happening is probably fine. That's the important part.

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

I would assume the formatted value so as not to confuse the user, or both options?

Let's go with copying the formatted value. If someone wants to copy without formatting, then they can select plaintext and then copy. We can change if there is feedback.

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

Here is an idea: color formatting of JSON and XML keywords. We could do it server side, but that would be a fair amount of work. There are JS libraries that do this that we could use:

https://github.com/highlightjs/highlight.js

We know the content type so we can tell the JS library for highlight as JSON for JSON, etc.

Copy link
Member

@drewnoakes drewnoakes left a comment

Choose a reason for hiding this comment

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

LGTM though would be good to get a UI expert's input. I share Tim's view about the extra click for copy, so would be interested to know if we have additional options here.

doc.WriteTo(utf8JsonWriter);
utf8JsonWriter.Flush();

_formattedText = Encoding.Default.GetString(memoryStream.ToArray());
Copy link
Member

Choose a reason for hiding this comment

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

I don't think it's correct to use the default encoding here. The Utf8JsonWriter will write UTF8 bytes, which can only be decoded as UTF8.

Copy link
Member

Choose a reason for hiding this comment

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

+1. Add some unit tests with various width unicode characters.

Comment on lines 104 to 108
TryFormatXml();
}
else if (_selectedOption == JsonFormat)
{
TryFormatJson();
Copy link
Member

Choose a reason for hiding this comment

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

If these "try" operations fail, should we set _selectedOption back to the item representing no formatting?

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The 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.

src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs Outdated Show resolved Hide resolved
src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs Outdated Show resolved Hide resolved
@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

Large content doesn't overflow with a scrollbar:

image

And long content doesn't wrap:

image

I think the content here should act like the console logs text display:

  1. Vertical scroll bar when content exceeds available height.
  2. Text wrapping when content exceeds available width. Ensure that a single long word also wraps (console logs does this).
  3. Line number so you can see whether content wrapped because it's long or there was a new line.

Console logs does all of this already. CSS can either be copied, or ideally, reused.

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

Menu is cutoff when located in details view and the details view is narrow:

image

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

I wrote a log with a fairly large JSON attribute (64kb minified). There is an error when trying to view it:

text-visualizer-json-error

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

Add an example of formatted data to stress app: #5021

@JamesNK
Copy link
Member

JamesNK commented Jul 23, 2024

format-select

  1. The button is currently always highlighted. In other places in the dashboard (e.g. resource type filter) the button is only highlighted if a non-default value is chosen. I think that should be done here as well. e.g. Plaintext = unhighlighted, anything else = highlighted
  2. I think that clicking on an option should close the menu. There is a MenuButton control in FluentUI. I think it might be the right kind of control to use in this situation - https://www.fluentui-blazor.net/MenuButton
  3. Nothing happens when clicking on an invalid option, e.g. selecting XML for non-XML content. I would have expected an error message. Since we're checking the content when the visualizer launches, what about disabling invalid options in the select? For example, disable XML and JSON options if the content is a regular sentence. Then we don't need to worry about showing an error message.

…-view

# Conflicts:
#	src/Aspire.Dashboard/Components/Controls/GridValue.razor
@adamint
Copy link
Member Author

adamint commented Aug 7, 2024

Some UI things I noticed:

  • The dialog vertical size doesn’t shrink to match the content. It should take the whole screen to show one line.
  • Also, there should be a max width on the dialog, so it doesn’t become too wide.
image

Max width is now set to 600px @JamesNK.

@JamesNK
Copy link
Member

JamesNK commented Aug 8, 2024

I think 1000px is the right spot. Enough room for most values, without growing too large on wide screens.

@JamesNK
Copy link
Member

JamesNK commented Aug 8, 2024

I made style fixes. It's quicker for me to do it rather than communicate here. Also, there was a regression in the old console viewer that I fixed.

var effectiveTheme = await _jsModule.InvokeAsync<string>("getCurrentTheme");
ThemeManager.EffectiveTheme = effectiveTheme;

await InvokeAsync(StateHasChanged);
Copy link
Member

Choose a reason for hiding this comment

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

Be careful with calling StateHasChanged and minimize how often it is used. I think in this case, it could be limited to just the new text dialog. Listening to theme change and calling state change in the dialog would be better than doing it globally.

Copy link
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

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

The only major remaining issue is the interaction with splitters. It would be good to know a fix is coming in fluentui.

@adamint
Copy link
Member Author

adamint commented Aug 9, 2024

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamint
Copy link
Member Author

adamint commented Aug 10, 2024

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamint
Copy link
Member Author

adamint commented Aug 10, 2024

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamint adamint merged commit 55eb46f into dotnet:main Aug 12, 2024
11 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Sep 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dashboard: Traces & Log messages - viewer for long fields
8 participants