forked from tsai/budibase
committed by
GitHub
26 changed files with 1000 additions and 121 deletions
@ -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> |
||||
@ -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 |
||||
|
} |
||||
@ -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 |
||||
@ -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, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue