mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
feat: Use JSON viewer for Network Body (#428)
This commit is contained in:
parent
0fa131f4b9
commit
3b29721254
3 changed files with 131 additions and 1 deletions
5
.changeset/quiet-eagles-applaud.md
Normal file
5
.changeset/quiet-eagles-applaud.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hyperdx/app': patch
|
||||
---
|
||||
|
||||
Render JSON network body in a JSON viewer
|
||||
107
packages/app/src/LogSidePanelElements.stories.tsx
Normal file
107
packages/app/src/LogSidePanelElements.stories.tsx
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import type { Meta } from '@storybook/react';
|
||||
|
||||
import { NetworkBody } from './LogSidePanelElements';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'LogSidePanelElements',
|
||||
component: NetworkBody,
|
||||
parameters: {},
|
||||
};
|
||||
|
||||
const MOCK_SQL_BODY = `SELECT
|
||||
toUnixTimestamp(toStartOfInterval(timestamp, INTERVAL '10 second')) as ts_bucket,
|
||||
if(multiSearchAny(severity_text, ['err', 'emerg', 'alert', 'crit', 'fatal']), 'error', 'info') as severity_group,
|
||||
count(*) as count
|
||||
FROM default.log_stream
|
||||
WHERE (1 = 1) AND ((_timestamp_sort_key >= 1717609920000000000 AND _timestamp_sort_key < 1717610820000000000) AND ((type = 'span')))
|
||||
GROUP BY ts_bucket, severity_group
|
||||
ORDER BY ts_bucket
|
||||
WITH FILL
|
||||
FROM toUnixTimestamp(toStartOfInterval(toDateTime(1717609920), INTERVAL '10 second'))
|
||||
TO toUnixTimestamp(toStartOfInterval(toDateTime(1717610820), INTERVAL '10 second'))
|
||||
STEP 10
|
||||
LIMIT 1000
|
||||
FORMAT JSON`;
|
||||
|
||||
const MOCK_JSON_BODY = `{
|
||||
"links": {
|
||||
"self": "http://example.com/articles",
|
||||
"next": "http://example.com/articles?page[offset]=2",
|
||||
"last": "http://example.com/articles?page[offset]=10"
|
||||
},
|
||||
"data": [{
|
||||
"type": "articles",
|
||||
"id": "1",
|
||||
"attributes": {
|
||||
"title": "JSON:API paints my bikeshed!"
|
||||
},
|
||||
"relationships": {
|
||||
"author": {
|
||||
"links": {
|
||||
"self": "http://example.com/articles/1/relationships/author",
|
||||
"related": "http://example.com/articles/1/author"
|
||||
},
|
||||
"data": { "type": "people", "id": "9" }
|
||||
},
|
||||
"comments": {
|
||||
"links": {
|
||||
"self": "http://example.com/articles/1/relationships/comments",
|
||||
"related": "http://example.com/articles/1/comments"
|
||||
},
|
||||
"data": [
|
||||
{ "type": "comments", "id": "5" },
|
||||
{ "type": "comments", "id": "12" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"self": "http://example.com/articles/1"
|
||||
}
|
||||
}],
|
||||
"included": [{
|
||||
"type": "people",
|
||||
"id": "9",
|
||||
"attributes": {
|
||||
"firstName": "Dan",
|
||||
"lastName": "Gebhardt",
|
||||
"twitter": "dgeb"
|
||||
},
|
||||
"links": {
|
||||
"self": "http://example.com/people/9"
|
||||
}
|
||||
}, {
|
||||
"type": "comments",
|
||||
"id": "5",
|
||||
"attributes": {
|
||||
"body": "First!"
|
||||
},
|
||||
"relationships": {
|
||||
"author": {
|
||||
"data": { "type": "people", "id": "2" }
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"self": "http://example.com/comments/5"
|
||||
}
|
||||
}, {
|
||||
"type": "comments",
|
||||
"id": "12",
|
||||
"attributes": {
|
||||
"body": "I like XML better"
|
||||
},
|
||||
"relationships": {
|
||||
"author": {
|
||||
"data": { "type": "people", "id": "9" }
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"self": "http://example.com/comments/12"
|
||||
}
|
||||
}]
|
||||
}`;
|
||||
|
||||
export const Sql = () => <NetworkBody body={MOCK_SQL_BODY} />;
|
||||
|
||||
export const Json = () => <NetworkBody body={MOCK_JSON_BODY} />;
|
||||
|
||||
export default meta;
|
||||
|
|
@ -4,6 +4,7 @@ import { CloseButton } from 'react-bootstrap';
|
|||
import { JSONTree } from 'react-json-tree';
|
||||
import { ColumnDef, Row } from '@tanstack/react-table';
|
||||
|
||||
import HyperJson from './components/HyperJson';
|
||||
import { TableCellButton } from './components/Table';
|
||||
import { UNDEFINED_WIDTH } from './tableUtils';
|
||||
import type { StacktraceBreadcrumb, StacktraceFrame } from './types';
|
||||
|
|
@ -388,6 +389,21 @@ export const NetworkBody = ({
|
|||
);
|
||||
}, []);
|
||||
|
||||
const parsedBody = React.useMemo(() => {
|
||||
if (typeof body !== 'string') return null;
|
||||
try {
|
||||
if (
|
||||
(body.startsWith('{') && body.endsWith('}')) ||
|
||||
(body.startsWith('[') && body.endsWith(']'))
|
||||
) {
|
||||
const parsed = JSON.parse(body);
|
||||
return parsed;
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}, [body]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{body != null && body != '' ? (
|
||||
|
|
@ -399,7 +415,9 @@ export const NetworkBody = ({
|
|||
whiteSpace: 'pre-wrap',
|
||||
}}
|
||||
>
|
||||
{typeof body === 'string' ? (
|
||||
{parsedBody ? (
|
||||
<HyperJson data={parsedBody} normallyExpanded />
|
||||
) : typeof body === 'string' ? (
|
||||
body
|
||||
) : (
|
||||
<JSONTree
|
||||
|
|
|
|||
Loading…
Reference in a new issue