Merge pull request #11962 from Budibase/budi-7583/filtering-data-provider-with-a-user-column-does-not-work

Filtering data providers by the new user column type
This commit is contained in:
Adria Navarro 2023-10-03 17:47:28 +02:00 committed by GitHub
commit 0867219a6e
5 changed files with 113 additions and 26 deletions

View File

@ -660,7 +660,8 @@
>Open schema editor</Button >Open schema editor</Button
> >
{:else if editableColumn.type === USER_REFRENCE_TYPE} {:else if editableColumn.type === USER_REFRENCE_TYPE}
<Toggle <!-- Disabled temporally -->
<!-- <Toggle
value={editableColumn.relationshipType === RelationshipType.MANY_TO_MANY} value={editableColumn.relationshipType === RelationshipType.MANY_TO_MANY}
on:change={e => on:change={e =>
(editableColumn.relationshipType = e.detail (editableColumn.relationshipType = e.detail
@ -669,7 +670,7 @@
disabled={!isCreating} disabled={!isCreating}
thin thin
text="Allow multiple users" text="Allow multiple users"
/> /> -->
{/if} {/if}
{#if editableColumn.type === AUTO_TYPE || editableColumn.autocolumn} {#if editableColumn.type === AUTO_TYPE || editableColumn.autocolumn}
<Select <Select

View File

@ -17,7 +17,10 @@
import { generate } from "shortid" import { generate } from "shortid"
import { LuceneUtils, Constants } from "@budibase/frontend-core" import { LuceneUtils, Constants } from "@budibase/frontend-core"
import { getFields } from "helpers/searchFields" import { getFields } from "helpers/searchFields"
import { FieldType } from "@budibase/types"
import { createEventDispatcher, onMount } from "svelte" import { createEventDispatcher, onMount } from "svelte"
import FilterUsers from "./FilterUsers.svelte"
import { RelationshipType } from "constants/backend"
export let schemaFields export let schemaFields
export let filters = [] export let filters = []
@ -29,7 +32,6 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const { OperatorOptions } = Constants const { OperatorOptions } = Constants
const { getValidOperatorsForType } = LuceneUtils
const KeyedFieldRegex = /\d[0-9]*:/g const KeyedFieldRegex = /\d[0-9]*:/g
const behaviourOptions = [ const behaviourOptions = [
{ value: "and", label: "Match all filters" }, { value: "and", label: "Match all filters" },
@ -131,11 +133,7 @@
const santizeOperator = filter => { const santizeOperator = filter => {
// Ensure a valid operator is selected // Ensure a valid operator is selected
const operators = getValidOperatorsForType( const operators = getValidOperatorsForType(filter).map(x => x.value)
filter.type,
filter.field,
datasource
).map(x => x.value)
if (!operators.includes(filter.operator)) { if (!operators.includes(filter.operator)) {
filter.operator = operators[0] ?? OperatorOptions.Equals.value filter.operator = operators[0] ?? OperatorOptions.Equals.value
} }
@ -148,7 +146,7 @@
filter.noValue = noValueOptions.includes(filter.operator) filter.noValue = noValueOptions.includes(filter.operator)
} }
const santizeValue = filter => { const santizeValue = (filter, previousType) => {
// Check if the operator allows a value at all // Check if the operator allows a value at all
if (filter.noValue) { if (filter.noValue) {
filter.value = null filter.value = null
@ -162,13 +160,20 @@
} }
} else if (filter.type === "array" && filter.valueType === "Value") { } else if (filter.type === "array" && filter.valueType === "Value") {
filter.value = [] filter.value = []
} else if (
previousType !== filter.type &&
(previousType === FieldType.BB_REFERENCE ||
filter.type === FieldType.BB_REFERENCE)
) {
filter.value = filter.type === "array" ? [] : null
} }
} }
const onFieldChange = filter => { const onFieldChange = filter => {
const previousType = filter.type
santizeTypes(filter) santizeTypes(filter)
santizeOperator(filter) santizeOperator(filter)
santizeValue(filter) santizeValue(filter, previousType)
} }
const onOperatorChange = filter => { const onOperatorChange = filter => {
@ -184,6 +189,32 @@
const schema = enrichedSchemaFields.find(x => x.name === field) const schema = enrichedSchemaFields.find(x => x.name === field)
return schema?.constraints?.inclusion || [] return schema?.constraints?.inclusion || []
} }
const getValidOperatorsForType = filter => {
if (!filter) {
return []
}
let type = filter.type
if (type === FieldType.BB_REFERENCE) {
const fieldSchema = getSchema(filter)
if (fieldSchema) {
type = {
type: fieldSchema.type,
multiple:
fieldSchema.relationshipType === RelationshipType.MANY_TO_MANY,
}
}
}
const operators = LuceneUtils.getValidOperatorsForType(
type,
filter.field,
datasource
)
return operators
}
</script> </script>
<DrawerContent> <DrawerContent>
@ -228,11 +259,7 @@
/> />
<Select <Select
disabled={!filter.field} disabled={!filter.field}
options={getValidOperatorsForType( options={getValidOperatorsForType(filter)}
filter.type,
filter.field,
datasource
)}
bind:value={filter.operator} bind:value={filter.operator}
on:change={() => onOperatorChange(filter)} on:change={() => onOperatorChange(filter)}
placeholder={null} placeholder={null}
@ -285,6 +312,14 @@
timeOnly={getSchema(filter)?.timeOnly} timeOnly={getSchema(filter)?.timeOnly}
bind:value={filter.value} bind:value={filter.value}
/> />
{:else if filter.type === FieldType.BB_REFERENCE}
<FilterUsers
bind:value={filter.value}
multiselect={getSchema(filter).relationshipType ===
RelationshipType.MANY_TO_MANY ||
filter.operator === OperatorOptions.In.value}
disabled={filter.noValue}
/>
{:else} {:else}
<DrawerBindableInput disabled /> <DrawerBindableInput disabled />
{/if} {/if}

View File

@ -0,0 +1,34 @@
<script>
import { Select, Multiselect } from "@budibase/bbui"
import { fetchData } from "@budibase/frontend-core"
import { API } from "api"
export let value = null
export let disabled
export let multiselect = false
$: fetch = fetchData({
API,
datasource: {
type: "user",
},
options: {
limit: 100,
},
})
$: options = $fetch.rows
$: component = multiselect ? Multiselect : Select
</script>
<svelte:component
this={component}
bind:value
autocomplete
{options}
getOptionLabel={option => option.email}
getOptionValue={option => option._id}
{disabled}
/>

View File

@ -2,7 +2,7 @@ version: "3.8"
services: services:
db: db:
container_name: postgres container_name: postgres
image: postgres image: postgres:15
restart: unless-stopped restart: unless-stopped
environment: environment:
POSTGRES_USER: root POSTGRES_USER: root
@ -25,4 +25,4 @@ services:
- "5050:80" - "5050:80"
volumes: volumes:
pg_data: pg_data:

View File

@ -12,12 +12,22 @@ import { deepGet } from "./helpers"
const HBS_REGEX = /{{([^{].*?)}}/g const HBS_REGEX = /{{([^{].*?)}}/g
type RequestedFieldType =
| Exclude<FieldType, FieldType.BB_REFERENCE>
| { type: FieldType.BB_REFERENCE; multiple: boolean }
export function isFieldType(
r: RequestedFieldType
): r is Exclude<FieldType, FieldType.BB_REFERENCE> {
return typeof r === "string" && Object.values(FieldType).includes(r)
}
/** /**
* Returns the valid operator options for a certain data type * Returns the valid operator options for a certain data type
* @param type the data type * @param type the data type
*/ */
export const getValidOperatorsForType = ( export const getValidOperatorsForType = (
type: FieldType, type: RequestedFieldType,
field: string, field: string,
datasource: Datasource & { tableId: any } // TODO: is this table id ever populated? datasource: Datasource & { tableId: any } // TODO: is this table id ever populated?
) => { ) => {
@ -44,22 +54,29 @@ export const getValidOperatorsForType = (
value: string value: string
label: string label: string
}[] = [] }[] = []
if (type === "string") { if (type === FieldType.STRING) {
ops = stringOps ops = stringOps
} else if (type === "number" || type === "bigint") { } else if (type === FieldType.NUMBER || type === FieldType.BIGINT) {
ops = numOps ops = numOps
} else if (type === "options") { } else if (type === FieldType.OPTIONS) {
ops = [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty, Op.In] ops = [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty, Op.In]
} else if (type === "array") { } else if (type === FieldType.ARRAY) {
ops = [Op.Contains, Op.NotContains, Op.Empty, Op.NotEmpty, Op.ContainsAny] ops = [Op.Contains, Op.NotContains, Op.Empty, Op.NotEmpty, Op.ContainsAny]
} else if (type === "boolean") { } else if (type === FieldType.BOOLEAN) {
ops = [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty] ops = [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
} else if (type === "longform") { } else if (type === FieldType.LONGFORM) {
ops = stringOps ops = stringOps
} else if (type === "datetime") { } else if (type === FieldType.DATETIME) {
ops = numOps ops = numOps
} else if (type === "formula") { } else if (type === FieldType.FORMULA) {
ops = stringOps.concat([Op.MoreThan, Op.LessThan]) ops = stringOps.concat([Op.MoreThan, Op.LessThan])
} else if (!isFieldType(type) && type.type === FieldType.BB_REFERENCE) {
if (type.multiple) {
// Temporally disabled
ops = []
} else {
ops = [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty, Op.In]
}
} }
// Only allow equal/not equal for _id in SQL tables // Only allow equal/not equal for _id in SQL tables