From e9f034c17fbebbb2b5ebcdc5669c95def1144fed Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Fri, 29 May 2026 02:32:49 -0700 Subject: [PATCH] Move feature tour step resets out of effects (#3060) * Move feature tour step resets out of effects * Record feature tour reset cleanup audit --- docs/reference/react-performance-audit.md | 6 ++- .../feature-wall/FeatureWallTourSurface.tsx | 44 ++++++++----------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/docs/reference/react-performance-audit.md b/docs/reference/react-performance-audit.md index 9f858f5e5..6cc7a3bd4 100644 --- a/docs/reference/react-performance-audit.md +++ b/docs/reference/react-performance-audit.md @@ -47,7 +47,7 @@ Initial inventory: ## Coverage Ledger -Current count after low-risk PRs #3038, #3041, #3042, #3044, #3051, #3052, #3053, #3054, #3055, #3056, #3058, and #3059: 954 Effect hook call sites. +Current count after low-risk PRs #3038, #3041, #3042, #3044, #3051, #3052, #3053, #3054, #3055, #3056, #3058, #3059, and #3060: 950 Effect hook call sites. | Area | Files / signal | Scan status | Notes | | ------------------------------ | -------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | @@ -92,6 +92,7 @@ These are candidate batches, not final conclusions. Each item needs code inspect | PR R | Quick Open query reset | Extra render pass from clearing the Quick Open input after the dialog opens. | `QuickOpen.tsx` covered by #3056 | Low | | PR S | Project group dialog open resets | Extra render pass from seeding name/delete dialog local state after the dialog opens. | `ProjectGroupNameDialog.tsx`, `ProjectGroupDeleteDialog.tsx` covered by #3058 | Low | | PR T | Onboarding agent fallback disclosure | Extra render pass from opening the fallback agent list when a selected agent first appears there. | `AgentStep.tsx` covered by #3059 | Low | +| PR U | Feature-wall tour workflow resets | Four local reset Effects run after workflow changes or close instead of in the selection/close path. | `FeatureWallTourSurface.tsx` covered by #3060 | Low | ## Merge Risk Scale @@ -116,7 +117,8 @@ These are candidate batches, not final conclusions. Each item needs code inspect | #3055 | `nwparker/react-perf-low-risk-7` | Repo combobox initializes mount-open state without an Effect | Low | Merged | `pnpm exec oxlint src/renderer/src/components/repo/RepoCombobox.tsx`; `pnpm run typecheck:web`. | | #3056 | `nwparker/react-perf-low-risk-8` | Quick Open clears its query on the open edge without a reset Effect | Low | Merged | `pnpm exec oxlint src/renderer/src/components/QuickOpen.tsx`; `pnpm run typecheck:web`. | | #3058 | `nwparker/react-perf-project-group-dialogs` | Project group dialogs reset local open-state during render | Low | Merged | `pnpm exec oxlint src/renderer/src/components/sidebar/ProjectGroupDeleteDialog.tsx src/renderer/src/components/sidebar/ProjectGroupNameDialog.tsx`; `pnpm run typecheck:web`. | -| #3059 | `nwparker/react-perf-agent-step-latch` | Onboarding agent fallback disclosure latch updates during render | Low | Open | `pnpm exec oxlint src/renderer/src/components/onboarding/AgentStep.tsx`; `pnpm run typecheck:web`. | +| #3059 | `nwparker/react-perf-agent-step-latch` | Onboarding agent fallback disclosure latch updates during render | Low | Merged | `pnpm exec oxlint src/renderer/src/components/onboarding/AgentStep.tsx`; `pnpm run typecheck:web`. | +| #3060 | `nwparker/react-perf-feature-tour-resets` | Feature-wall tour reset state moves into workflow/close transitions | Low | Open | `pnpm exec oxlint src/renderer/src/components/feature-wall/FeatureWallTourSurface.tsx`; `pnpm run typecheck:web`. | ## Reproduction Commands diff --git a/src/renderer/src/components/feature-wall/FeatureWallTourSurface.tsx b/src/renderer/src/components/feature-wall/FeatureWallTourSurface.tsx index 9363415fd..dd205efe8 100644 --- a/src/renderer/src/components/feature-wall/FeatureWallTourSurface.tsx +++ b/src/renderer/src/components/feature-wall/FeatureWallTourSurface.tsx @@ -94,6 +94,16 @@ export function FeatureWallTourSurface({ const [reviewStepId, setReviewStepId] = useState( () => reviewSteps[0]?.id ?? 'notes' ) + const [previousOpen, setPreviousOpen] = useState(isOpen) + if (isOpen !== previousOpen) { + setPreviousOpen(isOpen) + if (!isOpen) { + setSelectedId(DEFAULT_FEATURE_WALL_WORKFLOW_ID) + setAgentsStepId(agentsSteps[0]?.id ?? 'statuses') + setWorkbenchStepId(workbenchSteps[0]?.id ?? 'terminal') + setReviewStepId(reviewSteps[0]?.id ?? 'notes') + } + } const [orchestrationSkillInstalled, setOrchestrationSkillInstalled] = useState(false) const [browserUseSkillInstalled, setBrowserUseSkillInstalled] = useState(false) const completion = useFeatureWallCompletion( @@ -151,31 +161,6 @@ export function FeatureWallTourSurface({ } }, [isOpen, source]) - useEffect(() => { - if (!isOpen) { - setSelectedId(DEFAULT_FEATURE_WALL_WORKFLOW_ID) - setAgentsStepId(agentsSteps[0]?.id ?? 'statuses') - setWorkbenchStepId(workbenchSteps[0]?.id ?? 'terminal') - setReviewStepId(reviewSteps[0]?.id ?? 'notes') - } - }, [agentsSteps, isOpen, reviewSteps, workbenchSteps]) - - useEffect(() => { - if (selected.id === 'agents-orchestration') { - setAgentsStepId(agentsSteps[0]?.id ?? 'statuses') - } - }, [agentsSteps, selected.id]) - useEffect(() => { - if (selected.id === 'workbench') { - setWorkbenchStepId(workbenchSteps[0]?.id ?? 'terminal') - } - }, [selected.id, workbenchSteps]) - useEffect(() => { - if (selected.id === 'review') { - setReviewStepId(reviewSteps[0]?.id ?? 'notes') - } - }, [reviewSteps, selected.id]) - const { markWorkflowVisited, markAgentStepVisited, @@ -210,6 +195,13 @@ export function FeatureWallTourSurface({ return } setSelectedId(workflow.id) + if (workflow.id === 'agents-orchestration') { + setAgentsStepId(agentsSteps[0]?.id ?? 'statuses') + } else if (workflow.id === 'workbench') { + setWorkbenchStepId(workbenchSteps[0]?.id ?? 'terminal') + } else if (workflow.id === 'review') { + setReviewStepId(reviewSteps[0]?.id ?? 'notes') + } track('feature_wall_group_selected', { group_id: workflow.id, source }) const tile = getFeatureWallMediaTile(workflow.primaryTileId) if (tile) { @@ -221,7 +213,7 @@ export function FeatureWallTourSurface({ track('feature_wall_tile_focused', { tile_id: tile.id }) } }, - [markWorkflowVisited, selectedId, source] + [agentsSteps, markWorkflowVisited, reviewSteps, selectedId, source, workbenchSteps] ) const handleRailKeyDown = (event: KeyboardEvent, index: number): void => {