mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 22:39:36 +08:00
feat: add pause and resume functionality to file watcher; enhance error handling in useInPlaceEdit hook
This commit is contained in:
parent
3093a9e5d0
commit
f8428df247
@ -151,6 +151,7 @@ class FileStorage {
|
|||||||
private currentWatchPath?: string
|
private currentWatchPath?: string
|
||||||
private debounceTimer?: NodeJS.Timeout
|
private debounceTimer?: NodeJS.Timeout
|
||||||
private watcherConfig: Required<FileWatcherConfig> = DEFAULT_WATCHER_CONFIG
|
private watcherConfig: Required<FileWatcherConfig> = DEFAULT_WATCHER_CONFIG
|
||||||
|
private isPaused = false
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.initStorageDir()
|
this.initStorageDir()
|
||||||
@ -1448,6 +1449,12 @@ class FileStorage {
|
|||||||
|
|
||||||
private createChangeHandler() {
|
private createChangeHandler() {
|
||||||
return (eventType: string, filePath: string) => {
|
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)) {
|
if (!this.shouldWatchFile(filePath, eventType)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1744,8 +1751,8 @@ class FileStorage {
|
|||||||
public pauseFileWatcher = async (): Promise<void> => {
|
public pauseFileWatcher = async (): Promise<void> => {
|
||||||
if (this.watcher) {
|
if (this.watcher) {
|
||||||
logger.debug('Pausing file watcher')
|
logger.debug('Pausing file watcher')
|
||||||
// Chokidar doesn't have pause, so we temporarily set a flag
|
this.isPaused = true
|
||||||
// We'll handle this by clearing the debounce timer
|
// Clear any pending debounced notifications
|
||||||
if (this.debounceTimer) {
|
if (this.debounceTimer) {
|
||||||
clearTimeout(this.debounceTimer)
|
clearTimeout(this.debounceTimer)
|
||||||
this.debounceTimer = undefined
|
this.debounceTimer = undefined
|
||||||
@ -1759,6 +1766,7 @@ class FileStorage {
|
|||||||
public resumeFileWatcher = async (): Promise<void> => {
|
public resumeFileWatcher = async (): Promise<void> => {
|
||||||
if (this.watcher && this.currentWatchPath) {
|
if (this.watcher && this.currentWatchPath) {
|
||||||
logger.debug('Resuming file watcher')
|
logger.debug('Resuming file watcher')
|
||||||
|
this.isPaused = false
|
||||||
// Send a synthetic refresh event to trigger tree reload
|
// Send a synthetic refresh event to trigger tree reload
|
||||||
this.notifyChange('refresh', this.currentWatchPath)
|
this.notifyChange('refresh', this.currentWatchPath)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
|
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
const logger = loggerService.withContext('useInPlaceEdit')
|
const logger = loggerService.withContext('useInPlaceEdit')
|
||||||
export interface UseInPlaceEditOptions {
|
export interface UseInPlaceEditOptions {
|
||||||
onSave: ((value: string) => void) | ((value: string) => Promise<void>)
|
onSave: ((value: string) => void) | ((value: string) => Promise<void>)
|
||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
|
onError?: (error: unknown) => void
|
||||||
autoSelectOnStart?: boolean
|
autoSelectOnStart?: boolean
|
||||||
trimOnSave?: boolean
|
trimOnSave?: boolean
|
||||||
}
|
}
|
||||||
@ -28,7 +30,8 @@ export interface UseInPlaceEditReturn {
|
|||||||
* @returns An object containing the editing state and handler functions
|
* @returns An object containing the editing state and handler functions
|
||||||
*/
|
*/
|
||||||
export function useInPlaceEdit(options: UseInPlaceEditOptions): UseInPlaceEditReturn {
|
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 [isSaving, setIsSaving] = useState(false)
|
||||||
const [isEditing, setIsEditing] = useState(false)
|
const [isEditing, setIsEditing] = useState(false)
|
||||||
@ -68,9 +71,17 @@ export function useInPlaceEdit(options: UseInPlaceEditOptions): UseInPlaceEditRe
|
|||||||
setEditValue('')
|
setEditValue('')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error saving in-place edit', { 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)
|
setIsSaving(false)
|
||||||
}
|
}
|
||||||
}, [isSaving, trimOnSave, editValue, onSave])
|
}, [isSaving, trimOnSave, editValue, onSave, onError, t])
|
||||||
|
|
||||||
const cancelEdit = useCallback(() => {
|
const cancelEdit = useCallback(() => {
|
||||||
setIsEditing(false)
|
setIsEditing(false)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user