From 1d3c8c187b9c07ee1adc6a6669f756421ec9f324 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 7 Dec 2021 10:16:16 -0800 Subject: [PATCH] Web console: query view improvements and other fixes (#12031) * don't copy commas * use numeric type information * add VALUES keyword * propogate rollup config into spec * fix * cleanup * understand range partitioning * update snapshots * better comp apis * fix segment pages * update snapshots --- licenses.yaml | 6 +- web-console/lib/keywords.js | 1 + web-console/package-lock.json | 6 +- web-console/package.json | 2 +- .../components/braced-text/braced-text.scss | 4 + .../components/braced-text/braced-text.tsx | 30 +++- .../src/components/deferred/deferred.tsx | 2 +- web-console/src/components/index.ts | 1 + web-console/src/components/loader/loader.tsx | 6 +- .../menu-checkbox/menu-checkbox.tsx | 14 +- .../segment-timeline.spec.tsx | 2 +- .../compaction-dialog.spec.tsx.snap | 36 +++++ .../show-value-dialog.spec.tsx.snap | 3 +- .../show-value-dialog/show-value-dialog.scss | 11 +- .../show-value-dialog/show-value-dialog.tsx | 13 +- .../src/druid-models/compaction-config.tsx | 15 +- .../src/druid-models/ingestion-spec.tsx | 96 ++++++------ web-console/src/entry.ts | 5 + web-console/src/utils/druid-query.spec.ts | 2 +- web-console/src/utils/general.tsx | 30 ++++ web-console/src/utils/index.tsx | 1 + web-console/src/utils/sampler.ts | 26 ++++ web-console/src/utils/table-helpers.ts | 58 +++++++ .../views/datasource-view/datasource-view.tsx | 16 +- .../__snapshots__/query-view.spec.tsx.snap | 146 ++++++++++++++++++ .../__snapshots__/column-tree.spec.tsx.snap | 1 + .../time-menu-items/time-menu-items.tsx | 9 +- .../query-view/column-tree/column-tree.scss | 14 ++ .../query-view/column-tree/column-tree.tsx | 42 +++-- .../query-view/query-input/query-input.scss | 2 + .../query-view/query-output/query-output.tsx | 63 +++----- .../src/views/query-view/query-utils.ts | 9 +- .../src/views/query-view/query-view.tsx | 9 +- .../__snapshots__/segments-view.spec.tsx.snap | 2 +- .../src/views/segments-view/segments-view.tsx | 12 +- .../__snapshots__/services-view.spec.tsx.snap | 2 +- .../src/views/services-view/services-view.tsx | 6 +- 37 files changed, 547 insertions(+), 156 deletions(-) create mode 100644 web-console/src/utils/table-helpers.ts diff --git a/licenses.yaml b/licenses.yaml index 6ab305b3fa1..0a1b80d9f3e 100644 --- a/licenses.yaml +++ b/licenses.yaml @@ -5105,7 +5105,7 @@ license_category: binary module: web-console license_name: MIT License copyright: Matt Zabriskie -version: 0.21.1 +version: 0.21.4 license_file_path: licenses/bin/axios.MIT --- @@ -5294,7 +5294,7 @@ license_category: binary module: web-console license_name: Apache License version 2.0 copyright: Imply Data -version: 0.11.10 +version: 0.14.4 --- @@ -5313,7 +5313,7 @@ license_category: binary module: web-console license_name: MIT License copyright: Ruben Verborgh -version: 1.13.3 +version: 1.14.4 license_file_path: licenses/bin/follow-redirects.MIT --- diff --git a/web-console/lib/keywords.js b/web-console/lib/keywords.js index bf7d9004cc0..accae44e4cf 100644 --- a/web-console/lib/keywords.js +++ b/web-console/lib/keywords.js @@ -53,6 +53,7 @@ exports.SQL_KEYWORDS = [ 'ROW', 'ROWS', 'ONLY', + 'VALUES', ]; exports.SQL_EXPRESSION_PARTS = [ diff --git a/web-console/package-lock.json b/web-console/package-lock.json index dc3daa66c75..4e13d1a65d1 100644 --- a/web-console/package-lock.json +++ b/web-console/package-lock.json @@ -7970,9 +7970,9 @@ } }, "druid-query-toolkit": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.11.10.tgz", - "integrity": "sha512-jKqec2YMxCVvow8e9lmmrRKXxq/ugyeyKTVPaAUPbjoP4VHxk55BS2gXJ/S2ysCeVgvyJbjGbg2ZIkUzg4Whuw==", + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.14.4.tgz", + "integrity": "sha512-PmD5vwoHQxNxZ8E8vRdHvh5OjuvA+yHD5dhiKDzIzPtnFiwRHLJKyOLSQ6rmN1VAKbOdU4JCZIzPFUB8bEMBAQ==", "requires": { "tslib": "^2.2.0" } diff --git a/web-console/package.json b/web-console/package.json index c431277bad5..0cd79a9a89c 100644 --- a/web-console/package.json +++ b/web-console/package.json @@ -79,7 +79,7 @@ "d3-axis": "^1.0.12", "d3-scale": "^3.2.0", "d3-selection": "^1.4.0", - "druid-query-toolkit": "^0.11.10", + "druid-query-toolkit": "^0.14.4", "file-saver": "^2.0.2", "fontsource-open-sans": "^3.0.9", "has-own-prop": "^2.0.0", diff --git a/web-console/src/components/braced-text/braced-text.scss b/web-console/src/components/braced-text/braced-text.scss index 872cfd70493..56f649397e4 100644 --- a/web-console/src/components/braced-text/braced-text.scss +++ b/web-console/src/components/braced-text/braced-text.scss @@ -38,5 +38,9 @@ .zero-pad { visibility: hidden; } + + .unselectable { + user-select: none; + } } } diff --git a/web-console/src/components/braced-text/braced-text.tsx b/web-console/src/components/braced-text/braced-text.tsx index 3fd2b85e01a..c6478bb58f2 100644 --- a/web-console/src/components/braced-text/braced-text.tsx +++ b/web-console/src/components/braced-text/braced-text.tsx @@ -17,14 +17,17 @@ */ import { max } from 'd3-array'; -import React from 'react'; +import React, { Fragment } from 'react'; import './braced-text.scss'; +const THOUSANDS_SEPARATOR = ','; // Maybe one day make this locale aware + export interface BracedTextProps { text: string; braces: string[]; padFractionalPart?: boolean; + unselectableThousandsSeparator?: boolean; } export function findMostNumbers(strings: string[]): string { @@ -56,8 +59,29 @@ function zerosOfLength(n: number): string { return new Array(n + 1).join('0'); } +function arrayJoin(array: T[], separator: U): (T | U)[] { + const result: (T | U)[] = []; + for (let i = 0; i < array.length; i++) { + if (i) { + result.push(separator, array[i]); + } else { + result.push(array[i]); + } + } + return result; +} + +function hideThousandsSeparator(text: string) { + const parts = text.split(THOUSANDS_SEPARATOR); + if (parts.length < 2) return text; + return arrayJoin( + parts, + {THOUSANDS_SEPARATOR}, + ).map((x, i) => {x}); +} + export const BracedText = React.memo(function BracedText(props: BracedTextProps) { - const { text, braces, padFractionalPart } = props; + const { text, braces, padFractionalPart, unselectableThousandsSeparator } = props; let effectiveBraces = braces.concat(text); @@ -90,7 +114,7 @@ export const BracedText = React.memo(function BracedText(props: BracedTextProps) {findMostNumbers(effectiveBraces)} - {text} + {unselectableThousandsSeparator ? hideThousandsSeparator(text) : text} {zeroPad} diff --git a/web-console/src/components/deferred/deferred.tsx b/web-console/src/components/deferred/deferred.tsx index 38264483171..f4a9deb68c4 100644 --- a/web-console/src/components/deferred/deferred.tsx +++ b/web-console/src/components/deferred/deferred.tsx @@ -19,7 +19,7 @@ import React from 'react'; export interface DeferredProps { - content: () => JSX.Element; + content: () => JSX.Element | null; } export const Deferred = React.memo(function Deferred(props: DeferredProps) { diff --git a/web-console/src/components/index.ts b/web-console/src/components/index.ts index fdefa7cc34b..2680d1346ff 100644 --- a/web-console/src/components/index.ts +++ b/web-console/src/components/index.ts @@ -23,6 +23,7 @@ export * from './auto-form/auto-form'; export * from './braced-text/braced-text'; export * from './center-message/center-message'; export * from './clearable-input/clearable-input'; +export * from './deferred/deferred'; export * from './external-link/external-link'; export * from './form-json-selector/form-json-selector'; export * from './formatted-input/formatted-input'; diff --git a/web-console/src/components/loader/loader.tsx b/web-console/src/components/loader/loader.tsx index c2f1f50644b..40fca983f4b 100644 --- a/web-console/src/components/loader/loader.tsx +++ b/web-console/src/components/loader/loader.tsx @@ -16,11 +16,13 @@ * limitations under the License. */ +import classNames from 'classnames'; import React from 'react'; import './loader.scss'; export interface LoaderProps { + className?: string; loading?: boolean; // This is needed so that this component can be used as a LoadingComponent in react table loadingText?: string; cancelText?: string; @@ -28,11 +30,11 @@ export interface LoaderProps { } export const Loader = React.memo(function Loader(props: LoaderProps) { - const { loadingText, loading, cancelText, onCancel } = props; + const { className, loadingText, loading, cancelText, onCancel } = props; if (loading === false) return null; return ( -
+
{ checked: boolean; onChange: () => void; } export function MenuCheckbox(props: MenuCheckboxProps) { - const { text, checked, onChange } = props; + const { checked, onChange, className, shouldDismissPopover, ...rest } = props; return ( ); } diff --git a/web-console/src/components/segment-timeline/segment-timeline.spec.tsx b/web-console/src/components/segment-timeline/segment-timeline.spec.tsx index 5fba7ebd5f3..1d7fb6aab5a 100644 --- a/web-console/src/components/segment-timeline/segment-timeline.spec.tsx +++ b/web-console/src/components/segment-timeline/segment-timeline.spec.tsx @@ -17,7 +17,7 @@ */ import { render } from '@testing-library/react'; -import { sane } from 'druid-query-toolkit/build/test-utils'; +import { sane } from 'druid-query-toolkit'; import React from 'react'; import { Capabilities } from '../../utils'; diff --git a/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap b/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap index 45f015da411..c662ef6f97b 100644 --- a/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap @@ -207,6 +207,15 @@ exports[`CompactionDialog matches snapshot with compactionConfig (dynamic partit "required": true, "type": "string", }, + Object { + "defined": [Function], + "info":

+ The dimensions to partition on. +

, + "name": "tuningConfig.partitionsSpec.partitionDimensions", + "required": true, + "type": "string-array", + }, Object { "defined": [Function], "info": @@ -568,6 +577,15 @@ exports[`CompactionDialog matches snapshot with compactionConfig (hashed partiti "required": true, "type": "string", }, + Object { + "defined": [Function], + "info":

+ The dimensions to partition on. +

, + "name": "tuningConfig.partitionsSpec.partitionDimensions", + "required": true, + "type": "string-array", + }, Object { "defined": [Function], "info": @@ -929,6 +947,15 @@ exports[`CompactionDialog matches snapshot with compactionConfig (single_dim par "required": true, "type": "string", }, + Object { + "defined": [Function], + "info":

+ The dimensions to partition on. +

, + "name": "tuningConfig.partitionsSpec.partitionDimensions", + "required": true, + "type": "string-array", + }, Object { "defined": [Function], "info": @@ -1290,6 +1317,15 @@ exports[`CompactionDialog matches snapshot without compactionConfig 1`] = ` "required": true, "type": "string", }, + Object { + "defined": [Function], + "info":

+ The dimensions to partition on. +

, + "name": "tuningConfig.partitionsSpec.partitionDimensions", + "required": true, + "type": "string-array", + }, Object { "defined": [Function], "info": diff --git a/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap b/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap index cc5be82723f..8206d17ca5d 100644 --- a/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap @@ -16,7 +16,7 @@ exports[`clipboard dialog matches snapshot 1`] = ` tabindex="0" >
diff --git a/web-console/src/dialogs/show-value-dialog/show-value-dialog.scss b/web-console/src/dialogs/show-value-dialog/show-value-dialog.scss index 85271648d5a..5cce81bc92c 100644 --- a/web-console/src/dialogs/show-value-dialog/show-value-dialog.scss +++ b/web-console/src/dialogs/show-value-dialog/show-value-dialog.scss @@ -21,9 +21,18 @@ padding-bottom: 10px; } + &.normal.bp3-dialog { + height: 600px; + } + + &.large.bp3-dialog { + width: 90vw; + height: 90vh; + } + .bp3-input { margin: 10px; - height: 400px; + flex: 1; } .bp3-dialog-footer-actions { diff --git a/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx b/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx index c46f35f961c..f5291e172bc 100644 --- a/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx +++ b/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx @@ -18,6 +18,7 @@ import { Button, Classes, Dialog, Intent, TextArea } from '@blueprintjs/core'; import { IconNames } from '@blueprintjs/icons'; +import classNames from 'classnames'; import copy from 'copy-to-clipboard'; import React from 'react'; @@ -28,10 +29,11 @@ import './show-value-dialog.scss'; export interface ShowValueDialogProps { onClose: () => void; str: string; + size?: 'normal' | 'large'; } export const ShowValueDialog = React.memo(function ShowValueDialog(props: ShowValueDialogProps) { - const { onClose, str } = props; + const { onClose, str, size } = props; function handleCopy() { copy(str, { format: 'text/plain' }); @@ -42,8 +44,13 @@ export const ShowValueDialog = React.memo(function ShowValueDialog(props: ShowVa } return ( - -