diff --git a/packages/bbui/src/Modal/ModalContent.svelte b/packages/bbui/src/Modal/ModalContent.svelte index 678a813a61..09cc4f6c52 100644 --- a/packages/bbui/src/Modal/ModalContent.svelte +++ b/packages/bbui/src/Modal/ModalContent.svelte @@ -14,6 +14,7 @@ export let showConfirmButton = true export let showCloseIcon = true export let onConfirm = undefined + export let onCancel = undefined export let disabled = false export let showDivider = true @@ -28,6 +29,14 @@ } loading = false } + + async function close() { + loading = true + if (!onCancel || (await onCancel()) !== false) { + cancel() + } + loading = false + }
{#if showCancelButton} - + {/if} {#if showConfirmButton} +
{:else if schema[configKey].type === "boolean"}
@@ -42,4 +50,11 @@ grid-gap: var(--spacing-l); align-items: center; } + + .form-row.ssl { + display: grid; + grid-template-columns: 20% 20%; + grid-gap: var(--spacing-l); + align-items: center; + } diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte index e7affb30c4..0a04d8dc73 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte @@ -1,74 +1,160 @@ - - + + - - - - - + + + + + + + { + chooseNextModal() + }} + > + + All apps need data. You can connect to a data source below, or add data + to your app using Budibase's built-in database. + +
selectIntegration(INTERNAL)} + class="item hoverable" + > +
+ + Budibase DB +
+
+
+ + +
+ Connect to data source +
+
+ {#each Object.entries(integrations).filter(([key]) => key !== INTERNAL) as [integrationType, schema]} +
selectIntegration(integrationType)} + class="item hoverable" + > +
+ + + + {schema.name || IntegrationNames[integrationType]} +
+
+ {/each} +
+
+
+
+ + diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte new file mode 100644 index 0000000000..56fa26ee0a --- /dev/null +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte @@ -0,0 +1,72 @@ + + + saveDatasource()} + confirmText={integration.plus + ? "Fetch tables from database" + : "Save and continue to query"} + cancelText="Back" + size="M" +> + + Connect your database to Budibase using the config below. + + + + + + + diff --git a/packages/builder/src/components/integration/KeyValueBuilder.svelte b/packages/builder/src/components/integration/KeyValueBuilder.svelte index 83977fa2a8..04ab56103e 100644 --- a/packages/builder/src/components/integration/KeyValueBuilder.svelte +++ b/packages/builder/src/components/integration/KeyValueBuilder.svelte @@ -4,6 +4,7 @@ export let defaults export let object = defaults || {} export let readOnly + export let noAddButton let fields = Object.entries(object).map(([name, value]) => ({ name, value })) @@ -12,7 +13,7 @@ {} ) - function addEntry() { + export function addEntry() { fields = [...fields, {}] } @@ -32,7 +33,7 @@ {/if} {/each}
-{#if !readOnly} +{#if !readOnly && !noAddButton}
diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js index a892eb2129..c0d283b0ea 100644 --- a/packages/builder/src/constants/index.js +++ b/packages/builder/src/constants/index.js @@ -15,6 +15,20 @@ export const AppStatus = { DEPLOYED: "published", } +export const IntegrationNames = { + POSTGRES: "PostgreSQL", + MONGODB: "MongoDB", + COUCHDB: "CouchDB", + S3: "S3", + MYSQL: "MySQL", + REST: "REST", + DYNAMODB: "DynamoDB", + ELASTICSEARCH: "ElasticSearch", + SQL_SERVER: "SQL Server", + AIRTABLE: "Airtable", + ARANGODB: "ArangoDB", +} + // fields on the user table that cannot be edited export const UNEDITABLE_USER_FIELDS = [ "email", diff --git a/packages/builder/src/pages/builder/app/[application]/data/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/data/_layout.svelte index 5202bd45f2..f321a2c422 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/_layout.svelte @@ -1,12 +1,14 @@ + diff --git a/packages/builder/src/stores/backend/datasources.js b/packages/builder/src/stores/backend/datasources.js index 5e42315948..7c74074e03 100644 --- a/packages/builder/src/stores/backend/datasources.js +++ b/packages/builder/src/stores/backend/datasources.js @@ -67,7 +67,7 @@ export function createDatasourcesStore() { }) return json }, - save: async datasource => { + save: async (datasource, fetchSchema = false) => { let response if (datasource._id) { response = await api.put( @@ -75,7 +75,10 @@ export function createDatasourcesStore() { datasource ) } else { - response = await api.post("/api/datasources", datasource) + response = await api.post("/api/datasources", { + datasource: datasource, + fetchSchema, + }) } const json = await response.json() diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index 4a2fd7d86a..2ff7c7f9b8 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -41,15 +41,10 @@ exports.fetch = async function (ctx) { exports.buildSchemaFromDb = async function (ctx) { const db = new CouchDB(ctx.appId) - const datasourceId = ctx.params.datasourceId - const datasource = await db.get(datasourceId) + const datasource = await db.get(ctx.params.datasourceId) - const Connector = integrations[datasource.source] - - // Connect to the DB and build the schema - const connector = new Connector(datasource.config) - await connector.buildSchema(datasource._id, datasource.entities) - datasource.entities = connector.tables + const tables = await buildSchemaHelper(datasource) + datasource.entities = tables const response = await db.put(datasource) datasource._rev = response.rev @@ -81,12 +76,18 @@ exports.update = async function (ctx) { exports.save = async function (ctx) { const db = new CouchDB(ctx.appId) - const plus = ctx.request.body.plus + const plus = ctx.request.body.datasource.plus + const fetchSchema = ctx.request.body.fetchSchema const datasource = { _id: generateDatasourceID({ plus }), type: plus ? DocumentTypes.DATASOURCE_PLUS : DocumentTypes.DATASOURCE, - ...ctx.request.body, + ...ctx.request.body.datasource, + } + + if (fetchSchema) { + let tables = await buildSchemaHelper(datasource) + datasource.entities = tables } const response = await db.put(datasource) @@ -133,3 +134,14 @@ exports.query = async function (ctx) { ctx.throw(400, err) } } + +const buildSchemaHelper = async datasource => { + const Connector = integrations[datasource.source] + + // Connect to the DB and build the schema + const connector = new Connector(datasource.config) + await connector.buildSchema(datasource._id, datasource.entities) + datasource.entities = connector.tables + + return connector.tables +} diff --git a/packages/server/src/api/routes/tests/query.spec.js b/packages/server/src/api/routes/tests/query.spec.js index eadd475ed4..716817509b 100644 --- a/packages/server/src/api/routes/tests/query.spec.js +++ b/packages/server/src/api/routes/tests/query.spec.js @@ -1,6 +1,7 @@ // mock out postgres for this jest.mock("pg") +const { findLastKey } = require("lodash/fp") const setup = require("./utilities") const { checkBuilderEndpoint } = require("./utilities/TestFunctions") const { basicQuery, basicDatasource } = setup.structures @@ -19,10 +20,10 @@ describe("/queries", () => { }) async function createInvalidIntegration() { - const datasource = await config.createDatasource({ - ...basicDatasource(), + const datasource = await config.createDatasource({datasource: { + ...basicDatasource().datasource, source: "INVALID_INTEGRATION", - }) + }}) const query = await config.createQuery() return { datasource, query } } @@ -183,11 +184,14 @@ describe("/queries", () => { }) it("should fail with invalid integration type", async () => { - const { query } = await createInvalidIntegration() + const { query, datasource } = await createInvalidIntegration() await request .post(`/api/queries/${query._id}`) .send({ + datasourceId: datasource._id, parameters: {}, + fields: {}, + queryVerb: "read", }) .set(config.defaultHeaders()) .expect(400) diff --git a/packages/server/src/tests/utilities/structures.js b/packages/server/src/tests/utilities/structures.js index e4b2c7e1f0..9c900fec09 100644 --- a/packages/server/src/tests/utilities/structures.js +++ b/packages/server/src/tests/utilities/structures.js @@ -70,10 +70,12 @@ exports.basicRole = () => { exports.basicDatasource = () => { return { - type: "datasource", - name: "Test", - source: "POSTGRES", - config: {}, + datasource: { + type: "datasource", + name: "Test", + source: "POSTGRES", + config: {}, + }, } }