Refactor import statements and update component types in Detail.tsx, CodeEditor.tsx, and JSONFunctions.ts

This commit is contained in:
Simon Larsen
2024-04-22 13:35:58 +01:00
parent a9cc7f41ba
commit 89f3508ce0
4 changed files with 155 additions and 9 deletions

View File

@@ -8,6 +8,64 @@ import SerializableObjectDictionary from './SerializableObjectDictionary';
import JSON5 from 'json5';
export default class JSONFunctions {
public static nestJson(obj: JSONObject): JSONObject {
// obj could be in this format:
/**
* {
"http.url.protocol": "http",
"http.url.hostname": "localhost",
"http.host": "localhost",
*/
// we want to convert it to this format:
/**
* {
*
* "http": {
* "url": {
* "protocol": "http",
* "hostname": "localhost"
* },
* "host": "localhost",
* "method": "POST",
* "scheme": "http",
* "client_ip": "
* ...
*
* },
*/
const result: JSONObject = {};
for (const key in obj) {
const keys: Array<string> = key.split('.');
let currentObj: JSONObject = result;
for (let i = 0; i < keys.length; i++) {
const k: string | undefined = keys[i];
if (!k) {
continue;
}
if (i === keys.length - 1) {
currentObj[k] = obj[key];
} else {
if (!currentObj[k]) {
currentObj[k] = {};
}
currentObj = currentObj[k] as JSONObject;
}
}
}
return result;
}
public static isEmptyObject(
obj: JSONObject | BaseModel | null | undefined
): boolean {
@@ -294,6 +352,10 @@ export default class JSONFunctions {
return newVal;
}
public static toFormattedString(val: JSONValue): string {
return JSON.stringify(val, null, 4);
}
public static anyObjectToJSONObject(val: any): JSONObject {
return JSON.parse(JSON.stringify(val));
}

View File

@@ -35,7 +35,13 @@ const CodeEditor: FunctionComponent<ComponentProps> = (
const [helpText, setHelpText] = useState<string>('');
useEffect(() => {
setValue(props.value || '');
let value: string | undefined = props.value;
if (value && typeof value !== 'string') {
value = JSON.stringify(value, null, 4);
}
setValue(value || '');
}, [props.value]);
useEffect(() => {
@@ -79,7 +85,13 @@ const CodeEditor: FunctionComponent<ComponentProps> = (
const [value, setValue] = useState<string>('');
useEffect(() => {
setValue(props.initialValue || '');
let initialValue: string | undefined = props.initialValue;
if (initialValue && typeof initialValue !== 'string') {
initialValue = JSON.stringify(initialValue, null, 4);
}
setValue(initialValue || '');
}, [props.initialValue]);
return (
@@ -110,7 +122,7 @@ const CodeEditor: FunctionComponent<ComponentProps> = (
props.onBlur && props.onBlur();
props.onChange && props.onChange(code);
}}
defaultValue={props.initialValue || placeholder || ''}
defaultValue={value || placeholder || ''}
className={className}
options={{
acceptSuggestionOnCommitCharacter: true,

View File

@@ -348,7 +348,9 @@ const Detail: DetailFunction = <T extends GenericObject>(
<div className={`mt-1 text-sm text-gray-900 ${alignClassName}`}>
{data && (
<div
className={`${field.contentClassName} w-full flex`}
className={`${field.contentClassName} w-full ${
field.opts?.isCopyable ? 'flex' : ''
}`}
>
<div>{data}</div>

View File

@@ -20,6 +20,10 @@ import FieldType from 'CommonUI/src/Components/Types/FieldType';
import TelemetryService from 'Model/Models/TelemetryService';
import TelemetryServiceElement from '../TelemetryService/TelemetryServiceElement';
import SpanUtil, { DivisibilityFactor } from '../../Utils/SpanUtil';
import SpanStatusElement from './SpanStatusElement';
import CodeEditor from 'CommonUI/src/Components/CodeEditor/CodeEditor';
import CodeType from 'Common/Types/Code/CodeType';
import JSONFunctions from 'Common/Types/JSONFunctions';
export interface ComponentProps {
id: string;
@@ -63,6 +67,7 @@ const SpanViewer: FunctionComponent<ComponentProps> = (
endTimeUnixNano: true,
attributes: true,
durationUnixNano: true,
name: true,
};
useEffect(() => {
@@ -143,22 +148,51 @@ const SpanViewer: FunctionComponent<ComponentProps> = (
const getAttributesContentElement: GetReactElementFunction =
(): ReactElement => {
return <></>;
if (!span) {
return <ErrorMessage error="Span not found" />;
}
return (
<Detail<Span>
item={span}
fields={[
{
key: 'attributes',
title: 'Span Attributes',
description: 'The attributes of the span.',
fieldType: FieldType.Element,
getElement: (span: Span) => {
return (
<CodeEditor
type={CodeType.JSON}
initialValue={JSONFunctions.toFormattedString(
JSONFunctions.nestJson(
span.attributes || {}
)
)}
readOnly={true}
/>
);
},
},
]}
/>
);
};
const getEventsContentElement: GetReactElementFunction =
(): ReactElement => {
return <></>;
return <div>Coming Soon</div>;
};
const getErrorsContentElement: GetReactElementFunction =
(): ReactElement => {
return <></>;
return <div>Coming Soon</div>;
};
const getBasicInfo: GetReactElementFunction = (): ReactElement => {
if (!span) {
return <></>;
return <ErrorMessage error="Span not found" />;
}
return (
@@ -174,6 +208,33 @@ const SpanViewer: FunctionComponent<ComponentProps> = (
isCopyable: true,
},
},
{
key: 'name',
title: 'Span Name',
description: 'The name of the span.',
fieldType: FieldType.Text,
},
{
key: 'statusCode',
title: 'Span Status',
description: 'The status of the span.',
fieldType: FieldType.Element,
getElement: (span: Span) => {
return (
<div>
<SpanStatusElement
span={span}
title={
'Status: ' +
SpanUtil.getSpanStatusCodeFriendlyName(
span.statusCode!
)
}
/>{' '}
</div>
);
},
},
{
key: 'traceId',
title: 'Trace ID',
@@ -273,7 +334,16 @@ const SpanViewer: FunctionComponent<ComponentProps> = (
key: 'kind',
title: 'Span Kind',
description: 'The kind of span.',
fieldType: FieldType.Text,
fieldType: FieldType.Element,
getElement: (span: Span) => {
return (
<div>
{SpanUtil.getSpanKindFriendlyName(
span.kind!
)}
</div>
);
},
},
]}
/>