auto app creation from template E2E, added warning to automations that they can't run in dev
This commit is contained in:
parent
5f40c6e234
commit
5abb36b1ed
|
@ -3,7 +3,14 @@
|
||||||
import { database } from "stores/backend"
|
import { database } from "stores/backend"
|
||||||
import { automationStore } from "builderStore"
|
import { automationStore } from "builderStore"
|
||||||
import { notifications } from "@budibase/bbui"
|
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"
|
import analytics, { Events } from "analytics"
|
||||||
|
|
||||||
let name
|
let name
|
||||||
|
@ -56,6 +63,10 @@
|
||||||
onConfirm={createAutomation}
|
onConfirm={createAutomation}
|
||||||
disabled={!selectedTrigger || !name}
|
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"
|
<Body size="XS"
|
||||||
>Please name your automation, then select a trigger. Every automation must
|
>Please name your automation, then select a trigger. Every automation must
|
||||||
start with a trigger.
|
start with a trigger.
|
||||||
|
|
|
@ -83,12 +83,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createNewApp() {
|
async function createNewApp() {
|
||||||
const letTemplateToUse =
|
const templateToUse = Object.keys(template).length === 0 ? null : template
|
||||||
Object.keys(template).length === 0 ? null : template
|
|
||||||
submitting = true
|
submitting = true
|
||||||
|
|
||||||
// Check a template exists if we are important
|
// 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"
|
$errors.file = "Please choose a file to import"
|
||||||
valid = false
|
valid = false
|
||||||
submitting = false
|
submitting = false
|
||||||
|
@ -99,10 +98,10 @@
|
||||||
// Create form data to create app
|
// Create form data to create app
|
||||||
let data = new FormData()
|
let data = new FormData()
|
||||||
data.append("name", $values.name.trim())
|
data.append("name", $values.name.trim())
|
||||||
data.append("useTemplate", letTemplateToUse != null)
|
data.append("useTemplate", templateToUse != null)
|
||||||
if (letTemplateToUse) {
|
if (templateToUse) {
|
||||||
data.append("templateName", letTemplateToUse.name)
|
data.append("templateName", templateToUse.name)
|
||||||
data.append("templateKey", letTemplateToUse.key)
|
data.append("templateKey", templateToUse.key)
|
||||||
data.append("templateFile", $values.file)
|
data.append("templateFile", $values.file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +115,7 @@
|
||||||
analytics.captureEvent(Events.APP.CREATED, {
|
analytics.captureEvent(Events.APP.CREATED, {
|
||||||
name: $values.name,
|
name: $values.name,
|
||||||
appId: appJson.instance._id,
|
appId: appJson.instance._id,
|
||||||
letTemplateToUse,
|
templateToUse,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Select Correct Application/DB in prep for creating user
|
// Select Correct Application/DB in prep for creating user
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
notifications,
|
notifications,
|
||||||
Search,
|
Search,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||||
import UpdateAppModal from "components/start/UpdateAppModal.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 { onMount } from "svelte"
|
||||||
import { apps, auth, admin } from "stores/portal"
|
import { apps, auth, admin } from "stores/portal"
|
||||||
import download from "downloadjs"
|
import download from "downloadjs"
|
||||||
|
@ -24,6 +26,7 @@
|
||||||
import AppCard from "components/start/AppCard.svelte"
|
import AppCard from "components/start/AppCard.svelte"
|
||||||
import AppRow from "components/start/AppRow.svelte"
|
import AppRow from "components/start/AppRow.svelte"
|
||||||
import { AppStatus } from "constants"
|
import { AppStatus } from "constants"
|
||||||
|
import analytics, { Events } from "analytics"
|
||||||
|
|
||||||
let layout = "grid"
|
let layout = "grid"
|
||||||
let sortBy = "name"
|
let sortBy = "name"
|
||||||
|
@ -38,6 +41,7 @@
|
||||||
let searchTerm = ""
|
let searchTerm = ""
|
||||||
let cloud = $admin.cloud
|
let cloud = $admin.cloud
|
||||||
let appName = ""
|
let appName = ""
|
||||||
|
let creatingFromTemplate = false
|
||||||
|
|
||||||
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
||||||
$: filteredApps = enrichedApps.filter(app =>
|
$: filteredApps = enrichedApps.filter(app =>
|
||||||
|
@ -92,6 +96,59 @@
|
||||||
creatingApp = true
|
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 = () => {
|
const stopAppCreation = () => {
|
||||||
template = null
|
template = null
|
||||||
creatingApp = false
|
creatingApp = false
|
||||||
|
@ -194,7 +251,7 @@
|
||||||
template = {
|
template = {
|
||||||
key: templateKey,
|
key: templateKey,
|
||||||
}
|
}
|
||||||
initiateAppCreation()
|
autoCreateApp()
|
||||||
} else {
|
} else {
|
||||||
notifications.error("Your Template URL is invalid. Please try another.")
|
notifications.error("Your Template URL is invalid. Please try another.")
|
||||||
}
|
}
|
||||||
|
@ -202,12 +259,14 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await apps.load()
|
await apps.load()
|
||||||
loaded = true
|
|
||||||
// if the portal is loaded from an external URL with a template param
|
// if the portal is loaded from an external URL with a template param
|
||||||
const initInfo = await auth.getInitInfo()
|
const initInfo = await auth.getInitInfo()
|
||||||
if (initInfo.init_template) {
|
if (initInfo.init_template) {
|
||||||
|
creatingFromTemplate = true
|
||||||
createAppFromTemplateUrl(initInfo.init_template)
|
createAppFromTemplateUrl(initInfo.init_template)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
loaded = true
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -285,6 +344,12 @@
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if creatingFromTemplate}
|
||||||
|
<div class="empty-wrapper">
|
||||||
|
<p>Creating your Budibase app from your selected template...</p>
|
||||||
|
<Spinner size="10" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</Page>
|
</Page>
|
||||||
<Modal
|
<Modal
|
||||||
bind:this={creationModal}
|
bind:this={creationModal}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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()
|
|
@ -40,7 +40,7 @@ const INTEGRATIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// optionally add oracle integration if the oracle binary can be installed
|
// 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")
|
const oracle = require("./oracle")
|
||||||
DEFINITIONS[SourceNames.ORACLE] = oracle.schema
|
DEFINITIONS[SourceNames.ORACLE] = oracle.schema
|
||||||
INTEGRATIONS[SourceNames.ORACLE] = oracle.integration
|
INTEGRATIONS[SourceNames.ORACLE] = oracle.integration
|
||||||
|
|
|
@ -352,14 +352,23 @@ module OracleModule {
|
||||||
* Knex default returning behaviour does not work with oracle
|
* Knex default returning behaviour does not work with oracle
|
||||||
* Manually add the behaviour for the return column
|
* 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) {
|
if (bindings instanceof Array) {
|
||||||
bindings.push({ dir: oracledb.BIND_OUT })
|
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
|
let connection
|
||||||
try {
|
try {
|
||||||
connection = await this.getConnection()
|
connection = await this.getConnection()
|
||||||
|
@ -367,7 +376,10 @@ module OracleModule {
|
||||||
const options: ExecuteOptions = { autoCommit: true }
|
const options: ExecuteOptions = { autoCommit: true }
|
||||||
const bindings: BindParameters = query.bindings || []
|
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)
|
this.addReturning(query, bindings, returnColum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,8 +443,9 @@ module OracleModule {
|
||||||
async query(json: QueryJson) {
|
async query(json: QueryJson) {
|
||||||
const primaryKeys = json.meta!.table!.primary
|
const primaryKeys = json.meta!.table!.primary
|
||||||
const primaryKey = primaryKeys ? primaryKeys[0] : undefined
|
const primaryKey = primaryKeys ? primaryKeys[0] : undefined
|
||||||
const queryFn = (query: any, operation: string) => this.internalQuery(query, primaryKey, operation)
|
const queryFn = (query: any, operation: string) =>
|
||||||
const processFn = (response: any) => response.rows ? response.rows : []
|
this.internalQuery(query, primaryKey, operation)
|
||||||
|
const processFn = (response: any) => (response.rows ? response.rows : [])
|
||||||
const output = await this.queryWithReturning(json, queryFn, processFn)
|
const output = await this.queryWithReturning(json, queryFn, processFn)
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,11 @@ import { SqlQuery } from "../definitions/datasource"
|
||||||
import { Datasource, Table } from "../definitions/common"
|
import { Datasource, Table } from "../definitions/common"
|
||||||
import { SourceNames } from "../definitions/datasource"
|
import { SourceNames } from "../definitions/datasource"
|
||||||
const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
||||||
const { FieldTypes, BuildSchemaErrors, InvalidColumns } = require("../constants")
|
const {
|
||||||
|
FieldTypes,
|
||||||
|
BuildSchemaErrors,
|
||||||
|
InvalidColumns,
|
||||||
|
} = require("../constants")
|
||||||
|
|
||||||
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
||||||
const ROW_ID_REGEX = /^\[.*]$/g
|
const ROW_ID_REGEX = /^\[.*]$/g
|
||||||
|
@ -42,7 +46,7 @@ export enum SqlClients {
|
||||||
MS_SQL = "mssql",
|
MS_SQL = "mssql",
|
||||||
POSTGRES = "pg",
|
POSTGRES = "pg",
|
||||||
MY_SQL = "mysql",
|
MY_SQL = "mysql",
|
||||||
ORACLE = "oracledb"
|
ORACLE = "oracledb",
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isExternalTable(tableId: string) {
|
export function isExternalTable(tableId: string) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue