orchestrator refactor, user creation block

This commit is contained in:
Martin McKeaveney 2020-05-30 13:41:46 +01:00
parent 36da2576bc
commit 9a898a8d74
11 changed files with 91 additions and 75 deletions

View File

@ -1,6 +1,6 @@
import mustache from "mustache" import mustache from "mustache"
// TODO: tidy up import // TODO: tidy up import
import blockDefinitions from "../../../pages/[application]/workflow/WorkflowPanel/blockDefinitions" import blockDefinitions from "../../../components/workflow/WorkflowPanel/blockDefinitions"
import { generate } from "shortid" import { generate } from "shortid"
/** /**
@ -79,7 +79,7 @@ export default class Workflow {
type: block.type, type: block.type,
params: block.params, params: block.params,
args, args,
heading: definition.actionId, heading: block.actionId,
body: mustache.render(tagline, args), body: mustache.render(tagline, args),
}) })

View File

@ -1,31 +1,31 @@
import { isString } from "lodash/fp" // import { isString } from "lodash/fp"
import { // import {
BB_STATE_BINDINGPATH, // BB_STATE_BINDINGPATH,
BB_STATE_FALLBACK, // BB_STATE_FALLBACK,
BB_STATE_BINDINGSOURCE, // BB_STATE_BINDINGSOURCE,
isBound, // isBound,
parseBinding, // parseBinding,
} from "@budibase/client/src/state/parseBinding" // } from "@budibase/client/src/state/parseBinding"
export const isBinding = isBound // export const isBinding = isBound
export const setBinding = ({ path, fallback, source }, binding = {}) => { // export const setBinding = ({ path, fallback, source }, binding = {}) => {
if (isNonEmptyString(path)) binding[BB_STATE_BINDINGPATH] = path // if (isNonEmptyString(path)) binding[BB_STATE_BINDINGPATH] = path
if (isNonEmptyString(fallback)) binding[BB_STATE_FALLBACK] = fallback // if (isNonEmptyString(fallback)) binding[BB_STATE_FALLBACK] = fallback
binding[BB_STATE_BINDINGSOURCE] = source || "store" // binding[BB_STATE_BINDINGSOURCE] = source || "store"
return binding // return binding
} // }
export const getBinding = val => { // export const getBinding = val => {
const binding = parseBinding(val) // const binding = parseBinding(val)
return binding // return binding
? binding // ? binding
: { // : {
path: "", // path: "",
source: "store", // source: "store",
fallback: "", // fallback: "",
} // }
} // }
const isNonEmptyString = s => isString(s) && s.length > 0 // const isNonEmptyString = s => isString(s) && s.length > 0

View File

@ -43,13 +43,6 @@
) )
} }
async function selectRecord(record) {
return await api.loadRecord(record.key, {
appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase._id,
})
}
const ITEMS_PER_PAGE = 10 const ITEMS_PER_PAGE = 10
// Internal headers we want to hide from the user // Internal headers we want to hide from the user
const INTERNAL_HEADERS = ["_id", "_rev", "modelId", "type"] const INTERNAL_HEADERS = ["_id", "_rev", "modelId", "type"]

View File

@ -2,8 +2,7 @@
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import IconButton from "../common/IconButton.svelte" import IconButton from "../common/IconButton.svelte"
import Input from "../common/Input.svelte" import Input from "../common/Input.svelte"
import PropertyCascader from "./PropertyCascader" // import PropertyCascader from "./PropertyCascader"
import { isBinding, getBinding, setBinding } from "../common/binding"
import Colorpicker from "../common/Colorpicker.svelte" import Colorpicker from "../common/Colorpicker.svelte"
export let value = "" export let value = ""
@ -50,7 +49,7 @@
{/each} {/each}
</select> </select>
{:else} {:else}
<PropertyCascader {onChanged} {value} /> <!-- <PropertyCascader {onChanged} {value} /> -->
{/if} {/if}
</div> </div>

View File

@ -5,6 +5,8 @@
let params let params
console.log("wfblock", workflowBlock)
$: workflowParams = workflowBlock.params $: workflowParams = workflowBlock.params
? Object.entries(workflowBlock.params) ? Object.entries(workflowBlock.params)
: [] : []
@ -13,7 +15,7 @@
</script> </script>
<label class="uk-form-label"> <label class="uk-form-label">
{workflowBlock.type}: {workflowBlock.heading} {workflowBlock.type}: {workflowBlock.actionId}
</label> </label>
{#each workflowParams as [parameter, type]} {#each workflowParams as [parameter, type]}
<div class="uk-margin block-field"> <div class="uk-margin block-field">
@ -27,6 +29,18 @@
<option value={option}>{option}</option> <option value={option}>{option}</option>
{/each} {/each}
</select> </select>
{:else if type === 'accessLevel'}
<select
class="budibase__input"
bind:value={workflowBlock.args[parameter]}>
<option value="ADMIN">Admin</option>
<option value="POWER_USER">Power User</option>
</select>
{:else if type === 'password'}
<input
type="password"
class="budibase__input"
bind:value={workflowBlock.args[parameter]} />
{:else if type === 'number'} {:else if type === 'number'}
<input <input
type="number" type="number"

View File

@ -49,13 +49,14 @@ const ACTION = {
}, },
CREATE_USER: { CREATE_USER: {
description: "Create a new user.", description: "Create a new user.",
tagline: "Create user <b>{{username}}</b>",
icon: "ri-user-add-fill", icon: "ri-user-add-fill",
name: "Create User", name: "Create User",
environment: "SERVER", environment: "SERVER",
params: { params: {
name: "string", username: "string",
password: "password", password: "password",
accessLevel: "accessLevel", accessLevelId: "accessLevel",
}, },
}, },
SEND_EMAIL: { SEND_EMAIL: {

View File

@ -1,5 +1,7 @@
import get from "lodash/fp/get" import { get } from "svelte/store";
import { setState } from "../../state/setState";
import mustache from "mustache"; import mustache from "mustache";
import { appStore } from "../../state/store";
/** /**
* The workflow orchestrator is a class responsible for executing workflows. * The workflow orchestrator is a class responsible for executing workflows.
@ -15,25 +17,21 @@ export default class Orchestrator {
} }
set strategy(strategy) { set strategy(strategy) {
this._strategy = strategy this._strategy = strategy({ api: this.api, instanceId: this.instanceId });
} }
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({ this._strategy.run(workflow.definition)
workflow: workflow.definition,
api: this.api,
instanceId: this.instanceId,
})
} }
} }
// Execute a workflow from a running budibase app // Execute a workflow from a running budibase app
export const clientStrategy = { export const clientStrategy = ({ api, instanceId }) => ({
delay: ms => new Promise(resolve => setTimeout(resolve, ms)), delay: ms => new Promise(resolve => setTimeout(resolve, ms)),
context: {}, context: {},
bindContextArgs: function(args, api) { bindContextArgs: function(args) {
const mappedArgs = { ...args } const mappedArgs = { ...args }
console.log("original args", args) console.log("original args", args)
@ -42,35 +40,18 @@ export const clientStrategy = {
for (let arg in args) { for (let arg in args) {
const argValue = args[arg] const argValue = args[arg]
// Means that it's bound to state or workflow context // Means that it's bound to state or workflow context
console.log(argValue, get(appStore));
mappedArgs[arg] = mustache.render(argValue, { mappedArgs[arg] = mustache.render(argValue, {
context: this.context, context: this.context,
// TODO: map to the real state state: get(appStore)
state: {}
}); });
} }
// if (argValue.startsWith("$")) {
// // if value is bound to workflow context.
// if (argValue.startsWith("$context")) {
// const path = argValue.replace("$context.", "")
// // pass in the value from context
// mappedArgs[arg] = get(path, this.context)
// }
// // if the value is bound to state
// if (argValue.startsWith("$state")) {
// const path = argValue.replace("$state.", "")
// // pass in the value from state
// // TODO: not working
// mappedArgs[arg] = api.getState(path)
// }
// }
// }
console.log(mappedArgs) console.log(mappedArgs)
return Object.values(mappedArgs) return mappedArgs
}, },
run: async function({ workflow, api, instanceId }) { run: async function(workflow) {
const block = workflow.next const block = workflow.next
console.log("Executing workflow block", block) console.log("Executing workflow block", block)
@ -81,7 +62,7 @@ export const clientStrategy = {
if (block.environment === "CLIENT") { if (block.environment === "CLIENT") {
if (block.actionId === "SET_STATE") { if (block.actionId === "SET_STATE") {
// get props from the workflow context if required // get props from the workflow context if required
api.setState(...this.bindContextArgs(block.args)) setState(...Object.values(this.bindContextArgs(block.args)))
// update the context with the data // update the context with the data
this.context = { this.context = {
...this.context, ...this.context,
@ -135,7 +116,6 @@ export const clientStrategy = {
console.log("workflowContext", this.context) console.log("workflowContext", this.context)
// TODO: clean this up, don't pass all those args await this.run(workflow.next)
await this.run({ workflow: workflow.next, instanceId, api })
}, },
} })

View File

@ -1,5 +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 // TODO: refactor
export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => { export const screenRouter = ({ screens, onScreenSelected, appRootPath }) => {

View File

@ -0,0 +1,26 @@
const userController = require("../../user")
module.exports = async function createUser(user) {
console.log("SAVING this user", user)
const ctx = {
params: {
instanceId: "inst_60dd510_700f7dc06735403e81d5af91072d7241",
},
request: {
body: user
},
}
try {
const response = await userController.create(ctx)
return {
user: response
}
} catch (err) {
console.error(err);
return {
user: null
}
}
}

View File

@ -2,9 +2,11 @@ const viewController = require("../api/controllers/view")
const modelController = require("../api/controllers/model") const modelController = require("../api/controllers/model")
const workflowController = require("../api/controllers/workflow") const workflowController = require("../api/controllers/workflow")
// Access Level IDs
const ADMIN_LEVEL_ID = "ADMIN" const ADMIN_LEVEL_ID = "ADMIN"
const POWERUSER_LEVEL_ID = "POWER_USER" const POWERUSER_LEVEL_ID = "POWER_USER"
// Permissions
const READ_MODEL = "read-model" const READ_MODEL = "read-model"
const WRITE_MODEL = "write-model" const WRITE_MODEL = "write-model"
const READ_VIEW = "read-view" const READ_VIEW = "read-view"