'use client' import type { AccessChannels, EnvironmentDeployment, Release, } from '@dify/contracts/enterprise/types.gen' import type { ReactElement } from 'react' import { ReleaseSource } from '@dify/contracts/enterprise/types.gen' import { cn } from '@langgenius/dify-ui/cn' import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' import { PreviewCard, PreviewCardContent, PreviewCardTrigger, } from '@langgenius/dify-ui/preview-card' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { useTranslation } from 'react-i18next' import { SkeletonRectangle } from '@/app/components/base/skeleton' import Link from '@/next/link' import { formatDate } from '../../shared/domain/release' import { EnvironmentDeploymentBadge } from '../../shared/ui/deployment-status-badge' import { deploymentStatusLabelKey } from '../../shared/ui/deployment-status-style' import { getInstanceTabHref } from './instance-card-utils' const VISIBLE_ENVIRONMENT_COUNT = 3 function releaseSourceLabel( release: Release | undefined, t: ReturnType>['t'], ) { if (release?.source === ReleaseSource.RELEASE_SOURCE_SOURCE_APP || release?.sourceAppId) return t(($) => $['versions.sourceAppOption']) if (release?.source === ReleaseSource.RELEASE_SOURCE_UPLOAD) return t(($) => $['versions.manualDslOption']) return '—' } export function ReleaseMetaTooltip({ release, deployed, children, }: { release?: Release deployed: boolean children: ReactElement }) { const { t } = useTranslation('deployments') if (!release) return children const rows = [ { label: t(($) => $['card.tooltip.releaseName']), value: release.displayName }, { label: t(($) => $['card.tooltip.deploymentStatus']), value: deployed ? t(($) => $['card.tooltip.deployed']) : t(($) => $['card.tooltip.notDeployedShort']), }, { label: t(($) => $['card.tooltip.source']), value: releaseSourceLabel(release, t) }, { label: t(($) => $['card.tooltip.createdAt']), value: formatDate(release.createdAt) }, ] return (
{rows.map((row) => (
{row.label} {row.value}
))}
) } function EnvironmentChip({ row }: { row: EnvironmentDeployment }) { const { t } = useTranslation('deployments') const name = row.environment.displayName const status = row.status const statusLabel = t(($) => $[deploymentStatusLabelKey(status)]) const tooltipSummary = [ name, row.currentRelease ? row.currentRelease.displayName : undefined, statusLabel, ] .filter(Boolean) .join(' · ') return ( } /> {tooltipSummary} ) } function EnvironmentOverflow({ rows }: { rows: EnvironmentDeployment[] }) { const { t } = useTranslation('deployments') return ( {t(($) => $['card.envOverflow'], { count: rows.length })} } />
{rows.map((row) => { const status = row.status const summary = [ row.environment.displayName, row.currentRelease ? row.currentRelease.displayName : undefined, t(($) => $[deploymentStatusLabelKey(status)]), ] .filter(Boolean) .join(' · ') return ( {summary} ) })}
) } export function DeploymentStatusContent({ rows, emptyAction, }: { rows: EnvironmentDeployment[] emptyAction?: ReactElement }) { const visibleRows = rows.slice(0, VISIBLE_ENVIRONMENT_COUNT) const overflowRows = rows.slice(VISIBLE_ENVIRONMENT_COUNT) if (rows.length > 0) { return (
{visibleRows.map((row) => ( ))} {overflowRows.length > 0 && }
) } if (emptyAction) return
{emptyAction}
return null } export function DeploymentAccessLinks({ appInstanceId, access, isLoading, }: { appInstanceId: string access?: AccessChannels isLoading?: boolean }) { const { t } = useTranslation('deployments') if (isLoading) { return (
$['overview.accessStatus'])} className="flex min-w-0 grow items-center gap-2" >
) } const links = [ ...(access?.webAppEnabled ? [ { key: 'webapp', href: getInstanceTabHref(appInstanceId, 'access'), label: t(($) => $['card.access.webApp']), icon: 'i-ri-global-line', }, ] : []), ...(access?.webAppEnabled ? [ { key: 'cli', href: getInstanceTabHref(appInstanceId, 'access'), label: t(($) => $['card.access.cli']), icon: 'i-ri-terminal-box-line', }, ] : []), ...(access?.developerApiEnabled ? [ { key: 'api-tokens', href: getInstanceTabHref(appInstanceId, 'api-tokens'), label: t(($) => $['card.access.api']), icon: 'i-ri-code-s-slash-line', }, ] : []), ] if (links.length === 0) { return (
$['overview.accessStatus'])} className="flex min-w-0 grow items-center gap-1.5 text-text-quaternary" > {t(($) => $['card.access.none'])}
) } return (
$['overview.accessStatus'])} className="flex min-w-0 grow items-center gap-2" > {links.map((link) => ( } /> {link.label} ))}
) }