Files
Will Miao d06bfea02a fix(versions): stop the folder filter from hiding local versions
View all local versions answers "every local version of this model", but the
listing request still carried the active folder: versions moved to another
folder silently disappeared, and a group-by-model card's version count (counted
across the library) no longer matched the list it opened.

- suspend the folder filter when the view starts, remember it, and show the root
  selection so the sidebar and the grid agree
- restore the folder when the filter is cleared; keep it suspended across a
  page reload
- picking a folder while the filter is active now exits it instead of being
  silently ignored (the view is library-wide)
- hand a suspended folder back to its own page when another model page clears
  the stale filter
- backend contract unchanged: the client simply omits `folder` while the view
  is active

Tests cover the query params, folder suspend/restore/foreign handoff and the
sidebar folder handoff.
2026-11-07 12:46:58 +08:00

110 lines
4.4 KiB
JavaScript

import { describe, it, expect, vi } from 'vitest';
const {
SIDEBAR_MANAGER_MODULE,
STORAGE_HELPERS_MODULE,
MODEL_API_FACTORY_MODULE,
I18N_MODULE,
BULK_MANAGER_MODULE,
UI_HELPERS_MODULE,
UPDATE_CHECK_MODULE,
} = vi.hoisted(() => ({
SIDEBAR_MANAGER_MODULE: new URL('../../../static/js/components/SidebarManager.js', import.meta.url).pathname,
STORAGE_HELPERS_MODULE: new URL('../../../static/js/utils/storageHelpers.js', import.meta.url).pathname,
MODEL_API_FACTORY_MODULE: new URL('../../../static/js/api/modelApiFactory.js', import.meta.url).pathname,
I18N_MODULE: new URL('../../../static/js/utils/i18nHelpers.js', import.meta.url).pathname,
BULK_MANAGER_MODULE: new URL('../../../static/js/managers/BulkManager.js', import.meta.url).pathname,
UI_HELPERS_MODULE: new URL('../../../static/js/utils/uiHelpers.js', import.meta.url).pathname,
UPDATE_CHECK_MODULE: new URL('../../../static/js/utils/updateCheckHelpers.js', import.meta.url).pathname,
}));
vi.mock(MODEL_API_FACTORY_MODULE, () => ({ getModelApiClient: vi.fn() }));
vi.mock(I18N_MODULE, () => ({ translate: (key, _args, fallback) => fallback || key }));
vi.mock(BULK_MANAGER_MODULE, () => ({ bulkManager: {} }));
vi.mock(UI_HELPERS_MODULE, () => ({ showToast: vi.fn(), showActionToast: vi.fn() }));
vi.mock(UPDATE_CHECK_MODULE, () => ({ performFolderUpdateCheck: vi.fn() }));
const { SidebarManager } = await import(SIDEBAR_MANAGER_MODULE);
const { setStorageItem, getStorageItem } = await import(STORAGE_HELPERS_MODULE);
function createManager({ isVlmActive = false, isInitialized = true } = {}) {
const manager = new SidebarManager();
manager.pageType = 'loras';
manager.selectedPath = 'Styles';
manager.treeData = {};
manager.displayMode = 'tree';
manager.isInitialized = isInitialized;
manager.updateTreeSelection = vi.fn();
manager.updateBreadcrumbs = vi.fn();
manager.updateSidebarHeader = vi.fn();
const resetAndReload = vi.fn(async () => {});
manager.pageControls = {
pageState: { activeFolder: 'Styles' },
isVlmActive: vi.fn(() => isVlmActive),
exitVlmForNavigation: vi.fn(),
resetAndReload,
};
setStorageItem('loras_activeFolder', 'Styles');
return { manager, resetAndReload };
}
describe('SidebarManager View Local Versions folder handoff', () => {
it('leaves View Local Versions before applying a picked folder', async () => {
const { manager, resetAndReload } = createManager({ isVlmActive: true });
await manager.selectFolder('Pets');
// VLM is library-wide: picking a folder must end it, not be ignored
expect(manager.pageControls.exitVlmForNavigation).toHaveBeenCalledTimes(1);
expect(manager.pageControls.pageState.activeFolder).toBe('Pets');
expect(manager.selectedPath).toBe('Pets');
expect(getStorageItem('loras_activeFolder')).toBe('Pets');
expect(resetAndReload).toHaveBeenCalledTimes(1);
});
it('leaves the View Local Versions state alone when it is inactive', async () => {
const { manager } = createManager({ isVlmActive: false });
await manager.selectFolder('Pets');
expect(manager.pageControls.exitVlmForNavigation).not.toHaveBeenCalled();
});
it('follows a folder chosen outside the sidebar without reloading', () => {
const { manager, resetAndReload } = createManager();
manager.applyFolderSelection(null);
expect(manager.selectedPath).toBe('');
expect(manager.updateTreeSelection).toHaveBeenCalled();
expect(manager.updateBreadcrumbs).toHaveBeenCalled();
expect(manager.updateSidebarHeader).toHaveBeenCalled();
expect(resetAndReload).not.toHaveBeenCalled();
// The sidebar only mirrors the selection; PageControls owns persistence
expect(getStorageItem('loras_activeFolder')).toBe('Styles');
});
it('selects a restored folder', () => {
const { manager } = createManager();
manager.selectedPath = '';
manager.applyFolderSelection('Styles');
expect(manager.selectedPath).toBe('Styles');
});
it('only records the selection before the sidebar is initialized', () => {
const { manager } = createManager({ isInitialized: false });
// initialize() restores the persisted selection itself; painting now would
// touch a tree without data (and updateBreadcrumbs without an API client)
manager.applyFolderSelection(null);
expect(manager.selectedPath).toBe('');
expect(manager.updateTreeSelection).not.toHaveBeenCalled();
expect(manager.updateBreadcrumbs).not.toHaveBeenCalled();
});
});