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 ( - + ); }