Browse Source

Merge branch 'develop' into fix/gui-v2-webhook

pull/3129/head
Wing-Kam Wong 2 years ago
parent
commit
41a2375b9b
  1. 1
      packages/nc-gui-v2/components.d.ts
  2. 3
      packages/nc-gui-v2/components/cell/Checkbox.vue
  3. 7
      packages/nc-gui-v2/components/cell/Currency.vue
  4. 7
      packages/nc-gui-v2/components/cell/DatePicker.vue
  5. 6
      packages/nc-gui-v2/components/cell/DateTimePicker.vue
  6. 7
      packages/nc-gui-v2/components/cell/Decimal.vue
  7. 16
      packages/nc-gui-v2/components/cell/Duration.vue
  8. 11
      packages/nc-gui-v2/components/cell/Email.vue
  9. 7
      packages/nc-gui-v2/components/cell/Float.vue
  10. 7
      packages/nc-gui-v2/components/cell/Integer.vue
  11. 7
      packages/nc-gui-v2/components/cell/Json.vue
  12. 7
      packages/nc-gui-v2/components/cell/MultiSelect.vue
  13. 7
      packages/nc-gui-v2/components/cell/Percent.vue
  14. 7
      packages/nc-gui-v2/components/cell/Rating.vue
  15. 7
      packages/nc-gui-v2/components/cell/SingleSelect.vue
  16. 7
      packages/nc-gui-v2/components/cell/Text.vue
  17. 7
      packages/nc-gui-v2/components/cell/TextArea.vue
  18. 6
      packages/nc-gui-v2/components/cell/TimePicker.vue
  19. 11
      packages/nc-gui-v2/components/cell/Url.vue
  20. 6
      packages/nc-gui-v2/components/cell/YearPicker.vue
  21. 13
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  22. 68
      packages/nc-gui-v2/components/smartsheet-column/AdvancedOptions.vue
  23. 31
      packages/nc-gui-v2/components/smartsheet-column/CheckboxOptions.vue
  24. 25
      packages/nc-gui-v2/components/smartsheet-column/CurrencyOptions.vue
  25. 17
      packages/nc-gui-v2/components/smartsheet-column/DateOptions.vue
  26. 15
      packages/nc-gui-v2/components/smartsheet-column/DurationOptions.vue
  27. 130
      packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue
  28. 27
      packages/nc-gui-v2/components/smartsheet-column/EditOrAddProvider.vue
  29. 26
      packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue
  30. 48
      packages/nc-gui-v2/components/smartsheet-column/LinkedToAnotherRecordOptions.vue
  31. 26
      packages/nc-gui-v2/components/smartsheet-column/LookupOptions.vue
  32. 23
      packages/nc-gui-v2/components/smartsheet-column/PercentOptions.vue
  33. 33
      packages/nc-gui-v2/components/smartsheet-column/RatingOptions.vue
  34. 29
      packages/nc-gui-v2/components/smartsheet-column/RollupOptions.vue
  35. 19
      packages/nc-gui-v2/components/smartsheet-column/SelectOptions.vue
  36. 2
      packages/nc-gui-v2/components/smartsheet-column/SpecificDBTypeOptions.vue
  37. 20
      packages/nc-gui-v2/components/smartsheet-header/Cell.vue
  38. 38
      packages/nc-gui-v2/components/smartsheet-header/CellIcon.vue
  39. 15
      packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue
  40. 4
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue
  41. 18
      packages/nc-gui-v2/components/smartsheet/Form.vue
  42. 77
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  43. 13
      packages/nc-gui-v2/components/smartsheet/Pagination.vue
  44. 2
      packages/nc-gui-v2/components/smartsheet/expanded-form/Header.vue
  45. 8
      packages/nc-gui-v2/components/smartsheet/expanded-form/index.vue
  46. 14
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue
  47. 1
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue
  48. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/RenameableMenuItem.vue
  49. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/index.vue
  50. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/index.vue
  51. 4
      packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue
  52. 4
      packages/nc-gui-v2/components/virtual-cell/HasMany.vue
  53. 4
      packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue
  54. 4
      packages/nc-gui-v2/components/virtual-cell/components/ItemChip.vue
  55. 4
      packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue
  56. 94
      packages/nc-gui-v2/composables/useColumn.ts
  57. 54
      packages/nc-gui-v2/composables/useColumnCreateStore.ts
  58. 1
      packages/nc-gui-v2/composables/useViewColumns.ts
  59. 3
      packages/nc-gui-v2/context/index.ts
  60. 1
      packages/nc-gui-v2/package.json
  61. 8
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index/index.vue

1
packages/nc-gui-v2/components.d.ts vendored

@ -136,6 +136,7 @@ declare module '@vue/runtime-core' {
MdiNumeric: typeof import('~icons/mdi/numeric')['default']
MdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default']
MdiPlus: typeof import('~icons/mdi/plus')['default']
MdiPlusIconOutline: typeof import('~icons/mdi/plus-icon-outline')['default']
MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default']
MdiReload: typeof import('~icons/mdi/reload')['default']
MdiSearch: typeof import('~icons/mdi/search')['default']

3
packages/nc-gui-v2/components/cell/Checkbox.vue

@ -1,5 +1,6 @@
<script setup lang="ts">
import { ColumnInj, IsFormInj, getMdiIcon, inject } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue?: boolean | undefined | number
@ -19,7 +20,7 @@ const column = inject(ColumnInj)
const isForm = inject(IsFormInj)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const checkboxMeta = $computed(() => {
return {

7
packages/nc-gui-v2/components/cell/Currency.vue

@ -1,9 +1,10 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { ColumnInj, ReadonlyInj, computed, inject, useVModel } from '#imports'
import { ColumnInj, computed, inject, useVModel } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | null
modelValue: number | null | undefined
}
const props = defineProps<Props>()
@ -12,7 +13,7 @@ const emit = defineEmits(['update:modelValue'])
const column = inject(ColumnInj)!
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emit)

7
packages/nc-gui-v2/components/cell/DatePicker.vue

@ -1,9 +1,10 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { ColumnInj, ReadonlyInj } from '#imports'
import { ColumnInj } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | null
modelValue: string | null | undefined
}
const { modelValue } = defineProps<Props>()
@ -12,7 +13,7 @@ const emit = defineEmits(['update:modelValue'])
const columnMeta = inject(ColumnInj, null)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
let isDateInvalid = $ref(false)

6
packages/nc-gui-v2/components/cell/DateTimePicker.vue

@ -1,9 +1,9 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { ReadonlyInj } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | null
modelValue: string | null | undefined
}
const { modelValue } = defineProps<Props>()
@ -12,7 +12,7 @@ const emit = defineEmits(['update:modelValue'])
const { isMysql } = useProject()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
let isDateInvalid = $ref(false)

7
packages/nc-gui-v2/components/cell/Decimal.vue

@ -1,9 +1,10 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { ReadonlyInj, inject, useVModel } from '#imports'
import { inject, useVModel } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | null | string
modelValue: number | null | string | undefined
}
interface Emits {
@ -14,7 +15,7 @@ const props = defineProps<Props>()
const emits = defineEmits<Emits>()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emits)

16
packages/nc-gui-v2/components/cell/Duration.vue

@ -1,17 +1,9 @@
<script setup lang="ts">
import {
ColumnInj,
ReadonlyInj,
computed,
convertDurationToSeconds,
convertMS2Duration,
durationOptions,
inject,
ref,
} from '#imports'
import { ColumnInj, computed, convertDurationToSeconds, convertMS2Duration, durationOptions, inject, ref } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | string | null
modelValue: number | string | null | undefined
}
const { modelValue } = defineProps<Props>()
@ -20,7 +12,7 @@ const emit = defineEmits(['update:modelValue'])
const column = inject(ColumnInj)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const showWarningMessage = ref(false)

11
packages/nc-gui-v2/components/cell/Email.vue

@ -1,9 +1,10 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { ReadonlyInj, computed, inject, isEmail, useVModel } from '#imports'
import { computed, inject, isEmail, useVModel } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | null
modelValue: string | null | undefined
}
interface Emits {
@ -14,7 +15,7 @@ const props = defineProps<Props>()
const emits = defineEmits<Emits>()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emits)
@ -24,8 +25,8 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</script>
<template>
<input v-if="editEnabled" :ref="focus" v-model="vModel" class="outline-none prose-sm" @blur="editEnabled = false" />
<a v-else-if="validEmail" class="prose-sm underline hover:opacity-75" :href="`mailto:${vModel}`" target="_blank">
<input v-if="editEnabled" :ref="focus" v-model="vModel" class="outline-none text-sm" @blur="editEnabled = false" />
<a v-else-if="validEmail" class="text-sm underline hover:opacity-75" :href="`mailto:${vModel}`" target="_blank">
{{ vModel }}
</a>
<span v-else>{{ vModel }}</span>

7
packages/nc-gui-v2/components/cell/Float.vue

@ -1,9 +1,10 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { ReadonlyInj, inject, useVModel } from '#imports'
import { inject, useVModel } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | null
modelValue: number | null | undefined
}
interface Emits {
@ -14,7 +15,7 @@ const props = defineProps<Props>()
const emits = defineEmits<Emits>()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emits)

7
packages/nc-gui-v2/components/cell/Integer.vue

@ -1,9 +1,10 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { ReadonlyInj, inject, useVModel } from '#imports'
import { inject, useVModel } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | null
modelValue: number | null | undefined
}
interface Emits {
@ -14,7 +15,7 @@ const props = defineProps<Props>()
const emits = defineEmits<Emits>()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emits)

7
packages/nc-gui-v2/components/cell/Json.vue

@ -2,6 +2,7 @@
import { Modal as AModal } from 'ant-design-vue'
import Editor from '~/components/monaco/Editor.vue'
import { ReadonlyInj, computed, inject, ref, useVModel, watch } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | Record<string, any> | undefined
@ -15,7 +16,9 @@ const props = defineProps<Props>()
const emits = defineEmits<Emits>()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj, ref(false))
const readonly = inject(ReadonlyInj)
const vModel = useVModel(props, 'modelValue', emits)
@ -87,7 +90,7 @@ watch(editEnabled, () => {
<template>
<component :is="isExpanded ? AModal : 'div'" v-model:visible="isExpanded" :closable="false" centered :footer="null">
<div v-if="editEnabled" class="flex flex-col w-full">
<div v-if="editEnabled && !readonly" class="flex flex-col w-full">
<div class="flex flex-row justify-between pt-1 pb-2">
<a-button type="text" size="small" @click="isExpanded = !isExpanded">
<CilFullscreenExit v-if="isExpanded" class="h-2.5" />

7
packages/nc-gui-v2/components/cell/MultiSelect.vue

@ -1,11 +1,12 @@
<script lang="ts" setup>
import type { Select as AntSelect } from 'ant-design-vue'
import type { SelectOptionType } from 'nocodb-sdk'
import { ActiveCellInj, ColumnInj, ReadonlyInj, computed, inject } from '#imports'
import { ActiveCellInj, ColumnInj, computed, inject } from '#imports'
import { EditModeInj } from '~/context'
import MdiCloseCircle from '~icons/mdi/close-circle'
interface Props {
modelValue?: string | string[]
modelValue?: string | string[] | undefined
}
const { modelValue } = defineProps<Props>()
@ -18,7 +19,7 @@ const column = inject(ColumnInj)
// const isForm = inject<boolean>('isForm', false)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const active = inject(ActiveCellInj, ref(false))

7
packages/nc-gui-v2/components/cell/Percent.vue

@ -1,15 +1,16 @@
<script setup lang="ts">
import { ColumnInj, ReadonlyInj, computed, getPercentStep, inject, isValidPercent, renderPercent } from '#imports'
import { ColumnInj, computed, getPercentStep, inject, isValidPercent, renderPercent } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | string | null
modelValue: number | string | null | undefined
}
const { modelValue } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const column = inject(ColumnInj)

7
packages/nc-gui-v2/components/cell/Rating.vue

@ -1,8 +1,9 @@
<script setup lang="ts">
import { ColumnInj, ReadonlyInj, computed, inject } from '#imports'
import { ColumnInj, computed, inject } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue?: number | null
modelValue?: number | null | undefined
}
const { modelValue } = defineProps<Props>()
@ -11,7 +12,7 @@ const emits = defineEmits(['update:modelValue'])
const column = inject(ColumnInj)!
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const ratingMeta = computed(() => {
return {

7
packages/nc-gui-v2/components/cell/SingleSelect.vue

@ -1,10 +1,11 @@
<script lang="ts" setup>
import type { Select as AntSelect } from 'ant-design-vue'
import type { SelectOptionType } from 'nocodb-sdk'
import { ActiveCellInj, ColumnInj, ReadonlyInj, computed, inject } from '#imports'
import { ActiveCellInj, ColumnInj, computed, inject } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue?: string
modelValue?: string | undefined
}
const { modelValue } = defineProps<Props>()
@ -15,7 +16,7 @@ const column = inject(ColumnInj)
// const isForm = inject<boolean>('isForm', false)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const active = inject(ActiveCellInj, ref(false))

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

@ -1,16 +1,17 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { ReadonlyInj, inject } from '#imports'
import { inject } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | null
modelValue: string | null | undefined
}
const props = defineProps<Props>()
const emits = defineEmits(['update:modelValue'])
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emits)

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

