Browse Source

Feat : UIDT impmporovements (#2026)

* wip: rating cell ui implementation

Signed-off-by: Pranav C <pranavxc@gmail.com>

* wip: migration for meta column data field

Signed-off-by: Pranav C <pranavxc@gmail.com>

* wip: rating column options

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: rating cell creation and mapping metadata

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor:  change default type to int for rating

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: add email cell

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: accept invalid values for columns if validation disabled

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: remove additional options

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: checkbox customization

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: move validate checkbox to advance option

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: add tick icon in checkbox

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: start rating max value from 1

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: minor ui corrections

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: load rating component in gallery view

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: use default icon and color if meta missing(checkbox and rating)

re #2036

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: cache column with parsed metadata

re #2038

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: convert old rating column to number type

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: migration filename correction

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: component name

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2071/head
Pranav C 3 years ago committed by GitHub
parent
commit
8d33fa9b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      packages/nc-gui/components/project/spreadsheet/components/Cell.vue
  2. 38
      packages/nc-gui/components/project/spreadsheet/components/EditColumn.vue
  3. 19
      packages/nc-gui/components/project/spreadsheet/components/EditableCell.vue
  4. 22
      packages/nc-gui/components/project/spreadsheet/components/cell/EmailCell.vue
  5. 14
      packages/nc-gui/components/project/spreadsheet/components/cell/UrlCell.vue
  6. 98
      packages/nc-gui/components/project/spreadsheet/components/editColumn/RatingOptions.vue
  7. 95
      packages/nc-gui/components/project/spreadsheet/components/editColumn/checkboxOptions.vue
  8. 36
      packages/nc-gui/components/project/spreadsheet/components/editableCell/BooleanCell.vue
  9. 9
      packages/nc-gui/components/project/spreadsheet/components/editableCell/EditableUrlCell.vue
  10. 71
      packages/nc-gui/components/project/spreadsheet/components/editableCell/RatingCell.vue
  11. 6
      packages/nc-gui/components/project/spreadsheet/mixins/cell.js
  12. 18
      packages/nc-gui/components/project/spreadsheet/views/GridView.vue
  13. 66
      packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts
  14. 74
      packages/nocodb-sdk/src/lib/sqlUi/MysqlUi.ts
  15. 36
      packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts
  16. 79
      packages/nocodb-sdk/src/lib/sqlUi/PgUi.ts
  17. 76
      packages/nocodb-sdk/src/lib/sqlUi/SqliteUi.ts
  18. 3
      packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSqlv2.ts
  19. 40
      packages/nocodb/src/lib/noco-models/Column.ts
  20. 6
      packages/nocodb/src/lib/noco/common/XcMigrationSourcev2.ts
  21. 38
      packages/nocodb/src/lib/noco/migrationsv2/nc_015_add_meta_col_in_column_table.ts
  22. 4
      packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

11
packages/nc-gui/components/project/spreadsheet/components/Cell.vue

@ -11,11 +11,14 @@
<!-- <enum-list-editable-cell @click.stop="$emit('enableedit')" v-else-if="isEnum && selected" :value="value" :column="column"></enum-list-editable-cell>--> <!-- <enum-list-editable-cell @click.stop="$emit('enableedit')" v-else-if="isEnum && selected" :value="value" :column="column"></enum-list-editable-cell>-->
<enum-cell v-else-if="isEnum" :value="value" :column="column" @click.stop="$emit('enableedit')" /> <enum-cell v-else-if="isEnum" :value="value" :column="column" @click.stop="$emit('enableedit')" />
<url-cell v-else-if="isURL" :value="value" /> <url-cell v-else-if="isURL" :value="value" />
<email-cell v-else-if="isEmail" :value="value" />
<json-cell v-else-if="isJSON" :value="value" /> <json-cell v-else-if="isJSON" :value="value" />
<date-cell v-else-if="isDate" :value="value" /> <date-cell v-else-if="isDate" :value="value" />
<date-time-cell v-else-if="isDateTime" :value="value" /> <date-time-cell v-else-if="isDateTime" :value="value" />
<time-cell v-else-if="isTime" :value="value" /> <time-cell v-else-if="isTime" :value="value" />
<boolean-cell v-else-if="isBoolean" :value="value" /> <boolean-cell v-else-if="isBoolean" :value="value" read-only />
<rating-cell v-else-if="isRating" :value="value" read-only />
<span v-else :class="{'long-text-cell' : isTextArea}" :title="title">{{ value }}</span> <span v-else :class="{'long-text-cell' : isTextArea}" :title="title">{{ value }}</span>
</template> </template>
@ -30,12 +33,14 @@ import SetListCell from '~/components/project/spreadsheet/components/cell/SetLis
import EnumCell from '~/components/project/spreadsheet/components/cell/EnumCell' import EnumCell from '~/components/project/spreadsheet/components/cell/EnumCell'
import EditableAttachmentCell from '~/components/project/spreadsheet/components/editableCell/EditableAttachmentCell' import EditableAttachmentCell from '~/components/project/spreadsheet/components/editableCell/EditableAttachmentCell'
import BooleanCell from '~/components/project/spreadsheet/components/cell/BooleanCell' import BooleanCell from '~/components/project/spreadsheet/components/cell/BooleanCell'
import EmailCell from '~/components/project/spreadsheet/components/cell/EmailCell'
import RatingCell from '~/components/project/spreadsheet/components/editableCell/RatingCell'
export default { export default {
name: 'TableCell', name: 'TableCell',
components: { TimeCell, DateTimeCell, DateCell, JsonCell, UrlCell, EditableAttachmentCell, EnumCell, SetListCell, BooleanCell }, components: { RatingCell, EmailCell, TimeCell, DateTimeCell, DateCell, JsonCell, UrlCell, EditableAttachmentCell, EnumCell, SetListCell, BooleanCell },
mixins: [cell], mixins: [cell],
props: ['value', 'dbAlias', 'isLocked', 'selected'], props: ['value', 'dbAlias', 'isLocked', 'selected', 'column'],
computed: { computed: {
title() { title() {
if (typeof this.value === 'string') { return this.value } if (typeof this.value === 'string') { return this.value }

38
packages/nc-gui/components/project/spreadsheet/components/EditColumn.vue

@ -137,6 +137,21 @@
@input="newColumn.altered = newColumn.altered || 2" @input="newColumn.altered = newColumn.altered || 2"
/> />
</v-col> </v-col>
<v-col v-else-if="isRating" cols="12">
<rating-options
v-model="newColumn.meta"
:column="newColumn"
:meta="meta"
/>
</v-col>
<v-col v-else-if="isCheckbox" cols="12">
<checkbox-options
v-model="newColumn.meta"
:column="newColumn"
:meta="meta"
/>
</v-col>
<v-col <v-col
v-if="accordion" v-if="accordion"
cols="12" cols="12"
@ -160,6 +175,10 @@
<v-col v-show="advanceOptions || !accordion" cols="12"> <v-col v-show="advanceOptions || !accordion" cols="12">
<v-row> <v-row>
<v-col v-if="newColumn.meta && columnToValidate.includes(newColumn.uidt)" cols="12" class="pt-0 pb-0">
<v-checkbox v-model="newColumn.meta.validate" dense hide-details :label="`Accept only valid ${newColumn.uidt}`" class="mt-0" />
</v-col>
<template v-if="newColumn.uidt !== 'Formula'"> <template v-if="newColumn.uidt !== 'Formula'">
<v-col v-if="isLookup" cols="12"> <v-col v-if="isLookup" cols="12">
<lookup-options <lookup-options
@ -526,10 +545,15 @@ import RelationOptions from '~/components/project/spreadsheet/components/editCol
import DlgLabelSubmitCancel from '~/components/utils/DlgLabelSubmitCancel' import DlgLabelSubmitCancel from '~/components/utils/DlgLabelSubmitCancel'
import LinkedToAnotherOptions from '~/components/project/spreadsheet/components/editColumn/LinkedToAnotherOptions' import LinkedToAnotherOptions from '~/components/project/spreadsheet/components/editColumn/LinkedToAnotherOptions'
import { validateColumnName } from '~/helpers' import { validateColumnName } from '~/helpers'
import RatingOptions from '~/components/project/spreadsheet/components/editColumn/RatingOptions'
import CheckboxOptions from '~/components/project/spreadsheet/components/editColumn/checkboxOptions'
const columnToValidate = [UITypes.Email, UITypes.URL, UITypes.PhoneNumber]
export default { export default {
name: 'EditColumn', name: 'EditColumn',
components: { components: {
CheckboxOptions,
RatingOptions,
RollupOptions, RollupOptions,
FormulaOptions, FormulaOptions,
LookupOptions, LookupOptions,
@ -548,6 +572,7 @@ export default {
value: Boolean value: Boolean
}, },
data: () => ({ data: () => ({
columnToValidate,
valid: false, valid: false,
relationDeleteDlg: false, relationDeleteDlg: false,
newColumn: {}, newColumn: {},
@ -594,6 +619,12 @@ export default {
isLookup() { isLookup() {
return this.newColumn && this.newColumn.uidt === 'Lookup' return this.newColumn && this.newColumn.uidt === 'Lookup'
}, },
isRating() {
return this.newColumn && this.newColumn.uidt === UITypes.Rating
},
isCheckbox() {
return this.newColumn && this.newColumn.uidt === UITypes.Checkbox
},
isRollup() { isRollup() {
return this.newColumn && this.newColumn.uidt === 'Rollup' return this.newColumn && this.newColumn.uidt === 'Rollup'
}, },
@ -734,6 +765,7 @@ export default {
const colProp = this.sqlUi.getDataTypeForUiType(this.newColumn) const colProp = this.sqlUi.getDataTypeForUiType(this.newColumn)
this.newColumn = { this.newColumn = {
...this.newColumn, ...this.newColumn,
meta: null,
rqd: false, rqd: false,
pk: false, pk: false,
ai: false, ai: false,
@ -759,6 +791,12 @@ export default {
this.newColumn.dtxp = this.column.dtxp this.newColumn.dtxp = this.column.dtxp
} }
if (columnToValidate.includes(this.newColumn.uidt)) {
this.newColumn.meta = {
validate: this.newColumn.meta && this.newColumn.meta.validate
}
}
this.newColumn.altered = this.newColumn.altered || 2 this.newColumn.altered = this.newColumn.altered || 2
}, },
focusInput() { focusInput() {

19
packages/nc-gui/components/project/spreadsheet/components/EditableCell.vue

@ -23,9 +23,22 @@
v-on="$listeners" v-on="$listeners"
/> />
<rating-cell
v-if="isRating"
v-model="localState"
:active="active"
:is-form="isForm"
:column="column"
:is-public-grid="isPublic && !isForm"
:is-public-form="isPublic && isForm"
:is-locked="isLocked"
v-on="$listeners"
/>
<boolean-cell <boolean-cell
v-else-if="isBoolean" v-else-if="isBoolean"
v-model="localState" v-model="localState"
:column="column"
:is-form="isForm" :is-form="isForm"
v-on="parentListeners" v-on="parentListeners"
/> />
@ -132,10 +145,12 @@ import EditableAttachmentCell from '~/components/project/spreadsheet/components/
import EnumCell from '~/components/project/spreadsheet/components/cell/EnumCell' import EnumCell from '~/components/project/spreadsheet/components/cell/EnumCell'
import SetListEditableCell from '~/components/project/spreadsheet/components/editableCell/SetListEditableCell' import SetListEditableCell from '~/components/project/spreadsheet/components/editableCell/SetListEditableCell'
import SetListCell from '~/components/project/spreadsheet/components/cell/SetListCell' import SetListCell from '~/components/project/spreadsheet/components/cell/SetListCell'
import RatingCell from '~/components/project/spreadsheet/components/editableCell/RatingCell'
export default { export default {
name: 'EditableCell', name: 'EditableCell',
components: { components: {
RatingCell,
JsonEditableCell, JsonEditableCell,
EditableUrlCell, EditableUrlCell,
SetListCell, SetListCell,
@ -182,7 +197,7 @@ export default {
if (val !== this.value) { if (val !== this.value) {
this.changed = true this.changed = true
this.$emit('input', val) this.$emit('input', val)
if (this.isAttachment || this.isEnum || this.isBoolean || this.isSet || this.isTime || this.isDateTime || this.isDate) { if (this.isAttachment || this.isEnum || this.isBoolean || this.isRating || this.isSet || this.isTime || this.isDateTime || this.isDate) {
this.syncData() this.syncData()
} else if (!this.isCurrency) { } else if (!this.isCurrency) {
this.syncDataDebounce(this) this.syncDataDebounce(this)
@ -213,7 +228,7 @@ export default {
// this.$refs.input.focus(); // this.$refs.input.focus();
}, },
beforeDestroy() { beforeDestroy() {
if (this.changed && !(this.isAttachment || this.isEnum || this.isBoolean || this.isSet || this.isTime || this.isDateTime)) { if (this.changed && !(this.isAttachment || this.isEnum || this.isBoolean || this.isRating || this.isSet || this.isTime || this.isDateTime)) {
this.changed = false this.changed = false
this.$emit('change') this.$emit('change')
} }

22
packages/nc-gui/components/project/spreadsheet/components/cell/EmailCell.vue

@ -0,0 +1,22 @@
<template>
<a v-if="isEmail" :href="`mailto:${value}`" target="_blank">{{ value }}</a>
<span v-else>{{ value }}</span>
</template>
<script>
import { isEmail } from '~/helpers'
export default {
name: 'EmailCell',
props: ['value'],
computed: {
isEmail() {
return isEmail(this.value || '')
}
}
}
</script>
<style scoped>
</style>

14
packages/nc-gui/components/project/spreadsheet/components/cell/UrlCell.vue

@ -1,12 +1,20 @@
<template> <template>
<a v-if="value" :href="value" target="_blank">{{ value }}</a> <a v-if="isValid" :href="value" target="_blank">{{ value }}</a>
<span v-else /> <span v-else>{{ value }}</span>
</template> </template>
<script> <script>
import { isValidURL } from '~/helpers'
export default { export default {
name: 'UrlCell', name: 'UrlCell',
props: ['value'] props: ['value'],
computed: {
isValid() {
return this.value && isValidURL(this.value)
}
}
} }
</script> </script>

98
packages/nc-gui/components/project/spreadsheet/components/editColumn/RatingOptions.vue

@ -0,0 +1,98 @@
<template>
<div>
<div class="nc-rating-wrapper ui-type">
<v-select
v-model="colMeta.icon"
label="Icon"
:items="icons"
dense
outlined
class="caption"
:item-value="v=>v"
:value-comparator="(a,b) => a && b && a.full === b.full && a.empty === b.empty"
>
<template #item="{ item }">
<v-icon small :color="colMeta.color">
{{ item.full }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.empty }}
</v-icon>
</template>
<template #selection="{ item }">
<v-icon small :color="colMeta.color">
{{ item.full }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.empty }}
</v-icon>
</template>
</v-select>
<v-select
v-model="colMeta.max"
label="Max"
:items="[1,2,3,4,5,6,7,8,9,10]"
dense
outlined
class="caption"
/>
</div>
<v-color-picker
v-model="colMeta.color"
class="mx-auto"
hide-inputs
/>
</div>
</template>
<script>
export default {
name: 'RatingOptions',
props: ['column', 'meta', 'value'],
data: () => ({
colMeta: {
icon: {
full: 'mdi-star',
empty: 'mdi-star-outline'
},
color: '#fcb401',
max: 5
},
icons: [{
full: 'mdi-star',
empty: 'mdi-star-outline'
}, {
full: 'mdi-heart',
empty: 'mdi-heart-outline'
}, {
full: 'mdi-moon-full',
empty: 'mdi-moon-new'
}, {
full: 'mdi-thumb-up',
empty: 'mdi-thumb-up-outline'
}, {
full: 'mdi-flag',
empty: 'mdi-flag-outline'
}]
}),
watch: {
value() {
this.colMeta = this.value || {}
},
colMeta(v) {
this.$emit('input', v)
}
},
created() {
this.colMeta = this.value || { ...this.colMeta }
}
}
</script>
<style scoped lang="scss">
.nc-rating-wrapper {
display: flex;
gap: 16px
}
</style>

95
packages/nc-gui/components/project/spreadsheet/components/editColumn/checkboxOptions.vue

@ -0,0 +1,95 @@
<template>
<div>
<div class="nc-rating-wrapper ui-type">
<v-select
v-model="colMeta.icon"
label="Icon"
:items="icons"
dense
outlined
class="caption"
:item-value="v=>v"
:value-comparator="(a,b) => a && b && a.checked === b.checked && a.unchecked === b.unchecked"
>
<template #item="{ item }">
<v-icon small :color="colMeta.color">
{{ item.checked }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.unchecked }}
</v-icon>
</template>
<template #selection="{ item }">
<v-icon small :color="colMeta.color">
{{ item.checked }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.unchecked }}
</v-icon>
</template>
</v-select>
</div>
<v-color-picker
v-model="colMeta.color"
class="mx-auto"
hide-inputs
/>
</div>
</template>
<script>
export default {
name: 'CheckboxOptions',
props: ['column', 'meta', 'value'],
data: () => ({
colMeta: {
icon: {
checked: 'mdi-check-bold',
unchecked: 'mdi-crop-square'
},
color: '#777'
},
icons: [{
checked: 'mdi-check-bold',
unchecked: 'mdi-crop-square'
}, {
checked: 'mdi-check-circle-outline',
unchecked: 'mdi-checkbox-blank-circle-outline'
}, {
checked: 'mdi-star',
unchecked: 'mdi-star-outline'
}, {
checked: 'mdi-heart',
unchecked: 'mdi-heart-outline'
}, {
checked: 'mdi-moon-full',
unchecked: 'mdi-moon-new'
}, {
checked: 'mdi-thumb-up',
unchecked: 'mdi-thumb-up-outline'
}, {
checked: 'mdi-flag',
unchecked: 'mdi-flag-outline'
}]
}),
watch: {
value() {
this.colMeta = this.value || {}
},
colMeta(v) {
this.$emit('input', v)
}
},
created() {
this.colMeta = this.value || { ...this.colMeta }
}
}
</script>
<style scoped lang="scss">
.nc-rating-wrapper {
display: flex;
gap: 16px
}
</style>

36
packages/nc-gui/components/project/spreadsheet/components/editableCell/BooleanCell.vue

@ -1,6 +1,8 @@
<template> <template>
<div class="d-flex align-center " :class="{'justify-center':!isForm}"> <div class="d-flex align-center " :class="{'justify-center':!isForm,'nc-cell-hover-show': !localState}">
<input v-model="localState" type="checkbox" v-on="parentListeners"> <v-icon small :color="checkboxMeta.color" @click="toggle">
{{ localState ? checkedIcon :uncheckedIcon }}
</v-icon>
</div> </div>
</template> </template>
@ -8,10 +10,19 @@
export default { export default {
name: 'BooleanCell', name: 'BooleanCell',
props: { props: {
column: Object,
value: [String, Number, Boolean], value: [String, Number, Boolean],
isForm: Boolean isForm: Boolean,
readOnly: Boolean
}, },
computed: { computed: {
checkedIcon() {
return (this.checkboxMeta && this.checkboxMeta.icon && this.checkboxMeta.icon.checked) || 'mdi-check-bold'
},
uncheckedIcon() {
return (this.checkboxMeta && this.checkboxMeta.icon && this.checkboxMeta.icon.unchecked) || 'mdi-crop-square'
},
localState: { localState: {
get() { get() {
return this.value return this.value
@ -20,14 +31,27 @@ export default {
this.$emit('input', val) this.$emit('input', val)
} }
}, },
parentListeners() { parentListeners() {
const $listeners = {} const $listeners = {}
return $listeners return $listeners
},
checkboxMeta() {
return {
icon: {
checked: 'mdi-check-circle-outline',
unchecked: 'mdi-checkbox-blank-circle-outline'
},
color: 'primary',
...(this.column && this.column.meta
? this.column.meta
: {})
}
} }
}, },
mounted() { methods: {
this.$el.focus() toggle() {
this.localState = !this.localState
}
} }
} }
</script> </script>

9
packages/nc-gui/components/project/spreadsheet/components/editableCell/EditableUrlCell.vue

@ -8,7 +8,8 @@ import { isValidURL } from '@/helpers'
export default { export default {
name: 'EditableUrlCell', name: 'EditableUrlCell',
props: { props: {
value: String value: String,
column: Object
}, },
computed: { computed: {
localState: { localState: {
@ -16,7 +17,11 @@ export default {
return this.value return this.value
}, },
set(val) { set(val) {
if (isValidURL(val)) { this.$emit('input', val) } if (!(
this.column &&
this.column.meta &&
this.column.meta.validate
) || isValidURL(val)) { this.$emit('input', val) }
} }
}, },
parentListeners() { parentListeners() {

71
packages/nc-gui/components/project/spreadsheet/components/editableCell/RatingCell.vue

@ -0,0 +1,71 @@
<template>
<div class="d-100 h-100" :class="{'nc-cell-hover-show': localState == 0 || !localState}">
<v-rating
v-model="localState"
:length="ratingMeta.max"
dense
x-small
:disabled="readOnly"
clearable
>
<template #item="{isFilled, click}">
<v-icon v-if="isFilled" :size="15" :color="ratingMeta.color" @click="click">
{{ fullIcon }}
</v-icon>
<v-icon
v-else
:color="ratingMeta.color"
:size="15"
class="nc-cell-hover-show"
@click="click"
>
{{ emptyIcon }}
</v-icon>
</template>
</v-rating>
</div>
</template>
<script>
export default {
name: 'RatingCell',
props: {
column: Object,
value: [String, Number],
readOnly: Boolean
},
computed: {
fullIcon() {
return (this.ratingMeta && this.ratingMeta.icon && this.ratingMeta.icon.full) || 'mdi-star'
},
emptyIcon() {
return (this.ratingMeta && this.ratingMeta.icon && this.ratingMeta.icon.empty) || 'mdi-star-outline'
},
localState: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
ratingMeta() {
return {
icon: {
full: 'mdi-star',
empty: 'mdi-star-outline'
},
color: '#fcb401',
max: 5,
...(this.column && this.column.meta
? this.column.meta
: {})
}
}
}
}
</script>
<style scoped>
</style>

6
packages/nc-gui/components/project/spreadsheet/mixins/cell.js

@ -56,9 +56,15 @@ export default {
isURL() { isURL() {
return this.uiDatatype === 'URL' return this.uiDatatype === 'URL'
}, },
isEmail() {
return this.uiDatatype === UITypes.Email
},
isAttachment() { isAttachment() {
return this.uiDatatype === 'Attachment' return this.uiDatatype === 'Attachment'
}, },
isRating() {
return this.uiDatatype === UITypes.Rating
},
isCurrency() { isCurrency() {
return this.column.uidt == 'Currency' return this.column.uidt == 'Currency'
} }

18
packages/nc-gui/components/project/spreadsheet/views/GridView.vue

@ -632,8 +632,7 @@ export default {
break break
// delete // delete
case 46: case 46: {
{
if (this.editEnabled.col != null && this.editEnabled.row != null) { if (this.editEnabled.col != null && this.editEnabled.row != null) {
return return
} }
@ -820,6 +819,7 @@ export default {
(column && column.uidt === UITypes.DateTime) || (column && column.uidt === UITypes.DateTime) ||
(column && column.uidt === UITypes.Date) || (column && column.uidt === UITypes.Date) ||
(column && column.uidt === UITypes.Time) || (column && column.uidt === UITypes.Time) ||
(column && column.uidt === UITypes.Rating) ||
(this.sqlUi && (this.sqlUi &&
column.dt && column.dt &&
this.sqlUi.getAbstractType(column) === 'boolean') this.sqlUi.getAbstractType(column) === 'boolean')
@ -1163,4 +1163,18 @@ td:first-child {
.has-many-icon { .has-many-icon {
transform: rotate(90deg); transform: rotate(90deg);
} }
::v-deep {
tr {
.nc-cell-hover-show {
opacity: 0;
transition: .3s opacity;
}
&:hover .nc-cell-hover-show {
opacity: .7;
}
}
}
</style> </style>

66
packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes"; import UITypes from '../UITypes';
const dbTypes = [ const dbTypes = [
'bigint', 'bigint',
@ -35,7 +35,7 @@ const dbTypes = [
'uniqueidentifier', 'uniqueidentifier',
'varbinary', 'varbinary',
'xml', 'xml',
'varchar' 'varchar',
]; ];
export class MssqlUi { export class MssqlUi {
@ -62,7 +62,7 @@ export class MssqlUi {
altered: 1, altered: 1,
uidt: 'ID', uidt: 'ID',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'title', column_name: 'title',
@ -85,7 +85,7 @@ export class MssqlUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'created_at', column_name: 'created_at',
@ -108,7 +108,7 @@ export class MssqlUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'updated_at', column_name: 'updated_at',
@ -131,8 +131,8 @@ export class MssqlUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
} },
]; ];
} }
@ -157,7 +157,7 @@ export class MssqlUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}; };
} }
@ -741,13 +741,15 @@ export class MssqlUi {
} }
static extractFunctionName(query) { static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
static extractProcedureName(query) { static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
@ -827,7 +829,7 @@ export class MssqlUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: null, dtxp: null,
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}; };
switch (typeof json[keys[i]]) { switch (typeof json[keys[i]]) {
@ -835,13 +837,13 @@ export class MssqlUi {
if (Number.isInteger(json[keys[i]])) { if (Number.isInteger(json[keys[i]])) {
if (MssqlUi.isValidTimestamp(keys[i], json[keys[i]])) { if (MssqlUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'timestamp' dt: 'timestamp',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'int', dt: 'int',
np: 10, np: 10,
ns: 0 ns: 0,
}); });
} }
} else { } else {
@ -850,25 +852,25 @@ export class MssqlUi {
np: 10, np: 10,
ns: 2, ns: 2,
dtxp: '11', dtxp: '11',
dtxs: 2 dtxs: 2,
}); });
} }
break; break;
case 'string': case 'string':
if (MssqlUi.isValidDate(json[keys[i]])) { if (MssqlUi.isValidDate(json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'datetime' dt: 'datetime',
}); });
} else if (json[keys[i]].length <= 255) { } else if (json[keys[i]].length <= 255) {
Object.assign(column, { Object.assign(column, {
dt: 'varchar', dt: 'varchar',
np: 255, np: 255,
ns: 0, ns: 0,
dtxp: '255' dtxp: '255',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'text' dt: 'text',
}); });
} }
break; break;
@ -876,7 +878,7 @@ export class MssqlUi {
Object.assign(column, { Object.assign(column, {
dt: 'bit', dt: 'bit',
np: null, np: null,
ns: 0 ns: 0,
}); });
break; break;
case 'object': case 'object':
@ -884,7 +886,7 @@ export class MssqlUi {
dt: 'varchar', dt: 'varchar',
np: 255, np: 255,
ns: 0, ns: 0,
dtxp: '255' dtxp: '255',
}); });
break; break;
default: default:
@ -1043,9 +1045,7 @@ export class MssqlUi {
} }
} }
static getDataTypeForUiType( static getDataTypeForUiType(col): {
col
): {
readonly dt: string; readonly dt: string;
readonly [key: string]: any; readonly [key: string]: any;
} { } {
@ -1098,7 +1098,7 @@ export class MssqlUi {
colProp.validate = { colProp.validate = {
func: ['isMobilePhone'], func: ['isMobilePhone'],
args: [''], args: [''],
msg: ['Validation failed : isMobilePhone'] msg: ['Validation failed : isMobilePhone'],
}; };
break; break;
case 'Email': case 'Email':
@ -1106,7 +1106,7 @@ export class MssqlUi {
colProp.validate = { colProp.validate = {
func: ['isEmail'], func: ['isEmail'],
args: [''], args: [''],
msg: ['Validation failed : isEmail'] msg: ['Validation failed : isEmail'],
}; };
break; break;
case 'URL': case 'URL':
@ -1114,7 +1114,7 @@ export class MssqlUi {
colProp.validate = { colProp.validate = {
func: ['isURL'], func: ['isURL'],
args: [''], args: [''],
msg: ['Validation failed : isURL'] msg: ['Validation failed : isURL'],
}; };
break; break;
case 'Number': case 'Number':
@ -1128,7 +1128,7 @@ export class MssqlUi {
colProp.validate = { colProp.validate = {
func: ['isCurrency'], func: ['isCurrency'],
args: [''], args: [''],
msg: ['Validation failed : isCurrency'] msg: ['Validation failed : isCurrency'],
}; };
break; break;
case 'Percent': case 'Percent':
@ -1138,7 +1138,7 @@ export class MssqlUi {
colProp.dt = 'int'; colProp.dt = 'int';
break; break;
case 'Rating': case 'Rating':
colProp.dt = 'float'; colProp.dt = 'int';
break; break;
case 'Formula': case 'Formula':
colProp.dt = 'varchar'; colProp.dt = 'varchar';
@ -1224,7 +1224,7 @@ export class MssqlUi {
'numeric', 'numeric',
'real', 'real',
'smallint', 'smallint',
'tinyint' 'tinyint',
]; ];
case 'Decimal': case 'Decimal':
@ -1240,7 +1240,7 @@ export class MssqlUi {
'numeric', 'numeric',
'real', 'real',
'smallint', 'smallint',
'tinyint' 'tinyint',
]; ];
case 'Percent': case 'Percent':
@ -1253,7 +1253,7 @@ export class MssqlUi {
'numeric', 'numeric',
'real', 'real',
'smallint', 'smallint',
'tinyint' 'tinyint',
]; ];
case 'Duration': case 'Duration':
@ -1266,7 +1266,7 @@ export class MssqlUi {
'numeric', 'numeric',
'real', 'real',
'smallint', 'smallint',
'tinyint' 'tinyint',
]; ];
case 'Rating': case 'Rating':
@ -1279,7 +1279,7 @@ export class MssqlUi {
'numeric', 'numeric',
'real', 'real',
'smallint', 'smallint',
'tinyint' 'tinyint',
]; ];
case 'Formula': case 'Formula':
@ -1302,7 +1302,7 @@ export class MssqlUi {
case 'LastModifiedTime': case 'LastModifiedTime':
return [ return [
'datetimeoffset', 'datetimeoffset',
'datetime2' 'datetime2',
// 'datetime' // 'datetime'
]; ];

74
packages/nocodb-sdk/src/lib/sqlUi/MysqlUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes"; import UITypes from '../UITypes';
const dbTypes = [ const dbTypes = [
'int', 'int',
@ -39,7 +39,7 @@ const dbTypes = [
'multipoint', 'multipoint',
'multilinestring', 'multilinestring',
'multipolygon', 'multipolygon',
'json' 'json',
]; ];
export class MysqlUi { export class MysqlUi {
@ -66,7 +66,7 @@ export class MysqlUi {
altered: 1, altered: 1,
uidt: 'ID', uidt: 'ID',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'title', column_name: 'title',
@ -89,7 +89,7 @@ export class MysqlUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'created_at', column_name: 'created_at',
@ -112,7 +112,7 @@ export class MysqlUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'updated_at', column_name: 'updated_at',
@ -135,8 +135,8 @@ export class MysqlUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
} },
]; ];
} }
@ -161,7 +161,7 @@ export class MysqlUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}; };
} }
@ -659,13 +659,15 @@ export class MysqlUi {
} }
static extractFunctionName(query) { static extractFunctionName(query) {
const reg = /^\s*CREATE\s+.*?(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:`?[\w\d_]+`?\.)?`?([\w_\d]+)`?/i; const reg =
/^\s*CREATE\s+.*?(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:`?[\w\d_]+`?\.)?`?([\w_\d]+)`?/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
static extractProcedureName(query) { static extractProcedureName(query) {
const reg = /^\s*CREATE.*?\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE.*?\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
@ -677,14 +679,14 @@ export class MysqlUi {
// set headers before settings result // set headers before settings result
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const text = keys[i]; const text = keys[i];
headers.push({text, value: text, sortable: false}); headers.push({ text, value: text, sortable: false });
} }
} else { } else {
const keys = Object.keys(result); const keys = Object.keys(result);
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const text = keys[i]; const text = keys[i];
if (typeof text !== 'function') { if (typeof text !== 'function') {
headers.push({text, value: text, sortable: false}); headers.push({ text, value: text, sortable: false });
} }
} }
result = [result]; result = [result];
@ -750,7 +752,7 @@ export class MysqlUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: null, dtxp: null,
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}; };
switch (typeof json[keys[i]]) { switch (typeof json[keys[i]]) {
@ -758,13 +760,13 @@ export class MysqlUi {
if (Number.isInteger(json[keys[i]])) { if (Number.isInteger(json[keys[i]])) {
if (MysqlUi.isValidTimestamp(keys[i], json[keys[i]])) { if (MysqlUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'timestamp' dt: 'timestamp',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'int', dt: 'int',
np: 10, np: 10,
ns: 0 ns: 0,
}); });
} }
} else { } else {
@ -773,25 +775,25 @@ export class MysqlUi {
np: 10, np: 10,
ns: 2, ns: 2,
dtxp: '11', dtxp: '11',
dtxs: 2 dtxs: 2,
}); });
} }
break; break;
case 'string': case 'string':
if (MysqlUi.isValidDate(json[keys[i]])) { if (MysqlUi.isValidDate(json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'datetime' dt: 'datetime',
}); });
} else if (json[keys[i]].length <= 255) { } else if (json[keys[i]].length <= 255) {
Object.assign(column, { Object.assign(column, {
dt: 'varchar', dt: 'varchar',
np: 255, np: 255,
ns: 0, ns: 0,
dtxp: '255' dtxp: '255',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'text' dt: 'text',
}); });
} }
break; break;
@ -799,14 +801,14 @@ export class MysqlUi {
Object.assign(column, { Object.assign(column, {
dt: 'boolean', dt: 'boolean',
np: 3, np: 3,
ns: 0 ns: 0,
}); });
break; break;
case 'object': case 'object':
Object.assign(column, { Object.assign(column, {
dt: 'json', dt: 'json',
np: 3, np: 3,
ns: 0 ns: 0,
}); });
break; break;
default: default:
@ -991,7 +993,7 @@ export class MysqlUi {
colProp.validate = { colProp.validate = {
func: ['isMobilePhone'], func: ['isMobilePhone'],
args: [''], args: [''],
msg: ['Validation failed : isMobilePhone ({cn})'] msg: ['Validation failed : isMobilePhone ({cn})'],
}; };
break; break;
case 'Email': case 'Email':
@ -999,7 +1001,7 @@ export class MysqlUi {
colProp.validate = { colProp.validate = {
func: ['isEmail'], func: ['isEmail'],
args: [''], args: [''],
msg: ['Validation failed : isEmail ({cn})'] msg: ['Validation failed : isEmail ({cn})'],
}; };
break; break;
case 'URL': case 'URL':
@ -1007,7 +1009,7 @@ export class MysqlUi {
colProp.validate = { colProp.validate = {
func: ['isURL'], func: ['isURL'],
args: [''], args: [''],
msg: ['Validation failed : isURL ({cn})'] msg: ['Validation failed : isURL ({cn})'],
}; };
break; break;
case 'Number': case 'Number':
@ -1021,7 +1023,7 @@ export class MysqlUi {
colProp.validate = { colProp.validate = {
func: ['isCurrency'], func: ['isCurrency'],
args: [''], args: [''],
msg: ['Validation failed : isCurrency'] msg: ['Validation failed : isCurrency'],
}; };
break; break;
case 'Percent': case 'Percent':
@ -1031,7 +1033,7 @@ export class MysqlUi {
colProp.dt = 'int'; colProp.dt = 'int';
break; break;
case 'Rating': case 'Rating':
colProp.dt = 'float'; colProp.dt = 'int';
break; break;
case 'Formula': case 'Formula':
colProp.dt = 'varchar'; colProp.dt = 'varchar';
@ -1089,7 +1091,7 @@ export class MysqlUi {
'text', 'text',
'tinytext', 'tinytext',
'mediumtext', 'mediumtext',
'longtext' 'longtext',
]; ];
case 'Attachment': case 'Attachment':
@ -1101,7 +1103,7 @@ export class MysqlUi {
'text', 'text',
'tinytext', 'tinytext',
'mediumtext', 'mediumtext',
'longtext' 'longtext',
]; ];
case 'JSON': case 'JSON':
@ -1116,7 +1118,7 @@ export class MysqlUi {
'bit', 'bit',
'boolean', 'boolean',
'serial', 'serial',
'tinyint' 'tinyint',
]; ];
case 'MultiSelect': case 'MultiSelect':
@ -1148,7 +1150,7 @@ export class MysqlUi {
'float', 'float',
'decimal', 'decimal',
'double', 'double',
'serial' 'serial',
]; ];
case 'Decimal': case 'Decimal':
@ -1164,7 +1166,7 @@ export class MysqlUi {
'smallint', 'smallint',
'mediumint', 'mediumint',
'bigint', 'bigint',
'bit' 'bit',
]; ];
case 'Percent': case 'Percent':
@ -1177,7 +1179,7 @@ export class MysqlUi {
'smallint', 'smallint',
'mediumint', 'mediumint',
'bigint', 'bigint',
'bit' 'bit',
]; ];
case 'Duration': case 'Duration':
@ -1190,7 +1192,7 @@ export class MysqlUi {
'smallint', 'smallint',
'mediumint', 'mediumint',
'bigint', 'bigint',
'bit' 'bit',
]; ];
case 'Rating': case 'Rating':
@ -1203,7 +1205,7 @@ export class MysqlUi {
'smallint', 'smallint',
'mediumint', 'mediumint',
'bigint', 'bigint',
'bit' 'bit',
]; ];
case 'Formula': case 'Formula':
@ -1214,7 +1216,7 @@ export class MysqlUi {
'text', 'text',
'tinytext', 'tinytext',
'mediumtext', 'mediumtext',
'longtext' 'longtext',
]; ];
case 'Rollup': case 'Rollup':
@ -1248,7 +1250,7 @@ export class MysqlUi {
'polygon', 'polygon',
'multipoint', 'multipoint',
'multilinestring', 'multilinestring',
'multipolygon' 'multipolygon',
]; ];
case 'Button': case 'Button':

