diff --git a/.github/workflows/deploy-featurebranch.yml b/.github/workflows/deploy-featurebranch.yml new file mode 100644 index 0000000000..9057d32c4c --- /dev/null +++ b/.github/workflows/deploy-featurebranch.yml @@ -0,0 +1,19 @@ +name: deploy-featurebranch + +on: + pull_request: + branches: + - develop + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: passeidireto/trigger-external-workflow-action@main + env: + BRANCH: ${{ github.head_ref }} + with: + repository: budibase/budibase-deploys + event: featurebranch-qa-deploy + github_pat: ${{ secrets.GH_ACCESS_TOKEN }} diff --git a/lerna.json b/lerna.json index 05fea191af..b3411e35a2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.30-alpha.13", + "version": "2.9.33-alpha.4", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 4a5ef890bf..cc169eac09 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -17,6 +17,7 @@ export default function positionDropdown(element, opts) { maxWidth, useAnchorWidth, offset = 5, + customUpdate, } = opts if (!anchor) { return @@ -32,33 +33,42 @@ export default function positionDropdown(element, opts) { left: null, top: null, } - // Determine vertical styles - if (align === "right-outside") { - styles.top = anchorBounds.top - } else if (window.innerHeight - anchorBounds.bottom < (maxHeight || 100)) { - styles.top = anchorBounds.top - elementBounds.height - offset - styles.maxHeight = maxHeight || 240 - } else { - styles.top = anchorBounds.bottom + offset - styles.maxHeight = - maxHeight || window.innerHeight - anchorBounds.bottom - 20 - } - // Determine horizontal styles - if (!maxWidth && useAnchorWidth) { - styles.maxWidth = anchorBounds.width - } - if (useAnchorWidth) { - styles.minWidth = anchorBounds.width - } - if (align === "right") { - styles.left = anchorBounds.left + anchorBounds.width - elementBounds.width - } else if (align === "right-outside") { - styles.left = anchorBounds.right + offset - } else if (align === "left-outside") { - styles.left = anchorBounds.left - elementBounds.width - offset + if (typeof customUpdate === "function") { + styles = customUpdate(anchorBounds, elementBounds, styles) } else { - styles.left = anchorBounds.left + // Determine vertical styles + if (align === "right-outside") { + styles.top = anchorBounds.top + } else if ( + window.innerHeight - anchorBounds.bottom < + (maxHeight || 100) + ) { + styles.top = anchorBounds.top - elementBounds.height - offset + styles.maxHeight = maxHeight || 240 + } else { + styles.top = anchorBounds.bottom + offset + styles.maxHeight = + maxHeight || window.innerHeight - anchorBounds.bottom - 20 + } + + // Determine horizontal styles + if (!maxWidth && useAnchorWidth) { + styles.maxWidth = anchorBounds.width + } + if (useAnchorWidth) { + styles.minWidth = anchorBounds.width + } + if (align === "right") { + styles.left = + anchorBounds.left + anchorBounds.width - elementBounds.width + } else if (align === "right-outside") { + styles.left = anchorBounds.right + offset + } else if (align === "left-outside") { + styles.left = anchorBounds.left - elementBounds.width - offset + } else { + styles.left = anchorBounds.left + } } // Apply styles diff --git a/packages/bbui/src/DetailSummary/DetailSummary.svelte b/packages/bbui/src/DetailSummary/DetailSummary.svelte index f7e2611792..daa9f3f5ca 100644 --- a/packages/bbui/src/DetailSummary/DetailSummary.svelte +++ b/packages/bbui/src/DetailSummary/DetailSummary.svelte @@ -44,7 +44,9 @@ align-items: stretch; border-bottom: var(--border-light); } - + .property-group-container:last-child { + border-bottom: 0px; + } .property-group-name { cursor: pointer; display: flex; diff --git a/packages/bbui/src/Drawer/Drawer.svelte b/packages/bbui/src/Drawer/Drawer.svelte index 4ff4df854b..421d12615f 100644 --- a/packages/bbui/src/Drawer/Drawer.svelte +++ b/packages/bbui/src/Drawer/Drawer.svelte @@ -4,6 +4,8 @@ import Body from "../Typography/Body.svelte" import Heading from "../Typography/Heading.svelte" import { setContext } from "svelte" + import { createEventDispatcher } from "svelte" + import { generate } from "shortid" export let title export let fillWidth @@ -11,13 +13,17 @@ export let width = "calc(100% - 626px)" export let headless = false + const dispatch = createEventDispatcher() + let visible = false + let drawerId = generate() export function show() { if (visible) { return } visible = true + dispatch("drawerShow", drawerId) } export function hide() { @@ -25,6 +31,7 @@ return } visible = false + dispatch("drawerHide", drawerId) } setContext("drawer-actions", { diff --git a/packages/bbui/src/Form/Core/Combobox.svelte b/packages/bbui/src/Form/Core/Combobox.svelte index b68a24d8db..b1b264a9b7 100644 --- a/packages/bbui/src/Form/Core/Combobox.svelte +++ b/packages/bbui/src/Form/Core/Combobox.svelte @@ -2,8 +2,8 @@ import "@spectrum-css/inputgroup/dist/index-vars.css" import "@spectrum-css/popover/dist/index-vars.css" import "@spectrum-css/menu/dist/index-vars.css" - import { fly } from "svelte/transition" import { createEventDispatcher } from "svelte" + import clickOutside from "../../Actions/click_outside" export let value = null export let id = null @@ -80,10 +80,11 @@ {#if open} -
(open = false)} />
{ + open = false + }} >
- + Configure validation rules for this field. @@ -41,7 +40,7 @@ bind:rules={value} {type} {bindings} - {componentDefinition} + fieldName={componentInstance?.field} /> diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentInfoSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentInfoSection.svelte index f0288f0059..e73e6d7841 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentInfoSection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentInfoSection.svelte @@ -1,36 +1,12 @@ - -
-
- - {componentDefinition.name} -
- {componentDefinition.info} -
+ + - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte index 2ff605cc77..581e69cfaf 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte @@ -5,7 +5,7 @@ import DesignSection from "./DesignSection.svelte" import CustomStylesSection from "./CustomStylesSection.svelte" import ConditionalUISection from "./ConditionalUISection.svelte" - import ComponentInfoSection from "./ComponentInfoSection.svelte" + import { getBindableProperties, getComponentBindableProperties, @@ -55,9 +55,6 @@
{#if section == "settings"} - {#if componentDefinition?.info} - - {/if} { try { - await store.actions.components.updateSetting(setting.key, value) - + if (typeof onUpdateSetting === "function") { + await onUpdateSetting(setting, value) + } else { + await store.actions.components.updateSetting(setting.key, value) + } // Send event if required if (setting.sendEvents) { analytics.captureEvent(Events.COMPONENT_UPDATED, { @@ -97,7 +104,7 @@ } } - return true + return typeof setting.visible == "boolean" ? setting.visible : true } const canRenderControl = (instance, setting, isScreen) => { @@ -116,9 +123,22 @@ {#each sections as section, idx (section.name)} {#if section.visible} - + + {#if section.info} + + {:else if idx === 0 && section.name === "General" && componentDefinition.info} + + {/if}
- {#if idx === 0 && !componentInstance._component.endsWith("/layout") && !isScreen} + {#if idx === 0 && !componentInstance._component.endsWith("/layout") && !isScreen && showInstanceName} {/if} {/each} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/InfoDisplay.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/InfoDisplay.svelte new file mode 100644 index 0000000000..03bf771beb --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/InfoDisplay.svelte @@ -0,0 +1,66 @@ + + +
+ {#if title} +
+ + {title || ""} +
+ + {@html body} + {:else} + + + + + {@html body} + {/if} +
+ + diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index 6fa5822986..62ce0dc4d9 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -1,4 +1,4 @@ export { CommandWord, InitType, AnalyticsEvent } from "@budibase/types" -export const POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS" +export const POSTHOG_TOKEN = "phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU" export const GENERATED_USER_EMAIL = "admin@admin.com" diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 4c3b432de0..9194ac0838 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -4737,7 +4737,7 @@ ] }, { - "label": "Fields", + "label": "", "type": "fieldConfiguration", "key": "sidePanelFields", "nested": true, @@ -4747,17 +4747,7 @@ } }, { - "label": "Show delete", - "type": "boolean", - "key": "sidePanelShowDelete", - "nested": true, - "dependsOn": { - "setting": "clickBehaviour", - "value": "details" - } - }, - { - "label": "Save label", + "label": "Save button", "type": "text", "key": "sidePanelSaveLabel", "defaultValue": "Save", @@ -4768,7 +4758,7 @@ } }, { - "label": "Delete label", + "label": "Delete button", "type": "text", "key": "sidePanelDeleteLabel", "defaultValue": "Delete", @@ -5284,17 +5274,6 @@ "label": "Table", "key": "dataSource" }, - { - "type": "text", - "label": "Row ID", - "key": "rowId", - "nested": true, - "dependsOn": { - "setting": "actionType", - "value": "Create", - "invert": true - } - }, { "type": "text", "label": "Title", @@ -5302,116 +5281,55 @@ "nested": true }, { - "type": "select", - "label": "Size", - "key": "size", - "options": [ - { - "label": "Medium", - "value": "spectrum--medium" - }, - { - "label": "Large", - "value": "spectrum--large" - } - ], - "defaultValue": "spectrum--medium" - }, - { - "type": "text", - "label": "Empty text", - "key": "noRowsMessage", - "defaultValue": "We couldn't find a row to display", + "section": true, "dependsOn": { "setting": "actionType", "value": "Create", "invert": true - } - }, - { - "section": true, - "name": "Fields", + }, + "name": "Row details", + "info": "How to pass a row ID using bindings", "settings": [ { - "type": "fieldConfiguration", - "label": "Fields", - "key": "fields", - "selectAllFields": true + "type": "text", + "label": "Row ID", + "key": "rowId", + "nested": true }, { - "type": "select", - "label": "Field labels", - "key": "labelPosition", - "defaultValue": "left", - "options": [ - { - "label": "Left", - "value": "left" - }, - { - "label": "Above", - "value": "above" - } - ] - }, - { - "type": "boolean", - "label": "Disabled", - "key": "disabled", - "defaultValue": false, - "dependsOn": { - "setting": "actionType", - "value": "View", - "invert": true - } + "type": "text", + "label": "Empty text", + "key": "noRowsMessage", + "defaultValue": "We couldn't find a row to display", + "nested": true } ] }, { "section": true, "name": "Buttons", + "dependsOn": { + "setting": "actionType", + "value": "View", + "invert": true + }, "settings": [ - { - "type": "boolean", - "label": "Show save button", - "key": "showSaveButton", - "defaultValue": true, - "dependsOn": { - "setting": "actionType", - "value": "View", - "invert": true - } - }, { "type": "text", "key": "saveButtonLabel", - "label": "Save button label", + "label": "Save button", "nested": true, - "defaultValue": "Save", - "dependsOn": { - "setting": "showSaveButton", - "value": true - } - }, - { - "type": "boolean", - "label": "Allow delete", - "key": "showDeleteButton", - "defaultValue": false, - "dependsOn": { - "setting": "actionType", - "value": "Update" - } + "defaultValue": "Save" }, { "type": "text", "key": "deleteButtonLabel", - "label": "Delete button label", + "label": "Delete button", "nested": true, "defaultValue": "Delete", "dependsOn": { - "setting": "showDeleteButton", - "value": true + "setting": "actionType", + "value": "Update" } }, { @@ -5429,7 +5347,67 @@ "type": "boolean", "label": "Hide notifications", "key": "notificationOverride", - "defaultValue": false + "defaultValue": false, + "dependsOn": { + "setting": "actionType", + "value": "View", + "invert": true + } + } + ] + }, + { + "section": true, + "name": "Fields", + "settings": [ + { + "type": "select", + "label": "Align labels", + "key": "labelPosition", + "defaultValue": "left", + "options": [ + { + "label": "Left", + "value": "left" + }, + { + "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": "fieldConfiguration", + "key": "fields", + "nested": true, + "selectAllFields": true + }, + { + "type": "boolean", + "label": "Disabled", + "key": "disabled", + "defaultValue": false, + "dependsOn": { + "setting": "actionType", + "value": "View", + "invert": true + } } ] } diff --git a/packages/client/src/components/app/blocks/TableBlock.svelte b/packages/client/src/components/app/blocks/TableBlock.svelte index efc83fd5ac..e07c26544c 100644 --- a/packages/client/src/components/app/blocks/TableBlock.svelte +++ b/packages/client/src/components/app/blocks/TableBlock.svelte @@ -45,6 +45,9 @@ let enrichedSearchColumns let schemaLoaded = false + // Accommodate old config to ensure delete button does not reappear + $: deleteLabel = sidePanelShowDelete === false ? "" : sidePanelDeleteLabel + $: fetchSchema(dataSource) $: enrichSearchColumns(searchColumns, schema).then( val => (enrichedSearchColumns = val) @@ -245,10 +248,8 @@ bind:id={detailsFormBlockId} props={{ dataSource, - showSaveButton: true, - showDeleteButton: sidePanelShowDelete, - saveButtonLabel: sidePanelSaveLabel, - deleteButtonLabel: sidePanelDeleteLabel, + saveButtonLabel: sidePanelSaveLabel || "Save", //always show + deleteButtonLabel: deleteLabel, //respect config actionType: "Update", rowId: `{{ ${safe("state")}.${safe(stateKey)} }}`, fields: sidePanelFields || normalFields, diff --git a/packages/client/src/components/app/blocks/form/FormBlock.svelte b/packages/client/src/components/app/blocks/form/FormBlock.svelte index 20faee9013..5d57d10ab6 100644 --- a/packages/client/src/components/app/blocks/form/FormBlock.svelte +++ b/packages/client/src/components/app/blocks/form/FormBlock.svelte @@ -12,42 +12,59 @@ export let fields export let labelPosition export let title + export let showDeleteButton + export let showSaveButton export let saveButtonLabel export let deleteButtonLabel - export let showSaveButton - export let showDeleteButton export let rowId export let actionUrl export let noRowsMessage export let notificationOverride + // Accommodate old config to ensure delete button does not reappear + $: deleteLabel = showDeleteButton === false ? "" : deleteButtonLabel?.trim() + $: saveLabel = showSaveButton === false ? "" : saveButtonLabel?.trim() + const { fetchDatasourceSchema } = getContext("sdk") const convertOldFieldFormat = fields => { - if (typeof fields?.[0] === "string") { - return fields.map(field => ({ name: field, displayName: field })) + if (!fields) { + return [] } - - return fields + return fields.map(field => { + if (typeof field === "string") { + // existed but was a string + return { + name: field, + active: true, + } + } else { + // existed but had no state + return { + ...field, + active: typeof field?.active != "boolean" ? true : field?.active, + } + } + }) } const getDefaultFields = (fields, schema) => { - if (schema && (!fields || fields.length === 0)) { - const defaultFields = [] - - Object.values(schema).forEach(field => { - if (field.autocolumn) return - - defaultFields.push({ - name: field.name, - displayName: field.name, - }) - }) - - return defaultFields + if (!schema) { + return [] } + let defaultFields = [] - return fields + 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) } let schema @@ -56,7 +73,6 @@ $: formattedFields = convertOldFieldFormat(fields) $: fieldsOrDefault = getDefaultFields(formattedFields, schema) - $: fetchSchema(dataSource) $: dataProvider = `{{ literal ${safe(providerId)} }}` $: filter = [ @@ -82,15 +98,12 @@ fields: fieldsOrDefault, labelPosition, title, - saveButtonLabel, - deleteButtonLabel, - showSaveButton, - showDeleteButton, + saveButtonLabel: saveLabel, + deleteButtonLabel: deleteLabel, schema, repeaterId, notificationOverride, } - const fetchSchema = async () => { schema = (await fetchDatasourceSchema(dataSource)) || {} } diff --git a/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte b/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte index c638d58737..3c194e0f82 100644 --- a/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte +++ b/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte @@ -13,8 +13,6 @@ export let title export let saveButtonLabel export let deleteButtonLabel - export let showSaveButton - export let showDeleteButton export let schema export let repeaterId export let notificationOverride @@ -100,18 +98,33 @@ }, ] - $: renderDeleteButton = showDeleteButton && actionType === "Update" - $: renderSaveButton = showSaveButton && actionType !== "View" + $: renderDeleteButton = deleteButtonLabel && actionType === "Update" + $: renderSaveButton = saveButtonLabel && actionType !== "View" $: renderButtons = renderDeleteButton || renderSaveButton $: renderHeader = renderButtons || title const getComponentForField = field => { - if (!field || !schema?.[field]) { + const fieldSchemaName = field.field || field.name + if (!fieldSchemaName || !schema?.[fieldSchemaName]) { return null } - const type = schema[field].type + const type = schema[fieldSchemaName].type return FieldTypeToComponentMap[type] } + + const getPropsForField = field => { + let fieldProps = field._component + ? { + ...field, + } + : { + field: field.name, + label: field.name, + placeholder: field.name, + _instanceName: field.name, + } + return fieldProps + } {#if fields?.length} @@ -175,7 +188,7 @@ {#each fields as field, idx} - {#if getComponentForField(field.name)} + {#if getComponentForField(field) && field.active} {/if} diff --git a/packages/pro b/packages/pro index b7815e099b..140386c7ad 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit b7815e099bbd5e1410185c464dbd54f7287e732f +Subproject commit 140386c7ad7e3d50bd361fc702e49b288c1747c2 diff --git a/scripts/link-dependencies.sh b/scripts/link-dependencies.sh index ed42f29b4a..921e3be8f3 100755 --- a/scripts/link-dependencies.sh +++ b/scripts/link-dependencies.sh @@ -54,24 +54,36 @@ if [ -d "../account-portal" ]; then yarn bootstrap cd packages/server - echo "Linking backend-core to account-portal" + echo "Linking backend-core to account-portal (server)" yarn link "@budibase/backend-core" - echo "Linking string-templates to account-portal" + echo "Linking string-templates to account-portal (server)" yarn link "@budibase/string-templates" - echo "Linking types to account-portal" + echo "Linking types to account-portal (server)" yarn link "@budibase/types" + echo "Linking shared-core to account-portal (server)" + yarn link "@budibase/shared-core" + if [ $pro_loaded_locally = true ]; then - echo "Linking pro to account-portal" + echo "Linking pro to account-portal (server)" yarn link "@budibase/pro" fi cd ../ui - echo "Linking bbui to account-portal" + echo "Linking bbui to account-portal (ui)" yarn link "@budibase/bbui" - echo "Linking frontend-core to account-portal" + echo "Linking shared-core to account-portal (ui)" + yarn link "@budibase/shared-core" + + echo "Linking string-templates to account-portal (ui)" + yarn link "@budibase/string-templates" + + echo "Linking types to account-portal (ui)" + yarn link "@budibase/types" + + echo "Linking frontend-core to account-portal (ui)" yarn link "@budibase/frontend-core" fi