-
-
-
+
+ {/if}
{/if}
@@ -78,21 +129,30 @@
font-weight: bold;
display: flex;
align-items: center;
- justify-content: space-between;
margin-bottom: 20px;
}
- header > span {
+ .selected {
color: var(--font);
}
+ .config-item {
+ padding: 20px;
+ background: var(--light-grey);
+ }
+
+ header > span {
+ color: var(--dark-grey);
+ margin-right: 20px;
+ }
+
label {
font-weight: 500;
font-size: 14px;
color: var(--font);
}
- .delete-workflow-button {
+ .workflow-button {
font-family: Roboto;
width: 100%;
border: solid 1px #f2f2f2;
@@ -102,4 +162,24 @@
font-size: 12px;
font-weight: 500;
}
+
+ .test-result {
+ border: none;
+ width: 100%;
+ border-radius: 2px;
+ height: 32px;
+ font-size: 12px;
+ font-weight: 500;
+ color: var(--white);
+ text-align: center;
+ margin-bottom: 10px;
+ }
+
+ .passed {
+ background: #84c991;
+ }
+
+ .failed {
+ background: var(--coral);
+ }
diff --git a/packages/builder/src/components/workflow/SetupPanel/WorkflowBlockSetup.svelte b/packages/builder/src/components/workflow/SetupPanel/WorkflowBlockSetup.svelte
index 7bb16daa52..d629630099 100644
--- a/packages/builder/src/components/workflow/SetupPanel/WorkflowBlockSetup.svelte
+++ b/packages/builder/src/components/workflow/SetupPanel/WorkflowBlockSetup.svelte
@@ -76,5 +76,7 @@
textarea {
min-height: 150px;
+ font-family: inherit;
+ padding: 5px;
}
diff --git a/packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/WorkflowList.svelte b/packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/WorkflowList.svelte
index 9b03ee2f6d..ff13782114 100644
--- a/packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/WorkflowList.svelte
+++ b/packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/WorkflowList.svelte
@@ -28,7 +28,6 @@
async function saveWorkflow() {
const workflow = $workflowStore.currentWorkflow.workflow
- // TODO: Clean up args
await workflowStore.actions.save({
instanceId: $backendUiStore.selectedDatabase._id,
workflow,
diff --git a/packages/builder/src/components/workflow/WorkflowPanel/blockDefinitions.js b/packages/builder/src/components/workflow/WorkflowPanel/blockDefinitions.js
index 4e36353532..96da6a3910 100644
--- a/packages/builder/src/components/workflow/WorkflowPanel/blockDefinitions.js
+++ b/packages/builder/src/components/workflow/WorkflowPanel/blockDefinitions.js
@@ -22,17 +22,19 @@ const ACTION = {
},
SAVE_RECORD: {
name: "Save Record",
+ tagline: "Save a
{{model.name}} record",
icon: "ri-save-3-fill",
description: "Save a record to your database.",
environment: "SERVER",
params: {
- model: "string",
+ model: "model",
},
},
DELETE_RECORD: {
description: "Delete a record from your database.",
icon: "ri-delete-bin-line",
name: "Delete Record",
+ tagline: "Delete a
{{model.name}} record",
environment: "SERVER",
params: {
record: "string",
diff --git a/packages/client/src/api/workflow/actions.js b/packages/client/src/api/workflow/actions.js
index 795d34fad3..f7d4755fbf 100644
--- a/packages/client/src/api/workflow/actions.js
+++ b/packages/client/src/api/workflow/actions.js
@@ -1,6 +1,4 @@
-import { get } from "svelte/store"
import { setState } from "../../state/setState"
-import { appStore } from "../../state/store"
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
@@ -12,11 +10,11 @@ export default {
[id]: args,
}
},
- NAVIGATE: ({ context, args, id }) => {
+ NAVIGATE: () => {
// TODO client navigation
},
- DELAY: async ({ context, args }) => await delay(args.time),
- FILTER: ({ context, args }) => {
+ DELAY: async ({ args }) => await delay(args.time),
+ FILTER: ({ args }) => {
const { field, condition, value } = args
switch (condition) {
case "equals":
diff --git a/packages/client/src/api/workflow/index.js b/packages/client/src/api/workflow/index.js
index 94cd6fb6f8..6d6d12a97e 100644
--- a/packages/client/src/api/workflow/index.js
+++ b/packages/client/src/api/workflow/index.js
@@ -1,7 +1,7 @@
import { get } from "svelte/store"
import mustache from "mustache"
import { appStore } from "../../state/store"
-import Orchestrator from "./orchestrator";
+import Orchestrator from "./orchestrator"
import clientActions from "./actions"
// Execute a workflow from a running budibase app
@@ -28,8 +28,6 @@ export const clientStrategy = ({ api, instanceId }) => ({
},
run: async function(workflow) {
for (let block of workflow.steps) {
- console.log("Executing workflow block", block)
-
// This code gets run in the browser
if (block.environment === "CLIENT") {
const action = clientActions[block.actionId]
@@ -60,13 +58,11 @@ export const clientStrategy = ({ api, instanceId }) => ({
},
})
-export const triggerWorkflow = api => async ({ workflow }) => {
- const instanceId = "inst_ad75c7f_4f3e7d5d80a74b17a5187a18e2aba85e";
-
+export const triggerWorkflow = api => async ({ workflow, instanceId }) => {
const workflowOrchestrator = new Orchestrator(api, instanceId)
workflowOrchestrator.strategy = clientStrategy
- const EXECUTE_WORKFLOW_URL = `/api/${instanceId}/workflows/${workflow}`
+ const EXECUTE_WORKFLOW_URL = `/api/workflows/${workflow}`
const workflowDefinition = await api.get({ url: EXECUTE_WORKFLOW_URL })
workflowOrchestrator.execute(workflowDefinition)
diff --git a/packages/client/src/createApp.js b/packages/client/src/createApp.js
index d3fb51b124..a80c1009c7 100644
--- a/packages/client/src/createApp.js
+++ b/packages/client/src/createApp.js
@@ -1,4 +1,3 @@
-import { writable } from "svelte/store"
import { attachChildren } from "./render/attachChildren"
import { createTreeNode } from "./render/prepareRenderComponent"
import { screenRouter } from "./render/screenRouter"
@@ -7,7 +6,6 @@ import { createStateManager } from "./state/stateManager"
export const createApp = ({
componentLibraries,
frontendDefinition,
- user,
window,
}) => {
let routeTo
diff --git a/packages/client/src/render/screenRouter.js b/packages/client/src/render/screenRouter.js
index 1325bbd20a..262ed65f66 100644
--- a/packages/client/src/render/screenRouter.js
+++ b/packages/client/src/render/screenRouter.js
@@ -1,8 +1,6 @@
import regexparam from "regexparam"
import { routerStore } from "../state/store"
-import { initRouteStore } from "../state/store"
-// TODO: refactor
export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => {
const makeRootedPath = url => {
if (appRootPath) {
diff --git a/packages/client/src/state/eventHandlers.js b/packages/client/src/state/eventHandlers.js
index 88418ba1a3..b013956dd4 100644
--- a/packages/client/src/state/eventHandlers.js
+++ b/packages/client/src/state/eventHandlers.js
@@ -6,17 +6,12 @@ import { createApi } from "../api"
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType"
-export const eventHandlers = (store, rootPath, routeTo) => {
+export const eventHandlers = (rootPath, routeTo) => {
const handler = (parameters, execute) => ({
execute,
parameters,
})
- let currentState
- store.subscribe(state => {
- currentState = state
- })
-
const api = createApi({
rootPath,
setState,
diff --git a/packages/client/src/state/parseBinding.js b/packages/client/src/state/parseBinding.js
deleted file mode 100644
index 4ecf9887ef..0000000000
--- a/packages/client/src/state/parseBinding.js
+++ /dev/null
@@ -1,67 +0,0 @@
-// export const BB_STATE_BINDINGPATH = "##bbstate"
-// export const BB_STATE_BINDINGSOURCE = "##bbsource"
-// export const BB_STATE_FALLBACK = "##bbstatefallback"
-
-// export const isBound = prop => !!parseBinding(prop)
-
-// /**
-// *
-// * @param {object|string|number} prop - component property to parse for a dynamic state binding
-// * @returns {object|boolean}
-// */
-// export const parseBinding = prop => {
-// if (!prop) return false
-
-// if (isBindingExpression(prop)) {
-// return parseBindingExpression(prop)
-// }
-
-// if (isAlreadyBinding(prop)) {
-// return {
-// path: prop.path,
-// source: prop.source || "store",
-// fallback: prop.fallback,
-// }
-// }
-
-// if (hasBindingObject(prop)) {
-// return {
-// path: prop[BB_STATE_BINDINGPATH],
-// fallback: prop[BB_STATE_FALLBACK] || "",
-// source: prop[BB_STATE_BINDINGSOURCE] || "store",
-// }
-// }
-// }
-
-// export const isStoreBinding = binding => binding && binding.source === "store"
-// export const isContextBinding = binding =>
-// binding && binding.source === "context"
-// // export const isEventBinding = binding => binding && binding.source === "event"
-
-// const hasBindingObject = prop =>
-// typeof prop === "object" && prop[BB_STATE_BINDINGPATH] !== undefined
-
-// const isAlreadyBinding = prop => typeof prop === "object" && prop.path
-
-// const isBindingExpression = prop =>
-// typeof prop === "string" &&
-// (prop.startsWith("state.") ||
-// prop.startsWith("context.") ||
-// prop.startsWith("event.") ||
-// prop.startsWith("route."))
-
-// const parseBindingExpression = prop => {
-// let [source, ...rest] = prop.split(".")
-// let path = rest.join(".")
-
-// if (source === "route") {
-// source = "state"
-// path = `##routeParams.${path}`
-// }
-
-// return {
-// fallback: "", // TODO: provide fallback support
-// source,
-// path,
-// }
-// }
diff --git a/packages/client/src/state/stateManager.js b/packages/client/src/state/stateManager.js
index b4597be5dd..8e777ca4b9 100644
--- a/packages/client/src/state/stateManager.js
+++ b/packages/client/src/state/stateManager.js
@@ -21,27 +21,16 @@ const isMetaProp = propName =>
propName === "_styles"
export const createStateManager = ({
- // store,
appRootPath,
frontendDefinition,
componentLibraries,
onScreenSlotRendered,
routeTo,
}) => {
- let handlerTypes = eventHandlers(appStore, appRootPath, routeTo)
+ let handlerTypes = eventHandlers(appRootPath, routeTo)
let currentState
- // any nodes that have props that are bound to the store
- // let nodesBoundByProps = []
-
- // any node whose children depend on code, that uses the store
- // let nodesWithCodeBoundChildren = []
-
const getCurrentState = () => currentState
- // const registerBindings = _registerBindings(
- // nodesBoundByProps,
- // nodesWithCodeBoundChildren
- // )
const bb = bbFactory({
store: appStore,
@@ -53,131 +42,26 @@ export const createStateManager = ({
const setup = _setup({ handlerTypes, getCurrentState, bb, store: appStore })
- // TODO: remove
- const unsubscribe = appStore.subscribe(state => {
- console.log("store updated", state)
- return state
- })
-
- // const unsubscribe = store.subscribe(
- // onStoreStateUpdated({
- // setCurrentState: state => (currentState = state),
- // getCurrentState,
- // // nodesWithCodeBoundChildren,
- // // nodesBoundByProps,
- // componentLibraries,
- // onScreenSlotRendered,
- // setupState: setup,
- // })
- // )
-
return {
setup,
- destroy: () => unsubscribe(),
+ destroy: () => {},
getCurrentState,
store: appStore,
}
}
-const onStoreStateUpdated = ({
- setCurrentState,
- getCurrentState,
- componentLibraries,
- onScreenSlotRendered,
- setupState,
-}) => state => {
- // fire the state update event to re-render anything bound to this
- // setCurrentState(state)
- // setCurrentState(state)
- // attachChildren({
- // componentLibraries,
- // treeNode: createTreeNode(),
- // onScreenSlotRendered,
- // setupState,
- // getCurrentState,
- // })(document.querySelector("#app"), { hydrate: true, force: true })
- // // the original array gets changed by components' destroy()
- // // so we make a clone and check if they are still in the original
- // const nodesWithBoundChildren_clone = [...nodesWithCodeBoundChildren]
- // for (let node of nodesWithBoundChildren_clone) {
- // if (!nodesWithCodeBoundChildren.includes(node)) continue
- // attachChildren({
- // componentLibraries,
- // treeNode: node,
- // onScreenSlotRendered,
- // setupState,
- // getCurrentState,
- // })(node.rootElement, { hydrate: true, force: true })
- // }
-}
-
-// const _registerBindings = (nodesBoundByProps, nodesWithCodeBoundChildren) => (
-// node,
-// bindings
-// ) => {
-// if (bindings.length > 0) {
-// node.bindings = bindings
-// nodesBoundByProps.push(node)
-// const onDestroy = () => {
-// nodesBoundByProps = nodesBoundByProps.filter(n => n === node)
-// node.onDestroy = node.onDestroy.filter(d => d === onDestroy)
-// }
-// node.onDestroy.push(onDestroy)
-// }
-// if (
-// node.props._children &&
-// node.props._children.filter(c => c._codeMeta && c._codeMeta.dependsOnStore)
-// .length > 0
-// ) {
-// nodesWithCodeBoundChildren.push(node)
-// const onDestroy = () => {
-// nodesWithCodeBoundChildren = nodesWithCodeBoundChildren.filter(
-// n => n === node
-// )
-// node.onDestroy = node.onDestroy.filter(d => d === onDestroy)
-// }
-// node.onDestroy.push(onDestroy)
-// }
-// }
-
-// const setNodeState = (storeState, node) => {
-// if (!node.component) return
-// const newProps = { ...node.bindings.initialProps }
-
-// for (let binding of node.bindings) {
-// const val = getState(storeState, binding.path, binding.fallback)
-
-// if (val === undefined && newProps[binding.propName] !== undefined) {
-// delete newProps[binding.propName]
-// }
-
-// if (val !== undefined) {
-// newProps[binding.propName] = val
-// }
-// }
-
-// node.component.$set(newProps)
-// }
-
const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
const props = node.props
const context = node.context || {}
const initialProps = { ...props }
- // const storeBoundProps = []
const currentStoreState = get(appStore)
- console.log("node", node)
-
- // console.log("node", node);
- // console.log("nodeComponent", node.component);
-
for (let propName in props) {
if (isMetaProp(propName)) continue
const propValue = props[propName]
- // const binding = parseBinding(propValue)
- // TODO: better binding stuff
+ // A little bit of a hack - won't bind if the string doesn't start with {{
const isBound = typeof propValue === "string" && propValue.startsWith("{{")
if (isBound) {
@@ -191,27 +75,6 @@ const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
}
}
- // if (isBound) binding.propName = propName
-
- // if (isBound && binding.source === "state") {
- // storeBoundProps.push(binding)
-
- // initialProps[propName] = !currentStoreState
- // ? binding.fallback
- // : getState(
- // currentStoreState,
- // binding.path,
- // binding.fallback,
- // binding.source
- // )
- // }
-
- // if (isBound && binding.source === "context") {
- // initialProps[propName] = !context
- // ? propValue
- // : getState(context, binding.path, binding.fallback, binding.source)
- // }
-
if (isEventType(propValue)) {
const handlersInfos = []
for (let event of propValue) {
@@ -228,21 +91,6 @@ const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
state: getCurrentState(),
context,
})
- // const paramBinding = parseBinding(paramValue)
- // if (!paramBinding) {
- // resolvedParams[paramName] = () => paramValue
- // continue
- // }
-
- // let paramValueSource
-
- // if (paramBinding.source === "context") paramValueSource = context
- // if (paramBinding.source === "state")
- // paramValueSource = getCurrentState()
-
- // // The new dynamic event parameter bound to the relevant source
- // resolvedParams[paramName] = () =>
- // getState(paramValueSource, paramBinding.path, paramBinding.fallback)
}
handlerInfo.parameters = resolvedParams
@@ -262,8 +110,6 @@ const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
}
}
- // registerBindings(node, storeBoundProps)
-
const setup = _setup({ handlerTypes, getCurrentState, bb, store })
initialProps._bb = bb(node, setup)
diff --git a/packages/client/tests/workflowOrchestrator.spec.js b/packages/client/tests/workflowOrchestrator.spec.js
deleted file mode 100644
index 4858e9f51b..0000000000
--- a/packages/client/tests/workflowOrchestrator.spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-const TEST_WORKFLOW = {
- "_id": "8ebe79daf1c744c7ab204c0b964e309e",
- "_rev": "37-94ae573300721c98267cc1d18822c94d",
- "name": "Workflow",
- "type": "workflow",
- "definition": {
- "next": {
- "type": "CLIENT",
- "actionId": "SET_STATE",
- "args": {
- "path": "myPath",
- "value": "foo"
- },
- "next": {
- "type": "SERVER",
- "actionId": "SAVE_RECORD",
- "args": {
- "record": {
- "modelId": "f452a2b9c3a94251b9ea7be1e20e3b19",
- "name": "workflowRecord"
- },
- "next": {
- "type": "CLIENT",
- "actionId": "SET_STATE",
- "args": {
- "path": "myPath",
- "value": "$context.SAVE_RECORD.record.name"
- },
- }
- }
- }
- }
- }
-};
-
-describe("Workflow Orchestrator", () => {
- it("executes a workflow", () => {
- });
-
- it("", () => {
-
- });
-});
\ No newline at end of file
diff --git a/packages/server/src/api/controllers/view.js b/packages/server/src/api/controllers/view.js
index 8456837c6a..2f15d41570 100644
--- a/packages/server/src/api/controllers/view.js
+++ b/packages/server/src/api/controllers/view.js
@@ -11,7 +11,8 @@ const controller = {
if (
!name.startsWith("all") &&
name !== "by_type" &&
- name !== "by_username"
+ name !== "by_username" &&
+ name !== "by_workflow_trigger"
) {
response.push({
name,
diff --git a/packages/server/src/api/controllers/workflow/index.js b/packages/server/src/api/controllers/workflow/index.js
index 55173c28cb..4c5394ab2f 100644
--- a/packages/server/src/api/controllers/workflow/index.js
+++ b/packages/server/src/api/controllers/workflow/index.js
@@ -1,5 +1,5 @@
-const CouchDB = require("../../db")
-const newid = require("../../db/newid")
+const CouchDB = require("../../../db")
+const newid = require("../../../db/newid")
exports.create = async function(ctx) {
const db = new CouchDB(ctx.params.instanceId)
@@ -49,7 +49,7 @@ exports.fetch = async function(ctx) {
}
exports.find = async function(ctx) {
- const db = new CouchDB(ctx.params.instanceId)
+ const db = new CouchDB(ctx.user.instanceId)
ctx.body = await db.get(ctx.params.id)
}
@@ -61,7 +61,6 @@ exports.executeAction = async function(ctx) {
exports.fetchActionScript = async function(ctx) {
const workflowAction = require(`./actions/${ctx.action}`)
- console.log(workflowAction)
ctx.body = workflowAction
}
diff --git a/packages/server/src/api/routes/workflow.js b/packages/server/src/api/routes/workflow.js
index b4d8920261..2420e4cb52 100644
--- a/packages/server/src/api/routes/workflow.js
+++ b/packages/server/src/api/routes/workflow.js
@@ -1,13 +1,13 @@
const Router = require("@koa/router")
const controller = require("../controllers/workflow")
const authorized = require("../../middleware/authorized")
-const { BUILDER, EXECUTE_WORKFLOW } = require("../../utilities/accessLevels")
+const { BUILDER } = require("../../utilities/accessLevels")
const router = Router()
router
.get("/api/:instanceId/workflows", authorized(BUILDER), controller.fetch)
- .get("/api/:instanceId/workflows/:id", authorized(BUILDER), controller.find)
+ .get("/api/workflows/:id", authorized(BUILDER), controller.find)
.get(
"/api/:instanceId/workflows/:id/:action",
authorized(BUILDER),
diff --git a/packages/server/src/events/index.js b/packages/server/src/events/index.js
index 93b08bd1d8..019b866f9b 100644
--- a/packages/server/src/events/index.js
+++ b/packages/server/src/events/index.js
@@ -1,6 +1,6 @@
const EventEmitter = require("events").EventEmitter
const CouchDB = require("../db")
-const { Orchestrator, serverStrategy } = require("./workflow");
+const { Orchestrator, serverStrategy } = require("./workflow")
const emitter = new EventEmitter()
@@ -8,7 +8,7 @@ async function executeRelevantWorkflows(event, eventType) {
const db = new CouchDB(event.instanceId)
const workflowsToTrigger = await db.query("database/by_workflow_trigger", {
key: [eventType],
- include_docs: true
+ include_docs: true,
})
const workflows = workflowsToTrigger.rows.map(wf => wf.doc)
@@ -22,12 +22,12 @@ async function executeRelevantWorkflows(event, eventType) {
}
}
-emitter.on("record:save", async function(event) {
- await executeRelevantWorkflows(event, "record:save");
+emitter.on("action", async function(event) {
+ await executeRelevantWorkflows(event, "record:save")
})
emitter.on("record:delete", async function(event) {
- await executeRelevantWorkflows(event, "record:delete");
+ await executeRelevantWorkflows(event, "record:delete")
})
module.exports = emitter
diff --git a/packages/server/src/events/workflow.js b/packages/server/src/events/workflow.js
index f2796d91e2..6368274dff 100644
--- a/packages/server/src/events/workflow.js
+++ b/packages/server/src/events/workflow.js
@@ -37,7 +37,6 @@ exports.serverStrategy = () => ({
},
run: async function(workflow) {
for (let block of workflow.steps) {
- console.log("Executing workflow block", block)
if (block.type === "CLIENT") continue
const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
@@ -48,5 +47,5 @@ exports.serverStrategy = () => ({
[block.id]: response,
}
}
- }
-});
+ },
+})