diff --git a/superset-frontend/src/components/JsonModal/JsonModal.test.tsx b/superset-frontend/src/components/JsonModal/JsonModal.test.tsx index f0e2230f5a827c1ab13ab22c362b59077ab5b13a..44f01404a3b3055769159864fb958d94633a9942 100644 --- a/superset-frontend/src/components/JsonModal/JsonModal.test.tsx +++ b/superset-frontend/src/components/JsonModal/JsonModal.test.tsx @@ -42,6 +42,21 @@ test('renders JSON object in a tree view in a modal', () => { expect(getByTestId('mock-json-tree')).toBeInTheDocument(); }); +test('renders an object in a tree view in a modal', () => { + const jsonData = { a: 1 }; + const expected = JSON.stringify(jsonData); + const { getByText, getByTestId, queryByTestId } = render( + <JsonModal jsonObject={jsonData} jsonValue={jsonData} modalTitle="title" />, + { + useRedux: true, + }, + ); + expect(queryByTestId('mock-json-tree')).not.toBeInTheDocument(); + const link = getByText(expected); + fireEvent.click(link); + expect(getByTestId('mock-json-tree')).toBeInTheDocument(); +}); + test('renders bigInt value in a number format', () => { expect(convertBigIntStrToNumber('123')).toBe('123'); expect(convertBigIntStrToNumber('some string value')).toBe( diff --git a/superset-frontend/src/components/JsonModal/index.tsx b/superset-frontend/src/components/JsonModal/index.tsx index e599f483dcd2e99e2c5befaf24cebe8debdea9a7..79ff25ef5afc9be7aa7928fa3712bba6906886e6 100644 --- a/superset-frontend/src/components/JsonModal/index.tsx +++ b/superset-frontend/src/components/JsonModal/index.tsx @@ -36,7 +36,7 @@ * under the License. */ import JSONbig from 'json-bigint'; -import { FC } from 'react'; +import { FC, useMemo } from 'react'; import { JSONTree } from 'react-json-tree'; import { useJsonTreeTheme } from 'src/hooks/useJsonTreeTheme'; import Button from '../Button'; @@ -46,6 +46,10 @@ import ModalTrigger from '../ModalTrigger'; export function safeJsonObjectParse( data: unknown, ): null | unknown[] | Record<string, unknown> { + if (typeof data === 'object') { + return data as null | unknown[] | Record<string, unknown>; + } + // First perform a cheap proxy to avoid calling JSON.parse on data that is clearly not a // JSON object or array if ( @@ -78,7 +82,7 @@ function renderBigIntStrToNumber(value: string | number) { return <>{convertBigIntStrToNumber(value)}</>; } -type CellDataType = string | number | null; +type CellDataType = string | number | null | object; export interface Props { modalTitle: string; @@ -88,6 +92,11 @@ export interface Props { export const JsonModal: FC<Props> = ({ modalTitle, jsonObject, jsonValue }) => { const jsonTreeTheme = useJsonTreeTheme(); + const content = useMemo( + () => + typeof jsonValue === 'object' ? JSON.stringify(jsonValue) : jsonValue, + [jsonValue], + ); return ( <ModalTrigger @@ -100,11 +109,11 @@ export const JsonModal: FC<Props> = ({ modalTitle, jsonObject, jsonValue }) => { } modalFooter={ <Button> - <CopyToClipboard shouldShowText={false} text={jsonValue} /> + <CopyToClipboard shouldShowText={false} text={content} /> </Button> } modalTitle={modalTitle} - triggerNode={<>{jsonValue}</>} + triggerNode={<>{content}</>} /> ); };