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

amitmiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 13d4902  feat(native-filters): select group by support (#14217)
13d4902 is described below

commit 13d490271130810d7cf0b3eafc56ba71eeba66c0
Author: Amit Miran <[email protected]>
AuthorDate: Tue Apr 20 18:52:33 2021 +0300

    feat(native-filters): select group by support (#14217)
    
    * chore: initial commit
    
    * feat: groupby filter
    
    Co-authored-by: Simcha Shats <[email protected]>
---
 .../FiltersConfigForm/FiltersConfigForm.tsx        |   7 +-
 .../components/GroupBy/GroupByFilterPlugin.tsx     |  86 +++++++++++++++++++++
 .../src/filters/components/GroupBy/buildQuery.ts   |  45 +++++++++++
 .../src/filters/components/GroupBy/controlPanel.ts |  51 ++++++++++++
 .../components/GroupBy/images/thumbnail.png        | Bin 0 -> 5658 bytes
 .../src/filters/components/{ => GroupBy}/index.ts  |  29 +++++--
 .../{index.ts => GroupBy/transformProps.ts}        |  32 ++++++--
 .../src/filters/components/GroupBy/types.ts        |  50 ++++++++++++
 superset-frontend/src/filters/components/index.ts  |   1 +
 .../src/visualizations/presets/MainPreset.js       |   2 +
 10 files changed, 292 insertions(+), 11 deletions(-)

diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index 0a9ba42..b11d356 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -79,7 +79,12 @@ export interface FiltersConfigFormProps {
   parentFilters: { id: string; title: string }[];
 }
 
-const FILTERS_WITHOUT_COLUMN = ['filter_timegrain', 'filter_timecolumn'];
+// TODO: Need to do with it something
+const FILTERS_WITHOUT_COLUMN = [
+  'filter_timegrain',
+  'filter_timecolumn',
+  'filter_groupby',
+];
 
 /**
  * The configuration form for a specific filter.
diff --git 
a/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx 
b/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx
new file mode 100644
index 0000000..3440090
--- /dev/null
+++ b/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { ensureIsArray, ExtraFormData, t, tn } from '@superset-ui/core';
+import React, { useEffect, useState } from 'react';
+import { Select } from 'src/common/components';
+import { Styles, StyledSelect } from '../common';
+import { PluginFilterGroupByProps } from './types';
+
+const { Option } = Select;
+
+export default function PluginFilterGroupBy(props: PluginFilterGroupByProps) {
+  const { data, formData, height, width, setDataMask, filterState } = props;
+  const { defaultValue, inputRef, multiSelect } = formData;
+
+  const [value, setValue] = useState<string[]>(defaultValue ?? []);
+
+  const handleChange = (value?: string[] | string | null) => {
+    const resultValue: string[] = ensureIsArray<string>(value);
+    setValue(resultValue);
+    const extraFormData: ExtraFormData = {};
+    if (resultValue.length) {
+      extraFormData.interactive_groupby = resultValue;
+    }
+
+    setDataMask({
+      filterState: { value: resultValue.length ? resultValue : null },
+      extraFormData,
+    });
+  };
+
+  useEffect(() => {
+    handleChange(filterState.value);
+  }, [JSON.stringify(filterState.value), multiSelect]);
+
+  useEffect(() => {
+    handleChange(defaultValue ?? null);
+    // I think after Config Modal update some filter it re-creates default 
value for all other filters
+    // so we can process it like this `JSON.stringify` or start to use `Immer`
+  }, [JSON.stringify(defaultValue), multiSelect]);
+
+  const columns = data || [];
+  const placeholderText =
+    columns.length === 0
+      ? t('No columns')
+      : tn('%s option', '%s options', columns.length, columns.length);
+  return (
+    <Styles height={height} width={width}>
+      <StyledSelect
+        allowClear
+        value={value}
+        placeholder={placeholderText}
+        mode={multiSelect ? 'multiple' : undefined}
+        // @ts-ignore
+        onChange={handleChange}
+        ref={inputRef}
+      >
+        {columns.map(
+          (row: { column_name: string; verbose_name: string | null }) => {
+            const { column_name: columnName, verbose_name: verboseName } = row;
+            return (
+              <Option key={columnName} value={columnName}>
+                {verboseName ?? columnName}
+              </Option>
+            );
+          },
+        )}
+      </StyledSelect>
+    </Styles>
+  );
+}
diff --git a/superset-frontend/src/filters/components/GroupBy/buildQuery.ts 
b/superset-frontend/src/filters/components/GroupBy/buildQuery.ts
new file mode 100644
index 0000000..b6ca68a
--- /dev/null
+++ b/superset-frontend/src/filters/components/GroupBy/buildQuery.ts
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { buildQueryContext, QueryFormData } from '@superset-ui/core';
+
+/**
+ * The buildQuery function is used to create an instance of QueryContext that's
+ * sent to the chart data endpoint. In addition to containing information of 
which
+ * datasource to use, it specifies the type (e.g. full payload, samples, 
query) and
+ * format (e.g. CSV or JSON) of the result and whether or not to force refresh 
the data from
+ * the datasource as opposed to using a cached copy of the data, if available.
+ *
+ * More importantly though, QueryContext contains a property `queries`, which 
is an array of
+ * QueryObjects specifying individual data requests to be made. A QueryObject 
specifies which
+ * columns, metrics and filters, among others, to use during the query. 
Usually it will be enough
+ * to specify just one query based on the baseQueryObject, but for some more 
advanced use cases
+ * it is possible to define post processing operations in the QueryObject, or 
multiple queries
+ * if a viz needs multiple different result sets.
+ */
+export default function buildQuery(formData: QueryFormData) {
+  return buildQueryContext(formData, baseQueryObject => [
+    {
+      ...baseQueryObject,
+      result_type: 'columns',
+      columns: [],
+      metrics: [],
+      orderby: [],
+    },
+  ]);
+}
diff --git a/superset-frontend/src/filters/components/GroupBy/controlPanel.ts 
b/superset-frontend/src/filters/components/GroupBy/controlPanel.ts
new file mode 100644
index 0000000..33922d0
--- /dev/null
+++ b/superset-frontend/src/filters/components/GroupBy/controlPanel.ts
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { ControlPanelConfig, sections } from '@superset-ui/chart-controls';
+import { t } from '@superset-ui/core';
+import { DEFAULT_FORM_DATA } from './types';
+
+const { multiSelect } = DEFAULT_FORM_DATA;
+
+const config: ControlPanelConfig = {
+  controlPanelSections: [
+    // @ts-ignore
+    sections.legacyRegularTime,
+    {
+      label: t('UI Configuration'),
+      expanded: true,
+      controlSetRows: [
+        [
+          {
+            name: 'multiSelect',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Multiple select'),
+              default: multiSelect,
+              resetConfig: true,
+              renderTrigger: true,
+              description: t('Allow selecting multiple values'),
+            },
+          },
+        ],
+      ],
+    },
+  ],
+};
+
+export default config;
diff --git 
a/superset-frontend/src/filters/components/GroupBy/images/thumbnail.png 
b/superset-frontend/src/filters/components/GroupBy/images/thumbnail.png
new file mode 100644
index 0000000..7afef30
Binary files /dev/null and 
b/superset-frontend/src/filters/components/GroupBy/images/thumbnail.png differ
diff --git a/superset-frontend/src/filters/components/index.ts 
b/superset-frontend/src/filters/components/GroupBy/index.ts
similarity index 53%
copy from superset-frontend/src/filters/components/index.ts
copy to superset-frontend/src/filters/components/GroupBy/index.ts
index 662b7a8..44055fa 100644
--- a/superset-frontend/src/filters/components/index.ts
+++ b/superset-frontend/src/filters/components/GroupBy/index.ts
@@ -16,8 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-export { default as SelectFilterPlugin } from './Select';
-export { default as RangeFilterPlugin } from './Range';
-export { default as TimeFilterPlugin } from './Time';
-export { default as TimeColumnFilterPlugin } from './TimeColumn';
-export { default as TimeGrainFilterPlugin } from './TimeGrain';
+import { Behavior, ChartMetadata, ChartPlugin, t } from '@superset-ui/core';
+import buildQuery from './buildQuery';
+import controlPanel from './controlPanel';
+import transformProps from './transformProps';
+import thumbnail from './images/thumbnail.png';
+
+export default class FilterGroupByPlugin extends ChartPlugin {
+  constructor() {
+    const metadata = new ChartMetadata({
+      name: t('Group By'),
+      description: t('Group By filter plugin'),
+      behaviors: [Behavior.INTERACTIVE_CHART, Behavior.NATIVE_FILTER],
+      thumbnail,
+    });
+
+    super({
+      buildQuery,
+      controlPanel,
+      loadChart: () => import('./GroupByFilterPlugin'),
+      metadata,
+      transformProps,
+    });
+  }
+}
diff --git a/superset-frontend/src/filters/components/index.ts 
b/superset-frontend/src/filters/components/GroupBy/transformProps.ts
similarity index 60%
copy from superset-frontend/src/filters/components/index.ts
copy to superset-frontend/src/filters/components/GroupBy/transformProps.ts
index 662b7a8..ee075bb 100644
--- a/superset-frontend/src/filters/components/index.ts
+++ b/superset-frontend/src/filters/components/GroupBy/transformProps.ts
@@ -16,8 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-export { default as SelectFilterPlugin } from './Select';
-export { default as RangeFilterPlugin } from './Range';
-export { default as TimeFilterPlugin } from './Time';
-export { default as TimeColumnFilterPlugin } from './TimeColumn';
-export { default as TimeGrainFilterPlugin } from './TimeGrain';
+import { ChartProps } from '@superset-ui/core';
+import { DEFAULT_FORM_DATA } from './types';
+
+export default function transformProps(chartProps: ChartProps) {
+  const {
+    behaviors,
+    formData,
+    height,
+    hooks,
+    queriesData,
+    width,
+    filterState,
+  } = chartProps;
+  const { setDataMask = () => {} } = hooks;
+
+  const { data } = queriesData[0];
+
+  return {
+    filterState,
+    behaviors,
+    width,
+    height,
+    data,
+    formData: { ...DEFAULT_FORM_DATA, ...formData },
+    setDataMask,
+  };
+}
diff --git a/superset-frontend/src/filters/components/GroupBy/types.ts 
b/superset-frontend/src/filters/components/GroupBy/types.ts
new file mode 100644
index 0000000..7b8ae7a
--- /dev/null
+++ b/superset-frontend/src/filters/components/GroupBy/types.ts
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {
+  Behavior,
+  DataRecord,
+  FilterState,
+  QueryFormData,
+  SetDataMaskHook,
+} from '@superset-ui/core';
+import { RefObject } from 'react';
+import { PluginFilterStylesProps } from '../types';
+
+interface PluginFilterGroupByCustomizeProps {
+  defaultValue?: string[] | null;
+  inputRef?: RefObject<HTMLInputElement>;
+  multiSelect: boolean;
+}
+
+export type PluginFilterGroupByQueryFormData = QueryFormData &
+  PluginFilterStylesProps &
+  PluginFilterGroupByCustomizeProps;
+
+export type PluginFilterGroupByProps = PluginFilterStylesProps & {
+  behaviors: Behavior[];
+  data: DataRecord[];
+  setDataMask: SetDataMaskHook;
+  filterState: FilterState;
+  formData: PluginFilterGroupByQueryFormData;
+};
+
+export const DEFAULT_FORM_DATA: PluginFilterGroupByCustomizeProps = {
+  defaultValue: null,
+  multiSelect: false,
+};
diff --git a/superset-frontend/src/filters/components/index.ts 
b/superset-frontend/src/filters/components/index.ts
index 662b7a8..11ad1a4 100644
--- a/superset-frontend/src/filters/components/index.ts
+++ b/superset-frontend/src/filters/components/index.ts
@@ -20,4 +20,5 @@ export { default as SelectFilterPlugin } from './Select';
 export { default as RangeFilterPlugin } from './Range';
 export { default as TimeFilterPlugin } from './Time';
 export { default as TimeColumnFilterPlugin } from './TimeColumn';
+export { default as GroupByFilterPlugin } from './GroupBy';
 export { default as TimeGrainFilterPlugin } from './TimeGrain';
diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js 
b/superset-frontend/src/visualizations/presets/MainPreset.js
index 77cfdce..02c5414 100644
--- a/superset-frontend/src/visualizations/presets/MainPreset.js
+++ b/superset-frontend/src/visualizations/presets/MainPreset.js
@@ -68,6 +68,7 @@ import {
   TimeFilterPlugin,
   TimeColumnFilterPlugin,
   TimeGrainFilterPlugin,
+  GroupByFilterPlugin,
 } from 'src/filters/components/';
 import { PivotTableChartPlugin as PivotTableChartPluginV2 } from 
'@superset-ui/plugin-chart-pivot-table';
 import FilterBoxChartPlugin from '../FilterBox/FilterBoxChartPlugin';
@@ -129,6 +130,7 @@ export default class MainPreset extends Preset {
         new TimeFilterPlugin().configure({ key: 'filter_time' }),
         new TimeColumnFilterPlugin().configure({ key: 'filter_timecolumn' }),
         new TimeGrainFilterPlugin().configure({ key: 'filter_timegrain' }),
+        new GroupByFilterPlugin().configure({ key: 'filter_groupby' }),
       ],
     });
   }

Reply via email to