Browse Source

feat(nc-gui): sidebar data loading

pull/7611/head
DarkPhoenix2704 9 months ago
parent
commit
5d83c47355
  1. 73
      packages/nc-gui/components/smartsheet/calendar/SideMenu.vue
  2. 155
      packages/nc-gui/composables/useCalendarViewStore.ts

73
packages/nc-gui/components/smartsheet/calendar/SideMenu.vue

@ -1,13 +1,41 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { UITypes } from 'nocodb-sdk'
import { computed, ref } from '#imports'
const props = defineProps<{ const props = defineProps<{
visible: boolean visible: boolean
}>() }>()
const emit = defineEmits(['expand-record']) const emit = defineEmits(['expand-record'])
const INFINITY_SCROLL_THRESHOLD = 100
const { appInfo } = useGlobal()
const { t } = useI18n() const { t } = useI18n()
const { pageDate, selectedDate, selectedDateRange, activeDates, activeCalendarView } = useCalendarViewStoreOrThrow() const {
pageDate,
selectedDate,
calendarRange,
selectedDateRange,
activeDates,
activeCalendarView,
formattedSideBarData,
calDataType,
loadMoreSidebarData,
searchQuery,
sideBarFilterOption,
} = useCalendarViewStoreOrThrow()
const meta = inject(MetaInj, ref())
const fields = inject(FieldsInj, ref([]))
const sideBarListRef = ref<VNodeRef | null>(null)
const displayField = computed(() => meta.value?.columns?.find((c) => c.pv && fields.value.includes(c)) ?? null)
const options = computed(() => { const options = computed(() => {
switch (activeCalendarView.value) { switch (activeCalendarView.value) {
@ -17,7 +45,7 @@ const options = computed(() => {
{ label: 'without dates', value: 'withoutDates' }, { label: 'without dates', value: 'withoutDates' },
{ label: 'in selected hours', value: 'selectedHours' }, { label: 'in selected hours', value: 'selectedHours' },
{ label: 'all records', value: 'allRecords' }, { label: 'all records', value: 'allRecords' },
] ].filter((o) => o.value !== 'selectedHours' && calDataType.value === UITypes.Date)
case 'week' as const: case 'week' as const:
return [ return [
{ label: 'in this week', value: 'week' }, { label: 'in this week', value: 'week' },
@ -41,6 +69,22 @@ const options = computed(() => {
] ]
} }
}) })
watch(displayField, () => {
if (!displayField) return
searchQuery.field = displayField.value?.title ?? ''
})
const sideBarListScrollHandle = useDebounceFn(async (e: Event) => {
const target = e.target as HTMLElement
if (target.clientHeight + target.scrollTop + INFINITY_SCROLL_THRESHOLD >= target.scrollHeight) {
const pageSize = appInfo.value?.defaultLimit ?? 25
const page = Math.floor(formattedSideBarData.value.length / pageSize)
await loadMoreSidebarData({
offset: page * pageSize,
})
}
})
</script> </script>
<template> <template>
@ -59,7 +103,7 @@ const options = computed(() => {
/> />
<NcDateWeekSelector <NcDateWeekSelector
v-else-if="activeCalendarView === ('week' as const)" v-else-if="activeCalendarView === ('week' as const)"
v-model:active-dates="activeDatess" v-model:active-dates="activeDates"
v-model:page-date="pageDate" v-model:page-date="pageDate"
v-model:selected-week="selectedDateRange" v-model:selected-week="selectedDateRange"
week-picker week-picker
@ -79,29 +123,36 @@ const options = computed(() => {
<div class="px-4 flex flex-col gap-y-6 pt-4"> <div class="px-4 flex flex-col gap-y-6 pt-4">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span class="text-2xl font-bold">{{ t('objects.Records') }}</span> <span class="text-2xl font-bold">{{ t('objects.Records') }}</span>
<NcSelect :options="options" value="all records" /> <NcSelect v-model:value="sideBarFilterOption" :options="options" />
</div> </div>
<a-input class="!rounded-lg !border-gray-200 !px-4 !py-2" placeholder="Search your records"> <a-input
v-model:value="searchQuery.value"
class="!rounded-lg !border-gray-200 !px-4 !py-2"
placeholder="Search your records"
>
<template #prefix> <template #prefix>
<component :is="iconMap.search" class="h-4 w-4 mr-1 text-gray-500" /> <component :is="iconMap.search" class="h-4 w-4 mr-1 text-gray-500" />
</template> </template>
</a-input> </a-input>
<div <div
v-if="displayField && calendarRange && calendarRange.length"
:ref="sideBarListRef"
:class="{ :class="{
'h-[calc(100vh-40rem)]': activeCalendarView === ('day' as const) || activeCalendarView === ('week' as const), 'h-[calc(100vh-40rem)]': activeCalendarView === ('day' as const) || activeCalendarView === ('week' as const),
'h-[calc(100vh-29rem)]': activeCalendarView === ('month' as const) || activeCalendarView === ('year' as const), 'h-[calc(100vh-29rem)]': activeCalendarView === ('month' as const) || activeCalendarView === ('year' as const),
}" }"
class="gap-2 flex flex-col nc-scrollbar-md overflow-y-auto nc-calendar-top-height" class="gap-2 flex flex-col nc-scrollbar-md overflow-y-auto nc-calendar-top-height"
@scroll="sideBarListScrollHandle"
> >
<LazySmartsheetRow v-for="(record, rowIndex) in formattedSideBarData" :key="rowIndex" :row="record">
<LazySmartsheetCalendarSideRecordCard <LazySmartsheetCalendarSideRecordCard
v-for="(x, id) in Array(50)" :date="record.row[calendarRange[0].fk_from_col.title]"
:key="id" :name="record.row[displayField.title]"
:color="x % 2 === 0 ? 'maroon' : 'blue'" color="blue"
date="27 April 2003" @click="emit('expand-record', record)"
name="Saturday HackNight"
@click="emit('expand-record', id)"
/> />
</LazySmartsheetRow>
</div> </div>
</div> </div>
</div> </div>

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

@ -1,5 +1,5 @@
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import type { CalendarType, PaginatedType, UITypes, ViewType } from 'nocodb-sdk' import type { Api, CalendarType, PaginatedType, UITypes, ViewType } from 'nocodb-sdk'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { addDays, addMonths, addYears } from '~/utils' import { addDays, addMonths, addYears } from '~/utils'
import { IsPublicInj, type Row, ref, storeToRefs, useBase, useInjectionState } from '#imports' import { IsPublicInj, type Row, ref, storeToRefs, useBase, useInjectionState } from '#imports'
@ -31,6 +31,11 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
const calDataType = ref<UITypes.Date | UITypes.DateTime>() const calDataType = ref<UITypes.Date | UITypes.DateTime>()
const searchQuery = reactive({
value: '',
field: '',
})
const selectedDate = ref<Date>(new Date()) const selectedDate = ref<Date>(new Date())
const isCalendarDataLoading = ref<boolean>(false) const isCalendarDataLoading = ref<boolean>(false)
@ -43,10 +48,14 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
end: dayjs(selectedDate.value).startOf('week').add(6, 'day').toDate(), // This will be the following Saturday end: dayjs(selectedDate.value).startOf('week').add(6, 'day').toDate(), // This will be the following Saturday
}) })
const defaultPageSize = 1000 const defaultPageSize = 25
const formattedData = ref<Row[]>([]) const formattedData = ref<Row[]>([])
const formattedSideBarData = ref<Row[]>([])
const sideBarFilterOption = ref<string>(activeCalendarView.value)
const { api } = useApi() const { api } = useApi()
const { base } = storeToRefs(useBase()) const { base } = storeToRefs(useBase())
@ -81,12 +90,123 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
}) })
}) })
const sideBarxWhere = computed(() => {
if (!calendarRange.value) return ''
let whereClause = ''
if (activeCalendarView.value === 'day') {
switch (sideBarFilterOption.value) {
case 'day':
whereClause = `(${calendarRange.value[0].fk_from_col.title},eq,exactDate,${dayjs(selectedDate.value).format(
'YYYY-MM-DD',
)})`
break
case 'withoutDates':
whereClause = `(${calendarRange.value[0].fk_from_col.title},is,blank)`
break
case 'allRecords':
whereClause = ''
break
}
} else if (activeCalendarView.value === 'week') {
switch (sideBarFilterOption.value) {
case 'week':
whereClause = `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(
selectedDateRange.value.start,
).format('YYYY-MM-DD')})~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(
selectedDateRange.value.end,
).format('YYYY-MM-DD')})`
break
case 'withoutDates':
whereClause = `(${calendarRange.value[0].fk_from_col.title},is,blank)`
break
case 'allRecords':
whereClause = ''
break
case 'selectedDate':
whereClause = `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDate.value).format(
'YYYY-MM-DD',
)})~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(selectedDate.value).format('YYYY-MM-DD')})`
break
}
} else if (activeCalendarView.value === 'month') {
switch (sideBarFilterOption.value) {
case 'month':
whereClause = `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDate.value)
.startOf('month')
.format('YYYY-MM-DD')})~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(selectedDate.value)
.endOf('month')
.format('YYYY-MM-DD')})`
break
case 'withoutDates':
whereClause = `(${calendarRange.value[0].fk_from_col.title},is,blank)`
break
case 'allRecords':
whereClause = ''
break
case 'selectedDate':
whereClause = `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDate.value).format(
'YYYY-MM-DD',
)})~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(selectedDate.value).format('YYYY-MM-DD')})`
break
}
} else if (activeCalendarView.value === 'year') {
switch (sideBarFilterOption.value) {
case 'year':
whereClause = `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDate.value)
.startOf('year')
.format('YYYY-MM-DD')})~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(selectedDate.value)
.endOf('year')
.format('YYYY-MM-DD')})`
break
case 'withoutDates':
whereClause = `(${calendarRange.value[0].fk_from_col.title},is,blank)`
break
case 'allRecords':
whereClause = ''
break
case 'selectedDate':
whereClause = `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDate.value).format(
'YYYY-MM-DD',
)})~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(selectedDate.value).format('YYYY-MM-DD')})`
break
}
}
if (searchQuery.field && searchQuery.value) {
if (whereClause.length > 0) {
whereClause += '~and'
}
whereClause += `(${searchQuery.field},like,${searchQuery.value})`
}
return whereClause
})
async function loadMoreSidebarData(params: Parameters<Api<any>['dbViewRow']['list']>[4] = {}) {
if ((!base?.value?.id || !meta.value?.id || !viewMeta.value?.id) && !isPublic.value) return
const response = !isPublic.value
? await api.dbViewRow.list('noco', base.value.id!, meta.value!.id!, viewMeta.value!.id!, {
...params,
...{},
...{},
where: sideBarxWhere.value,
})
: await fetchSharedViewData({
...params,
sortsArr: sorts.value,
filtersArr: nestedFilters.value,
offset: params.offset,
where: sideBarxWhere.value,
})
formattedSideBarData.value = [...formattedSideBarData.value, ...formatData(response!.list)]
}
const xWhere = computed(() => { const xWhere = computed(() => {
if (!meta.value || !meta.value.columns || !calendarMetaData.value || !calendarMetaData.value.calendar_range) return '' if (!meta.value || !meta.value.columns || !calendarMetaData.value || !calendarMetaData.value.calendar_range) return ''
// If CalendarView, then we need to add the date filter to the where clause // If CalendarView, then we need to add the date filter to the where clause
let whereClause = where?.value ?? '' let whereClause = where?.value ?? ''
if (whereClause.length > 0) { if (whereClause.length > 0) {
whereClause += '~and(' whereClause += '~and'
} }
if (activeCalendarView.value === 'week') { if (activeCalendarView.value === 'week') {
whereClause += `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDateRange.value.start).format( whereClause += `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDateRange.value.start).format(
@ -243,22 +363,49 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
} }
} }
const loadSidebarData = async () => {
if (!base?.value?.id || !meta.value?.id || !viewMeta.value?.id) return
const res = await api.dbViewRow.list('noco', base.value.id!, meta.value!.id!, viewMeta.value!.id!, {
...queryParams.value,
...{},
where: sideBarxWhere?.value,
})
formattedSideBarData.value = formatData(res!.list)
}
watch(selectedDate, async () => { watch(selectedDate, async () => {
if (activeCalendarView.value === 'year') return if (activeCalendarView.value !== 'year') {
await loadCalendarData() await loadCalendarData()
}
await loadSidebarData()
}) })
watch(selectedDateRange, async () => { watch(selectedDateRange, async () => {
if (activeCalendarView.value !== 'week') return if (activeCalendarView.value !== 'week') return
await loadCalendarData() await loadCalendarData()
await loadSidebarData()
}) })
watch(activeCalendarView, async () => { watch(activeCalendarView, async () => {
sideBarFilterOption.value = activeCalendarView.value ?? 'allRecords'
await loadCalendarData() await loadCalendarData()
await loadSidebarData()
})
watch(sideBarFilterOption, async () => {
await loadSidebarData()
})
watch(searchQuery, async () => {
await loadSidebarData()
}) })
return { return {
filteredData, filteredData,
formattedSideBarData,
loadMoreSidebarData,
sideBarFilterOption,
searchQuery,
activeDates, activeDates,
isCalendarDataLoading, isCalendarDataLoading,
changeCalendarView, changeCalendarView,

Loading…
Cancel
Save