You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by gr...@apache.org on 2021/04/26 06:50:22 UTC
[superset] branch gg-ShowFilterBoxAsFilterComponent created (now
71d0d7f)
This is an automated email from the ASF dual-hosted git repository.
graceguo pushed a change to branch gg-ShowFilterBoxAsFilterComponent
in repository https://gitbox.apache.org/repos/asf/superset.git.
at 71d0d7f dispaly filter_box as native filters
This branch includes the following new commits:
new 71d0d7f dispaly filter_box as native filters
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[superset] 01/01: dispaly filter_box as native filters
Posted by gr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
graceguo pushed a commit to branch gg-ShowFilterBoxAsFilterComponent
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 71d0d7f48ccadabdb369bf3406c8326078dc7abc
Author: Grace <gr...@airbnb.com>
AuthorDate: Sun Apr 25 22:28:29 2021 -0700
dispaly filter_box as native filters
---
superset-frontend/src/dashboard/actions/hydrate.js | 306 +++++++++++++++++----
.../dashboard/components/gridComponents/Chart.jsx | 5 +-
.../components/nativeFilters/FilterBar/index.tsx | 1 +
superset-frontend/src/explore/constants.ts | 1 +
superset-frontend/src/filters/utils.ts | 10 +-
5 files changed, 266 insertions(+), 57 deletions(-)
diff --git a/superset-frontend/src/dashboard/actions/hydrate.js b/superset-frontend/src/dashboard/actions/hydrate.js
index 0206d91..d4b9872 100644
--- a/superset-frontend/src/dashboard/actions/hydrate.js
+++ b/superset-frontend/src/dashboard/actions/hydrate.js
@@ -17,44 +17,34 @@
* under the License.
*/
/* eslint-disable camelcase */
-import { isString, keyBy } from 'lodash';
+import {isString, keyBy, isEmpty} from 'lodash';
import shortid from 'shortid';
-import {
- Behavior,
- CategoricalColorNamespace,
- getChartMetadataRegistry,
-} from '@superset-ui/core';
+import {Behavior, CategoricalColorNamespace, getChartMetadataRegistry,} from '@superset-ui/core';
import querystring from 'query-string';
-import { chart } from 'src/chart/chartReducer';
-import { initSliceEntities } from 'src/dashboard/reducers/sliceEntities';
-import { getInitialState as getInitialNativeFilterState } from 'src/dashboard/reducers/nativeFilters';
-import { getParam } from 'src/modules/utils';
-import { applyDefaultFormData } from 'src/explore/store';
-import { buildActiveFilters } from 'src/dashboard/util/activeDashboardFilters';
+import {chart} from 'src/chart/chartReducer';
+import {initSliceEntities} from 'src/dashboard/reducers/sliceEntities';
+import {getInitialState as getInitialNativeFilterState} from 'src/dashboard/reducers/nativeFilters';
+import {getParam} from 'src/modules/utils';
+import {applyDefaultFormData} from 'src/explore/store';
+import {buildActiveFilters} from 'src/dashboard/util/activeDashboardFilters';
import findPermission from 'src/dashboard/util/findPermission';
-import {
- DASHBOARD_FILTER_SCOPE_GLOBAL,
- dashboardFilter,
-} from 'src/dashboard/reducers/dashboardFilters';
+import {DASHBOARD_FILTER_SCOPE_GLOBAL, dashboardFilter,} from 'src/dashboard/reducers/dashboardFilters';
import {
DASHBOARD_HEADER_ID,
- GRID_DEFAULT_CHART_WIDTH,
- GRID_COLUMN_COUNT,
DASHBOARD_ROOT_ID,
+ GRID_COLUMN_COUNT,
+ GRID_DEFAULT_CHART_WIDTH,
} from 'src/dashboard/util/constants';
-import {
- DASHBOARD_HEADER_TYPE,
- CHART_TYPE,
- ROW_TYPE,
-} from 'src/dashboard/util/componentTypes';
+import {CHART_TYPE, DASHBOARD_HEADER_TYPE, ROW_TYPE,} from 'src/dashboard/util/componentTypes';
import findFirstParentContainerId from 'src/dashboard/util/findFirstParentContainer';
import getEmptyLayout from 'src/dashboard/util/getEmptyLayout';
import getFilterConfigsFromFormdata from 'src/dashboard/util/getFilterConfigsFromFormdata';
import getLocationHash from 'src/dashboard/util/getLocationHash';
import newComponentFactory from 'src/dashboard/util/newComponentFactory';
-import { TIME_RANGE } from 'src/visualizations/FilterBox/FilterBox';
-import { FeatureFlag, isFeatureEnabled } from '../../featureFlags';
+import {TIME_RANGE} from 'src/visualizations/FilterBox/FilterBox';
+import {FeatureFlag, isFeatureEnabled} from '../../featureFlags';
+import {FILTER_CONFIG_ATTRIBUTES, TIME_FILTER_LABELS, TIME_FILTER_MAP} from "../../explore/constants";
const reservedQueryParams = new Set(['standalone', 'edit']);
@@ -77,6 +67,51 @@ const extractUrlParams = queryParams =>
return { ...acc, [key]: value };
}, {});
+const getPreselectedValuesFromDashboard = (
+ preselectedFilters,
+) => {
+ return (filterKey, column) => {
+ if (preselectedFilters[filterKey] &&
+ preselectedFilters[filterKey].hasOwnProperty(column)) {
+ // overwrite default values by dashboard default_filters
+ return preselectedFilters[filterKey][column];
+ }
+ }
+}
+
+const getFilterBoxDefaultValues = (config) => {
+ let defaultValues = config[FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE];
+
+ // treat empty string as null (no default value)
+ if (defaultValues === '') {
+ defaultValues = null;
+ }
+
+ // defaultValue could be ; separated values,
+ // could be null or ''
+ if (defaultValues && config[FILTER_CONFIG_ATTRIBUTES.MULTIPLE]) {
+ defaultValues = config.defaultValue.split(';');
+ }
+
+ return defaultValues
+}
+
+const buildValuesInArray = (value1, value2) => {
+ if (!isEmpty(value1)) {
+ return [value1];
+ } else if (isEmpty(value2)) {
+ return [value2];
+ } else{
+ return [];
+ }
+}
+
+const FILTER_BOX_TRANSITION_MODE = {
+ test: 'TEST',
+ snooze: 'SNOOZE',
+ confirmed: 'CONFIRMED',
+}
+
export const HYDRATE_DASHBOARD = 'HYDRATE_DASHBOARD';
export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
@@ -143,6 +178,8 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
let newSlicesContainerWidth = 0;
const filterScopes = metadata?.filter_scopes || {};
+ const filterConfig = metadata?.native_filter_configuration || [];
+ const isFilterBoxConverted = !!(metadata?.native_filter_configuration);
const chartQueries = {};
const dashboardFilters = {};
@@ -210,7 +247,9 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
}
// build DashboardFilters for interactive filter features
- if (slice.form_data.viz_type === 'filter_box') {
+ if (!isFilterBoxConverted &&
+ slice.form_data.viz_type === 'filter_box'
+ ) {
const configs = getFilterConfigsFromFormdata(slice.form_data);
let { columns } = configs;
const { labels } = configs;
@@ -243,22 +282,195 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
};
}, {});
- const componentId = chartIdToLayoutId[key];
- const directPathToFilter = (layout[componentId].parents || []).slice();
- directPathToFilter.push(componentId);
- dashboardFilters[key] = {
- ...dashboardFilter,
- chartId: key,
- componentId,
- datasourceId: slice.form_data.datasource,
- filterName: slice.slice_name,
- directPathToFilter,
- columns,
- labels,
- scopes: scopesByChartId,
- isInstantFilter: !!slice.form_data.instant_filtering,
- isDateFilter: Object.keys(columns).includes(TIME_RANGE),
- };
+ const {
+ date_filter = false,
+ datasource = '',
+ druid_time_origin,
+ filter_configs = [],
+ instant_filtering = false,
+ granularity,
+ granularity_sqla,
+ show_druid_time_granularity = false,
+ show_druid_time_origin = false,
+ show_sqla_time_column = false,
+ show_sqla_time_granularity = false,
+ time_grain_sqla,
+ time_range,
+ } = slice.form_data;
+
+ const getDashboardDefaultValues = getPreselectedValuesFromDashboard(preselectFilters);
+
+ if (date_filter) {
+ const {scope, immune} = scopesByChartId[TIME_FILTER_MAP['time_range']] || DASHBOARD_FILTER_SCOPE_GLOBAL;
+ const dashboardDefaultValues = getDashboardDefaultValues(key, TIME_FILTER_MAP['time_range']);
+ const timeRangeFilter = {
+ id: `NATIVE_FILTER-${shortid.generate()}`,
+ controlValues: {},
+ name: TIME_FILTER_LABELS['time_range'],
+ filterType: "filter_time",
+ targets: [{}],
+ defaultValue: dashboardDefaultValues || time_range,
+ cascadeParentIds: [],
+ scope: {
+ "rootPath": scope,
+ "excluded": immune,
+ },
+ isInstant: instant_filtering,
+ }
+ filterConfig.push(timeRangeFilter);
+
+ if (show_sqla_time_granularity) {
+ const {scope, immune} = scopesByChartId['time_grain_sqla'] || DASHBOARD_FILTER_SCOPE_GLOBAL;
+ const dashboardDefaultValues = getDashboardDefaultValues(key, TIME_FILTER_MAP['time_grain_sqla']);
+ const timeGrainFilter = {
+ id: `NATIVE_FILTER-${shortid.generate()}`,
+ controlValues: {},
+ name: TIME_FILTER_LABELS['time_grain_sqla'],
+ filterType: 'filter_timegrain',
+ targets: [
+ {
+ datasetId: parseInt(datasource.split('__')[0], 10),
+ }
+ ],
+ defaultValue: buildValuesInArray(dashboardDefaultValues, time_grain_sqla),
+ cascadeParentIds: [],
+ scope: {
+ "rootPath": scope,
+ "excluded": immune,
+ },
+ isInstant: instant_filtering,
+ }
+ filterConfig.push(timeGrainFilter);
+ }
+
+ if (show_sqla_time_column) {
+ const {scope, immune} = scopesByChartId['granularity_sqla'] || DASHBOARD_FILTER_SCOPE_GLOBAL;
+ const dashboardDefaultValues = getDashboardDefaultValues(key, TIME_FILTER_MAP['granularity_sqla']);
+ const timeColumnFilter = {
+ id: `NATIVE_FILTER-${shortid.generate()}`,
+ controlValues: {},
+ name: TIME_FILTER_LABELS['granularity_sqla'],
+ filterType: 'filter_timecolumn',
+ targets: [
+ {
+ datasetId: parseInt(datasource.split('__')[0], 10),
+ }
+ ],
+ defaultValue: buildValuesInArray(dashboardDefaultValues, granularity_sqla),
+ cascadeParentIds: [],
+ scope: {
+ "rootPath": scope,
+ "excluded": immune,
+ },
+ isInstant: instant_filtering,
+ }
+ filterConfig.push(timeColumnFilter);
+ }
+
+ if (show_druid_time_granularity) {
+ const {scope, immune} = scopesByChartId['granularity'] || DASHBOARD_FILTER_SCOPE_GLOBAL;
+ const dashboardDefaultValues = getDashboardDefaultValues(key, TIME_FILTER_MAP['granularity']);
+ const druidGranularityFilter = {
+ id: `NATIVE_FILTER-${shortid.generate()}`,
+ controlValues: {},
+ name: TIME_FILTER_LABELS['granularity'],
+ filterType: 'filter_timegrain',
+ targets: [
+ {
+ datasetId: parseInt(datasource.split('__')[0], 10),
+ }
+ ],
+ defaultValue: buildValuesInArray(dashboardDefaultValues, granularity),
+ cascadeParentIds: [],
+ scope: {
+ "rootPath": scope,
+ "excluded": immune,
+ },
+ isInstant: instant_filtering,
+ }
+ filterConfig.push(druidGranularityFilter);
+ }
+
+ // TODO: test
+ if (show_druid_time_origin) {
+ const {scope, immune} = scopesByChartId['druid_time_origin'] || DASHBOARD_FILTER_SCOPE_GLOBAL;
+ const dashboardDefaultValues = getDashboardDefaultValues(key, TIME_FILTER_MAP['druid_time_origin']);
+ const druidOriginFilter = {
+ id: `NATIVE_FILTER-${shortid.generate()}`,
+ controlValues: {},
+ name: TIME_FILTER_LABELS['druid_time_origin'],
+ filterType: 'filter_timegrain',
+ targets: [
+ {
+ datasetId: parseInt(datasource.split('__')[0], 10),
+ }
+ ],
+ defaultValue: buildValuesInArray(dashboardDefaultValues, druid_time_origin),
+ cascadeParentIds: [],
+ scope: {
+ "rootPath": scope,
+ "excluded": immune,
+ },
+ isInstant: instant_filtering,
+ }
+ filterConfig.push(druidOriginFilter);
+ }
+ }
+ filter_configs.forEach(config => {
+ const {scope, immune} = scopesByChartId[config.column] || DASHBOARD_FILTER_SCOPE_GLOBAL;
+ const defaultValues = getDashboardDefaultValues(key, config.column);
+ const entry = {
+ id: `NATIVE_FILTER-${config.key}`,
+ controlValues: {
+ // TODO: test
+ enableEmptyFilter: !config[FILTER_CONFIG_ATTRIBUTES.CLEARABLE],
+ defaultToFirstItem: false, // n/a
+ inverseSelection: false, // n/a
+ multiSelect: config[FILTER_CONFIG_ATTRIBUTES.MULTIPLE],
+ sortAscending: config[FILTER_CONFIG_ATTRIBUTES.SORT_ASCENDING],
+ },
+ name: config.label || config.column,
+ filterType: "filter_select",
+ targets: [
+ {
+ datasetId: parseInt(datasource.split('__')[0], 10),
+ column: {
+ name: config.column,
+ },
+ }
+ ],
+ // TODO: test
+ defaultValue: defaultValues || getFilterBoxDefaultValues(config),
+ cascadeParentIds:[],
+ scope:{
+ "rootPath": scope,
+ "excluded": immune,
+ },
+ isInstant: instant_filtering,
+ }
+ filterConfig.push(entry);
+ });
+
+ metadata = metadata || {};
+ metadata.native_filter_configuration = filterConfig;
+ // done
+
+ // const componentId = chartIdToLayoutId[key];
+ // const directPathToFilter = (layout[componentId].parents || []).slice();
+ // directPathToFilter.push(componentId);
+ // dashboardFilters[key] = {
+ // ...dashboardFilter,
+ // chartId: key,
+ // componentId,
+ // datasourceId: slice.form_data.datasource,
+ // filterName: slice.slice_name,
+ // directPathToFilter,
+ // columns,
+ // labels,
+ // scopes: scopesByChartId,
+ // isInstantFilter: !!slice.form_data.instant_filtering,
+ // isDateFilter: Object.keys(columns).includes(TIME_RANGE),
+ // };
}
// sync layout names with current slice names in case a slice was edited
@@ -269,10 +481,10 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
layout[layoutId].meta.sliceName = slice.slice_name;
}
});
- buildActiveFilters({
- dashboardFilters,
- components: layout,
- });
+ // buildActiveFilters({
+ // dashboardFilters,
+ // components: layout,
+ // });
// store the header as a layout component so we can undo/redo changes
layout[DASHBOARD_HEADER_ID] = {
@@ -298,7 +510,7 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
}
const nativeFilters = getInitialNativeFilterState({
- filterConfig: metadata?.native_filter_configuration || [],
+ filterConfig,
filterSetsConfig: metadata?.filter_sets_configuration || [],
});
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
index bc1f78f..831dfd3 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
@@ -93,6 +93,8 @@ const ChartOverlay = styled.div`
top: 0;
left: 0;
z-index: 5;
+ opacity: 0.25;
+ background-color: #000;
`;
export default class Chart extends React.Component {
@@ -279,6 +281,7 @@ export default class Chart extends React.Component {
const { queriesResponse, chartUpdateEndTime, chartStatus } = chart;
const isLoading = chartStatus === 'loading';
+ const isDeactivated = slice.viz_type === 'filter_box'
// eslint-disable-next-line camelcase
const isCached = queriesResponse?.map(({ is_cached }) => is_cached) || [];
const cachedDttm =
@@ -350,7 +353,7 @@ export default class Chart extends React.Component {
isOverflowable && 'dashboard-chart--overflowable',
)}
>
- {isLoading && (
+ {(isLoading || isDeactivated) && (
<ChartOverlay
style={{
width,
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
index 4771f03..d5557d5 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
@@ -212,6 +212,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
const isApplyDisabled =
!isInitialized || areObjectsEqual(dataMaskSelected, lastAppliedFilterData);
+ console.log('is filter change:', isFilterSetChanged)
return (
<BarWrapper {...getFilterBarTestId()} className={cx({ open: filtersOpen })}>
<CollapsedBar
diff --git a/superset-frontend/src/explore/constants.ts b/superset-frontend/src/explore/constants.ts
index 06fa62c..bd0de27 100644
--- a/superset-frontend/src/explore/constants.ts
+++ b/superset-frontend/src/explore/constants.ts
@@ -80,6 +80,7 @@ export const TIME_FILTER_LABELS = {
};
export const FILTER_CONFIG_ATTRIBUTES = {
+ SORT_ASCENDING: 'asc',
DEFAULT_VALUE: 'defaultValue',
MULTIPLE: 'multiple',
SEARCH_ALL_OPTIONS: 'searchAllOptions',
diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts
index 6ca88dd..1df31db 100644
--- a/superset-frontend/src/filters/utils.ts
+++ b/superset-frontend/src/filters/utils.ts
@@ -33,15 +33,7 @@ export const getSelectExtraFormData = (
inverseSelection = false,
): ExtraFormData => {
const extra: ExtraFormData = {};
- if (emptyFilter) {
- extra.adhoc_filters = [
- {
- expressionType: 'SQL',
- clause: 'WHERE',
- sqlExpression: '1 = 0',
- },
- ];
- } else {
+ if (!emptyFilter) {
extra.filters =
value === undefined || value === null || value.length === 0
? []