You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2023/03/14 15:04:52 UTC

[superset] branch master updated: feat(native-filters): allow cascading from time and numeric filters (#23319)

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

villebro 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 db95a93f43 feat(native-filters): allow cascading from time and numeric filters (#23319)
db95a93f43 is described below

commit db95a93f43a25d592ff5d9ce29c50e5a02068f9d
Author: Ville Brofeldt <33...@users.noreply.github.com>
AuthorDate: Tue Mar 14 17:04:44 2023 +0200

    feat(native-filters): allow cascading from time and numeric filters (#23319)
---
 .../FiltersConfigForm/ColumnSelect.tsx             |  6 +-
 .../FiltersConfigForm/DependencyList.tsx           |  9 ++-
 .../FiltersConfigForm/FiltersConfigForm.tsx        | 83 +++++++++++++---------
 .../FiltersConfigModal/FiltersConfigModal.tsx      | 17 +++--
 4 files changed, 68 insertions(+), 47 deletions(-)

diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
index 41c591ade3..758b9fd602 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
@@ -24,7 +24,6 @@ import { useToasts } from 'src/components/MessageToasts/withToasts';
 import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { cacheWrapper } from 'src/utils/cacheWrapper';
 import { NativeFiltersForm } from '../types';
-import { doesColumnMatchFilterType } from './utils';
 
 interface ColumnSelectProps {
   allowClear?: boolean;
@@ -84,10 +83,7 @@ export function ColumnSelect({
   );
 
   useEffect(() => {
-    if (
-      currentColumn &&
-      !doesColumnMatchFilterType(currentFilterType, currentColumn)
-    ) {
+    if (currentColumn && !filterValues(currentColumn)) {
       resetColumnField();
     }
   }, [currentColumn, currentFilterType, resetColumnField]);
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx
index 3ba2765a30..c4f6f71651 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx
@@ -23,10 +23,15 @@ import { Select } from 'src/components';
 import { CollapsibleControl } from './CollapsibleControl';
 
 interface DependencyListProps {
-  availableFilters: { label: string; value: string }[];
+  availableFilters: {
+    label: string;
+    value: string;
+    type: string | undefined;
+  }[];
   dependencies: string[];
   onDependenciesChange: (dependencies: string[]) => void;
   getDependencySuggestion: () => string;
+  children?: JSX.Element;
 }
 
 const MainPanel = styled.div`
@@ -176,6 +181,7 @@ const DependencyList = ({
   dependencies = [],
   onDependenciesChange,
   getDependencySuggestion,
+  children,
 }: DependencyListProps) => {
   const hasAvailableFilters = availableFilters.length > 0;
   const hasDependencies = dependencies.length > 0;
@@ -205,6 +211,7 @@ const DependencyList = ({
           onDependenciesChange={onDependenciesChange}
           getDependencySuggestion={getDependencySuggestion}
         />
+        {children}
       </CollapsibleControl>
     </MainPanel>
   );
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 0b6a33f069..4c18a2c85c 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -299,7 +299,9 @@ export interface FiltersConfigFormProps {
   removedFilters: Record<string, FilterRemoval>;
   restoreFilter: (filterId: string) => void;
   form: FormInstance<NativeFiltersForm>;
-  getAvailableFilters: (filterId: string) => { label: string; value: string }[];
+  getAvailableFilters: (
+    filterId: string,
+  ) => { label: string; value: string; type: string | undefined }[];
   handleActiveFilterPanelChange: (activeFilterPanel: string | string[]) => void;
   activeFilterPanelKeys: string | string[];
   isActive: boolean;
@@ -654,6 +656,9 @@ const FiltersConfigForm = (
 
   const availableFilters = getAvailableFilters(filterId);
   const hasAvailableFilters = availableFilters.length > 0;
+  const hasTimeDependency = availableFilters
+    .filter(filter => filter.type === 'filter_time')
+    .some(filter => dependencies.includes(filter.value));
 
   useEffect(() => {
     if (datasetId) {
@@ -736,6 +741,42 @@ const FiltersConfigForm = (
     return <RemovedFilter onClick={() => restoreFilter(filterId)} />;
   }
 
+  const timeColumn = (
+    <StyledRowFormItem
+      name={['filters', filterId, 'granularity_sqla']}
+      label={
+        <>
+          <StyledLabel>{t('Time column')}</StyledLabel>&nbsp;
+          <InfoTooltipWithTrigger
+            placement="top"
+            tooltip={
+              hasTimeDependency
+                ? t('Time column to apply dependent temporal filter to')
+                : t('Time column to apply time range to')
+            }
+          />
+        </>
+      }
+      initialValue={filterToEdit?.granularity_sqla}
+    >
+      <ColumnSelect
+        allowClear
+        form={form}
+        formField="granularity_sqla"
+        filterId={filterId}
+        filterValues={(column: Column) => !!column.is_dttm}
+        datasetId={datasetId}
+        onChange={column => {
+          // We need reset default value when when column changed
+          setNativeFilterFieldValues(form, filterId, {
+            granularity_sqla: column,
+          });
+          forceUpdate();
+        }}
+      />
+    </StyledRowFormItem>
+  );
+
   return (
     <StyledTabs
       activeKey={activeTabKey}
@@ -892,7 +933,9 @@ const FiltersConfigForm = (
                     getDependencySuggestion={() =>
                       getDependencySuggestion(filterId)
                     }
-                  />
+                  >
+                    {hasTimeDependency ? timeColumn : undefined}
+                  </DependencyList>
                 </StyledRowFormItem>
               )}
               {hasDataset && hasAdditionalFilters && (
@@ -966,39 +1009,9 @@ const FiltersConfigForm = (
                         />
                       </StyledRowFormItem>
                     )}
-                    {hasTimeRange && (
-                      <StyledRowFormItem
-                        name={['filters', filterId, 'granularity_sqla']}
-                        label={
-                          <>
-                            <StyledLabel>{t('Time column')}</StyledLabel>&nbsp;
-                            <InfoTooltipWithTrigger
-                              placement="top"
-                              tooltip={t(
-                                'Optional time column if time range should apply to another column than the default time column',
-                              )}
-                            />
-                          </>
-                        }
-                        initialValue={filterToEdit?.granularity_sqla}
-                      >
-                        <ColumnSelect
-                          allowClear
-                          form={form}
-                          formField="granularity_sqla"
-                          filterId={filterId}
-                          filterValues={(column: Column) => !!column.is_dttm}
-                          datasetId={datasetId}
-                          onChange={column => {
-                            // We need reset default value when when column changed
-                            setNativeFilterFieldValues(form, filterId, {
-                              granularity_sqla: column,
-                            });
-                            forceUpdate();
-                          }}
-                        />
-                      </StyledRowFormItem>
-                    )}
+                    {hasTimeRange && !hasTimeDependency
+                      ? timeColumn
+                      : undefined}
                   </CollapsibleControl>
                 </CleanFormItem>
               )}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
index fa7ef238e8..eb68e01ba6 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
@@ -89,7 +89,11 @@ export interface FiltersConfigModalProps {
   onSave: (filterConfig: FilterConfiguration) => Promise<void>;
   onCancel: () => void;
 }
-export const ALLOW_DEPENDENCIES = ['filter_select'];
+export const ALLOW_DEPENDENCIES = [
+  'filter_range',
+  'filter_select',
+  'filter_time',
+];
 
 const DEFAULT_EMPTY_FILTERS: string[] = [];
 const DEFAULT_REMOVED_FILTERS: Record<string, FilterRemoval> = {};
@@ -287,11 +291,12 @@ function FiltersConfigModal({
   const getAvailableFilters = useCallback(
     (filterId: string) =>
       filterIds
-        .filter(key => key !== filterId)
-        .filter(filterId => canBeUsedAsDependency(filterId))
-        .map(key => ({
-          label: getFilterTitle(key),
-          value: key,
+        .filter(id => id !== filterId)
+        .filter(id => canBeUsedAsDependency(id))
+        .map(id => ({
+          label: getFilterTitle(id),
+          value: id,
+          type: filterConfigMap[id]?.filterType,
         })),
     [canBeUsedAsDependency, filterIds, getFilterTitle],
   );