diff --git a/packages/builder/src/builderStore/getNewComponentName.js b/packages/builder/src/builderStore/getNewComponentName.js index a4565c2296..963c66ebce 100644 --- a/packages/builder/src/builderStore/getNewComponentName.js +++ b/packages/builder/src/builderStore/getNewComponentName.js @@ -33,7 +33,7 @@ export default function(component, state) { let index = 1 let name while (!name) { - const tryName = `${capitalised} ${index}` + const tryName = `${capitalised || "Copy"} ${index}` if (!matchingComponents.includes(tryName)) name = tryName index++ } diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index ec41627f54..488158586b 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -17,7 +17,7 @@ import { getParent, // saveScreenApi as _saveScreenApi, generateNewIdsForComponent, - getComponentDefinition, + getComponentDefinition, findChildComponentType, regenerateCssForScreen, savePage as _savePage, } from "../storeUtils" const INITIAL_FRONTEND_STATE = { @@ -171,18 +171,18 @@ export const getFrontendStore = () => { screen ) const json = await response.json() - - if (currentPageScreens.includes(screen)) return - screen._rev = json.rev screen._id = json.id - - const screens = [...currentPageScreens, screen] + const foundScreen = currentPageScreens.findIndex(el => el._id === screen._id) + if (currentPageScreens !== -1) { + currentPageScreens.splice(foundScreen, 1) + } + currentPageScreens.push(screen) // TODO: should carry out all server updates to screen in a single call store.update(state => { - state.pages[pageName]._screens = screens - state.screens = screens + state.pages[pageName]._screens = currentPageScreens + state.screens = currentPageScreens state.currentPreviewItem = screen const safeProps = makePropsSafe( state.components[screen.props._component], @@ -481,6 +481,59 @@ export const getFrontendStore = () => { return path }, + links: { + save: async (url, title) => { + let savePromise + store.update(state => { + // Try to extract a nav component from the master screen + const nav = findChildComponentType( + state.pages.main, + "@budibase/standard-components/Navigation" + ) + if (nav) { + let newLink + + // Clone an existing link if one exists + if (nav._children && nav._children.length) { + // Clone existing link style + newLink = cloneDeep(nav._children[0]) + + // Manipulate IDs to ensure uniqueness + generateNewIdsForComponent(newLink, state, false) + + // Set our new props + newLink._instanceName = `${title} Link` + newLink.url = url + newLink.text = title + } else { + // Otherwise create vanilla new link + const component = getComponentDefinition( + state, + "@budibase/standard-components/link" + ) + const instanceId = get(backendUiStore).selectedDatabase._id + newLink = createProps(component, { + url, + text: title, + _instanceName: `${title} Link`, + _instanceId: instanceId, + }).props + } + + // Save page and regenerate all CSS because otherwise weird things happen + nav._children = [...nav._children, newLink] + state.currentPageName = "main" + store.actions.screens.regenerateCss(state.pages.main) + for (let screen of state.pages.main._screens) { + store.actions.screens.regenerateCss(screen) + } + savePromise = store.actions.pages.save() + } + return state + }) + await savePromise + }, + }, }, } diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 638e0788dc..ee5f1b4b73 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -391,7 +391,7 @@ const setComponentProp = store => (name, value) => { current_component[name] = value state.currentComponentInfo = current_component - _saveCurrentPreviewItem(state) + //_saveCurrentPreviewItem(state) return state }) } @@ -403,7 +403,7 @@ const setPageOrScreenProp = store => (name, value) => { } else { state.currentPreviewItem[name] = value } - _saveCurrentPreviewItem(state) + //_saveCurrentPreviewItem(state) return state }) } @@ -418,7 +418,7 @@ const setComponentStyle = store => (type, name, value) => { regenerateCssForCurrentScreen(state) // save without messing with the store - _saveCurrentPreviewItem(state) + //_saveCurrentPreviewItem(state) return state }) } @@ -511,7 +511,7 @@ const pasteComponent = store => (targetComponent, mode) => { const index = mode === "above" ? targetIndex : targetIndex + 1 parent._children.splice(index, 0, cloneDeep(componentToPaste)) regenerateCssForCurrentScreen(s) - _saveCurrentPreviewItem(s) + //_saveCurrentPreviewItem(s) selectComponent(s, componentToPaste) return s diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 3c85e611dd..6b98ac8dc3 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -31,10 +31,10 @@ export const getParent = (rootProps, child) => { return parent } -export const saveCurrentPreviewItem = s => - s.currentFrontEndType === "page" - ? savePage(s) - : store.saveScreen(s.currentPreviewItem) +// export const saveCurrentPreviewItem = s => +// s.currentFrontEndType === "page" +// ? savePage(s) +// : store.actions.screens.save(s.currentPreviewItem) export const savePage = async state => { const pageName = state.currentPageName || "main" @@ -92,10 +92,10 @@ export const regenerateCssForCurrentScreen = state => { return state } -export const generateNewIdsForComponent = (c, state, changeName = true) => - walkProps(c, p => { - p._id = uuid() - if (changeName) p._instanceName = getNewComponentName(p._component, state) +export const generateNewIdsForComponent = (component, state, changeName = true) => + walkProps(component, prop => { + prop._id = uuid() + if (changeName) prop._instanceName = getNewComponentName(prop, state) }) export const getComponentDefinition = (state, name) => diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte index 146f881b2b..0fe19f9bc0 100644 --- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte +++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte @@ -55,7 +55,7 @@ // Record the table that created this screen so we can link it later screen.autoTableId = table._id try { - await store.createScreen(screen) + await store.actions.screens.create(screen) } catch (_) { // TODO: this is temporary // a cypress test is failing, because I added the @@ -70,7 +70,7 @@ const listPage = screens.find(screen => screen.props._instanceName.endsWith("List") ) - await store.createLink(listPage.route, table.name) + await store.actions.components.links.save(listPage.route, table.name) // Navigate to new table $goto(`./table/${table._id}`) diff --git a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte index 87df51cd16..8d119e8ec3 100644 --- a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte @@ -4,7 +4,7 @@ import { getComponentDefinition } from "builderStore/storeUtils" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import { last } from "lodash/fp" - import { getParent, saveCurrentPreviewItem } from "builderStore/storeUtils" + import { getParent } from "builderStore/storeUtils" import { DropdownMenu } from "@budibase/bbui" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" @@ -31,44 +31,44 @@ } const moveUpComponent = () => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) + store.update(state => { + const parent = getParent(state.currentPreviewItem.props, component) if (parent) { const currentIndex = parent._children.indexOf(component) - if (currentIndex === 0) return s + if (currentIndex === 0) return state const newChildren = parent._children.filter(c => c !== component) newChildren.splice(currentIndex - 1, 0, component) parent._children = newChildren } - s.currentComponentInfo = component - saveCurrentPreviewItem(s) + state.currentComponentInfo = component + store.actions.preview.saveSelected() - return s + return state }) } const moveDownComponent = () => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) + store.update(state => { + const parent = getParent(state.currentPreviewItem.props, component) if (parent) { const currentIndex = parent._children.indexOf(component) - if (currentIndex === parent._children.length - 1) return s + if (currentIndex === parent._children.length - 1) return state const newChildren = parent._children.filter(c => c !== component) newChildren.splice(currentIndex + 1, 0, component) parent._children = newChildren } - s.currentComponentInfo = component - saveCurrentPreviewItem(s) + state.currentComponentInfo = component + store.actions.preview.saveSelected() - return s + return state }) } - const copyComponent = () => { + const duplicateComponent = () => { storeComponentForCopy(false) pasteComponent("below") } @@ -82,7 +82,7 @@ selectComponent(parent) } - saveCurrentPreviewItem(state) + store.actions.preview.saveSelected() return state }) } @@ -119,7 +119,7 @@ + on:click={duplicateComponent} /> { + if (name === "_instanceName" && state.currentFrontEndType === "screen") { + state.currentPreviewItem.props[name] = value + } else { + state.currentPreviewItem[name] = value + } + store.actions.preview.saveSelected() + return state + }) + } + function getProps(obj, keys) { return keys.map((key, i) => [key, obj[key], obj.props._id + i]) } @@ -82,7 +94,7 @@ {panelDefinition} displayNameField={displayName} onChange={store.actions.components.updateProp} - onScreenPropChange={store.setPageOrScreenProp} + onScreenPropChange={setPageOrScreenProp} screenOrPageInstance={$store.currentView !== 'component' && $store.currentPreviewItem} /> {/if} diff --git a/packages/builder/src/components/userInterface/NewScreenModal.svelte b/packages/builder/src/components/userInterface/NewScreenModal.svelte index 7d6677ce17..73313773e9 100644 --- a/packages/builder/src/components/userInterface/NewScreenModal.svelte +++ b/packages/builder/src/components/userInterface/NewScreenModal.svelte @@ -71,9 +71,9 @@ draftScreen.props._component = baseComponent draftScreen.route = route - await store.createScreen(draftScreen) + await store.actions.screens.create(draftScreen) if (createLink) { - await store.createLink(route, name) + await store.actions.components.links.save(route, name) } if (templateIndex !== undefined) { diff --git a/packages/builder/src/components/userInterface/PagesList.svelte b/packages/builder/src/components/userInterface/PagesList.svelte index 477b390149..fa22ccfa1b 100644 --- a/packages/builder/src/components/userInterface/PagesList.svelte +++ b/packages/builder/src/components/userInterface/PagesList.svelte @@ -18,7 +18,6 @@ }, ] - console.log(store) if (!$store.currentPageName) store.actions.pages.select($params.page ? $params.page : "main") diff --git a/packages/server/src/api/controllers/deploy/aws.js b/packages/server/src/api/controllers/deploy/aws.js index 3e19812a00..e6cd514cac 100644 --- a/packages/server/src/api/controllers/deploy/aws.js +++ b/packages/server/src/api/controllers/deploy/aws.js @@ -42,6 +42,13 @@ exports.isInvalidationComplete = async function( return resp.Invalidation.Status === "Completed" } +/** + * Finalises the deployment, updating the quota for the user API key + * The verification process returns the levels to update to. + * Calls the "deployment-success" lambda. + * @param {object} quota The usage quota levels returned from the verifyDeploy + * @returns {Promise} The usage has been updated against the user API key. + */ exports.updateDeploymentQuota = async function(quota) { const DEPLOYMENT_SUCCESS_URL = env.DEPLOYMENT_CREDENTIALS_URL + "deploy/success" @@ -67,7 +74,8 @@ exports.updateDeploymentQuota = async function(quota) { /** * Verifies the users API key and - * Verifies that the deployment fits within the quota of the user, + * Verifies that the deployment fits within the quota of the user + * Links to the "check-api-key" lambda. * @param {String} appId - appId being deployed * @param {String} appId - appId being deployed * @param {quota} quota - current quota being changed with this application