2021-01-19 18:38:24 +01:00
|
|
|
import { get } from "svelte/store"
|
2021-07-25 13:09:50 +02:00
|
|
|
import {
|
|
|
|
routeStore,
|
|
|
|
builderStore,
|
|
|
|
confirmationStore,
|
|
|
|
authStore,
|
2021-08-26 12:28:44 +02:00
|
|
|
stateStore,
|
2021-09-01 12:41:48 +02:00
|
|
|
} from "stores"
|
|
|
|
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "api"
|
|
|
|
import { ActionTypes } from "constants"
|
2021-12-09 12:25:32 +01:00
|
|
|
import { enrichDataBindings } from "./enrichDataBinding"
|
2020-11-25 10:50:51 +01:00
|
|
|
|
|
|
|
const saveRowHandler = async (action, context) => {
|
2021-12-07 14:59:12 +01:00
|
|
|
const { fields, providerId, tableId } = action.parameters
|
|
|
|
let payload
|
|
|
|
if (providerId) {
|
2021-12-09 15:36:24 +01:00
|
|
|
payload = { ...context[providerId] }
|
2021-12-07 14:59:12 +01:00
|
|
|
} else {
|
|
|
|
payload = {}
|
|
|
|
}
|
|
|
|
if (fields) {
|
|
|
|
for (let [field, value] of Object.entries(fields)) {
|
|
|
|
payload[field] = value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tableId) {
|
|
|
|
payload.tableId = tableId
|
|
|
|
}
|
2021-12-09 12:25:32 +01:00
|
|
|
const row = await saveRow(payload)
|
|
|
|
return {
|
|
|
|
row,
|
|
|
|
}
|
2021-12-07 14:59:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const duplicateRowHandler = async (action, context) => {
|
2021-07-22 17:50:35 +02:00
|
|
|
const { fields, providerId, tableId } = action.parameters
|
2021-01-19 18:38:24 +01:00
|
|
|
if (providerId) {
|
2021-12-09 15:36:57 +01:00
|
|
|
let draft = { ...context[providerId] }
|
2021-01-19 18:38:24 +01:00
|
|
|
if (fields) {
|
2021-02-18 18:44:56 +01:00
|
|
|
for (let [field, value] of Object.entries(fields)) {
|
|
|
|
draft[field] = value
|
2021-01-21 12:31:45 +01:00
|
|
|
}
|
2021-01-19 18:38:24 +01:00
|
|
|
}
|
2021-07-22 17:50:35 +02:00
|
|
|
if (tableId) {
|
|
|
|
draft.tableId = tableId
|
|
|
|
}
|
2021-12-07 14:59:12 +01:00
|
|
|
delete draft._id
|
|
|
|
delete draft._rev
|
2021-01-19 18:38:24 +01:00
|
|
|
await saveRow(draft)
|
2020-11-25 10:50:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 12:32:22 +02:00
|
|
|
const deleteRowHandler = async action => {
|
2020-11-25 10:50:51 +01:00
|
|
|
const { tableId, revId, rowId } = action.parameters
|
2021-01-19 18:38:24 +01:00
|
|
|
if (tableId && revId && rowId) {
|
2021-02-04 20:18:32 +01:00
|
|
|
await deleteRow({ tableId, rowId, revId })
|
2021-01-19 18:38:24 +01:00
|
|
|
}
|
2020-11-25 10:50:51 +01:00
|
|
|
}
|
|
|
|
|
2021-05-04 12:32:22 +02:00
|
|
|
const triggerAutomationHandler = async action => {
|
2021-02-04 14:01:49 +01:00
|
|
|
const { fields } = action.parameters
|
2021-01-21 12:31:45 +01:00
|
|
|
if (fields) {
|
2021-02-18 18:44:56 +01:00
|
|
|
await triggerAutomation(action.parameters.automationId, fields)
|
2021-01-08 18:25:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 12:32:22 +02:00
|
|
|
const navigationHandler = action => {
|
2021-07-30 15:01:01 +02:00
|
|
|
const { url, peek } = action.parameters
|
2021-11-05 13:38:33 +01:00
|
|
|
routeStore.actions.navigate(url, peek)
|
2020-11-25 10:50:51 +01:00
|
|
|
}
|
|
|
|
|
2021-05-04 12:32:22 +02:00
|
|
|
const queryExecutionHandler = async action => {
|
2021-01-08 13:06:37 +01:00
|
|
|
const { datasourceId, queryId, queryParams } = action.parameters
|
2021-01-08 19:22:03 +01:00
|
|
|
await executeQuery({
|
|
|
|
datasourceId,
|
|
|
|
queryId,
|
2021-02-03 15:53:13 +01:00
|
|
|
parameters: queryParams,
|
2021-01-08 19:22:03 +01:00
|
|
|
})
|
2021-01-04 19:57:16 +01:00
|
|
|
}
|
|
|
|
|
2021-08-19 13:52:50 +02:00
|
|
|
const executeActionHandler = async (
|
|
|
|
context,
|
|
|
|
componentId,
|
|
|
|
actionType,
|
|
|
|
params
|
|
|
|
) => {
|
2021-02-05 13:54:36 +01:00
|
|
|
const fn = context[`${componentId}_${actionType}`]
|
2021-02-01 19:51:22 +01:00
|
|
|
if (fn) {
|
2021-08-19 13:52:50 +02:00
|
|
|
return await fn(params)
|
2021-02-01 19:51:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 13:54:36 +01:00
|
|
|
const validateFormHandler = async (action, context) => {
|
|
|
|
return await executeActionHandler(
|
|
|
|
context,
|
|
|
|
action.parameters.componentId,
|
2021-08-19 13:52:50 +02:00
|
|
|
ActionTypes.ValidateForm,
|
|
|
|
action.parameters.onlyCurrentStep
|
2021-02-05 13:54:36 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-09-23 20:34:01 +02:00
|
|
|
const refreshDataProviderHandler = async (action, context) => {
|
2021-02-05 13:54:36 +01:00
|
|
|
return await executeActionHandler(
|
|
|
|
context,
|
|
|
|
action.parameters.componentId,
|
|
|
|
ActionTypes.RefreshDatasource
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-07-25 13:07:25 +02:00
|
|
|
const logoutHandler = async () => {
|
|
|
|
await authStore.actions.logOut()
|
|
|
|
}
|
|
|
|
|
2021-07-26 13:58:18 +02:00
|
|
|
const clearFormHandler = async (action, context) => {
|
|
|
|
return await executeActionHandler(
|
|
|
|
context,
|
|
|
|
action.parameters.componentId,
|
|
|
|
ActionTypes.ClearForm
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-08-20 10:54:54 +02:00
|
|
|
const changeFormStepHandler = async (action, context) => {
|
2021-08-18 16:21:18 +02:00
|
|
|
return await executeActionHandler(
|
|
|
|
context,
|
|
|
|
action.parameters.componentId,
|
2021-08-20 10:54:54 +02:00
|
|
|
ActionTypes.ChangeFormStep,
|
|
|
|
action.parameters
|
2021-08-18 16:21:18 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-08-02 16:50:59 +02:00
|
|
|
const closeScreenModalHandler = () => {
|
2021-08-02 16:12:38 +02:00
|
|
|
// Emit this as a window event, so parent screens which are iframing us in
|
|
|
|
// can close the modal
|
2021-11-04 17:28:07 +01:00
|
|
|
window.parent.postMessage({ type: "close-screen-modal" })
|
2021-08-02 16:12:38 +02:00
|
|
|
}
|
|
|
|
|
2021-08-26 12:28:44 +02:00
|
|
|
const updateStateHandler = action => {
|
2021-08-26 18:52:04 +02:00
|
|
|
const { type, key, value, persist } = action.parameters
|
2021-08-26 12:28:44 +02:00
|
|
|
if (type === "set") {
|
2021-08-26 18:52:04 +02:00
|
|
|
stateStore.actions.setValue(key, value, persist)
|
2021-08-26 12:28:44 +02:00
|
|
|
} else if (type === "delete") {
|
|
|
|
stateStore.actions.deleteValue(key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-25 10:50:51 +01:00
|
|
|
const handlerMap = {
|
|
|
|
["Save Row"]: saveRowHandler,
|
2021-12-07 14:59:12 +01:00
|
|
|
["Duplicate Row"]: duplicateRowHandler,
|
2020-11-25 10:50:51 +01:00
|
|
|
["Delete Row"]: deleteRowHandler,
|
|
|
|
["Navigate To"]: navigationHandler,
|
2021-01-04 19:57:16 +01:00
|
|
|
["Execute Query"]: queryExecutionHandler,
|
2021-01-08 18:25:06 +01:00
|
|
|
["Trigger Automation"]: triggerAutomationHandler,
|
2021-02-01 19:51:22 +01:00
|
|
|
["Validate Form"]: validateFormHandler,
|
2021-09-23 20:34:01 +02:00
|
|
|
["Refresh Data Provider"]: refreshDataProviderHandler,
|
2021-07-25 13:07:25 +02:00
|
|
|
["Log Out"]: logoutHandler,
|
2021-07-26 15:22:14 +02:00
|
|
|
["Clear Form"]: clearFormHandler,
|
2021-08-02 16:50:59 +02:00
|
|
|
["Close Screen Modal"]: closeScreenModalHandler,
|
2021-08-20 10:54:54 +02:00
|
|
|
["Change Form Step"]: changeFormStepHandler,
|
2021-08-26 12:28:44 +02:00
|
|
|
["Update State"]: updateStateHandler,
|
2021-06-21 10:56:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const confirmTextMap = {
|
|
|
|
["Delete Row"]: "Are you sure you want to delete this row?",
|
|
|
|
["Save Row"]: "Are you sure you want to save this row?",
|
|
|
|
["Execute Query"]: "Are you sure you want to execute this query?",
|
|
|
|
["Trigger Automation"]: "Are you sure you want to trigger this automation?",
|
2020-11-25 10:50:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses an array of actions and returns a function which will execute the
|
|
|
|
* actions in the current context.
|
2021-06-21 10:56:46 +02:00
|
|
|
* A handler returning `false` is a flag to stop execution of handlers
|
2020-11-25 10:50:51 +01:00
|
|
|
*/
|
|
|
|
export const enrichButtonActions = (actions, context) => {
|
2021-01-19 18:38:24 +01:00
|
|
|
// Prevent button actions in the builder preview
|
2021-11-04 12:30:43 +01:00
|
|
|
if (!actions || get(builderStore).inBuilder) {
|
2021-01-19 18:38:24 +01:00
|
|
|
return () => {}
|
|
|
|
}
|
2021-11-04 12:30:43 +01:00
|
|
|
|
|
|
|
// If this is a function then it has already been enriched
|
|
|
|
if (typeof actions === "function") {
|
|
|
|
return actions
|
|
|
|
}
|
|
|
|
|
2021-12-09 12:25:32 +01:00
|
|
|
// Button context is built up as actions are executed.
|
|
|
|
// Inherit any previous button context which may have come from actions
|
|
|
|
// before a confirmable action since this breaks the chain.
|
|
|
|
let buttonContext = context.actions || []
|
|
|
|
|
2021-05-04 12:32:22 +02:00
|
|
|
const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]])
|
2020-11-25 10:50:51 +01:00
|
|
|
return async () => {
|
|
|
|
for (let i = 0; i < handlers.length; i++) {
|
2021-02-01 19:51:22 +01:00
|
|
|
try {
|
2021-12-09 12:25:32 +01:00
|
|
|
// Skip any non-existent action definitions
|
|
|
|
if (!handlers[i]) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Built total context for this action
|
|
|
|
const totalContext = { ...context, actions: buttonContext }
|
|
|
|
|
|
|
|
// Get and enrich this button action with the total context
|
|
|
|
let action = actions[i]
|
|
|
|
action = enrichDataBindings(action, totalContext)
|
2021-12-09 15:36:24 +01:00
|
|
|
const callback = async () => handlers[i](action, totalContext)
|
2021-06-21 10:56:46 +02:00
|
|
|
|
|
|
|
// If this action is confirmable, show confirmation and await a
|
|
|
|
// callback to execute further actions
|
|
|
|
if (action.parameters?.confirm) {
|
|
|
|
const defaultText = confirmTextMap[action["##eventHandlerType"]]
|
|
|
|
const confirmText = action.parameters?.confirmText || defaultText
|
2021-06-21 11:46:55 +02:00
|
|
|
confirmationStore.actions.showConfirmation(
|
|
|
|
action["##eventHandlerType"],
|
|
|
|
confirmText,
|
|
|
|
async () => {
|
|
|
|
// When confirmed, execute this action immediately,
|
|
|
|
// then execute the rest of the actions in the chain
|
|
|
|
const result = await callback()
|
|
|
|
if (result !== false) {
|
2021-12-09 12:25:32 +01:00
|
|
|
// Generate a new total context to pass into the next enrichment
|
|
|
|
buttonContext.push(result)
|
|
|
|
const newContext = { ...context, actions: buttonContext }
|
|
|
|
|
|
|
|
// Enrich and call the next button action
|
|
|
|
const next = enrichButtonActions(
|
|
|
|
actions.slice(i + 1),
|
|
|
|
newContext
|
|
|
|
)
|
2021-06-21 11:46:55 +02:00
|
|
|
await next()
|
|
|
|
}
|
2021-06-21 10:56:46 +02:00
|
|
|
}
|
2021-06-21 11:46:55 +02:00
|
|
|
)
|
2021-06-21 10:56:46 +02:00
|
|
|
|
2021-06-21 11:11:18 +02:00
|
|
|
// Stop enriching actions when encountering a confirmable action,
|
2021-06-21 10:56:46 +02:00
|
|
|
// as the callback continues the action chain
|
2021-02-01 19:51:22 +01:00
|
|
|
return
|
|
|
|
}
|
2021-06-21 10:56:46 +02:00
|
|
|
|
2021-06-21 11:11:18 +02:00
|
|
|
// For non-confirmable actions, execute the handler immediately
|
2021-06-21 10:56:46 +02:00
|
|
|
else {
|
|
|
|
const result = await callback()
|
|
|
|
if (result === false) {
|
|
|
|
return
|
2021-12-09 12:25:32 +01:00
|
|
|
} else {
|
|
|
|
buttonContext.push(result)
|
2021-06-21 10:56:46 +02:00
|
|
|
}
|
|
|
|
}
|
2021-02-01 19:51:22 +01:00
|
|
|
} catch (error) {
|
|
|
|
console.error("Error while executing button handler")
|
|
|
|
console.error(error)
|
2021-06-21 10:56:46 +02:00
|
|
|
// Stop executing further actions on error
|
2021-02-01 19:51:22 +01:00
|
|
|
return
|
|
|
|
}
|
2020-11-25 10:50:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|