Browse Source

move workflow to array data structure

pull/279/head
Martin McKeaveney 6 years ago
parent
commit
a220822e3a
  1. 2
      packages/builder/rollup.config.js
  2. 3
      packages/builder/src/App.svelte
  3. 143
      packages/builder/src/builderStore/store/workflow/Workflow.js
  4. 3
      packages/builder/src/builderStore/store/workflow/index.js
  5. 2
      packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte
  6. 6
      packages/builder/src/components/userInterface/EventsEditor/StateBindingCascader.svelte
  7. 2
      packages/builder/src/components/workflow/SetupPanel/DeleteWorkflowModal.svelte
  8. 2
      packages/builder/src/components/workflow/SetupPanel/ParamInputs/ComponentSelector.svelte
  9. 1
      packages/builder/src/components/workflow/SetupPanel/ParamInputs/ModelSelector.svelte
  10. 8
      packages/builder/src/components/workflow/SetupPanel/WorkflowBlockSetup.svelte
  11. 2
      packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/FlowChart.svelte
  12. 5
      packages/builder/src/components/workflow/WorkflowPanel/BlockList/BlockList.svelte
  13. 2
      packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/CreateWorkflowModal.svelte
  14. 9
      packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/WorkflowList.svelte
  15. 8
      packages/builder/src/components/workflow/WorkflowPanel/blockDefinitions.js
  16. 6
      packages/builder/src/components/workflow/index.js
  17. 29
      packages/client/src/api/workflow/actions.js
  18. 2
      packages/client/src/api/workflow/index.js
  19. 97
      packages/client/src/api/workflow/orchestrator.js
  20. 4
      packages/client/src/createApp.js
  21. 2
      packages/client/src/index.js
  22. 2
      packages/client/src/render/attachChildren.js
  23. 16
      packages/client/src/render/prepareRenderComponent.js
  24. 6
      packages/client/src/render/screenRouter.js
  25. 2
      packages/client/src/state/bbComponentApi.js
  26. 6
      packages/client/src/state/eventHandlers.js
  27. 10
      packages/client/src/state/getState.js
  28. 6
      packages/client/src/state/setState.js
  29. 56
      packages/client/src/state/stateManager.js
  30. 19
      packages/client/src/state/store.js
  31. 2
      packages/client/tests/testAppDef.js
  32. 4
      packages/server/src/api/controllers/instance.js
  33. 2
      packages/server/src/api/controllers/record.js
  34. 8
      packages/server/src/api/controllers/workflow/actions/CREATE_USER.js
  35. 22
      packages/server/src/events/index.js
  36. 2
      packages/server/src/schemas/index.js

2
packages/builder/rollup.config.js

@ -152,7 +152,7 @@ export default {
{
find: "builderStore",
replacement: path.resolve(projectRootDir, "src/builderStore"),
}
},
],
customResolver,
}),

3
packages/builder/src/App.svelte

