import type { ApiBasedExtensionResponse } from '@dify/contracts/api/console/api-based-extension/types.gen'
import type { ReactNode } from 'react'
import { Button } from '@langgenius/dify-ui/button'
import { useQuery } from '@tanstack/react-query'
import { useAtomValue } from 'jotai'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { SearchInput } from '@/app/components/base/search-input'
import { SkeletonContainer, SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton'
import { STEP_BY_STEP_TOUR_TARGETS } from '@/app/components/step-by-step-tour/target-registry'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { consoleQuery } from '@/service/client'
import { hasPermission } from '@/utils/permission'
import { Empty } from './empty'
import { Item } from './item'
import { ApiBasedExtensionModal } from './modal'
type ApiBasedExtensionDialogState =
| {
mode: 'create'
}
| {
mode: 'edit'
apiBasedExtension: ApiBasedExtensionResponse
}
| null
type ApiBasedExtensionPageProps = {
layout?: (parts: { body: ReactNode; toolbar: ReactNode }) => ReactNode
}
function ApiBasedExtensionListSkeleton() {
const { t } = useTranslation()
return (
$.loading, { ns: 'common' })} className="space-y-2">
{Array.from({ length: 2 }, (_, index) => (
))}
)
}
export function ApiBasedExtensionPage({ layout }: ApiBasedExtensionPageProps = {}) {
const { t } = useTranslation()
const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
const canManage = hasPermission(workspacePermissionKeys, 'api_extension.manage')
const { data: apiBasedExtensions = [], isPending: isLoading } = useQuery(
consoleQuery.apiBasedExtension.get.queryOptions(),
)
const [dialogState, setDialogState] = useState(null)
const [keywords, setKeywords] = useState('')
const filteredApiBasedExtensions = useMemo(() => {
const query = keywords.trim().toLowerCase()
if (!query) return apiBasedExtensions
return apiBasedExtensions.filter((apiBasedExtension) => {
return (
apiBasedExtension.name.toLowerCase().includes(query) ||
apiBasedExtension.api_endpoint.toLowerCase().includes(query)
)
})
}, [apiBasedExtensions, keywords])
const hasApiBasedExtensions = apiBasedExtensions.length > 0
const hasSearchKeywords = keywords.trim().length > 0
const handleOpenApiBasedExtensionModal = () => {
if (!canManage) return
setDialogState({
mode: 'create',
})
}
const handleEditApiBasedExtension = (apiBasedExtension: ApiBasedExtensionResponse) => {
if (!canManage) return
setDialogState({
mode: 'edit',
apiBasedExtension,
})
}
const handleApiBasedExtensionSaved = () => {
setDialogState(null)
}
const handleApiBasedExtensionModalOpenChange = (open: boolean) => {
if (!open) setDialogState(null)
}
const toolbar = (
)
const body = (
<>
{isLoading && }
{!isLoading && !hasApiBasedExtensions && }
{!isLoading &&
hasApiBasedExtensions &&
hasSearchKeywords &&
!filteredApiBasedExtensions.length && (
{t(($) => $['dataSource.notion.selector.noSearchResult'], { ns: 'common' })}
)}
{!isLoading &&
!!filteredApiBasedExtensions.length &&
filteredApiBasedExtensions.map((item, index) => (
))}
{dialogState?.mode === 'create' && (
)}
{dialogState?.mode === 'edit' && (
)}
>
)
if (layout) return layout({ body, toolbar })
return (
<>
{toolbar}
{body}
>
)
}