diff --git a/packages/server/src/api/controllers/rowAction/crud.ts b/packages/server/src/api/controllers/rowAction/crud.ts index b54a4966bf..7f3123e120 100644 --- a/packages/server/src/api/controllers/rowAction/crud.ts +++ b/packages/server/src/api/controllers/rowAction/crud.ts @@ -1,6 +1,7 @@ import { CreateRowActionRequest, Ctx, + RowActionResponse, RowActionsResponse, } from "@budibase/types" import sdk from "../../../sdk" @@ -20,7 +21,7 @@ export async function find(ctx: Ctx) { if (!(await sdk.rowActions.docExists(table._id!))) { ctx.body = { tableId: table._id!, - actions: [], + actions: {}, } return } @@ -33,15 +34,19 @@ export async function find(ctx: Ctx) { } export async function create( - ctx: Ctx + ctx: Ctx ) { const table = await getTable(ctx) - const created = await sdk.rowActions.create(table._id!, ctx.request.body) + const { id, ...createdAction } = await sdk.rowActions.create( + table._id!, + ctx.request.body + ) ctx.body = { tableId: table._id!, - ...created, + actionId: id, + ...createdAction, } ctx.status = 201 } diff --git a/packages/server/src/api/routes/tests/rowAction.spec.ts b/packages/server/src/api/routes/tests/rowAction.spec.ts index a241a23c6b..bee6964956 100644 --- a/packages/server/src/api/routes/tests/rowAction.spec.ts +++ b/packages/server/src/api/routes/tests/rowAction.spec.ts @@ -1,7 +1,7 @@ import _ from "lodash" import tk from "timekeeper" -import { CreateRowActionRequest } from "@budibase/types" +import { CreateRowActionRequest, RowActionResponse } from "@budibase/types" import * as setup from "./utilities" import { generator } from "@budibase/backend-core/tests" import { Expectations } from "src/tests/utilities/api/base" @@ -46,6 +46,12 @@ describe("/rowsActions", () => { } } + function createRowActionRequests(count: number): CreateRowActionRequest[] { + return generator + .unique(() => generator.word(), count) + .map(name => ({ name })) + } + function unauthorisedTests() { it("returns unauthorised (401) for unauthenticated requests", async () => { await createRowAction( @@ -84,85 +90,49 @@ describe("/rowsActions", () => { it("creates new row actions for tables without existing actions", async () => { const rowAction = createRowActionRequest() - - const res = await createRowAction(tableId, rowAction, { status: 201 }) + const res = await createRowAction(tableId, rowAction, { + status: 201, + }) expect(res).toEqual({ + tableId: tableId, + actionId: expect.stringMatching(/^row_action_\w+/), + ...rowAction, + }) + + expect(await config.api.rowAction.find(tableId)).toEqual({ _id: `ra_${tableId}`, _rev: expect.stringMatching(/^1-\w+/), - actions: [ - { - id: expect.any(String), - name: rowAction.name, - }, - ], tableId: tableId, + actions: { + [res.actionId]: rowAction, + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }) }) it("can create multiple row actions for the same table", async () => { - const rowActions = generator.unique(() => createRowActionRequest(), 3) + const rowActions = createRowActionRequests(3) + const responses: RowActionResponse[] = [] + for (const action of rowActions) { + responses.push(await createRowAction(tableId, action)) + } - await createRowAction(tableId, rowActions[0]) - await createRowAction(tableId, rowActions[1]) - const res = await createRowAction(tableId, rowActions[2]) - - expect(res).toEqual({ + expect(await config.api.rowAction.find(tableId)).toEqual({ _id: `ra_${tableId}`, _rev: expect.stringMatching(/^3-\w+/), - actions: rowActions.map(a => ({ - id: expect.any(String), - ...a, - })), + actions: { + [responses[0].actionId]: rowActions[0], + [responses[1].actionId]: rowActions[1], + [responses[2].actionId]: rowActions[2], + }, tableId: tableId, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }) }) - it("can create row actions for different tables", async () => { - const otherTable = await config.api.table.save( - setup.structures.basicTable() - ) - const otherTableId = otherTable._id! - - const rowAction1 = createRowActionRequest() - const rowAction2 = createRowActionRequest() - - const res1 = await createRowAction(tableId, rowAction1) - const res2 = await createRowAction(otherTableId, rowAction2) - - expect(res1).toEqual({ - _id: `ra_${tableId}`, - _rev: expect.stringMatching(/^1-\w+/), - actions: [ - { - id: expect.any(String), - ...rowAction1, - }, - ], - tableId: tableId, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }) - - expect(res2).toEqual({ - _id: `ra_${otherTableId}`, - _rev: expect.stringMatching(/^1-\w+/), - actions: [ - { - id: expect.any(String), - ...rowAction2, - }, - ], - tableId: otherTableId, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }) - }) - it("rejects with bad request when creating with no name", async () => { const rowAction: CreateRowActionRequest = { name: "", @@ -181,25 +151,25 @@ describe("/rowsActions", () => { unauthorisedTests() it("returns only the actions for the requested table", async () => { - const rowActions = generator.unique(() => createRowActionRequest(), 5) - for (const rowAction of rowActions) { - await createRowAction(tableId, rowAction) + const rowActions: RowActionResponse[] = [] + for (const action of createRowActionRequests(3)) { + rowActions.push(await createRowAction(tableId, action)) } const otherTable = await config.api.table.save( setup.structures.basicTable() ) - const otherTableId = otherTable._id! - await createRowAction(otherTableId, createRowActionRequest()) + await createRowAction(otherTable._id!, createRowActionRequest()) const response = await config.api.rowAction.find(tableId) expect(response).toEqual( expect.objectContaining({ tableId, - actions: rowActions.map(a => ({ - id: expect.any(String), - ...a, - })), + actions: { + [rowActions[0].actionId]: expect.any(Object), + [rowActions[1].actionId]: expect.any(Object), + [rowActions[2].actionId]: expect.any(Object), + }, }) ) }) @@ -209,7 +179,7 @@ describe("/rowsActions", () => { expect(response).toEqual( expect.objectContaining({ tableId, - actions: [], + actions: {}, }) ) }) diff --git a/packages/server/src/sdk/app/rowActions.ts b/packages/server/src/sdk/app/rowActions.ts index c283c183b8..fa60a075c9 100644 --- a/packages/server/src/sdk/app/rowActions.ts +++ b/packages/server/src/sdk/app/rowActions.ts @@ -1,7 +1,11 @@ import { context, utils } from "@budibase/backend-core" import { generateRowActionsID } from "../../db/utils" -import { TableRowActions } from "@budibase/types" +import { + SEPARATOR, + TableRowActions, + VirtualDocumentType, +} from "@budibase/types" export async function create(tableId: string, rowAction: { name: string }) { const db = context.getAppDB() @@ -14,16 +18,17 @@ export async function create(tableId: string, rowAction: { name: string }) { throw e } - doc = { _id: rowActionsId, actions: [] } + doc = { _id: rowActionsId, actions: {} } } - doc.actions.push({ - id: utils.newid(), - ...rowAction, - }) + const newId = `${VirtualDocumentType.ROW_ACTION}${SEPARATOR}${utils.newid()}` + doc.actions[newId] = rowAction await db.put(doc) - return await get(tableId) + return { + id: newId, + ...rowAction, + } } export async function get(tableId: string) { diff --git a/packages/server/src/tests/utilities/api/rowAction.ts b/packages/server/src/tests/utilities/api/rowAction.ts index 583475b666..a7c3932bc4 100644 --- a/packages/server/src/tests/utilities/api/rowAction.ts +++ b/packages/server/src/tests/utilities/api/rowAction.ts @@ -1,4 +1,8 @@ -import { CreateRowActionRequest, RowActionsResponse } from "@budibase/types" +import { + CreateRowActionRequest, + RowActionResponse, + RowActionsResponse, +} from "@budibase/types" import { Expectations, TestAPI } from "./base" export class RowActionAPI extends TestAPI { @@ -8,7 +12,7 @@ export class RowActionAPI extends TestAPI { expectations?: Expectations, config?: { publicUser?: boolean } ) => { - return await this._post( + return await this._post( `/api/tables/${tableId}/actions`, { body: rowAction, diff --git a/packages/types/src/api/web/app/rowAction.ts b/packages/types/src/api/web/app/rowAction.ts index dc2731f9b6..3219a5e4b7 100644 --- a/packages/types/src/api/web/app/rowAction.ts +++ b/packages/types/src/api/web/app/rowAction.ts @@ -1,11 +1,15 @@ -export interface CreateRowActionRequest { - name: string +export interface CreateRowActionRequest extends RowActionData {} + +export interface RowActionResponse extends RowActionData { + tableId: string + actionId: string } export interface RowActionsResponse { tableId: string - actions: { - id: string - name: string - }[] + actions: Record +} + +interface RowActionData { + name: string } diff --git a/packages/types/src/documents/app/index.ts b/packages/types/src/documents/app/index.ts index f6726fd53c..2b13676ba1 100644 --- a/packages/types/src/documents/app/index.ts +++ b/packages/types/src/documents/app/index.ts @@ -16,4 +16,4 @@ export * from "./links" export * from "./component" export * from "./sqlite" export * from "./snippet" -export * from "./rowActions" +export * from "./rowAction" diff --git a/packages/types/src/documents/app/rowActions.ts b/packages/types/src/documents/app/rowAction.ts similarity index 62% rename from packages/types/src/documents/app/rowActions.ts rename to packages/types/src/documents/app/rowAction.ts index 5eaf5de5d6..ea55d5dcd2 100644 --- a/packages/types/src/documents/app/rowActions.ts +++ b/packages/types/src/documents/app/rowAction.ts @@ -2,8 +2,10 @@ import { Document } from "../document" export interface TableRowActions extends Document { _id: string - actions: { - id: string - name: string - }[] + actions: Record< + string, + { + name: string + } + > } diff --git a/packages/types/src/documents/document.ts b/packages/types/src/documents/document.ts index 23aec05ee5..f5facfae9d 100644 --- a/packages/types/src/documents/document.ts +++ b/packages/types/src/documents/document.ts @@ -69,6 +69,7 @@ export enum InternalTable { // documents or enriched into existence as part of get requests export enum VirtualDocumentType { VIEW = "view", + ROW_ACTION = "row_action", } export interface Document {