| /** |
| * 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 React, { useState } from 'react'; |
| import { t, useTheme, css } from '@superset-ui/core'; |
| import { |
| 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 Icon from 'src/components/Icon'; |
| import { Indent, Panel, Reset, Title } from './Styles'; |
| import { Indicator } from './selectors'; |
| import FilterIndicator from './FilterIndicator'; |
| |
| export interface DetailsPanelProps { |
| appliedCrossFilterIndicators: Indicator[]; |
| appliedIndicators: Indicator[]; |
| incompatibleIndicators: Indicator[]; |
| unsetIndicators: Indicator[]; |
| onHighlightFilterSource: (path: string[]) => void; |
| children: JSX.Element; |
| } |
| |
| const DetailsPanelPopover = ({ |
| appliedCrossFilterIndicators = [], |
| appliedIndicators = [], |
| incompatibleIndicators = [], |
| unsetIndicators = [], |
| onHighlightFilterSource, |
| children, |
| }: DetailsPanelProps) => { |
| const theme = useTheme(); |
| |
| 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[]>(() => [ |
| ...getDefaultActivePanel(), |
| ]); |
| |
| function handlePopoverStatus(isOpen: boolean) { |
| // every time the popover opens, make sure the most relevant panel is active |
| if (isOpen) { |
| setActivePanels(getDefaultActivePanel()); |
| } |
| } |
| |
| function handleActivePanelChange(panels: string | string[]) { |
| // need to convert to an array so that handlePopoverStatus will work |
| if (typeof panels === 'string') { |
| setActivePanels([panels]); |
| } else { |
| setActivePanels(panels); |
| } |
| } |
| |
| const indicatorKey = (indicator: Indicator): string => |
| `${indicator.column} - ${indicator.name}`; |
| |
| const content = ( |
| <Panel> |
| <Global |
| styles={css` |
| .filterStatusPopover { |
| .ant-popover-inner { |
| background-color: ${theme.colors.grayscale.dark2}cc; |
| .ant-popover-inner-content { |
| padding-top: 0; |
| padding-bottom: 0; |
| } |
| } |
| &.ant-popover-placement-bottom, |
| &.ant-popover-placement-bottomLeft, |
| &.ant-popover-placement-bottomRight { |
| & > .ant-popover-content > .ant-popover-arrow { |
| border-top-color: ${theme.colors.grayscale.dark2}cc; |
| border-left-color: ${theme.colors.grayscale.dark2}cc; |
| } |
| } |
| &.ant-popover-placement-top, |
| &.ant-popover-placement-topLeft, |
| &.ant-popover-placement-topRight { |
| & > .ant-popover-content > .ant-popover-arrow { |
| border-bottom-color: ${theme.colors.grayscale.dark2}cc; |
| border-right-color: ${theme.colors.grayscale.dark2}cc; |
| } |
| } |
| &.ant-popover-placement-left, |
| &.ant-popover-placement-leftTop, |
| &.ant-popover-placement-leftBottom { |
| & > .ant-popover-content > .ant-popover-arrow { |
| border-top-color: ${theme.colors.grayscale.dark2}cc; |
| border-right-color: ${theme.colors.grayscale.dark2}cc; |
| } |
| } |
| &.ant-popover-placement-right, |
| &.ant-popover-placement-rightTop, |
| &.ant-popover-placement-rightBottom { |
| & > .ant-popover-content > .ant-popover-arrow { |
| border-bottom-color: ${theme.colors.grayscale.dark2}cc; |
| border-left-color: ${theme.colors.grayscale.dark2}cc; |
| } |
| } |
| &.ant-popover { |
| color: ${theme.colors.grayscale.light4}; |
| } |
| } |
| `} |
| /> |
| <Reset> |
| <Collapse |
| ghost |
| light |
| 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" |
| header={ |
| <Title bold color={theme.colors.success.base}> |
| <CheckCircleFilled />{' '} |
| {t('Applied Filters (%d)', appliedIndicators.length)} |
| </Title> |
| } |
| > |
| <Indent css={{ paddingBottom: theme.gridUnit * 3 }}> |
| {appliedIndicators.map(indicator => ( |
| <FilterIndicator |
| key={indicatorKey(indicator)} |
| indicator={indicator} |
| onClick={onHighlightFilterSource} |
| /> |
| ))} |
| </Indent> |
| </Collapse.Panel> |
| ) : null} |
| {incompatibleIndicators.length ? ( |
| <Collapse.Panel |
| key="incompatible" |
| header={ |
| <Title bold color={theme.colors.alert.base}> |
| <ExclamationCircleFilled />{' '} |
| {t( |
| 'Incompatible Filters (%d)', |
| incompatibleIndicators.length, |
| )} |
| </Title> |
| } |
| > |
| <Indent css={{ paddingBottom: theme.gridUnit * 3 }}> |
| {incompatibleIndicators.map(indicator => ( |
| <FilterIndicator |
| key={indicatorKey(indicator)} |
| indicator={indicator} |
| onClick={onHighlightFilterSource} |
| /> |
| ))} |
| </Indent> |
| </Collapse.Panel> |
| ) : null} |
| {unsetIndicators.length ? ( |
| <Collapse.Panel |
| key="unset" |
| header={ |
| <Title bold color={theme.colors.grayscale.light1}> |
| <MinusCircleFilled />{' '} |
| {t('Unset Filters (%d)', unsetIndicators.length)} |
| </Title> |
| } |
| disabled={!unsetIndicators.length} |
| > |
| <Indent css={{ paddingBottom: theme.gridUnit * 3 }}> |
| {unsetIndicators.map(indicator => ( |
| <FilterIndicator |
| key={indicatorKey(indicator)} |
| indicator={indicator} |
| onClick={onHighlightFilterSource} |
| /> |
| ))} |
| </Indent> |
| </Collapse.Panel> |
| ) : null} |
| </Collapse> |
| </Reset> |
| </Panel> |
| ); |
| |
| return ( |
| <Popover |
| overlayClassName="filterStatusPopover" |
| content={content} |
| onVisibleChange={handlePopoverStatus} |
| placement="bottom" |
| trigger="click" |
| > |
| {children} |
| </Popover> |
| ); |
| }; |
| |
| export default DetailsPanelPopover; |