This repository was archived by the owner on Aug 6, 2026. It is now read-only.
Repository navigation
feat(code): TanStack Router architectural cleanup #2456
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| src/renderer/routeTree.gen.ts linguist-generated=true |
323 changes: 26 additions & 297 deletions
323
apps/code/src/renderer/features/settings/components/SettingsDialog.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,318 +1,47 @@ | ||
| import { useOptionalAuthenticatedClient } from "@features/auth/hooks/authClient"; | ||
| import { useLogoutMutation } from "@features/auth/hooks/authMutations"; | ||
| import { | ||
| useAuthStateValue, | ||
| useCurrentUser, | ||
| } from "@features/auth/hooks/authQueries"; | ||
| import { getUserInitials } from "@features/auth/utils/userInitials"; | ||
| import { | ||
| type SettingsCategory, | ||
| useSettingsDialogStore, | ||
| } from "@features/settings/stores/settingsDialogStore"; | ||
| import { useFeatureFlag } from "@hooks/useFeatureFlag"; | ||
| import { useSeat } from "@hooks/useSeat"; | ||
| import { | ||
| ArrowLeft, | ||
| ArrowsClockwise, | ||
| CaretRight, | ||
| Code, | ||
| CreditCard, | ||
| Cube, | ||
| Folder, | ||
| GearSix, | ||
| GithubLogo, | ||
| Keyboard, | ||
| Palette, | ||
| SignOut, | ||
| SlackLogo, | ||
| Terminal, | ||
| TrafficSignal, | ||
| TreeStructure, | ||
| Wrench, | ||
| } from "@phosphor-icons/react"; | ||
| import { Avatar, Box, Flex, ScrollArea, Text } from "@radix-ui/themes"; | ||
| import { BILLING_FLAG } from "@shared/constants"; | ||
| import { type ReactNode, useEffect, useMemo } from "react"; | ||
| import { useHotkeys } from "react-hotkeys-hook"; | ||
| import { AdvancedSettings } from "./sections/AdvancedSettings"; | ||
| import { ClaudeCodeSettings } from "./sections/ClaudeCodeSettings"; | ||
| import { EnvironmentsSettings } from "./sections/environments/EnvironmentsSettings"; | ||
| import { GeneralSettings } from "./sections/GeneralSettings"; | ||
| import { GitHubSettings } from "./sections/GitHubSettings"; | ||
| import { PersonalizationSettings } from "./sections/PersonalizationSettings"; | ||
| import { PlanUsageSettings } from "./sections/PlanUsageSettings"; | ||
| import { ShortcutsSettings } from "./sections/ShortcutsSettings"; | ||
| import { SignalSourcesSettings } from "./sections/SignalSourcesSettings"; | ||
| import { SlackSettings } from "./sections/SlackSettings"; | ||
| import { TerminalSettings } from "./sections/TerminalSettings"; | ||
| import { UpdatesSettings } from "./sections/UpdatesSettings"; | ||
| import { WorkspacesSettings } from "./sections/WorkspacesSettings"; | ||
| import { WorktreesSettings } from "./sections/worktrees/WorktreesSettings"; | ||
|
|
||
| interface SidebarItem { | ||
| id: SettingsCategory; | ||
| label: string; | ||
| icon: ReactNode; | ||
| hasChevron?: boolean; | ||
| } | ||
|
|
||
| const SIDEBAR_ITEMS: SidebarItem[] = [ | ||
| { id: "general", label: "General", icon: <GearSix size={16} /> }, | ||
| { id: "plan-usage", label: "Plan & usage", icon: <CreditCard size={16} /> }, | ||
| { id: "workspaces", label: "Workspaces", icon: <Folder size={16} /> }, | ||
| { id: "worktrees", label: "Worktrees", icon: <TreeStructure size={16} /> }, | ||
| { | ||
| id: "environments", | ||
| label: "Environments", | ||
| icon: <Cube size={16} />, | ||
| }, | ||
| { | ||
| id: "personalization", | ||
| label: "Personalization", | ||
| icon: <Palette size={16} />, | ||
| }, | ||
| { id: "terminal", label: "Terminal", icon: <Terminal size={16} /> }, | ||
| { id: "claude-code", label: "Claude Code", icon: <Code size={16} /> }, | ||
| { id: "shortcuts", label: "Shortcuts", icon: <Keyboard size={16} /> }, | ||
| { id: "github", label: "GitHub", icon: <GithubLogo size={16} /> }, | ||
| { id: "slack", label: "Slack", icon: <SlackLogo size={16} /> }, | ||
|
|
||
| { | ||
| id: "signals", | ||
| label: "Signals", | ||
| icon: <TrafficSignal size={16} />, | ||
| }, | ||
| { id: "updates", label: "Updates", icon: <ArrowsClockwise size={16} /> }, | ||
| { id: "advanced", label: "Advanced", icon: <Wrench size={16} /> }, | ||
| ]; | ||
|
|
||
| const CATEGORY_TITLES: Record<SettingsCategory, string> = { | ||
| general: "General", | ||
| "plan-usage": "Plan & usage", | ||
| workspaces: "Workspaces", | ||
| worktrees: "Worktrees", | ||
| environments: "Environments", | ||
| "cloud-environments": "Environments", | ||
| personalization: "Personalization", | ||
| terminal: "Terminal", | ||
| "claude-code": "Claude Code", | ||
| shortcuts: "Shortcuts", | ||
| github: "GitHub", | ||
| slack: "Slack integration", | ||
|
|
||
| signals: "Signals", | ||
| updates: "Updates", | ||
| advanced: "Advanced", | ||
| }; | ||
|
|
||
| const CATEGORY_COMPONENTS: Record<SettingsCategory, React.ComponentType> = { | ||
| general: GeneralSettings, | ||
| "plan-usage": PlanUsageSettings, | ||
| workspaces: WorkspacesSettings, | ||
| worktrees: WorktreesSettings, | ||
| environments: EnvironmentsSettings, | ||
| "cloud-environments": EnvironmentsSettings, | ||
| personalization: PersonalizationSettings, | ||
| terminal: TerminalSettings, | ||
| "claude-code": ClaudeCodeSettings, | ||
| shortcuts: ShortcutsSettings, | ||
| github: GitHubSettings, | ||
| slack: SlackSettings, | ||
|
|
||
| signals: SignalSourcesSettings, | ||
| updates: UpdatesSettings, | ||
| advanced: AdvancedSettings, | ||
| }; | ||
|
|
||
| import { useSettingsDialogStore } from "@features/settings/stores/settingsDialogStore"; | ||
| import { useEffect } from "react"; | ||
| import { SettingsPanel } from "./SettingsPanel"; | ||
|
|
||
| // Modal/overlay form of the settings UI. Used in pre-router shells (e.g. | ||
| // `AiApprovalScreen`) where the routed `/settings/$category` page isn't | ||
| // available because RouterProvider hasn't mounted yet. Inside the main app, | ||
| // settings is a real route — `routes/settings/$category.tsx` renders | ||
| // `<SettingsPanel/>` directly. | ||
| export function SettingsDialog() { | ||
| const { isOpen, activeCategory, close, setCategory, formMode } = | ||
| useSettingsDialogStore(); | ||
| const isAuthenticated = useAuthStateValue( | ||
| (state) => state.status === "authenticated", | ||
| ); | ||
| const client = useOptionalAuthenticatedClient(); | ||
| const { data: user } = useCurrentUser({ client }); | ||
| const { seat, planLabel } = useSeat(); | ||
| const billingEnabled = useFeatureFlag(BILLING_FLAG); | ||
| const logoutMutation = useLogoutMutation(); | ||
|
|
||
| const sidebarItems = useMemo( | ||
| () => | ||
| billingEnabled | ||
| ? SIDEBAR_ITEMS | ||
| : SIDEBAR_ITEMS.filter((item) => item.id !== "plan-usage"), | ||
| [billingEnabled], | ||
| ); | ||
|
|
||
| useHotkeys("escape", close, { | ||
| enabled: isOpen, | ||
| enableOnContentEditable: true, | ||
| enableOnFormTags: true, | ||
| preventDefault: true, | ||
| }); | ||
| const isOpen = useSettingsDialogStore((s) => s.isOpen); | ||
| const close = useSettingsDialogStore((s) => s.close); | ||
|
|
||
| useEffect(() => { | ||
| if (!isOpen) return; | ||
| const handlePopState = () => { | ||
| if (isOpen && !window.history.state?.settingsOpen) { | ||
| if (!window.history.state?.settingsOpen) { | ||
| useSettingsDialogStore.setState({ isOpen: false }); | ||
| } | ||
| }; | ||
|
|
||
| window.addEventListener("popstate", handlePopState); | ||
| return () => window.removeEventListener("popstate", handlePopState); | ||
| }, [isOpen]); | ||
|
|
||
| if (!isOpen) { | ||
| return null; | ||
| } | ||
|
|
||
| const ActiveComponent = CATEGORY_COMPONENTS[activeCategory]; | ||
| useEffect(() => { | ||
| if (!isOpen) return; | ||
| const handleEscape = (e: KeyboardEvent) => { | ||
| if (e.key === "Escape") { | ||
| e.preventDefault(); | ||
| close(); | ||
| } | ||
| }; | ||
| window.addEventListener("keydown", handleEscape); | ||
| return () => window.removeEventListener("keydown", handleEscape); | ||
| }, [isOpen, close]); | ||
|
Comment on lines
+25
to
+35
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: apps/code/src/renderer/features/settings/components/SettingsDialog.tsx
Line: 25-35
Comment:
**Redundant Escape handler — `SettingsPanel` already owns it**
`SettingsPanel` now registers `useHotkeys("escape", close, { enabled: true, ... })` unconditionally while it is mounted. When the overlay is open, `SettingsPanel` is rendered inside `SettingsDialog`, so Escape already fires `close()` via the hotkey. This second listener on `window` fires a duplicate `close()` call immediately after. The guard `if (!wasOpen) return` in `close()` makes it harmless, but it violates the OnceAndOnlyOnce rule. This `keydown` effect can be dropped from `SettingsDialog`.
How can I resolve this? If you propose a fix, please make it concise. |
||
|
|
||
| const initials = getUserInitials(user); | ||
| if (!isOpen) return null; | ||
|
|
||
| return ( | ||
| <div | ||
| className="fixed inset-0 z-[100] flex bg-(--color-background)" | ||
| data-overlay="settings" | ||
| > | ||
| <div className="flex h-full w-[256px] shrink-0 flex-col border-gray-6 border-r"> | ||
| <div className="drag h-[36px] shrink-0 border-b border-b-(--gray-6)" /> | ||
|
|
||
| {isAuthenticated && user && ( | ||
| <Flex | ||
| align="center" | ||
| gap="3" | ||
| px="3" | ||
| py="3" | ||
| className="border-b border-b-(--gray-5)" | ||
| > | ||
| <Avatar size="2" fallback={initials} radius="full" color="amber" /> | ||
| <Flex direction="column" className="min-w-0"> | ||
| <Text truncate className="font-medium text-sm"> | ||
| {user.email} | ||
| </Text> | ||
| {seat && ( | ||
| <Text className="text-(--gray-9) text-[13px]"> | ||
| {planLabel} Plan | ||
| </Text> | ||
| )} | ||
| </Flex> | ||
| </Flex> | ||
| )} | ||
|
|
||
| <button | ||
| type="button" | ||
| className="mt-2 flex cursor-pointer items-center gap-2 border-0 bg-transparent px-3 py-2 text-left text-[13px] text-gray-11 transition-colors hover:bg-gray-3" | ||
| onClick={close} | ||
| > | ||
| <ArrowLeft size={14} /> | ||
| <span>Back to app</span> | ||
| </button> | ||
|
|
||
| <ScrollArea className="flex-1"> | ||
| <div className="flex flex-col pt-2"> | ||
| {sidebarItems.map((item) => { | ||
| const isActive = | ||
| activeCategory === item.id || | ||
| (item.id === "environments" && | ||
| activeCategory === "cloud-environments"); | ||
| return ( | ||
| <SidebarNavItem | ||
| key={item.id} | ||
| item={item} | ||
| isActive={isActive} | ||
| onClick={() => setCategory(item.id)} | ||
| /> | ||
| ); | ||
| })} | ||
| </div> | ||
| </ScrollArea> | ||
|
|
||
| {isAuthenticated && ( | ||
| <button | ||
| type="button" | ||
| disabled={logoutMutation.isPending} | ||
| className="flex cursor-pointer items-center gap-2 border-0 border-gray-5 border-t bg-transparent px-3 py-2.5 text-left font-mono text-[12px] text-gray-9 transition-colors hover:bg-gray-3 hover:text-gray-11 disabled:pointer-events-none disabled:opacity-50" | ||
| onClick={() => { | ||
| close(); | ||
| logoutMutation.mutate(); | ||
| }} | ||
| > | ||
| <SignOut size={14} /> | ||
| <span>Sign out</span> | ||
| </button> | ||
| )} | ||
| </div> | ||
|
|
||
| <div className="relative flex flex-1 flex-col overflow-hidden"> | ||
| <div className="drag h-[36px] shrink-0 border-b border-b-(--gray-6)" /> | ||
| <div className="relative flex flex-1 justify-center overflow-hidden"> | ||
| <svg | ||
| aria-hidden="true" | ||
| style={{ | ||
| maskImage: "linear-gradient(to top, black 0%, transparent 100%)", | ||
| WebkitMaskImage: | ||
| "linear-gradient(to top, black 0%, transparent 100%)", | ||
| }} | ||
| className="pointer-events-none absolute bottom-0 left-0 h-full w-full opacity-40" | ||
| > | ||
| <defs> | ||
| <pattern | ||
| id="settings-dot-pattern" | ||
| patternUnits="userSpaceOnUse" | ||
| width="8" | ||
| height="8" | ||
| > | ||
| <circle cx="0" cy="0" r="1" fill="var(--gray-6)" /> | ||
| <circle cx="0" cy="8" r="1" fill="var(--gray-6)" /> | ||
| <circle cx="8" cy="8" r="1" fill="var(--gray-6)" /> | ||
| <circle cx="8" cy="0" r="1" fill="var(--gray-6)" /> | ||
| <circle cx="4" cy="4" r="1" fill="var(--gray-6)" /> | ||
| </pattern> | ||
| </defs> | ||
| <rect | ||
| width="100%" | ||
| height="100%" | ||
| fill="url(#settings-dot-pattern)" | ||
| /> | ||
| </svg> | ||
| <ScrollArea className="h-full w-full"> | ||
| <Box p="6" mx="auto" className="relative z-[1] max-w-[800px]"> | ||
| <Flex direction="column" gap="4"> | ||
| {!formMode && ( | ||
| <Text className="font-medium text-lg leading-6.5"> | ||
| {CATEGORY_TITLES[activeCategory]} | ||
| </Text> | ||
| )} | ||
| <ActiveComponent /> | ||
| </Flex> | ||
| </Box> | ||
| </ScrollArea> | ||
| </div> | ||
| </div> | ||
| <SettingsPanel /> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| interface SidebarNavItemProps { | ||
| item: SidebarItem; | ||
| isActive: boolean; | ||
| onClick: () => void; | ||
| } | ||
|
|
||
| function SidebarNavItem({ item, isActive, onClick }: SidebarNavItemProps) { | ||
| return ( | ||
| <button | ||
| type="button" | ||
| className="flex w-full cursor-pointer items-center justify-between gap-2 border-0 bg-transparent px-3 py-1.5 text-left text-[13px] text-gray-11 transition-colors hover:bg-gray-3 data-[active]:bg-accent-4 data-[active]:text-gray-12" | ||
| data-active={isActive || undefined} | ||
| onClick={onClick} | ||
| > | ||
| <span className="flex items-center gap-2"> | ||
| <span className="text-gray-10">{item.icon}</span> | ||
| <span>{item.label}</span> | ||
| </span> | ||
| {item.hasChevron && <CaretRight size={12} className="text-gray-9" />} | ||
| </button> | ||
| ); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
open()no longer callswindow.history.pushState({ settingsOpen: true }), sowindow.history.state?.settingsOpenis alwaysundefined/ falsy. The condition!window.history.state?.settingsOpenis therefore alwaystrue, meaning anypopstateevent while the overlay is open (e.g. the user pressing Electron's back button inAiApprovalScreen) will unconditionally close the dialog — which was never the original intent.Either remove this handler entirely (the overlay is now the only remaining caller and there's no pushed state to guard against), or replace the condition with one that reflects the current behaviour.
Prompt To Fix With AI