From 8307bc2970368e1f65549e601600e0c9648ffc06 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 13 Oct 2021 20:35:11 +0530 Subject: [PATCH] fix: handle form view query params detail on table operations Handle following events - Table delete - Table update - Relation delete Signed-off-by: Pranav C --- .../components/spreadsheetNavDrawer.vue | 2 +- .../project/spreadsheet/public/xcForm.vue | 2 +- .../nocodb/src/lib/noco/NcProjectBuilder.ts | 2 +- .../src/lib/noco/common/BaseApiBuilder.ts | 379 ++++++++++++++++-- .../nocodb/src/lib/noco/meta/NcMetaMgr.ts | 6 +- .../nocodb/src/lib/noco/meta/NcMetaMgrEE.ts | 2 +- .../nc_007_alter_nc_shared_views_1.ts | 2 +- 7 files changed, 346 insertions(+), 49 deletions(-) diff --git a/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue b/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue index 48c6408680..e345444df4 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue @@ -760,7 +760,7 @@ export default { 'createSharedViewLink', { model_name: this.table, - meta: this.meta, + // meta: this.meta, query_params: { where: this.concatenatedXWhere, sort: this.sort, diff --git a/packages/nc-gui/components/project/spreadsheet/public/xcForm.vue b/packages/nc-gui/components/project/spreadsheet/public/xcForm.vue index cf2091a58c..7e3ad8cb6f 100644 --- a/packages/nc-gui/components/project/spreadsheet/public/xcForm.vue +++ b/packages/nc-gui/components/project/spreadsheet/public/xcForm.vue @@ -298,7 +298,7 @@ export default { password: this.password }]) this.client = client - this.meta = JSON.parse(meta) + this.meta = meta this.query_params = JSON.parse(qp) this.dbAlias = dbAlias this.metas = relatedTableMetas diff --git a/packages/nocodb/src/lib/noco/NcProjectBuilder.ts b/packages/nocodb/src/lib/noco/NcProjectBuilder.ts index 833b646513..363732fddc 100644 --- a/packages/nocodb/src/lib/noco/NcProjectBuilder.ts +++ b/packages/nocodb/src/lib/noco/NcProjectBuilder.ts @@ -275,7 +275,7 @@ export default class NcProjectBuilder { console.log(`Updated validations for table : ${data.req.args.tn}`); break; case 'xcUpdateVirtualKeyAlias': - await curBuilder.onVirtualColumnAliasUpdate(data.req.args.tn); + await curBuilder.onVirtualColumnAliasUpdate(data.req.args); console.log(`Updated validations for table : ${data.req.args.tn}`); break; diff --git a/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts b/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts index f359d99779..9303adbc9f 100644 --- a/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts +++ b/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts @@ -206,7 +206,7 @@ export default abstract class BaseApiBuilder public async onTableDelete(tn: string): Promise { this.baseLog(`onTableDelete : '%s'`, tn); XcCache.del([this.projectId, this.dbAlias, 'table', tn].join('::')); - return this.xcMeta.metaDelete( + await this.xcMeta.metaDelete( this.projectId, this.dbAlias, 'nc_relations', @@ -227,6 +227,15 @@ export default abstract class BaseApiBuilder } ); await this.deleteTableNameInACL(tn); + + await this.xcMeta.metaDelete( + this.projectId, + this.dbAlias, + 'nc_shared_views', + { + model_name: tn + } + ); } public async onRelationCreate( @@ -311,6 +320,127 @@ export default abstract class BaseApiBuilder XcCache.del([this.projectId, this.dbAlias, 'table', tnc].join('::')); XcCache.del([this.projectId, this.dbAlias, 'table', tnp].join('::')); + + for (const tn of [tnc, tnp]) { + const { + virtualViews, + sharedViews, + virtualViewsParamsArr, + sharedViewsParamsArr + } = await this.extractSharedAndVirtualViewsParams(tn); + + // extract alias of relation virtual column + const relation = tnc === tn ? 'bt' : 'hm'; + const alias = this.getMeta(tn)?.v?.find( + v => v?.[relation]?.tn === tnc && v?.[relation]?.rtn === tnp + )?._cn; + + // virtual views param update + for (const qp of [...virtualViewsParamsArr, ...sharedViewsParamsArr]) { + // @ts-ignore + const { showFields = {}, fieldsOrder, extraViewParams = {} } = qp; + + /* update show field */ + if (alias in showFields) { + delete showFields[alias]; + } + + /* update fieldsOrder */ + const index = fieldsOrder.indexOf(alias); + if (index > -1) { + fieldsOrder.splice(index, 0); + } + + /* update formView params */ + // extraViewParams.formParams.fields + if (extraViewParams?.formParams?.fields?.[alias]) { + delete extraViewParams.formParams.fields[alias]; + } + } + await this.updateSharedAndVirtualViewsParams( + virtualViewsParamsArr, + virtualViews, + sharedViewsParamsArr, + sharedViews + ); + } + } + + private async updateSharedAndVirtualViewsParams( + virtualViewsParamsArr: any[], + virtualViews: any[], + sharedViewsParamsArr: any[], + sharedViews: any[] + ) { + // update virtual views params + for (let i = 0; i < virtualViewsParamsArr.length; i++) { + await this.xcMeta.metaUpdate( + this.projectId, + this.dbAlias, + 'nc_models', + { + query_params: JSON.stringify(virtualViewsParamsArr[i]) + }, + virtualViews[i].id + ); + } + + // update shared views params + for (let i = 0; i < sharedViewsParamsArr.length; i++) { + await this.xcMeta.metaUpdate( + this.projectId, + this.dbAlias, + 'nc_shared_views', + { + query_params: JSON.stringify(sharedViewsParamsArr[i]) + }, + sharedViews[i].id + ); + } + } + + private async extractSharedAndVirtualViewsParams(tn: string) { + const virtualViews = await this.xcMeta.metaList( + this.projectId, + this.dbAlias, + 'nc_models', + { + condition: { + type: 'vtable', + parent_model_title: tn + } + } + ); + const sharedViews = await this.xcMeta.metaList( + this.projectId, + this.dbAlias, + 'nc_shared_views', + { + condition: { + model_name: tn + } + } + ); + const virtualViewsParamsArr = virtualViews.map(v => { + try { + return JSON.parse(v.query_params); + } catch (e) {} + return {}; + }); + + // @ts-ignore + const sharedViewsParamsArr = sharedViews.map(v => { + try { + return JSON.parse(v.query_params); + } catch (e) {} + return {}; + }); + return { + virtualViews, + sharedViews, + virtualViewsParamsArr, + sharedViewsParamsArr + }; } public async onTableRename( @@ -460,24 +590,12 @@ export default abstract class BaseApiBuilder const belongsTo = this.extractBelongsToRelationsOfTable(relations, tn); const hasMany = this.extractHasManyRelationsOfTable(relations, tn); - const virtualViews = await this.xcMeta.metaList( - this.projectId, - this.dbAlias, - 'nc_models', - { - condition: { - type: 'vtable', - parent_model_title: tn - } - } - ); - - const virtualViewsParamsArr = virtualViews.map(v => { - try { - return JSON.parse(v.query_params); - } catch (e) {} - return {}; - }); + const { + virtualViews, + sharedViews, + virtualViewsParamsArr, + sharedViewsParamsArr + } = await this.extractSharedAndVirtualViewsParams(tn); const ctx = this.generateContextForTable( tn, @@ -577,12 +695,22 @@ export default abstract class BaseApiBuilder ); // virtual views param update - for (const qp of [queryParams, ...virtualViewsParamsArr]) { + for (const qp of [ + queryParams, + ...virtualViewsParamsArr, + ...sharedViewsParamsArr + ]) { if (!qp) continue; // @ts-ignore - const { filters, sortList, showFields } = qp; + const { + filters, + sortList, + showFields = {}, + fieldsOrder, + extraViewParams = {} + } = qp; /* update sort field */ - const s = sortList.find(v => v.field === column.cno); + const s = sortList?.find(v => v.field === column.cno); if (s) { s.field = column.cn; } @@ -592,9 +720,26 @@ export default abstract class BaseApiBuilder delete showFields[column.cno]; } /* update filters */ - if (JSON.stringify(filters).includes(`"${column.cno}"`)) { + if ( + filters && + JSON.stringify(filters).includes(`"${column.cno}"`) + ) { filters.splice(0, filters.length); } + + /* update fieldsOrder */ + const index = fieldsOrder.indexOf(column.cno); + if (index > -1) { + fieldsOrder[index] = column.cn; + } + + /* update formView params */ + // extraViewParams.formParams.fields + if (extraViewParams?.formParams?.fields?.[column.cno]) { + extraViewParams.formParams.fields[column.cn] = + extraViewParams.formParams.fields[column.cno]; + delete extraViewParams.formParams.fields[column.cno]; + } } // update relation column name in meta data @@ -715,11 +860,19 @@ export default abstract class BaseApiBuilder aclOper.push(async () => this.deleteColumnNameInACL(tn, column.cno)); // virtual views param update - for (const qp of virtualViewsParamsArr) { + for (const qp of [...virtualViewsParamsArr, ...sharedViewsParamsArr]) { // @ts-ignore - const { filters, sortList, showFields } = qp; + const { + filters, + sortList, + showFields = {}, + fieldsOrder, + extraViewParams = {} + } = qp; /* update sort field */ - const sIndex = sortList.findIndex(v => v.field === column.cno); + const sIndex = (sortList || []).findIndex( + v => v.field === column.cno + ); if (sIndex > -1) { sortList.splice(sIndex, 1); } @@ -728,9 +881,21 @@ export default abstract class BaseApiBuilder delete showFields[column.cno]; } /* update filters */ - if (JSON.stringify(filters).includes(`"${column.cno}"`)) { + if (filters && JSON.stringify(filters)?.includes(`"${column.cno}"`)) { filters.splice(0, filters.length); } + + /* update fieldsOrder */ + const index = fieldsOrder.indexOf(column.cno); + if (index > -1) { + fieldsOrder.splice(index, 0); + } + + /* update formView params */ + // extraViewParams.formParams.fields + if (extraViewParams?.formParams?.fields?.[column.cno]) { + delete extraViewParams.formParams.fields[column.cno]; + } } // Delete lookup columns mapping to current column @@ -789,6 +954,20 @@ export default abstract class BaseApiBuilder if (queryParams?.showFields) { queryParams.showFields[column.cno] = true; } + + for (const qp of sharedViewsParamsArr) { + if (!qp) continue; + // @ts-ignore + const { showFields = {}, extraViewParams = {} } = qp; + + if (column.rqd) { + showFields[column.cn] = true; + extraViewParams.formParams = extraViewParams.formParams || {}; + extraViewParams.formParams.fields = + extraViewParams.formParams.fields || {}; + extraViewParams.formParams.fields[column.cn] = {}; + } + } } else { oldCol = oldMeta.columns.find(c => c.cn === column.cn); newCol = newMeta.columns.find(c => c.cn === column.cn); @@ -796,20 +975,15 @@ export default abstract class BaseApiBuilder newCol.validate = oldCol.validate; } } - - for (let i = 0; i < virtualViewsParamsArr.length; i++) { - await this.xcMeta.metaUpdate( - this.projectId, - this.dbAlias, - 'nc_models', - { - query_params: JSON.stringify(virtualViewsParamsArr[i]) - }, - virtualViews[i].id - ); - } } + await this.updateSharedAndVirtualViewsParams( + virtualViewsParamsArr, + virtualViews, + sharedViewsParamsArr, + sharedViews + ); + // update relation tables metadata for (const relMeta of relationTableMetas) { await this.xcMeta.metaUpdate( @@ -1187,6 +1361,54 @@ export default abstract class BaseApiBuilder XcCache.del([this.projectId, this.dbAlias, 'table', meta.tn].join('::')); this.models[meta.tn] = this.getBaseModel(meta); } + + // todo: many to many form view field update + + for (const [tnp, tnc] of [ + [parent, child], + [child, parent] + ]) { + const { + virtualViews, + sharedViews, + virtualViewsParamsArr, + sharedViewsParamsArr + } = await this.extractSharedAndVirtualViewsParams(tnp); + + const alias = this.getMeta(tnp)?.v?.find( + v => v?.tn === tnp && v?.mm?.rtn === tnc + )?._cn; + + // virtual views param update + for (const qp of [...virtualViewsParamsArr, ...sharedViewsParamsArr]) { + // @ts-ignore + const { showFields = {}, fieldsOrder, extraViewParams = {} } = qp; + + /* update show field */ + if (alias in showFields) { + delete showFields[alias]; + } + + /* update fieldsOrder */ + const index = fieldsOrder.indexOf(alias); + if (index > -1) { + fieldsOrder.splice(index, 0); + } + + /* update formView params */ + // extraViewParams.formParams.fields + if (extraViewParams?.formParams?.fields?.[alias]) { + delete extraViewParams.formParams.fields[alias]; + } + } + + await this.updateSharedAndVirtualViewsParams( + virtualViewsParamsArr, + virtualViews, + sharedViewsParamsArr, + sharedViews + ); + } } public getProjectId(): string { @@ -1197,15 +1419,88 @@ export default abstract class BaseApiBuilder await this.xcUpgrade(); } - public async onVirtualColumnAliasUpdate(tableName: string): Promise { + public async onVirtualColumnAliasUpdate({ + tn, + oldAlias, + newAlias + }: any): Promise { const model = await this.xcMeta.metaGet( this.projectId, this.dbAlias, 'nc_models', - { title: tableName } + { title: tn } ); const meta = JSON.parse(model.meta); - this.models[tableName] = this.getBaseModel(meta); + this.models[tn] = this.getBaseModel(meta); + + const virtualViews = await this.xcMeta.metaList( + this.projectId, + this.dbAlias, + 'nc_models', + { + condition: { + type: 'vtable', + parent_model_title: tn + } + } + ); + const sharedViews = await this.xcMeta.metaList( + this.projectId, + this.dbAlias, + 'nc_shared_views', + { + condition: { + model_name: tn + } + } + ); + + const virtualViewsParamsArr = virtualViews.map(v => { + try { + return JSON.parse(v.query_params); + } catch (e) {} + return {}; + }); + + // @ts-ignore + const sharedViewsParamsArr = sharedViews.map(v => { + try { + return JSON.parse(v.query_params); + } catch (e) {} + return {}; + }); + + for (const qp of [...sharedViewsParamsArr, ...virtualViewsParamsArr]) { + if (!qp) continue; + // @ts-ignore + const { showFields = {}, fieldsOrder, extraViewParams = {} } = qp; + /* update show field */ + if (oldAlias in showFields) { + showFields[newAlias] = showFields[oldAlias]; + delete showFields[oldAlias]; + } + + /* update fieldsOrder */ + const index = fieldsOrder.indexOf(oldAlias); + if (index > -1) { + fieldsOrder[index] = newAlias; + } + + /* update formView params */ + // extraViewParams.formParams.fields + if (extraViewParams?.formParams?.fields?.[oldAlias]) { + extraViewParams.formParams.fields[newAlias] = + extraViewParams.formParams.fields[oldAlias]; + delete extraViewParams.formParams.fields[oldAlias]; + } + } + + await this.updateSharedAndVirtualViewsParams( + virtualViewsParamsArr, + virtualViews, + sharedViewsParamsArr, + sharedViews + ); } protected async loadCommon(): Promise { diff --git a/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts b/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts index d9db436701..84536c7ad2 100644 --- a/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts +++ b/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts @@ -3421,7 +3421,7 @@ export default class NcMetaMgr { return { model_name: viewMeta.model_name, - meta: JSON.parse(viewMeta.meta), + meta: apiBuilder?.getMeta(viewMeta.model_name), //JSON.parse(viewMeta.meta), data: await model.list({ ...req.query, where, @@ -3583,7 +3583,9 @@ export default class NcMetaMgr { ?.find(pb => pb.id === viewMeta.project_id) ?.apiBuilders?.find(ab => ab.dbAlias === viewMeta.db_alias); - const tableMeta = JSON.parse(viewMeta.meta); + const tableMeta = (viewMeta.meta = apiBuilder?.getMeta( + viewMeta.model_name + )); const relatedTableMetas = {}; diff --git a/packages/nocodb/src/lib/noco/meta/NcMetaMgrEE.ts b/packages/nocodb/src/lib/noco/meta/NcMetaMgrEE.ts index eaf876e561..0725fb1533 100644 --- a/packages/nocodb/src/lib/noco/meta/NcMetaMgrEE.ts +++ b/packages/nocodb/src/lib/noco/meta/NcMetaMgrEE.ts @@ -185,7 +185,7 @@ export default class NcMetaMgrEE extends NcMetaMgr { db_alias: this.getDbAlias(args), model_name: args.args.model_name, view_name: args.args.view_name, - meta: JSON.stringify(args.args.meta), + // meta: JSON.stringify(args.args.meta), query_params: JSON.stringify(args.args.query_params), view_id: uuidv4(), password: args.args.password, diff --git a/packages/nocodb/src/lib/noco/migrations/nc_007_alter_nc_shared_views_1.ts b/packages/nocodb/src/lib/noco/migrations/nc_007_alter_nc_shared_views_1.ts index b73f424edf..324a78a574 100644 --- a/packages/nocodb/src/lib/noco/migrations/nc_007_alter_nc_shared_views_1.ts +++ b/packages/nocodb/src/lib/noco/migrations/nc_007_alter_nc_shared_views_1.ts @@ -2,7 +2,7 @@ import Knex from 'knex'; const up = async (knex: Knex) => { await knex.schema.alterTable('nc_shared_views', table => { - table.string('view_name',255); + table.string('view_name', 255); }); };