Merge pull request #7879 from Budibase/bug/sev2/is-in-filter-startswith-crash

Is in filter - only call startsWith if string type
This commit is contained in:
melohagan 2022-09-28 16:20:22 +01:00 committed by GitHub
commit bad09dd0cc
3 changed files with 59 additions and 45 deletions

View File

@ -43,7 +43,7 @@
let helpers = handlebarsCompletions() let helpers = handlebarsCompletions()
let getCaretPosition let getCaretPosition
let search = "" let search = ""
let initialValueJS = value?.startsWith("{{ js ") let initialValueJS = typeof value === "string" && value?.startsWith("{{ js ")
let mode = initialValueJS ? "JavaScript" : "Handlebars" let mode = initialValueJS ? "JavaScript" : "Handlebars"
let jsValue = initialValueJS ? value : null let jsValue = initialValueJS ? value : null
let hbsValue = initialValueJS ? null : value let hbsValue = initialValueJS ? null : value

View File

@ -20,6 +20,8 @@
import { createEventDispatcher, onMount } from "svelte" import { createEventDispatcher, onMount } from "svelte"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const { OperatorOptions } = Constants
const { getValidOperatorsForType } = LuceneUtils
export let schemaFields export let schemaFields
export let filters = [] export let filters = []
@ -45,7 +47,7 @@
{ {
id: generate(), id: generate(),
field: null, field: null,
operator: Constants.OperatorOptions.Equals.value, operator: OperatorOptions.Equals.value,
value: null, value: null,
valueType: "Value", valueType: "Value",
}, },
@ -66,49 +68,60 @@
return schemaFields.find(field => field.name === filter.field) return schemaFields.find(field => field.name === filter.field)
} }
const onFieldChange = (expression, field) => { const santizeTypes = filter => {
// Update the field types // Update type based on field
expression.type = enrichedSchemaFields.find(x => x.name === field)?.type const fieldSchema = enrichedSchemaFields.find(x => x.name === filter.field)
expression.externalType = getSchema(expression)?.externalType filter.type = fieldSchema?.type
// Ensure a valid operator is set // Update external type based on field
const validOperators = LuceneUtils.getValidOperatorsForType( filter.externalType = getSchema(filter)?.externalType
expression.type
).map(x => x.value)
if (!validOperators.includes(expression.operator)) {
expression.operator =
validOperators[0] ?? Constants.OperatorOptions.Equals.value
onOperatorChange(expression, expression.operator)
} }
// if changed to an array, change default value to empty array const santizeOperator = filter => {
const idx = filters.findIndex(x => x.id === expression.id) // Ensure a valid operator is selected
if (expression.type === "array") { const operators = getValidOperatorsForType(filter.type).map(x => x.value)
filters[idx].value = [] if (!operators.includes(filter.operator)) {
} else { filter.operator = operators[0] ?? OperatorOptions.Equals.value
filters[idx].value = null
}
} }
const onOperatorChange = (expression, operator) => { // Update the noValue flag if the operator does not take a value
const noValueOptions = [ const noValueOptions = [
Constants.OperatorOptions.Empty.value, OperatorOptions.Empty.value,
Constants.OperatorOptions.NotEmpty.value, OperatorOptions.NotEmpty.value,
] ]
expression.noValue = noValueOptions.includes(operator) filter.noValue = noValueOptions.includes(filter.operator)
if (expression.noValue) {
expression.value = null
} }
if (
operator === Constants.OperatorOptions.In.value && const santizeValue = filter => {
!Array.isArray(expression.value) // Check if the operator allows a value at all
) { if (filter.noValue) {
if (expression.value) { filter.value = null
expression.value = [expression.value] return
} else { }
expression.value = []
// Ensure array values are properly set and cleared
if (Array.isArray(filter.value)) {
if (filter.valueType !== "Value" || filter.type !== "array") {
filter.value = null
}
} else if (filter.type === "array" && filter.valueType === "Value") {
filter.value = []
} }
} }
const onFieldChange = filter => {
santizeTypes(filter)
santizeOperator(filter)
santizeValue(filter)
}
const onOperatorChange = filter => {
santizeOperator(filter)
santizeValue(filter)
}
const onValueTypeChange = filter => {
santizeValue(filter)
} }
const getFieldOptions = field => { const getFieldOptions = field => {
@ -153,23 +166,24 @@
<Select <Select
bind:value={filter.field} bind:value={filter.field}
options={fieldOptions} options={fieldOptions}
on:change={e => onFieldChange(filter, e.detail)} on:change={() => onFieldChange(filter)}
placeholder="Column" placeholder="Column"
/> />
<Select <Select
disabled={!filter.field} disabled={!filter.field}
options={LuceneUtils.getValidOperatorsForType(filter.type)} options={getValidOperatorsForType(filter.type)}
bind:value={filter.operator} bind:value={filter.operator}
on:change={e => onOperatorChange(filter, e.detail)} on:change={() => onOperatorChange(filter)}
placeholder={null} placeholder={null}
/> />
<Select <Select
disabled={filter.noValue || !filter.field} disabled={filter.noValue || !filter.field}
options={valueTypeOptions} options={valueTypeOptions}
bind:value={filter.valueType} bind:value={filter.valueType}
on:change={() => onValueTypeChange(filter)}
placeholder={null} placeholder={null}
/> />
{#if filter.valueType === "Binding"} {#if filter.field && filter.valueType === "Binding"}
<DrawerBindableInput <DrawerBindableInput
disabled={filter.noValue} disabled={filter.noValue}
title={`Value for "${filter.field}"`} title={`Value for "${filter.field}"`}
@ -250,7 +264,7 @@
column-gap: var(--spacing-l); column-gap: var(--spacing-l);
row-gap: var(--spacing-s); row-gap: var(--spacing-s);
align-items: center; align-items: center;
grid-template-columns: 1fr 120px 120px 1fr auto auto; grid-template-columns: 1fr 150px 120px 1fr 16px 16px;
} }
.filter-label { .filter-label {

View File

@ -40,7 +40,7 @@ export const OperatorOptions = {
}, },
NotContains: { NotContains: {
value: "notContains", value: "notContains",
label: "Does Not Contain", label: "Does not contain",
}, },
In: { In: {
value: "oneOf", value: "oneOf",