From 69ea28ad46e0ff3467535a36defc13390b39eb3b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 12 Dec 2023 20:22:48 +0000 Subject: [PATCH] Clean up and improve multi step form block --- .../builder/src/builderStore/dataBinding.js | 19 +-- .../src/builderStore/store/frontend.js | 13 +- .../controls/FormStepConfiguration.svelte | 21 +-- packages/client/manifest.json | 1 + .../app/blocks/MultiStepFormblock.svelte | 152 ++++++++---------- packages/frontend-core/src/utils/utils.js | 11 +- 6 files changed, 104 insertions(+), 113 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index d86e94aba2..52368a0723 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -465,8 +465,8 @@ const filterCategoryByContext = (component, context) => { const { _component } = component if (_component.endsWith("formblock")) { if ( - (component.actionType == "Create" && context.type === "schema") || - (component.actionType == "View" && context.type === "form") + (component.actionType === "Create" && context.type === "schema") || + (component.actionType === "View" && context.type === "form") ) { return false } @@ -474,20 +474,21 @@ const filterCategoryByContext = (component, context) => { return true } +// Enrich binding category information for certain components const getComponentBindingCategory = (component, context, def) => { let icon = def.icon let category = component._instanceName if (component._component.endsWith("formblock")) { - let contextCategorySuffix = { - form: "Fields", - schema: "Row", + if (context.type === "form") { + category = `${component._instanceName} - Fields` + icon = "Form" + } else if (context.type === "schema") { + category = `${component._instanceName} - Row` + icon = "Data" } - category = `${component._instanceName} - ${ - contextCategorySuffix[context.type] - }` - icon = context.type === "form" ? "Form" : "Data" } + return { icon, category, diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 7a72b7a9c3..2d62a0667e 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -1289,15 +1289,14 @@ export const getFrontendStore = () => { const settings = getComponentSettings(component._component) const updatedSetting = settings.find(setting => setting.key === name) - // Can be a single string or array of strings - const resetFields = settings.filter(setting => { - return ( + // Reset dependent fields + settings.forEach(setting => { + const needsReset = name === setting.resetOn || (Array.isArray(setting.resetOn) && setting.resetOn.includes(name)) - ) - }) - resetFields?.forEach(setting => { - component[setting.key] = null + if (needsReset) { + component[setting.key] = setting.defaultValue || null + } }) if ( diff --git a/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte b/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte index 8e37d1b058..184057e45e 100644 --- a/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte +++ b/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte @@ -5,7 +5,7 @@ import { currentAsset, store } from "builderStore" import { Helpers } from "@budibase/bbui" import { writable } from "svelte/store" - import { buildMultiStepFormBlockButtonConfig } from "@budibase/frontend-core/src/utils/utils" + import { Utils } from "@budibase/frontend-core" export let componentInstance export let componentBindings @@ -20,18 +20,18 @@ setContext("multi-step-form-block", multiStepStore) - $: currentStep = $multiStepStore.currentStep - $: stepCount = value?.length || 0 - $: multiStepStore.update(state => ({ ...state, stepCount })) - $: defaultButtonConfig = buildMultiStepFormBlockButtonConfig({ + $: defaultProps = Utils.buildMultiStepFormBlockDefaultProps({ _id: componentInstance._id, stepCount: stepCount, currentStep: currentStep, }) + $: currentStep = $multiStepStore.currentStep + $: stepCount = value?.length || 0 + $: multiStepStore.update(state => ({ ...state, stepCount })) $: dataSource = getDatasourceForProvider($currentAsset, componentInstance) $: emitCurrentStep(currentStep) $: sectionName = getSectionName($multiStepStore) - $: stepConfigInstance = buildPseudoInstance(value[currentStep] || {}) + $: stepInstance = buildPseudoInstance(value[currentStep], defaultProps) $: stepDef = { settings: [ { @@ -150,14 +150,15 @@ } } - const buildPseudoInstance = ({ buttons, fields, title, desc }) => { + const buildPseudoInstance = (instance, defaultProps) => { + const { buttons, fields, title, desc } = instance || {} return { _id: Helpers.uuid(), _component: "@budibase/standard-components/multistepformblockstep", _instanceName: `Step ${currentStep + 1}`, - buttons: buttons || defaultButtonConfig, + title: title ?? defaultProps.title, + buttons: buttons || defaultProps.buttons, fields, - title, desc, // Needed for field configuration @@ -169,7 +170,7 @@
{ - if ($builderStore?.component?._id === $component.id) { - return $builderStore?.component.step - } - return 0 - } - - $: currentStep = getCurrentStep( - $builderStore?.component?._id, - componentInstance - ) - - $: fetchSchema(dataSource) - - const getPropsForField = field => { - let fieldProps = field._component - ? { - ...field, - } - : { - field: field.name, - label: field.name, - placeholder: field.name, - _instanceName: field.name, - } - return fieldProps - } - - const getDefaultFields = (fields, schema) => { - if (!schema) { - return [] - } - let defaultFields = [] - - if (!fields || fields.length === 0) { - Object.values(schema) - .filter(field => !field.autocolumn) - .forEach(field => { - defaultFields.push({ - name: field.name, - active: true, - }) - }) - } - return [...fields, ...defaultFields].filter(field => field.active) - } - const FieldTypeToComponentMap = { string: "stringfield", number: "numberfield", @@ -79,6 +29,35 @@ bb_reference: "bbreferencefield", } + let schema + + $: fetchSchema(dataSource) + $: enrichedSteps = enrichSteps(steps, schema, $component.id) + $: currentStep = getCurrentStep( + $builderStore?.component?._id, + componentInstance + ) + + const getCurrentStep = () => { + if ($builderStore?.component?._id === $component.id) { + return $builderStore?.component.step + } + return 0 + } + + const getPropsForField = field => { + return field._component + ? { + ...field, + } + : { + field: field.name, + label: field.name, + placeholder: field.name, + _instanceName: field.name, + } + } + const getComponentForField = field => { const fieldSchemaName = field.field || field.name if (!fieldSchemaName || !schema?.[fieldSchemaName]) { @@ -92,24 +71,37 @@ schema = (await fetchDatasourceSchema(dataSource)) || {} } - $: stepProps = steps?.map((step, idx) => { - const { title, desc, fields, buttons } = step - return { - fields: getDefaultFields(fields || [], schema), - title, - desc, - buttons: - buttons || - Utils.buildMultiStepFormBlockButtonConfig({ - _id: $component.id, - stepCount: steps?.length ?? 0, - currentStep: idx, - }), + const getDefaultFields = (fields, schema) => { + if (fields?.length) { + return fields.filter(field => field.active) } - }) + return Object.values(schema || {}) + .filter(field => !field.autocolumn) + .map(field => ({ + name: field.name, + })) + } + + const enrichSteps = (steps, schema, id) => { + const safeSteps = steps?.length ? steps : [{}] + return safeSteps.map((step, idx) => { + const { title, desc, fields, buttons } = step + const defaultProps = Utils.buildMultiStepFormBlockDefaultProps({ + _id: id, + stepCount: safeSteps.length, + currentStep: idx, + }) + return { + fields: getDefaultFields(fields || [], schema), + title: title ?? defaultProps.title, + desc, + buttons: buttons || defaultProps.buttons, + } + }) + } -{#key stepProps} +{#key enrichedSteps} - {#each steps || [] as step, idx ("step" + step._id)} + {#each enrichedSteps as step, idx} - - + + - - - - - {#each stepProps?.[idx]?.fields || [] as field, fieldIdx ("field_" + fieldIdx)} - {#if getComponentForField(field) && field.active} + + + {#each step.fields as field, fieldIdx} + {#if getComponentForField(field)} {/if} {/each} diff --git a/packages/frontend-core/src/utils/utils.js b/packages/frontend-core/src/utils/utils.js index 84244f6bc4..7c3dc2f3b5 100644 --- a/packages/frontend-core/src/utils/utils.js +++ b/packages/frontend-core/src/utils/utils.js @@ -227,7 +227,7 @@ export const buildFormBlockButtonConfig = props => { }) } - if (actionType == "Update" && showDeleteButton !== false) { + if (actionType === "Update" && showDeleteButton !== false) { defaultButtons.push({ text: deleteText || "Delete", _id: Helpers.uuid(), @@ -241,7 +241,7 @@ export const buildFormBlockButtonConfig = props => { return defaultButtons } -export const buildMultiStepFormBlockButtonConfig = props => { +export const buildMultiStepFormBlockDefaultProps = props => { const { _id, stepCount, currentStep } = props || {} // Sanity check @@ -249,6 +249,8 @@ export const buildMultiStepFormBlockButtonConfig = props => { return } + // Default the title to "Step X" + const title = `Step {{ [${_id}-form].[__currentStep] }}` let buttons = [] // Add previous step button if we aren't the first step @@ -319,5 +321,8 @@ export const buildMultiStepFormBlockButtonConfig = props => { }) } - return buttons + return { + buttons, + title, + } }