36
packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts

@ -22,7 +22,7 @@ export class OracleUi {
altered: 1, altered: 1,
uidt: 'ID', uidt: 'ID',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'title', column_name: 'title',
@ -45,8 +45,8 @@ export class OracleUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
} },
// { // {
// column_name: "created_at", // column_name: "created_at",
// dt: "timestamp", // dt: "timestamp",
@ -107,7 +107,7 @@ export class OracleUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}; };
} }
@ -435,13 +435,15 @@ export class OracleUi {
} }
static extractFunctionName(query) { static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
static extractProcedureName(query) { static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
@ -522,7 +524,7 @@ export class OracleUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: '11', dtxp: '11',
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}); });
} else { } else {
columns.push({ columns.push({
@ -548,7 +550,7 @@ export class OracleUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: '11', dtxp: '11',
dtxs: 2, dtxs: 2,
altered: 1 altered: 1,
}); });
} }
@ -579,7 +581,7 @@ export class OracleUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: '45', dtxp: '45',
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}); });
} else { } else {
columns.push({ columns.push({
@ -605,7 +607,7 @@ export class OracleUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: null, dtxp: null,
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}); });
} }
@ -635,7 +637,7 @@ export class OracleUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: '1', dtxp: '1',
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}); });
break; break;
@ -663,7 +665,7 @@ export class OracleUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: null, dtxp: null,
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}); });
break; break;
@ -839,7 +841,7 @@ export class OracleUi {
colProp.validate = { colProp.validate = {
func: ['isMobilePhone'], func: ['isMobilePhone'],
args: [''], args: [''],
msg: ['Validation failed : isMobilePhone'] msg: ['Validation failed : isMobilePhone'],
}; };
break; break;
case 'Email': case 'Email':
@ -847,7 +849,7 @@ export class OracleUi {
colProp.validate = { colProp.validate = {
func: ['isEmail'], func: ['isEmail'],
args: [''], args: [''],
msg: ['Validation failed : isEmail'] msg: ['Validation failed : isEmail'],
}; };
break; break;
case 'URL': case 'URL':
@ -855,7 +857,7 @@ export class OracleUi {
colProp.validate = { colProp.validate = {
func: ['isURL'], func: ['isURL'],
args: [''], args: [''],
msg: ['Validation failed : isURL'] msg: ['Validation failed : isURL'],
}; };
break; break;
case 'Number': case 'Number':
@ -869,7 +871,7 @@ export class OracleUi {
colProp.validate = { colProp.validate = {
func: ['isCurrency'], func: ['isCurrency'],
args: [''], args: [''],
msg: ['Validation failed : isCurrency'] msg: ['Validation failed : isCurrency'],
}; };
break; break;
case 'Percent': case 'Percent':
@ -879,7 +881,7 @@ export class OracleUi {
colProp.dt = 'integer'; colProp.dt = 'integer';
break; break;
case 'Rating': case 'Rating':
colProp.dt = 'float'; colProp.dt = 'integer';
break; break;
case 'Formula': case 'Formula':
colProp.dt = 'varchar'; colProp.dt = 'varchar';

79
packages/nocodb-sdk/src/lib/sqlUi/PgUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes"; import UITypes from '../UITypes';
const dbTypes = [ const dbTypes = [
'int', 'int',
@ -98,7 +98,7 @@ const dbTypes = [
'unknown', 'unknown',
'void', 'void',
'xid', 'xid',
'xml' 'xml',
]; ];
export class PgUi { export class PgUi {
@ -125,7 +125,7 @@ export class PgUi {
altered: 1, altered: 1,
uidt: 'ID', uidt: 'ID',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'title', column_name: 'title',
@ -148,7 +148,7 @@ export class PgUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'created_at', column_name: 'created_at',
@ -171,7 +171,7 @@ export class PgUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'updated_at', column_name: 'updated_at',
@ -195,8 +195,8 @@ export class PgUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
} },
]; ];
} }
@ -221,7 +221,7 @@ export class PgUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}; };
} }
@ -1160,13 +1160,15 @@ export class PgUi {
} }
static extractFunctionName(query) { static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
static extractProcedureName(query) { static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
@ -1176,8 +1178,8 @@ export class PgUi {
headers.push({ text: 'Row count', value: 'rowCount', sortable: false }); headers.push({ text: 'Row count', value: 'rowCount', sortable: false });
result = [ result = [
{ {
rowCount: result.rowCount rowCount: result.rowCount,
} },
]; ];
} else { } else {
result = result.rows; result = result.rows;
@ -1251,7 +1253,7 @@ export class PgUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: null, dtxp: null,
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}; };
switch (typeof json[keys[i]]) { switch (typeof json[keys[i]]) {
@ -1259,13 +1261,13 @@ export class PgUi {
if (Number.isInteger(json[keys[i]])) { if (Number.isInteger(json[keys[i]])) {
if (PgUi.isValidTimestamp(keys[i], json[keys[i]])) { if (PgUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'timestamp' dt: 'timestamp',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'int', dt: 'int',
np: 10, np: 10,
ns: 0 ns: 0,
}); });
} }
} else { } else {
@ -1274,25 +1276,25 @@ export class PgUi {
np: null, np: null,
ns: null, ns: null,
dtxp: null, dtxp: null,
dtxs: null dtxs: null,
}); });
} }
break; break;
case 'string': case 'string':
if (PgUi.isValidDate(json[keys[i]])) { if (PgUi.isValidDate(json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'date' dt: 'date',
}); });
} else if (json[keys[i]].length <= 255) { } else if (json[keys[i]].length <= 255) {
Object.assign(column, { Object.assign(column, {
dt: 'character varying', dt: 'character varying',
np: null, np: null,
ns: 0, ns: 0,
dtxp: null dtxp: null,
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'text' dt: 'text',
}); });
} }
break; break;
@ -1300,14 +1302,14 @@ export class PgUi {
Object.assign(column, { Object.assign(column, {
dt: 'boolean', dt: 'boolean',
np: 3, np: 3,
ns: 0 ns: 0,
}); });
break; break;
case 'object': case 'object':
Object.assign(column, { Object.assign(column, {
dt: 'json', dt: 'json',
np: 3, np: 3,
ns: 0 ns: 0,
}); });
break; break;
default: default:
@ -1521,7 +1523,6 @@ export class PgUi {
case 'longblob': case 'longblob':
return 'blob'; return 'blob';
case 'enum': case 'enum':
return 'enum'; return 'enum';
case 'set': case 'set':
return 'set'; return 'set';
@ -1616,7 +1617,7 @@ export class PgUi {
colProp.validate = { colProp.validate = {
func: ['isMobilePhone'], func: ['isMobilePhone'],
args: [''], args: [''],
msg: ['Validation failed : isMobilePhone'] msg: ['Validation failed : isMobilePhone'],
}; };
break; break;
case 'Email': case 'Email':
@ -1624,7 +1625,7 @@ export class PgUi {
colProp.validate = { colProp.validate = {
func: ['isEmail'], func: ['isEmail'],
args: [''], args: [''],
msg: ['Validation failed : isEmail'] msg: ['Validation failed : isEmail'],
}; };
break; break;
case 'URL': case 'URL':
@ -1632,7 +1633,7 @@ export class PgUi {
colProp.validate = { colProp.validate = {
func: ['isURL'], func: ['isURL'],
args: [''], args: [''],
msg: ['Validation failed : isURL'] msg: ['Validation failed : isURL'],
}; };
break; break;
case 'Number': case 'Number':
@ -1646,7 +1647,7 @@ export class PgUi {
colProp.validate = { colProp.validate = {
func: ['isCurrency'], func: ['isCurrency'],
args: [''], args: [''],
msg: ['Validation failed : isCurrency'] msg: ['Validation failed : isCurrency'],
}; };
break; break;
case 'Percent': case 'Percent':
@ -1656,7 +1657,7 @@ export class PgUi {
colProp.dt = 'int8'; colProp.dt = 'int8';
break; break;
case 'Rating': case 'Rating':
colProp.dt = 'float8'; colProp.dt = 'smallint';
break; break;
case 'Formula': case 'Formula':
colProp.dt = 'character varying'; colProp.dt = 'character varying';
@ -1732,7 +1733,7 @@ export class PgUi {
'int8range', 'int8range',
'serial', 'serial',
'serial2', 'serial2',
'serial8' 'serial8',
]; ];
case 'MultiSelect': case 'MultiSelect':
@ -1753,7 +1754,7 @@ export class PgUi {
'timestamptz', 'timestamptz',
'timestamp with time zone', 'timestamp with time zone',
'timetz', 'timetz',
'time with time zone' 'time with time zone',
]; ];
case 'PhoneNumber': case 'PhoneNumber':
@ -1780,7 +1781,7 @@ export class PgUi {
'float8', 'float8',
'smallint', 'smallint',
'smallserial', 'smallserial',
'numeric' 'numeric',
]; ];
case 'Decimal': case 'Decimal':
@ -1802,7 +1803,7 @@ export class PgUi {
'money', 'money',
'float4', 'float4',
'float8', 'float8',
'numeric' 'numeric',
]; ];
case 'Percent': case 'Percent':
@ -1822,7 +1823,7 @@ export class PgUi {
'float8', 'float8',
'smallint', 'smallint',
'smallserial', 'smallserial',
'numeric' 'numeric',
]; ];
case 'Duration': case 'Duration':
@ -1842,7 +1843,7 @@ export class PgUi {
'float8', 'float8',
'smallint', 'smallint',
'smallserial', 'smallserial',
'numeric' 'numeric',
]; ];
case 'Rating': case 'Rating':
@ -1862,7 +1863,7 @@ export class PgUi {
'float8', 'float8',
'smallint', 'smallint',
'smallserial', 'smallserial',
'numeric' 'numeric',
]; ];
case 'Formula': case 'Formula':
@ -1884,7 +1885,7 @@ export class PgUi {
'serial2', 'serial2',
'serial8', 'serial8',
'smallint', 'smallint',
'smallserial' 'smallserial',
]; ];
case 'Lookup': case 'Lookup':
@ -1896,7 +1897,7 @@ export class PgUi {
'timestamp', 'timestamp',
'timestamp without time zone', 'timestamp without time zone',
'timestamptz', 'timestamptz',
'timestamp with time zone' 'timestamp with time zone',
]; ];
case 'DateTime': case 'DateTime':
@ -1906,7 +1907,7 @@ export class PgUi {
'timestamp', 'timestamp',
'timestamp without time zone', 'timestamp without time zone',
'timestamptz', 'timestamptz',
'timestamp with time zone' 'timestamp with time zone',
]; ];
case 'AutoNumber': case 'AutoNumber':
@ -1922,7 +1923,7 @@ export class PgUi {
'serial2', 'serial2',
'serial8', 'serial8',
'smallint', 'smallint',
'smallserial' 'smallserial',
]; ];
case 'Barcode': case 'Barcode':
@ -1937,7 +1938,7 @@ export class PgUi {
'line', 'line',
'lseg', 'lseg',
'path', 'path',
'circle' 'circle',
]; ];
case 'Button': case 'Button':

