mirror of https://github.com/nocodb/nocodb
Browse Source
* feat(nc-gui): new date picker setup * feat(nc-gui): new date picker * fix(nc-gui): date cell form view validation issue * fix(nc-gui): disable date cell type support in mobile view * fix(nc-gui): small changes * feat(nc-gui): new cell year and month picker * fix(nc-gui): add updated date time picker setup * feat: update date time cell picker * fix(nc-gui): add now option in time picker * fix(nc-gui): small changes * fix(nc-gui): add support to update month, year from date picker * fix(nc-gui): update date picker select mont/year flow * fix(test): date selector test case * fix(nc-gui): update dateTime cell time picker * fix(test): update time picker test case * chore(nc-gui): lint * fix(nc-gui): invalid date issue * fix(nc-gui): date time picker tab issue * fix(nc-gui): year cell test fail issue * fix(nc-gui): date picker filter test fail issue * fix(test): survey form test fail issue * fix(test): update year field fill handler test case * fix(test): update bulk update test * fix(nc-gui): datetime multiple api call issue * fix(test): update timezone related test * fix(test): timezone related test update * fix(nc-gui): tab focus issue * fix(test): filter datetime test udpate * fix(test): ai review changes * fix(nc-gui): date picker font weight issue * fix(nc-gui): update year picker font weight * fix(nc-gui): show full date from date time cell instead of truncate * fix(nc-gui): date time picker ui changes * fix(nc-gui): date time cell width issue * fix(nc-gui): update datetime time option width according to time format * fix(nc-gui): disable datetime input if cell is readonly * fic(nc-gui): add new time picker * feat(nc-gui): update time picker * chore(nc-gui): cleanup unwanted code * fix(test): update time cell test cases * fix(nc-gui): multiple api calls * fix(test): update time cell filter & bulk update test cases * fix(test): revert unrelated changes * fix(nc-gui): pr review changes * fix(nc-gui): add clear datetime cell icon in non grid viewpull/8559/head
Ramesh Mane
6 months ago
committed by
GitHub
21 changed files with 1194 additions and 282 deletions
@ -0,0 +1,150 @@
|
||||
<script lang="ts" setup> |
||||
import dayjs from 'dayjs' |
||||
|
||||
interface Props { |
||||
size?: 'medium' |
||||
selectedDate?: dayjs.Dayjs | null |
||||
pageDate?: dayjs.Dayjs |
||||
isCellInputField?: boolean |
||||
type: 'date' | 'time' | 'year' | 'month' |
||||
isOpen: boolean |
||||
} |
||||
|
||||
const props = withDefaults(defineProps<Props>(), { |
||||
size: 'medium', |
||||
selectedDate: null, |
||||
pageDate: () => dayjs(), |
||||
isCellInputField: false, |
||||
type: 'date', |
||||
isOpen: false, |
||||
}) |
||||
const emit = defineEmits(['update:selectedDate', 'update:pageDate', 'update:selectedWeek']) |
||||
// Page date is the date we use to manage which month/date that is currently being displayed |
||||
const pageDate = useVModel(props, 'pageDate', emit) |
||||
|
||||
const selectedDate = useVModel(props, 'selectedDate', emit) |
||||
|
||||
const { type, isOpen } = toRefs(props) |
||||
|
||||
const localPageDate = ref() |
||||
|
||||
const localSelectedDate = ref() |
||||
|
||||
const pickerType = ref<Props['type'] | undefined>() |
||||
|
||||
const pickerStack = ref<Props['type'][]>([]) |
||||
|
||||
const tempPickerType = computed(() => pickerType.value || type.value) |
||||
|
||||
const handleUpdatePickerType = (value?: Props['type']) => { |
||||
if (value) { |
||||
pickerType.value = value |
||||
pickerStack.value.push(value) |
||||
} else { |
||||
if (pickerStack.value.length > 1) { |
||||
pickerStack.value.pop() |
||||
const lastPicker = pickerStack.value.pop() |
||||
pickerType.value = lastPicker |
||||
} else { |
||||
pickerStack.value = [] |
||||
pickerType.value = type.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
const localStatePageDate = computed({ |
||||
get: () => { |
||||
if (localPageDate.value) { |
||||
return localPageDate.value |
||||
} |
||||
return pageDate.value |
||||
}, |
||||
set: (value) => { |
||||
pageDate.value = value |
||||
localPageDate.value = value |
||||
emit('update:pageDate', value) |
||||
}, |
||||
}) |
||||
|
||||
const localStateSelectedDate = computed({ |
||||
get: () => { |
||||
if (localSelectedDate.value) { |
||||
return localSelectedDate.value |
||||
} |
||||
return pageDate.value |
||||
}, |
||||
set: (value: dayjs.Dayjs) => { |
||||
if (!value.isValid()) return |
||||
|
||||
if (pickerType.value === type.value) { |
||||
localPageDate.value = value |
||||
emit('update:selectedDate', value) |
||||
localSelectedDate.value = undefined |
||||
return |
||||
} |
||||
|
||||
if (['date', 'month'].includes(type.value)) { |
||||
if (pickerType.value === 'year') { |
||||
localSelectedDate.value = dayjs(localPageDate.value ?? localSelectedDate.value ?? selectedDate.value ?? dayjs()).year( |
||||
+value.format('YYYY'), |
||||
) |
||||
} |
||||
if (type.value !== 'month' && pickerType.value === 'month') { |
||||
localSelectedDate.value = dayjs(localPageDate.value ?? localSelectedDate.value ?? selectedDate.value ?? dayjs()).month( |
||||
+value.format('MM') - 1, |
||||
) |
||||
} |
||||
|
||||
localPageDate.value = localSelectedDate.value |
||||
|
||||
handleUpdatePickerType() |
||||
} |
||||
}, |
||||
}) |
||||
|
||||
watch(isOpen, (next) => { |
||||
if (!next) { |
||||
pickerType.value = type.value |
||||
localPageDate.value = undefined |
||||
localSelectedDate.value = undefined |
||||
pickerStack.value = [] |
||||
} |
||||
}) |
||||
|
||||
onUnmounted(() => { |
||||
pickerType.value = type.value |
||||
localPageDate.value = undefined |
||||
localSelectedDate.value = undefined |
||||
pickerStack.value = [] |
||||
}) |
||||
onMounted(() => { |
||||
localPageDate.value = undefined |
||||
localSelectedDate.value = undefined |
||||
pickerStack.value = [] |
||||
}) |
||||
</script> |
||||
|
||||
<template> |
||||
<NcDateWeekSelector |
||||
v-if="tempPickerType === 'date'" |
||||
v-model:page-date="localStatePageDate" |
||||
v-model:selected-date="localStateSelectedDate" |
||||
:picker-type="pickerType" |
||||
:is-monday-first="false" |
||||
is-cell-input-field |
||||
size="medium" |
||||
@update:picker-type="handleUpdatePickerType" |
||||
/> |
||||
<NcMonthYearSelector |
||||
v-if="['month', 'year'].includes(tempPickerType)" |
||||
v-model:page-date="localStatePageDate" |
||||
v-model:selected-date="localStateSelectedDate" |
||||
:picker-type="pickerType" |
||||
:is-year-picker="tempPickerType === 'year'" |
||||
is-cell-input-field |
||||
size="medium" |
||||
@update:picker-type="handleUpdatePickerType" |
||||
/> |
||||
</template> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,104 @@
|
||||
<script lang="ts" setup> |
||||
import dayjs from 'dayjs' |
||||
|
||||
interface Props { |
||||
selectedDate: dayjs.Dayjs | null |
||||
is12hrFormat?: boolean |
||||
isMinGranularityPicker?: boolean |
||||
minGranularity?: number |
||||
isOpen?: boolean |
||||
} |
||||
|
||||
const props = withDefaults(defineProps<Props>(), { |
||||
selectedDate: null, |
||||
is12hrFormat: false, |
||||
isMinGranularityPicker: false, |
||||
minGranularity: 30, |
||||
isOpen: false, |
||||
}) |
||||
const emit = defineEmits(['update:selectedDate']) |
||||
|
||||
const pageDate = ref<dayjs.Dayjs>(dayjs()) |
||||
|
||||
const selectedDate = useVModel(props, 'selectedDate', emit) |
||||
|
||||
const { is12hrFormat, isMinGranularityPicker, minGranularity, isOpen } = toRefs(props) |
||||
|
||||
const timeOptionsWrapperRef = ref<HTMLDivElement>() |
||||
|
||||
const compareTime = (date1: dayjs.Dayjs, date2: dayjs.Dayjs) => { |
||||
if (!date1 || !date2) return false |
||||
|
||||
return date1.format('HH:mm') === date2.format('HH:mm') |
||||
} |
||||
|
||||
const handleSelectTime = (time: dayjs.Dayjs) => { |
||||
pageDate.value = dayjs().set('hour', time.get('hour')).set('minute', time.get('minute')) |
||||
|
||||
selectedDate.value = pageDate.value |
||||
|
||||
// emit('update:selectedDate', pageDate.value) |
||||
} |
||||
|
||||
// TODO: 12hr time format & regular time picker |
||||
const timeOptions = computed(() => { |
||||
return Array.from({ length: is12hrFormat.value ? 12 : 24 }).flatMap((_, h) => { |
||||
return (isMinGranularityPicker.value ? [0, minGranularity.value] : Array.from({ length: 60 })).map((_m, m) => { |
||||
const time = dayjs() |
||||
.set('hour', h) |
||||
.set('minute', isMinGranularityPicker.value ? (_m as number) : m) |
||||
|
||||
return time |
||||
}) |
||||
}) |
||||
}) |
||||
|
||||
const handleAutoScroll = (behavior: ScrollBehavior = 'instant') => { |
||||
if (!timeOptionsWrapperRef.value || !selectedDate.value) return |
||||
|
||||
setTimeout(() => { |
||||
const timeEl = timeOptionsWrapperRef.value?.querySelector( |
||||
`[data-testid="time-option-${selectedDate.value?.format('HH:mm')}"]`, |
||||
) |
||||
|
||||
timeEl?.scrollIntoView({ behavior, block: 'center' }) |
||||
}, 50) |
||||
} |
||||
|
||||
watch([selectedDate, isOpen], () => { |
||||
if (timeOptionsWrapperRef.value && isOpen.value && selectedDate.value) { |
||||
handleAutoScroll() |
||||
} |
||||
}) |
||||
|
||||
onMounted(() => { |
||||
handleAutoScroll() |
||||
}) |
||||
</script> |
||||
|
||||
<template> |
||||
<div class="flex flex-col max-w-[350px]"> |
||||
<div v-if="isMinGranularityPicker" ref="timeOptionsWrapperRef" class="h-[180px] overflow-y-auto nc-scrollbar-thin"> |
||||
<div |
||||
v-for="time of timeOptions" |
||||
:key="time.format('HH:mm')" |
||||
class="hover:bg-gray-100 py-1 px-3 text-sm text-gray-600 font-weight-500 text-center cursor-pointer" |
||||
:class="{ |
||||
'nc-selected bg-gray-100': selectedDate && compareTime(time, selectedDate), |
||||
}" |
||||
:data-testid="`time-option-${time.format('HH:mm')}`" |
||||
@click="handleSelectTime(time)" |
||||
> |
||||
{{ time.format('HH:mm') }} |
||||
</div> |
||||
</div> |
||||
<div v-else></div> |
||||
<div class="px-2 py-1 box-border flex items-center justify-center"> |
||||
<NcButton :tabindex="-1" class="!h-7" size="small" type="secondary" @click="handleSelectTime(dayjs())"> |
||||
<span class="text-small"> {{ $t('general.now') }} </span> |
||||
</NcButton> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<style lang="scss" scoped></style> |
Loading…
Reference in new issue