fix web-console show json bug (#10710)

* fix web-console show json bug

* replace all JSON.stringify

Co-authored-by: yuanyi <yuanyi@freewheel.tv>
This commit is contained in:
Yi Yuan 2021-01-09 06:55:55 +08:00 committed by GitHub
parent c62b7c19c3
commit 3624acbcf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 65 additions and 32 deletions

View File

@ -17,6 +17,7 @@
*/
import { shallow } from 'enzyme';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { JsonCollapse } from './json-collapse';
@ -24,7 +25,7 @@ import { JsonCollapse } from './json-collapse';
describe('JsonCollapse', () => {
it('matches snapshot', () => {
const jsonCollapse = shallow(
<JsonCollapse buttonText={'test'} stringValue={JSON.stringify({ name: 'test' })} />,
<JsonCollapse buttonText={'test'} stringValue={JSONBig.stringify({ name: 'test' })} />,
);
expect(jsonCollapse).toMatchSnapshot();
});

View File

@ -17,6 +17,7 @@
*/
import { Button, Collapse, TextArea } from '@blueprintjs/core';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';
import './json-collapse.scss';
@ -30,7 +31,7 @@ export const JsonCollapse = React.memo(function JsonCollapse(props: JsonCollapse
const { stringValue, buttonText } = props;
const [isOpen, setIsOpen] = useState(false);
const prettyValue = JSON.stringify(JSON.parse(stringValue), undefined, 2);
const prettyValue = JSONBig.stringify(JSON.parse(stringValue), undefined, 2);
return (
<div className="json-collapse">
<div className="collapse-buttons">

View File

@ -19,6 +19,7 @@
import { Editor } from 'brace';
import classNames from 'classnames';
import Hjson from 'hjson';
import * as JSONBig from 'json-bigint-native';
import React, { useEffect, useRef, useState } from 'react';
import AceEditor from 'react-ace';
@ -44,7 +45,7 @@ export function extractRowColumnFromHjsonError(
function stringifyJson(item: any): string {
if (item != null) {
const str = JSON.stringify(item, null, 2);
const str = JSONBig.stringify(item, undefined, 2);
if (str === '{}') return '{\n\n}'; // Very special case for an empty object to make it more beautiful
return str;
} else {
@ -54,7 +55,7 @@ function stringifyJson(item: any): string {
// Not the best way to check for deep equality but good enough for what we need
function deepEqual(a: any, b: any): boolean {
return JSON.stringify(a) === JSON.stringify(b);
return JSONBig.stringify(a) === JSONBig.stringify(b);
}
interface InternalValue {

View File

@ -17,6 +17,7 @@
*/
import { Tab, Tabs } from '@blueprintjs/core';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { useQueryManager } from '../../hooks';
@ -59,7 +60,7 @@ export const ShowHistory = React.memo(function ShowHistory(props: ShowHistoryPro
<ShowValue
jsonValue={
pastSupervisor.spec
? JSON.stringify(pastSupervisor.spec, undefined, 2)
? JSONBig.stringify(pastSupervisor.spec, undefined, 2)
: historyState.getErrorMessage()
}
downloadFilename={`version-${pastSupervisor.version}-${downloadFilename}`}

View File

@ -18,6 +18,7 @@
import { Button, ButtonGroup, Intent, TextArea } from '@blueprintjs/core';
import copy from 'copy-to-clipboard';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { useQueryManager } from '../../hooks';
@ -41,7 +42,7 @@ export const ShowJson = React.memo(function ShowJson(props: ShowJsonProps) {
const resp = await Api.instance.get(endpoint);
let data = resp.data;
if (transform) data = transform(data);
return typeof data === 'string' ? data : JSON.stringify(data, undefined, 2);
return typeof data === 'string' ? data : JSONBig.stringify(data, undefined, 2);
},
initQuery: null,
});

View File

@ -18,6 +18,7 @@
import { AnchorButton, Button, ButtonGroup, Intent, Switch } from '@blueprintjs/core';
import copy from 'copy-to-clipboard';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { Loader } from '../../components';
@ -68,7 +69,7 @@ export class ShowLog extends React.PureComponent<ShowLogProps, ShowLogState> {
);
const data = resp.data;
let logValue = typeof data === 'string' ? data : JSON.stringify(data, undefined, 2);
let logValue = typeof data === 'string' ? data : JSONBig.stringify(data, undefined, 2);
if (tailOffset) logValue = removeFirstPartialLine(logValue);
return logValue;
},

View File

@ -17,6 +17,7 @@
*/
import { IconNames } from '@blueprintjs/icons';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';
import { ShowValueDialog } from '../../dialogs/show-value-dialog/show-value-dialog';
@ -98,7 +99,7 @@ export const TableCell = React.memo(function TableCell(props: TableCellProps) {
} else if (Array.isArray(value)) {
return renderTruncated(`[${value.join(', ')}]`);
} else if (typeof value === 'object') {
return renderTruncated(JSON.stringify(value));
return renderTruncated(JSONBig.stringify(value));
} else {
return renderTruncated(String(value));
}

View File

@ -18,6 +18,7 @@
import { Button, Callout, Classes, Dialog, Intent, TextArea } from '@blueprintjs/core';
import Hjson from 'hjson';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';
import { QueryContext } from '../../utils/query-context';
@ -43,7 +44,7 @@ export const EditContextDialog = React.memo(function EditContextDialog(
const [state, setState] = useState<EditContextDialogState>(() => ({
queryContext: props.queryContext,
queryContextString: Object.keys(props.queryContext).length
? JSON.stringify(props.queryContext, undefined, 2)
? JSONBig.stringify(props.queryContext, undefined, 2)
: '{\n\n}',
}));

View File

@ -17,6 +17,7 @@
*/
import { render } from '@testing-library/react';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { HistoryDialog } from './history-dialog';
@ -26,8 +27,8 @@ describe('history dialog', () => {
const historyDialog = (
<HistoryDialog
historyRecords={[
{ auditTime: 'test', auditInfo: 'test', payload: JSON.stringify({ name: 'test' }) },
{ auditTime: 'test', auditInfo: 'test', payload: JSON.stringify({ name: 'test' }) },
{ auditTime: 'test', auditInfo: 'test', payload: JSONBig.stringify({ name: 'test' }) },
{ auditTime: 'test', auditInfo: 'test', payload: JSONBig.stringify({ name: 'test' }) },
]}
/>
);

View File

@ -25,6 +25,7 @@ import {
Intent,
TextArea,
} from '@blueprintjs/core';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { BasicQueryExplanation, SemiJoinQueryExplanation } from '../../utils';
@ -59,7 +60,11 @@ export const QueryPlanDialog = React.memo(function QueryPlanDialog(props: QueryP
);
}
queryString = JSON.stringify((explainResult as BasicQueryExplanation).query[0], undefined, 2);
queryString = JSONBig.stringify(
(explainResult as BasicQueryExplanation).query[0],
undefined,
2,
);
content = (
<div className="one-query">
<FormGroup label="Query">
@ -98,7 +103,7 @@ export const QueryPlanDialog = React.memo(function QueryPlanDialog(props: QueryP
<FormGroup label="Main query">
<TextArea
readOnly
value={JSON.stringify(
value={JSONBig.stringify(
(explainResult as SemiJoinQueryExplanation).mainQuery.query,
undefined,
2,
@ -109,7 +114,7 @@ export const QueryPlanDialog = React.memo(function QueryPlanDialog(props: QueryP
<FormGroup label="Sub query">
<TextArea
readOnly
value={JSON.stringify(
value={JSONBig.stringify(
(explainResult as SemiJoinQueryExplanation).subQueryRight.query,
undefined,
2,

View File

@ -17,6 +17,7 @@
*/
import { render } from '@testing-library/react';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import { SnitchDialog } from './snitch-dialog';
@ -35,8 +36,8 @@ describe('snitch dialog', () => {
onSave={() => {}}
onClose={() => {}}
historyRecords={[
{ auditTime: 'test', auditInfo: 'test', payload: JSON.stringify({ name: 'test' }) },
{ auditTime: 'test', auditInfo: 'test', payload: JSON.stringify({ name: 'test' }) },
{ auditTime: 'test', auditInfo: 'test', payload: JSONBig.stringify({ name: 'test' }) },
{ auditTime: 'test', auditInfo: 'test', payload: JSONBig.stringify({ name: 'test' }) },
]}
/>
);

View File

@ -17,6 +17,7 @@
*/
import { Button, Classes, Dialog, Intent } from '@blueprintjs/core';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';
import AceEditor from 'react-ace';
@ -33,7 +34,9 @@ export interface SpecDialogProps {
export const SpecDialog = React.memo(function SpecDialog(props: SpecDialogProps) {
const { onClose, onSubmit, title, initSpec } = props;
const [spec, setSpec] = useState(() => (initSpec ? JSON.stringify(initSpec, null, 2) : ''));
const [spec, setSpec] = useState(() =>
initSpec ? JSONBig.stringify(initSpec, undefined, 2) : '',
);
function postSpec(): void {
if (!validJson(spec)) return;

View File

@ -16,6 +16,8 @@
* limitations under the License.
*/
import * as JSONBig from 'json-bigint-native';
import { localStorageGet, LocalStorageKeys, localStorageSet } from '../utils';
export class LocalStorageBackedArray<T> {
@ -43,7 +45,7 @@ export class LocalStorageBackedArray<T> {
}
private setDataInStorage(): void {
localStorageSet(this.key, JSON.stringify(this.storedArray));
localStorageSet(this.key, JSONBig.stringify(this.storedArray));
}
toggle(value: T): LocalStorageBackedArray<T> {

View File

@ -16,6 +16,8 @@
* limitations under the License.
*/
import * as JSONBig from 'json-bigint-native';
export const LocalStorageKeys = {
CAPABILITIES_OVERRIDE: 'capabilities-override' as 'capabilities-override',
INGESTION_SPEC: 'ingestion-spec' as 'ingestion-spec',
@ -48,7 +50,7 @@ export function localStorageSet(key: LocalStorageKeys, value: string): void {
}
export function localStorageSetJson(key: LocalStorageKeys, value: any): void {
localStorageSet(key, JSON.stringify(value));
localStorageSet(key, JSONBig.stringify(value));
}
export function localStorageGet(key: LocalStorageKeys): string | undefined {

View File

@ -16,6 +16,8 @@
* limitations under the License.
*/
import * as JSONBig from 'json-bigint-native';
import { deepDelete, deepExtend, deepGet, deepSet, makePath, parsePath } from './object-change';
describe('object-change', () => {
@ -136,7 +138,7 @@ describe('object-change', () => {
});
it('works with arrays', () => {
expect(JSON.parse(JSON.stringify(deepDelete(thing, 'hello.wow.0')))).toEqual({
expect(JSON.parse(JSONBig.stringify(deepDelete(thing, 'hello.wow.0')))).toEqual({
hello: {
moon: 1,
wow: [

View File

@ -16,6 +16,8 @@
* limitations under the License.
*/
import * as JSONBig from 'json-bigint-native';
export interface QueryRecord {
version: string;
queryString: string;
@ -39,7 +41,7 @@ export class QueryRecordUtil {
if (
queryHistory.length &&
queryHistory[0].queryString === queryString &&
JSON.stringify(queryHistory[0].queryContext) === JSON.stringify(queryContext)
JSONBig.stringify(queryHistory[0].queryContext) === JSONBig.stringify(queryContext)
) {
return queryHistory;
}

View File

@ -16,6 +16,8 @@
* limitations under the License.
*/
import * as JSONBig from 'json-bigint-native';
import {
DimensionsSpec,
getSpecType,
@ -127,7 +129,7 @@ export function applyCache(sampleSpec: SampleSpec, cacheRows: CacheRows) {
sampleSpec = deepSet(sampleSpec, 'spec.ioConfig.type', 'index');
sampleSpec = deepSet(sampleSpec, 'spec.ioConfig.inputSource', {
type: 'inline',
data: cacheRows.map(r => JSON.stringify(r)).join('\n'),
data: cacheRows.map(r => JSONBig.stringify(r)).join('\n'),
});
const flattenSpec = deepGet(sampleSpec, 'spec.ioConfig.inputFormat.flattenSpec');

View File

@ -40,6 +40,7 @@ import {
} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import classNames from 'classnames';
import * as JSONBig from 'json-bigint-native';
import memoize from 'memoize-one';
import React from 'react';
@ -208,11 +209,11 @@ function showRawLine(line: SampleEntry): string {
function showDruidLine(line: SampleEntry): string {
if (!line.parsed) return 'No parse';
return `Druid row: ${JSON.stringify(line.parsed)}`;
return `Druid row: ${JSONBig.stringify(line.parsed)}`;
}
function showBlankLine(line: SampleEntry): string {
return line.parsed ? `[Row: ${JSON.stringify(line.parsed)}]` : '[Binary data]';
return line.parsed ? `[Row: ${JSONBig.stringify(line.parsed)}]` : '[Binary data]';
}
function getTimestampSpec(headerAndRows: HeaderAndRows | null): TimestampSpec {
@ -496,7 +497,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
deltaState.cacheRows = undefined;
}
this.setState(deltaState as LoadDataViewState);
localStorageSet(LocalStorageKeys.INGESTION_SPEC, JSON.stringify(newSpec));
localStorageSet(LocalStorageKeys.INGESTION_SPEC, JSONBig.stringify(newSpec));
};
private updateSpecPreview = (newSpecPreview: IngestionSpec) => {
@ -505,7 +506,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
private applyPreviewSpec = () => {
this.setState(({ spec, specPreview }) => {
localStorageSet(LocalStorageKeys.INGESTION_SPEC, JSON.stringify(specPreview));
localStorageSet(LocalStorageKeys.INGESTION_SPEC, JSONBig.stringify(specPreview));
return { spec: spec === specPreview ? Object.assign({}, specPreview) : specPreview }; // If applying again, make a shallow copy to force a refresh
});
};

View File

@ -17,6 +17,7 @@
*/
import classNames from 'classnames';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import ReactTable from 'react-table';
@ -86,7 +87,7 @@ export const ParseDataTable = React.memo(function ParseDataTable(props: ParseDat
})}
SubComponent={rowInfo => {
const { input, error } = rowInfo.original;
const inputStr = JSON.stringify(input, null, 2);
const inputStr = JSONBig.stringify(input, undefined, 2);
if (!error && input && canFlatten) {
return <pre className="parse-detail">{'Original row: ' + inputStr}</pre>;

View File

@ -26,6 +26,7 @@ import {
SqlRef,
trimString,
} from 'druid-query-toolkit';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';
import ReactTable from 'react-table';
@ -47,7 +48,7 @@ function stringifyValue(value: unknown): string {
case 'object':
if (!value) return String(value);
if (typeof (value as any).toISOString === 'function') return (value as any).toISOString();
return JSON.stringify(value);
return JSONBig.stringify(value);
default:
return String(value);

View File

@ -20,6 +20,7 @@ import { Code, Intent, Switch, Tooltip } from '@blueprintjs/core';
import classNames from 'classnames';
import { QueryResult, QueryRunner, SqlQuery } from 'druid-query-toolkit';
import Hjson from 'hjson';
import * as JSONBig from 'json-bigint-native';
import memoizeOne from 'memoize-one';
import React, { RefObject } from 'react';
import SplitterLayout from 'react-splitter-layout';
@ -318,7 +319,7 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
return null;
}
return {
queryString: JSON.stringify(parsed, null, 2),
queryString: JSONBig.stringify(parsed, undefined, 2),
};
});
}
@ -349,7 +350,7 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
outputObject[newName.name] = r[k];
}
}
return JSON.stringify(outputObject);
return JSONBig.stringify(outputObject);
});
}

View File

@ -19,6 +19,7 @@
import { Button, ButtonGroup, Intent, Label, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { SqlExpression, SqlRef } from 'druid-query-toolkit';
import * as JSONBig from 'json-bigint-native';
import React from 'react';
import ReactTable, { Filter } from 'react-table';
@ -254,7 +255,7 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
queryParts.push(
'ORDER BY ' +
query.sorted
.map((sort: any) => `${JSON.stringify(sort.id)} ${sort.desc ? 'DESC' : 'ASC'}`)
.map((sort: any) => `${JSONBig.stringify(sort.id)} ${sort.desc ? 'DESC' : 'ASC'}`)
.join(', '),
);
}
@ -271,7 +272,7 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
queryParts.push(
'ORDER BY ' +
query.sorted
.map((sort: any) => `${JSON.stringify(sort.id)} ${sort.desc ? 'DESC' : 'ASC'}`)
.map((sort: any) => `${JSONBig.stringify(sort.id)} ${sort.desc ? 'DESC' : 'ASC'}`)
.join(', '),
);
}