From 7dbfcc398e4c63824a738ea67a948b765652fc12 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Thu, 11 Jul 2024 10:04:25 +0200
Subject: [PATCH] Implement create

---
 .../src/api/controllers/rowAction/crud.ts     | 12 ++++++--
 .../src/api/routes/tests/rowAction.spec.ts    | 16 ++++++++--
 packages/server/src/db/utils.ts               |  8 +++++
 packages/server/src/sdk/app/rowActions.ts     | 30 +++++++++++++++++++
 packages/server/src/sdk/index.ts              |  2 ++
 packages/types/src/api/web/app/rowAction.ts   |  8 ++---
 packages/types/src/documents/app/index.ts     |  1 +
 .../types/src/documents/app/rowActions.ts     |  8 +++++
 8 files changed, 74 insertions(+), 11 deletions(-)
 create mode 100644 packages/server/src/sdk/app/rowActions.ts
 create mode 100644 packages/types/src/documents/app/rowActions.ts

diff --git a/packages/server/src/api/controllers/rowAction/crud.ts b/packages/server/src/api/controllers/rowAction/crud.ts
index 83b4215f35..53a417b223 100644
--- a/packages/server/src/api/controllers/rowAction/crud.ts
+++ b/packages/server/src/api/controllers/rowAction/crud.ts
@@ -25,12 +25,18 @@ export async function find(ctx: Ctx<void, RowActionsResponse>) {
   }
 }
 
-export async function create(ctx: Ctx<CreateRowActionRequest, void>) {
+export async function create(
+  ctx: Ctx<CreateRowActionRequest, RowActionsResponse>
+) {
   const table = await getTable(ctx)
 
-  // TODO
+  const created = await sdk.rowActions.create(table._id!, ctx.request.body)
 
-  ctx.status = 204
+  ctx.body = {
+    tableId: table._id!,
+    ...created,
+  }
+  ctx.status = 201
 }
 
 export function update() {
diff --git a/packages/server/src/api/routes/tests/rowAction.spec.ts b/packages/server/src/api/routes/tests/rowAction.spec.ts
index ea97e526d5..bd7932d352 100644
--- a/packages/server/src/api/routes/tests/rowAction.spec.ts
+++ b/packages/server/src/api/routes/tests/rowAction.spec.ts
@@ -1,4 +1,6 @@
 import _ from "lodash"
+import tk from "timekeeper"
+
 import { CreateRowActionRequest, Table } from "@budibase/types"
 import * as setup from "./utilities"
 import { generator } from "@budibase/backend-core/tests"
@@ -9,6 +11,7 @@ describe("/rowsActions", () => {
   let table: Table
 
   beforeAll(async () => {
+    tk.freeze(new Date())
     await config.init()
 
     table = await config.api.table.save(setup.structures.basicTable())
@@ -62,14 +65,21 @@ describe("/rowsActions", () => {
   describe("create", () => {
     unauthorisedTests()
 
-    it("accepts creating new row actions", async () => {
+    it("accepts creating new row actions for", async () => {
       const rowAction = createRowActionRequest()
 
       const res = await config.api.rowAction.save(table._id!, rowAction, {
-        status: 204,
+        status: 201,
       })
 
-      expect(res).toEqual({})
+      expect(res).toEqual({
+        _id: `${table._id}_row_actions`,
+        _rev: expect.stringMatching(/^1-\w+/),
+        actions: [{ name: rowAction.name }],
+        tableId: table._id,
+        createdAt: new Date().toISOString(),
+        updatedAt: new Date().toISOString(),
+      })
     })
 
     it("rejects with bad request when creating with no name", async () => {
diff --git a/packages/server/src/db/utils.ts b/packages/server/src/db/utils.ts
index 3bd1749d77..32e72ffad7 100644
--- a/packages/server/src/db/utils.ts
+++ b/packages/server/src/db/utils.ts
@@ -348,3 +348,11 @@ export function isRelationshipColumn(
 ): column is RelationshipFieldMetadata {
   return column.type === FieldType.LINK
 }
+
+/**
+ * Generates a new row actions ID.
+ * @returns The new row actions ID which the row actions doc can be stored under.
+ */
+export function generateRowActionsID(tableId: string) {
+  return `${tableId}${SEPARATOR}row_actions`
+}
diff --git a/packages/server/src/sdk/app/rowActions.ts b/packages/server/src/sdk/app/rowActions.ts
new file mode 100644
index 0000000000..bfc4155289
--- /dev/null
+++ b/packages/server/src/sdk/app/rowActions.ts
@@ -0,0 +1,30 @@
+import { context } from "@budibase/backend-core"
+
+import { generateRowActionsID } from "../../db/utils"
+import { TableRowActions } from "@budibase/types"
+
+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<TableRowActions>(rowActionsId)
+  } catch (e: any) {
+    if (e.status !== 404) {
+      throw e
+    }
+
+    doc = { _id: rowActionsId, actions: [] }
+  }
+
+  doc.actions.push(rowAction)
+  await db.put(doc)
+
+  return await get(tableId)
+}
+
+export async function get(tableId: string) {
+  const db = context.getAppDB()
+  const rowActionsId = generateRowActionsID(tableId)
+  return await db.get<TableRowActions>(rowActionsId)
+}
diff --git a/packages/server/src/sdk/index.ts b/packages/server/src/sdk/index.ts
index c3057e3d4f..a871546b60 100644
--- a/packages/server/src/sdk/index.ts
+++ b/packages/server/src/sdk/index.ts
@@ -10,6 +10,7 @@ import { default as users } from "./users"
 import { default as plugins } from "./plugins"
 import * as views from "./app/views"
 import * as permissions from "./app/permissions"
+import * as rowActions from "./app/rowActions"
 
 const sdk = {
   backups,
@@ -24,6 +25,7 @@ const sdk = {
   views,
   permissions,
   links,
+  rowActions,
 }
 
 // default export for TS
diff --git a/packages/types/src/api/web/app/rowAction.ts b/packages/types/src/api/web/app/rowAction.ts
index fceb606699..fd42de20f8 100644
--- a/packages/types/src/api/web/app/rowAction.ts
+++ b/packages/types/src/api/web/app/rowAction.ts
@@ -2,11 +2,9 @@ export interface CreateRowActionRequest {
   name: string
 }
 
-interface RowAction {
-  name: string
-}
-
 export interface RowActionsResponse {
   tableId: string
-  actions: RowAction[]
+  actions: {
+    name: string
+  }[]
 }
diff --git a/packages/types/src/documents/app/index.ts b/packages/types/src/documents/app/index.ts
index 3809fba6e5..f6726fd53c 100644
--- a/packages/types/src/documents/app/index.ts
+++ b/packages/types/src/documents/app/index.ts
@@ -16,3 +16,4 @@ export * from "./links"
 export * from "./component"
 export * from "./sqlite"
 export * from "./snippet"
+export * from "./rowActions"
diff --git a/packages/types/src/documents/app/rowActions.ts b/packages/types/src/documents/app/rowActions.ts
new file mode 100644
index 0000000000..d6dea34f2e
--- /dev/null
+++ b/packages/types/src/documents/app/rowActions.ts
@@ -0,0 +1,8 @@
+import { Document } from "../document"
+
+export interface TableRowActions extends Document {
+  _id: string
+  actions: {
+    name: string
+  }[]
+}