feat: add pause and resume functionality to file watcher; enhance error handling in useInPlaceEdit hook

This commit is contained in:
suyao 2025-12-03 16:53:27 +08:00
parent 3093a9e5d0
commit f8428df247
No known key found for this signature in database
2 changed files with 23 additions and 4 deletions

View File

@ -151,6 +151,7 @@ class FileStorage {
private currentWatchPath?: string
private debounceTimer?: NodeJS.Timeout
private watcherConfig: Required<FileWatcherConfig> = DEFAULT_WATCHER_CONFIG
private isPaused = false
constructor() {
this.initStorageDir()
@ -1448,6 +1449,12 @@ class FileStorage {
private createChangeHandler() {
return (eventType: string, filePath: string) => {
// Skip processing if watcher is paused
if (this.isPaused) {
logger.debug('File change ignored (watcher paused)', { eventType, filePath })
return
}
if (!this.shouldWatchFile(filePath, eventType)) {
return
}
@ -1744,8 +1751,8 @@ class FileStorage {
public pauseFileWatcher = async (): Promise<void> => {
if (this.watcher) {
logger.debug('Pausing file watcher')
// Chokidar doesn't have pause, so we temporarily set a flag
// We'll handle this by clearing the debounce timer
this.isPaused = true
// Clear any pending debounced notifications
if (this.debounceTimer) {
clearTimeout(this.debounceTimer)
this.debounceTimer = undefined
@ -1759,6 +1766,7 @@ class FileStorage {
public resumeFileWatcher = async (): Promise<void> => {
if (this.watcher && this.currentWatchPath) {
logger.debug('Resuming file watcher')
this.isPaused = false
// Send a synthetic refresh event to trigger tree reload
this.notifyChange('refresh', this.currentWatchPath)
}

View File

@ -1,10 +1,12 @@
import { loggerService } from '@logger'
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
const logger = loggerService.withContext('useInPlaceEdit')
export interface UseInPlaceEditOptions {
onSave: ((value: string) => void) | ((value: string) => Promise<void>)
onCancel?: () => void
onError?: (error: unknown) => void
autoSelectOnStart?: boolean
trimOnSave?: boolean
}
@ -28,7 +30,8 @@ export interface UseInPlaceEditReturn {
* @returns An object containing the editing state and handler functions
*/
export function useInPlaceEdit(options: UseInPlaceEditOptions): UseInPlaceEditReturn {
const { onSave, onCancel, autoSelectOnStart = true, trimOnSave = true } = options
const { onSave, onCancel, onError, autoSelectOnStart = true, trimOnSave = true } = options
const { t } = useTranslation()
const [isSaving, setIsSaving] = useState(false)
const [isEditing, setIsEditing] = useState(false)
@ -68,9 +71,17 @@ export function useInPlaceEdit(options: UseInPlaceEditOptions): UseInPlaceEditRe
setEditValue('')
} catch (error) {
logger.error('Error saving in-place edit', { error })
// Call custom error handler if provided, otherwise show default toast
if (onError) {
onError(error)
} else {
window.toast.error(t('common.save_failed') || 'Failed to save')
}
} finally {
setIsSaving(false)
}
}, [isSaving, trimOnSave, editValue, onSave])
}, [isSaving, trimOnSave, editValue, onSave, onError, t])
const cancelEdit = useCallback(() => {
setIsEditing(false)