tidy up
This commit is contained in:
parent
398f200661
commit
aeae4f50e2
|
@ -54,7 +54,6 @@
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"shortid": "^2.2.8",
|
"shortid": "^2.2.8",
|
||||||
"string_decoder": "^1.2.0",
|
"string_decoder": "^1.2.0",
|
||||||
"svelte-grid": "^1.10.8",
|
|
||||||
"svelte-simple-modal": "^0.3.0",
|
"svelte-simple-modal": "^0.3.0",
|
||||||
"uikit": "^3.1.7"
|
"uikit": "^3.1.7"
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,9 +17,9 @@ export default class Workflow {
|
||||||
|
|
||||||
addBlock(block) {
|
addBlock(block) {
|
||||||
// Make sure to add trigger if doesn't exist
|
// Make sure to add trigger if doesn't exist
|
||||||
if (!this.hasTrigger()) {
|
if (!this.hasTrigger() && block.type === "TRIGGER") {
|
||||||
this.workflow.definition.trigger = { id: generate(), ...block }
|
this.workflow.definition.trigger = { id: generate(), ...block }
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workflow.definition.steps.push({
|
this.workflow.definition.steps.push({
|
||||||
|
@ -60,7 +60,10 @@ export default class Workflow {
|
||||||
}
|
}
|
||||||
|
|
||||||
static buildUiTree(definition) {
|
static buildUiTree(definition) {
|
||||||
const steps = definition.steps.map(step => {
|
const steps = []
|
||||||
|
if (definition.trigger) steps.push(definition.trigger)
|
||||||
|
|
||||||
|
return [...steps, ...definition.steps].map(step => {
|
||||||
// The client side display definition for the block
|
// The client side display definition for the block
|
||||||
const definition = blockDefinitions[step.type][step.actionId]
|
const definition = blockDefinitions[step.type][step.actionId]
|
||||||
if (!definition) {
|
if (!definition) {
|
||||||
|
@ -88,9 +91,5 @@ export default class Workflow {
|
||||||
name: definition.name,
|
name: definition.name,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(definition);
|
|
||||||
|
|
||||||
return definition.trigger ? [definition.trigger, ...steps] : steps
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@ const workflowActions = store => ({
|
||||||
const workflow = {
|
const workflow = {
|
||||||
name,
|
name,
|
||||||
definition: {
|
definition: {
|
||||||
steps: []
|
steps: [],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
|
||||||
const CREATE_WORKFLOW_URL = `/api/${instanceId}/workflows`
|
const CREATE_WORKFLOW_URL = `/api/${instanceId}/workflows`
|
||||||
const response = await api.post(CREATE_WORKFLOW_URL, workflow)
|
const response = await api.post(CREATE_WORKFLOW_URL, workflow)
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
// import { isString } from "lodash/fp"
|
|
||||||
|
|
||||||
// import {
|
|
||||||
// BB_STATE_BINDINGPATH,
|
|
||||||
// BB_STATE_FALLBACK,
|
|
||||||
// BB_STATE_BINDINGSOURCE,
|
|
||||||
// isBound,
|
|
||||||
// parseBinding,
|
|
||||||
// } from "@budibase/client/src/state/parseBinding"
|
|
||||||
|
|
||||||
// export const isBinding = isBound
|
|
||||||
|
|
||||||
// export const setBinding = ({ path, fallback, source }, binding = {}) => {
|
|
||||||
// if (isNonEmptyString(path)) binding[BB_STATE_BINDINGPATH] = path
|
|
||||||
// if (isNonEmptyString(fallback)) binding[BB_STATE_FALLBACK] = fallback
|
|
||||||
// binding[BB_STATE_BINDINGSOURCE] = source || "store"
|
|
||||||
// return binding
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export const getBinding = val => {
|
|
||||||
// const binding = parseBinding(val)
|
|
||||||
// return binding
|
|
||||||
// ? binding
|
|
||||||
// : {
|
|
||||||
// path: "",
|
|
||||||
// source: "store",
|
|
||||||
// fallback: "",
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const isNonEmptyString = s => isString(s) && s.length > 0
|
|
|
@ -1,13 +1,8 @@
|
||||||
import { eventHandlers } from "../../../../client/src/state/eventHandlers"
|
import { eventHandlers } from "../../../../client/src/state/eventHandlers"
|
||||||
import { writable } from "svelte/store"
|
|
||||||
export { EVENT_TYPE_MEMBER_NAME } from "../../../../client/src/state/eventHandlers"
|
export { EVENT_TYPE_MEMBER_NAME } from "../../../../client/src/state/eventHandlers"
|
||||||
|
|
||||||
export const allHandlers = user => {
|
export const allHandlers = () => {
|
||||||
const store = writable({
|
const handlersObj = eventHandlers()
|
||||||
_bbuser: user,
|
|
||||||
})
|
|
||||||
|
|
||||||
const handlersObj = eventHandlers(store)
|
|
||||||
|
|
||||||
const handlers = Object.keys(handlersObj).map(name => ({
|
const handlers = Object.keys(handlersObj).map(name => ({
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
<NumberBox label="Max Length" bind:value={constraints.length.maximum} />
|
<NumberBox label="Max Length" bind:value={constraints.length.maximum} />
|
||||||
<ValuesList label="Categories" bind:values={constraints.inclusion} />
|
<ValuesList label="Categories" bind:values={constraints.inclusion} />
|
||||||
{:else if type === 'datetime'}
|
{:else if type === 'datetime'}
|
||||||
<!-- TODO: revisit and fix with JSON schema -->
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
label="Min Value"
|
label="Min Value"
|
||||||
bind:value={constraints.datetime.earliest} />
|
bind:value={constraints.datetime.earliest} />
|
||||||
|
|
|
@ -4,7 +4,6 @@ export default ({
|
||||||
selectedComponentType,
|
selectedComponentType,
|
||||||
selectedComponentId,
|
selectedComponentId,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
currentPageFunctions,
|
|
||||||
}) => `<html>
|
}) => `<html>
|
||||||
<head>
|
<head>
|
||||||
${stylesheetLinks}
|
${stylesheetLinks}
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
import { find, map, keys, reduce, keyBy } from "lodash/fp"
|
import { find, map, keys, reduce, keyBy } from "lodash/fp"
|
||||||
import { pipe } from "components/common/core"
|
import { pipe } from "components/common/core"
|
||||||
import {
|
import {
|
||||||
EVENT_TYPE_MEMBER_NAME,
|
EVENT_TYPE_MEMBER_NAME
|
||||||
allHandlers,
|
|
||||||
} from "components/common/eventHandlers"
|
} from "components/common/eventHandlers"
|
||||||
import { store, workflowStore } from "builderStore"
|
import { store, workflowStore } from "builderStore"
|
||||||
import { ArrowDownIcon } from "components/common/Icons/"
|
import { ArrowDownIcon } from "components/common/Icons/"
|
||||||
|
@ -26,7 +25,7 @@
|
||||||
class="budibase__input"
|
class="budibase__input"
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
bind:value={parameter.value}>
|
bind:value={parameter.value}>
|
||||||
{#each $workflowStore.workflows as workflow}
|
{#each $workflowStore.workflows.filter(wf => wf.live) as workflow}
|
||||||
<option value={workflow._id}>{workflow.name}</option>
|
<option value={workflow._id}>{workflow.name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="uk-margin block-field">
|
<div class="uk-margin block-field">
|
||||||
<label class="uk-form-label">Page</label>
|
|
||||||
<div class="uk-form-controls">
|
<div class="uk-form-controls">
|
||||||
<select class="budibase__input" bind:value>
|
<select class="budibase__input" bind:value>
|
||||||
{#each $backendUiStore.models as model}
|
{#each $backendUiStore.models as model}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
import { onMount, getContext } from "svelte"
|
import { onMount, getContext } from "svelte"
|
||||||
import { backendUiStore, workflowStore } from "builderStore"
|
import { backendUiStore, workflowStore } from "builderStore"
|
||||||
import { notifier } from "@beyonk/svelte-notifications"
|
import { notifier } from "@beyonk/svelte-notifications"
|
||||||
|
@ -8,6 +9,9 @@
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
let selectedTab = "SETUP"
|
||||||
|
let testResult
|
||||||
|
|
||||||
$: workflow =
|
$: workflow =
|
||||||
$workflowStore.currentWorkflow && $workflowStore.currentWorkflow.workflow
|
$workflowStore.currentWorkflow && $workflowStore.currentWorkflow.workflow
|
||||||
$: workflowBlock = $workflowStore.selectedWorkflowBlock
|
$: workflowBlock = $workflowStore.selectedWorkflowBlock
|
||||||
|
@ -26,23 +30,58 @@
|
||||||
workflowStore.actions.deleteWorkflowBlock(workflowBlock)
|
workflowStore.actions.deleteWorkflowBlock(workflowBlock)
|
||||||
notifier.info("Workflow block deleted.")
|
notifier.info("Workflow block deleted.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testWorkflow() {
|
||||||
|
testResult = "PASSED"
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<header>
|
<header>
|
||||||
<span>Setup</span>
|
<span
|
||||||
|
class="hoverable"
|
||||||
|
class:selected={selectedTab === 'SETUP'}
|
||||||
|
on:click={() => {
|
||||||
|
selectedTab = 'SETUP'
|
||||||
|
testResult = null
|
||||||
|
}}>
|
||||||
|
Setup
|
||||||
|
</span>
|
||||||
|
{#if !workflowBlock}
|
||||||
|
<span
|
||||||
|
class="hoverable"
|
||||||
|
class:selected={selectedTab === 'TEST'}
|
||||||
|
on:click={() => (selectedTab = 'TEST')}>
|
||||||
|
Test
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
|
{#if selectedTab === 'TEST'}
|
||||||
|
<div class="uk-margin config-item">
|
||||||
|
{#if testResult}
|
||||||
|
<button
|
||||||
|
transition:fade
|
||||||
|
class:passed={testResult === 'PASSED'}
|
||||||
|
class:failed={testResult === 'FAILED'}
|
||||||
|
class="test-result">
|
||||||
|
{testResult}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
<button class="workflow-button hoverable" on:click={testWorkflow}>
|
||||||
|
Test
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if selectedTab === 'SETUP'}
|
||||||
{#if workflowBlock}
|
{#if workflowBlock}
|
||||||
<WorkflowBlockSetup {workflowBlock} />
|
<WorkflowBlockSetup {workflowBlock} />
|
||||||
<button
|
<button class="workflow-button hoverable" on:click={deleteWorkflowBlock}>
|
||||||
class="delete-workflow-button hoverable"
|
|
||||||
on:click={deleteWorkflowBlock}>
|
|
||||||
Delete Block
|
Delete Block
|
||||||
</button>
|
</button>
|
||||||
{:else if $workflowStore.currentWorkflow}
|
{:else if $workflowStore.currentWorkflow}
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<label class="uk-form-label">Workflow: {workflow.name}</label>
|
<label class="uk-form-label">Workflow: {workflow.name}</label>
|
||||||
<div class="uk-margin">
|
<div class="uk-margin config-item">
|
||||||
<label class="uk-form-label">Name</label>
|
<label class="uk-form-label">Name</label>
|
||||||
<div class="uk-form-controls">
|
<div class="uk-form-controls">
|
||||||
<input
|
<input
|
||||||
|
@ -51,15 +90,27 @@
|
||||||
bind:value={workflow.name} />
|
bind:value={workflow.name} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-margin">
|
<div class="uk-margin config-item">
|
||||||
<label class="uk-form-label">User Access</label>
|
<label class="uk-form-label">User Access</label>
|
||||||
Some User Access Stuff Here
|
<label>
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="radio1" />
|
||||||
|
Admin
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<label>
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="radio1" />
|
||||||
|
Power User
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="delete-workflow-button hoverable" on:click={deleteWorkflow}>
|
<button
|
||||||
|
class="workflow-button hoverable"
|
||||||
|
on:click={deleteWorkflow}>
|
||||||
Delete Workflow
|
Delete Workflow
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -78,21 +129,30 @@
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
header > span {
|
.selected {
|
||||||
color: var(--font);
|
color: var(--font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.config-item {
|
||||||
|
padding: 20px;
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
header > span {
|
||||||
|
color: var(--dark-grey);
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--font);
|
color: var(--font);
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-workflow-button {
|
.workflow-button {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: solid 1px #f2f2f2;
|
border: solid 1px #f2f2f2;
|
||||||
|
@ -102,4 +162,24 @@
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
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);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -76,5 +76,7 @@
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
min-height: 150px;
|
min-height: 150px;
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
async function saveWorkflow() {
|
async function saveWorkflow() {
|
||||||
const workflow = $workflowStore.currentWorkflow.workflow
|
const workflow = $workflowStore.currentWorkflow.workflow
|
||||||
// TODO: Clean up args
|
|
||||||
await workflowStore.actions.save({
|
await workflowStore.actions.save({
|
||||||
instanceId: $backendUiStore.selectedDatabase._id,
|
instanceId: $backendUiStore.selectedDatabase._id,
|
||||||
workflow,
|
workflow,
|
||||||
|
|
|
@ -22,17 +22,19 @@ const ACTION = {
|
||||||
},
|
},
|
||||||
SAVE_RECORD: {
|
SAVE_RECORD: {
|
||||||
name: "Save Record",
|
name: "Save Record",
|
||||||
|
tagline: "Save a <b>{{model.name}}</b> record",
|
||||||
icon: "ri-save-3-fill",
|
icon: "ri-save-3-fill",
|
||||||
description: "Save a record to your database.",
|
description: "Save a record to your database.",
|
||||||
environment: "SERVER",
|
environment: "SERVER",
|
||||||
params: {
|
params: {
|
||||||
model: "string",
|
model: "model",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DELETE_RECORD: {
|
DELETE_RECORD: {
|
||||||
description: "Delete a record from your database.",
|
description: "Delete a record from your database.",
|
||||||
icon: "ri-delete-bin-line",
|
icon: "ri-delete-bin-line",
|
||||||
name: "Delete Record",
|
name: "Delete Record",
|
||||||
|
tagline: "Delete a <b>{{model.name}}</b> record",
|
||||||
environment: "SERVER",
|
environment: "SERVER",
|
||||||
params: {
|
params: {
|
||||||
record: "string",
|
record: "string",
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import { get } from "svelte/store"
|
|
||||||
import { setState } from "../../state/setState"
|
import { setState } from "../../state/setState"
|
||||||
import { appStore } from "../../state/store"
|
|
||||||
|
|
||||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
|
||||||
|
@ -12,11 +10,11 @@ export default {
|
||||||
[id]: args,
|
[id]: args,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NAVIGATE: ({ context, args, id }) => {
|
NAVIGATE: () => {
|
||||||
// TODO client navigation
|
// TODO client navigation
|
||||||
},
|
},
|
||||||
DELAY: async ({ context, args }) => await delay(args.time),
|
DELAY: async ({ args }) => await delay(args.time),
|
||||||
FILTER: ({ context, args }) => {
|
FILTER: ({ args }) => {
|
||||||
const { field, condition, value } = args
|
const { field, condition, value } = args
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case "equals":
|
case "equals":
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import mustache from "mustache"
|
import mustache from "mustache"
|
||||||
import { appStore } from "../../state/store"
|
import { appStore } from "../../state/store"
|
||||||
import Orchestrator from "./orchestrator";
|
import Orchestrator from "./orchestrator"
|
||||||
import clientActions from "./actions"
|
import clientActions from "./actions"
|
||||||
|
|
||||||
// Execute a workflow from a running budibase app
|
// Execute a workflow from a running budibase app
|
||||||
|
@ -28,8 +28,6 @@ export const clientStrategy = ({ api, instanceId }) => ({
|
||||||
},
|
},
|
||||||
run: async function(workflow) {
|
run: async function(workflow) {
|
||||||
for (let block of workflow.steps) {
|
for (let block of workflow.steps) {
|
||||||
console.log("Executing workflow block", block)
|
|
||||||
|
|
||||||
// This code gets run in the browser
|
// This code gets run in the browser
|
||||||
if (block.environment === "CLIENT") {
|
if (block.environment === "CLIENT") {
|
||||||
const action = clientActions[block.actionId]
|
const action = clientActions[block.actionId]
|
||||||
|
@ -60,13 +58,11 @@ export const clientStrategy = ({ api, instanceId }) => ({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const triggerWorkflow = api => async ({ workflow }) => {
|
export const triggerWorkflow = api => async ({ workflow, instanceId }) => {
|
||||||
const instanceId = "inst_ad75c7f_4f3e7d5d80a74b17a5187a18e2aba85e";
|
|
||||||
|
|
||||||
const workflowOrchestrator = new Orchestrator(api, instanceId)
|
const workflowOrchestrator = new Orchestrator(api, instanceId)
|
||||||
workflowOrchestrator.strategy = clientStrategy
|
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 })
|
const workflowDefinition = await api.get({ url: EXECUTE_WORKFLOW_URL })
|
||||||
|
|
||||||
workflowOrchestrator.execute(workflowDefinition)
|
workflowOrchestrator.execute(workflowDefinition)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { writable } from "svelte/store"
|
|
||||||
import { attachChildren } from "./render/attachChildren"
|
import { attachChildren } from "./render/attachChildren"
|
||||||
import { createTreeNode } from "./render/prepareRenderComponent"
|
import { createTreeNode } from "./render/prepareRenderComponent"
|
||||||
import { screenRouter } from "./render/screenRouter"
|
import { screenRouter } from "./render/screenRouter"
|
||||||
|
@ -7,7 +6,6 @@ import { createStateManager } from "./state/stateManager"
|
||||||
export const createApp = ({
|
export const createApp = ({
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
user,
|
|
||||||
window,
|
window,
|
||||||
}) => {
|
}) => {
|
||||||
let routeTo
|
let routeTo
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import regexparam from "regexparam"
|
import regexparam from "regexparam"
|
||||||
import { routerStore } from "../state/store"
|
import { routerStore } from "../state/store"
|
||||||
import { initRouteStore } from "../state/store"
|
|
||||||
|
|
||||||
// TODO: refactor
|
|
||||||
export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => {
|
export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => {
|
||||||
const makeRootedPath = url => {
|
const makeRootedPath = url => {
|
||||||
if (appRootPath) {
|
if (appRootPath) {
|
||||||
|
|
|
@ -6,17 +6,12 @@ import { createApi } from "../api"
|
||||||
|
|
||||||
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType"
|
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType"
|
||||||
|
|
||||||
export const eventHandlers = (store, rootPath, routeTo) => {
|
export const eventHandlers = (rootPath, routeTo) => {
|
||||||
const handler = (parameters, execute) => ({
|
const handler = (parameters, execute) => ({
|
||||||
execute,
|
execute,
|
||||||
parameters,
|
parameters,
|
||||||
})
|
})
|
||||||
|
|
||||||
let currentState
|
|
||||||
store.subscribe(state => {
|
|
||||||
currentState = state
|
|
||||||
})
|
|
||||||
|
|
||||||
const api = createApi({
|
const api = createApi({
|
||||||
rootPath,
|
rootPath,
|
||||||
setState,
|
setState,
|
||||||
|
|
|
@ -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,
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -21,27 +21,16 @@ const isMetaProp = propName =>
|
||||||
propName === "_styles"
|
propName === "_styles"
|
||||||
|
|
||||||
export const createStateManager = ({
|
export const createStateManager = ({
|
||||||
// store,
|
|
||||||
appRootPath,
|
appRootPath,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
routeTo,
|
routeTo,
|
||||||
}) => {
|
}) => {
|
||||||
let handlerTypes = eventHandlers(appStore, appRootPath, routeTo)
|
let handlerTypes = eventHandlers(appRootPath, routeTo)
|
||||||
let currentState
|
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 getCurrentState = () => currentState
|
||||||
// const registerBindings = _registerBindings(
|
|
||||||
// nodesBoundByProps,
|
|
||||||
// nodesWithCodeBoundChildren
|
|
||||||
// )
|
|
||||||
|
|
||||||
const bb = bbFactory({
|
const bb = bbFactory({
|
||||||
store: appStore,
|
store: appStore,
|
||||||
|
@ -53,131 +42,26 @@ export const createStateManager = ({
|
||||||
|
|
||||||
const setup = _setup({ handlerTypes, getCurrentState, bb, store: appStore })
|
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 {
|
return {
|
||||||
setup,
|
setup,
|
||||||
destroy: () => unsubscribe(),
|
destroy: () => {},
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
store: appStore,
|
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 _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
|
||||||
const props = node.props
|
const props = node.props
|
||||||
const context = node.context || {}
|
const context = node.context || {}
|
||||||
const initialProps = { ...props }
|
const initialProps = { ...props }
|
||||||
// const storeBoundProps = []
|
|
||||||
const currentStoreState = get(appStore)
|
const currentStoreState = get(appStore)
|
||||||
|
|
||||||
console.log("node", node)
|
|
||||||
|
|
||||||
// console.log("node", node);
|
|
||||||
// console.log("nodeComponent", node.component);
|
|
||||||
|
|
||||||
for (let propName in props) {
|
for (let propName in props) {
|
||||||
if (isMetaProp(propName)) continue
|
if (isMetaProp(propName)) continue
|
||||||
|
|
||||||
const propValue = props[propName]
|
const propValue = props[propName]
|
||||||
|
|
||||||
// const binding = parseBinding(propValue)
|
// A little bit of a hack - won't bind if the string doesn't start with {{
|
||||||
// TODO: better binding stuff
|
|
||||||
const isBound = typeof propValue === "string" && propValue.startsWith("{{")
|
const isBound = typeof propValue === "string" && propValue.startsWith("{{")
|
||||||
|
|
||||||
if (isBound) {
|
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)) {
|
if (isEventType(propValue)) {
|
||||||
const handlersInfos = []
|
const handlersInfos = []
|
||||||
for (let event of propValue) {
|
for (let event of propValue) {
|
||||||
|
@ -228,21 +91,6 @@ const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
|
||||||
state: getCurrentState(),
|
state: getCurrentState(),
|
||||||
context,
|
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
|
handlerInfo.parameters = resolvedParams
|
||||||
|
@ -262,8 +110,6 @@ const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// registerBindings(node, storeBoundProps)
|
|
||||||
|
|
||||||
const setup = _setup({ handlerTypes, getCurrentState, bb, store })
|
const setup = _setup({ handlerTypes, getCurrentState, bb, store })
|
||||||
initialProps._bb = bb(node, setup)
|
initialProps._bb = bb(node, setup)
|
||||||
|
|
||||||
|
|
|
@ -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("", () => {
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -11,7 +11,8 @@ const controller = {
|
||||||
if (
|
if (
|
||||||
!name.startsWith("all") &&
|
!name.startsWith("all") &&
|
||||||
name !== "by_type" &&
|
name !== "by_type" &&
|
||||||
name !== "by_username"
|
name !== "by_username" &&
|
||||||
|
name !== "by_workflow_trigger"
|
||||||
) {
|
) {
|
||||||
response.push({
|
response.push({
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../../db")
|
||||||
const newid = require("../../db/newid")
|
const newid = require("../../../db/newid")
|
||||||
|
|
||||||
exports.create = async function(ctx) {
|
exports.create = async function(ctx) {
|
||||||
const db = new CouchDB(ctx.params.instanceId)
|
const db = new CouchDB(ctx.params.instanceId)
|
||||||
|
@ -49,7 +49,7 @@ exports.fetch = async function(ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = 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)
|
ctx.body = await db.get(ctx.params.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ exports.executeAction = async function(ctx) {
|
||||||
|
|
||||||
exports.fetchActionScript = async function(ctx) {
|
exports.fetchActionScript = async function(ctx) {
|
||||||
const workflowAction = require(`./actions/${ctx.action}`)
|
const workflowAction = require(`./actions/${ctx.action}`)
|
||||||
console.log(workflowAction)
|
|
||||||
ctx.body = workflowAction
|
ctx.body = workflowAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
const Router = require("@koa/router")
|
const Router = require("@koa/router")
|
||||||
const controller = require("../controllers/workflow")
|
const controller = require("../controllers/workflow")
|
||||||
const authorized = require("../../middleware/authorized")
|
const authorized = require("../../middleware/authorized")
|
||||||
const { BUILDER, EXECUTE_WORKFLOW } = require("../../utilities/accessLevels")
|
const { BUILDER } = require("../../utilities/accessLevels")
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
.get("/api/:instanceId/workflows", authorized(BUILDER), controller.fetch)
|
.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(
|
.get(
|
||||||
"/api/:instanceId/workflows/:id/:action",
|
"/api/:instanceId/workflows/:id/:action",
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const EventEmitter = require("events").EventEmitter
|
const EventEmitter = require("events").EventEmitter
|
||||||
const CouchDB = require("../db")
|
const CouchDB = require("../db")
|
||||||
const { Orchestrator, serverStrategy } = require("./workflow");
|
const { Orchestrator, serverStrategy } = require("./workflow")
|
||||||
|
|
||||||
const emitter = new EventEmitter()
|
const emitter = new EventEmitter()
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ async function executeRelevantWorkflows(event, eventType) {
|
||||||
const db = new CouchDB(event.instanceId)
|
const db = new CouchDB(event.instanceId)
|
||||||
const workflowsToTrigger = await db.query("database/by_workflow_trigger", {
|
const workflowsToTrigger = await db.query("database/by_workflow_trigger", {
|
||||||
key: [eventType],
|
key: [eventType],
|
||||||
include_docs: true
|
include_docs: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const workflows = workflowsToTrigger.rows.map(wf => wf.doc)
|
const workflows = workflowsToTrigger.rows.map(wf => wf.doc)
|
||||||
|
@ -22,12 +22,12 @@ async function executeRelevantWorkflows(event, eventType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitter.on("record:save", async function(event) {
|
emitter.on("action", async function(event) {
|
||||||
await executeRelevantWorkflows(event, "record:save");
|
await executeRelevantWorkflows(event, "record:save")
|
||||||
})
|
})
|
||||||
|
|
||||||
emitter.on("record:delete", async function(event) {
|
emitter.on("record:delete", async function(event) {
|
||||||
await executeRelevantWorkflows(event, "record:delete");
|
await executeRelevantWorkflows(event, "record:delete")
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = emitter
|
module.exports = emitter
|
||||||
|
|
|
@ -37,7 +37,6 @@ exports.serverStrategy = () => ({
|
||||||
},
|
},
|
||||||
run: async function(workflow) {
|
run: async function(workflow) {
|
||||||
for (let block of workflow.steps) {
|
for (let block of workflow.steps) {
|
||||||
console.log("Executing workflow block", block)
|
|
||||||
if (block.type === "CLIENT") continue
|
if (block.type === "CLIENT") continue
|
||||||
|
|
||||||
const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
|
const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
|
||||||
|
@ -48,5 +47,5 @@ exports.serverStrategy = () => ({
|
||||||
[block.id]: response,
|
[block.id]: response,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
|
|
Loading…
Reference in New Issue