Merge branch 'server-workflows' of https://github.com/Budibase/budibase into server-workflows
This commit is contained in:
commit
9c20dba77b
|
@ -15,7 +15,6 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- <label class="selected-label">{workflowBlock.type}: {workflowBlock.name}</label> -->
|
|
||||||
{#each workflowParams as [parameter, type]}
|
{#each workflowParams as [parameter, type]}
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
<label class="label">{parameter}</label>
|
<label class="label">{parameter}</label>
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
$: selected =
|
$: selected =
|
||||||
$workflowStore.selectedWorkflowBlock != null &&
|
$workflowStore.selectedWorkflowBlock != null &&
|
||||||
$workflowStore.selectedWorkflowBlock.id === block.id
|
$workflowStore.selectedWorkflowBlock.id === block.id
|
||||||
|
|
||||||
console.log(selected)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { workflowStore } from "builderStore"
|
||||||
import { backendUiStore, workflowStore } from "builderStore"
|
|
||||||
import WorkflowList from "./WorkflowList/WorkflowList.svelte"
|
import WorkflowList from "./WorkflowList/WorkflowList.svelte"
|
||||||
import BlockList from "./BlockList/BlockList.svelte"
|
import BlockList from "./BlockList/BlockList.svelte"
|
||||||
import blockDefinitions from "./blockDefinitions"
|
|
||||||
|
|
||||||
let selectedTab = "WORKFLOWS"
|
let selectedTab = "WORKFLOWS"
|
||||||
let definitions = []
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { authenticate } from "./authenticate"
|
import { authenticate } from "./authenticate"
|
||||||
import { triggerWorkflow } from "./workflow"
|
|
||||||
import appStore from "../state/store"
|
import appStore from "../state/store"
|
||||||
|
|
||||||
const apiCall = method => async ({ url, body }) => {
|
const apiCall = method => async ({ url, body }) => {
|
||||||
|
@ -55,5 +54,4 @@ const apiOpts = {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
authenticate: authenticate(apiOpts),
|
authenticate: authenticate(apiOpts),
|
||||||
triggerWorkflow: triggerWorkflow(apiOpts),
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
|
|
||||||
export default {
|
|
||||||
NAVIGATE: () => {
|
|
||||||
// TODO client navigation
|
|
||||||
},
|
|
||||||
DELAY: async ({ args }) => await delay(args.time),
|
|
||||||
FILTER: ({ args }) => {
|
|
||||||
const { field, condition, value } = args
|
|
||||||
switch (condition) {
|
|
||||||
case "equals":
|
|
||||||
if (field !== value) return
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
import renderTemplateString from "../../state/renderTemplateString"
|
|
||||||
import appStore from "../../state/store"
|
|
||||||
import Orchestrator from "./orchestrator"
|
|
||||||
import clientActions from "./actions"
|
|
||||||
|
|
||||||
// Execute a workflow from a running budibase app
|
|
||||||
export const clientStrategy = ({ api }) => ({
|
|
||||||
context: {},
|
|
||||||
bindContextArgs: function(args) {
|
|
||||||
const mappedArgs = { ...args }
|
|
||||||
|
|
||||||
// bind the workflow action args to the workflow context, if required
|
|
||||||
for (let arg in args) {
|
|
||||||
const argValue = args[arg]
|
|
||||||
|
|
||||||
// We don't want to render mustache templates on non-strings
|
|
||||||
if (typeof argValue !== "string") continue
|
|
||||||
|
|
||||||
// Render the string with values from the workflow context and state
|
|
||||||
mappedArgs[arg] = renderTemplateString(argValue, {
|
|
||||||
context: this.context,
|
|
||||||
state: appStore.get(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedArgs
|
|
||||||
},
|
|
||||||
run: async function(workflow) {
|
|
||||||
for (let block of workflow.steps) {
|
|
||||||
// This code gets run in the browser
|
|
||||||
if (block.environment === "CLIENT") {
|
|
||||||
const action = clientActions[block.actionId]
|
|
||||||
await action({
|
|
||||||
context: this.context,
|
|
||||||
args: this.bindContextArgs(block.args),
|
|
||||||
id: block.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// this workflow block gets executed on the server
|
|
||||||
if (block.environment === "SERVER") {
|
|
||||||
const EXECUTE_WORKFLOW_URL = `/api/workflows/action`
|
|
||||||
const response = await api.post({
|
|
||||||
url: EXECUTE_WORKFLOW_URL,
|
|
||||||
body: {
|
|
||||||
action: block.actionId,
|
|
||||||
args: this.bindContextArgs(block.args, api),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
this.context = {
|
|
||||||
...this.context,
|
|
||||||
[block.actionId]: response,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export const triggerWorkflow = api => async ({ workflow }) => {
|
|
||||||
const workflowOrchestrator = new Orchestrator(api)
|
|
||||||
workflowOrchestrator.strategy = clientStrategy
|
|
||||||
|
|
||||||
const EXECUTE_WORKFLOW_URL = `/api/workflows/${workflow}`
|
|
||||||
const workflowDefinition = await api.get({ url: EXECUTE_WORKFLOW_URL })
|
|
||||||
|
|
||||||
workflowOrchestrator.execute(workflowDefinition)
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* The workflow orchestrator is a class responsible for executing workflows.
|
|
||||||
* It relies on the strategy pattern, which allows composable behaviour to be
|
|
||||||
* passed into its execute() function. This allows custom execution behaviour based
|
|
||||||
* on where the orchestrator is run.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export default class Orchestrator {
|
|
||||||
constructor(api) {
|
|
||||||
this.api = api
|
|
||||||
}
|
|
||||||
|
|
||||||
set strategy(strategy) {
|
|
||||||
this._strategy = strategy({ api: this.api })
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(workflow) {
|
|
||||||
if (workflow.live) {
|
|
||||||
this._strategy.run(workflow.definition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,3 @@
|
||||||
import api from "../api"
|
|
||||||
|
|
||||||
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType"
|
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType"
|
||||||
|
|
||||||
export const eventHandlers = routeTo => {
|
export const eventHandlers = routeTo => {
|
||||||
|
@ -10,7 +8,6 @@ export const eventHandlers = routeTo => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"Navigate To": handler(["url"], param => routeTo(param && param.url)),
|
"Navigate To": handler(["url"], param => routeTo(param && param.url)),
|
||||||
"Trigger Workflow": handler(["workflow"], api.triggerWorkflow),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
|
||||||
|
module.exports = async function delay({ args }) {
|
||||||
|
await wait(args.time)
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = async function filter({ args }) {
|
||||||
|
const { field, condition, value } = args
|
||||||
|
switch (condition) {
|
||||||
|
case "equals":
|
||||||
|
if (field !== value) return
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,8 +37,6 @@ exports.serverStrategy = () => ({
|
||||||
},
|
},
|
||||||
run: async function(workflow, context) {
|
run: async function(workflow, context) {
|
||||||
for (let block of workflow.steps) {
|
for (let block of workflow.steps) {
|
||||||
if (block.type === "CLIENT") continue
|
|
||||||
|
|
||||||
const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
|
const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
|
||||||
const response = await action({
|
const response = await action({
|
||||||
args: this.bindContextArgs(block.args),
|
args: this.bindContextArgs(block.args),
|
||||||
|
|
Loading…
Reference in New Issue