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} ) }