Clean up and improve multi step form block
This commit is contained in:
parent
01c8ef9f0f
commit
69ea28ad46
|
@ -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,
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -6095,6 +6095,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "static",
|
"type": "static",
|
||||||
|
"suffix": "form",
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"label": "Value",
|
"label": "Value",
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue