多维表格
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
5.5 KiB

<script lang="ts" setup>
const { activeTable } = storeToRefs(useTablesStore())
const { isMobileMode } = useGlobal()
const { isSharedBase, base } = storeToRefs(useBase())
const { t } = useI18n()
const { $api } = useNuxtApp()
const { refreshCommandPalette } = useCommandPalette()
const { activeView, views, openedViewsTab, viewsByTable } = storeToRefs(useViewsStore())
const { loadViews, removeFromRecentViews } = useViewsStore()
const { navigateToTable } = useTablesStore()
const isDropdownOpen = ref(false)
const isViewIdCopied = ref(false)
const isRenaming = ref(false)
const renameInputDom = ref()
const viewRenameTitle = ref('')
const error = ref<string | undefined>()
const onRenameMenuClick = () => {
isRenaming.value = true
isDropdownOpen.value = false
viewRenameTitle.value = activeView.value!.title
setTimeout(() => {
renameInputDom.value.focus()
})
}
watch(renameInputDom, () => {
renameInputDom.value?.focus()
})
const onRenameBlur = async () => {
if (validate()) {
activeView.value!.title = viewRenameTitle.value
isRenaming.value = false
error.value = undefined
await $api.dbView.update(activeView.value!.id!, {
title: viewRenameTitle.value,
})
} else {
renameInputDom.value?.focus()
}
}
/** validate view title */
function validate() {
if (!viewRenameTitle.value || viewRenameTitle.value.trim().length < 0) {
error.value = t('msg.error.viewNameRequired')
return false
}
if (viewRenameTitle.value.trim().length > 255) {
error.value = t('msg.error.nameMaxLength256')
return false
}
if (views.value.some((v) => v.title === viewRenameTitle.value && v.id !== activeView.value!.id)) {
error.value = t('msg.error.viewNameDuplicate')
return false
}
return true
}
watch(viewRenameTitle, () => {
if (error.value) {
error.value = undefined
}
})
watch(isDropdownOpen, () => {
setTimeout(() => {
isViewIdCopied.value = false
}, 250)
})
const resetViewRename = () => {
viewRenameTitle.value = activeView.value!.title
isRenaming.value = false
}
function openDeleteDialog() {
const isOpen = ref(true)
isDropdownOpen.value = false
const { close } = useDialog(resolveComponent('DlgViewDelete'), {
'modelValue': isOpen,
'view': activeView.value,
'onUpdate:modelValue': closeDialog,
'onDeleted': async () => {
closeDialog()
removeFromRecentViews({ viewId: activeView.value!.id, tableId: activeView.value!.fk_model_id, baseId: base.value.id })
refreshCommandPalette()
if (activeView.value?.id === activeView.value!.id) {
navigateToTable({
tableId: activeTable.value!.id!,
baseId: base.value.id!,
})
}
await loadViews({
tableId: activeTable.value!.id!,
force: true,
})
const activeNonDefaultViews = viewsByTable.value.get(activeTable!.value!.id!)?.filter((v) => !v.is_default) ?? []
activeTable!.value!.meta = {
...(activeTable!.value!.meta as object),
hasNonDefaultViews: activeNonDefaultViews.length > 1,
}
},
})
function closeDialog() {
isOpen.value = false
close(1000)
}
}
</script>
<template>
<div
v-if="isRenaming"
class="h-6 relative"
:class="{
'max-w-2/5': !isSharedBase && !isMobileMode && activeView?.is_default,
'max-w-3/5': !isSharedBase && !isMobileMode && !activeView?.is_default,
}"
>
<input
ref="renameInputDom"
v-model="viewRenameTitle"
class="ml-0.25 w-full px-1 py-0.5 rounded-md font-medium text-gray-800"
:class="{
'outline-brand-500': !error,
'outline-red-500 pr-6': error,
}"
@blur="onRenameBlur"
@keydown.enter="onRenameBlur"
@keydown.esc="resetViewRename"
/>
<NcTooltip v-if="error" class="absolute top-0.25 right-0.5 bg-white rounded-lg">
<template #title>
{{ error }}
</template>
<GeneralIcon icon="info" class="cursor-pointer" />
</NcTooltip>
</div>
<NcDropdown
v-else
v-model:visible="isDropdownOpen"
class="!xs:pointer-events-none nc-actions-menu-btn nc-view-context-btn"
overlay-class-name="nc-dropdown-actions-menu"
>
<div
v-e="['c:breadcrumb:view-actions']"
class="truncate nc-active-view-title flex gap-1 items-center !hover:(bg-gray-100 text-gray-800) ml-1 pl-1 pr-0.25 rounded-md py-1 cursor-pointer"
:class="{
'max-w-2/5': !isSharedBase && !isMobileMode && activeView?.is_default,
'max-w-3/5': !isSharedBase && !isMobileMode && !activeView?.is_default,
'max-w-1/2': isMobileMode,
'text-gray-500': activeView?.is_default,
'text-gray-800 font-medium': !activeView?.is_default,
}"
>
<NcTooltip class="truncate xs:pl-1.25 flex-1 text-inherit" show-on-truncate-only>
<template #title>{{ activeView?.is_default ? $t('title.defaultView') : activeView?.title }} </template>
<span
:class="{
'max-w-28/100': !isMobileMode,
}"
>
{{ activeView?.is_default ? $t('title.defaultView') : activeView?.title }}
</span>
</NcTooltip>
<GeneralIcon icon="chevronDown" class="!text-gray-500 mt-0.5" />
</div>
<template #overlay>
<SmartsheetToolbarViewActionMenu
:table="activeTable"
:view="activeView"
@close-modal="isDropdownOpen = false"
@rename="onRenameMenuClick"
@delete="openDeleteDialog"
/>
</template>
</NcDropdown>
<LazySmartsheetToolbarReload v-if="openedViewsTab === 'view' && !isMobileMode && !isRenaming" />
</template>