Browse Source

feat(gui-v2): table delete

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2830/head
Pranav C 2 years ago
parent
commit
9ace314b1b
  1. 70
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  2. 21
      packages/nc-gui-v2/composables/useMetas.ts
  3. 8
      packages/nc-gui-v2/composables/useTabs.ts

70
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -1,13 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from '@vue/reactivity' import { computed } from '@vue/reactivity'
import { onMounted } from '@vue/runtime-core' import { onMounted } from '@vue/runtime-core'
import type { TableType } from 'nocodb-sdk' import { Modal } from 'ant-design-vue'
import { UITypes } from 'nocodb-sdk'
import type { LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import { useToast } from 'vue-toastification'
import { $computed } from 'vue/macros' import { $computed } from 'vue/macros'
import { useNuxtApp, useRoute } from '#app' import { useNuxtApp, useRoute } from '#app'
// import Draggable from 'vuedraggable' // import Draggable from 'vuedraggable'
import useProject from '~/composables/useProject' import useProject from '~/composables/useProject'
import useTabs from '~/composables/useTabs' import useTabs from '~/composables/useTabs'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import MdiSettingIcon from '~icons/mdi/cog' import MdiSettingIcon from '~icons/mdi/cog'
import MdiTable from '~icons/mdi/table' import MdiTable from '~icons/mdi/table'
import MdiView from '~icons/mdi/eye-circle-outline' import MdiView from '~icons/mdi/eye-circle-outline'
@ -19,10 +23,12 @@ import MdiMenuIcon from '~icons/mdi/dots-vertical'
import MdiAPIDocIcon from '~icons/mdi/open-in-new' import MdiAPIDocIcon from '~icons/mdi/open-in-new'
const { addTab } = useTabs() const { addTab } = useTabs()
const toast = useToast()
const { $api } = useNuxtApp() const { $api } = useNuxtApp()
const { isUIAllowed } = useUIPermission() const { isUIAllowed } = useUIPermission()
const route = useRoute() const route = useRoute()
const { tables, loadTables } = useProject(route.params.projectId as string) const { tables, loadTables } = useProject(route.params.projectId as string)
const { closeTab } = useTabs()
const tablesById = $computed<Record<string, TableType>>(() => const tablesById = $computed<Record<string, TableType>>(() =>
tables?.value?.reduce((acc: Record<string, TableType>, table: TableType) => { tables?.value?.reduce((acc: Record<string, TableType>, table: TableType) => {
@ -105,6 +111,57 @@ const setMenuContext = (type: 'table' | 'main', value?: any) => {
contextMenuTarget.type = type contextMenuTarget.type = type
contextMenuTarget.value = value contextMenuTarget.value = value
} }
const deleteTable = (table: TableType) => {
// 'Click Submit to Delete The table'
Modal.confirm({
title: `Click Yes to Delete The table : ${table.title}`,
okText: 'Yes',
okType: 'danger',
cancelText: 'No',
async onOk() {
const { getMeta, removeMeta } = useMetas()
try {
const meta = (await getMeta(table.id as string)) as TableType
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 getMeta(
(c?.colOptions as LinkToAnotherRecordType)?.fk_related_model_id as string,
)) as TableType
return `${i + 1}. ${c.title} is a LinkToAnotherRecord of ${(refMeta && refMeta.title) || c.title}`
}),
)
toast.info(
h('div', {
innerHTML: `<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>`,
}),
)
return
}
await $api.dbTable.delete(table?.id as string)
closeTab({
type: 'table',
id: table.id,
title: table.title,
})
await loadTables()
removeMeta(table.id as string)
toast.info(`Deleted table ${table.title} successfully`)
} catch (e: any) {
toast.error(await extractSdkResponseErrorMsg(e))
}
},
})
}
</script> </script>
<template> <template>
@ -126,7 +183,9 @@ const setMenuContext = (type: 'table' | 'main', value?: any) => {
@contextmenu="setMenuContext('main')" @contextmenu="setMenuContext('main')"
> >
<MdiTable class="mr-1 text-gray-500" /> <MdiTable class="mr-1 text-gray-500" />
<span class="flex-grow text-bold">{{ $t('objects.tables') }} <template v-if="tables?.length">({{tables.length}})</template></span> <span class="flex-grow text-bold"
>{{ $t('objects.tables') }} <template v-if="tables?.length">({{ tables.length }})</template></span
>
<MdiPlus class="text-gray-500" @click.stop="tableCreateDlg = true" /> <MdiPlus class="text-gray-500" @click.stop="tableCreateDlg = true" />
<MdiMenuDown <MdiMenuDown
class="transition-transform !duration-100 text-gray-500" class="transition-transform !duration-100 text-gray-500"
@ -154,8 +213,7 @@ const setMenuContext = (type: 'table' | 'main', value?: any) => {
<template #overlay> <template #overlay>
<a-menu> <a-menu>
<a-menu-item class="!text-xs"> Rename</a-menu-item> <a-menu-item class="!text-xs"> Rename</a-menu-item>
<a-menu-item class="!text-xs"> UI ACL</a-menu-item> <a-menu-item class="!text-xs" @click="deleteTable(table)"> Delete</a-menu-item>
<a-menu-item class="!text-xs"> Delete</a-menu-item>
</a-menu> </a-menu>
</template> </template>
</a-dropdown> </a-dropdown>
@ -170,10 +228,10 @@ const setMenuContext = (type: 'table' | 'main', value?: any) => {
<a-menu> <a-menu>
<template v-if="contextMenuTarget.type === 'table'"> <template v-if="contextMenuTarget.type === 'table'">
<a-menu-item class="!text-xs">Table Rename</a-menu-item> <a-menu-item class="!text-xs">Table Rename</a-menu-item>
<a-menu-item class="!text-xs">Table Delete</a-menu-item> <a-menu-item class="!text-xs" @click="deleteTable(contextMenuTarget.value)">Table Delete</a-menu-item>
</template> </template>
<template v-else> <template v-else>
<a-menu-item @click="loadTables" class="!text-xs">Tables Refresh</a-menu-item> <a-menu-item class="!text-xs" @click="loadTables">Tables Refresh</a-menu-item>
</template> </template>
</a-menu> </a-menu>
</template> </template>

21
packages/nc-gui-v2/composables/useMetas.ts

@ -1,4 +1,4 @@
import type { TableType } from 'nocodb-sdk' import type { TableInfoType, TableType } from 'nocodb-sdk'
import { useNuxtApp, useState } from '#app' import { useNuxtApp, useState } from '#app'
import { useProject } from '#imports' import { useProject } from '#imports'
@ -8,13 +8,13 @@ export default () => {
const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({})) const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({}))
const getMeta = async (tableIdOrTitle: string, force = false) => { const getMeta = async (tableIdOrTitle: string, force = false): Promise<TableType | TableInfoType | null> => {
if (!force && metas[tableIdOrTitle as keyof typeof metas]) return metas[tableIdOrTitle as keyof typeof metas] if (!force && metas.value[tableIdOrTitle as string]) return metas.value[tableIdOrTitle as string]
const modelId = (tables.value.find((t) => t.title === tableIdOrTitle || t.id === tableIdOrTitle) || {}).id const modelId = (tables.value.find((t) => t.title === tableIdOrTitle || t.id === tableIdOrTitle) || {}).id
if (!modelId) { if (!modelId) {
console.warn(`Table '${tableIdOrTitle}' is not found in the table list`) console.warn(`Table '${tableIdOrTitle}' is not found in the table list`)
return return null
} }
const model = await $api.dbTable.read(modelId) const model = await $api.dbTable.read(modelId)
@ -28,5 +28,16 @@ export default () => {
return model return model
} }
return { getMeta, metas } const clearAllMeta = () => {
metas.value = {}
}
const removeMeta = (idOrTitle: string) => {
const meta = metas.value[idOrTitle]
if (meta) {
delete metas.value[meta.id]
delete metas.value[meta.title]
}
}
return { getMeta, clearAllMeta, metas, removeMeta }
} }

8
packages/nc-gui-v2/composables/useTabs.ts

@ -25,8 +25,12 @@ export default () => {
const clearTabs = () => { const clearTabs = () => {
tabs.value = [] tabs.value = []
} }
const closeTab = (index: number) => { const closeTab = (key: number | TabItem) => {
tabs.value.splice(index, 1) if (typeof key === 'number') tabs.value.splice(key, 1)
else {
const index = tabs.value.findIndex((tab) => tab.id === key.id && tab.type === key.type && tab.title === key.title)
if (index > -1) tabs.value.splice(index, 1)
}
} }
return { tabs, addTab, activeTab, clearTabs, closeTab } return { tabs, addTab, activeTab, clearTabs, closeTab }

Loading…
Cancel
Save