Browse Source

Merge pull request #1886 from nocodb/fix/1861-delete-table-bug

Fix - delete table bug
pull/1909/head
աɨռɢӄաօռɢ 3 years ago committed by GitHub
parent
commit
975506ad79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 110
      packages/nc-gui/components/project/table.vue
  2. 91
      packages/nocodb/src/lib/noco/meta/api/tableApis.ts

110
packages/nc-gui/components/project/table.vue

@ -14,11 +14,12 @@
> >
<template v-if="_isUIAllowed('smartSheet')"> <template v-if="_isUIAllowed('smartSheet')">
<v-tab v-show="relationTabs && relationTabs.length" class=""> <v-tab v-show="relationTabs && relationTabs.length" class="">
<v-icon small> mdi-table-edit </v-icon>&nbsp;<span <v-icon small>
mdi-table-edit
</v-icon>&nbsp;<span
class="caption text-capitalize font-weight-bold" class="caption text-capitalize font-weight-bold"
> >
{{ nodes.title }}</span {{ nodes.title }}</span>
>
</v-tab> </v-tab>
<v-tab-item style="height: 100%"> <v-tab-item style="height: 100%">
<rows-xc-data-table <rows-xc-data-table
@ -49,15 +50,16 @@
</template> </template>
<script> <script>
import { mapActions } from "vuex"; import { mapActions } from 'vuex'
import dlgLabelSubmitCancel from "../utils/dlgLabelSubmitCancel"; import { UITypes } from 'nocodb-sdk'
import { isMetaTable } from "@/helpers/xutils"; import dlgLabelSubmitCancel from '../utils/dlgLabelSubmitCancel'
import RowsXcDataTable from "@/components/project/spreadsheet/rowsXcDataTable"; import { isMetaTable } from '@/helpers/xutils'
import RowsXcDataTable from '@/components/project/spreadsheet/rowsXcDataTable'
export default { export default {
components: { components: {
RowsXcDataTable, RowsXcDataTable,
dlgLabelSubmitCancel, dlgLabelSubmitCancel
}, },
data() { data() {
return { return {
@ -72,87 +74,103 @@ export default {
loadRows: false, loadRows: false,
loadColumnsMock: false, loadColumnsMock: false,
relationTabs: [], relationTabs: [],
deleteId: null, deleteId: null
}; }
}, },
methods: { methods: {
async handleKeyDown(event) { async handleKeyDown(event) {
const activeTabEleKey = `tabs${this.active}`; const activeTabEleKey = `tabs${this.active}`
if ( if (
this.$refs[activeTabEleKey] && this.$refs[activeTabEleKey] &&
this.$refs[activeTabEleKey].handleKeyDown this.$refs[activeTabEleKey].handleKeyDown
) { ) {
await this.$refs[activeTabEleKey].handleKeyDown(event); await this.$refs[activeTabEleKey].handleKeyDown(event)
} }
}, },
...mapActions({ ...mapActions({
removeTableTab: "tabs/removeTableTab", removeTableTab: 'tabs/removeTableTab',
loadTablesFromParentTreeNode: "project/loadTablesFromParentTreeNode", loadTablesFromParentTreeNode: 'project/loadTablesFromParentTreeNode'
}), }),
mtdNewTableUpdate(value) { mtdNewTableUpdate(value) {
this.newTableCopy = value; this.newTableCopy = value
}, },
async deleteTable(action = "", id) { async deleteTable(action = '', id) {
if (id) { if (id) {
this.deleteId = id; this.deleteId = id
} }
if (action === "showDialog") { if (action === 'showDialog') {
this.dialogShow = true; this.dialogShow = true
} else if (action === "hideDialog") { } else if (action === 'hideDialog') {
this.dialogShow = false; this.dialogShow = false
} else { } else {
// todo : check relations and triggers
try { try {
await this.$api.dbTable.delete(this.deleteId); const meta = await this.$store.dispatch('meta/ActLoadMeta', { id: this.deleteId })
const relationColumns = meta.columns.filter(c => c.uidt === UITypes.LinkToAnotherRecord)
if (relationColumns.length) {
const refColMsgs = await Promise.all(relationColumns.map(async(c, i) => {
const refMeta = await this.$store.dispatch('meta/ActLoadMeta', { id: c.colOptions.fk_related_model_id })
return `${i + 1}. ${c.title} is a LinkToAnotherRecord of ${(refMeta && refMeta.title) || c.title}`
}))
this.$toast.info(`<div style="padding:10px 4px">Unable to delete tables because of the following.
<br><br>${refColMsgs.join('<br>')}<br><br>
Delete them & try again</div>
`).goAway(10000)
this.dialogShow = false
return
}
await this.$api.dbTable.delete(this.deleteId)
this.removeTableTab({ this.removeTableTab({
env: this.nodes.env, env: this.nodes.env,
dbAlias: this.nodes.dbAlias, dbAlias: this.nodes.dbAlias,
table_name: this.nodes.table_name, table_name: this.nodes.table_name
}); })
await this.loadTablesFromParentTreeNode({ await this.loadTablesFromParentTreeNode({
_nodes: { _nodes: {
...this.nodes, ...this.nodes
}, }
}); })
this.$store.commit("meta/MutMeta", { this.$store.commit('meta/MutMeta', {
key: this.nodes.table_name, key: this.nodes.table_name,
value: null, value: null
}); })
this.$store.commit("meta/MutMeta", { this.$store.commit('meta/MutMeta', {
key: this.deleteId, key: this.deleteId,
value: null, value: null
}); })
} catch (e) { } catch (e) {
const msg = await this._extractSdkResponseErrorMsg(e); const msg = await this._extractSdkResponseErrorMsg(e)
this.$toast.error(msg).goAway(3000); this.$toast.error(msg).goAway(3000)
} }
this.dialogShow = false; this.dialogShow = false
this.$e("a:table:delete"); this.$e('a:table:delete')
} }
}, },
onTabChange() { onTabChange() {
this.$emit("update:hideLogWindows", this.active === 2); this.$emit('update:hideLogWindows', this.active === 2)
}, }
}, },
computed: { computed: {
isMetaTable() { isMetaTable() {
return isMetaTable(this.nodes.table_name); return isMetaTable(this.nodes.table_name)
}, }
}, },
mounted() { mounted() {
this.onTabChange(); this.onTabChange()
}, },
props: { props: {
nodes: Object, nodes: Object,
hideLogWindows: Boolean, hideLogWindows: Boolean,
tabId: String, tabId: String,
isActive: Boolean, isActive: Boolean,
isView: Boolean, isView: Boolean
}, }
}; }
</script> </script>
<style scoped> <style scoped>

91
packages/nocodb/src/lib/noco/meta/api/tableApis.ts

@ -5,10 +5,12 @@ import { Tele } from 'nc-help';
import { import {
AuditOperationSubTypes, AuditOperationSubTypes,
AuditOperationTypes, AuditOperationTypes,
isVirtualCol,
ModelTypes, ModelTypes,
TableListType, TableListType,
TableReqType, TableReqType,
TableType TableType,
UITypes
} from 'nocodb-sdk'; } from 'nocodb-sdk';
import ProjectMgrv2 from '../../../sqlMgr/v2/ProjectMgrv2'; import ProjectMgrv2 from '../../../sqlMgr/v2/ProjectMgrv2';
import Project from '../../../noco-models/Project'; import Project from '../../../noco-models/Project';
@ -23,6 +25,7 @@ import getTableNameAlias, { getColumnNameAlias } from '../helpers/getTableName';
import Column from '../../../noco-models/Column'; import Column from '../../../noco-models/Column';
import NcConnectionMgrv2 from '../../common/NcConnectionMgrv2'; import NcConnectionMgrv2 from '../../common/NcConnectionMgrv2';
import getColumnUiType from '../helpers/getColumnUiType'; import getColumnUiType from '../helpers/getColumnUiType';
import LinkToAnotherRecordColumn from '../../../noco-models/LinkToAnotherRecordColumn';
export async function tableGet(req: Request, res: Response<TableType>) { export async function tableGet(req: Request, res: Response<TableType>) {
const table = await Model.getWithInfo({ const table = await Model.getWithInfo({
id: req.params.tableId id: req.params.tableId
@ -199,44 +202,60 @@ export async function tableUpdate(req: Request<any, any>, res) {
res.json({ msg: 'success' }); res.json({ msg: 'success' });
} }
export async function tableDelete(req: Request, res: Response, next) { export async function tableDelete(req: Request, res: Response) {
try { const table = await Model.getByIdOrName({ id: req.params.tableId });
const table = await Model.getByIdOrName({ id: req.params.tableId }); await table.getColumns();
await table.getColumns();
const project = await Project.getWithInfo(table.project_id);
const base = project.bases.find(b => b.id === table.base_id);
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
(table as any).tn = table.table_name;
table.columns.forEach(c => {
(c as any).cn = c.column_name;
});
if (table.type === ModelTypes.TABLE) { const relationColumns = table.columns.filter(
await sqlMgr.sqlOpPlus(base, 'tableDelete', table); c => c.uidt === UITypes.LinkToAnotherRecord
} else if (table.type === ModelTypes.VIEW) { );
await sqlMgr.sqlOpPlus(base, 'viewDelete', {
...table,
view_name: table.table_name
});
}
Audit.insert({ if (relationColumns?.length) {
project_id: project.id, const referredTables = await Promise.all(
op_type: AuditOperationTypes.TABLE, relationColumns.map(async c =>
op_sub_type: AuditOperationSubTypes.DELETED, c
user: (req as any)?.user?.email, .getColOptions<LinkToAnotherRecordColumn>()
description: `Deleted ${table.type} ${table.table_name} with alias ${table.title} `, .then(opt => opt.getRelatedTable())
ip: (req as any).clientIp .then()
}).then(() => {}); )
);
Tele.emit('evt', { evt_type: 'table:deleted' }); NcError.badRequest(
`Table can't be deleted since Table is being referred in following tables : ${referredTables.join(
res.json(await table.delete()); ', '
} catch (e) { )}. Delete LinkToAnotherRecord columns and try again.`
console.log(e); );
next(e);
} }
const project = await Project.getWithInfo(table.project_id);
const base = project.bases.find(b => b.id === table.base_id);
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
(table as any).tn = table.table_name;
table.columns = table.columns.filter(c => !isVirtualCol(c));
table.columns.forEach(c => {
(c as any).cn = c.column_name;
});
if (table.type === ModelTypes.TABLE) {
await sqlMgr.sqlOpPlus(base, 'tableDelete', table);
} else if (table.type === ModelTypes.VIEW) {
await sqlMgr.sqlOpPlus(base, 'viewDelete', {
...table,
view_name: table.table_name
});
}
Audit.insert({
project_id: project.id,
op_type: AuditOperationTypes.TABLE,
op_sub_type: AuditOperationSubTypes.DELETED,
user: (req as any)?.user?.email,
description: `Deleted ${table.type} ${table.table_name} with alias ${table.title} `,
ip: (req as any).clientIp
}).then(() => {});
Tele.emit('evt', { evt_type: 'table:deleted' });
res.json(await table.delete());
} }
const router = Router({ mergeParams: true }); const router = Router({ mergeParams: true });

Loading…
Cancel
Save