'use client' import type { SourceAppPickerValue } from '../state' import type { App } from '@/types/app' import { cn } from '@langgenius/dify-ui/cn' import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxInputGroup, ComboboxItem, ComboboxItemText, ComboboxList, ComboboxTrigger, } from '@langgenius/dify-ui/combobox' import { useAtomValue, useSetAtom } from 'jotai' import { useState } from 'react' import { useTranslation } from 'react-i18next' import AppIcon from '@/app/components/base/app-icon' import { SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton' import { useInfiniteScroll } from '@/features/deployments/shared/hooks/use-infinite-scroll' import { TitleTooltip } from '../../components/title-tooltip' import { createReleaseSourceAppSearchTextAtom, createReleaseSourceAppsQueryAtom, } from '../state' const SOURCE_APP_PICKER_SKELETON_KEYS = ['first-source-app', 'second-source-app', 'third-source-app'] function sourceAppSearchText(app: App) { return `${app.name} ${app.id}`.toLowerCase() } function SourceAppTrigger({ app }: { app?: SourceAppPickerValue }) { const { t } = useTranslation('deployments') return ( {app && ( )} {app?.name ?? t('createModal.appPickerPlaceholder')} ) } function SourceAppOption({ app }: { app: App }) { return ( {app.name} ( {app.id.slice(0, 8)} ) ) } function SourceAppPickerSkeleton() { return (
{SOURCE_APP_PICKER_SKELETON_KEYS.map(key => ( ))}
) } export function SourceAppPicker({ value, onChange, disabled = false }: { value?: SourceAppPickerValue onChange: (app: App) => void disabled?: boolean }) { const { t } = useTranslation('deployments') const [isShow, setIsShow] = useState(false) const searchText = useAtomValue(createReleaseSourceAppSearchTextAtom) const setSearchText = useSetAtom(createReleaseSourceAppSearchTextAtom) const sourceAppsQuery = useAtomValue(createReleaseSourceAppsQueryAtom) const { data, isLoading, isFetchingNextPage, hasNextPage, } = sourceAppsQuery const { rootRef, sentinelRef } = useInfiniteScroll(sourceAppsQuery, { enabled: isShow && !disabled, rootMargin: '0px 0px 160px 0px', threshold: 0.1, }) const apps = data?.pages.flatMap(page => page.data) ?? [] return ( items={apps} open={!disabled && isShow} inputValue={searchText} onOpenChange={(open) => { setIsShow(disabled ? false : open) }} onInputValueChange={(value) => { if (!disabled) setSearchText(value) }} onValueChange={(app) => { if (disabled) return if (!app) return onChange(app) setIsShow(false) }} itemToStringLabel={(app) => { if (!app) return '' return app.name }} itemToStringValue={(app) => { if (!app) return '' return app.id }} filter={(app, query) => sourceAppSearchText(app).includes(query.toLowerCase())} disabled={disabled} >
{(isLoading || isFetchingNextPage) && apps.length === 0 && } {(app: App) => ( )} {!(isLoading || isFetchingNextPage) && ( {t('createModal.appSearchEmpty')} )} {isFetchingNextPage && apps.length > 0 && (
{t('createModal.loadingApps')}
)} {hasNextPage &&
) }