feat: Add support for relative paths in notes working directory

- Added expandNotesPath utility function to handle ~, ., and .. paths
- Updated validateNotesDirectory to expand relative paths
- Updated getDirectoryStructure to expand paths before scanning
- Updated startFileWatcher to expand paths before watching
- Made notes path input field editable in settings UI
- Updated locale files to explain relative path support

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-11-12 09:01:28 +00:00
parent f16b63bd69
commit 7d6ffe472c
6 changed files with 41 additions and 11 deletions

View File

@ -1,6 +1,7 @@
import { loggerService } from '@logger'
import {
checkName,
expandNotesPath,
getFilesDir,
getFileType,
getName,
@ -741,7 +742,9 @@ class FileStorage {
public getDirectoryStructure = async (_: Electron.IpcMainInvokeEvent, dirPath: string): Promise<NotesTreeNode[]> => {
try {
return await scanDir(dirPath)
// Expand relative paths before scanning
const expandedPath = expandNotesPath(dirPath)
return await scanDir(expandedPath)
} catch (error) {
logger.error('Failed to get directory structure:', error as Error)
throw error
@ -754,8 +757,8 @@ class FileStorage {
return false
}
// Normalize path
const normalizedPath = path.resolve(dirPath)
// Expand and normalize path (handles ~, ., and .. paths)
const normalizedPath = expandNotesPath(dirPath)
// Check if directory exists
if (!fs.existsSync(normalizedPath)) {
@ -1008,7 +1011,8 @@ class FileStorage {
throw new Error('Directory path is required')
}
const normalizedPath = path.resolve(dirPath.trim())
// Expand relative paths before watching
const normalizedPath = expandNotesPath(dirPath.trim())
if (!fs.existsSync(normalizedPath)) {
throw new Error(`Directory does not exist: ${normalizedPath}`)

View File

@ -38,6 +38,33 @@ export function untildify(pathWithTilde: string) {
return pathWithTilde
}
/**
* Expand relative paths to absolute paths.
* Handles paths starting with ~, ., or ..
* @param pathString - The path to expand
* @param basePath - Optional base path for relative paths (defaults to userData directory)
* @returns Absolute path
*/
export function expandNotesPath(pathString: string, basePath?: string): string {
if (!pathString) {
return pathString
}
// First handle tilde expansion
let expandedPath = untildify(pathString)
// If it's already an absolute path, return it
if (path.isAbsolute(expandedPath)) {
return path.normalize(expandedPath)
}
// For relative paths, resolve against the base path (default to userData)
const base = basePath || app.getPath('userData')
expandedPath = path.resolve(base, expandedPath)
return path.normalize(expandedPath)
}
export async function hasWritePermission(dir: string) {
try {
logger.info(`Checking write permission for ${dir}`)

View File

@ -2102,8 +2102,8 @@
"select": "Select",
"select_directory_failed": "Failed to select directory",
"title": "Data Settings",
"work_directory_description": "Work directory is where all note files are stored. Changing the work directory won't move existing files, please migrate files manually.",
"work_directory_placeholder": "Select notes work directory"
"work_directory_description": "Work directory is where all note files are stored. Supports relative paths like ~/Notes or ./Notes for multi-device sync. Changing the work directory won't move existing files, please migrate files manually.",
"work_directory_placeholder": "Enter or select notes work directory (e.g., ~/Notes)"
},
"display": {
"compress_content": "Content Compression",

View File

@ -2102,8 +2102,8 @@
"select": "选择",
"select_directory_failed": "选择目录失败",
"title": "数据设置",
"work_directory_description": "工作目录是存储所有笔记文件的位置。更改工作目录不会移动现有文件,请手动迁移文件。",
"work_directory_placeholder": "选择笔记工作目录"
"work_directory_description": "工作目录是存储所有笔记文件的位置。支持相对路径如 ~/笔记 或 ./笔记 以实现多设备同步。更改工作目录不会移动现有文件,请手动迁移文件。",
"work_directory_placeholder": "输入或选择笔记工作目录(例如:~/笔记)"
},
"display": {
"compress_content": "缩减栏宽",

View File

@ -2102,8 +2102,8 @@
"select": "選擇",
"select_directory_failed": "選擇目錄失敗",
"title": "數據設置",
"work_directory_description": "工作目錄是存儲所有筆記文件的位置。\n更改工作目錄不會移動現有文件請手動遷移文件。",
"work_directory_placeholder": "選擇筆記工作目錄"
"work_directory_description": "工作目錄是存儲所有筆記文件的位置。支持相對路徑如 ~/筆記 或 ./筆記 以實現多設備同步。\n更改工作目錄不會移動現有文件請手動遷移文件。",
"work_directory_placeholder": "輸入或選擇筆記工作目錄(例如:~/筆記)"
},
"display": {
"compress_content": "縮減欄寬",

View File

@ -105,7 +105,6 @@ const NotesSettings: FC = () => {
value={tempPath}
onChange={(e) => setTempPath(e.target.value)}
placeholder={t('notes.settings.data.work_directory_placeholder')}
readOnly
/>
<Button
type="default"