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}