-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
[RA-TES-6185] Add more filter
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import React, { useState, MouseEvent } from 'react'; | ||
import { t } from '@superset-ui/core'; | ||
import { | ||
Button, | ||
Checkbox, | ||
Grid, | ||
ListSubheader, | ||
Menu, | ||
MenuItem, | ||
Stack, | ||
} from '@mui/material'; | ||
Check failure on line 11 in superset-frontend/src/katalon/CustomFilter/FilterExtension.tsx
|
||
|
||
interface FilterItem { | ||
id: string; | ||
name: string; | ||
element: JSX.Element; | ||
} | ||
|
||
interface FilterExtensionProps { | ||
items: FilterItem[]; | ||
} | ||
|
||
function FilterExtension(props: FilterExtensionProps) { | ||
const { items } = props; | ||
|
||
const [addFilter, setAddFilter] = useState<FilterItem[]>([]); | ||
|
||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); | ||
|
||
const handleClick = (event: MouseEvent<HTMLButtonElement>) => { | ||
setAnchorEl(event.currentTarget); | ||
}; | ||
|
||
const handleClose = () => { | ||
setAnchorEl(null); | ||
}; | ||
|
||
const handleAddOrRemove = (selectedFilter: FilterItem) => { | ||
setAddFilter((prevFilters: FilterItem[]) => { | ||
// Check if the filter is already added | ||
const isFilterExisting = prevFilters.some( | ||
filter => filter.id === selectedFilter.id, | ||
); | ||
|
||
if (isFilterExisting) { | ||
// If the filter exists, remove it from the list | ||
return prevFilters.filter(filter => filter.id !== selectedFilter.id); | ||
} | ||
return [...prevFilters, selectedFilter]; | ||
}); | ||
handleClose(); | ||
}; | ||
|
||
const renderPopperMenu = (invisbleFilter: FilterItem[]) => ( | ||
<Menu | ||
elevation={2} | ||
id="list-advance-filter" | ||
anchorEl={anchorEl} | ||
keepMounted | ||
open={Boolean(anchorEl)} | ||
onClose={handleClose} | ||
anchorOrigin={{ | ||
vertical: 'bottom', | ||
horizontal: 'center', | ||
}} | ||
transformOrigin={{ | ||
vertical: 'top', | ||
horizontal: 'center', | ||
}} | ||
> | ||
<ListSubheader | ||
sx={{ | ||
color: '#797B7F', | ||
Check failure on line 73 in superset-frontend/src/katalon/CustomFilter/FilterExtension.tsx
|
||
fontSize: 14, | ||
fontWeight: 700, | ||
}} | ||
> | ||
{t('all filters').toUpperCase()} | ||
</ListSubheader> | ||
{invisbleFilter.length !== 0 && | ||
invisbleFilter.map(item => { | ||
const isFilterExisting = addFilter.find( | ||
filterComponent => filterComponent?.id === item?.id, | ||
); | ||
return ( | ||
<MenuItem onClick={() => handleAddOrRemove(item)} key={item?.id}> | ||
<Grid | ||
container | ||
direction="row" | ||
justifyContent="center" | ||
alignItems="center" | ||
spacing={1} | ||
> | ||
<Grid item xs={8}> | ||
{item?.name} | ||
</Grid> | ||
<Grid item xs={4}> | ||
<Checkbox color="primary" checked={!!isFilterExisting} /> | ||
</Grid> | ||
</Grid> | ||
</MenuItem> | ||
); | ||
})} | ||
</Menu> | ||
); | ||
|
||
const renderAddMoreButton = () => { | ||
// Take the list all filters, | ||
// then device them into two parts | ||
const visibleFilter: FilterItem[] = items.slice(0, 2); | ||
const invisbleFilter: FilterItem[] = items.slice(3); | ||
|
||
return ( | ||
<Stack | ||
sx={{ | ||
display: 'flex', | ||
alignItems: 'center', | ||
flexWrap: 'wrap', | ||
gap: '3px', | ||
}} | ||
direction="row" | ||
spacing={2} | ||
> | ||
{visibleFilter.length !== 0 && | ||
visibleFilter.map((item, index) => ( | ||
<div key={index}>{item.element}</div> | ||
))} | ||
{addFilter.length !== 0 && | ||
addFilter.map((item, index) => <div key={index}>{item.element}</div>)} | ||
<Button | ||
sx={{ | ||
bgcolor: '#FFFFFF', | ||
Check failure on line 132 in superset-frontend/src/katalon/CustomFilter/FilterExtension.tsx
|
||
color: '#0F1866', | ||
Check failure on line 133 in superset-frontend/src/katalon/CustomFilter/FilterExtension.tsx
|
||
textTransform: 'none', | ||
fontSize: 16, | ||
fontWeight: 600, | ||
}} | ||
onClick={handleClick} | ||
> | ||
{t('+ Add more')} | ||
</Button> | ||
{renderPopperMenu(invisbleFilter)} | ||
</Stack> | ||
); | ||
}; | ||
|
||
return <>{renderAddMoreButton()}</>; | ||
} | ||
|
||
export default FilterExtension; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import React, { useMemo } from 'react'; | ||
import { | ||
DataMaskStateWithId, | ||
FeatureFlag, | ||
isFeatureEnabled, | ||
JsonObject, | ||
styled, | ||
t, | ||
} from '@superset-ui/core'; | ||
import Icons from 'src/components/Icons'; | ||
Check failure on line 10 in superset-frontend/src/katalon/CustomFilter/KatalonHorizontal.tsx
|
||
import Loading from 'src/components/Loading'; | ||
Check failure on line 11 in superset-frontend/src/katalon/CustomFilter/KatalonHorizontal.tsx
|
||
import { useSelector } from 'react-redux'; | ||
import { | ||
getFilterBarTestId, | ||
useChartsVerboseMaps, | ||
} from 'src/dashboard/components/nativeFilters/FilterBar/utils'; | ||
import { HorizontalBarProps } from 'src/dashboard/components/nativeFilters/FilterBar/types'; | ||
import { DashboardLayout, RootState } from 'src/dashboard/types'; | ||
import { crossFiltersSelector } from 'src/dashboard/components/nativeFilters/FilterBar/CrossFilters/selectors'; | ||
import { getUrlParam } from 'src/utils/urlUtils'; | ||
import { URL_PARAMS } from 'src/constants'; | ||
import FilterConfigurationLink from 'src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink'; | ||
import FilterBarSettings from 'src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings'; | ||
import FilterControls from 'src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls'; | ||
|
||
const HorizontalBar = styled.div` | ||
${({ theme }) => ` | ||
padding: ${theme.gridUnit * 3}px ${theme.gridUnit * 2}px ${ | ||
theme.gridUnit * 3 | ||
}px ${theme.gridUnit * 4}px; | ||
background: ${theme.colors.grayscale.light5}; | ||
box-shadow: inset 0px -2px 2px -1px ${theme.colors.grayscale.light2}; | ||
`} | ||
`; | ||
|
||
const HorizontalBarContent = styled.div` | ||
${({ theme }) => ` | ||
display: flex; | ||
flex-direction: row; | ||
flex-wrap: nowrap; | ||
align-items: center; | ||
justify-content: flex-start; | ||
line-height: 0; | ||
.loading { | ||
margin: ${theme.gridUnit * 2}px auto ${theme.gridUnit * 2}px; | ||
padding: 0; | ||
} | ||
`} | ||
`; | ||
|
||
const FilterBarEmptyStateContainer = styled.div` | ||
${({ theme }) => ` | ||
font-weight: ${theme.typography.weights.bold}; | ||
color: ${theme.colors.grayscale.base}; | ||
font-size: ${theme.typography.sizes.s}px; | ||
`} | ||
`; | ||
|
||
const FiltersLinkContainer = styled.div<{ hasFilters: boolean }>` | ||
${({ theme, hasFilters }) => ` | ||
height: 24px; | ||
display: flex; | ||
align-items: center; | ||
padding: 0 ${theme.gridUnit * 4}px 0 ${theme.gridUnit * 4}px; | ||
border-right: ${ | ||
hasFilters ? `1px solid ${theme.colors.grayscale.light2}` : 0 | ||
}; | ||
button { | ||
display: flex; | ||
align-items: center; | ||
> .anticon { | ||
height: 24px; | ||
padding-right: ${theme.gridUnit}px; | ||
} | ||
> .anticon + span, > .anticon { | ||
margin-right: 0; | ||
margin-left: 0; | ||
} | ||
} | ||
`} | ||
`; | ||
|
||
const HorizontalFilterBar: React.FC<HorizontalBarProps> = ({ | ||
actions, | ||
canEdit, | ||
dashboardId, | ||
dataMaskSelected, | ||
filterValues, | ||
isInitialized, | ||
onSelectionChange, | ||
}) => { | ||
const dataMask = useSelector<RootState, DataMaskStateWithId>( | ||
state => state.dataMask, | ||
); | ||
const chartConfiguration = useSelector<RootState, JsonObject>( | ||
state => state.dashboardInfo.metadata?.chart_configuration, | ||
); | ||
const dashboardLayout = useSelector<RootState, DashboardLayout>( | ||
state => state.dashboardLayout.present, | ||
); | ||
const isCrossFiltersEnabled = isFeatureEnabled( | ||
FeatureFlag.DASHBOARD_CROSS_FILTERS, | ||
); | ||
const verboseMaps = useChartsVerboseMaps(); | ||
|
||
const selectedCrossFilters = isCrossFiltersEnabled | ||
? crossFiltersSelector({ | ||
dataMask, | ||
chartConfiguration, | ||
dashboardLayout, | ||
verboseMaps, | ||
}) | ||
: []; | ||
const hasFilters = filterValues.length > 0 || selectedCrossFilters.length > 0; | ||
|
||
const actionsElement = useMemo( | ||
() => | ||
isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) ? actions : null, | ||
[actions], | ||
); | ||
|
||
const isKatalonEmbeddedMode = getUrlParam(URL_PARAMS.isKatalonEmbeddedMode); | ||
|
||
return ( | ||
<HorizontalBar {...getFilterBarTestId()}> | ||
<HorizontalBarContent> | ||
{!isInitialized ? ( | ||
<Loading position="inline-centered" /> | ||
) : ( | ||
<> | ||
{!isKatalonEmbeddedMode && ( | ||
<> | ||
<FilterBarSettings /> | ||
{canEdit && | ||
isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) && ( | ||
<FiltersLinkContainer hasFilters={hasFilters}> | ||
<FilterConfigurationLink | ||
dashboardId={dashboardId} | ||
createNewOnOpen={filterValues.length === 0} | ||
> | ||
<Icons.PlusSmall /> {t('Add/Edit Filters')} | ||
</FilterConfigurationLink> | ||
</FiltersLinkContainer> | ||
)} | ||
</> | ||
)} | ||
{!hasFilters && ( | ||
<FilterBarEmptyStateContainer data-test="horizontal-filterbar-empty"> | ||
{t('No filters are currently added to this dashboard.')} | ||
</FilterBarEmptyStateContainer> | ||
)} | ||
{hasFilters && ( | ||
<FilterControls | ||
dataMaskSelected={dataMaskSelected} | ||
onFilterSelectionChange={onSelectionChange} | ||
/> | ||
)} | ||
{actionsElement} | ||
</> | ||
)} | ||
</HorizontalBarContent> | ||
</HorizontalBar> | ||
); | ||
}; | ||
export default React.memo(HorizontalFilterBar); |