@ -11,6 +11,7 @@ interface Props {
modelValue ? : undefined | Filter [ ]
modelValue ? : undefined | Filter [ ]
webHook ? : boolean
webHook ? : boolean
draftFilter ? : Partial < FilterType >
draftFilter ? : Partial < FilterType >
isOpen ? : boolean
}
}
const props = withDefaults ( defineProps < Props > ( ) , {
const props = withDefaults ( defineProps < Props > ( ) , {
@ -27,6 +28,7 @@ const emit = defineEmits(['update:filtersLength', 'update:draftFilter', 'update:
const excludedFilterColUidt = [ UITypes . QrCode , UITypes . Barcode ]
const excludedFilterColUidt = [ UITypes . QrCode , UITypes . Barcode ]
const draftFilter = useVModel ( props , 'draftFilter' , emit )
const draftFilter = useVModel ( props , 'draftFilter' , emit )
const modelValue = useVModel ( props , 'modelValue' , emit )
const modelValue = useVModel ( props , 'modelValue' , emit )
const { nestedLevel , parentId , autoSave , hookId , showLoading , webHook } = toRefs ( props )
const { nestedLevel , parentId , autoSave , hookId , showLoading , webHook } = toRefs ( props )
@ -386,6 +388,15 @@ watch(
immediate : true ,
immediate : true ,
} ,
} ,
)
)
const addFilterBtnRef = ref ( )
watchEffect ( ( ) => {
if ( props . isOpen && ! nested . value && addFilterBtnRef . value ) {
setTimeout ( ( ) => {
addFilterBtnRef . value ? . $el ? . focus ( )
} , 10 )
}
} )
< / script >
< / script >
< template >
< template >
@ -394,13 +405,63 @@ watch(
: class = " {
: class = " {
'max-h-[max(80vh,500px)] min-w-112 py-2 pl-4' : ! nested ,
'max-h-[max(80vh,500px)] min-w-112 py-2 pl-4' : ! nested ,
'w-full ' : nested ,
'w-full ' : nested ,
'py-4' : ! filters . length ,
} "
} "
>
>
< div v-if ="nested" class="flex w-full items-center mb-2" >
< div :class ="[`nc-filter-logical-op-level-${nestedLevel}`]" > < slot name = "start" > < / slot > < / div >
< div class = "flex-grow" > < / div >
< NcDropdown :trigger ="['hover']" overlay -class -name = " nc -dropdown -filter -group -sub -menu " >
< GeneralIcon icon = "plus" class = "cursor-pointer" / >
< template # overlay >
< NcMenu >
< template v-if ="isEeUI && !isPublic" >
< template v-if ="filtersCount < getPlanLimit(PlanLimitTypes.FILTER_LIMIT)" >
< NcMenuItem @click.stop ="addFilter()" >
< div class = "flex items-center gap-1" >
< component :is ="iconMap.plus" / >
<!-- Add Filter -- >
{ { $t ( 'activity.addFilter' ) } }
< / div >
< / NcMenuItem >
< NcMenuItem v-if ="nestedLevel < 5" @click.stop="addFilterGroup()" >
< div class = "flex items-center gap-1" >
<!-- Add Filter Group -- >
< component :is ="iconMap.plusSquare" / >
{ { $t ( 'activity.addFilterGroup' ) } }
< / div >
< / NcMenuItem >
< / template >
< / template >
< template v-else >
< NcMenuItem @click.stop ="addFilter()" >
< div class = "flex items-center gap-1" >
< component :is ="iconMap.plus" / >
<!-- Add Filter -- >
{ { $t ( 'activity.addFilter' ) } }
< / div >
< / NcMenuItem >
< NcMenuItem v-if ="!webHook && nestedLevel < 5" @click.stop="addFilterGroup()" >
< div class = "flex items-center gap-1" >
<!-- Add Filter Group -- >
< component :is ="iconMap.plusSquare" / >
{ { $t ( 'activity.addFilterGroup' ) } }
< / div >
< / NcMenuItem >
< / template >
< / NcMenu >
< / template >
< / NcDropdown >
< div >
< slot name = "end" > < / slot >
< / div >
< / div >
< div
< div
v - if = "filters && filters.length"
v - if = "filters && filters.length"
ref = "wrapperDomRef"
ref = "wrapperDomRef"
class = "flex flex-col gap-y-3 nc-filter-grid w-full"
class = "flex flex-col gap-y-1.5 nc-filter-grid w-full"
: class = "{ 'max-h-420px nc-scrollbar-thin nc-filter-top-wrapper pr-4 my-2 py-1': !nested }"
: class = "{ 'max-h-420px nc-scrollbar-thin nc-filter-top-wrapper pr-4 my-2 py-1': !nested }"
@ click . stop
@ click . stop
>
>
@ -408,46 +469,7 @@ watch(
< template v-if ="filter.status !== 'delete'" >
< template v-if ="filter.status !== 'delete'" >
< template v-if ="filter.is_group" >
< template v-if ="filter.is_group" >
< div class = "flex flex-col w-full gap-y-2" >
< div class = "flex flex-col w-full gap-y-2" >
< div class = "flex flex-row w-full justify-between items-center" >
< div class = "flex rounded-lg p-2 w-full border-1" :class ="[`nc-filter-nested-level-${nestedLevel}`]" >
< span v-if ="!i" class="flex items-center ml-2" > {{ $ t ( ' labels.where ' ) }} < / span >
< div v -else :key ="`${i}nested`" class = "flex nc-filter-logical-op" >
< NcSelect
v - model : value = "filter.logical_op"
v - e = "['c:filter:logical-op:select']"
: dropdown - match - select - width = "false"
class = "min-w-20 capitalize"
placeholder = "Group op"
dropdown - class - name = "nc-dropdown-filter-logical-op-group"
: disabled = "visibleFilters.indexOf(filter) > 1 && !isLogicalOpChangeAllowed"
@ click . stop
@ change = "onLogicalOpUpdate(filter, i)"
>
< a -select -option v-for ="op in logicalOps" :key="op.value" :value="op.value" >
< div class = "flex items-center w-full justify-between w-full gap-2" >
< div class = "truncate flex-1 capitalize" > { { op . value } } < / div >
< component
: is = "iconMap.check"
v - if = "filter.logical_op === op.value"
id = "nc-selected-item-icon"
class = "text-primary w-4 h-4"
/ >
< / div >
< / a - s e l e c t - o p t i o n >
< / NcSelect >
< / div >
< NcButton
v - if = "!filter.readOnly"
: key = "i"
v - e = "['c:filter:delete']"
type = "text"
size = "small"
class = "nc-filter-item-remove-btn cursor-pointer"
@ click . stop = "deleteFilter(filter, i)"
>
< component :is ="iconMap.deleteListItem" / >
< / NcButton >
< / div >
< div class = "flex border-1 rounded-lg p-2 w-full" : class = "nestedLevel % 2 !== 0 ? 'bg-white' : 'bg-gray-100'" >
< LazySmartsheetToolbarColumnFilter
< LazySmartsheetToolbarColumnFilter
v - if = "filter.id || filter.children || !autoSave"
v - if = "filter.id || filter.children || !autoSave"
: key = "filter.id ?? i"
: key = "filter.id ?? i"
@ -457,22 +479,71 @@ watch(
: parent - id = "filter.id"
: parent - id = "filter.id"
: auto - save = "autoSave"
: auto - save = "autoSave"
: web - hook = "webHook"
: web - hook = "webHook"
/ >
>
< template # start >
< span v-if ="!i" class="flex items-center nc-filter-where-label ml-1" > {{ $ t ( ' labels.where ' ) }} < / span >
< div v -else :key ="`${i}nested`" class = "flex nc-filter-logical-op" >
< NcSelect
v - model : value = "filter.logical_op"
v - e = "['c:filter:logical-op:select']"
: dropdown - match - select - width = "false"
class = "min-w-18 max-w-18 capitalize"
placeholder = "Group op"
dropdown - class - name = "nc-dropdown-filter-logical-op-group"
: disabled = "i > 1 && !isLogicalOpChangeAllowed"
: class = "{ 'nc-disabled-logical-op': filter.readOnly || (i > 1 && !isLogicalOpChangeAllowed) }"
@ click . stop
@ change = "onLogicalOpUpdate(filter, i)"
>
< a -select -option v-for ="op in logicalOps" :key="op.value" :value="op.value" >
< div class = "flex items-center w-full justify-between w-full gap-2" >
< div class = "truncate flex-1 capitalize" > { { op . value } } < / div >
< component
: is = "iconMap.check"
v - if = "filter.logical_op === op.value"
id = "nc-selected-item-icon"
class = "text-primary w-4 h-4"
/ >
< / div >
< / a - s e l e c t - o p t i o n >
< / NcSelect >
< / div >
< / template >
< template # end >
< NcButton
v - if = "!filter.readOnly"
: key = "i"
v - e = "['c:filter:delete']"
type = "text"
size = "small"
class = "nc-filter-item-remove-btn cursor-pointer"
@ click . stop = "deleteFilter(filter, i)"
>
< component :is ="iconMap.deleteListItem" / >
< / NcButton >
< / template >
< / LazySmartsheetToolbarColumnFilter >
< / div >
< / div >
< / div >
< / div >
< / template >
< / template >
< div v -else class = "flex flex-row gap-x-2 w-full" :class ="`nc-filter-wrapper-${filter.fk_column_id}`" >
< span v-if ="!i" class="flex items-center ml-2 mr-7.35" > {{ $ t ( ' labels.where ' ) }} < / span >
< div v -else class = "flex flex-row gap-x-0 w-full nc-filter-wrapper" :class ="`nc-filter-wrapper-${filter.fk_column_id}`" >
< div v-if ="!i" class="flex items-center !min-w-18 !max-w-18 pl-3 nc-filter-where-label" >
{ { $t ( 'labels.where' ) } }
< / div >
< NcSelect
< NcSelect
v - else
v - else
v - model : value = "filter.logical_op"
v - model : value = "filter.logical_op"
v - e = "['c:filter:logical-op:select']"
v - e = "['c:filter:logical-op:select']"
: dropdown - match - select - width = "false"
: dropdown - match - select - width = "false"
class = "h-full !min-w-20 !max-w-20 capitalize"
class = "h-full !min-w-18 !max-w-18 capitalize"
hide - details
hide - details
: disabled = "filter.readOnly || (visibleFilters.indexOf(filter) > 1 && !isLogicalOpChangeAllowed)"
: disabled = "filter.readOnly || (visibleFilters.indexOf(filter) > 1 && !isLogicalOpChangeAllowed)"
dropdown - class - name = "nc-dropdown-filter-logical-op"
dropdown - class - name = "nc-dropdown-filter-logical-op"
: class = " {
'nc-disabled-logical-op' : filter . readOnly || ( visibleFilters . indexOf ( filter ) > 1 && ! isLogicalOpChangeAllowed ) ,
} "
@ change = "onLogicalOpUpdate(filter, i)"
@ change = "onLogicalOpUpdate(filter, i)"
@ click . stop
@ click . stop
>
>
@ -488,6 +559,7 @@ watch(
< / div >
< / div >
< / a - s e l e c t - o p t i o n >
< / a - s e l e c t - o p t i o n >
< / NcSelect >
< / NcSelect >
< SmartsheetToolbarFieldListAutoCompleteDropdown
< SmartsheetToolbarFieldListAutoCompleteDropdown
: key = "`${i}_6`"
: key = "`${i}_6`"
v - model = "filter.fk_column_id"
v - model = "filter.fk_column_id"
@ -497,6 +569,7 @@ watch(
@ click . stop
@ click . stop
@ change = "selectFilterField(filter, i)"
@ change = "selectFilterField(filter, i)"
/ >
/ >
< NcSelect
< NcSelect
v - model : value = "filter.comparison_op"
v - model : value = "filter.comparison_op"
v - e = "['c:filter:comparison-op:select']"
v - e = "['c:filter:comparison-op:select']"
@ -529,6 +602,7 @@ watch(
< / NcSelect >
< / NcSelect >
< div v-if ="['blank', 'notblank'].includes(filter.comparison_op)" class="flex flex-grow" > < / div >
< div v-if ="['blank', 'notblank'].includes(filter.comparison_op)" class="flex flex-grow" > < / div >
< NcSelect
< NcSelect
v - else - if = "isDateType(types[filter.fk_column_id])"
v - else - if = "isDateType(types[filter.fk_column_id])"
v - model : value = "filter.comparison_sub_op"
v - model : value = "filter.comparison_sub_op"
@ -567,6 +641,7 @@ watch(
< / a - s e l e c t - o p t i o n >
< / a - s e l e c t - o p t i o n >
< / template >
< / template >
< / NcSelect >
< / NcSelect >
< a -checkbox
< a -checkbox
v - if = "filter.field && types[filter.field] === 'boolean'"
v - if = "filter.field && types[filter.field] === 'boolean'"
v - model : checked = "filter.value"
v - model : checked = "filter.value"
@ -583,6 +658,7 @@ watch(
@ update - filter - value = "(value) => updateFilterValue(value, filter, i)"
@ update - filter - value = "(value) => updateFilterValue(value, filter, i)"
@ click . stop
@ click . stop
/ >
/ >
< div v -else -if = " ! isDateType ( types [ filter.fk_column_id ] ) " class = "flex-grow" > < / div >
< div v -else -if = " ! isDateType ( types [ filter.fk_column_id ] ) " class = "flex-grow" > < / div >
< NcButton
< NcButton
@ -600,56 +676,64 @@ watch(
< / template >
< / template >
< / div >
< / div >
< template v-if ="isEeUI && !isPublic " >
< template v-if ="!nested " >
< div
< template v-if ="isEeUI && !isPublic" >
v - if = "filtersCount < getPlanLimit(PlanLimitTypes.FILTER_LIMIT)"
< div
ref = "addFiltersRowDomRef "
v - if = "filtersCount < getPlanLimit(PlanLimitTypes.FILTER_LIMIT) "
class = "flex gap-2"
class = "flex gap-2"
: class = " {
: class = " {
'mt-1 mb-2' : filters . length ,
'mt-1 mb-2' : filters . length ,
} "
} "
>
>
< NcButton size = "small" type = "text" class = "!text-brand-500 " @click.stop ="addFilter()" >
< NcButton :ref ="addFilterBtnRef" size = "small" type = "text" class = "nc-btn-focus " @click.stop ="addFilter()" >
< div class = "flex items-center gap-1" >
< div class = "flex items-center gap-1" >
< component :is ="iconMap.plus" / >
< component :is ="iconMap.plus" / >
<!-- Add Filter -- >
<!-- Add Filter -- >
{ { $t ( 'activity.addFilter' ) } }
{ { $t ( 'activity.addFilter' ) } }
< / div >
< / div >
< / NcButton >
< / NcButton >
< NcButton v-if ="nestedLevel < 5" type="text" size="small" @click.stop="addFilterGroup()" >
< NcButton v-if ="nestedLevel < 5" class="nc-btn-focus" type="text" size="small" @click.stop="addFilterGroup()" >
< div class = "flex items-center gap-1" >
< div class = "flex items-center gap-1" >
<!-- Add Filter Group -- >
<!-- Add Filter Group -- >
< component :is ="iconMap.plus" / >
< component :is ="iconMap.plus" / >
{ { $t ( 'activity.addFilterGroup' ) } }
{ { $t ( 'activity.addFilterGroup' ) } }
< / div >
< / div >
< / NcButton >
< / NcButton >
< / div >
< / div >
< / template >
< / template >
< template v-else >
< div
ref = "addFiltersRowDomRef"
class = "flex gap-2"
: class = " {
'mt-1 mb-2' : filters . length ,
} "
>
< NcButton size = "small" type = "text" class = "!text-brand-500" @click.stop ="addFilter()" >
< div class = "flex items-center gap-1" >
< component :is ="iconMap.plus" / >
<!-- Add Filter -- >
{ { $t ( 'activity.addFilter' ) } }
< / div >
< / NcButton >
< NcButton v-if ="!webHook && nestedLevel < 5" type="text" size="small" @click.stop="addFilterGroup()" >
< template v-else >
< div class = "flex items-center gap-1" >
< div
<!-- Add Filter Group -- >
ref = "addFiltersRowDomRef"
< component :is ="iconMap.plus" / >
class = "flex gap-2"
{ { $t ( 'activity.addFilterGroup' ) } }
: class = " {
< / div >
'mt-1 mb-2' : filters . length ,
< / NcButton >
} "
< / div >
>
< NcButton ref = "addFilterBtnRef" class = "nc-btn-focus" size = "small" type = "text" @click.stop ="addFilter()" >
< div class = "flex items-center gap-1" >
< component :is ="iconMap.plus" / >
<!-- Add Filter -- >
{ { $t ( 'activity.addFilter' ) } }
< / div >
< / NcButton >
< NcButton
v - if = "!webHook && nestedLevel < 5"
class = "nc-btn-focus"
type = "text"
size = "small"
@ click . stop = "addFilterGroup()"
>
< div class = "flex items-center gap-1" >
<!-- Add Filter Group -- >
< component :is ="iconMap.plus" / >
{ { $t ( 'activity.addFilterGroup' ) } }
< / div >
< / NcButton >
< / div >
< / template >
< / template >
< / template >
< div
< div
v - if = "!filters.length"
v - if = "!filters.length"
@ -666,7 +750,7 @@ watch(
< / div >
< / div >
< / template >
< / template >
< style scoped >
< style scoped lang = "scss" >
. nc - filter - item - remove - btn {
. nc - filter - item - remove - btn {
@ apply text - gray - 600 hover : text - gray - 800 ;
@ apply text - gray - 600 hover : text - gray - 800 ;
}
}
@ -680,6 +764,112 @@ watch(
}
}
: deep ( . ant - select - selector ) {
: deep ( . ant - select - selector ) {
@ apply ! min - h - 8.25 ;
@ apply ! min - h - 8 ;
}
. nc - disabled - logical - op : deep ( . ant - select - arrow ) {
@ apply hidden ;
}
. nc - filter - wrapper {
@ apply bg - white ! rounded - lg border - 1 px border - [ # E7E7E9 ] ;
& > * {
@ apply ! border - none ;
}
& > * > : deep ( . ant - select - selector ) {
border : none ! important ;
box - shadow : none ! important ;
}
& > : not ( : last - child ) : not ( : empty ) {
border - right : 1 px solid # eee ! important ;
border - bottom - right - radius : 0 ! important ;
border - top - right - radius : 0 ! important ;
}
& > : not ( : first - child ) {
border - bottom - left - radius : 0 ! important ;
border - top - left - radius : 0 ! important ;
}
& > : last - child {
@ apply relative ;
& : : after {
content : '' ;
@ apply absolute h - full w - 1 px bg - [ # eee ] - left - 1 px top - 0 ;
}
}
: deep ( : : placeholder ) {
@ apply text - sm tracking - normal ;
}
: deep ( : : - ms - input - placeholder ) {
@ apply text - sm tracking - normal ;
}
: deep ( input ) {
@ apply text - sm ;
}
: deep ( . nc - select : not ( . nc - disabled - logical - op ) : hover ) {
& ,
. ant - select - selector {
@ apply bg - gray - 50 ;
}
}
}
. nc - filter - nested - level - 0 {
@ apply bg - [ # f9f9fa ] ;
}
. nc - filter - nested - level - 1 ,
. nc - filter - nested - level - 3 {
@ apply bg - gray - [ # f4f4f5 ] ;
}
. nc - filter - nested - level - 2 ,
. nc - filter - nested - level - 4 {
@ apply bg - gray - [ # e7e7e9 ] ;
}
. nc - filter - logical - op - level - 3 ,
. nc - filter - logical - op - level - 5 {
: deep ( . nc - select . ant - select . ant - select - selector ) {
@ apply border - [ # d9d9d9 ] ;
}
}
. nc - filter - where - label {
@ apply text - gray - 400 ;
}
: deep ( . ant - select - disabled . ant - select : not ( . ant - select - customize - input ) . ant - select - selector ) {
@ apply bg - transparent text - gray - 400 ;
}
: deep ( . nc - filter - logical - op . nc - select . ant - select . ant - select - selector ) {
@ apply shadow - none ;
}
: deep ( . nc - select - expand - btn ) {
@ apply text - gray - 500 ;
}
. menu - filter - dropdown {
input : not ( : disabled ) ,
select : not ( : disabled ) ,
. ant - select : not ( . ant - select - disabled ) {
@ apply text - [ # 4 A5268 ] ;
}
}
. nc - filter - input - wrapper : deep ( input ) {
@ apply ! px - 2 ;
}
. nc - btn - focus : focus {
@ apply ! text - brand - 500 ! shadow - none ;
}
}
< / style >
< / style >