diff --git a/packages/bbui/src/DetailSummary/DetailSummary.svelte b/packages/bbui/src/DetailSummary/DetailSummary.svelte
index daa9f3f5ca..808e12b6c4 100644
--- a/packages/bbui/src/DetailSummary/DetailSummary.svelte
+++ b/packages/bbui/src/DetailSummary/DetailSummary.svelte
@@ -5,6 +5,7 @@
export let name
export let show = false
export let collapsible = true
+ export let noPadding = false
const dispatch = createEventDispatcher()
const onHeaderClick = () => {
@@ -31,6 +32,7 @@
class="property-panel"
class:show={show || !collapsible}
class:no-title={!name}
+ class:no-padding={noPadding}
>
@@ -84,6 +86,10 @@
padding: var(--spacing-xl);
}
+ .property-panel.no-title.no-padding {
+ padding: 0px;
+ }
+
.show {
display: flex;
flex-direction: column;
diff --git a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte
index ce91c8f7b5..63bfecf386 100644
--- a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte
+++ b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte
@@ -34,6 +34,9 @@
$: canAddButtons = max == null || buttonList.length < max
const sanitizeValue = val => {
+ if (!Array.isArray(val)) {
+ return null
+ }
return val?.map(button => {
return button._component ? button : buildPseudoInstance(button)
})
diff --git a/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte b/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte
index 7f1ac1cf25..4d436a4679 100644
--- a/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte
+++ b/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte
@@ -39,7 +39,10 @@
)
}
- $: datasource = getDatasourceForProvider($currentAsset, componentInstance)
+ $: datasource =
+ componentInstance.dataSource ||
+ getDatasourceForProvider($currentAsset, componentInstance)
+
$: resourceId = datasource?.resourceId || datasource?.tableId
$: if (!isEqual(value, cachedValue)) {
diff --git a/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte b/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte
new file mode 100644
index 0000000000..dbaefaac96
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/FormStepConfiguration.svelte
@@ -0,0 +1,274 @@
+
+
+
+ {
+ const types = { formStepControl: FormStepControls }
+ return types[type]
+ }}
+ getCustomSectionTitle={section => {
+ console.log(section.name)
+ if (section.name === "Details" && stepState?.length > 0) {
+ return `Details (${currentStep}/${stepState?.length})`
+ }
+ return section.name
+ }}
+ showSectionTitle={false}
+ showInstanceName={false}
+ isScreen={false}
+ noPadding={true}
+ nested={true}
+ {bindings}
+ {componentBindings}
+ />
+
diff --git a/packages/builder/src/components/design/settings/controls/FormStepControls.svelte b/packages/builder/src/components/design/settings/controls/FormStepControls.svelte
new file mode 100644
index 0000000000..9aa6b43d10
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/FormStepControls.svelte
@@ -0,0 +1,81 @@
+
+
+{#if stepsCount === 1}
+ {
+ stepAction("addStep")
+ }}
+ >
+ Add Step
+
+{:else}
+
+
{
+ stepAction("previousStep")
+ }}
+ />
+ {
+ stepAction("nextStep")
+ }}
+ />
+ {
+ stepAction("removeStep")
+ }}
+ />
+ {
+ stepAction("addStep")
+ }}
+ />
+
+{/if}
+
+
diff --git a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte
index a6f3d1b218..78f299f237 100644
--- a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte
+++ b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte
@@ -24,6 +24,7 @@
export let propertyFocus = false
export let info = null
export let disableBindings = false
+ export let wide
$: nullishValue = value == null || value === ""
$: allBindings = getAllBindings(bindings, componentBindings, nested)
@@ -78,7 +79,7 @@
@@ -104,6 +105,7 @@
{...props}
on:drawerHide
on:drawerShow
+ on:meta
/>
{#if info}
@@ -147,7 +149,16 @@
position: relative;
}
.property-control.wide .control {
- grid-column: 1 / -1;
+ flex: 1;
+ }
+ .property-control.wide {
+ grid-template-columns: unset;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ }
+ .property-control.wide > * {
+ width: 100%;
}
.text {
font-size: var(--spectrum-global-dimension-font-size-75);
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte
index 6093d2a45e..6bc5f33398 100644
--- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte
@@ -15,9 +15,12 @@
export let componentBindings
export let isScreen = false
export let onUpdateSetting
+ export let getCustomComponent
+ export let getCustomSectionTitle
export let showSectionTitle = true
export let includeHidden = false
export let tag
+ export let noPadding = false
$: sections = getSections(
componentInstance,
@@ -129,13 +132,30 @@
})
}
+ const resolveComponentByType = setting => {
+ if (setting.type) {
+ return getComponentForSetting(setting)
+ } else if (setting.customType && typeof getCustomComponent === "function") {
+ return getCustomComponent(setting.customType)
+ }
+ }
+
+ const resolveSectionName = section => {
+ console.log(resolveSectionName)
+ if (typeof getCustomSectionTitle === "function") {
+ return getCustomSectionTitle(section)
+ } else {
+ return section.name
+ }
+ }
+
const canRenderControl = (instance, setting, isScreen, includeHidden) => {
// Prevent rendering on click setting for screens
if (setting?.type === "event" && isScreen) {
return false
}
// Check we have a component to render for this setting
- const control = getComponentForSetting(setting)
+ const control = resolveComponentByType(setting)
if (!control) {
return false
}
@@ -152,6 +172,7 @@
{#if section.info}
@@ -168,9 +189,10 @@
{#if setting.visible}
+ import BlockComponent from "components/BlockComponent.svelte"
+ import Block from "components/Block.svelte"
+ import { getContext } from "svelte"
+ import { builderStore } from "stores"
+
+ export let componentInstance
+ export let steps
+ export let dataSource
+ export let initialFormStep = 1
+
+ const { fetchDatasourceSchema } = getContext("sdk")
+ 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 = {
+ string: "stringfield",
+ number: "numberfield",
+ bigint: "bigintfield",
+ options: "optionsfield",
+ array: "multifieldselect",
+ boolean: "booleanfield",
+ longform: "longformfield",
+ datetime: "datetimefield",
+ attachment: "attachmentfield",
+ link: "relationshipfield",
+ json: "jsonfield",
+ barcodeqr: "codescanner",
+ bb_reference: "bbreferencefield",
+ }
+
+ const getComponentForField = field => {
+ const fieldSchemaName = field.field || field.name
+ if (!fieldSchemaName || !schema?.[fieldSchemaName]) {
+ return null
+ }
+ const type = schema[fieldSchemaName].type
+ return FieldTypeToComponentMap[type]
+ }
+
+ const fetchSchema = async () => {
+ schema = (await fetchDatasourceSchema(dataSource)) || {}
+ }
+
+ $: stepProps = steps?.map(step => {
+ const { title, desc, fields, buttons } = step
+ return {
+ fields: getDefaultFields(fields || [], schema),
+ title,
+ desc,
+ buttons,
+ }
+ })
+
+
+{#key stepProps}
+
+
+ {#each steps || [] as step, idx ("step" + step._id)}
+
+
+
+
+
+
+
+
+
+ {#each stepProps?.[idx]?.fields || [] as field, fieldIdx ("field_" + fieldIdx)}
+ {#if getComponentForField(field) && field.active}
+
+ {/if}
+ {/each}
+
+
+
+
+ {/each}
+
+
+{/key}
diff --git a/packages/client/src/components/app/blocks/index.js b/packages/client/src/components/app/blocks/index.js
index f74d2f0e12..2c8d81cf96 100644
--- a/packages/client/src/components/app/blocks/index.js
+++ b/packages/client/src/components/app/blocks/index.js
@@ -4,3 +4,4 @@ export { default as repeaterblock } from "./RepeaterBlock.svelte"
export { default as formblock } from "./form/FormBlock.svelte"
export { default as chartblock } from "./ChartBlock.svelte"
export { default as rowexplorer } from "./RowExplorer.svelte"
+export { default as multistepformblock } from "./MultiStepFormblock.svelte"
diff --git a/packages/client/src/components/app/forms/Form.svelte b/packages/client/src/components/app/forms/Form.svelte
index 1a740585f3..5b09a420fe 100644
--- a/packages/client/src/components/app/forms/Form.svelte
+++ b/packages/client/src/components/app/forms/Form.svelte
@@ -11,6 +11,7 @@
export let readonly = false
export let actionType = "Create"
export let initialFormStep = 1
+ export let step
// Not exposed as a builder setting. Used internally to disable validation
// for fields rendered in things like search blocks.
@@ -36,6 +37,15 @@
let table
let currentStep = writable(getInitialFormStep())
+ $: if (
+ currentStep &&
+ Number.isInteger($currentStep) &&
+ Number.isInteger(step) &&
+ step !== currentStep
+ ) {
+ currentStep.set(step)
+ }
+
$: fetchSchema(dataSource)
$: schemaKey = generateSchemaKey(schema)
$: initialValues = getInitialValues(actionType, dataSource, $context)
diff --git a/packages/client/src/index.js b/packages/client/src/index.js
index 415d9fa5f2..730425abfd 100644
--- a/packages/client/src/index.js
+++ b/packages/client/src/index.js
@@ -75,6 +75,11 @@ const loadBudibase = async () => {
} else {
dndStore.actions.reset()
}
+ } else if ("builder-meta") {
+ builderStore.update(state => ({
+ ...state,
+ ...data,
+ }))
}
}