@ -3,7 +3,7 @@ import type { ComponentPublicInstance } from '@vue/runtime-core'
import type { Form as AntForm , SelectProps } from 'ant-design-vue'
import { capitalize } from '@vue/runtime-core'
import type { FormType , GalleryType , GridType , KanbanType , MapType , TableType } from 'nocodb-sdk'
import { UITypes , ViewTypes } from 'nocodb-sdk'
import { UITypes , ViewTypes , isSystemColumn } from 'nocodb-sdk'
import { computed , message , nextTick , onBeforeMount , reactive , ref , useApi , useI18n , useVModel , watch } from '#imports'
interface Props {
@ -28,6 +28,10 @@ interface Form {
/ / f o r k a n b a n v i e w o n l y
fk _grp _col _id : string | null
fk _geo _data _col _id : string | null
/ / f o r c a l e n d a r v i e w o n l y
fk _from _col _id : string | null
fk _to _col _id : string | null / / F o r E E o n l y
}
const props = withDefaults ( defineProps < Props > ( ) , {
@ -62,12 +66,22 @@ const isViewCreating = ref(false)
const views = computed ( ( ) => viewsByTable . value . get ( tableId . value ) ? ? [ ] )
const isNecessaryColumnsPresent = ref ( true )
const errorMessages = {
[ ViewTypes . KANBAN ] : t ( 'msg.warning.kanbanNoFields' ) ,
[ ViewTypes . MAP ] : t ( 'msg.warning.mapNoFields' ) ,
[ ViewTypes . CALENDAR ] : t ( 'msg.warning.calendarNoFields' ) ,
}
const form = reactive < Form > ( {
title : props . title || '' ,
type : props . type ,
copy _from _id : null ,
fk _grp _col _id : null ,
fk _geo _data _col _id : null ,
fk _from _col _id : null ,
fk _to _col _id : null ,
} )
const viewSelectFieldOptions = ref < SelectProps [ ' options ' ] > ( [ ] )
@ -97,6 +111,7 @@ const typeAlias = computed(
[ ViewTypes . FORM ] : 'form' ,
[ ViewTypes . KANBAN ] : 'kanban' ,
[ ViewTypes . MAP ] : 'map' ,
[ ViewTypes . CALENDAR ] : 'calendar' ,
} [ props . type ] ) ,
)
@ -163,6 +178,15 @@ async function onSubmit() {
break
case ViewTypes . MAP :
data = await api . dbView . mapCreate ( tableId . value , form )
break
case ViewTypes . CALENDAR :
data = {
base _id : meta . value ? . base _id ,
source _id : meta . value ? . source _id ,
}
/ / T O D O : i m p l e m e n t a p i c a l l
/ / d a t a = a w a i t a p i . d b V i e w . c a l e n d a r C r e a t e ( t a b l e I d . v a l u e , f o r m )
break
}
if ( data ) {
@ -188,7 +212,7 @@ async function onSubmit() {
const isMetaLoading = ref ( false )
onMounted ( async ( ) => {
if ( props . type === ViewTypes . KANBAN || props . type === ViewTypes . MAP ) {
if ( props . type === ViewTypes . KANBAN || props . type === ViewTypes . MAP || props . type === ViewTypes . CALENDAR ) {
isMetaLoading . value = true
try {
meta . value = ( await getMeta ( tableId . value ) ) !
@ -206,9 +230,12 @@ onMounted(async () => {
if ( geoDataFieldColumnId . value ) {
/ / t a k e f r o m t h e o n e f r o m c o p y v i e w
form . fk _geo _data _col _id = geoDataFieldColumnId . value
} else {
/ / t a k e t h e f i r s t o p t i o n
} else if ( viewSelectFieldOptions . value ? . length ) {
/ / i f t h e r e i s g e o d a t a c o l u m n t a k e t h e f i r s t o p t i o n
form . fk _geo _data _col _id = viewSelectFieldOptions . value ? . [ 0 ] ? . value as string
} else {
/ / i f t h e r e i s n o g e o d a t a c o l u m n , d i s a b l e t h e c r e a t e b u t t o n
isNecessaryColumnsPresent . value = false
}
}
@ -226,9 +253,32 @@ onMounted(async () => {
if ( groupingFieldColumnId . value ) {
/ / t a k e f r o m t h e o n e f r o m c o p y v i e w
form . fk _grp _col _id = groupingFieldColumnId . value
} else if ( viewSelectFieldOptions . value ? . length ) {
/ / t a k e t h e f i r s t o p t i o n
form . fk _grp _col _id = viewSelectFieldOptions . value [ 0 ] . value as string
} else {
/ / i f t h e r e i s n o g r o u p i n g f i e l d c o l u m n , d i s a b l e t h e c r e a t e b u t t o n
isNecessaryColumnsPresent . value = false
}
}
if ( props . type === ViewTypes . CALENDAR ) {
console . log ( meta )
viewSelectFieldOptions . value = meta
. value ! . columns ! . filter ( ( el ) => el . uidt === UITypes . Date || ( el . uidt === UITypes . DateTime && ! isSystemColumn ( el ) ) )
. map ( ( field ) => {
return {
value : field . id ,
label : field . title ,
}
} )
if ( viewSelectFieldOptions . value ? . length ) {
/ / t a k e t h e f i r s t o p t i o n
form . fk _grp _col _id = viewSelectFieldOptions . value ? . [ 0 ] ? . value as string
form . fk _from _col _id = viewSelectFieldOptions . value [ 0 ] . value as string
} else {
/ / i f t h e r e i s n o g r o u p i n g f i e l d c o l u m n , d i s a b l e t h e c r e a t e b u t t o n
isNecessaryColumnsPresent . value = false
}
}
} catch ( e ) {
@ -241,7 +291,10 @@ onMounted(async () => {
< / script >
< template >
< NcModal v -model :visible ="vModel" size = "small" >
< NcModal
v - model : visible = "vModel"
: size = "[ViewTypes.KANBAN, ViewTypes.MAP, ViewTypes.CALENDAR].includes(form.type) ? 'medium' : 'small'"
>
< template # header >
< div class = "flex flex-row items-center gap-x-1.5" >
< GeneralViewIcon : meta = "{ type: form.type }" class = "nc-view-icon !text-xl" / >
@ -277,6 +330,14 @@ onMounted(async () => {
{ { $t ( 'labels.createKanbanView' ) } }
< / template >
< / template >
< template v -else -if = " form.type = = = ViewTypes.CALENDAR " >
< template v-if ="form.copy_from_id" >
{ { $t ( 'labels.duplicateCalendarView' ) } }
< / template >
< template v-else >
{ { $t ( 'labels.createCalendarView' ) } }
< / template >
< / template >
< template v-else >
< template v-if ="form.copy_from_id" >
{ { $t ( 'labels.duplicateMapView' ) } }
@ -288,12 +349,12 @@ onMounted(async () => {
< / div >
< / template >
< div class = "mt-2" >
< a -form ref = "formValidator" layout = "vertical" :model ="form" >
< a -form -item name = "title" :rules ="viewNameRules" >
< a -form v-if ="isNecessaryColumnsPresent" ref="formValidator" layout="vertical" :model ="form" >
< a -form -item name = "title" :rules ="viewNameRules" label = "View Name" >
< a -input
ref = "inputEl"
v - model : value = "form.title"
class = "nc-input-md"
class = "nc-input-md h-10 "
autofocus
: placeholder = "$t('labels.viewName')"
@ keydown . enter = "onSubmit"
@ -331,7 +392,41 @@ onMounted(async () => {
: not - found - content = "$t('placeholder.selectGeoFieldNotFound')"
/ >
< / a - f o r m - i t e m >
< div v-if ="form.type === ViewTypes.CALENDAR" class="flex w-full gap-3" >
< div class = "flex flex-col w-1/2" >
< span >
{ { $t ( 'labels.selectDateField' ) } }
< / span >
< NcSelect
: value = "form.fk_from_col_id"
class = "w-full"
: disabled = "isMetaLoading"
: loading = "isMetaLoading"
: options = "viewSelectFieldOptions"
/ >
< / div >
< div v-if ="isEeUI" class="flex flex-col w-1/2" >
< span >
{ { $t ( 'labels.selectEndDateField' ) } }
< / span >
< NcSelect
: value = "form.fk_to_col_id"
class = "w-full"
: disabled = "isMetaLoading"
: loading = "isMetaLoading"
: options = "viewSelectFieldOptions"
: placeholder = "$t('placeholder.notSelected')"
/ >
< / div >
< / div >
< / a - f o r m >
< div v -else -if = " ! isNecessaryColumnsPresent " class = "flex flex-row p-4 border-gray-200 border-1 gap-x-4 rounded-lg w-full" >
< GeneralIcon icon = "warning" class = "!text-5xl text-orange-500" / >
< div class = "text-gray-500" >
< h2 class = "font-semibold text-sm text-gray-800" > Suitable fields not present < / h2 >
{ { errorMessages [ form . type ] } }
< / div >
< / div >
< div class = "flex flex-row w-full justify-end gap-x-2 mt-7" >
< NcButton type = "secondary" @ click = "vModel = false" >
@ -341,6 +436,7 @@ onMounted(async () => {
< NcButton
v - e = "[form.copy_from_id ? 'a:view:duplicate' : 'a:view:create']"
type = "primary"
: disabled = "!isNecessaryColumnsPresent"
: loading = "isViewCreating"
@ click = "onSubmit"
>
@ -351,3 +447,12 @@ onMounted(async () => {
< / div >
< / NcModal >
< / template >
< style lang = "scss" >
. ant - form - item - required {
@ apply ! text - gray - 800 font - medium ;
& : before {
@ apply ! content - [ '' ] ;
}
}
< / style >