Browse Source

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
pull/9299/head
Anbarasu 3 months ago committed by GitHub
parent
commit
dd499d1d13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 22
      packages/nc-gui/components/dlg/ViewCreate.vue
  2. 5
      packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue
  3. 17
      packages/nc-gui/components/smartsheet/calendar/MonthView.vue
  4. 9
      packages/nc-gui/components/smartsheet/calendar/SideMenu.vue
  5. 13
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue
  6. 11
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue
  7. 9
      packages/nc-gui/composables/useCalendarViewStore.ts
  8. 1
      packages/nc-gui/lang/en.json
  9. 53
      packages/nocodb/src/helpers/catchError.ts

22
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)
})
}
</script> </script>
<template> <template>
@ -720,6 +729,19 @@ onMounted(async () => {
Add another date field Add another date field
</NcButton> --> </NcButton> -->
</div> </div>
<div
v-if="isCalendarReadonly(form.calendar_range)"
class="flex flex-row p-4 border-gray-200 border-1 gap-x-4 rounded-lg w-full"
>
<div class="text-gray-500 flex gap-4">
<GeneralIcon class="min-w-6 h-6 text-orange-500" icon="info" />
<div class="flex flex-col gap-1">
<h2 class="font-semibold text-sm mb-0 text-gray-800">Calendar is readonly</h2>
<span class="text-gray-500 font-default text-sm"> {{ $t('msg.info.calendarReadOnly') }}</span>
</div>
</div>
</div>
</template> </template>
</a-form> </a-form>
<div v-else-if="!isNecessaryColumnsPresent" class="flex flex-row p-4 border-gray-200 border-1 gap-x-4 rounded-lg w-full"> <div v-else-if="!isNecessaryColumnsPresent" class="flex flex-row p-4 border-gray-200 border-1 gap-x-4 rounded-lg w-full">

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

@ -15,6 +15,7 @@ const {
displayField, displayField,
sideBarFilterOption, sideBarFilterOption,
showSideMenu, showSideMenu,
updateFormat,
} = useCalendarViewStoreOrThrow() } = useCalendarViewStoreOrThrow()
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
@ -515,7 +516,7 @@ const calculateNewRow = (event: MouseEvent, skipChangeCheck?: boolean) => {
...dragRecord.value, ...dragRecord.value,
row: { row: {
...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() 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!) updateProperty.push(toCol.title!)
} }

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

@ -17,6 +17,7 @@ const {
viewMetaProperties, viewMetaProperties,
showSideMenu, showSideMenu,
updateRowProperty, updateRowProperty,
updateFormat,
} = useCalendarViewStoreOrThrow() } = useCalendarViewStoreOrThrow()
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
@ -400,10 +401,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean, skipChangeC
...dragRecord.value, ...dragRecord.value,
row: { row: {
...dragRecord.value?.row, ...dragRecord.value?.row,
[fromCol!.title!]: [fromCol!.title!]: dayjs(newStartDate).format(updateFormat.value),
calDataType.value === UITypes.Date
? dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ')
: dayjs(newStartDate).utc().format('YYYY-MM-DD HH:mm:ssZ'),
}, },
} }
@ -423,10 +421,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean, skipChangeC
endDate = newStartDate.clone() endDate = newStartDate.clone()
} }
newRow.row[toCol!.title!] = newRow.row[toCol!.title!] = dayjs(endDate).format(updateFormat.value)
calDataType.value === UITypes.Date
? dayjs(endDate).format('YYYY-MM-DD HH:mm:ssZ')
: dayjs(endDate).utc().format('YYYY-MM-DD HH:mm:ssZ')
updateProperty.push(toCol!.title!) updateProperty.push(toCol!.title!)
} }
@ -501,7 +496,7 @@ const onResize = (event: MouseEvent) => {
...resizeRecord.value, ...resizeRecord.value,
row: { row: {
...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 { } else {
@ -517,7 +512,7 @@ const onResize = (event: MouseEvent) => {
...resizeRecord.value, ...resizeRecord.value,
row: { row: {
...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 if (!fromCol) return
const newRecord = { const newRecord = {
row: { row: {
[fromCol.title!]: date.format('YYYY-MM-DD HH:mm:ssZ'), [fromCol.title!]: date.format(updateFormat.value),
}, },
} }
emit('newRecord', newRecord) emit('newRecord', newRecord)

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

@ -49,6 +49,7 @@ const {
searchQuery, searchQuery,
sideBarFilterOption, sideBarFilterOption,
showSideMenu, showSideMenu,
updateFormat,
} = useCalendarViewStoreOrThrow() } = useCalendarViewStoreOrThrow()
const sideBarListRef = ref<VNodeRef | null>(null) const sideBarListRef = ref<VNodeRef | null>(null)
@ -287,13 +288,13 @@ const newRecord = () => {
} }
if (activeCalendarView.value === 'day') { 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') { } 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') { } 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') { } 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 } }) emit('newRecord', { row, oldRow: {}, rowMeta: { new: true } })

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

@ -14,6 +14,7 @@ const {
displayField, displayField,
updateRowProperty, updateRowProperty,
viewMetaProperties, viewMetaProperties,
updateFormat,
} = useCalendarViewStoreOrThrow() } = useCalendarViewStoreOrThrow()
const maxVisibleDays = computed(() => { const maxVisibleDays = computed(() => {
@ -22,6 +23,8 @@ const maxVisibleDays = computed(() => {
const container = ref<null | HTMLElement>(null) const container = ref<null | HTMLElement>(null)
const { $e } = useNuxtApp()
const { width: containerWidth } = useElementSize(container) const { width: containerWidth } = useElementSize(container)
const { isUIAllowed } = useRoles() const { isUIAllowed } = useRoles()
@ -322,7 +325,7 @@ const onResize = (event: MouseEvent) => {
...resizeRecord.value, ...resizeRecord.value,
row: { row: {
...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') { } else if (resizeDirection.value === 'left') {
@ -340,7 +343,7 @@ const onResize = (event: MouseEvent) => {
...resizeRecord.value, ...resizeRecord.value,
row: { row: {
...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, ...dragRecord.value,
row: { row: {
...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() 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!) updateProperty.push(toCol.title!)
} }
@ -559,7 +562,7 @@ const addRecord = (date: dayjs.Dayjs) => {
if (!fromCol) return if (!fromCol) return
const newRecord = { const newRecord = {
row: { row: {
[fromCol.title!]: date.format('YYYY-MM-DD HH:mm:ssZ'), [fromCol.title!]: date.format(updateFormat.value),
}, },
} }
emits('newRecord', newRecord) emits('newRecord', newRecord)

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

@ -17,6 +17,7 @@ const {
updateRowProperty, updateRowProperty,
sideBarFilterOption, sideBarFilterOption,
showSideMenu, showSideMenu,
updateFormat,
} = useCalendarViewStoreOrThrow() } = useCalendarViewStoreOrThrow()
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
@ -655,7 +656,7 @@ const onResize = (event: MouseEvent) => {
...resizeRecord.value, ...resizeRecord.value,
row: { row: {
...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') { } else if (resizeDirection.value === 'left') {
@ -672,7 +673,7 @@ const onResize = (event: MouseEvent) => {
...resizeRecord.value, ...resizeRecord.value,
row: { row: {
...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, ...dragRecord.value,
row: { row: {
...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() 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!) updatedProperty.push(toCol.title!)
} }
@ -929,7 +930,7 @@ const addRecord = (date: dayjs.Dayjs) => {
if (!fromCol) return if (!fromCol) return
const newRecord = { const newRecord = {
row: { row: {
[fromCol.title!]: date.format('YYYY-MM-DD HH:mm:ssZ'), [fromCol.title!]: date.format(updateFormat.value),
}, },
} }
emits('newRecord', newRecord) emits('newRecord', newRecord)

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

@ -91,6 +91,8 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
const { api } = useApi() const { api } = useApi()
const { isMysql } = useBase()
const { base } = storeToRefs(useBase()) const { base } = storeToRefs(useBase())
const { $api, $e } = useNuxtApp() const { $api, $e } = useNuxtApp()
@ -114,6 +116,10 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
where: where?.value ?? '', 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< const calendarRange = ref<
Array<{ Array<{
fk_from_col: ColumnType fk_from_col: ColumnType
@ -772,7 +778,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
await fetchActiveDates() await fetchActiveDates()
return updatedRowData return updatedRowData
} catch (e: any) { } 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, selectedDateRange,
paginateCalendarView, paginateCalendarView,
viewMetaProperties, viewMetaProperties,
updateFormat,
} }
}, },
) )

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

@ -1500,6 +1500,7 @@
} }
}, },
"info": { "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", "schemaReadOnly": "Schema alterations are disabled for this source",
"enterWorkspaceName": "Enter workspace name", "enterWorkspaceName": "Enter workspace name",
"enterBaseName": "Enter base name", "enterBaseName": "Enter base name",

53
packages/nocodb/src/helpers/catchError.ts

@ -15,6 +15,7 @@ export enum DBError {
CONSTRAINT_EXIST = 'CONSTRAINT_EXIST', CONSTRAINT_EXIST = 'CONSTRAINT_EXIST',
CONSTRAINT_NOT_EXIST = 'CONSTRAINT_NOT_EXIST', CONSTRAINT_NOT_EXIST = 'CONSTRAINT_NOT_EXIST',
COLUMN_NOT_NULL = 'COLUMN_NOT_NULL', COLUMN_NOT_NULL = 'COLUMN_NOT_NULL',
DATA_TYPE_MISMATCH = 'DATA_TYPE_MISMATCH',
} }
// extract db errors using database error code // extract db errors using database error code
@ -49,6 +50,13 @@ export function extractDBError(error): {
case 'SQLITE_CORRUPT': case 'SQLITE_CORRUPT':
message = 'The database file is corrupt.'; message = 'The database file is corrupt.';
break; break;
case 'SQLITE_MISMATCH':
if (error.message) {
message = 'Data type mismatch in SQLite operation.';
_type = DBError.DATA_TYPE_MISMATCH;
}
break;
case 'SQLITE_ERROR': case 'SQLITE_ERROR':
message = 'A SQL error occurred.'; message = 'A SQL error occurred.';
@ -121,6 +129,26 @@ export function extractDBError(error): {
break; break;
// mysql errors // 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': case 'ER_TABLE_EXISTS_ERROR':
message = 'The table already exists.'; message = 'The table already exists.';
@ -273,6 +301,31 @@ export function extractDBError(error): {
} }
} }
break; 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': case '42701':
message = 'The column already exists.'; message = 'The column already exists.';
if (error.message) { if (error.message) {

Loading…
Cancel
Save