Browse Source

Merge branch 'develop' into feat/gui-v2-duration-options

pull/2975/head
Wing-Kam Wong 2 years ago
parent
commit
483d256b93
  1. 9
      .all-contributorsrc
  2. 1
      README.md
  3. 90
      packages/nc-gui-v2/components/cell/Text.vue
  4. 70
      packages/nc-gui-v2/components/cell/TextArea.vue
  5. 3
      packages/nc-gui-v2/components/dlg/AirtableImport.vue
  6. 3
      packages/nc-gui-v2/components/smartsheet-column/AdvancedOptions.vue
  7. 100
      packages/nc-gui-v2/components/smartsheet-column/CurrencyOptions.vue
  8. 12
      packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue
  9. 14
      packages/nc-gui-v2/components/smartsheet-header/CellIcon.vue
  10. 6
      packages/nc-gui-v2/components/smartsheet-header/VirtualCellIcon.vue
  11. 3
      packages/nc-gui-v2/components/smartsheet/VirtualCell.vue
  12. 9
      packages/nc-gui-v2/components/virtual-cell/Count.vue
  13. 2
      packages/nc-gui-v2/composables/useInjectionState/index.ts
  14. 2
      packages/nc-gui-v2/composables/useTableCreate.ts
  15. 2
      packages/nc-gui-v2/composables/useVirtualCell.ts
  16. 60
      packages/nc-gui-v2/package-lock.json
  17. 1
      packages/nc-gui-v2/package.json
  18. 3
      packages/nc-gui-v2/utils/columnUtils.ts
  19. 220
      packages/nc-gui-v2/utils/currencyUtils.ts
  20. 1
      packages/nc-gui-v2/utils/index.ts
  21. 2
      packages/nocodb-sdk/src/lib/UITypes.ts

9
.all-contributorsrc

