import type { OnNodeAdd } from '../../types' import type { SnippetListItem as SnippetListItemData } from '@/types/snippet' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { createPreviewCardHandle, PreviewCard, PreviewCardTrigger, } from '@langgenius/dify-ui/preview-card' import { ScrollAreaContent, ScrollAreaRoot, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport, } from '@langgenius/dify-ui/scroll-area' import { useInfiniteScroll } from 'ahooks' import { memo, useCallback, useDeferredValue, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import Loading from '@/app/components/base/loading' import { useInfiniteSnippetList } from '@/service/use-snippets' import { BlockSelectorPreviewCardContent } from '../preview-card' import SnippetDetailCard from './snippet-detail-card' import SnippetEmptyState from './snippet-empty-state' import SnippetListItem from './snippet-list-item' import SnippetTagsFilter from './snippet-tags-filter' import { useInsertSnippet } from './use-insert-snippet' type SnippetsProps = { searchText: string onSearchTextChange?: (searchText: string) => void insertPayload?: Parameters[1] onInserted?: () => void } const LoadingSkeleton = () => { const { t } = useTranslation() return (
$.loading, { ns: 'common' })} className="relative overflow-hidden" >
{['skeleton-1', 'skeleton-2', 'skeleton-3', 'skeleton-4'].map((key, index) => (
))}
) } const Snippets = ({ searchText, onSearchTextChange, insertPayload, onInserted }: SnippetsProps) => { const { t } = useTranslation() const { handleInsertSnippet } = useInsertSnippet() const deferredSearchText = useDeferredValue(searchText) const viewportRef = useRef(null) const [tagIds, setTagIds] = useState([]) const previewCardHandle = useMemo(() => createPreviewCardHandle(), []) const keyword = deferredSearchText.trim() || undefined const { data, isLoading, isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } = useInfiniteSnippetList({ page: 1, limit: 30, keyword, ...(tagIds.length ? { tag_ids: tagIds } : {}), is_published: true, }) const snippets = useMemo(() => { return (data?.pages ?? []).flatMap(({ data }) => data) }, [data?.pages]) const isNoMore = hasNextPage === false const handleSnippetClick = useCallback( async (snippetId: string) => { const inserted = await handleInsertSnippet(snippetId, insertPayload) if (inserted) onInserted?.() }, [handleInsertSnippet, insertPayload, onInserted], ) useInfiniteScroll( async () => { if (!hasNextPage || isFetchingNextPage) return { list: [] } await fetchNextPage() return { list: [] } }, { target: viewportRef, isNoMore: () => isNoMore, reloadDeps: [isNoMore, isFetchingNextPage, keyword, tagIds], }, ) const filter = (
) const content = isLoading || (isFetching && snippets.length === 0) ? ( ) : !snippets.length ? ( ) : ( {snippets.map((item) => { const row = ( handleSnippetClick(item.id)} /> ) return ( ) })} {isFetchingNextPage && (
)}
) return ( <> {filter}
{content}
{({ payload }) => { if (!payload) return null return ( ) }} ) } export default memo(Snippets)