Add form block and form block plus components
This commit is contained in:
parent
459c285d23
commit
d08d9d1248
|
@ -47,7 +47,6 @@ filterTests(["smoke", "all"], () => {
|
|||
cy.readFile(
|
||||
"cypress/support/queryLevelTransformerFunctionWithData.js"
|
||||
).then(transformerFunction => {
|
||||
//console.log(transformerFunction[1])
|
||||
cy.get(".CodeMirror textarea")
|
||||
// Highlight current text and overwrite with file contents
|
||||
.type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", {
|
||||
|
|
|
@ -65,7 +65,12 @@ export const getComponentBindableProperties = (asset, componentId) => {
|
|||
/**
|
||||
* Gets all data provider components above a component.
|
||||
*/
|
||||
export const getContextProviderComponents = (asset, componentId, type) => {
|
||||
export const getContextProviderComponents = (
|
||||
asset,
|
||||
componentId,
|
||||
type,
|
||||
options = { includeSelf: false }
|
||||
) => {
|
||||
if (!asset || !componentId) {
|
||||
return []
|
||||
}
|
||||
|
@ -73,7 +78,9 @@ export const getContextProviderComponents = (asset, componentId, type) => {
|
|||
// Get the component tree leading up to this component, ignoring the component
|
||||
// itself
|
||||
const path = findComponentPath(asset.props, componentId)
|
||||
path.pop()
|
||||
if (!options?.includeSelf) {
|
||||
path.pop()
|
||||
}
|
||||
|
||||
// Filter by only data provider components
|
||||
return path.filter(component => {
|
||||
|
@ -138,19 +145,7 @@ export const getDatasourceForProvider = (asset, component) => {
|
|||
if (!datasourceSetting) {
|
||||
return null
|
||||
}
|
||||
|
||||
// There are different types of setting which can be a datasource, for
|
||||
// example an actual datasource object, or a table ID string.
|
||||
// Convert the datasource setting into a proper datasource object so that
|
||||
// we can use it properly
|
||||
if (datasourceSetting.type === "table") {
|
||||
return {
|
||||
tableId: component[datasourceSetting?.key],
|
||||
type: "table",
|
||||
}
|
||||
} else {
|
||||
return component[datasourceSetting?.key]
|
||||
}
|
||||
return component[datasourceSetting?.key]
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -643,6 +638,17 @@ const buildFormSchema = component => {
|
|||
if (!component) {
|
||||
return schema
|
||||
}
|
||||
|
||||
// If this is a form block, simply use the fields setting
|
||||
if (component._component.endsWith("formblock")) {
|
||||
let schema = {}
|
||||
component.fields?.forEach(field => {
|
||||
schema[field] = { type: "string" }
|
||||
})
|
||||
return schema
|
||||
}
|
||||
|
||||
// Otherwise find all field component children
|
||||
const settings = getComponentSettings(component._component)
|
||||
const fieldSetting = settings.find(
|
||||
setting => setting.key === "field" && setting.type.startsWith("field/")
|
||||
|
|
|
@ -5,26 +5,20 @@
|
|||
"children": [
|
||||
"tableblock",
|
||||
"cardsblock",
|
||||
"repeaterblock"
|
||||
"repeaterblock",
|
||||
"formblock",
|
||||
"formblockplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Layout",
|
||||
"icon": "ClassicGridView",
|
||||
"children": [
|
||||
"container",
|
||||
"section"
|
||||
]
|
||||
"children": ["container", "section"]
|
||||
},
|
||||
{
|
||||
"name": "Data",
|
||||
"icon": "Data",
|
||||
"children": [
|
||||
"dataprovider",
|
||||
"repeater",
|
||||
"table",
|
||||
"dynamicfilter"
|
||||
]
|
||||
"children": ["dataprovider", "repeater", "table", "dynamicfilter"]
|
||||
},
|
||||
{
|
||||
"name": "Form",
|
||||
|
@ -51,22 +45,12 @@
|
|||
{
|
||||
"name": "Card",
|
||||
"icon": "Card",
|
||||
"children": [
|
||||
"spectrumcard",
|
||||
"cardstat"
|
||||
]
|
||||
"children": ["spectrumcard", "cardstat"]
|
||||
},
|
||||
{
|
||||
"name": "Chart",
|
||||
"icon": "GraphBarVertical",
|
||||
"children": [
|
||||
"bar",
|
||||
"line",
|
||||
"area",
|
||||
"pie",
|
||||
"donut",
|
||||
"candlestick"
|
||||
]
|
||||
"children": ["bar", "line", "area", "pie", "donut", "candlestick"]
|
||||
},
|
||||
{
|
||||
"name": "Elements",
|
||||
|
@ -87,4 +71,3 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
}
|
||||
} catch (error) {
|
||||
notifications.error("Error duplicating screen")
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
export let key
|
||||
export let actions
|
||||
export let bindings = []
|
||||
export let nested
|
||||
|
||||
let selectedAction = actions?.length ? actions[0] : null
|
||||
|
||||
|
@ -137,6 +138,7 @@
|
|||
this={selectedActionComponent}
|
||||
parameters={selectedAction.parameters}
|
||||
bindings={allBindings}
|
||||
{nested}
|
||||
/>
|
||||
</div>
|
||||
{/key}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
export let value = []
|
||||
export let name
|
||||
export let bindings
|
||||
export let nested
|
||||
|
||||
let drawer
|
||||
let tmpValue
|
||||
|
@ -83,5 +84,6 @@
|
|||
eventType={name}
|
||||
{bindings}
|
||||
{key}
|
||||
{nested}
|
||||
/>
|
||||
</Drawer>
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
|
||||
export let parameters
|
||||
export let bindings = []
|
||||
export let nested
|
||||
|
||||
$: formComponents = getContextProviderComponents(
|
||||
$currentAsset,
|
||||
$store.selectedComponentId,
|
||||
"form"
|
||||
"form",
|
||||
{ includeSelf: nested }
|
||||
)
|
||||
$: schemaComponents = getContextProviderComponents(
|
||||
$currentAsset,
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
bindings={allBindings}
|
||||
name={key}
|
||||
text={label}
|
||||
{nested}
|
||||
{key}
|
||||
{type}
|
||||
{...props}
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
<script>
|
||||
import { Select } from "@budibase/bbui"
|
||||
import { tables } from "stores/backend"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { tables as tablesStore } from "stores/backend"
|
||||
|
||||
export let value
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: tables = $tablesStore.list.map(m => ({
|
||||
label: m.name,
|
||||
tableId: m._id,
|
||||
type: "table",
|
||||
}))
|
||||
|
||||
const onChange = e => {
|
||||
const dataSource = tables?.find(x => x.tableId === e.detail)
|
||||
dispatch("change", dataSource)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<Select extraThin secondary wide on:change {value}>
|
||||
<option value="">Choose a table</option>
|
||||
{#each $tables.list as table}
|
||||
<option value={table._id}>{table.name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
div :global(> *) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
</style>
|
||||
<Select
|
||||
on:change={onChange}
|
||||
value={value?.tableId}
|
||||
options={tables}
|
||||
getOptionValue={x => x.tableId}
|
||||
getOptionLabel={x => x.label}
|
||||
/>
|
||||
|
|
|
@ -3637,5 +3637,255 @@
|
|||
"key": "value"
|
||||
}
|
||||
]
|
||||
},
|
||||
"formblock": {
|
||||
"name": "Form Block",
|
||||
"icon": "Form",
|
||||
"styles": ["size"],
|
||||
"block": true,
|
||||
"settings": [
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Type",
|
||||
"key": "actionType",
|
||||
"options": ["Create", "Update"],
|
||||
"defaultValue": "Create"
|
||||
},
|
||||
{
|
||||
"type": "dataSource",
|
||||
"label": "Schema",
|
||||
"key": "dataSource"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "Title",
|
||||
"key": "title"
|
||||
},
|
||||
{
|
||||
"section": true,
|
||||
"name": "Fields",
|
||||
"settings": [
|
||||
{
|
||||
"type": "multifield",
|
||||
"label": "Fields",
|
||||
"key": "fields"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Field labels",
|
||||
"key": "labelPosition",
|
||||
"defaultValue": "left",
|
||||
"options": [
|
||||
{
|
||||
"label": "Left",
|
||||
"value": "left"
|
||||
},
|
||||
{
|
||||
"label": "Right",
|
||||
"value": "right"
|
||||
},
|
||||
{
|
||||
"label": "Above",
|
||||
"value": "above"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Size",
|
||||
"key": "size",
|
||||
"options": [
|
||||
{
|
||||
"label": "Medium",
|
||||
"value": "spectrum--medium"
|
||||
},
|
||||
{
|
||||
"label": "Large",
|
||||
"value": "spectrum--large"
|
||||
}
|
||||
],
|
||||
"defaultValue": "spectrum--medium"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"section": true,
|
||||
"name": "Buttons",
|
||||
"settings": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Show primary button",
|
||||
"key": "showPrimaryButton",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "Text",
|
||||
"key": "primaryButtonText",
|
||||
"defaultValue": "Submit",
|
||||
"dependsOn": "showPrimaryButton"
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"label": "On click",
|
||||
"key": "primaryButtonOnClick",
|
||||
"nested": true,
|
||||
"dependsOn": "showPrimaryButton"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Show secondary button",
|
||||
"key": "showSecondaryButton",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "Text",
|
||||
"key": "secondaryButtonText",
|
||||
"defaultValue": "Action",
|
||||
"dependsOn": "showSecondaryButton"
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"label": "On click",
|
||||
"key": "secondaryButtonOnClick",
|
||||
"nested": true,
|
||||
"dependsOn": "showSecondaryButton"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"context": [
|
||||
{
|
||||
"type": "form",
|
||||
"suffix": "form"
|
||||
}
|
||||
]
|
||||
},
|
||||
"formblockplus": {
|
||||
"name": "Form Block+",
|
||||
"icon": "Form",
|
||||
"styles": ["size"],
|
||||
"block": true,
|
||||
"settings": [
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Type",
|
||||
"key": "actionType",
|
||||
"options": ["Create", "Update"],
|
||||
"defaultValue": "Create"
|
||||
},
|
||||
{
|
||||
"type": "table",
|
||||
"label": "Schema",
|
||||
"key": "dataSource"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "Row ID to update",
|
||||
"key": "rowId",
|
||||
"dependsOn": {
|
||||
"setting": "actionType",
|
||||
"value": "Update"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "Title",
|
||||
"key": "title",
|
||||
"nested": true
|
||||
},
|
||||
{
|
||||
"section": true,
|
||||
"name": "Fields",
|
||||
"settings": [
|
||||
{
|
||||
"type": "multifield",
|
||||
"label": "Fields",
|
||||
"key": "fields"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Field labels",
|
||||
"key": "labelPosition",
|
||||
"defaultValue": "left",
|
||||
"options": [
|
||||
{
|
||||
"label": "Left",
|
||||
"value": "left"
|
||||
},
|
||||
{
|
||||
"label": "Right",
|
||||
"value": "right"
|
||||
},
|
||||
{
|
||||
"label": "Above",
|
||||
"value": "above"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Size",
|
||||
"key": "size",
|
||||
"options": [
|
||||
{
|
||||
"label": "Medium",
|
||||
"value": "spectrum--medium"
|
||||
},
|
||||
{
|
||||
"label": "Large",
|
||||
"value": "spectrum--large"
|
||||
}
|
||||
],
|
||||
"defaultValue": "spectrum--medium"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"section": true,
|
||||
"name": "Buttons",
|
||||
"settings": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Show save button",
|
||||
"key": "showSaveButton",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Show delete button",
|
||||
"key": "showDeleteButton",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "actionType",
|
||||
"value": "Update"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"context": [
|
||||
{
|
||||
"type": "form",
|
||||
"suffix": "form"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"suffix": "repeater"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import BlockComponent from "../../BlockComponent.svelte"
|
||||
import Block from "../../Block.svelte"
|
||||
import { Heading, Layout } from "@budibase/bbui"
|
||||
import Placeholder from "../Placeholder.svelte"
|
||||
|
||||
export let actionType
|
||||
export let dataSource
|
||||
export let size
|
||||
export let disabled
|
||||
export let fields
|
||||
export let labelPosition
|
||||
export let title
|
||||
export let showPrimaryButton
|
||||
export let primaryButtonOnClick
|
||||
export let primaryButtonText
|
||||
export let showSecondaryButton
|
||||
export let secondaryButtonOnClick
|
||||
export let secondaryButtonText
|
||||
|
||||
const { styleable, fetchDatasourceSchema } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
const FieldTypeToComponentMap = {
|
||||
string: "stringfield",
|
||||
number: "numberfield",
|
||||
options: "optionsfield",
|
||||
array: "multifieldselect",
|
||||
boolean: "booleanfield",
|
||||
longform: "longformfield",
|
||||
datetime: "datetimefield",
|
||||
attachment: "attachmentfield",
|
||||
link: "relationshipfield",
|
||||
json: "jsonfield",
|
||||
}
|
||||
|
||||
let schema
|
||||
$: fetchSchema(dataSource)
|
||||
|
||||
const fetchSchema = async () => {
|
||||
schema = (await fetchDatasourceSchema(dataSource)) || {}
|
||||
}
|
||||
|
||||
const getComponentForField = field => {
|
||||
if (!field || !schema?.[field]) {
|
||||
return null
|
||||
}
|
||||
const type = schema[field].type
|
||||
return FieldTypeToComponentMap[type]
|
||||
}
|
||||
</script>
|
||||
|
||||
<Block>
|
||||
<div use:styleable={$component.styles}>
|
||||
{#if fields?.length}
|
||||
<BlockComponent
|
||||
type="form"
|
||||
props={{ actionType, dataSource, size, disabled }}
|
||||
context="form"
|
||||
>
|
||||
<Layout noPadding gap="M">
|
||||
<div class="title" class:with-text={!!title}>
|
||||
<Heading>{title || ""}</Heading>
|
||||
<div class="buttons">
|
||||
{#if showSecondaryButton}
|
||||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text: secondaryButtonText,
|
||||
onClick: secondaryButtonOnClick,
|
||||
quiet: true,
|
||||
type: "secondary",
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{#if showPrimaryButton}
|
||||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text: primaryButtonText,
|
||||
onClick: primaryButtonOnClick,
|
||||
type: "cta",
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<BlockComponent type="fieldgroup" props={{ labelPosition }}>
|
||||
{#each fields as field}
|
||||
{#if getComponentForField(field)}
|
||||
<BlockComponent
|
||||
type={getComponentForField(field)}
|
||||
props={{
|
||||
field,
|
||||
label: field,
|
||||
placeholder: field,
|
||||
disabled,
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</BlockComponent>
|
||||
</Layout>
|
||||
</BlockComponent>
|
||||
{:else}
|
||||
<Placeholder
|
||||
text="Choose your schema and add some fields to your form to get started"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</Block>
|
||||
|
||||
<style>
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
order: 2;
|
||||
}
|
||||
.title.with-text {
|
||||
order: 0;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,199 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import BlockComponent from "../../BlockComponent.svelte"
|
||||
import Block from "../../Block.svelte"
|
||||
import { Layout } from "@budibase/bbui"
|
||||
import Placeholder from "../Placeholder.svelte"
|
||||
import { makePropSafe as safe } from "@budibase/string-templates"
|
||||
|
||||
export let actionType
|
||||
export let dataSource
|
||||
export let size
|
||||
export let disabled
|
||||
export let fields
|
||||
export let labelPosition
|
||||
export let title
|
||||
export let showSaveButton
|
||||
export let showDeleteButton
|
||||
export let rowId
|
||||
|
||||
const { styleable, fetchDatasourceSchema, builderStore } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
const FieldTypeToComponentMap = {
|
||||
string: "stringfield",
|
||||
number: "numberfield",
|
||||
options: "optionsfield",
|
||||
array: "multifieldselect",
|
||||
boolean: "booleanfield",
|
||||
longform: "longformfield",
|
||||
datetime: "datetimefield",
|
||||
attachment: "attachmentfield",
|
||||
link: "relationshipfield",
|
||||
json: "jsonfield",
|
||||
}
|
||||
|
||||
let schema
|
||||
let formId
|
||||
let providerId
|
||||
let repeaterId
|
||||
|
||||
$: fetchSchema(dataSource)
|
||||
$: onSave = [
|
||||
{
|
||||
"##eventHandlerType": "Save Row",
|
||||
parameters: {
|
||||
providerId: formId,
|
||||
tableId: dataSource?.tableId,
|
||||
},
|
||||
},
|
||||
{
|
||||
"##eventHandlerType": "Close Screen Modal",
|
||||
},
|
||||
]
|
||||
$: onDelete = [
|
||||
{
|
||||
"##eventHandlerType": "Delete Row",
|
||||
parameters: {
|
||||
confirm: true,
|
||||
tableId: dataSource?.tableId,
|
||||
rowId: `{{ ${safe(repeaterId)}.${safe("_id")} }}`,
|
||||
revId: `{{ ${safe(repeaterId)}.${safe("_rev")} }}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
"##eventHandlerType": "Close Screen Modal",
|
||||
},
|
||||
]
|
||||
$: filter = [
|
||||
{
|
||||
field: "_id",
|
||||
operator: "equal",
|
||||
type: "string",
|
||||
value: rowId,
|
||||
valueType: "binding",
|
||||
},
|
||||
]
|
||||
// If we're using an "update" form, use the real data provider. If we're
|
||||
// using a create form, we just want a fake array so that our repeater
|
||||
// will actually render the form, but data doesn't matter.
|
||||
$: dataProvider =
|
||||
actionType === "Update"
|
||||
? `{{ literal ${safe(providerId)} }}`
|
||||
: { rows: [{}] }
|
||||
|
||||
const fetchSchema = async () => {
|
||||
schema = (await fetchDatasourceSchema(dataSource)) || {}
|
||||
}
|
||||
|
||||
const getComponentForField = field => {
|
||||
if (!field || !schema?.[field]) {
|
||||
return null
|
||||
}
|
||||
const type = schema[field].type
|
||||
return FieldTypeToComponentMap[type]
|
||||
}
|
||||
</script>
|
||||
|
||||
<Block>
|
||||
<div use:styleable={$component.styles}>
|
||||
{#if fields?.length}
|
||||
<BlockComponent
|
||||
type="dataprovider"
|
||||
context="provider"
|
||||
bind:id={providerId}
|
||||
props={{
|
||||
dataSource,
|
||||
filter,
|
||||
limit: rowId ? 1 : $builderStore.inBuilder ? 1 : 0,
|
||||
paginate: false,
|
||||
}}
|
||||
>
|
||||
<BlockComponent
|
||||
type="repeater"
|
||||
context="repeater"
|
||||
bind:id={repeaterId}
|
||||
props={{
|
||||
dataProvider,
|
||||
noRowsMessage: "We couldn't find a row to display",
|
||||
}}
|
||||
>
|
||||
<BlockComponent
|
||||
type="form"
|
||||
props={{ actionType, dataSource, size, disabled }}
|
||||
context="form"
|
||||
bind:id={formId}
|
||||
>
|
||||
<Layout noPadding gap="M">
|
||||
<div class="title" class:with-text={!!title}>
|
||||
<BlockComponent type="heading" props={{ text: title || "" }} />
|
||||
<div class="buttons">
|
||||
{#if showDeleteButton}
|
||||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text: "Delete",
|
||||
onClick: onDelete,
|
||||
quiet: true,
|
||||
type: "secondary",
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{#if showSaveButton}
|
||||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text: "Save",
|
||||
onClick: onSave,
|
||||
type: "cta",
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<BlockComponent type="fieldgroup" props={{ labelPosition }}>
|
||||
{#each fields as field}
|
||||
{#if getComponentForField(field)}
|
||||
<BlockComponent
|
||||
type={getComponentForField(field)}
|
||||
props={{
|
||||
field,
|
||||
label: field,
|
||||
placeholder: field,
|
||||
disabled,
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</BlockComponent>
|
||||
</Layout>
|
||||
</BlockComponent>
|
||||
</BlockComponent>
|
||||
</BlockComponent>
|
||||
{:else}
|
||||
<Placeholder
|
||||
text="Choose your schema and add some fields to your form to get started"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</Block>
|
||||
|
||||
<style>
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
order: 2;
|
||||
}
|
||||
.title.with-text {
|
||||
order: 0;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -1,3 +1,5 @@
|
|||
export { default as tableblock } from "./TableBlock.svelte"
|
||||
export { default as cardsblock } from "./CardsBlock.svelte"
|
||||
export { default as repeaterblock } from "./RepeaterBlock.svelte"
|
||||
export { default as formblock } from "./FormBlock.svelte"
|
||||
export { default as formblockplus } from "./FormBlockPlus.svelte"
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
palette,
|
||||
horizontal
|
||||
) => {
|
||||
console.log("new chart")
|
||||
const allCols = [labelColumn, ...(valueColumns || [null])]
|
||||
if (
|
||||
!dataProvider ||
|
||||
|
|
|
@ -40,36 +40,7 @@
|
|||
|
||||
// Fetches the form schema from this form's dataSource
|
||||
const fetchSchema = async dataSource => {
|
||||
if (!dataSource) {
|
||||
schema = {}
|
||||
}
|
||||
|
||||
// If the datasource is a query, then we instead use a schema of the query
|
||||
// parameters rather than the output schema
|
||||
else if (
|
||||
dataSource.type === "query" &&
|
||||
dataSource._id &&
|
||||
actionType === "Create"
|
||||
) {
|
||||
try {
|
||||
const query = await API.fetchQueryDefinition(dataSource._id)
|
||||
let paramSchema = {}
|
||||
const params = query.parameters || []
|
||||
params.forEach(param => {
|
||||
paramSchema[param.name] = { ...param, type: "string" }
|
||||
})
|
||||
schema = paramSchema
|
||||
} catch (error) {
|
||||
schema = {}
|
||||
}
|
||||
}
|
||||
|
||||
// For all other cases, just grab the normal schema
|
||||
else {
|
||||
const dataSourceSchema = await fetchDatasourceSchema(dataSource)
|
||||
schema = dataSourceSchema || {}
|
||||
}
|
||||
|
||||
schema = (await fetchDatasourceSchema(dataSource)) || {}
|
||||
if (!loaded) {
|
||||
loaded = true
|
||||
}
|
||||
|
|
|
@ -66,7 +66,6 @@ const createScreenStore = () => {
|
|||
}
|
||||
let children = []
|
||||
findChildrenByType(component, type, children)
|
||||
console.log(children)
|
||||
return children
|
||||
},
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch.js"
|
|||
*/
|
||||
export const fetchDatasourceSchema = async (
|
||||
datasource,
|
||||
options = { enrichRelationships: false }
|
||||
options = { enrichRelationships: false, formSchema: false }
|
||||
) => {
|
||||
const handler = {
|
||||
table: TableFetch,
|
||||
|
@ -35,7 +35,17 @@ export const fetchDatasourceSchema = async (
|
|||
|
||||
// Get the datasource definition and then schema
|
||||
const definition = await instance.getDefinition(datasource)
|
||||
let schema = instance.getSchema(datasource, definition)
|
||||
|
||||
// Get the normal schema as long as we aren't wanting a form schema
|
||||
let schema
|
||||
if (datasource?.type !== "query" || !options?.formSchema) {
|
||||
schema = instance.getSchema(datasource, definition)
|
||||
} else if (definition.parameters?.length) {
|
||||
schema = {}
|
||||
definition.parameters.forEach(param => {
|
||||
schema[param.name] = { ...param, type: "string" }
|
||||
})
|
||||
}
|
||||
if (!schema) {
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ export const buildAttachmentEndpoints = API => {
|
|||
* @param data the file to upload
|
||||
*/
|
||||
externalUpload: async ({ datasourceId, bucket, key, data }) => {
|
||||
console.log(API)
|
||||
const { signedUrl, publicUrl } = await getSignedDatasourceURL({
|
||||
datasourceId,
|
||||
bucket,
|
||||
|
|
Loading…
Reference in New Issue