Merge branch 'master' into feat/url-binding-default
This commit is contained in:
commit
398de18103
|
@ -18,6 +18,7 @@
|
||||||
"eslint-plugin-jest": "28.9.0",
|
"eslint-plugin-jest": "28.9.0",
|
||||||
"eslint-plugin-local-rules": "3.0.2",
|
"eslint-plugin-local-rules": "3.0.2",
|
||||||
"eslint-plugin-svelte": "2.46.1",
|
"eslint-plugin-svelte": "2.46.1",
|
||||||
|
"svelte-preprocess": "^6.0.3",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"kill-port": "^1.6.1",
|
"kill-port": "^1.6.1",
|
||||||
"lerna": "7.4.2",
|
"lerna": "7.4.2",
|
||||||
|
|
|
@ -424,7 +424,7 @@ export async function retrieveDirectory(bucketName: string, path: string) {
|
||||||
stream.pipe(writeStream)
|
stream.pipe(writeStream)
|
||||||
writePromises.push(
|
writePromises.push(
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
stream.on("finish", resolve)
|
writeStream.on("finish", resolve)
|
||||||
stream.on("error", reject)
|
stream.on("error", reject)
|
||||||
writeStream.on("error", reject)
|
writeStream.on("error", reject)
|
||||||
})
|
})
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 52 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -1,4 +1,4 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
export let sideNav = false
|
export let sideNav = false
|
||||||
export let hideDevTools = false
|
export let hideDevTools = false
|
||||||
export let hideFooter = false
|
export let hideFooter = false
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { Layout } from "@budibase/bbui"
|
import { Layout } from "@budibase/bbui"
|
||||||
import Bulgaria from "../../assets/bulgaria.png"
|
import Bulgaria from "../../assets/bulgaria.png"
|
||||||
import Covanta from "../../assets/covanta.png"
|
import Reworld from "../../assets/reworld.png"
|
||||||
import Schnellecke from "../../assets/schnellecke.png"
|
import Schnellecke from "../../assets/schnellecke.png"
|
||||||
|
|
||||||
const testimonials = [
|
const testimonials = [
|
||||||
{
|
{
|
||||||
text: "Budibase was the only solution that checked all the boxes for Covanta. Covanta expects to realize $3.2MM in savings due to the elimination of redundant data entry.",
|
text: "Budibase was the only solution that checked all the boxes for Reworld. Reworld expects to realize $3.2MM in savings due to the elimination of redundant data entry.",
|
||||||
name: "Charles Link",
|
name: "Charles Link",
|
||||||
role: "Senior Director, Data and Analytics",
|
role: "Senior Director, Data and Analytics",
|
||||||
image: Covanta,
|
image: Reworld,
|
||||||
imageSize: 105,
|
imageSize: 105,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,20 @@ const baseConfig: Config.InitialProjectOptions = {
|
||||||
transform: {
|
transform: {
|
||||||
"^.+\\.ts?$": "@swc/jest",
|
"^.+\\.ts?$": "@swc/jest",
|
||||||
"^.+\\.js?$": "@swc/jest",
|
"^.+\\.js?$": "@swc/jest",
|
||||||
"^.+\\.svelte?$": "<rootDir>/scripts/svelteTransformer.js",
|
"^.+\\.svelte$": [
|
||||||
|
"jest-chain-transform", // https://github.com/svelteness/svelte-jester/issues/166
|
||||||
|
{
|
||||||
|
transformers: [
|
||||||
|
[
|
||||||
|
"svelte-jester",
|
||||||
|
{
|
||||||
|
preprocess: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@swc/jest",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: ["/node_modules/(?!svelte/).*"],
|
transformIgnorePatterns: ["/node_modules/(?!svelte/).*"],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
|
|
|
@ -139,6 +139,7 @@
|
||||||
"@babel/core": "^7.22.5",
|
"@babel/core": "^7.22.5",
|
||||||
"@babel/preset-env": "7.16.11",
|
"@babel/preset-env": "7.16.11",
|
||||||
"@jest/types": "^29.6.3",
|
"@jest/types": "^29.6.3",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "1.4.0",
|
||||||
"@swc/core": "1.3.71",
|
"@swc/core": "1.3.71",
|
||||||
"@swc/jest": "0.2.27",
|
"@swc/jest": "0.2.27",
|
||||||
"@types/archiver": "6.0.2",
|
"@types/archiver": "6.0.2",
|
||||||
|
@ -164,6 +165,7 @@
|
||||||
"docker-compose": "0.23.17",
|
"docker-compose": "0.23.17",
|
||||||
"ioredis-mock": "8.9.0",
|
"ioredis-mock": "8.9.0",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
|
"jest-chain-transform": "^0.0.8",
|
||||||
"jest-extended": "^4.0.2",
|
"jest-extended": "^4.0.2",
|
||||||
"jest-openapi": "0.14.2",
|
"jest-openapi": "0.14.2",
|
||||||
"nock": "13.5.4",
|
"nock": "13.5.4",
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
const { compile } = require("svelte/compiler")
|
|
||||||
const { transformSync } = require("@babel/core")
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
process(sourceText) {
|
|
||||||
const { js } = compile(sourceText, { css: "injected", generate: "ssr" })
|
|
||||||
const { code } = transformSync(js.code, { babelrc: true })
|
|
||||||
|
|
||||||
return { code: code }
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -25,6 +25,7 @@ import sdk from "../../../sdk"
|
||||||
import * as pro from "@budibase/pro"
|
import * as pro from "@budibase/pro"
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
|
BudibaseAppProps,
|
||||||
Ctx,
|
Ctx,
|
||||||
DocumentType,
|
DocumentType,
|
||||||
Feature,
|
Feature,
|
||||||
|
@ -191,9 +192,14 @@ export const serveApp = async function (ctx: UserCtx<void, ServeAppResponse>) {
|
||||||
const themeVariables = getThemeVariables(appInfo?.theme)
|
const themeVariables = getThemeVariables(appInfo?.theme)
|
||||||
|
|
||||||
if (!env.isJest()) {
|
if (!env.isJest()) {
|
||||||
const plugins = objectStore.enrichPluginURLs(appInfo.usedPlugins)
|
const plugins = await objectStore.enrichPluginURLs(appInfo.usedPlugins)
|
||||||
|
/*
|
||||||
const { head, html, css } = AppComponent.render({
|
* Server rendering in svelte sadly does not support type checking, the .render function
|
||||||
|
* always will just expect "any" when typing - so it is pointless for us to type the
|
||||||
|
* BudibaseApp.svelte file as we can never detect if the types are correct. To get around this
|
||||||
|
* I've created a type which expects what the app will expect to receive.
|
||||||
|
*/
|
||||||
|
const props: BudibaseAppProps = {
|
||||||
title: branding?.platformTitle || `${appInfo.name}`,
|
title: branding?.platformTitle || `${appInfo.name}`,
|
||||||
showSkeletonLoader: appInfo.features?.skeletonLoader ?? false,
|
showSkeletonLoader: appInfo.features?.skeletonLoader ?? false,
|
||||||
hideDevTools,
|
hideDevTools,
|
||||||
|
@ -205,21 +211,17 @@ export const serveApp = async function (ctx: UserCtx<void, ServeAppResponse>) {
|
||||||
metaDescription: branding?.metaDescription || "",
|
metaDescription: branding?.metaDescription || "",
|
||||||
metaTitle:
|
metaTitle:
|
||||||
branding?.metaTitle || `${appInfo.name} - built with Budibase`,
|
branding?.metaTitle || `${appInfo.name} - built with Budibase`,
|
||||||
production: env.isProd(),
|
|
||||||
appId,
|
|
||||||
clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version),
|
clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version),
|
||||||
usedPlugins: plugins,
|
usedPlugins: plugins,
|
||||||
favicon:
|
favicon:
|
||||||
branding.faviconUrl !== ""
|
branding.faviconUrl !== ""
|
||||||
? await objectStore.getGlobalFileUrl("settings", "faviconUrl")
|
? await objectStore.getGlobalFileUrl("settings", "faviconUrl")
|
||||||
: "",
|
: "",
|
||||||
logo:
|
|
||||||
config?.logoUrl !== ""
|
|
||||||
? await objectStore.getGlobalFileUrl("settings", "logoUrl")
|
|
||||||
: "",
|
|
||||||
appMigrating: needMigrations,
|
appMigrating: needMigrations,
|
||||||
nonce: ctx.state.nonce,
|
nonce: ctx.state.nonce,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const { head, html, css } = AppComponent.render({ props })
|
||||||
const appHbs = loadHandlebarsFile(appHbsPath)
|
const appHbs = loadHandlebarsFile(appHbsPath)
|
||||||
ctx.body = await processString(appHbs, {
|
ctx.body = await processString(appHbs, {
|
||||||
head,
|
head,
|
||||||
|
@ -235,9 +237,10 @@ export const serveApp = async function (ctx: UserCtx<void, ServeAppResponse>) {
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!env.isJest()) {
|
if (!env.isJest()) {
|
||||||
const { head, html, css } = AppComponent.render({
|
const props: BudibaseAppProps = {
|
||||||
title: branding?.metaTitle,
|
usedPlugins: [],
|
||||||
metaTitle: branding?.metaTitle,
|
title: branding?.metaTitle || "",
|
||||||
|
metaTitle: branding?.metaTitle || "",
|
||||||
metaImage:
|
metaImage:
|
||||||
branding?.metaImageUrl ||
|
branding?.metaImageUrl ||
|
||||||
"https://res.cloudinary.com/daog6scxm/image/upload/v1698759482/meta-images/plain-branded-meta-image-coral_ocxmgu.png",
|
"https://res.cloudinary.com/daog6scxm/image/upload/v1698759482/meta-images/plain-branded-meta-image-coral_ocxmgu.png",
|
||||||
|
@ -246,7 +249,8 @@ export const serveApp = async function (ctx: UserCtx<void, ServeAppResponse>) {
|
||||||
branding.faviconUrl !== ""
|
branding.faviconUrl !== ""
|
||||||
? await objectStore.getGlobalFileUrl("settings", "faviconUrl")
|
? await objectStore.getGlobalFileUrl("settings", "faviconUrl")
|
||||||
: "",
|
: "",
|
||||||
})
|
}
|
||||||
|
const { head, html, css } = AppComponent.render({ props })
|
||||||
|
|
||||||
const appHbs = loadHandlebarsFile(appHbsPath)
|
const appHbs = loadHandlebarsFile(appHbsPath)
|
||||||
ctx.body = await processString(appHbs, {
|
ctx.body = await processString(appHbs, {
|
||||||
|
|
|
@ -1,23 +1,8 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
import ClientAppSkeleton from "@budibase/frontend-core/src/components/ClientAppSkeleton.svelte"
|
import ClientAppSkeleton from "@budibase/frontend-core/src/components/ClientAppSkeleton.svelte"
|
||||||
|
import type { BudibaseAppProps } from "@budibase/types"
|
||||||
|
|
||||||
export let title = ""
|
export let props: BudibaseAppProps
|
||||||
export let favicon = ""
|
|
||||||
|
|
||||||
export let metaImage = ""
|
|
||||||
export let metaTitle = ""
|
|
||||||
export let metaDescription = ""
|
|
||||||
|
|
||||||
export let clientLibPath
|
|
||||||
export let usedPlugins
|
|
||||||
export let appMigrating
|
|
||||||
|
|
||||||
export let showSkeletonLoader = false
|
|
||||||
export let hideDevTools
|
|
||||||
export let sideNav
|
|
||||||
export let hideFooter
|
|
||||||
|
|
||||||
export let nonce
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -28,27 +13,27 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Primary Meta Tags -->
|
<!-- Primary Meta Tags -->
|
||||||
<meta name="title" content={metaTitle} />
|
<meta name="title" content={props.metaTitle} />
|
||||||
<meta name="description" content={metaDescription} />
|
<meta name="description" content={props.metaDescription} />
|
||||||
|
|
||||||
<!-- Opengraph Meta Tags -->
|
<!-- Opengraph Meta Tags -->
|
||||||
<meta property="og:site_name" content="Budibase" />
|
<meta property="og:site_name" content="Budibase" />
|
||||||
<meta property="og:title" content={metaTitle} />
|
<meta property="og:title" content={props.metaTitle} />
|
||||||
<meta property="og:description" content={metaDescription} />
|
<meta property="og:description" content={props.metaDescription} />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:image" content={metaImage} />
|
<meta property="og:image" content={props.metaImage} />
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta property="twitter:card" content="summary_large_image" />
|
<meta property="twitter:card" content="summary_large_image" />
|
||||||
<meta property="twitter:site" content="@budibase" />
|
<meta property="twitter:site" content="@budibase" />
|
||||||
<meta property="twitter:image" content={metaImage} />
|
<meta property="twitter:image" content={props.metaImage} />
|
||||||
<meta property="twitter:image:alt" content={metaTitle} />
|
<meta property="twitter:image:alt" content={props.metaTitle} />
|
||||||
<meta property="twitter:title" content={metaTitle} />
|
<meta property="twitter:title" content={props.metaTitle} />
|
||||||
<meta property="twitter:description" content={metaDescription} />
|
<meta property="twitter:description" content={props.metaDescription} />
|
||||||
|
|
||||||
<title>{title}</title>
|
<title>{props.title}</title>
|
||||||
{#if favicon !== ""}
|
{#if props.favicon !== ""}
|
||||||
<link rel="icon" type="image/png" href={favicon} />
|
<link rel="icon" type="image/png" href={props.favicon} />
|
||||||
{:else}
|
{:else}
|
||||||
<link rel="icon" type="image/png" href="/builder/bblogo.png" />
|
<link rel="icon" type="image/png" href="/builder/bblogo.png" />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -105,11 +90,15 @@
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<body id="app">
|
<body id="app">
|
||||||
{#if showSkeletonLoader}
|
{#if props.showSkeletonLoader}
|
||||||
<ClientAppSkeleton {hideDevTools} {sideNav} {hideFooter} />
|
<ClientAppSkeleton
|
||||||
|
hideDevTools={props.hideDevTools}
|
||||||
|
sideNav={props.sideNav}
|
||||||
|
hideFooter={props.hideFooter}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<div id="error">
|
<div id="error">
|
||||||
{#if clientLibPath}
|
{#if props.clientLibPath}
|
||||||
<h1>There was an error loading your app</h1>
|
<h1>There was an error loading your app</h1>
|
||||||
<h2>
|
<h2>
|
||||||
The Budibase client library could not be loaded. Try republishing your
|
The Budibase client library could not be loaded. Try republishing your
|
||||||
|
@ -120,24 +109,24 @@
|
||||||
<p />
|
<p />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<script type="application/javascript" {nonce}>
|
<script type="application/javascript" nonce={props.nonce}>
|
||||||
window.INIT_TIME = Date.now()
|
window.INIT_TIME = Date.now()
|
||||||
</script>
|
</script>
|
||||||
{#if appMigrating}
|
{#if props.appMigrating}
|
||||||
<script type="application/javascript" {nonce}>
|
<script type="application/javascript" nonce={props.nonce}>
|
||||||
window.MIGRATING_APP = true
|
window.MIGRATING_APP = true
|
||||||
</script>
|
</script>
|
||||||
{/if}
|
{/if}
|
||||||
<script type="application/javascript" src={clientLibPath}>
|
<script type="application/javascript" src={props.clientLibPath}>
|
||||||
</script>
|
</script>
|
||||||
<!-- Custom components need inserted after the core client library -->
|
<!-- Custom components need inserted after the core client library -->
|
||||||
<!-- But before loadBudibase is called -->
|
<!-- But before loadBudibase is called -->
|
||||||
{#if usedPlugins?.length}
|
{#if props.usedPlugins?.length}
|
||||||
{#each usedPlugins as plugin}
|
{#each props.usedPlugins as plugin}
|
||||||
<script type="application/javascript" src={plugin.jsUrl}></script>
|
<script type="application/javascript" src={plugin.jsUrl}></script>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
<script type="application/javascript" {nonce}>
|
<script type="application/javascript" nonce={props.nonce}>
|
||||||
if (window.loadBudibase) {
|
if (window.loadBudibase) {
|
||||||
window.loadBudibase()
|
window.loadBudibase()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
} from "../../../integrations/tests/utils"
|
} from "../../../integrations/tests/utils"
|
||||||
import { Knex } from "knex"
|
import { Knex } from "knex"
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
|
import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
|
||||||
|
|
||||||
const descriptions = datasourceDescribe({
|
const descriptions = datasourceDescribe({
|
||||||
exclude: [DatabaseName.MONGODB, DatabaseName.SQS],
|
exclude: [DatabaseName.MONGODB, DatabaseName.SQS],
|
||||||
|
@ -41,39 +42,34 @@ if (descriptions.length) {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to execute a query", async () => {
|
it("should be able to execute a query", async () => {
|
||||||
let res = await setup.runStep(
|
const { steps } = await createAutomationBuilder(config)
|
||||||
config,
|
.onAppAction()
|
||||||
setup.actions.EXECUTE_QUERY.stepId,
|
.executeQuery({ query: { queryId: query._id! } })
|
||||||
{
|
.test({ fields: {} })
|
||||||
query: { queryId: query._id },
|
|
||||||
}
|
expect(steps[0].outputs.response).toEqual([{ a: "string", b: 1 }])
|
||||||
)
|
expect(steps[0].outputs.success).toEqual(true)
|
||||||
expect(res.response).toEqual([{ a: "string", b: 1 }])
|
|
||||||
expect(res.success).toEqual(true)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle a null query value", async () => {
|
it("should handle a null query value", async () => {
|
||||||
let res = await setup.runStep(
|
const { steps } = await createAutomationBuilder(config)
|
||||||
config,
|
.onAppAction()
|
||||||
setup.actions.EXECUTE_QUERY.stepId,
|
// @ts-expect-error - intentionally passing null
|
||||||
{
|
.executeQuery({ query: { queryId: null } })
|
||||||
query: null,
|
.test({ fields: {} })
|
||||||
}
|
|
||||||
)
|
expect(steps[0].outputs.response).toStartWith("Error:")
|
||||||
expect(res.response.message).toEqual("Invalid inputs")
|
expect(steps[0].outputs.success).toEqual(false)
|
||||||
expect(res.success).toEqual(false)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle an error executing a query", async () => {
|
it("should handle an error executing a query", async () => {
|
||||||
let res = await setup.runStep(
|
const { steps } = await createAutomationBuilder(config)
|
||||||
config,
|
.onAppAction()
|
||||||
setup.actions.EXECUTE_QUERY.stepId,
|
.executeQuery({ query: { queryId: "wrong_id" } })
|
||||||
{
|
.test({ fields: {} })
|
||||||
query: { queryId: "wrong_id" },
|
|
||||||
}
|
expect(steps[0].outputs.response).toStartWith("Error:")
|
||||||
)
|
expect(steps[0].outputs.success).toEqual(false)
|
||||||
expect(res.response).toBeDefined()
|
|
||||||
expect(res.success).toEqual(false)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,7 +19,7 @@ function generateResponse(to: string, from: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import * as setup from "../utilities"
|
import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
|
||||||
|
|
||||||
describe("test the outgoing webhook action", () => {
|
describe("test the outgoing webhook action", () => {
|
||||||
const config = new TestConfiguration()
|
const config = new TestConfiguration()
|
||||||
|
@ -60,13 +60,14 @@ describe("test the outgoing webhook action", () => {
|
||||||
...invite,
|
...invite,
|
||||||
}
|
}
|
||||||
let resp = generateResponse(inputs.to, inputs.from)
|
let resp = generateResponse(inputs.to, inputs.from)
|
||||||
const res = await setup.runStep(
|
|
||||||
config,
|
const { steps } = await createAutomationBuilder(config)
|
||||||
setup.actions.SEND_EMAIL_SMTP.stepId,
|
.onAppAction()
|
||||||
inputs
|
.sendSmtpEmail(inputs)
|
||||||
)
|
.test({ fields: {} })
|
||||||
expect(res.response).toEqual(resp)
|
|
||||||
expect(res.success).toEqual(true)
|
expect(steps[0].outputs.response).toEqual(resp)
|
||||||
|
expect(steps[0].outputs.success).toEqual(true)
|
||||||
expect(workerRequests.sendSmtpEmail).toHaveBeenCalledTimes(1)
|
expect(workerRequests.sendSmtpEmail).toHaveBeenCalledTimes(1)
|
||||||
expect(workerRequests.sendSmtpEmail).toHaveBeenCalledWith({
|
expect(workerRequests.sendSmtpEmail).toHaveBeenCalledWith({
|
||||||
to: "user1@example.com",
|
to: "user1@example.com",
|
||||||
|
@ -75,7 +76,11 @@ describe("test the outgoing webhook action", () => {
|
||||||
contents: "testing",
|
contents: "testing",
|
||||||
cc: "cc",
|
cc: "cc",
|
||||||
bcc: "bcc",
|
bcc: "bcc",
|
||||||
invite,
|
invite: {
|
||||||
|
...invite,
|
||||||
|
startTime: invite.startTime.toISOString(),
|
||||||
|
endTime: invite.endTime.toISOString(),
|
||||||
|
},
|
||||||
automation: true,
|
automation: true,
|
||||||
attachments: [
|
attachments: [
|
||||||
{ url: "attachment1", filename: "attachment1.txt" },
|
{ url: "attachment1", filename: "attachment1.txt" },
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
|
||||||
|
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||||
|
import { captureAutomationResults } from "../utilities"
|
||||||
|
import { Automation } from "@budibase/types"
|
||||||
|
|
||||||
|
describe("app action trigger", () => {
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
let automation: Automation
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.init()
|
||||||
|
automation = await createAutomationBuilder(config)
|
||||||
|
.onAppAction()
|
||||||
|
.serverLog({
|
||||||
|
text: "App action triggered",
|
||||||
|
})
|
||||||
|
.save()
|
||||||
|
.then(({ automation }) => automation)
|
||||||
|
|
||||||
|
await config.api.application.publish()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
config.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should trigger when the app action is performed", async () => {
|
||||||
|
const jobs = await captureAutomationResults(automation, async () => {
|
||||||
|
await config.withProdApp(async () => {
|
||||||
|
await config.api.automation.trigger(automation._id!, {
|
||||||
|
fields: {},
|
||||||
|
timeout: 1000,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(jobs).toHaveLength(1)
|
||||||
|
expect(jobs[0].data.event).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
fields: {},
|
||||||
|
timeout: 1000,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
|
@ -15,6 +15,8 @@ import {
|
||||||
isDidNotTriggerResponse,
|
isDidNotTriggerResponse,
|
||||||
SearchFilters,
|
SearchFilters,
|
||||||
TestAutomationRequest,
|
TestAutomationRequest,
|
||||||
|
TriggerAutomationRequest,
|
||||||
|
TriggerAutomationResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||||
import { automations } from "@budibase/shared-core"
|
import { automations } from "@budibase/shared-core"
|
||||||
|
@ -207,6 +209,15 @@ class AutomationRunner<TStep extends AutomationTriggerStepId> {
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async trigger(
|
||||||
|
request: TriggerAutomationRequest
|
||||||
|
): Promise<TriggerAutomationResponse> {
|
||||||
|
return await this.config.api.automation.trigger(
|
||||||
|
this.automation._id!,
|
||||||
|
request
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createAutomationBuilder(config: TestConfiguration) {
|
export function createAutomationBuilder(config: TestConfiguration) {
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||||
import { context } from "@budibase/backend-core"
|
import { BUILTIN_ACTION_DEFINITIONS } from "../../actions"
|
||||||
import { BUILTIN_ACTION_DEFINITIONS, getAction } from "../../actions"
|
|
||||||
import emitter from "../../../events/index"
|
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import {
|
import { Automation, AutomationData, Datasource } from "@budibase/types"
|
||||||
Automation,
|
|
||||||
AutomationActionStepId,
|
|
||||||
AutomationData,
|
|
||||||
Datasource,
|
|
||||||
} from "@budibase/types"
|
|
||||||
import { Knex } from "knex"
|
import { Knex } from "knex"
|
||||||
import { getQueue } from "../.."
|
import { getQueue } from "../.."
|
||||||
import { Job } from "bull"
|
import { Job } from "bull"
|
||||||
|
@ -41,36 +34,6 @@ export async function runInProd(fn: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runStep(
|
|
||||||
config: TestConfiguration,
|
|
||||||
stepId: string,
|
|
||||||
inputs: any,
|
|
||||||
stepContext?: any
|
|
||||||
) {
|
|
||||||
async function run() {
|
|
||||||
let step = await getAction(stepId as AutomationActionStepId)
|
|
||||||
expect(step).toBeDefined()
|
|
||||||
if (!step) {
|
|
||||||
throw new Error("No step found")
|
|
||||||
}
|
|
||||||
return step({
|
|
||||||
context: stepContext || {},
|
|
||||||
inputs,
|
|
||||||
appId: config ? config.getAppId() : "",
|
|
||||||
// don't really need an API key, mocked out usage quota, not being tested here
|
|
||||||
apiKey,
|
|
||||||
emitter,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (config.appId) {
|
|
||||||
return context.doInContext(config?.appId, async () => {
|
|
||||||
return run()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return run()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture all automation runs that occur during the execution of a function.
|
* Capture all automation runs that occur during the execution of a function.
|
||||||
* This function will wait for all messages to be processed before returning.
|
* This function will wait for all messages to be processed before returning.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
const { vitePreprocess } = require("@sveltejs/vite-plugin-svelte")
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Plugin } from "../"
|
||||||
|
|
||||||
|
export interface BudibaseAppProps {
|
||||||
|
title: string
|
||||||
|
favicon: string
|
||||||
|
metaImage: string
|
||||||
|
metaTitle: string
|
||||||
|
metaDescription: string
|
||||||
|
clientLibPath?: string
|
||||||
|
usedPlugins: Plugin[]
|
||||||
|
appMigrating?: boolean
|
||||||
|
showSkeletonLoader?: boolean
|
||||||
|
hideDevTools?: boolean
|
||||||
|
sideNav?: boolean
|
||||||
|
hideFooter?: boolean
|
||||||
|
nonce?: string
|
||||||
|
}
|
|
@ -4,3 +4,4 @@ export * from "./components"
|
||||||
export * from "./dataFetch"
|
export * from "./dataFetch"
|
||||||
export * from "./datasource"
|
export * from "./datasource"
|
||||||
export * from "./common"
|
export * from "./common"
|
||||||
|
export * from "./BudibaseApp"
|
||||||
|
|
|
@ -7,7 +7,8 @@ const { cp, readdir, copyFile, mkdir } = require("node:fs/promises")
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
|
|
||||||
const { build } = require("esbuild")
|
const { build } = require("esbuild")
|
||||||
const { compile } = require("svelte/compiler")
|
const { compile, preprocess } = require("svelte/compiler")
|
||||||
|
const sveltePreprocess = require("svelte-preprocess")
|
||||||
const { loadTsConfig } = require("load-tsconfig")
|
const { loadTsConfig } = require("load-tsconfig")
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -25,7 +26,14 @@ const svelteCompilePlugin = {
|
||||||
const dir = path.dirname(args.path)
|
const dir = path.dirname(args.path)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { js } = compile(source, { css: "injected", generate: "ssr" })
|
const preprocessed = await preprocess(
|
||||||
|
source,
|
||||||
|
sveltePreprocess({ filename: args.path })
|
||||||
|
)
|
||||||
|
const { js } = compile(preprocessed.code, {
|
||||||
|
css: "injected",
|
||||||
|
generate: "ssr",
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// The code placed in the generated file
|
// The code placed in the generated file
|
||||||
|
|
47
yarn.lock
47
yarn.lock
|
@ -2778,9 +2778,9 @@
|
||||||
through2 "^2.0.0"
|
through2 "^2.0.0"
|
||||||
|
|
||||||
"@budibase/pro@npm:@budibase/pro@latest":
|
"@budibase/pro@npm:@budibase/pro@latest":
|
||||||
version "3.2.47"
|
version "3.4.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.47.tgz#150d7b16b14932d03c84bdb0e6d570d490c28a5c"
|
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.6.tgz#62b6ee13a015b98d4768dc7821f468f8177da3e9"
|
||||||
integrity sha512-UeTIq7yzMUK6w/akUsRafoD/Kif6PXv4d7K1arn8GTMjwFm9QYu2hg1YkQ+duNdwyZ/GEPlEAV5SYK+NDgtpdA==
|
integrity sha512-MC3P5SMokmqbjejZMlNM6z7NB9o5H6hZ++yVvbyThniBPYfuDc2ssa1HNwwcuNE3uRLhcxcKe8CY/0SbFgn51g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@anthropic-ai/sdk" "^0.27.3"
|
"@anthropic-ai/sdk" "^0.27.3"
|
||||||
"@budibase/backend-core" "*"
|
"@budibase/backend-core" "*"
|
||||||
|
@ -13739,6 +13739,11 @@ jake@^10.8.5:
|
||||||
filelist "^1.0.1"
|
filelist "^1.0.1"
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
|
|
||||||
|
jest-chain-transform@^0.0.8:
|
||||||
|
version "0.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/jest-chain-transform/-/jest-chain-transform-0.0.8.tgz#cbb4d3aef8d02678b1852968a9b0c861f75eef5a"
|
||||||
|
integrity sha512-AELTTzYJ34WrmQKAbxUGT+xqnAHu0/XJZhahYNGvBVUhnAayjm1QmT45DQjwEbQPQp7gn6CXzu6rZA03riwBuw==
|
||||||
|
|
||||||
jest-changed-files@^29.7.0:
|
jest-changed-files@^29.7.0:
|
||||||
version "29.7.0"
|
version "29.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a"
|
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a"
|
||||||
|
@ -19730,7 +19735,16 @@ string-length@^4.0.1:
|
||||||
char-regex "^1.0.2"
|
char-regex "^1.0.2"
|
||||||
strip-ansi "^6.0.0"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
|
"string-width-cjs@npm:string-width@^4.2.0":
|
||||||
|
version "4.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
|
dependencies:
|
||||||
|
emoji-regex "^8.0.0"
|
||||||
|
is-fullwidth-code-point "^3.0.0"
|
||||||
|
strip-ansi "^6.0.1"
|
||||||
|
|
||||||
|
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
|
@ -19822,7 +19836,7 @@ stringify-object@^3.2.1:
|
||||||
is-obj "^1.0.1"
|
is-obj "^1.0.1"
|
||||||
is-regexp "^1.0.0"
|
is-regexp "^1.0.0"
|
||||||
|
|
||||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
|
@ -19836,6 +19850,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex "^4.1.0"
|
ansi-regex "^4.1.0"
|
||||||
|
|
||||||
|
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
|
dependencies:
|
||||||
|
ansi-regex "^5.0.1"
|
||||||
|
|
||||||
strip-ansi@^7.0.1:
|
strip-ansi@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
|
||||||
|
@ -20070,6 +20091,11 @@ svelte-portal@^2.2.1:
|
||||||
resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-2.2.1.tgz#b1d7bed78e56318db245996beb5483d8de6b9740"
|
resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-2.2.1.tgz#b1d7bed78e56318db245996beb5483d8de6b9740"
|
||||||
integrity sha512-uF7is5sM4aq5iN7QF/67XLnTUvQCf2iiG/B1BHTqLwYVY1dsVmTeXZ/LeEyU6dLjApOQdbEG9lkqHzxiQtOLEQ==
|
integrity sha512-uF7is5sM4aq5iN7QF/67XLnTUvQCf2iiG/B1BHTqLwYVY1dsVmTeXZ/LeEyU6dLjApOQdbEG9lkqHzxiQtOLEQ==
|
||||||
|
|
||||||
|
svelte-preprocess@^6.0.3:
|
||||||
|
version "6.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz#fdc1f9dc41b6f22bf8b1f059e9f21eaaae181eeb"
|
||||||
|
integrity sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA==
|
||||||
|
|
||||||
svelte-spa-router@^4.0.1:
|
svelte-spa-router@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-4.0.1.tgz#720ef0cc9a4af33b155812496545c7999483878c"
|
resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-4.0.1.tgz#720ef0cc9a4af33b155812496545c7999483878c"
|
||||||
|
@ -21583,7 +21609,7 @@ worker-farm@1.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
errno "~0.1.7"
|
errno "~0.1.7"
|
||||||
|
|
||||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
@ -21601,6 +21627,15 @@ wrap-ansi@^5.1.0:
|
||||||
string-width "^3.0.0"
|
string-width "^3.0.0"
|
||||||
strip-ansi "^5.0.0"
|
strip-ansi "^5.0.0"
|
||||||
|
|
||||||
|
wrap-ansi@^7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^4.0.0"
|
||||||
|
string-width "^4.1.0"
|
||||||
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
wrap-ansi@^8.1.0:
|
wrap-ansi@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||||
|
|
Loading…
Reference in New Issue