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.
175 lines
4.3 KiB
175 lines
4.3 KiB
<script setup lang="ts"> |
|
import { UITypes } from 'nocodb-sdk' |
|
import type { ColumnType } from 'nocodb-sdk' |
|
import { |
|
ActiveCellInj, |
|
ColumnInj, |
|
EditModeInj, |
|
IsFormInj, |
|
IsLockedInj, |
|
IsPublicInj, |
|
computed, |
|
inject, |
|
provide, |
|
ref, |
|
toRef, |
|
useColumn, |
|
useDebounceFn, |
|
useVModel, |
|
} from '#imports' |
|
import { NavigateDir } from '~/lib' |
|
|
|
interface Props { |
|
column: ColumnType |
|
modelValue: any |
|
editEnabled: boolean |
|
readOnly?: boolean |
|
rowIndex?: number |
|
active?: boolean |
|
virtual?: boolean |
|
} |
|
|
|
const props = defineProps<Props>() |
|
|
|
const emit = defineEmits(['update:modelValue', 'save', 'navigate', 'update:editEnabled']) |
|
|
|
const column = toRef(props, 'column') |
|
|
|
const active = toRef(props, 'active', false) |
|
|
|
const virtual = toRef(props, 'virtual', false) |
|
|
|
const readOnly = toRef(props, 'readOnly', undefined) |
|
|
|
provide(ColumnInj, column) |
|
|
|
provide(EditModeInj, useVModel(props, 'editEnabled', emit)) |
|
|
|
provide(ActiveCellInj, active) |
|
|
|
if (readOnly?.value) { |
|
provide(ReadonlyInj, readOnly.value) |
|
} |
|
|
|
const isForm = inject(IsFormInj, ref(false)) |
|
|
|
const isPublic = inject(IsPublicInj, ref(false)) |
|
|
|
const isLocked = inject(IsLockedInj, ref(false)) |
|
|
|
let changed = $ref(false) |
|
|
|
const syncValue = useDebounceFn(function () { |
|
changed = false |
|
emit('save') |
|
}, 1000) |
|
|
|
const isAutoSaved = $computed(() => { |
|
return [ |
|
UITypes.SingleLineText, |
|
UITypes.LongText, |
|
UITypes.PhoneNumber, |
|
UITypes.Email, |
|
UITypes.URL, |
|
UITypes.Number, |
|
UITypes.Decimal, |
|
UITypes.Percent, |
|
UITypes.Count, |
|
UITypes.AutoNumber, |
|
UITypes.SpecificDBType, |
|
UITypes.Geometry, |
|
].includes(column?.value?.uidt as UITypes) |
|
}) |
|
|
|
const isManualSaved = $computed(() => { |
|
return [UITypes.Currency, UITypes.Duration].includes(column?.value?.uidt as UITypes) |
|
}) |
|
|
|
const vModel = computed({ |
|
get: () => props.modelValue, |
|
set: (val) => { |
|
if (val !== props.modelValue) { |
|
changed = true |
|
emit('update:modelValue', val) |
|
if (isAutoSaved) { |
|
syncValue() |
|
} else if (!isManualSaved) { |
|
emit('save') |
|
changed = true |
|
} |
|
} |
|
}, |
|
}) |
|
|
|
const { |
|
isPrimary, |
|
isURL, |
|
isEmail, |
|
isJSON, |
|
isDate, |
|
isYear, |
|
isDateTime, |
|
isTime, |
|
isBoolean, |
|
isDuration, |
|
isRating, |
|
isCurrency, |
|
isAttachment, |
|
isTextArea, |
|
isString, |
|
isInt, |
|
isFloat, |
|
isDecimal, |
|
isSingleSelect, |
|
isMultiSelect, |
|
isPercent, |
|
isPhoneNumber, |
|
} = useColumn(column) |
|
|
|
const syncAndNavigate = (dir: NavigateDir) => { |
|
if (isJSON.value) return |
|
|
|
if (changed) { |
|
emit('save') |
|
changed = false |
|
} |
|
emit('navigate', dir) |
|
} |
|
</script> |
|
|
|
<template> |
|
<div |
|
class="nc-cell w-full h-full" |
|
:class="{ 'text-blue-600': isPrimary && !virtual && !isForm }" |
|
@keydown.stop.left |
|
@keydown.stop.right |
|
@keydown.stop.up |
|
@keydown.stop.down |
|
@keydown.stop.enter.exact="syncAndNavigate(NavigateDir.NEXT)" |
|
@keydown.stop.shift.enter.exact="syncAndNavigate(NavigateDir.PREV)" |
|
> |
|
<CellTextArea v-if="isTextArea" v-model="vModel" /> |
|
<CellCheckbox v-else-if="isBoolean" v-model="vModel" /> |
|
<CellAttachment v-else-if="isAttachment" v-model="vModel" :row-index="props.rowIndex" /> |
|
<CellSingleSelect v-else-if="isSingleSelect" v-model="vModel" /> |
|
<CellMultiSelect v-else-if="isMultiSelect" v-model="vModel" /> |
|
<CellDatePicker v-else-if="isDate" v-model="vModel" /> |
|
<CellYearPicker v-else-if="isYear" v-model="vModel" /> |
|
<CellDateTimePicker v-else-if="isDateTime" v-model="vModel" /> |
|
<CellTimePicker v-else-if="isTime" v-model="vModel" /> |
|
<CellRating v-else-if="isRating" v-model="vModel" /> |
|
<CellDuration v-else-if="isDuration" v-model="vModel" /> |
|
<CellEmail v-else-if="isEmail" v-model="vModel" /> |
|
<CellUrl v-else-if="isURL" v-model="vModel" /> |
|
<CellPhoneNumber v-else-if="isPhoneNumber" v-model="vModel" /> |
|
<CellPercent v-else-if="isPercent" v-model="vModel" /> |
|
<CellCurrency v-else-if="isCurrency" v-model="vModel" /> |
|
<CellDecimal v-else-if="isDecimal" v-model="vModel" /> |
|
<CellInteger v-else-if="isInt" v-model="vModel" /> |
|
<CellFloat v-else-if="isFloat" v-model="vModel" /> |
|
<CellText v-else-if="isString" v-model="vModel" /> |
|
<CellJson v-else-if="isJSON" v-model="vModel" /> |
|
<CellText v-else v-model="vModel" /> |
|
<div v-if="(isLocked || (isPublic && readOnly && !isForm)) && !isAttachment" class="nc-locked-overlay" @click.stop.prevent /> |
|
</div> |
|
</template>
|
|
|