server side event emitter
This commit is contained in:
parent
65d0161007
commit
dc90e141f5
|
@ -43,6 +43,7 @@
|
||||||
"@nx-js/compiler-util": "^2.0.0",
|
"@nx-js/compiler-util": "^2.0.0",
|
||||||
"codemirror": "^5.51.0",
|
"codemirror": "^5.51.0",
|
||||||
"date-fns": "^1.29.0",
|
"date-fns": "^1.29.0",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
"feather-icons": "^4.21.0",
|
"feather-icons": "^4.21.0",
|
||||||
"flatpickr": "^4.5.7",
|
"flatpickr": "^4.5.7",
|
||||||
"lodash": "^4.17.13",
|
"lodash": "^4.17.13",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import mustache from "mustache"
|
import mustache from "mustache"
|
||||||
// TODO: tidy up import
|
// TODO: tidy up import
|
||||||
import blockDefinitions from "../../../components/workflow/WorkflowPanel/blockDefinitions"
|
import blockDefinitions from "components/workflow/WorkflowPanel/blockDefinitions"
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,10 @@ export default class Workflow {
|
||||||
this.workflow = workflow
|
this.workflow = workflow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
return !this.workflow.definition.next
|
||||||
|
}
|
||||||
|
|
||||||
addBlock(block) {
|
addBlock(block) {
|
||||||
let node = this.workflow.definition
|
let node = this.workflow.definition
|
||||||
while (node.next) node = node.next
|
while (node.next) node = node.next
|
||||||
|
@ -74,6 +78,7 @@ export default class Workflow {
|
||||||
const tagline = definition.tagline || ""
|
const tagline = definition.tagline || ""
|
||||||
const args = block.args || {}
|
const args = block.args || {}
|
||||||
|
|
||||||
|
// all the fields the workflow block needs to render in the UI
|
||||||
tree.push({
|
tree.push({
|
||||||
id: block.id,
|
id: block.id,
|
||||||
type: block.type,
|
type: block.type,
|
||||||
|
@ -81,6 +86,7 @@ export default class Workflow {
|
||||||
args,
|
args,
|
||||||
heading: block.actionId,
|
heading: block.actionId,
|
||||||
body: mustache.render(tagline, args),
|
body: mustache.render(tagline, args),
|
||||||
|
name: definition.name
|
||||||
})
|
})
|
||||||
|
|
||||||
return this.buildUiTree(block.next, tree)
|
return this.buildUiTree(block.next, tree)
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<script>
|
||||||
|
import { store } from "builderStore"
|
||||||
|
import deepmerge from "deepmerge";
|
||||||
|
|
||||||
|
export let value
|
||||||
|
|
||||||
|
let pages = []
|
||||||
|
let components = []
|
||||||
|
let pageName
|
||||||
|
|
||||||
|
let selectedPage
|
||||||
|
let selectedScreen
|
||||||
|
|
||||||
|
$: pages = $store.pages
|
||||||
|
$: selectedPage = pages[pageName]
|
||||||
|
$: screens = selectedPage ? selectedPage._screens : []
|
||||||
|
$: if (selectedPage) {
|
||||||
|
let result = selectedPage
|
||||||
|
for (screen of screens) {
|
||||||
|
result = deepmerge(result, screen)
|
||||||
|
}
|
||||||
|
components = result.props._children
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="uk-margin block-field">
|
||||||
|
<label class="uk-form-label">Page</label>
|
||||||
|
<div class="uk-form-controls">
|
||||||
|
<select class="budibase__input" bind:value={pageName}>
|
||||||
|
{#each Object.keys(pages) as page}
|
||||||
|
<option value={page}>{page}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{#if components.length > 0}
|
||||||
|
<label class="uk-form-label">Component</label>
|
||||||
|
<div class="uk-form-controls">
|
||||||
|
<select class="budibase__input" bind:value>
|
||||||
|
{#each components as component}
|
||||||
|
<option value={component._id}>{component._id}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="uk-margin block-field">
|
||||||
|
<label class="uk-form-label">Page</label>
|
||||||
|
<div class="uk-form-controls">
|
||||||
|
<select class="budibase__input" bind:value>
|
||||||
|
{#each $backendUiStore.models as model}
|
||||||
|
<option value={model}>{model.name}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -79,10 +79,11 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span:not(.selected) {
|
header > span {
|
||||||
color: var(--dark-grey);
|
color: var(--font);
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
<script>
|
<script>
|
||||||
import { backendUiStore, store } from "builderStore"
|
import { backendUiStore, store } from "builderStore"
|
||||||
|
import ComponentSelector from "./ParamInputs/ComponentSelector.svelte";
|
||||||
|
import ModelSelector from "./ParamInputs/ModelSelector.svelte";
|
||||||
|
|
||||||
export let workflowBlock
|
export let workflowBlock
|
||||||
|
|
||||||
let params
|
let params
|
||||||
|
|
||||||
console.log("wfblock", workflowBlock)
|
|
||||||
|
|
||||||
$: workflowParams = workflowBlock.params
|
$: workflowParams = workflowBlock.params
|
||||||
? Object.entries(workflowBlock.params)
|
? Object.entries(workflowBlock.params)
|
||||||
: []
|
: []
|
||||||
$: components = Object.values($store.components).filter(comp => comp.name)
|
|
||||||
// $: workflowArgs = workflowBlock.args ? Object.keys(workflowBlock.args) : []
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label class="uk-form-label">
|
<label class="uk-form-label">
|
||||||
{workflowBlock.type}: {workflowBlock.actionId}
|
{workflowBlock.type}: {workflowBlock.name}
|
||||||
</label>
|
</label>
|
||||||
{#each workflowParams as [parameter, type]}
|
{#each workflowParams as [parameter, type]}
|
||||||
<div class="uk-margin block-field">
|
<div class="uk-margin block-field">
|
||||||
|
@ -29,6 +27,8 @@
|
||||||
<option value={option}>{option}</option>
|
<option value={option}>{option}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
{:else if type === 'component'}
|
||||||
|
<ComponentSelector bind:value={workflowBlock.args[parameter]} />
|
||||||
{:else if type === 'accessLevel'}
|
{:else if type === 'accessLevel'}
|
||||||
<select
|
<select
|
||||||
class="budibase__input"
|
class="budibase__input"
|
||||||
|
@ -52,19 +52,7 @@
|
||||||
class="budibase__input"
|
class="budibase__input"
|
||||||
bind:value={workflowBlock.args[parameter]} />
|
bind:value={workflowBlock.args[parameter]} />
|
||||||
{:else if type === 'model'}
|
{:else if type === 'model'}
|
||||||
<select
|
<ModelSelector bind:value={workflowBlock.args[parameter]} />
|
||||||
class="budibase__input"
|
|
||||||
bind:value={workflowBlock.args[parameter]}>
|
|
||||||
{#each $backendUiStore.models as model}
|
|
||||||
<option value={model._id}>{model.name}</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
{:else if type === 'component'}
|
|
||||||
<select class="budibase__input">
|
|
||||||
{#each components as component}
|
|
||||||
<option value={component.id}>{component.name}</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
{:else if type === 'string'}
|
{:else if type === 'string'}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -87,4 +75,8 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,42 +1,45 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore, workflowStore } from "builderStore"
|
||||||
import { WorkflowList } from "../"
|
import { WorkflowList } from "../"
|
||||||
import WorkflowBlock from "./WorkflowBlock.svelte"
|
import WorkflowBlock from "./WorkflowBlock.svelte"
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
import blockDefinitions from "../blockDefinitions"
|
import blockDefinitions from "../blockDefinitions"
|
||||||
|
|
||||||
const SUB_TABS = [
|
|
||||||
{
|
|
||||||
name: "Triggers",
|
|
||||||
key: "TRIGGER",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Actions",
|
|
||||||
key: "ACTION",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Logic",
|
|
||||||
key: "LOGIC",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
let selectedTab = "TRIGGER"
|
let selectedTab = "TRIGGER"
|
||||||
let definitions = []
|
let definitions = []
|
||||||
|
|
||||||
$: definitions = Object.entries(blockDefinitions[selectedTab])
|
$: definitions = Object.entries(blockDefinitions[selectedTab])
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (!$workflowStore.currentWorkflow.isEmpty() && selectedTab === "TRIGGER") {
|
||||||
|
selectedTab = "ACTION"
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="subtabs">
|
<div class="subtabs">
|
||||||
{#each SUB_TABS as tab}
|
{#if $workflowStore.currentWorkflow.isEmpty()}
|
||||||
<span
|
<span
|
||||||
class="hoverable"
|
class="hoverable"
|
||||||
class:selected={tab.key === selectedTab}
|
class:selected={'TRIGGER' === selectedTab}
|
||||||
on:click={() => (selectedTab = tab.key)}>
|
on:click={() => (selectedTab = 'TRIGGER')}>
|
||||||
{tab.name}
|
Triggers
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/if}
|
||||||
|
<span
|
||||||
|
class="hoverable"
|
||||||
|
class:selected={'ACTION' === selectedTab}
|
||||||
|
on:click={() => (selectedTab = 'ACTION')}>
|
||||||
|
Actions
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="hoverable"
|
||||||
|
class:selected={'LOGIC' === selectedTab}
|
||||||
|
on:click={() => (selectedTab = 'LOGIC')}>
|
||||||
|
Logic
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="blocklist">
|
<div id="blocklist">
|
||||||
{#each definitions as [actionId, blockDefinition]}
|
{#each definitions as [actionId, blockDefinition]}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
export let actionId
|
export let actionId
|
||||||
|
|
||||||
function addBlockToWorkflow() {
|
function addBlockToWorkflow() {
|
||||||
// TODO: store the block type in the DB as well
|
|
||||||
workflowStore.actions.addBlockToWorkflow({
|
workflowStore.actions.addBlockToWorkflow({
|
||||||
...blockDefinition,
|
...blockDefinition,
|
||||||
args: {},
|
args: {},
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<span
|
<span
|
||||||
class="hoverable"
|
class="hoverable workflow-header"
|
||||||
class:selected={selectedTab === 'WORKFLOWS'}
|
class:selected={selectedTab === 'WORKFLOWS'}
|
||||||
on:click={() => (selectedTab = 'WORKFLOWS')}>
|
on:click={() => (selectedTab = 'WORKFLOWS')}>
|
||||||
Workflows
|
Workflows
|
||||||
|
@ -37,10 +37,13 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflow-header {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
span:not(.selected) {
|
span:not(.selected) {
|
||||||
color: var(--dark-grey);
|
color: var(--dark-grey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ const ACTION = {
|
||||||
environment: "CLIENT",
|
environment: "CLIENT",
|
||||||
params: {
|
params: {
|
||||||
path: "string",
|
path: "string",
|
||||||
value: "string",
|
value: "longText",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NAVIGATE: {
|
NAVIGATE: {
|
||||||
|
@ -77,8 +77,9 @@ const ACTION = {
|
||||||
const TRIGGER = {
|
const TRIGGER = {
|
||||||
RECORD_SAVED: {
|
RECORD_SAVED: {
|
||||||
name: "Record Saved",
|
name: "Record Saved",
|
||||||
|
event: "record:save",
|
||||||
icon: "ri-save-line",
|
icon: "ri-save-line",
|
||||||
tagline: "Record is added to {{model}}",
|
tagline: "Record is added to <b>{{model.name}}</b>",
|
||||||
description: "Save a record to your database.",
|
description: "Save a record to your database.",
|
||||||
environment: "SERVER",
|
environment: "SERVER",
|
||||||
params: {
|
params: {
|
||||||
|
@ -87,44 +88,45 @@ const TRIGGER = {
|
||||||
},
|
},
|
||||||
RECORD_DELETED: {
|
RECORD_DELETED: {
|
||||||
name: "Record Deleted",
|
name: "Record Deleted",
|
||||||
|
event: "record:delete",
|
||||||
icon: "ri-delete-bin-line",
|
icon: "ri-delete-bin-line",
|
||||||
tagline: "Record is deleted from <b>{{model}}</b>",
|
tagline: "Record is deleted from <b>{{model.name}}</b>",
|
||||||
description: "Fired when a record is deleted from your database.",
|
description: "Fired when a record is deleted from your database.",
|
||||||
environment: "SERVER",
|
environment: "SERVER",
|
||||||
params: {
|
params: {
|
||||||
model: "model"
|
model: "model"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CLICK: {
|
// CLICK: {
|
||||||
name: "Click",
|
// name: "Click",
|
||||||
icon: "ri-cursor-line",
|
// icon: "ri-cursor-line",
|
||||||
tagline: "{{component}} is clicked",
|
// tagline: "{{component}} is clicked",
|
||||||
description: "Trigger when you click on an element in the UI.",
|
// description: "Trigger when you click on an element in the UI.",
|
||||||
environment: "CLIENT",
|
// environment: "CLIENT",
|
||||||
params: {
|
// params: {
|
||||||
component: "component"
|
// component: "component"
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
LOAD: {
|
// LOAD: {
|
||||||
name: "Load",
|
// name: "Load",
|
||||||
icon: "ri-loader-line",
|
// icon: "ri-loader-line",
|
||||||
tagline: "{{component}} is loaded",
|
// tagline: "{{component}} is loaded",
|
||||||
description: "Trigger an element has finished loading.",
|
// description: "Trigger an element has finished loading.",
|
||||||
environment: "CLIENT",
|
// environment: "CLIENT",
|
||||||
params: {
|
// params: {
|
||||||
component: "component"
|
// component: "component"
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
INPUT: {
|
// INPUT: {
|
||||||
name: "Input",
|
// name: "Input",
|
||||||
icon: "ri-text",
|
// icon: "ri-text",
|
||||||
tagline: "Text entered into {{component}",
|
// tagline: "Text entered into {{component}",
|
||||||
description: "Trigger when you type into an input box.",
|
// description: "Trigger when you type into an input box.",
|
||||||
environment: "CLIENT",
|
// environment: "CLIENT",
|
||||||
params: {
|
// params: {
|
||||||
component: "component"
|
// component: "component"
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
}
|
}
|
||||||
|
|
||||||
const LOGIC = {
|
const LOGIC = {
|
||||||
|
@ -135,9 +137,9 @@ const LOGIC = {
|
||||||
description: "Filter any workflows which do not meet certain conditions.",
|
description: "Filter any workflows which do not meet certain conditions.",
|
||||||
environment: "CLIENT",
|
environment: "CLIENT",
|
||||||
params: {
|
params: {
|
||||||
field: "string",
|
filter: "string",
|
||||||
condition: [
|
condition: [
|
||||||
"equals"
|
"equals",
|
||||||
],
|
],
|
||||||
value: "string"
|
value: "string"
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,6 +8,4 @@ export const triggerWorkflow = api => ({ workflow }) => {
|
||||||
workflowOrchestrator.strategy = clientStrategy
|
workflowOrchestrator.strategy = clientStrategy
|
||||||
|
|
||||||
workflowOrchestrator.execute(workflow)
|
workflowOrchestrator.execute(workflow)
|
||||||
|
|
||||||
// hit the API and get the workflow data back
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,10 @@ export default class Orchestrator {
|
||||||
async execute(workflowId) {
|
async execute(workflowId) {
|
||||||
const EXECUTE_WORKFLOW_URL = `/api/${this.instanceId}/workflows/${workflowId}`
|
const EXECUTE_WORKFLOW_URL = `/api/${this.instanceId}/workflows/${workflowId}`
|
||||||
const workflow = await this.api.get({ url: EXECUTE_WORKFLOW_URL })
|
const workflow = await this.api.get({ url: EXECUTE_WORKFLOW_URL })
|
||||||
this._strategy.run(workflow.definition)
|
|
||||||
|
if (workflow.live) {
|
||||||
|
this._strategy.run(workflow.definition)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,17 +83,9 @@ export const clientStrategy = ({ api, instanceId }) => ({
|
||||||
if (block.actionId === "FILTER") {
|
if (block.actionId === "FILTER") {
|
||||||
const { field, condition, value } = block.args;
|
const { field, condition, value } = block.args;
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case "=":
|
case "equals":
|
||||||
if (field !== value) return;
|
if (field !== value) return;
|
||||||
break;
|
break;
|
||||||
case "!=":
|
|
||||||
if (field === value) return;
|
|
||||||
break;
|
|
||||||
case "gt":
|
|
||||||
if (field < value) return;
|
|
||||||
break;
|
|
||||||
case "lt":
|
|
||||||
if (field > value) return;
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,16 @@ exports.create = async function(ctx) {
|
||||||
emit([doc.type], doc._id)
|
emit([doc.type], doc._id)
|
||||||
}.toString(),
|
}.toString(),
|
||||||
},
|
},
|
||||||
|
by_workflow_trigger: {
|
||||||
|
map: function(doc) {
|
||||||
|
if (doc.type === "workflow") {
|
||||||
|
const trigger = doc.definition.next
|
||||||
|
if (trigger) {
|
||||||
|
emit([trigger.event], trigger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toString()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ const newid = require("../../db/newid")
|
||||||
const ajv = new Ajv()
|
const ajv = new Ajv()
|
||||||
|
|
||||||
exports.save = async function(ctx) {
|
exports.save = async function(ctx) {
|
||||||
console.log("THIS INSTANCE", ctx.params.instanceId)
|
|
||||||
const db = new CouchDB(ctx.params.instanceId)
|
const db = new CouchDB(ctx.params.instanceId)
|
||||||
const record = ctx.request.body
|
const record = ctx.request.body
|
||||||
record.modelId = ctx.params.modelId
|
record.modelId = ctx.params.modelId
|
||||||
|
@ -45,7 +44,11 @@ exports.save = async function(ctx) {
|
||||||
record.type = "record"
|
record.type = "record"
|
||||||
const response = await db.post(record)
|
const response = await db.post(record)
|
||||||
record._rev = response.rev
|
record._rev = response.rev
|
||||||
// ctx.eventPublisher.emit("RECORD_CREATED", record)
|
|
||||||
|
ctx.eventEmitter.emit(`record:save`, {
|
||||||
|
record,
|
||||||
|
instanceId: ctx.params.instanceId
|
||||||
|
})
|
||||||
ctx.body = record
|
ctx.body = record
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.message = `${model.name} created successfully`
|
ctx.message = `${model.name} created successfully`
|
||||||
|
@ -85,4 +88,5 @@ exports.destroy = async function(ctx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.body = await db.remove(ctx.params.recordId, ctx.params.revId)
|
ctx.body = await db.remove(ctx.params.recordId, ctx.params.revId)
|
||||||
|
ctx.eventEmitter.emit(`record:delete`, record)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,24 +10,6 @@ exports.create = async function(ctx) {
|
||||||
|
|
||||||
workflow._id = newid()
|
workflow._id = newid()
|
||||||
|
|
||||||
// TODO: Possibly validate the workflow against a schema
|
|
||||||
|
|
||||||
// // validation with ajv
|
|
||||||
// const model = await db.get(record.modelId)
|
|
||||||
// const validate = ajv.compile({
|
|
||||||
// properties: model.schema,
|
|
||||||
// })
|
|
||||||
// const valid = validate(record)
|
|
||||||
|
|
||||||
// if (!valid) {
|
|
||||||
// ctx.status = 400
|
|
||||||
// ctx.body = {
|
|
||||||
// status: 400,
|
|
||||||
// errors: validate.errors,
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
workflow.type = "workflow"
|
workflow.type = "workflow"
|
||||||
const response = await db.post(workflow)
|
const response = await db.post(workflow)
|
||||||
workflow._rev = response.rev
|
workflow._rev = response.rev
|
||||||
|
|
|
@ -4,7 +4,7 @@ const logger = require("koa-pino-logger")
|
||||||
const http = require("http")
|
const http = require("http")
|
||||||
const api = require("./api")
|
const api = require("./api")
|
||||||
const env = require("./environment")
|
const env = require("./environment")
|
||||||
const eventPublisher = require("./events")
|
const eventEmitter = require("./events")
|
||||||
|
|
||||||
const app = new Koa()
|
const app = new Koa()
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ app.use(
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
app.context.publisher = eventPublisher
|
app.context.eventEmitter = eventEmitter
|
||||||
|
|
||||||
// api routes
|
// api routes
|
||||||
app.use(api.routes())
|
app.use(api.routes())
|
||||||
|
|
|
@ -1,3 +1,31 @@
|
||||||
const EventEmitter = require("events").EventEmitter
|
const EventEmitter = require("events").EventEmitter
|
||||||
|
const CouchDB = require("../db");
|
||||||
|
|
||||||
module.exports = new EventEmitter()
|
const emitter = new EventEmitter()
|
||||||
|
|
||||||
|
function determineWorkflowsToTrigger(instanceId, event) {
|
||||||
|
const db = new CouchDB(instanceId);
|
||||||
|
const workflowsToTrigger = await db.query("database/by_workflow_trigger", {
|
||||||
|
key: [event]
|
||||||
|
})
|
||||||
|
|
||||||
|
return workflowsToTrigger.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.on("record:save", async function(event) {
|
||||||
|
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")
|
||||||
|
|
||||||
|
for (let workflow of workflowsToTrigger) {
|
||||||
|
// SERVER SIDE STUFF!!
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = emitter
|
||||||
|
|
|
@ -17,18 +17,19 @@ const WORKFLOW_SCHEMA = {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
triggers: { type: "array" },
|
triggers: { type: "array" },
|
||||||
next: {
|
steps: { type: "array" }
|
||||||
type: "object",
|
// next: {
|
||||||
properties: {
|
// type: "object",
|
||||||
environment: { environment: "string" },
|
// properties: {
|
||||||
type: { type: "string" },
|
// environment: { environment: "string" },
|
||||||
actionId: { type: "string" },
|
// type: { type: "string" },
|
||||||
args: { type: "object" },
|
// actionId: { type: "string" },
|
||||||
conditions: { type: "array" },
|
// args: { type: "object" },
|
||||||
errorHandling: { type: "object" },
|
// conditions: { type: "array" },
|
||||||
next: { type: "object" },
|
// errorHandling: { type: "object" },
|
||||||
},
|
// next: { type: "object" },
|
||||||
},
|
// },
|
||||||
|
// },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue