1
0
Fork 0
mirror of synced 2024-06-26 10:00:41 +12:00

auto app creation from template E2E, added warning to automations that they can't run in dev

This commit is contained in:
Martin McKeaveney 2021-11-25 10:29:09 +01:00
parent 5f40c6e234
commit 5abb36b1ed
9 changed files with 187 additions and 1573 deletions

View file

@ -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}
>
<InlineAlert
header="You must publish your app to activate your automations."
message="To test your automation before publishing, you can use the 'Run Test' functionality on the next screen."
/>
<Body size="XS"
>Please name your automation, then select a trigger. Every automation must
start with a trigger.

View file

@ -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

View file

@ -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,59 @@
creatingApp = true
}
const autoCreateApp = async () => {
try {
// TODO: Iterate App Names and append a number
const appName = template.key + Math.floor(Math.random() * 100)
console.log("APP NAME", appName)
// 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,
})
// 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 +251,7 @@
template = {
key: templateKey,
}
initiateAppCreation()
autoCreateApp()
} else {
notifications.error("Your Template URL is invalid. Please try another.")
}
@ -202,12 +259,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
})
</script>
@ -285,6 +344,12 @@
</Modal>
</div>
{/if}
{#if creatingFromTemplate}
<div class="empty-wrapper">
<p>Creating your Budibase app from your selected template...</p>
<Spinner size="10" />
</div>
{/if}
</Page>
<Modal
bind:this={creationModal}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,46 @@
#!/usr/bin/env node
const { Client } = require("pg")
let client
// Connect
async function connect() {
client = new Client({
host: "localhost",
port: 5432,
database: "test",
user: "postgres",
password: "root",
})
await client.connect()
}
async function insertData() {
const data = [{ id: 1 }, { id: 3 }]
let sql = ""
for (let item of data) {
sql += `INSERT INTO test(id) VALUES(${item.id}); \n`
}
console.log(sql)
await client.query(sql)
}
// Fills up a postgres database
async function run() {
await connect()
// Drops table
await client.query("DROP TABLE IF EXISTS test")
// Creates new table
await client.query(`CREATE TABLE "test" ("id" serial, PRIMARY KEY ("id"))`)
// Insert some data
await insertData()
const res = await client.query("SELECT * from test")
console.log(res.rows)
await client.end()
}
run()

View file

@ -40,9 +40,9 @@ const INTEGRATIONS = {
}
// optionally add oracle integration if the oracle binary can be installed
if (!(process.arch === 'arm64' && process.platform === 'darwin')) {
if (!(process.arch === "arm64" && process.platform === "darwin")) {
const oracle = require("./oracle")
DEFINITIONS[SourceNames.ORACLE] = oracle.schema
DEFINITIONS[SourceNames.ORACLE] = oracle.schema
INTEGRATIONS[SourceNames.ORACLE] = oracle.integration
}

View file

@ -352,14 +352,23 @@ module OracleModule {
* Knex default returning behaviour does not work with oracle
* Manually add the behaviour for the return column
*/
private addReturning(query: SqlQuery, bindings: BindParameters, returnColumn: string) {
private addReturning(
query: SqlQuery,
bindings: BindParameters,
returnColumn: string
) {
if (bindings instanceof Array) {
bindings.push({ dir: oracledb.BIND_OUT })
query.sql = query.sql + ` returning \"${returnColumn}\" into :${bindings.length}`
query.sql =
query.sql + ` returning \"${returnColumn}\" into :${bindings.length}`
}
}
private async internalQuery<T>(query: SqlQuery, returnColum?: string, operation?: string): Promise<Result<T>> {
private async internalQuery<T>(
query: SqlQuery,
returnColum?: string,
operation?: string
): Promise<Result<T>> {
let connection
try {
connection = await this.getConnection()
@ -367,7 +376,10 @@ module OracleModule {
const options: ExecuteOptions = { autoCommit: true }
const bindings: BindParameters = query.bindings || []
if (returnColum && (operation === Operation.CREATE || operation === Operation.UPDATE)) {
if (
returnColum &&
(operation === Operation.CREATE || operation === Operation.UPDATE)
) {
this.addReturning(query, bindings, returnColum)
}
@ -414,14 +426,14 @@ module OracleModule {
return response.rows ? response.rows : []
}
async update(query: SqlQuery | string): Promise<any[]> {
async update(query: SqlQuery | string): Promise<any[]> {
const response = await this.internalQuery(getSqlQuery(query))
return response.rows && response.rows.length
? response.rows
: [{ updated: true }]
}
async delete(query: SqlQuery | string): Promise<any[]> {
async delete(query: SqlQuery | string): Promise<any[]> {
const response = await this.internalQuery(getSqlQuery(query))
return response.rows && response.rows.length
? response.rows
@ -431,8 +443,9 @@ module OracleModule {
async query(json: QueryJson) {
const primaryKeys = json.meta!.table!.primary
const primaryKey = primaryKeys ? primaryKeys[0] : undefined
const queryFn = (query: any, operation: string) => this.internalQuery(query, primaryKey, operation)
const processFn = (response: any) => response.rows ? response.rows : []
const queryFn = (query: any, operation: string) =>
this.internalQuery(query, primaryKey, operation)
const processFn = (response: any) => (response.rows ? response.rows : [])
const output = await this.queryWithReturning(json, queryFn, processFn)
return output
}

View file

@ -2,7 +2,11 @@ import { SqlQuery } from "../definitions/datasource"
import { Datasource, Table } from "../definitions/common"
import { SourceNames } from "../definitions/datasource"
const { DocumentTypes, SEPARATOR } = require("../db/utils")
const { FieldTypes, BuildSchemaErrors, InvalidColumns } = require("../constants")
const {
FieldTypes,
BuildSchemaErrors,
InvalidColumns,
} = require("../constants")
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
const ROW_ID_REGEX = /^\[.*]$/g
@ -42,7 +46,7 @@ export enum SqlClients {
MS_SQL = "mssql",
POSTGRES = "pg",
MY_SQL = "mysql",
ORACLE = "oracledb"
ORACLE = "oracledb",
}
export function isExternalTable(tableId: string) {

File diff suppressed because it is too large Load diff