Enhance Filter Functionality in Dashboard Components
- Integrated property filter value into the QuickPropertyFilters component for improved filtering capabilities. - Updated ObjectTable to register page sorter and manage filter states more effectively. - Refactored QuickPropertyFilters to include category labels and clear filter functionality, enhancing user experience. - Adjusted styles and layout for better usability and visual consistency across components.
This commit is contained in:
parent
415aa0cd9d
commit
e49c7c23ed
@ -935,6 +935,7 @@ const FilterInput = ({
|
|||||||
<QuickPropertyFilters
|
<QuickPropertyFilters
|
||||||
modelType={propertyFilter.modelType}
|
modelType={propertyFilter.modelType}
|
||||||
propertyName={propertyFilter.propertyName}
|
propertyName={propertyFilter.propertyName}
|
||||||
|
value={propertyFilterValue}
|
||||||
onChange={handlePropertyFilterChange}
|
onChange={handlePropertyFilterChange}
|
||||||
onModalOpenChange={handleQuickFilterModalOpenChange}
|
onModalOpenChange={handleQuickFilterModalOpenChange}
|
||||||
useCard={false}
|
useCard={false}
|
||||||
|
|||||||
@ -38,7 +38,6 @@ import ObjectProperty from './ObjectProperty'
|
|||||||
import ObjectCard from './ObjectCard'
|
import ObjectCard from './ObjectCard'
|
||||||
import FilterSidebar from './FilterSidebar'
|
import FilterSidebar from './FilterSidebar'
|
||||||
import SortSidebar from './SortSidebar'
|
import SortSidebar from './SortSidebar'
|
||||||
import XMarkIcon from '../../Icons/XMarkIcon'
|
|
||||||
import CheckIcon from '../../Icons/CheckIcon'
|
import CheckIcon from '../../Icons/CheckIcon'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
||||||
@ -139,13 +138,6 @@ const ColumnFilterDropdown = ({
|
|||||||
confirm()
|
confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetFilter = () => {
|
|
||||||
setExpression('')
|
|
||||||
setDraft([])
|
|
||||||
clearFilters()
|
|
||||||
confirm()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: 8 }}>
|
<div style={{ padding: 8 }}>
|
||||||
<Flex vertical gap='small'>
|
<Flex vertical gap='small'>
|
||||||
@ -155,14 +147,14 @@ const ColumnFilterDropdown = ({
|
|||||||
value={expression}
|
value={expression}
|
||||||
onChange={handleExpressionChange}
|
onChange={handleExpressionChange}
|
||||||
onPressEnter={applyFilter}
|
onPressEnter={applyFilter}
|
||||||
style={{ width: 200 }}
|
style={{ width: 260 }}
|
||||||
/>
|
/>
|
||||||
<Button onClick={resetFilter} icon={<XMarkIcon />} />
|
|
||||||
<Button type='primary' onClick={applyFilter} icon={<CheckIcon />} />
|
<Button type='primary' onClick={applyFilter} icon={<CheckIcon />} />
|
||||||
</Space.Compact>
|
</Space.Compact>
|
||||||
<QuickPropertyFilters
|
<QuickPropertyFilters
|
||||||
modelType={modelType}
|
modelType={modelType}
|
||||||
propertyName={propertyName}
|
propertyName={propertyName}
|
||||||
|
value={draft}
|
||||||
onChange={handleDraftChange}
|
onChange={handleDraftChange}
|
||||||
/>
|
/>
|
||||||
<Card size='small' styles={{ body: { padding: 0, height: 200 } }}>
|
<Card size='small' styles={{ body: { padding: 0, height: 200 } }}>
|
||||||
@ -291,7 +283,8 @@ const ObjectTable = forwardRef(
|
|||||||
persistFilter,
|
persistFilter,
|
||||||
persistSort,
|
persistSort,
|
||||||
persistTableState,
|
persistTableState,
|
||||||
registerPageFilter
|
registerPageFilter,
|
||||||
|
registerPageSorter
|
||||||
} = useTableStatePersistence({
|
} = useTableStatePersistence({
|
||||||
scope: type,
|
scope: type,
|
||||||
pagePath: location.pathname,
|
pagePath: location.pathname,
|
||||||
@ -1116,6 +1109,11 @@ const ObjectTable = forwardRef(
|
|||||||
return () => registerPageFilter({})
|
return () => registerPageFilter({})
|
||||||
}, [sidebarFilter, registerPageFilter])
|
}, [sidebarFilter, registerPageFilter])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
registerPageSorter(tableSorter)
|
||||||
|
return () => registerPageSorter({})
|
||||||
|
}, [tableSorter, registerPageSorter])
|
||||||
|
|
||||||
const getFilterDropdown = ({
|
const getFilterDropdown = ({
|
||||||
setSelectedKeys,
|
setSelectedKeys,
|
||||||
selectedKeys,
|
selectedKeys,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Descriptions,
|
Descriptions,
|
||||||
|
Dropdown,
|
||||||
Flex,
|
Flex,
|
||||||
Input,
|
Input,
|
||||||
Modal,
|
Modal,
|
||||||
@ -18,6 +19,7 @@ import {
|
|||||||
getModelProperties
|
getModelProperties
|
||||||
} from '../../../database/ObjectModels'
|
} from '../../../database/ObjectModels'
|
||||||
import { isDateTimePropertyType } from './filterExpression'
|
import { isDateTimePropertyType } from './filterExpression'
|
||||||
|
import { CaretRightFilled } from '@ant-design/icons'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
@ -135,6 +137,22 @@ const getPropertyCategory = (property) => {
|
|||||||
return 'text'
|
return 'text'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getCategoryLabel = (category) => {
|
||||||
|
switch (category) {
|
||||||
|
case 'boolean':
|
||||||
|
return 'Boolean'
|
||||||
|
case 'number':
|
||||||
|
return 'Number'
|
||||||
|
case 'date':
|
||||||
|
return 'Date'
|
||||||
|
case 'object':
|
||||||
|
return 'Object'
|
||||||
|
case 'text':
|
||||||
|
default:
|
||||||
|
return 'Text'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getFilterOptions = (category) => {
|
const getFilterOptions = (category) => {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
@ -146,6 +164,7 @@ const getFilterOptions = (category) => {
|
|||||||
return [
|
return [
|
||||||
{ key: 'equals', label: 'Equals', needsValue: true },
|
{ key: 'equals', label: 'Equals', needsValue: true },
|
||||||
{ key: 'notEquals', label: 'Does not equal', needsValue: true },
|
{ key: 'notEquals', label: 'Does not equal', needsValue: true },
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'greaterThan', label: 'Greater than', needsValue: true },
|
{ key: 'greaterThan', label: 'Greater than', needsValue: true },
|
||||||
{
|
{
|
||||||
key: 'greaterOrEqual',
|
key: 'greaterOrEqual',
|
||||||
@ -158,13 +177,16 @@ const getFilterOptions = (category) => {
|
|||||||
label: 'Less than or equal',
|
label: 'Less than or equal',
|
||||||
needsValue: true
|
needsValue: true
|
||||||
},
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'between', label: 'Between', needsRange: true }
|
{ key: 'between', label: 'Between', needsRange: true }
|
||||||
]
|
]
|
||||||
case 'date':
|
case 'date':
|
||||||
return [
|
return [
|
||||||
{ key: 'equals', label: 'On', needsValue: true },
|
{ key: 'equals', label: 'On', needsValue: true },
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'lessThan', label: 'Before', needsValue: true },
|
{ key: 'lessThan', label: 'Before', needsValue: true },
|
||||||
{ key: 'greaterThan', label: 'After', needsValue: true },
|
{ key: 'greaterThan', label: 'After', needsValue: true },
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'between', label: 'Between', needsRange: true }
|
{ key: 'between', label: 'Between', needsRange: true }
|
||||||
]
|
]
|
||||||
case 'object':
|
case 'object':
|
||||||
@ -181,20 +203,36 @@ const getFilterOptions = (category) => {
|
|||||||
label: 'Does not start with',
|
label: 'Does not start with',
|
||||||
needsValue: true
|
needsValue: true
|
||||||
},
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'contains', label: 'Contains', needsValue: true },
|
{ key: 'contains', label: 'Contains', needsValue: true },
|
||||||
{ key: 'notContains', label: 'Does not contain', needsValue: true },
|
{ key: 'notContains', label: 'Does not contain', needsValue: true },
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'endsWith', label: 'Ends with', needsValue: true },
|
{ key: 'endsWith', label: 'Ends with', needsValue: true },
|
||||||
{ key: 'notEndsWith', label: 'Does not end with', needsValue: true },
|
{ key: 'notEndsWith', label: 'Does not end with', needsValue: true },
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'equals', label: 'Equals', needsValue: true },
|
{ key: 'equals', label: 'Equals', needsValue: true },
|
||||||
{ key: 'notEquals', label: 'Does not equal', needsValue: true },
|
{ key: 'notEquals', label: 'Does not equal', needsValue: true },
|
||||||
|
{ type: 'divider' },
|
||||||
{ key: 'isEmpty', label: 'Is empty' }
|
{ key: 'isEmpty', label: 'Is empty' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildFilterMenuItems = (options, onOptionClick) =>
|
||||||
|
options.map((item) =>
|
||||||
|
item.type === 'divider'
|
||||||
|
? item
|
||||||
|
: {
|
||||||
|
key: item.key,
|
||||||
|
label: item.label,
|
||||||
|
onClick: () => onOptionClick(item)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const QuickPropertyFilters = ({
|
const QuickPropertyFilters = ({
|
||||||
modelType,
|
modelType,
|
||||||
propertyName,
|
propertyName,
|
||||||
|
value = [],
|
||||||
onChange,
|
onChange,
|
||||||
onModalOpenChange,
|
onModalOpenChange,
|
||||||
useCard = true
|
useCard = true
|
||||||
@ -216,6 +254,11 @@ const QuickPropertyFilters = ({
|
|||||||
const options = useMemo(() => getFilterOptions(category), [category])
|
const options = useMemo(() => getFilterOptions(category), [category])
|
||||||
|
|
||||||
const propertyLabel = property?.label || propertyName
|
const propertyLabel = property?.label || propertyName
|
||||||
|
const categoryLabel = getCategoryLabel(category)
|
||||||
|
|
||||||
|
const handleClear = () => {
|
||||||
|
onChange?.([])
|
||||||
|
}
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
onModalOpenChange?.(false)
|
onModalOpenChange?.(false)
|
||||||
@ -317,25 +360,41 @@ const QuickPropertyFilters = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterMenuItems = buildFilterMenuItems(options, handleOptionClick)
|
||||||
|
|
||||||
if (!property) return null
|
if (!property) return null
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<Flex vertical gap={0}>
|
<Flex gap={0} vertical>
|
||||||
{options.map((option) => (
|
<Button
|
||||||
|
disabled={!value?.length}
|
||||||
|
onClick={handleClear}
|
||||||
|
style={{
|
||||||
|
textAlign: 'left',
|
||||||
|
padding: '5px 12px',
|
||||||
|
justifyContent: 'flex-start'
|
||||||
|
}}
|
||||||
|
type='text'
|
||||||
|
>
|
||||||
|
Clear Filter from "{propertyLabel}"
|
||||||
|
</Button>
|
||||||
|
<Dropdown
|
||||||
|
menu={{ items: filterMenuItems }}
|
||||||
|
trigger={['hover']}
|
||||||
|
placement='rightTop'
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
key={option.key}
|
|
||||||
type='text'
|
|
||||||
block
|
|
||||||
style={{
|
style={{
|
||||||
justifyContent: 'flex-start',
|
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
padding: '5px 12px'
|
padding: '5px 12px',
|
||||||
|
justifyContent: 'flex-start'
|
||||||
}}
|
}}
|
||||||
onClick={() => handleOptionClick(option)}
|
type='text'
|
||||||
>
|
>
|
||||||
{option.label}
|
{categoryLabel} Filters
|
||||||
|
{<CaretRightFilled style={{ marginLeft: 'auto' }} />}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
</Dropdown>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -376,7 +435,7 @@ const QuickPropertyFilters = ({
|
|||||||
<Text>
|
<Text>
|
||||||
{activeOption.needsRange
|
{activeOption.needsRange
|
||||||
? `Enter a range to continue:`
|
? `Enter a range to continue:`
|
||||||
: `Enter a value to continue:`}
|
: `Enter a ${categoryLabel.toLowerCase()} value to continue:`}
|
||||||
</Text>
|
</Text>
|
||||||
{activeOption.needsRange ? (
|
{activeOption.needsRange ? (
|
||||||
<Flex vertical gap='middle'>
|
<Flex vertical gap='middle'>
|
||||||
@ -435,6 +494,7 @@ const QuickPropertyFilters = ({
|
|||||||
QuickPropertyFilters.propTypes = {
|
QuickPropertyFilters.propTypes = {
|
||||||
modelType: PropTypes.string,
|
modelType: PropTypes.string,
|
||||||
propertyName: PropTypes.string,
|
propertyName: PropTypes.string,
|
||||||
|
value: PropTypes.array,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
onModalOpenChange: PropTypes.func,
|
onModalOpenChange: PropTypes.func,
|
||||||
useCard: PropTypes.bool
|
useCard: PropTypes.bool
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user