Allow table with search block to render correct components for all relevant field types

This commit is contained in:
Andrew Kingston 2021-11-03 11:58:06 +00:00
parent fcf87956de
commit d054d496be
3 changed files with 129 additions and 60 deletions

View File

@ -2626,13 +2626,6 @@
"key": "rowCount", "key": "rowCount",
"defaultValue": 8 "defaultValue": 8
}, },
{
"type": "multifield",
"label": "Table Columns",
"key": "tableColumns",
"dependsOn": "dataSource",
"placeholder": "All columns"
},
{ {
"type": "select", "type": "select",
"label": "Size", "label": "Size",
@ -2649,14 +2642,21 @@
} }
] ]
}, },
{
"type": "multifield",
"label": "Table Columns",
"key": "tableColumns",
"dependsOn": "dataSource",
"placeholder": "All columns"
},
{ {
"type": "boolean", "type": "boolean",
"label": "Quiet", "label": "Quiet table variant",
"key": "quiet" "key": "quiet"
}, },
{ {
"type": "boolean", "type": "boolean",
"label": "Auto Columns", "label": "Show auto columns",
"key": "showAutoColumns", "key": "showAutoColumns",
"defaultValue": false "defaultValue": false
} }

View File

@ -2,7 +2,6 @@
import { getContext, setContext } from "svelte" import { getContext, setContext } from "svelte"
const component = getContext("component") const component = getContext("component")
const { styleable } = getContext("sdk")
// We need to set a block context to know we're inside a block, but also // We need to set a block context to know we're inside a block, but also
// to be able to reference the actual component ID of the block from // to be able to reference the actual component ID of the block from
@ -10,6 +9,4 @@
setContext("block", { id: $component.id }) setContext("block", { id: $component.id })
</script> </script>
<div use:styleable={$component.styles}> <slot />
<slot />
</div>

View File

@ -1,4 +1,5 @@
<script> <script>
import { onMount, getContext } from "svelte"
import Block from "components/Block.svelte" import Block from "components/Block.svelte"
import BlockComponent from "components/BlockComponent.svelte" import BlockComponent from "components/BlockComponent.svelte"
import { Heading } from "@budibase/bbui" import { Heading } from "@budibase/bbui"
@ -16,85 +17,156 @@
export let quiet export let quiet
export let size export let size
const { API, styleable } = getContext("sdk")
const context = getContext("context")
const component = getContext("component")
const schemaComponentMap = {
string: "stringfield",
options: "optionsfield",
number: "numberfield",
datetime: "datetimefield",
boolean: "booleanfield",
}
let formId let formId
let dataProviderId let dataProviderId
let schema
$: enrichedFilter = enrichFilter(filter, searchColumns, formId) $: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema)
$: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId)
// Enrich the default filter with the specified search fields // Enrich the default filter with the specified search fields
const enrichFilter = (filter, searchColumns, formId) => { const enrichFilter = (filter, columns, formId) => {
let enrichedFilter = [...(filter || [])] let enrichedFilter = [...(filter || [])]
searchColumns?.forEach(column => { columns?.forEach(column => {
enrichedFilter.push({ enrichedFilter.push({
field: column, field: column.name,
operator: "equal", operator: "equal",
type: "string", type: "string",
valueType: "Binding", valueType: "Binding",
value: `{{ [${formId}].[${column}] }}`, value: `{{ [${formId}].[${column.name}] }}`,
}) })
}) })
return enrichedFilter return enrichedFilter
} }
// Determine data types for search fields and only use those that are valid
const enrichSearchColumns = (searchColumns, schema) => {
let enrichedColumns = []
searchColumns?.forEach(column => {
const schemaType = schema?.[column]?.type
const componentType = schemaComponentMap[schemaType]
if (componentType) {
enrichedColumns.push({
name: column,
componentType,
})
}
})
return enrichedColumns
}
// Load the datasource schema on mount so we can determine column types
onMount(async () => {
if (dataSource) {
schema = await API.fetchDatasourceSchema(dataSource)
}
})
</script> </script>
<Block> <Block>
<BlockComponent type="form" bind:id={formId} props={{ dataSource }}> <div class={size} use:styleable={$component.styles}>
{#if searchColumns?.length} <BlockComponent type="form" bind:id={formId} props={{ dataSource }}>
<div class="search"> {#if title || enrichedSearchColumns?.length}
{#if title} <div class="header">
<div class="title"> <div class="title">
<Heading>{title}</Heading> <Heading>{title || ""}</Heading>
</div> </div>
{/if} {#if enrichedSearchColumns?.length}
{#each searchColumns as column} <div class="search" class:mobile={$context.device.mobile}>
<BlockComponent {#each enrichedSearchColumns as column}
type="stringfield" <BlockComponent
props={{ type={column.componentType}
field: column, props={{
placeholder: column, field: column.name,
label: column, placeholder: column.name,
}} text: column.name,
/> autoWidth: true,
{/each} }}
</div> />
{/if} {/each}
<BlockComponent </div>
type="dataprovider" {/if}
bind:id={dataProviderId} </div>
props={{ {/if}
dataSource,
filter: enrichedFilter,
sortColumn,
sortOrder,
paginate,
limit: rowCount,
}}
>
<BlockComponent <BlockComponent
type="table" type="dataprovider"
bind:id={dataProviderId}
props={{ props={{
dataProvider: `{{ literal [${dataProviderId}] }}`, dataSource,
columns: tableColumns, filter: enrichedFilter,
showAutoColumns, sortColumn,
rowCount, sortOrder,
quiet, paginate,
size, limit: rowCount,
}} }}
/> >
<BlockComponent
type="table"
props={{
dataProvider: `{{ literal [${dataProviderId}] }}`,
columns: tableColumns,
showAutoColumns,
rowCount,
quiet,
size,
}}
/>
</BlockComponent>
</BlockComponent> </BlockComponent>
</BlockComponent> </div>
</Block> </Block>
<style> <style>
.search { .header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-end; justify-content: space-between;
align-items: center; align-items: center;
gap: 20px;
flex-wrap: wrap;
margin-bottom: 20px; margin-bottom: 20px;
gap: 10px;
} }
.title { .title {
flex: 1 1 auto; flex: 1 1 auto;
} }
.search {
flex: 0 0 auto;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: 10px;
max-width: 100%;
flex-wrap: wrap;
}
.search :global(.component > *) {
width: 200px;
}
.search :global(.spectrum-InputGroup .spectrum-InputGroup-input) {
width: 100%;
}
.search :global(.spectrum-InputGroup) {
min-width: 0;
}
.search.mobile {
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
position: relative;
width: 100%;
}
.search.mobile :global(.component > *) {
width: 100%;
}
</style> </style>