'use client'
import type { GuideMethod, WorkflowSourceApp } from '@/features/deployments/create-guide/state'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { Input } from '@langgenius/dify-ui/input'
import { RadioRoot } from '@langgenius/dify-ui/radio'
import { RadioGroup } from '@langgenius/dify-ui/radio-group'
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 { DeploymentStateMessage } from '@/features/deployments/components/empty-state'
import { TitleTooltip } from '@/features/deployments/components/title-tooltip'
import { UnsupportedDslNodesAlert } from '@/features/deployments/components/unsupported-dsl-nodes-alert'
import {
continueFromSourceAtom,
dslFileAtom,
dslReadErrorAtom,
dslUnsupportedModeAtom,
effectiveSelectedAppAtom,
isReadingDslAtom,
methodAtom,
selectDslFileAtom,
selectMethodAtom,
selectSourceAppAtom,
setSourceSearchTextAtom,
sourceAppsQueryAtom,
sourceCanGoNextAtom,
sourceSearchTextAtom,
unsupportedDslNodesAtom,
} from '@/features/deployments/create-guide/state'
import { StepShell } from './layout'
const sourceAppSkeletonKeys = ['first-source-app', 'second-source-app', 'third-source-app']
export function SourceStepContent() {
const method = useAtomValue(methodAtom)
const unsupportedDslNodes = useAtomValue(unsupportedDslNodesAtom)
return (
{method === 'bindApp' && (
)}
{method === 'importDsl' && (
)}
)
}
function SourceMethodSection() {
const { t } = useTranslation('deployments')
const method = useAtomValue(methodAtom)
const selectMethod = useSetAtom(selectMethodAtom)
return (
value={method}
onValueChange={selectMethod}
className="flex flex-col items-stretch gap-2 sm:flex-row"
>
)
}
function SourceMethodCard({ value, icon, title, description, badge }: {
value: GuideMethod
icon: string
title: string
description: string
badge?: string
}) {
return (
value={value}
variant="unstyled"
className={cn(
`relative box-content h-[84px] w-full cursor-pointer rounded-xl border-[0.5px]
border-components-option-card-option-border bg-components-panel-on-panel-item-bg p-3
text-left shadow-xs outline-hidden hover:shadow-md focus-visible:ring-2
focus-visible:ring-state-accent-solid sm:w-[240px]`,
'data-checked:border-components-option-card-option-selected-border data-checked:bg-components-option-card-option-selected-bg data-checked:shadow-md data-checked:ring-[0.5px] data-checked:ring-components-option-card-option-selected-border data-checked:ring-inset',
)}
>
{title}
{badge && (
{badge}
)}
{description}
)
}
function SourceAppSelectionSection() {
const { t } = useTranslation('deployments')
return (
)
}
function SourceSearchInput() {
const { t } = useTranslation('deployments')
const sourceSearchText = useAtomValue(sourceSearchTextAtom)
const setSourceSearchText = useSetAtom(setSourceSearchTextAtom)
return (
setSourceSearchText(event.target.value)}
placeholder={t('createGuide.source.searchPlaceholder')}
className="h-9 pr-8 pl-8"
/>
{sourceSearchText && (
)}
)
}
function SourceAppList() {
const { t } = useTranslation('deployments')
const selectSourceApp = useSetAtom(selectSourceAppAtom)
const effectiveSelectedApp = useAtomValue(effectiveSelectedAppAtom)
const sourceAppsQuery = useAtomValue(sourceAppsQueryAtom)
const sourceApps = (sourceAppsQuery.data?.pages.flatMap(page => page.data) ?? []) as WorkflowSourceApp[]
const sourceAppsLoading = sourceAppsQuery.isLoading || sourceAppsQuery.isPlaceholderData || (sourceAppsQuery.isFetching && sourceApps.length === 0)
return (
{sourceAppsLoading
?
: sourceApps.length === 0
? (
{t('createGuide.source.empty')}
)
: (
{sourceApps.map(app => (
selectSourceApp(app)}
/>
))}
{sourceAppsQuery.hasNextPage && (
)}
)}
)
}
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 (
{t('createGuide.dsl.dropTitle')}
{t('createGuide.dsl.dropDescription')}
)
}
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 (
)
}