Clean up and improve multi step form block

This commit is contained in:
Andrew Kingston 2023-12-12 20:22:48 +00:00
parent 01c8ef9f0f
commit 69ea28ad46
6 changed files with 104 additions and 113 deletions

View File

@ -465,8 +465,8 @@ const filterCategoryByContext = (component, context) => {
const { _component } = component const { _component } = component
if (_component.endsWith("formblock")) { if (_component.endsWith("formblock")) {
if ( if (
(component.actionType == "Create" && context.type === "schema") || (component.actionType === "Create" && context.type === "schema") ||
(component.actionType == "View" && context.type === "form") (component.actionType === "View" && context.type === "form")
) { ) {
return false return false
} }
@ -474,20 +474,21 @@ const filterCategoryByContext = (component, context) => {
return true return true
} }
// Enrich binding category information for certain components
const getComponentBindingCategory = (component, context, def) => { const getComponentBindingCategory = (component, context, def) => {
let icon = def.icon let icon = def.icon
let category = component._instanceName let category = component._instanceName
if (component._component.endsWith("formblock")) { if (component._component.endsWith("formblock")) {
let contextCategorySuffix = { if (context.type === "form") {
form: "Fields", category = `${component._instanceName} - Fields`
schema: "Row", 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 { return {
icon, icon,
category, category,

View File

@ -1289,15 +1289,14 @@ export const getFrontendStore = () => {
const settings = getComponentSettings(component._component) const settings = getComponentSettings(component._component)
const updatedSetting = settings.find(setting => setting.key === name) const updatedSetting = settings.find(setting => setting.key === name)
// Can be a single string or array of strings // Reset dependent fields
const resetFields = settings.filter(setting => { settings.forEach(setting => {
return ( const needsReset =
name === setting.resetOn || name === setting.resetOn ||
(Array.isArray(setting.resetOn) && setting.resetOn.includes(name)) (Array.isArray(setting.resetOn) && setting.resetOn.includes(name))
) if (needsReset) {
}) component[setting.key] = setting.defaultValue || null
resetFields?.forEach(setting => { }
component[setting.key] = null
}) })
if ( if (

View File

@ -5,7 +5,7 @@
import { currentAsset, store } from "builderStore" import { currentAsset, store } from "builderStore"
import { Helpers } from "@budibase/bbui" import { Helpers } from "@budibase/bbui"
import { writable } from "svelte/store" 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 componentInstance
export let componentBindings export let componentBindings
@ -20,18 +20,18 @@
setContext("multi-step-form-block", multiStepStore) setContext("multi-step-form-block", multiStepStore)
$: currentStep = $multiStepStore.currentStep $: defaultProps = Utils.buildMultiStepFormBlockDefaultProps({
$: stepCount = value?.length || 0
$: multiStepStore.update(state => ({ ...state, stepCount }))
$: defaultButtonConfig = buildMultiStepFormBlockButtonConfig({
_id: componentInstance._id, _id: componentInstance._id,
stepCount: stepCount, stepCount: stepCount,
currentStep: currentStep, currentStep: currentStep,
}) })
$: currentStep = $multiStepStore.currentStep
$: stepCount = value?.length || 0
$: multiStepStore.update(state => ({ ...state, stepCount }))
$: dataSource = getDatasourceForProvider($currentAsset, componentInstance) $: dataSource = getDatasourceForProvider($currentAsset, componentInstance)
$: emitCurrentStep(currentStep) $: emitCurrentStep(currentStep)
$: sectionName = getSectionName($multiStepStore) $: sectionName = getSectionName($multiStepStore)
$: stepConfigInstance = buildPseudoInstance(value[currentStep] || {}) $: stepInstance = buildPseudoInstance(value[currentStep], defaultProps)
$: stepDef = { $: stepDef = {
settings: [ settings: [
{ {
@ -150,14 +150,15 @@
} }
} }
const buildPseudoInstance = ({ buttons, fields, title, desc }) => { const buildPseudoInstance = (instance, defaultProps) => {
const { buttons, fields, title, desc } = instance || {}
return { return {
_id: Helpers.uuid(), _id: Helpers.uuid(),
_component: "@budibase/standard-components/multistepformblockstep", _component: "@budibase/standard-components/multistepformblockstep",
_instanceName: `Step ${currentStep + 1}`, _instanceName: `Step ${currentStep + 1}`,
buttons: buttons || defaultButtonConfig, title: title ?? defaultProps.title,
buttons: buttons || defaultProps.buttons,
fields, fields,
title,
desc, desc,
// Needed for field configuration // Needed for field configuration
@ -169,7 +170,7 @@
<div class="nested-section"> <div class="nested-section">
<ComponentSettingsSection <ComponentSettingsSection
includeHidden includeHidden
componentInstance={stepConfigInstance} componentInstance={stepInstance}
componentDefinition={stepDef} componentDefinition={stepDef}
onUpdateSetting={processUpdate} onUpdateSetting={processUpdate}
showInstanceName={false} showInstanceName={false}

View File

@ -6095,6 +6095,7 @@
}, },
{ {
"type": "static", "type": "static",
"suffix": "form",
"values": [ "values": [
{ {
"label": "Value", "label": "Value",

View File

@ -13,56 +13,6 @@
const { fetchDatasourceSchema } = getContext("sdk") const { fetchDatasourceSchema } = getContext("sdk")
const component = getContext("component") const component = getContext("component")
let schema
let formId
const getCurrentStep = () => {
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 = { const FieldTypeToComponentMap = {
string: "stringfield", string: "stringfield",
number: "numberfield", number: "numberfield",
@ -79,6 +29,35 @@
bb_reference: "bbreferencefield", 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 getComponentForField = field => {
const fieldSchemaName = field.field || field.name const fieldSchemaName = field.field || field.name
if (!fieldSchemaName || !schema?.[fieldSchemaName]) { if (!fieldSchemaName || !schema?.[fieldSchemaName]) {
@ -92,24 +71,37 @@
schema = (await fetchDatasourceSchema(dataSource)) || {} schema = (await fetchDatasourceSchema(dataSource)) || {}
} }
$: stepProps = steps?.map((step, idx) => { const getDefaultFields = (fields, schema) => {
const { title, desc, fields, buttons } = step if (fields?.length) {
return { return fields.filter(field => field.active)
fields: getDefaultFields(fields || [], schema),
title,
desc,
buttons:
buttons ||
Utils.buildMultiStepFormBlockButtonConfig({
_id: $component.id,
stepCount: steps?.length ?? 0,
currentStep: idx,
}),
} }
}) 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,
}
})
}
</script> </script>
{#key stepProps} {#key enrichedSteps}
<Block> <Block>
<BlockComponent <BlockComponent
type="form" type="form"
@ -119,9 +111,8 @@
step: $builderStore.inBuilder === true ? currentStep + 1 : null, step: $builderStore.inBuilder === true ? currentStep + 1 : null,
}} }}
context="form" context="form"
bind:id={formId}
> >
{#each steps || [] as step, idx ("step" + step._id)} {#each enrichedSteps as step, idx}
<BlockComponent <BlockComponent
type="formstep" type="formstep"
props={{ step: idx + 1, _instanceName: `Step ${idx + 1}` }} props={{ step: idx + 1, _instanceName: `Step ${idx + 1}` }}
@ -143,39 +134,32 @@
size: "shrink", size: "shrink",
}} }}
> >
<BlockComponent type="container"> <BlockComponent type="container" order={0}>
<BlockComponent <BlockComponent type="heading" props={{ text: step.title }} />
type="heading"
props={{ text: stepProps?.[idx]?.title }}
/>
</BlockComponent> </BlockComponent>
<BlockComponent type="text" props={{ text: step.desc }} order={1} />
<BlockComponent <BlockComponent type="fieldgroup" order={2}>
type="text" {#each step.fields as field, fieldIdx}
props={{ text: stepProps?.[idx]?.desc }} {#if getComponentForField(field)}
/>
<BlockComponent type="fieldgroup">
{#each stepProps?.[idx]?.fields || [] as field, fieldIdx ("field_" + fieldIdx)}
{#if getComponentForField(field) && field.active}
<BlockComponent <BlockComponent
type={getComponentForField(field)} type={getComponentForField(field)}
props={getPropsForField(field)} props={getPropsForField(field)}
order={idx} order={fieldIdx}
interactive interactive
name={field?.field} name={field.field}
/> />
{/if} {/if}
{/each} {/each}
</BlockComponent> </BlockComponent>
<BlockComponent <BlockComponent
type="buttongroup" type="buttongroup"
props={{ buttons: stepProps?.[idx]?.buttons }} props={{ buttons: step.buttons }}
styles={{ styles={{
normal: { normal: {
"margin-top": "16px", "margin-top": "16px",
}, },
}} }}
order={3}
/> />
</BlockComponent> </BlockComponent>
</BlockComponent> </BlockComponent>

View File

@ -227,7 +227,7 @@ export const buildFormBlockButtonConfig = props => {
}) })
} }
if (actionType == "Update" && showDeleteButton !== false) { if (actionType === "Update" && showDeleteButton !== false) {
defaultButtons.push({ defaultButtons.push({
text: deleteText || "Delete", text: deleteText || "Delete",
_id: Helpers.uuid(), _id: Helpers.uuid(),
@ -241,7 +241,7 @@ export const buildFormBlockButtonConfig = props => {
return defaultButtons return defaultButtons
} }
export const buildMultiStepFormBlockButtonConfig = props => { export const buildMultiStepFormBlockDefaultProps = props => {
const { _id, stepCount, currentStep } = props || {} const { _id, stepCount, currentStep } = props || {}
// Sanity check // Sanity check
@ -249,6 +249,8 @@ export const buildMultiStepFormBlockButtonConfig = props => {
return return
} }
// Default the title to "Step X"
const title = `Step {{ [${_id}-form].[__currentStep] }}`
let buttons = [] let buttons = []
// Add previous step button if we aren't the first step // Add previous step button if we aren't the first step
@ -319,5 +321,8 @@ export const buildMultiStepFormBlockButtonConfig = props => {
}) })
} }
return buttons return {
buttons,
title,
}
} }