From bcf431a476bffe9691824f1561aed5843bff4c04 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 8 Nov 2023 14:43:28 +0000 Subject: [PATCH 01/79] Fix a few svelte bugs with the LinkedRowSelector component to fix adding/editing relationships via a model from the data UI --- .../automation/SetupPanel/RowSelectorTypes.svelte | 2 +- .../components/backend/DataTable/RowFieldControl.svelte | 7 ++++++- .../builder/src/components/common/LinkedRowSelector.svelte | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte index 373d174541..f6cce6182c 100644 --- a/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte +++ b/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte @@ -64,7 +64,7 @@ {:else if schema.type === "link"} onChange(e, field)} /> diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte index 61b706e28e..1ec32cb3fd 100644 --- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte +++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte @@ -70,7 +70,12 @@ options={meta.constraints.inclusion} /> {:else if type === "link"} - + (value = e.detail)} + /> {:else if type === "longform"} {#if meta.useRichText} diff --git a/packages/builder/src/components/common/LinkedRowSelector.svelte b/packages/builder/src/components/common/LinkedRowSelector.svelte index d357a0a54d..c45b7be195 100644 --- a/packages/builder/src/components/common/LinkedRowSelector.svelte +++ b/packages/builder/src/components/common/LinkedRowSelector.svelte @@ -56,12 +56,12 @@ /> {:else} row._id} sort - on:change={() => dispatch("change", linkedIds)} + on:change /> {/if} From 217ac49628c520f522cd3f503e577971f6232496 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 21 Nov 2023 13:02:06 +0000 Subject: [PATCH 02/79] wip --- packages/bbui/src/Form/Core/TextField.svelte | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/bbui/src/Form/Core/TextField.svelte b/packages/bbui/src/Form/Core/TextField.svelte index 7afd8f86c3..cbc062d99a 100644 --- a/packages/bbui/src/Form/Core/TextField.svelte +++ b/packages/bbui/src/Form/Core/TextField.svelte @@ -21,7 +21,7 @@ let focus = false const updateValue = newValue => { - if (readonly) { + if (readonly || disabled) { return } if (type === "number") { @@ -32,14 +32,14 @@ } const onFocus = () => { - if (readonly) { + if (readonly || disabled) { return } focus = true } const onBlur = event => { - if (readonly) { + if (readonly || disabled) { return } focus = false @@ -47,14 +47,14 @@ } const onInput = event => { - if (readonly || !updateOnChange) { + if (readonly || !updateOnChange || disabled) { return } updateValue(event.target.value) } const updateValueOnEnter = event => { - if (readonly) { + if (readonly || disabled) { return } if (event.key === "Enter") { @@ -66,10 +66,12 @@ if (type === "bigint") { return "numeric" } - return type === "number" ? "decimal" : "text" + return type === "number" ? +"decimal" : "text" } onMount(() => { + if (disabled) return; focus = autofocus if (focus) field.focus() }) @@ -119,4 +121,8 @@ .spectrum-Textfield { width: 100%; } + + input:focus:hover::placeholder { + color: var(--grey-8) !important; + } From 96046dab3dc56246056fadfc490030ca22517d42 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 21 Nov 2023 14:51:01 +0000 Subject: [PATCH 03/79] component name tooltips --- .../builder/src/builderStore/componentUtils.js | 17 +++++++++++++++++ .../src/components/common/NavItem.svelte | 5 ++++- .../builder/src/components/design/Panel.svelte | 7 +++++-- .../Component/ComponentSettingsPanel.svelte | 8 +++++--- .../ComponentList/ComponentTree.svelte | 2 ++ 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/builderStore/componentUtils.js b/packages/builder/src/builderStore/componentUtils.js index 522dbae416..85171ece66 100644 --- a/packages/builder/src/builderStore/componentUtils.js +++ b/packages/builder/src/builderStore/componentUtils.js @@ -1,4 +1,5 @@ import { store } from "./index" +import { get } from "svelte/store" import { Helpers } from "@budibase/bbui" import { decodeJSBinding, @@ -238,6 +239,10 @@ export const makeComponentUnique = component => { } export const getComponentText = component => { + if (component == null) { + return "" + } + if (component?._instanceName) { return component._instanceName } @@ -246,3 +251,15 @@ export const getComponentText = component => { "component" return capitalise(type) } + +export const getComponentName = component => { + if (component == null) { + return "" + } + + const components = get(store)?.components || {}; + const componentDefinition = components[component._component] || {}; + const name = componentDefinition.friendlyName || componentDefinition.name || ""; + + return name; +} diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte index 2c8a862535..5ec399a7ea 100644 --- a/packages/builder/src/components/common/NavItem.svelte +++ b/packages/builder/src/components/common/NavItem.svelte @@ -1,10 +1,11 @@ {#if $selectedComponent} {#key $selectedComponent._id} - + { if (e.key.toLowerCase() === "enter") { e.target.blur() diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ComponentList/ComponentTree.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ComponentList/ComponentTree.svelte index 8adc6cb5d4..6b5d356deb 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ComponentList/ComponentTree.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ComponentList/ComponentTree.svelte @@ -11,6 +11,7 @@ import { findComponentPath, getComponentText, + getComponentName, } from "builderStore/componentUtils" import { get } from "svelte/store" import { dndStore } from "./dndStore" @@ -109,6 +110,7 @@ on:drop={onDrop} text={getComponentText(component)} icon={getComponentIcon(component)} + iconTooltip={getComponentName(component)} withArrow={componentHasChildren(component)} indentLevel={level} selected={$store.selectedComponentId === component._id} From f1c3d50930c288b2d4d0aa33a373aecefce8b7c5 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Wed, 22 Nov 2023 20:50:55 +0000 Subject: [PATCH 04/79] functioning resize --- .../_components/ScreenList/index.svelte | 90 +++++-------- .../_components/ScreenList/resizable.js | 121 ++++++++++++++++++ 2 files changed, 150 insertions(+), 61 deletions(-) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte index ef5911c0f8..a7d56e047a 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte @@ -9,51 +9,42 @@ import NavItem from "components/common/NavItem.svelte" import RoleIndicator from "./RoleIndicator.svelte" import DropdownMenu from "./DropdownMenu.svelte" - import { onMount, tick } from "svelte" import { goto } from "@roxi/routify" + import { getVerticalResizeActions } from './resizable'; + import { tick } from "svelte" - let search = false + const [resizable, resizableHandle] = getVerticalResizeActions(); + + let searching = false let resizing = false let searchValue = "" let searchInput let container let screensContainer let scrolling = false - let previousHeight = null - let dragOffset $: filteredScreens = getFilteredScreens($sortedScreens, searchValue) - const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) - const openSearch = async () => { - search = true + searching = true await tick() searchInput.focus() screensContainer.scroll({ top: 0, behavior: "smooth" }) - previousHeight = $screensHeight - $screensHeight = "calc(100% + 1px)" } const closeSearch = async () => { - if (previousHeight) { - // Restore previous height and wait for animation - $screensHeight = previousHeight - previousHeight = null - await sleep(300) - } - search = false + searching = false searchValue = "" } - const getFilteredScreens = (screens, search) => { + const getFilteredScreens = (screens, searchValue) => { return screens.filter(screen => { - return !search || screen.routing.route.includes(search) + return !searchValue || screen.routing.route.includes(searchValue) }) } const handleAddButton = () => { - if (search) { + if (searching) { closeSearch() } else { $goto("../new") @@ -70,67 +61,35 @@ scrolling = e.target.scrollTop !== 0 } - const startResizing = e => { - // Reset the height store to match the true height - $screensHeight = `${container.getBoundingClientRect().height}px` - - // Store an offset to easily compute new height when moving the mouse - dragOffset = parseInt($screensHeight) - e.clientY - - // Add event listeners - resizing = true - document.addEventListener("mousemove", resize) - document.addEventListener("mouseup", stopResizing) - } - - const resize = e => { - // Prevent negative heights as this screws with layout - const newHeight = Math.max(0, e.clientY + dragOffset) - if (newHeight == null || isNaN(newHeight)) { - return - } - $screensHeight = `${newHeight}px` - } - - const stopResizing = () => { - resizing = false - document.removeEventListener("mousemove", resize) - } - - onMount(() => { - // Ensure we aren't stuck at 100% height from leaving while searching - if ($screensHeight == null || isNaN(parseInt($screensHeight))) { - $screensHeight = "210px" - } - })
-
+
Screens
-
+
@@ -164,8 +123,10 @@
screensHeight.set("210px")} />
@@ -177,10 +138,11 @@ min-height: 147px; max-height: calc(100% - 147px); position: relative; - } - .screens.search { transition: height 300ms ease-out; + } + .screens.searching { max-height: none; + height: 100% !important; } .screens.resizing { user-select: none; @@ -219,7 +181,7 @@ .input::placeholder { color: var(--spectrum-global-color-gray-600); } - .screens.search input { + .screens.searching input { display: block; } @@ -305,4 +267,10 @@ .divider:hover:after { background: var(--spectrum-global-color-gray-300); } + .divider.disabled { + cursor: auto; + } + .divider.disabled:after { + background: var(--spectrum-global-color-gray-200); + } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js new file mode 100644 index 0000000000..c3bccf024d --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js @@ -0,0 +1,121 @@ +export const getHorizontalResizeActions = (initialValue, setValue = () => {}) => { + let element = null; + + const elementAction = (node) => { + element = node; + + if (initialValue != null) { + element.style.height = `${initialValue}px` + } + + return { + destroy() { + element = null; + } + } + } + + const dragHandleAction = (node) => { + let startWidth = null; + let startPosition = null; + + const handleMouseMove = (e) => { + const change = e.pageX - startPosition; + element.style.width = `${startWidth + change}px` + } + + const handleMouseUp = () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + element.style.removeProperty('transition'); // remove temporary transition override + setValue(element.clientHeight); + } + + const handleMouseDown = (e) => { + if (e.target.hasAttribute("disabled") && e.target.getAttribute("disabled") !== "false") { + return; + } + + element.style.transition = "width 0ms"; // temporarily override any width transitions + startWidth = element.clientWidth; + startPosition = e.pageX; + + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + }; + + node.addEventListener("mousedown", handleMouseDown); + + return { + destroy() { + node.removeEventListener("mousedown", handleMouseDown); + } + } + } + + return [ + elementAction, + dragHandleAction + ] +}; + +export const getVerticalResizeActions = (initialValue, setValue = () => {}) => { + let element = null; + + const elementAction = (node) => { + element = node; + + if (initialValue != null) { + element.style.height = `${initialValue}px` + } + + return { + destroy() { + element = null; + } + } + } + + const dragHandleAction = (node) => { + let startHeight = null; + let startPosition = null; + + const handleMouseMove = (e) => { + const change = e.pageY - startPosition; + element.style.height = `${startHeight + change}px` + } + + const handleMouseUp = () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + element.style.removeProperty('transition'); // remove temporary transition override + setValue(element.clientHeight); + } + + const handleMouseDown = (e) => { + if (e.target.hasAttribute("disabled") && e.target.getAttribute("disabled") !== "false") { + return; + } + + element.style.transition = "height 0ms"; // temporarily override any height transitions + startHeight = element.clientHeight; + startPosition = e.pageY; + + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + }; + + node.addEventListener("mousedown", handleMouseDown); + + return { + destroy() { + node.removeEventListener("mousedown", handleMouseDown); + } + } + } + + return [ + elementAction, + dragHandleAction + ] +}; From 3d39a2f77b85b56fd0c563e7ddf59ba2d91f44aa Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 23 Nov 2023 09:47:07 +0000 Subject: [PATCH 05/79] Fix relationship filter setting being ignored, and debounce searches --- .../app/forms/RelationshipField.svelte | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/client/src/components/app/forms/RelationshipField.svelte b/packages/client/src/components/app/forms/RelationshipField.svelte index 41a071686e..f047b53a94 100644 --- a/packages/client/src/components/app/forms/RelationshipField.svelte +++ b/packages/client/src/components/app/forms/RelationshipField.svelte @@ -1,6 +1,6 @@
-
-
- -
-
- {#if $store.clientFeatures.devicePreview} - - {/if} -
-
- {#key $store.version} - - {/key} +
+
+ +
+
+ {#if $store.clientFeatures.devicePreview} + + {/if} +
+
+
+ {#key $store.version} + + {/key} +
+ From 9b99991b2e1267bebd772a80d2001a844c302bf5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 23 Nov 2023 14:01:58 +0000 Subject: [PATCH 10/79] Update SDK to account for new creator builder flag --- packages/shared-core/src/sdk/documents/users.ts | 10 +++++++++- packages/types/src/documents/global/user.ts | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/shared-core/src/sdk/documents/users.ts b/packages/shared-core/src/sdk/documents/users.ts index b58994aa46..ccd88bf854 100644 --- a/packages/shared-core/src/sdk/documents/users.ts +++ b/packages/shared-core/src/sdk/documents/users.ts @@ -87,13 +87,21 @@ export function hasAdminPermissions(user?: User | ContextUser): boolean { return !!user.admin?.global } +export function hasCreatorPermissions(user?: User | ContextUser): boolean { + if (!user) { + return false + } + return !!user.builder?.creator +} + export function isCreator(user?: User | ContextUser): boolean { if (!user) { return false } return ( - isGlobalBuilder(user) || + isGlobalBuilder(user!) || hasAdminPermissions(user) || + hasCreatorPermissions(user) || hasAppBuilderPermissions(user) || hasAppCreatorPermissions(user) ) diff --git a/packages/types/src/documents/global/user.ts b/packages/types/src/documents/global/user.ts index 9769661cd5..337855787f 100644 --- a/packages/types/src/documents/global/user.ts +++ b/packages/types/src/documents/global/user.ts @@ -44,6 +44,7 @@ export interface User extends Document { builder?: { global?: boolean apps?: string[] + creator?: boolean } admin?: { global: boolean From 35a35f92e61d6293a4f9648803e020a163065322 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 23 Nov 2023 14:02:29 +0000 Subject: [PATCH 11/79] Update constants and user invitation API to account for new creator flag --- packages/frontend-core/src/api/user.js | 26 ++++++++++++++++--------- packages/frontend-core/src/constants.js | 6 ++++-- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/frontend-core/src/api/user.js b/packages/frontend-core/src/api/user.js index 95c2167721..3a815b768e 100644 --- a/packages/frontend-core/src/api/user.js +++ b/packages/frontend-core/src/api/user.js @@ -214,15 +214,23 @@ export const buildUserEndpoints = API => ({ inviteUsers: async users => { return await API.post({ url: "/api/global/users/multi/invite", - body: users.map(user => ({ - email: user.email, - userInfo: { - admin: user.admin ? { global: true } : undefined, - builder: user.admin || user.builder ? { global: true } : undefined, - userGroups: user.groups, - roles: user.apps ? user.apps : undefined, - }, - })), + body: users.map(user => { + let builder = undefined + if (user.admin || user.builder) { + builder = { global: true } + } else if (user.creator) { + builder = { creator: true } + } + return { + email: user.email, + userInfo: { + admin: user.admin ? { global: true } : undefined, + builder, + userGroups: user.groups, + roles: user.apps ? user.apps : undefined, + }, + } + }), }) }, diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index 344326065a..d8982276f2 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -20,6 +20,7 @@ export const TableNames = { export const BudibaseRoles = { AppUser: "appUser", Developer: "developer", + Creator: "creator", Admin: "admin", } @@ -29,8 +30,9 @@ export const BudibaseRoleOptionsOld = [ { label: "Admin", value: BudibaseRoles.Admin }, ] export const BudibaseRoleOptions = [ - { label: "Member", value: BudibaseRoles.AppUser }, - { label: "Admin", value: BudibaseRoles.Admin }, + { label: "App user", value: BudibaseRoles.AppUser }, + { label: "Creator", value: BudibaseRoles.Creator }, + { label: "Account admin", value: BudibaseRoles.Admin }, ] export const BudibaseRoleOptionsNew = [ From b72b93e5b28cc3fcf28220dc2bff0dd2ee6c77ce Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 23 Nov 2023 14:03:23 +0000 Subject: [PATCH 12/79] Update user invitation modal and details page to allow creating creator users --- .../portal/users/users/[userId].svelte | 23 +++++++++++++++---- .../users/_components/AddUserModal.svelte | 2 +- .../builder/portal/users/users/index.svelte | 1 + 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index ec10ec8316..07ed1b26f4 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -98,7 +98,17 @@ return y._id === userId }) }) - $: globalRole = sdk.users.isAdmin(user) ? "admin" : "appUser" + $: globalRole = getGlobalRole(user) + + const getGlobalRole = user => { + if (sdk.users.isAdmin(user)) { + return Constants.BudibaseRoles.Admin + } else if (sdk.users.isCreator(user)) { + return Constants.BudibaseRoles.Creator + } else { + return Constants.BudibaseRoles.AppUser + } + } const getAvailableApps = (appList, privileged, roles) => { let availableApps = appList.slice() @@ -177,12 +187,17 @@ } async function updateUserRole({ detail }) { - if (detail === "developer") { + if (detail === Constants.BudibaseRoles.Developer) { toggleFlags({ admin: { global: false }, builder: { global: true } }) - } else if (detail === "admin") { + } else if (detail === Constants.BudibaseRoles.Admin) { toggleFlags({ admin: { global: true }, builder: { global: true } }) - } else if (detail === "appUser") { + } else if (detail === Constants.BudibaseRoles.AppUser) { toggleFlags({ admin: { global: false }, builder: { global: false } }) + } else if (detail === Constants.BudibaseRoles.Creator) { + toggleFlags({ + admin: { global: false }, + builder: { global: false, creator: true }, + }) } } diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte index 806468021f..0730c31674 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte @@ -98,7 +98,7 @@ align-items: center; flex-direction: row;" > -
+
({ email: user.email, builder: user.role === Constants.BudibaseRoles.Developer, + creator: user.role === Constants.BudibaseRoles.Creator, admin: user.role === Constants.BudibaseRoles.Admin, groups: userData.groups, })) From e0e27aa3c96a09c1fedc2060c9bc0e6c307266b5 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Thu, 23 Nov 2023 14:09:14 +0000 Subject: [PATCH 13/79] wip --- .../[screenId]/_components/AppPanel.svelte | 42 +++++------------ .../[screenId]/_components/LeftPanel.svelte | 46 +++++++++++++++++-- .../_components/ScreenList/resizable.js | 1 + 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte index 7cd3261bce..09f97302fd 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte @@ -3,42 +3,28 @@ import AppPreview from "./AppPreview.svelte" import { store, screenHistoryStore } from "builderStore" import UndoRedoControl from "components/common/UndoRedoControl.svelte" - import { getHorizontalResizeActions } from './resizable'; - - const [resizable, resizableHandle] = getHorizontalResizeActions();
-
-
-
- -
-
- {#if $store.clientFeatures.devicePreview} - - {/if} -
+
+
+
-
- {#key $store.version} - - {/key} +
+ {#if $store.clientFeatures.devicePreview} + + {/if}
- diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte index 96d4579eeb..4f77588e9b 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte @@ -1,21 +1,59 @@ -
- - +
+
+ + +
+
+
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js index e74b72c6e5..4b9f365018 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js @@ -20,6 +20,7 @@ const getResizeActions = (cssProperty, mouseMoveEventProperty, elementProperty, let startPosition = null; const handleMouseMove = (e) => { + e.preventDefault(); // Prevent highlighting while dragging const change = e[mouseMoveEventProperty] - startPosition; element.style[cssProperty] = `${startProperty + change}px` } From fd5dd8dd72563faf541fe73b1c0cea987bf212c4 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 23 Nov 2023 14:12:10 +0000 Subject: [PATCH 14/79] Dedupe and clean up some role logic and constants, and display roles properly in user list --- .../_components/BuilderSidePanel.svelte | 4 +-- .../portal/users/users/[userId].svelte | 13 ++------- .../_components/RoleTableRenderer.svelte | 4 +-- packages/builder/src/stores/portal/users.js | 19 +++++++++---- packages/frontend-core/src/constants.js | 28 +++++++++---------- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index a67c2d3c61..5c87c1c20c 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -804,8 +804,8 @@ option.value !== Constants.BudibaseRoles.Admin )} label="Role" diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 07ed1b26f4..8bb1ba5452 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -98,17 +98,7 @@ return y._id === userId }) }) - $: globalRole = getGlobalRole(user) - - const getGlobalRole = user => { - if (sdk.users.isAdmin(user)) { - return Constants.BudibaseRoles.Admin - } else if (sdk.users.isCreator(user)) { - return Constants.BudibaseRoles.Creator - } else { - return Constants.BudibaseRoles.AppUser - } - } + $: globalRole = users.getUserRole(user) const getAvailableApps = (appList, privileged, roles) => { let availableApps = appList.slice() @@ -310,6 +300,7 @@
import ScreenList from "./ScreenList/index.svelte" import ComponentList from "./ComponentList/index.svelte" - import { getHorizontalResizeActions } from './ScreenList/resizable'; + import { getHorizontalResizeActions } from "./ScreenList/resizable" - const [resizable, resizableHandle] = getHorizontalResizeActions(); + const [resizable, resizableHandle] = getHorizontalResizeActions()
@@ -11,13 +11,8 @@
-
- @@ -898,7 +891,6 @@ display: flex; flex-direction: column; gap: var(--spacing-s); - width: 400px; } .auth-entity-meta { @@ -927,7 +919,7 @@ .auth-entity, .auth-entity-header { display: grid; - grid-template-columns: 1fr 110px; + grid-template-columns: 1fr 180px; align-items: center; gap: var(--spacing-xl); } @@ -958,7 +950,7 @@ overflow-y: auto; overflow-x: hidden; position: absolute; - width: 400px; + width: 440px; right: 0; height: 100%; box-shadow: 0 0 40px 10px rgba(0, 0, 0, 0.1); From 295965d1d392ad3238aa776c4e0b5eaa979a122e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 15:23:22 +0000 Subject: [PATCH 37/79] Move picker subtitle to below the label --- packages/bbui/src/Form/Core/Picker.svelte | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index 6361b345d1..94fbe73cf2 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -224,13 +224,12 @@ {/if} - {#if getOptionSubtitle(option, idx)} - {getOptionSubtitle(option, idx)} - {/if} - {getOptionLabel(option, idx)} + {#if getOptionSubtitle(option, idx)} + + {getOptionSubtitle(option, idx)} + + {/if} {#if option.tag} @@ -275,10 +274,9 @@ font-size: 12px; line-height: 15px; font-weight: 500; - top: 10px; color: var(--spectrum-global-color-gray-600); display: block; - margin-bottom: var(--spacing-s); + margin-top: var(--spacing-s); } .spectrum-Picker-label.auto-width { From 8ee32b4353234742451aa88185d57d61025e2cb2 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Fri, 24 Nov 2023 15:31:43 +0000 Subject: [PATCH 38/79] Changes to the single image and CouchDB image builds to make them work with new Helm chart changes. --- hosting/couchdb/Dockerfile | 3 +- hosting/couchdb/build-target-paths.sh | 24 --------------- hosting/couchdb/runner.sh | 42 +++++++++++++++++++++++++-- hosting/single/Dockerfile | 2 -- hosting/single/runner.sh | 4 +-- 5 files changed, 43 insertions(+), 32 deletions(-) delete mode 100644 hosting/couchdb/build-target-paths.sh diff --git a/hosting/couchdb/Dockerfile b/hosting/couchdb/Dockerfile index 792856cac7..f83df7038b 100644 --- a/hosting/couchdb/Dockerfile +++ b/hosting/couchdb/Dockerfile @@ -29,7 +29,6 @@ WORKDIR /opt/couchdb ADD couch/vm.args couch/local.ini ./etc/ WORKDIR / -ADD build-target-paths.sh . ADD runner.sh ./bbcouch-runner.sh -RUN chmod +x ./bbcouch-runner.sh /opt/clouseau/bin/clouseau ./build-target-paths.sh +RUN chmod +x ./bbcouch-runner.sh /opt/clouseau/bin/clouseau CMD ["./bbcouch-runner.sh"] diff --git a/hosting/couchdb/build-target-paths.sh b/hosting/couchdb/build-target-paths.sh deleted file mode 100644 index 34227011f4..0000000000 --- a/hosting/couchdb/build-target-paths.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -echo ${TARGETBUILD} > /buildtarget.txt -if [[ "${TARGETBUILD}" = "aas" ]]; then - # Azure AppService uses /home for persistent data & SSH on port 2222 - DATA_DIR="${DATA_DIR:-/home}" - WEBSITES_ENABLE_APP_SERVICE_STORAGE=true - mkdir -p $DATA_DIR/{search,minio,couch} - mkdir -p $DATA_DIR/couch/{dbs,views} - chown -R couchdb:couchdb $DATA_DIR/couch/ - apt update - apt-get install -y openssh-server - echo "root:Docker!" | chpasswd - mkdir -p /tmp - chmod +x /tmp/ssh_setup.sh \ - && (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null) - cp /etc/sshd_config /etc/ssh/sshd_config - /etc/init.d/ssh restart - sed -i "s#DATA_DIR#/home#g" /opt/clouseau/clouseau.ini - sed -i "s#DATA_DIR#/home#g" /opt/couchdb/etc/local.ini -else - sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini - sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini -fi \ No newline at end of file diff --git a/hosting/couchdb/runner.sh b/hosting/couchdb/runner.sh index 4102d2a751..2e4d26122f 100644 --- a/hosting/couchdb/runner.sh +++ b/hosting/couchdb/runner.sh @@ -1,14 +1,52 @@ #!/bin/bash DATA_DIR=${DATA_DIR:-/data} + mkdir -p ${DATA_DIR} mkdir -p ${DATA_DIR}/couch/{dbs,views} mkdir -p ${DATA_DIR}/search chown -R couchdb:couchdb ${DATA_DIR}/couch -/build-target-paths.sh + +echo ${TARGETBUILD} > /buildtarget.txt +if [[ "${TARGETBUILD}" = "aas" ]]; then + # Azure AppService uses /home for persistent data & SSH on port 2222 + DATA_DIR="${DATA_DIR:-/home}" + WEBSITES_ENABLE_APP_SERVICE_STORAGE=true + mkdir -p $DATA_DIR/{search,minio,couch} + mkdir -p $DATA_DIR/couch/{dbs,views} + chown -R couchdb:couchdb $DATA_DIR/couch/ + apt update + apt-get install -y openssh-server + echo "root:Docker!" | chpasswd + mkdir -p /tmp + chmod +x /tmp/ssh_setup.sh \ + && (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null) + cp /etc/sshd_config /etc/ssh/sshd_config + /etc/init.d/ssh restart + sed -i "s#DATA_DIR#/home#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/home#g" /opt/couchdb/etc/local.ini +elif [[ "${TARGETBUILD}" = "single" ]]; then + sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini +elif [[ -n $KUBERNETES_SERVICE_HOST ]]; then + # In Kubernetes the directory /opt/couchdb/data has a persistent volume + # mount for storing database data. + sed -i "s#DATA_DIR#/opt/couchdb/data#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/opt/couchdb/data#g" /opt/couchdb/etc/local.ini + sed -i "s/^-name .*$//g" /opt/couchdb/etc/vm.args +else + sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini +fi + /opt/clouseau/bin/clouseau > /dev/stdout 2>&1 & /docker-entrypoint.sh /opt/couchdb/bin/couchdb & -sleep 10 + +while [[ $(curl -s -w "%{http_code}\n" http://localhost:5984/_up -o /dev/null) -ne 200 ]]; do + echo 'Waiting for CouchDB to start...'; + sleep 5; +done + curl -X PUT http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@localhost:5984/_users curl -X PUT http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@localhost:5984/_replicator sleep infinity \ No newline at end of file diff --git a/hosting/single/Dockerfile b/hosting/single/Dockerfile index ec03a1b5a2..e9ff6c6596 100644 --- a/hosting/single/Dockerfile +++ b/hosting/single/Dockerfile @@ -94,8 +94,6 @@ RUN chmod +x ./healthcheck.sh # For Azure App Service install SSH & point data locations to /home COPY hosting/single/ssh/sshd_config /etc/ COPY hosting/single/ssh/ssh_setup.sh /tmp -RUN /build-target-paths.sh - # setup letsencrypt certificate RUN apt-get install -y certbot python3-certbot-nginx diff --git a/hosting/single/runner.sh b/hosting/single/runner.sh index 87201c95c0..f4b2b5b127 100644 --- a/hosting/single/runner.sh +++ b/hosting/single/runner.sh @@ -22,11 +22,11 @@ declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONME # Azure App Service customisations if [[ "${TARGETBUILD}" = "aas" ]]; then - DATA_DIR="${DATA_DIR:-/home}" + export DATA_DIR="${DATA_DIR:-/home}" WEBSITES_ENABLE_APP_SERVICE_STORAGE=true /etc/init.d/ssh start else - DATA_DIR=${DATA_DIR:-/data} + export DATA_DIR=${DATA_DIR:-/data} fi mkdir -p ${DATA_DIR} # Mount NFS or GCP Filestore if env vars exist for it From 302f6f61063ee4e370f99a26cb46408c443017f7 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 15:47:40 +0000 Subject: [PATCH 39/79] Fix footer in fancy select and allow inviting creators from side panel --- .../bbui/src/FancyForm/FancySelect.svelte | 3 + .../_components/BuilderSidePanel.svelte | 68 ++++++++++--------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/packages/bbui/src/FancyForm/FancySelect.svelte b/packages/bbui/src/FancyForm/FancySelect.svelte index e015f51570..14911f10ab 100644 --- a/packages/bbui/src/FancyForm/FancySelect.svelte +++ b/packages/bbui/src/FancyForm/FancySelect.svelte @@ -12,11 +12,13 @@ export let error = null export let validate = null export let options = [] + export let footer = null export let isOptionEnabled = () => true export let getOptionLabel = option => extractProperty(option, "label") export let getOptionValue = option => extractProperty(option, "value") export let getOptionSubtitle = option => extractProperty(option, "subtitle") export let getOptionColour = () => null + const dispatch = createEventDispatcher() let open = false @@ -100,6 +102,7 @@ {error} {disabled} {options} + {footer} {getOptionLabel} {getOptionValue} {getOptionSubtitle} diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index adb0c985dc..726b79e23d 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -364,7 +364,10 @@ const payload = [ { email: newUserEmail, - builder: { global: creationRoleType === Constants.BudibaseRoles.Admin }, + builder: { + global: creationRoleType === Constants.BudibaseRoles.Admin, + creator: creationRoleType === Constants.BudibaseRoles.Creator, + }, admin: { global: creationRoleType === Constants.BudibaseRoles.Admin }, }, ] @@ -517,6 +520,18 @@ } return user.role } + + const checkAppAccess = e => { + // Ensure we don't get into an invalid combo of tenant role and app access + if ( + e.detail === Constants.BudibaseRoles.AppUser && + creationAccessType === Constants.Roles.CREATOR + ) { + creationAccessType = Constants.Roles.BASIC + } else if (e.detail === Constants.BudibaseRoles.Admin) { + creationAccessType = Constants.Roles.CREATOR + } + } @@ -802,28 +817,29 @@ option => option.value !== Constants.BudibaseRoles.Admin )} label="Access" + on:change={checkAppAccess} /> - {#if creationRoleType !== Constants.BudibaseRoles.Admin} - - - - {/if} + + + - {#if creationRoleType === Constants.BudibaseRoles.Admin} -
- - Admins will get full access to all apps and settings -
- {/if}
-
+
- {#if open} -
-
    - {#each options as option, idx} -
  • onPick(getOptionValue(option, idx))} - > - - {getOptionLabel(option, idx)} - - -
  • - {/each} -
-
- {/if}
+ {#if open} +
+
    + {#each options as option, idx} +
  • onPick(getOptionValue(option, idx))} + > + + {getOptionLabel(option, idx)} + {#if getOptionSubtitle(option, idx)} + + {getOptionSubtitle(option, idx)} + + {/if} + + +
  • + {/each} +
+
+ {/if}
diff --git a/packages/bbui/src/Form/InputDropdown.svelte b/packages/bbui/src/Form/InputDropdown.svelte index 93766495b8..54b07cf0d7 100644 --- a/packages/bbui/src/Form/InputDropdown.svelte +++ b/packages/bbui/src/Form/InputDropdown.svelte @@ -43,6 +43,7 @@ {quiet} {autofocus} {options} + isOptionSelected={option => option === dropdownValue} on:change={onChange} on:pick={onPick} on:click diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte index 0730c31674..346b293235 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte @@ -29,7 +29,6 @@ }, ] $: hasError = userData.find(x => x.error != null) - $: userCount = $licensing.userCount + userData.length $: reached = licensing.usersLimitReached(userCount) $: exceeded = licensing.usersLimitExceeded(userCount) diff --git a/packages/builder/src/pages/builder/portal/users/users/index.svelte b/packages/builder/src/pages/builder/portal/users/users/index.svelte index 744908fd14..50afd0004a 100644 --- a/packages/builder/src/pages/builder/portal/users/users/index.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/index.svelte @@ -191,18 +191,18 @@ for (const user of userData?.users ?? []) { const { email } = user - if ( newUsers.find(x => x.email === email) || currentUserEmails.includes(email) - ) + ) { continue - + } newUsers.push(user) } - if (!newUsers.length) + if (!newUsers.length) { notifications.info("Duplicated! There is no new users to add.") + } return { ...userData, users: newUsers } } @@ -267,7 +267,6 @@ try { await groups.actions.init() groupsLoaded = true - pendingInvites = await users.getInvites() invitesLoaded = true } catch (error) { From 7f17d2f94365e0621e04b41d9d6548d5424652d5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 16:34:58 +0000 Subject: [PATCH 44/79] Allow creating creator users via users store --- packages/builder/src/stores/portal/users.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js index f653259e13..0e64d7a6cd 100644 --- a/packages/builder/src/stores/portal/users.js +++ b/packages/builder/src/stores/portal/users.js @@ -78,6 +78,9 @@ export function createUsersStore() { case "developer": body.builder = { global: true } break + case "creator": + body.builder = { creator: true, global: false } + break case "admin": body.admin = { global: true } body.builder = { global: true } From bc48661a64638ed59059159dc8cf5ec3f70d1e57 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 16:45:37 +0000 Subject: [PATCH 45/79] Lint and update user app tables to use new copy --- .../pages/builder/portal/users/users/[userId].svelte | 1 + .../users/_components/AppRoleTableRenderer.svelte | 10 +++++++--- .../users/users/_components/ImportUsersModal.svelte | 2 +- .../users/users/_components/RoleTableRenderer.svelte | 6 ------ 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 8bb1ba5452..95e297e409 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -55,6 +55,7 @@ }, role: { width: "1fr", + displayName: "Access", }, } const customGroupTableRenderers = [ diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte index a9f2ca6e08..e0b743cfa2 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte @@ -14,6 +14,10 @@ } - - {getRoleLabel(value)} - +{#if value === Constants.Roles.CREATOR} + Can edit +{:else} + + Can use as {getRoleLabel(value)} + +{/if} diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte index 24f0222d14..bb03f166b3 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte @@ -11,11 +11,11 @@ import { emailValidator } from "helpers/validation" import { Constants } from "@budibase/frontend-core" import { capitalise } from "helpers" - import { BudibaseRoleOptions } from "@budibase/frontend-core/src/constants" const BYTES_IN_MB = 1000000 const FILE_SIZE_LIMIT = BYTES_IN_MB * 5 const MAX_USERS_UPLOAD_LIMIT = 1000 + export let createUsersFromCsv let files = [] diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte index d8abacf00b..936cd12517 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte @@ -4,12 +4,6 @@ export let row - const TooltipMap = { - appUser: "Only has access to assigned apps", - developer: "Access to the app builder", - admin: "Full access", - } - $: role = Constants.BudibaseRoleOptions.find( x => x.value === users.getUserRole(row) ) From 018d42b440bcc6ebfe43bcedf050922cebdf4d97 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 17:05:31 +0000 Subject: [PATCH 46/79] Be explicit when checking if a user is a creator or not when displaying their global role in the user table list and user details page --- packages/builder/src/stores/portal/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js index 0e64d7a6cd..5da5d4038d 100644 --- a/packages/builder/src/stores/portal/users.js +++ b/packages/builder/src/stores/portal/users.js @@ -129,7 +129,7 @@ export function createUsersStore() { return Constants.BudibaseRoles.Admin } else if (sdk.users.isBuilder(user)) { return Constants.BudibaseRoles.Developer - } else if (sdk.users.isCreator(user)) { + } else if (sdk.users.hasCreatorPermissions(user)) { return Constants.BudibaseRoles.Creator } else { return Constants.BudibaseRoles.AppUser From 168e87566294dab7ccbdd65aa403f5b8e8e443cf Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 17:27:22 +0000 Subject: [PATCH 47/79] Persist legacy creator access when promoting to creator --- .../src/pages/builder/portal/users/users/[userId].svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 95e297e409..368e45d83c 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -187,7 +187,11 @@ } else if (detail === Constants.BudibaseRoles.Creator) { toggleFlags({ admin: { global: false }, - builder: { global: false, creator: true }, + builder: { + global: false, + creator: true, + apps: user?.builder?.apps || [], + }, }) } } From a8c5f626667434cc9c0ff78324584942510ac34d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 17:28:06 +0000 Subject: [PATCH 48/79] Fix label for tenant role when inviting users via builder side panel --- .../app/[application]/_components/BuilderSidePanel.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 726b79e23d..b937d69fd7 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -816,7 +816,7 @@ : Constants.BudibaseRoleOptions.filter( option => option.value !== Constants.BudibaseRoles.Admin )} - label="Access" + label="Role" on:change={checkAppAccess} /> From 1ae61eb4d668d06bd31b7437c874164a16bb29bb Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Sun, 26 Nov 2023 18:29:51 +0000 Subject: [PATCH 49/79] update pro reference --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 13b15ecb28..5e3d59fc40 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 13b15ecb28a147fe89e55314f7f8dfe837c7bdd1 +Subproject commit 5e3d59fc4060fd44b14b2599269c207753d4e5be From 3180ab76bfa223beddb1403cb3833a364daa9b95 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 27 Nov 2023 00:54:12 +0000 Subject: [PATCH 50/79] Bump version to 2.13.16 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index faba64ce90..0345af6bcf 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.15", + "version": "2.13.16", "npmClient": "yarn", "packages": [ "packages/*" From 1eb5dc73455760d43eca8f641afda2618c2697d3 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 27 Nov 2023 09:18:02 +0000 Subject: [PATCH 51/79] updating master ref --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 5e3d59fc40..618613f357 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 5e3d59fc4060fd44b14b2599269c207753d4e5be +Subproject commit 618613f3575b01f74940d9f58fdb53a9a5b2dc1a From bcaad6c2195423c2e67b1dcb637f67b8f4221f94 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 27 Nov 2023 09:30:02 +0000 Subject: [PATCH 52/79] Bump version to 2.13.17 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 0345af6bcf..40e167f36c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.16", + "version": "2.13.17", "npmClient": "yarn", "packages": [ "packages/*" From a65b29eb880f264fbc4fc78d3468f6109bc7044b Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 27 Nov 2023 18:50:44 +0000 Subject: [PATCH 53/79] banner changes for new pricing, fix for onboarding to prevent flash of UI before onboarding tutorial --- packages/backend-core/src/objectStore/objectStore.ts | 4 ++-- .../src/pages/builder/portal/apps/_layout.svelte | 2 +- .../src/pages/builder/portal/apps/index.svelte | 12 ++++++++++++ packages/pro | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index cdaf19fa55..cfd988f5e0 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -260,12 +260,12 @@ export async function listAllObjects(bucketName: string, path: string) { } /** - * Generate a presigned url with a default TTL of 1 hour + * Generate a presigned url with a default TTL of 1 day */ export function getPresignedUrl( bucketName: string, key: string, - durationSeconds: number = 3600 + durationSeconds: number = 86400 ) { const objectStore = ObjectStore(bucketName, { presigning: true }) const params = { diff --git a/packages/builder/src/pages/builder/portal/apps/_layout.svelte b/packages/builder/src/pages/builder/portal/apps/_layout.svelte index 38c0274eca..8810edca9c 100644 --- a/packages/builder/src/pages/builder/portal/apps/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/apps/_layout.svelte @@ -14,7 +14,7 @@ import PortalSideBar from "./_components/PortalSideBar.svelte" // Don't block loading if we've already hydrated state - let loaded = $apps.length != null + let loaded = !!$apps?.length onMount(async () => { try { diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index ad0d3658ea..fb0ba8bc2e 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -1,5 +1,6 @@ @@ -48,7 +48,7 @@ .dividerClickExtender { position: absolute; - cursor: row-resize; + cursor: col-resize; height: 100%; width: 12px; } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte index f01533d6bd..e3e24d7b13 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte @@ -5,7 +5,7 @@ import RoleIndicator from "./RoleIndicator.svelte" import DropdownMenu from "./DropdownMenu.svelte" import { goto } from "@roxi/routify" - import { getVerticalResizeActions } from "./resizable" + import { getVerticalResizeActions } from "components/common/resizable" import NavHeader from "components/common/NavHeader.svelte" const [resizable, resizableHandle] = getVerticalResizeActions() From 9ac413a73fd0dcf858fdd92d21b96d381f79845b Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 28 Nov 2023 11:20:19 +0000 Subject: [PATCH 64/79] Remove healthcheck script for now. --- hosting/couchdb/Dockerfile | 4 ---- hosting/couchdb/healthcheck.sh | 13 ------------- 2 files changed, 17 deletions(-) delete mode 100644 hosting/couchdb/healthcheck.sh diff --git a/hosting/couchdb/Dockerfile b/hosting/couchdb/Dockerfile index 254a676f63..f83df7038b 100644 --- a/hosting/couchdb/Dockerfile +++ b/hosting/couchdb/Dockerfile @@ -29,10 +29,6 @@ WORKDIR /opt/couchdb ADD couch/vm.args couch/local.ini ./etc/ WORKDIR / -ADD healthcheck.sh ./healthcheck.sh -RUN chmod +x ./healthcheck.sh -HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh" - ADD runner.sh ./bbcouch-runner.sh RUN chmod +x ./bbcouch-runner.sh /opt/clouseau/bin/clouseau CMD ["./bbcouch-runner.sh"] diff --git a/hosting/couchdb/healthcheck.sh b/hosting/couchdb/healthcheck.sh deleted file mode 100644 index 758ee5111a..0000000000 --- a/hosting/couchdb/healthcheck.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -healthy=true - -if [[ $(curl -s -w "%{http_code}\n" http://localhost:5984/_up -o /dev/null) -ne 200 ]]; then - echo 'ERROR: CouchDB is not running'; - healthy=false -fi - -if [ $healthy == true ]; then - exit 0 -else - exit 1 -fi From 24357aa7de033002501b446eca22866500af2292 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 28 Nov 2023 11:42:20 +0000 Subject: [PATCH 65/79] update copy in banner --- packages/builder/src/pages/builder/portal/apps/index.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index fac5c502b3..cf2c61b11d 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -205,7 +205,7 @@ messages: [ { message: - "We've updated our pricing - read the blog post to learn more.", + "We've updated our pricing - see our website to learn more.", type: BANNER_TYPES.NEUTRAL, extraButtonText: "Learn More", extraButtonAction: () => From e35e4b592c441a3f075a47c1fb03793e3eece354 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 28 Nov 2023 11:48:11 +0000 Subject: [PATCH 66/79] Bump version to 2.13.19 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 38872a31b1..e54b76c5e9 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.18", + "version": "2.13.19", "npmClient": "yarn", "packages": [ "packages/*" From 204769b6e99be4aeef026c1d65f052718bff7c04 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 29 Nov 2023 09:19:08 +0000 Subject: [PATCH 67/79] Add @budibase/backend as code owners to packages/{server,worker,backend-core} --- packages/backend-core/CODEOWNERS | 1 + packages/server/CODEOWNERS | 1 + packages/worker/CODEOWNERS | 1 + 3 files changed, 3 insertions(+) create mode 100644 packages/backend-core/CODEOWNERS create mode 100644 packages/server/CODEOWNERS create mode 100644 packages/worker/CODEOWNERS diff --git a/packages/backend-core/CODEOWNERS b/packages/backend-core/CODEOWNERS new file mode 100644 index 0000000000..291ffa073e --- /dev/null +++ b/packages/backend-core/CODEOWNERS @@ -0,0 +1 @@ +* @budibase/backend \ No newline at end of file diff --git a/packages/server/CODEOWNERS b/packages/server/CODEOWNERS new file mode 100644 index 0000000000..291ffa073e --- /dev/null +++ b/packages/server/CODEOWNERS @@ -0,0 +1 @@ +* @budibase/backend \ No newline at end of file diff --git a/packages/worker/CODEOWNERS b/packages/worker/CODEOWNERS new file mode 100644 index 0000000000..291ffa073e --- /dev/null +++ b/packages/worker/CODEOWNERS @@ -0,0 +1 @@ +* @budibase/backend \ No newline at end of file From fb3c072165cc48b128ab8bcbdb11e33c73e6654f Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 29 Nov 2023 09:22:47 +0000 Subject: [PATCH 68/79] Capitalise @Budibase. --- packages/backend-core/CODEOWNERS | 2 +- packages/server/CODEOWNERS | 2 +- packages/worker/CODEOWNERS | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend-core/CODEOWNERS b/packages/backend-core/CODEOWNERS index 291ffa073e..84313fb9cf 100644 --- a/packages/backend-core/CODEOWNERS +++ b/packages/backend-core/CODEOWNERS @@ -1 +1 @@ -* @budibase/backend \ No newline at end of file +* @Budibase/backend \ No newline at end of file diff --git a/packages/server/CODEOWNERS b/packages/server/CODEOWNERS index 291ffa073e..84313fb9cf 100644 --- a/packages/server/CODEOWNERS +++ b/packages/server/CODEOWNERS @@ -1 +1 @@ -* @budibase/backend \ No newline at end of file +* @Budibase/backend \ No newline at end of file diff --git a/packages/worker/CODEOWNERS b/packages/worker/CODEOWNERS index 291ffa073e..84313fb9cf 100644 --- a/packages/worker/CODEOWNERS +++ b/packages/worker/CODEOWNERS @@ -1 +1 @@ -* @budibase/backend \ No newline at end of file +* @Budibase/backend \ No newline at end of file From a5a3b12936e85755e71920ec738d0879332b58c2 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:10:59 +0000 Subject: [PATCH 69/79] Return false don't throw (#12460) Co-authored-by: Sam Rose --- packages/shared-core/src/filters.ts | 2 +- .../shared-core/src/tests/filters.test.ts | 36 +++++++++---------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index 564e8a52c9..5e24b640d4 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -315,7 +315,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => { new Date(docValue).getTime() > new Date(testValue.high).getTime() ) } - throw "Cannot perform range filter - invalid type." + return false } ) diff --git a/packages/shared-core/src/tests/filters.test.ts b/packages/shared-core/src/tests/filters.test.ts index 6f488cffbd..bddd6cb1f0 100644 --- a/packages/shared-core/src/tests/filters.test.ts +++ b/packages/shared-core/src/tests/filters.test.ts @@ -130,32 +130,28 @@ describe("runLuceneQuery", () => { expect(runLuceneQuery(docs, query).map(row => row.order_id)).toEqual([2]) }) - it("should throw an error is an invalid doc value is passed into a range filter", async () => { + it("should return return all docs if an invalid doc value is passed into a range filter", async () => { + const docs = [ + { + order_id: 4, + customer_id: 1758, + order_status: 5, + order_date: "{{ Binding.INVALID }}", + required_date: "2017-03-05T00:00:00.000Z", + shipped_date: "2017-03-03T00:00:00.000Z", + store_id: 2, + staff_id: 7, + description: undefined, + label: "", + }, + ] const query = buildQuery("range", { order_date: { low: "2016-01-04T00:00:00.000Z", high: "2016-01-11T00:00:00.000Z", }, }) - expect(() => - runLuceneQuery( - [ - { - order_id: 4, - customer_id: 1758, - order_status: 5, - order_date: "INVALID", - required_date: "2017-03-05T00:00:00.000Z", - shipped_date: "2017-03-03T00:00:00.000Z", - store_id: 2, - staff_id: 7, - description: undefined, - label: "", - }, - ], - query - ) - ).toThrowError("Cannot perform range filter - invalid type.") + expect(runLuceneQuery(docs, query)).toEqual(docs) }) it("should return rows with matches on empty filter", () => { From 37dc8ba6e4d480e5a13b27d9367ea36868eeea4a Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:23:21 +0000 Subject: [PATCH 70/79] Only export selected columns (#12438) * Only export selected columns * Refactor and unit test --- .../src/sdk/app/rows/search/external.ts | 16 +++++------ .../src/sdk/app/rows/search/internal.ts | 5 ++-- .../server/src/sdk/tests/rows/row.spec.ts | 28 ++++++++++++++++++- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/server/src/sdk/app/rows/search/external.ts b/packages/server/src/sdk/app/rows/search/external.ts index 2fc6caeb39..8465f997e3 100644 --- a/packages/server/src/sdk/app/rows/search/external.ts +++ b/packages/server/src/sdk/app/rows/search/external.ts @@ -133,9 +133,14 @@ export async function exportRows( let result = await search({ tableId, query: requestQuery, sort, sortOrder }) let rows: Row[] = [] + let headers + + if (!tableName) { + throw new HTTPError("Could not find table name.", 400) + } + const schema = datasource.entities[tableName].schema // Filter data to only specified columns if required - if (columns && columns.length) { for (let i = 0; i < result.rows.length; i++) { rows[i] = {} @@ -143,22 +148,17 @@ export async function exportRows( rows[i][column] = result.rows[i][column] } } + headers = columns } else { rows = result.rows } - if (!tableName) { - throw new HTTPError("Could not find table name.", 400) - } - const schema = datasource.entities[tableName].schema let exportRows = cleanExportRows(rows, schema, format, columns) - let headers = Object.keys(schema) - let content: string switch (format) { case exporters.Format.CSV: - content = exporters.csv(headers, exportRows) + content = exporters.csv(headers ?? Object.keys(schema), exportRows) break case exporters.Format.JSON: content = exporters.json(exportRows) diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 87a33c0ba0..22cb3985b7 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -110,7 +110,7 @@ export async function exportRows( let rows: Row[] = [] let schema = table.schema - + let headers // Filter data to only specified columns if required if (columns && columns.length) { for (let i = 0; i < result.length; i++) { @@ -119,6 +119,7 @@ export async function exportRows( rows[i][column] = result[i][column] } } + headers = columns } else { rows = result } @@ -127,7 +128,7 @@ export async function exportRows( if (format === Format.CSV) { return { fileName: "export.csv", - content: csv(Object.keys(rows[0]), exportRows), + content: csv(headers ?? Object.keys(rows[0]), exportRows), } } else if (format === Format.JSON) { return { diff --git a/packages/server/src/sdk/tests/rows/row.spec.ts b/packages/server/src/sdk/tests/rows/row.spec.ts index af3d405e15..8b01356e35 100644 --- a/packages/server/src/sdk/tests/rows/row.spec.ts +++ b/packages/server/src/sdk/tests/rows/row.spec.ts @@ -18,7 +18,6 @@ jest.mock("../../../utilities/rowProcessor", () => ({ jest.mock("../../../api/controllers/view/exporters", () => ({ ...jest.requireActual("../../../api/controllers/view/exporters"), - csv: jest.fn(), Format: { CSV: "csv", }, @@ -102,5 +101,32 @@ describe("external row sdk", () => { new HTTPError("Could not find table name.", 400) ) }) + + it("should only export specified columns", async () => { + mockDatasourcesGet.mockImplementation(async () => ({ + entities: { + tablename: { + schema: { + name: {}, + age: {}, + dob: {}, + }, + }, + }, + })) + const headers = ["name", "dob"] + + const result = await exportRows({ + tableId: "datasource__tablename", + format: Format.CSV, + query: {}, + columns: headers, + }) + + expect(result).toEqual({ + fileName: "export.csv", + content: `"name","dob"`, + }) + }) }) }) From c2a82bb02190a493db79b7b101f6f38752e972e1 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:48:50 +0000 Subject: [PATCH 71/79] FIX broken references in a list of actions (#12459) * Refactor * Update action bindings on delete * Update action bindings on move * Fix with additional tests * Ensure visible binding is updated on drag release * fix * Refresh visible binding when action is deleted * Refactor * Refactor --- .../builder/src/builderStore/dataBinding.js | 84 ++++ .../builderStore/store/automation/index.js | 33 +- .../builderStore/tests/dataBinding.test.js | 459 ++++++++++++++++++ .../ButtonActionDrawer.svelte | 32 +- 4 files changed, 581 insertions(+), 27 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 85ac822006..d86e94aba2 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -29,6 +29,12 @@ const CAPTURE_VAR_INSIDE_TEMPLATE = /{{([^}]+)}}/g const CAPTURE_VAR_INSIDE_JS = /\$\("([^")]+)"\)/g const CAPTURE_HBS_TEMPLATE = /{{[\S\s]*?}}/g +const UpdateReferenceAction = { + ADD: "add", + DELETE: "delete", + MOVE: "move", +} + /** * Gets all bindable data context fields and instance fields. */ @@ -1226,3 +1232,81 @@ export const runtimeToReadableBinding = ( "readableBinding" ) } + +/** + * Used to update binding references for automation or action steps + * + * @param obj - The object to be updated + * @param originalIndex - The original index of the step being moved. Not applicable to add/delete. + * @param modifiedIndex - The new index of the step being modified + * @param action - Used to determine if a step is being added, deleted or moved + * @param label - The binding text that describes the steps + */ +export const updateReferencesInObject = ({ + obj, + modifiedIndex, + action, + label, + originalIndex, +}) => { + const stepIndexRegex = new RegExp(`{{\\s*${label}\\.(\\d+)\\.`, "g") + const updateActionStep = (str, index, replaceWith) => + str.replace(`{{ ${label}.${index}.`, `{{ ${label}.${replaceWith}.`) + for (const key in obj) { + if (typeof obj[key] === "string") { + let matches + while ((matches = stepIndexRegex.exec(obj[key])) !== null) { + const referencedStep = parseInt(matches[1]) + if ( + action === UpdateReferenceAction.ADD && + referencedStep >= modifiedIndex + ) { + obj[key] = updateActionStep( + obj[key], + referencedStep, + referencedStep + 1 + ) + } else if ( + action === UpdateReferenceAction.DELETE && + referencedStep > modifiedIndex + ) { + obj[key] = updateActionStep( + obj[key], + referencedStep, + referencedStep - 1 + ) + } else if (action === UpdateReferenceAction.MOVE) { + if (referencedStep === originalIndex) { + obj[key] = updateActionStep(obj[key], referencedStep, modifiedIndex) + } else if ( + modifiedIndex <= referencedStep && + modifiedIndex < originalIndex + ) { + obj[key] = updateActionStep( + obj[key], + referencedStep, + referencedStep + 1 + ) + } else if ( + modifiedIndex >= referencedStep && + modifiedIndex > originalIndex + ) { + obj[key] = updateActionStep( + obj[key], + referencedStep, + referencedStep - 1 + ) + } + } + } + } else if (typeof obj[key] === "object" && obj[key] !== null) { + updateReferencesInObject({ + obj: obj[key], + modifiedIndex, + action, + label, + originalIndex, + }) + } + } +} diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index ba2458f414..af83f73dc6 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -4,6 +4,7 @@ import { cloneDeep } from "lodash/fp" import { generate } from "shortid" import { selectedAutomation } from "builderStore" import { notifications } from "@budibase/bbui" +import { updateReferencesInObject } from "builderStore/dataBinding" const initialAutomationState = { automations: [], @@ -22,34 +23,14 @@ export const getAutomationStore = () => { return store } -const updateReferencesInObject = (obj, modifiedIndex, action) => { - const regex = /{{\s*steps\.(\d+)\./g - for (const key in obj) { - if (typeof obj[key] === "string") { - let matches - while ((matches = regex.exec(obj[key])) !== null) { - const referencedStep = parseInt(matches[1]) - if (action === "add" && referencedStep >= modifiedIndex) { - obj[key] = obj[key].replace( - `{{ steps.${referencedStep}.`, - `{{ steps.${referencedStep + 1}.` - ) - } else if (action === "delete" && referencedStep > modifiedIndex) { - obj[key] = obj[key].replace( - `{{ steps.${referencedStep}.`, - `{{ steps.${referencedStep - 1}.` - ) - } - } - } else if (typeof obj[key] === "object" && obj[key] !== null) { - updateReferencesInObject(obj[key], modifiedIndex, action) - } - } -} - const updateStepReferences = (steps, modifiedIndex, action) => { steps.forEach(step => { - updateReferencesInObject(step.inputs, modifiedIndex, action) + updateReferencesInObject({ + obj: step.inputs, + modifiedIndex, + action, + label: "steps", + }) }) } diff --git a/packages/builder/src/builderStore/tests/dataBinding.test.js b/packages/builder/src/builderStore/tests/dataBinding.test.js index 47f6564749..039e33a94d 100644 --- a/packages/builder/src/builderStore/tests/dataBinding.test.js +++ b/packages/builder/src/builderStore/tests/dataBinding.test.js @@ -2,6 +2,7 @@ import { expect, describe, it, vi } from "vitest" import { runtimeToReadableBinding, readableToRuntimeBinding, + updateReferencesInObject, } from "../dataBinding" vi.mock("@budibase/frontend-core") @@ -84,3 +85,461 @@ describe("readableToRuntimeBinding", () => { ).toEqual(`Hello {{ [user].[firstName] }}! The count is {{ count }}.`) }) }) + +describe("updateReferencesInObject", () => { + it("should increment steps in sequence on 'add'", () => { + let obj = [ + { + id: "a0", + parameters: { + text: "Alpha", + }, + }, + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "b2", + parameters: { + text: "Banana {{ actions.1.row }}", + }, + }, + { + id: "c3", + parameters: { + text: "Carrot {{ actions.1.row }}", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.3.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.4.row }}", + }, + }, + ] + updateReferencesInObject({ + obj, + modifiedIndex: 0, + action: "add", + label: "actions", + }) + + expect(obj).toEqual([ + { + id: "a0", + parameters: { + text: "Alpha", + }, + }, + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "b2", + parameters: { + text: "Banana {{ actions.2.row }}", + }, + }, + { + id: "c3", + parameters: { + text: "Carrot {{ actions.2.row }}", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.4.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.5.row }}", + }, + }, + ]) + }) + + it("should decrement steps in sequence on 'delete'", () => { + let obj = [ + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "b2", + parameters: { + text: "Banana {{ actions.1.row }}", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.3.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.4.row }}", + }, + }, + ] + updateReferencesInObject({ + obj, + modifiedIndex: 2, + action: "delete", + label: "actions", + }) + + expect(obj).toEqual([ + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "b2", + parameters: { + text: "Banana {{ actions.1.row }}", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.2.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.3.row }}", + }, + }, + ]) + }) + + it("should handle on 'move' to a lower index", () => { + let obj = [ + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "b2", + parameters: { + text: "Banana {{ actions.0.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.3.row }}", + }, + }, + { + id: "c3", + parameters: { + text: "Carrot {{ actions.0.row }}", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.2.row }}", + }, + }, + ] + updateReferencesInObject({ + obj, + modifiedIndex: 2, + action: "move", + label: "actions", + originalIndex: 4, + }) + + expect(obj).toEqual([ + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "b2", + parameters: { + text: "Banana {{ actions.0.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.4.row }}", + }, + }, + { + id: "c3", + parameters: { + text: "Carrot {{ actions.0.row }}", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.3.row }}", + }, + }, + ]) + }) + + it("should handle on 'move' to a higher index", () => { + let obj = [ + { + id: "b2", + parameters: { + text: "Banana {{ actions.0.row }}", + }, + }, + { + id: "c3", + parameters: { + text: "Carrot {{ actions.0.row }}", + }, + }, + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.2.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.3.row }}", + }, + }, + ] + updateReferencesInObject({ + obj, + modifiedIndex: 2, + action: "move", + label: "actions", + originalIndex: 0, + }) + + expect(obj).toEqual([ + { + id: "b2", + parameters: { + text: "Banana {{ actions.2.row }}", + }, + }, + { + id: "c3", + parameters: { + text: "Carrot {{ actions.2.row }}", + }, + }, + { + id: "a1", + parameters: { + text: "Apple", + }, + }, + { + id: "d4", + parameters: { + text: "Dog {{ actions.1.row }}", + }, + }, + { + id: "e5", + parameters: { + text: "Eagle {{ actions.3.row }}", + }, + }, + ]) + }) + + it("should handle on 'move' of action being referenced, dragged to a higher index", () => { + let obj = [ + { + "##eventHandlerType": "Validate Form", + id: "cCD0Dwcnq", + }, + { + "##eventHandlerType": "Close Screen Modal", + id: "3fbbIOfN0H", + }, + { + "##eventHandlerType": "Save Row", + parameters: { + tableId: "ta_bb_employee", + }, + id: "aehg5cTmhR", + }, + { + "##eventHandlerType": "Close Side Panel", + id: "mzkpf86cxo", + }, + { + "##eventHandlerType": "Navigate To", + id: "h0uDFeJa8A", + }, + { + parameters: { + autoDismiss: true, + type: "success", + message: "{{ actions.1.row }}", + }, + "##eventHandlerType": "Show Notification", + id: "JEI5lAyJZ", + }, + ] + updateReferencesInObject({ + obj, + modifiedIndex: 2, + action: "move", + label: "actions", + originalIndex: 1, + }) + + expect(obj).toEqual([ + { + "##eventHandlerType": "Validate Form", + id: "cCD0Dwcnq", + }, + { + "##eventHandlerType": "Close Screen Modal", + id: "3fbbIOfN0H", + }, + { + "##eventHandlerType": "Save Row", + parameters: { + tableId: "ta_bb_employee", + }, + id: "aehg5cTmhR", + }, + { + "##eventHandlerType": "Close Side Panel", + id: "mzkpf86cxo", + }, + { + "##eventHandlerType": "Navigate To", + id: "h0uDFeJa8A", + }, + { + parameters: { + autoDismiss: true, + type: "success", + message: "{{ actions.2.row }}", + }, + "##eventHandlerType": "Show Notification", + id: "JEI5lAyJZ", + }, + ]) + }) + + it("should handle on 'move' of action being referenced, dragged to a lower index", () => { + let obj = [ + { + "##eventHandlerType": "Save Row", + parameters: { + tableId: "ta_bb_employee", + }, + id: "aehg5cTmhR", + }, + { + "##eventHandlerType": "Validate Form", + id: "cCD0Dwcnq", + }, + { + "##eventHandlerType": "Close Screen Modal", + id: "3fbbIOfN0H", + }, + { + "##eventHandlerType": "Close Side Panel", + id: "mzkpf86cxo", + }, + { + "##eventHandlerType": "Navigate To", + id: "h0uDFeJa8A", + }, + { + parameters: { + autoDismiss: true, + type: "success", + message: "{{ actions.4.row }}", + }, + "##eventHandlerType": "Show Notification", + id: "JEI5lAyJZ", + }, + ] + updateReferencesInObject({ + obj, + modifiedIndex: 0, + action: "move", + label: "actions", + originalIndex: 4, + }) + + expect(obj).toEqual([ + { + "##eventHandlerType": "Save Row", + parameters: { + tableId: "ta_bb_employee", + }, + id: "aehg5cTmhR", + }, + { + "##eventHandlerType": "Validate Form", + id: "cCD0Dwcnq", + }, + { + "##eventHandlerType": "Close Screen Modal", + id: "3fbbIOfN0H", + }, + { + "##eventHandlerType": "Close Side Panel", + id: "mzkpf86cxo", + }, + { + "##eventHandlerType": "Navigate To", + id: "h0uDFeJa8A", + }, + { + parameters: { + autoDismiss: true, + type: "success", + message: "{{ actions.0.row }}", + }, + "##eventHandlerType": "Show Notification", + id: "JEI5lAyJZ", + }, + ]) + }) +}) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/ButtonActionDrawer.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/ButtonActionDrawer.svelte index f9541ea79f..109f9f62a2 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/ButtonActionDrawer.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/ButtonActionDrawer.svelte @@ -15,6 +15,7 @@ getEventContextBindings, getActionBindings, makeStateBinding, + updateReferencesInObject, } from "builderStore/dataBinding" import { cloneDeep } from "lodash/fp" @@ -30,6 +31,7 @@ let actionQuery let selectedAction = actions?.length ? actions[0] : null + let originalActionIndex const setUpdateActions = actions => { return actions @@ -115,6 +117,14 @@ if (isSelected) { selectedAction = actions?.length ? actions[0] : null } + + // Update action binding references + updateReferencesInObject({ + obj: actions, + modifiedIndex: index, + action: "delete", + label: "actions", + }) } const toggleActionList = () => { @@ -146,9 +156,29 @@ function handleDndConsider(e) { actions = e.detail.items + + // set the initial index of the action being dragged + if (e.detail.info.trigger === "draggedEntered") { + originalActionIndex = actions.findIndex( + action => action.id === e.detail.info.id + ) + } } function handleDndFinalize(e) { actions = e.detail.items + + // Update action binding references + updateReferencesInObject({ + obj: actions, + modifiedIndex: actions.findIndex( + action => action.id === e.detail.info.id + ), + action: "move", + label: "actions", + originalIndex: originalActionIndex, + }) + + originalActionIndex = -1 } const getAllBindings = (actionBindings, eventContextBindings, actions) => { @@ -289,7 +319,7 @@ {#if selectedActionComponent && !showAvailableActions} - {#key selectedAction.id} + {#key (selectedAction.id, originalActionIndex)}
Date: Wed, 29 Nov 2023 14:49:55 +0000 Subject: [PATCH 72/79] Removing codecov upload during Budibase CI/on PRs, right now this isn't much use due to the NX caching - if we wish to have accurate code coverage reports we will need to run a separate job periodically to check coverage by running the whole suite, with no caching. --- .github/workflows/budibase_ci.yml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 6e04ca6f67..cb713c93ac 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -99,11 +99,6 @@ jobs: else yarn test --ignore=@budibase/worker --ignore=@budibase/server --ignore=@budibase/pro fi - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos - name: codecov-umbrella - verbose: true test-worker: runs-on: ubuntu-latest @@ -129,12 +124,6 @@ jobs: yarn test --scope=@budibase/worker fi - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN || github.token }} # not required for public repos - name: codecov-umbrella - verbose: true - test-server: runs-on: ubuntu-latest steps: @@ -159,12 +148,6 @@ jobs: yarn test --scope=@budibase/server fi - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN || github.token }} # not required for public repos - name: codecov-umbrella - verbose: true - test-pro: runs-on: ubuntu-latest if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase' From 5ac30510c685a558dfe332cd734ba3cf55aaa0e5 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 29 Nov 2023 15:14:53 +0000 Subject: [PATCH 73/79] Bump version to 2.13.20 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index e54b76c5e9..deb273884d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.19", + "version": "2.13.20", "npmClient": "yarn", "packages": [ "packages/*" From 4fcb4d56776aee881d7351a01c43c39036c5170a Mon Sep 17 00:00:00 2001 From: Christos Alexiou Date: Wed, 29 Nov 2023 23:39:41 +0200 Subject: [PATCH 74/79] fix: use /health and remove 301 --- charts/budibase/templates/alb-ingress.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/budibase/templates/alb-ingress.yaml b/charts/budibase/templates/alb-ingress.yaml index 6cd1cf2cba..fd38364ba6 100644 --- a/charts/budibase/templates/alb-ingress.yaml +++ b/charts/budibase/templates/alb-ingress.yaml @@ -7,8 +7,8 @@ metadata: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip - alb.ingress.kubernetes.io/success-codes: 200,301 - alb.ingress.kubernetes.io/healthcheck-path: / + alb.ingress.kubernetes.io/success-codes: '200' + alb.ingress.kubernetes.io/healthcheck-path: '/health' {{- if .Values.ingress.certificateArn }} alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}' alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]' From 3192a594c73528a7eca8561d1fe8e18ab929783b Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 30 Nov 2023 08:58:01 +0000 Subject: [PATCH 75/79] Allow querying of users table from automation --- .../src/components/automation/SetupPanel/TableSelector.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte b/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte index 3434219384..1645ded66b 100644 --- a/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte +++ b/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte @@ -22,7 +22,7 @@