From 9254dc8b805ec8ac98e61e4e40f68626c91949d0 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Sun, 25 Aug 2019 16:56:27 -0700 Subject: [PATCH] Web console: Save query context also (#8395) * tidy up menus * fix query output API * save context also * pull out auto run into a switch * better copy * add group_id * support FLOAT also * use built in time logic * fix trunc direction * add skipCache * add manifest url * remove depricated props --- web-console/console-config.js | 5 +- web-console/package-lock.json | 6 +- web-console/package.json | 2 +- .../components/action-cell/action-cell.tsx | 4 - .../src/components/deferred/deferred.tsx | 4 - .../refresh-button/refresh-button.tsx | 5 +- .../segment-timeline/segment-timeline.tsx | 17 +- .../src/components/show-value/show-value.tsx | 4 - .../edit-context-dialog.tsx | 8 +- web-console/src/dialogs/index.ts | 1 + .../query-history-dialog.tsx | 18 +- .../query-plan-dialog.spec.tsx.snap | 14 +- .../query-plan-dialog/query-plan-dialog.scss | 4 + .../query-plan-dialog/query-plan-dialog.tsx | 39 +- .../show-value-dialog/show-value-dialog.tsx | 1 + web-console/src/utils/local-storage-keys.tsx | 15 + web-console/src/utils/query-context.tsx | 1 + web-console/src/utils/sampler.ts | 2 +- web-console/src/views/index.ts | 1 + .../views/load-data-view/load-data-view.tsx | 3 +- .../__snapshots__/query-view.spec.tsx.snap | 29 +- .../__snapshots__/column-tree.spec.tsx.snap | 184 +++++++- .../column-tree/column-tree-menu/index.ts | 21 + .../number-menu-items.spec.tsx | 9 +- .../number-menu-items/number-menu-items.tsx | 141 +++--- .../string-menu-items.spec.tsx | 9 +- .../string-menu-items/string-menu-items.tsx | 157 ++++--- .../time-menu-items/time-menu-items.spec.tsx | 9 +- .../time-menu-items/time-menu-items.tsx | 403 +++++++++--------- .../column-tree/column-tree.spec.tsx | 25 +- .../query-view/column-tree/column-tree.tsx | 291 ++++++------- .../query-output/query-output.spec.tsx | 9 +- .../query-view/query-output/query-output.tsx | 43 +- .../src/views/query-view/query-view.scss | 1 + .../src/views/query-view/query-view.tsx | 227 +++------- .../query-view/run-button/run-button.spec.tsx | 4 +- .../query-view/run-button/run-button.tsx | 32 +- .../__snapshots__/tasks-view.spec.tsx.snap | 14 + .../src/views/task-view/tasks-view.tsx | 18 +- web-console/src/visualization/bar-group.tsx | 2 +- web-console/src/visualization/bar-unit.tsx | 2 +- web-console/src/visualization/chart-axis.tsx | 2 +- .../src/visualization/stacked-bar-chart.tsx | 2 +- 43 files changed, 925 insertions(+), 863 deletions(-) create mode 100644 web-console/src/views/query-view/column-tree/column-tree-menu/index.ts diff --git a/web-console/console-config.js b/web-console/console-config.js index 127d3a00e9b..6fac8a2dd68 100644 --- a/web-console/console-config.js +++ b/web-console/console-config.js @@ -16,4 +16,7 @@ * limitations under the License. */ -window.consoleConfig = { /* future configs may go here */ }; +window.consoleConfig = { + "exampleManifestsUrl": "https://druid.apache.org/data/example-manifests.tsv" + /* future configs may go here */ +}; diff --git a/web-console/package-lock.json b/web-console/package-lock.json index 87bb3917c4f..a4ae431dacc 100644 --- a/web-console/package-lock.json +++ b/web-console/package-lock.json @@ -4428,9 +4428,9 @@ "integrity": "sha512-0sYnfUHHMoajaud/i5BHKA12bUxiWEHJ9rxGqVEppFxsEcxef0TZQ5J59lU+UniEBcz/sG5fTESRyS7cOm3tSQ==" }, "druid-query-toolkit": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.24.tgz", - "integrity": "sha512-kFvEXAjjNuJYpeRsAzzO/cJ2rr4nHBGTSCAA4UPxyt4pKNZE/OUap7IQbsdnxYmhkHgfjUBGcFteufaVHSn7SA==", + "version": "0.3.26", + "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.26.tgz", + "integrity": "sha512-j9HcwHCx2YnFSefYc1oJDw8rPq5zSB0tpGkaMp2GkO9syKbdncKfUPugZ613c5XIOBe+j5Hqh/luqh4sLacHGQ==", "requires": { "tslib": "^1.10.0" } diff --git a/web-console/package.json b/web-console/package.json index a221cc8f66b..553938f52e7 100644 --- a/web-console/package.json +++ b/web-console/package.json @@ -61,7 +61,7 @@ "d3": "^5.10.1", "d3-array": "^2.3.1", "druid-console": "0.0.2", - "druid-query-toolkit": "^0.3.24", + "druid-query-toolkit": "^0.3.26", "file-saver": "^2.0.2", "has-own-prop": "^2.0.0", "hjson": "^3.1.2", diff --git a/web-console/src/components/action-cell/action-cell.tsx b/web-console/src/components/action-cell/action-cell.tsx index 248c5ea6306..f48fc4c01ce 100644 --- a/web-console/src/components/action-cell/action-cell.tsx +++ b/web-console/src/components/action-cell/action-cell.tsx @@ -35,10 +35,6 @@ export class ActionCell extends React.PureComponent { static COLUMN_LABEL = 'Actions'; static COLUMN_WIDTH = 70; - constructor(props: ActionCellProps, context: any) { - super(props, context); - } - render(): JSX.Element { const { onDetail, actions } = this.props; const actionsMenu = actions ? basicActionsToMenu(actions) : null; diff --git a/web-console/src/components/deferred/deferred.tsx b/web-console/src/components/deferred/deferred.tsx index 6194979193d..7e6cde39535 100644 --- a/web-console/src/components/deferred/deferred.tsx +++ b/web-console/src/components/deferred/deferred.tsx @@ -25,10 +25,6 @@ export interface DeferredProps { export interface DeferredState {} export class Deferred extends React.PureComponent { - constructor(props: DeferredProps, context: any) { - super(props, context); - } - render(): JSX.Element { const { content } = this.props; return content(); diff --git a/web-console/src/components/refresh-button/refresh-button.tsx b/web-console/src/components/refresh-button/refresh-button.tsx index 9393e500f78..cfe68e55b8e 100644 --- a/web-console/src/components/refresh-button/refresh-button.tsx +++ b/web-console/src/components/refresh-button/refresh-button.tsx @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { IconNames } from '@blueprintjs/icons'; import React from 'react'; @@ -27,10 +28,6 @@ export interface RefreshButtonProps { } export class RefreshButton extends React.PureComponent { - constructor(props: RefreshButtonProps, context: any) { - super(props, context); - } - render(): JSX.Element { const { onRefresh, localStorageKey } = this.props; const intervals = [ diff --git a/web-console/src/components/segment-timeline/segment-timeline.tsx b/web-console/src/components/segment-timeline/segment-timeline.tsx index 34d3a88ffa9..dd9eea7762b 100644 --- a/web-console/src/components/segment-timeline/segment-timeline.tsx +++ b/web-console/src/components/segment-timeline/segment-timeline.tsx @@ -27,7 +27,7 @@ import { Loader } from '../loader/loader'; import './segment-timeline.scss'; -interface SegmentTimelineProps extends React.Props { +interface SegmentTimelineProps { chartHeight: number; chartWidth: number; } @@ -71,9 +71,7 @@ export interface BarChartMargin { } export class SegmentTimeline extends React.Component { - private dataQueryManager: QueryManager; - private datasourceQueryManager: QueryManager; - private colors = [ + static COLORS = [ '#b33040', '#d25c4d', '#f2b447', @@ -91,6 +89,13 @@ export class SegmentTimeline extends React.Component; + private datasourceQueryManager: QueryManager; private chartMargin = { top: 20, right: 10, bottom: 20, left: 10 }; constructor(props: SegmentTimelineProps) { @@ -249,7 +254,7 @@ export class SegmentTimeline extends React.Component d.y === 0)) { diff --git a/web-console/src/components/show-value/show-value.tsx b/web-console/src/components/show-value/show-value.tsx index f30f4c734c5..d1e6ce4691d 100644 --- a/web-console/src/components/show-value/show-value.tsx +++ b/web-console/src/components/show-value/show-value.tsx @@ -31,10 +31,6 @@ export interface ShowValueProps { } export class ShowValue extends React.PureComponent { - constructor(props: ShowValueProps, context: any) { - super(props, context); - } - render(): JSX.Element { const { endpoint, downloadFilename, jsonValue } = this.props; return ( diff --git a/web-console/src/dialogs/edit-context-dialog/edit-context-dialog.tsx b/web-console/src/dialogs/edit-context-dialog/edit-context-dialog.tsx index 5a6e320dca5..89e6dca96d3 100644 --- a/web-console/src/dialogs/edit-context-dialog/edit-context-dialog.tsx +++ b/web-console/src/dialogs/edit-context-dialog/edit-context-dialog.tsx @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Button, Callout, Classes, Dialog, Intent, TextArea } from '@blueprintjs/core'; import Hjson from 'hjson'; import React from 'react'; @@ -42,6 +43,7 @@ export class EditContextDialog extends React.PureComponent< constructor(props: EditContextDialogProps) { super(props); this.state = { + queryContext: props.queryContext, queryContextString: Object.keys(props.queryContext).length ? JSON.stringify(props.queryContext, undefined, 2) : '{\n\n}', @@ -72,10 +74,12 @@ export class EditContextDialog extends React.PureComponent< }; private handleSave = () => { - const { onQueryContextChange } = this.props; + const { onQueryContextChange, onClose } = this.props; const { queryContext } = this.state; if (!queryContext) return; + onQueryContextChange(queryContext); + onClose(); }; render(): JSX.Element { @@ -94,9 +98,9 @@ export class EditContextDialog extends React.PureComponent<
diff --git a/web-console/src/dialogs/index.ts b/web-console/src/dialogs/index.ts index 27bd358981e..0972cdc8ef7 100644 --- a/web-console/src/dialogs/index.ts +++ b/web-console/src/dialogs/index.ts @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export * from './about-dialog/about-dialog'; export * from './async-action-dialog/async-action-dialog'; export * from './compaction-dialog/compaction-dialog'; diff --git a/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx b/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx index 129ef827045..813b3b6c80e 100644 --- a/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx +++ b/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx @@ -26,9 +26,10 @@ import './query-history-dialog.scss'; export interface QueryRecord { version: string; queryString: string; + queryContext?: Record; } export interface QueryHistoryDialogProps { - setQueryString: (queryString: string) => void; + setQueryString: (queryString: string, queryContext: Record) => void; onClose: () => void; queryRecords: readonly QueryRecord[]; } @@ -51,9 +52,14 @@ export class QueryHistoryDialog extends React.PureComponent< static addQueryToHistory( queryHistory: readonly QueryRecord[], queryString: string, + queryContext: Record, ): readonly QueryRecord[] { - // Do not add to history if already the same as the last element - if (queryHistory.length && queryHistory[0].queryString === queryString) { + // Do not add to history if already the same as the last element in query and context + if ( + queryHistory.length && + queryHistory[0].queryString === queryString && + JSON.stringify(queryHistory[0].queryContext) === JSON.stringify(queryContext) + ) { return queryHistory; } @@ -61,7 +67,8 @@ export class QueryHistoryDialog extends React.PureComponent< { version: QueryHistoryDialog.getHistoryVersion(), queryString, - }, + queryContext, + } as QueryRecord, ] .concat(queryHistory) .slice(0, 10); @@ -77,8 +84,9 @@ export class QueryHistoryDialog extends React.PureComponent< private handleSelect = () => { const { queryRecords, setQueryString, onClose } = this.props; const { activeTab } = this.state; + const queryRecord = queryRecords[activeTab]; - setQueryString(queryRecords[activeTab].queryString); + setQueryString(queryRecord.queryString, queryRecord.queryContext || {}); onClose(); }; diff --git a/web-console/src/dialogs/query-plan-dialog/__snapshots__/query-plan-dialog.spec.tsx.snap b/web-console/src/dialogs/query-plan-dialog/__snapshots__/query-plan-dialog.spec.tsx.snap index e91d4b8c7ca..e5e442ef935 100644 --- a/web-console/src/dialogs/query-plan-dialog/__snapshots__/query-plan-dialog.spec.tsx.snap +++ b/web-console/src/dialogs/query-plan-dialog/__snapshots__/query-plan-dialog.spec.tsx.snap @@ -55,7 +55,9 @@ exports[`query plan dialog matches snapshot 1`] = `
-
+
test
@@ -75,16 +77,6 @@ exports[`query plan dialog matches snapshot 1`] = ` Close -
diff --git a/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.scss b/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.scss index 2835b799553..e7797a266e6 100644 --- a/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.scss +++ b/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.scss @@ -36,4 +36,8 @@ height: 25vh !important; } } + + .generic-result { + overflow: scroll; + } } diff --git a/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx b/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx index 6297e0cf9fe..8959cf7934a 100644 --- a/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx +++ b/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx @@ -38,23 +38,16 @@ export interface QueryPlanDialogProps { setQueryString: (queryString: string) => void; } -export interface QueryPlanDialogState {} - -export class QueryPlanDialog extends React.PureComponent< - QueryPlanDialogProps, - QueryPlanDialogState -> { +export class QueryPlanDialog extends React.PureComponent { constructor(props: QueryPlanDialogProps) { super(props); - this.state = {}; } - private queryString: string = ''; - render(): JSX.Element { const { explainResult, explainError, onClose, setQueryString } = this.props; let content: JSX.Element; + let queryString: string | undefined; if (explainError) { content =
{explainError}
; @@ -71,15 +64,11 @@ export class QueryPlanDialog extends React.PureComponent< ); } - this.queryString = JSON.stringify( - (explainResult as BasicQueryExplanation).query[0], - undefined, - 2, - ); + queryString = JSON.stringify((explainResult as BasicQueryExplanation).query[0], undefined, 2); content = (
-