From e0c88597a790c4aa0f38991d9456794a15401172 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 12 Nov 2021 13:42:55 +0000 Subject: [PATCH 01/11] Enable data providers to use array and attachment fields as their source --- .../builder/src/builderStore/dataBinding.js | 27 ++- .../DataProviderSelect.svelte | 5 +- .../PropertyControls/DataSourceSelect.svelte | 181 +++++++++++------- packages/client/src/api/datasources.js | 20 ++ .../src/components/app/DataProvider.svelte | 11 +- 5 files changed, 164 insertions(+), 80 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 9cf00be3d4..d4d535a532 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -333,8 +333,11 @@ const getUrlBindings = asset => { */ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { let schema, table + if (datasource) { const { type } = datasource + + // Determine the source table from the datasource type if (type === "provider") { const component = findComponent(asset.props, datasource.providerId) const source = getDatasourceForProvider(asset, component) @@ -342,11 +345,31 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { } else if (type === "query") { const queries = get(queriesStores).list table = queries.find(query => query._id === datasource._id) + } else if (type === "field") { + const { fieldType } = datasource + if (fieldType === "attachment") { + schema = { + url: { + type: "string", + }, + name: { + type: "string", + }, + } + } else if (fieldType === "array") { + schema = { + value: { + type: "string", + }, + } + } } else { const tables = get(tablesStore).list table = tables.find(table => table._id === datasource.tableId) } - if (table) { + + // Determine the schema from the table if not already determined + if (table && !schema) { if (type === "view") { schema = cloneDeep(table.views?.[datasource.name]?.schema) } else if (type === "query" && isForm) { @@ -525,7 +548,7 @@ function bindingReplacement(bindableProperties, textWithBindings, convertTo) { * {{ literal [componentId] }} */ function extractLiteralHandlebarsID(value) { - return value?.match(/{{\s*literal[\s[]+([a-fA-F0-9]+)[\s\]]*}}/)?.[1] + return value?.match(/{{\s*literal\s*\[+([^\]]+)].*}}/)?.[1] } /** diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataProviderSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataProviderSelect.svelte index d27a542f47..979443a403 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataProviderSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataProviderSelect.svelte @@ -11,10 +11,7 @@ const getValue = component => `{{ literal ${makePropSafe(component._id)} }}` $: path = findComponentPath($currentAsset.props, $store.selectedComponentId) - $: providers = path.filter( - component => - component._component === "@budibase/standard-components/dataprovider" - ) + $: providers = path.filter(c => c._component?.endsWith("/dataprovider")) // Set initial value to closest data provider onMount(() => { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte index d86f13e100..f12710e70d 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte @@ -20,16 +20,18 @@ import { notifications } from "@budibase/bbui" import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte" import IntegrationQueryEditor from "components/integration/index.svelte" - - const dispatch = createEventDispatcher() - let anchorRight, dropdownRight - let drawer + import { makePropSafe as safe } from "@budibase/string-templates" export let value = {} export let otherSources export let showAllQueries export let bindings = [] + const dispatch = createEventDispatcher() + const arrayTypes = ["attachment", "array"] + let anchorRight, dropdownRight + let drawer + $: text = value?.label ?? "Choose an option" $: tables = $tablesStore.list.map(m => ({ label: m.name, @@ -54,8 +56,6 @@ name: query.name, tableId: query._id, ...query, - schema: query.schema, - parameters: query.parameters, type: "query", })) $: dataProviders = getDataProviderComponents( @@ -65,29 +65,40 @@ label: provider._instanceName, name: provider._instanceName, providerId: provider._id, - value: `{{ literal [${provider._id}] }}`, + value: `{{ literal ${safe(provider._id)} }}`, type: "provider", - schema: provider.schema, - })) - $: queryBindableProperties = bindings.map(property => ({ - ...property, - category: property.type === "instance" ? "Component" : "Table", - label: property.readableBinding, - path: property.readableBinding, })) $: links = bindings .filter(x => x.fieldSchema?.type === "link") - .map(property => { + .map(binding => { + const { providerId, readableBinding, fieldSchema } = binding || {} + const { name, tableId } = fieldSchema || {} + const safeProviderId = safe(providerId) return { - providerId: property.providerId, - label: property.readableBinding, - fieldName: property.fieldSchema.name, - tableId: property.fieldSchema.tableId, + providerId, + label: readableBinding, + fieldName: name, + tableId, type: "link", // These properties will be enriched by the client library and provide // details of the parent row of the relationship field, from context - rowId: `{{ ${property.providerId}._id }}`, - rowTableId: `{{ ${property.providerId}.tableId }}`, + rowId: `{{ ${safeProviderId}.${safe("_id")} }}`, + rowTableId: `{{ ${safeProviderId}.${safe("tableId")} }}`, + } + }) + $: fields = bindings + .filter(x => arrayTypes.includes(x.fieldSchema?.type)) + .map(binding => { + const { providerId, readableBinding, fieldSchema } = binding || {} + const { name, type, tableId } = fieldSchema || {} + return { + providerId, + label: readableBinding, + fieldName: name, + fieldType: type, + tableId, + type: "field", + value: `{{ literal ${safe(providerId)}.${safe(name)} }}`, } }) @@ -102,6 +113,14 @@ ).source return $integrations[source].query[query.queryVerb] } + + const getQueryParams = query => { + return $queriesStore.list.find(q => q._id === query?._id)?.parameters || [] + } + + const getQueryDatasource = query => { + return $datasources.list.find(ds => ds._id === query?.datasourceId) + }
@@ -127,11 +146,10 @@ - {#if value.parameters.length > 0} + {#if getQueryParams(value._id).length > 0} query._id === value._id) - .parameters} + parameters={getQueryParams(value)} {bindings} /> {/if} @@ -139,9 +157,7 @@ height={200} query={value} schema={fetchQueryDefinition(value)} - datasource={$datasources.list.find( - ds => ds._id === value.datasourceId - )} + datasource={getQueryDatasource(value)} editable={false} /> @@ -159,52 +175,71 @@
  • handleSelected(table)}>{table.label}
  • {/each} - -
    - Views -
    -
      - {#each views as view} -
    • handleSelected(view)}>{view.label}
    • - {/each} -
    - -
    - Relationships -
    -
      - {#each links as link} -
    • handleSelected(link)}>{link.label}
    • - {/each} -
    - -
    - Queries -
    -
      - {#each queries as query} -
    • handleSelected(query)} - > - {query.label} -
    • - {/each} -
    - -
    - Data Providers -
    -
      - {#each dataProviders as provider} -
    • handleSelected(provider)} - > - {provider.label} -
    • - {/each} -
    + {#if views?.length} + +
    + Views +
    +
      + {#each views as view} +
    • handleSelected(view)}>{view.label}
    • + {/each} +
    + {/if} + {#if queries?.length} + +
    + Queries +
    +
      + {#each queries as query} +
    • handleSelected(query)} + > + {query.label} +
    • + {/each} +
    + {/if} + {#if links?.length} + +
    + Relationships +
    +
      + {#each links as link} +
    • handleSelected(link)}>{link.label}
    • + {/each} +
    + {/if} + {#if fields?.length} + +
    + Fields +
    +
      + {#each fields as field} +
    • handleSelected(field)}>{field.label}
    • + {/each} +
    + {/if} + {#if dataProviders?.length} + +
    + Data Providers +
    +
      + {#each dataProviders as provider} +
    • handleSelected(provider)} + > + {provider.label} +
    • + {/each} +
    + {/if} {#if otherSources?.length}
    diff --git a/packages/client/src/api/datasources.js b/packages/client/src/api/datasources.js index d2b05899cb..cea4ae0f3b 100644 --- a/packages/client/src/api/datasources.js +++ b/packages/client/src/api/datasources.js @@ -55,6 +55,26 @@ export const fetchDatasourceSchema = async dataSource => { return dataSource.value?.schema } + // Field sources will have their schema statically defined by the builder + if (type === "field") { + if (dataSource.fieldType === "attachment") { + return { + url: { + type: "string", + }, + name: { + type: "string", + }, + } + } else if (dataSource.fieldType === "array") { + return { + value: { + type: "string", + }, + } + } + } + // Tables, views and links can be fetched by table ID if ( (type === "table" || type === "view" || type === "link") && diff --git a/packages/client/src/components/app/DataProvider.svelte b/packages/client/src/components/app/DataProvider.svelte index a8e53f4906..0b9cbac4dd 100644 --- a/packages/client/src/components/app/DataProvider.svelte +++ b/packages/client/src/components/app/DataProvider.svelte @@ -183,7 +183,16 @@ } else if (dataSource?.type === "provider") { // For providers referencing another provider, just use the rows it // provides - allRows = dataSource?.value?.rows ?? [] + allRows = dataSource?.value?.rows || [] + } else if (dataSource?.type === "field") { + // Field sources will be available from context. + // Enrich non object elements into object to ensure a valid schema. + const data = dataSource?.value || [] + if (data[0] && typeof data[0] !== "object") { + allRows = data.map(value => ({ value })) + } else { + allRows = data + } } else { // For other data sources like queries or views, fetch all rows from the // server From 8b3edeea3b3e4855086d56e76d1a469849bfbbc5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 12 Nov 2021 14:48:53 +0000 Subject: [PATCH 02/11] Update settings bar to account for new block settings structure --- .../src/components/app/blocks/DataBlock.svelte | 0 .../src/components/preview/SettingsBar.svelte | 14 +++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 packages/client/src/components/app/blocks/DataBlock.svelte diff --git a/packages/client/src/components/app/blocks/DataBlock.svelte b/packages/client/src/components/app/blocks/DataBlock.svelte new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index 43c77ef1e6..e1d88b1367 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -17,7 +17,19 @@ $: definition = $builderStore.selectedComponentDefinition $: showBar = definition?.showSettingsBar && !$builderStore.isDragging - $: settings = definition?.settings?.filter(setting => setting.showInBar) ?? [] + $: settings = getBarSettings(definition) + + const getBarSettings = definition => { + let allSettings = [] + definition?.settings?.forEach(setting => { + if (setting.section) { + allSettings = allSettings.concat(setting.settings || []) + } else { + allSettings.push(setting) + } + }) + return allSettings.filter(setting => setting.showInBar) + } const updatePosition = () => { if (!showBar) { From 65111272b89f73f69ee3151d5cec17ec82939e91 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 12 Nov 2021 15:18:55 +0000 Subject: [PATCH 03/11] Allow blocks which take children to work with DND --- packages/client/src/components/preview/DNDHandler.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/preview/DNDHandler.svelte b/packages/client/src/components/preview/DNDHandler.svelte index 474df4a674..82828b1258 100644 --- a/packages/client/src/components/preview/DNDHandler.svelte +++ b/packages/client/src/components/preview/DNDHandler.svelte @@ -147,7 +147,7 @@ return } - const element = e.target.closest(".component") + const element = e.target.closest(".component:not(.block)") if ( element && element.classList.contains("droppable") && From 07f15c5759dbd67cbd72e03fec13617811eaf1cb Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 12 Nov 2021 15:19:25 +0000 Subject: [PATCH 04/11] Add data block component --- .../builder/src/builderStore/dataBinding.js | 1 + .../design/AppPreview/componentStructure.json | 3 +- packages/client/manifest.json | 198 ++++++++++++++++++ .../src/components/BlockComponent.svelte | 2 +- .../client/src/components/Component.svelte | 7 +- .../components/app/blocks/DataBlock.svelte | 60 ++++++ .../client/src/components/app/blocks/index.js | 1 + 7 files changed, 267 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index d4d535a532..e63e922f4f 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -346,6 +346,7 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { const queries = get(queriesStores).list table = queries.find(query => query._id === datasource._id) } else if (type === "field") { + table = { name: datasource.fieldName } const { fieldType } = datasource if (fieldType === "attachment") { schema = { diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json index c4fd33b084..c602000a03 100644 --- a/packages/builder/src/components/design/AppPreview/componentStructure.json +++ b/packages/builder/src/components/design/AppPreview/componentStructure.json @@ -4,7 +4,8 @@ "icon": "Article", "children": [ "tableblock", - "cardsblock" + "cardsblock", + "datablock" ] }, "section", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 4a50a11fce..eec7b82c5c 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2932,5 +2932,203 @@ "type": "schema", "suffix": "repeater" } + }, + "datablock": { + "name": "Data block", + "icon": "ViewList", + "illegalChildren": ["section"], + "hasChildren": true, + "showSettingsBar": true, + "settings": [ + { + "type": "dataSource", + "label": "Data", + "key": "dataSource" + }, + { + "type": "filter", + "label": "Filtering", + "key": "filter" + }, + { + "type": "field", + "label": "Sort Column", + "key": "sortColumn" + }, + { + "type": "select", + "label": "Sort Order", + "key": "sortOrder", + "options": ["Ascending", "Descending"], + "defaultValue": "Descending" + }, + { + "type": "number", + "label": "Limit", + "key": "limit", + "defaultValue": 10 + }, + { + "type": "boolean", + "label": "Paginate", + "key": "paginate" + }, + { + "section": true, + "name": "Layout settings", + "settings": [ + { + "type": "text", + "label": "Empty Text", + "key": "noRowsMessage", + "defaultValue": "No rows found" + }, + { + "type": "select", + "label": "Direction", + "key": "direction", + "showInBar": true, + "barStyle": "buttons", + "options": [ + { + "label": "Column", + "value": "column", + "barIcon": "ViewRow", + "barTitle": "Column layout" + }, + { + "label": "Row", + "value": "row", + "barIcon": "ViewColumn", + "barTitle": "Row layout" + } + ], + "defaultValue": "column" + }, + { + "type": "select", + "label": "Horiz. Align", + "key": "hAlign", + "showInBar": true, + "barStyle": "buttons", + "options": [ + { + "label": "Left", + "value": "left", + "barIcon": "AlignLeft", + "barTitle": "Align left" + }, + { + "label": "Center", + "value": "center", + "barIcon": "AlignCenter", + "barTitle": "Align center" + }, + { + "label": "Right", + "value": "right", + "barIcon": "AlignRight", + "barTitle": "Align right" + }, + { + "label": "Stretch", + "value": "stretch", + "barIcon": "MoveLeftRight", + "barTitle": "Align stretched horizontally" + } + ], + "defaultValue": "stretch" + }, + { + "type": "select", + "label": "Vert. Align", + "key": "vAlign", + "showInBar": true, + "barStyle": "buttons", + "options": [ + { + "label": "Top", + "value": "top", + "barIcon": "AlignTop", + "barTitle": "Align top" + }, + { + "label": "Middle", + "value": "middle", + "barIcon": "AlignMiddle", + "barTitle": "Align middle" + }, + { + "label": "Bottom", + "value": "bottom", + "barIcon": "AlignBottom", + "barTitle": "Align bottom" + }, + { + "label": "Stretch", + "value": "stretch", + "barIcon": "MoveUpDown", + "barTitle": "Align stretched vertically" + } + ], + "defaultValue": "top" + }, + { + "type": "select", + "label": "Gap", + "key": "gap", + "showInBar": true, + "barStyle": "picker", + "options": [ + { + "label": "None", + "value": "N" + }, + { + "label": "Small", + "value": "S" + }, + { + "label": "Medium", + "value": "M" + }, + { + "label": "Large", + "value": "L" + } + ], + "defaultValue": "M" + } + ] + } + ], + "context": [ + { + "type": "static", + "suffix": "provider", + "values": [ + { + "label": "Rows", + "key": "rows" + }, + { + "label": "Rows Length", + "key": "rowsLength" + }, + { + "label": "Schema", + "key": "schema" + }, + { + "label": "Page Number", + "key": "pageNumber" + } + ] + }, + { + "type": "schema", + "suffix": "repeater" + } + ] } } diff --git a/packages/client/src/components/BlockComponent.svelte b/packages/client/src/components/BlockComponent.svelte index 589998994d..c23f18f55c 100644 --- a/packages/client/src/components/BlockComponent.svelte +++ b/packages/client/src/components/BlockComponent.svelte @@ -30,6 +30,6 @@ } - + diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 346de98f2f..443691595e 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -17,6 +17,7 @@ export let instance = {} export let isLayout = false export let isScreen = false + export let isBlock = false // The enriched component settings let enrichedSettings @@ -44,7 +45,6 @@ // Get contexts const context = getContext("context") const insideScreenslot = !!getContext("screenslot") - const insideBlock = !!getContext("block") // Create component context const componentStore = writable({}) @@ -69,7 +69,7 @@ $: interactive = $builderStore.inBuilder && ($builderStore.previewType === "layout" || insideScreenslot) && - !insideBlock + !isBlock $: draggable = interactive && !isLayout && !isScreen $: droppable = interactive && !isLayout && !isScreen @@ -262,6 +262,7 @@ class:droppable class:empty class:interactive + class:block={isBlock} data-id={id} data-name={name} > @@ -272,7 +273,7 @@ {/each} {:else if emptyState} - {:else if insideBlock} + {:else if isBlock} {/if} diff --git a/packages/client/src/components/app/blocks/DataBlock.svelte b/packages/client/src/components/app/blocks/DataBlock.svelte index e69de29bb2..935de48cbc 100644 --- a/packages/client/src/components/app/blocks/DataBlock.svelte +++ b/packages/client/src/components/app/blocks/DataBlock.svelte @@ -0,0 +1,60 @@ + + + +
    + + {#if $component.empty} + + {:else} + + + + {/if} + +
    +
    diff --git a/packages/client/src/components/app/blocks/index.js b/packages/client/src/components/app/blocks/index.js index af238b901d..56d2fcbd01 100644 --- a/packages/client/src/components/app/blocks/index.js +++ b/packages/client/src/components/app/blocks/index.js @@ -1,2 +1,3 @@ export { default as tableblock } from "./TableBlock.svelte" export { default as cardsblock } from "./CardsBlock.svelte" +export { default as datablock } from "./DataBlock.svelte" From 04e8c4a93204e5eb9c6c2b4c3cbb15ea03aaa9be Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 12 Nov 2021 15:27:42 +0000 Subject: [PATCH 05/11] Clafify comments --- packages/client/src/api/datasources.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/api/datasources.js b/packages/client/src/api/datasources.js index cea4ae0f3b..981d8301ca 100644 --- a/packages/client/src/api/datasources.js +++ b/packages/client/src/api/datasources.js @@ -55,7 +55,7 @@ export const fetchDatasourceSchema = async dataSource => { return dataSource.value?.schema } - // Field sources will have their schema statically defined by the builder + // Field sources have their schema statically defined if (type === "field") { if (dataSource.fieldType === "attachment") { return { From cd94f72faaeb089353e3fb7b4de2cd10a348ad16 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 12 Nov 2021 15:28:08 +0000 Subject: [PATCH 06/11] Replace manual usage of square brackets with string-templates makePropSafe util --- packages/client/src/components/app/blocks/CardsBlock.svelte | 5 +++-- packages/client/src/components/app/blocks/DataBlock.svelte | 3 ++- packages/client/src/components/app/blocks/TableBlock.svelte | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/client/src/components/app/blocks/CardsBlock.svelte b/packages/client/src/components/app/blocks/CardsBlock.svelte index 9eccb2b2d1..1a8df189af 100644 --- a/packages/client/src/components/app/blocks/CardsBlock.svelte +++ b/packages/client/src/components/app/blocks/CardsBlock.svelte @@ -3,6 +3,7 @@ import Block from "components/Block.svelte" import BlockComponent from "components/BlockComponent.svelte" import { Heading } from "@budibase/bbui" + import { makePropSafe as safe } from "@budibase/string-templates" export let title export let dataSource @@ -103,7 +104,7 @@ } const col = linkColumn || "_id" const split = url.split("/:") - return `${split[0]}/{{ [${repeaterId}].[${col}] }}` + return `${split[0]}/{{ ${safe(repeaterId)}.${safe(col)} }}` } // Load the datasource schema on mount so we can determine column types @@ -171,7 +172,7 @@ bind:id={repeaterId} context="repeater" props={{ - dataProvider: `{{ literal [${dataProviderId}] }}`, + dataProvider: `{{ literal ${safe(dataProviderId)} }}`, direction: "row", hAlign: "stretch", vAlign: "top", diff --git a/packages/client/src/components/app/blocks/DataBlock.svelte b/packages/client/src/components/app/blocks/DataBlock.svelte index 935de48cbc..413d1df65e 100644 --- a/packages/client/src/components/app/blocks/DataBlock.svelte +++ b/packages/client/src/components/app/blocks/DataBlock.svelte @@ -3,6 +3,7 @@ import Block from "components/Block.svelte" import Placeholder from "components/app/Placeholder.svelte" import { getContext } from "svelte" + import { makePropSafe as safe } from "@budibase/string-templates" export let dataSource export let filter @@ -44,7 +45,7 @@ type="repeater" context="repeater" props={{ - dataProvider: `{{ literal [${providerId}] }}`, + dataProvider: `{{ literal ${safe(providerId)} }}`, noRowsMessage, direction, hAlign, diff --git a/packages/client/src/components/app/blocks/TableBlock.svelte b/packages/client/src/components/app/blocks/TableBlock.svelte index ac2a36adc7..255cbf44cf 100644 --- a/packages/client/src/components/app/blocks/TableBlock.svelte +++ b/packages/client/src/components/app/blocks/TableBlock.svelte @@ -3,6 +3,7 @@ import Block from "components/Block.svelte" import BlockComponent from "components/BlockComponent.svelte" import { Heading } from "@budibase/bbui" + import { makePropSafe as safe } from "@budibase/string-templates" export let title export let dataSource @@ -61,7 +62,7 @@ operator: column.type === "string" ? "string" : "equal", type: "string", valueType: "Binding", - value: `{{ [${formId}].[${column.name}] }}`, + value: `{{ ${safe(formId)}.${safe(column.name)} }}`, }) }) return enrichedFilter @@ -147,7 +148,7 @@ Date: Mon, 15 Nov 2021 12:25:01 +0000 Subject: [PATCH 07/11] Update data sources to correctly include block context suffixes in provider IDs --- packages/builder/src/builderStore/dataBinding.js | 8 ++++---- .../PropertyControls/DataSourceSelect.svelte | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index e63e922f4f..9a41ad2afc 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -207,11 +207,11 @@ const getProviderContextBindings = (asset, dataProviders) => { const keys = Object.keys(schema).sort() // Generate safe unique runtime prefix - let runtimeId = component._id + let providerId = component._id if (runtimeSuffix) { - runtimeId += `-${runtimeSuffix}` + providerId += `-${runtimeSuffix}` } - const safeComponentId = makePropSafe(runtimeId) + const safeComponentId = makePropSafe(providerId) // Create bindable properties for each schema field keys.forEach(key => { @@ -235,7 +235,7 @@ const getProviderContextBindings = (asset, dataProviders) => { // Field schema and provider are required to construct relationship // datasource options, based on bindable properties fieldSchema, - providerId: component._id, + providerId, }) }) }) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte index f12710e70d..bc15110c09 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte @@ -89,8 +89,8 @@ $: fields = bindings .filter(x => arrayTypes.includes(x.fieldSchema?.type)) .map(binding => { - const { providerId, readableBinding, fieldSchema } = binding || {} - const { name, type, tableId } = fieldSchema || {} + const { providerId, readableBinding, runtimeBinding } = binding + const { name, type, tableId } = binding.fieldSchema return { providerId, label: readableBinding, @@ -98,7 +98,7 @@ fieldType: type, tableId, type: "field", - value: `{{ literal ${safe(providerId)}.${safe(name)} }}`, + value: `{{ literal ${runtimeBinding} }}`, } }) From 9b05990418c0ce421074a94fda92271c015429fa Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 15 Nov 2021 12:25:30 +0000 Subject: [PATCH 08/11] Update literal helper to return an empty string rather than the string 'undefined' when the value is undefined --- packages/string-templates/src/helpers/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/string-templates/src/helpers/index.js b/packages/string-templates/src/helpers/index.js index b43fef44dc..6b9195047e 100644 --- a/packages/string-templates/src/helpers/index.js +++ b/packages/string-templates/src/helpers/index.js @@ -46,6 +46,9 @@ const HELPERS = [ }), // adds a note for post-processor new Helper(HelperFunctionNames.LITERAL, value => { + if (value === undefined) { + return "" + } const type = typeof value const outputVal = type === "object" ? JSON.stringify(value) : value return `{{${LITERAL_MARKER} ${type}-${outputVal}}}` From 1b4e95ed3c9419b44eb8a14d8051d1dd53a7aa73 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 15 Nov 2021 12:26:13 +0000 Subject: [PATCH 09/11] Be even more explicit about expecting an array data type for data provider rows --- packages/client/src/components/app/DataProvider.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/app/DataProvider.svelte b/packages/client/src/components/app/DataProvider.svelte index 0b9cbac4dd..68f6cc6c07 100644 --- a/packages/client/src/components/app/DataProvider.svelte +++ b/packages/client/src/components/app/DataProvider.svelte @@ -188,7 +188,7 @@ // Field sources will be available from context. // Enrich non object elements into object to ensure a valid schema. const data = dataSource?.value || [] - if (data[0] && typeof data[0] !== "object") { + if (Array.isArray(data) && data[0] && typeof data[0] !== "object") { allRows = data.map(value => ({ value })) } else { allRows = data From 9e94df969decb30956142930dd84da889bcdab33 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 15 Nov 2021 18:02:24 +0000 Subject: [PATCH 10/11] Remove unused prop --- .../PropertiesPanel/PropertyControls/PropertyControl.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte index 72b54f3b96..911688b30c 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte @@ -6,7 +6,6 @@ } from "builderStore/dataBinding" export let label = "" - export let bindable = true export let componentInstance = {} export let control = null export let key = "" From b1a2bb59a6db6b71b922f35967843a4159cea8fd Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 15 Nov 2021 18:07:51 +0000 Subject: [PATCH 11/11] Rename data block to repeater block --- .../src/components/design/AppPreview/componentStructure.json | 2 +- packages/client/manifest.json | 4 ++-- .../app/blocks/{DataBlock.svelte => RepeaterBlock.svelte} | 0 packages/client/src/components/app/blocks/index.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename packages/client/src/components/app/blocks/{DataBlock.svelte => RepeaterBlock.svelte} (100%) diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json index c602000a03..357ea5a7be 100644 --- a/packages/builder/src/components/design/AppPreview/componentStructure.json +++ b/packages/builder/src/components/design/AppPreview/componentStructure.json @@ -5,7 +5,7 @@ "children": [ "tableblock", "cardsblock", - "datablock" + "repeaterblock" ] }, "section", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index eec7b82c5c..125dbb8db3 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2933,8 +2933,8 @@ "suffix": "repeater" } }, - "datablock": { - "name": "Data block", + "repeaterblock": { + "name": "Repeater block", "icon": "ViewList", "illegalChildren": ["section"], "hasChildren": true, diff --git a/packages/client/src/components/app/blocks/DataBlock.svelte b/packages/client/src/components/app/blocks/RepeaterBlock.svelte similarity index 100% rename from packages/client/src/components/app/blocks/DataBlock.svelte rename to packages/client/src/components/app/blocks/RepeaterBlock.svelte diff --git a/packages/client/src/components/app/blocks/index.js b/packages/client/src/components/app/blocks/index.js index 56d2fcbd01..db4de8fc13 100644 --- a/packages/client/src/components/app/blocks/index.js +++ b/packages/client/src/components/app/blocks/index.js @@ -1,3 +1,3 @@ export { default as tableblock } from "./TableBlock.svelte" export { default as cardsblock } from "./CardsBlock.svelte" -export { default as datablock } from "./DataBlock.svelte" +export { default as repeaterblock } from "./RepeaterBlock.svelte"