This is an automated email from the ASF dual-hosted git repository.
kgabryje pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 435926b89e fix(dashboard): Add correct icon, label and badge to
horizontal native filters dropdown button (#22211)
435926b89e is described below
commit 435926b89e08395f3017a32ea00f3de252fd4fb7
Author: Cody Leff <[email protected]>
AuthorDate: Mon Nov 28 06:12:57 2022 -0700
fix(dashboard): Add correct icon, label and badge to horizontal native
filters dropdown button (#22211)
Co-authored-by: Kamil Gabryjelski <[email protected]>
---
.../superset-ui-core/src/query/types/Dashboard.ts | 2 +
.../src/components/DropdownContainer/index.tsx | 67 ++++++----
.../FilterBar/FilterControls/FilterControls.tsx | 144 ++++++++++++++-------
.../nativeFilters/FilterBar/Horizontal.tsx | 3 -
.../FilterBar/useFilterControlFactory.tsx | 9 +-
.../dashboard/components/nativeFilters/state.ts | 9 +-
6 files changed, 153 insertions(+), 81 deletions(-)
diff --git
a/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts
b/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts
index c86c1cfbe4..90c1e5856e 100644
--- a/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts
+++ b/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts
@@ -91,6 +91,8 @@ export type Filter = {
description: string;
};
+export type FilterWithDataMask = Filter & { dataMask: DataMaskWithId };
+
export type Divider = Partial<Omit<Filter, 'id' | 'type'>> & {
id: string;
title: string;
diff --git a/superset-frontend/src/components/DropdownContainer/index.tsx
b/superset-frontend/src/components/DropdownContainer/index.tsx
index 9af3a96534..d364d3542e 100644
--- a/superset-frontend/src/components/DropdownContainer/index.tsx
+++ b/superset-frontend/src/components/DropdownContainer/index.tsx
@@ -104,7 +104,7 @@ const DropdownContainer = forwardRef(
{
items,
onOverflowingStateChange,
- dropdownContent: popoverContent,
+ dropdownContent: getPopoverContent,
dropdownRef: popoverRef,
dropdownStyle: popoverStyle = {},
dropdownTriggerCount: popoverTriggerCount,
@@ -209,26 +209,31 @@ const DropdownContainer = forwardRef(
}
}, [notOverflowedIds, onOverflowingStateChange, overflowedIds]);
- const content = useMemo(
- () => (
- <div
- css={css`
- display: flex;
- flex-direction: column;
- gap: ${theme.gridUnit * 4}px;
- `}
- data-test="dropdown-content"
- style={popoverStyle}
- ref={popoverRef}
- >
- {popoverContent
- ? popoverContent(overflowedItems)
- : overflowedItems.map(item => item.element)}
- </div>
- ),
+ const overflowingCount =
+ overflowingIndex !== -1 ? items.length - overflowingIndex : 0;
+
+ const popoverContent = useMemo(
+ () =>
+ getPopoverContent || overflowingCount ? (
+ <div
+ css={css`
+ display: flex;
+ flex-direction: column;
+ gap: ${theme.gridUnit * 4}px;
+ `}
+ data-test="dropdown-content"
+ style={popoverStyle}
+ ref={popoverRef}
+ >
+ {getPopoverContent
+ ? getPopoverContent(overflowedItems)
+ : overflowedItems.map(item => item.element)}
+ </div>
+ ) : null,
[
+ getPopoverContent,
overflowedItems,
- popoverContent,
+ overflowingCount,
popoverRef,
popoverStyle,
theme.gridUnit,
@@ -244,9 +249,6 @@ const DropdownContainer = forwardRef(
[ref],
);
- const overflowingCount =
- overflowingIndex !== -1 ? items.length - overflowingIndex : 0;
-
return (
<div
ref={ref}
@@ -268,20 +270,33 @@ const DropdownContainer = forwardRef(
>
{notOverflowedItems.map(item => item.element)}
</div>
- {overflowingCount > 0 && (
+ {popoverContent && (
<Popover
- content={content}
+ content={popoverContent}
trigger="click"
visible={popoverVisible}
onVisibleChange={visible => setPopoverVisible(visible)}
+ placement="bottom"
>
<Button buttonStyle="secondary">
{popoverTriggerIcon}
{popoverTriggerText}
- <Badge count={popoverTriggerCount || overflowingCount} />
+ <Badge
+ count={popoverTriggerCount ?? overflowingCount}
+ css={css`
+ margin-left: ${popoverTriggerCount ?? overflowingCount
+ ? '8px'
+ : '0'};
+ `}
+ />
<Icons.DownOutlined
iconSize="m"
- iconColor={theme.colors.grayscale.base}
+ iconColor={theme.colors.grayscale.light1}
+ css={css`
+ .anticon {
+ display: flex;
+ }
+ `}
/>
</Button>
</Popover>
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
index 9b0347ebf0..5c0ce9f902 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
@@ -24,6 +24,8 @@ import {
Divider,
css,
SupersetTheme,
+ t,
+ isNativeFilter,
} from '@superset-ui/core';
import {
createHtmlPortalNode,
@@ -37,6 +39,7 @@ import {
} from 'src/dashboard/components/nativeFilters/state';
import { FilterBarOrientation, RootState } from 'src/dashboard/types';
import DropdownContainer from 'src/components/DropdownContainer';
+import Icons from 'src/components/Icons';
import { FiltersOutOfScopeCollapsible } from '../FiltersOutOfScopeCollapsible';
import { useFilterControlFactory } from '../useFilterControlFactory';
import { FiltersDropdownContent } from '../FiltersDropdownContent';
@@ -56,7 +59,7 @@ const FilterControls: FC<FilterControlsProps> = ({
state => state.dashboardInfo.filterBarOrientation,
);
- const [overflowIndex, setOverflowIndex] = useState(0);
+ const [overflowedIds, setOverflowedIds] = useState<string[]>([]);
const { filterControlFactory, filtersWithValues } = useFilterControlFactory(
dataMaskSelected,
@@ -100,52 +103,99 @@ const FilterControls: FC<FilterControlsProps> = ({
</>
);
- const renderHorizontalContent = () => {
- const items = filtersInScope.map(filter => ({
- id: filter.id,
- element: (
- <div
- css={css`
- flex-shrink: 0;
- `}
- >
- {renderer(filter)}
- </div>
- ),
- }));
- return (
- <div
- css={(theme: SupersetTheme) =>
- css`
- padding-left: ${theme.gridUnit * 4}px;
- min-width: 0;
- `
+ const items = useMemo(
+ () =>
+ filtersInScope.map(filter => ({
+ id: filter.id,
+ element: (
+ <div
+ css={css`
+ flex-shrink: 0;
+ `}
+ >
+ {renderer(filter)}
+ </div>
+ ),
+ })),
+ [filtersInScope, renderer],
+ );
+
+ const overflowedFiltersInScope = useMemo(
+ () => filtersInScope.filter(({ id }) => overflowedIds?.includes(id)),
+ [filtersInScope, overflowedIds],
+ );
+
+ const activeOverflowedFiltersInScope = useMemo(
+ () =>
+ overflowedFiltersInScope.filter(
+ filter => isNativeFilter(filter) && filter.dataMask.filterState?.value,
+ ).length,
+ [overflowedFiltersInScope],
+ );
+
+ const renderHorizontalContent = () => (
+ <div
+ css={(theme: SupersetTheme) =>
+ css`
+ padding-left: ${theme.gridUnit * 4}px;
+ min-width: 0;
+ `
+ }
+ >
+ <DropdownContainer
+ items={items}
+ dropdownTriggerIcon={
+ <Icons.FilterSmall
+ css={css`
+ && {
+ margin-right: -4px;
+ display: flex;
+ }
+ `}
+ />
}
- >
- <DropdownContainer
- items={items}
- dropdownContent={overflowedItems => {
- const overflowedItemIds = new Set(
- overflowedItems.map(({ id }) => id),
- );
- return (
- <FiltersDropdownContent
- filtersInScope={filtersInScope.filter(({ id }) =>
- overflowedItemIds.has(id),
- )}
- filtersOutOfScope={filtersOutOfScope}
- renderer={renderer}
- showCollapsePanel={showCollapsePanel}
- />
- );
- }}
- onOverflowingStateChange={overflowingState =>
- setOverflowIndex(overflowingState.notOverflowed.length)
+ dropdownTriggerText={t('More filters')}
+ dropdownTriggerCount={activeOverflowedFiltersInScope}
+ dropdownContent={
+ overflowedFiltersInScope.length ||
+ (filtersOutOfScope.length && showCollapsePanel)
+ ? () => (
+ <FiltersDropdownContent
+ filtersInScope={overflowedFiltersInScope}
+ filtersOutOfScope={filtersOutOfScope}
+ renderer={renderer}
+ showCollapsePanel={showCollapsePanel}
+ />
+ )
+ : undefined
+ }
+ onOverflowingStateChange={({ overflowed: nextOverflowedIds }) => {
+ if (
+ nextOverflowedIds.length !== overflowedIds.length ||
+ overflowedIds.reduce(
+ (a, b, i) => a || b !== nextOverflowedIds[i],
+ false,
+ )
+ ) {
+ setOverflowedIds(nextOverflowedIds);
}
- />
- </div>
+ }}
+ />
+ </div>
+ );
+
+ const overflowedByIndex = useMemo(() => {
+ const filtersOutOfScopeIds = new Set(filtersOutOfScope.map(({ id }) =>
id));
+ const overflowedFiltersInScopeIds = new Set(
+ overflowedFiltersInScope.map(({ id }) => id),
+ );
+
+ return filtersWithValues.map(
+ filter =>
+ filtersOutOfScopeIds.has(filter.id) ||
+ overflowedFiltersInScopeIds.has(filter.id),
);
- };
+ }, [filtersOutOfScope, filtersWithValues, overflowedFiltersInScope]);
return (
<>
@@ -153,7 +203,11 @@ const FilterControls: FC<FilterControlsProps> = ({
.filter((node, index) => filterIds.has(filtersWithValues[index].id))
.map((node, index) => (
<InPortal node={node}>
- {filterControlFactory(index, filterBarOrientation, overflowIndex)}
+ {filterControlFactory(
+ index,
+ filterBarOrientation,
+ overflowedByIndex[index],
+ )}
</InPortal>
))}
{filterBarOrientation === FilterBarOrientation.VERTICAL &&
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
index ac03b0e0ff..d085e08900 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
@@ -74,9 +74,6 @@ const FiltersLinkContainer = styled.div<{ hasFilters: boolean
}>`
button {
display: flex;
align-items: center;
- text-transform: capitalize;
- font-weight: ${theme.typography.weights.normal};
- color: ${theme.colors.primary.base};
> .anticon {
height: 24px;
padding-right: ${theme.gridUnit}px;
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx
index fe855ec3e3..6893e629cb 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx
@@ -23,6 +23,7 @@ import {
DataMaskStateWithId,
Divider,
Filter,
+ FilterWithDataMask,
isFilterDivider,
} from '@superset-ui/core';
import { FilterBarOrientation } from 'src/dashboard/types';
@@ -37,7 +38,7 @@ export const useFilterControlFactory = (
) => {
const filters = useFilters();
const filterValues = useMemo(() => Object.values(filters), [filters]);
- const filtersWithValues: (Filter | Divider)[] = useMemo(
+ const filtersWithValues: (FilterWithDataMask | Divider)[] = useMemo(
() =>
filterValues.map(filter => ({
...filter,
@@ -50,7 +51,7 @@ export const useFilterControlFactory = (
(
index: number,
filterBarOrientation: FilterBarOrientation,
- overflowIndex: number,
+ overflow: boolean,
) => {
const filter = filtersWithValues[index];
if (isFilterDivider(filter)) {
@@ -59,7 +60,7 @@ export const useFilterControlFactory = (
title={filter.title}
description={filter.description}
orientation={filterBarOrientation}
- overflow={index >= overflowIndex}
+ overflow={overflow}
/>
);
}
@@ -71,7 +72,7 @@ export const useFilterControlFactory = (
onFilterSelectionChange={onFilterSelectionChange}
inView={false}
orientation={filterBarOrientation}
- overflow={index >= overflowIndex}
+ overflow={overflow}
/>
);
},
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/state.ts
b/superset-frontend/src/dashboard/components/nativeFilters/state.ts
index 030b65859b..51d987a577 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/state.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/state.ts
@@ -23,6 +23,7 @@ import {
FilterConfiguration,
Divider,
isFilterDivider,
+ FilterWithDataMask,
} from '@superset-ui/core';
import { ActiveTabs, DashboardLayout, RootState } from '../../types';
import { TAB_TYPE } from '../../util/componentTypes';
@@ -109,13 +110,15 @@ function useIsFilterInScope() {
}));
}
-export function useSelectFiltersInScope(filters: (Filter | Divider)[]) {
+export function useSelectFiltersInScope(
+ filters: (FilterWithDataMask | Divider)[],
+) {
const dashboardHasTabs = useDashboardHasTabs();
const isFilterInScope = useIsFilterInScope();
return useMemo(() => {
- let filtersInScope: (Filter | Divider)[] = [];
- const filtersOutOfScope: (Filter | Divider)[] = [];
+ let filtersInScope: (FilterWithDataMask | Divider)[] = [];
+ const filtersOutOfScope: (FilterWithDataMask | Divider)[] = [];
// we check native filters scopes only on dashboards with tabs
if (!dashboardHasTabs) {