diff --git a/packages/builder/cypress/integration/createAutomation.spec.js b/packages/builder/cypress/integration/createAutomation.spec.js index afd405d5ab..6ff013cd7a 100644 --- a/packages/builder/cypress/integration/createAutomation.spec.js +++ b/packages/builder/cypress/integration/createAutomation.spec.js @@ -12,7 +12,7 @@ context("Create a automation", () => { cy.get("[data-cy='new-screen'] > .spectrum-Icon").click() cy.get(".modal-inner-wrapper").within(() => { cy.get("input").type("Add Row") - cy.contains("Row Created").click() + cy.contains("Row Created").click({ force: true }) cy.wait(500) cy.get(".spectrum-Button--cta").click() }) diff --git a/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte b/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte index cf3dc8f314..36723d7726 100644 --- a/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte @@ -3,7 +3,14 @@ import { database } from "stores/backend" import { automationStore } from "builderStore" import { notifications } from "@budibase/bbui" - import { Input, ModalContent, Layout, Body, Icon } from "@budibase/bbui" + import { + Input, + InlineAlert, + ModalContent, + Layout, + Body, + Icon, + } from "@budibase/bbui" import analytics, { Events } from "analytics" let name @@ -56,6 +63,10 @@ onConfirm={createAutomation} disabled={!selectedTrigger || !name} > + Please name your automation, then select a trigger. Every automation must start with a trigger. diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte index 54e455b92f..550da98d6b 100644 --- a/packages/builder/src/components/integration/QueryViewer.svelte +++ b/packages/builder/src/components/integration/QueryViewer.svelte @@ -32,31 +32,22 @@ import { onMount } from "svelte" export let query - export let fields = [] + let fields = query.schema ? schemaToFields(query.schema) : [] let parameters let data = [] let roleId const transformerDocs = "https://docs.budibase.com/building-apps/data/transformers" const typeOptions = [ - { label: "Text", value: "STRING" }, - { label: "Number", value: "NUMBER" }, - { label: "Boolean", value: "BOOLEAN" }, - { label: "Datetime", value: "DATETIME" }, + { label: "Text", value: "string" }, + { label: "Number", value: "number" }, + { label: "Boolean", value: "boolean" }, + { label: "Datetime", value: "datetime" }, ] $: datasource = $datasources.list.find(ds => ds._id === query.datasourceId) - $: query.schema = fields.reduce( - (acc, next) => ({ - ...acc, - [next.name]: { - name: next.name, - type: "string", - }, - }), - {} - ) + $: query.schema = fieldsToSchema(fields) $: datasourceType = datasource?.source $: integrationInfo = $integrations[datasourceType] $: queryConfig = integrationInfo?.query @@ -135,7 +126,7 @@ // unique fields returned by the server fields = json.schemaFields.map(field => ({ name: field, - type: "STRING", + type: "string", })) } catch (err) { notifications.error(`Query Error: ${err.message}`) @@ -155,6 +146,26 @@ } } + function schemaToFields(schema) { + return Object.keys(schema).map(key => ({ + name: key, + type: query.schema[key].type, + })) + } + + function fieldsToSchema(fieldsToConvert) { + return fieldsToConvert.reduce( + (acc, next) => ({ + ...acc, + [next.name]: { + name: next.name, + type: next.type, + }, + }), + {} + ) + } + onMount(async () => { if (!query || !query._id) { roleId = Roles.BASIC diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 68845e075b..75df17e532 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -83,12 +83,11 @@ } async function createNewApp() { - const letTemplateToUse = - Object.keys(template).length === 0 ? null : template + const templateToUse = Object.keys(template).length === 0 ? null : template submitting = true // Check a template exists if we are important - if (letTemplateToUse?.fromFile && !$values.file) { + if (templateToUse?.fromFile && !$values.file) { $errors.file = "Please choose a file to import" valid = false submitting = false @@ -99,10 +98,10 @@ // Create form data to create app let data = new FormData() data.append("name", $values.name.trim()) - data.append("useTemplate", letTemplateToUse != null) - if (letTemplateToUse) { - data.append("templateName", letTemplateToUse.name) - data.append("templateKey", letTemplateToUse.key) + data.append("useTemplate", templateToUse != null) + if (templateToUse) { + data.append("templateName", templateToUse.name) + data.append("templateKey", templateToUse.key) data.append("templateFile", $values.file) } @@ -116,7 +115,7 @@ analytics.captureEvent(Events.APP.CREATED, { name: $values.name, appId: appJson.instance._id, - letTemplateToUse, + templateToUse, }) // Select Correct Application/DB in prep for creating user diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index da0d977a42..15076a9a53 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -13,9 +13,11 @@ notifications, Search, } from "@budibase/bbui" + import Spinner from "components/common/Spinner.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte" import UpdateAppModal from "components/start/UpdateAppModal.svelte" - import { del } from "builderStore/api" + import { store, automationStore } from "builderStore" + import api, { del, post, get } from "builderStore/api" import { onMount } from "svelte" import { apps, auth, admin } from "stores/portal" import download from "downloadjs" @@ -24,6 +26,7 @@ import AppCard from "components/start/AppCard.svelte" import AppRow from "components/start/AppRow.svelte" import { AppStatus } from "constants" + import analytics, { Events } from "analytics" let layout = "grid" let sortBy = "name" @@ -38,6 +41,7 @@ let searchTerm = "" let cloud = $admin.cloud let appName = "" + let creatingFromTemplate = false $: enrichedApps = enrichApps($apps, $auth.user, sortBy) $: filteredApps = enrichedApps.filter(app => @@ -92,6 +96,62 @@ creatingApp = true } + const autoCreateApp = async () => { + try { + // Auto name app if has same name + let appName = template.key + const appsWithSameName = $apps.filter(app => + app.name?.startsWith(appName) + ) + appName = `${appName}-${appsWithSameName.length + 1}` + + // Create form data to create app + let data = new FormData() + data.append("name", appName) + data.append("useTemplate", true) + data.append("templateKey", template.key) + + // Create App + const appResp = await post("/api/applications", data, {}) + const appJson = await appResp.json() + if (!appResp.ok) { + throw new Error(appJson.message) + } + + analytics.captureEvent(Events.APP.CREATED, { + name: appName, + appId: appJson.instance._id, + template, + fromTemplateMarketplace: true, + }) + + // Select Correct Application/DB in prep for creating user + const applicationPkg = await get( + `/api/applications/${appJson.instance._id}/appPackage` + ) + const pkg = await applicationPkg.json() + if (applicationPkg.ok) { + await store.actions.initialise(pkg) + await automationStore.actions.fetch() + // update checklist - incase first app + await admin.init() + } else { + throw new Error(pkg) + } + + // Create user + const userResp = await api.post(`/api/users/metadata/self`, { + roleId: "BASIC", + }) + await userResp.json() + await auth.setInitInfo({}) + $goto(`/builder/app/${appJson.instance._id}`) + } catch (error) { + console.error(error) + notifications.error(error) + } + } + const stopAppCreation = () => { template = null creatingApp = false @@ -194,7 +254,7 @@ template = { key: templateKey, } - initiateAppCreation() + autoCreateApp() } else { notifications.error("Your Template URL is invalid. Please try another.") } @@ -202,12 +262,14 @@ onMount(async () => { await apps.load() - loaded = true // if the portal is loaded from an external URL with a template param const initInfo = await auth.getInitInfo() if (initInfo.init_template) { + creatingFromTemplate = true createAppFromTemplateUrl(initInfo.init_template) + return } + loaded = true }) @@ -285,6 +347,12 @@ {/if} + {#if creatingFromTemplate} +
+

Creating your Budibase app from your selected template...

+ +
+ {/if} =2.3.x" - -svg.filter.js@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/svg.filter.js/-/svg.filter.js-2.0.2.tgz#91008e151389dd9230779fcbe6e2c9a362d1c203" - integrity sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM= - dependencies: - svg.js "^2.2.5" - -svg.js@>=2.3.x, svg.js@^2.0.1, svg.js@^2.2.5, svg.js@^2.4.0, svg.js@^2.6.5: - version "2.7.1" - resolved "https://registry.yarnpkg.com/svg.js/-/svg.js-2.7.1.tgz#eb977ed4737001eab859949b4a398ee1bb79948d" - integrity sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA== - -svg.pathmorphing.js@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz#c25718a1cc7c36e852ecabc380e758ac09bb2b65" - integrity sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww== - dependencies: - svg.js "^2.4.0" - -svg.resize.js@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/svg.resize.js/-/svg.resize.js-1.4.3.tgz#885abd248e0cd205b36b973c4b578b9a36f23332" - integrity sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw== - dependencies: - svg.js "^2.6.5" - svg.select.js "^2.1.2" - -svg.select.js@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-2.1.2.tgz#e41ce13b1acff43a7441f9f8be87a2319c87be73" - integrity sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ== - dependencies: - svg.js "^2.2.5" - -svg.select.js@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-3.0.1.tgz#a4198e359f3825739226415f82176a90ea5cc917" - integrity sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw== - dependencies: - svg.js "^2.6.5" - symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -6474,14 +5748,6 @@ throttleit@^1.0.0: resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - through@2, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -6504,11 +5770,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= -to-gfm-code-block@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" - integrity sha1-JdBFpfrlUxielje1kJANpzLYqoI= - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -6636,18 +5897,6 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typeof-article@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" - integrity sha1-nwfnM8P7tkb/qeYcCN66zUYOBq8= - dependencies: - kind-of "^3.1.0" - -uglify-js@^3.1.4: - version "3.14.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.3.tgz#c0f25dfea1e8e5323eccf59610be08b6043c15cf" - integrity sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g== - unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -6789,11 +6038,6 @@ vite@^2.1.5: optionalDependencies: fsevents "~2.3.2" -vm2@^3.9.4: - version "3.9.5" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496" - integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng== - w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -6894,11 +6138,6 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -6946,11 +6185,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" @@ -6994,11 +6228,6 @@ yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -year@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" - integrity sha1-QIOuUgoxiyPshgN/MADLiSvfm7A= - yup@0.29.2: version "0.29.2" resolved "https://registry.yarnpkg.com/yup/-/yup-0.29.2.tgz#5302abd9024cca335b987793f8df868e410b7b67"