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 2021/05/13 05:24:15 UTC

[druid] branch 0.21.1 updated: Fix required field treatment (#11228) (#11237)

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

cwylie pushed a commit to branch 0.21.1
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/0.21.1 by this push:
     new 5d6f141  Fix required field treatment (#11228) (#11237)
5d6f141 is described below

commit 5d6f141d71ca74a3eb2e0f02ce01bfba1e53b2f0
Author: Clint Wylie <cw...@apache.org>
AuthorDate: Wed May 12 22:23:27 2021 -0700

    Fix required field treatment (#11228) (#11237)
    
    Co-authored-by: Vadim Ogievetsky <va...@ogievetsky.com>
---
 .../__snapshots__/auto-form.spec.tsx.snap          | 66 +++++++++++++++------
 .../src/components/auto-form/auto-form.spec.tsx    | 28 ++++++---
 web-console/src/components/auto-form/auto-form.tsx | 69 +++++++++++-----------
 web-console/src/druid-models/ingestion-spec.tsx    |  1 -
 web-console/src/druid-models/timestamp-spec.tsx    |  1 -
 .../src/views/load-data-view/load-data-view.tsx    | 15 +++--
 6 files changed, 113 insertions(+), 67 deletions(-)

diff --git a/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap b/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap
index 02a63a1..0e28a10 100644
--- a/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap
+++ b/web-console/src/components/auto-form/__snapshots__/auto-form.spec.tsx.snap
@@ -5,8 +5,8 @@ exports[`AutoForm matches snapshot 1`] = `
   className="auto-form"
 >
   <Memo(FormGroupWithInfo)
-    key="testOne"
-    label="Test one"
+    key="testNumber"
+    label="Test number"
   >
     <Memo(NumericInputWithDefault)
       disabled={false}
@@ -18,8 +18,8 @@ exports[`AutoForm matches snapshot 1`] = `
     />
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testTwo"
-    label="Test two"
+    key="testSizeBytes"
+    label="Test size bytes"
   >
     <Blueprint3.NumericInput
       allowNumericCharactersOnly={true}
@@ -40,8 +40,8 @@ exports[`AutoForm matches snapshot 1`] = `
     />
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testThree"
-    label="Test three"
+    key="testString"
+    label="Test string"
   >
     <Memo(SuggestibleInput)
       disabled={false}
@@ -52,8 +52,20 @@ exports[`AutoForm matches snapshot 1`] = `
     />
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testFour"
-    label="Test four"
+    key="testStringWithDefault"
+    label="Test string with default"
+  >
+    <Memo(SuggestibleInput)
+      disabled={false}
+      onBlur={[Function]}
+      onValueChange={[Function]}
+      placeholder=""
+      value="Hello World"
+    />
+  </Memo(FormGroupWithInfo)>
+  <Memo(FormGroupWithInfo)
+    key="testBoolean"
+    label="Test boolean"
   >
     <Blueprint3.ButtonGroup>
       <Blueprint3.Button
@@ -73,8 +85,8 @@ exports[`AutoForm matches snapshot 1`] = `
     </Blueprint3.ButtonGroup>
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testFourWithDefault"
-    label="Test four with default"
+    key="testBooleanWithDefault"
+    label="Test boolean with default"
   >
     <Blueprint3.ButtonGroup>
       <Blueprint3.Button
@@ -94,8 +106,8 @@ exports[`AutoForm matches snapshot 1`] = `
     </Blueprint3.ButtonGroup>
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testFive"
-    label="Test five"
+    key="testStringArray"
+    label="Test string array"
   >
     <Memo(ArrayInput)
       disabled={false}
@@ -105,23 +117,43 @@ exports[`AutoForm matches snapshot 1`] = `
     />
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testSix"
-    label="Test six"
+    key="testStringArrayWithDefault"
+    label="Test string array with default"
   >
-    <Memo(JsonInput)
+    <Memo(ArrayInput)
+      disabled={false}
       onChange={[Function]}
       placeholder=""
+      values={
+        Array [
+          "Hello",
+          "World",
+        ]
+      }
     />
   </Memo(FormGroupWithInfo)>
   <Memo(FormGroupWithInfo)
-    key="testSeven"
-    label="Test seven"
+    key="testJson"
+    label="Test json"
   >
     <Memo(JsonInput)
       onChange={[Function]}
       placeholder=""
     />
   </Memo(FormGroupWithInfo)>
+  <Memo(FormGroupWithInfo)
+    key="testStringRequiredAndDefaultValue"
+    label="Test string required and default value"
+  >
+    <Memo(SuggestibleInput)
+      disabled={false}
+      intent="primary"
+      onBlur={[Function]}
+      onValueChange={[Function]}
+      placeholder=""
+      value=""
+    />
+  </Memo(FormGroupWithInfo)>
   <Blueprint3.FormGroup
     key="more-or-less"
   >
diff --git a/web-console/src/components/auto-form/auto-form.spec.tsx b/web-console/src/components/auto-form/auto-form.spec.tsx
index d0e6c41..c239130 100644
--- a/web-console/src/components/auto-form/auto-form.spec.tsx
+++ b/web-console/src/components/auto-form/auto-form.spec.tsx
@@ -28,14 +28,26 @@ describe('AutoForm', () => {
     const autoForm = shallow(
       <AutoForm
         fields={[
-          { name: 'testOne', type: 'number' },
-          { name: 'testTwo', type: 'size-bytes' },
-          { name: 'testThree', type: 'string' },
-          { name: 'testFour', type: 'boolean' },
-          { name: 'testFourWithDefault', type: 'boolean', defaultValue: false },
-          { name: 'testFive', type: 'string-array' },
-          { name: 'testSix', type: 'json' },
-          { name: 'testSeven', type: 'json' },
+          { name: 'testNumber', type: 'number' },
+          { name: 'testSizeBytes', type: 'size-bytes' },
+          { name: 'testString', type: 'string' },
+          { name: 'testStringWithDefault', type: 'string', defaultValue: 'Hello World' },
+          { name: 'testBoolean', type: 'boolean' },
+          { name: 'testBooleanWithDefault', type: 'boolean', defaultValue: false },
+          { name: 'testStringArray', type: 'string-array' },
+          {
+            name: 'testStringArrayWithDefault',
+            type: 'string-array',
+            defaultValue: ['Hello', 'World'],
+          },
+          { name: 'testJson', type: 'json' },
+
+          {
+            name: 'testStringRequiredAndDefaultValue',
+            type: 'string',
+            defaultValue: 'hello',
+            required: () => true,
+          },
 
           { name: 'testNotDefined', type: 'string', defined: false },
           { name: 'testAdvanced', type: 'string', hideInMore: true },
diff --git a/web-console/src/components/auto-form/auto-form.tsx b/web-console/src/components/auto-form/auto-form.tsx
index 32dc874..86c44b8 100644
--- a/web-console/src/components/auto-form/auto-form.tsx
+++ b/web-console/src/components/auto-form/auto-form.tsx
@@ -62,6 +62,12 @@ export interface Field<M> {
   issueWithValue?: (value: any) => string | undefined;
 }
 
+interface ComputedFieldValues {
+  required: boolean;
+  defaultValue?: any;
+  modelValue: any;
+}
+
 export interface AutoFormProps<M> {
   fields: Field<M>[];
   model: M | undefined;
@@ -93,6 +99,15 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
     return newLabel;
   }
 
+  static computeFieldValues<M>(model: M | undefined, field: Field<M>): ComputedFieldValues {
+    const required = AutoForm.evaluateFunctor(field.required, model, false);
+    return {
+      required,
+      defaultValue: required ? undefined : field.defaultValue,
+      modelValue: deepGet(model as any, field.name),
+    };
+  }
+
   static evaluateFunctor<M, R>(
     functor: undefined | Functor<M, R>,
     model: M | undefined,
@@ -204,12 +219,12 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
 
   private renderNumberInput(field: Field<T>): JSX.Element {
     const { model, large, onFinalize } = this.props;
+    const { required, defaultValue, modelValue } = AutoForm.computeFieldValues(model, field);
 
-    const modelValue = deepGet(model as any, field.name);
     return (
       <NumericInputWithDefault
         value={modelValue}
-        defaultValue={field.defaultValue}
+        defaultValue={defaultValue}
         onValueChange={(valueAsNumber: number, valueAsString: string) => {
           let newValue: number | undefined;
           if (valueAsString !== '' && !isNaN(valueAsNumber)) {
@@ -228,21 +243,18 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
         large={large}
         disabled={AutoForm.evaluateFunctor(field.disabled, model, false)}
         placeholder={AutoForm.evaluateFunctor(field.placeholder, model, '')}
-        intent={
-          AutoForm.evaluateFunctor(field.required, model, false) && modelValue == null
-            ? AutoForm.REQUIRED_INTENT
-            : undefined
-        }
+        intent={required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined}
       />
     );
   }
 
   private renderSizeBytesInput(field: Field<T>): JSX.Element {
     const { model, large, onFinalize } = this.props;
+    const { required, defaultValue, modelValue } = AutoForm.computeFieldValues(model, field);
 
     return (
       <NumericInput
-        value={deepGet(model as any, field.name) || field.defaultValue}
+        value={modelValue || defaultValue}
         onValueChange={(v: number) => {
           if (isNaN(v)) return;
           this.fieldChange(field, v);
@@ -256,17 +268,18 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
         fill
         large={large}
         disabled={AutoForm.evaluateFunctor(field.disabled, model, false)}
+        intent={required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined}
       />
     );
   }
 
   private renderStringInput(field: Field<T>, sanitize?: (str: string) => string): JSX.Element {
     const { model, large, onFinalize } = this.props;
+    const { required, defaultValue, modelValue } = AutoForm.computeFieldValues(model, field);
 
-    const modelValue = deepGet(model as any, field.name);
     return (
       <SuggestibleInput
-        value={modelValue != null ? modelValue : field.defaultValue || ''}
+        value={modelValue != null ? modelValue : defaultValue || ''}
         onValueChange={v => {
           if (sanitize && typeof v === 'string') v = sanitize(v);
           this.fieldChange(field, v);
@@ -279,24 +292,17 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
         suggestions={AutoForm.evaluateFunctor(field.suggestions, model, undefined)}
         large={large}
         disabled={AutoForm.evaluateFunctor(field.disabled, model, false)}
-        intent={
-          AutoForm.evaluateFunctor(field.required, model, false) && modelValue == null
-            ? AutoForm.REQUIRED_INTENT
-            : undefined
-        }
+        intent={required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined}
       />
     );
   }
 
   private renderBooleanInput(field: Field<T>): JSX.Element {
     const { model, large, onFinalize } = this.props;
-    const modelValue = deepGet(model as any, field.name);
-    const shownValue = modelValue == null ? field.defaultValue : modelValue;
+    const { required, defaultValue, modelValue } = AutoForm.computeFieldValues(model, field);
+    const shownValue = modelValue == null ? defaultValue : modelValue;
     const disabled = AutoForm.evaluateFunctor(field.disabled, model, false);
-    const intent =
-      AutoForm.evaluateFunctor(field.required, model, false) && modelValue == null
-        ? AutoForm.REQUIRED_INTENT
-        : undefined;
+    const intent = required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined;
 
     return (
       <ButtonGroup large={large}>
@@ -342,41 +348,34 @@ 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);
+    const { required, defaultValue, modelValue } = AutoForm.computeFieldValues(model, field);
+
     return (
       <ArrayInput
-        values={modelValue || []}
+        values={modelValue || defaultValue || []}
         onChange={(v: any) => {
           this.fieldChange(field, v);
         }}
         placeholder={AutoForm.evaluateFunctor(field.placeholder, model, '')}
         large={large}
         disabled={AutoForm.evaluateFunctor(field.disabled, model, false)}
-        intent={
-          AutoForm.evaluateFunctor(field.required, model, false) && modelValue == null
-            ? AutoForm.REQUIRED_INTENT
-            : undefined
-        }
+        intent={required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined}
       />
     );
   }
 
   private renderIntervalInput(field: Field<T>): JSX.Element {
     const { model } = this.props;
+    const { required, defaultValue, modelValue } = AutoForm.computeFieldValues(model, field);
 
-    const modelValue = deepGet(model as any, field.name);
     return (
       <IntervalInput
-        interval={modelValue != null ? modelValue : field.defaultValue || ''}
+        interval={modelValue != null ? modelValue : defaultValue || ''}
         onValueChange={(v: any) => {
           this.fieldChange(field, v);
         }}
         placeholder={AutoForm.evaluateFunctor(field.placeholder, model, '')}
-        intent={
-          AutoForm.evaluateFunctor(field.required, model, false) && modelValue == null
-            ? AutoForm.REQUIRED_INTENT
-            : undefined
-        }
+        intent={required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined}
       />
     );
   }
diff --git a/web-console/src/druid-models/ingestion-spec.tsx b/web-console/src/druid-models/ingestion-spec.tsx
index d4c9bdc..b963f31 100644
--- a/web-console/src/druid-models/ingestion-spec.tsx
+++ b/web-console/src/druid-models/ingestion-spec.tsx
@@ -908,7 +908,6 @@ export function getIoConfigFormFields(ingestionComboType: IngestionComboType): F
             'kinesis.us-gov-east-1.amazonaws.com',
             'kinesis.us-gov-west-1.amazonaws.com',
           ],
-          required: true,
           info: (
             <>
               The Amazon Kinesis stream endpoint for a region. You can find a list of endpoints{' '}
diff --git a/web-console/src/druid-models/timestamp-spec.tsx b/web-console/src/druid-models/timestamp-spec.tsx
index b6c595b..01fcfd3 100644
--- a/web-console/src/druid-models/timestamp-spec.tsx
+++ b/web-console/src/druid-models/timestamp-spec.tsx
@@ -100,7 +100,6 @@ export const TIMESTAMP_SPEC_FIELDS: Field<TimestampSpec>[] = [
     name: 'column',
     type: 'string',
     defaultValue: 'timestamp',
-    required: true,
   },
   {
     name: 'format',
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 783b448..daf79a3 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
@@ -706,7 +706,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     comboType: IngestionComboTypeWithExtra,
     disabled?: boolean,
   ): JSX.Element | undefined {
-    const { overlordModules, selectedComboType } = this.state;
+    const { overlordModules, selectedComboType, spec } = this.state;
     if (!overlordModules) return;
     const requiredModule = getRequiredModule(comboType);
     const goodToGo = !disabled && (!requiredModule || overlordModules.includes(requiredModule));
@@ -716,10 +716,15 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
         className={classNames({ disabled: !goodToGo, active: selectedComboType === comboType })}
         interactive
         elevation={1}
-        onClick={() => {
-          this.setState({
-            selectedComboType: selectedComboType !== comboType ? comboType : undefined,
-          });
+        onClick={e => {
+          if (e.altKey && e.shiftKey) {
+            this.updateSpec(updateIngestionType(spec, comboType as any));
+            this.updateStep('connect');
+          } else {
+            this.setState({
+              selectedComboType: selectedComboType !== comboType ? comboType : undefined,
+            });
+          }
         }}
       >
         <img

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