Properly clean up row actions on table deletion.
This commit is contained in:
parent
f0d52f2ea0
commit
a00a64bb6e
|
@ -139,6 +139,7 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
|
||||||
export async function destroy(ctx: UserCtx) {
|
export async function destroy(ctx: UserCtx) {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
|
await sdk.rowActions.deleteAll(tableId)
|
||||||
const deletedTable = await pickApi({ tableId }).destroy(ctx)
|
const deletedTable = await pickApi({ tableId }).destroy(ctx)
|
||||||
await events.table.deleted(deletedTable)
|
await events.table.deleted(deletedTable)
|
||||||
ctx.eventEmitter &&
|
ctx.eventEmitter &&
|
||||||
|
|
|
@ -1041,4 +1041,44 @@ describe("/rowsActions", () => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("scenarios", () => {
|
||||||
|
// https://linear.app/budibase/issue/BUDI-8717/
|
||||||
|
it("should not brick the app when deleting a table with row actions", async () => {
|
||||||
|
const view = await config.api.viewV2.create({
|
||||||
|
tableId,
|
||||||
|
name: generator.guid(),
|
||||||
|
schema: {
|
||||||
|
name: { visible: true },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const rowAction = await config.api.rowAction.save(tableId, {
|
||||||
|
name: generator.guid(),
|
||||||
|
})
|
||||||
|
|
||||||
|
await config.api.rowAction.setViewPermission(
|
||||||
|
tableId,
|
||||||
|
view.id,
|
||||||
|
rowAction.id
|
||||||
|
)
|
||||||
|
|
||||||
|
let actionsResp = await config.api.rowAction.find(tableId)
|
||||||
|
expect(actionsResp.actions[rowAction.id]).toEqual({
|
||||||
|
...rowAction,
|
||||||
|
allowedSources: [tableId, view.id],
|
||||||
|
})
|
||||||
|
|
||||||
|
const table = await config.api.table.get(tableId)
|
||||||
|
await config.api.table.destroy(table._id!, table._rev!)
|
||||||
|
|
||||||
|
// In the bug reported by Conor, when a delete got deleted its row action
|
||||||
|
// document was not being cleaned up. This meant there existed code paths
|
||||||
|
// that would find it and try to reference the tables within it, resulting
|
||||||
|
// in errors.
|
||||||
|
await config.api.automation.fetchEnriched({
|
||||||
|
status: 200,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { context, docIds, HTTPError, utils } from "@budibase/backend-core"
|
import { context, docIds, HTTPError, utils } from "@budibase/backend-core"
|
||||||
import {
|
import {
|
||||||
|
Automation,
|
||||||
AutomationTriggerStepId,
|
AutomationTriggerStepId,
|
||||||
SEPARATOR,
|
SEPARATOR,
|
||||||
TableRowActions,
|
TableRowActions,
|
||||||
|
@ -105,6 +106,20 @@ export async function getAll(tableId: string) {
|
||||||
return await db.get<TableRowActions>(rowActionsId)
|
return await db.get<TableRowActions>(rowActionsId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteAll(tableId: string) {
|
||||||
|
const db = context.getAppDB()
|
||||||
|
|
||||||
|
const doc = await getAll(tableId)
|
||||||
|
const automationIds = Object.values(doc.actions).map(a => a.automationId)
|
||||||
|
const automations = await db.getMultiple<Automation>(automationIds)
|
||||||
|
|
||||||
|
for (const automation of automations) {
|
||||||
|
await sdk.automations.remove(automation._id!, automation._rev!)
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.remove(doc)
|
||||||
|
}
|
||||||
|
|
||||||
export async function docExists(tableId: string) {
|
export async function docExists(tableId: string) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const rowActionsId = generateRowActionsID(tableId)
|
const rowActionsId = generateRowActionsID(tableId)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Automation } from "@budibase/types"
|
import { Automation, FetchAutomationResponse } from "@budibase/types"
|
||||||
import { Expectations, TestAPI } from "./base"
|
import { Expectations, TestAPI } from "./base"
|
||||||
|
|
||||||
export class AutomationAPI extends TestAPI {
|
export class AutomationAPI extends TestAPI {
|
||||||
|
@ -14,6 +14,26 @@ export class AutomationAPI extends TestAPI {
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetch = async (
|
||||||
|
expectations?: Expectations
|
||||||
|
): Promise<FetchAutomationResponse> => {
|
||||||
|
return await this._get<FetchAutomationResponse>(`/api/automations`, {
|
||||||
|
expectations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchEnriched = async (
|
||||||
|
expectations?: Expectations
|
||||||
|
): Promise<FetchAutomationResponse> => {
|
||||||
|
return await this._get<FetchAutomationResponse>(
|
||||||
|
`/api/automations?enrich=true`,
|
||||||
|
{
|
||||||
|
expectations,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
post = async (
|
post = async (
|
||||||
body: Automation,
|
body: Automation,
|
||||||
expectations?: Expectations
|
expectations?: Expectations
|
||||||
|
|
Loading…
Reference in New Issue