diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js
index 94faa124a8..e92034c120 100644
--- a/packages/builder/cypress/support/commands.js
+++ b/packages/builder/cypress/support/commands.js
@@ -115,22 +115,22 @@ Cypress.Commands.add("createUser", (email, password, role) => {
// Create User
cy.contains("Users").click()
- cy.contains("Create New Row").click()
+ cy.contains("Create New User").click()
cy.get(".modal").within(() => {
cy.get("input")
.first()
- .type(password)
+ .type(email)
cy.get("input")
.eq(1)
- .type(email)
+ .type(password)
cy.get("select")
.first()
.select(role)
// Save
cy.get(".buttons")
- .contains("Create Row")
+ .contains("Create User")
.click()
})
})
diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js
index 887ef733e4..cf668670bb 100644
--- a/packages/builder/src/builderStore/index.js
+++ b/packages/builder/src/builderStore/index.js
@@ -2,9 +2,9 @@ import { getFrontendStore } from "./store/frontend"
import { getBackendUiStore } from "./store/backend"
import { getAutomationStore } from "./store/automation/"
import { getThemeStore } from "./store/theme"
-import { derived } from "svelte/store"
+import { derived, writable } from "svelte/store"
import analytics from "analytics"
-import { LAYOUT_NAMES } from "../constants"
+import { FrontendTypes, LAYOUT_NAMES } from "../constants"
import { makePropsSafe } from "components/userInterface/assetParsing/createProps"
export const store = getFrontendStore()
@@ -13,18 +13,12 @@ export const automationStore = getAutomationStore()
export const themeStore = getThemeStore()
export const currentAsset = derived(store, $store => {
- const layout = $store.layouts
- ? $store.layouts.find(layout => layout._id === $store.currentAssetId)
- : null
-
- if (layout) return layout
-
- const screen = $store.screens
- ? $store.screens.find(screen => screen._id === $store.currentAssetId)
- : null
-
- if (screen) return screen
-
+ const type = $store.currentFrontEndType
+ if (type === FrontendTypes.SCREEN) {
+ return $store.screens.find(screen => screen._id === $store.selectedScreenId)
+ } else if (type === FrontendTypes.LAYOUT) {
+ return $store.layouts.find(layout => layout._id === $store.selectedLayoutId)
+ }
return null
})
@@ -59,8 +53,14 @@ export const selectedComponent = derived(
}
)
-export const currentAssetName = derived(store, () => {
- return currentAsset.name
+export const currentAssetId = derived(store, $store => {
+ return $store.currentFrontEndType === FrontendTypes.SCREEN
+ ? $store.selectedScreenId
+ : $store.selectedLayoutId
+})
+
+export const currentAssetName = derived(currentAsset, $currentAsset => {
+ return $currentAsset?.name
})
// leave this as before for consistency
@@ -74,6 +74,8 @@ export const mainLayout = derived(store, $store => {
)
})
+export const selectedAccessRole = writable("BASIC")
+
export const initialise = async () => {
try {
await analytics.activate()
diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js
index 3cdabf1ed5..5592488590 100644
--- a/packages/builder/src/builderStore/store/backend.js
+++ b/packages/builder/src/builderStore/store/backend.js
@@ -6,6 +6,7 @@ const INITIAL_BACKEND_UI_STATE = {
tables: [],
views: [],
users: [],
+ roles: [],
selectedDatabase: {},
selectedTable: {},
draftTable: {},
@@ -177,6 +178,26 @@ export const getBackendUiStore = () => {
return state
}),
},
+ roles: {
+ fetch: async () => {
+ const response = await api.get("/api/roles")
+ const roles = await response.json()
+ store.update(state => {
+ state.roles = roles
+ return state
+ })
+ },
+ delete: async role => {
+ const response = await api.delete(`/api/roles/${role._id}/${role._rev}`)
+ await store.actions.roles.fetch()
+ return response
+ },
+ save: async role => {
+ const response = await api.post("/api/roles", role)
+ await store.actions.roles.fetch()
+ return response
+ },
+ },
}
return store
diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js
index 5bb10a24c2..263041aadd 100644
--- a/packages/builder/src/builderStore/store/frontend.js
+++ b/packages/builder/src/builderStore/store/frontend.js
@@ -3,7 +3,6 @@ import { cloneDeep } from "lodash/fp"
import {
createProps,
getBuiltin,
- makePropsSafe,
} from "components/userInterface/assetParsing/createProps"
import {
allScreens,
@@ -11,6 +10,7 @@ import {
currentAsset,
mainLayout,
selectedComponent,
+ selectedAccessRole,
} from "builderStore"
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
import api from "../api"
@@ -32,7 +32,8 @@ const INITIAL_FRONTEND_STATE = {
screens: [],
components: [],
currentFrontEndType: "none",
- currentAssetId: "",
+ selectedScreenId: "",
+ selectedLayoutId: "",
selectedComponentId: "",
errors: [],
hasAppPackage: false,
@@ -83,28 +84,31 @@ export const getFrontendStore = () => {
},
},
screens: {
- select: async screenId => {
- let promise
+ select: screenId => {
store.update(state => {
- const screen = get(allScreens).find(screen => screen._id === screenId)
+ let screens = get(allScreens)
+ let screen =
+ screens.find(screen => screen._id === screenId) || screens[0]
if (!screen) return state
- state.currentFrontEndType = FrontendTypes.SCREEN
- state.currentAssetId = screenId
- state.currentView = "detail"
+ // Update role to the screen's role setting so that it will always
+ // be visible
+ selectedAccessRole.set(screen.routing.roleId)
- promise = store.actions.screens.regenerateCss(screen)
+ state.currentFrontEndType = FrontendTypes.SCREEN
+ state.selectedScreenId = screen._id
+ state.currentView = "detail"
state.selectedComponentId = screen.props?._id
return state
})
- await promise
},
create: async screen => {
screen = await store.actions.screens.save(screen)
store.update(state => {
- state.currentAssetId = screen._id
+ state.selectedScreenId = screen._id
state.selectedComponentId = screen.props._id
state.currentFrontEndType = FrontendTypes.SCREEN
+ selectedAccessRole.set(screen.routing.roleId)
return state
})
return screen
@@ -113,6 +117,7 @@ export const getFrontendStore = () => {
const creatingNewScreen = screen._id === undefined
const response = await api.post(`/api/screens`, screen)
screen = await response.json()
+ await store.actions.routing.fetch()
store.update(state => {
const foundScreen = state.screens.findIndex(
@@ -122,28 +127,14 @@ export const getFrontendStore = () => {
state.screens.splice(foundScreen, 1)
}
state.screens.push(screen)
-
- if (creatingNewScreen) {
- const safeProps = makePropsSafe(
- state.components[screen.props._component],
- screen.props
- )
- state.selectedComponentId = safeProps._id
- screen.props = safeProps
- }
return state
})
- return screen
- },
- regenerateCss: async asset => {
- const response = await api.post("/api/css/generate", asset)
- asset._css = (await response.json())?.css
- },
- regenerateCssForCurrentScreen: async () => {
- const asset = get(currentAsset)
- if (asset) {
- await store.actions.screens.regenerateCss(asset)
+
+ if (creatingNewScreen) {
+ store.actions.screens.select(screen._id)
}
+
+ return screen
},
delete: async screens => {
const screensToDelete = Array.isArray(screens) ? screens : [screens]
@@ -159,8 +150,8 @@ export const getFrontendStore = () => {
`/api/screens/${screenToDelete._id}/${screenToDelete._rev}`
)
)
- if (screenToDelete._id === state.currentAssetId) {
- state.currentAssetId = ""
+ if (screenToDelete._id === state.selectedScreenId) {
+ state.selectedScreenId = null
}
}
return state
@@ -181,50 +172,44 @@ export const getFrontendStore = () => {
},
},
layouts: {
- select: async layoutId => {
+ select: layoutId => {
store.update(state => {
- const layout = store.actions.layouts.find(layoutId)
-
+ const layout =
+ store.actions.layouts.find(layoutId) || get(store).layouts[0]
+ if (!layout) return
state.currentFrontEndType = FrontendTypes.LAYOUT
state.currentView = "detail"
-
- state.currentAssetId = layout._id
+ state.selectedLayoutId = layout._id
state.selectedComponentId = layout.props?._id
-
return state
})
- let cssPromises = []
- cssPromises.push(store.actions.screens.regenerateCssForCurrentScreen())
-
- for (let screen of get(allScreens)) {
- cssPromises.push(store.actions.screens.regenerateCss(screen))
- }
- await Promise.all(cssPromises)
},
save: async layout => {
const layoutToSave = cloneDeep(layout)
- delete layoutToSave._css
-
+ const creatingNewLayout = layoutToSave._id === undefined
const response = await api.post(`/api/layouts`, layoutToSave)
-
- const json = await response.json()
+ const savedLayout = await response.json()
store.update(state => {
const layoutIdx = state.layouts.findIndex(
- stateLayout => stateLayout._id === json._id
+ stateLayout => stateLayout._id === savedLayout._id
)
-
if (layoutIdx >= 0) {
// update existing layout
- state.layouts.splice(layoutIdx, 1, json)
+ state.layouts.splice(layoutIdx, 1, savedLayout)
} else {
// save new layout
- state.layouts.push(json)
+ state.layouts.push(savedLayout)
}
-
- state.currentAssetId = json._id
return state
})
+
+ // Select layout if creating a new one
+ if (creatingNewLayout) {
+ store.actions.layouts.select(savedLayout._id)
+ }
+
+ return savedLayout
},
find: layoutId => {
if (!layoutId) {
@@ -237,16 +222,17 @@ export const getFrontendStore = () => {
const response = await api.delete(
`/api/layouts/${layoutToDelete._id}/${layoutToDelete._rev}`
)
-
if (response.status !== 200) {
const json = await response.json()
throw new Error(json.message)
}
-
store.update(state => {
state.layouts = state.layouts.filter(
layout => layout._id !== layoutToDelete._id
)
+ if (layoutToDelete._id === state.selectedLayoutId) {
+ state.selectedLayoutId = get(mainLayout)._id
+ }
return state
})
},
@@ -372,7 +358,6 @@ export const getFrontendStore = () => {
const index = mode === "above" ? targetIndex : targetIndex + 1
parent._children.splice(index, 0, cloneDeep(componentToPaste))
- promises.push(store.actions.screens.regenerateCssForCurrentScreen())
promises.push(store.actions.preview.saveSelected())
store.actions.components.select(componentToPaste)
@@ -390,8 +375,6 @@ export const getFrontendStore = () => {
}
selected._styles[type][name] = value
- promises.push(store.actions.screens.regenerateCssForCurrentScreen())
-
// save without messing with the store
promises.push(store.actions.preview.saveSelected())
return state
@@ -476,13 +459,8 @@ export const getFrontendStore = () => {
}).props
}
- // Save layout and regenerate all CSS because otherwise weird things happen
+ // Save layout
nav._children = [...nav._children, newLink]
- state.currentAssetId = layout._id
- promises.push(store.actions.screens.regenerateCss(layout))
- for (let screen of get(allScreens)) {
- promises.push(store.actions.screens.regenerateCss(screen))
- }
promises.push(store.actions.layouts.save(layout))
}
return state
diff --git a/packages/builder/src/components/backend/DataTable/DataTable.svelte b/packages/builder/src/components/backend/DataTable/DataTable.svelte
index 063ca34633..436a3b4dee 100644
--- a/packages/builder/src/components/backend/DataTable/DataTable.svelte
+++ b/packages/builder/src/components/backend/DataTable/DataTable.svelte
@@ -4,12 +4,17 @@
import CreateColumnButton from "./buttons/CreateColumnButton.svelte"
import CreateViewButton from "./buttons/CreateViewButton.svelte"
import ExportButton from "./buttons/ExportButton.svelte"
+ import EditRolesButton from "./buttons/EditRolesButton.svelte"
import * as api from "./api"
import Table from "./Table.svelte"
+ import { TableNames } from "constants"
+ import CreateEditUser from "./modals/CreateEditUser.svelte"
+ import CreateEditRow from "./modals/CreateEditRow.svelte"
let data = []
let loading = false
+ $: isUsersTable = $backendUiStore.selectedTable?._id === TableNames.USERS
$: title = $backendUiStore.selectedTable.name
$: schema = $backendUiStore.selectedTable.schema
$: tableView = {
@@ -29,11 +34,22 @@
}
-
+
{#if schema && Object.keys(schema).length > 0}
-
+
{/if}
+ {#if isUsersTable}
+
+ {/if}
diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
index 8b1c2e18e6..bddb66e4c9 100644
--- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
+++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
@@ -7,20 +7,16 @@
Toggle,
RichText,
} from "@budibase/bbui"
- import { backendUiStore } from "builderStore"
- import { TableNames } from "constants"
import Dropzone from "components/common/Dropzone.svelte"
import { capitalise } from "../../../helpers"
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
export let meta
- export let creating
export let value = meta.type === "boolean" ? false : ""
+ export let readonly
$: type = meta.type
$: label = capitalise(meta.name)
- $: editingUser =
- !creating && $backendUiStore.selectedTable?._id === TableNames.USERS
{#if type === 'options'}
@@ -53,5 +49,5 @@
data-cy="{meta.name}-input"
{type}
bind:value
- disabled={editingUser} />
+ disabled={readonly} />
{/if}
diff --git a/packages/builder/src/components/backend/DataTable/Table.svelte b/packages/builder/src/components/backend/DataTable/Table.svelte
index 2599e4f8b0..1e6c53bd11 100644
--- a/packages/builder/src/components/backend/DataTable/Table.svelte
+++ b/packages/builder/src/components/backend/DataTable/Table.svelte
@@ -7,10 +7,15 @@
import { notifier } from "builderStore/store/notifications"
import Spinner from "components/common/Spinner.svelte"
import DeleteRowsButton from "./buttons/DeleteRowsButton.svelte"
- import { getRenderer, editRowRenderer } from "./cells/cellRenderers"
+ import {
+ getRenderer,
+ editRowRenderer,
+ userRowRenderer,
+ } from "./cells/cellRenderers"
import TableLoadingOverlay from "./TableLoadingOverlay"
import TableHeader from "./TableHeader"
import "@budibase/svelte-ag-grid/dist/index.css"
+ import { TableNames } from "constants"
export let schema = {}
export let data = []
@@ -42,7 +47,18 @@
animateRows: true,
}
+ $: isUsersTable = tableId === TableNames.USERS
$: {
+ if (isUsersTable) {
+ schema.email.displayFieldName = "Email"
+ schema.roleId.displayFieldName = "Role"
+ }
+ }
+
+ $: {
+ // Reset selection every time data changes
+ selectedRows = []
+
let result = []
if (allowEditing) {
result = [
@@ -57,23 +73,34 @@
suppressMenu: true,
minWidth: 114,
width: 114,
- cellRenderer: editRowRenderer,
+ cellRenderer: isUsersTable ? userRowRenderer : editRowRenderer,
},
]
}
- Object.keys(schema || {}).forEach((key, idx) => {
+ const canEditColumn = key => {
+ if (!allowEditing) {
+ return false
+ }
+ return !(isUsersTable && ["email", "roleId"].includes(key))
+ }
+
+ Object.entries(schema || {}).forEach(([key, value]) => {
result.push({
headerCheckboxSelection: false,
headerComponent: TableHeader,
headerComponentParams: {
field: schema[key],
- editable: allowEditing,
+ editable: canEditColumn(key),
},
- headerName: key,
+ headerName: value.displayFieldName || key,
field: key,
sortable: true,
- cellRenderer: getRenderer(schema[key], true),
+ cellRenderer: getRenderer({
+ schema: schema[key],
+ editable: true,
+ isUsersTable,
+ }),
cellRendererParams: {
selectRelationship,
},
diff --git a/packages/builder/src/components/backend/DataTable/buttons/CreateRowButton.svelte b/packages/builder/src/components/backend/DataTable/buttons/CreateRowButton.svelte
index 3c0444881f..19975ac1a1 100644
--- a/packages/builder/src/components/backend/DataTable/buttons/CreateRowButton.svelte
+++ b/packages/builder/src/components/backend/DataTable/buttons/CreateRowButton.svelte
@@ -1,6 +1,9 @@
@@ -8,9 +11,9 @@
-
+
diff --git a/packages/builder/src/components/backend/DataTable/buttons/EditRolesButton.svelte b/packages/builder/src/components/backend/DataTable/buttons/EditRolesButton.svelte
new file mode 100644
index 0000000000..024905fddc
--- /dev/null
+++ b/packages/builder/src/components/backend/DataTable/buttons/EditRolesButton.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DataTable/cells/RoleCell.svelte b/packages/builder/src/components/backend/DataTable/cells/RoleCell.svelte
new file mode 100644
index 0000000000..a45f376a3e
--- /dev/null
+++ b/packages/builder/src/components/backend/DataTable/cells/RoleCell.svelte
@@ -0,0 +1,10 @@
+
+
+{roleName}
diff --git a/packages/builder/src/components/backend/DataTable/cells/cellRenderers.js b/packages/builder/src/components/backend/DataTable/cells/cellRenderers.js
index 209f23119f..15a7910186 100644
--- a/packages/builder/src/components/backend/DataTable/cells/cellRenderers.js
+++ b/packages/builder/src/components/backend/DataTable/cells/cellRenderers.js
@@ -1,16 +1,25 @@
import AttachmentList from "./AttachmentCell.svelte"
import EditRow from "../modals/EditRow.svelte"
+import CreateEditUser from "../modals/CreateEditUser.svelte"
import DeleteRow from "../modals/DeleteRow.svelte"
import RelationshipDisplay from "./RelationshipCell.svelte"
+import RoleCell from "./RoleCell.svelte"
const renderers = {
attachment: attachmentRenderer,
link: linkedRowRenderer,
}
-export function getRenderer(schema, editable) {
+export function getRenderer({ schema, editable, isUsersTable }) {
+ const rendererParams = {
+ options: schema.options,
+ constraints: schema.constraints,
+ editable,
+ }
if (renderers[schema.type]) {
- return renderers[schema.type](schema.options, schema.constraints, editable)
+ return renderers[schema.type](rendererParams)
+ } else if (isUsersTable && schema.name === "roleId") {
+ return roleRenderer(rendererParams)
} else {
return false
}
@@ -45,15 +54,31 @@ export function editRowRenderer(params) {
return container
}
-/* eslint-disable no-unused-vars */
-function attachmentRenderer(options, constraints, editable) {
+export function userRowRenderer(params) {
+ const container = document.createElement("div")
+ container.style.height = "100%"
+ container.style.display = "flex"
+ container.style.alignItems = "center"
+
+ new EditRow({
+ target: container,
+ props: {
+ row: params.data,
+ modalContentComponent: CreateEditUser,
+ },
+ })
+
+ return container
+}
+
+function attachmentRenderer() {
return params => {
const container = document.createElement("div")
container.style.height = "100%"
container.style.display = "flex"
container.style.alignItems = "center"
- const attachmentInstance = new AttachmentList({
+ new AttachmentList({
target: container,
props: {
files: params.value || [],
@@ -64,7 +89,6 @@ function attachmentRenderer(options, constraints, editable) {
}
}
-/* eslint-disable no-unused-vars */
function linkedRowRenderer() {
return params => {
let container = document.createElement("div")
@@ -84,3 +108,21 @@ function linkedRowRenderer() {
return container
}
}
+
+function roleRenderer() {
+ return params => {
+ let container = document.createElement("div")
+ container.style.display = "grid"
+ container.style.height = "100%"
+ container.style.alignItems = "center"
+
+ new RoleCell({
+ target: container,
+ props: {
+ roleId: params.value,
+ },
+ })
+
+ return container
+ }
+}
diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditRowModal.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditRow.svelte
similarity index 81%
rename from packages/builder/src/components/backend/DataTable/modals/CreateEditRowModal.svelte
rename to packages/builder/src/components/backend/DataTable/modals/CreateEditRow.svelte
index e99c5762d8..050c7ce200 100644
--- a/packages/builder/src/components/backend/DataTable/modals/CreateEditRowModal.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditRow.svelte
@@ -1,6 +1,5 @@
+
+
+
+
+
+
+
+ {#each customSchemaKeys as [key, meta]}
+
+ {/each}
+
diff --git a/packages/builder/src/components/backend/DataTable/modals/EditRoles.svelte b/packages/builder/src/components/backend/DataTable/modals/EditRoles.svelte
new file mode 100644
index 0000000000..3b97f6d61b
--- /dev/null
+++ b/packages/builder/src/components/backend/DataTable/modals/EditRoles.svelte
@@ -0,0 +1,132 @@
+
+
+
+ {#if errors.length}
+
+ {/if}
+
+ {#if selectedRole}
+
+
+
+ {/if}
+
+ {#if !isCreating}
+
+ {/if}
+
+
diff --git a/packages/builder/src/components/backend/DataTable/modals/EditRow.svelte b/packages/builder/src/components/backend/DataTable/modals/EditRow.svelte
index a4d2a74fc2..5d858a50f4 100644
--- a/packages/builder/src/components/backend/DataTable/modals/EditRow.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/EditRow.svelte
@@ -1,8 +1,9 @@
{#if hasErrors}
-
+
{#each errors as error}
-
{error.dataPath} {error.message}
+
{error.dataPath || ''} {error.message}
{/each}
{/if}
@@ -17,6 +17,8 @@
border-radius: var(--border-radius-m);
margin: 0;
padding: var(--spacing-m);
+ background-color: rgba(241, 165, 165, 0.2);
+ color: var(--red);
}
.error {
diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte
index 5b1ede4394..8eca07b1b0 100644
--- a/packages/builder/src/components/common/NavItem.svelte
+++ b/packages/builder/src/components/common/NavItem.svelte
@@ -61,7 +61,7 @@
}
.nav-item:hover,
.nav-item.selected {
- border-radius: var(--border-radius-m);
+ border-radius: var(--border-radius-s);
}
.content {
diff --git a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte
index ccb0153e45..0c0fa6156f 100644
--- a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte
+++ b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte
@@ -84,6 +84,7 @@
overflow: hidden;
margin: auto;
height: 100%;
+ background-color: white;
}
.component-container iframe {
border: 0;
diff --git a/packages/builder/src/components/userInterface/ComponentNavigationTree/ComponentTree.svelte b/packages/builder/src/components/userInterface/ComponentNavigationTree/ComponentTree.svelte
index 6a2019aa69..320a81f00d 100644
--- a/packages/builder/src/components/userInterface/ComponentNavigationTree/ComponentTree.svelte
+++ b/packages/builder/src/components/userInterface/ComponentNavigationTree/ComponentTree.svelte
@@ -1,6 +1,6 @@
- {#each Object.keys($store.routes || {}) as path}
-
+ {#each paths as path, idx}
+
0} {path} route={routes[path]} />
{/each}
+
+ {#if !paths.length}
+
+ There aren't any screens configured with this access role.
+
+ {/if}
+
+
diff --git a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
index b4ac25bdd5..4699a8e415 100644
--- a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
+++ b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
@@ -6,6 +6,7 @@
import CategoryTab from "./CategoryTab.svelte"
import DesignView from "./DesignView.svelte"
import SettingsView from "./SettingsView.svelte"
+ import { setWith } from "lodash"
let flattenedPanel = flattenComponents(panelStructure.categories)
let categories = [
@@ -69,7 +70,7 @@
) {
selectedAsset.props._instanceName = value
} else {
- selectedAsset[name] = value
+ setWith(selectedAsset, name.split("."), value, Object)
}
return state
})
diff --git a/packages/builder/src/components/userInterface/ComponentSelectionList.svelte b/packages/builder/src/components/userInterface/ComponentSelectionList.svelte
index 260eff72c6..60f40be6e2 100644
--- a/packages/builder/src/components/userInterface/ComponentSelectionList.svelte
+++ b/packages/builder/src/components/userInterface/ComponentSelectionList.svelte
@@ -1,6 +1,11 @@
diff --git a/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte b/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte
index 23d2e6cf1a..698476dcd8 100644
--- a/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte
+++ b/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte
@@ -1,13 +1,19 @@
-{#if $store.currentAssetId === layout._id && layout.props?._children}
+{#if $store.selectedLayoutId === layout._id && layout.props?._children}
import { goto } from "@sveltech/routify"
- import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications"
- import { store, backendUiStore, allScreens } from "builderStore"
+ import { store } from "builderStore"
import { Input, ModalContent } from "@budibase/bbui"
- import analytics from "analytics"
-
- const CONTAINER = "@budibase/standard-components/container"
let name = ""
async function save() {
try {
- await store.actions.layouts.save({ name })
- $goto(`./${$store.currentAssetId}`)
+ const layout = await store.actions.layouts.save({ name })
+ $goto(`./${layout._id}`)
notifier.success(`Layout ${name} created successfully`)
} catch (err) {
notifier.danger(`Error creating layout ${name}.`)
diff --git a/packages/builder/src/components/userInterface/NewScreenModal.svelte b/packages/builder/src/components/userInterface/NewScreenModal.svelte
index 05a18adb7f..db9181b1bd 100644
--- a/packages/builder/src/components/userInterface/NewScreenModal.svelte
+++ b/packages/builder/src/components/userInterface/NewScreenModal.svelte
@@ -1,17 +1,11 @@
+
+
diff --git a/packages/builder/src/components/userInterface/SettingsView.svelte b/packages/builder/src/components/userInterface/SettingsView.svelte
index dd4644882c..eee50d8cf6 100644
--- a/packages/builder/src/components/userInterface/SettingsView.svelte
+++ b/packages/builder/src/components/userInterface/SettingsView.svelte
@@ -1,8 +1,10 @@
diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte
index 75061ac327..a7a972a435 100644
--- a/packages/client/src/components/ClientApp.svelte
+++ b/packages/client/src/components/ClientApp.svelte
@@ -3,7 +3,7 @@
import { setContext, onMount } from "svelte"
import Component from "./Component.svelte"
import SDK from "../sdk"
- import { createDataStore, routeStore, screenStore } from "../store"
+ import { createDataStore, initialise, screenStore } from "../store"
// Provide contexts
setContext("sdk", SDK)
@@ -14,13 +14,11 @@
// Load app config
onMount(async () => {
- await routeStore.actions.fetchRoutes()
- await screenStore.actions.fetchScreens()
+ await initialise()
loaded = true
})
{#if loaded && $screenStore.activeLayout}
-
{/if}
diff --git a/packages/client/src/components/Router.svelte b/packages/client/src/components/Router.svelte
index 5684b189eb..3c2d71c422 100644
--- a/packages/client/src/components/Router.svelte
+++ b/packages/client/src/components/Router.svelte
@@ -7,7 +7,15 @@
const { styleable } = getContext("sdk")
const component = getContext("component")
- $: routerConfig = getRouterConfig($routeStore.routes)
+ // Only wrap this as an array to take advantage of svelte keying,
+ // to ensure the svelte-spa-router is fully remounted when route config
+ // changes
+ $: configs = [
+ {
+ routes: getRouterConfig($routeStore.routes),
+ id: $routeStore.routeSessionId,
+ },
+ ]
const getRouterConfig = routes => {
let config = {}
@@ -25,11 +33,11 @@
}
-{#if routerConfig}
+{#each configs as config (config.id)}
-
+
-{/if}
+{/each}