mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-24 18:07:17 +01:00
Convert regex filter select to input with autocomplete (#4170)
This commit is contained in:
parent
a52a9e460c
commit
965deb2cb2
@ -7,7 +7,7 @@ import { SelectGradientOverflow } from 'lib/components/SelectGradientOverflow'
|
||||
import { Link } from '../Link'
|
||||
import { PropertySelect } from './PropertySelect'
|
||||
import { OperatorValueSelect } from 'lib/components/PropertyFilters/OperatorValueSelect'
|
||||
import { isOperatorMulti } from 'lib/utils'
|
||||
import { isOperatorMulti, isOperatorRegex } from 'lib/utils'
|
||||
|
||||
const { TabPane } = Tabs
|
||||
|
||||
@ -83,7 +83,11 @@ function PropertyPaneContents({
|
||||
value={value}
|
||||
onChange={(newOperator, newValue) => {
|
||||
setThisFilter(propkey, newValue, newOperator, type)
|
||||
if (newOperator && newValue && !isOperatorMulti(newOperator)) {
|
||||
if (
|
||||
newOperator &&
|
||||
newValue &&
|
||||
!(isOperatorMulti(newOperator) || isOperatorRegex(newOperator))
|
||||
) {
|
||||
onComplete()
|
||||
}
|
||||
}}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Select } from 'antd'
|
||||
import { AutoComplete, Select } from 'antd'
|
||||
import { useThrottledCallback } from 'use-debounce'
|
||||
import api from '../../api'
|
||||
import { isMobile, isOperatorFlag, isOperatorMulti, isOperatorRegex, isValidRegex } from 'lib/utils'
|
||||
import { SelectGradientOverflow } from 'lib/components/SelectGradientOverflow'
|
||||
@ -7,20 +8,20 @@ import { SelectGradientOverflow } from 'lib/components/SelectGradientOverflow'
|
||||
export function PropertyValue({
|
||||
propertyKey,
|
||||
type,
|
||||
endpoint,
|
||||
placeholder,
|
||||
style,
|
||||
endpoint = undefined,
|
||||
placeholder = undefined,
|
||||
style = {},
|
||||
bordered = true,
|
||||
onSet,
|
||||
value,
|
||||
operator,
|
||||
outerOptions,
|
||||
outerOptions = undefined,
|
||||
}) {
|
||||
const [input, setInput] = useState('')
|
||||
const [optionsCache, setOptionsCache] = useState({})
|
||||
const [options, setOptions] = useState({})
|
||||
|
||||
function loadPropertyValues(newInput) {
|
||||
const loadPropertyValues = useThrottledCallback((newInput) => {
|
||||
if (type === 'cohort') {
|
||||
return
|
||||
}
|
||||
@ -44,7 +45,7 @@ export function PropertyValue({
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}, 300)
|
||||
|
||||
function setValue(newValue) {
|
||||
onSet(newValue)
|
||||
@ -62,58 +63,90 @@ export function PropertyValue({
|
||||
|
||||
const validationError = getValidationError(operator, value)
|
||||
|
||||
const commonInputProps = {
|
||||
autoFocus: !value && !isMobile(),
|
||||
style: { width: '100%', ...style },
|
||||
value: value || placeholder,
|
||||
loading: optionsCache[input] === 'loading',
|
||||
onSearch: (newInput) => {
|
||||
setInput(newInput)
|
||||
if (!optionsCache[newInput] && !isOperatorFlag(operator)) {
|
||||
loadPropertyValues(newInput)
|
||||
}
|
||||
},
|
||||
['data-attr']: 'prop-val',
|
||||
dropdownMatchSelectWidth: 350,
|
||||
bordered,
|
||||
placeholder,
|
||||
allowClear: value,
|
||||
onKeyDown: (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.target.blur()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SelectGradientOverflow
|
||||
mode={isOperatorMulti(operator) ? 'multiple' : undefined}
|
||||
showSearch
|
||||
autoFocus={!value && !isMobile()}
|
||||
style={{ width: '100%', ...style }}
|
||||
onChange={(val, payload) => {
|
||||
if (isOperatorMulti(operator) && payload.length > 0) {
|
||||
setValue(val)
|
||||
} else {
|
||||
setValue(payload?.value ?? null)
|
||||
}
|
||||
}}
|
||||
value={value || placeholder}
|
||||
loading={optionsCache[input] === 'loading'}
|
||||
onSearch={(newInput) => {
|
||||
setInput(newInput)
|
||||
if (!optionsCache[newInput] && !isOperatorFlag(operator)) {
|
||||
loadPropertyValues(newInput)
|
||||
}
|
||||
}}
|
||||
data-attr="prop-val"
|
||||
dropdownMatchSelectWidth={350}
|
||||
bordered={bordered}
|
||||
placeholder={placeholder}
|
||||
allowClear={value}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.target.blur()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{input && (
|
||||
<Select.Option key={input} value={input} className="ph-no-capture">
|
||||
Specify: {input}
|
||||
</Select.Option>
|
||||
)}
|
||||
{displayOptions.map(({ name, id }, index) => (
|
||||
<Select.Option
|
||||
key={id || name}
|
||||
value={id || name}
|
||||
data-attr={'prop-val-' + index}
|
||||
className="ph-no-capture"
|
||||
title={name}
|
||||
>
|
||||
{name === true && 'true'}
|
||||
{name === false && 'false'}
|
||||
{name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</SelectGradientOverflow>
|
||||
{isOperatorRegex(operator) ? (
|
||||
<AutoComplete
|
||||
{...commonInputProps}
|
||||
onChange={(val) => {
|
||||
setValue(val ?? null)
|
||||
}}
|
||||
>
|
||||
{input && (
|
||||
<Select.Option key={input} value={input} className="ph-no-capture">
|
||||
Specify: {input}
|
||||
</Select.Option>
|
||||
)}
|
||||
{displayOptions.map(({ name, id }, index) => (
|
||||
<AutoComplete.Option
|
||||
key={id || name}
|
||||
value={id || name}
|
||||
data-attr={'prop-val-' + index}
|
||||
className="ph-no-capture"
|
||||
title={name}
|
||||
>
|
||||
{name === true && 'true'}
|
||||
{name === false && 'false'}
|
||||
{name}
|
||||
</AutoComplete.Option>
|
||||
))}
|
||||
</AutoComplete>
|
||||
) : (
|
||||
<SelectGradientOverflow
|
||||
{...commonInputProps}
|
||||
mode={isOperatorMulti(operator) ? 'multiple' : undefined}
|
||||
showSearch
|
||||
onChange={(val, payload) => {
|
||||
if (isOperatorMulti(operator) && payload.length > 0) {
|
||||
setValue(val)
|
||||
} else {
|
||||
setValue(payload?.value ?? null)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{input && (
|
||||
<Select.Option key={input} value={input} className="ph-no-capture">
|
||||
Specify: {input}
|
||||
</Select.Option>
|
||||
)}
|
||||
{displayOptions.map(({ name, id }, index) => (
|
||||
<Select.Option
|
||||
key={id || name}
|
||||
value={id || name}
|
||||
data-attr={'prop-val-' + index}
|
||||
className="ph-no-capture"
|
||||
title={name}
|
||||
>
|
||||
{name === true && 'true'}
|
||||
{name === false && 'false'}
|
||||
{name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</SelectGradientOverflow>
|
||||
)}
|
||||
{validationError && <p className="text-danger">{validationError}</p>}
|
||||
</>
|
||||
)
|
||||
|
@ -87,6 +87,7 @@
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"rrweb": "^0.9.14",
|
||||
"sass": "^1.26.2",
|
||||
"use-debounce": "^6.0.1",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -11946,6 +11946,11 @@ use-debounce@^5.2.1:
|
||||
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-5.2.1.tgz#7366543c769f1de3e92104dee64de5c4dfddfd33"
|
||||
integrity sha512-BQG5uEypYHd/ASF6imzYR8tJHh5qGn28oZG/5iVAbljV6MUrfyT4jzxA8co+L+WLCT1U8VBwzzvlb3CHmUDpEA==
|
||||
|
||||
use-debounce@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-6.0.1.tgz#ed1eb2b30189408fb9792ea2887f4c6c3cb401a3"
|
||||
integrity sha512-kpvIxpa0vOLz/2I2sfNJ72mUeaT2CMNCu5BT1f2HkV9qZK27UVSOFf1sSSu+wjJE4TcR2VTXS2SM569+m3TN7Q==
|
||||
|
||||
use-local-storage-state@^6.0.0:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/use-local-storage-state/-/use-local-storage-state-6.0.3.tgz#65add61b8450b071354ce31b5a69b8908e69b497"
|
||||
|
Loading…
Reference in New Issue
Block a user