76
packages/nocodb-sdk/src/lib/sqlUi/SqliteUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes"; import UITypes from '../UITypes';
const dbTypes = [ const dbTypes = [
'int', 'int',
@ -22,7 +22,7 @@ const dbTypes = [
'datetime', 'datetime',
'text', 'text',
'varchar', 'varchar',
'timestamp' 'timestamp',
]; ];
export class SqliteUi { export class SqliteUi {
@ -49,7 +49,7 @@ export class SqliteUi {
altered: 1, altered: 1,
uidt: 'ID', uidt: 'ID',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'title', column_name: 'title',
@ -72,7 +72,7 @@ export class SqliteUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'created_at', column_name: 'created_at',
@ -95,7 +95,7 @@ export class SqliteUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
}, },
{ {
column_name: 'updated_at', column_name: 'updated_at',
@ -118,8 +118,8 @@ export class SqliteUi {
altered: 1, altered: 1,
uidt: UITypes.DateTime, uidt: UITypes.DateTime,
uip: '', uip: '',
uicn: '' uicn: '',
} },
]; ];
} }
@ -144,7 +144,7 @@ export class SqliteUi {
altered: 1, altered: 1,
uidt: 'SingleLineText', uidt: 'SingleLineText',
uip: '', uip: '',
uicn: '' uicn: '',
}; };
} }
@ -498,13 +498,15 @@ export class SqliteUi {
} }
static extractFunctionName(query) { static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
static extractProcedureName(query) { static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i; const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg); const match = query.match(reg);
return match && match[1]; return match && match[1];
} }
@ -584,7 +586,7 @@ export class SqliteUi {
dtx: 'specificType', dtx: 'specificType',
dtxp: null, dtxp: null,
dtxs: 0, dtxs: 0,
altered: 1 altered: 1,
}; };
switch (typeof json[keys[i]]) { switch (typeof json[keys[i]]) {
@ -592,16 +594,16 @@ export class SqliteUi {
if (Number.isInteger(json[keys[i]])) { if (Number.isInteger(json[keys[i]])) {
if (SqliteUi.isValidTimestamp(keys[i], json[keys[i]])) { if (SqliteUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, { Object.assign(column, {
dt: 'timestamp' dt: 'timestamp',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'integer' dt: 'integer',
}); });
} }
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'real' dt: 'real',
}); });
} }
break; break;
@ -613,24 +615,24 @@ export class SqliteUi {
// } else // } else
if (json[keys[i]].length <= 255) { if (json[keys[i]].length <= 255) {
Object.assign(column, { Object.assign(column, {
dt: 'varchar' dt: 'varchar',
}); });
} else { } else {
Object.assign(column, { Object.assign(column, {
dt: 'text' dt: 'text',
}); });
} }
break; break;
case 'boolean': case 'boolean':
Object.assign(column, { Object.assign(column, {
dt: 'integer' dt: 'integer',
}); });
break; break;
case 'object': case 'object':
Object.assign(column, { Object.assign(column, {
dt: 'text', dt: 'text',
np: null, np: null,
dtxp: null dtxp: null,
}); });
break; break;
default: default:
@ -807,7 +809,7 @@ export class SqliteUi {
colProp.validate = { colProp.validate = {
func: ['isMobilePhone'], func: ['isMobilePhone'],
args: [''], args: [''],
msg: ['Validation failed : isMobilePhone'] msg: ['Validation failed : isMobilePhone'],
}; };
break; break;
case 'Email': case 'Email':
@ -815,7 +817,7 @@ export class SqliteUi {
colProp.validate = { colProp.validate = {
func: ['isEmail'], func: ['isEmail'],
args: [''], args: [''],
msg: ['Validation failed : isEmail'] msg: ['Validation failed : isEmail'],
}; };
break; break;
case 'URL': case 'URL':
@ -823,7 +825,7 @@ export class SqliteUi {
colProp.validate = { colProp.validate = {
func: ['isURL'], func: ['isURL'],
args: [''], args: [''],
msg: ['Validation failed : isURL'] msg: ['Validation failed : isURL'],
}; };
break; break;
case 'Number': case 'Number':
@ -837,7 +839,7 @@ export class SqliteUi {
colProp.validate = { colProp.validate = {
func: ['isCurrency'], func: ['isCurrency'],
args: [''], args: [''],
msg: ['Validation failed : isCurrency'] msg: ['Validation failed : isCurrency'],
}; };
break; break;
case 'Percent': case 'Percent':
@ -847,7 +849,7 @@ export class SqliteUi {
colProp.dt = 'integer'; colProp.dt = 'integer';
break; break;
case 'Rating': case 'Rating':
colProp.dt = 'float'; colProp.dt = 'integer';
break; break;
case 'Formula': case 'Formula':
colProp.dt = 'varchar'; colProp.dt = 'varchar';
@ -911,7 +913,7 @@ export class SqliteUi {
'bigint', 'bigint',
'int2', 'int2',
'int8', 'int8',
'boolean' 'boolean',
]; ];
case 'MultiSelect': case 'MultiSelect':
@ -929,7 +931,7 @@ export class SqliteUi {
'mediumint', 'mediumint',
'bigint', 'bigint',
'int2', 'int2',
'int8' 'int8',
]; ];
case 'Time': case 'Time':
@ -941,7 +943,7 @@ export class SqliteUi {
'mediumint', 'mediumint',
'bigint', 'bigint',
'int2', 'int2',
'int8' 'int8',
]; ];
case 'PhoneNumber': case 'PhoneNumber':
@ -965,7 +967,7 @@ export class SqliteUi {
'real', 'real',
'double', 'double',
'double precision', 'double precision',
'float' 'float',
]; ];
case 'Decimal': case 'Decimal':
@ -985,7 +987,7 @@ export class SqliteUi {
'bigint', 'bigint',
'int2', 'int2',
'int8', 'int8',
'numeric' 'numeric',
]; ];
case 'Percent': case 'Percent':
@ -1002,7 +1004,7 @@ export class SqliteUi {
'bigint', 'bigint',
'int2', 'int2',
'int8', 'int8',
'numeric' 'numeric',
]; ];
case 'Duration': case 'Duration':
@ -1014,15 +1016,11 @@ export class SqliteUi {
'mediumint', 'mediumint',
'bigint', 'bigint',
'int2', 'int2',
'int8' 'int8',
]; ];
case 'Rating': case 'Rating':
return [ return [
'real',
'double',
'double precision',
'float',
'int', 'int',
'integer', 'integer',
'tinyint', 'tinyint',
@ -1031,7 +1029,11 @@ export class SqliteUi {
'bigint', 'bigint',
'int2', 'int2',
'int8', 'int8',
'numeric' 'numeric',
'real',
'double',
'double precision',
'float',
]; ];
case 'Formula': case 'Formula':
@ -1049,7 +1051,7 @@ export class SqliteUi {
'mediumint', 'mediumint',
'bigint', 'bigint',
'int2', 'int2',
'int8' 'int8',
]; ];
case 'Lookup': case 'Lookup':
@ -1072,7 +1074,7 @@ export class SqliteUi {
'mediumint', 'mediumint',
'bigint', 'bigint',
'int2', 'int2',
'int8' 'int8',
]; ];
case 'Barcode': case 'Barcode':

