Browse Source

feat(nc-gui): pr review changes

pull/7611/head
DarkPhoenix2704 8 months ago
parent
commit
89b9e90370
  1. 4
      packages/nc-gui/components/nc/DateWeekSelector.vue
  2. 4
      packages/nc-gui/components/nc/MonthYearSelector.vue
  3. 2
      packages/nc-gui/components/smartsheet/Toolbar.vue
  4. 1
      packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue
  5. 33
      packages/nc-gui/components/smartsheet/calendar/MonthView.vue
  6. 30
      packages/nc-gui/components/smartsheet/calendar/SideMenu.vue
  7. 2
      packages/nc-gui/components/smartsheet/calendar/SideRecordCard.vue
  8. 3
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue
  9. 111
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue
  10. 40
      packages/nc-gui/composables/useCalendarViewStore.ts

4
packages/nc-gui/components/nc/DateWeekSelector.vue

@ -171,7 +171,7 @@ const paginate = (action: 'next' | 'prev') => {
:key="index"
:class="{
'rounded-lg': !weekPicker,
'bg-brand-50 border-2 !border-brand-500': isSelectedDate(date) && !weekPicker && isDayInPagedMonth(date),
'bg-brand-50 border-1 !border-brand-500': isSelectedDate(date) && !weekPicker && isDayInPagedMonth(date),
'hover:(border-1 border-gray-200 bg-gray-100)': !isSelectedDate(date) && !weekPicker,
'nc-selected-week z-1': isDateInSelectedWeek(date) && weekPicker,
'text-gray-400': !isDateInCurrentMonth(date),
@ -185,7 +185,7 @@ const paginate = (action: 'next' | 'prev') => {
<span
v-if="isActiveDate(date)"
:class="{
'border-2 border-white !h-2 !w-2': dayjs(date).isSame(dayjs(), 'date'),
'border-1 border-white !h-2 !w-2': dayjs(date).isSame(dayjs(), 'date'),
}"
class="absolute z-2 h-1.5 w-1.5 rounded-full bg-brand-500 top-1 right-1"
></span>

4
packages/nc-gui/components/nc/MonthYearSelector.vue

@ -110,7 +110,7 @@ const compareYear = (date1: dayjs.Dayjs, date2: dayjs.Dayjs) => {
v-for="(month, id) in months"
:key="id"
:class="{
'!bg-brand-50 !border-2 !border-brand-500': isMonthSelected(month),
'!bg-brand-50 !border-1 !border-brand-500': isMonthSelected(month),
}"
class="h-9 rounded-lg flex font-medium items-center justify-center hover:(border-1 border-gray-200 bg-gray-100) text-gray-500 cursor-pointer"
@click="selectedDate = month"
@ -123,7 +123,7 @@ const compareYear = (date1: dayjs.Dayjs, date2: dayjs.Dayjs) => {
v-for="(year, id) in years"
:key="id"
:class="{
'!bg-brand-50 !border-2 !border-brand-500': compareYear(year, selectedDate),
'!bg-brand-50 !border-1 !border-brand-500': compareYear(year, selectedDate),
}"
class="h-9 rounded-lg flex font-medium items-center justify-center hover:(border-1 border-gray-200 bg-gray-100) text-gray-500 cursor-pointer"
@click="selectedDate = year"

2
packages/nc-gui/components/smartsheet/Toolbar.vue

@ -51,7 +51,7 @@ const { allowCSVDownload } = useSharedView()
<LazySmartsheetToolbarCalendarRange v-if="isCalendar" />
<LazySmartsheetToolbarFieldsMenu
v-if="isGrid || isGallery || isKanban || isMap || isCalendar"
v-if="isGrid || isGallery || isKanban || isMap || !isCalendar"
:show-system-fields="false"
/>

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

@ -635,7 +635,6 @@ const dragStart = (event: MouseEvent, record: Row) => {
>
<LazySmartsheetRow :row="record">
<LazySmartsheetCalendarVRecordCard
:date="dayjs(record.row![record.rowMeta!.range!.fk_from_col.title!]).format('HH:mm')"
:name="record.row![displayField!.title!]"
:position="record.rowMeta!.position"
:record="record"

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

@ -66,7 +66,7 @@ const dates = computed(() => {
let numberOfRows = Math.ceil(daysToDisplay / 7)
numberOfRows = Math.max(numberOfRows, 5)
const weeksArray: Array<Array<Date>> = []
const weeksArray: Array<Array<dayjs.Dayjs>> = []
let currentDay = firstDayToDisplay
for (let week = 0; week < numberOfRows; week++) {
const weekArray = []
@ -86,7 +86,10 @@ function getRandomNumbers() {
return randomValues.join('')
}
const recordsToDisplay = computed(() => {
const recordsToDisplay = computed<{
records: Row[]
count: { [p: string]: { overflow: boolean; count: number; overflowCount: number } }
}>(() => {
if (!dates.value || !calendarRange.value) return []
const perWidth = gridContainerWidth.value / 7
@ -174,7 +177,10 @@ const recordsToDisplay = computed(() => {
let currentWeekStart = startDate.startOf('week')
const id = record.rowMeta.id ?? getRandomNumbers()
while (currentWeekStart.isBefore(endDate)) {
while (
currentWeekStart.isSameOrBefore(endDate, 'day') &&
currentWeekStart.isBefore(dates.value[dates.value.length - 1][6])
) {
const currentWeekEnd = currentWeekStart.endOf('week')
const recordStart = currentWeekStart.isBefore(startDate) ? startDate : currentWeekStart
const recordEnd = currentWeekEnd.isAfter(endDate) ? endDate : currentWeekEnd
@ -245,7 +251,9 @@ const recordsToDisplay = computed(() => {
position = 'rounded'
} else if (startDate.isSame(recordStart, 'week')) {
if (isStartMonthBeforeCurrentWeek) {
position = 'rightRounded'
if (endDate.isSame(currentWeekEnd, 'week')) {
position = 'rounded'
} else position = 'leftRounded'
} else position = 'leftRounded'
} else if (endDate.isSame(currentWeekEnd, 'week')) {
position = 'rightRounded'
@ -278,17 +286,16 @@ const recordsToDisplay = computed(() => {
id,
},
})
currentWeekStart = currentWeekStart.add(1, 'week').endOf('week')
currentWeekStart = currentWeekStart.add(1, 'week')
}
}
})
})
const result: { records: Row[]; count: { [p: string]: { overflow: boolean; count: number; overflowCount: number } } } = {
return {
records: recordsToDisplay,
count: recordsInDay,
}
return result
})
const onDrag = (event: MouseEvent) => {
@ -566,7 +573,7 @@ const dragStart = (event: MouseEvent, record: Row) => {
isDragging.value = true
dragElement.value = target
draggingId.value = record.rowMeta.id
draggingId.value = record.rowMeta!.id!
dragRecord.value = record
document.addEventListener('mousemove', onDrag)
@ -717,11 +724,11 @@ const isDateSelected = (date: dayjs.Dayjs) => {
v-for="(day, dateIndex) in week"
:key="`${weekIndex}-${dateIndex}`"
:class="{
'border-brand-500 border-2 border-r-2 border-b-2':
'border-brand-500 border-1 border-r-1 border-b-1':
isDateSelected(day) || (focusedDate && dayjs(day).isSame(focusedDate, 'day')),
'!text-gray-400': !isDayInPagedMonth(day),
'!text-gray-200': !isDayInPagedMonth(day),
}"
class="text-right relative group text-sm h-full border-r-1 border-b-1 border-gray-200 font-semibold hover:bg-gray-50 text-gray-800 bg-white"
class="text-right relative group text-sm h-full border-r-1 border-b-1 border-gray-200 font-medium hover:bg-gray-50 text-gray-800 bg-white"
@click="selectDate(day)"
>
<div v-if="isUIAllowed('dataEdit')" class="flex justify-between p-1">
@ -794,7 +801,7 @@ const isDateSelected = (date: dayjs.Dayjs) => {
</NcButton>
<span
:class="{
'bg-brand-50 text-brand-500': day.isSame(dayjs(), 'date'),
'bg-brand-50 text-brand-500': day.isSame(dayjs(), 'date'),
}"
class="px-1.5 rounded-lg py-1 my-1"
>
@ -809,7 +816,7 @@ const isDateSelected = (date: dayjs.Dayjs) => {
recordsToDisplay.count[dayjs(day).format('YYYY-MM-DD')]?.overflow &&
!draggingId
"
class="!absolute bottom-1 text-center w-13 mx-auto inset-x-0 z-3 text-gray-500"
class="!absolute bottom-1 text-center w-15 mx-auto inset-x-0 z-3 text-gray-500"
size="xxsmall"
type="secondary"
@click="viewMore(day)"

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

@ -22,6 +22,7 @@ const {
pageDate,
displayField,
selectedDate,
selectedTime,
selectedMonth,
calendarRange,
selectedDateRange,
@ -91,6 +92,7 @@ const renderData = computed<Array<Row>>(() => {
sideBarFilterOption.value === 'month' ||
sideBarFilterOption.value === 'year' ||
sideBarFilterOption.value === 'selectedDate' ||
sideBarFilterOption.value === 'selectedHours' ||
sideBarFilterOption.value === 'week' ||
sideBarFilterOption.value === 'day'
) {
@ -118,6 +120,10 @@ const renderData = computed<Array<Row>>(() => {
fromDate = dayjs(selectedDate.value).startOf('day')
toDate = dayjs(selectedDate.value).endOf('day')
break
case 'selectedHours':
fromDate = dayjs(selectedTime.value).startOf('hour')
toDate = dayjs(selectedTime.value).endOf('hour')
break
}
if (from && to) {
@ -143,6 +149,10 @@ const renderData = computed<Array<Row>>(() => {
if (from.isSame(selectedDate.value, 'day')) {
pushToArray(rangedData, record, range)
}
} else if (sideBarFilterOption.value === 'selectedHours') {
if (from.isSame(selectedTime.value, 'hour')) {
pushToArray(rangedData, record, range)
}
} else if (
sideBarFilterOption.value === 'week' ||
sideBarFilterOption.value === 'month' ||
@ -196,11 +206,21 @@ const options = computed(() => {
]
}
case 'week' as const:
return [
{ label: 'In this week', value: 'week' },
{ label: 'Without dates', value: 'withoutDates' },
{ label: 'All records', value: 'allRecords' },
]
if (calDataType.value === UITypes.Date) {
return [
{ label: 'In this day', value: 'day' },
{ label: 'Without dates', value: 'withoutDates' },
{ label: 'All records', value: 'allRecords' },
]
} else {
return [
{ label: 'In this day', value: 'day' },
{ label: 'Without dates', value: 'withoutDates' },
{ label: 'All records', value: 'allRecords' },
{ label: 'In selected hours', value: 'selectedHours' },
{ label: 'In selected date', value: 'selectedDate' },
]
}
case 'month' as const:
return [
{ label: 'In this month', value: 'month' },

2
packages/nc-gui/components/smartsheet/calendar/SideRecordCard.vue

@ -32,7 +32,7 @@ const props = withDefaults(defineProps<Props>(), {
class="block h-10 w-1 rounded"
></span>
<div class="flex flex-col gap-1 ml-3">
<span class="text-sm text-gray-800">{{ name }}</span>
<span class="text-sm max-w-36 truncate text-gray-800">{{ name }}</span>
<span v-if="showDate" class="text-xs text-gray-500">{{ fromDate }} {{ toDate ? ` - ${toDate}` : '' }}</span>
</div>
</div>

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

@ -591,7 +591,7 @@ const dropEvent = (event: DragEvent) => {
v-for="date in weekDates"
:key="date.toISOString()"
:class="{
'!border-2 border-brand-500': dayjs(date).isSame(selectedDate, 'day'),
'!border-1 border-brand-500': dayjs(date).isSame(selectedDate, 'day'),
}"
class="flex flex-col border-r-1 min-h-[100vh] last:border-r-0 items-center w-1/7"
@click="selectedDate = date"
@ -614,7 +614,6 @@ const dropEvent = (event: DragEvent) => {
>
<LazySmartsheetRow :row="record">
<LazySmartsheetCalendarRecordCard
:date="dayjs(record.row[record.rowMeta.range!.fk_from_col.title!]).format('DD-MM-YYYY')"
:name="record.row[displayField!.title!]"
:position="record.rowMeta.position"
:record="record"

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

@ -5,8 +5,17 @@ import { computed, ref } from '#imports'
const emits = defineEmits(['expandRecord'])
const { selectedDateRange, formattedData, formattedSideBarData, calendarRange, displayField, selectedTime, updateRowProperty } =
useCalendarViewStoreOrThrow()
const {
selectedDateRange,
formattedData,
formattedSideBarData,
calendarRange,
displayField,
selectedTime,
updateRowProperty,
sideBarFilterOption,
showSideMenu,
} = useCalendarViewStoreOrThrow()
const container = ref<null | HTMLElement>(null)
@ -47,8 +56,19 @@ function getRandomNumbers() {
return randomValues.join('')
}
const recordsAcrossAllRange = computed(() => {
if (!formattedData.value || !calendarRange.value || !container.value) return []
const recordsAcrossAllRange = computed<{
records: Array<Row>
count: {
[key: string]: {
[key: string]: {
id: Array<string>
overflow: boolean
overflowCount: number
}
}
}
}>(() => {
if (!formattedData.value || !calendarRange.value || !container.value) return { records: [], count: {} }
const { scrollHeight } = container.value
@ -60,12 +80,14 @@ const recordsAcrossAllRange = computed(() => {
const overlaps: {
[key: string]: {
[key: string]: Array<string>
[key: string]: {
id: Array<string>
overflow: boolean
overflowCount: number
}
}
} = {}
if (!calendarRange.value) return []
let recordsToDisplay: Array<Row> = []
calendarRange.value.forEach((range) => {
@ -94,14 +116,25 @@ const recordsAcrossAllRange = computed(() => {
const hourKey = startDate?.format('HH:mm')
const id = record.rowMeta.id ?? getRandomNumbers()
let style: Partial<CSSStyleDeclaration> = {}
if (dateKey && hourKey) {
if (!overlaps[dateKey]) {
overlaps[dateKey] = {}
}
if (!overlaps[dateKey][hourKey]) {
overlaps[dateKey][hourKey] = []
overlaps[dateKey][hourKey] = {
id: [],
overflow: false,
overflowCount: 0,
}
}
overlaps[dateKey][hourKey].push(id)
overlaps[dateKey][hourKey].id.push(id)
}
if (overlaps[dateKey][hourKey].id.length > 4) {
overlaps[dateKey][hourKey].overflow = true
style.display = 'none'
overlaps[dateKey][hourKey].overflowCount += 1
}
let dayIndex = dayjs(dateKey).day() - 1
@ -112,7 +145,8 @@ const recordsAcrossAllRange = computed(() => {
const hourIndex = datesHours.value[dayIndex].findIndex((h) => h.format('HH:mm') === hourKey)
const style: Partial<CSSStyleDeclaration> = {
style = {
...style,
top: `${hourIndex * perHeight}px`,
height: `${perHeight / 2 - 30}px`,
}
@ -190,15 +224,28 @@ const recordsAcrossAllRange = computed(() => {
let _startHourIndex = startHourIndex
let style: Partial<CSSStyleDeclaration> = {}
while (_startHourIndex <= endHourIndex) {
const hourKey = datesHours.value[dayIndex][_startHourIndex].format('HH:mm')
if (!overlaps[dateKey]) {
overlaps[dateKey] = {}
}
if (!overlaps[dateKey][hourKey]) {
overlaps[dateKey][hourKey] = []
overlaps[dateKey][hourKey] = {
id: [],
overflow: false,
overflowCount: 0,
}
}
overlaps[dateKey][hourKey].id.push(id)
if (overlaps[dateKey][hourKey].id.length > 4) {
overlaps[dateKey][hourKey].overflow = true
style.display = 'none'
overlaps[dateKey][hourKey].overflowCount += 1
}
overlaps[dateKey][hourKey].push(id)
_startHourIndex++
}
@ -208,7 +255,8 @@ const recordsAcrossAllRange = computed(() => {
const height = (endHourIndex - startHourIndex + 1) * perHeight - spanHours - 5
const style: Partial<CSSStyleDeclaration> = {
style = {
...style,
top: `${top}px`,
height: `${height}px`,
}
@ -238,9 +286,9 @@ const recordsAcrossAllRange = computed(() => {
const dateKey = dayjs(selectedDateRange.value.start).add(dayIndex, 'day').format('YYYY-MM-DD')
for (const hours in overlaps[dateKey]) {
if (overlaps[dateKey][hours].includes(record.rowMeta.id!)) {
maxOverlaps = Math.max(maxOverlaps, overlaps[dateKey][hours].length)
overlapIndex = Math.max(overlapIndex, overlaps[dateKey][hours].indexOf(record.rowMeta.id!))
if (overlaps[dateKey][hours].id.includes(record.rowMeta.id!)) {
maxOverlaps = Math.max(maxOverlaps, overlaps[dateKey][hours].id.length - overlaps[dateKey][hours].overflowCount)
overlapIndex = Math.max(overlapIndex, overlaps[dateKey][hours].id.indexOf(record.rowMeta.id!))
}
}
const spacing = 1
@ -256,7 +304,10 @@ const recordsAcrossAllRange = computed(() => {
})
})
return recordsToDisplay
return {
records: recordsToDisplay,
count: overlaps,
}
})
const dragElement = ref<HTMLElement | null>(null)
@ -662,6 +713,12 @@ const dropEvent = (event: DragEvent) => {
updateRowProperty(newRow, updateProperty, false)
}
}
const viewMore = (hour: dayjs.Dayjs) => {
sideBarFilterOption.value = 'selectedHours'
selectedTime.value = hour
showSideMenu.value = true
}
</script>
<template>
@ -681,20 +738,33 @@ const dropEvent = (event: DragEvent) => {
v-for="(hour, hourIndex) in date"
:key="hourIndex"
:class="{
'border-2 !border-brand-500': hour.isSame(selectedTime, 'hour'),
'border-1 !border-brand-500': hour.isSame(selectedTime, 'hour'),
}"
class="text-center relative h-56 text-sm text-gray-500 w-full py-1 border-gray-200 border-1 border-r-white border-t-white last:border-r-white bg-gray-50"
@click="selectedTime = hour.toDate()"
@click="selectedTime = hour"
>
<span v-if="date[0].day() === selectedDateRange.start?.day()" class="absolute left-1">
{{ hour.format('h A') }}
</span>
<NcButton
v-if="recordsAcrossAllRange?.count?.[hour.format('YYYY-MM-DD')]?.[hour.format('HH:mm')]?.overflow"
class="!absolute bottom-1 text-center w-15 ml-auto inset-x-0 z-3 text-gray-500"
size="xxsmall"
type="secondary"
@click="viewMore(hour)"
>
<span class="text-xs">
+
{{ recordsAcrossAllRange?.count[hour.format('YYYY-MM-DD')][hour.format('HH:mm')]?.overflowCount }}
more
</span>
</NcButton>
</div>
</div>
<div class="absolute pointer-events-none inset-0 !mt-[20px]">
<div
v-for="(record, rowIndex) in recordsAcrossAllRange"
v-for="(record, rowIndex) in recordsAcrossAllRange.records"
:key="rowIndex"
:data-unique-id="record.rowMeta!.id"
:style="record.rowMeta!.style"
@ -704,7 +774,6 @@ const dropEvent = (event: DragEvent) => {
>
<LazySmartsheetRow :row="record">
<LazySmartsheetCalendarVRecordCard
:date="dayjs(record.row![record.rowMeta!.range!.fk_from_col.title!]).format('HH:mm')"
:name="record.row![displayField!.title!]"
:position="record.rowMeta!.position"
:record="record"

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

@ -1,7 +1,15 @@
import type { ComputedRef, Ref } from 'vue'
import { type Api, type CalendarType, type ColumnType, type PaginatedType, type TableType, type ViewType } from 'nocodb-sdk'
import {
type Api,
type CalendarType,
type ColumnType,
type PaginatedType,
type TableType,
UITypes,
type ViewType,
} from 'nocodb-sdk'
import dayjs from 'dayjs'
import { addDays, addMonths, addYears, extractPkFromRow, extractSdkResponseErrorMsg, rowPkData } from '~/utils'
import { extractPkFromRow, extractSdkResponseErrorMsg, rowPkData } from '~/utils'
import { IsPublicInj, type Row, ref, storeToRefs, useBase, useInjectionState, useUndoRedo } from '#imports'
const formatData = (list: Record<string, any>[]) =>
@ -40,7 +48,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
const selectedDate = ref<dayjs.Dayjs>(dayjs())
const selectedTime = ref<dayjs.Dayjs | null>(null)
const selectedTime = ref<dayjs.Dayjs>(dayjs())
const selectedMonth = ref<dayjs.Dayjs>(dayjs())
@ -146,7 +154,8 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
sideBarFilterOption.value === 'month' ||
sideBarFilterOption.value === 'day' ||
sideBarFilterOption.value === 'year' ||
sideBarFilterOption.value === 'selectedDate'
sideBarFilterOption.value === 'selectedDate' ||
sideBarFilterOption.value === 'selectedHours'
) {
let fromDate: string | null | dayjs.Dayjs = null
let toDate: string | null | dayjs.Dayjs = null
@ -177,10 +186,19 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
fromDate = selectedDate.value.startOf('day')
toDate = selectedDate.value.endOf('day')
break
case 'selectedHours':
fromDate = selectedTime.value?.startOf('hour')
toDate = selectedTime.value?.endOf('hour')
break
}
fromDate = fromDate!.format('YYYY-MM-DD HH:mm:ssZ')
toDate = toDate!.format('YYYY-MM-DD HH:mm:ssZ')
if (calDataType.value === UITypes.Date) {
fromDate = fromDate!.format('YYYY-MM-DD')
toDate = toDate!.format('YYYY-MM-DD')
} else {
fromDate = fromDate!.format('YYYY-MM-DD HH:mm:ssZ')
toDate = toDate!.format('YYYY-MM-DD HH:mm:ssZ')
}
calendarRange.value.forEach((range) => {
const fromCol = range.fk_from_col
@ -675,15 +693,19 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
watch(selectedDate, async () => {
if (activeCalendarView.value === 'month' || activeCalendarView.value === 'week') {
await loadSidebarData()
if (sideBarFilterOption.value === 'selectedDate') {
await loadSidebarData()
}
} else {
await Promise.all([loadCalendarData(), loadSidebarData()])
}
})
watch(selectedMonth, async () => {
watch(selectedMonth, async (value, oldValue) => {
if (activeCalendarView.value !== 'month') return
await Promise.all([loadCalendarData(), loadSidebarData()])
if (value.month() !== oldValue.month()) {
await Promise.all([loadCalendarData(), loadSidebarData()])
}
})
watch(selectedDateRange, async () => {

Loading…
Cancel
Save