From 12bc8b166855a629a4218dd52b52cd3da7787936 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 6 Apr 2026 21:15:41 +0800 Subject: [PATCH] refactor: streamline AI-CAD into single-screen workspace --- components/ai-cad/ai-cad-workbench.tsx | 799 +++++++++---------------- 1 file changed, 272 insertions(+), 527 deletions(-) diff --git a/components/ai-cad/ai-cad-workbench.tsx b/components/ai-cad/ai-cad-workbench.tsx index 554720ddb..a29aa4373 100644 --- a/components/ai-cad/ai-cad-workbench.tsx +++ b/components/ai-cad/ai-cad-workbench.tsx @@ -1,11 +1,11 @@ "use client"; import { - AlertCircle, ArrowUpRight, Bot, Box, BrainCircuit, + Camera, CheckCircle2, ChevronDown, ChevronLeft, @@ -20,6 +20,7 @@ import { Loader2, MoreHorizontal, Orbit, + Paperclip, Plus, RotateCcw, Send, @@ -476,22 +477,6 @@ function getStatusBadgeClass(status: Model3DTaskStatus) { } } -function getMessageStateClass(state?: ChatMessageState) { - switch (state) { - case "success": - return "border-emerald-200 bg-emerald-50/70"; - case "failed": - return "border-rose-200 bg-rose-50/80"; - case "running": - return "border-sky-200 bg-sky-50/80"; - case "queued": - case "thinking": - return "border-[#ddd7ca] bg-[#f5f1e8]"; - default: - return "border-[#ddd7ca] bg-[#f5f1e8]"; - } -} - function getMessageStateLabel(state?: ChatMessageState) { switch (state) { case "thinking": @@ -547,17 +532,6 @@ function getProviderLabel(provider: CadGenerationProvider) { return provider === "kittycad-cad" ? "KittyCAD CAD" : "Tripo3D"; } -function getProviderSourceLabel(source?: AiCadProviderStatus["source"] | null) { - switch (source) { - case "provider": - return "系统设置"; - case "env": - return "环境变量"; - default: - return "未配置"; - } -} - function readNullableText(value: unknown) { return typeof value === "string" && value.trim() ? value : null; } @@ -2260,8 +2234,7 @@ export function AiCadWorkbench() { ); const [kittycadProviderStatus, setKittycadProviderStatus] = useState(null); - const [isLoadingKittycadProviderStatus, setIsLoadingKittycadProviderStatus] = - useState(true); + const [, setIsLoadingKittycadProviderStatus] = useState(true); const [viewerSettings, setViewerSettings] = useState( DEFAULT_VIEWER_SETTINGS ); @@ -2587,7 +2560,6 @@ export function AiCadWorkbench() { canIterateKittyCadVersion(activeVersion) ? activeVersion : null; - const willSubmitAsIteration = Boolean(iterationBaseVersion); const activeDownloadEntries = buildDownloadEntries(activeVersion); const primaryDownloadEntry = activeDownloadEntries[0] ?? null; const activeCodeEntry = @@ -2612,7 +2584,6 @@ export function AiCadWorkbench() { const activeVersionStructuredDirectives = activeVersion ? extractStructuredPromptDirectives(activeVersion.prompt) : []; - const promptStructuredDirectives = extractStructuredPromptDirectives(prompt); const versionCompareNotes = buildVersionCompareNotes({ activeVersion, parentVersion: activeParentVersion, @@ -2733,6 +2704,8 @@ export function AiCadWorkbench() { workspaces.find((workspace) => workspace.id === activeWorkspaceId) ?? null; const activeWorkspaceName = activeWorkspace?.name || "AI-CAD 工作台"; const normalizedWorkspaceName = normalizeWorkspaceTitle(activeWorkspaceName); + const shouldForceTreeCollapsed = + !activeVersion && activeLeftPanelView === "tree"; const isWorkspaceActionDisabled = isSubmitting || isCreatingWorkspace || isDeletingWorkspace; const canDeleteActiveWorkspace = @@ -2747,11 +2720,6 @@ export function AiCadWorkbench() { !prompt.trim() || isSubmitting || (generationProvider === "kittycad-cad" && !isKittycadConfigured); - const promptCharacterCount = prompt.trim().length; - const promptLineCount = prompt.trim() - ? prompt.trim().split(NEWLINE_SPLIT_RE).length - : 0; - const serializedWorkbenchSnapshot = serializeWorkbenchState({ prompt, generationProvider, @@ -3256,20 +3224,6 @@ export function AiCadWorkbench() { })); } - function handleInsertStructuredDirective( - directiveKey: StructuredPromptDirectiveKey - ) { - setPrompt((current) => - upsertStructuredPromptDirective(current, directiveKey, activeVersion) - ); - } - - function handleInsertStructuredTemplate() { - setPrompt((current) => - buildStructuredPromptTemplate(current, activeVersion) - ); - } - async function handleCopyCodeContent(code: string) { if ( typeof window === "undefined" || @@ -3604,60 +3558,9 @@ export function AiCadWorkbench() { -
-
-
- - - {generationProvider === "kittycad-cad" - ? "KittyCAD / Zoo CAD" - : "Tripo3D"} - - - {activeVersion - ? `Focus V${activeVersion.versionNumber}` - : "Ready for first pass"} - - -
- -
- {versions.length} versions - {completedCount} done - - {hasPendingTasks - ? `${pendingTaskCount} task active` - : "Workspace stable"} - -
-
- - {(workspaceSyncError || workspaceOperationError) && ( -
+ {(workspaceSyncError || workspaceOperationError) && ( +
+
{workspaceSyncError ? (

云端同步提示:{workspaceSyncError} @@ -3669,132 +3572,114 @@ export function AiCadWorkbench() {

) : null}
- )} -
+
+ )}
-
-
- Panels -
-
- { - historyPanelRef.current?.expand(); - setActiveLeftPanelView("project"); - }} - shortLabel="Proj" - /> - { - historyPanelRef.current?.expand(); - setActiveLeftPanelView("tree"); - }} - shortLabel="Tree" - /> - { - resultPanelRef.current?.expand(); - setActiveResultTab("preview"); - }} - shortLabel="3D" - /> - { - resultPanelRef.current?.expand(); - setActiveResultTab("code"); - }} - shortLabel="KCL" - /> - conversationPanelRef.current?.expand()} - shortLabel="AI" - /> -
+
+ { + historyPanelRef.current?.expand(); + setActiveLeftPanelView("project"); + }} + shortLabel="Proj" + /> + { + historyPanelRef.current?.expand(); + setActiveLeftPanelView("tree"); + }} + shortLabel="Tree" + /> + { + resultPanelRef.current?.expand(); + setActiveResultTab("preview"); + }} + shortLabel="3D" + /> + { + resultPanelRef.current?.expand(); + setActiveResultTab("code"); + }} + shortLabel="KCL" + /> + conversationPanelRef.current?.expand()} + shortLabel="AI" + />
-
-
- Tools -
-
- {primaryDownloadEntry ? ( - - - - Export - - - ) : ( - - )} - -
+ )} +
-
-
- Canvas Workspace -
- - Docked Panels - -
+
{activeVersion @@ -4016,89 +3901,72 @@ export function AiCadWorkbench() { -
- {messages.map((message) => { - const linkedVersion = message.versionId - ? findVersionById(versions, message.versionId) - : null; + {activeVersion || messages.length > 1 ? ( +
+ {messages.map((message) => { + const linkedVersion = message.versionId + ? findVersionById(versions, message.versionId) + : null; - return ( -
-
-
- {message.role === "user" ? ( - <> - - 你 - - ) : ( - <> - - AI-CAD Agent - - )} - - {formatClockTime(message.createdAt)} - -
- {message.role !== "user" && - message.state ? ( - - {getMessageStateLabel(message.state)} - - ) : null} -
- - {linkedVersion ? ( -
- - V{linkedVersion.versionNumber} - - +
+
+ {message.role === "user" ? ( + <> + + 你 + + ) : ( + <> + + AI-CAD Agent + )} - > - {getStatusLabel(linkedVersion.status)} - - {linkedVersion.generationMode === - "iterate" ? ( - - 连续修改 + + {formatClockTime(message.createdAt)} + +
+ {message.role !== "user" && + message.state ? ( + + {getMessageStateLabel(message.state)} ) : null} - {linkedVersion.parentVersionId ? ( - - linked output - - ) : ( - - root output - - )}
- ) : null} -
- {message.content} -
+ {linkedVersion ? ( +
+ + V{linkedVersion.versionNumber} + + + {getStatusLabel(linkedVersion.status)} + +
+ ) : null} -
-
- {linkedVersion ? ( +
+ {message.content} +
+ + {linkedVersion ? ( +
- ) : null} - {linkedVersion && - canIterateKittyCadVersion( - linkedVersion - ) ? ( - - handleFocusVersionForIteration( - linkedVersion - ) - } - /> - ) : null} - - setPrompt(message.content) - } - /> -
- - {linkedVersion - ? linkedVersion.generationMode === - "iterate" - ? "variant thread" - : "initial thread" - : message.role === "assistant" - ? "agent note" - : "prompt draft"} - + {canIterateKittyCadVersion( + linkedVersion + ) ? ( + + handleFocusVersionForIteration( + linkedVersion + ) + } + /> + ) : null} +
+ ) : null}
-
- ); - })} -
+ ); + })} +
+ ) : ( +
+
+

+ Try requesting a model, ask engineering + questions, or let's explore ideas. +

+
+
+ )}
-
- - 生成引擎 - - - {generationProvider === "tripo-3d" ? ( - <> - - Tripo 模型版本 + {activeVersion ? ( +
+ + 生成引擎 + + + {generationProvider === "tripo-3d" ? ( + <> + + Tripo 模型版本 + + + + ) : ( + + 输出 GLB / STEP / KCL - - - ) : ( - - 输出 GLB / STEP / KCL - - )} - {activeVersion ? ( - - {willSubmitAsIteration - ? `基于 V${activeVersion.versionNumber} 连续修改` - : `参考版本 V${activeVersion.versionNumber}`} - - ) : null} -
- - {generationProvider === "kittycad-cad" ? ( -
-
- -
- {isLoadingKittycadProviderStatus ? ( - - 正在检查 KittyCAD CAD 配置状态... - - ) : kittycadProviderStatus?.configured ? ( - - 当前将通过 - {kittycadProviderStatus.providerName - ? ` ${kittycadProviderStatus.providerName}` - : " KittyCAD CAD"} - 发起生成,配置来源: - {getProviderSourceLabel( - kittycadProviderStatus.source - )} - 。 - - ) : ( - - 还没有检测到 KittyCAD CAD - 可用配置。请先到“系统设置 > 本地AI”保存 - API Token,或者先切换到 Tripo3D 回退链路。 - - )} -
-
) : null} @@ -4277,72 +4091,12 @@ export function AiCadWorkbench() { ))}
- -
- Prompt Directives -
-
- - {STRUCTURED_PROMPT_DIRECTIVES.map( - (directive) => ( - - ) - )} -
- {promptStructuredDirectives.length > 0 ? ( -
- {promptStructuredDirectives.map( - (directive) => ( - - {directive.label}: - {truncateText(directive.value, 22)} - - ) - )} -
- ) : null}
) : null}
-
-
- - Compose - - - {willSubmitAsIteration - ? "Iterative edit" - : "New version"} - -
-
- {promptLineCount} lines - {promptCharacterCount} chars -
-