ruvector/studio/components/interfaces/Integrations/Landing/useInstalledIntegrations.tsx
rUv 814f595995 feat(studio): Add complete RuVector Studio application
Major additions:
- Complete Next.js studio application with 1600+ components
- Docker support (Dockerfile.combined, docker-compose.yml)
- GCP deployment documentation and benchmarks
- SQL benchmark scripts for performance testing
- Sentry integration for monitoring
- Comprehensive test suite and mocks

Studio features:
- Dashboard and admin interfaces
- Data visualization components
- Authentication and user management
- API integration with RuVector backend
- Static data and public assets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:04:48 +00:00

101 lines
3.5 KiB
TypeScript

import { useMemo } from 'react'
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
import { useSchemasQuery } from 'data/database/schemas-query'
import { useFDWsQuery } from 'data/fdw/fdws-query'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { EMPTY_ARR } from 'lib/void'
import { wrapperMetaComparator } from '../Wrappers/Wrappers.utils'
import { INTEGRATIONS } from './Integrations.constants'
export const useInstalledIntegrations = () => {
const { data: project } = useSelectedProjectQuery()
const { integrationsWrappers } = useIsFeatureEnabled(['integrations:wrappers'])
const allIntegrations = useMemo(() => {
if (integrationsWrappers) {
return INTEGRATIONS
} else {
return INTEGRATIONS.filter((integration) => !integration.id.endsWith('_wrapper'))
}
}, [integrationsWrappers])
const {
data,
error: fdwError,
isError: isErrorFDWs,
isLoading: isFDWLoading,
isSuccess: isSuccessFDWs,
} = useFDWsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const {
data: extensions,
error: extensionsError,
isError: isErrorExtensions,
isLoading: isExtensionsLoading,
isSuccess: isSuccessExtensions,
} = useDatabaseExtensionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const {
data: schemas,
error: schemasError,
isError: isErrorSchemas,
isLoading: isSchemasLoading,
isSuccess: isSuccessSchemas,
} = useSchemasQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const isHooksEnabled = schemas?.some((schema) => schema.name === 'supabase_functions')
const wrappers = useMemo(() => data ?? EMPTY_ARR, [data])
const installedIntegrations = useMemo(() => {
return allIntegrations
.filter((i) => {
// special handling for supabase webhooks
if (i.id === 'webhooks') {
return isHooksEnabled
}
if (i.type === 'wrapper') {
return wrappers.find((w) => wrapperMetaComparator(i.meta, w))
}
if (i.type === 'postgres_extension') {
return i.requiredExtensions.every((extName) => {
const foundExtension = (extensions ?? []).find((ext) => ext.name === extName)
return !!foundExtension?.installed_version
})
}
return false
})
.sort((a, b) => a.name.localeCompare(b.name))
}, [wrappers, extensions, isHooksEnabled])
// available integrations are all integrations that can be installed. If an integration can't be installed (needed
// extensions are not available on this DB image), the UI will provide a tooltip explaining why.
const availableIntegrations = useMemo(
() => allIntegrations.sort((a, b) => a.name.localeCompare(b.name)),
[]
)
const error = fdwError || extensionsError || schemasError
const isLoading = isSchemasLoading || isFDWLoading || isExtensionsLoading
const isError = isErrorFDWs || isErrorExtensions || isErrorSchemas
const isSuccess = isSuccessFDWs && isSuccessExtensions && isSuccessSchemas
return {
// show all integrations at once instead of showing partial results
installedIntegrations: isLoading ? EMPTY_ARR : installedIntegrations,
availableIntegrations: isLoading ? EMPTY_ARR : availableIntegrations,
error,
isError,
isLoading,
isSuccess,
}
}