3
packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSqlv2.ts

@ -1776,6 +1776,9 @@ class BaseModelSqlv2 {
// let cols = Object.keys(this.columns); // let cols = Object.keys(this.columns);
for (let i = 0; i < this.model.columns.length; ++i) { for (let i = 0; i < this.model.columns.length; ++i) {
const column = this.model.columns[i]; const column = this.model.columns[i];
// skip validation if `validate` is undefined or false
if (!column?.meta?.validate) continue;
const validate = column.getValidators(); const validate = column.getValidators();
const cn = column.column_name; const cn = column.column_name;
if (!validate) continue; if (!validate) continue;

40
packages/nocodb/src/lib/noco-models/Column.ts

@ -56,6 +56,7 @@ export default class Column<T = any> implements ColumnType {
public order: number; public order: number;
public validate: any; public validate: any;
public meta: any;
constructor(data: Partial<ColumnType | Column>) { constructor(data: Partial<ColumnType | Column>) {
Object.assign(this, data); Object.assign(this, data);
@ -106,7 +107,11 @@ export default class Column<T = any> implements ColumnType {
order: column.order, order: column.order,
project_id: column.project_id, project_id: column.project_id,
base_id: column.base_id, base_id: column.base_id,
system: column.system system: column.system,
meta:
column.meta && typeof column.meta === 'object'
? JSON.stringify(column.meta)
: column.meta
}; };
if (column.validate) { if (column.validate) {
@ -375,6 +380,17 @@ export default class Column<T = any> implements ColumnType {
order: 'asc' order: 'asc'
} }
}); });
columnsList.forEach(column => {
if (column.meta && typeof column.meta === 'string') {
try {
column.meta = JSON.parse(column.meta);
} catch {
column.meta = {};
}
}
});
await NocoCache.setList(CacheScope.COLUMN, [fk_model_id], columnsList); await NocoCache.setList(CacheScope.COLUMN, [fk_model_id], columnsList);
} }
columnsList.sort( columnsList.sort(
@ -452,6 +468,11 @@ export default class Column<T = any> implements ColumnType {
MetaTable.COLUMNS, MetaTable.COLUMNS,
colId colId
); );
try {
colData.meta = JSON.parse(colData.meta);
} catch {
colData.meta = {};
}
await NocoCache.set(`${CacheScope.COLUMN}:${colId}`, colData); await NocoCache.set(`${CacheScope.COLUMN}:${colId}`, colData);
} }
if (colData) { if (colData) {
@ -783,7 +804,8 @@ export default class Column<T = any> implements ColumnType {
au: column.au, au: column.au,
pv: column.pv, pv: column.pv,
system: column.system, system: column.system,
validate: null validate: null,
meta: column.meta
}; };
if (column.validate) { if (column.validate) {
@ -801,7 +823,19 @@ export default class Column<T = any> implements ColumnType {
await NocoCache.set(key, o); await NocoCache.set(key, o);
} }
// set meta // set meta
await ncMeta.metaUpdate(null, null, MetaTable.COLUMNS, updateObj, colId); await ncMeta.metaUpdate(
null,
null,
MetaTable.COLUMNS,
{
...updateObj,
meta:
updateObj.meta && typeof updateObj.meta === 'object'
? JSON.stringify(updateObj.meta)
: updateObj.meta
},
colId
);
await this.insertColOption(column, colId, ncMeta); await this.insertColOption(column, colId, ncMeta);
} }

