@ -186,6 +186,8 @@ const focusLabel = ref<HTMLTextAreaElement>()
const searchQuery = ref ( '' )
const searchQuery = ref ( '' )
const autoScrollFormField = ref ( false )
const { t } = useI18n ( )
const { t } = useI18n ( )
const { betaFeatureToggleState } = useBetaFeatureToggle ( )
const { betaFeatureToggleState } = useBetaFeatureToggle ( )
@ -444,7 +446,7 @@ function setFormData() {
localColumns . value = col
localColumns . value = col
. filter ( ( f ) => ! hiddenColTypes . includes ( f . uidt ) && ! systemFieldsIds . value . includes ( f . fk _column _id ) )
. filter ( ( f ) => ! hiddenColTypes . includes ( f . uidt ) && ! systemFieldsIds . value . includes ( f . fk _column _id ) )
. sort ( ( a , b ) => a . order - b . order )
. sort ( ( a , b ) => a . order - b . order )
. map ( ( c ) => ( { ... c , label : c . label || c . title , required : ! ! c . required } ) )
. map ( ( c ) => ( { ... c , required : ! ! c . required } ) )
}
}
function isRequired ( _columnObj : Record < string , any > , required = false ) {
function isRequired ( _columnObj : Record < string , any > , required = false ) {
@ -519,9 +521,13 @@ const columnSupportsScanning = (elementType: UITypes) =>
betaFeatureToggleState . show &&
betaFeatureToggleState . show &&
[ UITypes . SingleLineText , UITypes . Number , UITypes . Email , UITypes . URL , UITypes . LongText ] . includes ( elementType )
[ UITypes . SingleLineText , UITypes . Number , UITypes . Email , UITypes . URL , UITypes . LongText ] . includes ( elementType )
const onFormItemClick = ( element : any ) => {
const onFormItemClick = ( element : any , sidebarClick : boolean = false ) => {
if ( isLocked . value || ! isEditable ) return
if ( isLocked . value || ! isEditable ) return
if ( sidebarClick ) {
autoScrollFormField . value = true
}
activeRow . value = element . id
activeRow . value = element . id
}
}
@ -643,6 +649,16 @@ const onFocusActiveFieldLabel = (e: FocusEvent) => {
; ( e . target as HTMLTextAreaElement ) . select ( )
; ( e . target as HTMLTextAreaElement ) . select ( )
}
}
const updateFieldTitle = ( value : string ) => {
if ( ! activeField . value ) return
if ( activeField . value . title === value ) {
activeField . value . label = null
} else {
activeField . value . label = value
}
}
const updateSelectFieldLayout = ( value : boolean ) => {
const updateSelectFieldLayout = ( value : boolean ) => {
if ( ! activeField . value ) return
if ( ! activeField . value ) return
@ -702,9 +718,10 @@ watch(
} ,
} ,
)
)
watch ( activeField , ( newValue ) => {
const handleAutoScrollFormField = ( title : string , isSidebar : boolean ) => {
if ( newValue ) {
const field = document . querySelector (
const field = document . querySelector ( ` .nc-form-field-item- ${ CSS . escape ( newValue ? . title ? . replaceAll ( ' ' , '' ) ) } ` )
` ${ isSidebar ? '.nc-form-field-item-' : '.nc-form-drag-' } ${ CSS . escape ( title ? . replaceAll ( ' ' , '' ) ) } ` ,
)
if ( field ) {
if ( field ) {
setTimeout ( ( ) => {
setTimeout ( ( ) => {
@ -713,6 +730,19 @@ watch(activeField, (newValue) => {
}
}
}
}
watch ( activeField , ( newValue , oldValue ) => {
if ( newValue && autoScrollFormField . value ) {
nextTick ( ( ) => {
handleAutoScrollFormField ( newValue . title , false )
} )
} else if ( oldValue ) {
nextTick ( ( ) => {
handleAutoScrollFormField ( oldValue . title , true )
} )
}
autoScrollFormField . value = false
dropdownStates . value = {
dropdownStates . value = {
... dropdownStates . value ,
... dropdownStates . value ,
showColumnMenu : false ,
showColumnMenu : false ,
@ -756,10 +786,11 @@ useEventListener(
document ,
document ,
'mousedown' ,
'mousedown' ,
( e : MouseEvent ) => {
( e : MouseEvent ) => {
console . log ( 'e.target' , e . target )
if (
if (
( draggableRef . value ? . targetDomElement && draggableRef . value ? . targetDomElement . contains ( e . target ) ) ||
( draggableRef . value ? . targetDomElement && draggableRef . value ? . targetDomElement . contains ( e . target ) ) ||
( e . target as HTMLElement ) ? . closest (
( e . target as HTMLElement ) ? . closest (
'.nc-form-right-panel, [class*="dropdown"], .nc-form-rich-text-field, .ant-modal, .ant-modal-wrap, .nc-share-base-button' ,
'.nc-form-right-panel, [class*="dropdown"], .nc-form-rich-text-field, .ant-modal, .ant-modal-wrap, .nc-share-base-button, .nc-form-right-sidebar-content-resizable-wrapper .splitpanes__splitter ' ,
)
)
) {
) {
return
return
@ -1360,7 +1391,7 @@ useEventListener(
< a -textarea
< a -textarea
ref = "focusLabel"
ref = "focusLabel"
v - model : value = "activeField.label"
: value = "activeField.label || activeField.title "
: rows = "1"
: rows = "1"
auto - size
auto - size
hide - details
hide - details
@ -1369,6 +1400,7 @@ useEventListener(
: placeholder = "$t('msg.info.formInput')"
: placeholder = "$t('msg.info.formInput')"
@ focus = "onFocusActiveFieldLabel"
@ focus = "onFocusActiveFieldLabel"
@ keydown . enter . prevent
@ keydown . enter . prevent
@ update : value = "updateFieldTitle"
@ change = "updateColMeta(activeField)"
@ change = "updateColMeta(activeField)"
/ >
/ >
@ -1427,26 +1459,29 @@ useEventListener(
< / div >
< / div >
<!-- Limit options -- >
<!-- Limit options -- >
< div v-if ="isSelectTypeCol(activeField.uidt)" class="flex items-start justify-between gap-3" >
< div v-if ="isSelectTypeCol(activeField.uidt)" class="w-full flex items-start justify-between gap-3" >
< div class = "flex items-center gap-3" >
< div class = "flex-1 max-w-[calc(100%_-_40px)]" >
< div class = "flex-1" >
< div class = "font-medium text-gray-800" > { { $t ( 'labels.limitOptions' ) } } < / div >
< div class = "font-medium text-gray-800" > { { $t ( 'labels.limitOptions' ) } } < / div >
< div class = "text-gray-500 mt-2" > { { $t ( 'labels.limitOptionsSubtext' ) } } . < / div >
< div class = "text-gray-500 mt-2" > { { $t ( 'labels.limitOptionsSubtext' ) } } . < / div >
< div v-if ="activeField.meta.isLimitOption" class="mt-3" >
< div v-if ="activeField.meta.isLimitOption" class="mt-3" >
< LazySmartsheetFormLimitOptions
< LazySmartsheetFormLimitOptions
v - model : model - value = "activeField.meta.limitOptions"
v - model : model - value = "activeField.meta.limitOptions"
: form - field - state = "formState[activeField.title] || ''"
: column = "activeField"
: column = "activeField"
: is - required = "isRequired(activeField, activeField.required)"
: is - required = "isRequired(activeField, activeField.required)"
@ update : model - value = "updateColMeta(activeField)"
@ update : model - value = "updateColMeta(activeField)"
@ update : form - field - state = " ( value ) => {
formState [ activeField ! . title ] = value
} "
> < / LazySmartsheetFormLimitOptions >
> < / LazySmartsheetFormLimitOptions >
< / div >
< / div >
< / div >
< / div >
< / div >
< a -switch
< a -switch
v - model : checked = "activeField.meta.isLimitOption"
v - model : checked = "activeField.meta.isLimitOption"
v - e = "['a:form-view:field:limit-options']"
v - e = "['a:form-view:field:limit-options']"
size = "small"
size = "small"
class = "nc-form-switch-focus"
class = "flex-none nc-form-switch-focus"
@ change = "updateColMeta(activeField)"
@ change = "updateColMeta(activeField)"
/ >
/ >
< / div >
< / div >
@ -1581,21 +1616,26 @@ useEventListener(
< div
< div
v - if = "field.title.toLowerCase().includes(searchQuery.toLowerCase())"
v - if = "field.title.toLowerCase().includes(searchQuery.toLowerCase())"
: key = "field.id"
: key = "field.id"
class = "w-full px-2 py-1.5 flex flex-row items-center border-b-1 last:border-none border-gray-200"
class = "w-full px-2 flex flex-row items-center border-b-1 last:border-none border-gray-200"
: class = " [
: class = " [
` nc-form-field-item- ${ field . title . replaceAll ( ' ' , '' ) } ` ,
` nc-form-field-item- ${ field . title . replaceAll ( ' ' , '' ) } ` ,
` ${ activeRow === field . id ? 'bg-brand-50 font-medium' : 'hover:bg-gray-50' } ` ,
` ${ activeRow === field . id ? 'bg-brand-50 font-medium' : 'hover:bg-gray-50' } ` ,
] "
] "
: data - testid = "`nc-form-field-item-${field.title}`"
: data - testid = "`nc-form-field-item-${field.title}`"
>
>
< div class = "py-1.5 flex items-center" >
< component :is ="iconMap.drag" class = "flex-none cursor-move !h-4 !w-4 text-gray-600 mr-1" / >
< component :is ="iconMap.drag" class = "flex-none cursor-move !h-4 !w-4 text-gray-600 mr-1" / >
< / div >
< div
class = "flex-1 flex items-center justify-between cursor-pointer max-w-[calc(100%_-_20px)] py-1.5"
>
< div
< div
class = "flex-1 flex items-center justify-between cursor-pointer max-w-[calc(100%_-_20px)]"
class = "flex-1 flex items-center cursor-pointer max-w-[calc(100%_-_4 0px)]"
@ click = "showOrHideColumn(field, !field.show, true)"
@ click . prevent = "onFormItemClick(field , true)"
>
>
< SmartsheetHeaderVirtualCellIcon v -if = " field & & isVirtualCol ( field ) " :column-meta ="field" / >
< SmartsheetHeaderVirtualCellIcon v -if = " field & & isVirtualCol ( field ) " :column-meta ="field" / >
< SmartsheetHeaderCellIcon v -else :column-meta ="field" / >
< SmartsheetHeaderCellIcon v -else :column-meta ="field" / >
< div class = "flex-1 flex items-center justify-start max-w-[calc(100%_-_68px)] mr-4 " >
< div class = "flex-1 flex items-center justify-start max-w-[calc(100%_-_28px)] " >
< div class = "w-full flex items-center" >
< div class = "w-full flex items-center" >
< div class = "ml-1 inline-flex" : class = "field.label?.trim() ? 'max-w-1/2' : 'max-w-[95%]'" >
< div class = "ml-1 inline-flex" : class = "field.label?.trim() ? 'max-w-1/2' : 'max-w-[95%]'" >
< NcTooltip class = "truncate text-sm" :disabled ="drag" show -on -truncate -only >
< NcTooltip class = "truncate text-sm" :disabled ="drag" show -on -truncate -only >
@ -1627,11 +1667,18 @@ useEventListener(
>
>
< / div >
< / div >
< / div >
< / div >
< / div >
< a -switch
< a -switch
: checked = "!!field.show"
: checked = "!!field.show"
: disabled = "field.required || isLocked || !isEditable"
: disabled = "field.required || isLocked || !isEditable"
class = "nc-switch"
class = "flex-none nc-switch"
size = "small"
size = "small"
@ change = "
( value ) => {
showOrHideColumn ( field , value , true )
}
"
/ >
/ >
< / div >
< / div >
< / div >
< / div >