feat(versions): add base filter toggle UI and styling

Add CSS classes and JavaScript logic for the base filter toggle button in the versions toolbar. The filter allows users to switch between showing all versions or only versions matching the current base model. Includes styling for different states (active, hover, disabled) and accessibility features like screen reader support.
This commit is contained in:
Will Miao
2025-11-18 06:46:50 +08:00
parent 3661b11b70
commit 655157434e
13 changed files with 521 additions and 52 deletions

View File

@@ -28,7 +28,14 @@ vi.mock(UI_HELPERS_MODULE, () => ({
showToast: vi.fn(),
}));
const stateMock = { global: { settings: { autoplay_on_hover: false } } };
const stateMock = {
global: {
settings: {
autoplay_on_hover: false,
update_flag_strategy: 'any',
},
},
};
vi.mock(STATE_MODULE, () => ({
state: stateMock,
}));
@@ -59,6 +66,7 @@ describe('ModelVersionsTab media rendering', () => {
</div>
`;
stateMock.global.settings.autoplay_on_hover = false;
stateMock.global.settings.update_flag_strategy = 'any';
({ getModelApiClient } = await import(API_FACTORY_MODULE));
fetchModelUpdateVersions = vi.fn();
getModelApiClient.mockReturnValue({
@@ -146,4 +154,133 @@ describe('ModelVersionsTab media rendering', () => {
expect(imageElement?.getAttribute('src')).toBe(previewUrl);
expect(document.querySelector('.version-media video')).toBeFalsy();
});
it('shows a stable label with a short state indicator', async () => {
stateMock.global.settings.update_flag_strategy = 'any';
fetchModelUpdateVersions.mockResolvedValue({
success: true,
record: {
shouldIgnore: false,
inLibraryVersionIds: [5],
versions: [
{
versionId: 5,
name: 'base',
baseModel: 'SDXL',
previewUrl: '/api/lm/previews/v-base.png',
sizeBytes: 1024,
isInLibrary: true,
shouldIgnore: false,
},
],
},
});
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
const controller = initVersionsTab({
modalId: 'model-versions-modal',
modelType: 'loras',
modelId: 321,
currentVersionId: 5,
});
await controller.load();
const toggleText = document.querySelector('.versions-filter-toggle .sr-only');
expect(toggleText?.textContent?.trim()).toBe('Base filter: All versions');
});
it('filters versions to the current base model when strategy is same_base', async () => {
stateMock.global.settings.update_flag_strategy = 'same_base';
fetchModelUpdateVersions.mockResolvedValue({
success: true,
record: {
shouldIgnore: false,
inLibraryVersionIds: [10],
versions: [
{
versionId: 10,
name: 'v1.0',
baseModel: 'SDXL',
previewUrl: '/api/lm/previews/v1.png',
sizeBytes: 1024,
isInLibrary: true,
shouldIgnore: false,
},
{
versionId: 11,
name: 'v1.1',
baseModel: 'Realistic',
previewUrl: '/api/lm/previews/v1-1.png',
sizeBytes: 2048,
isInLibrary: false,
shouldIgnore: false,
},
],
},
});
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
const controller = initVersionsTab({
modalId: 'model-versions-modal',
modelType: 'loras',
modelId: 789,
currentVersionId: 10,
});
await controller.load();
expect(document.querySelectorAll('.model-version-row').length).toBe(1);
});
it('toggle button can switch to display all versions', async () => {
stateMock.global.settings.update_flag_strategy = 'same_base';
fetchModelUpdateVersions.mockResolvedValue({
success: true,
record: {
shouldIgnore: false,
inLibraryVersionIds: [10],
versions: [
{
versionId: 10,
name: 'v1.0',
baseModel: 'SDXL',
previewUrl: '/api/lm/previews/v1.png',
sizeBytes: 1024,
isInLibrary: true,
shouldIgnore: false,
},
{
versionId: 11,
name: 'v1.1',
baseModel: 'Realistic',
previewUrl: '/api/lm/previews/v1-1.png',
sizeBytes: 2048,
isInLibrary: false,
shouldIgnore: false,
},
],
},
});
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
const controller = initVersionsTab({
modalId: 'model-versions-modal',
modelType: 'loras',
modelId: 987,
currentVersionId: 10,
});
await controller.load();
expect(document.querySelectorAll('.model-version-row').length).toBe(1);
const toggleButton = document.querySelector('[data-versions-action="toggle-version-display-mode"]');
expect(toggleButton).toBeTruthy();
const toggleTextBefore = document.querySelector('.versions-filter-toggle .sr-only');
expect(toggleTextBefore?.textContent?.trim()).toContain('Same base');
toggleButton?.click();
expect(document.querySelectorAll('.model-version-row').length).toBe(2);
const toggleTextAfter = document.querySelector('.versions-filter-toggle .sr-only');
expect(toggleTextAfter?.textContent?.trim()).toContain('All versions');
});
});