Skip to content

Commit

Permalink
feat: Programmatically open "more filters" dropdown in Horizontal Fil…
Browse files Browse the repository at this point in the history
…ter Bar (#22276)

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
  • Loading branch information
geido and michael-s-molina committed Dec 2, 2022
1 parent 7bc5f04 commit df91664
Show file tree
Hide file tree
Showing 33 changed files with 234 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export type NativeFiltersState = {
filters: Filters;
filterSets: FilterSets;
focusedFilterId?: string;
hoveredFilterId?: string;
};

export type DashboardComponentMetadata = {
Expand Down
24 changes: 24 additions & 0 deletions superset-frontend/src/dashboard/actions/nativeFilters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,28 @@ export function unsetFocusedNativeFilter(): UnsetFocusedNativeFilter {
};
}

export const SET_HOVERED_NATIVE_FILTER = 'SET_HOVERED_NATIVE_FILTER';
export interface SetHoveredNativeFilter {
type: typeof SET_HOVERED_NATIVE_FILTER;
id: string;
}
export const UNSET_HOVERED_NATIVE_FILTER = 'UNSET_HOVERED_NATIVE_FILTER';
export interface UnsetHoveredNativeFilter {
type: typeof UNSET_HOVERED_NATIVE_FILTER;
}

export function setHoveredNativeFilter(id: string): SetHoveredNativeFilter {
return {
type: SET_HOVERED_NATIVE_FILTER,
id,
};
}
export function unsetHoveredNativeFilter(): UnsetHoveredNativeFilter {
return {
type: UNSET_HOVERED_NATIVE_FILTER,
};
}

export type AnyFilterAction =
| SetFilterConfigBegin
| SetFilterConfigComplete
Expand All @@ -383,6 +405,8 @@ export type AnyFilterAction =
| SetBootstrapData
| SetFocusedNativeFilter
| UnsetFocusedNativeFilter
| SetHoveredNativeFilter
| UnsetHoveredNativeFilter
| CreateFilterSetBegin
| CreateFilterSetComplete
| CreateFilterSetFail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,8 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
const canEdit = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
);
const directPathToChild = useSelector<RootState, string[]>(
state => state.dashboardState.directPathToChild,
);
const nativeFilters = useSelector((state: RootState) => state.nativeFilters);
const focusedFilterId = nativeFilters?.focusedFilterId;
const fullSizeChartId = useSelector<RootState, number | null>(
state => state.dashboardState.fullSizeChartId,
);
Expand Down Expand Up @@ -369,7 +368,7 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
{showFilterBar &&
filterBarOrientation === FilterBarOrientation.HORIZONTAL && (
<FilterBar
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
orientation={FilterBarOrientation.HORIZONTAL}
/>
)}
Expand Down Expand Up @@ -401,7 +400,7 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
</div>
),
[
directPathToChild,
focusedFilterId,
nativeFiltersEnabled,
filterBarOrientation,
editMode,
Expand Down Expand Up @@ -437,7 +436,7 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
<StickyPanel ref={containerRef} width={filterBarWidth}>
<ErrorBoundary>
<FilterBar
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
orientation={FilterBarOrientation.VERTICAL}
verticalConfig={{
filtersOpen: dashboardFiltersOpen,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import cx from 'classnames';
import { DataMaskStateWithId, Filters } from '@superset-ui/core';
import Icons from 'src/components/Icons';
import { usePrevious } from 'src/hooks/usePrevious';
import { setFocusedNativeFilter } from 'src/dashboard/actions/nativeFilters';
import DetailsPanelPopover from './DetailsPanel';
import { Pill } from './Styles';
import {
Expand All @@ -31,7 +32,6 @@ import {
selectIndicatorsForChart,
selectNativeIndicatorsForChart,
} from './selectors';
import { setDirectPathToChild } from '../../actions/dashboardState';
import {
ChartsState,
DashboardInfo,
Expand Down Expand Up @@ -87,7 +87,7 @@ export const FiltersBadge = ({ chartId }: FiltersBadgeProps) => {

const onHighlightFilterSource = useCallback(
(path: string[]) => {
dispatch(setDirectPathToChild(path));
dispatch(setFocusedNativeFilter(path[0]));
},
[dispatch],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,10 @@ export class Tabs extends React.PureComponent {
const { tabIndex: selectedTabIndex, activeKey } = this.state;

let tabsToHighlight;
if (nativeFilters?.focusedFilterId) {
tabsToHighlight =
nativeFilters.filters[nativeFilters.focusedFilterId].tabsInScope;
const highlightedFilterId =
nativeFilters?.focusedFilterId || nativeFilters?.hoveredFilterId;
if (highlightedFilterId) {
tabsToHighlight = nativeFilters.filters[highlightedFilterId]?.tabsInScope;
}
return (
<DragDroppable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ const FilterControl = ({
filter,
icon,
onFilterSelectionChange,
directPathToChild,
focusedFilterId,
inView,
showOverflow,
parentRef,
Expand Down Expand Up @@ -298,7 +298,7 @@ const FilterControl = ({
dataMaskSelected={dataMaskSelected}
filter={filter}
showOverflow={showOverflow}
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
onFilterSelectionChange={onFilterSelectionChange}
inView={inView}
parentRef={parentRef}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { FC, useCallback, useMemo, useState } from 'react';
import React, {
FC,
useEffect,
useCallback,
useMemo,
useRef,
useState,
} from 'react';
import {
DataMask,
DataMaskStateWithId,
Expand All @@ -40,20 +47,22 @@ import {
useSelectFiltersInScope,
} from 'src/dashboard/components/nativeFilters/state';
import { FilterBarOrientation, RootState } from 'src/dashboard/types';
import DropdownContainer from 'src/components/DropdownContainer';
import DropdownContainer, {
Ref as DropdownContainerRef,
} from 'src/components/DropdownContainer';
import Icons from 'src/components/Icons';
import { FiltersOutOfScopeCollapsible } from '../FiltersOutOfScopeCollapsible';
import { useFilterControlFactory } from '../useFilterControlFactory';
import { FiltersDropdownContent } from '../FiltersDropdownContent';

type FilterControlsProps = {
directPathToChild?: string[];
focusedFilterId?: string;
dataMaskSelected: DataMaskStateWithId;
onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void;
};

const FilterControls: FC<FilterControlsProps> = ({
directPathToChild,
focusedFilterId,
dataMaskSelected,
onFilterSelectionChange,
}) => {
Expand All @@ -65,10 +74,11 @@ const FilterControls: FC<FilterControlsProps> = ({
);

const [overflowedIds, setOverflowedIds] = useState<string[]>([]);
const popoverRef = useRef<DropdownContainerRef>(null);

const { filterControlFactory, filtersWithValues } = useFilterControlFactory(
dataMaskSelected,
directPathToChild,
focusedFilterId,
onFilterSelectionChange,
);
const portalNodes = useMemo(() => {
Expand Down Expand Up @@ -183,6 +193,7 @@ const FilterControls: FC<FilterControlsProps> = ({
)
: undefined
}
ref={popoverRef}
onOverflowingStateChange={({ overflowed: nextOverflowedIds }) => {
if (
nextOverflowedIds.length !== overflowedIds.length ||
Expand Down Expand Up @@ -211,6 +222,12 @@ const FilterControls: FC<FilterControlsProps> = ({
);
}, [filtersOutOfScope, filtersWithValues, overflowedFiltersInScope]);

useEffect(() => {
if (focusedFilterId && overflowedIds.includes(focusedFilterId)) {
popoverRef?.current?.open();
}
}, [focusedFilterId, popoverRef, overflowedIds]);

return (
<>
{portalNodes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ import { waitForAsyncData } from 'src/middleware/asyncEvent';
import { ClientErrorObject } from 'src/utils/getClientErrorObject';
import { FilterBarOrientation, RootState } from 'src/dashboard/types';
import { onFiltersRefreshSuccess } from 'src/dashboard/actions/dashboardState';
import { dispatchFocusAction } from './utils';
import { FAST_DEBOUNCE } from 'src/constants';
import { dispatchHoverAction, dispatchFocusAction } from './utils';
import { FilterControlProps } from './types';
import { getFormData } from '../../utils';
import { useFilterDependencies } from './state';
Expand Down Expand Up @@ -78,7 +79,7 @@ const useShouldFilterRefresh = () => {
const FilterValue: React.FC<FilterControlProps> = ({
dataMaskSelected,
filter,
directPathToChild,
focusedFilterId,
onFilterSelectionChange,
inView = true,
showOverflow,
Expand Down Expand Up @@ -211,10 +212,12 @@ const FilterValue: React.FC<FilterControlProps> = ({
]);

useEffect(() => {
if (directPathToChild?.[0] === filter.id) {
inputRef?.current?.focus();
if (focusedFilterId && focusedFilterId === filter.id) {
setTimeout(() => {
inputRef?.current?.focus();
}, FAST_DEBOUNCE);
}
}, [inputRef, directPathToChild, filter.id]);
}, [inputRef, focusedFilterId, filter.id]);

const setDataMask = useCallback(
(dataMask: DataMask) => onFilterSelectionChange(filter, dataMask),
Expand All @@ -230,14 +233,32 @@ const FilterValue: React.FC<FilterControlProps> = ({
[dispatch],
);

const setHoveredFilter = useCallback(
() => dispatchHoverAction(dispatch, id),
[dispatch, id],
);
const unsetHoveredFilter = useCallback(
() => dispatchHoverAction(dispatch),
[dispatch],
);

const hooks = useMemo(
() => ({
setDataMask,
setHoveredFilter,
unsetHoveredFilter,
setFocusedFilter,
unsetFocusedFilter,
setFilterActive,
}),
[setDataMask, setFilterActive, setFocusedFilter, unsetFocusedFilter],
[
setDataMask,
setFilterActive,
setHoveredFilter,
unsetHoveredFilter,
setFocusedFilter,
unsetFocusedFilter,
],
);

const isMissingRequiredValue = checkIsMissingRequiredValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface FilterControlProps extends BaseFilterProps {
dataMask?: DataMask;
};
icon?: React.ReactElement;
directPathToChild?: string[];
focusedFilterId?: string;
onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void;
inView?: boolean;
showOverflow?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,21 @@ import { Dispatch } from 'react';
import {
setFocusedNativeFilter,
unsetFocusedNativeFilter,
setHoveredNativeFilter,
unsetHoveredNativeFilter,
} from 'src/dashboard/actions/nativeFilters';
import { FAST_DEBOUNCE } from 'src/constants';

export const dispatchHoverAction = debounce(
(dispatch: Dispatch<any>, id?: string) => {
if (id) {
dispatch(setHoveredNativeFilter(id));
} else {
dispatch(unsetHoveredNativeFilter());
}
},
FAST_DEBOUNCE,
);

export const dispatchFocusAction = debounce(
(dispatch: Dispatch<any>, id?: string) => {
Expand All @@ -31,5 +45,5 @@ export const dispatchFocusAction = debounce(
dispatch(unsetFocusedNativeFilter());
}
},
300,
FAST_DEBOUNCE,
);
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const HorizontalFilterBar: React.FC<HorizontalBarProps> = ({
dataMaskSelected,
filterValues,
isInitialized,
directPathToChild,
focusedFilterId,
onSelectionChange,
}) => {
const hasFilters = filterValues.length > 0;
Expand Down Expand Up @@ -124,7 +124,7 @@ const HorizontalFilterBar: React.FC<HorizontalBarProps> = ({
{hasFilters && (
<FilterControls
dataMaskSelected={dataMaskSelected}
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
onFilterSelectionChange={onSelectionChange}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ const VerticalFilterBar: React.FC<VerticalBarProps> = ({
actions,
canEdit,
dataMaskSelected,
directPathToChild,
focusedFilterId,
filtersOpen,
filterValues,
height,
Expand Down Expand Up @@ -258,7 +258,7 @@ const VerticalFilterBar: React.FC<VerticalBarProps> = ({
<FilterControlsWrapper>
<FilterControls
dataMaskSelected={dataMaskSelected}
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
onFilterSelectionChange={onSelectionChange}
/>
</FilterControlsWrapper>
Expand Down Expand Up @@ -300,7 +300,7 @@ const VerticalFilterBar: React.FC<VerticalBarProps> = ({
<FilterControlsWrapper>
<FilterControls
dataMaskSelected={dataMaskSelected}
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
onFilterSelectionChange={onSelectionChange}
/>
</FilterControlsWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const publishDataMask = debounce(

export const FilterBarScrollContext = createContext(false);
const FilterBar: React.FC<FiltersBarProps> = ({
directPathToChild,
focusedFilterId,
orientation = FilterBarOrientation.VERTICAL,
verticalConfig,
}) => {
Expand Down Expand Up @@ -254,7 +254,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
canEdit={canEdit}
dashboardId={dashboardId}
dataMaskSelected={dataMaskSelected}
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
filterValues={filterValues}
isInitialized={isInitialized}
onSelectionChange={handleFilterSelectionChange}
Expand All @@ -264,7 +264,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
actions={actions}
canEdit={canEdit}
dataMaskSelected={dataMaskSelected}
directPathToChild={directPathToChild}
focusedFilterId={focusedFilterId}
filtersOpen={verticalConfig.filtersOpen}
filterValues={filterValues}
isInitialized={isInitialized}
Expand Down

0 comments on commit df91664

Please sign in to comment.