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 2021/02/16 14:13:18 UTC
[superset] branch master updated: feat(native-filters): enable
filter indicator and make datasource optional (#13148)
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 5aa38ef feat(native-filters): enable filter indicator and make datasource optional (#13148)
5aa38ef is described below
commit 5aa38ef929223353ca26fb6b881798c91e46348d
Author: simcha90 <56...@users.noreply.github.com>
AuthorDate: Tue Feb 16 16:12:35 2021 +0200
feat(native-filters): enable filter indicator and make datasource optional (#13148)
* refactor: continue decouple native filters
* refactor(native-filters): decouple native filter parms from config modal
* lint: fix TS errors
* lint: fix TS errors
* refactor: update filter badge
* refactor: rename ant filters
* test: fix tests
* test: fix tests
* refactor: remove 18 from dataset
---
.../spec/fixtures/mockDashboardInfo.js | 11 +-
.../spec/fixtures/mockNativeFilters.ts | 11 +-
.../nativeFilters/NativeFiltersModal_spec.tsx | 17 +-
.../dashboard/fixtures/mockNativeFilters.js | 6 +-
.../dashboard/components/FiltersBadge/selectors.ts | 57 +++---
.../nativeFilters/FilterBar/FilterValue.tsx | 14 +-
.../FilterConfigModal/FilterConfigForm.tsx | 194 ++++++++++++---------
.../FilterConfigModal/FilterConfigModal.tsx | 18 +-
.../FilterConfigModal/FiltersList.tsx | 67 -------
.../nativeFilters/FilterConfigModal/state.ts | 7 +-
.../nativeFilters/FilterConfigModal/types.ts | 4 +-
.../nativeFilters/FilterConfigModal/utils.ts | 10 +-
.../dashboard/components/nativeFilters/types.ts | 10 +-
.../dashboard/components/nativeFilters/utils.ts | 48 ++---
.../src/dashboard/containers/FiltersBadge.tsx | 9 +-
.../{AntdRangeFilter.tsx => RangeFilterPlugin.tsx} | 8 +-
.../src/filters/components/Range/index.ts | 6 +-
.../src/filters/components/Range/types.ts | 10 +-
....stories.tsx => SelectFilterPlugin.stories.tsx} | 4 +-
...AntdSelectFilter.tsx => SelectFilterPlugin.tsx} | 10 +-
.../src/filters/components/Select/index.ts | 6 +-
.../src/filters/components/Select/types.ts | 16 +-
.../{AntdTimeFilter.tsx => TimeFilterPlugin.tsx} | 8 +-
.../src/filters/components/Time/index.ts | 5 +-
.../src/filters/components/Time/types.ts | 10 +-
superset-frontend/src/filters/components/index.ts | 4 +-
superset-frontend/src/filters/components/types.ts | 2 +-
.../src/visualizations/presets/MainPreset.js | 8 +-
28 files changed, 292 insertions(+), 288 deletions(-)
diff --git a/superset-frontend/spec/fixtures/mockDashboardInfo.js b/superset-frontend/spec/fixtures/mockDashboardInfo.js
index 228c724..68f3974 100644
--- a/superset-frontend/spec/fixtures/mockDashboardInfo.js
+++ b/superset-frontend/spec/fixtures/mockDashboardInfo.js
@@ -19,7 +19,16 @@
export default {
id: 1234,
slug: 'dashboardSlug',
- metadata: {},
+ metadata: {
+ filter_configuration: [
+ {
+ id: 'DefaultsID',
+ filterType: 'filter_select',
+ targets: [{}],
+ cascadeParentIds: [],
+ },
+ ],
+ },
userId: 'mock_user_id',
dash_edit_perm: true,
dash_save_perm: true,
diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts
index 42404fc..3cc5a9f 100644
--- a/superset-frontend/spec/fixtures/mockNativeFilters.ts
+++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { FilterType } from 'src/dashboard/components/nativeFilters/types';
import { NativeFiltersState } from 'src/dashboard/reducers/types';
export const nativeFilters: NativeFiltersState = {
@@ -24,7 +23,7 @@ export const nativeFilters: NativeFiltersState = {
'NATIVE_FILTER-e7Q8zKixx': {
id: 'NATIVE_FILTER-e7Q8zKixx',
name: 'region',
- filterType: FilterType.filter_select,
+ filterType: 'filter_select',
targets: [
{
datasetId: 2,
@@ -49,7 +48,7 @@ export const nativeFilters: NativeFiltersState = {
'NATIVE_FILTER-x9QPw0so1': {
id: 'NATIVE_FILTER-x9QPw0so1',
name: 'country_code',
- filterType: FilterType.filter_select,
+ filterType: 'filter_select',
targets: [
{
datasetId: 2,
@@ -75,6 +74,9 @@ export const nativeFilters: NativeFiltersState = {
filtersState: {
'NATIVE_FILTER-e7Q8zKixx': {
id: 'NATIVE_FILTER-e7Q8zKixx',
+ currentState: {
+ value: ['East Asia & Pacific'],
+ },
extraFormData: {
append_form_data: {
filters: [
@@ -128,6 +130,9 @@ export const singleNativeFiltersState = {
[NATIVE_FILTER_ID]: {
id: NATIVE_FILTER_ID,
extraFormData,
+ currentState: {
+ value: ['No, not an ethnic minority'],
+ },
},
},
};
diff --git a/superset-frontend/spec/javascripts/dashboard/components/nativeFilters/NativeFiltersModal_spec.tsx b/superset-frontend/spec/javascripts/dashboard/components/nativeFilters/NativeFiltersModal_spec.tsx
index 8432288..69082c5 100644
--- a/superset-frontend/spec/javascripts/dashboard/components/nativeFilters/NativeFiltersModal_spec.tsx
+++ b/superset-frontend/spec/javascripts/dashboard/components/nativeFilters/NativeFiltersModal_spec.tsx
@@ -40,10 +40,25 @@ Object.defineProperty(window, 'matchMedia', {
})),
});
+jest.mock('@superset-ui/core', () => ({
+ // @ts-ignore
+ ...jest.requireActual('@superset-ui/core'),
+ getChartMetadataRegistry: () => ({
+ items: {
+ filter_select: {
+ value: {
+ datasourceCount: 1,
+ behaviors: ['NATIVE_FILTER'],
+ },
+ },
+ },
+ }),
+}));
+
describe('FiltersConfigModal', () => {
const mockedProps = {
isOpen: true,
- initialFilterId: 'DefaultFilterId',
+ initialFilterId: 'DefaultsID',
createNewOnOpen: true,
onCancel: jest.fn(),
save: jest.fn(),
diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js
index 0025faa..8ed2bb7 100644
--- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js
+++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js
@@ -18,10 +18,10 @@
*/
export const nativeFiltersInfo = {
filters: {
- DefaultID1: {
- id: 'DefaultID1',
+ DefaultsID: {
+ id: 'DefaultsID',
name: 'test',
- type: 'text',
+ type: 'filter_select',
targets: [
{
datasetId: 0,
diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts
index 29a8aae..97bf3b6 100644
--- a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts
+++ b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts
@@ -18,10 +18,9 @@
*/
import { TIME_FILTER_MAP } from 'src/explore/constants';
import { getChartIdsInFilterScope } from 'src/dashboard/util/activeDashboardFilters';
-import {
- NativeFiltersState,
- NativeFilterState,
-} from 'src/dashboard/reducers/types';
+import { NativeFiltersState } from 'src/dashboard/reducers/types';
+import { getTreeCheckedItems } from '../nativeFilters/FilterConfigModal/utils';
+import { Layout } from '../../types';
export enum IndicatorStatus {
Unset = 'UNSET',
@@ -130,7 +129,7 @@ const getRejectedColumns = (chart: any): Set<string> =>
);
export type Indicator = {
- column: string;
+ column?: string;
name: string;
value: string[];
status: IndicatorStatus;
@@ -172,50 +171,52 @@ export const selectIndicatorsForChart = (
return indicators;
};
-const selectNativeIndicatorValue = (
- filterState: NativeFilterState,
-): string[] => {
- const filters = filterState?.extraFormData?.append_form_data?.filters;
- if (filters?.length) {
- const filter = filters[0];
- if ('val' in filter) {
- const val = filter.val as string | string[];
- if (Array.isArray(val)) {
- return val;
- }
- return [val];
- }
- }
- return [];
-};
-
export const selectNativeIndicatorsForChart = (
nativeFilters: NativeFiltersState,
chartId: number,
charts: any,
+ dashboardLayout: Layout,
): Indicator[] => {
const chart = charts[chartId];
const appliedColumns = getAppliedColumns(chart);
const rejectedColumns = getRejectedColumns(chart);
- const getStatus = (column: string, value: string[]): IndicatorStatus => {
- if (rejectedColumns.has(column)) return IndicatorStatus.Incompatible;
- if (appliedColumns.has(column) && value.length > 0) {
+ const getStatus = (
+ value: string[],
+ isAffectedByScope: boolean,
+ column?: string,
+ ): IndicatorStatus => {
+ if (!column && isAffectedByScope) {
+ // Filter without datasource
+ return IndicatorStatus.Applied;
+ }
+ if (column && rejectedColumns.has(column))
+ return IndicatorStatus.Incompatible;
+ if (column && appliedColumns.has(column) && value.length > 0) {
return IndicatorStatus.Applied;
}
return IndicatorStatus.Unset;
};
const indicators = Object.values(nativeFilters.filters).map(nativeFilter => {
- const column = nativeFilter.targets[0].column.name;
+ const isAffectedByScope = getTreeCheckedItems(
+ nativeFilter.scope,
+ dashboardLayout,
+ ).some(
+ layoutItem => dashboardLayout[layoutItem]?.meta?.chartId === chartId,
+ );
+ const column = nativeFilter.targets[0]?.column?.name;
const filterState = nativeFilters.filtersState[nativeFilter.id];
- const value = selectNativeIndicatorValue(filterState);
+ let value = filterState?.currentState?.value ?? [];
+ if (!Array.isArray(value)) {
+ value = [value];
+ }
return {
column,
name: nativeFilter.name,
path: [nativeFilter.id],
- status: getStatus(column, value),
+ status: getStatus(value, isAffectedByScope, column),
value,
};
});
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx
index d0e2024..509f80b 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx
@@ -51,15 +51,19 @@ const FilterValue: React.FC<FilterProps> = ({
const { id, targets, filterType } = filter;
const cascadingFilters = useCascadingFilters(id);
const filterState = useFilterState(id);
- const [loading, setLoading] = useState<boolean>(true);
const [state, setState] = useState([]);
const [error, setError] = useState<boolean>(false);
const [formData, setFormData] = useState<Partial<QueryFormData>>({});
const inputRef = useRef<HTMLInputElement>(null);
const [target] = targets;
- const { datasetId = 18, column } = target;
+ const {
+ datasetId,
+ column = {},
+ }: Partial<{ datasetId: number; column: { name?: string } }> = target;
const { name: groupby } = column;
const currentValue = filterState.currentState?.value;
+ const hasDataSource = !!(datasetId && groupby);
+ const [loading, setLoading] = useState<boolean>(hasDataSource);
useEffect(() => {
const newFormData = getFormData({
datasetId,
@@ -71,6 +75,9 @@ const FilterValue: React.FC<FilterProps> = ({
});
if (!areObjectsEqual(formData || {}, newFormData)) {
setFormData(newFormData);
+ if (!hasDataSource) {
+ return;
+ }
getChartDataRequest({
formData: newFormData,
force: false,
@@ -131,7 +138,8 @@ const FilterValue: React.FC<FilterProps> = ({
height={20}
width={220}
formData={formData}
- queriesData={state}
+ // For charts that don't have datasource we need workaround for empty placeholder
+ queriesData={hasDataSource ? state : [{ data: [null] }]}
chartType={filterType}
// @ts-ignore (update superset-ui)
hooks={{ setExtraFormData }}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigForm.tsx
index 44e0683..b46d91b 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigForm.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigForm.tsx
@@ -21,6 +21,8 @@ import {
SuperChart,
t,
getChartControlPanelRegistry,
+ getChartMetadataRegistry,
+ Behavior,
} from '@superset-ui/core';
import { FormInstance } from 'antd/lib/form';
import React, { useCallback } from 'react';
@@ -39,15 +41,10 @@ import { CustomControlItem } from '@superset-ui/chart-controls';
import { ColumnSelect } from './ColumnSelect';
import { NativeFiltersForm } from './types';
import FilterScope from './FilterScope';
-import {
- FilterTypeNames,
- getControlItems,
- setFilterFieldValues,
- useForceUpdate,
-} from './utils';
+import { getControlItems, setFilterFieldValues, useForceUpdate } from './utils';
import { useBackendFormUpdate } from './state';
import { getFormData } from '../utils';
-import { Filter, FilterType } from '../types';
+import { Filter } from '../types';
type DatasetSelectValue = {
value: number;
@@ -121,9 +118,25 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
const controlItems = getControlItems(
controlPanelRegistry.get(formFilter?.filterType),
);
- useBackendFormUpdate(form, filterId, filterToEdit);
- const initDatasetId = filterToEdit?.targets[0].datasetId;
+ const nativeFilterItems = getChartMetadataRegistry().items;
+ const nativeFilterVizTypes = Object.entries(nativeFilterItems)
+ // @ts-ignore
+ .filter(([, { value }]) =>
+ value.behaviors?.includes(Behavior.NATIVE_FILTER),
+ )
+ .map(([key]) => key);
+
+ // @ts-ignore
+ const hasDatasource = !!nativeFilterItems[formFilter?.filterType]?.value
+ ?.datasourceCount;
+
+ const hasFilledDatasource =
+ (formFilter?.dataset && formFilter?.column) || !hasDatasource;
+
+ useBackendFormUpdate(form, filterId, filterToEdit, hasDatasource);
+
+ const initDatasetId = filterToEdit?.targets[0]?.datasetId;
const initColumn = filterToEdit?.targets[0]?.column?.name;
const newFormData = getFormData({
datasetId: formFilter?.dataset?.value,
@@ -179,69 +192,76 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
<Input />
</StyledFormItem>
<StyledFormItem
- name={['filters', filterId, 'dataset']}
- initialValue={{ value: initDatasetId }}
- label={<StyledLabel>{t('Datasource')}</StyledLabel>}
- rules={[{ required: !removed, message: t('Datasource is required') }]}
- data-test="datasource-input"
+ name={['filters', filterId, 'filterType']}
+ rules={[{ required: !removed, message: t('Name is required') }]}
+ initialValue={filterToEdit?.filterType || 'filter_select'}
+ label={<StyledLabel>{t('Filter Type')}</StyledLabel>}
>
- <SupersetResourceSelect
- initialId={initDatasetId}
- resource="dataset"
- searchColumn="table_name"
- transformItem={datasetToSelectOption}
- isMulti={false}
- onError={onDatasetSelectError}
- onChange={e => {
- // We need reset column when dataset changed
- const datasetId = formFilter?.dataset?.value;
- if (datasetId && e?.value !== datasetId) {
- setFilterFieldValues(form, filterId, {
- column: null,
- });
- }
+ <Select
+ options={nativeFilterVizTypes.map(filterType => ({
+ value: filterType,
+ // @ts-ignore
+ label: nativeFilterItems[filterType]?.value.name,
+ }))}
+ onChange={({ value }: { value: string }) => {
+ setFilterFieldValues(form, filterId, {
+ filterType: value,
+ defaultValue: null,
+ });
forceUpdate();
}}
/>
</StyledFormItem>
</StyledContainer>
- <StyledFormItem
- // don't show the column select unless we have a dataset
- // style={{ display: datasetId == null ? undefined : 'none' }}
- name={['filters', filterId, 'column']}
- initialValue={initColumn}
- label={<StyledLabel>{t('Field')}</StyledLabel>}
- rules={[{ required: !removed, message: t('Field is required') }]}
- data-test="field-input"
- >
- <ColumnSelect
- form={form}
- filterId={filterId}
- datasetId={formFilter?.dataset?.value}
- onChange={forceUpdate}
- />
- </StyledFormItem>
- <StyledFormItem
- name={['filters', filterId, 'filterType']}
- rules={[{ required: !removed, message: t('Name is required') }]}
- initialValue={filterToEdit?.filterType || FilterType.filter_select}
- label={<StyledLabel>{t('Filter Type')}</StyledLabel>}
- >
- <Select
- options={Object.values(FilterType).map(filterType => ({
- value: filterType,
- label: FilterTypeNames[filterType],
- }))}
- onChange={({ value }: { value: FilterType }) => {
- setFilterFieldValues(form, filterId, {
- filterType: value,
- defaultValue: null,
- });
- forceUpdate();
- }}
- />
- </StyledFormItem>
- {formFilter?.dataset && formFilter?.column && (
+ {hasDatasource && (
+ <>
+ <StyledFormItem
+ name={['filters', filterId, 'dataset']}
+ initialValue={{ value: initDatasetId }}
+ label={<StyledLabel>{t('Datasource')}</StyledLabel>}
+ rules={[
+ { required: !removed, message: t('Datasource is required') },
+ ]}
+ data-test="datasource-input"
+ >
+ <SupersetResourceSelect
+ initialId={initDatasetId}
+ resource="dataset"
+ searchColumn="table_name"
+ transformItem={datasetToSelectOption}
+ isMulti={false}
+ onError={onDatasetSelectError}
+ onChange={e => {
+ // We need reset column when dataset changed
+ const datasetId = formFilter?.dataset?.value;
+ if (datasetId && e?.value !== datasetId) {
+ setFilterFieldValues(form, filterId, {
+ column: null,
+ });
+ }
+ forceUpdate();
+ }}
+ />
+ </StyledFormItem>
+ <StyledFormItem
+ // don't show the column select unless we have a dataset
+ // style={{ display: datasetId == null ? undefined : 'none' }}
+ name={['filters', filterId, 'column']}
+ initialValue={initColumn}
+ label={<StyledLabel>{t('Field')}</StyledLabel>}
+ rules={[{ required: !removed, message: t('Field is required') }]}
+ data-test="field-input"
+ >
+ <ColumnSelect
+ form={form}
+ filterId={filterId}
+ datasetId={formFilter?.dataset?.value}
+ onChange={forceUpdate}
+ />
+ </StyledFormItem>
+ </>
+ )}
+ {hasFilledDatasource && (
<CleanFormItem
name={['filters', filterId, 'defaultValueFormData']}
hidden
@@ -259,25 +279,29 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
data-test="default-input"
label={<StyledLabel>{t('Default Value')}</StyledLabel>}
>
- {formFilter?.dataset &&
- formFilter?.column &&
- formFilter?.defaultValueQueriesData && (
- <SuperChart
- height={25}
- width={250}
- formData={newFormData}
- queriesData={formFilter?.defaultValueQueriesData}
- chartType={formFilter?.filterType}
- hooks={{
- setExtraFormData: ({ currentState }) => {
- setFilterFieldValues(form, filterId, {
- defaultValue: currentState?.value,
- });
- forceUpdate();
- },
- }}
- />
- )}
+ {((hasFilledDatasource && formFilter?.defaultValueQueriesData) ||
+ !hasDatasource) && (
+ <SuperChart
+ height={25}
+ width={250}
+ formData={newFormData}
+ // For charts that don't have datasource we need workaround for empty placeholder
+ queriesData={
+ hasDatasource
+ ? formFilter?.defaultValueQueriesData
+ : [{ data: [null] }]
+ }
+ chartType={formFilter?.filterType}
+ hooks={{
+ setExtraFormData: ({ currentState }) => {
+ setFilterFieldValues(form, filterId, {
+ defaultValue: currentState?.value,
+ });
+ forceUpdate();
+ },
+ }}
+ />
+ )}
</StyledFormItem>
<StyledFormItem
name={['filters', filterId, 'parentFilter']}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigModal.tsx
index 18a6026..87fa81e 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigModal.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FilterConfigModal.tsx
@@ -400,20 +400,22 @@ export function FilterConfigModal({
const formInputs = values.filters[id];
// if user didn't open a filter, return the original config
if (!formInputs) return filterConfigMap[id];
+ let target = {};
+ if (formInputs.dataset && formInputs.column) {
+ target = {
+ datasetId: formInputs.dataset.value,
+ column: {
+ name: formInputs.column,
+ },
+ };
+ }
return {
id,
controlValues: formInputs.controlValues,
name: formInputs.name,
filterType: formInputs.filterType,
// for now there will only ever be one target
- targets: [
- {
- datasetId: formInputs.dataset.value,
- column: {
- name: formInputs.column,
- },
- },
- ],
+ targets: [target],
defaultValue: formInputs.defaultValue || null,
cascadeParentIds: formInputs.parentFilter
? [formInputs.parentFilter.value]
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FiltersList.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FiltersList.tsx
deleted file mode 100644
index 09a84f6..0000000
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/FiltersList.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * 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 React from 'react';
-import { styled } from '@superset-ui/core';
-import { Button } from 'src/common/components';
-import Icon from 'src/components/Icon';
-import { useFilterConfiguration } from '../state';
-
-interface Args {
- filter: any;
- index: number;
-}
-
-interface FiltersListProps {
- setEditFilter: (arg0: Args) => void;
- setDataset: (arg0: any) => void;
-}
-const FiltersStyle = styled.div`
- display: flex;
- flex-direction: row;
-`;
-
-const FiltersList = ({ setEditFilter, setDataset }: FiltersListProps) => {
- const filterConfigs = useFilterConfiguration();
- <>
- {filterConfigs.map((filter, i: number) => (
- <FiltersStyle>
- <Button
- type="link"
- key={filter.name}
- onClick={() => {
- setEditFilter({ filter, index: i });
- setDataset(filter.targets[0].datasetId);
- }}
- >
- {filter.name}
- </Button>
- <span
- role="button"
- title="Edit dashboard"
- tabIndex={0}
- className="action-button"
- >
- <Icon name="trash" />
- </span>
- </FiltersStyle>
- ))}
- </>;
-};
-
-export default FiltersList;
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/state.ts
index ef6b291..fc4ddfe 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/state.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/state.ts
@@ -79,11 +79,16 @@ export const useBackendFormUpdate = (
form: FormInstance<NativeFiltersForm>,
filterId: string,
filterToEdit?: Filter,
+ hasDatasource?: boolean,
) => {
const forceUpdate = useForceUpdate();
const formFilter = (form.getFieldValue('filters') || {})[filterId];
useEffect(() => {
let resolvedDefaultValue: any = null;
+ if (!hasDatasource) {
+ forceUpdate();
+ return;
+ }
// No need to check data set change because it cascading update column
// So check that column exists is enough
if (!formFilter?.column) {
@@ -107,7 +112,7 @@ export const useBackendFormUpdate = (
if (
filterToEdit?.filterType === formFilter?.filterType &&
filterToEdit?.targets[0].datasetId === formFilter?.dataset?.value &&
- formFilter?.column === filterToEdit?.targets[0]?.column?.name
+ formFilter?.column === filterToEdit?.targets[0].column?.name
) {
resolvedDefaultValue = filterToEdit?.defaultValue;
}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/types.ts
index aa9c531..1cde740 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/types.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/types.ts
@@ -17,7 +17,7 @@
* under the License.
*/
import { QueryObjectFilterClause } from '@superset-ui/core';
-import { Column, FilterType, Scope } from '../types';
+import { Column, Scope } from '../types';
export enum Scoping {
all,
@@ -30,7 +30,7 @@ export type AntCallback = (value1?: any, value2?: any) => void;
export interface NativeFiltersFormItem {
scope: Scope;
name: string;
- filterType: FilterType;
+ filterType: string;
dataset: {
value: number;
label: string;
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/utils.ts
index 000779d..18991c6 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/utils.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal/utils.ts
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { t } from '@superset-ui/core';
+
import { flatMapDeep } from 'lodash';
import { Charts, Layout, LayoutItem } from 'src/dashboard/types';
import {
@@ -29,7 +29,7 @@ import React from 'react';
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
import { CustomControlItem } from '@superset-ui/chart-controls';
import { TreeItem } from './types';
-import { FilterType, Scope } from '../types';
+import { Scope } from '../types';
export const useForceUpdate = () => {
const [, updateState] = React.useState({});
@@ -155,12 +155,6 @@ export const findFilterScope = (
};
};
-export const FilterTypeNames = {
- [FilterType.filter_select]: t('Select'),
- [FilterType.filter_range]: t('Range'),
- [FilterType.filter_time]: t('Time'),
-};
-
export const setFilterFieldValues = (
form: FormInstance,
filterId: string,
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/types.ts
index c8ec615..f104523 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/types.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/types.ts
@@ -27,12 +27,6 @@ export interface Scope {
excluded: number[];
}
-export enum FilterType {
- filter_select = 'filter_select',
- filter_range = 'filter_range',
- filter_time = 'filter_time',
-}
-
/** The target of a filter is the datasource/column being filtered */
export interface Target {
datasetId: number;
@@ -51,10 +45,10 @@ export interface Filter {
id: string; // randomly generated at filter creation
name: string;
scope: Scope;
- filterType: FilterType;
+ filterType: string;
// for now there will only ever be one target
// when multiple targets are supported, change this to Target[]
- targets: [Target];
+ targets: [Partial<Target>];
controlValues: {
[key: string]: any;
};
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
index ea8cb1a..b6d436d 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
@@ -41,26 +41,34 @@ export const getFormData = ({
datasetId?: number;
inputRef?: RefObject<HTMLInputElement>;
cascadingFilters?: object;
- groupby: string;
-}): Partial<QueryFormData> => ({
- adhoc_filters: [],
- datasource: `${datasetId}__table`,
- extra_filters: [],
- extra_form_data: cascadingFilters,
- granularity_sqla: 'ds',
- groupby: [groupby],
- metrics: ['count'],
- row_limit: 10000,
- showSearch: true,
- currentValue,
- defaultValue,
- time_range: 'No filter',
- time_range_endpoints: ['inclusive', 'exclusive'],
- url_params: {},
- viz_type: 'filter_select',
- inputRef,
- ...controlValues,
-});
+ groupby?: string;
+}): Partial<QueryFormData> => {
+ let otherProps: { datasource?: string; groupby?: string[] } = {};
+ if (datasetId && groupby) {
+ otherProps = {
+ datasource: `${datasetId}__table`,
+ groupby: [groupby],
+ };
+ }
+ return {
+ adhoc_filters: [],
+ extra_filters: [],
+ extra_form_data: cascadingFilters,
+ granularity_sqla: 'ds',
+ metrics: ['count'],
+ row_limit: 10000,
+ showSearch: true,
+ currentValue,
+ defaultValue,
+ time_range: 'No filter',
+ time_range_endpoints: ['inclusive', 'exclusive'],
+ url_params: {},
+ viz_type: 'filter_select',
+ inputRef,
+ ...controlValues,
+ ...otherProps,
+ };
+};
export function mergeExtraFormData(
originalExtra: ExtraFormData,
diff --git a/superset-frontend/src/dashboard/containers/FiltersBadge.tsx b/superset-frontend/src/dashboard/containers/FiltersBadge.tsx
index 10cb14d..6a888f2 100644
--- a/superset-frontend/src/dashboard/containers/FiltersBadge.tsx
+++ b/superset-frontend/src/dashboard/containers/FiltersBadge.tsx
@@ -52,7 +52,13 @@ const sortByStatus = (indicators: Indicator[]): Indicator[] => {
};
const mapStateToProps = (
- { datasources, dashboardFilters, nativeFilters, charts }: any,
+ {
+ datasources,
+ dashboardFilters,
+ nativeFilters,
+ charts,
+ dashboardLayout: { present },
+ }: any,
{ chartId }: FiltersBadgeProps,
) => {
const dashboardIndicators = selectIndicatorsForChart(
@@ -66,6 +72,7 @@ const mapStateToProps = (
nativeFilters,
chartId,
charts,
+ present,
);
const indicators = uniqWith(
diff --git a/superset-frontend/src/filters/components/Range/AntdRangeFilter.tsx b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx
similarity index 87%
rename from superset-frontend/src/filters/components/Range/AntdRangeFilter.tsx
rename to superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx
index 82ae289..c009b77 100644
--- a/superset-frontend/src/filters/components/Range/AntdRangeFilter.tsx
+++ b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx
@@ -19,16 +19,16 @@
import { styled } from '@superset-ui/core';
import React from 'react';
import { Slider } from 'src/common/components';
-import { AntdPluginFilterRangeProps } from './types';
-import { AntdPluginFilterStylesProps } from '../types';
+import { PluginFilterRangeProps } from './types';
+import { PluginFilterStylesProps } from '../types';
import { getRangeExtraFormData } from '../../utils';
-const Styles = styled.div<AntdPluginFilterStylesProps>`
+const Styles = styled.div<PluginFilterStylesProps>`
height: ${({ height }) => height};
width: ${({ width }) => width};
`;
-export default function AntdRangeFilter(props: AntdPluginFilterRangeProps) {
+export default function RangeFilterPlugin(props: PluginFilterRangeProps) {
const { data, formData, height, width, setExtraFormData, inputRef } = props;
const [row] = data;
// @ts-ignore
diff --git a/superset-frontend/src/filters/components/Range/index.ts b/superset-frontend/src/filters/components/Range/index.ts
index a3715eb..0fe4310 100644
--- a/superset-frontend/src/filters/components/Range/index.ts
+++ b/superset-frontend/src/filters/components/Range/index.ts
@@ -22,10 +22,10 @@ import controlPanel from './controlPanel';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
-export default class AntdRangeFilterPlugin extends ChartPlugin {
+export default class RangeFilterPlugin extends ChartPlugin {
constructor() {
const metadata = new ChartMetadata({
- name: t('Range filter plugin'),
+ name: t('Range filter'),
description: 'Range filter plugin using AntD',
behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER],
thumbnail,
@@ -34,7 +34,7 @@ export default class AntdRangeFilterPlugin extends ChartPlugin {
super({
buildQuery,
controlPanel,
- loadChart: () => import('./AntdRangeFilter'),
+ loadChart: () => import('./RangeFilterPlugin'),
metadata,
transformProps,
});
diff --git a/superset-frontend/src/filters/components/Range/types.ts b/superset-frontend/src/filters/components/Range/types.ts
index 4b23262..a07c8d7 100644
--- a/superset-frontend/src/filters/components/Range/types.ts
+++ b/superset-frontend/src/filters/components/Range/types.ts
@@ -22,18 +22,18 @@ import {
SetExtraFormDataHook,
} from '@superset-ui/core';
import { RefObject } from 'react';
-import { AntdPluginFilterStylesProps } from '../types';
+import { PluginFilterStylesProps } from '../types';
-interface AntdPluginFilterSelectCustomizeProps {
+interface PluginFilterSelectCustomizeProps {
max?: number;
min?: number;
}
export type PluginFilterRangeQueryFormData = QueryFormData &
- AntdPluginFilterStylesProps &
- AntdPluginFilterSelectCustomizeProps;
+ PluginFilterStylesProps &
+ PluginFilterSelectCustomizeProps;
-export type AntdPluginFilterRangeProps = AntdPluginFilterStylesProps & {
+export type PluginFilterRangeProps = PluginFilterStylesProps & {
data: DataRecord[];
formData: PluginFilterRangeQueryFormData;
setExtraFormData: SetExtraFormDataHook;
diff --git a/superset-frontend/src/filters/components/Select/AntdSelectFilter.stories.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
similarity index 94%
rename from superset-frontend/src/filters/components/Select/AntdSelectFilter.stories.tsx
rename to superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
index 67929e4..41e1ced 100644
--- a/superset-frontend/src/filters/components/Select/AntdSelectFilter.stories.tsx
+++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
@@ -21,10 +21,10 @@ import { action } from '@storybook/addon-actions';
import { boolean, withKnobs } from '@storybook/addon-knobs';
import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core';
import { mockQueryDataForCountries } from 'spec/fixtures/mockNativeFilters';
-import AntdSelectFilterPlugin from './index';
+import SelectFilterPlugin from './index';
import transformProps from './transformProps';
-new AntdSelectFilterPlugin().configure({ key: 'filter_select' }).register();
+new SelectFilterPlugin().configure({ key: 'filter_select' }).register();
getChartTransformPropsRegistry().registerValue('filter_select', transformProps);
diff --git a/superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
similarity index 92%
rename from superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx
rename to superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
index ccac766..70664af 100644
--- a/superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx
+++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
@@ -19,20 +19,18 @@
import { styled } from '@superset-ui/core';
import React, { useEffect, useState } from 'react';
import { Select } from 'src/common/components';
-import { AntdPluginFilterSelectProps } from './types';
-import { AntdPluginFilterStylesProps } from '../types';
+import { PluginFilterSelectProps } from './types';
+import { PluginFilterStylesProps } from '../types';
import { getSelectExtraFormData } from '../../utils';
-const Styles = styled.div<AntdPluginFilterStylesProps>`
+const Styles = styled.div<PluginFilterStylesProps>`
height: ${({ height }) => height};
width: ${({ width }) => width};
`;
const { Option } = Select;
-export default function AntdPluginFilterSelect(
- props: AntdPluginFilterSelectProps,
-) {
+export default function PluginFilterSelect(props: PluginFilterSelectProps) {
const { data, formData, height, width, setExtraFormData } = props;
const {
defaultValue,
diff --git a/superset-frontend/src/filters/components/Select/index.ts b/superset-frontend/src/filters/components/Select/index.ts
index 15ba057..0c68a63 100644
--- a/superset-frontend/src/filters/components/Select/index.ts
+++ b/superset-frontend/src/filters/components/Select/index.ts
@@ -22,10 +22,10 @@ import controlPanel from './controlPanel';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
-export default class AntdFilterSelectPlugin extends ChartPlugin {
+export default class FilterSelectPlugin extends ChartPlugin {
constructor() {
const metadata = new ChartMetadata({
- name: t('Select filter plugin'),
+ name: t('Select filter'),
description: 'Select filter plugin using AntD',
behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER],
thumbnail,
@@ -34,7 +34,7 @@ export default class AntdFilterSelectPlugin extends ChartPlugin {
super({
buildQuery,
controlPanel,
- loadChart: () => import('./AntdSelectFilter'),
+ loadChart: () => import('./SelectFilterPlugin'),
metadata,
transformProps,
});
diff --git a/superset-frontend/src/filters/components/Select/types.ts b/superset-frontend/src/filters/components/Select/types.ts
index 476c436..7657940 100644
--- a/superset-frontend/src/filters/components/Select/types.ts
+++ b/superset-frontend/src/filters/components/Select/types.ts
@@ -22,9 +22,9 @@ import {
SetExtraFormDataHook,
} from '@superset-ui/core';
import { RefObject } from 'react';
-import { AntdPluginFilterStylesProps } from '../types';
+import { PluginFilterStylesProps } from '../types';
-interface AntdPluginFilterSelectCustomizeProps {
+interface PluginFilterSelectCustomizeProps {
defaultValue?: (string | number)[] | null;
currentValue?: (string | number)[] | null;
enableEmptyFilter: boolean;
@@ -34,17 +34,17 @@ interface AntdPluginFilterSelectCustomizeProps {
inputRef?: RefObject<HTMLInputElement>;
}
-export type AntdPluginFilterSelectQueryFormData = QueryFormData &
- AntdPluginFilterStylesProps &
- AntdPluginFilterSelectCustomizeProps;
+export type PluginFilterSelectQueryFormData = QueryFormData &
+ PluginFilterStylesProps &
+ PluginFilterSelectCustomizeProps;
-export type AntdPluginFilterSelectProps = AntdPluginFilterStylesProps & {
+export type PluginFilterSelectProps = PluginFilterStylesProps & {
data: DataRecord[];
setExtraFormData: SetExtraFormDataHook;
- formData: AntdPluginFilterSelectQueryFormData;
+ formData: PluginFilterSelectQueryFormData;
};
-export const DEFAULT_FORM_DATA: AntdPluginFilterSelectCustomizeProps = {
+export const DEFAULT_FORM_DATA: PluginFilterSelectCustomizeProps = {
defaultValue: null,
currentValue: null,
enableEmptyFilter: false,
diff --git a/superset-frontend/src/filters/components/Time/AntdTimeFilter.tsx b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx
similarity index 89%
rename from superset-frontend/src/filters/components/Time/AntdTimeFilter.tsx
rename to superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx
index c00b988..00dfa02 100644
--- a/superset-frontend/src/filters/components/Time/AntdTimeFilter.tsx
+++ b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx
@@ -19,18 +19,18 @@
import { styled } from '@superset-ui/core';
import React, { useState, useEffect } from 'react';
import DateFilterControl from 'src/explore/components/controls/DateFilterControl/DateFilterControl';
-import { AntdPluginFilterStylesProps } from '../types';
-import { AntdPluginFilterTimeProps } from './types';
+import { PluginFilterStylesProps } from '../types';
+import { PluginFilterTimeProps } from './types';
const DEFAULT_VALUE = 'Last week';
-const Styles = styled.div<AntdPluginFilterStylesProps>`
+const Styles = styled.div<PluginFilterStylesProps>`
height: ${({ height }) => height}px;
width: ${({ width }) => width}px;
overflow-x: scroll;
`;
-export default function AntdTimeFilter(props: AntdPluginFilterTimeProps) {
+export default function TimeFilterPlugin(props: PluginFilterTimeProps) {
const { formData, setExtraFormData, width } = props;
const { defaultValue, currentValue } = formData;
diff --git a/superset-frontend/src/filters/components/Time/index.ts b/superset-frontend/src/filters/components/Time/index.ts
index f6e2bd6..1a0b7aa 100644
--- a/superset-frontend/src/filters/components/Time/index.ts
+++ b/superset-frontend/src/filters/components/Time/index.ts
@@ -24,15 +24,16 @@ import thumbnail from './images/thumbnail.png';
export default class TimeFilterPlugin extends ChartPlugin {
constructor() {
const metadata = new ChartMetadata({
- name: t('Time range filter plugin'),
+ name: t('Time filter'),
description: 'Custom time filter plugin',
behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER],
thumbnail,
+ datasourceCount: 0,
});
super({
controlPanel,
- loadChart: () => import('./AntdTimeFilter'),
+ loadChart: () => import('./TimeFilterPlugin'),
metadata,
transformProps,
});
diff --git a/superset-frontend/src/filters/components/Time/types.ts b/superset-frontend/src/filters/components/Time/types.ts
index 7676e0f..f1fc35e 100644
--- a/superset-frontend/src/filters/components/Time/types.ts
+++ b/superset-frontend/src/filters/components/Time/types.ts
@@ -21,21 +21,21 @@ import {
DataRecord,
SetExtraFormDataHook,
} from '@superset-ui/core';
-import { AntdPluginFilterStylesProps } from '../types';
+import { PluginFilterStylesProps } from '../types';
interface PluginFilterTimeCustomizeProps {
defaultValue?: string | null;
currentValue?: string | null;
}
-export type AntdPluginFilterSelectQueryFormData = QueryFormData &
- AntdPluginFilterStylesProps &
+export type PluginFilterSelectQueryFormData = QueryFormData &
+ PluginFilterStylesProps &
PluginFilterTimeCustomizeProps;
-export type AntdPluginFilterTimeProps = AntdPluginFilterStylesProps & {
+export type PluginFilterTimeProps = PluginFilterStylesProps & {
data: DataRecord[];
setExtraFormData: SetExtraFormDataHook;
- formData: AntdPluginFilterSelectQueryFormData;
+ formData: PluginFilterSelectQueryFormData;
};
export const DEFAULT_FORM_DATA: PluginFilterTimeCustomizeProps = {
diff --git a/superset-frontend/src/filters/components/index.ts b/superset-frontend/src/filters/components/index.ts
index 0f9582a..1139f77 100644
--- a/superset-frontend/src/filters/components/index.ts
+++ b/superset-frontend/src/filters/components/index.ts
@@ -16,6 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-export { default as AntdSelectFilterPlugin } from './Select';
-export { default as AntdRangeFilterPlugin } from './Range';
+export { default as SelectFilterPlugin } from './Select';
+export { default as RangeFilterPlugin } from './Range';
export { default as TimeFilterPlugin } from './Time';
diff --git a/superset-frontend/src/filters/components/types.ts b/superset-frontend/src/filters/components/types.ts
index 869dc79..41511cb 100644
--- a/superset-frontend/src/filters/components/types.ts
+++ b/superset-frontend/src/filters/components/types.ts
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-export interface AntdPluginFilterStylesProps {
+export interface PluginFilterStylesProps {
height: number;
width: number;
}
diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js
index 0bee414..6ad96b6 100644
--- a/superset-frontend/src/visualizations/presets/MainPreset.js
+++ b/superset-frontend/src/visualizations/presets/MainPreset.js
@@ -60,8 +60,8 @@ import {
EchartsTimeseriesChartPlugin,
} from '@superset-ui/plugin-chart-echarts';
import {
- AntdSelectFilterPlugin,
- AntdRangeFilterPlugin,
+ SelectFilterPlugin,
+ RangeFilterPlugin,
TimeFilterPlugin,
} from 'src/filters/components/';
import FilterBoxChartPlugin from '../FilterBox/FilterBoxChartPlugin';
@@ -112,8 +112,8 @@ export default class MainPreset extends Preset {
new EchartsTimeseriesChartPlugin().configure({
key: 'echarts_timeseries',
}),
- new AntdSelectFilterPlugin().configure({ key: 'filter_select' }),
- new AntdRangeFilterPlugin().configure({ key: 'filter_range' }),
+ new SelectFilterPlugin().configure({ key: 'filter_select' }),
+ new RangeFilterPlugin().configure({ key: 'filter_range' }),
new TimeFilterPlugin().configure({ key: 'filter_time' }),
],
});