From 12bcd2c625f810268ff78138ecebd784bc0bc3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E5=A4=A9=E5=9B=B0?= <2570024918@qq.com> Date: Wed, 2 Sep 2026 20:16:10 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(windows):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=98=BE=E7=A4=BA=E5=88=AB=E5=90=8D=E4=BB=A5?= =?UTF-8?q?=E5=8C=BA=E5=88=86=E5=90=8C=E5=90=8D=E6=96=87=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为工作区项目标签增加 displayAlias 字段并持久化,在标题栏、项目标签栏 及侧边栏以「文件夹名 (别名)」格式展示;用户可通过项目上下文菜单设置 别名,解决多个同名文件夹项目同时打开时难以区分路径的问题。 Closes #404 Co-authored-by: Cursor --- .../file-system/stores/file-system.store.ts | 27 ++++++++---- .../layout/components/main-layout.tsx | 5 ++- .../components/sidebar/sidebar-projects.tsx | 12 +++++- .../window/components/project-tab-bar.test.ts | 2 +- .../window/components/project-tab-bar.tsx | 6 ++- .../title-bar/title-project-menu.tsx | 7 +++- .../prompt-project-display-alias.ts | 42 +++++++++++++++++++ .../features/window/stores/project.store.ts | 8 ++-- .../window/stores/workspace-tabs.store.ts | 15 +++++++ .../utils/project-display-label.test.ts | 20 +++++++++ .../window/utils/project-display-label.ts | 16 +++++++ windows/tauri/src/i18n/locale.ts | 5 +++ 12 files changed, 145 insertions(+), 20 deletions(-) create mode 100644 windows/tauri/src/features/window/controllers/prompt-project-display-alias.ts create mode 100644 windows/tauri/src/features/window/utils/project-display-label.test.ts create mode 100644 windows/tauri/src/features/window/utils/project-display-label.ts diff --git a/windows/tauri/src/features/file-system/stores/file-system.store.ts b/windows/tauri/src/features/file-system/stores/file-system.store.ts index c051d9418..a154ab221 100644 --- a/windows/tauri/src/features/file-system/stores/file-system.store.ts +++ b/windows/tauri/src/features/file-system/stores/file-system.store.ts @@ -43,6 +43,7 @@ import { restoreProjectUiState, } from "@/features/window/stores/workspace-ui-session"; import { useWorkspaceTabsStore } from "@/features/window/stores/workspace-tabs.store"; +import { getProjectDisplayLabel } from "@/features/window/utils/project-display-label"; import { createAppWindow } from "@/features/window/utils/create-app-window"; import { serializeTerminals } from "@/features/terminal/lib/terminal-session-storage"; import { useTerminalTabsStore } from "@/features/terminal/stores/terminal-tabs.store"; @@ -641,7 +642,7 @@ const openLocalWorkspace = async ( state.isFileTreeLoading = true; }); - const projectName = getFolderName(path); + const folderName = getFolderName(path); const readDirectoryStartedAt = performance.now(); logWorkspaceOpenStep("start", "readDirectoryContents", path); @@ -649,7 +650,7 @@ const openLocalWorkspace = async ( logWorkspaceOpenStep("end", "readDirectoryContents", path, readDirectoryStartedAt); const fileTree = sortFileEntries(entries); - const wrappedFileTree = wrapWithRootFolder(fileTree, path, projectName); + const wrappedFileTree = wrapWithRootFolder(fileTree, path, folderName); if (treeState === "expand-root") { fileTreeStore.getState().actions.setExpandedPaths(new Set([path])); @@ -657,18 +658,20 @@ const openLocalWorkspace = async ( fileTreeStore.getState().actions.collapseAll(); } + const workspaceTab = useWorkspaceTabsStore + .getState() + .projectTabs.find((projectTab) => projectTab.id === workspaceId); + const displayName = workspaceTab ? getProjectDisplayLabel(workspaceTab) : folderName; + const { setRootFolderPath, setProjectName, setActiveProjectId } = projectStore.getState().actions; setRootFolderPath(path); - setProjectName(projectName); + setProjectName(displayName); if (restoreUiState) { restoreProjectUiState(path, workspaceId); } - const workspaceTab = useWorkspaceTabsStore - .getState() - .projectTabs.find((projectTab) => projectTab.id === workspaceId); setActiveProjectId(workspaceId); if (!prewarm) { useRecentFoldersStore.getState().actions.addToRecents(path, { @@ -683,7 +686,7 @@ const openLocalWorkspace = async ( state.isFileTreeLoading = false; state.files = wrappedFileTree; state.rootFolderPath = path; - state.workspaceFolders = [{ path, name: projectName, isPrimary: true }]; + state.workspaceFolders = [{ path, name: folderName, isPrimary: true }]; state.filesVersion++; state.projectFilesCache = undefined; }); @@ -1432,6 +1435,9 @@ const createFileSystemStore = (workspaceId: string): StoreApi { const isRemote = isRemoteProjectPath(project.path); const isActive = project.id === activeProjectId; + const displayName = getProjectDisplayLabel(project); return ( @@ -67,8 +71,8 @@ export function SidebarProjectDots({ )} aria-label={ isActive - ? t("titleProject.currentProject", { project: project.name }) - : t("titleProject.switchToProject", { project: project.name }) + ? t("titleProject.currentProject", { project: displayName }) + : t("titleProject.switchToProject", { project: displayName }) } aria-current={isActive ? "page" : undefined} aria-disabled={isSwitchingProject} @@ -138,6 +142,10 @@ export function SidebarProjectDots({ {t("titleProject.selectIcon")} ) : null} + void promptProjectDisplayAlias(project)}> + + {t("titleProject.setDisplayAlias")} +
{projects.map((project) => { - const closeLabel = t("titleProject.closeProject", { name: project.name }); + const displayName = getProjectDisplayLabel(project); + const closeLabel = t("titleProject.closeProject", { name: displayName }); return (
@@ -71,7 +73,7 @@ export function ProjectTabBar({ hideWhenSingle = false }: ProjectTabBarProps) { )} aria-hidden="true" /> - {project.name} + {displayName} {project.isActive ? (