6
packages/nocodb/src/lib/noco/common/XcMigrationSourcev2.ts

@ -2,6 +2,7 @@ import * as nc_011 from '../migrationsv2/nc_011';
import * as nc_012_alter_column_data_types from '../migrationsv2/nc_012_alter_column_data_types'; import * as nc_012_alter_column_data_types from '../migrationsv2/nc_012_alter_column_data_types';
import * as nc_013_sync_source from '../migrationsv2/nc_013_sync_source'; import * as nc_013_sync_source from '../migrationsv2/nc_013_sync_source';
import * as nc_014_alter_column_data_types from '../migrationsv2/nc_014_alter_column_data_types'; import * as nc_014_alter_column_data_types from '../migrationsv2/nc_014_alter_column_data_types';
import * as nc_015_add_meta_col_in_column_table from '../migrationsv2/nc_015_add_meta_col_in_column_table';
// Create a custom migration source class // Create a custom migration source class
export default class XcMigrationSourcev2 { export default class XcMigrationSourcev2 {
@ -14,7 +15,8 @@ export default class XcMigrationSourcev2 {
'nc_011', 'nc_011',
'nc_012_alter_column_data_types', 'nc_012_alter_column_data_types',
'nc_013_sync_source', 'nc_013_sync_source',
'nc_014_alter_column_data_types' 'nc_014_alter_column_data_types',
'nc_015_add_meta_col_in_column_table'
]); ]);
} }
@ -32,6 +34,8 @@ export default class XcMigrationSourcev2 {
return nc_013_sync_source; return nc_013_sync_source;
case 'nc_014_alter_column_data_types': case 'nc_014_alter_column_data_types':
return nc_014_alter_column_data_types; return nc_014_alter_column_data_types;
case 'nc_015_add_meta_col_in_column_table':
return nc_015_add_meta_col_in_column_table;
} }
} }
} }

38
packages/nocodb/src/lib/noco/migrationsv2/nc_015_add_meta_col_in_column_table.ts

@ -0,0 +1,38 @@
import Knex from 'knex';
import { MetaTable } from '../../utils/globals';
const up = async (knex: Knex) => {
await knex.schema.alterTable(MetaTable.COLUMNS, table => {
table.text('meta');
});
};
const down = async knex => {
await knex.schema.alterTable(MetaTable.COLUMNS, table => {
table.dropColumn('meta');
});
};
export { up, down };
/**
* @copyright Copyright (c) 2022, Xgene Cloud Ltd
*
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

4
packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

@ -436,6 +436,10 @@ async function migrateProjectModels(
columnMeta.uidt = UITypes.ForeignKey; columnMeta.uidt = UITypes.ForeignKey;
} }
if (columnMeta.uidt === UITypes.Rating) {
columnMeta.uidt = UITypes.Number;
}
const column = await Column.insert( const column = await Column.insert(
{ {
...columnMeta, ...columnMeta,

Loading…
Cancel
Save