diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte index ec9b9561904..50814897b48 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte @@ -9,7 +9,6 @@ import { sdk } from "@budibase/shared-core" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import UpdateAutomationModal from "components/automation/AutomationPanel/UpdateAutomationModal.svelte" - import UpdateRowActionModal from "components/automation/AutomationPanel/UpdateRowActionModal.svelte" import NavItem from "components/common/NavItem.svelte" export let automation @@ -17,7 +16,6 @@ let confirmDeleteDialog let updateAutomationDialog - let updateRowActionDialog $: isRowAction = sdk.automations.isRowAction(automation) @@ -92,7 +90,7 @@ name: "Edit", keyBind: null, visible: true, - callback: updateRowActionDialog.show, + callback: updateAutomationDialog.show, }, del, ] @@ -135,8 +133,4 @@ This action cannot be undone. -{#if isRowAction} - -{:else} - -{/if} + diff --git a/packages/builder/src/components/automation/AutomationPanel/UpdateRowActionModal.svelte b/packages/builder/src/components/automation/AutomationPanel/UpdateRowActionModal.svelte deleted file mode 100644 index 20f06608dc4..00000000000 --- a/packages/builder/src/components/automation/AutomationPanel/UpdateRowActionModal.svelte +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - Learn about automations - - - - - diff --git a/packages/server/src/api/controllers/rowAction/crud.ts b/packages/server/src/api/controllers/rowAction/crud.ts index ca84b2ea304..3baaff6fcca 100644 --- a/packages/server/src/api/controllers/rowAction/crud.ts +++ b/packages/server/src/api/controllers/rowAction/crud.ts @@ -2,9 +2,9 @@ import { CreateRowActionRequest, Ctx, RowActionPermissions, + RowActionPermissionsResponse, RowActionResponse, RowActionsResponse, - UpdateRowActionRequest, } from "@budibase/types" import sdk from "../../../sdk" @@ -30,6 +30,7 @@ export async function find(ctx: Ctx) { } const { actions } = rowActions + const automationNames = await sdk.rowActions.getNames(rowActions) const result: RowActionsResponse = { actions: Object.entries(actions).reduce>( (acc, [key, action]) => ({ @@ -37,7 +38,7 @@ export async function find(ctx: Ctx) { [key]: { id: key, tableId, - name: action.name, + name: automationNames[action.automationId], automationId: action.automationId, allowedSources: flattenAllowedSources(tableId, action.permissions), }, @@ -68,26 +69,6 @@ export async function create( ctx.status = 201 } -export async function update( - ctx: Ctx -) { - const table = await getTable(ctx) - const tableId = table._id! - const { actionId } = ctx.params - - const action = await sdk.rowActions.update(tableId, actionId, { - name: ctx.request.body.name, - }) - - ctx.body = { - tableId, - id: action.id, - name: action.name, - automationId: action.automationId, - allowedSources: flattenAllowedSources(tableId, action.permissions), - } -} - export async function remove(ctx: Ctx) { const table = await getTable(ctx) const { actionId } = ctx.params @@ -96,22 +77,22 @@ export async function remove(ctx: Ctx) { ctx.status = 204 } -export async function setTablePermission(ctx: Ctx) { +export async function setTablePermission( + ctx: Ctx +) { const table = await getTable(ctx) const tableId = table._id! const { actionId } = ctx.params const action = await sdk.rowActions.setTablePermission(tableId, actionId) ctx.body = { - tableId, - id: action.id, - name: action.name, - automationId: action.automationId, allowedSources: flattenAllowedSources(tableId, action.permissions), } } -export async function unsetTablePermission(ctx: Ctx) { +export async function unsetTablePermission( + ctx: Ctx +) { const table = await getTable(ctx) const tableId = table._id! const { actionId } = ctx.params @@ -119,15 +100,13 @@ export async function unsetTablePermission(ctx: Ctx) { const action = await sdk.rowActions.unsetTablePermission(tableId, actionId) ctx.body = { - tableId, - id: action.id, - name: action.name, - automationId: action.automationId, allowedSources: flattenAllowedSources(tableId, action.permissions), } } -export async function setViewPermission(ctx: Ctx) { +export async function setViewPermission( + ctx: Ctx +) { const table = await getTable(ctx) const tableId = table._id! const { actionId, viewId } = ctx.params @@ -138,15 +117,13 @@ export async function setViewPermission(ctx: Ctx) { viewId ) ctx.body = { - tableId, - id: action.id, - name: action.name, - automationId: action.automationId, allowedSources: flattenAllowedSources(tableId, action.permissions), } } -export async function unsetViewPermission(ctx: Ctx) { +export async function unsetViewPermission( + ctx: Ctx +) { const table = await getTable(ctx) const tableId = table._id! const { actionId, viewId } = ctx.params @@ -158,10 +135,6 @@ export async function unsetViewPermission(ctx: Ctx) { ) ctx.body = { - tableId, - id: action.id, - name: action.name, - automationId: action.automationId, allowedSources: flattenAllowedSources(tableId, action.permissions), } } diff --git a/packages/server/src/api/routes/rowAction.ts b/packages/server/src/api/routes/rowAction.ts index 3d146335094..b4b595164c2 100644 --- a/packages/server/src/api/routes/rowAction.ts +++ b/packages/server/src/api/routes/rowAction.ts @@ -40,12 +40,6 @@ router rowActionValidator(), rowActionController.create ) - .put( - "/api/tables/:tableId/actions/:actionId", - authorized(BUILDER), - rowActionValidator(), - rowActionController.update - ) .delete( "/api/tables/:tableId/actions/:actionId", authorized(BUILDER), diff --git a/packages/server/src/api/routes/tests/rowAction.spec.ts b/packages/server/src/api/routes/tests/rowAction.spec.ts index c0b5c4210fd..5cec83fe23d 100644 --- a/packages/server/src/api/routes/tests/rowAction.spec.ts +++ b/packages/server/src/api/routes/tests/rowAction.spec.ts @@ -328,129 +328,6 @@ describe("/rowsActions", () => { }) }) - describe("update", () => { - unauthorisedTests((expectations, testConfig) => - config.api.rowAction.update( - tableId, - generator.guid(), - createRowActionRequest(), - expectations, - testConfig - ) - ) - - it("can update existing actions", async () => { - for (const rowAction of createRowActionRequests(3)) { - await createRowAction(tableId, rowAction) - } - - const persisted = await config.api.rowAction.find(tableId) - - const [actionId, actionData] = _.sample( - Object.entries(persisted.actions) - )! - - const updatedName = generator.string() - - const res = await config.api.rowAction.update(tableId, actionId, { - name: updatedName, - }) - - expect(res).toEqual({ - id: actionId, - tableId, - name: updatedName, - automationId: actionData.automationId, - allowedSources: [tableId], - }) - - expect(await config.api.rowAction.find(tableId)).toEqual( - expect.objectContaining({ - actions: expect.objectContaining({ - [actionId]: { - name: updatedName, - id: actionData.id, - tableId: actionData.tableId, - automationId: actionData.automationId, - allowedSources: [tableId], - }, - }), - }) - ) - }) - - it("trims row action names", async () => { - const rowAction = await createRowAction(tableId, createRowActionRequest()) - - const res = await config.api.rowAction.update(tableId, rowAction.id, { - name: " action name ", - }) - - expect(res).toEqual(expect.objectContaining({ name: "action name" })) - - expect(await config.api.rowAction.find(tableId)).toEqual( - expect.objectContaining({ - actions: expect.objectContaining({ - [rowAction.id]: expect.objectContaining({ - name: "action name", - }), - }), - }) - ) - }) - - it("throws Bad Request when trying to update by a non-existing id", async () => { - await createRowAction(tableId, createRowActionRequest()) - - await config.api.rowAction.update( - tableId, - generator.guid(), - createRowActionRequest(), - { status: 400 } - ) - }) - - it("throws Bad Request when trying to update by a via another table id", async () => { - const otherTable = await config.api.table.save( - setup.structures.basicTable() - ) - await createRowAction(otherTable._id!, createRowActionRequest()) - - const action = await createRowAction(tableId, createRowActionRequest()) - await config.api.rowAction.update( - otherTable._id!, - action.id, - createRowActionRequest(), - { status: 400 } - ) - }) - - it("can not use existing row action names (for the same table)", async () => { - const action1 = await createRowAction(tableId, createRowActionRequest()) - const action2 = await createRowAction(tableId, createRowActionRequest()) - - await config.api.rowAction.update( - tableId, - action1.id, - { name: action2.name }, - { - status: 409, - body: { - message: "A row action with the same name already exists.", - }, - } - ) - }) - - it("does not throw with name conflicts for the same row action", async () => { - const action1 = await createRowAction(tableId, createRowActionRequest()) - - await config.api.rowAction.update(tableId, action1.id, { - name: action1.name, - }) - }) - }) - describe("delete", () => { unauthorisedTests((expectations, testConfig) => config.api.rowAction.delete( diff --git a/packages/server/src/sdk/app/automations/crud.ts b/packages/server/src/sdk/app/automations/crud.ts index 3888e6882aa..b982d5b45e9 100644 --- a/packages/server/src/sdk/app/automations/crud.ts +++ b/packages/server/src/sdk/app/automations/crud.ts @@ -1,4 +1,3 @@ -import { sdk } from "@budibase/shared-core" import { Automation, RequiredKeys, @@ -99,6 +98,12 @@ export async function get(automationId: string) { return trimUnexpectedObjectFields(result) } +export async function find(ids: string[]) { + const db = getDb() + const result = await db.getMultiple(ids) + return result.map(trimUnexpectedObjectFields) +} + export async function create(automation: Automation) { automation = trimUnexpectedObjectFields(automation) const db = getDb() @@ -289,13 +294,6 @@ function guardInvalidUpdatesAndThrow( } }) } - - if ( - sdk.automations.isRowAction(automation) && - automation.name !== oldAutomation.name - ) { - throw new Error("Row actions cannot be renamed") - } } function trimUnexpectedObjectFields(automation: T): T { diff --git a/packages/server/src/sdk/app/automations/tests/index.spec.ts b/packages/server/src/sdk/app/automations/tests/index.spec.ts index bf4c886cf0d..6c70392300e 100644 --- a/packages/server/src/sdk/app/automations/tests/index.spec.ts +++ b/packages/server/src/sdk/app/automations/tests/index.spec.ts @@ -1,5 +1,5 @@ import { sample } from "lodash/fp" -import { Automation, AutomationTriggerStepId } from "@budibase/types" +import { Automation } from "@budibase/types" import { generator } from "@budibase/backend-core/tests" import TestConfiguration from "../../../../tests/utilities/TestConfiguration" import automationSdk from "../" @@ -26,25 +26,6 @@ describe("automation sdk", () => { }) }) - it("cannot rename row action automations", async () => { - await config.doInContext(config.getAppId(), async () => { - const automation = structures.newAutomation({ - trigger: { - ...structures.automationTrigger(), - stepId: AutomationTriggerStepId.ROW_ACTION, - }, - }) - - const response = await automationSdk.create(automation) - - const newName = generator.guid() - const update = { ...response, name: newName } - await expect(automationSdk.update(update)).rejects.toThrow( - "Row actions cannot be renamed" - ) - }) - }) - it.each([ ["trigger", (a: Automation) => a.definition.trigger], ["step", (a: Automation) => a.definition.steps[0]], diff --git a/packages/server/src/sdk/app/automations/utils.ts b/packages/server/src/sdk/app/automations/utils.ts index 8b397df75f7..f5ae8bf9484 100644 --- a/packages/server/src/sdk/app/automations/utils.ts +++ b/packages/server/src/sdk/app/automations/utils.ts @@ -2,7 +2,6 @@ import { Automation, AutomationActionStepId, AutomationBuilderData, - TableRowActions, } from "@budibase/types" import { sdk as coreSdk } from "@budibase/shared-core" import sdk from "../../../sdk" @@ -26,15 +25,6 @@ export async function getBuilderData( return tableNameCache[tableId] } - const rowActionNameCache: Record = {} - async function getRowActionName(tableId: string, rowActionId: string) { - if (!rowActionNameCache[tableId]) { - rowActionNameCache[tableId] = await sdk.rowActions.getAll(tableId) - } - - return rowActionNameCache[tableId]?.actions[rowActionId]?.name - } - const result: Record = {} for (const automation of automations) { const isRowAction = coreSdk.automations.isRowAction(automation) @@ -49,12 +39,7 @@ export async function getBuilderData( } const tableName = await getTableName(tableId) - const rowActionName = await getRowActionName(tableId, rowActionId) - - if (!rowActionName) { - throw new Error(`Row action not found: ${rowActionId}`) - } - + const rowActionName = automation.name result[automation._id!] = { displayName: rowActionName, triggerInfo: { diff --git a/packages/server/src/sdk/app/rowActions.ts b/packages/server/src/sdk/app/rowActions.ts index 08a173ee13e..de73969696a 100644 --- a/packages/server/src/sdk/app/rowActions.ts +++ b/packages/server/src/sdk/app/rowActions.ts @@ -13,16 +13,19 @@ import { definitions as TRIGGER_DEFINITIONS } from "../../automations/triggerInf import * as triggers from "../../automations/triggers" import sdk from ".." -function ensureUniqueAndThrow( +async function ensureUniqueAndThrow( doc: TableRowActions, name: string, existingRowActionId?: string ) { + const names = await getNames(doc) + name = name.toLowerCase().trim() + if ( - Object.entries(doc.actions).find( - ([id, a]) => - a.name.toLowerCase() === name.toLowerCase() && - id !== existingRowActionId + Object.entries(names).find( + ([automationId, automationName]) => + automationName.toLowerCase().trim() === name && + automationId !== existingRowActionId ) ) { throw new HTTPError("A row action with the same name already exists.", 409) @@ -34,18 +37,12 @@ export async function create(tableId: string, rowAction: { name: string }) { const db = context.getAppDB() const rowActionsId = generateRowActionsID(tableId) - let doc: TableRowActions - try { - doc = await db.get(rowActionsId) - } catch (e: any) { - if (e.status !== 404) { - throw e - } - + let doc = await db.tryGet(rowActionsId) + if (!doc) { doc = { _id: rowActionsId, actions: {} } } - ensureUniqueAndThrow(doc, action.name) + await ensureUniqueAndThrow(doc, action.name) const appId = context.getAppId() if (!appId) { @@ -74,7 +71,6 @@ export async function create(tableId: string, rowAction: { name: string }) { }) doc.actions[newRowActionId] = { - name: action.name, automationId: automation._id!, permissions: { table: { runAllowed: true }, @@ -85,6 +81,7 @@ export async function create(tableId: string, rowAction: { name: string }) { return { id: newRowActionId, + name: automation.name, ...doc.actions[newRowActionId], } } @@ -159,20 +156,6 @@ async function updateDoc( } } -export async function update( - tableId: string, - rowActionId: string, - rowActionData: { name: string } -) { - const newName = rowActionData.name.trim() - - return await updateDoc(tableId, rowActionId, actionsDoc => { - ensureUniqueAndThrow(actionsDoc, newName, rowActionId) - actionsDoc.actions[rowActionId].name = newName - return actionsDoc - }) -} - async function guardView(tableId: string, viewId: string) { let view if (docIds.isViewId(viewId)) { @@ -248,13 +231,8 @@ export async function run( throw new HTTPError("Table not found", 404) } - const rowActions = await getAll(tableId) - const rowAction = rowActions?.actions[rowActionId] - if (!rowAction) { - throw new HTTPError("Row action not found", 404) - } - - const automation = await sdk.automations.get(rowAction.automationId) + const { automationId } = await get(tableId, rowActionId) + const automation = await sdk.automations.get(automationId) const row = await sdk.rows.find(tableId, rowId) await triggers.externalTrigger( @@ -272,3 +250,17 @@ export async function run( { getResponses: true } ) } + +export async function getNames({ actions }: TableRowActions) { + const automations = await sdk.automations.find( + Object.values(actions).map(({ automationId }) => automationId) + ) + const automationNames = automations.reduce>( + (names, a) => { + names[a._id] = a.name + return names + }, + {} + ) + return automationNames +} diff --git a/packages/server/src/tests/utilities/api/rowAction.ts b/packages/server/src/tests/utilities/api/rowAction.ts index 0fd59362577..5d5ef69b8a9 100644 --- a/packages/server/src/tests/utilities/api/rowAction.ts +++ b/packages/server/src/tests/utilities/api/rowAction.ts @@ -1,5 +1,6 @@ import { CreateRowActionRequest, + RowActionPermissionsResponse, RowActionResponse, RowActionsResponse, RowActionTriggerRequest, @@ -40,23 +41,6 @@ export class RowActionAPI extends TestAPI { ) } - update = async ( - tableId: string, - rowActionId: string, - rowAction: CreateRowActionRequest, - expectations?: Expectations, - config?: { publicUser?: boolean } - ) => { - return await this._put( - `/api/tables/${tableId}/actions/${rowActionId}`, - { - body: rowAction, - expectations, - ...config, - } - ) - } - delete = async ( tableId: string, rowActionId: string, @@ -78,7 +62,7 @@ export class RowActionAPI extends TestAPI { expectations?: Expectations, config?: { publicUser?: boolean } ) => { - return await this._post( + return await this._post( `/api/tables/${tableId}/actions/${rowActionId}/permissions`, { expectations: { @@ -96,7 +80,7 @@ export class RowActionAPI extends TestAPI { expectations?: Expectations, config?: { publicUser?: boolean } ) => { - return await this._delete( + return await this._delete( `/api/tables/${tableId}/actions/${rowActionId}/permissions`, { expectations: { @@ -115,7 +99,7 @@ export class RowActionAPI extends TestAPI { expectations?: Expectations, config?: { publicUser?: boolean } ) => { - return await this._post( + return await this._post( `/api/tables/${tableId}/actions/${rowActionId}/permissions/${viewId}`, { expectations: { @@ -134,7 +118,7 @@ export class RowActionAPI extends TestAPI { expectations?: Expectations, config?: { publicUser?: boolean } ) => { - return await this._delete( + return await this._delete( `/api/tables/${tableId}/actions/${rowActionId}/permissions/${viewId}`, { expectations: { diff --git a/packages/types/src/api/web/app/rowAction.ts b/packages/types/src/api/web/app/rowAction.ts index 0061be275ec..84e4e529edc 100644 --- a/packages/types/src/api/web/app/rowAction.ts +++ b/packages/types/src/api/web/app/rowAction.ts @@ -1,14 +1,17 @@ interface RowActionData { name: string } +interface RowActionPermissionsData { + allowedSources: string[] | undefined +} export interface CreateRowActionRequest extends RowActionData {} -export interface UpdateRowActionRequest extends RowActionData {} -export interface RowActionResponse extends RowActionData { +export interface RowActionResponse + extends RowActionData, + RowActionPermissionsData { id: string tableId: string automationId: string - allowedSources: string[] | undefined } export interface RowActionsResponse { @@ -18,3 +21,6 @@ export interface RowActionsResponse { export interface RowActionTriggerRequest { rowId: string } + +export interface RowActionPermissionsResponse + extends RowActionPermissionsData {} diff --git a/packages/types/src/documents/app/rowAction.ts b/packages/types/src/documents/app/rowAction.ts index 071b480b1c0..db3637b708b 100644 --- a/packages/types/src/documents/app/rowAction.ts +++ b/packages/types/src/documents/app/rowAction.ts @@ -6,7 +6,6 @@ export interface TableRowActions extends Document { } export interface RowActionData { - name: string automationId: string permissions: RowActionPermissions }