diff --git a/lerna.json b/lerna.json index 76b53fd5e1..6647325f26 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.1.15-alpha.3", + "version": "1.1.17", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index da7fc95d0f..c0daca06d4 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.1.15-alpha.3", + "version": "1.1.17", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -20,7 +20,7 @@ "test:watch": "jest --watchAll" }, "dependencies": { - "@budibase/types": "^1.1.15-alpha.3", + "@budibase/types": "^1.1.17", "@techpass/passport-openidconnect": "0.3.2", "aws-sdk": "2.1030.0", "bcrypt": "5.0.1", diff --git a/packages/backend-core/src/context/index.ts b/packages/backend-core/src/context/index.ts index e0db18dde6..1e430f01de 100644 --- a/packages/backend-core/src/context/index.ts +++ b/packages/backend-core/src/context/index.ts @@ -67,6 +67,10 @@ export const getTenantIDFromAppID = (appId: string) => { // used for automations, API endpoints should always be in context already export const doInTenant = (tenantId: string | null, task: any) => { + // make sure default always selected in single tenancy + if (!env.MULTI_TENANCY) { + tenantId = tenantId || DEFAULT_TENANT_ID + } // the internal function is so that we can re-use an existing // context - don't want to close DB on a parent context async function internal(opts = { existing: false }) { diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 0c5488a2e5..1e10ac9d98 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "1.1.15-alpha.3", + "version": "1.1.17", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.2.1", - "@budibase/string-templates": "^1.1.15-alpha.3", + "@budibase/string-templates": "^1.1.17", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/bbui/src/Drawer/Drawer.svelte b/packages/bbui/src/Drawer/Drawer.svelte index af09b014d0..e1880d0ed4 100644 --- a/packages/bbui/src/Drawer/Drawer.svelte +++ b/packages/bbui/src/Drawer/Drawer.svelte @@ -82,6 +82,7 @@ } .fillWidth { + left: 260px !important; width: calc(100% - 260px) !important; } diff --git a/packages/builder/package.json b/packages/builder/package.json index dcd3bd28c6..16a7d69dda 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "1.1.15-alpha.3", + "version": "1.1.17", "license": "GPL-3.0", "private": true, "scripts": { @@ -69,10 +69,10 @@ } }, "dependencies": { - "@budibase/bbui": "^1.1.15-alpha.3", - "@budibase/client": "^1.1.15-alpha.3", - "@budibase/frontend-core": "^1.1.15-alpha.3", - "@budibase/string-templates": "^1.1.15-alpha.3", + "@budibase/bbui": "^1.1.17", + "@budibase/client": "^1.1.17", + "@budibase/frontend-core": "^1.1.17", + "@budibase/string-templates": "^1.1.17", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 28ef1f4376..35c4587874 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -2,7 +2,6 @@ import { getFrontendStore } from "./store/frontend" import { getAutomationStore } from "./store/automation" import { getThemeStore } from "./store/theme" import { derived } from "svelte/store" -import { LAYOUT_NAMES } from "../constants" import { findComponent, findComponentPath } from "./componentUtils" import { RoleUtils } from "@budibase/frontend-core" @@ -28,6 +27,10 @@ export const selectedComponent = derived( } ) +// For legacy compatibility only, but with the new design UI this is just +// the selected screen +export const currentAsset = selectedScreen + export const sortedScreens = derived(store, $store => { return $store.screens.slice().sort((a, b) => { // Sort by role first @@ -66,12 +69,3 @@ export const selectedComponentPath = derived( ).map(component => component._id) } ) - -export const mainLayout = derived(store, $store => { - return $store.layouts?.find( - layout => layout._id === LAYOUT_NAMES.MASTER.PRIVATE - ) -}) - -// For compatibility -export const currentAsset = selectedScreen diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 16ae5ce215..58d803aa03 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -1,6 +1,6 @@ import { get, writable } from "svelte/store" import { cloneDeep } from "lodash/fp" -import { currentAsset, mainLayout, selectedComponent } from "builderStore" +import { selectedScreen, selectedComponent } from "builderStore" import { datasources, integrations, @@ -11,7 +11,6 @@ import { import { API } from "api" import analytics, { Events } from "analytics" import { - findComponentType, findComponentParent, findClosestMatchingComponent, findAllMatchingComponents, @@ -21,6 +20,7 @@ import { } from "../componentUtils" import { Helpers } from "@budibase/bbui" import { DefaultAppTheme, LAYOUT_NAMES } from "../../constants" +import { Utils } from "@budibase/frontend-core" const INITIAL_FRONTEND_STATE = { apps: [], @@ -61,6 +61,26 @@ const INITIAL_FRONTEND_STATE = { export const getFrontendStore = () => { const store = writable({ ...INITIAL_FRONTEND_STATE }) + // This is a fake implementation of a "patch" API endpoint to try and prevent + // 409s. All screen doc mutations (aside from creation) use this function, + // which queues up invocations sequentially and ensures pending mutations are + // always applied to the most up-to-date doc revision. + // This is slightly better than just a traditional "patch" endpoint and this + // supports deeply mutating the current doc rather than just appending data. + const sequentialScreenPatch = Utils.sequential(async (patchFn, screenId) => { + const state = get(store) + const screen = state.screens.find(screen => screen._id === screenId) + if (!screen) { + return + } + let clone = cloneDeep(screen) + const result = patchFn(clone) + if (result === false) { + return + } + return await store.actions.screens.save(clone) + }) + store.actions = { reset: () => { store.set({ ...INITIAL_FRONTEND_STATE }) @@ -137,12 +157,12 @@ export const getFrontendStore = () => { theme: { save: async theme => { const appId = get(store).appId - await API.saveAppMetadata({ + const app = await API.saveAppMetadata({ appId, metadata: { theme }, }) store.update(state => { - state.theme = theme + state.theme = app.theme return state }) }, @@ -150,12 +170,12 @@ export const getFrontendStore = () => { customTheme: { save: async customTheme => { const appId = get(store).appId - await API.saveAppMetadata({ + const app = await API.saveAppMetadata({ appId, metadata: { customTheme }, }) store.update(state => { - state.customTheme = customTheme + state.customTheme = app.customTheme return state }) }, @@ -163,33 +183,35 @@ export const getFrontendStore = () => { navigation: { save: async navigation => { const appId = get(store).appId - await API.saveAppMetadata({ + const app = await API.saveAppMetadata({ appId, metadata: { navigation }, }) store.update(state => { - state.navigation = navigation - return state - }) - }, - }, - routing: { - fetch: async () => { - const response = await API.fetchAppRoutes() - store.update(state => { - state.routes = response.routes + state.navigation = app.navigation return state }) }, }, screens: { select: screenId => { - store.update(state => { - let screens = state.screens - let screen = - screens.find(screen => screen._id === screenId) || screens[0] - if (!screen) return state + // Check this screen exists + const state = get(store) + const screen = state.screens.find(screen => screen._id === screenId) + if (!screen) { + return + } + // Check screen isn't already selected + if ( + state.selectedScreenId === screen._id && + state.selectedComponentId === screen.props?._id + ) { + return + } + + // Select new screen + store.update(state => { state.selectedScreenId = screen._id state.selectedComponentId = screen.props?._id return state @@ -198,25 +220,40 @@ export const getFrontendStore = () => { save: async screen => { const creatingNewScreen = screen._id === undefined const savedScreen = await API.saveScreen(screen) + const routesResponse = await API.fetchAppRoutes() store.update(state => { + // Update screen object const idx = state.screens.findIndex(x => x._id === savedScreen._id) if (idx !== -1) { state.screens.splice(idx, 1, savedScreen) } else { state.screens.push(savedScreen) } + + // Select the new screen if creating a new one + if (creatingNewScreen) { + state.selectedScreenId = savedScreen._id + state.selectedComponentId = savedScreen.props._id + } + + // Update routes + state.routes = routesResponse.routes + return state }) - - // Refresh routes - await store.actions.routing.fetch() - - // Select the new screen if creating a new one - if (creatingNewScreen) { - store.actions.screens.select(savedScreen._id) - } return savedScreen }, + patch: async (patchFn, screenId) => { + // Default to the currently selected screen + if (!screenId) { + const state = get(store) + screenId = state.selectedScreenId + } + if (!screenId || !patchFn) { + return + } + return await sequentialScreenPatch(patchFn, screenId) + }, delete: async screens => { const screensToDelete = Array.isArray(screens) ? screens : [screens] @@ -238,60 +275,78 @@ export const getFrontendStore = () => { promises.push(store.actions.links.delete(deleteUrls)) await Promise.all(promises) const deletedIds = screensToDelete.map(screen => screen._id) + const routesResponse = await API.fetchAppRoutes() store.update(state => { // Remove deleted screens from state state.screens = state.screens.filter(screen => { return !deletedIds.includes(screen._id) }) + // Deselect the current screen if it was deleted if (deletedIds.includes(state.selectedScreenId)) { state.selectedScreenId = null + state.selectedComponentId = null } + + // Update routing + state.routes = routesResponse.routes + return state }) - - // Refresh routes - await store.actions.routing.fetch() }, - updateHomeScreen: async (screen, makeHomeScreen = true) => { - let promises = [] - - // Find any existing home screen for this role so we can remove it, - // if we are setting this to be the new home screen - if (makeHomeScreen) { - const roleId = screen.routing.roleId - let existingHomeScreen = get(store).screens.find(s => { - return ( - s.routing.roleId === roleId && - s.routing.homeScreen && - s._id !== screen._id - ) - }) - if (existingHomeScreen) { - existingHomeScreen.routing.homeScreen = false - promises.push(store.actions.screens.save(existingHomeScreen)) - } + updateSetting: async (screen, name, value) => { + if (!screen || !name) { + return } - // Update the passed in screen - screen.routing.homeScreen = makeHomeScreen - promises.push(store.actions.screens.save(screen)) - return await Promise.all(promises) + // Apply setting update + const patch = screen => { + if (!screen) { + return false + } + // Skip update if the value is the same + if (Helpers.deepGet(screen, name) === value) { + return false + } + Helpers.deepSet(screen, name, value) + } + await store.actions.screens.patch(patch, screen._id) + + // Ensure we don't have more than one home screen for this new role. + // This could happen after updating multiple different settings. + const state = get(store) + const updatedScreen = state.screens.find(s => s._id === screen._id) + if (!updatedScreen) { + return + } + const otherHomeScreens = state.screens.filter(s => { + return ( + s.routing.roleId === updatedScreen.routing.roleId && + s.routing.homeScreen && + s._id !== screen._id + ) + }) + if (otherHomeScreens.length) { + const patch = screen => { + screen.routing.homeScreen = false + } + for (let otherHomeScreen of otherHomeScreens) { + await store.actions.screens.patch(patch, otherHomeScreen._id) + } + } }, removeCustomLayout: async screen => { // Pull relevant settings from old layout, if required const layout = get(store).layouts.find(x => x._id === screen.layoutId) - screen.layoutId = null - screen.showNavigation = layout?.props.navigation !== "None" - screen.width = layout?.props.width || "Large" - await store.actions.screens.save(screen) + const patch = screen => { + screen.layoutId = null + screen.showNavigation = layout?.props.navigation !== "None" + screen.width = layout?.props.width || "Large" + } + await store.actions.screens.patch(patch, screen._id) }, }, preview: { - saveSelected: async () => { - const selectedAsset = get(currentAsset) - return await store.actions.screens.save(selectedAsset) - }, setDevice: device => { store.update(state => { state.previewDevice = device @@ -301,41 +356,28 @@ export const getFrontendStore = () => { }, layouts: { select: layoutId => { + // Check this layout exists + const state = get(store) + const layout = state.layouts.find(layout => layout._id === layoutId) + if (!layout) { + return + } + + // Check layout isn't already selected + if ( + state.selectedLayoutId === layout._id && + state.selectedComponentId === layout.props?._id + ) { + return + } + + // Select new layout store.update(state => { - const layout = - store.actions.layouts.find(layoutId) || get(store).layouts[0] - if (!layout) return state.selectedLayoutId = layout._id state.selectedComponentId = layout.props?._id return state }) }, - save: async layout => { - const creatingNewLayout = layout._id === undefined - const savedLayout = await API.saveLayout(layout) - store.update(state => { - const idx = state.layouts.findIndex(x => x._id === savedLayout._id) - if (idx !== -1) { - state.layouts.splice(idx, 1, savedLayout) - } else { - state.layouts.push(savedLayout) - } - return state - }) - - // Select layout if creating a new one - if (creatingNewLayout) { - store.actions.layouts.select(savedLayout._id) - } - return savedLayout - }, - find: layoutId => { - if (!layoutId) { - return get(mainLayout) - } - const storeContents = get(store) - return storeContents.layouts.find(layout => layout._id === layoutId) - }, delete: async layout => { if (!layout?._id) { return @@ -345,10 +387,6 @@ export const getFrontendStore = () => { layoutRev: layout._rev, }) store.update(state => { - // Select main layout if we deleted the selected layout - if (layout._id === state.selectedLayoutId) { - state.selectedLayoutId = get(mainLayout)._id - } state.layouts = state.layouts.filter(x => x._id !== layout._id) return state }) @@ -386,7 +424,7 @@ export const getFrontendStore = () => { } if (componentName.endsWith("/formstep")) { const parentForm = findClosestMatchingComponent( - get(currentAsset).props, + get(selectedScreen).props, get(selectedComponent)._id, component => component._component.endsWith("/form") ) @@ -407,48 +445,59 @@ export const getFrontendStore = () => { } }, create: async (componentName, presetProps) => { - const selected = get(selectedComponent) - const asset = get(currentAsset) - - // Create new component + const state = get(store) const componentInstance = store.actions.components.createInstance( componentName, presetProps ) - if (!componentInstance || !asset) { + if (!componentInstance) { return } - // Find parent node to attach this component to - let parentComponent - if (selected) { - // Use current screen or layout as parent if no component is selected - const definition = store.actions.components.getDefinition( - selected._component + // Patch selected screen + await store.actions.screens.patch(screen => { + // Find the selected component + const currentComponent = findComponent( + screen.props, + state.selectedComponentId ) - if (definition?.hasChildren) { - // Use selected component if it allows children - parentComponent = selected - } else { - // Otherwise we need to use the parent of this component - parentComponent = findComponentParent(asset?.props, selected._id) + if (!currentComponent) { + return false } - } else { - // Use screen or layout if no component is selected - parentComponent = asset?.props - } - // Attach component - if (!parentComponent) { - return - } - if (!parentComponent._children) { - parentComponent._children = [] - } - parentComponent._children.push(componentInstance) + // Find parent node to attach this component to + let parentComponent + if (currentComponent) { + // Use selected component as parent if one is selected + const definition = store.actions.components.getDefinition( + currentComponent._component + ) + if (definition?.hasChildren) { + // Use selected component if it allows children + parentComponent = currentComponent + } else { + // Otherwise we need to use the parent of this component + parentComponent = findComponentParent( + screen.props, + currentComponent._id + ) + } + } else { + // Use screen or layout if no component is selected + parentComponent = screen.props + } - // Save components and update UI - await store.actions.preview.saveSelected() + // Attach new component + if (!parentComponent) { + return false + } + if (!parentComponent._children) { + parentComponent._children = [] + } + parentComponent._children.push(componentInstance) + }) + + // Select new component store.update(state => { state.selectedComponentId = componentInstance._id return state @@ -461,50 +510,58 @@ export const getFrontendStore = () => { return componentInstance }, + patch: async (patchFn, componentId, screenId) => { + // Use selected component by default + if (!componentId && !screenId) { + const state = get(store) + componentId = state.selectedComponentId + screenId = state.selectedScreenId + } + // Invalid if only a screen or component ID provided + if (!componentId || !screenId || !patchFn) { + return + } + const patchScreen = screen => { + let component = findComponent(screen.props, componentId) + if (!component) { + return false + } + return patchFn(component, screen) + } + await store.actions.screens.patch(patchScreen, screenId) + }, delete: async component => { if (!component) { return } - const asset = get(currentAsset) - if (!asset) { - return - } + let parentId - // Fetch full definition - component = findComponent(asset.props, component._id) + // Patch screen + await store.actions.screens.patch(screen => { + // Check component exists + component = findComponent(screen.props, component._id) + if (!component) { + return false + } - // Ensure we aren't deleting the screen slot - if (component._component?.endsWith("/screenslot")) { - throw "You can't delete the screen slot" - } - - // Ensure we aren't deleting something that contains the screen slot - const screenslot = findComponentType( - component, - "@budibase/standard-components/screenslot" - ) - if (screenslot != null) { - throw "You can't delete a component that contains the screen slot" - } - - const parent = findComponentParent(asset.props, component._id) - if (parent) { + // Check component has a valid parent + const parent = findComponentParent(screen.props, component._id) + if (!parent) { + return false + } + parentId = parent._id parent._children = parent._children.filter( child => child._id !== component._id ) - store.update(state => { - state.selectedComponentId = parent._id - return state - }) - } - await store.actions.preview.saveSelected() + }) + + // Select the deleted component's parent + store.update(state => { + state.selectedComponentId = parentId + return state + }) }, copy: (component, cut = false, selectParent = true) => { - const selectedAsset = get(currentAsset) - if (!selectedAsset) { - return null - } - // Update store with copied component store.update(state => { state.componentToPaste = cloneDeep(component) @@ -512,13 +569,11 @@ export const getFrontendStore = () => { return state }) - // Remove the component from its parent if we're cutting + // Select the parent if cutting if (cut) { - const parent = findComponentParent(selectedAsset.props, component._id) + const screen = get(selectedScreen) + const parent = findComponentParent(screen?.props, component._id) if (parent) { - parent._children = parent._children.filter( - child => child._id !== component._id - ) if (selectParent) { store.update(state => { state.selectedComponentId = parent._id @@ -528,24 +583,42 @@ export const getFrontendStore = () => { } } }, - paste: async (targetComponent, mode) => { - let promises = [] - store.update(state => { - // Stop if we have nothing to paste - if (!state.componentToPaste) { - return state + paste: async (targetComponent, mode, targetScreen) => { + const state = get(store) + if (!state.componentToPaste) { + return + } + let newComponentId + + // Patch screen + const patch = screen => { + // Get up to date ref to target + targetComponent = findComponent(screen.props, targetComponent._id) + if (!targetComponent) { + return } const cut = state.componentToPaste.isCut - - // Clone the component to paste and make unique if copying - delete state.componentToPaste.isCut + const originalId = state.componentToPaste._id let componentToPaste = cloneDeep(state.componentToPaste) - if (cut) { - state.componentToPaste = null - } else { + delete componentToPaste.isCut + + // Make new component unique if copying + if (!cut) { makeComponentUnique(componentToPaste) } + newComponentId = componentToPaste._id + // Delete old component if cutting + if (cut) { + const parent = findComponentParent(screen.props, originalId) + if (parent?._children) { + parent._children = parent._children.filter( + component => component._id !== originalId + ) + } + } + + // Paste new component if (mode === "inside") { // Paste inside target component if chosen if (!targetComponent._children) { @@ -553,66 +626,106 @@ export const getFrontendStore = () => { } targetComponent._children.push(componentToPaste) } else { - // Otherwise find the parent so we can paste in the correct order - // in the parents child components - const selectedAsset = get(currentAsset) - if (!selectedAsset) { - return state - } + // Otherwise paste in the correct order in the parent's children const parent = findComponentParent( - selectedAsset.props, + screen.props, targetComponent._id ) - if (!parent) { - return state + if (!parent?._children) { + return false } - - // Insert the component in the correct position - const targetIndex = parent._children.indexOf(targetComponent) + const targetIndex = parent._children.findIndex(component => { + return component._id === targetComponent._id + }) const index = mode === "above" ? targetIndex : targetIndex + 1 - parent._children.splice(index, 0, cloneDeep(componentToPaste)) + parent._children.splice(index, 0, componentToPaste) } + } + const targetScreenId = targetScreen?._id || state.selectedScreenId + await store.actions.screens.patch(patch, targetScreenId) - // Save and select the new component - promises.push(store.actions.preview.saveSelected()) - state.selectedComponentId = componentToPaste._id + store.update(state => { + // Remove copied component if cutting + if (state.componentToPaste.isCut) { + delete state.componentToPaste + } + state.selectedScreenId = targetScreenId + state.selectedComponentId = newComponentId return state }) - await Promise.all(promises) + }, + moveUp: async component => { + await store.actions.screens.patch(screen => { + const componentId = component?._id + const parent = findComponentParent(screen.props, componentId) + if (!parent?._children?.length) { + return false + } + const currentIndex = parent._children.findIndex( + child => child._id === componentId + ) + if (currentIndex === 0) { + return false + } + const originalComponent = cloneDeep(parent._children[currentIndex]) + const newChildren = parent._children.filter( + component => component._id !== componentId + ) + newChildren.splice(currentIndex - 1, 0, originalComponent) + parent._children = newChildren + }) + }, + moveDown: async component => { + await store.actions.screens.patch(screen => { + const componentId = component?._id + const parent = findComponentParent(screen.props, componentId) + if (!parent?._children?.length) { + return false + } + const currentIndex = parent._children.findIndex( + child => child._id === componentId + ) + if (currentIndex === parent._children.length - 1) { + return false + } + const originalComponent = cloneDeep(parent._children[currentIndex]) + const newChildren = parent._children.filter( + component => component._id !== componentId + ) + newChildren.splice(currentIndex + 1, 0, originalComponent) + parent._children = newChildren + }) }, updateStyle: async (name, value) => { - const selected = get(selectedComponent) - if (value == null || value === "") { - delete selected._styles.normal[name] - } else { - selected._styles.normal[name] = value - } - await store.actions.preview.saveSelected() + await store.actions.components.patch(component => { + if (value == null || value === "") { + delete component._styles.normal[name] + } else { + component._styles.normal[name] = value + } + }) }, updateCustomStyle: async style => { - const selected = get(selectedComponent) - selected._styles.custom = style - await store.actions.preview.saveSelected() + await store.actions.components.patch(component => { + component._styles.custom = style + }) }, updateConditions: async conditions => { - const selected = get(selectedComponent) - selected._conditions = conditions - await store.actions.preview.saveSelected() - }, - updateProp: async (name, value) => { - let component = get(selectedComponent) - if (!name || !component) { - return - } - if (component[name] === value) { - return - } - component[name] = value - store.update(state => { - state.selectedComponentId = component._id - return state + await store.actions.components.patch(component => { + component._conditions = conditions + }) + }, + updateSetting: async (name, value) => { + await store.actions.components.patch(component => { + if (!name || !component) { + return false + } + // Skip update if the value is the same + if (component[name] === value) { + return false + } + component[name] = value }) - await store.actions.preview.saveSelected() }, }, links: { diff --git a/packages/builder/src/components/design/settings/controls/ResetFieldsButton.svelte b/packages/builder/src/components/design/settings/controls/ResetFieldsButton.svelte index e927526b92..16aaf91ce2 100644 --- a/packages/builder/src/components/design/settings/controls/ResetFieldsButton.svelte +++ b/packages/builder/src/components/design/settings/controls/ResetFieldsButton.svelte @@ -18,7 +18,7 @@ const dataSource = form?.dataSource const fields = makeDatasourceFormComponents(dataSource) try { - await store.actions.components.updateProp( + await store.actions.components.updateSetting( "_children", fields.map(field => field.json()) ) 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 d86e4a3c8d..76118cc9c8 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 @@ -17,7 +17,8 @@ getOptionValue={x => x._id} getOptionIcon={x => (x.routing.homeScreen ? "Home" : "WebPage")} getOptionColour={x => RoleUtils.getRoleColour(x.routing.roleId)} - bind:value={$store.selectedScreenId} + value={$store.selectedScreenId} + on:change={e => store.actions.screens.select(e.detail)} />
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index e332f8e896..abb956c9d3 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -85,6 +85,10 @@ previewDevice: $store.previewDevice, messagePassing: $store.clientFeatures.messagePassing, navigation: $store.navigation, + hiddenComponentIds: + $store.componentToPaste?._id && $store.componentToPaste?.isCut + ? [$store.componentToPaste?._id] + : [], isBudibaseEvent: true, } @@ -138,7 +142,7 @@ $goto("./components") } } else if (type === "update-prop") { - await store.actions.components.updateProp(data.prop, data.value) + await store.actions.components.updateSetting(data.prop, data.value) } else if (type === "delete-component" && data.id) { confirmDeleteComponent(data.id) } else if (type === "duplicate-component" && data.id) { diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/iframeTemplate.js b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/iframeTemplate.js index def32dd45f..1c789d858e 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/iframeTemplate.js +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/iframeTemplate.js @@ -65,7 +65,8 @@ export default ` theme, customTheme, previewDevice, - navigation + navigation, + hiddenComponentIds } = parsed // Set some flags so the app knows we're in the builder @@ -79,6 +80,7 @@ export default ` window["##BUDIBASE_PREVIEW_CUSTOM_THEME##"] = customTheme window["##BUDIBASE_PREVIEW_DEVICE##"] = previewDevice window["##BUDIBASE_PREVIEW_NAVIGATION##"] = navigation + window["##BUDIBASE_HIDDEN_COMPONENT_IDS##"] = hiddenComponentIds // Initialise app try { diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentDropdownMenu.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentDropdownMenu.svelte index ae031e14bd..ed66c66c29 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentDropdownMenu.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentDropdownMenu.svelte @@ -1,8 +1,6 @@