diff --git a/frontend/src/container/LogDetailedView/TableView.tsx b/frontend/src/container/LogDetailedView/TableView.tsx index 92b15d1b57..eea61f2a32 100644 --- a/frontend/src/container/LogDetailedView/TableView.tsx +++ b/frontend/src/container/LogDetailedView/TableView.tsx @@ -1,14 +1,18 @@ import { blue, orange } from '@ant-design/colors'; import { Input } from 'antd'; +import { ColumnsType } from 'antd/es/table'; +import Editor from 'components/Editor'; import AddToQueryHOC from 'components/Logs/AddToQueryHOC'; import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC'; import { ResizeTable } from 'components/ResizeTable'; import flatten from 'flat'; import { fieldSearchFilter } from 'lib/logs/fieldSearch'; +import { isEmpty } from 'lodash-es'; import React, { useMemo, useState } from 'react'; import { ILog } from 'types/api/logs/log'; import ActionItem from './ActionItem'; +import { recursiveParseJSON } from './utils'; // Fields which should be restricted from adding it to query const RESTRICTED_FIELDS = ['timestamp']; @@ -41,10 +45,10 @@ function TableView({ logData }: TableViewProps): JSX.Element | null { return null; } - const columns = [ + const columns: ColumnsType = [ { title: 'Action', - width: 100, + width: 15, render: (fieldData: Record): JSX.Element | null => { const fieldKey = fieldData.field.split('.').slice(-1); if (!RESTRICTED_FIELDS.includes(fieldKey[0])) { @@ -57,7 +61,8 @@ function TableView({ logData }: TableViewProps): JSX.Element | null { title: 'Field', dataIndex: 'field', key: 'field', - width: 100, + width: 30, + ellipsis: true, render: (field: string): JSX.Element => { const fieldKey = field.split('.').slice(-1); const renderedField = {field}; @@ -78,16 +83,36 @@ function TableView({ logData }: TableViewProps): JSX.Element | null { key: 'value', width: 80, ellipsis: false, - render: (field: never): JSX.Element => ( - - {field} - - ), + render: (field, record): JSX.Element => { + if (record.field === 'body') { + const parsedBody = recursiveParseJSON(field); + if (!isEmpty(parsedBody)) { + return ( + + ); + } + } + + return ( + + {field} + + ); + }, }, ]; return ( -
+ <> setFieldSearchInput(e.target.value)} /> -
+ ); } +interface DataType { + key: string; + field: string; + value: string; +} + export default TableView; diff --git a/frontend/src/container/LogDetailedView/util.test.ts b/frontend/src/container/LogDetailedView/util.test.ts new file mode 100644 index 0000000000..5d6459ea47 --- /dev/null +++ b/frontend/src/container/LogDetailedView/util.test.ts @@ -0,0 +1,47 @@ +import { recursiveParseJSON } from './utils'; + +describe('recursiveParseJSON', () => { + it('should return an empty object if the input is not valid JSON', () => { + const result = recursiveParseJSON('not valid JSON'); + expect(result).toEqual({}); + }); + + it('should return the parsed JSON object for valid JSON input', () => { + const jsonString = '{"name": "John", "age": 30}'; + const result = recursiveParseJSON(jsonString); + expect(result).toEqual({ name: 'John', age: 30 }); + }); + + it('should recursively parse nested JSON objects', () => { + const jsonString = + '{"name": "John", "age": 30, "address": {"street": "123 Main St", "city": "Anytown", "state": "CA"}}'; + const result = recursiveParseJSON(jsonString); + expect(result).toEqual({ + name: 'John', + age: 30, + address: { + street: '123 Main St', + city: 'Anytown', + state: 'CA', + }, + }); + }); + + it('should recursively parse nested JSON arrays', () => { + const jsonString = '[1, 2, [3, 4], {"foo": "bar"}]'; + const result = recursiveParseJSON(jsonString); + expect(result).toEqual([1, 2, [3, 4], { foo: 'bar' }]); + }); + + it('should recursively parse deeply nested JSON objects', () => { + const jsonString = '{"foo": {"bar": {"baz": {"qux": {"value": 42}}}}}'; + const result = recursiveParseJSON(jsonString); + expect(result).toEqual({ foo: { bar: { baz: { qux: { value: 42 } } } } }); + }); + + it('should handle JSON input that contains escaped characters', () => { + const jsonString = '{"name": "John\\", \\"Doe", "age": 30}'; + const result = recursiveParseJSON(jsonString); + expect(result).toEqual({ name: 'John", "Doe', age: 30 }); + }); +}); diff --git a/frontend/src/container/LogDetailedView/utils.ts b/frontend/src/container/LogDetailedView/utils.ts new file mode 100644 index 0000000000..00a89c96d1 --- /dev/null +++ b/frontend/src/container/LogDetailedView/utils.ts @@ -0,0 +1,11 @@ +export const recursiveParseJSON = (obj: string): Record => { + try { + const value = JSON.parse(obj); + if (typeof value === 'string') { + return recursiveParseJSON(value); + } + return value; + } catch (e) { + return {}; + } +};