1
0
Fork 0
mirror of synced 2024-07-09 00:06:05 +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> <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,30 +18,15 @@
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 =
filters?.find(filter => filter.onEmptyFilter)?.onEmptyFilter ?? "all"
rawFilters = (filters || [])
.filter(filter => filter.operator !== "allOr" && !filter.onEmptyFilter)
.map(filter => {
const { field } = filter const { field } = filter
let newFilter = { ...filter } let newFilter = { ...filter }
delete newFilter.allOr delete newFilter.allOr
@ -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}

View file

@ -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>