Browse Source

fix(nc-gui): calendar minor fixes (#7943)

* fix(nocodb):  skip data refetch when hiding fix(nocodb): duplicate view does not copy field formattings

* fix(nc-gui): update the size of icons

* fix(nc-gui): single select focus not lost on escape press

* fix(nc-gui): disable focus on cell, if opening and not creating

* fix(nocodb): playwright failing

* fix(nc-gui): playwright failing

* fix(nc-gui): hide loading on field enable/disable

* fix(nc-gui): allow all fields reorder. prevent reorder tigger loading screen on load
pull/7956/head
Anbarasu 3 months ago committed by GitHub
parent
commit
2ee96cf36c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      packages/nc-gui/components/cell/SingleSelect.vue
  2. 16
      packages/nc-gui/components/smartsheet/calendar/DayView/DateField.vue
  3. 16
      packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue
  4. 15
      packages/nc-gui/components/smartsheet/calendar/MonthView.vue
  5. 7
      packages/nc-gui/components/smartsheet/calendar/RecordCard.vue
  6. 7
      packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue
  7. 15
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue
  8. 16
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue
  9. 19
      packages/nc-gui/components/smartsheet/calendar/index.vue
  10. 2
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  11. 20
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  12. 6
      packages/nc-gui/components/tabs/Smartsheet.vue
  13. 8
      packages/nc-gui/composables/useCalendarViewStore.ts
  14. 2
      packages/nc-gui/composables/useViewColumns.ts
  15. 29
      packages/nocodb/src/models/View.ts

7
packages/nc-gui/components/cell/SingleSelect.vue

@ -1,7 +1,7 @@
<script lang="ts" setup>
import type { Select as AntSelect } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import tinycolor from 'tinycolor2'
import type { Select as AntSelect } from 'ant-design-vue'
import type { SelectOptionType } from 'nocodb-sdk'
import type { FormFieldsLimitOptionsType } from '~/lib'
import {
@ -187,11 +187,6 @@ useSelectedCellKeyupListener(activeCell, (e) => {
}
})
// close dropdown list on escape
useSelectedCellKeyupListener(isOpen, (e) => {
if (e.key === 'Escape') isOpen.value = false
})
async function addIfMissingAndSave() {
if (!tempSelectedOptState.value || isPublic.value) return false

16
packages/nc-gui/components/smartsheet/calendar/DayView/DateField.vue

@ -1,7 +1,7 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import type { ColumnType } from 'nocodb-sdk'
import { type Row, computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { type Row, computed, ref, useViewColumnsOrThrow } from '#imports'
import { isRowEmpty } from '~/utils'
const emit = defineEmits(['expandRecord', 'newRecord'])
@ -29,8 +29,6 @@ const getFieldStyle = (field: ColumnType) => {
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
// We loop through all the records and calculate the position of each record based on the range
// We only need to calculate the top, of the record since there is no overlap in the day view of date Field
const recordsAcrossAllRange = computed<Row[]>(() => {
@ -223,17 +221,7 @@ const newRecord = () => {
size="small"
@click="emit('expandRecord', record)"
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField!).bold"
:column="displayField!"
:italic="getFieldStyle(displayField!).italic"
:underline="getFieldStyle(displayField!).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<template v-for="(field, id) in fields" :key="id">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, field!)"
v-model="record.row[field!.title!]"

16
packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue

@ -1,7 +1,7 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import type { ColumnType } from 'nocodb-sdk'
import { type Row, computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { type Row, computed, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emit = defineEmits(['expandRecord', 'newRecord'])
@ -40,8 +40,6 @@ const getFieldStyle = (field: ColumnType) => {
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
const hours = computed(() => {
const hours: Array<dayjs.Dayjs> = []
const _selectedDate = dayjs(selectedDate.value)
@ -991,17 +989,7 @@ const newRecord = (hour: dayjs.Dayjs) => {
color="blue"
@resize-start="onResizeStart"
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField!).bold"
:column="displayField!"
:italic="getFieldStyle(displayField!).italic"
:underline="getFieldStyle(displayField!).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<template v-for="(field, id) in fields" :key="id">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, field!)"
v-model="record.row[field!.title!]"

15
packages/nc-gui/components/smartsheet/calendar/MonthView.vue

@ -1,7 +1,7 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import type { ColumnType } from 'nocodb-sdk'
import { type Row, computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { type Row, computed, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emit = defineEmits(['newRecord', 'expandRecord'])
@ -75,8 +75,6 @@ const getFieldStyle = (field: ColumnType | undefined) => {
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
const dates = computed(() => {
const startOfMonth = selectedMonth.value.startOf('month')
const endOfMonth = selectedMonth.value.endOf('month')
@ -796,16 +794,7 @@ const addRecord = (date: dayjs.Dayjs) => {
@resize-start="onResizeStart"
@dblclick.stop="emit('expandRecord', record)"
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
:italic="getFieldStyle(displayField).italic"
:underline="getFieldStyle(displayField).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<template v-for="(field, id) in fields" :key="id">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, field!)"
v-model="record.row[field!.title!]"

7
packages/nc-gui/components/smartsheet/calendar/RecordCard.vue

@ -79,7 +79,12 @@ const emit = defineEmits(['resize-start'])
}"
class="text-sm pr-3 mb-0.5 mr-3 break-word whitespace-nowrap overflow-hidden text-ellipsis w-full truncate text-gray-800"
>
<slot />
<NcTooltip :disabled="selected" show-on-truncate-only>
<slot />
<template #title>
<slot />
</template>
</NcTooltip>
</span>
<span v-if="position === 'leftRounded' || position === 'none'" class="absolute my-0 right-5"> .... </span>
</div>

7
packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue

@ -71,7 +71,12 @@ const emit = defineEmits(['resize-start'])
<div v-if="position === 'bottomRounded' || position === 'none'" class="ml-3">....</div>
<span class="pl-1 pr-1 text-sm h-[80%] text-gray-800 leading-7 break-all whitespace-normal truncate w-full overflow-y-hidden">
<slot />
<NcTooltip :disabled="selected" show-on-truncate-only>
<slot />
<template #title>
<slot />
</template>
</NcTooltip>
</span>
<div v-if="position === 'topRounded' || position === 'none'" class="h-full pb-7 flex items-end ml-3">....</div>

15
packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue

@ -2,7 +2,7 @@
import dayjs from 'dayjs'
import { type ColumnType } from 'nocodb-sdk'
import type { Row } from '~/lib'
import { computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { computed, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emits = defineEmits(['expandRecord', 'newRecord'])
@ -32,8 +32,6 @@ const getFieldStyle = (field: ColumnType | undefined) => {
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
// Calculate the dates of the week
const weekDates = computed(() => {
let startOfWeek = dayjs(selectedDateRange.value.start)
@ -589,16 +587,7 @@ const addRecord = (date: dayjs.Dayjs) => {
@dblclick.stop="emits('expandRecord', record)"
@resize-start="onResizeStart"
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
:italic="getFieldStyle(displayField).italic"
:underline="getFieldStyle(displayField).underline"
/>
</template>
<template v-for="(field, index) in fieldsWithoutDisplay" :key="index">
<template v-for="(field, index) in fields" :key="index">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, field!)"
v-model="record.row[field!.title!]"

16
packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue

@ -2,7 +2,7 @@
import dayjs from 'dayjs'
import { type ColumnType } from 'nocodb-sdk'
import type { Row } from '~/lib'
import { computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { computed, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emits = defineEmits(['expandRecord', 'newRecord'])
@ -45,8 +45,6 @@ const getFieldStyle = (field: ColumnType | undefined) => {
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
// Since it is a datetime Week view, we need to create a 2D array of dayjs objects to represent the hours in a day for each day in the week
const datesHours = computed(() => {
const datesHours: Array<Array<dayjs.Dayjs>> = []
@ -827,17 +825,7 @@ const addRecord = (date: dayjs.Dayjs) => {
:selected="record.rowMeta!.id === dragRecord?.rowMeta?.id"
@resize-start="onResizeStart"
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
:italic="getFieldStyle(displayField).italic"
:underline="getFieldStyle(displayField).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<template v-for="(field, id) in fields" :key="id">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, field!)"
v-model="record.row[field!.title!]"

19
packages/nc-gui/components/smartsheet/calendar/index.vue

@ -52,6 +52,7 @@ const {
selectedMonth,
activeDates,
pageDate,
fetchActiveDates,
showSideMenu,
selectedDateRange,
paginateCalendarView,
@ -127,8 +128,12 @@ reloadViewMetaHook?.on(async () => {
await loadCalendarMeta()
})
reloadViewDataHook?.on(async () => {
await Promise.all([loadCalendarData(), loadSidebarData()])
reloadViewDataHook?.on(async (params: void | { shouldShowLoading?: boolean }) => {
await Promise.all([
loadCalendarData(params?.shouldShowLoading ?? false),
loadSidebarData(params?.shouldShowLoading ?? false),
fetchActiveDates(),
])
})
const goToToday = () => {
@ -187,7 +192,15 @@ const headerText = computed(() => {
<NcDropdown v-model:visible="calendarRangeDropdown" :auto-close="false" :trigger="['click']">
<NcButton :class="{ '!w-22': activeCalendarView === 'year' }" class="w-45" full-width size="small" type="secondary">
<div class="flex px-2 w-full items-center justify-between">
<span class="font-bold text-center text-brand-500" data-testid="nc-calendar-active-date">{{ headerText }}</span>
<div class="flex gap-1 text-brand-500">
<span class="font-bold text-center" data-testid="nc-calendar-active-date">{{
activeCalendarView === 'month' ? headerText.split(' ')[0] : headerText
}}</span>
<span v-if="activeCalendarView === 'month'">
{{ ` ${headerText.split(' ')[1]}` }}
</span>
</div>
<component :is="iconMap.arrowDown" class="h-4 w-4 text-gray-700" />
</div>
</NcButton>

2
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -333,7 +333,7 @@ onMounted(async () => {
isLoading.value = false
if (focusFirstCell) {
if (focusFirstCell && isNew.value) {
setTimeout(() => {
cellWrapperEl.value?.$el?.querySelector('input,select,textarea')?.focus()
}, 300)

20
packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue

@ -133,7 +133,9 @@ const onMove = async (_event: { moved: { newIndex: number; oldIndex: number } },
)
await loadViewColumns()
reloadViewDataHook?.trigger()
await reloadViewDataHook?.trigger({
shouldShowLoading: false,
})
$e('a:fields:reorder')
} catch (e) {
@ -406,34 +408,34 @@ useMenuCloseOnEsc(open)
:class="{
'!bg-gray-800 !text-white': field.bold,
}"
class="!rounded-r-none"
class="!rounded-r-none !w-5 !h-5"
size="xxsmall"
type="secondary"
@click.stop="toggleFieldStyles(field, 'bold', !field.bold)"
>
<component :is="iconMap.bold" />
<component :is="iconMap.bold" class="!w-3 !h-3" />
</NcButton>
<NcButton
:class="{
'!bg-gray-800 !text-white': field.italic,
}"
class="!rounded-x-none !border-x-0"
class="!rounded-x-none !border-x-0 !w-5 !h-5"
size="xxsmall"
type="secondary"
@click.stop="toggleFieldStyles(field, 'italic', !field.italic)"
>
<component :is="iconMap.italic" />
<component :is="iconMap.italic" class="!w-3 !h-3" />
</NcButton>
<NcButton
:class="{
'!bg-gray-800 !text-white': field.underline,
}"
class="!rounded-l-none"
class="!rounded-l-none !w-5 !h-5"
size="xxsmall"
type="secondary"
@click.stop="toggleFieldStyles(field, 'underline', !field.underline)"
>
<component :is="iconMap.underline" />
<component :is="iconMap.underline" class="!w-3 !h-3" />
</NcButton>
</div>
<NcSwitch :checked="field.show" :disabled="field.isViewEssentialField" @change="$t('a:fields:show-hide')" />
@ -499,4 +501,8 @@ useMenuCloseOnEsc(open)
// :deep(.ant-checkbox) {
// @apply top-auto;
// }
:deep(.xxsmall) {
@apply !min-w-0;
}
</style>

6
packages/nc-gui/components/tabs/Smartsheet.vue

@ -56,7 +56,7 @@ const { isGallery, isGrid, isForm, isKanban, isLocked, isMap, isCalendar } = use
useSqlEditor()
const reloadEventHook = createEventHook()
const reloadViewDataEventHook = createEventHook()
const reloadViewMetaEventHook = createEventHook<void | boolean>()
@ -70,7 +70,7 @@ useProvideCalendarViewStore(meta, activeView)
provide(MetaInj, meta)
provide(ActiveViewInj, activeView)
provide(IsLockedInj, isLocked)
provide(ReloadViewDataHookInj, reloadEventHook)
provide(ReloadViewDataHookInj, reloadViewDataEventHook)
provide(ReloadViewMetaHookInj, reloadViewMetaEventHook)
provide(OpenNewRecordFormHookInj, openNewRecordFormHook)
provide(FieldsInj, fields)
@ -81,7 +81,7 @@ provide(
computed(() => !isUIAllowed('dataEdit')),
)
useProvideViewColumns(activeView, meta, () => reloadEventHook?.trigger())
useProvideViewColumns(activeView, meta, () => reloadViewDataEventHook?.trigger())
const grid = ref()

8
packages/nc-gui/composables/useCalendarViewStore.ts

@ -432,7 +432,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
}
}
async function loadCalendarData() {
async function loadCalendarData(showLoading = true) {
if ((!base?.value?.id || !meta.value?.id || !viewMeta.value?.id) && !isPublic?.value) return
if (activeCalendarView.value === 'year') {
@ -479,7 +479,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
nextDate = nextDate!.format('YYYY-MM-DD HH:mm:ssZ')
try {
isCalendarDataLoading.value = true
if (showLoading) isCalendarDataLoading.value = true
const res = !isPublic.value
? await api.dbCalendarViewRow.list(
@ -592,10 +592,10 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
}
}
const loadSidebarData = async () => {
const loadSidebarData = async (showLoading = true) => {
if (!base?.value?.id || !meta.value?.id || !viewMeta.value?.id) return
try {
isSidebarLoading.value = true
if (showLoading) isSidebarLoading.value = true
const res = !isPublic.value
? await api.dbViewRow.list('noco', base.value.id!, meta.value!.id!, viewMeta.value.id, {
...queryParams.value,

2
packages/nc-gui/composables/useViewColumns.ts

@ -191,7 +191,7 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
if (!disableDataReload) {
await loadViewColumns()
reloadData?.()
reloadData?.({ shouldShowLoading: false })
}
}

29
packages/nocodb/src/models/View.ts

@ -1544,6 +1544,9 @@ export default class View implements ViewType {
'base_id',
'source_id',
'order',
...(view.type === ViewTypes.CALENDAR
? ['bold', 'italic', 'underline']
: []),
...(view.type === ViewTypes.FORM
? [
'label',
@ -1593,6 +1596,20 @@ export default class View implements ViewType {
let galleryShowLimit = 0;
let kanbanShowLimit = 0;
let calendarRangeColumns;
if (view.type == ViewTypes.CALENDAR) {
const calendarRange = await CalendarRange.read(view.id, ncMeta);
if (calendarRange) {
calendarRangeColumns = calendarRange.ranges
.map((range) => [
range.fk_from_column_id,
(range as any).fk_to_column_id,
])
.flat();
}
}
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
@ -1637,16 +1654,8 @@ export default class View implements ViewType {
}
} else if (view.type === ViewTypes.FORM && isSystemColumn(column)) {
show = false;
} else if (view.type === ViewTypes.CALENDAR && !copyFromView) {
const calendarRange = await CalendarRange.read(view.id, ncMeta);
if (!calendarRange) break;
const calendarRangeColumns = calendarRange.ranges
.map((range) => [
range.fk_from_column_id,
(range as any).fk_to_column_id,
])
.flat();
} else if (view.type === ViewTypes.CALENDAR) {
if (!calendarRangeColumns) break;
if (calendarRangeColumns.includes(column.id)) {
show = true;
}

Loading…
Cancel
Save