Add filtering to repeaters
This commit is contained in:
parent
9dc94fbed6
commit
1a00fbacde
|
@ -0,0 +1,75 @@
|
||||||
|
<script>
|
||||||
|
import { Button, Drawer, Spacer } from "@budibase/bbui"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { notifier } from "builderStore/store/notifications"
|
||||||
|
import {
|
||||||
|
getDatasourceForProvider,
|
||||||
|
getSchemaForDatasource,
|
||||||
|
} from "builderStore/dataBinding"
|
||||||
|
import SaveFields from "./EventsEditor/actions/SaveFields.svelte"
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let value = {}
|
||||||
|
export let componentInstance
|
||||||
|
let drawer
|
||||||
|
let tempValue = value
|
||||||
|
|
||||||
|
$: schemaFields = getSchemaFields(componentInstance)
|
||||||
|
|
||||||
|
const getSchemaFields = component => {
|
||||||
|
const datasource = getDatasourceForProvider(component)
|
||||||
|
const { schema } = getSchemaForDatasource(datasource)
|
||||||
|
return Object.values(schema || {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveFilter = async () => {
|
||||||
|
dispatch("change", tempValue)
|
||||||
|
notifier.success("Filters saved.")
|
||||||
|
drawer.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFieldsChanged = event => {
|
||||||
|
tempValue = event.detail
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Button secondary wide on:click={drawer.show}>Define Filters</Button>
|
||||||
|
<Drawer bind:this={drawer} title={'Filtering'}>
|
||||||
|
<heading slot="buttons">
|
||||||
|
<Button thin blue on:click={saveFilter}>Save</Button>
|
||||||
|
</heading>
|
||||||
|
<div slot="body">
|
||||||
|
<div class="root">
|
||||||
|
{#if !Object.keys(tempValue || {}).length}
|
||||||
|
<p>Add your first filter column.</p>
|
||||||
|
<Spacer small />
|
||||||
|
{/if}
|
||||||
|
<div class="fields">
|
||||||
|
<SaveFields
|
||||||
|
parameterFields={value}
|
||||||
|
{schemaFields}
|
||||||
|
on:fieldschanged={onFieldsChanged} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
padding: var(--spacing-m);
|
||||||
|
min-height: 40vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0 0 var(--spacing-s) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields {
|
||||||
|
display: grid;
|
||||||
|
column-gap: var(--spacing-s);
|
||||||
|
row-gap: var(--spacing-s);
|
||||||
|
grid-template-columns: auto 1fr auto 1fr auto;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -18,6 +18,7 @@
|
||||||
import MultiFieldSelect from "./PropertyControls/MultiFieldSelect.svelte"
|
import MultiFieldSelect from "./PropertyControls/MultiFieldSelect.svelte"
|
||||||
import SchemaSelect from "./PropertyControls/SchemaSelect.svelte"
|
import SchemaSelect from "./PropertyControls/SchemaSelect.svelte"
|
||||||
import EventsEditor from "./PropertyControls/EventsEditor"
|
import EventsEditor from "./PropertyControls/EventsEditor"
|
||||||
|
import FilterEditor from "./PropertyControls/FilterEditor.svelte"
|
||||||
import ScreenSelect from "./PropertyControls/ScreenSelect.svelte"
|
import ScreenSelect from "./PropertyControls/ScreenSelect.svelte"
|
||||||
import DetailScreenSelect from "./PropertyControls/DetailScreenSelect.svelte"
|
import DetailScreenSelect from "./PropertyControls/DetailScreenSelect.svelte"
|
||||||
import { IconSelect } from "./PropertyControls/IconSelect"
|
import { IconSelect } from "./PropertyControls/IconSelect"
|
||||||
|
@ -73,6 +74,7 @@
|
||||||
field: FieldSelect,
|
field: FieldSelect,
|
||||||
multifield: MultiFieldSelect,
|
multifield: MultiFieldSelect,
|
||||||
schema: SchemaSelect,
|
schema: SchemaSelect,
|
||||||
|
filter: FilterEditor,
|
||||||
"field/string": StringFieldSelect,
|
"field/string": StringFieldSelect,
|
||||||
"field/number": NumberFieldSelect,
|
"field/number": NumberFieldSelect,
|
||||||
"field/options": OptionsFieldSelect,
|
"field/options": OptionsFieldSelect,
|
||||||
|
|
|
@ -118,6 +118,11 @@
|
||||||
"label": "Empty Text",
|
"label": "Empty Text",
|
||||||
"key": "noRowsMessage",
|
"key": "noRowsMessage",
|
||||||
"defaultValue": "No rows found."
|
"defaultValue": "No rows found."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "filter",
|
||||||
|
"label": "Filtering",
|
||||||
|
"key": "filter"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
export let datasource
|
export let datasource
|
||||||
export let noRowsMessage
|
export let noRowsMessage
|
||||||
|
export let filter
|
||||||
|
|
||||||
const { API, styleable, Provider, builderStore, ActionTypes } = getContext(
|
const { API, styleable, Provider, builderStore, ActionTypes } = getContext(
|
||||||
"sdk"
|
"sdk"
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
let loaded = false
|
let loaded = false
|
||||||
|
|
||||||
$: fetchData(datasource)
|
$: fetchData(datasource)
|
||||||
|
$: filteredRows = filterRows(rows, filter)
|
||||||
$: actions = [
|
$: actions = [
|
||||||
{
|
{
|
||||||
type: ActionTypes.RefreshDatasource,
|
type: ActionTypes.RefreshDatasource,
|
||||||
|
@ -21,21 +23,34 @@
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
async function fetchData(datasource) {
|
const fetchData = async datasource => {
|
||||||
if (!isEmpty(datasource)) {
|
if (!isEmpty(datasource)) {
|
||||||
rows = await API.fetchDatasource(datasource)
|
rows = await API.fetchDatasource(datasource)
|
||||||
}
|
}
|
||||||
loaded = true
|
loaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterRows = (rows, filter) => {
|
||||||
|
if (!Object.keys(filter || {}).length) {
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
let filteredData = [...rows]
|
||||||
|
Object.keys(filter).forEach(field => {
|
||||||
|
filteredData = filteredData.filter(row => {
|
||||||
|
return row[field] === filter[field].value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return filteredData
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Provider {actions}>
|
<Provider {actions}>
|
||||||
<div use:styleable={$component.styles}>
|
<div use:styleable={$component.styles}>
|
||||||
{#if rows.length > 0}
|
{#if filteredRows.length > 0}
|
||||||
{#if $component.children === 0 && $builderStore.inBuilder}
|
{#if $component.children === 0 && $builderStore.inBuilder}
|
||||||
<p><i class="ri-image-line" />Add some components to display.</p>
|
<p><i class="ri-image-line" />Add some components to display.</p>
|
||||||
{:else}
|
{:else}
|
||||||
{#each rows as row}
|
{#each filteredRows as row}
|
||||||
<Provider data={row}>
|
<Provider data={row}>
|
||||||
<slot />
|
<slot />
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|
Loading…
Reference in New Issue