From 2731518fe1b8f7d2c591145cf3a3ff8f838a6b9c Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Wed, 3 Mar 2021 14:24:00 +0200 Subject: [PATCH 01/21] refactor(native-filters): move data mask to root reducer --- superset-frontend/package-lock.json | 7 +- superset-frontend/package.json | 1 + .../src/chart/ChartContainer.jsx | 4 +- superset-frontend/src/chart/ChartRenderer.jsx | 7 +- .../src/dashboard/actions/nativeFilters.ts | 63 +++---------- .../components/FiltersBadge/selectors.ts | 7 +- .../FilterBar/CascadeFilterControl.tsx | 2 +- .../FilterBar/CascadePopover.tsx | 11 ++- .../nativeFilters/FilterBar/FilterBar.tsx | 46 +++++----- .../nativeFilters/FilterBar/state.ts | 33 ++----- .../nativeFilters/FilterBar/types.ts | 2 +- .../components/nativeFilters/utils.ts | 12 +-- .../src/dashboard/containers/Chart.jsx | 6 +- .../src/dashboard/containers/Dashboard.jsx | 6 +- .../src/dashboard/reducers/index.js | 2 + .../src/dashboard/reducers/nativeFilters.ts | 90 +------------------ .../src/dashboard/reducers/types.ts | 26 +----- .../util/activeDashboardNativeFilters.ts | 17 ++-- .../charts/getFormDataWithExtraFilters.ts | 21 +++-- superset-frontend/src/dataMask/actions.ts | 80 +++++++++++++++++ superset-frontend/src/dataMask/reducer.ts | 84 +++++++++++++++++ superset-frontend/src/dataMask/types.ts | 46 ++++++++++ 22 files changed, 322 insertions(+), 251 deletions(-) create mode 100644 superset-frontend/src/dataMask/actions.ts create mode 100644 superset-frontend/src/dataMask/reducer.ts create mode 100644 superset-frontend/src/dataMask/types.ts diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 2547c63d24e5e..8d43989587a83 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -59,6 +59,7 @@ "fontsource-inter": "^3.0.5", "geolib": "^2.0.24", "global-box": "^1.2.0", + "immer": "^8.0.1", "immutable": "^4.0.0-rc.12", "interweave": "^11.2.0", "jquery": "^3.5.1", @@ -32483,8 +32484,7 @@ "node_modules/immer": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", - "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==", - "dev": true + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" }, "node_modules/immutable": { "version": "4.0.0-rc.12", @@ -86415,8 +86415,7 @@ "immer": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", - "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==", - "dev": true + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" }, "immutable": { "version": "4.0.0-rc.12", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 5ef09e1010d2f..a6a5baa45fa2d 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -111,6 +111,7 @@ "fontsource-inter": "^3.0.5", "geolib": "^2.0.24", "global-box": "^1.2.0", + "immer": "^8.0.1", "immutable": "^4.0.0-rc.12", "interweave": "^11.2.0", "jquery": "^3.5.1", diff --git a/superset-frontend/src/chart/ChartContainer.jsx b/superset-frontend/src/chart/ChartContainer.jsx index 118acec4d5a22..9925986ad2f48 100644 --- a/superset-frontend/src/chart/ChartContainer.jsx +++ b/superset-frontend/src/chart/ChartContainer.jsx @@ -22,14 +22,14 @@ import { bindActionCreators } from 'redux'; import * as actions from './chartAction'; import { logEvent } from '../logger/actions'; import Chart from './Chart'; -import { updateExtraFormData } from '../dashboard/actions/nativeFilters'; +import { updateDataMask } from '../dataMask/actions'; function mapDispatchToProps(dispatch) { return { actions: bindActionCreators( { ...actions, - updateExtraFormData, + updateDataMask, logEvent, }, dispatch, diff --git a/superset-frontend/src/chart/ChartRenderer.jsx b/superset-frontend/src/chart/ChartRenderer.jsx index ca391bac95679..e94c1936b9c14 100644 --- a/superset-frontend/src/chart/ChartRenderer.jsx +++ b/superset-frontend/src/chart/ChartRenderer.jsx @@ -75,11 +75,8 @@ class ChartRenderer extends React.Component { setControlValue: this.handleSetControlValue, onFilterMenuOpen: this.props.onFilterMenuOpen, onFilterMenuClose: this.props.onFilterMenuClose, - setDataMask: filtersState => { - this.props.actions?.updateExtraFormData( - this.props.chartId, - filtersState, - ); + setDataMask: dataMask => { + this.props.actions?.updateDataMask(this.props.chartId, dataMask); }, }; } diff --git a/superset-frontend/src/dashboard/actions/nativeFilters.ts b/superset-frontend/src/dashboard/actions/nativeFilters.ts index 6b3c655f57565..f8df3d87790e9 100644 --- a/superset-frontend/src/dashboard/actions/nativeFilters.ts +++ b/superset-frontend/src/dashboard/actions/nativeFilters.ts @@ -17,16 +17,13 @@ * under the License. */ -import { makeApi, DataMask } from '@superset-ui/core'; +import { makeApi } from '@superset-ui/core'; import { Dispatch } from 'redux'; import { FilterConfiguration } from 'src/dashboard/components/nativeFilters/types'; import { dashboardInfoChanged } from './dashboardInfo'; -import { - FiltersState, - FilterState, - FiltersSet, - FilterStateType, -} from '../reducers/types'; +import { FiltersSet } from '../reducers/types'; +import { DataMaskType, MultipleDataMaskState } from '../../dataMask/types'; +import { SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE } from '../../dataMask/actions'; export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN'; export interface SetFilterConfigBegin { @@ -99,6 +96,10 @@ export const setFilterConfiguration = ( type: SET_FILTER_CONFIG_COMPLETE, filterConfig, }); + dispatch({ + type: SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE, + filterConfig, + }); } catch (err) { dispatch({ type: SET_FILTER_CONFIG_FAIL, filterConfig }); } @@ -143,62 +144,24 @@ export const setFilterSetsConfiguration = ( } }; -export const UPDATE_EXTRA_FORM_DATA = 'UPDATE_EXTRA_FORM_DATA'; -export interface UpdateExtraFormData { - type: typeof UPDATE_EXTRA_FORM_DATA; - filterId: string; - nativeFilters?: Omit; - crossFilters?: Omit; - ownFilters?: Omit; -} - export const SAVE_FILTER_SETS = 'SAVE_FILTER_SETS'; export interface SaveFilterSets { type: typeof SAVE_FILTER_SETS; name: string; - filtersState: Pick; + dataMask: Pick; filtersSetId: string; } -export const SET_FILTERS_STATE = 'SET_FILTERS_STATE'; -export interface SetFiltersState { - type: typeof SET_FILTERS_STATE; - filtersState: FiltersState; -} - -/** - * Sets the selected option(s) for a given filter - * @param filterId the id of the nativeFilters filter - * @param filterState - */ -export function updateExtraFormData( - filterId: string, - filterState: DataMask, -): UpdateExtraFormData { - return { - type: UPDATE_EXTRA_FORM_DATA, - filterId, - ...filterState, - }; -} - export function saveFilterSets( name: string, filtersSetId: string, - filtersState: Pick, + dataMask: Pick, ): SaveFilterSets { return { type: SAVE_FILTER_SETS, name, filtersSetId, - filtersState, - }; -} - -export function setFiltersState(filtersState: FiltersState): SetFiltersState { - return { - type: SET_FILTERS_STATE, - filtersState, + dataMask, }; } @@ -209,6 +172,4 @@ export type AnyFilterAction = | SetFilterSetsConfigBegin | SetFilterSetsConfigComplete | SetFilterSetsConfigFail - | SetFiltersState - | SaveFilterSets - | UpdateExtraFormData; + | SaveFilterSets; diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts index abef1afb36423..286fe90813c72 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts +++ b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts @@ -21,6 +21,7 @@ import { getChartIdsInFilterScope } from 'src/dashboard/util/activeDashboardFilt import { NativeFiltersState } from 'src/dashboard/reducers/types'; import { Layout } from '../../types'; import { getTreeCheckedItems } from '../nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils'; +import { MultipleDataMaskState } from '../../../dataMask/types'; export enum IndicatorStatus { Unset = 'UNSET', @@ -173,6 +174,7 @@ export const selectIndicatorsForChart = ( export const selectNativeIndicatorsForChart = ( nativeFilters: NativeFiltersState, + dataMask: MultipleDataMaskState, chartId: number, charts: any, dashboardLayout: Layout, @@ -210,9 +212,8 @@ export const selectNativeIndicatorsForChart = ( layoutItem => dashboardLayout[layoutItem]?.meta?.chartId === chartId, ); const column = nativeFilter.targets[0]?.column?.name; - const filterState = - nativeFilters.filtersState.nativeFilters?.[nativeFilter.id]; - let value = filterState?.currentState?.value ?? []; + const dataMaskNativeFilters = dataMask.nativeFilters?.[nativeFilter.id]; + let value = dataMaskNativeFilters?.currentState?.value ?? []; if (!Array.isArray(value)) { value = [value]; } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilterControl.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilterControl.tsx index 8d7f60f0a815c..a0e6d673a2259 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilterControl.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilterControl.tsx @@ -26,7 +26,7 @@ import { CascadeFilter } from './types'; interface CascadeFilterControlProps { filter: CascadeFilter; directPathToChild?: string[]; - onFilterSelectionChange: (filter: Filter, filterState: DataMask) => void; + onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void; } const StyledCascadeChildrenList = styled.ul` diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx index 0ab31ac8ca6bc..a7cd9c842d000 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx @@ -21,18 +21,20 @@ import { styled, t, DataMask } from '@superset-ui/core'; import Popover from 'src/common/components/Popover'; import Icon from 'src/components/Icon'; import { Pill } from 'src/dashboard/components/FiltersBadge/Styles'; -import { useFilterStateNative } from './state'; +import { useSelector } from 'react-redux'; import FilterControl from './FilterControl'; import CascadeFilterControl from './CascadeFilterControl'; import { CascadeFilter } from './types'; import { Filter } from '../types'; +import { getInitialMask } from '../../../../dataMask/reducer'; +import { MultipleMask } from '../../../../dataMask/types'; interface CascadePopoverProps { filter: CascadeFilter; visible: boolean; directPathToChild?: string[]; onVisibleChange: (visible: boolean) => void; - onFilterSelectionChange: (filter: Filter, filterState: DataMask) => void; + onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void; } const StyledTitleBox = styled.div` @@ -80,7 +82,10 @@ const CascadePopover: React.FC = ({ directPathToChild, }) => { const [currentPathToChild, setCurrentPathToChild] = useState(); - const filterStateNative = useFilterStateNative(filter.id); + const filterStateNative = useSelector( + state => + state.dataMask.nativeFilters[filter.id] ?? getInitialMask(filter.id), + ); useEffect(() => { setCurrentPathToChild(directPathToChild); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx index b1c403e641792..41a246e7dbdec 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx @@ -16,21 +16,25 @@ * specific language governing permissions and limitations * under the License. */ -import { styled, t, tn, DataMask } from '@superset-ui/core'; +import { styled, t, tn } from '@superset-ui/core'; import React, { useState, useEffect, useMemo, ChangeEvent } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import cx from 'classnames'; import Button from 'src/components/Button'; import Icon from 'src/components/Icon'; -import { FiltersSet, FilterState } from 'src/dashboard/reducers/types'; +import { FiltersSet } from 'src/dashboard/reducers/types'; import { Input, Select } from 'src/common/components'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; +import { setFilterSetsConfiguration } from 'src/dashboard/actions/nativeFilters'; +import { updateDataMask } from 'src/dataMask/actions'; import { - setFilterSetsConfiguration, - updateExtraFormData, -} from 'src/dashboard/actions/nativeFilters'; + MultipleDataMask, + MultipleMask, + SingleDataMask, + SingleDataMaskState, +} from 'src/dataMask/types'; import FilterConfigurationLink from './FilterConfigurationLink'; -import { useFilters, useFilterSets, useFiltersStateNative } from './state'; +import { useFilters, useFilterSets } from './state'; import { useFilterConfiguration } from '../state'; import { Filter } from '../types'; import { @@ -176,11 +180,11 @@ const FilterBar: React.FC = ({ toggleFiltersBar, directPathToChild, }) => { - const [filterData, setFilterData] = useState<{ - [filterId: string]: Omit; - }>({}); + const [filterData, setFilterData] = useState({}); const dispatch = useDispatch(); - const filtersStateNative = useFiltersStateNative(); + const dataMaskState = useSelector( + state => state.dataMask.nativeFilters ?? {}, + ); const filterSets = useFilterSets(); const filterConfigs = useFilterConfiguration(); const filterSetsConfigs = useSelector( @@ -232,21 +236,21 @@ const FilterBar: React.FC = ({ const handleFilterSelectionChange = ( filter: Pick & Partial, - filtersState: DataMask, + dataMask: Partial, ) => { setFilterData(prevFilterData => { const children = cascadeChildren[filter.id] || []; // force instant updating on initialization or for parent filters if (filter.isInstant || children.length > 0) { - dispatch(updateExtraFormData(filter.id, filtersState)); + dispatch(updateDataMask(filter.id, dataMask)); } - if (!filtersState.nativeFilters) { + if (!dataMask.nativeFilters) { return { ...prevFilterData }; } return { ...prevFilterData, - [filter.id]: filtersState.nativeFilters, + [filter.id]: dataMask.nativeFilters, }; }); }; @@ -257,9 +261,9 @@ const FilterBar: React.FC = ({ return; } const filtersSet = filterSets[value]; - Object.values(filtersSet.filtersState?.nativeFilters ?? []).forEach( - filterState => { - const { extraFormData, currentState, id } = filterState as FilterState; + Object.values(filtersSet.dataMask?.nativeFilters ?? []).forEach( + dataMask => { + const { extraFormData, currentState, id } = dataMask as MultipleMask; handleFilterSelectionChange( { id }, { nativeFilters: { extraFormData, currentState } }, @@ -273,7 +277,7 @@ const FilterBar: React.FC = ({ filterIds.forEach(filterId => { if (filterData[filterId]) { dispatch( - updateExtraFormData(filterId, { + updateDataMask(filterId, { nativeFilters: filterData[filterId], }), ); @@ -294,8 +298,8 @@ const FilterBar: React.FC = ({ { name: filtersSetName.trim(), id: generateFiltersSetId(), - filtersState: { - nativeFilters: filtersStateNative, + dataMask: { + nativeFilters: dataMaskState, }, }, ]), @@ -319,7 +323,7 @@ const FilterBar: React.FC = ({ const handleResetAll = () => { filterConfigs.forEach(filter => { dispatch( - updateExtraFormData(filter.id, { + updateDataMask(filter.id, { nativeFilters: { currentState: { ...filterData[filter.id]?.currentState, diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts index 316195d884316..53b3511a4f58f 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts @@ -17,13 +17,8 @@ * under the License. */ import { useSelector } from 'react-redux'; -import { getInitialFilterState } from 'src/dashboard/reducers/nativeFilters'; -import { - NativeFiltersState, - FilterState, - FilterSets, - FilterStates, -} from 'src/dashboard/reducers/types'; +import { NativeFiltersState, FilterSets } from 'src/dashboard/reducers/types'; +import { MultipleDataMaskState } from 'src/dataMask/types'; import { mergeExtraFormData } from '../utils'; import { Filter } from '../types'; @@ -31,12 +26,6 @@ export function useFilters() { return useSelector(state => state.nativeFilters.filters); } -export function useFiltersStateNative() { - return useSelector( - state => state.nativeFilters.filtersState.nativeFilters ?? {}, - ); -} - export function useFilterSets() { return useSelector( state => state.nativeFilters.filterSets ?? {}, @@ -44,10 +33,12 @@ export function useFilterSets() { } export function useCascadingFilters(id: string) { - const { - filters, - filtersState: { nativeFilters }, - } = useSelector(state => state.nativeFilters); + const { filters } = useSelector( + state => state.nativeFilters, + ); + const { nativeFilters } = useSelector( + state => state.dataMask, + ); const filter = filters[id]; const cascadeParentIds: string[] = filter?.cascadeParentIds ?? []; let cascadedFilters = {}; @@ -60,11 +51,3 @@ export function useCascadingFilters(id: string) { }); return cascadedFilters; } - -export function useFilterStateNative(id: string) { - return useSelector( - state => - state.nativeFilters.filtersState.nativeFilters[id] ?? - getInitialFilterState(id), - ); -} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts index 404eb419fc829..896aa47a55efd 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts @@ -24,7 +24,7 @@ export interface FilterProps { filter: Filter; icon?: React.ReactElement; directPathToChild?: string[]; - onFilterSelectionChange: (filter: Filter, filterState: DataMask) => void; + onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void; } export interface CascadeFilter extends Filter { diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts index e63d484e52259..ffcef497dffd3 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts @@ -27,7 +27,7 @@ import { Charts } from 'src/dashboard/types'; import { RefObject } from 'react'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { Filter } from './types'; -import { NativeFiltersState } from '../../reducers/types'; +import { MultipleDataMaskState } from '../../../dataMask/types'; export const getFormData = ({ datasetId, @@ -117,21 +117,21 @@ export function isCrossFilter(vizType: string) { } export function getExtraFormData( - nativeFilters: NativeFiltersState, + dataMask: MultipleDataMaskState, charts: Charts, filterIdsAppliedOnChart: string[], ): ExtraFormData { let extraFormData: ExtraFormData = {}; filterIdsAppliedOnChart.forEach(key => { - const filterState = nativeFilters.filtersState.nativeFilters[key] || {}; - const { extraFormData: newExtra = {} } = filterState; + const singleDataMask = dataMask.nativeFilters[key] || {}; + const { extraFormData: newExtra = {} } = singleDataMask; extraFormData = mergeExtraFormData(extraFormData, newExtra); }); if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) { Object.entries(charts).forEach(([key, chart]) => { if (isCrossFilter(chart?.formData?.viz_type)) { - const filterState = nativeFilters.filtersState.crossFilters[key] || {}; - const { extraFormData: newExtra = {} } = filterState; + const singleDataMask = dataMask.crossFilters[key] || {}; + const { extraFormData: newExtra = {} } = singleDataMask; extraFormData = mergeExtraFormData(extraFormData, newExtra); } }); diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx b/superset-frontend/src/dashboard/containers/Chart.jsx index 0e39dc2f21ede..a56ad4cb69210 100644 --- a/superset-frontend/src/dashboard/containers/Chart.jsx +++ b/superset-frontend/src/dashboard/containers/Chart.jsx @@ -44,6 +44,7 @@ function mapStateToProps( dashboardInfo, dashboardState, dashboardLayout, + dataMask, datasources, sliceEntities, nativeFilters, @@ -65,7 +66,8 @@ function mapStateToProps( colorScheme, colorNamespace, sliceId: id, - nativeFilters, + nativeFilters: nativeFilters.filters, + dataMask, }); formData.dashboardId = dashboardInfo.id; @@ -82,7 +84,7 @@ function mapStateToProps( supersetCanExplore: !!dashboardInfo.superset_can_explore, supersetCanCSV: !!dashboardInfo.superset_can_csv, sliceCanEdit: !!dashboardInfo.slice_can_edit, - ownCurrentState: nativeFilters.filtersState.ownFilters?.[id]?.currentState, + ownCurrentState: dataMask.ownFilters?.[id]?.currentState, }; } diff --git a/superset-frontend/src/dashboard/containers/Dashboard.jsx b/superset-frontend/src/dashboard/containers/Dashboard.jsx index 90e7734729a25..e2bf97b8029ee 100644 --- a/superset-frontend/src/dashboard/containers/Dashboard.jsx +++ b/superset-frontend/src/dashboard/containers/Dashboard.jsx @@ -35,6 +35,7 @@ function mapStateToProps(state) { datasources, sliceEntities, charts, + dataMask, dashboardInfo, dashboardState, dashboardLayout, @@ -58,11 +59,12 @@ function mapStateToProps(state) { activeFilters: { ...getActiveFilters(), ...getActiveNativeFilters({ - nativeFilters, + filters: nativeFilters.filters, + dataMask, layout: dashboardLayout.present, }), }, - ownDataCharts: nativeFilters.filtersState.ownFilters ?? {}, + ownDataCharts: dataMask.ownFilters ?? {}, slices: sliceEntities.slices, layout: dashboardLayout.present, impressionId, diff --git a/superset-frontend/src/dashboard/reducers/index.js b/superset-frontend/src/dashboard/reducers/index.js index 61964de92e60e..1932fab7e1ea7 100644 --- a/superset-frontend/src/dashboard/reducers/index.js +++ b/superset-frontend/src/dashboard/reducers/index.js @@ -19,6 +19,7 @@ import { combineReducers } from 'redux'; import charts from '../../chart/chartReducer'; +import dataMask from '../../dataMask/reducer'; import dashboardInfo from './dashboardInfo'; import dashboardState from './dashboardState'; import dashboardFilters from './dashboardFilters'; @@ -35,6 +36,7 @@ export default combineReducers({ datasources, dashboardInfo, dashboardFilters, + dataMask, nativeFilters, dashboardState, dashboardLayout, diff --git a/superset-frontend/src/dashboard/reducers/nativeFilters.ts b/superset-frontend/src/dashboard/reducers/nativeFilters.ts index 59ed13576589c..92d0708ce4732 100644 --- a/superset-frontend/src/dashboard/reducers/nativeFilters.ts +++ b/superset-frontend/src/dashboard/reducers/nativeFilters.ts @@ -21,27 +21,10 @@ import { SAVE_FILTER_SETS, SET_FILTER_CONFIG_COMPLETE, SET_FILTER_SETS_CONFIG_COMPLETE, - SET_FILTERS_STATE, - UPDATE_EXTRA_FORM_DATA, - UpdateExtraFormData, } from 'src/dashboard/actions/nativeFilters'; -import { - FiltersSet, - FiltersState, - FilterState, - FilterStateType, - NativeFiltersState, -} from './types'; +import { FiltersSet, NativeFiltersState } from './types'; import { FilterConfiguration } from '../components/nativeFilters/types'; -export function getInitialFilterState(id: string): FilterState { - return { - id, - extraFormData: {}, - currentState: {}, - }; -} - export function getInitialState({ filterSetsConfig, filterConfig, @@ -53,30 +36,15 @@ export function getInitialState({ }): NativeFiltersState { const state: Partial = {}; - const emptyFiltersState = { - [FilterStateType.NativeFilters]: {}, - [FilterStateType.CrossFilters]: {}, - [FilterStateType.OwnFilters]: {}, - }; - const filters = {}; - const filtersState = { ...emptyFiltersState }; if (filterConfig) { filterConfig.forEach(filter => { const { id } = filter; filters[id] = filter; - filtersState.nativeFilters[id] = - prevState?.filtersState?.nativeFilters[id] || getInitialFilterState(id); }); state.filters = filters; - state.filtersState = { - ...emptyFiltersState, - ...prevState?.filtersState, - nativeFilters: filtersState.nativeFilters, - }; } else { state.filters = prevState?.filters ?? {}; - state.filtersState = prevState?.filtersState ?? { ...emptyFiltersState }; } if (filterSetsConfig) { @@ -92,59 +60,15 @@ export function getInitialState({ return state as NativeFiltersState; } -const getUnitState = ( - unitName: FilterStateType, - action: UpdateExtraFormData, - filtersState: FiltersState, -) => { - if (action[unitName]) - return { - ...filtersState[unitName], - [action.filterId]: { - ...filtersState[unitName][action.filterId], - ...action[unitName], - }, - }; - return { ...filtersState[unitName] }; -}; - export default function nativeFilterReducer( state: NativeFiltersState = { filters: {}, filterSets: {}, - filtersState: { - [FilterStateType.NativeFilters]: {}, - [FilterStateType.CrossFilters]: {}, - [FilterStateType.OwnFilters]: {}, - }, }, action: AnyFilterAction, ) { - const { filters, filtersState, filterSets } = state; + const { filterSets } = state; switch (action.type) { - case UPDATE_EXTRA_FORM_DATA: - return { - ...state, - filters, - filtersState: { - ...filtersState, - [FilterStateType.NativeFilters]: getUnitState( - FilterStateType.NativeFilters, - action, - filtersState, - ), - [FilterStateType.CrossFilters]: getUnitState( - FilterStateType.CrossFilters, - action, - filtersState, - ), - [FilterStateType.OwnFilters]: getUnitState( - FilterStateType.OwnFilters, - action, - filtersState, - ), - }, - }; case SAVE_FILTER_SETS: return { ...state, @@ -153,18 +77,10 @@ export default function nativeFilterReducer( [action.filtersSetId]: { id: action.filtersSetId, name: action.name, - filtersState: action.filtersState, + dataMask: action.dataMask, }, }, }; - case SET_FILTERS_STATE: - return { - ...state, - filtersState: { - ...filtersState, - ...action.filtersState, - }, - }; case SET_FILTER_CONFIG_COMPLETE: return getInitialState({ filterConfig: action.filterConfig, state }); diff --git a/superset-frontend/src/dashboard/reducers/types.ts b/superset-frontend/src/dashboard/reducers/types.ts index 03e273f9e44b5..5292e1e33a27f 100644 --- a/superset-frontend/src/dashboard/reducers/types.ts +++ b/superset-frontend/src/dashboard/reducers/types.ts @@ -18,8 +18,8 @@ */ import componentTypes from 'src/dashboard/util/componentTypes'; -import { ExtraFormData, DataMaskCurrentState } from '@superset-ui/core'; import { Filter } from '../components/nativeFilters/types'; +import { MultipleDataMaskState } from '../../dataMask/types'; export enum Scoping { all, @@ -67,43 +67,21 @@ export type LayoutItem = { }; }; -/** Current state of the filter, stored in `nativeFilters` in redux */ -export type FilterState = { - id: string; // ties this filter state to the config object - extraFormData?: ExtraFormData; - currentState: DataMaskCurrentState; -}; - export type FiltersSet = { id: string; name: string; - filtersState: Partial; + dataMask: Partial; }; export type FilterSets = { [filtersSetId: string]: FiltersSet; }; -export type FilterStates = { [filterId: string]: FilterState }; - -export enum FilterStateType { - NativeFilters = 'nativeFilters', - CrossFilters = 'crossFilters', - OwnFilters = 'ownFilters', -} - -export type FiltersState = { - [FilterStateType.NativeFilters]: FilterStates; - [FilterStateType.CrossFilters]: FilterStates; - [FilterStateType.OwnFilters]: FilterStates; -}; - export type Filters = { [filterId: string]: Filter; }; export type NativeFiltersState = { filters: Filters; - filtersState: FiltersState; filterSets: FilterSets; }; diff --git a/superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts b/superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts index af8954d43f612..e2f50afc0b3e7 100644 --- a/superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts +++ b/superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts @@ -19,8 +19,9 @@ import { CHART_TYPE } from './componentTypes'; import { Scope } from '../components/nativeFilters/types'; import { ActiveFilters, LayoutItem } from '../types'; -import { NativeFiltersState } from '../reducers/types'; +import { Filters } from '../reducers/types'; import { DASHBOARD_ROOT_ID } from './constants'; +import { MultipleDataMaskState } from '../../dataMask/types'; // Looking for affected chart scopes and values export const findAffectedCharts = ({ @@ -71,22 +72,24 @@ export const findAffectedCharts = ({ }; export const getActiveNativeFilters = ({ - nativeFilters, + filters, + dataMask, layout, }: { - nativeFilters: NativeFiltersState; + dataMask: MultipleDataMaskState; + filters: Filters; layout: { [key: string]: LayoutItem }; }): ActiveFilters => { const activeNativeFilters = {}; - if (!nativeFilters?.filtersState?.nativeFilters) { + if (!dataMask?.nativeFilters) { return activeNativeFilters; } Object.values({ - ...nativeFilters.filtersState.nativeFilters, - ...nativeFilters.filtersState.crossFilters, + ...dataMask.nativeFilters, + ...dataMask.crossFilters, }).forEach(({ id: filterId, extraFormData }) => { // TODO: for a case of a cross filters (should be updated will be added scope there) - const scope = nativeFilters?.filters?.[filterId]?.scope ?? { + const scope = filters?.[filterId]?.scope ?? { rootPath: [DASHBOARD_ROOT_ID], excluded: [], }; diff --git a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts index b3d78272b1d4d..0451b9eb85f55 100644 --- a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts +++ b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts @@ -27,9 +27,10 @@ import { getExtraFormData, mergeExtraFormData, } from 'src/dashboard/components/nativeFilters/utils'; +import { MultipleDataMaskState } from 'src/dataMask/types'; import getEffectiveExtraFilters from './getEffectiveExtraFilters'; import { getActiveNativeFilters } from '../activeDashboardNativeFilters'; -import { NativeFiltersState } from '../../reducers/types'; +import { Filters } from '../../reducers/types'; // We cache formData objects so that our connected container components don't always trigger // render cascades. we cannot leverage the reselect library because our cache size is >1 @@ -44,7 +45,8 @@ export interface GetFormDataWithExtraFiltersArguments { colorScheme?: string; colorNamespace?: string; sliceId: number; - nativeFilters: NativeFiltersState; + dataMask: MultipleDataMaskState; + nativeFilters: Filters; } // this function merge chart's formData with dashboard filters value, @@ -54,11 +56,12 @@ export default function getFormDataWithExtraFilters({ chart, charts, filters, + nativeFilters, colorScheme, colorNamespace, sliceId, layout, - nativeFilters, + dataMask, }: GetFormDataWithExtraFiltersArguments) { // Propagate color mapping to chart const scale = CategoricalColorNamespace.getScale(colorScheme, colorNamespace); @@ -72,20 +75,24 @@ export default function getFormDataWithExtraFilters({ cachedFormdataByChart[sliceId].color_namespace === colorNamespace && isEqual(cachedFormdataByChart[sliceId].label_colors, labelColors) && !!cachedFormdataByChart[sliceId] && - nativeFilters === undefined + dataMask === undefined ) { return cachedFormdataByChart[sliceId]; } let extraData: { extra_form_data?: JsonObject } = {}; - const activeNativeFilters = getActiveNativeFilters({ nativeFilters, layout }); + const activeNativeFilters = getActiveNativeFilters({ + dataMask, + layout, + filters: nativeFilters, + }); const filterIdsAppliedOnChart = Object.entries(activeNativeFilters) .filter(([, { scope }]) => scope.includes(chart.id)) .map(([filterId]) => filterId); if (filterIdsAppliedOnChart.length) { extraData = { extra_form_data: getExtraFormData( - nativeFilters, + dataMask, charts, filterIdsAppliedOnChart, ), @@ -93,7 +100,7 @@ export default function getFormDataWithExtraFilters({ } const { extraFormData: newExtra = {} } = - nativeFilters.filtersState?.ownFilters?.[chart.id] ?? {}; + dataMask?.ownFilters?.[chart.id] ?? {}; extraData.extra_form_data = mergeExtraFormData( extraData?.extra_form_data, newExtra, diff --git a/superset-frontend/src/dataMask/actions.ts b/superset-frontend/src/dataMask/actions.ts new file mode 100644 index 0000000000000..19a3642a4866d --- /dev/null +++ b/superset-frontend/src/dataMask/actions.ts @@ -0,0 +1,80 @@ +/** + * 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 { + MultipleMask, + SingleDataMaskState, + MultipleDataMaskState, +} from './types'; +import { FilterConfiguration } from '../dashboard/components/nativeFilters/types'; + +export const SET_DATA_MASK = 'SET_DATA_MASK'; +export interface SetDataMask { + type: typeof SET_DATA_MASK; + dataMask: MultipleDataMaskState; +} + +export const UPDATE_DATA_MASK = 'UPDATE_DATA_MASK'; +export interface UpdateDataMask { + type: typeof UPDATE_DATA_MASK; + filterId: string; + nativeFilters?: Omit; + crossFilters?: Omit; + ownFilters?: Omit; +} + +export const SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE = + 'SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE'; +export interface SetDataMaskForFilterConfigComplete { + type: typeof SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE; + filterConfig: FilterConfiguration; +} +export const SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL = + 'SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL'; +export interface SetDataMaskForFilterConfigFail { + type: typeof SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL; + filterConfig: FilterConfiguration; +} + +export function updateDataMask( + filterId: string, + dataMask: { + nativeFilters?: Omit; + crossFilters?: Omit; + ownFilters?: Omit; + }, +): UpdateDataMask { + return { + type: UPDATE_DATA_MASK, + filterId, + ...dataMask, + }; +} + +export function setDataMask(dataMask: MultipleDataMaskState): SetDataMask { + return { + type: SET_DATA_MASK, + dataMask, + }; +} + +export type AnyDataMaskAction = + | SetDataMask + | UpdateDataMask + | SetDataMaskForFilterConfigFail + | SetDataMaskForFilterConfigComplete; diff --git a/superset-frontend/src/dataMask/reducer.ts b/superset-frontend/src/dataMask/reducer.ts new file mode 100644 index 0000000000000..739d0b2f1eb77 --- /dev/null +++ b/superset-frontend/src/dataMask/reducer.ts @@ -0,0 +1,84 @@ +/** + * 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. + */ + +/* eslint-disable no-param-reassign */ +import produce from 'immer'; +import { MultipleMask, DataMaskType, MultipleDataMaskState } from './types'; +import { + AnyDataMaskAction, + SET_DATA_MASK, + SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE, + UPDATE_DATA_MASK, + UpdateDataMask, +} from './actions'; + +export function getInitialMask(id: string): MultipleMask { + return { + id, + extraFormData: {}, + currentState: {}, + }; +} + +const setUnitDataMask = ( + unitName: DataMaskType, + action: UpdateDataMask, + dataMaskState: MultipleDataMaskState, +) => { + if (action[unitName]) { + dataMaskState[unitName][action.filterId] = { + ...dataMaskState[unitName][action.filterId], + ...action[unitName], + }; + } +}; + +const dataMaskReducer = produce( + ( + draft: MultipleDataMaskState = { + [DataMaskType.NativeFilters]: {}, + [DataMaskType.CrossFilters]: {}, + [DataMaskType.OwnFilters]: {}, + }, + action: AnyDataMaskAction, + ) => { + switch (action.type) { + case UPDATE_DATA_MASK: + Object.values(DataMaskType).forEach(unitName => + setUnitDataMask(unitName, action, draft), + ); + break; + + case SET_DATA_MASK: + draft = action.dataMask; + break; + + case SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE: + (action.filterConfig ?? []).forEach(({ id }) => { + draft[DataMaskType.NativeFilters][id] = + draft[DataMaskType.NativeFilters][id] ?? getInitialMask(id); + }); + break; + + default: + } + }, +); + +export default dataMaskReducer; diff --git a/superset-frontend/src/dataMask/types.ts b/superset-frontend/src/dataMask/types.ts new file mode 100644 index 0000000000000..1e9b756c8553e --- /dev/null +++ b/superset-frontend/src/dataMask/types.ts @@ -0,0 +1,46 @@ +/** + * 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 { ExtraFormData, DataMaskCurrentState } from '@superset-ui/core'; + +export enum DataMaskType { + NativeFilters = 'nativeFilters', + CrossFilters = 'crossFilters', + OwnFilters = 'ownFilters', +} + +export type SingleMask = { + extraFormData?: ExtraFormData; + currentState: DataMaskCurrentState; +}; + +export type MultipleMask = SingleMask & { id: string }; + +export type MultipleDataMask = { [filterId: string]: MultipleMask }; +export type MultipleDataMaskState = { + [DataMaskType.NativeFilters]: MultipleDataMask; + [DataMaskType.CrossFilters]: MultipleDataMask; + [DataMaskType.OwnFilters]: MultipleDataMask; +}; + +export type SingleDataMask = { [filterId: string]: SingleMask }; +export type SingleDataMaskState = { + [DataMaskType.NativeFilters]: SingleMask; + [DataMaskType.CrossFilters]: SingleMask; + [DataMaskType.OwnFilters]: SingleMask; +}; From 6652d198ce0eeff9d2a4f026d40e19c053cb0294 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Wed, 3 Mar 2021 15:28:57 +0200 Subject: [PATCH 02/21] refactor: update rest stuff for dataMask --- superset-frontend/package-lock.json | 4 ++ .../spec/fixtures/mockNativeFilters.ts | 48 ++++++++++--------- superset-frontend/spec/fixtures/mockStore.js | 4 +- .../util/getFormDataWithExtraFilters_spec.ts | 18 +++---- .../src/dashboard/containers/FiltersBadge.tsx | 2 + .../charts/getFormDataWithExtraFilters.ts | 6 +-- superset-frontend/src/dataMask/actions.ts | 6 +-- superset-frontend/src/dataMask/reducer.ts | 15 +++--- 8 files changed, 54 insertions(+), 49 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 8d43989587a83..739540d55123d 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -23776,6 +23776,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, + "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -35073,6 +35074,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, + "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -54863,6 +54865,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, + "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -55908,6 +55911,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, + "hasInstallScript": true, "optional": true, "os": [ "darwin" diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts index b60bff23b58c8..d3a32857fed1e 100644 --- a/superset-frontend/spec/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts @@ -17,6 +17,7 @@ * under the License. */ import { NativeFiltersState } from 'src/dashboard/reducers/types'; +import { MultipleDataMaskState } from '../../src/dataMask/types'; export const nativeFilters: NativeFiltersState = { filterSets: {}, @@ -72,33 +73,34 @@ export const nativeFilters: NativeFiltersState = { isInstant: true, }, }, - filtersState: { - crossFilters: {}, - ownFilters: {}, - nativeFilters: { - 'NATIVE_FILTER-e7Q8zKixx': { - id: 'NATIVE_FILTER-e7Q8zKixx', - extraFormData: { - append_form_data: { - filters: [ - { - col: 'region', - op: 'IN', - val: ['East Asia & Pacific'], - }, - ], - }, - }, - currentState: { - value: ['East Asia & Pacific'], +}; + +export const datMask: MultipleDataMaskState = { + crossFilters: {}, + ownFilters: {}, + nativeFilters: { + 'NATIVE_FILTER-e7Q8zKixx': { + id: 'NATIVE_FILTER-e7Q8zKixx', + extraFormData: { + append_form_data: { + filters: [ + { + col: 'region', + op: 'IN', + val: ['East Asia & Pacific'], + }, + ], }, }, - 'NATIVE_FILTER-x9QPw0so1': { - id: 'NATIVE_FILTER-x9QPw0so1', - extraFormData: {}, - currentState: {}, + currentState: { + value: ['East Asia & Pacific'], }, }, + 'NATIVE_FILTER-x9QPw0so1': { + id: 'NATIVE_FILTER-x9QPw0so1', + extraFormData: {}, + currentState: {}, + }, }, }; diff --git a/superset-frontend/spec/fixtures/mockStore.js b/superset-frontend/spec/fixtures/mockStore.js index 2b34ff390ea31..6e12b5f0ed9ba 100644 --- a/superset-frontend/spec/fixtures/mockStore.js +++ b/superset-frontend/spec/fixtures/mockStore.js @@ -28,7 +28,7 @@ import { } from './mockDashboardLayout'; import { sliceId } from './mockChartQueries'; import { dashboardFilters } from './mockDashboardFilters'; -import { nativeFilters } from './mockNativeFilters'; +import { nativeFilters, dataMask } from './mockNativeFilters'; export const storeWithState = state => createStore(rootReducer, state, compose(applyMiddleware(thunk))); @@ -77,6 +77,7 @@ export const getMockStoreWithFilters = () => createStore(rootReducer, { ...mockState, dashboardFilters, + dataMask, charts: { ...mockState.charts, [sliceIdWithAppliedFilter]: { @@ -102,6 +103,7 @@ export const getMockStoreWithNativeFilters = () => createStore(rootReducer, { ...mockState, nativeFilters, + dataMask, charts: { ...mockState.charts, [sliceIdWithAppliedFilter]: { diff --git a/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts b/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts index 7f538fba4fa45..18242e32491a3 100644 --- a/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts +++ b/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts @@ -61,15 +61,15 @@ describe('getFormDataWithExtraFilters', () => { }, } as unknown) as Filter, }, - filtersState: { - crossFilters: {}, - ownFilters: {}, - nativeFilters: { - [filterId]: { - id: filterId, - extraFormData: {}, - currentState: {}, - }, + }, + dataMask: { + crossFilters: {}, + ownFilters: {}, + nativeFilters: { + [filterId]: { + id: filterId, + extraFormData: {}, + currentState: {}, }, }, }, diff --git a/superset-frontend/src/dashboard/containers/FiltersBadge.tsx b/superset-frontend/src/dashboard/containers/FiltersBadge.tsx index 6a888f23ce08b..c38e320bae246 100644 --- a/superset-frontend/src/dashboard/containers/FiltersBadge.tsx +++ b/superset-frontend/src/dashboard/containers/FiltersBadge.tsx @@ -57,6 +57,7 @@ const mapStateToProps = ( dashboardFilters, nativeFilters, charts, + dataMask, dashboardLayout: { present }, }: any, { chartId }: FiltersBadgeProps, @@ -70,6 +71,7 @@ const mapStateToProps = ( const nativeIndicators = selectNativeIndicatorsForChart( nativeFilters, + dataMask, chartId, charts, present, diff --git a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts index 0451b9eb85f55..4c5f1550a78a5 100644 --- a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts +++ b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts @@ -30,7 +30,7 @@ import { import { MultipleDataMaskState } from 'src/dataMask/types'; import getEffectiveExtraFilters from './getEffectiveExtraFilters'; import { getActiveNativeFilters } from '../activeDashboardNativeFilters'; -import { Filters } from '../../reducers/types'; +import { NativeFiltersState } from '../../reducers/types'; // We cache formData objects so that our connected container components don't always trigger // render cascades. we cannot leverage the reselect library because our cache size is >1 @@ -46,7 +46,7 @@ export interface GetFormDataWithExtraFiltersArguments { colorNamespace?: string; sliceId: number; dataMask: MultipleDataMaskState; - nativeFilters: Filters; + nativeFilters: NativeFiltersState; } // this function merge chart's formData with dashboard filters value, @@ -84,7 +84,7 @@ export default function getFormDataWithExtraFilters({ const activeNativeFilters = getActiveNativeFilters({ dataMask, layout, - filters: nativeFilters, + filters: nativeFilters.filters, }); const filterIdsAppliedOnChart = Object.entries(activeNativeFilters) .filter(([, { scope }]) => scope.includes(chart.id)) diff --git a/superset-frontend/src/dataMask/actions.ts b/superset-frontend/src/dataMask/actions.ts index 19a3642a4866d..b624d4624be72 100644 --- a/superset-frontend/src/dataMask/actions.ts +++ b/superset-frontend/src/dataMask/actions.ts @@ -16,11 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { - MultipleMask, - SingleDataMaskState, - MultipleDataMaskState, -} from './types'; +import { MultipleMask, MultipleDataMaskState } from './types'; import { FilterConfiguration } from '../dashboard/components/nativeFilters/types'; export const SET_DATA_MASK = 'SET_DATA_MASK'; diff --git a/superset-frontend/src/dataMask/reducer.ts b/superset-frontend/src/dataMask/reducer.ts index 739d0b2f1eb77..7e40f32e9da27 100644 --- a/superset-frontend/src/dataMask/reducer.ts +++ b/superset-frontend/src/dataMask/reducer.ts @@ -45,19 +45,13 @@ const setUnitDataMask = ( dataMaskState[unitName][action.filterId] = { ...dataMaskState[unitName][action.filterId], ...action[unitName], + id: action.filterId, }; } }; const dataMaskReducer = produce( - ( - draft: MultipleDataMaskState = { - [DataMaskType.NativeFilters]: {}, - [DataMaskType.CrossFilters]: {}, - [DataMaskType.OwnFilters]: {}, - }, - action: AnyDataMaskAction, - ) => { + (draft: MultipleDataMaskState, action: AnyDataMaskAction) => { switch (action.type) { case UPDATE_DATA_MASK: Object.values(DataMaskType).forEach(unitName => @@ -79,6 +73,11 @@ const dataMaskReducer = produce( default: } }, + { + [DataMaskType.NativeFilters]: {}, + [DataMaskType.CrossFilters]: {}, + [DataMaskType.OwnFilters]: {}, + }, ); export default dataMaskReducer; From 266a0a39c8550fb300ee304af08f2b132d0e9c99 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Wed, 3 Mar 2021 15:56:57 +0200 Subject: [PATCH 03/21] refactor: add ownCrrentState to explore --- superset-frontend/src/chart/ChartRenderer.jsx | 1 + .../src/explore/components/ExploreChartPanel.jsx | 2 ++ .../src/explore/components/ExploreViewContainer.jsx | 4 +++- superset-frontend/src/explore/reducers/index.js | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/superset-frontend/src/chart/ChartRenderer.jsx b/superset-frontend/src/chart/ChartRenderer.jsx index e94c1936b9c14..bb9857861346c 100644 --- a/superset-frontend/src/chart/ChartRenderer.jsx +++ b/superset-frontend/src/chart/ChartRenderer.jsx @@ -94,6 +94,7 @@ class ChartRenderer extends React.Component { return ( this.hasQueryResponseChange || nextProps.annotationData !== this.props.annotationData || + nextProps.ownCurrentState !== this.props.ownCurrentState || nextProps.height !== this.props.height || nextProps.width !== this.props.width || nextProps.triggerRender || diff --git a/superset-frontend/src/explore/components/ExploreChartPanel.jsx b/superset-frontend/src/explore/components/ExploreChartPanel.jsx index e84b5c4301459..779f515ab1d0f 100644 --- a/superset-frontend/src/explore/components/ExploreChartPanel.jsx +++ b/superset-frontend/src/explore/components/ExploreChartPanel.jsx @@ -47,6 +47,7 @@ const propTypes = { table_name: PropTypes.string, vizType: PropTypes.string.isRequired, form_data: PropTypes.object, + ownCurrentState: PropTypes.object, standalone: PropTypes.number, timeout: PropTypes.number, refreshOverlayVisible: PropTypes.bool, @@ -189,6 +190,7 @@ const ExploreChartPanel = props => { state; @@ -28,6 +29,7 @@ const impressionId = (state = '') => state; export default combineReducers({ charts, saveModal, + dataMask, explore, impressionId, messageToasts, From 5344dd4b65073b4edb13395b58db11d57629580a Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 09:37:55 +0200 Subject: [PATCH 04/21] fix: fix immer reducer --- .../src/dashboard/actions/nativeFilters.ts | 6 ++++- superset-frontend/src/dataMask/actions.ts | 16 +---------- superset-frontend/src/dataMask/reducer.ts | 27 ++++++++++--------- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/superset-frontend/src/dashboard/actions/nativeFilters.ts b/superset-frontend/src/dashboard/actions/nativeFilters.ts index f8df3d87790e9..98b3d40dac36f 100644 --- a/superset-frontend/src/dashboard/actions/nativeFilters.ts +++ b/superset-frontend/src/dashboard/actions/nativeFilters.ts @@ -23,7 +23,10 @@ import { FilterConfiguration } from 'src/dashboard/components/nativeFilters/type import { dashboardInfoChanged } from './dashboardInfo'; import { FiltersSet } from '../reducers/types'; import { DataMaskType, MultipleDataMaskState } from '../../dataMask/types'; -import { SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE } from '../../dataMask/actions'; +import { + SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE, + SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL, +} from '../../dataMask/actions'; export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN'; export interface SetFilterConfigBegin { @@ -102,6 +105,7 @@ export const setFilterConfiguration = ( }); } catch (err) { dispatch({ type: SET_FILTER_CONFIG_FAIL, filterConfig }); + dispatch({ type: SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL, filterConfig }); } }; diff --git a/superset-frontend/src/dataMask/actions.ts b/superset-frontend/src/dataMask/actions.ts index b624d4624be72..be4ba79574dba 100644 --- a/superset-frontend/src/dataMask/actions.ts +++ b/superset-frontend/src/dataMask/actions.ts @@ -16,15 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import { MultipleMask, MultipleDataMaskState } from './types'; +import { MultipleMask } from './types'; import { FilterConfiguration } from '../dashboard/components/nativeFilters/types'; -export const SET_DATA_MASK = 'SET_DATA_MASK'; -export interface SetDataMask { - type: typeof SET_DATA_MASK; - dataMask: MultipleDataMaskState; -} - export const UPDATE_DATA_MASK = 'UPDATE_DATA_MASK'; export interface UpdateDataMask { type: typeof UPDATE_DATA_MASK; @@ -62,15 +56,7 @@ export function updateDataMask( }; } -export function setDataMask(dataMask: MultipleDataMaskState): SetDataMask { - return { - type: SET_DATA_MASK, - dataMask, - }; -} - export type AnyDataMaskAction = - | SetDataMask | UpdateDataMask | SetDataMaskForFilterConfigFail | SetDataMaskForFilterConfigComplete; diff --git a/superset-frontend/src/dataMask/reducer.ts b/superset-frontend/src/dataMask/reducer.ts index 7e40f32e9da27..b7d4c1a89cf8f 100644 --- a/superset-frontend/src/dataMask/reducer.ts +++ b/superset-frontend/src/dataMask/reducer.ts @@ -22,7 +22,6 @@ import produce from 'immer'; import { MultipleMask, DataMaskType, MultipleDataMaskState } from './types'; import { AnyDataMaskAction, - SET_DATA_MASK, SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE, UPDATE_DATA_MASK, UpdateDataMask, @@ -50,6 +49,12 @@ const setUnitDataMask = ( } }; +const emptyDataMask = { + [DataMaskType.NativeFilters]: {}, + [DataMaskType.CrossFilters]: {}, + [DataMaskType.OwnFilters]: {}, +}; + const dataMaskReducer = produce( (draft: MultipleDataMaskState, action: AnyDataMaskAction) => { switch (action.type) { @@ -59,25 +64,21 @@ const dataMaskReducer = produce( ); break; - case SET_DATA_MASK: - draft = action.dataMask; - break; - case SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE: - (action.filterConfig ?? []).forEach(({ id }) => { - draft[DataMaskType.NativeFilters][id] = - draft[DataMaskType.NativeFilters][id] ?? getInitialMask(id); + Object.values(DataMaskType).forEach(unitName => { + draft[unitName] = emptyDataMask[unitName]; + }); + (action.filterConfig ?? []).forEach(filter => { + draft[DataMaskType.NativeFilters][filter.id] = + draft[DataMaskType.NativeFilters][filter.id] ?? + getInitialMask(filter.id); }); break; default: } }, - { - [DataMaskType.NativeFilters]: {}, - [DataMaskType.CrossFilters]: {}, - [DataMaskType.OwnFilters]: {}, - }, + emptyDataMask, ); export default dataMaskReducer; From dabfd24bfc164ee9490c5adb668e3f6857cd6f0f Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 10:26:56 +0200 Subject: [PATCH 05/21] fix: merge with master --- superset-frontend/src/chart/chartAction.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/superset-frontend/src/chart/chartAction.js b/superset-frontend/src/chart/chartAction.js index 139b7f17abf73..79418c1a99577 100644 --- a/superset-frontend/src/chart/chartAction.js +++ b/superset-frontend/src/chart/chartAction.js @@ -41,7 +41,7 @@ import { logEvent } from '../logger/actions'; import { Logger, LOG_ACTIONS_LOAD_CHART } from '../logger/LogUtils'; import { getClientErrorObject } from '../utils/getClientErrorObject'; import { allowCrossDomain as domainShardingEnabled } from '../utils/hostNamesConfig'; -import { updateExtraFormData } from '../dashboard/actions/nativeFilters'; +import { updateDataMask } from '../dataMask/actions'; export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED'; export function chartUpdateStarted(queryController, latestQueryFormData, key) { @@ -366,8 +366,8 @@ export function exploreJSON( }; if (dashboardId) requestParams.dashboard_id = dashboardId; - const setDataMask = filtersState => { - dispatch(updateExtraFormData(formData.slice_id, filtersState)); + const setDataMask = dataMask => { + dispatch(updateDataMask(formData.slice_id, dataMask)); }; const chartDataRequest = getChartDataRequest({ setDataMask, From 802823c1fd908b543e801ff1eb215ef505f339aa Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 10:53:18 +0200 Subject: [PATCH 06/21] refactor: support explore dataMask --- .../spec/fixtures/mockNativeFilters.ts | 17 +++---- superset-frontend/spec/fixtures/mockState.js | 6 ++- .../dashboard/components/Dashboard_spec.jsx | 4 +- .../dashboard/fixtures/mockNativeFilters.js | 15 ++++--- .../components/ExploreViewContainer.jsx | 44 ++++++++++++++----- 5 files changed, 59 insertions(+), 27 deletions(-) diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts index d3a32857fed1e..0a120ca66c9c6 100644 --- a/superset-frontend/spec/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts @@ -134,14 +134,15 @@ export const singleNativeFiltersState = { isRequired: false, }, }, - filtersState: { - nativeFilters: { - [NATIVE_FILTER_ID]: { - id: NATIVE_FILTER_ID, - extraFormData, - currentState: { - value: ['No, not an ethnic minority'], - }, +}; + +export const singleDataMask = { + nativeFilters: { + [NATIVE_FILTER_ID]: { + id: NATIVE_FILTER_ID, + extraFormData, + currentState: { + value: ['No, not an ethnic minority'], }, }, }, diff --git a/superset-frontend/spec/fixtures/mockState.js b/superset-frontend/spec/fixtures/mockState.js index 1f1e6c4d2a06a..dfa77fdf477a0 100644 --- a/superset-frontend/spec/fixtures/mockState.js +++ b/superset-frontend/spec/fixtures/mockState.js @@ -18,7 +18,10 @@ */ import datasources from 'spec/fixtures/mockDatasource'; import messageToasts from 'spec/javascripts/messageToasts/mockMessageToasts'; -import { nativeFiltersInfo } from 'spec/javascripts/dashboard/fixtures/mockNativeFilters'; +import { + nativeFiltersInfo, + mockDataMaskInfo, +} from 'spec/javascripts/dashboard/fixtures/mockNativeFilters'; import chartQueries from './mockChartQueries'; import { dashboardLayout } from './mockDashboardLayout'; import dashboardInfo from './mockDashboardInfo'; @@ -31,6 +34,7 @@ export default { sliceEntities: sliceEntitiesForChart, charts: chartQueries, nativeFilters: nativeFiltersInfo, + dataMask: mockDataMaskInfo, dashboardInfo, dashboardFilters: emptyFilters, dashboardState, diff --git a/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx index 96b7e6ce6bde5..bf11b94f66186 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx @@ -33,6 +33,7 @@ import { NATIVE_FILTER_ID, layoutForSingleNativeFilter, singleNativeFiltersState, + singleDataMask, } from 'spec/fixtures/mockNativeFilters'; import dashboardInfo from 'spec/fixtures/mockDashboardInfo'; import { dashboardLayout } from 'spec/fixtures/mockDashboardLayout'; @@ -154,7 +155,8 @@ describe('Dashboard', () => { activeFilters: { ...OVERRIDE_FILTERS, ...getActiveNativeFilters({ - nativeFilters: singleNativeFiltersState, + dataMask: singleDataMask, + filters: singleNativeFiltersState.filters, layout: layoutForSingleNativeFilter, }), }, diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js index a667ffc41a7e1..56e092fceced0 100644 --- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js +++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js @@ -41,13 +41,14 @@ export const nativeFiltersInfo = { isRequired: false, }, }, - filtersState: { - nativeFilters: { - DefaultsID: { - id: 'DefaultId', - currentState: { - value: [], - }, +}; + +export const mockDataMaskInfo = { + nativeFilters: { + DefaultsID: { + id: 'DefaultId', + currentState: { + value: [], }, }, }, diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx index 0717a938909a2..c747ee3c60b73 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx @@ -54,6 +54,7 @@ import { LOG_ACTIONS_MOUNT_EXPLORER, LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS, } from '../../logger/LogUtils'; +import { mergeExtraFormData } from '../../dashboard/components/nativeFilters/utils'; const propTypes = { ...ExploreChartPanel.propTypes, @@ -163,6 +164,10 @@ function ExploreViewContainer(props) { const wasDynamicPluginLoading = usePrevious(isDynamicPluginLoading); const previousControls = usePrevious(props.controls); + const [ + chartIsStaleByOwnCurrentState, + setChartIsStaleByOwnCurrentState, + ] = useState(false); const windowSize = useWindowSize(); const [showingModal, setShowingModal] = useState(false); @@ -222,6 +227,7 @@ function ExploreViewContainer(props) { } function onQuery() { + setChartIsStaleByOwnCurrentState(false); props.actions.triggerQuery(true, props.chart.id); addHistory(); } @@ -294,6 +300,15 @@ function ExploreViewContainer(props) { } }, []); + const reRenderChart = () => { + props.actions.updateQueryFormData( + getFormDataFromControls(props.controls), + props.chart.id, + ); + props.actions.renderTriggered(new Date().getTime(), props.chart.id); + addHistory(); + }; + // effect to run when controls change useEffect(() => { if (previousControls) { @@ -320,17 +335,12 @@ function ExploreViewContainer(props) { key => props.controls[key].renderTrigger, ); if (hasDisplayControlChanged) { - props.actions.updateQueryFormData( - getFormDataFromControls(props.controls), - props.chart.id, - ); - props.actions.renderTriggered(new Date().getTime(), props.chart.id); - addHistory(); + reRenderChart(); } } - }, [props.controls]); + }, [props.controls, props.ownCurrentState]); - const chartIsStale = useMemo(() => { + const chartIsStaleByControls = useMemo(() => { if (previousControls) { const changedControlKeys = Object.keys(props.controls).filter( key => @@ -350,6 +360,15 @@ function ExploreViewContainer(props) { return false; }, [previousControls, props.controls]); + useEffect(() => { + if (props.ownCurrentState !== undefined) { + setChartIsStaleByOwnCurrentState(true); + reRenderChart(); + } + }, [JSON.stringify(props.ownCurrentState)]); + + const chartIsStale = chartIsStaleByControls || chartIsStaleByOwnCurrentState; + if (chartIsStale) { props.actions.logEvent(LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS); } @@ -542,6 +561,12 @@ ExploreViewContainer.propTypes = propTypes; function mapStateToProps(state) { const { explore, charts, impressionId, dataMask } = state; const form_data = getFormDataFromControls(explore.controls); + form_data.extra_form_data = mergeExtraFormData( + { ...form_data.extra_form_data }, + { + ...dataMask.ownFilters[explore.slice.slice_id]?.extraFormData, + }, + ); const chartKey = Object.keys(charts)[0]; const chart = charts[chartKey]; return { @@ -571,8 +596,7 @@ function mapStateToProps(state) { forcedHeight: explore.forced_height, chart, timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT, - ownCurrentState: - dataMask.ownFilters?.[explore.form_data.slice_id]?.currentState, + ownCurrentState: dataMask.ownFilters[explore.slice.slice_id]?.currentState, impressionId, }; } From 8aed24043aade4383cc9ec1c8f4712438d5b3809 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 11:29:24 +0200 Subject: [PATCH 07/21] refactor: support explore dataMask --- .../src/explore/components/ExploreViewContainer.jsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx index c747ee3c60b73..f5b4b9a068a17 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx @@ -164,10 +164,6 @@ function ExploreViewContainer(props) { const wasDynamicPluginLoading = usePrevious(isDynamicPluginLoading); const previousControls = usePrevious(props.controls); - const [ - chartIsStaleByOwnCurrentState, - setChartIsStaleByOwnCurrentState, - ] = useState(false); const windowSize = useWindowSize(); const [showingModal, setShowingModal] = useState(false); @@ -227,7 +223,6 @@ function ExploreViewContainer(props) { } function onQuery() { - setChartIsStaleByOwnCurrentState(false); props.actions.triggerQuery(true, props.chart.id); addHistory(); } @@ -340,7 +335,7 @@ function ExploreViewContainer(props) { } }, [props.controls, props.ownCurrentState]); - const chartIsStaleByControls = useMemo(() => { + const chartIsStale = useMemo(() => { if (previousControls) { const changedControlKeys = Object.keys(props.controls).filter( key => @@ -358,17 +353,15 @@ function ExploreViewContainer(props) { ); } return false; - }, [previousControls, props.controls]); + }, [previousControls, props.controls, JSON.stringify(props.ownCurrentState)]); useEffect(() => { if (props.ownCurrentState !== undefined) { - setChartIsStaleByOwnCurrentState(true); + onQuery(); reRenderChart(); } }, [JSON.stringify(props.ownCurrentState)]); - const chartIsStale = chartIsStaleByControls || chartIsStaleByOwnCurrentState; - if (chartIsStale) { props.actions.logEvent(LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS); } From a0fa11474bb4431f0da2da31b2ec2efc6b477fbb Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 11:32:43 +0200 Subject: [PATCH 08/21] docs: add comment --- superset-frontend/src/dataMask/reducer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/superset-frontend/src/dataMask/reducer.ts b/superset-frontend/src/dataMask/reducer.ts index b7d4c1a89cf8f..891c40d527080 100644 --- a/superset-frontend/src/dataMask/reducer.ts +++ b/superset-frontend/src/dataMask/reducer.ts @@ -18,6 +18,7 @@ */ /* eslint-disable no-param-reassign */ +// <- When we work with Immer, we need reassign, so disabling lint import produce from 'immer'; import { MultipleMask, DataMaskType, MultipleDataMaskState } from './types'; import { From eaec7eff4b2b0d669705ca0106cb76ec2c943c47 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 11:53:33 +0200 Subject: [PATCH 09/21] refactor: remove json stringify --- .../src/explore/components/ExploreViewContainer.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx index f5b4b9a068a17..f78318d656c0a 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx @@ -353,14 +353,14 @@ function ExploreViewContainer(props) { ); } return false; - }, [previousControls, props.controls, JSON.stringify(props.ownCurrentState)]); + }, [previousControls, props.controls]); useEffect(() => { if (props.ownCurrentState !== undefined) { onQuery(); reRenderChart(); } - }, [JSON.stringify(props.ownCurrentState)]); + }, [props.ownCurrentState]); if (chartIsStale) { props.actions.logEvent(LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS); From cba34679770ab7c77a1e9ad3cc5c66518e3e95d5 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 12:31:42 +0200 Subject: [PATCH 10/21] fix: fix failed cases --- .../src/explore/components/ExploreViewContainer.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx index f78318d656c0a..a682ba832e860 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx @@ -557,7 +557,7 @@ function mapStateToProps(state) { form_data.extra_form_data = mergeExtraFormData( { ...form_data.extra_form_data }, { - ...dataMask.ownFilters[explore.slice.slice_id]?.extraFormData, + ...dataMask?.ownFilters?.[explore.slice.slice_id]?.extraFormData, }, ); const chartKey = Object.keys(charts)[0]; @@ -589,7 +589,8 @@ function mapStateToProps(state) { forcedHeight: explore.forced_height, chart, timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT, - ownCurrentState: dataMask.ownFilters[explore.slice.slice_id]?.currentState, + ownCurrentState: + dataMask?.ownFilters?.[explore.slice.slice_id]?.currentState, impressionId, }; } From 04d6398c594aac51f65834b04bcd57a9c790a562 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Thu, 4 Mar 2021 12:43:06 +0200 Subject: [PATCH 11/21] feat: filter bat buttons start --- .../nativeFilters/FilterBar/FilterBar.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx index 41a246e7dbdec..b604ac4159610 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx @@ -141,7 +141,7 @@ const TitleArea = styled.h4` flex-direction: row; justify-content: space-between; margin: 0; - padding: ${({ theme }) => theme.gridUnit * 4}px; + padding: ${({ theme }) => theme.gridUnit * 2}px; & > span { flex-grow: 1; } @@ -154,14 +154,14 @@ const TitleArea = styled.h4` `; const ActionButtons = styled.div` - display: flex; + display: grid; flex-direction: row; - justify-content: space-around; - padding: ${({ theme }) => theme.gridUnit * 4}px; - padding-top: 0; + grid-template-columns: 1fr 1fr; + ${({ theme }) => + `padding: 0 ${theme.gridUnit * 2}px ${theme.gridUnit * 2}px`}; border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; .btn { - flex: 1 1 50%; + flex: 1; } `; @@ -181,6 +181,7 @@ const FilterBar: React.FC = ({ directPathToChild, }) => { const [filterData, setFilterData] = useState({}); + const [isFiltersChanged, setIsFilterChanged] = useState(false); const dispatch = useDispatch(); const dataMaskState = useSelector( state => state.dataMask.nativeFilters ?? {}, @@ -360,14 +361,15 @@ const FilterBar: React.FC = ({ {isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) && ( - +
{t('Choose filters set')}
@@ -431,7 +452,7 @@ const FilterBar: React.FC = ({ {t('Save Filters Set')}
-
+ )} {cascadeFilters.map(filter => ( From 09b594aa069fbae363428d32b744c298f2581c50 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Sun, 7 Mar 2021 08:25:00 +0200 Subject: [PATCH 16/21] fix: fix CR notes --- .../spec/fixtures/mockNativeFilters.ts | 4 ++-- superset-frontend/spec/fixtures/mockStore.js | 6 +++--- .../dashboard/components/Dashboard_spec.jsx | 4 ++-- ...mockNativeFilters.js => mockNativeFilters.ts} | 16 +++++++++++----- .../src/dashboard/actions/nativeFilters.ts | 8 ++++---- .../components/FiltersBadge/selectors.ts | 2 +- .../nativeFilters/FilterBar/CascadePopover.tsx | 4 ++-- .../src/dashboard/reducers/index.js | 4 ++-- .../src/dashboard/reducers/types.ts | 2 +- .../explore/components/ExploreViewContainer.jsx | 6 +++--- 10 files changed, 31 insertions(+), 25 deletions(-) rename superset-frontend/spec/javascripts/dashboard/fixtures/{mockNativeFilters.js => mockNativeFilters.ts} (76%) diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts index 9d04ce99f65e4..6d475e3b0955e 100644 --- a/superset-frontend/spec/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts @@ -75,7 +75,7 @@ export const nativeFilters: NativeFiltersState = { }, }; -export const dataMask: DataMaskStateWithId = { +export const dataMaskWith2Filters: DataMaskStateWithId = { crossFilters: {}, ownFilters: {}, nativeFilters: { @@ -136,7 +136,7 @@ export const singleNativeFiltersState = { }, }; -export const singleDataMask = { +export const dataMaskWith1Filter = { nativeFilters: { [NATIVE_FILTER_ID]: { id: NATIVE_FILTER_ID, diff --git a/superset-frontend/spec/fixtures/mockStore.js b/superset-frontend/spec/fixtures/mockStore.js index 6e12b5f0ed9ba..8bf1a073321f2 100644 --- a/superset-frontend/spec/fixtures/mockStore.js +++ b/superset-frontend/spec/fixtures/mockStore.js @@ -28,7 +28,7 @@ import { } from './mockDashboardLayout'; import { sliceId } from './mockChartQueries'; import { dashboardFilters } from './mockDashboardFilters'; -import { nativeFilters, dataMask } from './mockNativeFilters'; +import { nativeFilters, dataMaskWith2Filters } from './mockNativeFilters'; export const storeWithState = state => createStore(rootReducer, state, compose(applyMiddleware(thunk))); @@ -77,7 +77,7 @@ export const getMockStoreWithFilters = () => createStore(rootReducer, { ...mockState, dashboardFilters, - dataMask, + dataMask: dataMaskWith2Filters, charts: { ...mockState.charts, [sliceIdWithAppliedFilter]: { @@ -103,7 +103,7 @@ export const getMockStoreWithNativeFilters = () => createStore(rootReducer, { ...mockState, nativeFilters, - dataMask, + dataMask: dataMaskWith2Filters, charts: { ...mockState.charts, [sliceIdWithAppliedFilter]: { diff --git a/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx index bf11b94f66186..733f82490c43d 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx @@ -33,7 +33,7 @@ import { NATIVE_FILTER_ID, layoutForSingleNativeFilter, singleNativeFiltersState, - singleDataMask, + dataMaskWith1Filter, } from 'spec/fixtures/mockNativeFilters'; import dashboardInfo from 'spec/fixtures/mockDashboardInfo'; import { dashboardLayout } from 'spec/fixtures/mockDashboardLayout'; @@ -155,7 +155,7 @@ describe('Dashboard', () => { activeFilters: { ...OVERRIDE_FILTERS, ...getActiveNativeFilters({ - dataMask: singleDataMask, + dataMask: dataMaskWith1Filter, filters: singleNativeFiltersState.filters, layout: layoutForSingleNativeFilter, }), diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts similarity index 76% rename from superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js rename to superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts index 56e092fceced0..7a8bff0687928 100644 --- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.js +++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts @@ -16,12 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -export const nativeFiltersInfo = { +import { DataMaskStateWithId } from 'src/dataMask/types'; +import { NativeFiltersState } from 'src/dashboard/reducers/types'; + +export const nativeFiltersInfo: NativeFiltersState = { filters: { DefaultsID: { + cascadeParentIds: [], id: 'DefaultsID', name: 'test', - type: 'filter_select', + filterType: 'filter_select', targets: [ { datasetId: 0, @@ -37,13 +41,15 @@ export const nativeFiltersInfo = { excluded: [], }, isInstant: true, - allowsMultipleValues: true, - isRequired: false, + controlValues: { + allowsMultipleValues: true, + isRequired: false, + }, }, }, }; -export const mockDataMaskInfo = { +export const mockDataMaskInfo: DataMaskStateWithId = { nativeFilters: { DefaultsID: { id: 'DefaultId', diff --git a/superset-frontend/src/dashboard/actions/nativeFilters.ts b/superset-frontend/src/dashboard/actions/nativeFilters.ts index f52548f474fec..a1571fed7810c 100644 --- a/superset-frontend/src/dashboard/actions/nativeFilters.ts +++ b/superset-frontend/src/dashboard/actions/nativeFilters.ts @@ -20,13 +20,13 @@ import { makeApi } from '@superset-ui/core'; import { Dispatch } from 'redux'; import { FilterConfiguration } from 'src/dashboard/components/nativeFilters/types'; -import { dashboardInfoChanged } from './dashboardInfo'; -import { FiltersSet } from '../reducers/types'; -import { DataMaskType, DataMaskStateWithId } from '../../dataMask/types'; +import { DataMaskType, DataMaskStateWithId } from 'src/dataMask/types'; import { SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE, SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL, -} from '../../dataMask/actions'; +} from 'src/dataMask/actions'; +import { dashboardInfoChanged } from './dashboardInfo'; +import { FiltersSet } from '../reducers/types'; export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN'; export interface SetFilterConfigBegin { diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts index d7ad57653125b..89eea4bc9c5a5 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts +++ b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts @@ -19,9 +19,9 @@ import { TIME_FILTER_MAP } from 'src/explore/constants'; import { getChartIdsInFilterScope } from 'src/dashboard/util/activeDashboardFilters'; import { NativeFiltersState } from 'src/dashboard/reducers/types'; +import { DataMaskStateWithId } from 'src/dataMask/types'; import { Layout } from '../../types'; import { getTreeCheckedItems } from '../nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils'; -import { DataMaskStateWithId } from '../../../dataMask/types'; export enum IndicatorStatus { Unset = 'UNSET', diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx index 067013b7f5666..430003bb1bafb 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadePopover.tsx @@ -22,12 +22,12 @@ import Popover from 'src/common/components/Popover'; import Icon from 'src/components/Icon'; import { Pill } from 'src/dashboard/components/FiltersBadge/Styles'; import { useSelector } from 'react-redux'; +import { getInitialMask } from 'src/dataMask/reducer'; +import { MaskWithId } from 'src/dataMask/types'; import FilterControl from './FilterControl'; import CascadeFilterControl from './CascadeFilterControl'; import { CascadeFilter } from './types'; import { Filter } from '../types'; -import { getInitialMask } from '../../../../dataMask/reducer'; -import { MaskWithId } from '../../../../dataMask/types'; interface CascadePopoverProps { filter: CascadeFilter; diff --git a/superset-frontend/src/dashboard/reducers/index.js b/superset-frontend/src/dashboard/reducers/index.js index 1932fab7e1ea7..481f1675ff4aa 100644 --- a/superset-frontend/src/dashboard/reducers/index.js +++ b/superset-frontend/src/dashboard/reducers/index.js @@ -18,8 +18,8 @@ */ import { combineReducers } from 'redux'; -import charts from '../../chart/chartReducer'; -import dataMask from '../../dataMask/reducer'; +import charts from 'src/chart/chartReducer'; +import dataMask from 'src/dataMask/reducer'; import dashboardInfo from './dashboardInfo'; import dashboardState from './dashboardState'; import dashboardFilters from './dashboardFilters'; diff --git a/superset-frontend/src/dashboard/reducers/types.ts b/superset-frontend/src/dashboard/reducers/types.ts index 207d67c139fa4..78b3ea7812735 100644 --- a/superset-frontend/src/dashboard/reducers/types.ts +++ b/superset-frontend/src/dashboard/reducers/types.ts @@ -18,8 +18,8 @@ */ import componentTypes from 'src/dashboard/util/componentTypes'; +import { DataMaskStateWithId } from 'src/dataMask/types'; import { Filter } from '../components/nativeFilters/types'; -import { DataMaskStateWithId } from '../../dataMask/types'; export enum Scoping { all, diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx index bf82992cc971c..b6e7e9ccfb294 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx @@ -36,6 +36,9 @@ import { } from 'src/utils/localStorageHelpers'; import { URL_PARAMS } from 'src/constants'; import cx from 'classnames'; +import * as chartActions from 'src/chart/chartAction'; +import { fetchDatasourceMetadata } from 'src/dashboard/actions/datasources'; +import { chartPropShape } from 'src/dashboard/util/propShapes'; import ExploreChartPanel from './ExploreChartPanel'; import ConnectedControlPanelsContainer from './ControlPanelsContainer'; import SaveModal from './SaveModal'; @@ -44,11 +47,8 @@ import DataSourcePanel from './DatasourcePanel'; import { getExploreLongUrl } from '../exploreUtils'; import { areObjectsEqual } from '../../reduxUtils'; import { getFormDataFromControls } from '../controlUtils'; -import { chartPropShape } from '../../dashboard/util/propShapes'; import * as exploreActions from '../actions/exploreActions'; import * as saveModalActions from '../actions/saveModalActions'; -import * as chartActions from '../../chart/chartAction'; -import { fetchDatasourceMetadata } from '../../dashboard/actions/datasources'; import * as logActions from '../../logger/actions'; import { LOG_ACTIONS_MOUNT_EXPLORER, From 052706737ec1fd43e2a7bb93955c91beadfe8bd6 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Sun, 7 Mar 2021 08:34:40 +0200 Subject: [PATCH 17/21] fix: fix CR notes --- .../spec/javascripts/dashboard/fixtures/mockNativeFilters.ts | 1 + .../src/explore/components/ExploreViewContainer.jsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts index 7a8bff0687928..1659a76dd566b 100644 --- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts @@ -20,6 +20,7 @@ import { DataMaskStateWithId } from 'src/dataMask/types'; import { NativeFiltersState } from 'src/dashboard/reducers/types'; export const nativeFiltersInfo: NativeFiltersState = { + filterSets: {}, filters: { DefaultsID: { cascadeParentIds: [], diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx index b6e7e9ccfb294..8144776a4afc0 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx @@ -39,6 +39,7 @@ import cx from 'classnames'; import * as chartActions from 'src/chart/chartAction'; import { fetchDatasourceMetadata } from 'src/dashboard/actions/datasources'; import { chartPropShape } from 'src/dashboard/util/propShapes'; +import { mergeExtraFormData } from 'src/dashboard/components/nativeFilters/utils'; import ExploreChartPanel from './ExploreChartPanel'; import ConnectedControlPanelsContainer from './ControlPanelsContainer'; import SaveModal from './SaveModal'; @@ -54,7 +55,6 @@ import { LOG_ACTIONS_MOUNT_EXPLORER, LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS, } from '../../logger/LogUtils'; -import { mergeExtraFormData } from '../../dashboard/components/nativeFilters/utils'; const propTypes = { ...ExploreChartPanel.propTypes, From 2d12c37b38822890f49f19b4f2cb641de8149c71 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Sun, 7 Mar 2021 08:40:16 +0200 Subject: [PATCH 18/21] fix: fix CR notes --- .../javascripts/dashboard/fixtures/mockNativeFilters.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts index 1659a76dd566b..aaef255674f62 100644 --- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { DataMaskStateWithId } from 'src/dataMask/types'; +import { DataMaskStateWithId, DataMaskType } from 'src/dataMask/types'; import { NativeFiltersState } from 'src/dashboard/reducers/types'; export const nativeFiltersInfo: NativeFiltersState = { @@ -51,7 +51,9 @@ export const nativeFiltersInfo: NativeFiltersState = { }; export const mockDataMaskInfo: DataMaskStateWithId = { - nativeFilters: { + [DataMaskType.CrossFilters]: {}, + [DataMaskType.OwnFilters]: {}, + [DataMaskType.NativeFilters]: { DefaultsID: { id: 'DefaultId', currentState: { From a9202b1c811b785010a8122d64fe19667a355c99 Mon Sep 17 00:00:00 2001 From: Simcha Shats Date: Sun, 7 Mar 2021 09:20:03 +0200 Subject: [PATCH 19/21] feat: buttons in filter bar --- .../nativeFilters/FilterBar/FilterBar.tsx | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx index fff56c3fb3423..ff98c7caaf83f 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.tsx @@ -36,8 +36,9 @@ import { DataMaskState, } from 'src/dataMask/types'; import { useImmer } from 'use-immer'; +import { getInitialMask } from 'src/dataMask/reducer'; import FilterConfigurationLink from './FilterConfigurationLink'; -import { useFilters, useFilterSets } from './state'; +import { useFilterSets } from './state'; import { useFilterConfiguration } from '../state'; import { Filter } from '../types'; import { @@ -46,7 +47,7 @@ import { mapParentFiltersToChildren, } from './utils'; import CascadePopover from './CascadePopover'; -import { getInitialMask } from '../../../../dataMask/reducer'; +import { areObjectsEqual } from '../../../../reduxUtils'; const barWidth = `250px`; @@ -198,7 +199,10 @@ const FilterBar: React.FC = ({ directPathToChild, }) => { const [filterData, setFilterData] = useImmer({}); - const [isFiltersChanged, setIsFilterChanged] = useState(false); + const [ + lastAppliedFilterData, + setLastAppliedFilterData, + ] = useImmer({}); const dispatch = useDispatch(); const dataMaskState = useSelector( state => state.dataMask.nativeFilters ?? {}, @@ -296,7 +300,7 @@ const FilterBar: React.FC = ({ ); } }); - setIsFilterChanged(false); + setLastAppliedFilterData(() => filterData); }; useEffect(() => { @@ -305,14 +309,6 @@ const FilterBar: React.FC = ({ } }, [isInitialized]); - useEffect(() => { - if (isInitialized) { - setIsFilterChanged(true); - } - // !need ignore isInitialized - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [JSON.stringify(filterData)]); - const handleSaveFilterSets = () => { dispatch( setFilterSetsConfiguration( @@ -390,7 +386,10 @@ const FilterBar: React.FC = ({ {t('Clear all')}