'use client' import type { GuideMethod, WorkflowSourceApp, } from '@/features/deployments/create-guide/state/types' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Input } from '@langgenius/dify-ui/input' import { RadioGroup, RadioItem } from '@langgenius/dify-ui/radio' import { useAtomValue, useSetAtom } from 'jotai' import { useTranslation } from 'react-i18next' import Uploader from '@/app/components/app/create-from-dsl-modal/uploader' import AppIcon from '@/app/components/base/app-icon' import { SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton' import { dslFileAtom, effectiveMethodAtom, sourceSearchTextAtom, } from '@/features/deployments/create-guide/state/primitives' import { unsupportedDslNodesAtom } from '@/features/deployments/create-guide/state/queries' import { dslReadErrorAtom, dslUnsupportedModeAtom, effectiveSelectedAppAtom, isReadingDslAtom, sourceAppsAtom, sourceAppsErrorAtom, sourceAppsFetchNextPageAtom, sourceAppsHasNextPageAtom, sourceAppsIsFetchingAtom, sourceAppsIsFetchingNextPageAtom, sourceAppsIsLoadingAtom, sourceAppsIsPlaceholderDataAtom, } from '@/features/deployments/create-guide/state/source' import { continueFromSourceAtom, selectDslFileAtom, selectMethodAtom, selectSourceAppAtom, setSourceSearchTextAtom, sourceCanGoNextAtom, } from '@/features/deployments/create-guide/state/workflow' import { DeploymentStateMessage } from '@/features/deployments/shared/components/empty-state' import { TitleTooltip } from '@/features/deployments/shared/components/title-tooltip' import { UnsupportedDslNodesAlert } from '@/features/deployments/shared/components/unsupported-dsl-nodes-alert' import { isDeploymentDslImportEnabled } from '@/features/deployments/shared/domain/feature-flags' import { useInfiniteScroll } from '@/features/deployments/shared/hooks/use-infinite-scroll' import { StepShell } from './layout' const sourceAppSkeletonKeys = ['first-source-app', 'second-source-app', 'third-source-app'] export function SourceStepContent() { const method = useAtomValue(effectiveMethodAtom) const unsupportedDslNodes = useAtomValue(unsupportedDslNodesAtom) return (
{method === 'bindApp' && } {method === 'importDsl' && }
) } function SourceMethodSection() { const { t } = useTranslation('deployments') const method = useAtomValue(effectiveMethodAtom) const selectMethod = useSetAtom(selectMethodAtom) return ( $['createGuide.steps.method'])} description={t(($) => $['createGuide.method.description'])} descriptionClassName="lg:hidden" hideHeader > value={method} onValueChange={selectMethod} className="flex flex-col items-stretch gap-2 sm:flex-row" > $['createGuide.methods.bindApp.title'])} description={t(($) => $['createGuide.methods.bindApp.description'])} /> {isDeploymentDslImportEnabled && ( $['createGuide.methods.importDsl.title'])} description={t(($) => $['createGuide.methods.importDsl.description'])} /> )} ) } function SourceMethodCard({ value, icon, title, description, badge, }: { value: GuideMethod icon: string title: string description: string badge?: string }) { return ( value={value} nativeButton render={ )} ) } function SourceAppList() { const { t } = useTranslation('deployments') const selectSourceApp = useSetAtom(selectSourceAppAtom) const effectiveSelectedApp = useAtomValue(effectiveSelectedAppAtom) const sourceApps = useAtomValue(sourceAppsAtom) const sourceAppsError = useAtomValue(sourceAppsErrorAtom) const sourceAppsFetchNextPage = useAtomValue(sourceAppsFetchNextPageAtom) const sourceAppsHasNextPage = useAtomValue(sourceAppsHasNextPageAtom) const sourceAppsIsFetching = useAtomValue(sourceAppsIsFetchingAtom) const sourceAppsIsFetchingNextPage = useAtomValue(sourceAppsIsFetchingNextPageAtom) const sourceAppsIsLoading = useAtomValue(sourceAppsIsLoadingAtom) const sourceAppsIsPlaceholderData = useAtomValue(sourceAppsIsPlaceholderDataAtom) const sourceAppsLoading = sourceAppsIsLoading || sourceAppsIsPlaceholderData || (sourceAppsIsFetching && sourceApps.length === 0) const { rootRef, sentinelRef } = useInfiniteScroll( { error: sourceAppsError, fetchNextPage: sourceAppsFetchNextPage, hasNextPage: sourceAppsHasNextPage, isFetching: sourceAppsIsFetching, isFetchingNextPage: sourceAppsIsFetchingNextPage, isLoading: sourceAppsIsLoading, }, { enabled: !sourceAppsLoading, rootMargin: '0px 0px 160px 0px', threshold: 0.1, }, ) return (
{sourceAppsLoading ? ( ) : sourceApps.length === 0 ? ( {t(($) => $['createGuide.source.empty'])} ) : (
{sourceApps.map((app) => ( selectSourceApp(app)} /> ))} {sourceAppsIsFetchingNextPage && (
{t(($) => $['createModal.loadingApps'])}
)} {sourceAppsHasNextPage && )}
) } function SourceAppSkeleton() { return (
{sourceAppSkeletonKeys.map((key) => (
))}
) } function SourceAppOption({ app, onSelect, selected, }: { app: WorkflowSourceApp onSelect: () => void selected: boolean }) { return ( ) } function DslUploadSection() { const { t } = useTranslation('deployments') const dslFile = useAtomValue(dslFileAtom) const selectDslFile = useSetAtom(selectDslFileAtom) return ( $['createGuide.dsl.title'])} description={t(($) => $['createGuide.dsl.description'])} hideHeader >
) } function DslReadStatus() { const { t } = useTranslation('deployments') const isReadingDsl = useAtomValue(isReadingDslAtom) const dslReadError = useAtomValue(dslReadErrorAtom) const dslUnsupportedMode = useAtomValue(dslUnsupportedModeAtom) return ( <> {isReadingDsl && (
{t(($) => $['createGuide.dsl.reading'])}
)} {dslReadError && (
{t(($) => $['createGuide.dsl.readFailed'])}
)} {dslUnsupportedMode && (
{t(($) => $['createGuide.dsl.unsupportedMode'])}
)} ) } export function SourceActionButtons() { const { t } = useTranslation('deployments') const canGoNext = useAtomValue(sourceCanGoNextAtom) const continueFromSource = useSetAtom(continueFromSourceAtom) return ( ) }