Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(native-filters): Filter set tabs #13507

Merged
merged 31 commits into from
Mar 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2731518
refactor(native-filters): move data mask to root reducer
simcha90 Mar 3, 2021
de6a332
Merge branch 'master' of github.com:apache/superset into filtersState…
simcha90 Mar 3, 2021
6652d19
refactor: update rest stuff for dataMask
simcha90 Mar 3, 2021
266a0a3
refactor: add ownCrrentState to explore
simcha90 Mar 3, 2021
5344dd4
fix: fix immer reducer
simcha90 Mar 4, 2021
2b4bd8f
Merge branch 'master' of github.com:apache/superset into filtersState…
simcha90 Mar 4, 2021
dabfd24
fix: merge with master
simcha90 Mar 4, 2021
802823c
refactor: support explore dataMask
simcha90 Mar 4, 2021
8aed240
refactor: support explore dataMask
simcha90 Mar 4, 2021
a0fa114
docs: add comment
simcha90 Mar 4, 2021
eaec7ef
refactor: remove json stringify
simcha90 Mar 4, 2021
cba3467
fix: fix failed cases
simcha90 Mar 4, 2021
04d6398
feat: filter bat buttons start
simcha90 Mar 4, 2021
af9e35a
fix: fix CR notes
simcha90 Mar 4, 2021
64fb87d
fix: fix cascade filters
simcha90 Mar 4, 2021
57c954f
fix: fix CR notes
simcha90 Mar 4, 2021
bd9b767
Merge branch 'filtersState_to_data_mask' of github.com:simchaNielsen/…
simcha90 Mar 4, 2021
bff44d1
refactor: add clear all
simcha90 Mar 7, 2021
09b594a
fix: fix CR notes
simcha90 Mar 7, 2021
c522391
Merge branch 'master' of github.com:apache/superset into filtersState…
simcha90 Mar 7, 2021
1bf1552
Merge branch 'filtersState_to_data_mask' of github.com:simchaNielsen/…
simcha90 Mar 7, 2021
0527067
fix: fix CR notes
simcha90 Mar 7, 2021
9abe26e
Merge branch 'filtersState_to_data_mask' of github.com:simchaNielsen/…
simcha90 Mar 7, 2021
2d12c37
fix: fix CR notes
simcha90 Mar 7, 2021
84d8cbd
Merge branch 'filtersState_to_data_mask' of github.com:simchaNielsen/…
simcha90 Mar 7, 2021
a9202b1
feat: buttons in filter bar
simcha90 Mar 7, 2021
9ae46b9
Merge branch 'master' of github.com:apache/superset into filter_bar_a…
simcha90 Mar 7, 2021
cdcae95
lint: update imports
simcha90 Mar 7, 2021
6c91054
feat: add tabs for filter sets
simcha90 Mar 7, 2021
844adaa
Merge branch 'master' of github.com:apache/superset into filter-set_tabs
simcha90 Mar 7, 2021
93e5d97
Merge branch 'master' of github.com:apache/superset into filter-set_tabs
simcha90 Mar 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,29 @@
*/

/* eslint-disable no-param-reassign */
import { styled, t, tn } from '@superset-ui/core';
import React, { useState, useEffect, useMemo, ChangeEvent } from 'react';
import { styled, t } from '@superset-ui/core';
import React, { useState, useEffect, useMemo } 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 } from 'src/dashboard/reducers/types';
import { Input, Select } from 'src/common/components';
import { Tabs } from 'src/common/components';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { setFilterSetsConfiguration } from 'src/dashboard/actions/nativeFilters';
import { updateDataMask } from 'src/dataMask/actions';
import {
DataMaskUnitWithId,
MaskWithId,
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 { useFilterSets } from './state';
import { useFilterConfiguration } from '../state';
import { Filter } from '../types';
import {
buildCascadeFiltersTree,
generateFiltersSetId,
mapParentFiltersToChildren,
} from './utils';
import { buildCascadeFiltersTree, mapParentFiltersToChildren } from './utils';
import CascadePopover from './CascadePopover';
import FilterSets from './FilterSets';

const barWidth = `250px`;

Expand Down Expand Up @@ -86,18 +79,6 @@ const Bar = styled.div`
}
`;

const StyledTitle = styled.h4`
width: 100%;
font-size: ${({ theme }) => theme.typography.sizes.s}px;
color: ${({ theme }) => theme.colors.grayscale.dark1};
margin: 0;
overflow-wrap: break-word;

& > .ant-select {
width: 100%;
}
`;

const CollapsedBar = styled.div`
position: absolute;
top: 0;
Expand Down Expand Up @@ -137,15 +118,6 @@ const StyledCollapseIcon = styled(Icon)`
margin-bottom: ${({ theme }) => theme.gridUnit * 3}px;
`;

const FilterSet = styled.div`
display: grid;
align-items: center;
justify-content: center;
grid-template-columns: 1fr;
grid-gap: 10px;
padding-top: 10px;
`;

const TitleArea = styled.h4`
display: flex;
flex-direction: row;
Expand All @@ -166,25 +138,32 @@ const TitleArea = styled.h4`
}
`;

const StyledTabs = styled(Tabs)`
& .ant-tabs-nav-list {
width: 100%;
}
& .ant-tabs-tab {
display: flex;
justify-content: center;
margin: 0;
flex: 1;
}
`;

const ActionButtons = styled.div`
display: grid;
flex-direction: row;
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;
}
`;

const Sets = styled(ActionButtons)`
grid-template-columns: 1fr;
`;

const FilterControls = styled.div`
padding: ${({ theme }) => theme.gridUnit * 4}px;
padding: 0 ${({ theme }) => theme.gridUnit * 4}px;
`;

interface FiltersBarProps {
Expand All @@ -207,15 +186,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
const dataMaskState = useSelector<any, DataMaskUnitWithId>(
state => state.dataMask.nativeFilters ?? {},
);
const filterSets = useFilterSets();
const filterConfigs = useFilterConfiguration();
const filterSetsConfigs = useSelector<any, FiltersSet[]>(
state => state.dashboardInfo?.metadata?.filter_sets_configuration || [],
);
const [filtersSetName, setFiltersSetName] = useState('');
const [selectedFiltersSetId, setSelectedFiltersSetId] = useState<
string | null
>(null);
const canEdit = useSelector<any, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
);
Expand Down Expand Up @@ -272,23 +243,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({
});
};

