diff --git a/lerna.json b/lerna.json index b3e7fe4677..3fd23f5743 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.2.2", + "version": "0.2.4", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index e61f1b38e9..ece9565e18 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -155,9 +155,13 @@ Cypress.Commands.add("navigateToFrontend", () => { Cypress.Commands.add("createScreen", (screenName, route) => { cy.contains("Create New Screen").click() cy.get(".modal").within(() => { - cy.get("input:first").type(screenName) + cy.get("input") + .eq(0) + .type(screenName) if (route) { - cy.get("input:last").type(route) + cy.get("input") + .eq(1) + .type(route) } cy.contains("Create Screen").click() }) diff --git a/packages/builder/package.json b/packages/builder/package.json index d9a4f56ef3..089043a375 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.2.2", + "version": "0.2.4", "license": "AGPL-3.0", "private": true, "scripts": { @@ -64,7 +64,7 @@ }, "dependencies": { "@budibase/bbui": "^1.44.0", - "@budibase/client": "^0.2.2", + "@budibase/client": "^0.2.4", "@budibase/colorpicker": "^1.0.1", "@fortawesome/fontawesome-free": "^5.14.0", "@sentry/browser": "5.19.1", diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 311d7a63a3..01ab3db45a 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -27,7 +27,9 @@ import { regenerateCssForScreen, generateNewIdsForComponent, getComponentDefinition, + findChildComponentType, } from "../storeUtils" + export const getStore = () => { const initial = { apps: [], @@ -56,6 +58,7 @@ export const getStore = () => { store.setCurrentScreen = setCurrentScreen(store) store.deleteScreens = deleteScreens(store) store.setCurrentPage = setCurrentPage(store) + store.createLink = createLink(store) store.createScreen = createScreen(store) store.addStylesheet = addStylesheet(store) store.removeStylesheet = removeStylesheet(store) @@ -190,6 +193,58 @@ const createScreen = store => async screen => { await savePromise } +const createLink = store => 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] + setCurrentPage("main") + regenerateCssForScreen(state.pages.main) + for (let screen of state.pages.main._screens) { + regenerateCssForScreen(screen) + } + savePromise = _savePage(state) + } + return state + }) + await savePromise +} + const setCurrentScreen = store => screenName => { store.update(s => { const screen = getExactComponent(s.screens, screenName, true) diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 6155974d2b..2c486a9bdb 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -38,7 +38,7 @@ export const saveCurrentPreviewItem = s => export const savePage = async s => { const pageName = s.currentPageName || "main" const page = s.pages[pageName] - await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, { + await api.post(`/_builder/api/${s.appId}/pages/${pageName}`, { page: { componentLibraries: s.pages.componentLibraries, ...page }, uiFunctions: s.currentPageFunctions, screens: page._screens, @@ -84,7 +84,9 @@ export const regenerateCssForScreen = screen => { } export const regenerateCssForCurrentScreen = state => { - regenerateCssForScreen(state.currentPreviewItem) + if (state.currentPreviewItem) { + regenerateCssForScreen(state.currentPreviewItem) + } return state } @@ -96,3 +98,33 @@ export const generateNewIdsForComponent = (c, state, changeName = true) => export const getComponentDefinition = (state, name) => name.startsWith("##") ? getBuiltin(name) : state.components[name] + +export const findChildComponentType = (node, typeToFind) => { + // Stop recursion if invalid props + if (!node || !typeToFind) { + return null + } + + // Stop recursion if this element matches + if (node._component === typeToFind) { + return node + } + + // Otherwise check if any children match + // Stop recursion if no valid children to process + const children = node._children || (node.props && node.props._children) + if (!children || !children.length) { + return null + } + + // Recurse and check each child component + for (let child of children) { + const childResult = findChildComponentType(child, typeToFind) + if (childResult) { + return childResult + } + } + + // If we reach here then no children were valid + return null +} diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte index a931dafb62..bba3342686 100644 --- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte +++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte @@ -38,21 +38,21 @@ } async function saveTable() { + // Create table const table = await backendUiStore.actions.tables.save({ name, schema: dataImport.schema || {}, dataImport, }) notifier.success(`Table ${name} created successfully.`) - $goto(`./table/${table._id}`) analytics.captureEvent("Table Created", { name }) + // Create auto screens const screens = screenTemplates($store, [table]) .filter(template => defaultScreens.includes(template.id)) .map(template => template.create()) - for (let screen of screens) { - // record the table that created this screen so we can link it later + // Record the table that created this screen so we can link it later screen.autoTableId = table._id try { await store.createScreen(screen) @@ -65,6 +65,15 @@ // we should remove this after this has been released } } + + // Create autolink to newly created list page + const listPage = screens.find(screen => + screen.props._instanceName.endsWith("List") + ) + await store.createLink(listPage.route, table.name) + + // Navigate to new table + $goto(`./table/${table._id}`) } diff --git a/packages/builder/src/components/deploy/DeploymentHistory.svelte b/packages/builder/src/components/deploy/DeploymentHistory.svelte new file mode 100644 index 0000000000..abfe6eefb4 --- /dev/null +++ b/packages/builder/src/components/deploy/DeploymentHistory.svelte @@ -0,0 +1,162 @@ + + +{#if deployments.length > 0} +
+
+

Deployment History

+ + View Your Deployed App → + +
+
+ {#each deployments as deployment} +
+
+ + {formatDate(deployment.updatedAt, 'fullDate')} + + + {formatDate(deployment.updatedAt, 'timeOnly')} + +
+
+ {deployment.status} +
+
+ {/each} +
+
+{/if} + + diff --git a/packages/builder/src/components/userInterface/NewScreenModal.svelte b/packages/builder/src/components/userInterface/NewScreenModal.svelte index 6d02439c1b..7d6677ce17 100644 --- a/packages/builder/src/components/userInterface/NewScreenModal.svelte +++ b/packages/builder/src/components/userInterface/NewScreenModal.svelte @@ -1,7 +1,14 @@