Merge pull request #1429 from Budibase/lab-day/scripting-block
Lab day/scripting block
This commit is contained in:
commit
f536b3d370
|
@ -38,7 +38,9 @@
|
||||||
<header>
|
<header>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<Heading size="XS">{title}</Heading>
|
<Heading size="XS">{title}</Heading>
|
||||||
<Body size="XXS"><slot name="description" /></Body>
|
<Body size="XXS">
|
||||||
|
<slot name="description" />
|
||||||
|
</Body>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<slot name="buttons" />
|
<slot name="buttons" />
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
>
|
>
|
||||||
{#if error}
|
{#if error}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
class="spectrum-Icon spectrum-Icon--sizeM
|
||||||
|
spectrum-Textfield-validationIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
<div slot="control" class="icon">
|
<div slot="control" class="icon">
|
||||||
<Icon s hoverable name="MoreSmallList" />
|
<Icon s hoverable name="MoreSmallList" />
|
||||||
</div>
|
</div>
|
||||||
<MenuItem noClose icon="Delete" on:click={confirmDeleteDialog.show}
|
<MenuItem noClose icon="Delete" on:click={confirmDeleteDialog.show}>
|
||||||
>Delete</MenuItem
|
Delete
|
||||||
>
|
</MenuItem>
|
||||||
</ActionMenu>
|
</ActionMenu>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
<script>
|
<script>
|
||||||
import TableSelector from "./TableSelector.svelte"
|
import TableSelector from "./TableSelector.svelte"
|
||||||
import RowSelector from "./RowSelector.svelte"
|
import RowSelector from "./RowSelector.svelte"
|
||||||
|
import QuerySelector from "./QuerySelector.svelte"
|
||||||
import SchemaSetup from "./SchemaSetup.svelte"
|
import SchemaSetup from "./SchemaSetup.svelte"
|
||||||
|
import QueryParamSelector from "./QueryParamSelector.svelte"
|
||||||
import { Button, Input, Select, Label } from "@budibase/bbui"
|
import { Button, Input, Select, Label } from "@budibase/bbui"
|
||||||
import { automationStore } from "builderStore"
|
import { automationStore } from "builderStore"
|
||||||
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
||||||
import DrawerBindableInput from "../../common/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "../../common/DrawerBindableInput.svelte"
|
||||||
import AutomationBindingPanel from "./AutomationBindingPanel.svelte"
|
import AutomationBindingPanel from "./AutomationBindingPanel.svelte"
|
||||||
|
import Editor from "components/integration/QueryEditor.svelte"
|
||||||
|
import CodeEditorModal from "./CodeEditorModal.svelte"
|
||||||
|
|
||||||
export let block
|
export let block
|
||||||
export let webhookModal
|
export let webhookModal
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script>
|
||||||
|
import { Button, Modal, ModalContent } from "@budibase/bbui"
|
||||||
|
|
||||||
|
let modal
|
||||||
|
|
||||||
|
export const show = () => {
|
||||||
|
modal.show()
|
||||||
|
}
|
||||||
|
export const hide = () => {
|
||||||
|
modal.hide()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:this={modal} width="60%">
|
||||||
|
<ModalContent
|
||||||
|
title="Edit Code"
|
||||||
|
showConfirmButton={false}
|
||||||
|
showCancelButton={false}
|
||||||
|
>
|
||||||
|
<div class="container">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
<Button primary on:click={show}>Edit Code</Button>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container :global(section > header) {
|
||||||
|
/* Fix margin defined in BBUI as L rather than XL */
|
||||||
|
margin-bottom: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
.container :global(textarea) {
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import { queries } from "stores/backend"
|
||||||
|
import { Select } from "@budibase/bbui"
|
||||||
|
import DrawerBindableInput from "../../common/DrawerBindableInput.svelte"
|
||||||
|
import AutomationBindingPanel from "./AutomationBindingPanel.svelte"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
export let bindings
|
||||||
|
|
||||||
|
$: query = $queries.list.find(query => query._id === value?.queryId)
|
||||||
|
$: parameters = query?.parameters ?? []
|
||||||
|
|
||||||
|
// Ensure any nullish queryId values get set to empty string so
|
||||||
|
// that the select works
|
||||||
|
$: if (value?.queryId == null) value = { queryId: "" }
|
||||||
|
$: console.log("daValuz", value)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="block-field">
|
||||||
|
<Select bind:value={value.queryId} extraThin secondary>
|
||||||
|
<option value="">Choose an option</option>
|
||||||
|
{#each $queries.list as query}
|
||||||
|
<option value={query._id}>{query.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if parameters.length}
|
||||||
|
<div class="schema-fields">
|
||||||
|
{#each parameters as field}
|
||||||
|
<DrawerBindableInput
|
||||||
|
panel={AutomationBindingPanel}
|
||||||
|
extraThin
|
||||||
|
value={value[field.name]}
|
||||||
|
on:change={e => {
|
||||||
|
value[field.name] = e.detail
|
||||||
|
}}
|
||||||
|
label={field.name}
|
||||||
|
type="string"
|
||||||
|
{bindings}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.schema-fields {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spacing-xl);
|
||||||
|
margin-top: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
.schema-fields :global(label) {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script>
|
||||||
|
import { queries } from "stores/backend"
|
||||||
|
import { Select } from "@budibase/bbui"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="block-field">
|
||||||
|
<Select bind:value secondary extraThin>
|
||||||
|
<option value="">Choose an option</option>
|
||||||
|
{#each $queries.list as query}
|
||||||
|
<option value={query._id}>{query.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
</div>
|
|
@ -54,7 +54,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div class="add-field"><i class="ri-add-line" on:click={addField} /></div>
|
<div class="add-field">
|
||||||
|
<i class="ri-add-line" on:click={addField} />
|
||||||
|
</div>
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
{#each fieldsArray as field}
|
{#each fieldsArray as field}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
|
|
||||||
<slot name="icon" />
|
<slot name="icon" />
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<div class="icon"><Icon size="S" name={icon} /></div>
|
<div class="icon">
|
||||||
|
<Icon size="S" name={icon} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="text">{text}</div>
|
<div class="text">{text}</div>
|
||||||
{#if withActions}
|
{#if withActions}
|
||||||
|
|
|
@ -71,36 +71,42 @@
|
||||||
<Icon size="S" hoverable name="MoreSmallList" />
|
<Icon size="S" hoverable name="MoreSmallList" />
|
||||||
</div>
|
</div>
|
||||||
<MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
|
<MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
|
||||||
<MenuItem noClose icon="ChevronUp" on:click={moveUpComponent}
|
<MenuItem noClose icon="ChevronUp" on:click={moveUpComponent}>
|
||||||
>Move up</MenuItem
|
Move up
|
||||||
>
|
</MenuItem>
|
||||||
<MenuItem noClose icon="ChevronDown" on:click={moveDownComponent}
|
<MenuItem noClose icon="ChevronDown" on:click={moveDownComponent}>
|
||||||
>Move down</MenuItem
|
Move down
|
||||||
>
|
</MenuItem>
|
||||||
<MenuItem noClose icon="Duplicate" on:click={duplicateComponent}
|
<MenuItem noClose icon="Duplicate" on:click={duplicateComponent}>
|
||||||
>Duplicate</MenuItem
|
Duplicate
|
||||||
>
|
</MenuItem>
|
||||||
<MenuItem icon="Cut" on:click={() => storeComponentForCopy(true)}
|
<MenuItem icon="Cut" on:click={() => storeComponentForCopy(true)}>
|
||||||
>Cut</MenuItem
|
Cut
|
||||||
>
|
</MenuItem>
|
||||||
<MenuItem icon="Copy" on:click={() => storeComponentForCopy(false)}
|
<MenuItem icon="Copy" on:click={() => storeComponentForCopy(false)}>
|
||||||
>Copy</MenuItem
|
Copy
|
||||||
>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="LayersBringToFront"
|
icon="LayersBringToFront"
|
||||||
on:click={() => pasteComponent("above")}
|
on:click={() => pasteComponent("above")}
|
||||||
disabled={noPaste}>Paste above</MenuItem
|
disabled={noPaste}
|
||||||
>
|
>
|
||||||
|
Paste above
|
||||||
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="LayersSendToBack"
|
icon="LayersSendToBack"
|
||||||
on:click={() => pasteComponent("below")}
|
on:click={() => pasteComponent("below")}
|
||||||
disabled={noPaste}>Paste below</MenuItem
|
disabled={noPaste}
|
||||||
>
|
>
|
||||||
|
Paste below
|
||||||
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="ShowOneLayer"
|
icon="ShowOneLayer"
|
||||||
on:click={() => pasteComponent("inside")}
|
on:click={() => pasteComponent("inside")}
|
||||||
disabled={noPaste || noChildrenAllowed}>Paste inside</MenuItem
|
disabled={noPaste || noChildrenAllowed}
|
||||||
>
|
>
|
||||||
|
Paste inside
|
||||||
|
</MenuItem>
|
||||||
</ActionMenu>
|
</ActionMenu>
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
bind:this={confirmDeleteDialog}
|
bind:this={confirmDeleteDialog}
|
||||||
|
|
|
@ -33,7 +33,9 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{#if !readOnly}
|
{#if !readOnly}
|
||||||
<div><Button secondary thin outline on:click={addEntry}>Add</Button></div>
|
<div>
|
||||||
|
<Button secondary thin outline on:click={addEntry}>Add</Button>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -132,6 +132,10 @@
|
||||||
|
|
||||||
if (destroyed) return
|
if (destroyed) return
|
||||||
|
|
||||||
|
CodeMirror.commands.autocomplete = function (cm) {
|
||||||
|
CodeMirror.showHint(cm, CodeMirror.hint.javascript)
|
||||||
|
}
|
||||||
|
|
||||||
editor = CodeMirror.fromTextArea(refs.editor, opts)
|
editor = CodeMirror.fromTextArea(refs.editor, opts)
|
||||||
|
|
||||||
editor.on("change", instance => {
|
editor.on("change", instance => {
|
||||||
|
|
|
@ -57,9 +57,9 @@
|
||||||
<Heading size="S">Configuration</Heading>
|
<Heading size="S">Configuration</Heading>
|
||||||
<Button secondary on:click={saveDatasource}>Save</Button>
|
<Button secondary on:click={saveDatasource}>Save</Button>
|
||||||
</div>
|
</div>
|
||||||
<Body size="S"
|
<Body size="S">
|
||||||
>Connect your database to Budibase using the config below.</Body
|
Connect your database to Budibase using the config below.
|
||||||
>
|
</Body>
|
||||||
<IntegrationConfigForm
|
<IntegrationConfigForm
|
||||||
schema={integration.datasource}
|
schema={integration.datasource}
|
||||||
integration={datasource.config}
|
integration={datasource.config}
|
||||||
|
|
|
@ -5826,10 +5826,10 @@ svelte-portal@0.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-0.1.0.tgz#cc2821cc84b05ed5814e0218dcdfcbebc53c1742"
|
resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-0.1.0.tgz#cc2821cc84b05ed5814e0218dcdfcbebc53c1742"
|
||||||
integrity sha512-kef+ksXVKun224mRxat+DdO4C+cGHla+fEcZfnBAvoZocwiaceOfhf5azHYOPXSSB1igWVFTEOF3CDENPnuWxg==
|
integrity sha512-kef+ksXVKun224mRxat+DdO4C+cGHla+fEcZfnBAvoZocwiaceOfhf5azHYOPXSSB1igWVFTEOF3CDENPnuWxg==
|
||||||
|
|
||||||
svelte@^3.36.0:
|
svelte@^3.37.0:
|
||||||
version "3.37.0"
|
version "3.38.2"
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.37.0.tgz#dc7cd24bcc275cdb3f8c684ada89e50489144ccd"
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5"
|
||||||
integrity sha512-TRF30F4W4+d+Jr2KzUUL1j8Mrpns/WM/WacxYlo5MMb2E5Qy2Pk1Guj6GylxsW9OnKQl1tnF8q3hG/hQ3h6VUA==
|
integrity sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg==
|
||||||
|
|
||||||
symbol-observable@^1.1.0:
|
symbol-observable@^1.1.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
|
|
|
@ -90,6 +90,8 @@
|
||||||
"arangojs": "7.2.0",
|
"arangojs": "7.2.0",
|
||||||
"aws-sdk": "^2.767.0",
|
"aws-sdk": "^2.767.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
|
"bull": "^3.22.0",
|
||||||
|
"bull-board": "^1.5.1",
|
||||||
"chmodr": "1.2.0",
|
"chmodr": "1.2.0",
|
||||||
"csvtojson": "2.0.10",
|
"csvtojson": "2.0.10",
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
|
@ -106,6 +108,7 @@
|
||||||
"koa": "2.7.0",
|
"koa": "2.7.0",
|
||||||
"koa-body": "4.2.0",
|
"koa-body": "4.2.0",
|
||||||
"koa-compress": "4.0.1",
|
"koa-compress": "4.0.1",
|
||||||
|
"koa-connect": "^2.1.0",
|
||||||
"koa-pino-logger": "3.0.0",
|
"koa-pino-logger": "3.0.0",
|
||||||
"koa-send": "5.0.0",
|
"koa-send": "5.0.0",
|
||||||
"koa-session": "5.12.0",
|
"koa-session": "5.12.0",
|
||||||
|
|
|
@ -37,6 +37,7 @@ async function init() {
|
||||||
PORT: 4001,
|
PORT: 4001,
|
||||||
MINIO_URL: "http://localhost:10000/",
|
MINIO_URL: "http://localhost:10000/",
|
||||||
COUCH_DB_URL: "http://budibase:budibase@localhost:10000/db/",
|
COUCH_DB_URL: "http://budibase:budibase@localhost:10000/db/",
|
||||||
|
REDIS_URL: "http://localhost:10000/cache/",
|
||||||
WORKER_URL: "http://localhost:4002",
|
WORKER_URL: "http://localhost:4002",
|
||||||
JWT_SECRET: "testsecret",
|
JWT_SECRET: "testsecret",
|
||||||
MINIO_ACCESS_KEY: "budibase",
|
MINIO_ACCESS_KEY: "budibase",
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
const vm = require("vm")
|
||||||
|
|
||||||
|
class ScriptExecutor {
|
||||||
|
constructor(body) {
|
||||||
|
this.script = new vm.Script(body.script)
|
||||||
|
this.context = vm.createContext(body.context)
|
||||||
|
this.context.fetch = fetch
|
||||||
|
}
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
const returnValue = this.script.runInContext(this.context)
|
||||||
|
return returnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.execute = async function (ctx) {
|
||||||
|
const executor = new ScriptExecutor(ctx.request.body)
|
||||||
|
|
||||||
|
const result = executor.execute()
|
||||||
|
ctx.body = result
|
||||||
|
}
|
|
@ -5,6 +5,10 @@ const compress = require("koa-compress")
|
||||||
const zlib = require("zlib")
|
const zlib = require("zlib")
|
||||||
const { mainRoutes, staticRoutes } = require("./routes")
|
const { mainRoutes, staticRoutes } = require("./routes")
|
||||||
const pkg = require("../../package.json")
|
const pkg = require("../../package.json")
|
||||||
|
const bullboard = require("bull-board")
|
||||||
|
const expressApp = require("express")()
|
||||||
|
|
||||||
|
expressApp.use("/bulladmin", bullboard.router)
|
||||||
|
|
||||||
const router = new Router()
|
const router = new Router()
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
const Router = require("@koa/router")
|
||||||
|
const controller = require("../controllers/hosting")
|
||||||
|
const authorized = require("../../middleware/authorized")
|
||||||
|
const { BUILDER } = require("../../utilities/security/permissions")
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
router.post("/api/script", authorized(BUILDER), controller.save)
|
||||||
|
|
||||||
|
module.exports = router
|
|
@ -3,6 +3,8 @@ const createRow = require("./steps/createRow")
|
||||||
const updateRow = require("./steps/updateRow")
|
const updateRow = require("./steps/updateRow")
|
||||||
const deleteRow = require("./steps/deleteRow")
|
const deleteRow = require("./steps/deleteRow")
|
||||||
const createUser = require("./steps/createUser")
|
const createUser = require("./steps/createUser")
|
||||||
|
const executeScript = require("./steps/executeScript")
|
||||||
|
const executeQuery = require("./steps/executeQuery")
|
||||||
const outgoingWebhook = require("./steps/outgoingWebhook")
|
const outgoingWebhook = require("./steps/outgoingWebhook")
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
const Sentry = require("@sentry/node")
|
const Sentry = require("@sentry/node")
|
||||||
|
@ -18,6 +20,8 @@ const BUILTIN_ACTIONS = {
|
||||||
DELETE_ROW: deleteRow.run,
|
DELETE_ROW: deleteRow.run,
|
||||||
CREATE_USER: createUser.run,
|
CREATE_USER: createUser.run,
|
||||||
OUTGOING_WEBHOOK: outgoingWebhook.run,
|
OUTGOING_WEBHOOK: outgoingWebhook.run,
|
||||||
|
EXECUTE_SCRIPT: executeScript.run,
|
||||||
|
EXECUTE_QUERY: executeQuery.run,
|
||||||
}
|
}
|
||||||
const BUILTIN_DEFINITIONS = {
|
const BUILTIN_DEFINITIONS = {
|
||||||
SEND_EMAIL: sendEmail.definition,
|
SEND_EMAIL: sendEmail.definition,
|
||||||
|
@ -26,6 +30,8 @@ const BUILTIN_DEFINITIONS = {
|
||||||
DELETE_ROW: deleteRow.definition,
|
DELETE_ROW: deleteRow.definition,
|
||||||
CREATE_USER: createUser.definition,
|
CREATE_USER: createUser.definition,
|
||||||
OUTGOING_WEBHOOK: outgoingWebhook.definition,
|
OUTGOING_WEBHOOK: outgoingWebhook.definition,
|
||||||
|
EXECUTE_SCRIPT: executeScript.definition,
|
||||||
|
EXECUTE_QUERY: executeQuery.definition,
|
||||||
}
|
}
|
||||||
|
|
||||||
let MANIFEST = null
|
let MANIFEST = null
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
const queryController = require("../../api/controllers/query")
|
||||||
|
|
||||||
|
module.exports.definition = {
|
||||||
|
name: "External Data Connector",
|
||||||
|
tagline: "Execute Data Connector",
|
||||||
|
icon: "ri-database-2-line",
|
||||||
|
description: "Execute a query in an external data connector",
|
||||||
|
type: "ACTION",
|
||||||
|
stepId: "EXECUTE_QUERY",
|
||||||
|
inputs: {},
|
||||||
|
schema: {
|
||||||
|
inputs: {
|
||||||
|
properties: {
|
||||||
|
query: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
queryId: {
|
||||||
|
type: "string",
|
||||||
|
customType: "query",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
customType: "queryParams",
|
||||||
|
title: "Parameters",
|
||||||
|
required: ["queryId"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["query"],
|
||||||
|
},
|
||||||
|
outputs: {
|
||||||
|
properties: {
|
||||||
|
response: {
|
||||||
|
type: "object",
|
||||||
|
description: "The response from the datasource execution",
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Whether the action was successful",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["response", "success"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.run = async function ({ inputs, appId, emitter }) {
|
||||||
|
if (inputs.query == null) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
response: {
|
||||||
|
message: "Invalid inputs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { queryId, ...rest } = inputs.query
|
||||||
|
|
||||||
|
const ctx = {
|
||||||
|
params: {
|
||||||
|
queryId,
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
parameters: rest,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
appId,
|
||||||
|
eventEmitter: emitter,
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryController.execute(ctx)
|
||||||
|
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
response: ctx.body,
|
||||||
|
success: ctx.status === 200,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
response: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
const scriptController = require("../../api/controllers/script")
|
||||||
|
|
||||||
|
module.exports.definition = {
|
||||||
|
name: "Scripting",
|
||||||
|
tagline: "Execute JavaScript Code",
|
||||||
|
icon: "ri-terminal-box-line",
|
||||||
|
description: "Run a piece of JavaScript code in your automation",
|
||||||
|
type: "ACTION",
|
||||||
|
stepId: "EXECUTE_SCRIPT",
|
||||||
|
inputs: {},
|
||||||
|
schema: {
|
||||||
|
inputs: {
|
||||||
|
properties: {
|
||||||
|
code: {
|
||||||
|
type: "string",
|
||||||
|
customType: "code",
|
||||||
|
title: "Code",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["code"],
|
||||||
|
},
|
||||||
|
outputs: {
|
||||||
|
properties: {
|
||||||
|
value: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The result of the last statement of the executed script.",
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Whether the action was successful",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["success"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.run = async function ({ inputs, appId, context, emitter }) {
|
||||||
|
if (inputs.code == null) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
response: {
|
||||||
|
message: "Invalid inputs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = {
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
script: inputs.code,
|
||||||
|
context,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user: { appId },
|
||||||
|
eventEmitter: emitter,
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await scriptController.execute(ctx)
|
||||||
|
return {
|
||||||
|
success: ctx.status === 200,
|
||||||
|
value: ctx.body,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
response: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,7 @@ class Orchestrator {
|
||||||
appId: this._appId,
|
appId: this._appId,
|
||||||
apiKey: automation.apiKey,
|
apiKey: automation.apiKey,
|
||||||
emitter: this._emitter,
|
emitter: this._emitter,
|
||||||
|
context: this._context,
|
||||||
})
|
})
|
||||||
if (step.stepId === FILTER_STEP_ID && !outputs.success) {
|
if (step.stepId === FILTER_STEP_ID && !outputs.success) {
|
||||||
break
|
break
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
const CouchDB = require("../db")
|
const CouchDB = require("../db")
|
||||||
const emitter = require("../events/index")
|
const emitter = require("../events/index")
|
||||||
const InMemoryQueue = require("../utilities/queue/inMemoryQueue")
|
const Queue = require("bull")
|
||||||
|
const { setQueues, BullAdapter } = require("bull-board")
|
||||||
const { getAutomationParams } = require("../db/utils")
|
const { getAutomationParams } = require("../db/utils")
|
||||||
const { coerce } = require("../utilities/rowProcessor")
|
const { coerce } = require("../utilities/rowProcessor")
|
||||||
|
|
||||||
let automationQueue = new InMemoryQueue("automationQueue")
|
let automationQueue = new Queue("automationQueue")
|
||||||
|
|
||||||
|
// Set up queues for bull board admin
|
||||||
|
setQueues([new BullAdapter(automationQueue)])
|
||||||
|
|
||||||
const FAKE_STRING = "TEST"
|
const FAKE_STRING = "TEST"
|
||||||
const FAKE_BOOL = false
|
const FAKE_BOOL = false
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -226,10 +226,10 @@ svelte-hmr@^0.13.3:
|
||||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.13.3.tgz#fba5739b477ea44caf70e542a24a4352bee2b897"
|
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.13.3.tgz#fba5739b477ea44caf70e542a24a4352bee2b897"
|
||||||
integrity sha512-gagW62pLQ2lULmvNA3pIZu9pBCYOaGu3rQikUOv6Nokz5VxUgT9/mQLfMxj9phDEKHCg/lgr3i6PkqZDbO9P2Q==
|
integrity sha512-gagW62pLQ2lULmvNA3pIZu9pBCYOaGu3rQikUOv6Nokz5VxUgT9/mQLfMxj9phDEKHCg/lgr3i6PkqZDbO9P2Q==
|
||||||
|
|
||||||
svelte@^3.35.0:
|
svelte@^3.37.0:
|
||||||
version "3.37.0"
|
version "3.38.2"
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.37.0.tgz#dc7cd24bcc275cdb3f8c684ada89e50489144ccd"
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5"
|
||||||
integrity sha512-TRF30F4W4+d+Jr2KzUUL1j8Mrpns/WM/WacxYlo5MMb2E5Qy2Pk1Guj6GylxsW9OnKQl1tnF8q3hG/hQ3h6VUA==
|
integrity sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg==
|
||||||
|
|
||||||
svg.draggable.js@^2.2.2:
|
svg.draggable.js@^2.2.2:
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
|
|
Loading…
Reference in New Issue