mirror of https://github.com/apache/druid.git
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:
parent
c62b7c19c3
commit
3624acbcf8
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}`}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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}',
|
||||
}));
|
||||
|
||||
|
|
|
@ -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' }) },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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' }) },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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(', '),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue