Browse Source

refactor(gui-v2): use sortable instead of vuedraggable

pull/2837/head
braks 2 years ago
parent
commit
9e715b65b9
  1. 72
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue

72
packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue

@ -1,9 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { FormType, GalleryType, GridType, KanbanType, ViewTypes } from 'nocodb-sdk' import type { FormType, GalleryType, GridType, KanbanType, ViewTypes } from 'nocodb-sdk'
import type { SortableEvent } from 'sortablejs' import type { SortableEvent } from 'sortablejs'
import { Menu as AntMenu, notification } from 'ant-design-vue' import type { Menu as AntMenu } from 'ant-design-vue'
import Draggable from 'vuedraggable' import { notification } from 'ant-design-vue'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import Sortable from 'sortablejs'
import RenameableMenuItem from './RenameableMenuItem.vue' import RenameableMenuItem from './RenameableMenuItem.vue'
import { inject, ref, useApi, useTabs, watch } from '#imports' import { inject, ref, useApi, useTabs, watch } from '#imports'
import { extractSdkResponseErrorMsg } from '~/utils' import { extractSdkResponseErrorMsg } from '~/utils'
@ -32,8 +33,11 @@ const selected = ref<string[]>([])
let deleteModalVisible = $ref(false) let deleteModalVisible = $ref(false)
/** view to delete for modal */
let toDelete = $ref<Record<string, any> | undefined>() let toDelete = $ref<Record<string, any> | undefined>()
const menuRef = ref<typeof AntMenu>()
/** Watch currently active view, so we can mark it in the menu */ /** Watch currently active view, so we can mark it in the menu */
watch(activeView, (nextActiveView) => { watch(activeView, (nextActiveView) => {
const _nextActiveView = nextActiveView as GridType | FormType | KanbanType const _nextActiveView = nextActiveView as GridType | FormType | KanbanType
@ -43,6 +47,7 @@ watch(activeView, (nextActiveView) => {
} }
}) })
/** validate view title */
function validate(value?: string) { function validate(value?: string) {
if (!value || value.trim().length < 0) { if (!value || value.trim().length < 0) {
return 'View name is required' return 'View name is required'
@ -55,7 +60,14 @@ function validate(value?: string) {
return true return true
} }
function onSortStart(evt: SortableEvent) {
evt.stopImmediatePropagation()
evt.preventDefault()
dragging = true
}
async function onSortEnd(evt: SortableEvent) { async function onSortEnd(evt: SortableEvent) {
dragging = false
if (views.value.length < 2) return if (views.value.length < 2) return
const { newIndex = 0, oldIndex = 0 } = evt const { newIndex = 0, oldIndex = 0 } = evt
@ -89,6 +101,22 @@ async function onSortEnd(evt: SortableEvent) {
await api.dbView.update(currentItem.id, { order: _nextOrder }) await api.dbView.update(currentItem.id, { order: _nextOrder })
} }
let sortable: Sortable
// todo: replace with vuedraggable
const initSortable = (el: HTMLElement) => {
if (sortable) sortable.destroy()
sortable = new Sortable(el, {
handle: '.nc-drag-icon',
ghostClass: 'ghost',
onStart: onSortStart,
onEnd: onSortEnd,
})
}
onMounted(() => menuRef.value && initSortable(menuRef.value.$el))
// todo: fix view type, alias is missing for some reason? // todo: fix view type, alias is missing for some reason?
/** Navigate to view and add new tab if necessary */ /** Navigate to view and add new tab if necessary */
function changeView(view: { id: string; alias?: string; title?: string; type: ViewTypes }) { function changeView(view: { id: string; alias?: string; title?: string; type: ViewTypes }) {
@ -133,12 +161,13 @@ async function onRename(view: Record<string, any>) {
} }
} }
/** Delete a view */ /** Open delete modal */
async function onDelete(view: Record<string, any>) { async function onDelete(view: Record<string, any>) {
toDelete = view toDelete = view
deleteModalVisible = true deleteModalVisible = true
} }
/** View was deleted, trigger reload */
function onDeleted() { function onDeleted() {
emits('deleted') emits('deleted')
toDelete = undefined toDelete = undefined
@ -149,29 +178,22 @@ function onDeleted() {
<template> <template>
<h3 class="nc-headline pt-3 px-3 text-xs font-semibold">{{ $t('objects.views') }}</h3> <h3 class="nc-headline pt-3 px-3 text-xs font-semibold">{{ $t('objects.views') }}</h3>
<Draggable <a-menu
:list="views" ref="menuRef"
:tag="AntMenu.name" :class="{ dragging }"
item-key="title" class="flex-1 max-h-[50vh] md:max-h-[200px] lg:max-h-[400px] xl:max-h-[600px] overflow-y-scroll scrollbar-thin-primary"
handle=".nc-drag-icon" :selected-keys="selected"
:component-data="{
class: 'flex-1 max-h-[50vh] md:max-h-[200px] lg:max-h-[400px] xl:max-h-[600px] overflow-y-scroll scrollbar-thin-primary',
selectedKeys: selected,
}"
@end="onSortEnd"
> >
<template #item="{ element: view }"> <RenameableMenuItem
<div :id="view.id"> v-for="view of views"
<RenameableMenuItem :key="view.id"
:view="view" :view="view"
@change-view="changeView" @change-view="changeView"
@open-modal="$emit('openModal', $event)" @open-modal="$emit('openModal', $event)"
@delete="onDelete" @delete="onDelete"
@rename="onRename" @rename="onRename"
/> />
</div> </a-menu>
</template>
</Draggable>
<dlg-view-delete v-model="deleteModalVisible" :view="toDelete" @deleted="onDeleted" /> <dlg-view-delete v-model="deleteModalVisible" :view="toDelete" @deleted="onDeleted" />
</template> </template>

Loading…
Cancel
Save