feat(native-filters): Update filter bar buttons (#13506)
* refactor(native-filters): move data mask to root reducer * refactor: update rest stuff for dataMask * refactor: add ownCrrentState to explore * fix: fix immer reducer * fix: merge with master * refactor: support explore dataMask * refactor: support explore dataMask * docs: add comment * refactor: remove json stringify * fix: fix failed cases * feat: filter bat buttons start * fix: fix CR notes * fix: fix cascade filters * fix: fix CR notes * refactor: add clear all * fix: fix CR notes * fix: fix CR notes * fix: fix CR notes * feat: buttons in filter bar * lint: update imports * test: fix tests
This commit is contained in:
parent
45972e9945
commit
3970d7316b
|
|
@ -122,6 +122,7 @@
|
|||
"rison": "^0.1.1",
|
||||
"shortid": "^2.2.6",
|
||||
"urijs": "^1.19.4",
|
||||
"use-immer": "^0.4.2",
|
||||
"use-query-params": "^1.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -54551,6 +54552,15 @@
|
|||
"ts-essentials": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/use-immer": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.4.2.tgz",
|
||||
"integrity": "sha512-ONfZHEv/gzt/jyYxrJD3ZFUllKJED8F1mds9Fr9CYj54LmsiuGDg3vkx+R7WHS72p7DbSS1QbM7xNYrVWX+KcA==",
|
||||
"peerDependencies": {
|
||||
"immer": ">=2.0.0",
|
||||
"react": "^16.8.0 || ^17.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/use-isomorphic-layout-effect": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.0.0.tgz",
|
||||
|
|
@ -104943,6 +104953,12 @@
|
|||
"ts-essentials": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"use-immer": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.4.2.tgz",
|
||||
"integrity": "sha512-ONfZHEv/gzt/jyYxrJD3ZFUllKJED8F1mds9Fr9CYj54LmsiuGDg3vkx+R7WHS72p7DbSS1QbM7xNYrVWX+KcA==",
|
||||
"requires": {}
|
||||
},
|
||||
"use-isomorphic-layout-effect": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@
|
|||
"rison": "^0.1.1",
|
||||
"shortid": "^2.2.6",
|
||||
"urijs": "^1.19.4",
|
||||
"use-immer": "^0.4.2",
|
||||
"use-query-params": "^1.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ describe('FilterBar', () => {
|
|||
expect(wrapper.find({ name: 'filter' })).toExist();
|
||||
expect(wrapper.find({ name: 'collapse' })).toExist();
|
||||
});
|
||||
it('has apply and reset all buttons', () => {
|
||||
it('has apply and clear all buttons', () => {
|
||||
expect(wrapper.find(Button).length).toBe(2);
|
||||
expect(wrapper.find(Button).at(0)).toHaveProp('buttonStyle', 'secondary');
|
||||
expect(wrapper.find(Button).at(0)).toHaveProp('buttonStyle', 'tertiary');
|
||||
expect(wrapper.find(Button).at(1)).toHaveProp('buttonStyle', 'primary');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { styled, t, tn } from '@superset-ui/core';
|
||||
import React, { useState, useEffect, useMemo, ChangeEvent } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
|
@ -33,8 +35,11 @@ import {
|
|||
DataMaskUnit,
|
||||
DataMaskState,
|
||||
} from 'src/dataMask/types';
|
||||
import { useImmer } from 'use-immer';
|
||||
import { getInitialMask } from 'src/dataMask/reducer';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import FilterConfigurationLink from './FilterConfigurationLink';
|
||||
import { useFilters, useFilterSets } from './state';
|
||||
import { useFilterSets } from './state';
|
||||
import { useFilterConfiguration } from '../state';
|
||||
import { Filter } from '../types';
|
||||
import {
|
||||
|
|
@ -48,6 +53,7 @@ const barWidth = `250px`;
|
|||
|
||||
const BarWrapper = styled.div`
|
||||
width: ${({ theme }) => theme.gridUnit * 8}px;
|
||||
|
||||
&.open {
|
||||
width: ${barWidth}; // arbitrary...
|
||||
}
|
||||
|
|
@ -70,6 +76,7 @@ const Bar = styled.div`
|
|||
transition: transform ${({ theme }) => theme.transitionTiming}s;
|
||||
transition-delay: 0s;
|
||||
} */
|
||||
|
||||
&.open {
|
||||
display: flex;
|
||||
/* &.animated {
|
||||
|
|
@ -85,6 +92,7 @@ const StyledTitle = styled.h4`
|
|||
color: ${({ theme }) => theme.colors.grayscale.dark1};
|
||||
margin: 0;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
& > .ant-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
@ -105,6 +113,7 @@ const CollapsedBar = styled.div`
|
|||
transition: transform ${({ theme }) => theme.transitionTiming}s;
|
||||
transition-delay: 0s;
|
||||
} */
|
||||
|
||||
&.open {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -115,6 +124,7 @@ const CollapsedBar = styled.div`
|
|||
transition-delay: ${({ theme }) => theme.transitionTiming * 3}s;
|
||||
} */
|
||||
}
|
||||
|
||||
svg {
|
||||
width: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
height: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
|
|
@ -141,12 +151,15 @@ 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;
|
||||
}
|
||||
|
||||
& :not(:first-child) {
|
||||
margin-left: ${({ theme }) => theme.gridUnit}px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -154,17 +167,22 @@ 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;
|
||||
}
|
||||
`;
|
||||
|
||||
const Sets = styled(ActionButtons)`
|
||||
grid-template-columns: 1fr;
|
||||
`;
|
||||
|
||||
const FilterControls = styled.div`
|
||||
padding: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
`;
|
||||
|
|
@ -180,7 +198,11 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
toggleFiltersBar,
|
||||
directPathToChild,
|
||||
}) => {
|
||||
const [filterData, setFilterData] = useState<DataMaskUnit>({});
|
||||
const [filterData, setFilterData] = useImmer<DataMaskUnit>({});
|
||||
const [
|
||||
lastAppliedFilterData,
|
||||
setLastAppliedFilterData,
|
||||
] = useImmer<DataMaskUnit>({});
|
||||
const dispatch = useDispatch();
|
||||
const dataMaskState = useSelector<any, DataMaskUnitWithId>(
|
||||
state => state.dataMask.nativeFilters ?? {},
|
||||
|
|
@ -190,7 +212,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
const filterSetsConfigs = useSelector<any, FiltersSet[]>(
|
||||
state => state.dashboardInfo?.metadata?.filter_sets_configuration || [],
|
||||
);
|
||||
const filters = useFilters();
|
||||
const [filtersSetName, setFiltersSetName] = useState('');
|
||||
const [selectedFiltersSetId, setSelectedFiltersSetId] = useState<
|
||||
string | null
|
||||
|
|
@ -238,20 +259,16 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
filter: Pick<Filter, 'id'> & Partial<Filter>,
|
||||
dataMask: Partial<DataMaskState>,
|
||||
) => {
|
||||
setFilterData(prevFilterData => {
|
||||
setFilterData(draft => {
|
||||
const children = cascadeChildren[filter.id] || [];
|
||||
// force instant updating on initialization or for parent filters
|
||||
if (filter.isInstant || children.length > 0) {
|
||||
dispatch(updateDataMask(filter.id, dataMask));
|
||||
}
|
||||
|
||||
if (!dataMask.nativeFilters) {
|
||||
return { ...prevFilterData };
|
||||
if (dataMask.nativeFilters) {
|
||||
draft[filter.id] = dataMask.nativeFilters;
|
||||
}
|
||||
return {
|
||||
...prevFilterData,
|
||||
[filter.id]: dataMask.nativeFilters,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -283,6 +300,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
);
|
||||
}
|
||||
});
|
||||
setLastAppliedFilterData(() => filterData);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -320,21 +338,20 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
setSelectedFiltersSetId(null);
|
||||
};
|
||||
|
||||
const handleResetAll = () => {
|
||||
const handleClearAll = () => {
|
||||
filterConfigs.forEach(filter => {
|
||||
dispatch(
|
||||
updateDataMask(filter.id, {
|
||||
nativeFilters: {
|
||||
currentState: {
|
||||
...filterData[filter.id]?.currentState,
|
||||
value: filters[filter.id]?.defaultValue,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
setFilterData(draft => {
|
||||
draft[filter.id] = getInitialMask(filter.id);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const isClearAllDisabled = !Object.values(dataMaskState).every(
|
||||
filter =>
|
||||
filterData[filter.id]?.currentState?.value === null ||
|
||||
(!filterData[filter.id] && filter.currentState?.value === null),
|
||||
);
|
||||
|
||||
return (
|
||||
<BarWrapper data-test="filter-bar" className={cx({ open: filtersOpen })}>
|
||||
<CollapsedBar
|
||||
|
|
@ -360,14 +377,19 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
</TitleArea>
|
||||
<ActionButtons>
|
||||
<Button
|
||||
buttonStyle="secondary"
|
||||
disabled={!isClearAllDisabled}
|
||||
buttonStyle="tertiary"
|
||||
buttonSize="small"
|
||||
onClick={handleResetAll}
|
||||
onClick={handleClearAll}
|
||||
data-test="filter-reset-button"
|
||||
>
|
||||
{t('Reset all')}
|
||||
{t('Clear all')}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={
|
||||
!isInitialized ||
|
||||
areObjectsEqual(filterData, lastAppliedFilterData)
|
||||
}
|
||||
buttonStyle="primary"
|
||||
htmlType="submit"
|
||||
buttonSize="small"
|
||||
|
|
@ -378,7 +400,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
</Button>
|
||||
</ActionButtons>
|
||||
{isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) && (
|
||||
<ActionButtons>
|
||||
<Sets>
|
||||
<FilterSet>
|
||||
<StyledTitle>
|
||||
<div>{t('Choose filters set')}</div>
|
||||
|
|
@ -429,7 +451,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||
{t('Save Filters Set')}
|
||||
</Button>
|
||||
</FilterSet>
|
||||
</ActionButtons>
|
||||
</Sets>
|
||||
)}
|
||||
<FilterControls>
|
||||
{cascadeFilters.map(filter => (
|
||||
|
|
|
|||
Loading…
Reference in New Issue