styling, bug fixes, client library state updates

This commit is contained in:
Martin McKeaveney 2020-05-29 16:06:23 +01:00
parent bba7b93b75
commit 385bcfe51f
11 changed files with 166 additions and 146 deletions

View File

@ -40,8 +40,13 @@ export default class Workflow {
block = block.next block = block.next
} }
// delete the block found // delete the block matching your id
previous.next = block.next || {} if (!block.next) {
delete previous.next
} else {
previous.next = block.next
}
} }
createUiTree() { createUiTree() {

View File

@ -1,14 +1,15 @@
<script> <script>
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"
import api from "builderStore/api" import api from "builderStore/api"
import WorkflowBlockSetup from "./WorkflowBlockSetup.svelte" import WorkflowBlockSetup from "./WorkflowBlockSetup.svelte"
import DeleteWorkflowModal from "./DeleteWorkflowModal.svelte" import DeleteWorkflowModal from "./DeleteWorkflowModal.svelte"
const { open, close } = getContext("simple-modal") const { open, close } = getContext("simple-modal")
$: workflow = $workflowStore.currentWorkflow && $workflowStore.currentWorkflow.workflow $: workflow =
$workflowStore.currentWorkflow && $workflowStore.currentWorkflow.workflow
$: workflowBlock = $workflowStore.selectedWorkflowBlock $: workflowBlock = $workflowStore.selectedWorkflowBlock
function deleteWorkflow() { function deleteWorkflow() {
@ -23,7 +24,7 @@
function deleteWorkflowBlock() { function deleteWorkflowBlock() {
workflowStore.actions.deleteWorkflowBlock(workflowBlock) workflowStore.actions.deleteWorkflowBlock(workflowBlock)
notifier.info("Workflow block deleted."); notifier.info("Workflow block deleted.")
} }
</script> </script>
@ -31,15 +32,15 @@
<header> <header>
<span>Setup</span> <span>Setup</span>
</header> </header>
<div class="panel-body"> {#if workflowBlock}
{#if workflowBlock} <WorkflowBlockSetup {workflowBlock} />
<WorkflowBlockSetup {workflowBlock} /> <button
<button class="delete-workflow-button hoverable"
class="delete-workflow-button hoverable" on:click={deleteWorkflowBlock}>
on:click={deleteWorkflowBlock}> Delete Block
Delete Block </button>
</button> {:else if $workflowStore.currentWorkflow}
{:else if $workflowStore.currentWorkflow} <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">
<label class="uk-form-label">Name</label> <label class="uk-form-label">Name</label>
@ -54,19 +55,22 @@
<label class="uk-form-label">User Access</label> <label class="uk-form-label">User Access</label>
Some User Access Stuff Here Some User Access Stuff Here
</div> </div>
<button </div>
class="delete-workflow-button hoverable" <button class="delete-workflow-button hoverable" on:click={deleteWorkflow}>
on:click={deleteWorkflow}> Delete Workflow
Delete Workflow </button>
</button> {/if}
{/if}
</div>
</section> </section>
<style> <style>
section { section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
}
.panel-body {
flex: 1;
} }
header { header {

View File

@ -14,16 +14,10 @@
$: workflowLive = selectedWorkflow && selectedWorkflow.workflow.live $: workflowLive = selectedWorkflow && selectedWorkflow.workflow.live
$: if (selectedWorkflow) $: uiTree = selectedWorkflow ? selectedWorkflow.createUiTree() : []
uiTree = selectedWorkflow ? selectedWorkflow.createUiTree() : []
$: instanceId = $backendUiStore.selectedDatabase._id $: instanceId = $backendUiStore.selectedDatabase._id
function onDelete(block) {
// TODO finish
workflowStore.actions.deleteWorkflowBlock(block)
}
function onSelect(block) { function onSelect(block) {
workflowStore.update(state => { workflowStore.update(state => {
state.selectedWorkflowBlock = block state.selectedWorkflowBlock = block
@ -44,7 +38,7 @@
</script> </script>
<section> <section>
<Flowchart blocks={uiTree} {onSelect} on:delete={onDelete} /> <Flowchart blocks={uiTree} {onSelect} />
<footer> <footer>
{#if selectedWorkflow} {#if selectedWorkflow}
<button <button

View File

@ -59,6 +59,11 @@
</section> </section>
<style> <style>
section {
display: flex;
flex-direction: column;
}
i { i {
color: #adaec4; color: #adaec4;
} }
@ -70,6 +75,7 @@
ul { ul {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
flex: 1;
} }
.live { .live {

View File

@ -9,29 +9,27 @@
let definitions = [] let definitions = []
</script> </script>
<section> <header>
<header> <span
class="hoverable"
class:selected={selectedTab === 'WORKFLOWS'}
on:click={() => (selectedTab = 'WORKFLOWS')}>
Workflows
</span>
{#if $workflowStore.currentWorkflow}
<span <span
class="hoverable" class="hoverable"
class:selected={selectedTab === 'WORKFLOWS'} class:selected={selectedTab === 'ADD'}
on:click={() => (selectedTab = 'WORKFLOWS')}> on:click={() => (selectedTab = 'ADD')}>
Workflows Add
</span> </span>
{#if $workflowStore.currentWorkflow}
<span
class="hoverable"
class:selected={selectedTab === 'ADD'}
on:click={() => (selectedTab = 'ADD')}>
Add
</span>
{/if}
</header>
{#if selectedTab === 'WORKFLOWS'}
<WorkflowList />
{:else if selectedTab === 'ADD'}
<BlockList />
{/if} {/if}
</section> </header>
{#if selectedTab === 'WORKFLOWS'}
<WorkflowList />
{:else if selectedTab === 'ADD'}
<BlockList />
{/if}
<style> <style>
header { header {

View File

@ -22,11 +22,6 @@
background: var(--background); background: var(--background);
} }
.nav {
padding: 20px;
height: 100%;
}
.root { .root {
height: 100%; height: 100%;
display: flex; display: flex;
@ -39,10 +34,9 @@
} }
.nav { .nav {
padding: 20px;
overflow: auto; overflow: auto;
flex: 0 1 auto;
width: 275px; width: 275px;
height: 100%;
border: 1px solid var(--medium-grey); border: 1px solid var(--medium-grey);
background: var(--white); background: var(--white);
} }

View File

@ -91,6 +91,25 @@ export const clientStrategy = {
if (block.actionId === "DELAY") { if (block.actionId === "DELAY") {
await this.delay(block.args.time) await this.delay(block.args.time)
} }
if (block.actionId === "FILTER") {
const { field, condition, value } = block.args;
switch (condition) {
case "=":
if (field !== value) return;
break;
case "!=":
if (field === value) return;
break;
case "gt":
if (field < value) return;
break;
case "lt":
if (field > value) return;
default:
return;
}
}
} }
// this workflow block gets executed on the server // this workflow block gets executed on the server

View File

@ -24,9 +24,8 @@ export const createApp = ({
routeTo, routeTo,
appRootPath: frontendDefinition.appRootPath, appRootPath: frontendDefinition.appRootPath,
}) })
const getAttachChildrenParams = attachChildrenParams(stateManager)
screenSlotNode.props._children = [screen.props] screenSlotNode.props._children = [screen.props]
const initialiseChildParams = getAttachChildrenParams(screenSlotNode) const initialiseChildParams = attachChildrenParams(stateManager, screenSlotNode)
attachChildren(initialiseChildParams)(screenSlotNode.rootElement, { attachChildren(initialiseChildParams)(screenSlotNode.rootElement, {
hydrate: true, hydrate: true,
force: true, force: true,
@ -48,17 +47,13 @@ export const createApp = ({
routeTo(currentUrl || fallbackPath) routeTo(currentUrl || fallbackPath)
} }
const attachChildrenParams = stateManager => { const attachChildrenParams = (stateManager, treeNode) => ({
const getInitialiseParams = treeNode => ({ componentLibraries,
componentLibraries, treeNode,
treeNode, onScreenSlotRendered,
onScreenSlotRendered, setupState: stateManager.setup,
setupState: stateManager.setup, getCurrentState: stateManager.getCurrentState,
getCurrentState: stateManager.getCurrentState, });
})
return getInitialiseParams
}
let rootTreeNode let rootTreeNode
const pageStateManager = createStateManager({ const pageStateManager = createStateManager({
@ -79,8 +74,7 @@ export const createApp = ({
_children: [page.props], _children: [page.props],
} }
rootTreeNode.rootElement = target rootTreeNode.rootElement = target
const getInitialiseParams = attachChildrenParams(pageStateManager) const initChildParams = attachChildrenParams(pageStateManager, rootTreeNode)
const initChildParams = getInitialiseParams(rootTreeNode)
attachChildren(initChildParams)(target, { attachChildren(initChildParams)(target, {
hydrate: true, hydrate: true,

View File

@ -40,6 +40,13 @@ export const bbFactory = ({
delete: apiCall("DELETE"), delete: apiCall("DELETE"),
} }
const safeCallEvent = (event, context) => {
const isFunction = obj =>
!!(obj && obj.constructor && obj.call && obj.apply)
if (isFunction(event)) event(context)
}
return (treeNode, setupState) => { return (treeNode, setupState) => {
const attachParams = { const attachParams = {
componentLibraries, componentLibraries,
@ -53,7 +60,7 @@ export const bbFactory = ({
attachChildren: attachChildren(attachParams), attachChildren: attachChildren(attachParams),
context: treeNode.context, context: treeNode.context,
props: treeNode.props, props: treeNode.props,
call: (event, context) => event(context), call: safeCallEvent,
setStateFromBinding: (binding, value) => setStateFromBinding: (binding, value) =>
setStateFromBinding(store, binding, value), setStateFromBinding(store, binding, value),
setState: (path, value) => setState(store, path, value), setState: (path, value) => setState(store, path, value),

View File

@ -29,12 +29,8 @@ export const eventHandlers = (store, rootPath, routeTo) => {
return { return {
"Set State": handler(["path", "value"], setStateHandler), "Set State": handler(["path", "value"], setStateHandler),
"Load Record": handler(["recordKey", "statePath"], api.loadRecord),
"List Records": handler(["indexKey", "statePath"], api.listRecords),
"Save Record": handler(["statePath"], api.saveRecord),
"Navigate To": handler(["url"], param => routeTo(param && param.url)), "Navigate To": handler(["url"], param => routeTo(param && param.url)),
"Trigger Workflow": handler(["workflow"], api.triggerWorkflow), "Trigger Workflow": handler(["workflow"], api.triggerWorkflow)
Authenticate: handler(["username", "password"], api.authenticate),
} }
} }

View File

@ -4,6 +4,7 @@ import {
EVENT_TYPE_MEMBER_NAME, EVENT_TYPE_MEMBER_NAME,
} from "./eventHandlers" } from "./eventHandlers"
import { bbFactory } from "./bbComponentApi" import { bbFactory } from "./bbComponentApi"
import { createTreeNode } from "../render/prepareRenderComponent"
import { getState } from "./getState" import { getState } from "./getState"
import { attachChildren } from "../render/attachChildren" import { attachChildren } from "../render/attachChildren"
import mustache from "mustache" import mustache from "mustache"
@ -34,16 +35,16 @@ export const createStateManager = ({
let currentState let currentState
// any nodes that have props that are bound to the store // any nodes that have props that are bound to the store
let nodesBoundByProps = [] // let nodesBoundByProps = []
// any node whose children depend on code, that uses the store // any node whose children depend on code, that uses the store
let nodesWithCodeBoundChildren = [] // let nodesWithCodeBoundChildren = []
const getCurrentState = () => currentState const getCurrentState = () => currentState
const registerBindings = _registerBindings( // const registerBindings = _registerBindings(
nodesBoundByProps, // nodesBoundByProps,
nodesWithCodeBoundChildren // nodesWithCodeBoundChildren
) // )
const bb = bbFactory({ const bb = bbFactory({
store, store,
getCurrentState, getCurrentState,
@ -52,14 +53,14 @@ export const createStateManager = ({
onScreenSlotRendered, onScreenSlotRendered,
}) })
const setup = _setup(handlerTypes, getCurrentState, registerBindings, bb) const setup = _setup(handlerTypes, getCurrentState, bb)
const unsubscribe = store.subscribe( const unsubscribe = store.subscribe(
onStoreStateUpdated({ onStoreStateUpdated({
setCurrentState: s => (currentState = s), setCurrentState: state => (currentState = state),
getCurrentState, getCurrentState,
nodesWithCodeBoundChildren, // nodesWithCodeBoundChildren,
nodesBoundByProps, // nodesBoundByProps,
componentLibraries, componentLibraries,
onScreenSlotRendered, onScreenSlotRendered,
setupState: setup, setupState: setup,
@ -77,91 +78,93 @@ export const createStateManager = ({
const onStoreStateUpdated = ({ const onStoreStateUpdated = ({
setCurrentState, setCurrentState,
getCurrentState, getCurrentState,
nodesWithCodeBoundChildren,
// nodesBoundByProps,
componentLibraries, componentLibraries,
onScreenSlotRendered, onScreenSlotRendered,
setupState, setupState,
}) => state => { }) => state => {
setCurrentState(state) setCurrentState(state)
// 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({ attachChildren({
componentLibraries, componentLibraries,
treeNode: node, treeNode: createTreeNode(),
onScreenSlotRendered, onScreenSlotRendered,
setupState, setupState,
getCurrentState, getCurrentState,
})(node.rootElement, { hydrate: true, force: true }) })(document.querySelector("#app"), { hydrate: true, force: true })
}
// for (let node of nodesBoundByProps) { // // the original array gets changed by components' destroy()
// setNodeState(state, node) // // 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) => ( // const _registerBindings = (nodesBoundByProps, nodesWithCodeBoundChildren) => (
node, // node,
bindings // bindings
) => { // ) => {
if (bindings.length > 0) { // if (bindings.length > 0) {
node.bindings = bindings // node.bindings = bindings
nodesBoundByProps.push(node) // nodesBoundByProps.push(node)
const onDestroy = () => { // const onDestroy = () => {
nodesBoundByProps = nodesBoundByProps.filter(n => n === node) // nodesBoundByProps = nodesBoundByProps.filter(n => n === node)
node.onDestroy = node.onDestroy.filter(d => d === onDestroy) // node.onDestroy = node.onDestroy.filter(d => d === onDestroy)
} // }
node.onDestroy.push(onDestroy) // node.onDestroy.push(onDestroy)
} // }
if ( // if (
node.props._children && // node.props._children &&
node.props._children.filter(c => c._codeMeta && c._codeMeta.dependsOnStore) // node.props._children.filter(c => c._codeMeta && c._codeMeta.dependsOnStore)
.length > 0 // .length > 0
) { // ) {
nodesWithCodeBoundChildren.push(node) // nodesWithCodeBoundChildren.push(node)
const onDestroy = () => { // const onDestroy = () => {
nodesWithCodeBoundChildren = nodesWithCodeBoundChildren.filter( // nodesWithCodeBoundChildren = nodesWithCodeBoundChildren.filter(
n => n === node // n => n === node
) // )
node.onDestroy = node.onDestroy.filter(d => d === onDestroy) // node.onDestroy = node.onDestroy.filter(d => d === onDestroy)
} // }
node.onDestroy.push(onDestroy) // node.onDestroy.push(onDestroy)
} // }
} // }
const setNodeState = (storeState, node) => { // const setNodeState = (storeState, node) => {
if (!node.component) return // if (!node.component) return
const newProps = { ...node.bindings.initialProps } // const newProps = { ...node.bindings.initialProps }
for (let binding of node.bindings) { // for (let binding of node.bindings) {
const val = getState(storeState, binding.path, binding.fallback) // const val = getState(storeState, binding.path, binding.fallback)
if (val === undefined && newProps[binding.propName] !== undefined) { // if (val === undefined && newProps[binding.propName] !== undefined) {
delete newProps[binding.propName] // delete newProps[binding.propName]
} // }
if (val !== undefined) { // if (val !== undefined) {
newProps[binding.propName] = val // newProps[binding.propName] = val
} // }
} // }
node.component.$set(newProps) // node.component.$set(newProps)
} // }
const _setup = ( const _setup = (
handlerTypes, handlerTypes,
getCurrentState, getCurrentState,
registerBindings,
bb bb
) => node => { ) => node => {
console.log(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 storeBoundProps = []
const currentStoreState = getCurrentState() const currentStoreState = getCurrentState()
for (let propName in props) { for (let propName in props) {
@ -249,9 +252,9 @@ const _setup = (
} }
} }
registerBindings(node, storeBoundProps) // registerBindings(node, storeBoundProps)
const setup = _setup(handlerTypes, getCurrentState, registerBindings, bb) const setup = _setup(handlerTypes, getCurrentState, bb)
initialProps._bb = bb(node, setup) initialProps._bb = bb(node, setup)
return initialProps return initialProps