feat: enhance model move functionality with cache entry updates

- Return cache entry data from model move operations for immediate UI updates
- Add recalculate_type parameter to update_single_model_cache for proper type adjustment
- Propagate cache entry through API layer to frontend MoveManager
- Enable virtual scroller to update moved items with new cache data
This commit is contained in:
Will Miao
2025-12-31 10:33:22 +08:00
parent 2b239c3747
commit 8120716cd8
4 changed files with 39 additions and 15 deletions

View File

@@ -496,12 +496,15 @@ class ModelMoveService:
'new_file_path': file_path 'new_file_path': file_path
} }
new_file_path = await self.scanner.move_model(file_path, target_path) move_result = await self.scanner.move_model(file_path, target_path)
if new_file_path: if move_result:
new_file_path = move_result.get("new_path")
cache_entry = move_result.get("cache_entry")
return { return {
'success': True, 'success': True,
'original_file_path': file_path, 'original_file_path': file_path,
'new_file_path': new_file_path 'new_file_path': new_file_path,
'cache_entry': cache_entry
} }
else: else:
return { return {
@@ -539,7 +542,8 @@ class ModelMoveService:
"original_file_path": file_path, "original_file_path": file_path,
"new_file_path": result.get('new_file_path'), "new_file_path": result.get('new_file_path'),
"success": result['success'], "success": result['success'],
"message": result.get('message', result.get('error', 'Unknown')) "message": result.get('message', result.get('error', 'Unknown')),
"cache_entry": result.get('cache_entry')
}) })
success_count = sum(1 for r in results if r["success"]) success_count = sum(1 for r in results if r["success"])

View File

@@ -1216,9 +1216,12 @@ class ModelScanner:
except Exception as e: except Exception as e:
logger.error(f"Error moving metadata file: {e}") logger.error(f"Error moving metadata file: {e}")
await self.update_single_model_cache(source_path, target_file, metadata) update_result = await self.update_single_model_cache(source_path, target_file, metadata, recalculate_type=True)
return target_file return {
"new_path": target_file,
"cache_entry": update_result if isinstance(update_result, dict) else None
}
except Exception as e: except Exception as e:
logger.error(f"Error moving model: {e}", exc_info=True) logger.error(f"Error moving model: {e}", exc_info=True)
@@ -1250,7 +1253,7 @@ class ModelScanner:
logger.error(f"Error updating metadata paths: {e}", exc_info=True) logger.error(f"Error updating metadata paths: {e}", exc_info=True)
return None return None
async def update_single_model_cache(self, original_path: str, new_path: str, metadata: Dict) -> bool: async def update_single_model_cache(self, original_path: str, new_path: str, metadata: Dict, recalculate_type: bool = False) -> Union[bool, Dict]:
"""Update cache after a model has been moved or modified""" """Update cache after a model has been moved or modified"""
cache = await self.get_cached_data() cache = await self.get_cached_data()
@@ -1287,6 +1290,9 @@ class ModelScanner:
file_path_override=normalized_new_path, file_path_override=normalized_new_path,
) )
if recalculate_type:
cache_entry = self.adjust_cached_entry(cache_entry)
cache.raw_data.append(cache_entry) cache.raw_data.append(cache_entry)
cache.add_to_version_index(cache_entry) cache.add_to_version_index(cache_entry)
@@ -1307,7 +1313,7 @@ class ModelScanner:
if cache_modified: if cache_modified:
await self._persist_current_cache() await self._persist_current_cache()
return True return cache_entry if metadata else True
def has_hash(self, sha256: str) -> bool: def has_hash(self, sha256: str) -> bool:
"""Check if a model with given hash exists""" """Check if a model with given hash exists"""

View File

@@ -936,7 +936,8 @@ export class BaseModelApiClient {
if (result.success) { if (result.success) {
return { return {
original_file_path: result.original_file_path || filePath, original_file_path: result.original_file_path || filePath,
new_file_path: result.new_file_path new_file_path: result.new_file_path,
cache_entry: result.cache_entry
}; };
} }
return null; return null;

View File

@@ -327,15 +327,22 @@ class MoveManager {
if (!isVisible) { if (!isVisible) {
state.virtualScroller.removeItemByFilePath(result.original_file_path); state.virtualScroller.removeItemByFilePath(result.original_file_path);
} else if (result.new_file_path !== result.original_file_path) { } else {
const newFileNameWithExt = result.new_file_path.substring(result.new_file_path.lastIndexOf('/') + 1); const newFileNameWithExt = result.new_file_path.substring(result.new_file_path.lastIndexOf('/') + 1);
const baseFileName = newFileNameWithExt.substring(0, newFileNameWithExt.lastIndexOf('.')); const baseFileName = newFileNameWithExt.substring(0, newFileNameWithExt.lastIndexOf('.'));
state.virtualScroller.updateSingleItem(result.original_file_path, { const updateData = {
file_path: result.new_file_path, file_path: result.new_file_path,
file_name: baseFileName, file_name: baseFileName,
folder: newRelativeFolder folder: newRelativeFolder
}); };
// Only update model_type if it's present in the cache_entry
if (result.cache_entry && result.cache_entry.model_type) {
updateData.model_type = result.cache_entry.model_type;
}
state.virtualScroller.updateSingleItem(result.original_file_path, updateData);
} }
} }
}); });
@@ -352,15 +359,21 @@ class MoveManager {
if (!isVisible) { if (!isVisible) {
state.virtualScroller.removeItemByFilePath(this.currentFilePath); state.virtualScroller.removeItemByFilePath(this.currentFilePath);
} else { } else {
// Update the model card even if it stays visible
const newFileNameWithExt = result.new_file_path.substring(result.new_file_path.lastIndexOf('/') + 1); const newFileNameWithExt = result.new_file_path.substring(result.new_file_path.lastIndexOf('/') + 1);
const baseFileName = newFileNameWithExt.substring(0, newFileNameWithExt.lastIndexOf('.')); const baseFileName = newFileNameWithExt.substring(0, newFileNameWithExt.lastIndexOf('.'));
state.virtualScroller.updateSingleItem(this.currentFilePath, { const updateData = {
file_path: result.new_file_path, file_path: result.new_file_path,
file_name: baseFileName, file_name: baseFileName,
folder: newRelativeFolder folder: newRelativeFolder
}); };
// Only update model_type if it's present in the cache_entry
if (result.cache_entry && result.cache_entry.model_type) {
updateData.model_type = result.cache_entry.model_type;
}
state.virtualScroller.updateSingleItem(this.currentFilePath, updateData);
} }
} }
} }