Skip to content

Commit

Permalink
Add the Datetime field filter (#703)
Browse files Browse the repository at this point in the history
* added the advanced mode toggler

* added the PQL block

* added styles files

* added handlers for PQL Query textarea value

* updated addOrUpdatePQLQuery method

* updated the ListDataProviding by adding the errorData field

* added the Alert component

* updated the Alert stories

* updated the Alert component

* deleted unused code

* refactoring

* updated the PQL info icon style and behaviour

* added hook for PQL Query logic

* added hook for includeDescedants logic

* updated behaviour for PQL error case

* updated the Alert component

* fixed bug when the filter should be resetted

* added the datetime component to the DynamicTypesFieldFilters

* deleted unused code after conflicts merging

* added the setting switcher

* added styles and updated types using

* added DatePicker and DateRangePicker components

* updated the addOrUpdateFieldFilter by handling case when the data are equal

* updated logic for using DateRangePicker

* refactoring

* fixed types

* deleted unused code

* updated types and comments in the useFilters hook

* updated the handleChangeDate methods

* Automatic frontend build

---------

Co-authored-by: ValeriaMaltseva <[email protected]>
  • Loading branch information
ValeriaMaltseva and ValeriaMaltseva authored Nov 20, 2024
1 parent 9ee0fa7 commit c86e78b
Show file tree
Hide file tree
Showing 28 changed files with 2,320 additions and 18 deletions.
2 changes: 2 additions & 0 deletions assets/js/src/core/app/config/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { serviceIds } from '@Pimcore/app/config/services/service-ids'
import { DynamicTypeFieldFilterText } from '@Pimcore/modules/element/dynamic-types/defintinitions/field-filters/types/text/dynamic-type-field-filter-text'
import { DynamicTypeFieldFilterNumber } from '@Pimcore/modules/element/dynamic-types/defintinitions/field-filters/types/number/dynamic-type-field-filter-number'
import { DynamicTypeFieldFilterSelect } from '@Pimcore/modules/element/dynamic-types/defintinitions/field-filters/types/select/dynamic-type-field-filter-select'
import { DynamicTypeFieldFilterDatetime } from '@Pimcore/modules/element/dynamic-types/defintinitions/field-filters/types/datetime/dynamic-type-field-filter-datetime'
import { DynamicTypeGridCellText } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/text/dynamic-type-grid-cell-text'
import { DynamicTypeGridCellRegistry } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/dynamic-type-grid-cell-registry'
import { DynamicTypeGridCellTextarea } from '@Pimcore/modules/element/dynamic-types/defintinitions/grid-cell/types/textarea/dynamic-type-grid-cell-text'
Expand Down Expand Up @@ -130,6 +131,7 @@ container.bind(serviceIds['DynamicTypes/FieldFilterRegistry']).to(DynamicTypeFie
container.bind(serviceIds['DynamicTypes/FieldFilter/Text']).to(DynamicTypeFieldFilterText).inSingletonScope()
container.bind(serviceIds['DynamicTypes/FieldFilter/Number']).to(DynamicTypeFieldFilterNumber).inSingletonScope()
container.bind(serviceIds['DynamicTypes/FieldFilter/Select']).to(DynamicTypeFieldFilterSelect).inSingletonScope()
container.bind(serviceIds['DynamicTypes/FieldFilter/Datetime']).to(DynamicTypeFieldFilterDatetime).inSingletonScope()

// dynamic types grid cells
container.bind(serviceIds['DynamicTypes/GridCellRegistry']).to(DynamicTypeGridCellRegistry).inSingletonScope()
Expand Down
1 change: 1 addition & 0 deletions assets/js/src/core/app/config/services/service-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const serviceIds = {
'DynamicTypes/FieldFilter/Text': 'DynamicTypes/FieldFilter/Text',
'DynamicTypes/FieldFilter/Number': 'DynamicTypes/FieldFilter/Number',
'DynamicTypes/FieldFilter/Select': 'DynamicTypes/FieldFilter/Select',
'DynamicTypes/FieldFilter/Datetime': 'DynamicTypes/FieldFilter/Datetime',

'DynamicTypes/GridCell/Text': 'DynamicTypes/GridCell/Text',
'DynamicTypes/GridCell/Textarea': 'DynamicTypes/GridCell/Textarea',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import {
type OutputType
} from './utils/date-picker-utils'

type DateRange = [start: Dayjs | null, end: Dayjs | null]
type DateRangeTargetValue = [start: DatePickerValueType, end: DatePickerValueType]
export type DateRange = [start: Dayjs | null, end: Dayjs | null]
export type DateRangeTargetValue = [start: DatePickerValueType, end: DatePickerValueType]

export type DateRangePickerProps = OriginalRangePickerProps & {
value?: DateRangeTargetValue
value?: DateRangeTargetValue | null
onChange?: (dates: DateRangeTargetValue | null) => void
outputType?: OutputType
outputFormat?: string
Expand All @@ -47,6 +47,7 @@ const valueFromDayJs = (value: DateRange | null, outputType?: OutputType, output
if (value === null) {
return null
}

return [
fromDayJs(value[0], outputType, outputFormat),
fromDayJs(value[1], outputType, outputFormat)
Expand Down
5 changes: 3 additions & 2 deletions assets/js/src/core/components/stack-list/stack-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

import React, { useEffect, useState } from 'react'
import cn from 'classnames'
import { StackListItem, type StackListItemProps } from './stack-list-item'
import { useStyles } from './stack-list.styles'
import { useSortableContext } from '../drag-and-drop/hooks/use-sortable-context'
Expand All @@ -37,9 +38,9 @@ export const StackList = ({ items, onItemsChange }: StackListProps): React.JSX.E
}, [items])

return (
<div className={ ['stack-list', styles.stackList].join(' ') }>
<div className={ cn('stack-list', styles.stackList) }>
<ContextHolder>
{itemsState.map((item, index) => (
{itemsState.map((item) => (
<div
className="stack-list__item"
key={ item.id }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ interface FieldFiltersListContainerProps {
export const FieldFiltersListContainer = ({ columns }: FieldFiltersListContainerProps): React.JSX.Element => {
const { removeFieldFilter, removeColumn } = useFilters()

const onRemoveColumnClick = (column: GridColumnConfiguration): void => {
removeColumn(column)
removeFieldFilter(column)
}

const items: StackListProps['items'] = columns.map((column) => ({
id: column.key,
children: <Tag>{column.key}</Tag>,
Expand All @@ -49,9 +54,4 @@ export const FieldFiltersListContainer = ({ columns }: FieldFiltersListContainer
{items.length > 0 && <StackList items={ items } />}
</>
)

function onRemoveColumnClick (column: GridColumnConfiguration): void {
removeColumn(column)
removeFieldFilter(column)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@ import { isEmptyValue } from '@Pimcore/utils/type-utils'
import { type FILTER_TYPE } from '../../../constants/systemTypes'

interface UseFiltersHookReturn extends IFilterContext, useGridConfigHookReturn {
addOrUpdateFieldFilter: (column: GridColumnConfiguration, value: string | number | null) => void
addOrUpdateFieldFilter: (column: GridColumnConfiguration, value: string | number | object | null) => void
removeFieldFilter: (column: GridColumnConfiguration) => void
getFieldFilter: (column: GridColumnConfiguration) => FieldFilter | undefined
resetFilters: () => void
updateIsIncludeDescendants: (value: boolean) => void
addOrUpdateFilterValue: ({ type, value }: { type: FILTER_TYPE, value: string }) => void
}

type FieldFilterValue = string | object

export interface FieldFilter {
key: string
type: string
filterValue: string
filterValue: FieldFilterValue
}

type ColumnFiltersList = Array<FilterOptions['columnFilters']> | []
Expand Down Expand Up @@ -81,7 +83,7 @@ export const useFilters = (): UseFiltersHookReturn => {
})
}

const addOrUpdateFieldFilter = (column: GridColumnConfiguration, value: string): void => {
const addOrUpdateFieldFilter = (column: GridColumnConfiguration, value: FieldFilterValue): void => {
const fieldFilters = filterOptions.columnFilters
let newFilters: FieldFilter[] = []

Expand All @@ -92,9 +94,14 @@ export const useFilters = (): UseFiltersHookReturn => {
filterValue: value
}]

setFilterOptions((filterOptions) => {
// Update only if the current filters have changed (necessary when filter values are objects)
setFilterOptions((prevFilterOptions) => {
if (JSON.stringify(prevFilterOptions.columnFilters) === JSON.stringify(newFilters)) {
return prevFilterOptions
}

return {
...filterOptions,
...prevFilterOptions,
columnFilters: newFilters
}
})
Expand All @@ -105,6 +112,7 @@ export const useFilters = (): UseFiltersHookReturn => {
const fieldFiltersArray = fieldFilters as FieldFilter[]
const filterIndex = fieldFiltersArray.findIndex((filter) => filter.key === column.key)

// Check if the filter doesn't exist
if (filterIndex === -1) {
newFilters = [
...fieldFiltersArray,
Expand All @@ -124,9 +132,14 @@ export const useFilters = (): UseFiltersHookReturn => {
newFilters = fieldFiltersArray
}

setFilterOptions((filterOptions) => {
// Update only if the current filters have changed (necessary when filter values are objects)
setFilterOptions((prevFilterOptions) => {
if (JSON.stringify(prevFilterOptions.columnFilters) === JSON.stringify(newFilters)) {
return prevFilterOptions
}

return {
...filterOptions,
...prevFilterOptions,
columnFilters: newFilters
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { useState, useMemo } from 'react'
import { Select } from '@Pimcore/components/select/select'
import { Flex } from '@Pimcore/components/flex/flex'
import { DatePicker } from '@Pimcore/components/date-picker/date-picker'
import { DateRangePicker, type DateRangeTargetValue } from '@Pimcore/components/date-picker/date-range-picker'
import type { AbstractFieldFilterDefinition } from '@Pimcore/modules/element/dynamic-types/defintinitions/field-filters/dynamic-type-field-filter-abstract'
import { useFilters } from '@Pimcore/modules/asset/editor/types/folder/tab-manager/tabs/list/sidebar/filters/hooks/use-filters'

enum DatePickerSettingValue {
ON = 'on',
BETWEEN = 'between'
}

interface FieldFilterDatetimeON {
on: number
}

interface FieldFilterDatetimeBetween {
from: number
to: number
}

interface FieldFilterDatetime {
filterValue?: FieldFilterDatetimeON | FieldFilterDatetimeBetween
}

const SETTING_OPTIONS = [
{ label: 'On', value: DatePickerSettingValue.ON },
{ label: 'Between', value: DatePickerSettingValue.BETWEEN }
]

const DATE_FORMAT = 'YYYY-MM-DD'

export interface DynamicTypeFieldFilterDatetimeProps extends AbstractFieldFilterDefinition {}

export const DynamicTypeFieldFilterDatetimeComponent = ({ column }: DynamicTypeFieldFilterDatetimeProps): React.JSX.Element => {
const [settingValue, setSettingValue] = useState<DatePickerSettingValue>(DatePickerSettingValue.ON)

const { getFieldFilter, addOrUpdateFieldFilter } = useFilters()

const fieldFilter = getFieldFilter(column) as FieldFilterDatetime

const getDateValue = (datetimeType: DatePickerSettingValue): null | number | number[] => {
const currentFilterValue = fieldFilter?.filterValue

if (currentFilterValue == null) return null

if (datetimeType === DatePickerSettingValue.ON && 'on' in currentFilterValue) {
setSettingValue(DatePickerSettingValue.ON)

return currentFilterValue.on
}

if (
datetimeType === DatePickerSettingValue.BETWEEN &&
'from' in currentFilterValue &&
'to' in currentFilterValue
) {
setSettingValue(DatePickerSettingValue.BETWEEN)

return [currentFilterValue.from, currentFilterValue.to]
}

return null
}

const valueOn = useMemo(() => getDateValue(DatePickerSettingValue.ON) as number | null, [fieldFilter])
const valueBetween = useMemo(() => getDateValue(DatePickerSettingValue.BETWEEN) as DateRangeTargetValue | null, [fieldFilter])

const [dateOnValue, setDateOnValue] = useState<null | number>(valueOn)
const [dateBetweenValue, setDateBetweenValue] = useState<null | DateRangeTargetValue>(valueBetween)

const handleChangeDateOnValue = (date: number): void => {
setDateOnValue(date)
setDateBetweenValue(null)

addOrUpdateFieldFilter(column, { on: date })
}

const handleChangeDateBetweenValue = (dates: DateRangeTargetValue): void => {
setDateBetweenValue(dates)
setDateOnValue(null)

addOrUpdateFieldFilter(column, { from: dates?.[0], to: dates?.[1] })
}

return (
<Flex
align="center"
gap="extra-small"
>
<Select
onChange={ (value: DatePickerSettingValue) => { setSettingValue(value) } }
options={ SETTING_OPTIONS }
value={ settingValue }
width={ 90 }
/>

{settingValue === DatePickerSettingValue.ON && (
<DatePicker
format={ DATE_FORMAT }
onChange={ handleChangeDateOnValue }
outputType='timestamp'
value={ dateOnValue }
/>
)}

{settingValue === DatePickerSettingValue.BETWEEN && (
<DateRangePicker
format={ DATE_FORMAT }
onChange={ handleChangeDateBetweenValue }
outputType='timestamp'
value={ dateBetweenValue }
/>
)}
</Flex>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface DynamicTypeFieldFilterTextProps extends AbstractFieldFilterDefi
export const DynamicTypeFieldFilterTextComponent = ({ column }: DynamicTypeFieldFilterTextProps): React.JSX.Element => {
const { addOrUpdateFieldFilter, getFieldFilter } = useFilters()
const fieldFilter = getFieldFilter(column)
const value = fieldFilter?.filterValue ?? ''
const value = (fieldFilter?.filterValue ?? '') as string
const [_value, setValue] = useState(value)

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { type ReactElement } from 'react'
import { type DynamicTypeFieldFilterAbstract } from '../../dynamic-type-field-filter-abstract'
import { DynamicTypeFieldFilterDatetimeComponent, type DynamicTypeFieldFilterDatetimeProps } from '../../components/dynamic-type-field-filter-datetime-component'
import { injectable } from 'inversify'

@injectable()
export class DynamicTypeFieldFilterDatetime implements DynamicTypeFieldFilterAbstract {
id = 'datetime'

getFieldFilterComponent (props: DynamicTypeFieldFilterDatetimeProps): ReactElement<DynamicTypeFieldFilterDatetimeProps> {
return (
<DynamicTypeFieldFilterDatetimeComponent { ...props } />
)
}
}
2 changes: 2 additions & 0 deletions assets/js/src/core/modules/element/dynamic-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { serviceIds } from '@Pimcore/app/config/services/service-ids'
import { type DynamicTypeFieldFilterText } from './defintinitions/field-filters/types/text/dynamic-type-field-filter-text'
import { type DynamicTypeFieldFilterNumber } from './defintinitions/field-filters/types/number/dynamic-type-field-filter-number'
import { type DynamicTypeFieldFilterSelect } from './defintinitions/field-filters/types/select/dynamic-type-field-filter-select'
import { type DynamicTypeFieldFilterDatetime } from './defintinitions/field-filters/types/datetime/dynamic-type-field-filter-datetime'
import { type DynamicTypeGridCellText } from './defintinitions/grid-cell/types/text/dynamic-type-grid-cell-text'
import { type DynamicTypeGridCellRegistry } from './defintinitions/grid-cell/dynamic-type-grid-cell-registry'
import { type DynamicTypeGridCellTextarea } from './defintinitions/grid-cell/types/textarea/dynamic-type-grid-cell-text'
Expand Down Expand Up @@ -93,6 +94,7 @@ moduleSystem.registerModule({
fieldFilterRegistry.registerDynamicType(container.get<DynamicTypeFieldFilterText>(serviceIds['DynamicTypes/FieldFilter/Text']))
fieldFilterRegistry.registerDynamicType(container.get<DynamicTypeFieldFilterNumber>(serviceIds['DynamicTypes/FieldFilter/Number']))
fieldFilterRegistry.registerDynamicType(container.get<DynamicTypeFieldFilterSelect>(serviceIds['DynamicTypes/FieldFilter/Select']))
fieldFilterRegistry.registerDynamicType(container.get<DynamicTypeFieldFilterDatetime>(serviceIds['DynamicTypes/FieldFilter/Datetime']))

const GridCellRegistry = container.get<DynamicTypeGridCellRegistry>(serviceIds['DynamicTypes/GridCellRegistry'])

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"entrypoints": {
"vendor": {
"js": [
"/bundles/pimcorestudioui/build/1b057f34-a8bd-44af-a50e-3ef79387fa8b/vendor.js"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"bundles/pimcorestudioui/build/1b057f34-a8bd-44af-a50e-3ef79387fa8b/vendor.js": "/bundles/pimcorestudioui/build/1b057f34-a8bd-44af-a50e-3ef79387fa8b/vendor.js"
}
2 changes: 2 additions & 0 deletions public/build/1b057f34-a8bd-44af-a50e-3ef79387fa8b/vendor.js

Large diffs are not rendered by default.

Loading

0 comments on commit c86e78b

Please sign in to comment.