Skip to content

Commit

Permalink
feat(cross-filter): Cross filter badge (apache#13687)
Browse files Browse the repository at this point in the history
  • Loading branch information
simcha90 authored Mar 18, 2021
1 parent 9efe1a4 commit 577ecc2
Show file tree
Hide file tree
Showing 20 changed files with 468 additions and 290 deletions.
22 changes: 22 additions & 0 deletions superset-frontend/images/icons/cross-filter-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions superset-frontend/src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { ReactComponent as AlertSolidSmallIcon } from 'images/icons/alert_solid_
import { ReactComponent as BinocularsIcon } from 'images/icons/binoculars.svg';
import { ReactComponent as BoltIcon } from 'images/icons/bolt.svg';
import { ReactComponent as BoltSmallIcon } from 'images/icons/bolt_small.svg';
import { ReactComponent as CrossFilterBadge } from 'images/icons/cross-filter-badge.svg';
import { ReactComponent as BoltSmallRunIcon } from 'images/icons/bolt_small_run.svg';
import { ReactComponent as CalendarIcon } from 'images/icons/calendar.svg';
import { ReactComponent as CancelIcon } from 'images/icons/cancel.svg';
Expand Down Expand Up @@ -165,6 +166,7 @@ export type IconName =
| 'caret-right'
| 'caret-up'
| 'certified'
| 'cross-filter-badge'
| 'check'
| 'checkbox-half'
| 'checkbox-off'
Expand Down Expand Up @@ -281,6 +283,7 @@ export const iconsRegistry: Record<
'alert-solid-small': AlertSolidSmallIcon,
'bolt-small': BoltSmallIcon,
'bolt-small-run': BoltSmallRunIcon,
'cross-filter-badge': CrossFilterBadge,
'cancel-solid': CancelSolidIcon,
'cancel-x': CancelXIcon,
'card-view': CardViewIcon,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ import { useForceUpdate } from '../nativeFilters/FiltersConfigModal/FiltersConfi
import { CrossFilterScopingFormType } from './types';

type CrossFilterScopingFormProps = {
chartId: number;
scope: Scope;
form: FormInstance<CrossFilterScopingFormType>;
};

const CrossFilterScopingForm: FC<CrossFilterScopingFormProps> = ({
form,
scope,
chartId,
}) => {
const forceUpdate = useForceUpdate();
const formScope = form.getFieldValue('scope');
Expand All @@ -44,6 +46,7 @@ const CrossFilterScopingForm: FC<CrossFilterScopingFormProps> = ({
});
}}
scope={scope}
chartId={chartId}
formScope={formScope}
forceUpdate={forceUpdate}
formScoping={formScoping}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ const CrossFilterScopingModal: FC<CrossFilterScopingModalProps> = ({
dispatch(
setChartConfiguration({
...chartConfig,
[chartId]: { crossFilters: { scope: form.getFieldValue('scope') } },
[chartId]: {
id: chartId,
crossFilters: { scope: form.getFieldValue('scope') },
},
}),
);
onClose();
Expand Down Expand Up @@ -88,7 +91,7 @@ const CrossFilterScopingModal: FC<CrossFilterScopingModalProps> = ({
}
>
<StyledForm preserve={false} form={form} layout="vertical">
<CrossFilterScopingForm form={form} scope={scope} />
<CrossFilterScopingForm form={form} scope={scope} chartId={chartId} />
</StyledForm>
</StyledModal>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,20 @@
import React, { useState } from 'react';
import { t, useTheme, css } from '@superset-ui/core';
import {
SearchOutlined,
MinusCircleFilled,
CheckCircleFilled,
ExclamationCircleFilled,
} from '@ant-design/icons';
import { Popover } from 'src/common/components/index';
import Collapse from 'src/common/components/Collapse';
import { Global } from '@emotion/core';
import {
Indent,
Item,
ItemIcon,
Panel,
Reset,
Title,
FilterValue,
} from './Styles';
import Icon from 'src/components/Icon';
import { Indent, Panel, Reset, Title } from './Styles';
import { Indicator } from './selectors';
import { getFilterValueForDisplay } from '../nativeFilters/FilterBar/FilterSets/utils';

export interface IndicatorProps {
indicator: Indicator;
onClick: (path: string[]) => void;
}

const Indicator = ({
indicator: { column, name, value = [], path },
onClick,
}: IndicatorProps) => {
const resultValue = getFilterValueForDisplay(value);
return (
<Item onClick={() => onClick([...path, `LABEL-${column}`])}>
<Title bold>
<ItemIcon>
<SearchOutlined />
</ItemIcon>
{name}
{resultValue ? ': ' : ''}
</Title>
<FilterValue>{resultValue}</FilterValue>
</Item>
);
};
import FilterIndicator from './FilterIndicator';

export interface DetailsPanelProps {
appliedCrossFilterIndicators: Indicator[];
appliedIndicators: Indicator[];
incompatibleIndicators: Indicator[];
unsetIndicators: Indicator[];
Expand All @@ -72,6 +41,7 @@ export interface DetailsPanelProps {
}

const DetailsPanelPopover = ({
appliedCrossFilterIndicators = [],
appliedIndicators = [],
incompatibleIndicators = [],
unsetIndicators = [],
Expand All @@ -80,21 +50,34 @@ const DetailsPanelPopover = ({
}: DetailsPanelProps) => {
const theme = useTheme();

function defaultActivePanel() {
if (incompatibleIndicators.length) return 'incompatible';
if (appliedIndicators.length) return 'applied';
return 'unset';
}
const getDefaultActivePanel = () => {
const result = [];
if (appliedCrossFilterIndicators.length) {
result.push('appliedCrossFilters');
}
if (appliedIndicators.length) {
result.push('applied');
}
if (incompatibleIndicators.length) {
result.push('incompatible');
}
if (result.length) {
return result;
}
return ['unset'];
};

const [activePanels, setActivePanels] = useState<string[]>(() => [
defaultActivePanel(),
...getDefaultActivePanel(),
]);

function handlePopoverStatus(isOpen: boolean) {
// every time the popover opens, make sure the most relevant panel is active
if (isOpen) {
if (!activePanels.includes(defaultActivePanel())) {
setActivePanels([...activePanels, defaultActivePanel()]);
if (
!activePanels.find(panel => getDefaultActivePanel().includes(panel))
) {
setActivePanels([...activePanels, ...getDefaultActivePanel()]);
}
}
}
Expand Down Expand Up @@ -168,6 +151,33 @@ const DetailsPanelPopover = ({
activeKey={activePanels}
onChange={handleActivePanelChange}
>
{appliedCrossFilterIndicators.length ? (
<Collapse.Panel
key="appliedCrossFilters"
header={
<Title bold color={theme.colors.primary.light1}>
<Icon
name="cross-filter-badge"
css={{ fill: theme.colors.primary.light1 }}
/>
{t(
'Applied Cross Filters (%d)',
appliedCrossFilterIndicators.length,
)}
</Title>
}
>
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
{appliedCrossFilterIndicators.map(indicator => (
<FilterIndicator
key={indicatorKey(indicator)}
indicator={indicator}
onClick={onHighlightFilterSource}
/>
))}
</Indent>
</Collapse.Panel>
) : null}
{appliedIndicators.length ? (
<Collapse.Panel
key="applied"
Expand All @@ -180,7 +190,7 @@ const DetailsPanelPopover = ({
>
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
{appliedIndicators.map(indicator => (
<Indicator
<FilterIndicator
key={indicatorKey(indicator)}
indicator={indicator}
onClick={onHighlightFilterSource}
Expand All @@ -204,7 +214,7 @@ const DetailsPanelPopover = ({
>
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
{incompatibleIndicators.map(indicator => (
<Indicator
<FilterIndicator
key={indicatorKey(indicator)}
indicator={indicator}
onClick={onHighlightFilterSource}
Expand All @@ -226,7 +236,7 @@ const DetailsPanelPopover = ({
>
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
{unsetIndicators.map(indicator => (
<Indicator
<FilterIndicator
key={indicatorKey(indicator)}
indicator={indicator}
onClick={onHighlightFilterSource}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { SearchOutlined } from '@ant-design/icons';
import React, { FC } from 'react';
import { getFilterValueForDisplay } from '../nativeFilters/FilterBar/FilterSets/utils';
import { FilterValue, Item, ItemIcon, Title } from './Styles';

import { Indicator } from './selectors';

export interface IndicatorProps {
indicator: Indicator;
onClick?: (path: string[]) => void;
}

const FilterIndicator: FC<IndicatorProps> = ({
indicator: { column, name, value, path = [] },
onClick = () => {},
}) => {
const resultValue = getFilterValueForDisplay(value);
return (
<Item onClick={() => onClick([...path, `LABEL-${column}`])}>
<Title bold>
<ItemIcon>
<SearchOutlined />
</ItemIcon>
{name}
{resultValue ? ': ' : ''}
</Title>
<FilterValue>{resultValue}</FilterValue>
</Item>
);
};

export default FilterIndicator;
21 changes: 12 additions & 9 deletions superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ export const Pill = styled.div`
background: ${({ theme }) => theme.colors.grayscale.dark1};
}
&.has-cross-filters {
background: ${({ theme }) => theme.colors.primary.base};
&:hover {
background: ${({ theme }) => theme.colors.primary.dark1};
}
}
&.has-incompatible-filters {
color: ${({ theme }) => theme.colors.grayscale.dark2};
background: ${({ theme }) => theme.colors.alert.base};
Expand All @@ -73,15 +80,6 @@ export const Pill = styled.div`
}
`;

export const WarningPill = styled(Pill)`
background: ${({ theme }) => theme.colors.alert.base};
color: ${({ theme }) => theme.colors.grayscale.dark1};
`;

export const UnsetPill = styled(Pill)`
background: ${({ theme }) => theme.colors.grayscale.light1};
`;

export interface TitleProps {
bold?: boolean;
color?: string;
Expand All @@ -95,6 +93,11 @@ export const Title = styled.span<TitleProps>`
return 'auto';
}};
color: ${({ color, theme }) => color || theme.colors.grayscale.light5};
display: flex;
align-items: center;
& > * {
margin-right: ${({ theme }) => theme.gridUnit}px;
}
`;

export const ItemIcon = styled.i`
Expand Down
Loading

0 comments on commit 577ecc2

Please sign in to comment.