Refactor form block layout and add functional update and view multi step forms

This commit is contained in:
Andrew Kingston 2023-12-13 13:09:57 +00:00
parent ac0f034ff4
commit 08cd5bbb91
6 changed files with 123 additions and 87 deletions

View File

@ -78,7 +78,7 @@
var(--spacing-xl); var(--spacing-xl);
} }
.property-panel.no-title { .property-panel.no-title {
padding-top: 0; padding-top: var(--spacing-xl);
} }
.show { .show {

View File

@ -32,21 +32,19 @@
const generalSettings = settings.filter( const generalSettings = settings.filter(
setting => !setting.section && setting.tag === tag setting => !setting.section && setting.tag === tag
) )
const customSections = settings.filter( const customSections = settings.filter(
setting => setting.section && setting.tag === tag setting => setting.section && setting.tag === tag
) )
let sections = [ let sections = []
...(generalSettings?.length if (generalSettings.length) {
? [ sections.push({
{
name: "General", name: "General",
settings: generalSettings, settings: generalSettings,
}, })
] }
: []), if (customSections.length) {
...(customSections || []), sections = sections.concat(customSections)
] }
// Filter out settings which shouldn't be rendered // Filter out settings which shouldn't be rendered
sections.forEach(section => { sections.forEach(section => {

View File

@ -1,10 +1,13 @@
<script> <script>
import BlockComponent from "components/BlockComponent.svelte" import BlockComponent from "components/BlockComponent.svelte"
import Block from "components/Block.svelte"
import { getContext } from "svelte" import { getContext } from "svelte"
import { builderStore } from "stores" import { builderStore } from "stores"
import { Utils } from "@budibase/frontend-core" import { Utils } from "@budibase/frontend-core"
import FormBlockWrapper from "./form/FormBlockWrapper.svelte"
export let actionType
export let rowId
export let noRowsMessage
export let steps export let steps
export let dataSource export let dataSource
export let initialFormStep = 1 export let initialFormStep = 1
@ -102,6 +105,8 @@
_id: id, _id: id,
stepCount: safeSteps.length, stepCount: safeSteps.length,
currentStep: idx, currentStep: idx,
actionType,
dataSource,
}) })
return { return {
fields: getDefaultFields(fields || [], schema), fields: getDefaultFields(fields || [], schema),
@ -113,20 +118,17 @@
} }
</script> </script>
<Block> <FormBlockWrapper {actionType} {dataSource} {rowId} {noRowsMessage}>
<BlockComponent <BlockComponent
type="form" type="form"
context="form"
props={{ props={{
dataSource, dataSource,
initialFormStep, initialFormStep,
step: currentStep, step: currentStep,
actionType: actionType === "Create" ? "Create" : "Update",
readonly: actionType === "View",
}} }}
context="form"
>
{#each enrichedSteps as step, idx}
<BlockComponent
type="formstep"
props={{ step: idx + 1, _instanceName: `Step ${idx + 1}` }}
styles={{ styles={{
normal: { normal: {
width: "600px", width: "600px",
@ -134,6 +136,11 @@
"margin-right": "auto", "margin-right": "auto",
}, },
}} }}
>
{#each enrichedSteps as step, idx}
<BlockComponent
type="formstep"
props={{ step: idx + 1, _instanceName: `Step ${idx + 1}` }}
> >
<BlockComponent <BlockComponent
type="container" type="container"
@ -176,4 +183,4 @@
</BlockComponent> </BlockComponent>
{/each} {/each}
</BlockComponent> </BlockComponent>
</Block> </FormBlockWrapper>

View File

@ -1,10 +1,8 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import BlockComponent from "components/BlockComponent.svelte"
import Block from "components/Block.svelte"
import { makePropSafe as safe } from "@budibase/string-templates"
import InnerFormBlock from "./InnerFormBlock.svelte" import InnerFormBlock from "./InnerFormBlock.svelte"
import { Utils } from "@budibase/frontend-core" import { Utils } from "@budibase/frontend-core"
import FormBlockWrapper from "./FormBlockWrapper.svelte"
export let actionType export let actionType
export let dataSource export let dataSource
@ -71,22 +69,10 @@
} }
let schema let schema
let providerId
let repeaterId
$: formattedFields = convertOldFieldFormat(fields) $: formattedFields = convertOldFieldFormat(fields)
$: fieldsOrDefault = getDefaultFields(formattedFields, schema) $: fieldsOrDefault = getDefaultFields(formattedFields, schema)
$: fetchSchema(dataSource) $: fetchSchema(dataSource)
$: dataProvider = `{{ literal ${safe(providerId)} }}`
$: filter = [
{
field: "_id",
operator: "equal",
type: "string",
value: !rowId ? `{{ ${safe("url")}.${safe("id")} }}` : rowId,
valueType: "Binding",
},
]
// We could simply spread $$props into the inner form and append our // We could simply spread $$props into the inner form and append our
// additions, but that would create svelte warnings about unused props and // additions, but that would create svelte warnings about unused props and
// make maintenance in future more confusing as we typically always have a // make maintenance in future more confusing as we typically always have a
@ -102,7 +88,6 @@
title, title,
description, description,
schema, schema,
repeaterId,
notificationOverride, notificationOverride,
buttons: buttons:
buttons || buttons ||
@ -124,43 +109,6 @@
} }
</script> </script>
<Block> <FormBlockWrapper {actionType} {dataSource} {rowId} {noRowsMessage}>
{#if actionType === "Create"}
<BlockComponent
type="container"
props={{
direction: "column",
hAlign: "left",
vAlign: "stretch",
}}
>
<InnerFormBlock {...innerProps} /> <InnerFormBlock {...innerProps} />
</BlockComponent> </FormBlockWrapper>
{:else}
<BlockComponent
type="dataprovider"
context="provider"
bind:id={providerId}
props={{
dataSource,
filter,
limit: 1,
paginate: false,
}}
>
<BlockComponent
type="repeater"
context="repeater"
bind:id={repeaterId}
props={{
dataProvider,
noRowsMessage: noRowsMessage || "We couldn't find a row to display",
direction: "column",
hAlign: "center",
}}
>
<InnerFormBlock {...innerProps} />
</BlockComponent>
</BlockComponent>
{/if}
</Block>

View File

@ -0,0 +1,64 @@
<script>
import BlockComponent from "components/BlockComponent.svelte"
import Block from "components/Block.svelte"
import { makePropSafe as safe } from "@budibase/string-templates"
import { getContext } from "svelte"
export let actionType
export let dataSource
export let rowId
export let noRowsMessage
const component = getContext("component")
$: providerId = `${$component.id}-provider`
$: dataProvider = `{{ literal ${safe(providerId)} }}`
$: filter = [
{
field: "_id",
operator: "equal",
type: "string",
value: !rowId ? `{{ ${safe("url")}.${safe("id")} }}` : rowId,
valueType: "Binding",
},
]
</script>
<Block>
{#if actionType === "Create"}
<BlockComponent
type="container"
props={{
direction: "column",
hAlign: "left",
vAlign: "stretch",
}}
>
<slot />
</BlockComponent>
{:else}
<BlockComponent
type="dataprovider"
context="provider"
props={{
dataSource,
filter,
limit: 1,
paginate: false,
}}
>
<BlockComponent
type="repeater"
context="repeater"
props={{
dataProvider,
noRowsMessage: noRowsMessage || "We couldn't find a row to display",
direction: "column",
hAlign: "center",
}}
>
<slot />
</BlockComponent>
</BlockComponent>
{/if}
</Block>

View File

@ -242,15 +242,16 @@ export const buildFormBlockButtonConfig = props => {
} }
export const buildMultiStepFormBlockDefaultProps = props => { export const buildMultiStepFormBlockDefaultProps = props => {
const { _id, stepCount, currentStep } = props || {} const { _id, stepCount, currentStep, actionType, dataSource } = props || {}
// Sanity check // Sanity check
if (!_id || !stepCount) { if (!_id || !stepCount) {
return return
} }
// Default the title to "Step X"
const title = `Step {{ [${_id}-form].[__currentStep] }}` const title = `Step {{ [${_id}-form].[__currentStep] }}`
const resourceId = dataSource?.resourceId
const formId = `${_id}-form`
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
@ -266,7 +267,7 @@ export const buildMultiStepFormBlockDefaultProps = props => {
{ {
parameters: { parameters: {
type: "prev", type: "prev",
componentId: `${_id}-form`, componentId: formId,
}, },
"##eventHandlerType": "Change Form Step", "##eventHandlerType": "Change Form Step",
}, },
@ -287,13 +288,13 @@ export const buildMultiStepFormBlockDefaultProps = props => {
{ {
"##eventHandlerType": "Validate Form", "##eventHandlerType": "Validate Form",
parameters: { parameters: {
componentId: `${_id}-form`, componentId: formId,
}, },
}, },
{ {
parameters: { parameters: {
type: "next", type: "next",
componentId: `${_id}-form`, componentId: formId,
}, },
"##eventHandlerType": "Change Form Step", "##eventHandlerType": "Change Form Step",
}, },
@ -302,7 +303,7 @@ export const buildMultiStepFormBlockDefaultProps = props => {
} }
// Add save button if we are the last step // Add save button if we are the last step
if (currentStep === stepCount - 1) { if (actionType !== "View" && currentStep === stepCount - 1) {
buttons.push({ buttons.push({
_id: Helpers.uuid(), _id: Helpers.uuid(),
_component: "@budibase/standard-components/button", _component: "@budibase/standard-components/button",
@ -314,9 +315,27 @@ export const buildMultiStepFormBlockDefaultProps = props => {
{ {
"##eventHandlerType": "Validate Form", "##eventHandlerType": "Validate Form",
parameters: { parameters: {
componentId: `${_id}-form`, componentId: formId,
}, },
}, },
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: resourceId,
providerId: formId,
},
},
// Clear a create form once submitted
...(actionType !== "Create"
? []
: [
{
"##eventHandlerType": "Clear Form",
parameters: {
componentId: formId,
},
},
]),
], ],
}) })
} }