From dd499d1d13ef722a1158fa81c307bf9ef2eb37d8 Mon Sep 17 00:00:00 2001 From: Anbarasu Date: Wed, 28 Aug 2024 19:37:11 +0530 Subject: [PATCH] Nc misc fixes (#9363) * fix: show calendar is readonly when system fields or computed fields are used * fix: handle data type mismatch * fix: handle mysql 5 errors in calendar * fix: mysql drag drop fix --- packages/nc-gui/components/dlg/ViewCreate.vue | 22 ++++++++ .../calendar/DayView/DateTimeField.vue | 5 +- .../smartsheet/calendar/MonthView.vue | 17 +++--- .../smartsheet/calendar/SideMenu.vue | 9 ++-- .../calendar/WeekView/DateField.vue | 13 +++-- .../calendar/WeekView/DateTimeField.vue | 11 ++-- .../composables/useCalendarViewStore.ts | 9 +++- packages/nc-gui/lang/en.json | 1 + packages/nocodb/src/helpers/catchError.ts | 53 +++++++++++++++++++ 9 files changed, 112 insertions(+), 28 deletions(-) diff --git a/packages/nc-gui/components/dlg/ViewCreate.vue b/packages/nc-gui/components/dlg/ViewCreate.vue index 87581a44b6..4b90e3ac29 100644 --- a/packages/nc-gui/components/dlg/ViewCreate.vue +++ b/packages/nc-gui/components/dlg/ViewCreate.vue @@ -441,6 +441,15 @@ onMounted(async () => { } } }) + +const isCalendarReadonly = (calendarRange?: Array<{ fk_from_column_id: string; fk_to_column_id: string | null }>) => { + if (!calendarRange) return false + return calendarRange.some((range) => { + console.log(range) + const column = viewSelectFieldOptions.value?.find((c) => c.value === range?.fk_from_column_id) + return !column || ![UITypes.DateTime, UITypes.Date].includes(column.uidt) + }) +}
diff --git a/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue b/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue index 5276ebeb7a..90c6ca3169 100644 --- a/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue +++ b/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue @@ -15,6 +15,7 @@ const { displayField, sideBarFilterOption, showSideMenu, + updateFormat, } = useCalendarViewStoreOrThrow() const { $e } = useNuxtApp() @@ -515,7 +516,7 @@ const calculateNewRow = (event: MouseEvent, skipChangeCheck?: boolean) => { ...dragRecord.value, row: { ...dragRecord.value.row, - [fromCol.title!]: dayjs(newStartDate).utc().format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: dayjs(newStartDate).format(updateFormat.value), }, } @@ -538,7 +539,7 @@ const calculateNewRow = (event: MouseEvent, skipChangeCheck?: boolean) => { endDate = newStartDate.clone() } - newRow.row[toCol.title!] = dayjs(endDate).utc().format('YYYY-MM-DD HH:mm:ssZ') + newRow.row[toCol.title!] = dayjs(endDate).format(updateFormat.value) updateProperty.push(toCol.title!) } diff --git a/packages/nc-gui/components/smartsheet/calendar/MonthView.vue b/packages/nc-gui/components/smartsheet/calendar/MonthView.vue index ed79de6946..39cec46048 100644 --- a/packages/nc-gui/components/smartsheet/calendar/MonthView.vue +++ b/packages/nc-gui/components/smartsheet/calendar/MonthView.vue @@ -17,6 +17,7 @@ const { viewMetaProperties, showSideMenu, updateRowProperty, + updateFormat, } = useCalendarViewStoreOrThrow() const { $e } = useNuxtApp() @@ -400,10 +401,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean, skipChangeC ...dragRecord.value, row: { ...dragRecord.value?.row, - [fromCol!.title!]: - calDataType.value === UITypes.Date - ? dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ') - : dayjs(newStartDate).utc().format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol!.title!]: dayjs(newStartDate).format(updateFormat.value), }, } @@ -423,10 +421,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean, skipChangeC endDate = newStartDate.clone() } - newRow.row[toCol!.title!] = - calDataType.value === UITypes.Date - ? dayjs(endDate).format('YYYY-MM-DD HH:mm:ssZ') - : dayjs(endDate).utc().format('YYYY-MM-DD HH:mm:ssZ') + newRow.row[toCol!.title!] = dayjs(endDate).format(updateFormat.value) updateProperty.push(toCol!.title!) } @@ -501,7 +496,7 @@ const onResize = (event: MouseEvent) => { ...resizeRecord.value, row: { ...resizeRecord.value.row, - [toCol!.title!]: dayjs(newEndDate).format('YYYY-MM-DD HH:mm:ssZ'), + [toCol!.title!]: dayjs(newEndDate).format(updateFormat.value), }, } } else { @@ -517,7 +512,7 @@ const onResize = (event: MouseEvent) => { ...resizeRecord.value, row: { ...resizeRecord.value.row, - [fromCol!.title!]: dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol!.title!]: dayjs(newStartDate).format(updateFormat.value), }, } } @@ -689,7 +684,7 @@ const addRecord = (date: dayjs.Dayjs) => { if (!fromCol) return const newRecord = { row: { - [fromCol.title!]: date.format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: date.format(updateFormat.value), }, } emit('newRecord', newRecord) diff --git a/packages/nc-gui/components/smartsheet/calendar/SideMenu.vue b/packages/nc-gui/components/smartsheet/calendar/SideMenu.vue index 9093d4b50b..53adce2ccf 100644 --- a/packages/nc-gui/components/smartsheet/calendar/SideMenu.vue +++ b/packages/nc-gui/components/smartsheet/calendar/SideMenu.vue @@ -49,6 +49,7 @@ const { searchQuery, sideBarFilterOption, showSideMenu, + updateFormat, } = useCalendarViewStoreOrThrow() const sideBarListRef = ref(null) @@ -287,13 +288,13 @@ const newRecord = () => { } if (activeCalendarView.value === 'day') { - row[calendarRange.value[0]!.fk_from_col!.title!] = selectedDate.value.format('YYYY-MM-DD HH:mm:ssZ') + row[calendarRange.value[0]!.fk_from_col!.title!] = selectedDate.value.format(updateFormat.value) } else if (activeCalendarView.value === 'week') { - row[calendarRange.value[0]!.fk_from_col!.title!] = selectedDateRange.value.start.format('YYYY-MM-DD HH:mm:ssZ') + row[calendarRange.value[0]!.fk_from_col!.title!] = selectedDateRange.value.start.format(updateFormat.value) } else if (activeCalendarView.value === 'month') { - row[calendarRange.value[0]!.fk_from_col!.title!] = (selectedDate.value ?? selectedMonth.value).format('YYYY-MM-DD HH:mm:ssZ') + row[calendarRange.value[0]!.fk_from_col!.title!] = (selectedDate.value ?? selectedMonth.value).format(updateFormat.value) } else if (activeCalendarView.value === 'year') { - row[calendarRange.value[0]!.fk_from_col!.title!] = selectedDate.value.format('YYYY-MM-DD HH:mm:ssZ') + row[calendarRange.value[0]!.fk_from_col!.title!] = selectedDate.value.format(updateFormat.value) } emit('newRecord', { row, oldRow: {}, rowMeta: { new: true } }) diff --git a/packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue b/packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue index 8071b26605..224310c55d 100644 --- a/packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue +++ b/packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue @@ -14,6 +14,7 @@ const { displayField, updateRowProperty, viewMetaProperties, + updateFormat, } = useCalendarViewStoreOrThrow() const maxVisibleDays = computed(() => { @@ -22,6 +23,8 @@ const maxVisibleDays = computed(() => { const container = ref(null) +const { $e } = useNuxtApp() + const { width: containerWidth } = useElementSize(container) const { isUIAllowed } = useRoles() @@ -322,7 +325,7 @@ const onResize = (event: MouseEvent) => { ...resizeRecord.value, row: { ...resizeRecord.value.row, - [toCol.title!]: newEndDate.format('YYYY-MM-DD HH:mm:ssZ'), + [toCol.title!]: newEndDate.format(updateFormat.value), }, } } else if (resizeDirection.value === 'left') { @@ -340,7 +343,7 @@ const onResize = (event: MouseEvent) => { ...resizeRecord.value, row: { ...resizeRecord.value.row, - [fromCol.title!]: dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: dayjs(newStartDate).format(updateFormat.value), }, } } @@ -399,7 +402,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBarData?: boolean) => { ...dragRecord.value, row: { ...dragRecord.value.row, - [fromCol.title!]: dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: dayjs(newStartDate).format(updateFormat.value), }, } @@ -423,7 +426,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBarData?: boolean) => { endDate = newStartDate.clone() } - newRow.row[toCol.title!] = dayjs(endDate).format('YYYY-MM-DD HH:mm:ssZ') + newRow.row[toCol.title!] = dayjs(endDate).format(updateFormat.value) updateProperty.push(toCol.title!) } @@ -559,7 +562,7 @@ const addRecord = (date: dayjs.Dayjs) => { if (!fromCol) return const newRecord = { row: { - [fromCol.title!]: date.format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: date.format(updateFormat.value), }, } emits('newRecord', newRecord) diff --git a/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue b/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue index b3b5a5a11d..d40044ff0d 100644 --- a/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue +++ b/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue @@ -17,6 +17,7 @@ const { updateRowProperty, sideBarFilterOption, showSideMenu, + updateFormat, } = useCalendarViewStoreOrThrow() const { $e } = useNuxtApp() @@ -655,7 +656,7 @@ const onResize = (event: MouseEvent) => { ...resizeRecord.value, row: { ...resizeRecord.value.row, - [toCol.title!]: newEndDate.format('YYYY-MM-DD HH:mm:ssZ'), + [toCol.title!]: newEndDate.format(updateFormat.value), }, } } else if (resizeDirection.value === 'left') { @@ -672,7 +673,7 @@ const onResize = (event: MouseEvent) => { ...resizeRecord.value, row: { ...resizeRecord.value.row, - [fromCol.title!]: dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: dayjs(newStartDate).format(updateFormat.value), }, } } @@ -744,7 +745,7 @@ const calculateNewRow = ( ...dragRecord.value, row: { ...dragRecord.value.row, - [fromCol.title!]: dayjs(newStartDate).utc().format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: dayjs(newStartDate).format(updateFormat.value), }, } @@ -762,7 +763,7 @@ const calculateNewRow = ( endDate = newStartDate.clone() } - newRow.row[toCol.title!] = dayjs(endDate).utc().format('YYYY-MM-DD HH:mm:ssZ') + newRow.row[toCol.title!] = dayjs(endDate).format(updateFormat.value) updatedProperty.push(toCol.title!) } @@ -929,7 +930,7 @@ const addRecord = (date: dayjs.Dayjs) => { if (!fromCol) return const newRecord = { row: { - [fromCol.title!]: date.format('YYYY-MM-DD HH:mm:ssZ'), + [fromCol.title!]: date.format(updateFormat.value), }, } emits('newRecord', newRecord) diff --git a/packages/nc-gui/composables/useCalendarViewStore.ts b/packages/nc-gui/composables/useCalendarViewStore.ts index 8fa3c4d950..a5b963063f 100644 --- a/packages/nc-gui/composables/useCalendarViewStore.ts +++ b/packages/nc-gui/composables/useCalendarViewStore.ts @@ -91,6 +91,8 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState( const { api } = useApi() + const { isMysql } = useBase() + const { base } = storeToRefs(useBase()) const { $api, $e } = useNuxtApp() @@ -114,6 +116,10 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState( where: where?.value ?? '', })) + const updateFormat = computed(() => { + return isMysql(meta.value?.source_id) ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD HH:mm:ssZ' + }) + const calendarRange = ref< Array<{ fk_from_col: ColumnType @@ -772,7 +778,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState( await fetchActiveDates() return updatedRowData } catch (e: any) { - message.error(`${t('msg.error.rowUpdateFailed')} ${await extractSdkResponseErrorMsg(e)}`) + message.error(`${t('msg.error.rowUpdateFailed')}: ${await extractSdkResponseErrorMsg(e)}`) } } @@ -913,6 +919,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState( selectedDateRange, paginateCalendarView, viewMetaProperties, + updateFormat, } }, ) diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 8ad7d249e3..c4b92f2114 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -1500,6 +1500,7 @@ } }, "info": { + "calendarReadOnly": "You will not be able to drag records between dates when computed or system fields are used.", "schemaReadOnly": "Schema alterations are disabled for this source", "enterWorkspaceName": "Enter workspace name", "enterBaseName": "Enter base name", diff --git a/packages/nocodb/src/helpers/catchError.ts b/packages/nocodb/src/helpers/catchError.ts index 5c2d91c0c7..9cf6fd9a10 100644 --- a/packages/nocodb/src/helpers/catchError.ts +++ b/packages/nocodb/src/helpers/catchError.ts @@ -15,6 +15,7 @@ export enum DBError { CONSTRAINT_EXIST = 'CONSTRAINT_EXIST', CONSTRAINT_NOT_EXIST = 'CONSTRAINT_NOT_EXIST', COLUMN_NOT_NULL = 'COLUMN_NOT_NULL', + DATA_TYPE_MISMATCH = 'DATA_TYPE_MISMATCH', } // extract db errors using database error code @@ -49,6 +50,13 @@ export function extractDBError(error): { case 'SQLITE_CORRUPT': message = 'The database file is corrupt.'; break; + + case 'SQLITE_MISMATCH': + if (error.message) { + message = 'Data type mismatch in SQLite operation.'; + _type = DBError.DATA_TYPE_MISMATCH; + } + break; case 'SQLITE_ERROR': message = 'A SQL error occurred.'; @@ -121,6 +129,26 @@ export function extractDBError(error): { break; // mysql errors + case 'ER_TRUNCATED_WRONG_VALUE': + case 'ER_WRONG_VALUE': + if (error.message) { + const typeMismatchMatch = error.message.match( + /Incorrect (\w+) value: (.+) for column '(\w+)'/i, + ); + if (typeMismatchMatch) { + const dataType = typeMismatchMatch[1]; + const invalidValue = typeMismatchMatch[2]; + const columnName = typeMismatchMatch[3]; + + message = `Invalid ${dataType} value '${invalidValue}' for column '${columnName}'`; + _type = DBError.DATA_TYPE_MISMATCH; + _extra = { dataType, column: columnName, value: invalidValue }; + } else { + message = 'Invalid data format for a column.'; + _type = DBError.DATA_TYPE_MISMATCH; + } + } + break; case 'ER_TABLE_EXISTS_ERROR': message = 'The table already exists.'; @@ -273,6 +301,31 @@ export function extractDBError(error): { } } break; + case '22P02': // PostgreSQL invalid_text_representation + case '22003': // PostgreSQL numeric_value_out_of_range + if (error.message) { + const pgTypeMismatchMatch = error.message.match( + /invalid input syntax for (\w+): "(.+)"(?: in column "(\w+)")?/i, + ); + if (pgTypeMismatchMatch) { + const dataType = pgTypeMismatchMatch[1]; + const invalidValue = pgTypeMismatchMatch[2]; + const columnName = pgTypeMismatchMatch[3] || 'unknown'; + + message = `Invalid ${dataType} value '${invalidValue}' for column '${columnName}'`; + _type = DBError.DATA_TYPE_MISMATCH; + _extra = { dataType, column: columnName, value: invalidValue }; + } else { + const detailMatch = error.detail + ? error.detail.match(/Column (\w+)/) + : null; + const columnName = detailMatch ? detailMatch[1] : 'unknown'; + message = `Invalid data type or value for column '${columnName}'.`; + _type = DBError.DATA_TYPE_MISMATCH; + _extra = { column: columnName }; + } + } + break; case '42701': message = 'The column already exists.'; if (error.message) {