mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.3 KiB
156 lines
4.3 KiB
<script lang="ts" setup> |
|
import type { ColumnType, TableType } from 'nocodb-sdk' |
|
import { UITypes, isSystemColumn } from 'nocodb-sdk' |
|
|
|
const reloadData = inject(ReloadViewDataHookInj)! |
|
|
|
const { meta } = useSmartsheetStoreOrThrow() |
|
|
|
const activeView = inject(ActiveViewInj, ref()) |
|
|
|
const { search, loadFieldQuery } = useFieldQuery() |
|
|
|
const isDropdownOpen = ref(false) |
|
|
|
const showSearchBox = ref(false) |
|
|
|
const globalSearchRef = ref<HTMLInputElement>() |
|
|
|
const globalSearchWrapperRef = ref<HTMLInputElement>() |
|
|
|
const { isMobileMode } = useGlobal() |
|
|
|
const columns = computed( |
|
() => (meta.value as TableType)?.columns?.filter((column) => !isSystemColumn(column) && column?.uidt !== UITypes.Links) ?? [], |
|
) |
|
|
|
watch( |
|
() => activeView.value?.id, |
|
(n, o) => { |
|
if (n !== o) { |
|
loadFieldQuery(activeView.value?.id) |
|
} |
|
}, |
|
{ immediate: true }, |
|
) |
|
|
|
function onPressEnter() { |
|
reloadData.trigger({ shouldShowLoading: false, offset: 0 }) |
|
} |
|
|
|
const displayColumnLabel = computed(() => { |
|
if (search.value.field) { |
|
// use search field label if specified |
|
return columns.value?.find((column) => column.id === search.value.field)?.title |
|
} |
|
// use primary value label by default |
|
const pvColumn = columns.value?.find((column) => column.pv) |
|
search.value.field = pvColumn?.id as string |
|
return pvColumn?.title |
|
}) |
|
|
|
watchDebounced( |
|
() => search.value.query, |
|
() => { |
|
onPressEnter() |
|
}, |
|
{ |
|
debounce: 500, |
|
maxWait: 600, |
|
}, |
|
) |
|
|
|
const onSelectOption = (column: ColumnType) => { |
|
search.value.field = column.id as string |
|
isDropdownOpen.value = false |
|
} |
|
|
|
const handleShowSearchInput = () => { |
|
showSearchBox.value = true |
|
|
|
nextTick(() => { |
|
globalSearchRef.value?.focus() |
|
}) |
|
} |
|
|
|
onClickOutside(globalSearchWrapperRef, (e) => { |
|
const targetEl = e.target as HTMLElement |
|
if (search.value.query || targetEl.closest('.nc-dropdown-toolbar-search-field-option')) { |
|
return |
|
} |
|
|
|
showSearchBox.value = false |
|
}) |
|
</script> |
|
|
|
<template> |
|
<div ref="globalSearchWrapperRef" class="nc-global-search-wrapper"> |
|
<a-button |
|
v-if="!search.query && !showSearchBox" |
|
class="nc-toolbar-btn" |
|
data-testid="nc-global-search-show-input" |
|
@click="handleShowSearchInput" |
|
> |
|
<GeneralIcon icon="search" class="h-4 w-4 text-gray-700 group-hover:text-black" /> |
|
</a-button> |
|
<div |
|
v-else |
|
class="flex flex-row border-1 rounded-lg h-7 xs:(h-10 ml-0) ml-1 border-gray-200 overflow-hidden focus-within:border-primary" |
|
:class="{ 'border-primary': search.query.length !== 0 }" |
|
> |
|
<NcDropdown |
|
v-model:visible="isDropdownOpen" |
|
:trigger="['click']" |
|
overlay-class-name="nc-dropdown-toolbar-search-field-option" |
|
> |
|
<div |
|
class="flex items-center group px-2 cursor-pointer border-r-1 border-gray-200 hover:bg-gray-100" |
|
:class="{ 'bg-gray-50 ': isDropdownOpen }" |
|
@click="isDropdownOpen = !isDropdownOpen" |
|
> |
|
<GeneralIcon icon="search" class="ml-1 mr-2 h-3.5 w-3.5 text-gray-500 group-hover:text-black" /> |
|
<div v-if="!isMobileMode" class="w-16 text-xs font-medium text-gray-400 truncate"> |
|
{{ displayColumnLabel }} |
|
</div> |
|
<div class="xs:(text-gray-600) group-hover:text-gray-700 sm:(text-gray-400)"> |
|
<component :is="iconMap.arrowDown" class="text-sm text-inherit" /> |
|
</div> |
|
</div> |
|
<template #overlay> |
|
<SmartsheetToolbarFieldListWithSearch |
|
:is-parent-open="isDropdownOpen" |
|
:selected-option-id="search.field" |
|
show-selected-option |
|
:options="columns" |
|
toolbar-menu="globalSearch" |
|
@selected="onSelectOption" |
|
/> |
|
</template> |
|
</NcDropdown> |
|
|
|
<form class="p-0"> |
|
<a-input |
|
v-if="search.query || showSearchBox" |
|
ref="globalSearchRef" |
|
v-model:value="search.query" |
|
name="globalSearchQuery" |
|
size="small" |
|
class="text-xs w-40 h-full" |
|
:placeholder="`${$t('general.searchIn')} ${displayColumnLabel}`" |
|
:bordered="false" |
|
data-testid="search-data-input" |
|
@press-enter="onPressEnter" |
|
> |
|
</a-input> |
|
</form> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
<style scoped> |
|
:deep(input::placeholder) { |
|
@apply !text-gray-400; |
|
line-height: 0.8rem !important; |
|
font-size: 0.8rem !important; |
|
} |
|
</style>
|
|
|