'use client' import type { ReactNode } from 'react' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Input } from '@langgenius/dify-ui/input' import { useAtomValue } from 'jotai' import { debounce, useQueryState } from 'nuqs' import { useTranslation } from 'react-i18next' import { StudioListHeader } from '@/app/components/apps/studio-list-header' import { SkeletonRectangle } from '@/app/components/base/skeleton' import { DeploymentEmptyState, DeploymentStateMessage } from '../../shared/components/empty-state' import { useInfiniteScroll } from '../../shared/hooks/use-infinite-scroll' import { deploymentsListErrorAtom, deploymentsListFetchNextPageAtom, deploymentsListHasFilterAtom, deploymentsListHasNextPageAtom, deploymentsListIsFetchingAtom, deploymentsListIsFetchingNextPageAtom, deploymentsListIsLoadingAtom, deploymentsListRowsAtom, deploymentsListShowEmptyStateAtom, deploymentsListShowErrorStateAtom, deploymentsListShowSkeletonAtom, envFilterQueryState, keywordsQueryState, } from '../state' import { CreateDeploymentButton } from './create-deployment-button' import { EnvironmentFilter } from './environment-filter' import { InstanceCard } from './instance-card' const INSTANCE_CARD_SKELETON_KEYS = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'] function DeploymentsListState({ children }: { children: ReactNode }) { return {children} } function DeploymentsListEmpty() { const { t } = useTranslation('deployments') const hasFilter = useAtomValue(deploymentsListHasFilterAtom) const [_keywords, setKeywords] = useQueryState('keywords', keywordsQueryState) const [_envFilter, setEnvFilter] = useQueryState('env', envFilterQueryState) function clearFilters() { void setKeywords(null) void setEnvFilter(null) } return ( $['list.emptyFilteredTitle']) : t(($) => $['list.emptyTitle'])} description={ hasFilter ? t(($) => $['list.emptyFilteredDescription']) : t(($) => $['list.emptyDescription']) } action={ hasFilter ? ( {t(($) => $['list.clearFilters'])} ) : ( ) } /> ) } function InstanceCardSkeleton() { return ( ) } function DeploymentsListSkeleton() { return INSTANCE_CARD_SKELETON_KEYS.map((key) => ) } function DeploymentsSearchInput({ className }: { className?: string }) { const { t } = useTranslation('deployments') const [keywords, setKeywords] = useQueryState('keywords', keywordsQueryState) function handleKeywordsChange(next: string) { void setKeywords(next.trim() ? next : null, { limitUrlUpdates: next.trim() ? debounce(300) : undefined, shallow: false, }) } return ( $['filter.searchPlaceholder'])} placeholder={t(($) => $['filter.searchPlaceholder'])} value={keywords} onChange={(e) => handleKeywordsChange(e.target.value)} /> {keywords && ( $['list.clearSearch'])} className="absolute top-1/2 right-2.5 flex size-4 -translate-y-1/2 items-center justify-center text-text-quaternary hover:text-text-secondary" onClick={() => handleKeywordsChange('')} > )} ) } function DeploymentsListControls() { const { t } = useTranslation() return ( {t(($) => $['menus.deployments'], { ns: 'common' })} } > ) } export function DeploymentsListShell() { const { t } = useTranslation('deployments') const deploymentsListError = useAtomValue(deploymentsListErrorAtom) const deploymentsListFetchNextPage = useAtomValue(deploymentsListFetchNextPageAtom) const deploymentsListHasNextPage = useAtomValue(deploymentsListHasNextPageAtom) const deploymentsListIsFetching = useAtomValue(deploymentsListIsFetchingAtom) const deploymentsListIsFetchingNextPage = useAtomValue(deploymentsListIsFetchingNextPageAtom) const deploymentsListIsLoading = useAtomValue(deploymentsListIsLoadingAtom) const appInstanceSummaries = useAtomValue(deploymentsListRowsAtom) const showSkeleton = useAtomValue(deploymentsListShowSkeletonAtom) const showErrorState = useAtomValue(deploymentsListShowErrorStateAtom) const showEmptyState = useAtomValue(deploymentsListShowEmptyStateAtom) const { rootRef, sentinelRef } = useInfiniteScroll({ error: deploymentsListError, fetchNextPage: deploymentsListFetchNextPage, hasNextPage: deploymentsListHasNextPage, isFetching: deploymentsListIsFetching, isFetchingNextPage: deploymentsListIsFetchingNextPage, isLoading: deploymentsListIsLoading, }) return ( {showSkeleton ? ( ) : showErrorState ? ( {t(($) => $['common.loadFailed'])} ) : showEmptyState ? ( ) : ( appInstanceSummaries.map((summary) => ( )) )} {deploymentsListIsFetchingNextPage && } ) }