From d94473bca56168f723736d7706451d208ebef0a9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 19 Jan 2021 17:38:24 +0000 Subject: [PATCH] Update button actions and remove deprecated code --- .../builder/src/builderStore/dataBinding.js | 134 +++++++++++------- .../EventsEditor/actions/CreateRow.svelte | 53 ------- .../EventsEditor/actions/DeleteRow.svelte | 51 +++---- .../EventsEditor/actions/SaveRow.svelte | 93 +++--------- .../EventsEditor/actions/UpdateRow.svelte | 127 ----------------- packages/client/src/utils/buttonActions.js | 50 ++++--- packages/standard-components/src/Form.svelte | 4 +- 7 files changed, 153 insertions(+), 359 deletions(-) delete mode 100644 packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CreateRow.svelte delete mode 100644 packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/UpdateRow.svelte diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index fb2bc62935..7d3f390220 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -1,3 +1,4 @@ +import { cloneDeep } from "lodash/fp" import { get } from "svelte/store" import { backendUiStore, store } from "builderStore" import { findAllMatchingComponents, findComponentPath } from "./storeUtils" @@ -15,10 +16,9 @@ export const getBindableProperties = (rootComponent, componentId) => { } /** - * Gets all bindable data contexts. These are fields of schemas of data contexts - * provided by data provider components, such as lists or row detail components. + * Gets all data provider components above a component. */ -export const getBindableContexts = (rootComponent, componentId) => { +export const getDataProviderComponents = (rootComponent, componentId) => { if (!rootComponent || !componentId) { return [] } @@ -28,43 +28,67 @@ export const getBindableContexts = (rootComponent, componentId) => { const path = findComponentPath(rootComponent, componentId) path.pop() - // Enrich components with their definitions - const enriched = path.map(component => ({ - instance: component, - definition: store.actions.components.getDefinition(component._component), - })) + // Filter by only data provider components + return path.filter(component => { + const def = store.actions.components.getDefinition(component._component) + return def?.dataProvider + }) +} + +/** + * Gets a datasource object for a certain data provider component + */ +export const getDatasourceForProvider = component => { + const def = store.actions.components.getDefinition(component?._component) + if (!def) { + return null + } + + // Extract datasource from component instance + const datasourceSetting = def.settings.find(setting => { + return setting.key === def.datasourceSetting + }) + if (!datasourceSetting) { + return null + } + + // There are different types of setting which can be a datasource, for + // example an actual datasource object, or a table ID string. + // Convert the datasource setting into a proper datasource object so that + // we can use it properly + if (datasourceSetting.type === "datasource") { + return component[datasourceSetting?.key] + } else if (datasourceSetting.type === "table") { + return { + tableId: component[datasourceSetting?.key], + type: "table", + } + } + return null +} + +/** + * Gets all bindable data contexts. These are fields of schemas of data contexts + * provided by data provider components, such as lists or row detail components. + */ +export const getBindableContexts = (rootComponent, componentId) => { + const dataProviders = getDataProviderComponents(rootComponent, componentId) // Extract any components which provide data contexts - const providers = enriched.filter(comp => comp.definition?.dataProvider) let contexts = [] - providers.forEach(({ definition, instance }) => { - // Extract datasource from component instance - const datasourceSetting = definition.settings.find(setting => { - return setting.key === definition.datasourceSetting - }) - if (!datasourceSetting) { - return - } - - // There are different types of setting which can be a datasource, for - // example an actual datasource object, or a table ID string. - // Convert the datasource setting into a proper datasource object so that - // we can use it properly - let datasource - if (datasourceSetting.type === "datasource") { - datasource = instance[datasourceSetting?.key] - } else if (datasourceSetting.type === "table") { - datasource = { - tableId: instance[datasourceSetting?.key], - type: "table", - } - } + dataProviders.forEach(component => { + const datasource = getDatasourceForProvider(component) if (!datasource) { return } - const { schema, table } = getSchemaForDatasource(datasource) + // Get schema and add _id and _rev fields + let { schema, table } = getSchemaForDatasource(datasource) + schema["_id"] = { type: "string" } + schema["_rev"] = { type: "string " } const keys = Object.keys(schema).sort() + + // Create bindable properties for each schema field keys.forEach(key => { const fieldSchema = schema[key] // Replace certain bindings with a new property to help display components @@ -77,11 +101,12 @@ export const getBindableContexts = (rootComponent, componentId) => { contexts.push({ type: "context", - runtimeBinding: `${instance._id}.${runtimeBoundKey}`, - readableBinding: `${instance._instanceName}.${table.name}.${key}`, + runtimeBinding: `${component._id}.${runtimeBoundKey}`, + readableBinding: `${component._instanceName}.${table.name}.${key}`, fieldSchema, - providerId: instance._id, + providerId: component._id, tableId: datasource.tableId, + field: key, }) }) }) @@ -115,27 +140,22 @@ export const getBindableComponents = rootComponent => { /** * Gets a schema for a datasource object. */ -const getSchemaForDatasource = datasource => { - const tables = get(backendUiStore).tables - const { type } = datasource - const table = tables.find(table => table._id === datasource.tableId) - let schema - if (table) { - if (type === "table") { - schema = table.schema ?? {} - } else if (type === "view") { - schema = table.views?.[datasource.name]?.schema ?? {} - } else if (type === "link") { - schema = table.schema ?? {} +export const getSchemaForDatasource = datasource => { + let schema, table + if (datasource) { + const tables = get(backendUiStore).tables + const { type } = datasource + table = tables.find(table => table._id === datasource.tableId) + if (table) { + if (type === "table") { + schema = cloneDeep(table.schema) + } else if (type === "view") { + schema = cloneDeep(table.views?.[datasource.name]?.schema) + } else if (type === "link") { + schema = cloneDeep(table.schema) + } } } - if (schema) { - // Add ID and rev fields for any valid datasources - schema["_id"] = { type: "string" } - schema["_rev"] = { type: "string " } - } else { - schema = {} - } return { schema, table } } @@ -143,6 +163,9 @@ const getSchemaForDatasource = datasource => { * Converts a readable data binding into a runtime data binding */ export function readableToRuntimeBinding(bindableProperties, textWithBindings) { + if (typeof textWithBindings !== "string") { + return textWithBindings + } const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE) || [] let result = textWithBindings boundValues.forEach(boundValue => { @@ -160,6 +183,9 @@ export function readableToRuntimeBinding(bindableProperties, textWithBindings) { * Converts a runtime data binding into a readable data binding */ export function runtimeToReadableBinding(bindableProperties, textWithBindings) { + if (typeof textWithBindings !== "string") { + return textWithBindings + } const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE) || [] let result = textWithBindings boundValues.forEach(boundValue => { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CreateRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CreateRow.svelte deleted file mode 100644 index a23abfc9ca..0000000000 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CreateRow.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - -
- - - - {#if parameters.tableId} - - {/if} -
- - diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte index 3dd0ec6752..e61fadd57b 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte @@ -1,51 +1,36 @@
- {#if idFields.length === 0} + {#if dataProviderComponents.length === 0}
Delete row can only be used within a component that provides data, such as a List @@ -54,9 +39,9 @@ diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte index 2a9b719685..4eef700ad0 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte @@ -1,77 +1,28 @@
- {#if idFields.length === 0} + {#if !dataProviderComponents.length}
- Update row can only be used within a component that provides data, such as - a List + Save Row can only be used within a component that provides data, such as a + Repeater
{:else} - + {#each dataProviderComponents as provider} + {/each} {/if} diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/UpdateRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/UpdateRow.svelte deleted file mode 100644 index b63a5c2d22..0000000000 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/UpdateRow.svelte +++ /dev/null @@ -1,127 +0,0 @@ - - -
- {#if idFields.length === 0} -
- Update row can only be used within a component that provides data, such as - a List -
- {:else} - - - {/if} - - {#if rowId} - - {/if} -
- - diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index b2caf83d1c..46be914f5c 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -1,39 +1,49 @@ +import { get } from "svelte/store" import { enrichDataBinding } from "./enrichDataBinding" -import { routeStore } from "../store" +import { routeStore, builderStore } from "../store" import { saveRow, deleteRow, triggerAutomation } from "../api" const saveRowHandler = async (action, context) => { - let draft = context[`${action.parameters.contextPath}_draft`] - if (action.parameters.fields) { - Object.entries(action.parameters.fields).forEach(([key, entry]) => { - draft[key] = enrichDataBinding(entry.value, context) - }) + const { fields, providerId } = action.parameters + if (providerId) { + let draft = context[`${action.parameters.providerId}_draft`] + if (fields) { + Object.entries(fields).forEach(([key, entry]) => { + draft[key] = enrichDataBinding(entry.value, context) + }) + } + await saveRow(draft) } - await saveRow(draft) } const deleteRowHandler = async (action, context) => { const { tableId, revId, rowId } = action.parameters - await deleteRow({ - tableId: enrichDataBinding(tableId, context), - rowId: enrichDataBinding(rowId, context), - revId: enrichDataBinding(revId, context), - }) + if (tableId && revId && rowId) { + await deleteRow({ + tableId: enrichDataBinding(tableId, context), + rowId: enrichDataBinding(rowId, context), + revId: enrichDataBinding(revId, context), + }) + } } const triggerAutomationHandler = async (action, context) => { const params = {} - for (let field in action.parameters.fields) { - params[field] = enrichDataBinding( - action.parameters.fields[field].value, - context - ) + if (action.parameters.fields) { + for (let field in action.parameters.fields) { + params[field] = enrichDataBinding( + action.parameters.fields[field].value, + context + ) + } } await triggerAutomation(action.parameters.automationId, params) } const navigationHandler = action => { - routeStore.actions.navigate(action.parameters.url) + if (action.parameters.url) { + routeStore.actions.navigate(action.parameters.url) + } } const handlerMap = { @@ -48,6 +58,10 @@ const handlerMap = { * actions in the current context. */ export const enrichButtonActions = (actions, context) => { + // Prevent button actions in the builder preview + if (get(builderStore).inBuilder) { + return () => {} + } const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]]) return async () => { for (let i = 0; i < handlers.length; i++) { diff --git a/packages/standard-components/src/Form.svelte b/packages/standard-components/src/Form.svelte index f868956dd9..0da894b31e 100644 --- a/packages/standard-components/src/Form.svelte +++ b/packages/standard-components/src/Form.svelte @@ -28,8 +28,8 @@ const getFormData = async context => { if (context) { const tableDefinition = await API.fetchTableDefinition(context.tableId) - schema = tableDefinition.schema - fields = Object.keys(schema) + schema = tableDefinition?.schema + fields = Object.keys(schema ?? {}) // Use the draft version for editing row = $dataContext[`${$dataContext.closestComponentId}_draft`]