fix(recipe): align refresh split button behavior with models page

- refreshRecipes() now accepts fullRebuild param and passes it to scan endpoint
- Use consistent toast.api.refreshComplete / toast.api.refreshFailed keys
- Use loadingManager.show() with progress bar (matching models page style)
- Both Refresh and Rebuild Cache now hit the real /api/lm/recipes/scan endpoint
- Add sidebarManager.refresh() after recipe scan completes
- Backend scan_recipes handler reads full_rebuild query param
This commit is contained in:
Will Miao
2026-06-02 09:50:59 +08:00
parent d9fd60bec1
commit dd5d9cfcb2
3 changed files with 27 additions and 36 deletions

View File

@@ -461,7 +461,11 @@ class RecipeQueryHandler:
if recipe_scanner is None:
raise RuntimeError("Recipe scanner unavailable")
self._logger.info("Manually triggering recipe cache rebuild")
full_rebuild = request.query.get("full_rebuild", "true").lower() == "true"
self._logger.info(
"Manually triggering recipe cache %s",
"full rebuild" if full_rebuild else "refresh",
)
await recipe_scanner.get_cached_data(force_refresh=True)
return web.json_response(
{"success": True, "message": "Recipe cache refreshed successfully"}

View File

@@ -294,47 +294,37 @@ export async function resetAndReload(updateFolders = false, options = {}) {
}
/**
* Sync changes - quick refresh without rebuilding cache (similar to models page)
* Refreshes the recipe list by triggering a backend scan, then reloading.
* @param {boolean} fullRebuild - If true, fully rebuild the cache; if false, incremental scan
*/
export async function syncChanges() {
export async function refreshRecipes(fullRebuild = true) {
const actionLabel = fullRebuild ? 'Rebuilding recipe cache' : 'Refreshing recipes';
const actionToast = fullRebuild ? 'Full rebuild' : 'Refresh';
try {
state.loadingManager.showSimpleLoading('Syncing changes...');
state.loadingManager.show(`${actionLabel}...`, 0);
// Simply reload the recipes without rebuilding cache
await resetAndReload(false);
const url = new URL(RECIPE_ENDPOINTS.scan, window.location.origin);
url.searchParams.append('full_rebuild', fullRebuild);
showToast('toast.recipes.syncComplete', {}, 'success');
} catch (error) {
console.error('Error syncing recipes:', error);
showToast('toast.recipes.syncFailed', { message: error.message }, 'error');
} finally {
state.loadingManager.hide();
state.loadingManager.restoreProgressBar();
}
}
/**
* Refreshes the recipe list by first rebuilding the cache and then loading recipes
*/
export async function refreshRecipes() {
try {
state.loadingManager.showSimpleLoading('Refreshing recipes...');
// Call the API endpoint to rebuild the recipe cache
const response = await fetch(RECIPE_ENDPOINTS.scan);
const response = await fetch(url);
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || 'Failed to refresh recipe cache');
throw new Error(`Failed to refresh recipe cache: ${response.status} ${response.statusText}`);
}
const data = await response.json();
if (data.status === 'cancelled') {
showToast('toast.api.operationCancelled', {}, 'info');
return;
}
// After successful cache rebuild, reload the recipes
await resetAndReload(false);
showToast('toast.recipes.refreshComplete', {}, 'success');
showToast('toast.api.refreshComplete', { action: actionToast }, 'success');
} catch (error) {
console.error('Error refreshing recipes:', error);
showToast('toast.recipes.refreshFailed', { message: error.message }, 'error');
showToast('toast.api.refreshFailed', { action: fullRebuild ? 'rebuild' : 'refresh', type: 'recipe' }, 'error');
} finally {
state.loadingManager.hide();
state.loadingManager.restoreProgressBar();

View File

@@ -8,7 +8,7 @@ import { getSessionItem, removeSessionItem } from './utils/storageHelpers.js';
import { RecipeContextMenu } from './components/ContextMenu/index.js';
import { DuplicatesManager } from './components/DuplicatesManager.js';
import { refreshVirtualScroll } from './utils/infiniteScroll.js';
import { refreshRecipes, syncChanges, RecipeSidebarApiClient } from './api/recipeApi.js';
import { refreshRecipes, RecipeSidebarApiClient } from './api/recipeApi.js';
import { sidebarManager } from './components/SidebarManager.js';
class RecipePageControls {
@@ -23,12 +23,9 @@ class RecipePageControls {
}
async refreshModels(fullRebuild = false) {
if (fullRebuild) {
await refreshRecipes();
return;
}
await refreshRecipes(fullRebuild);
await syncChanges();
await sidebarManager.refresh();
}
getSidebarApiClient() {