tidy up, styling
This commit is contained in:
parent
401b6689bc
commit
3a983cea8a
|
@ -9,6 +9,17 @@
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const ACCESS_LEVELS = [
|
||||||
|
{
|
||||||
|
name: "Admin",
|
||||||
|
key: "ADMIN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Power User",
|
||||||
|
key: "POWER_USER"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
let selectedTab = "SETUP"
|
let selectedTab = "SETUP"
|
||||||
let testResult
|
let testResult
|
||||||
|
|
||||||
|
@ -92,16 +103,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-margin config-item">
|
<div class="uk-margin config-item">
|
||||||
<label class="uk-form-label">User Access</label>
|
<label class="uk-form-label">User Access</label>
|
||||||
<label>
|
<div class="access-levels">
|
||||||
<input class="uk-checkbox" type="checkbox" name="radio1" />
|
{#each ACCESS_LEVELS as { name, key }}
|
||||||
Admin
|
<span class="access-level">
|
||||||
</label>
|
<label>{name}</label>
|
||||||
<br />
|
<input class="uk-checkbox" type="checkbox" />
|
||||||
<label>
|
</span>
|
||||||
<input class="uk-checkbox" type="checkbox" name="radio1" />
|
{/each}
|
||||||
Power User
|
</div>
|
||||||
</label>
|
|
||||||
<br />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="workflow-button hoverable" on:click={deleteWorkflow}>
|
<button class="workflow-button hoverable" on:click={deleteWorkflow}>
|
||||||
|
@ -161,6 +170,21 @@
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflow-button:hover {
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-level {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-level label {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.test-result {
|
.test-result {
|
||||||
border: none;
|
border: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -119,4 +119,8 @@
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.new-workflow-button:hover {
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -46,16 +46,16 @@ const ACTION = {
|
||||||
record: {},
|
record: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
FIND_RECORD: {
|
// FIND_RECORD: {
|
||||||
description: "Find a record in your database.",
|
// description: "Find a record in your database.",
|
||||||
tagline: "<b>Find</b> a <b>{{record.model.name}}</b> record",
|
// tagline: "<b>Find</b> a <b>{{record.model.name}}</b> record",
|
||||||
icon: "ri-search-line",
|
// icon: "ri-search-line",
|
||||||
name: "Find Record",
|
// name: "Find Record",
|
||||||
environment: "SERVER",
|
// environment: "SERVER",
|
||||||
params: {
|
// params: {
|
||||||
record: "string",
|
// record: "string",
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
CREATE_USER: {
|
CREATE_USER: {
|
||||||
description: "Create a new user.",
|
description: "Create a new user.",
|
||||||
tagline: "Create user <b>{{username}}</b>",
|
tagline: "Create user <b>{{username}}</b>",
|
||||||
|
|
|
@ -5,7 +5,7 @@ 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
|
||||||
export const clientStrategy = ({ api, instanceId }) => ({
|
export const clientStrategy = ({ api }) => ({
|
||||||
context: {},
|
context: {},
|
||||||
bindContextArgs: function(args) {
|
bindContextArgs: function(args) {
|
||||||
const mappedArgs = { ...args }
|
const mappedArgs = { ...args }
|
||||||
|
@ -40,7 +40,7 @@ export const clientStrategy = ({ api, instanceId }) => ({
|
||||||
|
|
||||||
// this workflow block gets executed on the server
|
// this workflow block gets executed on the server
|
||||||
if (block.environment === "SERVER") {
|
if (block.environment === "SERVER") {
|
||||||
const EXECUTE_WORKFLOW_URL = `/api/${instanceId}/workflows/action`
|
const EXECUTE_WORKFLOW_URL = `/api/workflows/action`
|
||||||
const response = await api.post({
|
const response = await api.post({
|
||||||
url: EXECUTE_WORKFLOW_URL,
|
url: EXECUTE_WORKFLOW_URL,
|
||||||
body: {
|
body: {
|
||||||
|
@ -58,8 +58,8 @@ export const clientStrategy = ({ api, instanceId }) => ({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const triggerWorkflow = api => async ({ workflow, instanceId }) => {
|
export const triggerWorkflow = api => async ({ workflow }) => {
|
||||||
const workflowOrchestrator = new Orchestrator(api, instanceId)
|
const workflowOrchestrator = new Orchestrator(api)
|
||||||
workflowOrchestrator.strategy = clientStrategy
|
workflowOrchestrator.strategy = clientStrategy
|
||||||
|
|
||||||
const EXECUTE_WORKFLOW_URL = `/api/workflows/${workflow}`
|
const EXECUTE_WORKFLOW_URL = `/api/workflows/${workflow}`
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
import { get } from "svelte/store"
|
|
||||||
import mustache from "mustache"
|
|
||||||
import { appStore } from "../../state/store"
|
|
||||||
import clientActions from "./actions"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workflow orchestrator is a class responsible for executing workflows.
|
* The workflow orchestrator is a class responsible for executing workflows.
|
||||||
* It relies on the strategy pattern, which allows composable behaviour to be
|
* It relies on the strategy pattern, which allows composable behaviour to be
|
||||||
|
@ -11,13 +6,12 @@ import clientActions from "./actions"
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default class Orchestrator {
|
export default class Orchestrator {
|
||||||
constructor(api, instanceId) {
|
constructor(api) {
|
||||||
this.api = api
|
this.api = api
|
||||||
this.instanceId = instanceId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set strategy(strategy) {
|
set strategy(strategy) {
|
||||||
this._strategy = strategy({ api: this.api, instanceId: this.instanceId })
|
this._strategy = strategy({ api: this.api })
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(workflow) {
|
async execute(workflow) {
|
||||||
|
@ -26,59 +20,3 @@ export default class Orchestrator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a workflow from a running budibase app
|
|
||||||
export const clientStrategy = ({ api, instanceId }) => ({
|
|
||||||
context: {},
|
|
||||||
bindContextArgs: function(args) {
|
|
||||||
const mappedArgs = { ...args }
|
|
||||||
|
|
||||||
// bind the workflow action args to the workflow context, if required
|
|
||||||
for (let arg in args) {
|
|
||||||
const argValue = args[arg]
|
|
||||||
|
|
||||||
// We don't want to render mustache templates on non-strings
|
|
||||||
if (typeof argValue !== "string") continue
|
|
||||||
|
|
||||||
// Render the string with values from the workflow context and state
|
|
||||||
mappedArgs[arg] = mustache.render(argValue, {
|
|
||||||
context: this.context,
|
|
||||||
state: get(appStore),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedArgs
|
|
||||||
},
|
|
||||||
run: async function(workflow) {
|
|
||||||
for (let block of workflow.steps) {
|
|
||||||
console.log("Executing workflow block", block)
|
|
||||||
|
|
||||||
// This code gets run in the browser
|
|
||||||
if (block.environment === "CLIENT") {
|
|
||||||
const action = clientActions[block.actionId]
|
|
||||||
await action({
|
|
||||||
context: this.context,
|
|
||||||
args: this.bindContextArgs(block.args),
|
|
||||||
id: block.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// this workflow block gets executed on the server
|
|
||||||
if (block.environment === "SERVER") {
|
|
||||||
const EXECUTE_WORKFLOW_URL = `/api/${instanceId}/workflows/action`
|
|
||||||
const response = await api.post({
|
|
||||||
url: EXECUTE_WORKFLOW_URL,
|
|
||||||
body: {
|
|
||||||
action: block.actionId,
|
|
||||||
args: this.bindContextArgs(block.args, api),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
this.context = {
|
|
||||||
...this.context,
|
|
||||||
[block.actionId]: response,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
|
@ -65,7 +65,6 @@ const _setup = ({ handlerTypes, getCurrentState, bb, store }) => node => {
|
||||||
const isBound = typeof propValue === "string" && propValue.startsWith("{{")
|
const isBound = typeof propValue === "string" && propValue.startsWith("{{")
|
||||||
|
|
||||||
if (isBound) {
|
if (isBound) {
|
||||||
console.log("NODE IS BOUND", node)
|
|
||||||
initialProps[propName] = mustache.render(propValue, {
|
initialProps[propName] = mustache.render(propValue, {
|
||||||
state: currentStoreState,
|
state: currentStoreState,
|
||||||
context,
|
context,
|
||||||
|
|
|
@ -43,10 +43,11 @@ exports.save = async function(ctx) {
|
||||||
const response = await db.post(record)
|
const response = await db.post(record)
|
||||||
record._rev = response.rev
|
record._rev = response.rev
|
||||||
|
|
||||||
ctx.eventEmitter.emit(`record:save`, {
|
ctx.eventEmitter &&
|
||||||
record,
|
ctx.eventEmitter.emit(`record:save`, {
|
||||||
instanceId: ctx.params.instanceId,
|
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`
|
||||||
|
@ -86,7 +87,7 @@ 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)
|
ctx.eventEmitter && ctx.eventEmitter.emit(`record:delete`, record)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.validate = async function(ctx) {
|
exports.validate = async function(ctx) {
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
const userController = require("../../user")
|
const userController = require("../../user")
|
||||||
|
|
||||||
module.exports = async function createUser(user) {
|
module.exports = async function createUser({ args, instanceId }) {
|
||||||
console.log("SAVING this user", user)
|
|
||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
params: {
|
params: {
|
||||||
instanceId: "inst_60dd510_700f7dc06735403e81d5af91072d7241",
|
instanceId,
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
body: user,
|
body: args.user,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
export default async function() {
|
|
||||||
const response = await fetch("www.google.com")
|
|
||||||
console.log(response)
|
|
||||||
console.log("CUSTOM ACTION")
|
|
||||||
return {
|
|
||||||
message: "CUSTOM_WORKFLOW_SCRIPT",
|
|
||||||
response,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +1,29 @@
|
||||||
const recordController = require("../../record")
|
const recordController = require("../../record")
|
||||||
|
|
||||||
module.exports = async function saveRecord(args) {
|
module.exports = async function saveRecord({ args, instanceId }) {
|
||||||
|
const { model, ...record } = args.record
|
||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
params: {
|
params: {
|
||||||
instanceId: "inst_60dd510_700f7dc06735403e81d5af91072d7241",
|
instanceId,
|
||||||
|
modelId: model._id,
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
body: args.record,
|
body: record,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
await recordController.save(ctx)
|
await recordController.save(ctx)
|
||||||
|
|
||||||
return {
|
try {
|
||||||
record: ctx.body,
|
return {
|
||||||
|
record: ctx.body,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
return {
|
||||||
|
record: null,
|
||||||
|
error: err.message,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ const sgMail = require("@sendgrid/mail")
|
||||||
|
|
||||||
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
|
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
|
||||||
|
|
||||||
module.exports = async function sendEmail(args) {
|
module.exports = async function sendEmail({ args }) {
|
||||||
const msg = {
|
const msg = {
|
||||||
to: args.to,
|
to: args.to,
|
||||||
from: args.from,
|
from: args.from,
|
||||||
|
@ -20,7 +20,7 @@ module.exports = async function sendEmail(args) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
err,
|
error: err.message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,12 @@ exports.find = async function(ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.executeAction = async function(ctx) {
|
exports.executeAction = async function(ctx) {
|
||||||
const workflowAction = require(`./actions/${ctx.request.body.action}`)
|
const { args, action } = ctx.request.body
|
||||||
const response = await workflowAction(ctx.request.body.args)
|
const workflowAction = require(`./actions/${action}`)
|
||||||
|
const response = await workflowAction({
|
||||||
|
args,
|
||||||
|
instanceId: ctx.user.instanceId,
|
||||||
|
})
|
||||||
ctx.body = response
|
ctx.body = response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ router
|
||||||
)
|
)
|
||||||
.put("/api/:instanceId/workflows", authorized(BUILDER), controller.update)
|
.put("/api/:instanceId/workflows", authorized(BUILDER), controller.update)
|
||||||
.post("/api/:instanceId/workflows", authorized(BUILDER), controller.create)
|
.post("/api/:instanceId/workflows", authorized(BUILDER), controller.create)
|
||||||
.post("/api/:instanceId/workflows/action", controller.executeAction)
|
.post("/api/workflows/action", controller.executeAction)
|
||||||
.delete(
|
.delete(
|
||||||
"/api/:instanceId/workflows/:id/:rev",
|
"/api/:instanceId/workflows/:id/:rev",
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { app, BrowserWindow } = require("electron")
|
const { app, BrowserWindow, shell } = require("electron")
|
||||||
const { join } = require("path")
|
const { join } = require("path")
|
||||||
const { homedir } = require("os")
|
const { homedir } = require("os")
|
||||||
const isDev = require("electron-is-dev")
|
const isDev = require("electron-is-dev")
|
||||||
|
@ -18,6 +18,11 @@ const APP_TITLE = "Budibase Builder"
|
||||||
|
|
||||||
let win
|
let win
|
||||||
|
|
||||||
|
function handleRedirect(e, url) {
|
||||||
|
e.preventDefault()
|
||||||
|
shell.openExternal(url)
|
||||||
|
}
|
||||||
|
|
||||||
async function createWindow() {
|
async function createWindow() {
|
||||||
app.server = await require("./app")()
|
app.server = await require("./app")()
|
||||||
win = new BrowserWindow({ width: 1920, height: 1080 })
|
win = new BrowserWindow({ width: 1920, height: 1080 })
|
||||||
|
@ -28,6 +33,10 @@ async function createWindow() {
|
||||||
} else {
|
} else {
|
||||||
autoUpdater.checkForUpdatesAndNotify()
|
autoUpdater.checkForUpdatesAndNotify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// open _blank in default browser
|
||||||
|
win.webContents.on("new-window", handleRedirect)
|
||||||
|
win.webContents.on("will-navigate", handleRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(createWindow)
|
app.whenReady().then(createWindow)
|
||||||
|
|
Loading…
Reference in New Issue