1
0
Fork 0
mirror of synced 2024-07-03 13:30:46 +12:00

Handle extra filters in base

This commit is contained in:
Adria Navarro 2024-04-11 16:00:56 +02:00
parent 6945ed5674
commit 2fcdf2602e
2 changed files with 82 additions and 54 deletions

View file

@ -1,5 +1,5 @@
<script>
import { DrawerContent, Select } from "@budibase/bbui"
import { DrawerContent } from "@budibase/bbui"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
@ -18,40 +18,25 @@
const dispatch = createEventDispatcher()
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 matchAny = false
let onEmptyFilter = "all"
$: parseFilters(rawFilters)
$: dispatch("change", enrichFilters(rawFilters, matchAny, onEmptyFilter))
$: dispatch("change", enrichFilters(rawFilters))
// Remove field key prefixes and determine which behaviours to use
const parseFilters = filters => {
matchAny = filters?.find(filter => filter.operator === "allOr") != null
onEmptyFilter =
filters?.find(filter => filter.onEmptyFilter)?.onEmptyFilter ?? "all"
rawFilters = (filters || [])
.filter(filter => filter.operator !== "allOr" && !filter.onEmptyFilter)
.map(filter => {
const { field } = filter
let newFilter = { ...filter }
delete newFilter.allOr
if (typeof field === "string" && field.match(KeyedFieldRegex) != null) {
const parts = field.split(":")
parts.shift()
newFilter.field = parts.join(":")
}
return newFilter
})
rawFilters = (filters || []).map(filter => {
const { field } = filter
let newFilter = { ...filter }
delete newFilter.allOr
if (typeof field === "string" && field.match(KeyedFieldRegex) != null) {
const parts = field.split(":")
parts.shift()
newFilter.field = parts.join(":")
}
return newFilter
})
}
onMount(() => {
@ -65,7 +50,7 @@
// Add field key prefixes and a special metadata filter object to indicate
// how to handle filter behaviour
const enrichFilters = (rawFilters, matchAny, onEmptyFilter) => {
const enrichFilters = rawFilters => {
let count = 1
return rawFilters
.filter(filter => filter.field)
@ -73,40 +58,19 @@
...filter,
field: `${count++}:${filter.field}`,
}))
.concat(matchAny ? [{ operator: "allOr" }] : [])
.concat([{ onEmptyFilter }])
.concat(...rawFilters.filter(filter => !filter.field))
}
</script>
<DrawerContent padding={false}>
<FilterBuilder
bind:filters={rawFilters}
behaviourFilters={true}
{schemaFields}
{datasource}
{allowBindings}
>
<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="filteringHeroContent" class="filteringHeroContent" />
<div slot="binding" let:filter>
<DrawerBindableInput
disabled={filter.noValue}

View file

@ -21,8 +21,24 @@
export let schemaFields
export let filters = []
export let datasource
export let behaviourFilters = 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")
$: fieldOptions = (schemaFields ?? [])
@ -144,6 +160,22 @@
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>
<div class="container" class:mobile={$context?.device?.mobile}>
@ -154,6 +186,30 @@
Add your first filter expression.
{:else}
<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}
</Body>
{#if filters?.length}
@ -162,7 +218,7 @@
<Label>Filters</Label>
</div>
<div class="fields">
{#each filters as filter}
{#each filters.filter(filter => filter.operator !== "allOr" && !filter.onEmptyFilter) as filter}
<Select
bind:value={filter.field}
options={fieldOptions}
@ -284,4 +340,12 @@
.filter-label {
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>