diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index b5551d6076..1a65ac5e13 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -281,3 +281,8 @@ a { .ant-modal { @apply !top-[50px]; } + + +.ant-select-item-option-active:not(.ant-select-item-option-disabled) { + @apply bg-primary bg-opacity-20; +} diff --git a/packages/nc-gui/components/account/UserList.vue b/packages/nc-gui/components/account/UserList.vue index a6ac569901..4ce5764c3e 100644 --- a/packages/nc-gui/components/account/UserList.vue +++ b/packages/nc-gui/components/account/UserList.vue @@ -29,7 +29,9 @@ const searchText = ref('') const pagination = reactive({ total: 0, pageSize: 10, + position: ['bottomCenter'], }) + const loadUsers = async (page = currentPage, limit = currentLimit) => { currentPage = page try { @@ -158,7 +160,7 @@ const copyPasswordResetUrl = async (user: User) => { { callback('Email is required') return } - const invalidEmails = (value || '').split(/\s*,\s*/).filter((e: string) => !isEmail(e)) + const invalidEmails = (value || '').split(/\s*,\s*/).filter((e: string) => !validateEmail(e)) if (invalidEmails.length > 0) { callback(`${invalidEmails.length > 1 ? ' Invalid emails:' : 'Invalid email:'} ${invalidEmails.join(', ')} `) } else { diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index dcfd660be9..1b59039051 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -33,8 +33,6 @@ const { modelValue } = defineProps() const emit = defineEmits(['update:modelValue']) -const { isMysql } = useProject() - const column = inject(ColumnInj)! const readOnly = inject(ReadonlyInj)! @@ -59,6 +57,8 @@ const { $api } = useNuxtApp() const { getMeta } = useMetas() +const { isPg, isMysql } = useProject() + // a variable to keep newly created options value // temporary until it's add the option to column meta const tempSelectedOptsState = reactive([]) @@ -171,8 +171,19 @@ useSelectedCellKeyupListener(active, (e) => { isOpen.value = true } break + case 'ArrowUp': + case 'ArrowDown': + case 'ArrowRight': + case 'ArrowLeft': + case 'Delete': + // skip + break default: - isOpen.value = true + // toggle only if char key pressed + if (e.key?.length === 1) { + e.stopPropagation() + isOpen.value = true + } break } }) @@ -195,9 +206,28 @@ async function addIfMissingAndSave() { }) column.value.colOptions = { options: newOptions.map(({ value: _, ...rest }) => rest) } - await $api.dbTableColumn.update((column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string), { - ...column.value, - }) + const updatedColMeta = { ...column.value } + + // todo: refactor and avoid repetition + if (updatedColMeta.cdf) { + // Postgres returns default value wrapped with single quotes & casted with type so we have to get value between single quotes to keep it unified for all databases + if (isPg.value) { + updatedColMeta.cdf = updatedColMeta.cdf.substring( + updatedColMeta.cdf.indexOf(`'`) + 1, + updatedColMeta.cdf.lastIndexOf(`'`), + ) + } + + // Mysql escapes single quotes with backslash so we keep quotes but others have to unescaped + if (!isMysql.value) { + updatedColMeta.cdf = updatedColMeta.cdf.replace(/''/g, "'") + } + } + + await $api.dbTableColumn.update( + (column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string), + updatedColMeta, + ) activeOptCreateInProgress.value-- if (!activeOptCreateInProgress.value) { diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index ab20e724a8..b89bad6bc2 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -49,6 +49,8 @@ const searchVal = ref() const { getMeta } = useMetas() +const { isPg, isMysql } = useProject() + // a variable to keep newly created option value // temporary until it's add the option to column meta const tempSelectedOptState = ref() @@ -102,6 +104,13 @@ useSelectedCellKeyupListener(active, (e) => { isOpen.value = true } break + default: + // toggle only if char key pressed + if (e.key?.length === 1) { + e.stopPropagation() + isOpen.value = true + } + break } }) @@ -120,9 +129,28 @@ async function addIfMissingAndSave() { }) column.value.colOptions = { options: options.value.map(({ value: _, ...rest }) => rest) } - await $api.dbTableColumn.update((column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string), { - ...column.value, - }) + const updatedColMeta = { ...column.value } + + // todo: refactor and avoid repetition + if (updatedColMeta.cdf) { + // Postgres returns default value wrapped with single quotes & casted with type so we have to get value between single quotes to keep it unified for all databases + if (isPg.value) { + updatedColMeta.cdf = updatedColMeta.cdf.substring( + updatedColMeta.cdf.indexOf(`'`) + 1, + updatedColMeta.cdf.lastIndexOf(`'`), + ) + } + + // Mysql escapes single quotes with backslash so we keep quotes but others have to unescaped + if (!isMysql.value) { + updatedColMeta.cdf = updatedColMeta.cdf.replace(/''/g, "'") + } + } + + await $api.dbTableColumn.update( + (column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string), + updatedColMeta, + ) vModel.value = newOptValue await getMeta(column.value.fk_model_id!, true) } catch (e) { diff --git a/packages/nc-gui/components/smartsheet/column/SelectOptions.vue b/packages/nc-gui/components/smartsheet/column/SelectOptions.vue index f02646718b..8ddefd56a2 100644 --- a/packages/nc-gui/components/smartsheet/column/SelectOptions.vue +++ b/packages/nc-gui/components/smartsheet/column/SelectOptions.vue @@ -174,13 +174,12 @@ watch(inputs, () => { /> - + +
+ {{ validateInfos['colOptions.options'].help[0][0] }} +
diff --git a/packages/nc-gui/composables/useColumnCreateStore.ts b/packages/nc-gui/composables/useColumnCreateStore.ts index 922b12464c..c51f40bdb1 100644 --- a/packages/nc-gui/composables/useColumnCreateStore.ts +++ b/packages/nc-gui/composables/useColumnCreateStore.ts @@ -195,9 +195,15 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState try { if (!(await validate())) return } catch (e) { - console.log(e) - console.trace() - message.error(t('msg.error.formValidationFailed')) + const errorMsgs = e.errorFields + ?.map((e: any) => e.errors?.join(', ')) + .filter(Boolean) + .join(', ') + if (errorMsgs) { + message.error(errorMsgs) + } else { + message.error(t('msg.error.formValidationFailed')) + } return }