diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 5524cb5991..8345a55b40 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -86,8 +86,8 @@ export const getFrontendStore = () => { description: application.description, appId: application.appId, url: application.url, - layouts, - screens, + layouts: layouts || [], + screens: screens || [], theme: application.theme || "spectrum--light", customTheme: application.customTheme, hasAppPackage: true, @@ -109,49 +109,36 @@ export const getFrontendStore = () => { theme: { save: async theme => { const appId = get(store).appId - try { - await API.saveAppMetadata({ - appId, - metadata: { theme }, - }) - store.update(state => { - state.theme = theme - return state - }) - } catch (error) { - notifications.error("Error updating theme") - } + await API.saveAppMetadata({ + appId, + metadata: { theme }, + }) + store.update(state => { + state.theme = theme + return state + }) }, }, customTheme: { save: async customTheme => { const appId = get(store).appId - try { - await API.saveAppMetadata({ - appId, - metadata: { customTheme }, - }) - store.update(state => { - state.customTheme = customTheme - return state - }) - } catch (error) { - notifications.error("Error updating custom theme") - } + await API.saveAppMetadata({ + appId, + metadata: { customTheme }, + }) + store.update(state => { + state.customTheme = customTheme + return state + }) }, }, routing: { fetch: async () => { - try { - const routes = await API.getAppRoutes() - console.log(routes) - store.update(state => { - state.routes = routes.routes - return state - }) - } catch (error) { - notifications.error("Error fetching app routes") - } + const response = await API.fetchAppRoutes() + store.update(state => { + state.routes = response.routes + return state + }) }, }, screens: { @@ -174,50 +161,41 @@ export const getFrontendStore = () => { }) }, create: async screen => { - try { - const savedScreen = await API.saveScreen(screen) - store.update(state => { - state.selectedScreenId = savedScreen._id - state.selectedComponentId = savedScreen.props._id - state.currentFrontEndType = FrontendTypes.SCREEN - selectedAccessRole.set(savedScreen.routing.roleId) - return savedScreen - }) + const savedScreen = await API.saveScreen(screen) + store.update(state => { + state.screens.push(savedScreen) + state.selectedScreenId = savedScreen._id + state.selectedComponentId = savedScreen.props._id + state.currentFrontEndType = FrontendTypes.SCREEN + selectedAccessRole.set(savedScreen.routing.roleId) + return state + }) - // Refresh routes - await store.actions.routing.fetch() - return savedScreen - } catch (error) { - notifications.error("Error creating screen") - return null - } + // Refresh routes + await store.actions.routing.fetch() + return savedScreen }, save: async screen => { - try { - const creatingNewScreen = screen._id === undefined - const savedScreen = await API.saveScreen(screen) - store.update(state => { - const idx = state.screens.findIndex(x => x._id === savedScreen._id) - if (idx !== -1) { - state.screens.splice(idx, 1, savedScreen) - } else { - state.screens.push(savedScreen) - } - 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) + const creatingNewScreen = screen._id === undefined + const savedScreen = await API.saveScreen(screen) + store.update(state => { + const idx = state.screens.findIndex(x => x._id === savedScreen._id) + if (idx !== -1) { + state.screens.splice(idx, 1, savedScreen) + } else { + state.screens.push(savedScreen) } - return savedScreen - } catch (error) { - notifications.error("Error saving screen") - return null + 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 }, delete: async screens => { const screensToDelete = Array.isArray(screens) ? screens : [screens] @@ -241,23 +219,22 @@ export const getFrontendStore = () => { ) }) - try { - await Promise.all(promises) - const deletedIds = screensToDelete.map(screen => screen._id) - 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 - } - return state + await Promise.all(promises) + const deletedIds = screensToDelete.map(screen => screen._id) + store.update(state => { + // Remove deleted screens from state + state.screens = state.screens.filter(screen => { + return !deletedIds.includes(screen._id) }) - } catch (error) { - notifications.error("Error deleting screens") - } + // Deselect the current screen if it was deleted + if (deletedIds.includes(state.selectedScreenId)) { + state.selectedScreenId = null + } + return state + }) + + // Refresh routes + await store.actions.routing.fetch() }, }, preview: { @@ -291,28 +268,23 @@ export const getFrontendStore = () => { }) }, save: async layout => { - try { - 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) + 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 savedLayout - } catch (error) { - notifications.error("Error saving layout") - return null + return state + }) + + // Select layout if creating a new one + if (creatingNewLayout) { + store.actions.layouts.select(savedLayout._id) } + return savedLayout }, find: layoutId => { if (!layoutId) { @@ -325,22 +297,18 @@ export const getFrontendStore = () => { if (!layout?._id) { return } - try { - await API.deleteLayout({ - layoutId: layout._id, - 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 - }) - } catch (error) { - notifications.error("Failed to delete layout") - } + await API.deleteLayout({ + layoutId: layout._id, + 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 + }) }, }, components: { @@ -622,11 +590,6 @@ export const getFrontendStore = () => { selected._styles.custom = style await store.actions.preview.saveSelected() }, - resetStyles: async () => { - const selected = get(selectedComponent) - selected._styles = { normal: {}, hover: {}, active: {} } - await store.actions.preview.saveSelected() - }, updateConditions: async conditions => { const selected = get(selectedComponent) selected._conditions = conditions diff --git a/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte b/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte index a1a5a7a242..cdab47db66 100644 --- a/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte +++ b/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte @@ -1,5 +1,5 @@ diff --git a/packages/builder/src/components/design/AppPreview/ComponentSelectionList.svelte b/packages/builder/src/components/design/AppPreview/ComponentSelectionList.svelte index a968effaf5..cabcea756e 100644 --- a/packages/builder/src/components/design/AppPreview/ComponentSelectionList.svelte +++ b/packages/builder/src/components/design/AppPreview/ComponentSelectionList.svelte @@ -1,5 +1,11 @@ diff --git a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte index 77700fc264..2a886fab0c 100644 --- a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte @@ -146,44 +146,49 @@ } }) - const handleBudibaseEvent = event => { + const handleBudibaseEvent = async event => { const { type, data } = event.data || event.detail if (!type) { return } - if (type === "select-component" && data.id) { - store.actions.components.select({ _id: data.id }) - } else if (type === "update-prop") { - store.actions.components.updateProp(data.prop, data.value) - } else if (type === "delete-component" && data.id) { - confirmDeleteComponent(data.id) - } else if (type === "preview-loaded") { - // Wait for this event to show the client library if intelligent - // loading is supported - loading = false - } else if (type === "move-component") { - const { componentId, destinationComponentId } = data - const rootComponent = get(currentAsset).props + try { + if (type === "select-component" && data.id) { + store.actions.components.select({ _id: data.id }) + } else if (type === "update-prop") { + await store.actions.components.updateProp(data.prop, data.value) + } else if (type === "delete-component" && data.id) { + confirmDeleteComponent(data.id) + } else if (type === "preview-loaded") { + // Wait for this event to show the client library if intelligent + // loading is supported + loading = false + } else if (type === "move-component") { + const { componentId, destinationComponentId } = data + const rootComponent = get(currentAsset).props - // Get source and destination components - const source = findComponent(rootComponent, componentId) - const destination = findComponent(rootComponent, destinationComponentId) + // Get source and destination components + const source = findComponent(rootComponent, componentId) + const destination = findComponent(rootComponent, destinationComponentId) - // Stop if the target is a child of source - const path = findComponentPath(source, destinationComponentId) - const ids = path.map(component => component._id) - if (ids.includes(data.destinationComponentId)) { - return + // Stop if the target is a child of source + const path = findComponentPath(source, destinationComponentId) + const ids = path.map(component => component._id) + if (ids.includes(data.destinationComponentId)) { + return + } + + // Cut and paste the component to the new destination + if (source && destination) { + store.actions.components.copy(source, true) + await store.actions.components.paste(destination, data.mode) + } + } else { + console.warn(`Client sent unknown event type: ${type}`) } - - // Cut and paste the component to the new destination - if (source && destination) { - store.actions.components.copy(source, true) - store.actions.components.paste(destination, data.mode) - } - } else { - console.warn(`Client sent unknown event type: ${type}`) + } catch (error) { + console.warn(error) + notifications.error("Error handling event from app preview") } } @@ -196,7 +201,7 @@ try { await store.actions.components.delete({ _id: idToDelete }) } catch (error) { - notifications.error(error) + notifications.error("Error deleting component") } idToDelete = null } diff --git a/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte b/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte index 14747191c2..e10ac4f0cd 100644 --- a/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte +++ b/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte @@ -9,6 +9,7 @@ Label, Select, Button, + notifications, } from "@budibase/bbui" import { store } from "builderStore" import AppThemeSelect from "./AppThemeSelect.svelte" @@ -43,23 +44,31 @@ ] const updateProperty = property => { - return e => { - store.actions.customTheme.save({ - ...get(store).customTheme, - [property]: e.detail, - }) + return async e => { + try { + store.actions.customTheme.save({ + ...get(store).customTheme, + [property]: e.detail, + }) + } catch (error) { + notifications.error("Error updating custom theme") + } } } const resetTheme = () => { - const theme = get(store).theme - store.actions.customTheme.save({ - ...defaultTheme, - navBackground: - theme === "spectrum--light" - ? "var(--spectrum-global-color-gray-50)" - : "var(--spectrum-global-color-gray-100)", - }) + try { + const theme = get(store).theme + store.actions.customTheme.save({ + ...defaultTheme, + navBackground: + theme === "spectrum--light" + ? "var(--spectrum-global-color-gray-50)" + : "var(--spectrum-global-color-gray-100)", + }) + } catch (error) { + notifications.error("Error saving custom theme") + } } diff --git a/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte b/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte index 8ab8c23134..0fcd43b58e 100644 --- a/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte +++ b/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte @@ -29,10 +29,14 @@ if (currentIndex === 0) { return } - const newChildren = parent._children.filter(c => c !== component) - newChildren.splice(currentIndex - 1, 0, component) - parent._children = newChildren - store.actions.preview.saveSelected() + try { + const newChildren = parent._children.filter(c => c !== component) + newChildren.splice(currentIndex - 1, 0, component) + parent._children = newChildren + store.actions.preview.saveSelected() + } catch (error) { + notifications.error("Error saving screen") + } } const moveDownComponent = () => { @@ -45,10 +49,14 @@ if (currentIndex === parent._children.length - 1) { return } - const newChildren = parent._children.filter(c => c !== component) - newChildren.splice(currentIndex + 1, 0, component) - parent._children = newChildren - store.actions.preview.saveSelected() + try { + const newChildren = parent._children.filter(c => c !== component) + newChildren.splice(currentIndex + 1, 0, component) + parent._children = newChildren + store.actions.preview.saveSelected() + } catch (error) { + notifications.error("Error saving screen") + } } const duplicateComponent = () => { @@ -60,7 +68,7 @@ try { await store.actions.components.delete(component) } catch (error) { - notifications.error(error) + notifications.error("Error deleting component") } } @@ -70,8 +78,12 @@ } const pasteComponent = (mode, preserveBindings = false) => { - // lives in store - also used by drag drop - store.actions.components.paste(component, mode, preserveBindings) + try { + // lives in store - also used by drag drop + store.actions.components.paste(component, mode, preserveBindings) + } catch (error) { + notifications.error("Error saving component") + } } diff --git a/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/ComponentTree.svelte b/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/ComponentTree.svelte index 910ffc18f8..c5dfd63cf9 100644 --- a/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/ComponentTree.svelte +++ b/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/ComponentTree.svelte @@ -4,6 +4,7 @@ import ComponentDropdownMenu from "../ComponentDropdownMenu.svelte" import NavItem from "components/common/NavItem.svelte" import { capitalise } from "helpers" + import { notifications } from "@budibase/bbui" export let components = [] export let currentComponent @@ -62,6 +63,14 @@ } closedNodes = closedNodes } + + const onDrop = async () => { + try { + await dragDropStore.actions.drop() + } catch (error) { + notifications.error("Error saving component") + } + }