Files
nocodb/packages/nc-gui/components/extensions/Market/ExtensionsTab.vue
mertmit 69a29568c7 chore: sync
Signed-off-by: mertmit <mertmit99@gmail.com>
2026-01-10 00:21:02 +03:00

143 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts" setup>
interface Props {
searchQuery: string
isOpen: boolean
}
const props = withDefaults(defineProps<Props>(), {})
const emits = defineEmits(['update:searchQuery', 'update:isOpen'])
const searchQuery = useVModel(props, 'searchQuery', emits)
const isOpen = useVModel(props, 'isOpen', emits)
const { $e } = useNuxtApp()
watchDebounced(
searchQuery,
() => {
if (searchQuery.value) {
$e('c:extensions:marketplace:search')
}
},
{ debounce: 3000 },
)
const { availableExtensions, addExtension, getExtensionAssetsUrl, showExtensionDetails, extensionAccess } = useExtensions()
const { blockAddNewExtension } = useEeConfig()
const filteredAvailableExtensions = computed(() =>
(availableExtensions.value || []).filter(
(ext) =>
ext.title.toLowerCase().includes(searchQuery.value.toLowerCase()?.trim()) ||
ext.subTitle.toLowerCase().includes(searchQuery.value.toLowerCase()?.trim()),
),
)
const onExtensionClick = (extensionId: string) => {
showExtensionDetails(extensionId, 'market')
isOpen.value = false
}
const onAddExtension = (ext: any) => {
addExtension(ext)
isOpen.value = false
}
</script>
<template>
<div class="h-full py-4 overflow-auto nc-scrollbar-thin">
<div class="h-full flex flex-col gap-5 flex-1 pt-2 px-6 w-full mx-auto">
<div class="text-base font-bold text-nc-content-gray">Popular Extensions</div>
<div v-if="searchQuery" class="text-base text-nc-content-gray-subtle">Search result for {{ searchQuery }}</div>
<div
class="pb-2 grid gap-4"
:class="{
'h-full': searchQuery && !filteredAvailableExtensions.length && availableExtensions.length,
'grid-cols-1 md:grid-cols-2 xl:grid-cols-3': !(
searchQuery &&
!filteredAvailableExtensions.length &&
availableExtensions.length
),
}"
>
<template v-for="ext of filteredAvailableExtensions" :key="ext.id">
<div
class="nc-market-extension-item flex items-center gap-3 border-1 rounded-xl p-3 cursor-pointer hover:bg-nc-bg-gray-extralight transition-all"
:data-testid="`nc-extension-${ext.id}`"
@click="onExtensionClick(ext.id)"
>
<div class="h-[56px] w-[56px] overflow-hidden m-auto flex-none">
<img :src="getExtensionAssetsUrl(ext.iconUrl)" alt="icon" class="w-full h-full object-contain" />
</div>
<div class="flex-1 flex flex-grow flex-col gap-2">
<div>
<div class="flex items-center gap-2">
<div class="text-sm font-bold text-nc-content-gray line-clamp-1">
{{ ext.title }}
</div>
<NcBadgeBeta v-if="ext.showAsBeta" />
</div>
<div v-if="ext.publisher?.name" class="mt-0.5 text-xs leading-[18px] text-nc-content-gray-muted line-clamp-1">
Built by {{ ext.publisher.name }}
</div>
</div>
<NcTooltip
:title="ext.subTitle"
show-on-truncate-only
:line-clamp="2"
class="text-small leading-[18px] text-nc-content-gray-subtle line-clamp-2"
>
{{ ext.subTitle }}
</NcTooltip>
</div>
<NcTooltip v-if="!blockAddNewExtension" :disabled="extensionAccess.create">
<template #title>
{{ $t('tooltip.youDoNotHaveSufficientPermissionToAddExtension') }}
</template>
<NcButton
size="small"
type="secondary"
class="flex-none !px-7px"
:disabled="!extensionAccess.create"
@click.stop="onAddExtension(ext)"
>
<div class="flex items-center gap-1 -ml-3px text-small">
<GeneralIcon icon="plus" />
{{ $t('general.add') }}
</div>
</NcButton>
</NcTooltip>
</div>
</template>
<div
v-if="searchQuery && !filteredAvailableExtensions.length && availableExtensions.length"
class="w-full h-full flex items-center justify-center"
>
<div class="pb-6 text-nc-content-gray-muted flex flex-col items-center gap-6 text-center">
<img
src="~assets/img/placeholder/no-search-result-found.png"
class="!w-[164px] flex-none"
alt="No search results found"
/>
{{ $t('title.noResultsMatchedYourSearch') }}
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.nc-market-extension-item {
&:hover {
box-shadow: 0px 4px 8px -2px rgba(var(--rgb-base), 0.08), 0px 2px 4px -2px rgba(var(--rgb-base), 0.04);
}
}
</style>