@ -7,8 +7,7 @@
import AppNotification, {
showAppNotification,
} from "components/common/AppNotification.svelte"
import { NotificationDisplay } from '@beyonk/svelte-notifications'
import { NotificationDisplay } from "@beyonk/svelte-notifications"
function showErrorBanner() {
showAppNotification({

143
packages/builder/src/builderStore/store/workflow/Workflow.js

@ -13,82 +13,109 @@ export default class Workflow {
}
isEmpty() {
return !this.workflow.definition.next
// return this.workflow.definition.next
return this.workflow.length > 0
}
addBlock(block) {
let node = this.workflow.definition
while (node.next) node = node.next
node.next = {
// Make sure to add trigger if doesn't exist
this.workflow.definition.steps.push({
id: generate(),
...block
}
...block,
})
}
updateBlock(updatedBlock, id) {
let block = this.workflow.definition
const { steps, trigger } = this.workflow.definition
// if the block is a trigger do X
while (block.id !== id) block = block.next
if (!block) throw new Error("Block not found.")
// if step
const stepIdx = steps.findIndex(step => step.id === id)
block = updatedBlock
// while (block.id !== id) block = block.next
if (stepIdx < 0) throw new Error("Block not found.")
steps.splice(stepIdx, 1, updatedBlock)
}
deleteBlock(id) {
let previous = null
let block = this.workflow.definition
// iterate through the blocks
while (block.id !== id) {
previous = block
block = block.next
}
// delete the block matching your id
if (!block.next) {
delete previous.next
} else {
previous.next = block.next
}
const { steps, trigger } = this.workflow.definition
const stepIdx = steps.findIndex(step => step.id === id)
if (stepIdx < 0) throw new Error("Block not found.")
steps.splice(stepIdx, 1)
}
createUiTree() {
if (!this.workflow.definition.next) return []
return Workflow.buildUiTree(this.workflow.definition.next)
if (!this.workflow.definition) return []
return Workflow.buildUiTree(this.workflow.definition)
}
static buildUiTree(block, tree = []) {
if (!block) return tree
// The client side display definition for the block
const definition = blockDefinitions[block.type][block.actionId]
if (!definition) {
throw new Error(
`No block definition exists for the chosen block. Check there's an entry in the block definitions for ${block.actionId}`
)
}
if (!definition.params) {
throw new Error(
`Blocks should always have parameters. Ensure that the block definition is correct for ${block.actionId}`
)
}
const tagline = definition.tagline || ""
const args = block.args || {}
// all the fields the workflow block needs to render in the UI
tree.push({
id: block.id,
type: block.type,
params: block.params,
args,
heading: block.actionId,
body: mustache.render(tagline, args),
name: definition.name
static buildUiTree(definition) {
return definition.steps.map(step => {
// The client side display definition for the block
const definition = blockDefinitions[step.type][step.actionId]
if (!definition) {
throw new Error(
`No block definition exists for the chosen block. Check there's an entry in the block definitions for ${step.actionId}`
)
}
if (!definition.params) {
throw new Error(
`Blocks should always have parameters. Ensure that the block definition is correct for ${step.actionId}`
)
}
const tagline = definition.tagline || ""
const args = step.args || {}
return {
id: step.id,
type: step.type,
params: step.params,
args,
heading: step.actionId,
body: mustache.render(tagline, args),
name: definition.name,
}
})
return this.buildUiTree(block.next, tree)
}
// static buildUiTree(block, tree = []) {
// if (!block) return tree
// // The client side display definition for the block
// const definition = blockDefinitions[block.type][block.actionId]
// if (!definition) {
// throw new Error(
// `No block definition exists for the chosen block. Check there's an entry in the block definitions for ${block.actionId}`
// )
// }
// if (!definition.params) {
// throw new Error(
// `Blocks should always have parameters. Ensure that the block definition is correct for ${block.actionId}`
// )
// }
// const tagline = definition.tagline || ""
// const args = block.args || {}
// // all the fields the workflow block needs to render in the UI
// tree.push({
// id: block.id,
// type: block.type,
// params: block.params,
// args,
// heading: block.actionId,
// body: mustache.render(tagline, args),
// name: definition.name
// })
// return this.buildUiTree(block.next, tree)
// }
}

3
packages/builder/src/builderStore/store/workflow/index.js

@ -13,7 +13,8 @@ const workflowActions = store => ({
})
},
create: async ({ instanceId, name }) => {
const workflow = { name, definition: {} }
// TODO: set these defaults in the backend
const workflow = { name, definition: { trigger: {}, steps: [] } }
const CREATE_WORKFLOW_URL = `/api/${instanceId}/workflows`
const response = await api.post(CREATE_WORKFLOW_URL, workflow)
const json = await response.json()

2
packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte

@ -116,7 +116,7 @@
stylesheetLinks,
selectedComponentType,
selectedComponentId,
frontendDefinition: JSON.stringify(frontendDefinition)
frontendDefinition: JSON.stringify(frontendDefinition),
})} />
{/if}
</div>

6
packages/builder/src/components/userInterface/EventsEditor/StateBindingCascader.svelte

@ -17,14 +17,16 @@
export let onChange
let isOpen = false
</script>
<div class="handler-option">
<span>{parameter.name}</span>
<div class="handler-input">
{#if parameter.name === 'workflow'}
<select class="budibase__input" on:change={onChange} bind:value={parameter.value}>
<select
class="budibase__input"
on:change={onChange}
bind:value={parameter.value}>
{#each $workflowStore.workflows as workflow}
<option value={workflow._id}>{workflow.name}</option>
{/each}

2
packages/builder/src/components/workflow/SetupPanel/DeleteWorkflowModal.svelte

@ -1,6 +1,6 @@
<script>
import { store, backendUiStore, workflowStore } from "builderStore"
import { notifier } from '@beyonk/svelte-notifications'
import { notifier } from "@beyonk/svelte-notifications"
import api from "builderStore/api"
import ActionButton from "components/common/ActionButton.svelte"

2
packages/builder/src/components/workflow/SetupPanel/ParamInputs/ComponentSelector.svelte

@ -1,6 +1,6 @@
<script>
import { store } from "builderStore"
import deepmerge from "deepmerge";
import deepmerge from "deepmerge"
export let value

1
packages/builder/src/components/workflow/SetupPanel/ParamInputs/ModelSelector.svelte

@ -1,4 +1,3 @@
<script>
import { backendUiStore } from "builderStore"

8
packages/builder/src/components/workflow/SetupPanel/WorkflowBlockSetup.svelte

@ -1,7 +1,7 @@
<script>
import { backendUiStore, store } from "builderStore"
import ComponentSelector from "./ParamInputs/ComponentSelector.svelte";
import ModelSelector from "./ParamInputs/ModelSelector.svelte";
import ComponentSelector from "./ParamInputs/ComponentSelector.svelte"
import ModelSelector from "./ParamInputs/ModelSelector.svelte"
export let workflowBlock
@ -12,9 +12,7 @@
: []
</script>
<label class="uk-form-label">
{workflowBlock.type}: {workflowBlock.name}
</label>
<label class="uk-form-label">{workflowBlock.type}: {workflowBlock.name}</label>
{#each workflowParams as [parameter, type]}
<div class="uk-margin block-field">
<label class="uk-form-label">{parameter}</label>

2
packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/FlowChart.svelte

@ -1,6 +1,6 @@
<script>
import FlowItem from "./FlowItem.svelte"
import Arrow from "./Arrow.svelte";
import Arrow from "./Arrow.svelte"
export let blocks = []
export let onSelect

5
packages/builder/src/components/workflow/WorkflowPanel/BlockList/BlockList.svelte

@ -12,7 +12,10 @@
$: definitions = Object.entries(blockDefinitions[selectedTab])
$: {
if (!$workflowStore.currentWorkflow.isEmpty() && selectedTab === "TRIGGER") {
if (
!$workflowStore.currentWorkflow.isEmpty() &&
selectedTab === "TRIGGER"
) {
selectedTab = "ACTION"
}
}

2
packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/CreateWorkflowModal.svelte

@ -1,6 +1,6 @@
<script>
import { store, backendUiStore, workflowStore } from "builderStore"
import { notifier } from '@beyonk/svelte-notifications'
import { notifier } from "@beyonk/svelte-notifications"
import api from "builderStore/api"
import ActionButton from "components/common/ActionButton.svelte"

9
packages/builder/src/components/workflow/WorkflowPanel/WorkflowList/WorkflowList.svelte

@ -1,6 +1,6 @@
<script>
import Modal from "svelte-simple-modal"
import { notifier } from "@beyonk/svelte-notifications";
import { notifier } from "@beyonk/svelte-notifications"
import { onMount, getContext } from "svelte"
import { backendUiStore, workflowStore } from "builderStore"
import api from "builderStore/api"
@ -9,7 +9,8 @@
const { open, close } = getContext("simple-modal")
$: currentWorkflowId =
$workflowStore.currentWorkflow && $workflowStore.currentWorkflow.workflow._id
$workflowStore.currentWorkflow &&
$workflowStore.currentWorkflow.workflow._id
function newWorkflow() {
open(
@ -30,9 +31,9 @@
// TODO: Clean up args
await workflowStore.actions.save({
instanceId: $backendUiStore.selectedDatabase._id,
workflow
workflow,
})
notifier.success(`Workflow ${workflow.name} saved.`);
notifier.success(`Workflow ${workflow.name} saved.`)
}
</script>

8
packages/builder/src/components/workflow/WorkflowPanel/blockDefinitions.js

@ -94,7 +94,7 @@ const TRIGGER = {
description: "Fired when a record is deleted from your database.",
environment: "SERVER",
params: {
model: "model"
model: "model",
},
},
// CLICK: {
@ -138,10 +138,8 @@ const LOGIC = {
environment: "CLIENT",
params: {
filter: "string",
condition: [
"equals",
],
value: "string"
condition: ["equals"],
value: "string",
},
},
DELAY: {

6
packages/builder/src/components/workflow/index.js

@ -1,3 +1,3 @@
export { default as WorkflowBuilder } from "./WorkflowBuilder/WorkflowBuilder.svelte";
export { default as SetupPanel } from "./SetupPanel/SetupPanel.svelte";
export { default as WorkflowPanel } from "./WorkflowPanel/WorkflowPanel.svelte";
export { default as WorkflowBuilder } from "./WorkflowBuilder/WorkflowBuilder.svelte"
export { default as SetupPanel } from "./SetupPanel/SetupPanel.svelte"
export { default as WorkflowPanel } from "./WorkflowPanel/WorkflowPanel.svelte"

29
packages/client/src/api/workflow/actions.js

@ -0,0 +1,29 @@
import { get } from "svelte/store"
import { setState } from "../../state/setState"
import { appStore } from "../../state/store"
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
export default {
SET_STATE: ({ context, args, id }) => {
// get props from the workflow context if required
setState(...Object.values(args))
// update the context with the data
context = {
...context,
[id]: args,
}
},
NAVIGATE: ({ context, args, id }) => {},
DELAY: async ({ context, args }) => await delay(args.time),
FILTER: (context, args) => {
const { field, condition, value } = args
switch (condition) {
case "equals":
if (field !== value) return
break
default:
return
}
},
}

2
packages/client/src/api/workflow/index.js

@ -3,7 +3,7 @@ import Orchestrator, { clientStrategy } from "./orchestrator"
export const triggerWorkflow = api => ({ workflow }) => {
const workflowOrchestrator = new Orchestrator(
api,
"inst_60dd510_700f7dc06735403e81d5af91072d7241"
"inst_ad75c7f_4f3e7d5d80a74b17a5187a18e2aba85e"
)
workflowOrchestrator.strategy = clientStrategy

97
packages/client/src/api/workflow/orchestrator.js

@ -1,7 +1,7 @@
import { get } from "svelte/store";
import { setState } from "../../state/setState";
import mustache from "mustache";
import { appStore } from "../../state/store";
import { get } from "svelte/store"
import mustache from "mustache"
import { appStore } from "../../state/store"
import clientActions from "./actions"
/**
* The workflow orchestrator is a class responsible for executing workflows.
@ -17,7 +17,7 @@ export default class Orchestrator {
}
set strategy(strategy) {
this._strategy = strategy({ api: this.api, instanceId: this.instanceId });
this._strategy = strategy({ api: this.api, instanceId: this.instanceId })
}
async execute(workflowId) {
@ -32,85 +32,58 @@ export default class Orchestrator {
// Execute a workflow from a running budibase app
export const clientStrategy = ({ api, instanceId }) => ({
delay: ms => new Promise(resolve => setTimeout(resolve, ms)),
context: {},
bindContextArgs: function(args) {
const mappedArgs = { ...args }
console.log("original args", 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
// Means that it's bound to state or workflow context
console.log(argValue, get(appStore));
mappedArgs[arg] = mustache.render(argValue, {
context: this.context,
state: get(appStore)
});
state: get(appStore),
})
}
console.log(mappedArgs)
return mappedArgs
},
run: async function(workflow) {
const block = workflow.next
console.log("Executing workflow block", block)
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]
await action({
context: this.context,
args: this.bindContextArgs(block.args),
id: block.id,
})
}
if (!block) return
// this workflow block gets executed on the server
if (block.environment === "SERVER") {
const EXECUTE_WORKFLOW_URL = `/api/${instanceId}/workflows/action`
const response = await api.post({
url: EXECUTE_WORKFLOW_URL,
body: {
action: block.actionId,
args: this.bindContextArgs(block.args, api),
},
})
// This code gets run in the browser
if (block.environment === "CLIENT") {
if (block.actionId === "SET_STATE") {
// get props from the workflow context if required
setState(...Object.values(this.bindContextArgs(block.args)))
// update the context with the data
this.context = {
...this.context,
SET_STATE: block.args,
}
}
if (block.actionId === "NAVIGATE") {
}
if (block.actionId === "DELAY") {
await this.delay(block.args.time)
}
if (block.actionId === "FILTER") {
const { field, condition, value } = block.args;
switch (condition) {
case "equals":
if (field !== value) return;
break;
default:
return;
[block.actionId]: response,
}
}
}
// this workflow block gets executed on the server
if (block.environment === "SERVER") {
const EXECUTE_WORKFLOW_URL = `/api/${instanceId}/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,
}
console.log("workflowContext", this.context)
}
console.log("workflowContext", this.context)
await this.run(workflow.next)
},
})

4
packages/client/src/createApp.js

@ -8,7 +8,7 @@ export const createApp = ({
componentLibraries,
frontendDefinition,
user,
window
window,
}) => {
let routeTo
let currentUrl
@ -38,7 +38,7 @@ export const createApp = ({
routeTo = screenRouter({
screens: frontendDefinition.screens,
onScreenSelected,
appRootPath: frontendDefinition.appRootPath
appRootPath: frontendDefinition.appRootPath,
})
const fallbackPath = window.location.pathname.replace(
frontendDefinition.appRootPath,

2
packages/client/src/index.js

@ -39,7 +39,7 @@ export const loadBudibase = async opts => {
componentLibraries: componentLibraryModules,
frontendDefinition,
user,
window
window,
})
const route = _window.location

2
packages/client/src/render/attachChildren.js

@ -42,7 +42,7 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
parentNode: treeNode,
ComponentConstructor,
htmlElement,
anchor
anchor,
})
for (let childNode of childNodesThisIteration) {

16
packages/client/src/render/prepareRenderComponent.js

@ -1,12 +1,12 @@
import { appStore } from "../state/store"
import mustache from "mustache";
import mustache from "mustache"
export const prepareRenderComponent = ({
ComponentConstructor,
htmlElement,
anchor,
props,
parentNode
parentNode,
}) => {
const parentContext = (parentNode && parentNode.context) || {}
@ -42,14 +42,16 @@ export const prepareRenderComponent = ({
// make this node listen to the store
if (thisNode.stateBound) {
const unsubscribe = appStore.subscribe(state => {
const storeBoundProps = { ...initialProps._bb.props };
const storeBoundProps = { ...initialProps._bb.props }
for (let prop in storeBoundProps) {
if (typeof storeBoundProps[prop] === "string") {
storeBoundProps[prop] = mustache.render(storeBoundProps[prop], { state });
storeBoundProps[prop] = mustache.render(storeBoundProps[prop], {
state,
})
}
}
thisNode.component.$set(storeBoundProps);
});
}
thisNode.component.$set(storeBoundProps)
})
thisNode.unsubscribe = unsubscribe
}
}

6
packages/client/src/render/screenRouter.js

@ -1,5 +1,5 @@
import regexparam from "regexparam"
import { routerStore } from "../state/store";
import { routerStore } from "../state/store"
import { initRouteStore } from "../state/store"
// TODO: refactor
@ -43,8 +43,8 @@ export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => {
}
routerStore.update(state => {
state["##routeParams"] = params;
return state;
state["##routeParams"] = params
return state
})
const screenIndex = current !== -1 ? current : fallback

2
packages/client/src/state/bbComponentApi.js

@ -51,7 +51,7 @@ export const bbFactory = ({
componentLibraries,
treeNode,
onScreenSlotRendered,
setupState
setupState,
}
return {

6
packages/client/src/state/eventHandlers.js

@ -1,7 +1,7 @@
import { setState } from "./setState"
import { getState } from "./getState"
import { isArray, isUndefined } from "lodash/fp"
import { appStore } from "./store";
import { appStore } from "./store"
import { createApi } from "../api"
@ -21,7 +21,7 @@ export const eventHandlers = (store, rootPath, routeTo) => {
const api = createApi({
rootPath,
setState,
getState: (path, fallback) => getState(path, fallback)
getState: (path, fallback) => getState(path, fallback),
})
const setStateHandler = ({ path, value }) => setState(path, value)
@ -29,7 +29,7 @@ export const eventHandlers = (store, rootPath, routeTo) => {
return {
"Set State": handler(["path", "value"], setStateHandler),
"Navigate To": handler(["url"], param => routeTo(param && param.url)),
"Trigger Workflow": handler(["workflow"], api.triggerWorkflow)
"Trigger Workflow": handler(["workflow"], api.triggerWorkflow),
}
}

10
packages/client/src/state/getState.js

@ -1,10 +1,10 @@
// import { isUndefined, isObject } from "lodash/fp"
import { get } from "svelte/store";
import getOr from "lodash/fp/getOr";
import { appStore } from "./store";
import { get } from "svelte/store"
import getOr from "lodash/fp/getOr"
import { appStore } from "./store"
export const getState = (path, fallback) => {
if (!path || path.length === 0) return fallback
return getOr(fallback, path, get(appStore));
}
return getOr(fallback, path, get(appStore))
}

6
packages/client/src/state/setState.js

@ -1,11 +1,11 @@
import set from "lodash/fp/set";
import { appStore } from "./store";
import set from "lodash/fp/set"
import { appStore } from "./store"
export const setState = (path, value) => {
if (!path || path.length === 0) return
appStore.update(state => {
state = set(path, value, state);
state = set(path, value, state)
return state
})
}

56
packages/client/src/state/stateManager.js

@ -5,8 +5,8 @@ import {
} from "./eventHandlers"
import { bbFactory } from "./bbComponentApi"
import mustache from "mustache"
import { get } from "svelte/store";
import { appStore } from "./store";
import { get } from "svelte/store"
import { appStore } from "./store"
const doNothing = () => {}
doNothing.isPlaceholder = true
@ -55,9 +55,9 @@ export const createStateManager = ({
// TODO: remove
const unsubscribe = appStore.subscribe(state => {
console.log("store updated", state);
return state;
});
console.log("store updated", state)
return state
})
// const unsubscribe = store.subscribe(
// onStoreStateUpdated({
@ -84,20 +84,18 @@ const onStoreStateUpdated = ({
getCurrentState,
componentLibraries,
onScreenSlotRendered,
setupState
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 })
// 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]
@ -161,19 +159,14 @@ const onStoreStateUpdated = ({
// node.component.$set(newProps)
// }
const _setup = ({
handlerTypes,
getCurrentState,
bb,
store
}) => node => {
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("node", node);
// console.log("nodeComponent", node.component);
@ -185,12 +178,12 @@ const _setup = ({
// const binding = parseBinding(propValue)
// TODO: better binding stuff
const isBound = typeof propValue === "string" && propValue.startsWith("{{");
const isBound = typeof propValue === "string" && propValue.startsWith("{{")
if (isBound) {
initialProps[propName] = mustache.render(propValue, {
state: currentStoreState,
context
context,
})
if (!node.stateBound) {
@ -230,10 +223,11 @@ const _setup = ({
const resolvedParams = {}
for (let paramName in handlerInfo.parameters) {
const paramValue = handlerInfo.parameters[paramName]
resolvedParams[paramName] = () => mustache.render(paramValue, {
state: getCurrentState(),
context,
})
resolvedParams[paramName] = () =>
mustache.render(paramValue, {
state: getCurrentState(),
context,
})
// const paramBinding = parseBinding(paramValue)
// if (!paramBinding) {
// resolvedParams[paramName] = () => paramValue

19
packages/client/src/state/store.js

@ -1,16 +1,9 @@
import { writable } from "svelte/store";
import { writable } from "svelte/store"
const appStore = writable({});
appStore.actions = {
const appStore = writable({})
appStore.actions = {}
};
const routerStore = writable({})
routerStore.actions = {}
const routerStore = writable({});
routerStore.actions = {
}
export {
appStore,
routerStore
}
export { appStore, routerStore }

2
packages/client/tests/testAppDef.js

@ -182,4 +182,4 @@ const maketestlib = window => ({
set(opts.props)
opts.target.appendChild(node)
},
})
})

4
packages/server/src/api/controllers/instance.js

@ -37,8 +37,8 @@ exports.create = async function(ctx) {
emit([trigger.event], trigger)
}
}
}.toString()
}
}.toString(),
},
},
})

2
packages/server/src/api/controllers/record.js

@ -47,7 +47,7 @@ exports.save = async function(ctx) {
ctx.eventEmitter.emit(`record:save`, {
record,
instanceId: ctx.params.instanceId
instanceId: ctx.params.instanceId,
})
ctx.body = record
ctx.status = 200

8
packages/server/src/api/controllers/workflow/actions/CREATE_USER.js

@ -8,19 +8,19 @@ module.exports = async function createUser(user) {
instanceId: "inst_60dd510_700f7dc06735403e81d5af91072d7241",
},
request: {
body: user
body: user,
},
}
try {
const response = await userController.create(ctx)
return {
user: response
user: response,
}
} catch (err) {
console.error(err);
console.error(err)
return {
user: null
user: null,
}
}
}

22
packages/server/src/events/index.js

@ -1,27 +1,33 @@
const EventEmitter = require("events").EventEmitter
const CouchDB = require("../db");
const CouchDB = require("../db")
const emitter = new EventEmitter()
function determineWorkflowsToTrigger(instanceId, event) {
const db = new CouchDB(instanceId);
async function determineWorkflowsToTrigger(instanceId, event) {
const db = new CouchDB(instanceId)
const workflowsToTrigger = await db.query("database/by_workflow_trigger", {
key: [event]
key: [event],
})
return workflowsToTrigger.rows;
return workflowsToTrigger.rows
}
emitter.on("record:save", async function(event) {
const workflowsToTrigger = await determineWorkflowsToTrigger(instanceId, "record:save")
const workflowsToTrigger = await determineWorkflowsToTrigger(
instanceId,
"record:save"
)
for (let workflow of workflowsToTrigger) {
// SERVER SIDE STUFF!!
}
})
emitter.on("record:delete", function(event) {
const workflowsToTrigger = await determineWorkflowsToTrigger(instanceId, "record:delete")
emitter.on("record:delete", async function(event) {
const workflowsToTrigger = await determineWorkflowsToTrigger(
instanceId,
"record:delete"
)
for (let workflow of workflowsToTrigger) {
// SERVER SIDE STUFF!!

2
packages/server/src/schemas/index.js

@ -17,7 +17,7 @@ const WORKFLOW_SCHEMA = {
type: "object",
properties: {
triggers: { type: "array" },
steps: { type: "array" }
steps: { type: "array" },
// next: {
// type: "object",
// properties: {

Loading…
Cancel
Save