fix(move): recalculate sub_type when moving models across roots

Moving a checkpoint into a unet root (or vice versa) moved the file and
updated the in-memory cache, but three stale spots survived until a
manual cache rebuild:

- The moved .metadata.json kept the old sub_type, and the opportunistic
  sync_cache_from_metadata path (fired by get_model_metadata and example
  image metadata updates) trusted it, reverting the cache entry and the
  SQLite snapshot to the pre-move sub_type. Loader nodes filter strictly
  on sub_type, so the model stayed listed under the old type.
- The manager page discarded the move response's cache_entry, so the
  card badge (CKPT/DM) and context menu label kept showing the old type.

Fixes:
- move_model now re-resolves sub_type from the target location (new
  resolve_sub_type_for_path hook) and persists it into the moved
  .metadata.json.
- _sync_cache_from_metadata_impl runs desired entries through
  adjust_cached_entry so location-derived fields cannot be re-poisoned
  by stale metadata snapshots.
- MoveManager carries cache_entry.sub_type into the in-place card
  update so badge and context menu reflect the new type immediately.
This commit is contained in:
Will Miao
2026-09-09 17:28:41 +08:00
parent cc9d3bff42
commit a03dc4002f
5 changed files with 279 additions and 14 deletions
+22 -10
View File
@@ -329,7 +329,11 @@ class MoveManager {
const results = await apiClient.moveBulkModels(this.bulkFilePaths, targetPath, this.useDefaultPath);
movedFiles = (results || [])
.filter(r => r.success)
.map(r => ({ original_file_path: r.original_file_path, new_file_path: r.new_file_path }));
.map(r => ({
original_file_path: r.original_file_path,
new_file_path: r.new_file_path,
sub_type: r.cache_entry?.sub_type
}));
// Deselect moving items and exit bulk mode
this.bulkFilePaths.forEach(path => bulkManager.deselectItem(path));
@@ -340,7 +344,11 @@ class MoveManager {
if (result) {
movedFiles.push({
original_file_path: result.original_file_path || this.currentFilePath,
new_file_path: result.new_file_path
new_file_path: result.new_file_path,
// The backend recalculates location-derived fields
// (e.g. checkpoint -> diffusion_model) during the move;
// carry them so the card re-renders with the new type.
sub_type: result.cache_entry?.sub_type
});
}
@@ -379,24 +387,28 @@ class MoveManager {
}
if (stillVisible) {
const newData = {
file_path: moved.new_file_path,
folder: newRelativeFolder
};
if (moved.sub_type) newData.sub_type = moved.sub_type;
pathsToUpdate.push({
originalPath: moved.original_file_path,
newData: {
file_path: moved.new_file_path,
folder: newRelativeFolder
}
newData
});
} else {
pathsToRemove.push(moved.original_file_path);
}
} else {
// No folder filter active — items remain visible, just update path
const newData = {
file_path: moved.new_file_path,
folder: this._getRelativeFolder(moved.new_file_path)
};
if (moved.sub_type) newData.sub_type = moved.sub_type;
pathsToUpdate.push({
originalPath: moved.original_file_path,
newData: {
file_path: moved.new_file_path,
folder: this._getRelativeFolder(moved.new_file_path)
}
newData
});
}
}