You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by cw...@apache.org on 2019/09/12 09:42:44 UTC

[incubator-druid] branch 0.16.0-incubating updated: Web console: Force intervals config (#8514) (#8521)

This is an automated email from the ASF dual-hosted git repository.

cwylie pushed a commit to branch 0.16.0-incubating
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git


The following commit(s) were added to refs/heads/0.16.0-incubating by this push:
     new eb75cb8  Web console: Force intervals config (#8514) (#8521)
eb75cb8 is described below

commit eb75cb8a9d1f41c969ec0ad709a293521dceb77a
Author: Clint Wylie <cw...@apache.org>
AuthorDate: Thu Sep 12 02:42:34 2019 -0700

    Web console: Force intervals config (#8514) (#8521)
    
    * make sure intervals are required
    
    * all truncated values everywhere
    
    * continue to spec when going from tasks table
    
    * remove unused thigns
    
    * fix alert
---
 .../src/components/array-input/array-input.tsx     |  6 ++-
 web-console/src/components/auto-form/auto-form.tsx |  8 ++-
 .../src/components/table-cell/table-cell.tsx       | 60 ++++++++++++++--------
 web-console/src/utils/ingestion-spec.tsx           |  6 +--
 .../src/views/load-data-view/load-data-view.tsx    | 39 ++++++++------
 .../parse-data-table/parse-data-table.spec.tsx     |  1 -
 .../parse-data-table/parse-data-table.tsx          |  3 +-
 7 files changed, 75 insertions(+), 48 deletions(-)

diff --git a/web-console/src/components/array-input/array-input.tsx b/web-console/src/components/array-input/array-input.tsx
index 5411f6f..de4fbd0 100644
--- a/web-console/src/components/array-input/array-input.tsx
+++ b/web-console/src/components/array-input/array-input.tsx
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import { TextArea } from '@blueprintjs/core';
+import { Intent, TextArea } from '@blueprintjs/core';
 import React from 'react';
 
 import { compact } from '../../utils';
@@ -28,6 +28,7 @@ export interface ArrayInputProps {
   placeholder?: string;
   large?: boolean;
   disabled?: boolean;
+  intent?: Intent;
 }
 
 export class ArrayInput extends React.PureComponent<ArrayInputProps, { stringValue: string }> {
@@ -51,7 +52,7 @@ export class ArrayInput extends React.PureComponent<ArrayInputProps, { stringVal
   };
 
   render(): JSX.Element {
-    const { className, placeholder, large, disabled } = this.props;
+    const { className, placeholder, large, disabled, intent } = this.props;
     const { stringValue } = this.state;
     return (
       <TextArea
@@ -61,6 +62,7 @@ export class ArrayInput extends React.PureComponent<ArrayInputProps, { stringVal
         placeholder={placeholder}
         large={large}
         disabled={disabled}
+        intent={intent}
         fill
       />
     );
diff --git a/web-console/src/components/auto-form/auto-form.tsx b/web-console/src/components/auto-form/auto-form.tsx
index 15c3f51..4ff5856 100644
--- a/web-console/src/components/auto-form/auto-form.tsx
+++ b/web-console/src/components/auto-form/auto-form.tsx
@@ -244,15 +244,21 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
 
   private renderStringArrayInput(field: Field<T>): JSX.Element {
     const { model, large } = this.props;
+    const modelValue = deepGet(model as any, field.name);
     return (
       <ArrayInput
-        values={deepGet(model as any, field.name) || []}
+        values={modelValue || []}
         onChange={(v: any) => {
           this.fieldChange(field, v);
         }}
         placeholder={field.placeholder}
         large={large}
         disabled={AutoForm.evaluateFunctor(field.disabled, model)}
+        intent={
+          AutoForm.evaluateFunctor(field.required, model) && modelValue == null
+            ? Intent.PRIMARY
+            : undefined
+        }
       />
     );
   }
diff --git a/web-console/src/components/table-cell/table-cell.tsx b/web-console/src/components/table-cell/table-cell.tsx
index 5a6b535..8d019fe 100644
--- a/web-console/src/components/table-cell/table-cell.tsx
+++ b/web-console/src/components/table-cell/table-cell.tsx
@@ -19,15 +19,19 @@
 import { IconNames } from '@blueprintjs/icons';
 import React from 'react';
 
+import { ShowValueDialog } from '../../dialogs/show-value-dialog/show-value-dialog';
 import { ActionIcon } from '../action-icon/action-icon';
 
 import './table-cell.scss';
 
-export interface NullTableCellProps {
+export interface TableCellProps {
   value?: any;
   timestamp?: boolean;
   unparseable?: boolean;
-  openModal?: (str: string) => void;
+}
+
+export interface TableCellState {
+  showValue?: string;
 }
 
 interface ShortParts {
@@ -36,26 +40,9 @@ interface ShortParts {
   suffix: string;
 }
 
-export class TableCell extends React.PureComponent<NullTableCellProps> {
+export class TableCell extends React.PureComponent<TableCellProps, TableCellState> {
   static MAX_CHARS_TO_SHOW = 50;
 
-  possiblyTruncate(str: string): React.ReactNode {
-    if (str.length <= TableCell.MAX_CHARS_TO_SHOW) return str;
-
-    const { prefix, omitted, suffix } = TableCell.shortenString(str);
-    return (
-      <span className="table-cell truncated">
-        {prefix}
-        <span className="omitted">{omitted}</span>
-        {suffix}
-        <ActionIcon
-          icon={IconNames.MORE}
-          onClick={() => (this.props.openModal ? this.props.openModal(str) : null)}
-        />
-      </span>
-    );
-  }
-
   static shortenString(str: string): ShortParts {
     // Print something like:
     // BAAAArAAEiQKpDAEAACwZCBAGSBgiSEAAAAQpAIDwAg...23 omitted...gwiRoQBJIC
@@ -69,6 +56,35 @@ export class TableCell extends React.PureComponent<NullTableCellProps> {
     };
   }
 
+  constructor(props: TableCellProps) {
+    super(props);
+    this.state = {};
+  }
+
+  private renderShowValueDialog(): JSX.Element | undefined {
+    const { showValue } = this.state;
+    if (!showValue) return;
+
+    return (
+      <ShowValueDialog onClose={() => this.setState({ showValue: undefined })} str={showValue} />
+    );
+  }
+
+  private renderTruncated(str: string): React.ReactNode {
+    if (str.length <= TableCell.MAX_CHARS_TO_SHOW) return str;
+
+    const { prefix, omitted, suffix } = TableCell.shortenString(str);
+    return (
+      <span className="table-cell truncated">
+        {prefix}
+        <span className="omitted">{omitted}</span>
+        {suffix}
+        <ActionIcon icon={IconNames.MORE} onClick={() => this.setState({ showValue: str })} />
+        {this.renderShowValueDialog()}
+      </span>
+    );
+  }
+
   render(): React.ReactNode {
     const { value, timestamp, unparseable } = this.props;
     if (unparseable) {
@@ -81,9 +97,9 @@ export class TableCell extends React.PureComponent<NullTableCellProps> {
           </span>
         );
       } else if (Array.isArray(value)) {
-        return this.possiblyTruncate(`[${value.join(', ')}]`);
+        return this.renderTruncated(`[${value.join(', ')}]`);
       } else {
-        return this.possiblyTruncate(String(value));
+        return this.renderTruncated(String(value));
       }
     } else {
       if (timestamp) {
diff --git a/web-console/src/utils/ingestion-spec.tsx b/web-console/src/utils/ingestion-spec.tsx
index aa04bf3..952d3ba 100644
--- a/web-console/src/utils/ingestion-spec.tsx
+++ b/web-console/src/utils/ingestion-spec.tsx
@@ -588,7 +588,7 @@ export interface GranularitySpec {
   queryGranularity?: string;
   segmentGranularity?: string;
   rollup?: boolean;
-  intervals?: string;
+  intervals?: string | string[];
 }
 
 export interface MetricSpec {
@@ -1541,11 +1541,11 @@ export interface TuningConfig {
   fetchThreads?: number;
 }
 
-export function invalidTuningConfig(tuningConfig: TuningConfig): boolean {
+export function invalidTuningConfig(tuningConfig: TuningConfig, intervals: any): boolean {
   return Boolean(
     tuningConfig.type === 'index_parallel' &&
       tuningConfig.forceGuaranteedRollup &&
-      !tuningConfig.numShards,
+      (!tuningConfig.numShards || !intervals),
   );
 }
 
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 00eb64b..87e1853 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
@@ -50,7 +50,6 @@ import {
   Loader,
 } from '../../components';
 import { AsyncActionDialog } from '../../dialogs';
-import { ShowValueDialog } from '../../dialogs/show-value-dialog/show-value-dialog';
 import { AppToaster } from '../../singletons/toaster';
 import { UrlBaser } from '../../singletons/url-baser';
 import {
@@ -251,8 +250,6 @@ export interface LoadDataViewState {
   showResetConfirm: boolean;
   newRollup?: boolean;
   newDimensionMode?: DimensionMode;
-  showViewValueModal: boolean;
-  str: string;
 
   // welcome
   overlordModules?: string[];
@@ -317,8 +314,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
       // dialogs / modals
       showResetConfirm: false,
-      showViewValueModal: false,
-      str: '',
 
       // general
       sampleStrategy: 'start',
@@ -507,7 +502,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
         {step === 'loading' && this.renderLoading()}
 
         {this.renderResetConfirm()}
-        {this.renderViewValueModal()}
       </div>
     );
   }
@@ -651,15 +645,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     );
   }
 
-  renderViewValueModal(): JSX.Element | undefined {
-    const { showViewValueModal, str } = this.state;
-    if (!showViewValueModal) return;
-
-    return (
-      <ShowValueDialog onClose={() => this.setState({ showViewValueModal: false })} str={str} />
-    );
-  }
-
   renderWelcomeStepMessage(): JSX.Element | undefined {
     const { selectedComboType, exampleManifests } = this.state;
 
@@ -1225,7 +1210,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             )}
           </div>
           <ParseDataTable
-            openModal={str => this.setState({ showViewValueModal: true, str: str })}
             sampleData={parserQueryState.data}
             columnFilter={columnFilter}
             canFlatten={canFlatten}
@@ -2649,6 +2633,25 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             model={tuningConfig}
             onChange={t => this.updateSpec(deepSet(spec, 'tuningConfig', t))}
           />
+          <AutoForm
+            fields={[
+              {
+                name: 'dataSchema.granularitySpec.intervals',
+                label: 'Time intervals',
+                type: 'string-array',
+                placeholder: 'ex: 2018-01-01/2018-06-01',
+                required: s => Boolean(deepGet(s, 'tuningConfig.forceGuaranteedRollup')),
+                info: (
+                  <>
+                    A comma separated list of intervals for the raw data being ingested. Ignored for
+                    real-time ingestion.
+                  </>
+                ),
+              },
+            ]}
+            model={spec}
+            onChange={s => this.updateSpec(s)}
+          />
         </div>
         <div className="control">
           <Callout className="intro">
@@ -2658,7 +2661,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
           {this.renderParallelPickerIfNeeded()}
         </div>
         {this.renderNextBar({
-          disabled: invalidTuningConfig(tuningConfig),
+          disabled: invalidTuningConfig(tuningConfig, granularitySpec.intervals),
         })}
       </>
     );
@@ -2864,6 +2867,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     try {
       const resp = await axios.get(`/druid/indexer/v1/supervisor/${initSupervisorId}`);
       this.updateSpec(resp.data);
+      this.setState({ continueToSpec: true });
       this.updateStep('spec');
     } catch (e) {
       AppToaster.show({
@@ -2879,6 +2883,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     try {
       const resp = await axios.get(`/druid/indexer/v1/task/${initTaskId}`);
       this.updateSpec(resp.data.payload);
+      this.setState({ continueToSpec: true });
       this.updateStep('spec');
     } catch (e) {
       AppToaster.show({
diff --git a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
index 92da603..4ec2037 100644
--- a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
@@ -35,7 +35,6 @@ describe('parse data table', () => {
 
     const parseDataTable = (
       <ParseDataTable
-        openModal={() => {}}
         sampleData={sampleData}
         columnFilter=""
         canFlatten={false}
diff --git a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
index 2d00968..380eab2 100644
--- a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
@@ -34,7 +34,6 @@ export interface ParseDataTableProps {
   flattenedColumnsOnly: boolean;
   flattenFields: FlattenField[];
   onFlattenFieldSelect: (field: FlattenField, index: number) => void;
-  openModal: (str: string) => void;
 }
 
 export class ParseDataTable extends React.PureComponent<ParseDataTableProps> {
@@ -78,7 +77,7 @@ export class ParseDataTable extends React.PureComponent<ParseDataTableProps> {
               if (row.original.unparseable) {
                 return <TableCell unparseable />;
               }
-              return <TableCell value={row.value} openModal={str => this.props.openModal(str)} />;
+              return <TableCell value={row.value} />;
             },
             headerClassName: classNames({
               flattened: flattenField,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org