import { useEffect, useState } from 'react' import { useCloudEnvStore } from './store' import { useRepoStore } from '../repos/store' import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { SidebarLayout } from '../sidebar/components' import { Skeleton } from '@/components/ui/skeleton' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip' import { Code2, Terminal, MousePointer2, Lock, Radio, Zap, Square, RefreshCw, Copy, Check, Wind, Plane, Rocket, ExternalLink, Info } from 'lucide-react' import { toast } from 'sonner' import { WorkspaceInfo } from '@kevisual/cnb' import clsx from 'clsx' import { WorkspaceDetailDialog } from '../repos/modules/WorkspaceDetailDialog' import { useShallow } from 'zustand/shallow' type WorkspaceOpen = { url?: string webide?: string jumpUrl?: string remoteSsh?: string jetbrains?: Record codebuddy?: string codebuddycn?: string vscode?: string cursor?: string 'vscode-insiders'?: string trae?: string 'trae-cn'?: string windsurf?: string 'windsurf-next'?: string antigravity?: string ssh?: string } interface LinkItem { key: string label: string icon: React.ReactNode getUrl: (data: WorkspaceOpen) => string | undefined } const linkItems: LinkItem[] = [ { key: 'jumpUrl', label: 'Jump', icon: , getUrl: (d) => d.jumpUrl }, { key: 'webide', label: 'Web IDE', icon: , getUrl: (d) => d.webide }, { key: 'vscode', label: 'VS Code', icon: , getUrl: (d) => d.vscode }, { key: 'ssh', label: 'SSH', icon: , getUrl: (d) => d.ssh }, ] function LinkCard({ item, workspaceData }: { item: LinkItem; workspaceData: WorkspaceOpen }) { const url = item.getUrl(workspaceData) const [copied, setCopied] = useState(false) if (!url) return null const handleClick = () => { if (url.startsWith('ssh') || url.startsWith('cnb')) { return } window.open(url, '_blank') } const handleCopy = async (e: React.MouseEvent) => { e.stopPropagation() try { await navigator.clipboard.writeText(url) setCopied(true) toast.success('已复制') setTimeout(() => setCopied(false), 2000) } catch { toast.error('复制失败') } } return (
{item.icon}
{item.label}

{url}

) } function WorkspaceCard({ workspace, onStop }: { workspace: WorkspaceInfo; onStop: (ws: WorkspaceInfo) => void }) { const [loading, setLoading] = useState(true) const [workspaceData, setWorkspaceData] = useState(null) const getWorkspaceDetail = useCloudEnvStore((state) => state.getWorkspaceDetail) const repoStore = useRepoStore(useShallow((state) => ({ setShowWorkspaceDialog: state.setShowWorkspaceDialog, setWorkspaceTab: state.setWorkspaceTab, }))) useEffect(() => { const fetchDetail = async () => { setLoading(true) const data = await getWorkspaceDetail(workspace) setWorkspaceData(data) setLoading(false) } fetchDetail() }, [workspace, getWorkspaceDetail]) const handleShowDetail = async () => { const data = await getWorkspaceDetail(workspace) useRepoStore.setState({ selectWorkspace: workspace, workspaceLink: data || {}, showWorkspaceDialog: true, workspaceTab: 'dev' }) } return (
{workspace.slug}
{workspace.branch && ( {workspace.branch} )}
{loading ? (
{[1, 2, 3, 4].map((i) => (
))}
) : workspaceData ? (
{linkItems.map((item) => ( ))}
) : (
暂无链接信息
)} ) } export default function CloudEnvPage() { const { workspaceList, loading, getWorkspaceList, stopWorkspace } = useCloudEnvStore() useEffect(() => { getWorkspaceList() }, [getWorkspaceList]) return (

云端开发环境

当前运行中的云端开发环境

{loading && workspaceList.length === 0 ? (
{[1, 2, 3].map((i) => ( ))}
) : workspaceList.length === 0 ? (

暂无运行中的工作区

在仓库管理页面启动工作区即可在此查看

) : (
{workspaceList.map((workspace) => ( ))}
)}
) }