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:
Tom Butcher 2026-09-01 20:13:59 +01:00
parent 415aa0cd9d
commit e49c7c23ed
3 changed files with 81 additions and 22 deletions

View File

@ -935,6 +935,7 @@ const FilterInput = ({
<QuickPropertyFilters
modelType={propertyFilter.modelType}
propertyName={propertyFilter.propertyName}
value={propertyFilterValue}
onChange={handlePropertyFilterChange}
onModalOpenChange={handleQuickFilterModalOpenChange}
useCard={false}

View File

@ -38,7 +38,6 @@ import ObjectProperty from './ObjectProperty'
import ObjectCard from './ObjectCard'
import FilterSidebar from './FilterSidebar'
import SortSidebar from './SortSidebar'
import XMarkIcon from '../../Icons/XMarkIcon'
import CheckIcon from '../../Icons/CheckIcon'
import { useLocation } from 'react-router-dom'
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
@ -139,13 +138,6 @@ const ColumnFilterDropdown = ({
confirm()
}
const resetFilter = () => {
setExpression('')
setDraft([])
clearFilters()
confirm()
}
return (
<div style={{ padding: 8 }}>
<Flex vertical gap='small'>
@ -155,14 +147,14 @@ const ColumnFilterDropdown = ({
value={expression}
onChange={handleExpressionChange}
onPressEnter={applyFilter}
style={{ width: 200 }}
style={{ width: 260 }}
/>
<Button onClick={resetFilter} icon={<XMarkIcon />} />
<Button type='primary' onClick={applyFilter} icon={<CheckIcon />} />
</Space.Compact>
<QuickPropertyFilters
modelType={modelType}
propertyName={propertyName}
value={draft}
onChange={handleDraftChange}
/>
<Card size='small' styles={{ body: { padding: 0, height: 200 } }}>
@ -291,7 +283,8 @@ const ObjectTable = forwardRef(
persistFilter,
persistSort,
persistTableState,
registerPageFilter
registerPageFilter,
registerPageSorter
} = useTableStatePersistence({
scope: type,
pagePath: location.pathname,
@ -1116,6 +1109,11 @@ const ObjectTable = forwardRef(
return () => registerPageFilter({})
}, [sidebarFilter, registerPageFilter])
useEffect(() => {
registerPageSorter(tableSorter)
return () => registerPageSorter({})
}, [tableSorter, registerPageSorter])
const getFilterDropdown = ({
setSelectedKeys,
selectedKeys,

View File

@ -4,6 +4,7 @@ import {
Card,
DatePicker,
Descriptions,
Dropdown,
Flex,
Input,
Modal,
@ -18,6 +19,7 @@ import {
getModelProperties
} from '../../../database/ObjectModels'
import { isDateTimePropertyType } from './filterExpression'
import { CaretRightFilled } from '@ant-design/icons'
const { Text } = Typography
@ -135,6 +137,22 @@ const getPropertyCategory = (property) => {
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) => {
switch (category) {
case 'boolean':
@ -146,6 +164,7 @@ const getFilterOptions = (category) => {
return [
{ key: 'equals', label: 'Equals', needsValue: true },
{ key: 'notEquals', label: 'Does not equal', needsValue: true },
{ type: 'divider' },
{ key: 'greaterThan', label: 'Greater than', needsValue: true },
{
key: 'greaterOrEqual',
@ -158,13 +177,16 @@ const getFilterOptions = (category) => {
label: 'Less than or equal',
needsValue: true
},
{ type: 'divider' },
{ key: 'between', label: 'Between', needsRange: true }
]
case 'date':
return [
{ key: 'equals', label: 'On', needsValue: true },
{ type: 'divider' },
{ key: 'lessThan', label: 'Before', needsValue: true },
{ key: 'greaterThan', label: 'After', needsValue: true },
{ type: 'divider' },
{ key: 'between', label: 'Between', needsRange: true }
]
case 'object':
@ -181,20 +203,36 @@ const getFilterOptions = (category) => {
label: 'Does not start with',
needsValue: true
},
{ type: 'divider' },
{ key: 'contains', label: 'Contains', needsValue: true },
{ key: 'notContains', label: 'Does not contain', needsValue: true },
{ type: 'divider' },
{ key: 'endsWith', label: 'Ends with', needsValue: true },
{ key: 'notEndsWith', label: 'Does not end with', needsValue: true },
{ type: 'divider' },
{ key: 'equals', label: 'Equals', needsValue: true },
{ key: 'notEquals', label: 'Does not equal', needsValue: true },
{ type: 'divider' },
{ 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 = ({
modelType,
propertyName,
value = [],
onChange,
onModalOpenChange,
useCard = true
@ -216,6 +254,11 @@ const QuickPropertyFilters = ({
const options = useMemo(() => getFilterOptions(category), [category])
const propertyLabel = property?.label || propertyName
const categoryLabel = getCategoryLabel(category)
const handleClear = () => {
onChange?.([])
}
const closeModal = () => {
onModalOpenChange?.(false)
@ -317,25 +360,41 @@ const QuickPropertyFilters = ({
)
}
const filterMenuItems = buildFilterMenuItems(options, handleOptionClick)
if (!property) return null
const content = (
<Flex vertical gap={0}>
{options.map((option) => (
<Flex gap={0} vertical>
<Button
disabled={!value?.length}
onClick={handleClear}
style={{
textAlign: 'left',
padding: '5px 12px',
justifyContent: 'flex-start'
}}
type='text'
>
Clear Filter from &quot;{propertyLabel}&quot;
</Button>
<Dropdown
menu={{ items: filterMenuItems }}
trigger={['hover']}
placement='rightTop'
>
<Button
key={option.key}
type='text'
block
style={{
justifyContent: 'flex-start',
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>
))}
</Dropdown>
</Flex>
)
@ -376,7 +435,7 @@ const QuickPropertyFilters = ({
<Text>
{activeOption.needsRange
? `Enter a range to continue:`
: `Enter a value to continue:`}
: `Enter a ${categoryLabel.toLowerCase()} value to continue:`}
</Text>
{activeOption.needsRange ? (
<Flex vertical gap='middle'>
@ -435,6 +494,7 @@ const QuickPropertyFilters = ({
QuickPropertyFilters.propTypes = {
modelType: PropTypes.string,
propertyName: PropTypes.string,
value: PropTypes.array,
onChange: PropTypes.func,
onModalOpenChange: PropTypes.func,
useCard: PropTypes.bool