Browse Source

feat(nc-gui): show active dates

pull/7611/head
DarkPhoenix2704 9 months ago
parent
commit
59ce391bde
  1. 75
      packages/nc-gui/components/dlg/ViewCreate.vue
  2. 15
      packages/nc-gui/components/smartsheet/calendar/DayView.vue
  3. 7
      packages/nc-gui/components/smartsheet/calendar/SideMenu.vue
  4. 7
      packages/nc-gui/components/smartsheet/calendar/WeekView.vue
  5. 12
      packages/nc-gui/components/smartsheet/calendar/YearView.vue
  6. 81
      packages/nc-gui/composables/useCalendarViewStore.ts
  7. 4
      packages/nc-gui/lang/en.json
  8. 2
      packages/nc-gui/plugins/a.dayjs.ts

75
packages/nc-gui/components/dlg/ViewCreate.vue

@ -424,53 +424,42 @@ onMounted(async () => {
/> />
</a-form-item> </a-form-item>
<template v-if="form.type === ViewTypes.CALENDAR"> <template v-if="form.type === ViewTypes.CALENDAR">
<div v-for="(range, index) in form.calendarRange" :key="`range-${index}`" class="flex w-full gap-3"> <div v-for="(range, index) in form.calendarRange" :key="`range-${index}`" class="flex w-full items-center gap-2">
<div class="flex flex-col gap-2 w-1/2"> <span>
{{ $t('labels.organizeBy') }}
</span>
<NcSelect
v-model:value="range.fk_from_column_id"
:disabled="isMetaLoading"
:loading="isMetaLoading"
:options="viewSelectFieldOptions"
/>
<div
v-if="range.fk_to_column_id === null && isEeUI"
class="cursor-pointer flex items-center gap-1 mb-1"
@click="range.fk_to_column_id = ''"
>
<component :is="iconMap.plus" class="h-4 w-4" />
{{ $t('activity.setEndDate') }}
</div>
<template v-else-if="isEeUI">
<span> <span>
{{ $t('labels.organizeRecordsBy') }} {{ $t('activity.withEndDate') }}
</span> </span>
<NcSelect <div class="flex">
v-model:value="range.fk_from_column_id" <NcSelect
:disabled="isMetaLoading" v-model:value="range.fk_to_column_id"
:loading="isMetaLoading" :disabled="isMetaLoading"
:options="viewSelectFieldOptions" :loading="isMetaLoading"
class="w-full" :options="viewSelectFieldOptions"
/> :placeholder="$t('placeholder.notSelected')"
</div> class="!rounded-r-none nc-to-select"
<div v-if="range.fk_to_column_id === null && isEeUI" class="flex flex-col justify-end w-1/2">
<div class="cursor-pointer flex items-center font-medium gap-1 mb-1" @click="range.fk_to_column_id = ''">
<component :is="iconMap.plus" class="h-4 w-4" />
{{ $t('activity.setEndDate') }}
</div>
</div>
<div v-else-if="isEeUI" class="flex gap-2 flex-col w-1/2">
<div class="flex flex-row justify-between">
<span>
{{ $t('labels.endDateField') }}
</span>
<component
:is="iconMap.delete"
class="h-4 w-4 cursor-pointer text-red-500"
@click="
() => {
range.fk_to_column_id = null
}
"
/> />
<NcButton class="!rounded-l-none" size="small" type="secondary" @click="range.fk_to_column_id = null">
<component :is="iconMap.delete" class="h-4 w-4" />
</NcButton>
</div> </div>
<NcSelect </template>
v-model:value="range.fk_to_column_id"
:disabled="isMetaLoading"
:loading="isMetaLoading"
:options="
viewSelectFieldOptions.filter(
(el) => el.uidt === viewSelectFieldOptions.find((el) => el.id === range.fk_from_column_id),
)
"
:placeholder="$t('placeholder.notSelected')"
class="w-full"
/>
</div>
</div> </div>
</template> </template>
</a-form> </a-form>

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

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { UITypes } from 'nocodb-sdk'; import { UITypes } from 'nocodb-sdk'
import { computed, ref, type Row } from '#imports'; import { type Row, computed, ref } from '#imports'
interface Props { interface Props {
isEmbed?: boolean isEmbed?: boolean
@ -20,7 +20,7 @@ const data = toRefs(props).data
const displayField = computed(() => meta.value?.columns?.find((c) => c.pv && fields.value.includes(c)) ?? null) const displayField = computed(() => meta.value?.columns?.find((c) => c.pv && fields.value.includes(c)) ?? null)
const { pageDate, selectedDate, calDataType, formattedData, calendarRange } = useCalendarViewStoreOrThrow() const { pageDate, selectedDate, calDataType, filteredData, calendarRange } = useCalendarViewStoreOrThrow()
const hours = computed(() => { const hours = computed(() => {
const hours = [] const hours = []
@ -33,15 +33,14 @@ const hours = computed(() => {
const renderData = computed(() => { const renderData = computed(() => {
console.log(data.value) console.log(data.value)
if (data.value) { if (data.value) {
return data.value return data.value
} }
return formattedData.value return filteredData.value
}) })
</script> </script>
<template> <template>
<template v-if="formattedData.length"> <template v-if="filteredData && filteredData.length">
<div <div
v-if="calDataType === UITypes.Date" v-if="calDataType === UITypes.Date"
:class="{ :class="{
@ -70,7 +69,9 @@ const renderData = computed(() => {
class="flex flex-col mt-3 gap-2 w-full px-1" class="flex flex-col mt-3 gap-2 w-full px-1"
></div> ></div>
</template> </template>
<div v-else-if="!data" class="w-full h-full flex text-md font-bold text-gray-500 items-center justify-center">No Records in this day</div> <div v-else-if="!data" class="w-full h-full flex text-md font-bold text-gray-500 items-center justify-center">
No Records in this day
</div>
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

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

@ -7,6 +7,8 @@ const emit = defineEmits(['expand-record'])
const { t } = useI18n() const { t } = useI18n()
const { pageDate, selectedDate, selectedDateRange, activeDates, activeCalendarView } = useCalendarViewStoreOrThrow()
const options = computed(() => { const options = computed(() => {
switch (activeCalendarView.value) { switch (activeCalendarView.value) {
case 'day' as const: case 'day' as const:
@ -39,8 +41,6 @@ const options = computed(() => {
] ]
} }
}) })
const { pageDate, selectedDate, selectedDateRange, activeDates, activeCalendarView } = useCalendarViewStoreOrThrow()
</script> </script>
<template> <template>
@ -53,12 +53,13 @@ const { pageDate, selectedDate, selectedDateRange, activeDates, activeCalendarVi
> >
<NcDateWeekSelector <NcDateWeekSelector
v-if="activeCalendarView === ('day' as const)" v-if="activeCalendarView === ('day' as const)"
v-model:active-dates="activeDates"
v-model:page-date="pageDate" v-model:page-date="pageDate"
v-model:selected-date="selectedDate" v-model:selected-date="selectedDate"
:active-dates="activeDates"
/> />
<NcDateWeekSelector <NcDateWeekSelector
v-else-if="activeCalendarView === ('week' as const)" v-else-if="activeCalendarView === ('week' as const)"
v-model:active-dates="activeDatess"
v-model:page-date="pageDate" v-model:page-date="pageDate"
v-model:selected-week="selectedDateRange" v-model:selected-week="selectedDateRange"
week-picker week-picker

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

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import dayjs from 'dayjs'; import dayjs from 'dayjs'
const { selectedDateRange, formattedData, calendarRange } = useCalendarViewStoreOrThrow() const { selectedDateRange, filteredData, calendarRange } = useCalendarViewStoreOrThrow()
const weekDates = computed(() => { const weekDates = computed(() => {
const startOfWeek = new Date(selectedDateRange.value.start) const startOfWeek = new Date(selectedDateRange.value.start)
@ -16,7 +16,8 @@ const weekDates = computed(() => {
const getData = (date: Date) => { const getData = (date: Date) => {
const range = calendarRange.value[0] const range = calendarRange.value[0]
return formattedData.value.filter((record) => dayjs(date).isSame(dayjs(record.row[range.fk_from_col.title]))) if (!filteredData.value) return []
return filteredData.value.filter((record) => dayjs(date).isSame(dayjs(record.row[range.fk_from_col.title])))
} }
</script> </script>

12
packages/nc-gui/components/smartsheet/calendar/YearView.vue

@ -1,11 +1,10 @@
<script setup lang="ts"> <script lang="ts" setup>
const { pageDate, selectedDate, selectedDateRange } = useCalendarViewStoreOrThrow() const { selectedDate, activeDates } = useCalendarViewStoreOrThrow()
const months = computed(() => { const months = computed(() => {
const date = new Date()
const months = [] const months = []
for (let i = 0; i < 12; i++) { for (let i = 0; i < 12; i++) {
months.push(new Date(date.getFullYear(), i, selectedDate.value.getDate())) months.push(new Date(selectedDate.value.getFullYear(), i, selectedDate.value.getDate()))
} }
return months return months
}) })
@ -16,12 +15,13 @@ const months = computed(() => {
<NcDateWeekSelector <NcDateWeekSelector
v-for="(month, index) in months" v-for="(month, index) in months"
:key="month" :key="month"
v-model:active-dates="activeDates"
v-model:page-date="months[index]" v-model:page-date="months[index]"
v-model:selected-date="selectedDate" v-model:selected-date="selectedDate"
disable-pagination
class="max-w-[350px]" class="max-w-[350px]"
disable-pagination
/> />
</div> </div>
</template> </template>
<style scoped lang="scss"></style> <style lang="scss" scoped></style>

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

@ -1,7 +1,7 @@
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import type { CalendarType, PaginatedType, UITypes, ViewType } from 'nocodb-sdk' import type { 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'
const formatData = (list: Record<string, any>[]) => const formatData = (list: Record<string, any>[]) =>
@ -75,32 +75,41 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
return calendarMetaData.value.calendar_range.map((range) => { return calendarMetaData.value.calendar_range.map((range) => {
// Get the column data for the calendar range // Get the column data for the calendar range
return { return {
fk_from_col: meta.value.columns.find((col) => col.id === range.fk_from_column_id), fk_from_col: meta.value!.columns!.find((col) => col.id === range.fk_from_column_id),
fk_to_col: meta.value.columns.find((col) => col.id === range.fk_to_column_id), fk_to_col: meta.value!.columns!.find((col) => col.id === range.fk_to_column_id),
} }
}) })
}) })
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 ''
console.log(meta.value.columns.find((col) => col.id === calendarMetaData.value.calendar_range[0].fk_from_column_id))
// 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 += `(${ whereClause += `(${calendarRange.value[0].fk_from_col.title},gte,exactDate,${dayjs(selectedDateRange.value.start).format(
meta.value.columns.find((col) => col.id === calendarMetaData.value.calendar_range[0].fk_from_column_id).title 'YYYY-MM-DD',
},gte,exactDate,${dayjs(selectedDateRange.value.start).format('YYYY-MM-DD')})` )})`
whereClause += `~and(${ whereClause += `~and(${calendarRange.value[0].fk_from_col.title},lte,exactDate,${dayjs(
meta.value.columns.find((col) => col.id === calendarMetaData.value.calendar_range[0].fk_from_column_id).title selectedDateRange.value.end,
},lte,exactDate,${dayjs(selectedDateRange.value.end).format('YYYY-MM-DD')})` ).format('YYYY-MM-DD')})`
return whereClause return whereClause
} else if (activeCalendarView.value === 'day') { } else if (activeCalendarView.value === 'day') {
return `(${ return `(${calendarRange.value[0].fk_from_col.title},eq,exactDate,${dayjs(selectedDate.value).format('YYYY-MM-DD')})`
meta.value.columns.find((col) => col.id === calendarMetaData.value.calendar_range[0].fk_from_column_id).title } else if (activeCalendarView.value === 'month') {
},eq,exactDate,${dayjs(selectedDate.value).format('YYYY-MM-DD')})` return `(${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')})`
} else if (activeCalendarView.value === 'year') {
return `(${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')})`
} }
}) })
@ -108,8 +117,22 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
const activeDates = computed(() => { const activeDates = computed(() => {
const dates = new Set<Date>() const dates = new Set<Date>()
formattedData.value.forEach((row) => { formattedData.value.forEach((row) => {
const date = dayjs(row.row[calendarMetaData.value.calendar_range![0].fk_from_column_id!]).toDate() const start = row.row[calendarRange.value[0].fk_from_col.title]
dates.add(date) let end
if (calendarRange.value[0].fk_to_col) {
end = row.row[calendarRange.value[0].fk_to_col.title]
}
if (start && end) {
const startDate = dayjs(start)
const endDate = dayjs(end)
let currentDate = startDate
while (currentDate.isSameOrBefore(endDate)) {
dates.add(currentDate.toDate())
currentDate = currentDate.add(1, 'day')
}
} else if (start) {
dates.add(new Date(start))
}
}) })
return Array.from(dates) return Array.from(dates)
}) })
@ -136,8 +159,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
? (sharedView.value?.view as CalendarType) ? (sharedView.value?.view as CalendarType)
: await $api.dbView.calendarRead(viewMeta.value.id) : await $api.dbView.calendarRead(viewMeta.value.id)
activeCalendarView.value = JSON.parse(calendarMetaData.value?.meta ?? '{}')?.active_view ?? 'month' activeCalendarView.value = JSON.parse(calendarMetaData.value?.meta ?? '{}')?.active_view ?? 'month'
calDataType.value = meta.value.columns.find((col) => col.id === calendarMetaData.value.calendar_range[0].fk_from_column_id) calDataType.value = calendarRange.value[0].fk_from_col.uidt
?.uidt as UITypes.Date | UITypes.DateTime
} }
async function loadCalendarData() { async function loadCalendarData() {
@ -154,6 +176,28 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
isCalendarDataLoading.value = false isCalendarDataLoading.value = false
} }
const filteredData = computed(() => {
if (!formattedData.value) return []
if (activeCalendarView === 'week') {
return formattedData.value.filter((row) => {
const startDate = dayjs(row.row[calendarRange.value[0].fk_from_col.title])
const endDate = dayjs(row.row[calendarRange.value[0].fk_to_col.title])
return startDate.isSameOrBefore(selectedDateRange.value.end) && endDate.isSameOrAfter(selectedDateRange.value.start)
})
} else if (activeCalendarView === 'day') {
return formattedData.value.filter((row) => {
const startDate = dayjs(row.row[calendarRange.value[0].fk_from_col.title])
return startDate.isSame(selectedDate.value)
})
} else if (activeCalendarView === 'month') {
return formattedData.value.filter((row) => {
const startDate = dayjs(row.row[calendarRange.value[0].fk_from_col.title])
const endDate = dayjs(row.row[calendarRange.value[0].fk_to_col.title])
return startDate.isSameOrBefore(selectedDate.value) && endDate.isSameOrAfter(selectedDate.value)
})
}
})
async function updateCalendarMeta(updateObj: Partial<CalendarType>) { async function updateCalendarMeta(updateObj: Partial<CalendarType>) {
if (!viewMeta?.value?.id || !isUIAllowed('dataEdit')) return if (!viewMeta?.value?.id || !isUIAllowed('dataEdit')) return
await $api.dbView.calendarUpdate(viewMeta.value.id, updateObj) await $api.dbView.calendarUpdate(viewMeta.value.id, updateObj)
@ -200,6 +244,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
} }
watch(selectedDate, async () => { watch(selectedDate, async () => {
if (activeCalendarView.value === 'year') return
await loadCalendarData() await loadCalendarData()
}) })
@ -213,7 +258,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
}) })
return { return {
formattedData, filteredData,
activeDates, activeDates,
isCalendarDataLoading, isCalendarDataLoading,
changeCalendarView, changeCalendarView,

4
packages/nc-gui/lang/en.json

@ -436,6 +436,7 @@
"generalSettings": "General Settings", "generalSettings": "General Settings",
"ssoSettings": "SSO Settings", "ssoSettings": "SSO Settings",
"organizeRecordsBy": "Organize records by", "organizeRecordsBy": "Organize records by",
"organizeBy": "Organize by",
"heading1": "Heading 1", "heading1": "Heading 1",
"heading2": "Heading 2", "heading2": "Heading 2",
"heading3": "Heading 3", "heading3": "Heading 3",
@ -681,7 +682,8 @@
} }
}, },
"activity": { "activity": {
"setEndDate": "Set end date", "setEndDate": "Set End Date",
"withEndDate": "with end date",
"calendar": "Calendar", "calendar": "Calendar",
"viewSettings": "View settings", "viewSettings": "View settings",
"googleOAuth": "Google OAuth", "googleOAuth": "Google OAuth",

2
packages/nc-gui/plugins/a.dayjs.ts

@ -6,6 +6,7 @@ import utc from 'dayjs/plugin/utc.js'
import weekday from 'dayjs/plugin/weekday.js' import weekday from 'dayjs/plugin/weekday.js'
import timezone from 'dayjs/plugin/timezone.js' import timezone from 'dayjs/plugin/timezone.js'
import updateLocale from 'dayjs/plugin/updateLocale' import updateLocale from 'dayjs/plugin/updateLocale'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
import { defineNuxtPlugin } from '#imports' import { defineNuxtPlugin } from '#imports'
export default defineNuxtPlugin(() => { export default defineNuxtPlugin(() => {
@ -16,6 +17,7 @@ export default defineNuxtPlugin(() => {
extend(weekday) extend(weekday)
extend(timezone) extend(timezone)
extend(updateLocale) extend(updateLocale)
extend(isSameOrBefore)
dayjs.updateLocale('en', { dayjs.updateLocale('en', {
weekStart: 1, weekStart: 1,
}) })

Loading…
Cancel
Save