Merge pull request #14247 from Budibase/BUDI-8441/row-action-run-api
Row action run api
This commit is contained in:
commit
9a181c9707
|
@ -187,7 +187,9 @@
|
|||
<Divider />
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="XS">History</Heading>
|
||||
<Body size="S">Free plan stores up to 1 day of automation history</Body>
|
||||
{#if licensePlan?.type === Constants.PlanType.FREE}
|
||||
<Body size="S">Free plan stores up to 1 day of automation history</Body>
|
||||
{/if}
|
||||
</Layout>
|
||||
<div class="controls">
|
||||
<div class="search">
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
export function run() {
|
||||
throw new Error("Function not implemented.")
|
||||
import { RowActionTriggerRequest, Ctx } from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
|
||||
export async function run(ctx: Ctx<RowActionTriggerRequest, void>) {
|
||||
const { tableId, actionId } = ctx.params
|
||||
const { rowId } = ctx.request.body
|
||||
|
||||
await sdk.rowActions.run(tableId, actionId, rowId)
|
||||
ctx.status = 200
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import Router from "@koa/router"
|
||||
import Joi from "joi"
|
||||
import { middleware, permissions } from "@budibase/backend-core"
|
||||
import * as rowActionController from "../controllers/rowAction"
|
||||
import { authorizedResource } from "../../middleware/authorized"
|
||||
|
||||
import { middleware, permissions } from "@budibase/backend-core"
|
||||
import Joi from "joi"
|
||||
|
||||
const { PermissionLevel, PermissionType } = permissions
|
||||
|
||||
export function rowActionValidator() {
|
||||
function rowActionValidator() {
|
||||
return middleware.joiValidator.body(
|
||||
Joi.object({
|
||||
name: Joi.string().required(),
|
||||
|
@ -16,6 +15,15 @@ export function rowActionValidator() {
|
|||
)
|
||||
}
|
||||
|
||||
function rowTriggerValidator() {
|
||||
return middleware.joiValidator.body(
|
||||
Joi.object({
|
||||
rowId: Joi.string().required(),
|
||||
}),
|
||||
{ allowUnknown: false }
|
||||
)
|
||||
}
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
// CRUD endpoints
|
||||
|
@ -45,7 +53,8 @@ router
|
|||
|
||||
// Other endpoints
|
||||
.post(
|
||||
"/api/tables/:tableId/actions/:actionId/run",
|
||||
"/api/tables/:tableId/actions/:actionId/trigger",
|
||||
rowTriggerValidator(),
|
||||
authorizedResource(PermissionType.TABLE, PermissionLevel.READ, "tableId"),
|
||||
rowActionController.run
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import * as setup from "./utilities"
|
||||
|
||||
import {
|
||||
DatabaseName,
|
||||
getDatasource,
|
||||
|
@ -7,7 +9,6 @@ import {
|
|||
import tk from "timekeeper"
|
||||
import emitter from "../../../../src/events"
|
||||
import { outputProcessing } from "../../../utilities/rowProcessor"
|
||||
import * as setup from "./utilities"
|
||||
import { context, InternalTable, tenancy } from "@budibase/backend-core"
|
||||
import { quotas } from "@budibase/pro"
|
||||
import {
|
||||
|
|
|
@ -9,11 +9,12 @@ import {
|
|||
|
||||
export const definition: AutomationTriggerSchema = {
|
||||
type: AutomationStepType.TRIGGER,
|
||||
name: "Row Action",
|
||||
event: AutomationEventType.ROW_ACTION, // TODO
|
||||
icon: "Workflow", // TODO
|
||||
tagline:
|
||||
"Row action triggered in {{inputs.enriched.table.name}} by {{inputs.enriched.row._id}}",
|
||||
name: "Row Action",
|
||||
description: "TODO description",
|
||||
icon: "Workflow",
|
||||
description: "TODO description", // TODO
|
||||
stepId: AutomationTriggerStepId.ROW_ACTION,
|
||||
inputs: {},
|
||||
schema: {
|
||||
|
@ -28,8 +29,27 @@ export const definition: AutomationTriggerSchema = {
|
|||
},
|
||||
required: ["tableId"],
|
||||
},
|
||||
outputs: { properties: {} },
|
||||
outputs: {
|
||||
properties: {
|
||||
id: {
|
||||
type: AutomationIOType.STRING,
|
||||
description: "Row ID - can be used for updating",
|
||||
},
|
||||
revision: {
|
||||
type: AutomationIOType.STRING,
|
||||
description: "Revision of row",
|
||||
},
|
||||
table: {
|
||||
type: AutomationIOType.OBJECT,
|
||||
customType: AutomationCustomIOType.TABLE,
|
||||
title: "The table linked to the row action",
|
||||
},
|
||||
row: {
|
||||
type: AutomationIOType.OBJECT,
|
||||
customType: AutomationCustomIOType.ROW,
|
||||
description: "The row linked to the row action",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
event: AutomationEventType.ROW_SAVE,
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
AutomationStatus,
|
||||
} from "@budibase/types"
|
||||
import { executeInThread } from "../threads/automation"
|
||||
import { dataFilters } from "@budibase/shared-core"
|
||||
import { dataFilters, sdk } from "@budibase/shared-core"
|
||||
|
||||
export const TRIGGER_DEFINITIONS = definitions
|
||||
const JOB_OPTS = {
|
||||
|
@ -121,17 +121,15 @@ function rowPassesFilters(row: Row, filters: SearchFilters) {
|
|||
|
||||
export async function externalTrigger(
|
||||
automation: Automation,
|
||||
params: { fields: Record<string, any>; timeout?: number },
|
||||
params: { fields: Record<string, any>; timeout?: number; appId?: string },
|
||||
{ getResponses }: { getResponses?: boolean } = {}
|
||||
): Promise<any> {
|
||||
if (automation.disabled) {
|
||||
throw new Error("Automation is disabled")
|
||||
}
|
||||
|
||||
if (
|
||||
automation.definition != null &&
|
||||
automation.definition.trigger != null &&
|
||||
automation.definition.trigger.stepId === definitions.APP.stepId &&
|
||||
automation.definition.trigger.stepId === "APP" &&
|
||||
sdk.automations.isAppAction(automation) &&
|
||||
!(await checkTestFlag(automation._id!))
|
||||
) {
|
||||
// values are likely to be submitted as strings, so we shall convert to correct type
|
||||
|
@ -141,6 +139,13 @@ export async function externalTrigger(
|
|||
coercedFields[key] = coerce(params.fields[key], fields[key])
|
||||
}
|
||||
params.fields = coercedFields
|
||||
} else if (sdk.automations.isRowAction(automation)) {
|
||||
params = {
|
||||
...params,
|
||||
// Until we don't refactor all the types, we want to flatten the nested "fields" object
|
||||
...params.fields,
|
||||
fields: {},
|
||||
}
|
||||
}
|
||||
const data: AutomationData = { automation, event: params }
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { sample } from "lodash/fp"
|
||||
import { Automation, AutomationTriggerStepId } from "@budibase/types"
|
||||
import { generator } from "@budibase/backend-core/tests"
|
||||
import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
|
||||
import automationSdk from "../"
|
||||
import { structures } from "../../../../api/routes/tests/utilities"
|
||||
import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
|
||||
|
||||
describe("automation sdk", () => {
|
||||
const config = new TestConfiguration()
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
TableRowActions,
|
||||
} from "@budibase/types"
|
||||
import { sdk as coreSdk } from "@budibase/shared-core"
|
||||
import sdk from "../../../sdk"
|
||||
|
||||
export function checkForCollectStep(automation: Automation) {
|
||||
return automation.definition.steps.some(
|
||||
|
@ -15,8 +16,6 @@ export function checkForCollectStep(automation: Automation) {
|
|||
export async function getBuilderData(
|
||||
automations: Automation[]
|
||||
): Promise<Record<string, AutomationBuilderData>> {
|
||||
const sdk = (await import("../../../sdk")).default
|
||||
|
||||
const tableNameCache: Record<string, string> = {}
|
||||
async function getTableName(tableId: string) {
|
||||
if (!tableNameCache[tableId]) {
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { context, HTTPError, utils } from "@budibase/backend-core"
|
||||
|
||||
import { generateRowActionsID } from "../../db/utils"
|
||||
import {
|
||||
SEPARATOR,
|
||||
TableRowActions,
|
||||
VirtualDocumentType,
|
||||
} from "@budibase/types"
|
||||
import { generateRowActionsID } from "../../db/utils"
|
||||
import automations from "./automations"
|
||||
import { definitions as TRIGGER_DEFINITIONS } from "../../automations/triggerInfo"
|
||||
import * as triggers from "../../automations/triggers"
|
||||
import sdk from ".."
|
||||
|
||||
function ensureUniqueAndThrow(
|
||||
doc: TableRowActions,
|
||||
|
@ -143,3 +145,28 @@ export async function remove(tableId: string, rowActionId: string) {
|
|||
const db = context.getAppDB()
|
||||
await db.put(actionsDoc)
|
||||
}
|
||||
|
||||
export async function run(tableId: any, rowActionId: any, rowId: string) {
|
||||
const table = await sdk.tables.getTable(tableId)
|
||||
if (!table) {
|
||||
throw new HTTPError("Table not found", 404)
|
||||
}
|
||||
|
||||
const { actions } = await get(tableId)
|
||||
|
||||
const rowAction = actions[rowActionId]
|
||||
if (!rowAction) {
|
||||
throw new HTTPError("Row action not found", 404)
|
||||
}
|
||||
|
||||
const automation = await sdk.automations.get(rowAction.automationId)
|
||||
|
||||
const row = await sdk.rows.find(tableId, rowId)
|
||||
await triggers.externalTrigger(automation, {
|
||||
fields: {
|
||||
row,
|
||||
table,
|
||||
},
|
||||
appId: context.getAppId(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,3 +5,9 @@ export function isRowAction(automation: Automation) {
|
|||
automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION
|
||||
return result
|
||||
}
|
||||
|
||||
export function isAppAction(automation: Automation) {
|
||||
const result =
|
||||
automation.definition.trigger.stepId === AutomationTriggerStepId.APP
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -13,3 +13,7 @@ export interface RowActionResponse extends RowActionData {
|
|||
export interface RowActionsResponse {
|
||||
actions: Record<string, RowActionResponse>
|
||||
}
|
||||
|
||||
export interface RowActionTriggerRequest {
|
||||
rowId: string
|
||||
}
|
||||
|
|
|
@ -279,6 +279,7 @@ export enum AutomationEventType {
|
|||
APP_TRIGGER = "app:trigger",
|
||||
CRON_TRIGGER = "cron:trigger",
|
||||
WEBHOOK_TRIGGER = "web:trigger",
|
||||
ROW_ACTION = "row:action",
|
||||
}
|
||||
|
||||
export type UpdatedRowEventEmitter = {
|
||||
|
|
Loading…
Reference in New Issue