const takeFiltersSet = (value: string) => {
setSelectedFiltersSetId(value);
if (!value) {
return;
}
const filtersSet = filterSets[value];
Object.values(filtersSet.dataMask?.nativeFilters ?? []).forEach(
dataMask => {
const { extraFormData, currentState, id } = dataMask as MaskWithId;
handleFilterSelectionChange(
{ id },
{ nativeFilters: { extraFormData, currentState } },
);
},
);
};

const handleApply = () => {
const filterIds = Object.keys(filterData);
filterIds.forEach(filterId => {
Expand All @@ -309,35 +263,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({
}
}, [isInitialized]);

const handleSaveFilterSets = () => {
dispatch(
setFilterSetsConfiguration(
filterSetsConfigs.concat([
{
name: filtersSetName.trim(),
id: generateFiltersSetId(),
dataMask: {
nativeFilters: dataMaskState,
},
},
]),
),
);
setFiltersSetName('');
};

const handleDeleteFilterSets = () => {
dispatch(
setFilterSetsConfiguration(
filterSetsConfigs.filter(
filtersSet => filtersSet.id !== selectedFiltersSetId,
),
),
);
setFiltersSetName('');
setSelectedFiltersSetId(null);
};

const handleClearAll = () => {
filterConfigs.forEach(filter => {
setFilterData(draft => {
Expand All @@ -352,6 +277,24 @@ const FilterBar: React.FC<FiltersBarProps> = ({
(!filterData[filter.id] && filter.currentState?.value === null),
);

const getFilterControls = () => (
<FilterControls>
{cascadeFilters.map(filter => (
<CascadePopover
data-test="cascade-filters-control"
key={filter.id}
visible={visiblePopoverId === filter.id}
onVisibleChange={visible =>
setVisiblePopoverId(visible ? filter.id : null)
}
filter={filter}
onFilterSelectionChange={handleFilterSelectionChange}
directPathToChild={directPathToChild}
/>
))}
</FilterControls>
);

return (
<BarWrapper data-test="filter-bar" className={cx({ open: filtersOpen })}>
<CollapsedBar
Expand All @@ -363,9 +306,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
</CollapsedBar>
<Bar className={cx({ open: filtersOpen })}>
<TitleArea>
<span>
{t('Filters')} ({filterConfigs.length})
</span>
<span>{t('Filters')}</span>
{canEdit && (
<FilterConfigurationLink
createNewOnOpen={filterConfigs.length === 0}
Expand Down Expand Up @@ -399,75 +340,28 @@ const FilterBar: React.FC<FiltersBarProps> = ({
{t('Apply')}
</Button>
</ActionButtons>
{isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) && (
<Sets>
<FilterSet>
<StyledTitle>
<div>{t('Choose filters set')}</div>
<Select
size="small"
allowClear
value={selectedFiltersSetId as string}
placeholder={tn(
'Available %d sets',
Object.keys(filterSets).length,
)}
onChange={takeFiltersSet}
>
{Object.values(filterSets).map(({ name, id }) => (
<Select.Option value={id}>{name}</Select.Option>
))}
</Select>
</StyledTitle>
<Button
buttonStyle="warning"
buttonSize="small"
disabled={!selectedFiltersSetId}
onClick={handleDeleteFilterSets}
data-test="filter-save-filters-set-button"
>
{t('Delete Filters Set')}
</Button>
<StyledTitle>
<div>{t('Name')}</div>
<Input
size="small"
placeholder={t('Enter filter set name')}
value={filtersSetName}
onChange={({
target: { value },
}: ChangeEvent<HTMLInputElement>) => {
setFiltersSetName(value);
}}
/>
</StyledTitle>
<Button
buttonStyle="secondary"
buttonSize="small"
disabled={filtersSetName.trim() === ''}
onClick={handleSaveFilterSets}
data-test="filter-save-filters-set-button"
>
{t('Save Filters Set')}
</Button>
</FilterSet>
</Sets>
{isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) ? (
<StyledTabs
centered
defaultActiveKey="allFilters"
onChange={() => {}}
>
<Tabs.TabPane
tab={t(`All Filters (${filterConfigs.length})`)}
key="allFilters"
>
{getFilterControls()}
</Tabs.TabPane>
<Tabs.TabPane tab={t('Filter Sets')} key="filterSets">
<FilterSets
dataMaskState={dataMaskState}
onFilterSelectionChange={handleFilterSelectionChange}
/>
</Tabs.TabPane>
</StyledTabs>
) : (
getFilterControls()
)}
<FilterControls>
{cascadeFilters.map(filter => (
<CascadePopover
data-test="cascade-filters-control"
key={filter.id}
visible={visiblePopoverId === filter.id}
onVisibleChange={visible =>
setVisiblePopoverId(visible ? filter.id : null)
}
filter={filter}
onFilterSelectionChange={handleFilterSelectionChange}
directPathToChild={directPathToChild}
/>
))}
</FilterControls>
</Bar>
</BarWrapper>
);
Expand Down
Loading