feat(recipes): add Unknown base-model filter bucket for undetermined recipes

Normalize undetermined recipe base_model to None in RecipeFormatParser
(previously ''). get_base_models now reports an "Unknown" bucket backed
by a dedicated __unknown__ marker, and the listing filter matches it
against recipes whose base model is falsy. Frontend renders the bucket
label as "Unknown" while filtering via the marker.

Tests: handler, scanner, parser, and frontend filtering.
This commit is contained in:
Will Miao
2026-08-31 09:09:53 +08:00
parent 8d46d26abe
commit 2a3c632dc5
8 changed files with 214 additions and 11 deletions
@@ -350,6 +350,49 @@ describe('FilterManager tag and base model filters', () => {
expect(baseModelChip.classList.contains('active')).toBe(false);
});
it('filters recipes by the unknown base model bucket via its marker value', async () => {
global.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
success: true,
base_models: [
{ name: 'Unknown', value: '__unknown__', count: 3 },
{ name: 'SDXL', count: 2 },
],
}),
});
renderControlsDom('recipes');
const stateModule = await import('../../../static/js/state/index.js');
stateModule.initPageState('recipes');
const { getCurrentPageState } = stateModule;
const { FilterManager } = await import('../../../static/js/managers/FilterManager.js');
const loadRecipesMock = vi.fn().mockResolvedValue(undefined);
window.recipeManager = { loadRecipes: loadRecipesMock };
new FilterManager({ page: 'recipes' });
await vi.waitFor(() => {
const chip = document.querySelector('[data-base-model="__unknown__"]');
expect(chip).not.toBeNull();
});
const unknownChip = document.querySelector('[data-base-model="__unknown__"]');
// Display label is "Unknown" even though the filter value is the marker
expect(unknownChip.textContent).toContain('Unknown');
unknownChip.dispatchEvent(new Event('click', { bubbles: true }));
await vi.waitFor(() => expect(loadRecipesMock).toHaveBeenCalledTimes(1));
expect(getCurrentPageState().filters.baseModel).toEqual(['__unknown__']);
expect(unknownChip.classList.contains('active')).toBe(true);
const storageKey = 'lora_manager_recipes_filters';
const storedFilters = JSON.parse(localStorage.getItem(storageKey));
expect(storedFilters.baseModel).toEqual(['__unknown__']);
});
it('filters base model chips locally without changing selected state', async () => {
global.fetch = vi.fn().mockResolvedValue({
ok: true,