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)
+ })
+}
@@ -720,6 +729,19 @@ onMounted(async () => {
Add another date field
-->
+
+
+
+
+
+
Calendar is readonly
+ {{ $t('msg.info.calendarReadOnly') }}
+
+
+
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) {