From 797b4577d4acd32efcac6c08b46eee234342f781 Mon Sep 17 00:00:00 2001 From: SnapOtter Date: Thu, 7 May 2026 20:33:25 +0800 Subject: [PATCH] fix: show tool name instead of bundle name on AI feature install prompt The install prompt and error messages were showing the underlying AI bundle name (e.g. "Background Removal") instead of the actual tool name (e.g. "Passport Photo"). Now the UI shows the correct tool name and description while still installing the correct bundle behind the scenes. Closes #130 --- .../components/features/feature-install-prompt.tsx | 11 +++++++++-- apps/web/src/hooks/use-pipeline-processor.ts | 4 ++-- apps/web/src/hooks/use-tool-processor.ts | 11 ++++++----- apps/web/src/pages/tool-page.tsx | 7 ++++++- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/web/src/components/features/feature-install-prompt.tsx b/apps/web/src/components/features/feature-install-prompt.tsx index be3e9f21..308a862f 100644 --- a/apps/web/src/components/features/feature-install-prompt.tsx +++ b/apps/web/src/components/features/feature-install-prompt.tsx @@ -47,9 +47,15 @@ interface FeatureInstallPromptProps { bundle: FeatureBundleState; isAdmin: boolean; toolName?: string; + toolDescription?: string; } -export function FeatureInstallPrompt({ bundle, isAdmin, toolName }: FeatureInstallPromptProps) { +export function FeatureInstallPrompt({ + bundle, + isAdmin, + toolName, + toolDescription, +}: FeatureInstallPromptProps) { const { installBundle, clearError, installing, errors, startTimes, queued } = useFeaturesStore(); const progress = installing[bundle.id] ?? null; const error = errors[bundle.id] ?? null; @@ -57,6 +63,7 @@ export function FeatureInstallPrompt({ bundle, isAdmin, toolName }: FeatureInsta const isQueued = queued.includes(bundle.id); const startTime = startTimes[bundle.id] ?? null; const displayName = toolName || bundle.name; + const displayDescription = toolDescription || bundle.description; const [messageIndex, setMessageIndex] = useState(() => Math.floor(Math.random() * PROGRESS_MESSAGES.length), @@ -103,7 +110,7 @@ export function FeatureInstallPrompt({ bundle, isAdmin, toolName }: FeatureInsta

{displayName}

-

{bundle.description}

+

{displayDescription}

This feature requires an additional download (~{bundle.estimatedSize})

diff --git a/apps/web/src/hooks/use-pipeline-processor.ts b/apps/web/src/hooks/use-pipeline-processor.ts index c8e6914d..2014a8f2 100644 --- a/apps/web/src/hooks/use-pipeline-processor.ts +++ b/apps/web/src/hooks/use-pipeline-processor.ts @@ -148,7 +148,7 @@ export function usePipelineProcessor() { const parsed = parseApiError(body, xhr.status); if (typeof parsed === "object" && parsed.type === "feature_not_installed") { setError( - `Feature "${parsed.featureName}" is not installed. Enable it in Settings → AI Features.`, + `The "${parsed.featureName}" feature is not installed. Enable it in Settings → AI Features.`, ); } else { setError(parsed as string); @@ -279,7 +279,7 @@ export function usePipelineProcessor() { } else { const parsed = parseApiError(body, response.status); if (typeof parsed === "object" && parsed.type === "feature_not_installed") { - errorMsg = `Feature "${parsed.featureName}" is not installed. Enable it in Settings → AI Features.`; + errorMsg = `The "${parsed.featureName}" feature is not installed. Enable it in Settings → AI Features.`; } else { errorMsg = parsed as string; } diff --git a/apps/web/src/hooks/use-tool-processor.ts b/apps/web/src/hooks/use-tool-processor.ts index b8f9cacc..3b730982 100644 --- a/apps/web/src/hooks/use-tool-processor.ts +++ b/apps/web/src/hooks/use-tool-processor.ts @@ -1,4 +1,4 @@ -import { PYTHON_SIDECAR_TOOLS } from "@snapotter/shared"; +import { PYTHON_SIDECAR_TOOLS, TOOLS } from "@snapotter/shared"; import { useCallback, useEffect, useRef, useState } from "react"; import { formatHeaders, parseApiError } from "@/lib/api"; import { generateId } from "@/lib/utils"; @@ -47,6 +47,7 @@ export function useToolProcessor(toolId: string) { const isAiTool = AI_PYTHON_TOOLS.has(toolId); const isMediumTool = MEDIUM_TOOLS.has(toolId); + const toolName = TOOLS.find((t) => t.id === toolId)?.name ?? toolId; const processingTimerRef = useRef | null>(null); // Clean up on unmount @@ -280,7 +281,7 @@ export function useToolProcessor(toolId: string) { const parsed = parseApiError(body, xhr.status); if (typeof parsed === "object" && parsed.type === "feature_not_installed") { setError( - `Feature "${parsed.featureName}" is not installed. Enable it in Settings → AI Features.`, + `${toolName} requires the "${parsed.featureName}" feature. Enable it in Settings → AI Features.`, ); } else { setError(parsed as string); @@ -324,7 +325,7 @@ export function useToolProcessor(toolId: string) { }); xhr.send(formData); }, - [toolId, isAiTool, isMediumTool, setProcessing, setError], + [toolId, isAiTool, isMediumTool, setProcessing, setError, toolName], ); const processAllFiles = useCallback( @@ -407,7 +408,7 @@ export function useToolProcessor(toolId: string) { const body = JSON.parse(text); const parsed = parseApiError(body, response.status); if (typeof parsed === "object" && parsed.type === "feature_not_installed") { - errorMsg = `Feature "${parsed.featureName}" is not installed. Enable it in Settings → AI Features.`; + errorMsg = `${toolName} requires the "${parsed.featureName}" feature. Enable it in Settings → AI Features.`; } else { errorMsg = parsed as string; } @@ -465,7 +466,7 @@ export function useToolProcessor(toolId: string) { setProgress(IDLE_PROGRESS); } }, - [toolId, processFiles, setProcessing, setError], + [toolId, processFiles, setProcessing, setError, toolName], ); return { diff --git a/apps/web/src/pages/tool-page.tsx b/apps/web/src/pages/tool-page.tsx index a1376575..7d37b449 100644 --- a/apps/web/src/pages/tool-page.tsx +++ b/apps/web/src/pages/tool-page.tsx @@ -292,7 +292,12 @@ export function ToolPage() { if (isAiTool && !toolInstalled && featureBundle) { return ( - + ); }