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: Programmatically open "more filters" dropdown in Horizontal Filter Bar #22276

Merged
merged 14 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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 @@ -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
Loading