mirror of https://github.com/Budibase/budibase.git
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