@ -1,16 +1,17 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { ReadonlyInj, computed, inject } from '#imports'
import { computed, inject } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | null
modelValue: string | null | undefined
}
const { modelValue } = defineProps<Props>()
const emits = defineEmits(['update:modelValue'])
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = computed({
get: () => modelValue ?? '',

6
packages/nc-gui-v2/components/cell/TimePicker.vue

@ -1,10 +1,10 @@
<script setup lang="ts">
import { onClickOutside } from '@vueuse/core'
import dayjs from 'dayjs'
import { ReadonlyInj } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue?: string | null
modelValue?: string | null | undefined
}
const { modelValue } = defineProps<Props>()
@ -13,7 +13,7 @@ const emit = defineEmits(['update:modelValue'])
const { isMysql } = useProject()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
let isTimeInvalid = $ref(false)

11
packages/nc-gui-v2/components/cell/Url.vue

@ -1,9 +1,10 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { ColumnInj, ReadonlyInj, computed, inject, isValidURL } from '#imports'
import { ColumnInj, computed, inject, isValidURL } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: string | null
modelValue: string | null | undefined
}
const { modelValue: value } = defineProps<Props>()
@ -12,7 +13,7 @@ const emit = defineEmits(['update:modelValue'])
const column = inject(ColumnInj)!
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const vModel = computed({
get: () => value,
@ -36,8 +37,8 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</script>
<template>
<input v-if="editEnabled" :ref="focus" v-model="vModel" class="outline-none" @blur="editEnabled = false" />
<nuxt-link v-else-if="isValid" class="py-2 underline hover:opacity-75" :to="url" target="_blank">{{ value }} </nuxt-link>
<input v-if="editEnabled" :ref="focus" v-model="vModel" class="outline-none text-sm" @blur="editEnabled = false" />
<nuxt-link v-else-if="isValid" class="text-sm underline hover:opacity-75" :to="url" target="_blank">{{ value }} </nuxt-link>
<span v-else>{{ value }}</span>
</template>

6
packages/nc-gui-v2/components/cell/YearPicker.vue

@ -1,17 +1,17 @@
<script setup lang="ts">
import { onClickOutside } from '@vueuse/core'
import dayjs from 'dayjs'
import { ReadonlyInj } from '#imports'
import { EditModeInj } from '~/context'
interface Props {
modelValue: number | string | null
modelValue: number | string | null | undefined
}
const { modelValue } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
let isYearInvalid = $ref(false)

13
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -29,8 +29,6 @@ const tablesById = $computed<Record<string, TableType>>(() =>
}, {}),
)
const showTableList = ref(true)
const tableCreateDlg = ref(false)
let key = $ref(0)
@ -165,17 +163,6 @@ const activeTable = computed(() => {
<template v-if="tables?.length"> ({{ tables.length }}) </template>
</span>
<MdiPlus
v-if="isUIAllowed('treeview-add-button')"
v-t="['c:table:create:navdraw']"
class="transform text-gray-500 hover:(text-pink-500 scale-105) nc-btn-tbl-add"
@click.stop="tableCreateDlg = true"
/>
<MdiMenuDown
class="transition-transform !duration-100 text-gray-500 hover:text-pink-500"
:class="{ 'transform rotate-180': showTableList }"
/>
</div>
<div style="direction: ltr" class="flex-1">
<div v-if="tables.length" class="transition-height duration-200 overflow-hidden">

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

@ -1,18 +1,28 @@
<script setup lang="ts">
import type { UITypes } from 'nocodb-sdk'
import { computed, useColumnCreateStoreOrThrow } from '#imports'
import { computed } from '#imports'
const { formState, validateInfos, sqlUi, onDataTypeChange, onAlter } = useColumnCreateStoreOrThrow()!
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const { sqlUi } = useProject()
const { onAlter, onDataTypeChange, validateInfos } = useColumnCreateStoreOrThrow()
// todo: 2nd argument of `getDataTypeListForUiType` is missing!
const dataTypes = computed(() => sqlUi?.value?.getDataTypeListForUiType(formState.value as { uidt: UITypes }, '' as any))
const dataTypes = computed(() => sqlUi?.value?.getDataTypeListForUiType(vModel.value as { uidt: UITypes }, '' as any))
// to avoid type error with checkbox
formState.value.rqd = !!formState.value.rqd
formState.value.pk = !!formState.value.pk
formState.value.un = !!formState.value.un
formState.value.ai = !!formState.value.ai
formState.value.au = !!formState.value.au
vModel.value.rqd = !!vModel.value.rqd
vModel.value.pk = !!vModel.value.pk
vModel.value.un = !!vModel.value.un
vModel.value.ai = !!vModel.value.ai
vModel.value.au = !!vModel.value.au
</script>
<template>
@ -20,45 +30,37 @@ formState.value.au = !!formState.value.au
<div class="flex justify-space-between">
<a-form-item label="NN">
<a-checkbox
v-model:checked="formState.rqd"
:disabled="formState.pk || !sqlUi.columnEditable(formState)"
v-model:checked="vModel.rqd"
:disabled="vModel.pk || !sqlUi.columnEditable(vModel)"
class="nc-column-checkbox-NN"
@change="onAlter"
/>
</a-form-item>
<a-form-item label="PK">
<a-checkbox
v-model:checked="formState.pk"
:disabled="!sqlUi.columnEditable(formState)"
v-model:checked="vModel.pk"
:disabled="!sqlUi.columnEditable(vModel)"
class="nc-column-checkbox-PK"
@change="onAlter"
/>
</a-form-item>
<a-form-item label="AI">
<a-checkbox
v-model:checked="formState.ai"
:disabled="sqlUi.colPropUNDisabled(formState) || !sqlUi.columnEditable(formState)"
v-model:checked="vModel.ai"
:disabled="sqlUi.colPropUNDisabled(vModel) || !sqlUi.columnEditable(vModel)"
class="nc-column-checkbox-AI"
@change="onAlter"
/>
</a-form-item>
<a-form-item
label="UN"
:disabled="sqlUi.colPropUNDisabled(formState) || !sqlUi.columnEditable(formState)"
@change="onAlter"
>
<a-checkbox v-model:checked="formState.un" class="nc-column-checkbox-UN" />
<a-form-item label="UN" :disabled="sqlUi.colPropUNDisabled(vModel) || !sqlUi.columnEditable(vModel)" @change="onAlter">
<a-checkbox v-model:checked="vModel.un" class="nc-column-checkbox-UN" />
</a-form-item>
<a-form-item
label="AU"
:disabled="sqlUi.colPropAuDisabled(formState) || !sqlUi.columnEditable(formState)"
@change="onAlter"
>
<a-checkbox v-model:checked="formState.au" class="nc-column-checkbox-AU" />
<a-form-item label="AU" :disabled="sqlUi.colPropAuDisabled(vModel) || !sqlUi.columnEditable(vModel)" @change="onAlter">
<a-checkbox v-model:checked="vModel.au" class="nc-column-checkbox-AU" />
</a-form-item>
</div>
<a-form-item :label="$t('labels.databaseType')" v-bind="validateInfos.dt">
<a-select v-model:value="formState.dt" @change="onDataTypeChange">
<a-select v-model:value="vModel.dt" @change="onDataTypeChange">
<a-select-option v-for="type in dataTypes" :key="type" :value="type">
{{ type }}
</a-select-option>
@ -66,17 +68,17 @@ formState.value.au = !!formState.value.au
</a-form-item>
<a-form-item :label="$t('labels.lengthValue')">
<a-input
v-model:value="formState.dtxp"
:disabled="sqlUi.getDefaultLengthIsDisabled(formState.dt) || !sqlUi.columnEditable(formState)"
v-model:value="vModel.dtxp"
:disabled="sqlUi.getDefaultLengthIsDisabled(vModel.dt) || !sqlUi.columnEditable(vModel)"
@input="onAlter"
/>
</a-form-item>
<a-form-item v-if="sqlUi.showScale(formState)" label="Scale">
<a-input v-model="formState.dtxs" :disabled="!sqlUi.columnEditable(formState)" @input="onAlter" />
<a-form-item v-if="sqlUi.showScale(vModel)" label="Scale">
<a-input v-model="vModel.dtxs" :disabled="!sqlUi.columnEditable(vModel)" @input="onAlter" />
</a-form-item>
<a-form-item :label="$t('placeholder.defaultValue')">
<a-textarea v-model:value="formState.cdf" auto-size @input="onAlter(2, true)" />
<span class="text-gray-400 text-xs">{{ sqlUi.getDefaultValueForDatatype(formState.dt) }}</span>
<a-textarea v-model:value="vModel.cdf" auto-size @input="onAlter(2, true)" />
<span class="text-gray-400 text-xs">{{ sqlUi.getDefaultValueForDatatype(vModel.dt) }}</span>
</a-form-item>
</div>
</template>

31
packages/nc-gui-v2/components/smartsheet-column/CheckboxOptions.vue

@ -1,8 +1,13 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow } from '#imports'
import { getMdiIcon } from '@/utils'
const { formState } = useColumnCreateStoreOrThrow()
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
// cater existing v1 cases
const iconList = [
@ -37,34 +42,34 @@ const iconList = [
]
const picked = computed({
get: () => formState.value.meta.color,
get: () => vModel.value.meta.color,
set: (val) => {
formState.value.meta.color = val
vModel.value.meta.color = val
},
})
// set default value
formState.value.meta = {
vModel.value.meta = {
icon: {
checked: 'mdi-check-bold',
unchecked: 'mdi-crop-square',
},
color: '#777',
...formState.value.meta,
...vModel.value.meta,
}
// antdv doesn't support object as value
// use iconIdx as value and update back in watch
const iconIdx = iconList.findIndex(
(ele) => ele.checked === formState.value.meta.icon.checked && ele.unchecked === formState.value.meta.icon.unchecked,
(ele) => ele.checked === vModel.value.meta.icon.checked && ele.unchecked === vModel.value.meta.icon.unchecked,
)
formState.value.meta.iconIdx = iconIdx === -1 ? 0 : iconIdx
vModel.value.meta.iconIdx = iconIdx === -1 ? 0 : iconIdx
watch(
() => formState.value.meta.iconIdx,
() => vModel.value.meta.iconIdx,
(v) => {
formState.value.meta.icon = iconList[v]
vModel.value.meta.icon = iconList[v]
},
)
</script>
@ -73,20 +78,20 @@ watch(
<a-row>
<a-col :span="24">
<a-form-item label="Icon">
<a-select v-model:value="formState.meta.iconIdx" class="w-52">
<a-select v-model:value="vModel.meta.iconIdx" class="w-52">
<a-select-option v-for="(icon, i) of iconList" :key="i" :value="i">
<div class="flex items-center">
<component
:is="getMdiIcon(icon.checked)"
class="mx-1"
:style="{
color: formState.meta.color,
color: vModel.meta.color,
}"
/>
<component
:is="getMdiIcon(icon.unchecked)"
:style="{
color: formState.meta.color,
color: vModel.meta.color,
}"
/>
</div>

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

@ -1,14 +1,20 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow, useProject } from '#imports'
import { useProject } from '#imports'
import { currencyCodes, currencyLocales, validateCurrencyCode, validateCurrencyLocale } from '@/utils'
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
interface Option {
label: string
value: string
}
const { formState, validateInfos, setAdditionalValidations } = useColumnCreateStoreOrThrow()
const validators = {
'meta.currency_locale': [
{
@ -36,7 +42,8 @@ const validators = {
],
}
// set additional validations
const { setAdditionalValidations, validateInfos } = useColumnCreateStoreOrThrow()
setAdditionalValidations({
...validators,
})
@ -47,7 +54,7 @@ const currencyList = currencyCodes || []
const currencyLocaleList = currencyLocales() || []
const isMoney = computed(() => formState.value.dt === 'money')
const isMoney = computed(() => vModel.value.dt === 'money')
const message = computed(() => {
if (isMoney.value && isPg) return "PostgreSQL 'money' type has own currency settings"
@ -59,10 +66,10 @@ function filterOption(input: string, option: Option) {
}
// set default value
formState.value.meta = {
vModel.value.meta = {
currency_locale: 'en-US',
currency_code: 'USD',
...formState.value.meta,
...vModel.value.meta,
}
</script>
@ -71,7 +78,7 @@ formState.value.meta = {
<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"
v-model:value="vModel.meta.currency_locale"
class="w-52"
show-search
:filter-option="filterOption"
@ -86,7 +93,7 @@ formState.value.meta = {
<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"
v-model:value="vModel.meta.currency_code"
class="w-52"
show-search
:filter-option="filterOption"

17
packages/nc-gui-v2/components/smartsheet-column/DateOptions.vue

@ -1,18 +1,23 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow } from '#imports'
import { dateFormats } from '~/utils'
const { formState } = $(useColumnCreateStoreOrThrow())
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
if (!formState.meta?.date_format) {
if (!formState.meta) formState.meta = {}
formState.meta.date_format = dateFormats[0]
if (!vModel.value.meta?.date_format) {
if (!vModel.value.meta) vModel.value.meta = {}
vModel.value.meta.date_format = dateFormats[0]
}
</script>
<template>
<a-form-item label="Date Format">
<a-select v-model:value="formState.meta.date_format">
<a-select v-model:value="vModel.meta.date_format">
<a-select-option v-for="(format, i) of dateFormats" :key="i" :value="format">
<div class="flex flex-row items-center">
<div class="text-xs">

15
packages/nc-gui-v2/components/smartsheet-column/DurationOptions.vue

@ -1,8 +1,13 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow } from '#imports'
import { durationOptions } from '@/utils'
const { formState } = useColumnCreateStoreOrThrow()
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const durationOptionList =
durationOptions.map((o) => ({
@ -12,9 +17,9 @@ const durationOptionList =
})) || []
// set default value
formState.value.meta = {
vModel.value.meta = {
duration: 0,
...formState.value.meta,
...vModel.value.meta,
}
</script>
@ -25,7 +30,7 @@ formState.value.meta = {
</a-col>
<a-col :span="24">
<a-form-item label="Duration Format">
<a-select v-model:value="formState.meta.duration" class="w-52">
<a-select v-model:value="vModel.meta.duration" class="w-52">
<a-select-option v-for="(duration, i) of durationOptionList" :key="i" :value="duration.id">
{{ duration.title }}
</a-select-option>

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

@ -1,28 +1,26 @@
<script lang="ts" setup>
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import { computed, inject, useColumnCreateStoreOrThrow, useMetas, watchEffect } from '#imports'
import { computed, inject, useMetas, watchEffect } from '#imports'
import { MetaInj, ReloadViewDataHookInj } from '~/context'
import { uiTypes } from '~/utils/columnUtils'
import MdiPlusIcon from '~icons/mdi/plus-circle-outline'
import MdiMinusIcon from '~icons/mdi/minus-circle-outline'
import MdiIdentifierIcon from '~icons/mdi/identifier'
interface Props {
editColumnDropdown?: boolean
}
const { editColumnDropdown } = defineProps<Props>()
const emit = defineEmits(['submit', 'cancel'])
const emit = defineEmits(['cancel', 'submit'])
const meta = inject(MetaInj)
const { formState, generateNewColumnMeta, addOrUpdate, onAlter, onUidtOrIdTypeChange, validateInfos, isEdit } =
useColumnCreateStoreOrThrow()
const reloadDataTrigger = inject(ReloadViewDataHookInj)
const advancedOptions = ref(false)
const { getMeta } = useMetas()
const formulaOptionsRef = ref()
const { formState, validateInfos, onUidtOrIdTypeChange, onAlter, addOrUpdate, generateNewColumnMeta, isEdit } =
useColumnCreateStoreOrThrow()
const editOrAddRef = ref<HTMLElement>()
const columnToValidate = [UITypes.Email, UITypes.URL, UITypes.PhoneNumber]
@ -44,18 +42,8 @@ const uiTypesOptions = computed<typeof uiTypes>(() => {
})
const reloadMetaAndData = async () => {
emit('cancel')
await getMeta(meta?.value.id as string, true)
reloadDataTrigger?.trigger()
emit('submit')
}
function onCancel() {
emit('cancel')
if (formState.value.uidt === UITypes.Formula) {
// close formula drawer
formulaOptionsRef.value.formulaSuggestionDrawer = false
}
}
async function onSubmit() {
@ -65,55 +53,69 @@ async function onSubmit() {
setTimeout(() => {
advancedOptions.value = false
}, 500)
emit('submit')
}
// create column meta if it's a new column
watchEffect(() => {
if (!isEdit.value && formState.value.altered !== 1) {
generateNewColumnMeta()
}
})
// focus and select the column name field
const antInput = ref()
watchEffect(() => {
if (antInput.value && formState.value) {
// todo: replace setTimeout
setTimeout(() => {
antInput.value.focus()
antInput.value.select()
antInput.value?.focus()
antInput.value?.select()
}, 300)
}
advancedOptions.value = false
})
watch(
() => editColumnDropdown,
(v) => {
if (v) {
if (formState.value.uidt === UITypes.Formula) {
formulaOptionsRef.value.formulaSuggestionDrawer = true
}
}
},
)
// for cases like formula
if (!formState.value?.column_name) {
formState.value.column_name = formState.value?.title
onMounted(() => {
if (isEdit.value === false) {
generateNewColumnMeta()
}
if (formState.value.uidt === UITypes.Formula) {
formulaOptionsRef.value.formulaSuggestionDrawer = true
}
// for cases like formula
if (formState.value && !formState.value.column_name) {
formState.value.column_name = formState.value?.title
}
})
onUnmounted(() => {
if (formState.value.uidt === UITypes.Formula) {
// close formula drawer
formulaOptionsRef.value.formulaSuggestionDrawer = false
}
})
const handleClose = (e: MouseEvent) => {
if (
e.target &&
editOrAddRef?.value &&
!editOrAddRef.value.contains(e.target) &&
!e.target.closest('.ant-dropdown') &&
!e.target.closest('.ant-select') &&
!e.target.closest('.ant-select-item')
) {
emit('cancel')
}
}
useEventListener(document, 'click', handleClose)
</script>
<template>
<div class="min-w-[400px] max-h-[95vh] bg-white shadow p-6 overflow-auto" @click.stop>
<a-form v-model="formState" name="column-create-or-edit" layout="vertical">
<div ref="editOrAddRef" class="min-w-[400px] max-h-[95vh] bg-white shadow p-6 overflow-auto" @click.stop>
<a-form v-if="formState" v-model="formState" name="column-create-or-edit" layout="vertical">
<div class="flex flex-col gap-2">
<a-form-item :label="$t('labels.columnName')" v-bind="validateInfos.title">
<a-input ref="antInput" v-model:value="formState.title" class="nc-column-name-input" @input="onAlter(8)" />
</a-form-item>
<a-form-item
v-if="!(editColumnDropdown && !!onlyNameUpdateOnEditColumns.find((col) => col === formState.uidt))"
v-if="!(isEdit && !!onlyNameUpdateOnEditColumns.find((col) => col === formState.uidt))"
:label="$t('labels.columnType')"
>
<a-select v-model:value="formState.uidt" show-search class="nc-column-type-input" @change="onUidtOrIdTypeChange">
@ -125,20 +127,28 @@ if (!formState.value?.column_name) {
</a-select-option>
</a-select>
</a-form-item>
<SmartsheetColumnFormulaOptions v-if="formState.uidt === UITypes.Formula" ref="formulaOptionsRef" />
<SmartsheetColumnCurrencyOptions v-if="formState.uidt === UITypes.Currency" />
<SmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" />
<SmartsheetColumnRatingOptions v-if="formState.uidt === UITypes.Rating" />
<SmartsheetColumnCheckboxOptions v-if="formState.uidt === UITypes.Checkbox" />
<SmartsheetColumnLookupOptions v-if="!editColumnDropdown && formState.uidt === UITypes.Lookup" />
<SmartsheetColumnDateOptions v-if="formState.uidt === UITypes.Date" />
<SmartsheetColumnRollupOptions v-if="!editColumnDropdown && formState.uidt === UITypes.Rollup" />
<SmartsheetColumnFormulaOptions
v-if="formState.uidt === UITypes.Formula"
ref="formulaOptionsRef"
v-model:value="formState"
/>
<SmartsheetColumnCurrencyOptions v-if="formState.uidt === UITypes.Currency" v-model:value="formState" />
<SmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" v-model:value="formState" />
<SmartsheetColumnRatingOptions v-if="formState.uidt === UITypes.Rating" v-model:value="formState" />
<SmartsheetColumnCheckboxOptions v-if="formState.uidt === UITypes.Checkbox" v-model:value="formState" />
<SmartsheetColumnLookupOptions v-if="!isEdit && formState.uidt === UITypes.Lookup" v-model:value="formState" />
<SmartsheetColumnDateOptions v-if="formState.uidt === UITypes.Date" v-model:value="formState" />
<SmartsheetColumnRollupOptions v-if="!isEdit && formState.uidt === UITypes.Rollup" v-model:value="formState" />
<SmartsheetColumnLinkedToAnotherRecordOptions
v-if="!editColumnDropdown && formState.uidt === UITypes.LinkToAnotherRecord"
v-if="!isEdit && formState.uidt === UITypes.LinkToAnotherRecord"
v-model:value="formState"
/>
<SmartsheetColumnSpecificDBTypeOptions v-if="formState.uidt === UITypes.SpecificDBType" />
<SmartsheetColumnPercentOptions v-if="formState.uidt === UITypes.Percent" />
<SmartsheetColumnSelectOptions v-if="formState.uidt === UITypes.SingleSelect || formState.uidt === UITypes.MultiSelect" />
<SmartsheetColumnPercentOptions v-if="formState.uidt === UITypes.Percent" v-model:value="formState" />
<SmartsheetColumnSelectOptions
v-if="formState.uidt === UITypes.SingleSelect || formState.uidt === UITypes.MultiSelect"
v-model:value="formState"
/>
</div>
<div
v-if="!isVirtualCol(formState.uidt)"
@ -159,15 +169,15 @@ if (!formState.value?.column_name) {
{{ `Accept only valid ${formState.uidt}` }}
</span>
</a-checkbox>
<SmartsheetColumnAdvancedOptions />
<SmartsheetColumnAdvancedOptions v-model:value="formState" />
</div>
<a-form-item>
<div class="flex justify-end gap-1 mt-4">
<a-button html-type="button" @click="onCancel">
<a-button html-type="button" @click="emit('cancel')">
<!-- Cancel -->
{{ $t('general.cancel') }}
</a-button>
<a-button html-type="submit" type="primary" @click="onSubmit">
<a-button html-type="submit" type="primary" @click.prevent="onSubmit">
<!-- Save -->
{{ $t('general.save') }}
</a-button>

27
packages/nc-gui-v2/components/smartsheet-column/EditOrAddProvider.vue

@ -0,0 +1,27 @@
<script lang="ts" setup>
import type { ColumnType, TableType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { inject } from '#imports'
import { MetaInj } from '~/context'
interface Props {
column?: Ref<ColumnType & { meta: any }>
}
const props = defineProps<Props>()
const emit = defineEmits(['submit', 'cancel'])
const meta = inject(MetaInj)
if (props?.column) {
const column = toRef(props, 'column')
useProvideColumnCreateStore(meta as Ref<TableType>, column)
} else {
useProvideColumnCreateStore(meta as Ref<TableType>)
}
</script>
<template>
<SmartsheetColumnEditOrAdd @submit="emit('submit')" @cancel="emit('cancel')"></SmartsheetColumnEditOrAdd>
</template>

26
packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue

@ -4,7 +4,7 @@ import type { ListItem as AntListItem } from 'ant-design-vue'
import jsep from 'jsep'
import type { ColumnType } from 'nocodb-sdk'
import { UITypes, jsepCurlyHook } from 'nocodb-sdk'
import { onMounted, useColumnCreateStoreOrThrow, useDebounceFn } from '#imports'
import { onMounted, useDebounceFn } from '#imports'
import { MetaInj } from '~/context'
import {
NcAutocompleteTree,
@ -17,6 +17,16 @@ import {
validateDateWithUnknownFormat,
} from '@/utils'
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const { setAdditionalValidations, validateInfos, sqlUi, column } = useColumnCreateStoreOrThrow()
enum JSEPNode {
COMPOUND = 'Compound',
IDENTIFIER = 'Identifier',
@ -29,8 +39,6 @@ enum JSEPNode {
ARRAY_EXP = 'ArrayExpression',
}
const { formState, validateInfos, setAdditionalValidations, sqlUi, column } = useColumnCreateStoreOrThrow()
const meta = inject(MetaInj)
const columns = computed(() => meta?.value?.columns || [])
@ -512,11 +520,11 @@ function appendText(item: Record<string, any>) {
const len = wordToComplete.value?.length || 0
if (item.type === 'function') {
formState.value.formula_raw = insertAtCursor(formulaRef.value.$el, text, len, 1)
vModel.value.formula_raw = insertAtCursor(formulaRef.value.$el, text, len, 1)
} else if (item.type === 'column') {
formState.value.formula_raw = insertAtCursor(formulaRef.value.$el, `{${text}}`, len + +!isCurlyBracketBalanced())
vModel.value.formula_raw = insertAtCursor(formulaRef.value.$el, `{${text}}`, len + +!isCurlyBracketBalanced())
} else {
formState.value.formula_raw = insertAtCursor(formulaRef.value.$el, text, len)
vModel.value.formula_raw = insertAtCursor(formulaRef.value.$el, text, len)
}
autocomplete.value = false
wordToComplete.value = ''
@ -582,7 +590,7 @@ function scrollToSelectedOption() {
}
// set default value
formState.value.formula_raw = (column?.value?.colOptions as Record<string, any>)?.formula_raw || ''
vModel.value.formula_raw = (column?.value?.colOptions as Record<string, any>)?.formula_raw || ''
// set additional validations
setAdditionalValidations({
@ -603,8 +611,8 @@ onMounted(() => {
<a-form-item v-bind="validateInfos.formula_raw" label="Formula">
<a-textarea
ref="formulaRef"
v-model:value="formState.formula_raw"
class="mb-2"
v-model:value="vModel.formula_raw"
class="mb-2 nc-formula-input"
@keydown.down.prevent="suggestionListDown"
@keydown.up.prevent="suggestionListUp"
@keydown.enter.prevent="selectText"

48
packages/nc-gui-v2/components/smartsheet-column/LinkedToAnotherRecordOptions.vue

@ -1,32 +1,42 @@
<script setup lang="ts">
import { ModelTypes, MssqlUi, SqliteUi } from 'nocodb-sdk'
import { inject, useColumnCreateStoreOrThrow, useProject } from '#imports'
import { inject, useProject } from '#imports'
import { MetaInj } from '~/context'
import MdiPlusIcon from '~icons/mdi/plus-circle-outline'
import MdiMinusIcon from '~icons/mdi/minus-circle-outline'
const { formState, validateInfos, onDataTypeChange, setAdditionalValidations } = $(useColumnCreateStoreOrThrow())
const { tables, sqlUi } = $(useProject())
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const meta = $(inject(MetaInj)!)
const { setAdditionalValidations, validateInfos, onDataTypeChange } = useColumnCreateStoreOrThrow()
const { tables, sqlUi } = $(useProject())
setAdditionalValidations({
childId: [{ required: true, message: 'Required' }],
})
const onUpdateDeleteOptions = sqlUi === MssqlUi ? ['NO ACTION'] : ['NO ACTION', 'CASCADE', 'RESTRICT', 'SET NULL', 'SET DEFAULT']
if (!formState.parentId) formState.parentId = meta.id
if (!formState.childId) formState.childId = null
if (!formState.childColumn) formState.childColumn = `${meta.table_name}_id`
if (!formState.childTable) formState.childTable = meta.table_name
if (!formState.parentTable) formState.parentTable = formState.rtn || ''
if (!formState.parentColumn) formState.parentColumn = formState.rcn || ''
if (!vModel.value.parentId) vModel.value.parentId = meta.id
if (!vModel.value.childId) vModel.value.childId = null
if (!vModel.value.childColumn) vModel.value.childColumn = `${meta.table_name}_id`
if (!vModel.value.childTable) vModel.value.childTable = meta.table_name
if (!vModel.value.parentTable) vModel.value.parentTable = vModel.value.rtn || ''
if (!vModel.value.parentColumn) vModel.value.parentColumn = vModel.value.rcn || ''
if (!formState.type) formState.type = 'hm'
if (!formState.onUpdate) formState.onUpdate = onUpdateDeleteOptions[0]
if (!formState.onDelete) formState.onDelete = onUpdateDeleteOptions[0]
if (!formState.virtual) formState.virtual = sqlUi === SqliteUi
if (!formState.alias) formState.alias = formState.column_name
if (!vModel.value.type) vModel.value.type = 'hm'
if (!vModel.value.onUpdate) vModel.value.onUpdate = onUpdateDeleteOptions[0]
if (!vModel.value.onDelete) vModel.value.onDelete = onUpdateDeleteOptions[0]
if (!vModel.value.virtual) vModel.value.virtual = sqlUi === SqliteUi
if (!vModel.value.alias) vModel.value.alias = vModel.value.column_name
const advancedOptions = $(ref(false))
@ -43,13 +53,13 @@ const refTables = $computed(() => {
<div class="w-full flex flex-col mb-2 mt-4">
<div class="border-2 p-6">
<a-form-item v-bind="validateInfos.type">
<a-radio-group v-model:value="formState.type" name="type" v-bind="validateInfos.type">
<a-radio-group v-model:value="vModel.type" name="type" v-bind="validateInfos.type">
<a-radio value="hm">Has Many</a-radio>
<a-radio value="mm">Many To Many</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item class="flex w-full pb-2 mt-4" :label="$t('labels.childTable')" v-bind="validateInfos.childId">
<a-select v-model:value="formState.childId" @change="onDataTypeChange">
<a-select v-model:value="vModel.childId" @change="onDataTypeChange">
<a-select-option v-for="(table, index) in refTables" :key="index" :value="table.id">
{{ table.title }}
</a-select-option>
@ -68,14 +78,14 @@ const refTables = $computed(() => {
<div v-if="advancedOptions" class="flex flex-col p-6 gap-4 border-2 mt-2">
<div class="flex flex-row space-x-2">
<a-form-item class="flex w-1/2" :label="$t('labels.onUpdate')">
<a-select v-model:value="formState.onUpdate" :disabled="formState.virtual" name="onUpdate" @change="onDataTypeChange">
<a-select v-model:value="vModel.onUpdate" :disabled="vModel.virtual" name="onUpdate" @change="onDataTypeChange">
<a-select-option v-for="(option, index) in onUpdateDeleteOptions" :key="index" :value="option">
{{ option }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="flex w-1/2" :label="$t('labels.onDelete')">
<a-select v-model:value="formState.onDelete" :disabled="formState.virtual" name="onDelete" @change="onDataTypeChange">
<a-select v-model:value="vModel.onDelete" :disabled="vModel.virtual" name="onDelete" @change="onDataTypeChange">
<a-select-option v-for="(option, index) in onUpdateDeleteOptions" :key="index" :value="option">
{{ option }}
</a-select-option>
@ -84,7 +94,7 @@ const refTables = $computed(() => {
</div>
<div class="flex flex-row">
<a-form-item>
<a-checkbox v-model:checked="formState.virtual" name="virtual" @change="onDataTypeChange">Virtual Relation</a-checkbox>
<a-checkbox v-model:checked="vModel.virtual" name="virtual" @change="onDataTypeChange">Virtual Relation</a-checkbox>
</a-form-item>
</div>
</div>

26
packages/nc-gui-v2/components/smartsheet-column/LookupOptions.vue

@ -1,12 +1,22 @@
<script setup lang="ts">
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes, isSystemColumn } from 'nocodb-sdk'
import { useColumnCreateStoreOrThrow } from '#imports'
import { MetaInj } from '~/context'
const { formState, validateInfos, onDataTypeChange, setAdditionalValidations } = $(useColumnCreateStoreOrThrow())
const { tables } = $(useProject())
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const meta = $(inject(MetaInj)!)
const { setAdditionalValidations, validateInfos, onDataTypeChange } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject())
const { metas } = $(useMetas())
setAdditionalValidations({
@ -14,8 +24,8 @@ setAdditionalValidations({
fk_lookup_column_id: [{ required: true, message: 'Required' }],
})
if (!formState.fk_relation_column_id) formState.fk_relation_column_id = null
if (!formState.fk_lookup_column_id) formState.fk_lookup_column_id = null
if (!vModel.value.fk_relation_column_id) vModel.value.fk_relation_column_id = null
if (!vModel.value.fk_lookup_column_id) vModel.value.fk_lookup_column_id = null
const relationNames = {
mm: 'Many To Many',
@ -42,7 +52,7 @@ const refTables = $computed(() => {
})
const columns = $computed(() => {
const selectedTable = refTables.find((t) => t.column.id === formState.fk_relation_column_id)
const selectedTable = refTables.find((t) => t.column.id === vModel.value.fk_relation_column_id)
if (!selectedTable?.id) {
return []
}
@ -55,7 +65,7 @@ const columns = $computed(() => {
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.childTable')" v-bind="validateInfos.fk_relation_column_id">
<a-select v-model:value="formState.fk_relation_column_id" dropdown-class-name="!w-64" @change="onDataTypeChange">
<a-select v-model:value="vModel.fk_relation_column_id" dropdown-class-name="!w-64" @change="onDataTypeChange">
<a-select-option v-for="(table, index) in refTables" :key="index" :value="table.col.fk_column_id">
<div class="flex flex-row space-x-0.5 h-full pb-0.5 items-center justify-between">
<div class="font-semibold text-xs">{{ table.column.title }}</div>
@ -67,7 +77,7 @@ const columns = $computed(() => {
</a-select>
</a-form-item>
<a-form-item class="flex w-1/2" :label="$t('labels.childColumn')" v-bind="validateInfos.fk_lookup_column_id">
<a-select v-model:value="formState.fk_lookup_column_id" name="fk_lookup_column_id" @change="onDataTypeChange">
<a-select v-model:value="vModel.fk_lookup_column_id" name="fk_lookup_column_id" @change="onDataTypeChange">
<a-select-option v-for="(column, index) of columns" :key="index" :value="column.id">
{{ column.title }}
</a-select-option>

23
packages/nc-gui-v2/components/smartsheet-column/PercentOptions.vue

@ -1,20 +1,25 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow } from '#imports'
import { precisions } from '@/utils/percentUtils'
const { formState } = $(useColumnCreateStoreOrThrow())
interface Props {
value: Record<string, any>
}
if (!formState.meta) formState.meta = {}
if (!formState.meta?.precision) formState.meta.precision = precisions[0].id
if (!formState.meta?.negative) formState.meta.negative = false
if (!formState.meta?.default) formState.meta.default = null
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
if (!vModel.value.meta) vModel.value.meta = {}
if (!vModel.value.meta?.negative) vModel.value.meta.negative = false
if (!vModel.value.meta?.default) vModel.value.meta.default = null
if (!vModel.value.meta?.precision) vModel.value.meta.precision = precisions[0].id
</script>
<template>
<div class="flex flex-col mt-2 gap-2">
<div class="flex flex-row space-x-2">
<a-form-item class="flex w-1/2" label="Precision">
<a-select v-model:value="formState.meta.precision">
<a-select v-model:value="vModel.meta.precision">
<a-select-option v-for="(precision, i) of precisions" :key="i" :value="precision.id">
<div class="flex flex-row items-center">
<div class="text-xs">
@ -25,13 +30,13 @@ if (!formState.meta?.default) formState.meta.default = null
</a-select>
</a-form-item>
<a-form-item label="Default Number (%)">
<a-input v-model:value="formState.meta.default" name="default" type="number" />
<a-input v-model:value="vModel.meta.default" name="default" type="number" />
</a-form-item>
</div>
<div class="flex flex-row mt-2">
<a-form-item>
<div class="flex flex-row space-x-2 items-center">
<a-switch v-model:checked="formState.meta.negative" name="negative" />
<a-switch v-model:checked="vModel.meta.negative" name="negative" />
<div class="text-xs">Allow negative numbers</div>
</div>
</a-form-item>

33
packages/nc-gui-v2/components/smartsheet-column/RatingOptions.vue

@ -1,8 +1,13 @@
<script setup lang="ts">
import { useColumnCreateStoreOrThrow } from '#imports'
import { getMdiIcon } from '@/utils'
const { formState } = useColumnCreateStoreOrThrow()
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
// cater existing v1 cases
const iconList = [
@ -29,14 +34,14 @@ const iconList = [
]
const picked = computed({
get: () => formState.value.meta.color,
get: () => vModel.value.meta.color,
set: (val) => {
formState.value.meta.color = val
vModel.value.meta.color = val
},
})
// set default value
formState.value.meta = {
vModel.value.meta = {
iconIdx: 0,
icon: {
full: 'mdi-star',
@ -44,21 +49,21 @@ formState.value.meta = {
},
color: '#fcb401',
max: 5,
...formState.value.meta,
...vModel.value.meta,
}
// antdv doesn't support object as value
// use iconIdx as value and update back in watch
const iconIdx = iconList.findIndex(
(ele) => ele.full === formState.value.meta.icon.full && ele.empty === formState.value.meta.icon.empty,
(ele) => ele.full === vModel.value.meta.icon.full && ele.empty === vModel.value.meta.icon.empty,
)
formState.value.meta.iconIdx = iconIdx === -1 ? 0 : iconIdx
vModel.value.meta.iconIdx = iconIdx === -1 ? 0 : iconIdx
watch(
() => formState.value.meta.iconIdx,
() => vModel.value.meta.iconIdx,
(v) => {
formState.value.meta.icon = iconList[v]
vModel.value.meta.icon = iconList[v]
},
)
</script>
@ -67,20 +72,20 @@ watch(
<a-row :gutter="8">
<a-col :span="12">
<a-form-item label="Icon">
<a-select v-model:value="formState.meta.iconIdx" class="w-52">
<a-select v-model:value="vModel.meta.iconIdx" class="w-52">
<a-select-option v-for="(icon, i) of iconList" :key="i" :value="i">
<div class="flex items-center">
<component
:is="getMdiIcon(icon.full)"
class="mx-1"
:style="{
color: formState.meta.color,
color: vModel.meta.color,
}"
/>
<component
:is="getMdiIcon(icon.empty)"
:style="{
color: formState.meta.color,
color: vModel.meta.color,
}"
/>
</div>
@ -90,7 +95,7 @@ watch(
</a-col>
<a-col :span="12">
<a-form-item label="Max">
<a-select v-model:value="formState.meta.max" class="w-52">
<a-select v-model:value="vModel.meta.max" class="w-52">
<a-select-option v-for="(v, i) in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" :key="i" :value="v">
{{ v }}
</a-select-option>

29
packages/nc-gui-v2/components/smartsheet-column/RollupOptions.vue

@ -1,13 +1,22 @@
<script setup lang="ts">
import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { inject, useColumnCreateStoreOrThrow, useMetas, useProject } from '#imports'
import { inject, useMetas, useProject } from '#imports'
import { MetaInj } from '~/context'
const { formState, validateInfos, onDataTypeChange, setAdditionalValidations } = $(useColumnCreateStoreOrThrow())
const { tables } = $(useProject())
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const meta = $(inject(MetaInj)!)
const { setAdditionalValidations, validateInfos, onDataTypeChange } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject())
const { metas } = $(useMetas())
setAdditionalValidations({
@ -33,9 +42,9 @@ const aggrFunctionsList = [
{ text: 'avgDistinct', value: 'avgDistinct' },
]
if (!formState.fk_relation_column_id) formState.fk_relation_column_id = null
if (!formState.fk_rollup_column_id) formState.fk_rollup_column_id = null
if (!formState.rollup_function) formState.rollup_function = null
if (!vModel.value.fk_relation_column_id) vModel.value.fk_relation_column_id = null
if (!vModel.value.fk_rollup_column_id) vModel.value.value.fk_rollup_column_id = null
if (!vModel.value.rollup_function) vModel.value.rollup_function = null
const refTables = $computed(() => {
if (!tables || !tables.length) {
@ -54,7 +63,7 @@ const refTables = $computed(() => {
})
const columns = $computed(() => {
const selectedTable = refTables.find((t) => t.column.id === formState.fk_relation_column_id)
const selectedTable = refTables.find((t) => t.column.id === vModel.value.fk_relation_column_id)
if (!selectedTable?.id) {
return []
@ -68,7 +77,7 @@ const columns = $computed(() => {
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.childTable')" v-bind="validateInfos.fk_relation_column_id">
<a-select v-model:value="formState.fk_relation_column_id" dropdown-class-name="!w-64" @change="onDataTypeChange">
<a-select v-model:value="vModel.fk_relation_column_id" dropdown-class-name="!w-64" @change="onDataTypeChange">
<a-select-option v-for="(table, index) in refTables" :key="index" :value="table.col.fk_column_id">
<div class="flex flex-row space-x-0.5 h-full pb-0.5 items-center justify-between">
<div class="font-semibold text-xs">{{ table.column.title }}</div>
@ -80,7 +89,7 @@ const columns = $computed(() => {
</a-select>
</a-form-item>
<a-form-item class="flex w-1/2" :label="$t('labels.childColumn')" v-bind="validateInfos.fk_rollup_column_id">
<a-select v-model:value="formState.fk_rollup_column_id" name="fk_rollup_column_id" @change="onDataTypeChange">
<a-select v-model:value="vModel.fk_rollup_column_id" name="fk_rollup_column_id" @change="onDataTypeChange">
<a-select-option v-for="(column, index) of columns" :key="index" :value="column.id">
{{ column.title }}
</a-select-option>
@ -88,7 +97,7 @@ const columns = $computed(() => {
</a-form-item>
</div>
<a-form-item label="Aggregate function" v-bind="validateInfos.rollup_function">
<a-select v-model:value="formState.rollup_function" @change="onDataTypeChange">
<a-select v-model:value="vModel.rollup_function" @change="onDataTypeChange">
<a-select-option v-for="(func, index) of aggrFunctionsList" :key="index" :value="func.value">
{{ func.text }}
</a-select-option>

19
packages/nc-gui-v2/components/smartsheet-column/SelectOptions.vue

@ -1,14 +1,21 @@
<script setup lang="ts">
import Draggable from 'vuedraggable'
import { UITypes } from 'nocodb-sdk'
import { useColumnCreateStoreOrThrow } from '#imports'
import { enumColor } from '@/utils'
import MdiDragIcon from '~icons/mdi/drag-vertical'
import MdiArrowDownDropCircle from '~icons/mdi/arrow-down-drop-circle'
import MdiClose from '~icons/mdi/close'
import MdiPlusIcon from '~icons/mdi/plus'
const { formState, setAdditionalValidations } = useColumnCreateStoreOrThrow()
interface Props {
value: Record<string, any>
}
const props = defineProps<Props>()
const emit = defineEmits(['update:value'])
const vModel = useVModel(props, 'value', emit)
const { setAdditionalValidations } = useColumnCreateStoreOrThrow()
let options = $ref<any[]>([])
const colorMenus = $ref<any>({})
@ -24,7 +31,7 @@ const validators = {
if (!opt.title.length) {
return reject(new Error("Select options can't be null"))
}
if (formState.value.uidt === UITypes.MultiSelect && opt.title.includes(',')) {
if (vModel.value.uidt === UITypes.MultiSelect && opt.title.includes(',')) {
return reject(new Error("MultiSelect columns can't have commas(',')"))
}
if (options.filter((el) => el.title === opt.title).length !== 1) {
@ -64,12 +71,12 @@ const removeOption = (index: number) => {
}
onMounted(() => {
if (!formState.value.colOptions?.options) {
formState.value.colOptions = {
if (!vModel.value.colOptions?.options) {
vModel.value.colOptions = {
options: [],
}
}
options = formState.value.colOptions.options
options = vModel.value.colOptions.options
// Support for older options
for (const op of options.filter((el) => el.order === null)) {
op.title = op.title.replace(/^'/, '').replace(/'$/, '')

2
packages/nc-gui-v2/components/smartsheet-column/SpecificDBTypeOptions.vue

@ -1,3 +1,3 @@
<template>
<SmartsheetColumnAdvancedOptions class="mt-4 mb-2" />
<div class="mt-4 mb-2" />
</template>

20
packages/nc-gui-v2/components/smartsheet-header/Cell.vue

@ -1,16 +1,11 @@
<script setup lang="ts">
import type { ColumnType, TableType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import type { ColumnType } from 'nocodb-sdk'
import { inject, toRef } from 'vue'
import { ColumnInj, IsFormInj, MetaInj } from '~/context'
import { useProvideColumnCreateStore } from '#imports'
import { ColumnInj, IsFormInj } from '~/context'
const props = defineProps<{ column: ColumnType & { meta: any }; required?: boolean; hideMenu?: boolean }>()
const hideMenu = toRef(props, 'hideMenu')
const meta = inject(MetaInj)
const isForm = inject(IsFormInj, ref(false))
const column = toRef(props, 'column')
@ -26,9 +21,6 @@ function onVisibleChange() {
// by clicking cancel button
editColumnDropdown.value = true
}
// instantiate column update store
useProvideColumnCreateStore(meta as Ref<TableType>, column)
</script>
<template>
@ -50,12 +42,14 @@ useProvideColumnCreateStore(meta as Ref<TableType>, column)
>
<div />
<template #overlay>
<SmartsheetColumnEditOrAdd
<SmartsheetColumnEditOrAddProvider
v-if="editColumnDropdown"
:column="column"
class="w-full"
:edit-column-dropdown="editColumnDropdown"
@submit="editColumnDropdown = false"
@cancel="editColumnDropdown = false"
@click.stop
@keydown.stop
@cancel="editColumnDropdown = false"
/>
</template>
</a-dropdown>

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

@ -36,47 +36,47 @@ const additionalColMeta = useColumn(column as Ref<ColumnType>)
const icon = computed(() => {
if (column?.value?.pk) {
return KeyIcon
} else if (additionalColMeta.isJSON) {
} else if (additionalColMeta.isJSON.value) {
return JSONIcon
} else if (additionalColMeta.isDate) {
} else if (additionalColMeta.isDate.value) {
return CalendarIcon
} else if (additionalColMeta.isDateTime) {
} else if (additionalColMeta.isDateTime.value) {
return DatetimeIcon
} else if (additionalColMeta.isSet) {
} else if (additionalColMeta.isSet.value) {
return MultiSelectIcon
} else if (additionalColMeta.isSingleSelect) {
} else if (additionalColMeta.isSingleSelect.value) {
return SingleSelectIcon
} else if (additionalColMeta.isBoolean) {
} else if (additionalColMeta.isBoolean.value) {
return BooleanIcon
} else if (additionalColMeta.isTextArea) {
} else if (additionalColMeta.isTextArea.value) {
return TextAreaIcon
} else if (additionalColMeta.isEmail) {
} else if (additionalColMeta.isEmail.value) {
return EmailIcon
} else if (additionalColMeta.isYear) {
} else if (additionalColMeta.isYear.value) {
return CalendarIcon
} else if (additionalColMeta.isTime) {
} else if (additionalColMeta.isTime.value) {
return ClockIcon
} else if (additionalColMeta.isRating) {
} else if (additionalColMeta.isRating.value) {
return RatingIcon
} else if (additionalColMeta.isAttachment) {
} else if (additionalColMeta.isAttachment.value) {
return AttachmentIcon
} else if (additionalColMeta.isDecimal) {
} else if (additionalColMeta.isDecimal.value) {
return DecimalIcon
} else if (additionalColMeta.isPhoneNumber) {
} else if (additionalColMeta.isPhoneNumber.value) {
return FilePhoneIcon
}
// else if(additionalColMeta.isForeignKey) {
// return FKIcon
// }
else if (additionalColMeta.isURL) {
else if (additionalColMeta.isURL.value) {
return WebIcon
} else if (additionalColMeta.isCurrency) {
} else if (additionalColMeta.isCurrency.value) {
return CurrencyIcon
} else if (additionalColMeta.isPercent) {
} else if (additionalColMeta.isPercent.value) {
return PercentIcon
} else if (additionalColMeta.isInt || additionalColMeta.isFloat) {
} else if (additionalColMeta.isInt.value || additionalColMeta.isFloat.value) {
return NumericIcon
} else if (additionalColMeta.isString) {
} else if (additionalColMeta.isString.value) {
return StringIcon
} else {
return GenericIcon

15
packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue

@ -1,9 +1,8 @@
<script setup lang="ts">
import { substituteColumnIdWithAliasInFormula } from 'nocodb-sdk'
import type { ColumnType, FormulaType, LinkToAnotherRecordType, LookupType, RollupType, TableType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import type { ColumnType, FormulaType, LinkToAnotherRecordType, LookupType, RollupType } from 'nocodb-sdk'
import { ColumnInj, IsFormInj, MetaInj } from '~/context'
import { provide, toRef, useMetas, useProvideColumnCreateStore } from '#imports'
import { provide, toRef, useMetas } from '#imports'
const props = defineProps<{ column: ColumnType & { meta: any }; hideMenu?: boolean; required?: boolean }>()
@ -90,8 +89,6 @@ function onVisibleChange() {
// by clicking cancel button
editColumnDropdown.value = true
}
useProvideColumnCreateStore(meta as Ref<TableType>, column)
</script>
<template>
@ -126,12 +123,14 @@ useProvideColumnCreateStore(meta as Ref<TableType>, column)
>
<div />
<template #overlay>
<SmartsheetColumnEditOrAdd
<SmartsheetColumnEditOrAddProvider
v-if="editColumnDropdown"
:column="column"
class="w-full"
:edit-column-dropdown="editColumnDropdown"
@submit="editColumnDropdown = false"
@cancel="editColumnDropdown = false"
@click.stop
@keydown.stop
@cancel="editColumnDropdown = false"
/>
</template>
</a-dropdown>

4
packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue

@ -107,11 +107,11 @@ const onMove = (event: { moved: { newIndex: number } }) => {
</a-checkbox>
</div>
<div class="p-2 flex gap-2" @click.stop>
<a-button size="small" class="!text-xs text-gray-500 text-capitalize" @click.stop="showAll">
<a-button size="small" class="!text-xs text-gray-500 text-capitalize" @click.stop="showAll()">
<!-- Show All -->
{{ $t('general.showAll') }}
</a-button>
<a-button size="small" class="!text-xs text-gray-500 text-capitalize" @click.stop="hideAll">
<a-button size="small" class="!text-xs text-gray-500 text-capitalize" @click.stop="hideAll()">
<!-- Hide All -->
{{ $t('general.hideAll') }}
</a-button>

18
packages/nc-gui-v2/components/smartsheet/Form.vue

@ -30,8 +30,6 @@ const meta = inject(MetaInj)
const view = inject(ActiveViewInj)
if (meta) useProvideColumnCreateStore(meta)
const { loadFormView, insertRow, formColumnData, formViewData, updateFormView } = useViewData(meta, view as any)
const { showAll, hideAll, saveOrUpdate } = useViewColumns(view, meta as any, false, async () => {
@ -47,8 +45,6 @@ const hiddenColumns = ref<Record<string, any>>([])
const draggableRef = ref()
const editOrAddRef = ref()
const systemFieldsIds = ref<Record<string, any>>([])
const showColumnDropdown = ref(false)
@ -293,10 +289,6 @@ onClickOutside(draggableRef, () => {
activeRow.value = ''
})
onClickOutside(editOrAddRef, () => {
showColumnDropdown.value = false
})
onMounted(async () => {
await loadFormView()
setFormData()
@ -390,7 +382,7 @@ onMounted(async () => {
{{ $t('msg.info.dragDropHide') }}
</div>
<a-dropdown v-model:visible="showColumnDropdown" :trigger="['click']">
<a-button type="link" class="w-full caption mt-2" size="large" @click="showColumnDropdown = true">
<a-button type="link" class="w-full caption mt-2" size="large" @click.stop="showColumnDropdown = true">
<div class="flex items-center prose-sm justify-center text-gray-400">
<mdi-plus />
<!-- Add new field to this table -->
@ -398,7 +390,13 @@ onMounted(async () => {
</div>
</a-button>
<template #overlay>
<SmartsheetColumnEditOrAdd ref="editOrAddRef" @submit="submitCallback" @cancel="showColumnDropdown = false" />
<SmartsheetColumnEditOrAddProvider
v-if="showColumnDropdown"
@submit="submitCallback"
@cancel="showColumnDropdown = false"
@click.stop
@keydown.stop
/>
</template>
</a-dropdown>
</template>

77
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -11,7 +11,6 @@ import {
ref,
useEventListener,
useGridViewColumnWidth,
useProvideColumnCreateStore,
useSmartsheetStoreOrThrow,
useViewData,
watch,
@ -92,7 +91,7 @@ provide(PaginationDataInj, paginationData)
provide(ChangePageInj, changePage)
provide(ReadonlyInj, isUIAllowed('xcDatatableEditable'))
provide(ReadonlyInj, !isUIAllowed('xcDatatableEditable'))
reloadViewDataHook?.on(async () => {
await loadData()
@ -127,9 +126,6 @@ defineExpose({
loadData,
})
// instantiate column create store
if (meta) useProvideColumnCreateStore(meta)
// reset context menu target on hide
watch(contextMenu, () => {
if (!contextMenu.value) {
@ -298,9 +294,9 @@ const expandForm = (row: Row, state: Record<string, any>) => {
<a-dropdown v-model:visible="contextMenu" :trigger="['contextmenu']">
<table ref="smartTable" class="xc-row-table nc-grid backgroundColorDefault" @contextmenu.prevent="contextMenu = true">
<thead>
<tr class="nc-grid-header">
<tr class="nc-grid-header border-1 bg-gray-100 sticky top[-1px]">
<th>
<div class="w-full h-full bg-gray-100 flex w-[80px] px-1 items-center">
<div class="w-full h-full bg-gray-100 flex min-w-[80px] pl-5 pr-1 items-center">
<div class="nc-no-label text-gray-500" :class="{ hidden: selectedAllRecords }">#</div>
<div
:class="{ hidden: !selectedAllRecords, flex: selectedAllRecords }"
@ -329,14 +325,20 @@ const expandForm = (row: Row, state: Record<string, any>) => {
</div>
</th>
<!-- v-if="!isLocked && !isVirtual && !isPublicView && _isUIAllowed('add-column')" -->
<th v-if="isUIAllowed('add-column')" v-t="['c:column:add']" @click="addColumnDropdown = true">
<th v-if="isUIAllowed('add-column')" v-t="['c:column:add']" @click.stop="addColumnDropdown = true">
<a-dropdown v-model:visible="addColumnDropdown" :trigger="['click']">
<div class="h-full w-[60px] flex align-center justify-center">
<MdiPlus class="text-sm" />
</div>
<template #overlay>
<SmartsheetColumnEditOrAdd @click.stop @keydown.stop @cancel="addColumnDropdown = false" />
<SmartsheetColumnEditOrAddProvider
v-if="addColumnDropdown"
@submit="addColumnDropdown = false"
@cancel="addColumnDropdown = false"
@click.stop
@keydown.stop
/>
</template>
</a-dropdown>
</th>
@ -346,33 +348,30 @@ const expandForm = (row: Row, state: Record<string, any>) => {
<SmartsheetRow v-for="(row, rowIndex) of data" :key="rowIndex" :row="row">
<template #default="{ state }">
<tr class="nc-grid-row">
<td key="row-index" class="caption nc-grid-cell">
<div class="align-center flex w-[80px]">
<td key="row-index" class="caption nc-grid-cell pl-5 pr-1">
<div class="align-center flex min-w-[80px]">
<div class="nc-row-no" :class="{ hidden: row.rowMeta.selected }">{{ rowIndex + 1 }}</div>
<div
:class="{ hidden: !row.rowMeta.selected, flex: row.rowMeta.selected }"
class="nc-row-expand-and-checkbox"
>
<a-checkbox v-model:checked="row.rowMeta.selected" />
<span class="flex-1" />
<div class="nc-expand">
<span
v-if="row.rowMeta?.commentCount"
class="py-1 px-3 rounded-full text-xs"
:style="{ backgroundColor: enumColor.light[row.rowMeta.commentCount % enumColor.light.length] }"
</div>
<span class="flex-1" />
<div class="nc-expand" :class="{ 'nc-comment': row.rowMeta?.commentCount }">
<span
v-if="row.rowMeta?.commentCount"
class="py-1 px-3 rounded-full text-xs cursor-pointer select-none transform hover:(scale-110)"
:style="{ backgroundColor: enumColor.light[row.rowMeta.commentCount % enumColor.light.length] }"
@click="expandForm(row, state)"
>
{{ row.rowMeta.commentCount }}
</span>
<div v-else class="cursor-pointer flex items-center border-1 active:ring rounded p-1 hover:bg-primary/10">
<MdiArrowExpand
class="select-none transform hover:(text-pink-500 scale-120) nc-row-expand"
@click="expandForm(row, state)"
>
{{ row.rowMeta.commentCount }}
</span>
<div
v-else
class="cursor-pointer flex items-center border-1 active:ring rounded p-1 hover:bg-primary/10"
>
<MdiArrowExpand
class="select-none transform hover:(text-pink-500 scale-120)"
@click="expandForm(row, state)"
/>
</div>
/>
</div>
</div>
</div>
@ -431,8 +430,8 @@ const expandForm = (row: Row, state: Record<string, any>) => {
class="text-left pointer nc-grid-add-new-cell"
@click="addEmptyRow()"
>
<div class="px-2 w-full flex items-center">
<MdiPlus class="text-pint-500 text-xs" />
<div class="px-2 w-full flex items-center text-gray-500">
<MdiPlus class="text-pint-500 text-xs ml-2" />
<span class="ml-1">
{{ $t('activity.addRow') }}
@ -482,7 +481,7 @@ const expandForm = (row: Row, state: Record<string, any>) => {
position: relative;
}
td > div {
td:not(:first-child) > div {
overflow: hidden;
@apply flex align-center h-auto px-1;
}
@ -532,10 +531,15 @@ const expandForm = (row: Row, state: Record<string, any>) => {
.nc-grid-row {
.nc-row-expand-and-checkbox {
@apply w-full items-center justify-between p-1;
@apply w-full items-center justify-between;
}
.nc-expand {
@apply hidden;
&:not(.nc-comment) {
@apply hidden;
}
&.nc-comment {
display: flex;
}
}
&:hover {
@ -554,6 +558,11 @@ const expandForm = (row: Row, state: Record<string, any>) => {
}
.nc-grid-header {
position: sticky;
top: -1px;
@apply z-1;
&:hover {
.nc-no-label {
@apply hidden;

13
packages/nc-gui-v2/components/smartsheet/Pagination.vue

@ -19,7 +19,9 @@ const page = computed({
<template>
<div class="flex items-center">
<span v-if="count !== null && count !== Infinity" class="caption ml-2"> {{ count }} record{{ count !== 1 ? 's' : '' }} </span>
<span v-if="count !== null && count !== Infinity" class="caption ml-5 text-gray-500">
{{ count }} record{{ count !== 1 ? 's' : '' }}
</span>
<div class="flex-1" />
@ -27,7 +29,7 @@ const page = computed({
v-if="count !== Infinity"
v-model:current="page"
size="small"
class="!text-xs !m-1"
class="!text-xs !m-1 nc-pagination"
:total="count"
:page-size="size"
show-less-items
@ -51,4 +53,11 @@ const page = computed({
line-height: 21px !important;
@apply text-sm;
}
:deep(.ant-pagination-item:not(.ant-pagination-item-active) a) {
line-height: 21px !important;
@apply text-sm text-gray-500;
}
:deep(.ant-pagination-item-link) {
@apply text-gray-500;
}
</style>

2
packages/nc-gui-v2/components/smartsheet/expanded-form/Header.vue

@ -54,7 +54,7 @@ const iconColor = '#1890ff'
v-if="isUIAllowed('rowComments')"
class="cursor-pointer select-none"
@click="commentsDrawer = !commentsDrawer"
/>>
/>
<a-button class="!text" @click="emit('cancel')">
<!-- Cancel -->
{{ $t('general.cancel') }}

8
packages/nc-gui-v2/components/smartsheet/expanded-form/index.vue

@ -82,15 +82,15 @@ const isExpanded = useVModel(props, 'modelValue', emits)
<template>
<a-modal v-model:visible="isExpanded" :footer="null" width="min(90vw,1000px)" :body-style="{ padding: 0 }" :closable="false">
<Header @cancel="isExpanded = false" />
<a-card class="!bg-gray-100 min-h-[70vh]">
<div class="flex h-full nc-form-wrapper items-stretch">
<a-card class="!bg-gray-100">
<div class="flex h-full nc-form-wrapper items-stretch min-h-[70vh]">
<div class="flex-grow overflow-auto scrollbar-thin-primary">
<div class="w-[500px] mx-auto">
<div v-for="col in fields" :key="col.title" class="mt-2 py-2">
<div v-for="col in fields" :key="col.title" class="mt-2 py-2" :class="`nc-expand-col-${col.title}`">
<SmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
<SmartsheetHeaderCell v-else :column="col" />
<div class="!bg-white rounded px-1 min-h-[35px] flex align-center">
<div class="!bg-white rounded px-1 min-h-[35px] flex align-center mt-2">
<SmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="row.row[col.title]" :row="row" :column="col" />
<SmartsheetCell
v-else

14
packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue

@ -41,7 +41,11 @@ function onOpenModal(type: ViewTypes, title = '') {
{{ $t('activity.createView') }}
</h3>
<a-menu-item key="grid" class="group !flex !items-center !my-0 !h-[30px]" @click="onOpenModal(ViewTypes.GRID)">
<a-menu-item
key="grid"
class="group !flex !items-center !my-0 !h-[30px] nc-create-3-view"
@click="onOpenModal(ViewTypes.GRID)"
>
<a-tooltip placement="left">
<template #title>
{{ $t('msg.info.addView.grid') }}
@ -59,7 +63,11 @@ function onOpenModal(type: ViewTypes, title = '') {
</a-tooltip>
</a-menu-item>
<a-menu-item key="gallery" class="group !flex !items-center !-my0 !h-[30px]" @click="onOpenModal(ViewTypes.GALLERY)">
<a-menu-item
key="gallery"
class="group !flex !items-center !-my0 !h-[30px] nc-create-2-view"
@click="onOpenModal(ViewTypes.GALLERY)"
>
<a-tooltip placement="left">
<template #title>
{{ $t('msg.info.addView.gallery') }}
@ -80,7 +88,7 @@ function onOpenModal(type: ViewTypes, title = '') {
<a-menu-item
v-if="!isView"
key="form"
class="group !flex !items-center !my-0 !h-[30px]"
class="group !flex !items-center !my-0 !h-[30px] nc-create-1-view"
@click="onOpenModal(ViewTypes.FORM)"
>
<a-tooltip placement="left">

1
packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue

@ -183,6 +183,7 @@ function onDeleted() {
:class="[
isMarked === view.id ? 'bg-gray-200' : '',
route.params.viewTitle && route.params.viewTitle.includes(view.title) ? 'active' : '',
`nc-view-item nc-${view.type}-view-item`,
]"
@change-view="changeView"
@open-modal="$emit('openModal', $event)"

2
packages/nc-gui-v2/components/smartsheet/sidebar/RenameableMenuItem.vue

@ -183,7 +183,7 @@ function onStopEdit() {
{{ $t('activity.deleteView') }}
</template>
<MdiTrashCan class="hidden group-hover:block text-red-500" @click.stop="onDelete" />
<MdiTrashCan class="hidden group-hover:block text-red-500 nc-view-delete-icon" @click.stop="onDelete" />
</a-tooltip>
</template>
</div>

2
packages/nc-gui-v2/components/smartsheet/sidebar/index.vue

@ -113,7 +113,7 @@ function onCreate(view: GridType | FormType | KanbanType | GalleryType) {
</div>
</a-tooltip>
<div class="dot" />
<div v-if="isUIAllowed('virtualViewsCreateOrEdit')" class="dot" />
<a-tooltip placement="left">
<template #title> Get API Snippet</template>

2
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/index.vue

@ -12,7 +12,7 @@ const { isUIAllowed } = useUIPermission()
<LockMenu v-if="isUIAllowed('view-type')" />
<div class="dot" />
<div v-if="isUIAllowed('view-type')" class="dot" />
<Reload />

4
packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue

@ -4,7 +4,7 @@ import type { Ref } from 'vue'
import ItemChip from './components/ItemChip.vue'
import ListItems from './components/ListItems.vue'
import { inject, ref, useProvideLTARStore, useSmartsheetRowStoreOrThrow } from '#imports'
import { ActiveCellInj, CellValueInj, ColumnInj, ReadonlyInj, ReloadViewDataHookInj, RowInj } from '~/context'
import { ActiveCellInj, CellValueInj, ColumnInj, EditModeInj, ReloadViewDataHookInj, RowInj } from '~/context'
import MdiArrowExpand from '~icons/mdi/arrow-expand'
import MdiPlus from '~icons/mdi/plus'
@ -18,7 +18,7 @@ const row = inject(RowInj)
const active = inject(ActiveCellInj)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const listItemsDlg = ref(false)

4
packages/nc-gui-v2/components/virtual-cell/HasMany.vue

@ -5,7 +5,7 @@ import ItemChip from './components/ItemChip.vue'
import ListChildItems from './components/ListChildItems.vue'
import ListItems from './components/ListItems.vue'
import { computed, inject, ref, useProvideLTARStore, useSmartsheetRowStoreOrThrow } from '#imports'
import { CellValueInj, ColumnInj, IsFormInj, ReadonlyInj, ReloadViewDataHookInj, RowInj } from '~/context'
import { CellValueInj, ColumnInj, EditModeInj, IsFormInj, ReloadViewDataHookInj, RowInj } from '~/context'
const column = inject(ColumnInj)!
@ -17,7 +17,7 @@ const reloadTrigger = inject(ReloadViewDataHookInj)!
const isForm = inject(IsFormInj)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const listItemsDlg = ref(false)

4
packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue

@ -5,7 +5,7 @@ import ItemChip from './components/ItemChip.vue'
import ListChildItems from './components/ListChildItems.vue'
import ListItems from './components/ListItems.vue'
import { computed, inject, ref, useProvideLTARStore, useSmartsheetRowStoreOrThrow } from '#imports'
import { CellValueInj, ColumnInj, IsFormInj, ReadonlyInj, ReloadViewDataHookInj, RowInj } from '~/context'
import { CellValueInj, ColumnInj, EditModeInj, IsFormInj, ReloadViewDataHookInj, RowInj } from '~/context'
const column = inject(ColumnInj)!
@ -17,7 +17,7 @@ const reloadTrigger = inject(ReloadViewDataHookInj)!
const isForm = inject(IsFormInj)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const listItemsDlg = ref(false)

4
packages/nc-gui-v2/components/virtual-cell/components/ItemChip.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import { useLTARStoreOrThrow } from '#imports'
import { ActiveCellInj, IsFormInj, ReadonlyInj } from '~/context'
import { ActiveCellInj, EditModeInj, IsFormInj } from '~/context'
interface Props {
value?: string | number | boolean
@ -13,7 +13,7 @@ const emit = defineEmits(['unlink'])
const { relatedTableMeta } = useLTARStoreOrThrow()
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const active = inject(ActiveCellInj, ref(false))

4
packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue

@ -2,7 +2,7 @@
import { Empty, Modal } from 'ant-design-vue'
import type { ColumnType } from 'nocodb-sdk'
import { computed, useLTARStoreOrThrow, useSmartsheetRowStoreOrThrow, useVModel, watch } from '#imports'
import { ColumnInj, IsFormInj, ReadonlyInj } from '~/context'
import { ColumnInj, EditModeInj, IsFormInj } from '~/context'
const props = defineProps<{ modelValue?: boolean }>()
const emit = defineEmits(['update:modelValue', 'attachRecord'])
@ -13,7 +13,7 @@ const isForm = inject(IsFormInj, ref(false))
const column = inject(ColumnInj)
const editEnabled = inject(ReadonlyInj)
const editEnabled = inject(EditModeInj)
const {
childrenList,

94
packages/nc-gui-v2/composables/useColumn.ts

@ -1,55 +1,61 @@
import type { ColumnType } from 'nocodb-sdk'
import { SqlUiFactory, UITypes, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import { useProject } from '#imports'
export function useColumn(column: Ref<ColumnType>) {
const { project } = useProject()
const uiDatatype: UITypes = column?.value?.uidt as UITypes
const abstractType = isVirtualCol(column?.value)
? null
: SqlUiFactory.create(project.value?.bases?.[0]?.config || { client: 'mysql2' }).getAbstractType(column?.value)
const uiDatatype: ComputedRef<UITypes> = computed(() => column?.value?.uidt as UITypes)
const abstractType = computed(() =>
isVirtualCol(column?.value)
? null
: SqlUiFactory.create(project.value?.bases?.[0]?.config || { client: 'mysql2' }).getAbstractType(column?.value),
)
const dataTypeLow = column?.value?.dt?.toLowerCase()
const isBoolean = abstractType === 'boolean'
const isString = abstractType === 'string'
const isTextArea = uiDatatype === UITypes.LongText
const isInt = abstractType === 'integer'
const isFloat = abstractType === 'float'
const isDate = abstractType === 'date' || uiDatatype === 'Date'
const isYear = abstractType === 'year' || uiDatatype === 'Year'
const isTime = abstractType === 'time' || uiDatatype === 'Time'
const isDateTime = abstractType === 'datetime' || uiDatatype === 'DateTime'
const isJSON = uiDatatype === 'JSON'
const isEnum = uiDatatype === 'SingleSelect'
const isSingleSelect = uiDatatype === 'SingleSelect'
const isSet = uiDatatype === 'MultiSelect'
const isMultiSelect = uiDatatype === 'MultiSelect'
const isURL = uiDatatype === 'URL'
const isEmail = uiDatatype === UITypes.Email
const isAttachment = uiDatatype === 'Attachment'
const isRating = uiDatatype === UITypes.Rating
const isCurrency = uiDatatype === 'Currency'
const isPhoneNumber = uiDatatype === UITypes.PhoneNumber
const isDecimal = uiDatatype === UITypes.Decimal
const isDuration = uiDatatype === UITypes.Duration
const isPercent = uiDatatype === UITypes.Percent
const isAutoSaved = [
UITypes.SingleLineText,
UITypes.LongText,
UITypes.PhoneNumber,
UITypes.Email,
UITypes.URL,
UITypes.Number,
UITypes.Decimal,
UITypes.Percent,
UITypes.Count,
UITypes.AutoNumber,
UITypes.SpecificDBType,
UITypes.Geometry,
].includes(uiDatatype)
const isManualSaved = [UITypes.Currency, UITypes.Year, UITypes.Time, UITypes.Duration].includes(uiDatatype)
const dataTypeLow = computed(() => column?.value?.dt?.toLowerCase())
const isBoolean = computed(() => abstractType.value === 'boolean')
const isString = computed(() => abstractType.value === 'string')
const isTextArea = computed(() => uiDatatype.value === UITypes.LongText)
const isInt = computed(() => abstractType.value === 'integer')
const isFloat = computed(() => abstractType.value === 'float')
const isDate = computed(() => abstractType.value === 'date' || uiDatatype.value === 'Date')
const isYear = computed(() => abstractType.value === 'year' || uiDatatype.value === 'Year')
const isTime = computed(() => abstractType.value === 'time' || uiDatatype.value === 'Time')
const isDateTime = computed(() => abstractType.value === 'datetime' || uiDatatype.value === 'DateTime')
const isJSON = computed(() => uiDatatype.value === 'JSON')
const isEnum = computed(() => uiDatatype.value === 'SingleSelect')
const isSingleSelect = computed(() => uiDatatype.value === 'SingleSelect')
const isSet = computed(() => uiDatatype.value === 'MultiSelect')
const isMultiSelect = computed(() => uiDatatype.value === 'MultiSelect')
const isURL = computed(() => uiDatatype.value === 'URL')
const isEmail = computed(() => uiDatatype.value === UITypes.Email)
const isAttachment = computed(() => uiDatatype.value === 'Attachment')
const isRating = computed(() => uiDatatype.value === UITypes.Rating)
const isCurrency = computed(() => uiDatatype.value === 'Currency')
const isPhoneNumber = computed(() => uiDatatype.value === UITypes.PhoneNumber)
const isDecimal = computed(() => uiDatatype.value === UITypes.Decimal)
const isDuration = computed(() => uiDatatype.value === UITypes.Duration)
const isPercent = computed(() => uiDatatype.value === UITypes.Percent)
const isAutoSaved = computed(() =>
[
UITypes.SingleLineText,
UITypes.LongText,
UITypes.PhoneNumber,
UITypes.Email,
UITypes.URL,
UITypes.Number,
UITypes.Decimal,
UITypes.Percent,
UITypes.Count,
UITypes.AutoNumber,
UITypes.SpecificDBType,
UITypes.Geometry,
].includes(uiDatatype.value),
)
const isManualSaved = computed(() =>
[UITypes.Currency, UITypes.Year, UITypes.Time, UITypes.Duration].includes(uiDatatype.value),
)
return {
abstractType,

54
packages/nc-gui-v2/composables/useColumnCreateStore.ts

@ -1,4 +1,5 @@
import { createInjectionState } from '@vueuse/core'
import clone from 'just-clone'
import { Form, message } from 'ant-design-vue'
import type { ColumnType, TableType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
@ -25,18 +26,28 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
const { $api } = useNuxtApp()
const { getMeta } = useMetas()
const isEdit = computed(() => !!column?.value?.id)
const idType = null
// state
// todo: give proper type - ColumnType
const additionalValidations = ref<Record<string, any>>({})
const setAdditionalValidations = (validations: Record<string, any>) => {
additionalValidations.value = validations
}
const formState = ref<Record<string, any>>({
title: 'title',
uidt: UITypes.SingleLineText,
...(column?.value || {}),
meta: column?.value?.meta || {},
...clone(column?.value || {}),
})
const additionalValidations = ref<Record<string, any>>({})
// actions
const generateNewColumnMeta = () => {
setAdditionalValidations({})
formState.value = { meta: {}, ...sqlUi.value.getNewColumn((meta.value?.columns?.length || 0) + 1) }
formState.value.title = formState.value.column_name
}
const validators = computed(() => {
return {
@ -77,17 +88,6 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
const { resetFields, validate, validateInfos } = useForm(formState, validators)
const setAdditionalValidations = (validations: Record<string, any>) => {
additionalValidations.value = validations
}
// actions
const generateNewColumnMeta = () => {
setAdditionalValidations({})
formState.value = { meta: {}, ...sqlUi.value.getNewColumn((meta.value?.columns?.length || 0) + 1) }
formState.value.title = formState.value.title || formState.value.column_name
}
const onUidtOrIdTypeChange = () => {
const { isCurrency } = useColumn(ref(formState.value as ColumnType))
@ -118,7 +118,7 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
}
}
if (isCurrency) {
if (isCurrency.value) {
if (column?.value?.uidt === UITypes.Currency) {
formState.value.dtxp = column.value.dtxp
formState.value.dtxs = column.value.dtxs
@ -151,7 +151,7 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
formState.value.dtxp = column?.value.dtxp
}
if (isCurrency) {
if (isCurrency.value) {
if (column?.value?.uidt === UITypes.Currency) {
formState.value.dtxp = column.value.dtxp
formState.value.dtxs = column.value.dtxs
@ -177,6 +177,8 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
console.log(formState, validators)
if (!(await validate())) return
} catch (e) {
console.log(e)
console.trace()
message.error('Form validation failed')
return
}
@ -220,18 +222,18 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
return {
formState,
generateNewColumnMeta,
addOrUpdate,
onAlter,
onDataTypeChange,
onUidtOrIdTypeChange,
setAdditionalValidations,
resetFields,
validate,
validateInfos,
setAdditionalValidations,
onUidtOrIdTypeChange,
sqlUi,
onDataTypeChange,
onAlter,
addOrUpdate,
generateNewColumnMeta,
isEdit: computed(() => !!column?.value?.id),
isEdit,
column,
sqlUi,
}
},
)

1
packages/nc-gui-v2/composables/useViewColumns.ts

@ -41,7 +41,6 @@ export function useViewColumns(
[curr.fk_column_id]: curr,
}
}, {})
fields.value = meta.value?.columns
?.map((column) => {
const currentColumnField = fieldById[column.id!] || {}

3
packages/nc-gui-v2/context/index.ts

@ -22,6 +22,5 @@ export const ReadonlyInj: InjectionKey<any> = Symbol('readonly-injection')
export const ReloadViewDataHookInj: InjectionKey<EventHook<void>> = Symbol('reload-view-data-injection')
export const FieldsInj: InjectionKey<Ref<any[]>> = Symbol('fields-injection')
export const ViewListInj: InjectionKey<Ref<ViewType[]>> = Symbol('view-list-injection')
export const RightSidebarInj: InjectionKey<Ref<boolean>> = Symbol('right-sidebar-injection')
export const EditModeInj: InjectionKey<ComputedRef<boolean>> = Symbol('edit-mode-injection')
export const EditModeInj: InjectionKey<Ref<boolean>> = Symbol('edit-mode-injection')

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

@ -18,6 +18,7 @@
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"jsep": "^1.3.6",
"just-clone": "^6.1.1",
"jwt-decode": "^3.1.2",
"locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0",

8
packages/nc-gui-v2/pages/[projectType]/[projectId]/index/index.vue

@ -3,7 +3,7 @@ import type { TabItem } from '~/composables'
import { TabType } from '~/composables'
import { TabMetaInj } from '~/context'
import { useTabs, useUIPermission } from '#imports'
import MdiPlusIcon from '~icons/mdi/plus'
import MdiPlusBoxOutline from '~icons/mdi/plus-box-outline'
import MdiTableIcon from '~icons/mdi/table'
import MdiCsvIcon from '~icons/mdi/file-document-outline'
import MdiExcelIcon from '~icons/mdi/file-excel'
@ -61,7 +61,7 @@ const icon = (tab: TabItem) => {
<a-sub-menu key="addORImport">
<template #title>
<div class="text-sm flex items-center gap-2 pt-[8px] pb-3">
<MdiPlusIcon />
<MdiPlusBoxOutline />
Add / Import
</div>
</template>
@ -144,7 +144,7 @@ const icon = (tab: TabItem) => {
</template>
</a-tabs>
</div>
<div class="w-full min-h-[300px] grow">
<div class="w-full min-h-[300px] flex-grow">
<NuxtPage />
</div>
</div>
@ -174,7 +174,7 @@ const icon = (tab: TabItem) => {
@apply font-weight-medium;
}
& > .ant-tabs-tab:not(.ant-tabs-tab-active) {
@apply bg-gray-100;
@apply bg-gray-100 text-gray-500;
}
}
}

Loading…
Cancel
Save