From d57e64e60ae461b61769aa96a09887f214d8a763 Mon Sep 17 00:00:00 2001 From: Isaac Newton Date: Mon, 28 Apr 2025 11:53:18 +0700 Subject: [PATCH 1/2] Fix mode switching performance in PromptsView by using local state for instant UI updates --- .../src/components/prompts/PromptsView.tsx | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 61c61490e7..5cf2f1fc9a 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -60,6 +60,13 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { customModes, } = useExtensionState() + // Use a local state to track the visually active mode + // This prevents flickering when switching modes rapidly by: + // 1. Updating the UI immediately when a mode is clicked + // 2. Not syncing with the backend mode state (which would cause flickering) + // 3. Still sending the mode change to the backend for persistence + const [visualMode, setVisualMode] = useState(mode) + // Memoize modes to preserve array order const modes = useMemo(() => getAllModes(customModes), [customModes]) @@ -126,22 +133,25 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { // Handle mode switching with explicit state initialization const handleModeSwitch = useCallback( (modeConfig: ModeConfig) => { - if (modeConfig.slug === mode) return // Prevent unnecessary updates + if (modeConfig.slug === visualMode) return // Prevent unnecessary updates + + // Immediately update visual state for instant feedback + setVisualMode(modeConfig.slug) - // First switch the mode + // Then send the mode change message to the backend switchMode(modeConfig.slug) // Exit tools edit mode when switching modes setIsToolsEditMode(false) }, - [mode, switchMode, setIsToolsEditMode], + [visualMode, switchMode, setIsToolsEditMode], ) // Helper function to get current mode's config const getCurrentMode = useCallback((): ModeConfig | undefined => { - const findMode = (m: ModeConfig): boolean => m.slug === mode + const findMode = (m: ModeConfig): boolean => m.slug === visualMode return customModes?.find(findMode) || modes.find(findMode) - }, [mode, customModes, modes]) + }, [visualMode, customModes, modes]) // Helper function to safely access mode properties const getModeProperty = ( @@ -472,7 +482,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
{modes.map((modeConfig) => { - const isActive = mode === modeConfig.slug + const isActive = visualMode === modeConfig.slug return (
{ - const customMode = findModeBySlug(mode, customModes) - const prompt = customModePrompts?.[mode] as PromptComponent + const customMode = findModeBySlug(visualMode, customModes) + const prompt = customModePrompts?.[visualMode] as PromptComponent return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(mode) })()} onChange={(e) => { const value = (e as CustomEvent)?.detail?.target?.value || ((e as any).target as HTMLTextAreaElement).value - const customMode = findModeBySlug(mode, customModes) + const customMode = findModeBySlug(visualMode, customModes) if (customMode) { // For custom modes, update the JSON file - updateCustomMode(mode, { + updateCustomMode(visualMode, { ...customMode, roleDefinition: value.trim() || "", source: customMode.source || "global", }) } else { // For built-in modes, update the prompts - updateAgentPrompt(mode, { + updateAgentPrompt(visualMode, { roleDefinition: value.trim() || undefined, }) } @@ -617,7 +627,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
{t("prompts:tools.title")}
- {findModeBySlug(mode, customModes) && ( + {findModeBySlug(visualMode, customModes) && ( )}
- {!findModeBySlug(mode, customModes) && ( + {!findModeBySlug(visualMode, customModes) && (
{t("prompts:tools.builtInModesText")}
)} - {isToolsEditMode && findModeBySlug(mode, customModes) ? ( + {isToolsEditMode && findModeBySlug(visualMode, customModes) ? (
{availableGroups.map((group) => { const currentMode = getCurrentMode() - const isCustomMode = findModeBySlug(mode, customModes) + const isCustomMode = findModeBySlug(visualMode, customModes) const customMode = isCustomMode const isGroupEnabled = isCustomMode ? customMode?.groups?.some((g) => getGroupName(g) === group) @@ -710,7 +720,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { marginBottom: "4px", }}>
{t("prompts:customInstructions.title")}
- {!findModeBySlug(mode, customModes) && ( + {!findModeBySlug(visualMode, customModes) && (
{ - const customMode = findModeBySlug(mode, customModes) - const prompt = customModePrompts?.[mode] as PromptComponent + const customMode = findModeBySlug(visualMode, customModes) + const prompt = customModePrompts?.[visualMode] as PromptComponent return ( customMode?.customInstructions ?? prompt?.customInstructions ?? @@ -750,18 +760,18 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { const value = (e as CustomEvent)?.detail?.target?.value || ((e as any).target as HTMLTextAreaElement).value - const customMode = findModeBySlug(mode, customModes) + const customMode = findModeBySlug(visualMode, customModes) if (customMode) { // For custom modes, update the JSON file - updateCustomMode(mode, { + updateCustomMode(visualMode, { ...customMode, customInstructions: value.trim() || undefined, source: customMode.source || "global", }) } else { // For built-in modes, update the prompts - const existingPrompt = customModePrompts?.[mode] as PromptComponent - updateAgentPrompt(mode, { + const existingPrompt = customModePrompts?.[visualMode] as PromptComponent + updateAgentPrompt(visualMode, { ...existingPrompt, customInstructions: value.trim(), }) From 9a7ee332f0f647227adb01da8c10f46688297274 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 28 Apr 2025 11:05:45 -0400 Subject: [PATCH 2/2] Update webview-ui/src/components/prompts/PromptsView.tsx Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --- webview-ui/src/components/prompts/PromptsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 5cf2f1fc9a..c399f79156 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -567,7 +567,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { value={(() => { const customMode = findModeBySlug(visualMode, customModes) const prompt = customModePrompts?.[visualMode] as PromptComponent - return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(mode) + return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(visualMode) })()} onChange={(e) => { const value =