@ -837,6 +837,15 @@
"contributions": [ "contributions": [
"translation" "translation"
] ]
},
{
"login": "drsantam",
"name": "Santam Chakraborty",
"avatar_url": "https://avatars.githubusercontent.com/u/10681456?v=4",
"profile": "https://github.com/drsantam",
"contributions": [
"translation"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

1
README.md

@ -449,6 +449,7 @@ Our mission is to provide the most powerful no-code interface for databases whic
</tr> </tr>
<tr> <tr>
<td align="center"><a href="https://yohanboniface.me"><img src="https://avatars.githubusercontent.com/u/146023?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yohan Boniface</b></sub></a><br /><a href="#translation-yohanboniface" title="Translation">🌍</a></td> <td align="center"><a href="https://yohanboniface.me"><img src="https://avatars.githubusercontent.com/u/146023?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yohan Boniface</b></sub></a><br /><a href="#translation-yohanboniface" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/drsantam"><img src="https://avatars.githubusercontent.com/u/10681456?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Santam Chakraborty</b></sub></a><br /><a href="#translation-drsantam" title="Translation">🌍</a></td>
</tr> </tr>
</table> </table>

90
packages/nc-gui-v2/components/cell/Text.vue

@ -1,100 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, inject, onMounted, ref } from '#imports' import { inject, onMounted, ref } from '#imports'
interface Props { interface Props {
modelValue: any modelValue: any
} }
const { modelValue: value } = defineProps<Props>() const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue']) const emits = defineEmits(['update:modelValue'])
const editEnabled = inject<boolean>('editEnabled', false) const editEnabled = inject<boolean>('editEnabled', false)
const root = ref<HTMLInputElement>() const root = ref<HTMLInputElement>()
const localState = computed({ const vModel = useVModel(props, 'modelValue', emits)
get: () => value,
set: (val) => emit('update:modelValue', val),
})
onMounted(() => { const onSetRef = (el: HTMLInputElement) => {
root.value?.focus() el.focus()
})
/* export default {
name: 'TextCell',
props: {
value: [String, Object, Number, Boolean, Array],
},
computed: {
localState: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
},
},
parentListeners() {
const $listeners = {}
if (this.$listeners.blur) {
$listeners.blur = this.$listeners.blur
} }
if (this.$listeners.focus) {
$listeners.focus = this.$listeners.focus
}
if (this.$listeners.cancel) {
$listeners.cancel = this.$listeners.cancel
}
return $listeners
},
},
mounted() {
this.$el.focus()
},
} */
</script> </script>
<template> <template>
<input v-if="editEnabled" ref="root" v-model="localState" /> <input v-if="editEnabled" :ref="onSetRef" v-model="vModel" class="h-full w-full outline-none" />
<span v-else>{{ localState }}</span> <span v-else>{{ vModel }}</span>
<!-- v-on="parentListeners" /> -->
</template> </template>
<style scoped> <style scoped></style>
input,
textarea {
width: 100%;
height: 100%;
color: var(--v-textColor-base);
outline: none;
}
</style>
<!--
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@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/>.
*
*/
-->

70
packages/nc-gui-v2/components/cell/TextArea.vue

@ -5,70 +5,34 @@ interface Props {
modelValue?: string modelValue?: string
} }
const { modelValue: value } = defineProps<Props>() const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue']) const emits = defineEmits(['update:modelValue'])
const editEnabled = inject<boolean>('editEnabled', false) const editEnabled = inject<boolean>('editEnabled', false)
const root = ref<HTMLInputElement>() const vModel = useVModel(props, 'modelValue', emits)
const localState = computed({ const onSetRef = (el: HTMLInputElement) => {
get: () => value, el.focus()
set: (val) => emit('update:modelValue', val),
})
onMounted(() => {
root.value?.focus()
})
/* export default {
name: 'TextAreaCell',
props: {
value: String,
},
computed: {
localState: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
},
},
parentListeners() {
const $listeners = {}
if (this.$listeners.blur) {
$listeners.blur = this.$listeners.blur
} }
if (this.$listeners.focus) {
$listeners.focus = this.$listeners.focus
}
return $listeners
},
},
created() {
this.localState = this.value
},
mounted() {
this.$refs.textarea && this.$refs.textarea.focus()
},
} */
</script> </script>
<template> <template>
<textarea v-if="editEnabled" ref="root" v-model="localState" rows="4" @keydown.alt.enter.stop @keydown.shift.enter.stop /> <textarea
<span v-else>{{ localState }}</span> v-if="editEnabled"
:ref="onSetRef"
v-model="vModel"
rows="4"
class="h-full w-full min-h-[60px] outline-none"
@keydown.alt.enter.stop
@keydown.shift.enter.stop
/>
<span v-else>{{ vModel }}</span>
</template> </template>
<style scoped> <style scoped>
input, textarea:focus {
textarea { @apply ring-transparent;
width: 100%;
min-height: 60px;
height: 100%;
color: var(--v-textColor-base);
} }
</style> </style>

3
packages/nc-gui-v2/components/dlg/AirtableImport.vue

@ -336,7 +336,8 @@ onBeforeUnmount(() => {
</div> </div>
</a-card> </a-card>
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<a-button v-if="showGoToDashboardButton" class="mt-4" size="large" @click="dialogShow = false">Go to Dashboard</a-button <a-button v-if="showGoToDashboardButton" class="mt-4" size="large" @click="dialogShow = false"
>Go to Dashboard</a-button
> >
</div> </div>
</div> </div>

3
packages/nc-gui-v2/components/smartsheet-column/AdvancedOptions.vue

@ -5,9 +5,6 @@ const { formState, validateInfos, setAdditionalValidations, sqlUi, onDataTypeCha
const dataTypes = computed(() => sqlUi?.value?.getDataTypeListForUiType(formState)) const dataTypes = computed(() => sqlUi?.value?.getDataTypeListForUiType(formState))
// set additional validations
setAdditionalValidations({})
// to avoid type error with checkbox // to avoid type error with checkbox
formState.value.rqd = !!formState.value.rqd formState.value.rqd = !!formState.value.rqd
formState.value.pk = !!formState.value.pk formState.value.pk = !!formState.value.pk

100
packages/nc-gui-v2/components/smartsheet-column/CurrencyOptions.vue

@ -0,0 +1,100 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow, useProject } from '#imports'
import { currencyCodes, currencyLocales, validateCurrencyCode, validateCurrencyLocale } from '@/utils'
interface Option {
label: string
value: string
}
const { formState, validateInfos, setAdditionalValidations, sqlUi, onDataTypeChange, onAlter } = useColumnCreateStoreOrThrow()
const validators = {
'meta.currency_locale': [
{
validator: (_: any, locale: any) => {
return new Promise<void>((resolve, reject) => {
if (!validateCurrencyLocale(locale)) {
return reject(new Error('Invalid locale'))
}
resolve()
})
},
},
],
'meta.currency_code': [
{
validator: (_: any, currencyCode: any) => {
return new Promise<void>((resolve, reject) => {
if (!validateCurrencyCode(currencyCode)) {
return reject(new Error('Invalid Currency Code'))
}
resolve()
})
},
},
],
}
// set additional validations
setAdditionalValidations({
...validators,
})
const { isPg } = useProject()
const currencyList = currencyCodes || []
const currencyLocaleList = currencyLocales() || []
const isMoney = computed(() => formState.value.dt === 'money')
const message = computed(() => {
if (isMoney.value && isPg) return "PostgreSQL 'money' type has own currency settings"
return ''
})
function filterOption(input: string, option: Option) {
return option.value.toUpperCase().includes(input.toUpperCase())
}
</script>
<template>
<a-row>
<a-col :span="12">
<a-form-item v-bind="validateInfos['meta.currency_locale']" label="Currency Locale">
<a-select
v-model:value="formState.meta.currency_locale"
size="small"
class="w-52"
show-search
:filter-option="filterOption"
:disabled="isMoney && isPg"
>
<a-select-option v-for="(currencyLocale, i) of currencyLocaleList" :key="i" :value="currencyLocale.value">
{{ currencyLocale.text }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item v-bind="validateInfos['meta.currency_code']" label="Currency Code">
<a-select
v-model:value="formState.meta.currency_code"
class="w-52"
show-search
:filter-option="filterOption"
size="small"
:disabled="isMoney && isPg"
>
<a-select-option v-for="(currencyCode, i) of currencyList" :key="i" :value="currencyCode">
{{ currencyCode }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col v-if="isMoney && isPg">
<span class="text-[#FB8C00]">{{ message }}</span>
</a-col>
</a-row>
</template>

12
packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue

@ -23,6 +23,8 @@ const {
isEdit, isEdit,
} = useColumnCreateStoreOrThrow() } = useColumnCreateStoreOrThrow()
const columnToValidate = [UITypes.Email, UITypes.URL, UITypes.PhoneNumber]
const uiTypesOptions = computed<typeof uiTypes>(() => { const uiTypesOptions = computed<typeof uiTypes>(() => {
return [ return [
...uiTypes.filter((t) => !isEdit || !t.virtual), ...uiTypes.filter((t) => !isEdit || !t.virtual),
@ -85,6 +87,7 @@ watchEffect(() => {
</a-select> </a-select>
</a-form-item> </a-form-item>
<SmartsheetColumnCurrencyOptions v-if="formState.uidt === UITypes.Currency" />
<SmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" /> <SmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" />
<div> <div>
@ -97,6 +100,15 @@ watchEffect(() => {
</div> </div>
</div> </div>
<div class="overflow-hidden" :class="advancedOptions ? 'h-min' : 'h-0'"> <div class="overflow-hidden" :class="advancedOptions ? 'h-min' : 'h-0'">
<a-checkbox
v-if="formState.meta && columnToValidate.includes(formState.uidt)"
v-model:checked="formState.meta.validate"
class="ml-1 mb-1"
>
<span class="text-xs text-gray-600">
{{ `Accept only valid ${formState.uidt}` }}
</span>
</a-checkbox>
<SmartsheetColumnAdvancedOptions /> <SmartsheetColumnAdvancedOptions />
</div> </div>
<a-form-item> <a-form-item>

14
packages/nc-gui-v2/components/smartsheet-header/CellIcon.vue

@ -5,10 +5,13 @@ import FilePhoneIcon from '~icons/mdi/file-phone'
import { useColumn } from '#imports' import { useColumn } from '#imports'
import KeyIcon from '~icons/mdi/key-variant' import KeyIcon from '~icons/mdi/key-variant'
import JSONIcon from '~icons/mdi/code-json' import JSONIcon from '~icons/mdi/code-json'
import ClockIcon from '~icons/mdi/clock-time-five'
// import FKIcon from '~icons/mdi/link-variant' // import FKIcon from '~icons/mdi/link-variant'
import WebIcon from '~icons/mdi/web'
import TextAreaIcon from '~icons/mdi/card-text-outline' import TextAreaIcon from '~icons/mdi/card-text-outline'
import StringIcon from '~icons/mdi/alpha-a-box-outline' import StringIcon from '~icons/mdi/alpha-a-box-outline'
import BooleanIcon from '~icons/mdi/check-box-outline' import BooleanIcon from '~icons/mdi/check-box-outline'
import YearIcon from '~icons/mdi/calendar'
import SingleSelectIcon from '~icons/mdi/radiobox-marked' import SingleSelectIcon from '~icons/mdi/radiobox-marked'
import MultiSelectIcon from '~icons/mdi/checkbox-multiple-marked' import MultiSelectIcon from '~icons/mdi/checkbox-multiple-marked'
import DatetimeIcon from '~icons/mdi/calendar-clock' import DatetimeIcon from '~icons/mdi/calendar-clock'
@ -17,7 +20,6 @@ import RatingIcon from '~icons/mdi/star'
import GenericIcon from '~icons/mdi/square-rounded' import GenericIcon from '~icons/mdi/square-rounded'
import NumericIcon from '~icons/mdi/numeric' import NumericIcon from '~icons/mdi/numeric'
import AttachmentIcon from '~icons/mdi/image-multiple-outline' import AttachmentIcon from '~icons/mdi/image-multiple-outline'
import URLIcon from '~icons/mdi/link'
import EmailIcon from '~icons/mdi/email' import EmailIcon from '~icons/mdi/email'
import CurrencyIcon from '~icons/mdi/currency-usd-circle-outline' import CurrencyIcon from '~icons/mdi/currency-usd-circle-outline'
import PercentIcon from '~icons/mdi/percent-outline' import PercentIcon from '~icons/mdi/percent-outline'
@ -48,14 +50,16 @@ const icon = computed(() => {
return TextAreaIcon return TextAreaIcon
} else if (additionalColMeta.isEmail) { } else if (additionalColMeta.isEmail) {
return EmailIcon return EmailIcon
} else if (additionalColMeta.isYear) {
return YearIcon
} else if (additionalColMeta.isTime) {
return ClockIcon
} else if (additionalColMeta.isRating) { } else if (additionalColMeta.isRating) {
return RatingIcon return RatingIcon
} else if (additionalColMeta.isAttachment) { } else if (additionalColMeta.isAttachment) {
return AttachmentIcon return AttachmentIcon
} else if (additionalColMeta.isDecimal) { } else if (additionalColMeta.isDecimal) {
return DecimalIcon return DecimalIcon
} else if (additionalColMeta.isInt || additionalColMeta.isFloat) {
return NumericIcon
} else if (additionalColMeta.isPhoneNumber) { } else if (additionalColMeta.isPhoneNumber) {
return FilePhoneIcon return FilePhoneIcon
} }
@ -63,11 +67,13 @@ const icon = computed(() => {
// return FKIcon // return FKIcon
// } // }
else if (additionalColMeta.isURL) { else if (additionalColMeta.isURL) {
return URLIcon return WebIcon
} else if (additionalColMeta.isCurrency) { } else if (additionalColMeta.isCurrency) {
return CurrencyIcon return CurrencyIcon
} else if (additionalColMeta.isPercent) { } else if (additionalColMeta.isPercent) {
return PercentIcon return PercentIcon
} else if (additionalColMeta.isInt || additionalColMeta.isFloat) {
return NumericIcon
} else if (additionalColMeta.isString) { } else if (additionalColMeta.isString) {
return StringIcon return StringIcon
} else { } else {

6
packages/nc-gui-v2/components/smartsheet-header/VirtualCellIcon.vue

@ -8,6 +8,8 @@ import BTIcon from '~icons/mdi/table-arrow-left'
import MMIcon from '~icons/mdi/table-network' import MMIcon from '~icons/mdi/table-network'
import FormulaIcon from '~icons/mdi/math-integral' import FormulaIcon from '~icons/mdi/math-integral'
import RollupIcon from '~icons/mdi/movie-roll' import RollupIcon from '~icons/mdi/movie-roll'
import CountIcon from '~icons/mdi/counter'
import SpecificDBTypeIcon from '~icons/mdi/database-settings'
const { columnMeta } = defineProps<{ columnMeta?: ColumnType }>() const { columnMeta } = defineProps<{ columnMeta?: ColumnType }>()
@ -25,12 +27,16 @@ const icon = computed(() => {
return BTIcon return BTIcon
} }
break break
case UITypes.SpecificDBType:
return SpecificDBTypeIcon
case UITypes.Formula: case UITypes.Formula:
return FormulaIcon return FormulaIcon
case UITypes.Lookup: case UITypes.Lookup:
return GenericIcon return GenericIcon
case UITypes.Rollup: case UITypes.Rollup:
return RollupIcon return RollupIcon
case UITypes.Count:
return CountIcon
} }
return GenericIcon return GenericIcon
}) })

3
packages/nc-gui-v2/components/smartsheet/VirtualCell.vue

@ -15,7 +15,7 @@ const emit = defineEmits(['update:modelValue'])
provide(ColumnInj, column) provide(ColumnInj, column)
provide('value', value) provide('value', value)
const { isLookup, isBt, isRollup, isMm, isHm, isFormula } = useVirtualCell(column) const { isLookup, isBt, isRollup, isMm, isHm, isFormula, isCount } = useVirtualCell(column)
</script> </script>
<template> <template>
@ -25,6 +25,7 @@ const { isLookup, isBt, isRollup, isMm, isHm, isFormula } = useVirtualCell(colum
<VirtualCellBelongsTo v-else-if="isBt" /> <VirtualCellBelongsTo v-else-if="isBt" />
<VirtualCellRollup v-else-if="isRollup" /> <VirtualCellRollup v-else-if="isRollup" />
<VirtualCellFormula v-else-if="isFormula" /> <VirtualCellFormula v-else-if="isFormula" />
<VirtualCellCount v-else-if="isCount" />
<!-- <v-lazy> --> <!-- <v-lazy> -->
<!-- <has-many-cell <!-- <has-many-cell

9
packages/nc-gui-v2/components/virtual-cell/Count.vue

@ -0,0 +1,9 @@
<script setup lang="ts">
// TODO: wait for Count Column implementation
</script>
<template>
<span class="prose-sm"></span>
</template>
<style scoped lang="scss"></style>

2
packages/nc-gui-v2/composables/useInjectionState/index.ts

@ -3,7 +3,7 @@ import type { InjectionKey } from 'vue'
export function useInjectionState<Arguments extends any[], Return>( export function useInjectionState<Arguments extends any[], Return>(
composable: (...args: Arguments) => Return, composable: (...args: Arguments) => Return,
keyName = 'InjectionState', keyName = 'InjectionState',
): readonly [useProvidingState: (...args: Arguments) => void, useInjectedState: () => Return | undefined] { ): readonly [useInjectionState: (...args: Arguments) => Return, useInjectedState: () => Return | undefined] {
const key: string | InjectionKey<Return> = Symbol(keyName) const key: string | InjectionKey<Return> = Symbol(keyName)
const useProvidingState = (...args: Arguments) => { const useProvidingState = (...args: Arguments) => {

2
packages/nc-gui-v2/composables/useTableCreate.ts

@ -1,8 +1,8 @@
import type { TableType } from 'nocodb-sdk' import type { TableType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk' import { UITypes } from 'nocodb-sdk'
import { useToast } from 'vue-toastification'
import { useProject } from './useProject' import { useProject } from './useProject'
import { useNuxtApp } from '#app' import { useNuxtApp } from '#app'
import { useToast } from 'vue-toastification'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils' import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
export function useTableCreate(onTableCreate?: (tableMeta: TableType) => void) { export function useTableCreate(onTableCreate?: (tableMeta: TableType) => void) {

2
packages/nc-gui-v2/composables/useVirtualCell.ts

@ -20,6 +20,7 @@ export function useVirtualCell(column: ColumnType) {
const isLookup = computed(() => column.uidt === UITypes.Lookup) const isLookup = computed(() => column.uidt === UITypes.Lookup)
const isRollup = computed(() => column.uidt === UITypes.Rollup) const isRollup = computed(() => column.uidt === UITypes.Rollup)
const isFormula = computed(() => column.uidt === UITypes.Formula) const isFormula = computed(() => column.uidt === UITypes.Formula)
const isCount = computed(() => column.uidt === UITypes.Count)
return { return {
isHm, isHm,
@ -28,5 +29,6 @@ export function useVirtualCell(column: ColumnType) {
isLookup, isLookup,
isRollup, isRollup,
isFormula, isFormula,
isCount,
} }
} }

60
packages/nc-gui-v2/package-lock.json generated

@ -11,6 +11,7 @@
"dayjs": "^1.11.3", "dayjs": "^1.11.3",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",
@ -8554,6 +8555,14 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true "dev": true
}, },
"node_modules/iso639-codes": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/iso639-codes/-/iso639-codes-1.0.1.tgz",
"integrity": "sha512-jdTSv8yn6D7GODDrRtuWG7y3du3aoa+ki5H8h/Y48/NleNAd7Fw/M2niTTLXGH4QnqhJ98hg1JMQtP9csQ31Lg==",
"engines": {
"node": ">=8"
}
},
"node_modules/jest-worker": { "node_modules/jest-worker": {
"version": "26.6.2", "version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
@ -8801,6 +8810,11 @@
"integrity": "sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==", "integrity": "sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==",
"dev": true "dev": true
}, },
"node_modules/langs": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/langs/-/langs-2.0.0.tgz",
"integrity": "sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA=="
},
"node_modules/lazystream": { "node_modules/lazystream": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
@ -9001,6 +9015,19 @@
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
} }
}, },
"node_modules/locale-codes": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/locale-codes/-/locale-codes-1.3.1.tgz",
"integrity": "sha512-C7fxGkU4jAuHqavtKj4IhSD2yPEzChFMRfNHjzwIAz9JTbYHtBJDcQQgmJDezBogk9/vvgS7chKMhpVEKavk5A==",
"dependencies": {
"iso639-codes": "^1.0.1",
"langs": "^2.0.0",
"windows-locale": "^1.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@ -14214,6 +14241,14 @@
"integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==", "integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==",
"dev": true "dev": true
}, },
"node_modules/windows-locale": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/windows-locale/-/windows-locale-1.1.3.tgz",
"integrity": "sha512-0OlMOPNGj7GTB6C7WmqS3o4eydjnoYj0uwot2KJf7E0JUucwYwzkcvCWQwnuOV60WqDMeGJpSankgveNMj5r0g==",
"engines": {
"node": ">=v10.24.1"
}
},
"node_modules/wmf": { "node_modules/wmf": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
@ -20699,6 +20734,11 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true "dev": true
}, },
"iso639-codes": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/iso639-codes/-/iso639-codes-1.0.1.tgz",
"integrity": "sha512-jdTSv8yn6D7GODDrRtuWG7y3du3aoa+ki5H8h/Y48/NleNAd7Fw/M2niTTLXGH4QnqhJ98hg1JMQtP9csQ31Lg=="
},
"jest-worker": { "jest-worker": {
"version": "26.6.2", "version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
@ -20893,6 +20933,11 @@
"integrity": "sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==", "integrity": "sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==",
"dev": true "dev": true
}, },
"langs": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/langs/-/langs-2.0.0.tgz",
"integrity": "sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA=="
},
"lazystream": { "lazystream": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
@ -21050,6 +21095,16 @@
"integrity": "sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==", "integrity": "sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==",
"dev": true "dev": true
}, },
"locale-codes": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/locale-codes/-/locale-codes-1.3.1.tgz",
"integrity": "sha512-C7fxGkU4jAuHqavtKj4IhSD2yPEzChFMRfNHjzwIAz9JTbYHtBJDcQQgmJDezBogk9/vvgS7chKMhpVEKavk5A==",
"requires": {
"iso639-codes": "^1.0.1",
"langs": "^2.0.0",
"windows-locale": "^1.1.0"
}
},
"locate-path": { "locate-path": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@ -24944,6 +24999,11 @@
} }
} }
}, },
"windows-locale": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/windows-locale/-/windows-locale-1.1.3.tgz",
"integrity": "sha512-0OlMOPNGj7GTB6C7WmqS3o4eydjnoYj0uwot2KJf7E0JUucwYwzkcvCWQwnuOV60WqDMeGJpSankgveNMj5r0g=="
},
"wmf": { "wmf": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",

1
packages/nc-gui-v2/package.json

@ -17,6 +17,7 @@
"dayjs": "^1.11.3", "dayjs": "^1.11.3",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",

3
packages/nc-gui-v2/utils/columnUtils.ts

@ -3,6 +3,7 @@ import LinkVariant from '~icons/mdi/link-variant'
import TableColumnPlusBefore from '~icons/mdi/table-column-plus-before' import TableColumnPlusBefore from '~icons/mdi/table-column-plus-before'
import FormatColorText from '~icons/mdi/format-color-text' import FormatColorText from '~icons/mdi/format-color-text'
import TextSubject from '~icons/mdi/text-subject' import TextSubject from '~icons/mdi/text-subject'
import JSONIcon from '~icons/mdi/code-json'
import Attachment from '~icons/mdi/attachment' import Attachment from '~icons/mdi/attachment'
import CheckboxMarkedOutline from '~icons/mdi/checkbox-marked-outline' import CheckboxMarkedOutline from '~icons/mdi/checkbox-marked-outline'
import FormatListBulletedSquare from '~icons/mdi/format-list-bulleted-square' import FormatListBulletedSquare from '~icons/mdi/format-list-bulleted-square'
@ -135,7 +136,7 @@ const uiTypes = [
}, },
{ {
name: UITypes.JSON, name: UITypes.JSON,
icon: 'mdi-code-json', icon: JSONIcon,
}, },
{ {
name: UITypes.SpecificDBType, name: UITypes.SpecificDBType,

220
packages/nc-gui-v2/utils/currencyUtils.ts

@ -0,0 +1,220 @@
import locale from 'locale-codes'
export const currencyCodes = [
'AED',
'AFN',
'ALL',
'AMD',
'ANG',
'AOA',
'ARS',
'AUD',
'AWG',
'AZN',
'BAM',
'BBD',
'BDT',
'BGN',
'BHD',
'BIF',
'BMD',
'BND',
'BOB',
'BOV',
'BRL',
'BSD',
'BTN',
'BWP',
'BYR',
'BZD',
'CAD',
'CDF',
'CHE',
'CHF',
'CHW',
'CLF',
'CLP',
'CNY',
'COP',
'COU',
'CRC',
'CUP',
'CVE',
'CYP',
'CZK',
'DJF',
'DKK',
'DOP',
'DZD',
'EEK',
'EGP',
'ERN',
'ETB',
'EUR',
'FJD',
'FKP',
'GBP',
'GEL',
'GHC',
'GIP',
'GMD',
'GNF',
'GTQ',
'GYD',
'HKD',
'HNL',
'HRK',
'HTG',
'HUF',
'IDR',
'ILS',
'INR',
'IQD',
'IRR',
'ISK',
'JMD',
'JOD',
'JPY',
'KES',
'KGS',
'KHR',
'KMF',
'KPW',
'KRW',
'KWD',
'KYD',
'KZT',
'LAK',
'LBP',
'LKR',
'LRD',
'LSL',
'LTL',
'LVL',
'LYD',
'MAD',
'MDL',
'MGA',
'MKD',
'MMK',
'MNT',
'MOP',
'MRO',
'MTL',
'MUR',
'MVR',
'MWK',
'MXN',
'MXV',
'MYR',
'MZN',
'NAD',
'NGN',
'NIO',
'NOK',
'NPR',
'NZD',
'OMR',
'PAB',
'PEN',
'PGK',
'PHP',
'PKR',
'PLN',
'PYG',
'QAR',
'ROL',
'RON',
'RSD',
'RUB',
'RWF',
'SAR',
'SBD',
'SCR',
'SDD',
'SEK',
'SGD',
'SHP',
'SIT',
'SKK',
'SLL',
'SOS',
'SRD',
'STD',
'SYP',
'SZL',
'THB',
'TJS',
'TMM',
'TND',
'TOP',
'TRY',
'TTD',
'TWD',
'TZS',
'UAH',
'UGX',
'USD',
'USN',
'USS',
'UYU',
'UZS',
'VEB',
'VND',
'VUV',
'WST',
'XAF',
'XAG',
'XAU',
'XBA',
'XBB',
'XBC',
'XBD',
'XCD',
'XDR',
'XFO',
'XFU',
'XOF',
'XPD',
'XPF',
'XPT',
'XTS',
'XXX',
'YER',
'ZAR',
'ZMK',
'ZWD',
]
export function validateCurrencyCode(v: string) {
return currencyCodes.includes(v)
}
export function currencyLocales() {
const localeList = locale.all
.filter((l: Record<string, any>) => {
try {
if (Intl.NumberFormat.supportedLocalesOf(l.tag).length > 0) {
return true
}
return false
} catch (e) {
return false
}
})
.map((l: Record<string, any>) => {
return {
text: `${l.name} (${l.tag})`,
value: l.tag,
}
})
return localeList
}
export function validateCurrencyLocale(v: string) {
try {
return Intl.NumberFormat.supportedLocalesOf(v).length > 0
} catch (e) {
return false
}
}

1
packages/nc-gui-v2/utils/index.ts

@ -10,3 +10,4 @@ export * from './projectCreateUtils'
export * from './urlUtils' export * from './urlUtils'
export * from './validation' export * from './validation'
export * from './viewUtils' export * from './viewUtils'
export * from './currencyUtils'

2
packages/nocodb-sdk/src/lib/UITypes.ts

@ -46,10 +46,12 @@ export function isVirtualCol(
| ColumnType | ColumnType
) { ) {
return [ return [
UITypes.SpecificDBType,
UITypes.LinkToAnotherRecord, UITypes.LinkToAnotherRecord,
UITypes.Formula, UITypes.Formula,
UITypes.Rollup, UITypes.Rollup,
UITypes.Lookup, UITypes.Lookup,
UITypes.Count,
].includes(<UITypes>(typeof col === 'object' ? col?.uidt : col)); ].includes(<UITypes>(typeof col === 'object' ? col?.uidt : col));
} }

Loading…
Cancel
Save