mirror of https://github.com/nocodb/nocodb
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.
248 lines
6.7 KiB
248 lines
6.7 KiB
<script lang="ts" setup> |
|
import type { ColumnReqType, ColumnType } from 'nocodb-sdk' |
|
import { UITypes } from 'nocodb-sdk' |
|
import { computed } from 'vue' |
|
import { |
|
ActiveViewInj, |
|
ColumnInj, |
|
IsLockedInj, |
|
MetaInj, |
|
ReloadViewDataHookInj, |
|
SmartsheetStoreEvents, |
|
iconMap, |
|
inject, |
|
message, |
|
toRefs, |
|
useI18n, |
|
useMetas, |
|
useNuxtApp, |
|
useSmartsheetStoreOrThrow, |
|
} from '#imports' |
|
|
|
const props = defineProps<{ |
|
column: ColumnType |
|
formColumn: Record<string, any> |
|
isRequired?: boolean |
|
isOpen: boolean |
|
onDelete: () => void |
|
}>() |
|
|
|
const emit = defineEmits(['hideField', 'update:isOpen', 'delete']) |
|
|
|
const { column, isRequired } = toRefs(props) |
|
|
|
const isOpen = useVModel(props, 'isOpen', emit) |
|
|
|
const { eventBus } = useSmartsheetStoreOrThrow() |
|
|
|
const reloadDataHook = inject(ReloadViewDataHookInj) |
|
|
|
const meta = inject(MetaInj, ref()) |
|
|
|
const view = inject(ActiveViewInj, ref()) |
|
|
|
const isLocked = inject(IsLockedInj) |
|
|
|
provide(ColumnInj, column) |
|
|
|
const { $api } = useNuxtApp() |
|
|
|
const { t } = useI18n() |
|
|
|
const { getMeta } = useMetas() |
|
|
|
const showDeleteColumnModal = ref(false) |
|
|
|
const isDuplicateDlgOpen = ref(false) |
|
const selectedColumnExtra = ref<any>() |
|
const duplicateDialogRef = ref<any>() |
|
|
|
const duplicateVirtualColumn = async () => { |
|
let columnCreatePayload = {} |
|
|
|
// generate duplicate column title |
|
const duplicateColumnTitle = getUniqueColumnName(`${column!.value.title} copy`, meta!.value!.columns!) |
|
|
|
columnCreatePayload = { |
|
...column!.value!, |
|
...(column!.value.colOptions ?? {}), |
|
title: duplicateColumnTitle, |
|
column_name: duplicateColumnTitle.replace(/\s/g, '_'), |
|
id: undefined, |
|
colOptions: undefined, |
|
order: undefined, |
|
system: false, |
|
} |
|
|
|
try { |
|
const gridViewColumnList = (await $api.dbViewColumn.list(view.value?.id as string)).list |
|
|
|
const currentColumnIndex = gridViewColumnList.findIndex((f) => f.fk_column_id === column!.value.id) |
|
let newColumnOrder |
|
if (currentColumnIndex === gridViewColumnList.length - 1) { |
|
newColumnOrder = gridViewColumnList[currentColumnIndex].order! + 1 |
|
} else { |
|
newColumnOrder = (gridViewColumnList[currentColumnIndex].order! + gridViewColumnList[currentColumnIndex + 1].order!) / 2 |
|
} |
|
|
|
await $api.dbTableColumn.create(meta!.value!.id!, { |
|
...columnCreatePayload, |
|
pv: false, |
|
view_id: view.value!.id as string, |
|
column_order: { |
|
order: newColumnOrder, |
|
view_id: view.value!.id as string, |
|
}, |
|
} as ColumnReqType) |
|
await getMeta(meta!.value!.id!, true) |
|
|
|
eventBus.emit(SmartsheetStoreEvents.FIELD_RELOAD) |
|
reloadDataHook?.trigger() |
|
|
|
// message.success(t('msg.success.columnDuplicated')) |
|
} catch (e) { |
|
message.error(await extractSdkResponseErrorMsg(e)) |
|
} |
|
// closing dropdown |
|
isOpen.value = false |
|
} |
|
|
|
const openDuplicateDlg = async () => { |
|
if (!column?.value) return |
|
if ( |
|
column.value.uidt && |
|
[ |
|
UITypes.Lookup, |
|
UITypes.Rollup, |
|
UITypes.CreatedTime, |
|
UITypes.LastModifiedTime, |
|
UITypes.CreatedBy, |
|
UITypes.LastModifiedBy, |
|
].includes(column.value.uidt as UITypes) |
|
) { |
|
duplicateVirtualColumn() |
|
} else { |
|
const gridViewColumnList = (await $api.dbViewColumn.list(view.value?.id as string)).list |
|
|
|
const currentColumnIndex = gridViewColumnList.findIndex((f) => f.fk_column_id === column!.value.id) |
|
let newColumnOrder |
|
if (currentColumnIndex === gridViewColumnList.length - 1) { |
|
newColumnOrder = gridViewColumnList[currentColumnIndex].order! + 1 |
|
} else { |
|
newColumnOrder = (gridViewColumnList[currentColumnIndex].order! + gridViewColumnList[currentColumnIndex + 1].order!) / 2 |
|
} |
|
|
|
selectedColumnExtra.value = { |
|
pv: false, |
|
view_id: view.value!.id as string, |
|
column_order: { |
|
order: newColumnOrder, |
|
view_id: view.value!.id as string, |
|
}, |
|
} |
|
|
|
if (column.value.uidt === UITypes.Formula) { |
|
nextTick(() => { |
|
duplicateDialogRef?.value?.duplicate() |
|
}) |
|
} else { |
|
isDuplicateDlgOpen.value = true |
|
} |
|
|
|
isOpen.value = false |
|
} |
|
} |
|
|
|
// hide the field in view |
|
const hideField = async () => { |
|
if (isRequired.value) return |
|
isOpen.value = false |
|
emit('hideField') |
|
} |
|
|
|
const handleDelete = () => { |
|
// closing the dropdown |
|
// when modal opens |
|
isOpen.value = false |
|
showDeleteColumnModal.value = true |
|
} |
|
|
|
const isDeleteAllowed = computed(() => { |
|
return column?.value && !column.value.system |
|
}) |
|
const isDuplicateAllowed = computed(() => { |
|
return column?.value && !column.value.system |
|
}) |
|
</script> |
|
|
|
<template> |
|
<a-dropdown |
|
v-if="!isLocked" |
|
v-model:visible="isOpen" |
|
:trigger="['click']" |
|
placement="bottomLeft" |
|
overlay-class-name="nc-dropdown-form-column-operations !border-1 rounded-lg !shadow-xl" |
|
@click.stop="isOpen = !isOpen" |
|
> |
|
<NcButton |
|
type="secondary" |
|
size="small" |
|
class="nc-form-add-field" |
|
data-testid="nc-form-add-field" |
|
@click.stop="showAddColumnDropdown = true" |
|
> |
|
<component :is="iconMap.threeDotVertical" class="flex-none w-4 h-4" /> |
|
</NcButton> |
|
<template #overlay> |
|
<NcMenu class="flex flex-col gap-1 border-gray-200 nc-column-options"> |
|
<!-- Todo: Duplicate column with form column settings --> |
|
<!-- eslint-disable vue/no-constant-condition --> |
|
<NcMenuItem v-if="false" :disabled="!isDuplicateAllowed" @click="openDuplicateDlg"> |
|
<div class="nc-column-duplicate nc-form-header-menu-item"> |
|
<component :is="iconMap.duplicate" /> |
|
<!-- Duplicate --> |
|
{{ t('general.duplicate') }} |
|
</div> |
|
</NcMenuItem> |
|
|
|
<NcMenuItem :disabled="isRequired" @click="hideField"> |
|
<div class="nc-column-insert-before nc-form-header-menu-item"> |
|
<component :is="iconMap.eye" class="!w-3.75 !h-3.75" /> |
|
<!-- Hide Field --> |
|
{{ $t('general.hideField') }} |
|
</div> |
|
</NcMenuItem> |
|
|
|
<template v-if="!column?.pv"> |
|
<a-divider class="!my-0" /> |
|
|
|
<NcMenuItem :disabled="!isDeleteAllowed" class="!hover:bg-red-50" @click="handleDelete"> |
|
<div class="nc-column-delete nc-form-header-menu-item text-red-600"> |
|
<component :is="iconMap.delete" /> |
|
<!-- Delete --> |
|
{{ $t('general.delete') }} |
|
</div> |
|
</NcMenuItem> |
|
</template> |
|
</NcMenu> |
|
</template> |
|
</a-dropdown> |
|
<SmartsheetHeaderDeleteColumnModal |
|
v-model:visible="showDeleteColumnModal" |
|
class="nc-form-column-delete-dropdown" |
|
:on-delete-column="onDelete" |
|
/> |
|
<DlgColumnDuplicate |
|
v-if="column" |
|
ref="duplicateDialogRef" |
|
v-model="isDuplicateDlgOpen" |
|
:column="column" |
|
:extra="selectedColumnExtra" |
|
/> |
|
</template> |
|
|
|
<style scoped> |
|
.nc-form-header-menu-item { |
|
@apply flex items-center gap-2; |
|
} |
|
</style>
|
|
|