Handle extra filters in base
This commit is contained in:
parent
6945ed5674
commit
2fcdf2602e
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { DrawerContent, Select } from "@budibase/bbui"
|
import { DrawerContent } from "@budibase/bbui"
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
|
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
|
||||||
|
|
||||||
|
@ -18,40 +18,25 @@
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const KeyedFieldRegex = /\d[0-9]*:/g
|
const KeyedFieldRegex = /\d[0-9]*:/g
|
||||||
const behaviourOptions = [
|
|
||||||
{ value: "and", label: "Match all filters" },
|
|
||||||
{ value: "or", label: "Match any filter" },
|
|
||||||
]
|
|
||||||
const onEmptyOptions = [
|
|
||||||
{ value: "all", label: "Return all table rows" },
|
|
||||||
{ value: "none", label: "Return no rows" },
|
|
||||||
]
|
|
||||||
|
|
||||||
let rawFilters
|
let rawFilters
|
||||||
let matchAny = false
|
|
||||||
let onEmptyFilter = "all"
|
|
||||||
|
|
||||||
$: parseFilters(rawFilters)
|
$: parseFilters(rawFilters)
|
||||||
$: dispatch("change", enrichFilters(rawFilters, matchAny, onEmptyFilter))
|
$: dispatch("change", enrichFilters(rawFilters))
|
||||||
|
|
||||||
// Remove field key prefixes and determine which behaviours to use
|
// Remove field key prefixes and determine which behaviours to use
|
||||||
const parseFilters = filters => {
|
const parseFilters = filters => {
|
||||||
matchAny = filters?.find(filter => filter.operator === "allOr") != null
|
rawFilters = (filters || []).map(filter => {
|
||||||
onEmptyFilter =
|
const { field } = filter
|
||||||
filters?.find(filter => filter.onEmptyFilter)?.onEmptyFilter ?? "all"
|
let newFilter = { ...filter }
|
||||||
rawFilters = (filters || [])
|
delete newFilter.allOr
|
||||||
.filter(filter => filter.operator !== "allOr" && !filter.onEmptyFilter)
|
if (typeof field === "string" && field.match(KeyedFieldRegex) != null) {
|
||||||
.map(filter => {
|
const parts = field.split(":")
|
||||||
const { field } = filter
|
parts.shift()
|
||||||
let newFilter = { ...filter }
|
newFilter.field = parts.join(":")
|
||||||
delete newFilter.allOr
|
}
|
||||||
if (typeof field === "string" && field.match(KeyedFieldRegex) != null) {
|
return newFilter
|
||||||
const parts = field.split(":")
|
})
|
||||||
parts.shift()
|
|
||||||
newFilter.field = parts.join(":")
|
|
||||||
}
|
|
||||||
return newFilter
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
@ -65,7 +50,7 @@
|
||||||
|
|
||||||
// Add field key prefixes and a special metadata filter object to indicate
|
// Add field key prefixes and a special metadata filter object to indicate
|
||||||
// how to handle filter behaviour
|
// how to handle filter behaviour
|
||||||
const enrichFilters = (rawFilters, matchAny, onEmptyFilter) => {
|
const enrichFilters = rawFilters => {
|
||||||
let count = 1
|
let count = 1
|
||||||
return rawFilters
|
return rawFilters
|
||||||
.filter(filter => filter.field)
|
.filter(filter => filter.field)
|
||||||
|
@ -73,40 +58,19 @@
|
||||||
...filter,
|
...filter,
|
||||||
field: `${count++}:${filter.field}`,
|
field: `${count++}:${filter.field}`,
|
||||||
}))
|
}))
|
||||||
.concat(matchAny ? [{ operator: "allOr" }] : [])
|
.concat(...rawFilters.filter(filter => !filter.field))
|
||||||
.concat([{ onEmptyFilter }])
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DrawerContent padding={false}>
|
<DrawerContent padding={false}>
|
||||||
<FilterBuilder
|
<FilterBuilder
|
||||||
bind:filters={rawFilters}
|
bind:filters={rawFilters}
|
||||||
|
behaviourFilters={true}
|
||||||
{schemaFields}
|
{schemaFields}
|
||||||
{datasource}
|
{datasource}
|
||||||
{allowBindings}
|
{allowBindings}
|
||||||
>
|
>
|
||||||
<div slot="filteringHeroContent" class="filteringHeroContent">
|
<div slot="filteringHeroContent" class="filteringHeroContent" />
|
||||||
<Select
|
|
||||||
label="Behaviour"
|
|
||||||
value={matchAny ? "or" : "and"}
|
|
||||||
options={behaviourOptions}
|
|
||||||
getOptionLabel={opt => opt.label}
|
|
||||||
getOptionValue={opt => opt.value}
|
|
||||||
on:change={e => (matchAny = e.detail === "or")}
|
|
||||||
placeholder={null}
|
|
||||||
/>
|
|
||||||
{#if datasource?.type === "table"}
|
|
||||||
<Select
|
|
||||||
label="When filter empty"
|
|
||||||
value={onEmptyFilter}
|
|
||||||
options={onEmptyOptions}
|
|
||||||
getOptionLabel={opt => opt.label}
|
|
||||||
getOptionValue={opt => opt.value}
|
|
||||||
on:change={e => (onEmptyFilter = e.detail)}
|
|
||||||
placeholder={null}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div slot="binding" let:filter>
|
<div slot="binding" let:filter>
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
disabled={filter.noValue}
|
disabled={filter.noValue}
|
||||||
|
|
|
@ -21,8 +21,24 @@
|
||||||
export let schemaFields
|
export let schemaFields
|
||||||
export let filters = []
|
export let filters = []
|
||||||
export let datasource
|
export let datasource
|
||||||
|
export let behaviourFilters = false
|
||||||
export let allowBindings = false
|
export let allowBindings = false
|
||||||
|
|
||||||
|
$: matchAny = filters?.find(filter => filter.operator === "allOr") != null
|
||||||
|
$: onEmptyFilter =
|
||||||
|
filters?.find(filter => filter.onEmptyFilter)?.onEmptyFilter ?? "all"
|
||||||
|
|
||||||
|
$: console.warn(filters)
|
||||||
|
|
||||||
|
const behaviourOptions = [
|
||||||
|
{ value: "and", label: "Match all filters" },
|
||||||
|
{ value: "or", label: "Match any filter" },
|
||||||
|
]
|
||||||
|
const onEmptyOptions = [
|
||||||
|
{ value: "all", label: "Return all table rows" },
|
||||||
|
{ value: "none", label: "Return no rows" },
|
||||||
|
]
|
||||||
|
|
||||||
const context = getContext("context")
|
const context = getContext("context")
|
||||||
|
|
||||||
$: fieldOptions = (schemaFields ?? [])
|
$: fieldOptions = (schemaFields ?? [])
|
||||||
|
@ -144,6 +160,22 @@
|
||||||
filter.value = filter.type === FieldType.ARRAY ? [] : null
|
filter.value = filter.type === FieldType.ARRAY ? [] : null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAllOr(option) {
|
||||||
|
filters = filters.filter(f => f.operator !== "allOr")
|
||||||
|
if (option === "or") {
|
||||||
|
filters.push({ operator: "allOr" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOnEmptyFilter(value) {
|
||||||
|
const existingFilter = filters?.find(filter => filter.onEmptyFilter)
|
||||||
|
if (existingFilter) {
|
||||||
|
existingFilter.onEmptyFilter = value
|
||||||
|
} else {
|
||||||
|
filters.push({ onEmptyFilter: value })
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container" class:mobile={$context?.device?.mobile}>
|
<div class="container" class:mobile={$context?.device?.mobile}>
|
||||||
|
@ -154,6 +186,30 @@
|
||||||
Add your first filter expression.
|
Add your first filter expression.
|
||||||
{:else}
|
{:else}
|
||||||
<slot name="filteringHeroContent" />
|
<slot name="filteringHeroContent" />
|
||||||
|
{#if behaviourFilters}
|
||||||
|
<div class="behaviour-filters">
|
||||||
|
<Select
|
||||||
|
label="Behaviour"
|
||||||
|
value={matchAny ? "or" : "and"}
|
||||||
|
options={behaviourOptions}
|
||||||
|
getOptionLabel={opt => opt.label}
|
||||||
|
getOptionValue={opt => opt.value}
|
||||||
|
on:change={e => handleAllOr(e.detail)}
|
||||||
|
placeholder={null}
|
||||||
|
/>
|
||||||
|
{#if datasource?.type === "table"}
|
||||||
|
<Select
|
||||||
|
label="When filter empty"
|
||||||
|
value={onEmptyFilter}
|
||||||
|
options={onEmptyOptions}
|
||||||
|
getOptionLabel={opt => opt.label}
|
||||||
|
getOptionValue={opt => opt.value}
|
||||||
|
on:change={e => handleOnEmptyFilter(e.detail)}
|
||||||
|
placeholder={null}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</Body>
|
</Body>
|
||||||
{#if filters?.length}
|
{#if filters?.length}
|
||||||
|
@ -162,7 +218,7 @@
|
||||||
<Label>Filters</Label>
|
<Label>Filters</Label>
|
||||||
</div>
|
</div>
|
||||||
<div class="fields">
|
<div class="fields">
|
||||||
{#each filters as filter}
|
{#each filters.filter(filter => filter.operator !== "allOr" && !filter.onEmptyFilter) as filter}
|
||||||
<Select
|
<Select
|
||||||
bind:value={filter.field}
|
bind:value={filter.field}
|
||||||
options={fieldOptions}
|
options={fieldOptions}
|
||||||
|
@ -284,4 +340,12 @@
|
||||||
.filter-label {
|
.filter-label {
|
||||||
margin-bottom: var(--spacing-s);
|
margin-bottom: var(--spacing-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.behaviour-filters {
|
||||||
|
display: grid;
|
||||||
|
column-gap: var(--spacing-l);
|
||||||
|
row-gap: var(--spacing-s);
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: minmax(150px, 1fr) 170px 120px minmax(150px, 1fr) 16px 16px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue