diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js
index dc995d611c..00eaaf0249 100644
--- a/packages/builder/src/builderStore/dataBinding.js
+++ b/packages/builder/src/builderStore/dataBinding.js
@@ -120,71 +120,79 @@ const getContextBindings = (asset, componentId) => {
// Create bindings for each data provider
dataProviders.forEach(component => {
const def = store.actions.components.getDefinition(component._component)
- const contextDefinition = def.context
- let schema
- let readablePrefix
+ const contexts = Array.isArray(def.context) ? def.context : [def.context]
- if (contextDefinition.type === "form") {
- // Forms do not need table schemas
- // Their schemas are built from their component field names
- schema = buildFormSchema(component)
- readablePrefix = "Fields"
- } else if (contextDefinition.type === "static") {
- // Static contexts are fully defined by the components
- schema = {}
- const values = contextDefinition.values || []
- values.forEach(value => {
- schema[value.key] = { name: value.label, type: "string" }
- })
- } else if (contextDefinition.type === "schema") {
- // Schema contexts are generated dynamically depending on their data
- const datasource = getDatasourceForProvider(asset, component)
- if (!datasource) {
+ // Create bindings for each context block provided by this data provider
+ contexts.forEach(context => {
+ if (!context?.type) {
return
}
- const info = getSchemaForDatasource(asset, datasource)
- schema = info.schema
- readablePrefix = info.table?.name
- }
- if (!schema) {
- return
- }
- const keys = Object.keys(schema).sort()
+ let schema
+ let readablePrefix
- // Create bindable properties for each schema field
- const safeComponentId = makePropSafe(component._id)
- keys.forEach(key => {
- const fieldSchema = schema[key]
-
- // Make safe runtime binding and replace certain bindings with a
- // new property to help display components
- let runtimeBoundKey = key
- if (fieldSchema.type === "link") {
- runtimeBoundKey = `${key}_text`
- } else if (fieldSchema.type === "attachment") {
- runtimeBoundKey = `${key}_first`
+ if (context.type === "form") {
+ // Forms do not need table schemas
+ // Their schemas are built from their component field names
+ schema = buildFormSchema(component)
+ readablePrefix = "Fields"
+ } else if (context.type === "static") {
+ // Static contexts are fully defined by the components
+ schema = {}
+ const values = context.values || []
+ values.forEach(value => {
+ schema[value.key] = { name: value.label, type: "string" }
+ })
+ } else if (context.type === "schema") {
+ // Schema contexts are generated dynamically depending on their data
+ const datasource = getDatasourceForProvider(asset, component)
+ if (!datasource) {
+ return
+ }
+ const info = getSchemaForDatasource(asset, datasource)
+ schema = info.schema
+ readablePrefix = info.table?.name
}
- const runtimeBinding = `${safeComponentId}.${makePropSafe(
- runtimeBoundKey
- )}`
-
- // Optionally use a prefix with readable bindings
- let readableBinding = component._instanceName
- if (readablePrefix) {
- readableBinding += `.${readablePrefix}`
+ if (!schema) {
+ return
}
- readableBinding += `.${fieldSchema.name || key}`
- // Create the binding object
- bindings.push({
- type: "context",
- runtimeBinding,
- readableBinding,
- // Field schema and provider are required to construct relationship
- // datasource options, based on bindable properties
- fieldSchema,
- providerId: component._id,
+ const keys = Object.keys(schema).sort()
+
+ // Create bindable properties for each schema field
+ const safeComponentId = makePropSafe(component._id)
+ keys.forEach(key => {
+ const fieldSchema = schema[key]
+
+ // Make safe runtime binding and replace certain bindings with a
+ // new property to help display components
+ let runtimeBoundKey = key
+ if (fieldSchema.type === "link") {
+ runtimeBoundKey = `${key}_text`
+ } else if (fieldSchema.type === "attachment") {
+ runtimeBoundKey = `${key}_first`
+ }
+ const runtimeBinding = `${safeComponentId}.${makePropSafe(
+ runtimeBoundKey
+ )}`
+
+ // Optionally use a prefix with readable bindings
+ let readableBinding = component._instanceName
+ if (readablePrefix) {
+ readableBinding += `.${readablePrefix}`
+ }
+ readableBinding += `.${fieldSchema.name || key}`
+
+ // Create the binding object
+ bindings.push({
+ type: "context",
+ runtimeBinding,
+ readableBinding,
+ // Field schema and provider are required to construct relationship
+ // datasource options, based on bindable properties
+ fieldSchema,
+ providerId: component._id,
+ })
})
})
})
diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json
index c83686158f..cea20a7dcf 100644
--- a/packages/builder/src/components/design/AppPreview/componentStructure.json
+++ b/packages/builder/src/components/design/AppPreview/componentStructure.json
@@ -10,6 +10,7 @@
"icon": "Form",
"children": [
"form",
+ "formstep",
"fieldgroup",
"stringfield",
"numberfield",
diff --git a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte
index 9ec1108985..f047e9316b 100644
--- a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte
@@ -85,6 +85,8 @@
props={{
options: setting.options || [],
placeholder: setting.placeholder || null,
+ min: setting.min || null,
+ max: setting.max || null,
}}
{bindings}
{componentDefinition}
diff --git a/packages/client/src/constants.js b/packages/client/src/constants.js
index 7204b8c951..99e95e8398 100644
--- a/packages/client/src/constants.js
+++ b/packages/client/src/constants.js
@@ -7,6 +7,8 @@ export const ActionTypes = {
RefreshDatasource: "RefreshDatasource",
SetDataProviderQuery: "SetDataProviderQuery",
ClearForm: "ClearForm",
+ NextFormStep: "NextFormStep",
+ PrevFormStep: "PrevFormStep",
}
export const ApiVersion = "1"
diff --git a/packages/standard-components/manifest.json b/packages/standard-components/manifest.json
index b8c7bdc41d..d5d22aba3a 100644
--- a/packages/standard-components/manifest.json
+++ b/packages/standard-components/manifest.json
@@ -1705,7 +1705,9 @@
"illegalChildren": ["section"],
"actions": [
"ValidateForm",
- "ClearForm"
+ "ClearForm",
+ "NextFormStep",
+ "PrevFormStep"
],
"styles": ["size"],
"settings": [
@@ -1727,7 +1729,7 @@
},
{
"type": "number",
- "label": "Number of steps",
+ "label": "Steps",
"key": "steps",
"defaultValue": 1
},
@@ -1738,8 +1740,51 @@
"defaultValue": false
}
],
+ "context": [
+ {
+ "type": "static",
+ "values": [
+ {
+ "label": "Valid",
+ "key": "valid"
+ },
+ {
+ "label": "Step",
+ "key": "step"
+ }
+ ]
+ },
+ {
+ "type": "form"
+ }
+ ]
+ },
+ "formstep": {
+ "name": "Form Step",
+ "icon": "Form",
+ "hasChildren": true,
+ "illegalChildren": ["section"],
+ "actions": [
+ "ValidateFormStep"
+ ],
+ "styles": ["size"],
+ "settings": [
+ {
+ "type": "number",
+ "label": "Step",
+ "key": "step",
+ "defaultValue": 1,
+ "min": 1
+ }
+ ],
"context": {
- "type": "form"
+ "type": "static",
+ "values": [
+ {
+ "label": "Valid",
+ "key": "valid"
+ }
+ ]
}
},
"fieldgroup": {
diff --git a/packages/standard-components/src/forms/FormStep.svelte b/packages/standard-components/src/forms/FormStep.svelte
index e69de29bb2..449978ec08 100644
--- a/packages/standard-components/src/forms/FormStep.svelte
+++ b/packages/standard-components/src/forms/FormStep.svelte
@@ -0,0 +1,18 @@
+
+
+{#if !formContext}
+