-
-
-
- mdi-link-variant-remove
-
- mdi-delete-outline
-
-
+
+
+
+
+
+
+ mdi-link-variant-remove
+
+ mdi-delete-outline
+
+
- {{ ch[primaryCol] }}
- (Primary Key : {{ ch[primaryKey] }})
-
-
-
+
{{ ch[primaryCol] }}
+ (Primary Key : {{ ch[primaryKey] }})
+
+
+
+
+
+ No item{{ bt ? '' : 's' }} found
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -70,6 +74,9 @@ export default {
name: "listChildItems",
components: {Pagination},
props: {
+ bt: Boolean,
+ localState: [Array],
+ isNew: Boolean,
value: Boolean,
title: {
type: String,
@@ -87,20 +94,19 @@ export default {
parentMeta: Object,
size: Number,
api: [Object, Function],
- mm:[Object, Boolean]
+ mm: [Object, Boolean]
},
data: () => ({
data: null,
page: 1
}),
mounted() {
- this.loadData();
+ this.loadData();
},
methods: {
async loadData() {
- if (!this.api) return;
-
- this.data = await this.api.paginatedList({
+ if (!this.api || this.isNew) return;
+ this.data = await this.api.paginatedList({
limit: this.size,
offset: this.size * (this.page - 1),
...this.queryParams
@@ -115,6 +121,11 @@ export default {
return this.value;
}
}
+ },
+ watch: {
+ queryParams() {
+ this.loadData();
+ }
}
}
diff --git a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listChildItemsModal.vue b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listChildItemsModal.vue
new file mode 100644
index 0000000000..6a3e5e20c2
--- /dev/null
+++ b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listChildItemsModal.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue
index 214ac27714..1b6ab771f7 100644
--- a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue
+++ b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue
@@ -46,7 +46,7 @@
-
diff --git a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/hasManyCell.vue b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/hasManyCell.vue
index c6c0dfd5df..64cb48d59c 100644
--- a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/hasManyCell.vue
+++ b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/hasManyCell.vue
@@ -1,22 +1,24 @@
-
-
-
-
-
-
- mdi-plus
- mdi-arrow-expand
-
+
+
+
+
+
+
+
+ mdi-plus
+ mdi-arrow-expand
+
+
({
newRecordModal: false,
@@ -138,7 +147,11 @@ export default {
isNewChild: false,
localState: []
}),
-
+ async mounted() {
+ if (this.isForm) {
+ await this.loadChildMeta()
+ }
+ },
methods: {
async showChildListModal() {
await this.loadChildMeta();
@@ -157,7 +170,7 @@ export default {
await this.childApi.delete(id)
this.dialogShow = false;
this.$emit('loadTableData')
- if (this.childListModal && this.$refs.childList) {
+ if ((this.childListModal || this.isForm) && this.$refs.childList) {
this.$refs.childList.loadData();
}
} catch (e) {
@@ -167,6 +180,11 @@ export default {
}
},
async unlinkChild(child) {
+ if (this.isNew) {
+ this.localState.splice(this.localState.indexOf(child), 1)
+ return;
+ }
+
await this.loadChildMeta();
const column = this.childMeta.columns.find(c => c.cn === this.hm.cn);
if (column.rqd) {
@@ -177,7 +195,7 @@ export default {
const id = this.childMeta.columns.filter((c) => c.pk).map(c => child[c._cn]).join('___');
await this.childApi.update(id, {[_cn]: null}, child)
this.$emit('loadTableData')
- if (this.childListModal && this.$refs.childList) {
+ if ((this.childListModal || this.isForm) && this.$refs.childList) {
this.$refs.childList.loadData();
}
// }
@@ -214,12 +232,12 @@ export default {
await this.childApi.update(id, {
[_cn]: this.parentId
}, {
- [_cn]: child[this.childPrimaryKey]
+ [_cn]: child[this.childForeignKey]
});
this.$emit('loadTableData')
- if (this.childListModal) {
- await this.showChildListModal()
+ if ((this.childListModal || this.isForm) && this.$refs.childList) {
+ this.$refs.childList.loadData();
}
},
async editChild(child) {
@@ -295,12 +313,16 @@ export default {
}
},
watch: {
- isNew(n, o) {
+ isNew(n, o) {
+ debugger
if (!n && o) {
+ debugger
let child;
+ debugger
while (child = this.localState.pop()) {
- this.addChildToParent(child)
+ this.addChildToParent(child)
}
+ this.$emit('newRecordsSaved')
}
}
}
diff --git a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/manyToManyCell.vue b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/manyToManyCell.vue
index e537e8d2e4..e1233b6061 100644
--- a/packages/nc-gui/components/project/spreadsheet/components/virtualCell/manyToManyCell.vue
+++ b/packages/nc-gui/components/project/spreadsheet/components/virtualCell/manyToManyCell.vue
@@ -1,24 +1,24 @@
-
-
-
-
-
-
-
-
-
- mdi-plus
- mdi-arrow-expand
-
+
+
+
+
+
+
+
+
+ mdi-plus
+ mdi-arrow-expand
+
+
({
isNewChild: false,
@@ -159,7 +163,11 @@ export default {
expandFormModal: false,
localState: []
}),
-
+ async mounted() {
+ if (this.isForm) {
+ await Promise.all([this.loadChildMeta(), this.loadAssociateTableMeta()]);
+ }
+ },
methods: {
async onChildSave(child) {
if (this.isNewChild) {
@@ -172,6 +180,10 @@ export default {
await Promise.all([this.loadChildMeta(), this.loadAssociateTableMeta()]);
this.childListModal = true;
}, async unlinkChild(child) {
+ if (this.isNew) {
+ this.localState.splice(this.localState.indexOf(child), 1)
+ return;
+ }
await Promise.all([this.loadChildMeta(), this.loadAssociateTableMeta()]);
const _pcn = this.meta.columns.find(c => c.cn === this.mm.cn)._cn;
@@ -183,9 +195,8 @@ export default {
const id = this.assocMeta.columns.filter((c) => c.cn === apcn || c.cn === accn).map(c => c.cn === apcn ? this.row[_pcn] : child[_ccn]).join('___');
await this.assocApi.delete(id)
this.$emit('loadTableData')
- if (this.childListModal && this.$refs.childList) {
+ if ((this.childListModal || this.isForm) && this.$refs.childList) {
this.$refs.childList.loadData();
- // this.showChildListModal()
}
},
async removeChild(child) {
@@ -198,9 +209,11 @@ export default {
} else {
const id = this.childMeta.columns.filter((c) => c.pk).map(c => child[c._cn]).join('___');
await this.childApi.delete(id)
- this.showChildListModal();
this.dialogShow = false;
this.$emit('loadTableData')
+ if ((this.childListModal || this.isForm) && this.$refs.childList) {
+ this.$refs.childList.loadData();
+ }
}
}
},
@@ -231,7 +244,7 @@ export default {
async showNewRecordModal() {
await Promise.all([this.loadChildMeta(), this.loadAssociateTableMeta()]);
this.newRecordModal = true;
- // this.list = await this.childApi.paginatedList({})
+ // this.list = await this.c hildApi.paginatedList({})
},
async addChildToParent(child) {
if (this.isNew) {
@@ -257,6 +270,9 @@ export default {
console.log(e)
}
this.newRecordModal = false;
+ if ((this.childListModal || this.isForm) && this.$refs.childList) {
+ this.$refs.childList.loadData();
+ }
},
@@ -348,12 +364,13 @@ export default {
},
},
watch: {
- isNew(n, o) {
+ async isNew(n, o) {
if (!n && o) {
let child;
while (child = this.localState.pop()) {
- this.addChildToParent(child)
+ await this.addChildToParent(child)
}
+ this.$emit('newRecordsSaved')
}
}
}
diff --git a/packages/nc-gui/components/project/spreadsheet/components/virtualHeaderCell.vue b/packages/nc-gui/components/project/spreadsheet/components/virtualHeaderCell.vue
index acdd54a5a0..483b7013cf 100644
--- a/packages/nc-gui/components/project/spreadsheet/components/virtualHeaderCell.vue
+++ b/packages/nc-gui/components/project/spreadsheet/components/virtualHeaderCell.vue
@@ -33,23 +33,66 @@
Primary value will be shown in place of primary key
-
-
- mdi-delete-outline
- Delete
- -->
+ -->
+
+ mdi-delete-outline
+ Delete
+
-
+
+
+ Confirm
+
+ Do you want to delete '{{
+ column.cn
+ }}' column ?
+
+
+
+
+ Cancel
+ Confirm
+
+
+
diff --git a/packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue b/packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue
index f7a30bac1e..cbc2d44c84 100644
--- a/packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue
+++ b/packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue
@@ -399,12 +399,11 @@
v-model="showExpandModal">
@@ -820,7 +822,7 @@ export default {
const {rowMeta} = this.data[this.data.length - 1];
this.expandRow(this.data.length - 1, rowMeta)
}
- this.save()
+ // this.save()
},
@@ -859,7 +861,7 @@ export default {
},
loadTableDataDeb: debounce(async function (self) {
await self.loadTableDataFn()
- }, 100),
+ }, 200),
loadTableData() {
this.loadTableDataDeb(this)
},
@@ -918,7 +920,6 @@ export default {
return this.meta && this.meta._tn ? ApiFactory.create(this.$store.getters['project/GtrProjectType'], this.meta && this.meta._tn, this.meta && this.meta.columns, this) : null;
}
},
-
}
diff --git a/packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue b/packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue
index 94119c8db7..3df2061dda 100644
--- a/packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue
+++ b/packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue
@@ -27,6 +27,7 @@
@@ -132,8 +133,8 @@
:api="api"
:active="selected.col === col && selected.row === row"
:sql-ui="sqlUi"
- v-on="$listeners"
:is-new="rowMeta.new"
+ v-on="$listeners"
@updateCol="(...args) => updateCol(...args, columnObj.bt && meta.columns.find( c => c.cn === columnObj.bt.cn), col, row)"
>
diff --git a/packages/nc-gui/store/sqlMgr.js b/packages/nc-gui/store/sqlMgr.js
index a94c8cd621..acb723892c 100644
--- a/packages/nc-gui/store/sqlMgr.js
+++ b/packages/nc-gui/store/sqlMgr.js
@@ -263,6 +263,7 @@ function translateUiToLibCall(args, op, opArgs) {
case 'relationDelete':
case 'xcVirtualRelationDelete':
+ case 'xcRelationColumnDelete':
data.type = "Relation delete";
data.title = '';
data.module = "";
diff --git a/packages/nocodb/src/lib/noco/NcProjectBuilder.ts b/packages/nocodb/src/lib/noco/NcProjectBuilder.ts
index 624dd53fa8..d491187497 100644
--- a/packages/nocodb/src/lib/noco/NcProjectBuilder.ts
+++ b/packages/nocodb/src/lib/noco/NcProjectBuilder.ts
@@ -128,13 +128,23 @@ export default class NcProjectBuilder {
});
console.log(`Added new relation between : ${data.req.args.parentTable} ==> ${data.req.args.childTable}`)
break;
-
- case 'xcVirtualRelationDelete':
- await curBuilder.onRelationDelete(data.req.args.parentTable, data.req.args.childTable, {
+ case 'xcRelationColumnDelete':
+ await curBuilder.onRelationCreate(data.req.args.parentTable, data.req.args.childTable, {
...data.req.args,
virtual: true
});
- console.log(`Deleted relation between : ${data.req.args.parentTable} ==> ${data.req.args.childTable}`)
+ console.log(`Added new relation between : ${data.req.args.parentTable} ==> ${data.req.args.childTable}`)
+ break;
+
+ case 'xcVirtualRelationDelete':
+ if(data.req.args?.type === 'mm'){
+ curBuilder.onManyToManyRelationDelete(data.req.args.parentTable, data.req.args.childTable)
+ }
+ // await curBuilder.onRelationDelete(data.req.args.parentTable, data.req.args.childTable, {
+ // ...data.req.args,
+ // virtual: true
+ // });
+ // console.log(`Deleted relation between : ${data.req.args.parentTable} ==> ${data.req.args.childTable}`)
break;
diff --git a/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts b/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts
index c0ce21d67a..8c61b9e087 100644
--- a/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts
+++ b/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts
@@ -366,7 +366,7 @@ export default abstract class BaseApiBuilder implements XcDynami
this.baseLog(`onTableUpdate : Generating new model meta for '%s' table`, tn)
/* create models from table */
- const newMeta:any = ModelXcMetaFactory.create(this.connectionConfig, {dir: '', ctx, filename: ''}).getObject();
+ const newMeta: any = ModelXcMetaFactory.create(this.connectionConfig, {dir: '', ctx, filename: ''}).getObject();
/* get ACL row */
@@ -750,6 +750,27 @@ export default abstract class BaseApiBuilder implements XcDynami
return this.getManyToManyRelations({parent, child})
}
+ public async onManyToManyRelationDelete(parent: string, child: string, _args?: any) {
+
+ const parentMeta = this.metas[parent];
+ const childMeta = this.metas[child];
+
+ parentMeta.manyToMany = parentMeta.manyToMany.filter(mm => !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === child))
+ childMeta.manyToMany = childMeta.manyToMany.filter(mm => !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === child))
+
+ parentMeta.v = parentMeta.v.filter(({mm}) => !mm || !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === child))
+ childMeta.v = childMeta.v.filter(({mm}) => !mm || !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === child))
+
+ for (const meta of [parentMeta, childMeta]) {
+
+ await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', {
+ mm: 1,
+ }, {title: meta.tn})
+ XcCache.del([this.projectId, this.dbAlias, 'table', meta.tn].join('::'));
+ this.models[meta.tn] = this.getBaseModel(meta)
+ }
+ }
+
protected async loadCommon(): Promise {
this.baseLog(`loadCommon :`);
diff --git a/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts b/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts
index 1c18daf1d6..0922765149 100644
--- a/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts
+++ b/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts
@@ -1470,6 +1470,10 @@ export default class NcMetaMgr {
result = await this.xcM2MRelationCreate(args, req);
break;
+ case 'xcRelationColumnDelete':
+ result = await this.xcRelationColumnDelete(args, req);
+ break;
+
case 'xcVirtualRelationDelete':
result = await this.xcVirtualRelationDelete(args, req);
break;
@@ -2448,6 +2452,128 @@ export default class NcMetaMgr {
}
+ }
+
+
+
+ // todo : transaction
+ protected async xcRelationColumnDelete(args: any, req): Promise {
+ const dbAlias = this.getDbAlias(args);
+ const projectId = this.getProjectId(args);
+
+ // const parent = await this.xcMeta.metaGet(projectId, dbAlias, 'nc_models', {
+ // title: args.args.parentTable
+ // });
+ // // @ts-ignore
+ // const parentMeta = JSON.parse(parent.meta);
+ // @ts-ignore
+ // todo: compare column
+ switch (args.args.type) {
+ case 'bt':
+ case 'hm':
+ const child = await this.xcMeta.metaGet(projectId, dbAlias, 'nc_models', {
+ title: args.args.childTable
+ });
+ const childMeta = JSON.parse(child.meta);
+ const relation = childMeta.belongsTo.find(bt => bt.rtn === args.args.parentTable);
+ {
+ const opArgs = {
+ ...args,
+ args: {
+ childColumn: relation.cn,
+ childTable: relation.tn,
+ parentTable: relation.rtn,
+ parentColumn: relation.rcn
+ },
+ api: 'relationDelete'
+ };
+ const out = await this.projectMgr.getSqlMgr({id: projectId}).handleRequest('relationDelete', opArgs);
+
+ if (this.listener) {
+ await this.listener({
+ req: opArgs,
+ res: out,
+ user: req.user,
+ ctx: {req}
+ });
+ }
+ }
+ {
+ const originalColumns = childMeta.columns;
+ const columns = childMeta.columns.map(c => ({...c, ...(relation.cn === c.cn ? {altered: 4} : {})}))
+
+ const opArgs = {
+ ...args,
+ args: {
+ columns,
+ originalColumns,
+ tn: childMeta.tn,
+ sqlOpPlus: true
+ },
+ api: 'tableUpdate'
+ }
+
+ const out = await this.projectMgr.getSqlMgr({id: projectId}).handleRequest('tableUpdate', opArgs);
+
+ if (this.listener) {
+ await this.listener({
+ req: opArgs,
+ res: out,
+ user: req.user,
+ ctx: {req}
+ });
+ }
+ }
+ break;
+ case 'mm': {
+ const assoc = await this.xcMeta.metaGet(projectId, dbAlias, 'nc_models', {
+ title: args.args.assocTable
+ });
+ const assocMeta = JSON.parse(assoc.meta);
+ const rel1 = assocMeta.belongsTo.find(bt => bt.rtn === args.args.parentTable)
+ const rel2 = assocMeta.belongsTo.find(bt => bt.rtn === args.args.parentTable)
+ await this.xcRelationColumnDelete({
+ ...args,
+ args: {
+ parentTable: rel1.rtn,
+ parentColumn: rel1.rcn,
+ childTable: rel1.tn,
+ childColumn: rel1.cn,
+ }
+ },req)
+ await this.xcRelationColumnDelete({
+ ...args,
+ args: {
+ parentTable: rel2.rtn,
+ parentColumn: rel2.rcn,
+ childTable: rel2.tn,
+ childColumn: rel2.cn,
+ }
+ },req);
+
+
+ const opArgs = {
+ ...args,
+ args: assocMeta,
+ api: 'tableDelete'
+ };
+ const out = await this.projectMgr.getSqlMgr({id: projectId}).handleRequest('tableDelete', opArgs);
+
+ if (this.listener) {
+ await this.listener({
+ req: opArgs,
+ res: out,
+ user: req.user,
+ ctx: {req}
+ });
+ }
+
+ }
+ break;
+ }
+
+
+
}
protected async xcVirtualRelationDelete(args: any, req): Promise {
diff --git a/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts b/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts
index 97bb8e841b..e9e5e80afe 100644
--- a/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts
+++ b/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts
@@ -1028,7 +1028,6 @@ export class RestApiBuilder extends BaseApiBuilder {
});
-
/* Add new has many relation to virtual columns */
oldMeta.v = oldMeta.v || [];
oldMeta.v.push({
@@ -1211,8 +1210,10 @@ export class RestApiBuilder extends BaseApiBuilder {
const oldMeta = JSON.parse(existingModel.meta);
Object.assign(oldMeta, {
hasMany: meta.hasMany,
+ v: oldMeta.v.filter(({hm}) => !hm || hm.rtn !== tnp || hm.tn !== tnc)
});
+ // todo: delete from query_params
await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', {
title: tnp,
meta: JSON.stringify(oldMeta),
@@ -1244,8 +1245,9 @@ export class RestApiBuilder extends BaseApiBuilder {
const oldMeta = JSON.parse(existingModel.meta);
Object.assign(oldMeta, {
belongsTo: meta.belongsTo,
+ v: oldMeta.v.filter(({bt}) => !bt || bt.rtn !== tnp || bt.tn !== tnc)
});
-
+ // todo: delete from query_params
await this.xcMeta.metaUpdate(this.projectId,
this.dbAlias,
'nc_models', {