mirror of https://github.com/apache/druid.git
Web console: update DQT to latest version and fix bigint crash (#14318)
* update dqt * don't crash on bigint values * better submit experiance * bump to an even version
This commit is contained in:
parent
88831b1dd0
commit
1873fca6c7
|
@ -5814,7 +5814,7 @@ license_category: binary
|
||||||
module: web-console
|
module: web-console
|
||||||
license_name: Apache License version 2.0
|
license_name: Apache License version 2.0
|
||||||
copyright: Imply Data
|
copyright: Imply Data
|
||||||
version: 0.18.3
|
version: 0.18.12
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"d3-axis": "^2.1.0",
|
"d3-axis": "^2.1.0",
|
||||||
"d3-scale": "^3.3.0",
|
"d3-scale": "^3.3.0",
|
||||||
"d3-selection": "^2.0.0",
|
"d3-selection": "^2.0.0",
|
||||||
"druid-query-toolkit": "^0.18.3",
|
"druid-query-toolkit": "^0.18.12",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
"follow-redirects": "^1.14.7",
|
"follow-redirects": "^1.14.7",
|
||||||
"fontsource-open-sans": "^3.0.9",
|
"fontsource-open-sans": "^3.0.9",
|
||||||
|
@ -8211,9 +8211,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/druid-query-toolkit": {
|
"node_modules/druid-query-toolkit": {
|
||||||
"version": "0.18.3",
|
"version": "0.18.12",
|
||||||
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.18.3.tgz",
|
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.18.12.tgz",
|
||||||
"integrity": "sha512-Za2U2NsFyun5HXeWnLCICnTFzZp4aC17aSOjgVbQgEWZNMPht51U4paE3SVhPDObkWDjDUYAqVv+mO+ZyMx9Og==",
|
"integrity": "sha512-wDcZUW8vhiJXARC44EFFwUeZW6lawXWv++bxHIUKaxq3M5byBuWPKjEDTCdPEHprxmR2sxaTpsPw4A6KiRmBog==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.1"
|
"tslib": "^2.3.1"
|
||||||
},
|
},
|
||||||
|
@ -32625,9 +32625,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"druid-query-toolkit": {
|
"druid-query-toolkit": {
|
||||||
"version": "0.18.3",
|
"version": "0.18.12",
|
||||||
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.18.3.tgz",
|
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.18.12.tgz",
|
||||||
"integrity": "sha512-Za2U2NsFyun5HXeWnLCICnTFzZp4aC17aSOjgVbQgEWZNMPht51U4paE3SVhPDObkWDjDUYAqVv+mO+ZyMx9Og==",
|
"integrity": "sha512-wDcZUW8vhiJXARC44EFFwUeZW6lawXWv++bxHIUKaxq3M5byBuWPKjEDTCdPEHprxmR2sxaTpsPw4A6KiRmBog==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.3.1"
|
"tslib": "^2.3.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
"d3-axis": "^2.1.0",
|
"d3-axis": "^2.1.0",
|
||||||
"d3-scale": "^3.3.0",
|
"d3-scale": "^3.3.0",
|
||||||
"d3-selection": "^2.0.0",
|
"d3-selection": "^2.0.0",
|
||||||
"druid-query-toolkit": "^0.18.3",
|
"druid-query-toolkit": "^0.18.12",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
"follow-redirects": "^1.14.7",
|
"follow-redirects": "^1.14.7",
|
||||||
"fontsource-open-sans": "^3.0.9",
|
"fontsource-open-sans": "^3.0.9",
|
||||||
|
|
|
@ -31,7 +31,7 @@ export const JsonCollapse = React.memo(function JsonCollapse(props: JsonCollapse
|
||||||
const { stringValue, buttonText } = props;
|
const { stringValue, buttonText } = props;
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const prettyValue = JSONBig.stringify(JSON.parse(stringValue), undefined, 2);
|
const prettyValue = JSONBig.stringify(JSONBig.parse(stringValue), undefined, 2);
|
||||||
return (
|
return (
|
||||||
<div className="json-collapse">
|
<div className="json-collapse">
|
||||||
<div className="collapse-buttons">
|
<div className="collapse-buttons">
|
||||||
|
|
|
@ -21,13 +21,14 @@ import * as JSONBig from 'json-bigint-native';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import AceEditor from 'react-ace';
|
import AceEditor from 'react-ace';
|
||||||
|
|
||||||
import { validJson } from '../../utils';
|
import { AppToaster } from '../../singletons';
|
||||||
|
import { offsetToRowColumn } from '../../utils';
|
||||||
|
|
||||||
import './spec-dialog.scss';
|
import './spec-dialog.scss';
|
||||||
|
|
||||||
export interface SpecDialogProps {
|
export interface SpecDialogProps {
|
||||||
onSubmit: (spec: JSON) => void | Promise<void>;
|
onSubmit(spec: JSON): void | Promise<void>;
|
||||||
onClose: () => void;
|
onClose(): void;
|
||||||
title: string;
|
title: string;
|
||||||
initSpec?: any;
|
initSpec?: any;
|
||||||
}
|
}
|
||||||
|
@ -38,9 +39,23 @@ export const SpecDialog = React.memo(function SpecDialog(props: SpecDialogProps)
|
||||||
initSpec ? JSONBig.stringify(initSpec, undefined, 2) : '',
|
initSpec ? JSONBig.stringify(initSpec, undefined, 2) : '',
|
||||||
);
|
);
|
||||||
|
|
||||||
function postSpec(): void {
|
function handleSubmit(): void {
|
||||||
if (!validJson(spec)) return;
|
let parsed: any;
|
||||||
void onSubmit(JSON.parse(spec));
|
try {
|
||||||
|
parsed = JSONBig.parse(spec);
|
||||||
|
} catch (e) {
|
||||||
|
const rowColumn = typeof e.at === 'number' ? offsetToRowColumn(spec, e.at) : undefined;
|
||||||
|
AppToaster.show({
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
message: `Could not parse JSON: ${e.message}${
|
||||||
|
rowColumn ? ` (at line ${rowColumn.row + 1}, column ${rowColumn.column + 1})` : ''
|
||||||
|
}`,
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSubmit(parsed);
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,12 +93,7 @@ export const SpecDialog = React.memo(function SpecDialog(props: SpecDialogProps)
|
||||||
<div className={Classes.DIALOG_FOOTER}>
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
<Button text="Close" onClick={onClose} />
|
<Button text="Close" onClick={onClose} />
|
||||||
<Button
|
<Button text="Submit" intent={Intent.PRIMARY} onClick={handleSubmit} disabled={!spec} />
|
||||||
text="Submit"
|
|
||||||
intent={Intent.PRIMARY}
|
|
||||||
onClick={postSpec}
|
|
||||||
disabled={!validJson(spec)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
moveElement,
|
moveElement,
|
||||||
moveToIndex,
|
moveToIndex,
|
||||||
objectHash,
|
objectHash,
|
||||||
|
offsetToRowColumn,
|
||||||
parseCsvLine,
|
parseCsvLine,
|
||||||
swapElements,
|
swapElements,
|
||||||
} from './general';
|
} from './general';
|
||||||
|
@ -171,4 +172,19 @@ describe('general', () => {
|
||||||
expect(objectHash({ hello: 'world1' })).toEqual('cc14ad13');
|
expect(objectHash({ hello: 'world1' })).toEqual('cc14ad13');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('offsetToRowColumn', () => {
|
||||||
|
it('works', () => {
|
||||||
|
expect(offsetToRowColumn('Hello\nThis is a test\nstring.', -6)).toBeUndefined();
|
||||||
|
expect(offsetToRowColumn('Hello\nThis is a test\nstring.', 666)).toBeUndefined();
|
||||||
|
expect(offsetToRowColumn('Hello\nThis is a test\nstring.', 3)).toEqual({
|
||||||
|
column: 3,
|
||||||
|
row: 0,
|
||||||
|
});
|
||||||
|
expect(offsetToRowColumn('Hello\nThis is a test\nstring.', 24)).toEqual({
|
||||||
|
column: 3,
|
||||||
|
row: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -465,3 +465,26 @@ export function tickIcon(checked: boolean): IconName {
|
||||||
export function generate8HexId(): string {
|
export function generate8HexId(): string {
|
||||||
return (Math.random() * 1e10).toString(16).replace('.', '').slice(0, 8);
|
return (Math.random() * 1e10).toString(16).replace('.', '').slice(0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function offsetToRowColumn(
|
||||||
|
str: string,
|
||||||
|
offset: number,
|
||||||
|
): { row: number; column: number } | undefined {
|
||||||
|
// Ensure offset is within the string length
|
||||||
|
if (offset < 0 || offset > str.length) return;
|
||||||
|
|
||||||
|
const lines = str.split('\n');
|
||||||
|
for (let row = 0; row < lines.length; row++) {
|
||||||
|
const line = lines[row];
|
||||||
|
if (offset < line.length) {
|
||||||
|
return {
|
||||||
|
row,
|
||||||
|
column: offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
offset -= line.length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ describe('object-change', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('works with arrays', () => {
|
it('works with arrays', () => {
|
||||||
expect(JSON.parse(JSONBig.stringify(deepDelete(thing, 'hello.wow.0')))).toEqual({
|
expect(JSONBig.parse(JSONBig.stringify(deepDelete(thing, 'hello.wow.0')))).toEqual({
|
||||||
hello: {
|
hello: {
|
||||||
moon: 1,
|
moon: 1,
|
||||||
wow: [
|
wow: [
|
||||||
|
|
|
@ -23,7 +23,7 @@ import ReactTable from 'react-table';
|
||||||
|
|
||||||
import { TableCell } from '../../../components';
|
import { TableCell } from '../../../components';
|
||||||
import type { DruidFilter } from '../../../druid-models';
|
import type { DruidFilter } from '../../../druid-models';
|
||||||
import { getFilterDimension } from '../../../druid-models';
|
import { getFilterDimension, TIME_COLUMN } from '../../../druid-models';
|
||||||
import {
|
import {
|
||||||
DEFAULT_TABLE_CLASS_NAME,
|
DEFAULT_TABLE_CLASS_NAME,
|
||||||
STANDARD_TABLE_PAGE_SIZE,
|
STANDARD_TABLE_PAGE_SIZE,
|
||||||
|
@ -67,7 +67,7 @@ export const FilterTable = React.memo(function FilterTable(props: FilterTablePro
|
||||||
showPagination={sampleResponse.data.length > STANDARD_TABLE_PAGE_SIZE}
|
showPagination={sampleResponse.data.length > STANDARD_TABLE_PAGE_SIZE}
|
||||||
columns={filterMap(getHeaderNamesFromSampleResponse(sampleResponse), (columnName, i) => {
|
columns={filterMap(getHeaderNamesFromSampleResponse(sampleResponse), (columnName, i) => {
|
||||||
if (!caseInsensitiveContains(columnName, columnFilter)) return;
|
if (!caseInsensitiveContains(columnName, columnFilter)) return;
|
||||||
const timestamp = columnName === '__time';
|
const isTimestamp = columnName === TIME_COLUMN;
|
||||||
const filterIndex = dimensionFilters.findIndex(f => getFilterDimension(f) === columnName);
|
const filterIndex = dimensionFilters.findIndex(f => getFilterDimension(f) === columnName);
|
||||||
const filter = dimensionFilters[filterIndex];
|
const filter = dimensionFilters[filterIndex];
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ export const FilterTable = React.memo(function FilterTable(props: FilterTablePro
|
||||||
onFilterSelect(filter, filterIndex);
|
onFilterSelect(filter, filterIndex);
|
||||||
} else {
|
} else {
|
||||||
onFilterSelect(
|
onFilterSelect(
|
||||||
timestamp
|
isTimestamp
|
||||||
? { type: 'interval', dimension: columnName, intervals: [] }
|
? { type: 'interval', dimension: columnName, intervals: [] }
|
||||||
: { type: 'selector', dimension: columnName, value: '' },
|
: { type: 'selector', dimension: columnName, value: '' },
|
||||||
-1,
|
-1,
|
||||||
|
@ -102,7 +102,7 @@ export const FilterTable = React.memo(function FilterTable(props: FilterTablePro
|
||||||
accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName] : null),
|
accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName] : null),
|
||||||
width: 140,
|
width: 140,
|
||||||
Cell: function FilterTableCell(row: RowRenderProps) {
|
Cell: function FilterTableCell(row: RowRenderProps) {
|
||||||
return <TableCell value={timestamp ? new Date(row.value) : row.value} />;
|
return <TableCell value={isTimestamp ? new Date(Number(row.value)) : row.value} />;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import {
|
||||||
getTimestampDetailFromSpec,
|
getTimestampDetailFromSpec,
|
||||||
getTimestampSpecColumnFromSpec,
|
getTimestampSpecColumnFromSpec,
|
||||||
possibleDruidFormatForValues,
|
possibleDruidFormatForValues,
|
||||||
|
TIME_COLUMN,
|
||||||
} from '../../../druid-models';
|
} from '../../../druid-models';
|
||||||
import {
|
import {
|
||||||
DEFAULT_TABLE_CLASS_NAME,
|
DEFAULT_TABLE_CLASS_NAME,
|
||||||
|
@ -86,7 +87,7 @@ export const ParseTimeTable = React.memo(function ParseTimeTable(props: ParseTim
|
||||||
pageSizeOptions={STANDARD_TABLE_PAGE_SIZE_OPTIONS}
|
pageSizeOptions={STANDARD_TABLE_PAGE_SIZE_OPTIONS}
|
||||||
showPagination={sampleResponse.data.length > STANDARD_TABLE_PAGE_SIZE}
|
showPagination={sampleResponse.data.length > STANDARD_TABLE_PAGE_SIZE}
|
||||||
columns={filterMap(getHeaderNamesFromSampleResponse(sampleResponse), (columnName, i) => {
|
columns={filterMap(getHeaderNamesFromSampleResponse(sampleResponse), (columnName, i) => {
|
||||||
const isTimestamp = columnName === '__time';
|
const isTimestamp = columnName === TIME_COLUMN;
|
||||||
if (!isTimestamp && !caseInsensitiveContains(columnName, columnFilter)) return;
|
if (!isTimestamp && !caseInsensitiveContains(columnName, columnFilter)) return;
|
||||||
const used = timestampSpecColumn === columnName;
|
const used = timestampSpecColumn === columnName;
|
||||||
const possibleFormat = isTimestamp
|
const possibleFormat = isTimestamp
|
||||||
|
@ -134,7 +135,7 @@ export const ParseTimeTable = React.memo(function ParseTimeTable(props: ParseTim
|
||||||
if (row.original.unparseable) {
|
if (row.original.unparseable) {
|
||||||
return <TableCellUnparseable timestamp={isTimestamp} />;
|
return <TableCellUnparseable timestamp={isTimestamp} />;
|
||||||
}
|
}
|
||||||
return <TableCell value={isTimestamp ? new Date(row.value) : row.value} />;
|
return <TableCell value={isTimestamp ? new Date(Number(row.value)) : row.value} />;
|
||||||
},
|
},
|
||||||
width: isTimestamp ? 200 : 140,
|
width: isTimestamp ? 200 : 140,
|
||||||
resizable: !isTimestamp,
|
resizable: !isTimestamp,
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
getDimensionSpecType,
|
getDimensionSpecType,
|
||||||
getMetricSpecName,
|
getMetricSpecName,
|
||||||
inflateDimensionSpec,
|
inflateDimensionSpec,
|
||||||
|
TIME_COLUMN,
|
||||||
} from '../../../druid-models';
|
} from '../../../druid-models';
|
||||||
import {
|
import {
|
||||||
DEFAULT_TABLE_CLASS_NAME,
|
DEFAULT_TABLE_CLASS_NAME,
|
||||||
|
@ -109,7 +110,7 @@ export const SchemaTable = React.memo(function SchemaTable(props: SchemaTablePro
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const isTimestamp = columnName === '__time';
|
const isTimestamp = columnName === TIME_COLUMN;
|
||||||
const dimensionSpecIndex = dimensions
|
const dimensionSpecIndex = dimensions
|
||||||
? dimensions.findIndex(d => getDimensionSpecName(d) === columnName)
|
? dimensions.findIndex(d => getDimensionSpecName(d) === columnName)
|
||||||
: -1;
|
: -1;
|
||||||
|
@ -151,7 +152,7 @@ export const SchemaTable = React.memo(function SchemaTable(props: SchemaTablePro
|
||||||
width: isTimestamp ? 200 : 140,
|
width: isTimestamp ? 200 : 140,
|
||||||
accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName] : null),
|
accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName] : null),
|
||||||
Cell: function SchemaTableCell(row: RowRenderProps) {
|
Cell: function SchemaTableCell(row: RowRenderProps) {
|
||||||
return <TableCell value={isTimestamp ? new Date(row.value) : row.value} />;
|
return <TableCell value={isTimestamp ? new Date(Number(row.value)) : row.value} />;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ReactTable from 'react-table';
|
||||||
|
|
||||||
import { TableCell } from '../../../components';
|
import { TableCell } from '../../../components';
|
||||||
import type { Transform } from '../../../druid-models';
|
import type { Transform } from '../../../druid-models';
|
||||||
|
import { TIME_COLUMN } from '../../../druid-models';
|
||||||
import {
|
import {
|
||||||
DEFAULT_TABLE_CLASS_NAME,
|
DEFAULT_TABLE_CLASS_NAME,
|
||||||
STANDARD_TABLE_PAGE_SIZE,
|
STANDARD_TABLE_PAGE_SIZE,
|
||||||
|
@ -79,7 +80,7 @@ export const TransformTable = React.memo(function TransformTable(props: Transfor
|
||||||
showPagination={sampleResponse.data.length > STANDARD_TABLE_PAGE_SIZE}
|
showPagination={sampleResponse.data.length > STANDARD_TABLE_PAGE_SIZE}
|
||||||
columns={filterMap(getHeaderNamesFromSampleResponse(sampleResponse), (columnName, i) => {
|
columns={filterMap(getHeaderNamesFromSampleResponse(sampleResponse), (columnName, i) => {
|
||||||
if (!caseInsensitiveContains(columnName, columnFilter)) return;
|
if (!caseInsensitiveContains(columnName, columnFilter)) return;
|
||||||
const timestamp = columnName === '__time';
|
const isTimestamp = columnName === TIME_COLUMN;
|
||||||
const transformIndex = transforms.findIndex(f => f.name === columnName);
|
const transformIndex = transforms.findIndex(f => f.name === columnName);
|
||||||
if (transformIndex === -1 && transformedColumnsOnly) return;
|
if (transformIndex === -1 && transformedColumnsOnly) return;
|
||||||
const transform = transforms[transformIndex];
|
const transform = transforms[transformIndex];
|
||||||
|
@ -119,7 +120,7 @@ export const TransformTable = React.memo(function TransformTable(props: Transfor
|
||||||
accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName] : null),
|
accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName] : null),
|
||||||
width: 140,
|
width: 140,
|
||||||
Cell: function TransformTableCell(row: RowRenderProps) {
|
Cell: function TransformTableCell(row: RowRenderProps) {
|
||||||
return <TableCell value={timestamp ? new Date(row.value) : row.value} />;
|
return <TableCell value={isTimestamp ? new Date(Number(row.value)) : row.value} />;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -17,18 +17,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button, Classes, Dialog, Intent } from '@blueprintjs/core';
|
import { Button, Classes, Dialog, Intent } from '@blueprintjs/core';
|
||||||
|
import * as JSONBig from 'json-bigint-native';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import AceEditor from 'react-ace';
|
import AceEditor from 'react-ace';
|
||||||
|
|
||||||
import { Execution } from '../../../druid-models';
|
import { Execution } from '../../../druid-models';
|
||||||
import { AppToaster } from '../../../singletons';
|
import { AppToaster } from '../../../singletons';
|
||||||
import { validJson } from '../../../utils';
|
import { offsetToRowColumn } from '../../../utils';
|
||||||
|
|
||||||
import './execution-submit-dialog.scss';
|
import './execution-submit-dialog.scss';
|
||||||
|
|
||||||
export interface ExecutionSubmitDialogProps {
|
export interface ExecutionSubmitDialogProps {
|
||||||
onSubmit: (execution: Execution) => void;
|
onSubmit(execution: Execution): void;
|
||||||
onClose: () => void;
|
onClose(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
|
export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
|
||||||
|
@ -37,15 +38,18 @@ export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
|
||||||
const { onClose, onSubmit } = props;
|
const { onClose, onSubmit } = props;
|
||||||
const [archive, setArchive] = useState('');
|
const [archive, setArchive] = useState('');
|
||||||
|
|
||||||
function submitProfile(): void {
|
function handleSubmit(): void {
|
||||||
if (!validJson(archive)) return;
|
|
||||||
let parsed: any;
|
let parsed: any;
|
||||||
try {
|
try {
|
||||||
parsed = JSON.parse(archive);
|
parsed = JSONBig.parse(archive);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
const rowColumn = typeof e.at === 'number' ? offsetToRowColumn(archive, e.at) : undefined;
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
message: `Could not parse JSON: ${e.message}`,
|
message: `Could not parse JSON: ${e.message}${
|
||||||
|
rowColumn ? ` (at line ${rowColumn.row + 1}, column ${rowColumn.column + 1})` : ''
|
||||||
|
}`,
|
||||||
|
timeout: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -129,8 +133,8 @@ export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
|
||||||
<Button
|
<Button
|
||||||
text="Submit"
|
text="Submit"
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
onClick={submitProfile}
|
onClick={handleSubmit}
|
||||||
disabled={!validJson(archive)}
|
disabled={!archive}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue