From 4836fbc1668413ba6463678446ecd0b08c1bd14d Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 3 Oct 2022 12:50:16 +0800 Subject: [PATCH] feat(nocodb): prevent column deletion if it is being used in kanban --- .../nocodb/src/lib/meta/api/columnApis.ts | 19 ++++++++++++++++--- packages/nocodb/src/lib/models/KanbanView.ts | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/meta/api/columnApis.ts b/packages/nocodb/src/lib/meta/api/columnApis.ts index 42938b6085..c99cb77eb2 100644 --- a/packages/nocodb/src/lib/meta/api/columnApis.ts +++ b/packages/nocodb/src/lib/meta/api/columnApis.ts @@ -34,6 +34,7 @@ import mapDefaultPrimaryValue from '../helpers/mapDefaultPrimaryValue'; import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; import { metaApiMetrics } from '../helpers/apiMetrics'; import FormulaColumn from '../../models/FormulaColumn'; +import KanbanView from '../../models/KanbanView'; import { MetaTable } from '../../utils/globals'; const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10); @@ -541,7 +542,7 @@ export async function columnAdd(req: Request, res: Response) { // handle single quote for default value if (driverType === 'mysql' || driverType === 'mysql2') { - colBody.cdf = colBody.cdf.replace(/'/g, "\'"); + colBody.cdf = colBody.cdf.replace(/'/g, "'"); } else { colBody.cdf = colBody.cdf.replace(/'/g, "''"); } @@ -837,7 +838,7 @@ export async function columnUpdate(req: Request, res: Response) { // handle single quote for default value if (driverType === 'mysql' || driverType === 'mysql2') { - colBody.cdf = colBody.cdf.replace(/'/g, "\'"); + colBody.cdf = colBody.cdf.replace(/'/g, "'"); } else { colBody.cdf = colBody.cdf.replace(/'/g, "''"); } @@ -1509,9 +1510,21 @@ export async function columnDelete(req: Request, res: Response) { } Tele.emit('evt', { evt_type: 'raltion:deleted' }); break; - case UITypes.ForeignKey: + case UITypes.ForeignKey: { NcError.notImplemented(); break; + } + // @ts-expect-error + case UITypes.SingleSelect: { + if (column.uidt === UITypes.SingleSelect) { + if (await KanbanView.IsColumnBeingUsedAsGroupingField(column.id)) { + NcError.badRequest( + `The column '${column.column_name}' is being used in Kanban View. Please delete Kanban View first.` + ); + } + } + /* falls through to default */ + } default: { const tableUpdateBody = { ...table, diff --git a/packages/nocodb/src/lib/models/KanbanView.ts b/packages/nocodb/src/lib/models/KanbanView.ts index 1b3d1a00e6..fb5652df9d 100644 --- a/packages/nocodb/src/lib/models/KanbanView.ts +++ b/packages/nocodb/src/lib/models/KanbanView.ts @@ -42,6 +42,21 @@ export default class KanbanView implements KanbanType { return view && new KanbanView(view); } + public static async IsColumnBeingUsedAsGroupingField( + columnId: string, + ncMeta = Noco.ncMeta + ) { + return ( + ( + await ncMeta.metaList2(null, null, MetaTable.KANBAN_VIEW, { + condition: { + grp_column_id: columnId, + }, + }) + ).length > 0 + ); + } + static async insert(view: Partial, ncMeta = Noco.ncMeta) { const insertObj = { project_id: view.project_id,