From 788bc94143677a7edc01f2a81c155625a25a852a Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 3 Nov 2020 18:01:37 -0800 Subject: [PATCH 01/13] remove unused fields --- .../src/druid-models/ingestion-spec.tsx | 43 +------------------ .../src/druid-models/timestamp-spec.tsx | 7 ++- .../views/load-data-view/load-data-view.tsx | 15 ++++++- 3 files changed, 21 insertions(+), 44 deletions(-) diff --git a/web-console/src/druid-models/ingestion-spec.tsx b/web-console/src/druid-models/ingestion-spec.tsx index e58c59165049..5b7abc2dd315 100644 --- a/web-console/src/druid-models/ingestion-spec.tsx +++ b/web-console/src/druid-models/ingestion-spec.tsx @@ -983,45 +983,6 @@ export function getIoConfigTuningFormFields( ), }, - { - name: 'inputSource.maxCacheCapacityBytes', - label: 'Max cache capacity bytes', - type: 'number', - defaultValue: 1073741824, - info: ( - <> -

- Maximum size of the cache space in bytes. 0 means disabling cache. Cached files are - not removed until the ingestion task completes. -

- - ), - }, - { - name: 'inputSource.maxFetchCapacityBytes', - label: 'Max fetch capacity bytes', - type: 'number', - defaultValue: 1073741824, - info: ( - <> -

- Maximum size of the fetch space in bytes. 0 means disabling prefetch. Prefetched - files are removed immediately once they are read. -

- - ), - }, - { - name: 'inputSource.prefetchTriggerBytes', - label: 'Prefetch trigger bytes', - type: 'number', - placeholder: 'maxFetchCapacityBytes / 2', - info: ( - <> -

Threshold to trigger prefetching the objects.

- - ), - }, ]; case 'index_parallel:local': @@ -2091,14 +2052,14 @@ export function updateSchemaWithSample( } if (rollup) { - newSpec = deepSet(newSpec, 'spec.dataSchema.granularitySpec.queryGranularity', 'HOUR'); + newSpec = deepSet(newSpec, 'spec.dataSchema.granularitySpec.queryGranularity', 'hour'); const metrics = getMetricSpecs(headerAndRows, typeHints); if (metrics) { newSpec = deepSet(newSpec, 'spec.dataSchema.metricsSpec', metrics); } } else { - newSpec = deepSet(newSpec, 'spec.dataSchema.granularitySpec.queryGranularity', 'NONE'); + newSpec = deepSet(newSpec, 'spec.dataSchema.granularitySpec.queryGranularity', 'none'); newSpec = deepDelete(newSpec, 'spec.dataSchema.metricsSpec'); } diff --git a/web-console/src/druid-models/timestamp-spec.tsx b/web-console/src/druid-models/timestamp-spec.tsx index 8e17d20dbbce..b6c595b17dab 100644 --- a/web-console/src/druid-models/timestamp-spec.tsx +++ b/web-console/src/druid-models/timestamp-spec.tsx @@ -123,7 +123,7 @@ export const TIMESTAMP_SPEC_FIELDS: Field[] = [ ], info: (

- Please specify your timestamp format by using the suggestions menu or typing in a{' '} + Specify your timestamp format by using the suggestions menu or typing in a{' '} format string @@ -135,7 +135,10 @@ export const TIMESTAMP_SPEC_FIELDS: Field[] = [ name: 'missingValue', type: 'string', placeholder: '(optional)', - info:

This value will be used if the specified column can not be found.

, + info: ( +

Specify a static value for cases when the source time column is missing or is null.

+ ), + suggestions: ['2020-01-01T00:00:00Z'], }, ]; diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx index 4db8286bf532..380bc976f437 100644 --- a/web-console/src/views/load-data-view/load-data-view.tsx +++ b/web-console/src/views/load-data-view/load-data-view.tsx @@ -2419,7 +2419,20 @@ export class LoadDataView extends React.PureComponent This granularity determines how timestamps will be truncated (not at all, to From 6727c44f0195568fe32d95e952e7e1e31b0a9fd7 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Wed, 4 Nov 2020 18:05:49 -0800 Subject: [PATCH 02/13] keep tables live --- web-console/src/utils/query-manager.tsx | 3 + web-console/src/utils/query-state.ts | 15 +- .../views/load-data-view/load-data-view.tsx | 305 ++++++++++-------- .../src/views/query-view/query-view.tsx | 5 +- 4 files changed, 193 insertions(+), 135 deletions(-) diff --git a/web-console/src/utils/query-manager.tsx b/web-console/src/utils/query-manager.tsx index 906c7b6bd27f..97a239ebe35e 100644 --- a/web-console/src/utils/query-manager.tsx +++ b/web-console/src/utils/query-manager.tsx @@ -95,6 +95,7 @@ export class QueryManager { this.setState( new QueryState({ data, + lastData: this.state.getSomeData(), }), ); }, @@ -107,6 +108,7 @@ export class QueryManager { this.setState( new QueryState({ error: e, + lastData: this.state.getSomeData(), }), ); }, @@ -119,6 +121,7 @@ export class QueryManager { this.setState( new QueryState({ loading: true, + lastData: this.state.getSomeData(), }), ); diff --git a/web-console/src/utils/query-state.ts b/web-console/src/utils/query-state.ts index e3eeaf2e9ce2..ecbcd020554b 100644 --- a/web-console/src/utils/query-state.ts +++ b/web-console/src/utils/query-state.ts @@ -18,6 +18,13 @@ export type QueryStateState = 'init' | 'loading' | 'data' | 'error'; +export interface QueryStateOptions { + loading?: boolean; + error?: E; + data?: T; + lastData?: T; +} + export class QueryState { static INIT: QueryState = new QueryState({}); static LOADING: QueryState = new QueryState({ loading: true }); @@ -25,8 +32,9 @@ export class QueryState { public state: QueryStateState = 'init'; public error?: E; public data?: T; + public lastData?: T; - constructor(opts: { loading?: boolean; error?: E; data?: T }) { + constructor(opts: QueryStateOptions) { const hasData = typeof opts.data !== 'undefined'; if (typeof opts.error !== 'undefined') { if (hasData) { @@ -43,6 +51,7 @@ export class QueryState { this.state = opts.loading ? 'loading' : 'init'; } } + this.lastData = opts.lastData; } isInit(): boolean { @@ -71,4 +80,8 @@ export class QueryState { const { data } = this; return Boolean(data && Array.isArray(data) && data.length === 0); } + + getSomeData(): T | undefined { + return this.data || this.lastData; + } } diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx index 380bc976f437..66bff62c5af9 100644 --- a/web-console/src/views/load-data-view/load-data-view.tsx +++ b/web-console/src/views/load-data-view/load-data-view.tsx @@ -1273,32 +1273,35 @@ export class LoadDataView extends React.PureComponent ({ + parserQueryState: initRun + ? QueryState.INIT + : new QueryState({ error: new Error(issue), lastData: parserQueryState.getSomeData() }), + })); return; } - this.setState({ - parserQueryState: new QueryState({ loading: true }), - }); + this.setState(({ parserQueryState }) => ({ + parserQueryState: new QueryState({ loading: true, lastData: parserQueryState.getSomeData() }), + })); let sampleResponse: SampleResponse; try { sampleResponse = await sampleForParser(spec, sampleStrategy); } catch (e) { - this.setState({ - parserQueryState: new QueryState({ error: e }), - }); + this.setState(({ parserQueryState }) => ({ + parserQueryState: new QueryState({ error: e, lastData: parserQueryState.getSomeData() }), + })); return; } - this.setState({ + this.setState(({ parserQueryState }) => ({ cacheRows: getCacheRowsFromSampleResponse(sampleResponse), parserQueryState: new QueryState({ data: headerAndRowsFromSampleResponse(sampleResponse, '__time', inputFormatColumns), + lastData: parserQueryState.getSomeData(), }), - }); + })); } renderParserStep() { @@ -1322,11 +1325,8 @@ export class LoadDataView extends React.PureComponent ); - } else if (parserQueryState.isLoading()) { - mainFill = ; - } else if (parserQueryState.error) { - mainFill = {`Error: ${parserQueryState.getErrorMessage()}`}; - } else if (parserQueryState.data) { + } else { + const data = parserQueryState.getSomeData(); mainFill = (
@@ -1344,14 +1344,20 @@ export class LoadDataView extends React.PureComponent )}
- + {data && ( + + )} + {parserQueryState.isLoading() && } + {parserQueryState.error && ( + {`Error: ${parserQueryState.getErrorMessage()}`} + )}
); } @@ -1541,29 +1547,38 @@ export class LoadDataView extends React.PureComponent ({ timestampQueryState: initRun ? QueryState.INIT - : new QueryState({ error: new Error('must complete parse step') }), - }); + : new QueryState({ + error: new Error('must complete parse step'), + lastData: timestampQueryState.getSomeData(), + }), + })); return; } - this.setState({ - timestampQueryState: new QueryState({ loading: true }), - }); + this.setState(({ timestampQueryState }) => ({ + timestampQueryState: new QueryState({ + loading: true, + lastData: timestampQueryState.getSomeData(), + }), + })); let sampleResponse: SampleResponse; try { sampleResponse = await sampleForTimestamp(spec, cacheRows); } catch (e) { - this.setState({ - timestampQueryState: new QueryState({ error: e }), - }); + this.setState(({ timestampQueryState }) => ({ + timestampQueryState: new QueryState({ + error: e, + lastData: timestampQueryState.getSomeData(), + }), + })); return; } - this.setState({ + this.setState(({ timestampQueryState }) => ({ timestampQueryState: new QueryState({ data: { headerAndRows: headerAndRowsFromSampleResponse( @@ -1573,8 +1588,9 @@ export class LoadDataView extends React.PureComponent ); - } else if (timestampQueryState.isLoading()) { - mainFill = ; - } else if (timestampQueryState.error) { - mainFill = {`Error: ${timestampQueryState.getErrorMessage()}`}; - } else if (timestampQueryState.data) { + } else { + const data = timestampQueryState.getSomeData(); mainFill = (
@@ -1612,16 +1625,22 @@ export class LoadDataView extends React.PureComponent this.setState({ specialColumnsOnly: !specialColumnsOnly })} />
- + {data && ( + + )} + {timestampQueryState.isLoading() && } + {timestampQueryState.error && ( + {`Error: ${timestampQueryState.getErrorMessage()}`} + )}
); } @@ -1736,37 +1755,47 @@ export class LoadDataView extends React.PureComponent ({ transformQueryState: initRun ? QueryState.INIT - : new QueryState({ error: new Error('must complete parse step') }), - }); + : new QueryState({ + error: new Error('must complete parse step'), + lastData: transformQueryState.getSomeData(), + }), + })); return; } - this.setState({ - transformQueryState: new QueryState({ loading: true }), - }); + this.setState(({ transformQueryState }) => ({ + transformQueryState: new QueryState({ + loading: true, + lastData: transformQueryState.getSomeData(), + }), + })); let sampleResponse: SampleResponse; try { sampleResponse = await sampleForTransform(spec, cacheRows); } catch (e) { - this.setState({ - transformQueryState: new QueryState({ error: e }), - }); + this.setState(({ transformQueryState }) => ({ + transformQueryState: new QueryState({ + error: e, + lastData: transformQueryState.getSomeData(), + }), + })); return; } - this.setState({ + this.setState(({ transformQueryState }) => ({ transformQueryState: new QueryState({ data: headerAndRowsFromSampleResponse( sampleResponse, undefined, ['__time'].concat(inputFormatColumns), ), + lastData: transformQueryState.getSomeData(), }), - }); + })); } renderTransformStep() { @@ -1784,11 +1813,8 @@ export class LoadDataView extends React.PureComponent{`Please fill in the previous steps`}; - } else if (transformQueryState.isLoading()) { - mainFill = ; - } else if (transformQueryState.error) { - mainFill = {`Error: ${transformQueryState.getErrorMessage()}`}; - } else if (transformQueryState.data) { + } else { + const data = transformQueryState.getSomeData(); mainFill = (
@@ -1804,17 +1830,20 @@ export class LoadDataView extends React.PureComponent
- + {data && ( + + )} + {transformQueryState.isLoading() && } + {transformQueryState.error && ( + {`Error: ${transformQueryState.getErrorMessage()}`} + )}
); } @@ -1951,30 +1980,33 @@ export class LoadDataView extends React.PureComponent ({ filterQueryState: initRun ? QueryState.INIT - : new QueryState({ error: new Error('must complete parse step') }), - }); + : new QueryState({ + error: new Error('must complete parse step'), + lastData: filterQueryState.getSomeData(), + }), + })); return; } - this.setState({ - filterQueryState: new QueryState({ loading: true }), - }); + this.setState(({ filterQueryState }) => ({ + filterQueryState: new QueryState({ loading: true, lastData: filterQueryState.getSomeData() }), + })); let sampleResponse: SampleResponse; try { sampleResponse = await sampleForFilter(spec, cacheRows); } catch (e) { - this.setState({ - filterQueryState: new QueryState({ error: e }), - }); + this.setState(({ filterQueryState }) => ({ + filterQueryState: new QueryState({ error: e, lastData: filterQueryState.getSomeData() }), + })); return; } if (sampleResponse.data.length) { - this.setState({ + this.setState(({ filterQueryState }) => ({ filterQueryState: new QueryState({ data: headerAndRowsFromSampleResponse( sampleResponse, @@ -1982,8 +2014,9 @@ export class LoadDataView extends React.PureComponent ({ + filterQueryState: new QueryState({ error: e, lastData: filterQueryState.getSomeData() }), + })); return; } @@ -2006,12 +2039,13 @@ export class LoadDataView extends React.PureComponent ({ // cacheRows: sampleResponseNoFilter.cacheKey, filterQueryState: new QueryState({ data: deepSet(headerAndRowsNoFilter, 'rows', []), + lastData: filterQueryState.getSomeData(), }), - }); + })); } private getMemoizedDimensionFiltersFromSpec = memoize(spec => { @@ -2026,11 +2060,8 @@ export class LoadDataView extends React.PureComponentPlease enter more details for the previous steps; - } else if (filterQueryState.isLoading()) { - mainFill = ; - } else if (filterQueryState.error) { - mainFill = {`Error: ${filterQueryState.getErrorMessage()}`}; - } else if (filterQueryState.data) { + } else { + const data = filterQueryState.getSomeData(); mainFill = (
@@ -2040,17 +2071,20 @@ export class LoadDataView extends React.PureComponent
- + {data && ( + + )} + {filterQueryState.isLoading() && } + {filterQueryState.error && ( + {`Error: ${filterQueryState.getErrorMessage()}`} + )}
); } @@ -2233,29 +2267,32 @@ export class LoadDataView extends React.PureComponent ({ schemaQueryState: initRun ? QueryState.INIT - : new QueryState({ error: new Error('must complete parse step') }), - }); + : new QueryState({ + error: new Error('must complete parse step'), + lastData: schemaQueryState.getSomeData(), + }), + })); return; } - this.setState({ - schemaQueryState: new QueryState({ loading: true }), - }); + this.setState(({ schemaQueryState }) => ({ + schemaQueryState: new QueryState({ loading: true, lastData: schemaQueryState.getSomeData() }), + })); let sampleResponse: SampleResponse; try { sampleResponse = await sampleForSchema(spec, cacheRows); } catch (e) { - this.setState({ - schemaQueryState: new QueryState({ error: e }), - }); + this.setState(({ schemaQueryState }) => ({ + schemaQueryState: new QueryState({ error: e, lastData: schemaQueryState.getSomeData() }), + })); return; } - this.setState({ + this.setState(({ schemaQueryState }) => ({ schemaQueryState: new QueryState({ data: { headerAndRows: headerAndRowsFromSampleResponse( @@ -2266,8 +2303,9 @@ export class LoadDataView extends React.PureComponentPlease enter more details for the previous steps; - } else if (schemaQueryState.isLoading()) { - mainFill = ; - } else if (schemaQueryState.error) { - mainFill = {`Error: ${schemaQueryState.getErrorMessage()}`}; - } else if (schemaQueryState.data) { + } else { + const data = schemaQueryState.getSomeData(); mainFill = (
@@ -2301,13 +2336,19 @@ export class LoadDataView extends React.PureComponent
- + {data && ( + + )} + {schemaQueryState.isLoading() && } + {schemaQueryState.error && ( + {`Error: ${schemaQueryState.getErrorMessage()}`} + )}
); } diff --git a/web-console/src/views/query-view/query-view.tsx b/web-console/src/views/query-view/query-view.tsx index c44a3d3858b4..4cb2a2ff7c12 100644 --- a/web-console/src/views/query-view/query-view.tsx +++ b/web-console/src/views/query-view/query-view.tsx @@ -459,6 +459,7 @@ export class QueryView extends React.PureComponent
- {queryResult && ( + {someQueryResult && ( )} From f8571aba080122d097858f47298c319ea139d3da Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Thu, 5 Nov 2020 17:04:06 -0800 Subject: [PATCH 03/13] advanced --- .../src/components/auto-form/auto-form.tsx | 50 ++++- .../src/druid-models/ingestion-spec.tsx | 50 +++++ .../views/load-data-view/info-messages.tsx | 196 ++++++++++++++++++ .../views/load-data-view/load-data-view.tsx | 173 +++++----------- 4 files changed, 339 insertions(+), 130 deletions(-) create mode 100644 web-console/src/views/load-data-view/info-messages.tsx diff --git a/web-console/src/components/auto-form/auto-form.tsx b/web-console/src/components/auto-form/auto-form.tsx index 6ae9e4b3b4d6..88586ac80a1d 100644 --- a/web-console/src/components/auto-form/auto-form.tsx +++ b/web-console/src/components/auto-form/auto-form.tsx @@ -17,6 +17,7 @@ */ import { Button, ButtonGroup, FormGroup, Intent, NumericInput } from '@blueprintjs/core'; +import { IconNames } from '@blueprintjs/icons'; import React from 'react'; import { deepDelete, deepGet, deepSet } from '../../utils'; @@ -54,6 +55,7 @@ export interface Field { disabled?: Functor; defined?: Functor; required?: Functor; + advanced?: Functor; adjustment?: (model: M) => M; issueWithValue?: (value: any) => string | undefined; } @@ -68,7 +70,14 @@ export interface AutoFormProps { globalAdjustment?: (model: M) => M; } -export class AutoForm> extends React.PureComponent> { +export interface AutoFormState { + showAdvanced: boolean; +} + +export class AutoForm> extends React.PureComponent< + AutoFormProps, + AutoFormState +> { static REQUIRED_INTENT = Intent.PRIMARY; static makeLabelName(label: string): string { @@ -138,7 +147,9 @@ export class AutoForm> extends React.PureComponent constructor(props: AutoFormProps) { super(props); - this.state = {}; + this.state = { + showAdvanced: false, + }; } private fieldChange = (field: Field, newValue: any) => { @@ -391,7 +402,6 @@ export class AutoForm> extends React.PureComponent private renderField = (field: Field) => { const { model } = this.props; if (!model) return; - if (!AutoForm.evaluateFunctor(field.defined, model, true)) return; const label = field.label || AutoForm.makeLabelName(field.name); return ( @@ -415,12 +425,44 @@ export class AutoForm> extends React.PureComponent ); } + renderAdvanced() { + const { showAdvanced } = this.state; + + return ( + +