From 4d15dd6cfc415de379a4c4613b397607a97dfb09 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 16 Apr 2024 07:14:17 +0000 Subject: [PATCH] feat: view columns api --- .../controllers/view-columns.controller.ts | 17 +++ .../nocodb/src/models/GalleryViewColumn.ts | 3 + packages/nocodb/src/models/View.ts | 92 +++++++++++- .../src/services/view-columns.service.ts | 131 +++++++++++++++++- 4 files changed, 240 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/controllers/view-columns.controller.ts b/packages/nocodb/src/controllers/view-columns.controller.ts index 9647b342de..6d26fc81d9 100644 --- a/packages/nocodb/src/controllers/view-columns.controller.ts +++ b/packages/nocodb/src/controllers/view-columns.controller.ts @@ -73,4 +73,21 @@ export class ViewColumnsController { }); return result; } + + + + @Patch( + '/api/v3/meta/views/:viewId/columns', + ) + @Acl('columnList') + async columnUpdate(@Param('viewId') viewId: string, @Body() body: ViewColumnReqType[] | Record) { + return new PagedResponseImpl( + await this.viewColumnsService.columnsUpdate({ + viewId, + columns: body, + req + }), + ); + } + } diff --git a/packages/nocodb/src/models/GalleryViewColumn.ts b/packages/nocodb/src/models/GalleryViewColumn.ts index 6ea557ef75..73c16810c2 100644 --- a/packages/nocodb/src/models/GalleryViewColumn.ts +++ b/packages/nocodb/src/models/GalleryViewColumn.ts @@ -121,4 +121,7 @@ export default class GalleryViewColumn { ); return views?.map((v) => new GalleryViewColumn(v)); } + + // todo: update method + } diff --git a/packages/nocodb/src/models/View.ts b/packages/nocodb/src/models/View.ts index 7aa326f58d..303e8b3129 100644 --- a/packages/nocodb/src/models/View.ts +++ b/packages/nocodb/src/models/View.ts @@ -1196,6 +1196,94 @@ export default class View implements ViewType { ); } + private static extractViewColumnsTableName(view: View) { + let table; + switch (view.type) { + case ViewTypes.GRID: + table = MetaTable.GRID_VIEW_COLUMNS; + break; + case ViewTypes.GALLERY: + table = MetaTable.GALLERY_VIEW_COLUMNS; + break; + case ViewTypes.KANBAN: + table = MetaTable.KANBAN_VIEW_COLUMNS; + break; + case ViewTypes.FORM: + table = MetaTable.FORM_VIEW_COLUMNS; + break; + case ViewTypes.MAP: + table = MetaTable.MAP_VIEW_COLUMNS; + break; + } + return table; + } + + private static extractViewTableName(view: View) { + let table; + switch (view.type) { + case ViewTypes.GRID: + table = MetaTable.GRID_VIEW; + break; + case ViewTypes.GALLERY: + table = MetaTable.GALLERY_VIEW; + break; + case ViewTypes.KANBAN: + table = MetaTable.KANBAN_VIEW; + break; + case ViewTypes.FORM: + table = MetaTable.FORM_VIEW; + break; + case ViewTypes.MAP: + table = MetaTable.MAP_VIEW; + break; + } + return table; + } + + private static extractViewColumnsTableNameScope(view: View) { + let scope; + switch (view.type) { + case ViewTypes.GRID: + scope = CacheScope.GRID_VIEW_COLUMN; + break; + case ViewTypes.GALLERY: + scope = CacheScope.GALLERY_VIEW_COLUMN; + break; + case ViewTypes.MAP: + scope = CacheScope.MAP_VIEW_COLUMN; + break; + case ViewTypes.KANBAN: + scope = CacheScope.KANBAN_VIEW_COLUMN; + break; + case ViewTypes.FORM: + scope = CacheScope.FORM_VIEW_COLUMN; + break; + } + return scope; + } + + private static extractViewTableNameScope(view: View) { + let scope; + switch (view.type) { + case ViewTypes.GRID: + scope = CacheScope.GRID_VIEW; + break; + case ViewTypes.GALLERY: + scope = CacheScope.GALLERY_VIEW; + break; + case ViewTypes.MAP: + scope = CacheScope.MAP_VIEW; + break; + case ViewTypes.KANBAN: + scope = CacheScope.KANBAN_VIEW; + break; + case ViewTypes.FORM: + scope = CacheScope.FORM_VIEW; + break; + } + return scope; + } + static async showAllColumns( viewId, ignoreColdIds = [], @@ -1948,7 +2036,7 @@ export default class View implements ViewType { return insertedView; } - private static extractViewColumnsTableName(view: View) { + protected static extractViewColumnsTableName(view: View) { let table; switch (view.type) { case ViewTypes.GRID: @@ -1973,7 +2061,7 @@ export default class View implements ViewType { return table; } - private static extractViewTableName(view: View) { + protected static extractViewTableName(view: View) { let table; switch (view.type) { case ViewTypes.GRID: diff --git a/packages/nocodb/src/services/view-columns.service.ts b/packages/nocodb/src/services/view-columns.service.ts index 333ebfbba5..adfdd69c4a 100644 --- a/packages/nocodb/src/services/view-columns.service.ts +++ b/packages/nocodb/src/services/view-columns.service.ts @@ -1,10 +1,17 @@ import { Injectable } from '@nestjs/common'; -import { AppEvents } from 'nocodb-sdk'; +import { AppEvents, ViewTypes } from 'nocodb-sdk'; +import GridViewColumn from '../models/GridViewColumn'; +import GalleryViewColumn from '../models/GalleryViewColumn'; +import KanbanViewColumn from '../models/KanbanViewColumn'; +import MapViewColumn from '../models/MapViewColumn'; +import FormViewColumn from '../models/FormViewColumn'; import type { ViewColumnReqType, ViewColumnUpdateReqType } from 'nocodb-sdk'; import type { NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { View } from '~/models'; +import { NcError } from '~/helpers/catchError'; +import Noco from '~/Noco'; @Injectable() export class ViewColumnsService { @@ -13,6 +20,7 @@ export class ViewColumnsService { async columnList(param: { viewId: string }) { return await View.getColumns(param.viewId, undefined); } + async columnAdd(param: { viewId: string; column: ViewColumnReqType; @@ -63,4 +71,125 @@ export class ViewColumnsService { return result; } + + async columnsUpdate(param: { + viewId: string; + columns: ViewColumnReqType[] | Record; + req: any; + }) { + const { viewId, columns } = param; + + const view = await View.get(viewId); + + + const updateOrInsertOptions: Promise[] = []; + + let result: any; + const ncMeta = await Noco.ncMeta.startTransaction(); + try { + if (!view) { + NcError.notFound('View not found'); + } + + const table = View.extractViewColumnsTableName(view); + + // iterate over view columns and update/insert accordingly + for (const [indexOrId, column] of Object.entries(columns)) { + const columnId = + typeof param.columns === 'object' ? indexOrId : column.id; + + const existingCol = await ncMeta.metaGet2(null, null, table, { + fk_view_id: viewId, + fk_column_id: columnId, + }); + + switch (view.type) { + case ViewTypes.GRID: + if (existingCol) { + updateOrInsertOptions.push( + GridViewColumn.update(existingCol.id, column, ncMeta), + ); + } else { + updateOrInsertOptions.push( + GridViewColumn.insert({ + fk_view_id: viewId, + fk_column_id: columnId, + ...column, + }, ncMeta), + ); + } + case ViewTypes.GALLERY: + if (existingCol) { + updateOrInsertOptions.push( + GalleryViewColumn.update(existingCol.id, column, ncMeta), + ); + } else { + updateOrInsertOptions.push( + GalleryViewColumn.insert({ + fk_view_id: viewId, + fk_column_id: columnId, + ...column, + }, ncMeta), + ); + } + case ViewTypes.KANBAN: + if (existingCol) { + updateOrInsertOptions.push( + KanbanViewColumn.update(existingCol.id, column, ncMeta), + ); + } else { + updateOrInsertOptions.push( + KanbanViewColumn.insert({ + fk_view_id: viewId, + fk_column_id: columnId, + ...column, + }, ncMeta), + ); + } + break; + case ViewTypes.MAP: + if (existingCol) { + updateOrInsertOptions.push( + MapViewColumn.update(existingCol.id, column, ncMeta), + ); + } else { + updateOrInsertOptions.push( + MapViewColumn.insert({ + fk_view_id: viewId, + fk_column_id: columnId, + ...column, + }, ncMeta), + ); + } + break; + case ViewTypes.FORM: + if (existingCol) { + updateOrInsertOptions.push( + FormViewColumn.update(existingCol.id, column, ncMeta), + ); + } else { + updateOrInsertOptions.push( + FormViewColumn.insert({ + fk_view_id: viewId, + fk_column_id: columnId, + ...column, + }, ncMeta), + ); + } + break; + } + } + + await Promise.all(updateOrInsertOptions); + + await ncMeta.commit(); + + await View.clearSingleQueryCache(view.fk_model_id, [view]); + + return result; + } catch (e) { + await ncMeta.rollback(); + throw e; + } + } }