fix(app): normalize Windows paths for consistent project matching

On Windows, paths can use either forward slashes (C:/Users/...) or
backslashes (C:\Users\...). Deep links from external apps like GitButler
use forward slashes, while paths from the file system may use backslashes.
This caused duplicate project entries and broken ~ display.

- Add normalizePath() to convert backslashes to forward slashes
- Normalize paths in project open/close/expand/collapse/move/touch
- Fix ~ home directory display by normalizing before comparison
- Normalize paths at entry points (openProject, navigateToProject)
This commit is contained in:
Hegyi Áron Ferenc
2026-02-01 19:26:33 +01:00
parent 1798af72b0
commit fbea9a9103
4 changed files with 51 additions and 20 deletions

View File

@@ -7,6 +7,10 @@ import { Persist, persisted } from "@/utils/persist"
type StoredProject = { worktree: string; expanded: boolean }
export function normalizePath(input: string) {
return input.replaceAll("\\", "/")
}
export function normalizeServerUrl(input: string) {
const trimmed = input.trim()
if (!trimmed) return
@@ -163,39 +167,44 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
open(directory: string) {
const key = origin()
if (!key) return
const normalized = normalizePath(directory)
const current = store.projects[key] ?? []
if (current.find((x) => x.worktree === directory)) return
setStore("projects", key, [{ worktree: directory, expanded: true }, ...current])
if (current.find((x) => normalizePath(x.worktree) === normalized)) return
setStore("projects", key, [{ worktree: normalized, expanded: true }, ...current])
},
close(directory: string) {
const key = origin()
if (!key) return
const normalized = normalizePath(directory)
const current = store.projects[key] ?? []
setStore(
"projects",
key,
current.filter((x) => x.worktree !== directory),
current.filter((x) => normalizePath(x.worktree) !== normalized),
)
},
expand(directory: string) {
const key = origin()
if (!key) return
const normalized = normalizePath(directory)
const current = store.projects[key] ?? []
const index = current.findIndex((x) => x.worktree === directory)
const index = current.findIndex((x) => normalizePath(x.worktree) === normalized)
if (index !== -1) setStore("projects", key, index, "expanded", true)
},
collapse(directory: string) {
const key = origin()
if (!key) return
const normalized = normalizePath(directory)
const current = store.projects[key] ?? []
const index = current.findIndex((x) => x.worktree === directory)
const index = current.findIndex((x) => normalizePath(x.worktree) === normalized)
if (index !== -1) setStore("projects", key, index, "expanded", false)
},
move(directory: string, toIndex: number) {
const key = origin()
if (!key) return
const normalized = normalizePath(directory)
const current = store.projects[key] ?? []
const fromIndex = current.findIndex((x) => x.worktree === directory)
const fromIndex = current.findIndex((x) => normalizePath(x.worktree) === normalized)
if (fromIndex === -1 || fromIndex === toIndex) return
const result = [...current]
const [item] = result.splice(fromIndex, 1)
@@ -210,7 +219,8 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
touch(directory: string) {
const key = origin()
if (!key) return
setStore("lastProject", key, directory)
const normalized = normalizePath(directory)
setStore("lastProject", key, normalized)
},
},
}