Browse Source

fix: issue with sortable

re #2820

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2830/head
Pranav C 2 years ago
parent
commit
d4976686ff
  1. 130
      packages/nc-gui-v2/components/dashboard/TreeView.vue

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

@ -1,15 +1,15 @@
<script setup lang="ts">
import { computed } from '@vue/reactivity'
import { onMounted } from '@vue/runtime-core'
import { Modal } from 'ant-design-vue'
import { UITypes } from 'nocodb-sdk'
import type { LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import Sortable from 'sortablejs'
import { useToast } from 'vue-toastification'
import { $computed } from 'vue/macros'
import { watchEffect } from '#imports'
import { useNuxtApp, useRoute } from '#app'
import useProject from '~/composables/useProject'
import useTabs from '~/composables/useTabs'
import useTabs, { TabItem } from '~/composables/useTabs'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import MdiSettingIcon from '~icons/mdi/cog'
import MdiTable from '~icons/mdi/table'
@ -40,46 +40,60 @@ const settingsDlg = ref(false)
const showTableList = ref(true)
const tableCreateDlg = ref(false)
const tableDeleteDlg = ref(false)
const menuRef = $ref<HTMLLIElement>()
let key = $ref(0)
let sortable: Sortable
onMounted(() => {
setTimeout(() => {
const el = document.querySelector('.sortable-list') // Must get this DomElement,
Sortable.create(el, {
handle: '.nc-drag-icon',
onChange: async (evt) => {
const { newIndex = 0, oldIndex = 0 } = evt
const itemEl = evt.item as HTMLLIElement
const item = tablesById[itemEl.dataset.id as string]
// get the html collection of all list items
const children: HTMLCollection = evt.to.children
// get items before and after the moved item
const itemBeforeEl = children[newIndex - 1] as HTMLLIElement
const itemAfterEl = children[newIndex + 1] as HTMLLIElement
// get items meta of before and after the moved item
const itemBefore = itemBeforeEl && tablesById[itemBeforeEl.dataset.id as string]
const itemAfter = itemAfterEl && tablesById[itemAfterEl.dataset.id as string]
// set new order value based on the new order of the items
if (children.length - 1 === evt.newIndex) {
item.order = (itemBefore.order as number) + 1
} else if (newIndex === 0) {
item.order = (itemAfter.order as number) / 2
} else {
item.order = ((itemBefore.order as number) + (itemAfter.order as number)) / 2
}
// todo: replace with vuedraggable
const initSortable = (el: Element) => {
if (sortable) sortable.destroy()
sortable = Sortable.create(el as HTMLLIElement, {
handle: '.nc-drag-icon',
onEnd: async (evt) => {
const { newIndex = 0, oldIndex = 0 } = evt
// update the item order
await $api.dbTable.reorder(item.id as string, {
order: item.order as any,
})
},
animation: 150,
})
}, 1000)
const itemEl = evt.item as HTMLLIElement
const item = tablesById[itemEl.dataset.id as string]
// get the html collection of all list items
const children: HTMLCollection = evt.to.children
// get items before and after the moved item
const itemBeforeEl = children[newIndex - 1] as HTMLLIElement
const itemAfterEl = children[newIndex + 1] as HTMLLIElement
// get items meta of before and after the moved item
const itemBefore = itemBeforeEl && tablesById[itemBeforeEl.dataset.id as string]
const itemAfter = itemAfterEl && tablesById[itemAfterEl.dataset.id as string]
// set new order value based on the new order of the items
if (children.length - 1 === evt.newIndex) {
item.order = (itemBefore.order as number) + 1
} else if (newIndex === 0) {
item.order = (itemAfter.order as number) / 2
} else {
item.order = ((itemBefore.order as number) + (itemAfter.order as number)) / 2
}
// update the order of the moved item
tables.value?.splice(newIndex, 0, ...tables.value?.splice(oldIndex, 1))
// force re-render the list
key++
// update the item order
await $api.dbTable.reorder(item.id as string, {
order: item.order as any,
})
},
animation: 150,
})
}
watchEffect(() => {
if (menuRef) {
initSortable(menuRef)
}
})
const icon = (table: TableType) => {
@ -167,10 +181,19 @@ const deleteTable = (table: TableType) => {
const renameTableDlg = ref(false)
const renameTableMeta = ref()
const showRenameTableDlg = (table: TableType) => {
const showRenameTableDlg = (table: TableType, rightClick = false) => {
$e(rightClick ? 'c:table:rename:navdraw:right-click' : 'c:table:rename:navdraw:options')
renameTableMeta.value = table
renameTableDlg.value = true
}
const reloadTables = async () => {
$e('a:table:refresh:navdraw')
await loadTables()
}
const addTableTab = (table: TableType) => {
$e('a:table:open')
addTab({ title: table.title, id: table.id })
}
</script>
<template>
@ -203,15 +226,16 @@ const showRenameTableDlg = (table: TableType) => {
</div>
<div class="flex-1">
<div class="transition-height duration-200 overflow-hidden" :class="{ 'h-100': showTableList, 'h-0': !showTableList }">
<a-menu class="border-none sortable-list">
<a-menu-item
v-for="table in filteredTables"
<div :key="key" ref="menuRef" class="border-none sortable-list">
<div
v-for="table in tables"
:key="table.id"
v-t="['a:table:open']"
:class="{ hidden: !filteredTables?.includes(table) }"
class="!pl-1 py-1 !h-[28px] !my-0 text-sm pointer group"
:data-order="table.order"
:data-id="table.id"
@click="addTab({ type: 'table', title: table.title, id: table.id })"
@click="addTableTab(table)"
>
<div class="flex align-center gap-1 h-full" @contextmenu="setMenuContext('table', table)">
<MdiDrag class="transition-opacity opacity-0 group-hover:opacity-100 text-gray-500 nc-drag-icon cursor-move" />
@ -222,16 +246,14 @@ const showRenameTableDlg = (table: TableType) => {
<MdiMenuIcon class="transition-opacity opacity-0 group-hover:opacity-100" />
<template #overlay>
<a-menu class="cursor-pointer">
<a-menu-item v-t="['c:table:rename:navdraw:options']" class="!text-xs" @click="showRenameTableDlg(table)">
Rename</a-menu-item
>
<a-menu-item class="!text-xs" @click="showRenameTableDlg(table)"> Rename </a-menu-item>
<a-menu-item class="!text-xs" @click="deleteTable(table)"> Delete</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</a-menu-item>
</a-menu>
</div>
</div>
</div>
</div>
</div>
@ -239,11 +261,7 @@ const showRenameTableDlg = (table: TableType) => {
<template #overlay>
<a-menu class="cursor-pointer">
<template v-if="contextMenuTarget.type === 'table'">
<a-menu-item
v-t="['c:table:rename:navdraw:right-click']"
class="!text-xs"
@click="showRenameTableDlg(contextMenuTarget.value)"
>
<a-menu-item class="!text-xs" @click="showRenameTableDlg(contextMenuTarget.value)">
{{ $t('general.rename') }}
</a-menu-item>
<a-menu-item class="!text-xs" @click="deleteTable(contextMenuTarget.value)">
@ -251,7 +269,7 @@ const showRenameTableDlg = (table: TableType) => {
</a-menu-item>
</template>
<template v-else>
<a-menu-item v-t="['a:table:refresh:navdraw']" class="!text-xs" @click="loadTables">
<a-menu-item class="!text-xs" @click="reloadTables">
{{ $t('general.reload') }}
</a-menu-item>
</template>

Loading…
Cancel
Save