mirror of https://github.com/nocodb/nocodb
Wing-Kam Wong
2 years ago
21 changed files with 469 additions and 148 deletions
@ -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/>. |
|
||||||
* |
|
||||||
*/ |
|
||||||
--> |
|
||||||
|
@ -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> |
@ -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> |
@ -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 |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue