import type { ReactNode } from 'react'
import { useSuspenseQuery } from '@tanstack/react-query'
import { memo, useCallback, useMemo, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { SearchInput } from '@/app/components/base/search-input'
import { SkeletonContainer, SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton'
import { usePluginsWithLatestVersion } from '@/app/components/plugins/hooks'
import { usePluginSettingsAccess } from '@/app/components/plugins/plugin-page/use-reference-setting'
import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { STEP_BY_STEP_TOUR_TARGETS } from '@/app/components/step-by-step-tour/target-registry'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { useRenderI18nObject } from '@/hooks/use-i18n'
import { useGetDataSourceListAuth, useInvalidDataSourceListAuth } from '@/service/use-datasource'
import { useInvalidDataSourceList } from '@/service/use-pipeline'
import { useInstalledPluginList, useInvalidateInstalledPluginList } from '@/service/use-plugins'
import UpdateSettingDialog from '../update-setting-dialog'
import Card from './card'
import InstallFromMarketplace from './install-from-marketplace'
type DataSourcePageProps = {
layout?: (parts: { body: ReactNode; toolbar: ReactNode }) => ReactNode
onOpenMarketplace?: () => void
stickyToolbar?: boolean
}
function DataSourceCardSkeleton() {
return (
)
}
function DataSourceListSkeleton() {
const { t } = useTranslation()
return (
$.loading, { ns: 'common' })} className="space-y-2">
{Array.from({ length: 2 }, (_, index) => (
))}
)
}
const DataSourcePage = ({ layout, onOpenMarketplace, stickyToolbar }: DataSourcePageProps) => {
const { t } = useTranslation()
const renderI18nObject = useRenderI18nObject()
const [searchText, setSearchText] = useState('')
const { canSetPluginPreferences } = usePluginSettingsAccess()
const { data: enable_marketplace } = useSuspenseQuery({
...systemFeaturesQueryOptions(),
select: (s) => s.enable_marketplace,
})
const { data, isLoading: isDataSourceListLoading } = useGetDataSourceListAuth()
const { data: installedPluginList } = useInstalledPluginList()
const pluginListWithLatestVersion = usePluginsWithLatestVersion(installedPluginList?.plugins)
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const invalidateDataSourceListAuth = useInvalidDataSourceListAuth()
const invalidateDataSourceList = useInvalidDataSourceList()
const dataSources = useMemo(() => data?.result ?? [], [data?.result])
const dataSourcePluginDetails = useMemo(() => {
return pluginListWithLatestVersion.filter(
(plugin) => plugin.declaration.category === PluginCategoryEnum.datasource,
)
}, [pluginListWithLatestVersion])
const filteredDataSources = useMemo(() => {
const normalizedSearchText = searchText.trim().toLowerCase()
if (!normalizedSearchText) return dataSources
return dataSources.filter((item) => {
const searchableText = [
item.name,
item.provider,
item.author,
renderI18nObject(item.label),
renderI18nObject(item.description),
]
.join(' ')
.toLowerCase()
return searchableText.includes(normalizedSearchText)
})
}, [dataSources, renderI18nObject, searchText])
const handlePluginUpdate = useCallback(() => {
invalidateInstalledPluginList()
invalidateDataSourceListAuth()
invalidateDataSourceList()
}, [invalidateDataSourceList, invalidateDataSourceListAuth, invalidateInstalledPluginList])
const toolbar = (
$['operation.search'], { ns: 'common' })}
value={searchText}
onValueChange={setSearchText}
/>
{canSetPluginPreferences && }
)
const body = (
<>
{isDataSourceListLoading && }
{!isDataSourceListLoading && !dataSources.length && (
$['dataSourcePage.notSetUpTitle']}
ns="common"
components={{
highlight: ,
}}
/>
{t(($) => $['dataSourcePage.installFirst'], { ns: 'common' })}
)}
{!isDataSourceListLoading && !!filteredDataSources.length && (
{filteredDataSources.map((item, index) => {
const pluginDetail = dataSourcePluginDetails.find(
(plugin) => plugin.plugin_id === item.plugin_id,
)
return (
)
})}
)}
{!isDataSourceListLoading && enable_marketplace && (
)}
>
)
if (layout)
return {layout({ body, toolbar })}
return (
{toolbar}
{body}
)
}
export default memo(DataSourcePage)