diff --git a/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte b/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte index 5c4f90606d..09732ce4f2 100644 --- a/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte +++ b/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte @@ -21,6 +21,7 @@ export let allowHelpers = true export let updateOnChange = true export let drawerLeft + export let disableBindings = false const dispatch = createEventDispatcher() let bindingDrawer @@ -62,7 +63,7 @@ {placeholder} {updateOnChange} /> - {#if !disabled} + {#if !disabled && !disableBindings}
{ diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/SaveRow.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/SaveRow.svelte index c1917ad90f..27b6463ffa 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/SaveRow.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/SaveRow.svelte @@ -21,7 +21,8 @@ $: schemaComponents = getContextProviderComponents( $currentAsset, $store.selectedComponentId, - "schema" + "schema", + { includeSelf: nested } ) $: providerOptions = getProviderOptions(formComponents, schemaComponents) $: schemaFields = getSchemaFields(parameters?.tableId) 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 324418511b..ce91c8f7b5 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte @@ -4,10 +4,15 @@ import { createEventDispatcher } from "svelte" import { store } from "builderStore" import { Helpers } from "@budibase/bbui" + import { getEventContextBindings } from "builderStore/dataBinding" + export let componentInstance export let componentBindings export let bindings export let value + export let key + export let nested + export let max const dispatch = createEventDispatcher() @@ -15,12 +20,18 @@ $: buttonList = sanitizeValue(value) || [] $: buttonCount = buttonList.length + $: eventContextBindings = getEventContextBindings({ + componentInstance, + settingKey: key, + }) + $: allBindings = [...bindings, ...eventContextBindings] $: itemProps = { componentBindings: componentBindings || [], - bindings, + bindings: allBindings, removeButton, - canRemove: buttonCount > 1, + nested, } + $: canAddButtons = max == null || buttonList.length < max const sanitizeValue = val => { return val?.map(button => { @@ -86,11 +97,16 @@ focus={focusItem} draggable={buttonCount > 1} /> - - {/if} + +
diff --git a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte index a05fd9a39b..56b5deace4 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte @@ -9,11 +9,33 @@ export let bindings export let anchor export let removeButton - export let canRemove + export let nested $: readableText = isJSBinding(item.text) ? "(JavaScript function)" : runtimeToReadableBinding([...bindings, componentBindings], item.text) + + // If this is a nested setting (for example inside a grid or form block) then + // we need to mark all the settings of the actual buttons as nested too, to + // allow us to reference context provided by the block. + // We will need to update this in future if the normal button component + // gets broken into multiple settings sections, as we assume a flat array. + const updatedNestedFlags = settings => { + if (!nested || !settings?.length) { + return settings + } + let newSettings = settings.map(setting => ({ + ...setting, + nested: true, + })) + // We need to prevent bindings for the button names because of how grid + // blocks work. This is an edge case but unavoidable. + let name = newSettings.find(x => x.key === "text") + if (name) { + name.disableBindings = true + } + return newSettings + }
@@ -24,12 +46,12 @@ {componentBindings} {bindings} on:change + parseSettings={updatedNestedFlags} />
{readableText || "Button"}
col.name) $: schemaOverrides = getSchemaOverrides(columns) + $: enrichedButtons = enrichButtons(buttons) const getSchemaOverrides = columns => { let overrides = {} @@ -33,6 +43,25 @@ }) return overrides } + + const enrichButtons = buttons => { + if (!buttons?.length) { + return null + } + return buttons.map(settings => ({ + size: "M", + text: settings.text, + type: settings.type, + onClick: async row => { + // We add a fake context binding in here, which allows us to pretend + // that the grid provides a "schema" binding - that lets us use the + // clicked row in things like save row actions + const enrichedContext = { ...get(context), [get(component).id]: row } + const fn = enrichButtonActions(settings.onClick, enrichedContext) + return await fn?.({ row }) + }, + })) + }
onRowClick?.({ row: e.detail })} />
diff --git a/packages/client/src/sdk.js b/packages/client/src/sdk.js index 1d77f3e2da..69c2cc9fd4 100644 --- a/packages/client/src/sdk.js +++ b/packages/client/src/sdk.js @@ -14,6 +14,7 @@ import { dndIsDragging, confirmationStore, roleStore, + stateStore, } from "stores" import { styleable } from "utils/styleable" import { linkable } from "utils/linkable" @@ -24,9 +25,13 @@ import BlockComponent from "components/BlockComponent.svelte" import { ActionTypes } from "./constants" import { fetchDatasourceSchema } from "./utils/schema.js" import { getAPIKey } from "./utils/api.js" +import { enrichButtonActions } from "./utils/buttonActions.js" +import { processStringSync, makePropSafe } from "@budibase/string-templates" export default { API, + + // Stores authStore, notificationStore, routeStore, @@ -41,13 +46,23 @@ export default { currentRole, confirmationStore, roleStore, + stateStore, + + // Utils styleable, linkable, getAction, fetchDatasourceSchema, - Provider, - ActionTypes, getAPIKey, + enrichButtonActions, + processStringSync, + makePropSafe, + + // Components + Provider, Block, BlockComponent, + + // Constants + ActionTypes, } diff --git a/packages/frontend-core/src/components/grid/cells/GridCell.svelte b/packages/frontend-core/src/components/grid/cells/GridCell.svelte index dcc76b9c75..d10eb25528 100644 --- a/packages/frontend-core/src/components/grid/cells/GridCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/GridCell.svelte @@ -15,7 +15,7 @@ $: style = getStyle(width, selectedUser) const getStyle = (width, selectedUser) => { - let style = `flex: 0 0 ${width}px;` + let style = width === "auto" ? "width: auto;" : `flex: 0 0 ${width}px;` if (selectedUser) { style += `--user-color:${selectedUser.color};` } diff --git a/packages/frontend-core/src/components/grid/layout/ButtonColumn.svelte b/packages/frontend-core/src/components/grid/layout/ButtonColumn.svelte new file mode 100644 index 0000000000..d484f9408d --- /dev/null +++ b/packages/frontend-core/src/components/grid/layout/ButtonColumn.svelte @@ -0,0 +1,144 @@ + + + +
+ +
+ {#each buttons as button} + + {/each} +
+
+
+ +
+
($hoveredRowId = null)}> + + {#each $renderedRows as row} + {@const rowSelected = !!$selectedRows[row._id]} + {@const rowHovered = $hoveredRowId === row._id} + {@const rowFocused = $focusedRow?._id === row._id} +
($hoveredRowId = row._id)} + on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)} + > + +
+ {#each buttons as button} + + {/each} +
+
+
+ {/each} +
+
+
+ + diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index e2ecd0f968..285282ddf7 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -48,6 +48,7 @@ export let fixedRowHeight = null export let notifySuccess = null export let notifyError = null + export let buttons = null // Unique identifier for DOM nodes inside this instance const rand = Math.random() @@ -99,6 +100,7 @@ fixedRowHeight, notifySuccess, notifyError, + buttons, }) // Set context for children to consume diff --git a/packages/frontend-core/src/components/grid/layout/GridBody.svelte b/packages/frontend-core/src/components/grid/layout/GridBody.svelte index 0bb2a51fb4..559c465b86 100644 --- a/packages/frontend-core/src/components/grid/layout/GridBody.svelte +++ b/packages/frontend-core/src/components/grid/layout/GridBody.svelte @@ -3,6 +3,7 @@ import GridScrollWrapper from "./GridScrollWrapper.svelte" import GridRow from "./GridRow.svelte" import { BlankRowID } from "../lib/constants" + import ButtonColumn from "./ButtonColumn.svelte" const { bounds, @@ -13,6 +14,7 @@ dispatch, isDragging, config, + props, } = getContext("grid") let body @@ -54,6 +56,9 @@ /> {/if} + {#if $props.buttons?.length} + + {/if}