From cb496d18193baaf908e60018e3289e0875707d82 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 1 Jun 2020 11:52:15 +0100 Subject: [PATCH] workflow DAO tests --- packages/builder/src/App.svelte | 4 ++ .../builderStore/store/workflow/Workflow.js | 52 ++++----------- .../src/builderStore/store/workflow/index.js | 1 - .../store/workflow/tests/Workflow.js | 1 - .../store/workflow/tests/Workflow.spec.js | 57 +++++++++++++++++ .../tests/__snapshots__/Workflow.spec.js.snap | 49 ++++++++++++++ .../store/workflow/tests/testWorkflow.js | 64 +++++++++++++++++++ .../WorkflowBuilder/WorkflowBuilder.svelte | 3 +- .../{svelte-flows => flowchart}/Arrow.svelte | 0 .../FlowChart.svelte | 0 .../FlowItem.svelte | 0 .../{svelte-flows => flowchart}/api.js | 0 .../{svelte-flows => flowchart}/index.js | 0 .../workflow/[workflow]/_layout.svelte | 0 packages/client/src/api/workflow/actions.js | 8 +-- .../client/src/api/workflow/orchestrator.js | 4 +- packages/client/src/createApp.js | 1 - packages/client/src/index.js | 1 - packages/client/src/state/bbComponentApi.js | 1 - packages/client/src/state/eventHandlers.js | 1 - packages/client/src/state/getState.js | 1 - .../workflow/actions/SAVE_RECORD.js | 2 - packages/server/src/events/index.js | 4 +- 23 files changed, 193 insertions(+), 61 deletions(-) delete mode 100644 packages/builder/src/builderStore/store/workflow/tests/Workflow.js create mode 100644 packages/builder/src/builderStore/store/workflow/tests/Workflow.spec.js create mode 100644 packages/builder/src/builderStore/store/workflow/tests/__snapshots__/Workflow.spec.js.snap create mode 100644 packages/builder/src/builderStore/store/workflow/tests/testWorkflow.js rename packages/builder/src/components/workflow/WorkflowBuilder/{svelte-flows => flowchart}/Arrow.svelte (100%) rename packages/builder/src/components/workflow/WorkflowBuilder/{svelte-flows => flowchart}/FlowChart.svelte (100%) rename packages/builder/src/components/workflow/WorkflowBuilder/{svelte-flows => flowchart}/FlowItem.svelte (100%) rename packages/builder/src/components/workflow/WorkflowBuilder/{svelte-flows => flowchart}/api.js (100%) rename packages/builder/src/components/workflow/WorkflowBuilder/{svelte-flows => flowchart}/index.js (100%) create mode 100644 packages/builder/src/pages/[application]/workflow/[workflow]/_layout.svelte diff --git a/packages/builder/src/App.svelte b/packages/builder/src/App.svelte index 4ead618ba6..72d287e9cb 100644 --- a/packages/builder/src/App.svelte +++ b/packages/builder/src/App.svelte @@ -25,7 +25,11 @@ $basepath = "/_builder" + + + + diff --git a/packages/builder/src/builderStore/store/workflow/Workflow.js b/packages/builder/src/builderStore/store/workflow/Workflow.js index c8ae55dbf3..d50e16b5da 100644 --- a/packages/builder/src/builderStore/store/workflow/Workflow.js +++ b/packages/builder/src/builderStore/store/workflow/Workflow.js @@ -1,5 +1,4 @@ import mustache from "mustache" -// TODO: tidy up import import blockDefinitions from "components/workflow/WorkflowPanel/blockDefinitions" import { generate } from "shortid" @@ -13,12 +12,19 @@ export default class Workflow { } isEmpty() { - // return this.workflow.definition.next - return this.workflow.length > 0 + return this.workflow.definition.trigger.length === 0 } addBlock(block) { // Make sure to add trigger if doesn't exist + // if (this.isEmpty()) { + // this.workflow.definition.triggers.push({ + // id: generate(), + // ...block, + // }) + // return; + // } + this.workflow.definition.steps.push({ id: generate(), ...block, @@ -27,13 +33,10 @@ export default class Workflow { updateBlock(updatedBlock, id) { const { steps, trigger } = this.workflow.definition + // TODO: Account for trigger - // if the block is a trigger do X - - // if step const stepIdx = steps.findIndex(step => step.id === id) - // while (block.id !== id) block = block.next if (stepIdx < 0) throw new Error("Block not found.") steps.splice(stepIdx, 1, updatedBlock) @@ -41,6 +44,7 @@ export default class Workflow { deleteBlock(id) { const { steps, trigger } = this.workflow.definition + // TODO: Account for trigger const stepIdx = steps.findIndex(step => step.id === id) @@ -84,38 +88,4 @@ export default class Workflow { } }) } - - // 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) - // } } diff --git a/packages/builder/src/builderStore/store/workflow/index.js b/packages/builder/src/builderStore/store/workflow/index.js index 8b534aab5c..b41bb8d8f7 100644 --- a/packages/builder/src/builderStore/store/workflow/index.js +++ b/packages/builder/src/builderStore/store/workflow/index.js @@ -68,7 +68,6 @@ const workflowActions = store => ({ }, select: workflow => { store.update(state => { - // TODO: better naming state.currentWorkflow = new Workflow(workflow) state.selectedWorkflowBlock = null return state diff --git a/packages/builder/src/builderStore/store/workflow/tests/Workflow.js b/packages/builder/src/builderStore/store/workflow/tests/Workflow.js deleted file mode 100644 index a892d688b3..0000000000 --- a/packages/builder/src/builderStore/store/workflow/tests/Workflow.js +++ /dev/null @@ -1 +0,0 @@ -describe("Workflow Data Object", () => {}) diff --git a/packages/builder/src/builderStore/store/workflow/tests/Workflow.spec.js b/packages/builder/src/builderStore/store/workflow/tests/Workflow.spec.js new file mode 100644 index 0000000000..fd14404a5f --- /dev/null +++ b/packages/builder/src/builderStore/store/workflow/tests/Workflow.spec.js @@ -0,0 +1,57 @@ +import Workflow from "../Workflow"; +import TEST_WORKFLOW from "./testWorkflow"; + +const TEST_BLOCK = { + id: "VFWeZcIPx", + name: "Update UI State", + tagline: "Update {{path}} to {{value}}", + icon: "ri-refresh-line", + description: "Update your User Interface with some data.", + environment: "CLIENT", + params: { + path: "string", + value: "longText", + }, + args: { + path: "foo", + value: "started...", + }, + actionId: "SET_STATE", + type: "ACTION", +} + +describe("Workflow Data Object", () => { + let workflow + + beforeEach(() => { + workflow = new Workflow({ ...TEST_WORKFLOW }); + }); + + it("adds a workflow block to the workflow", () => { + workflow.addBlock(TEST_BLOCK); + expect(workflow.workflow.definition) + }) + + it("updates a workflow block with new attributes", () => { + const firstBlock = workflow.workflow.definition.steps[0]; + const updatedBlock = { + ...firstBlock, + name: "UPDATED" + }; + workflow.updateBlock(updatedBlock, firstBlock.id); + expect(workflow.workflow.definition.steps[0]).toEqual(updatedBlock) + }) + + it("deletes a workflow block successfully", () => { + const { steps } = workflow.workflow.definition + const originalLength = steps.length + + const lastBlock = steps[steps.length - 1]; + workflow.deleteBlock(lastBlock.id); + expect(workflow.workflow.definition.steps.length).toBeLessThan(originalLength); + }) + + it("builds a tree that gets rendered in the flowchart builder", () => { + expect(Workflow.buildUiTree(TEST_WORKFLOW.definition)).toMatchSnapshot(); + }) +}) diff --git a/packages/builder/src/builderStore/store/workflow/tests/__snapshots__/Workflow.spec.js.snap b/packages/builder/src/builderStore/store/workflow/tests/__snapshots__/Workflow.spec.js.snap new file mode 100644 index 0000000000..732764a082 --- /dev/null +++ b/packages/builder/src/builderStore/store/workflow/tests/__snapshots__/Workflow.spec.js.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Workflow Data Object builds a tree that gets rendered in the flowchart builder 1`] = ` +Array [ + Object { + "args": Object { + "time": 3000, + }, + "body": "Delay for 3000 milliseconds", + "heading": "DELAY", + "id": "zJQcZUgDS", + "name": "Delay", + "params": Object { + "time": "number", + }, + "type": "LOGIC", + }, + Object { + "args": Object { + "path": "foo", + "value": "finished", + }, + "body": "Update foo to finished", + "heading": "SET_STATE", + "id": "3RSTO7BMB", + "name": "Update UI State", + "params": Object { + "path": "string", + "value": "longText", + }, + "type": "ACTION", + }, + Object { + "args": Object { + "path": "foo", + "value": "started...", + }, + "body": "Update foo to started...", + "heading": "SET_STATE", + "id": "VFWeZcIPx", + "name": "Update UI State", + "params": Object { + "path": "string", + "value": "longText", + }, + "type": "ACTION", + }, +] +`; diff --git a/packages/builder/src/builderStore/store/workflow/tests/testWorkflow.js b/packages/builder/src/builderStore/store/workflow/tests/testWorkflow.js new file mode 100644 index 0000000000..2ef6018bf0 --- /dev/null +++ b/packages/builder/src/builderStore/store/workflow/tests/testWorkflow.js @@ -0,0 +1,64 @@ +export default { + _id: "53b6148c65d1429c987e046852d11611", + _rev: "4-02c6659734934895812fa7be0215ee59", + name: "Test Workflow", + definition: { + trigger: {}, + steps: [ + { + id: "VFWeZcIPx", + name: "Update UI State", + tagline: "Update {{path}} to {{value}}", + icon: "ri-refresh-line", + description: "Update your User Interface with some data.", + environment: "CLIENT", + params: { + path: "string", + value: "longText", + }, + args: { + path: "foo", + value: "started...", + }, + actionId: "SET_STATE", + type: "ACTION", + }, + { + id: "zJQcZUgDS", + name: "Delay", + icon: "ri-time-fill", + tagline: "Delay for {{time}} milliseconds", + description: "Delay the workflow until an amount of time has passed.", + environment: "CLIENT", + params: { + time: "number", + }, + args: { + time: 3000, + }, + actionId: "DELAY", + type: "LOGIC", + }, + { + id: "3RSTO7BMB", + name: "Update UI State", + tagline: "Update {{path}} to {{value}}", + icon: "ri-refresh-line", + description: "Update your User Interface with some data.", + environment: "CLIENT", + params: { + path: "string", + value: "longText", + }, + args: { + path: "foo", + value: "finished", + }, + actionId: "SET_STATE", + type: "ACTION", + }, + ], + }, + type: "workflow", + live: true, +} diff --git a/packages/builder/src/components/workflow/WorkflowBuilder/WorkflowBuilder.svelte b/packages/builder/src/components/workflow/WorkflowBuilder/WorkflowBuilder.svelte index af3b108b7b..6399ab727a 100644 --- a/packages/builder/src/components/workflow/WorkflowBuilder/WorkflowBuilder.svelte +++ b/packages/builder/src/components/workflow/WorkflowBuilder/WorkflowBuilder.svelte @@ -2,14 +2,13 @@ import { onMount } from "svelte" import { workflowStore, backendUiStore } from "builderStore" import { notifier } from "@beyonk/svelte-notifications" - import Flowchart from "./svelte-flows/Flowchart.svelte" + import Flowchart from "./flowchart/Flowchart.svelte" import api from "builderStore/api" let selectedWorkflow let uiTree let instanceId = $backendUiStore.selectedDatabase._id - // TODO: better naming $: selectedWorkflow = $workflowStore.currentWorkflow $: workflowLive = selectedWorkflow && selectedWorkflow.workflow.live diff --git a/packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/Arrow.svelte b/packages/builder/src/components/workflow/WorkflowBuilder/flowchart/Arrow.svelte similarity index 100% rename from packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/Arrow.svelte rename to packages/builder/src/components/workflow/WorkflowBuilder/flowchart/Arrow.svelte diff --git a/packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/FlowChart.svelte b/packages/builder/src/components/workflow/WorkflowBuilder/flowchart/FlowChart.svelte similarity index 100% rename from packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/FlowChart.svelte rename to packages/builder/src/components/workflow/WorkflowBuilder/flowchart/FlowChart.svelte diff --git a/packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/FlowItem.svelte b/packages/builder/src/components/workflow/WorkflowBuilder/flowchart/FlowItem.svelte similarity index 100% rename from packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/FlowItem.svelte rename to packages/builder/src/components/workflow/WorkflowBuilder/flowchart/FlowItem.svelte diff --git a/packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/api.js b/packages/builder/src/components/workflow/WorkflowBuilder/flowchart/api.js similarity index 100% rename from packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/api.js rename to packages/builder/src/components/workflow/WorkflowBuilder/flowchart/api.js diff --git a/packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/index.js b/packages/builder/src/components/workflow/WorkflowBuilder/flowchart/index.js similarity index 100% rename from packages/builder/src/components/workflow/WorkflowBuilder/svelte-flows/index.js rename to packages/builder/src/components/workflow/WorkflowBuilder/flowchart/index.js diff --git a/packages/builder/src/pages/[application]/workflow/[workflow]/_layout.svelte b/packages/builder/src/pages/[application]/workflow/[workflow]/_layout.svelte new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/client/src/api/workflow/actions.js b/packages/client/src/api/workflow/actions.js index 44d863cd3f..795d34fad3 100644 --- a/packages/client/src/api/workflow/actions.js +++ b/packages/client/src/api/workflow/actions.js @@ -6,17 +6,17 @@ 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 }) => {}, + NAVIGATE: ({ context, args, id }) => { + // TODO client navigation + }, DELAY: async ({ context, args }) => await delay(args.time), - FILTER: (context, args) => { + FILTER: ({ context, args }) => { const { field, condition, value } = args switch (condition) { case "equals": diff --git a/packages/client/src/api/workflow/orchestrator.js b/packages/client/src/api/workflow/orchestrator.js index 1473b183e7..e69e41b918 100644 --- a/packages/client/src/api/workflow/orchestrator.js +++ b/packages/client/src/api/workflow/orchestrator.js @@ -43,7 +43,7 @@ export const clientStrategy = ({ api, instanceId }) => ({ // 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 + // Render the string with values from the workflow context and state mappedArgs[arg] = mustache.render(argValue, { context: this.context, state: get(appStore), @@ -82,8 +82,6 @@ export const clientStrategy = ({ api, instanceId }) => ({ [block.actionId]: response, } } - - console.log("workflowContext", this.context) } }, }) diff --git a/packages/client/src/createApp.js b/packages/client/src/createApp.js index 4655c0ebe7..d3fb51b124 100644 --- a/packages/client/src/createApp.js +++ b/packages/client/src/createApp.js @@ -61,7 +61,6 @@ export const createApp = ({ let rootTreeNode const pageStateManager = createStateManager({ - // store: writable({ _bbuser: user }), frontendDefinition, componentLibraries, onScreenSlotRendered, diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 3e86f3ddec..95f722d445 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -11,7 +11,6 @@ export const loadBudibase = async opts => { const frontendDefinition = _window["##BUDIBASE_FRONTEND_DEFINITION##"] - // TODO: update const user = {} const componentLibraryModules = (opts && opts.componentLibraries) || {} diff --git a/packages/client/src/state/bbComponentApi.js b/packages/client/src/state/bbComponentApi.js index 34746058f7..9945d17b36 100644 --- a/packages/client/src/state/bbComponentApi.js +++ b/packages/client/src/state/bbComponentApi.js @@ -1,5 +1,4 @@ import { setState } from "./setState" -// import { isBound } from "./parseBinding" import { attachChildren } from "../render/attachChildren" import { getContext, setContext } from "./getSetContext" diff --git a/packages/client/src/state/eventHandlers.js b/packages/client/src/state/eventHandlers.js index f1de2592f8..88418ba1a3 100644 --- a/packages/client/src/state/eventHandlers.js +++ b/packages/client/src/state/eventHandlers.js @@ -1,7 +1,6 @@ import { setState } from "./setState" import { getState } from "./getState" import { isArray, isUndefined } from "lodash/fp" -import { appStore } from "./store" import { createApi } from "../api" diff --git a/packages/client/src/state/getState.js b/packages/client/src/state/getState.js index 4afe27236a..236b54c6dc 100644 --- a/packages/client/src/state/getState.js +++ b/packages/client/src/state/getState.js @@ -1,4 +1,3 @@ -// import { isUndefined, isObject } from "lodash/fp" import { get } from "svelte/store" import getOr from "lodash/fp/getOr" import { appStore } from "./store" diff --git a/packages/server/src/api/controllers/workflow/actions/SAVE_RECORD.js b/packages/server/src/api/controllers/workflow/actions/SAVE_RECORD.js index 24225f2287..20d70850a3 100644 --- a/packages/server/src/api/controllers/workflow/actions/SAVE_RECORD.js +++ b/packages/server/src/api/controllers/workflow/actions/SAVE_RECORD.js @@ -1,8 +1,6 @@ const recordController = require("../../record") module.exports = async function saveRecord(args) { - console.log("SAVING this record", args.record) - const ctx = { params: { instanceId: "inst_60dd510_700f7dc06735403e81d5af91072d7241", diff --git a/packages/server/src/events/index.js b/packages/server/src/events/index.js index 76dc231f15..5c386e97b6 100644 --- a/packages/server/src/events/index.js +++ b/packages/server/src/events/index.js @@ -19,7 +19,7 @@ emitter.on("record:save", async function(event) { ) for (let workflow of workflowsToTrigger) { - // SERVER SIDE STUFF!! + // TODO: server side workflow triggers } }) @@ -30,7 +30,7 @@ emitter.on("record:delete", async function(event) { ) for (let workflow of workflowsToTrigger) { - // SERVER SIDE STUFF!! + // TODO: server side workflow triggers } })