mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-21 19:21:27 -03:00
feat(frontend): opt-in Other Models toggles, hidden nav and announcement
- The Other nav entry is hidden while the feature is off (nav-item--hidden, toggled client-side after enabling) and now uses the fa-shapes icon. - Shared utils/otherModels.js helpers (enable through the settings API, open the settings Library section) are reused by the disabled page, the announcement banner and the download modal. - BannerService registers a one-time dismissible "other-models-announcement" banner while the feature is off; SettingsManager drops the banner and updates the nav when the master switch flips. - A disabled download routing answer now surfaces a showActionToast with an "Enable Other Models" action. - Settings UI: master toggle + five sub_type checkboxes whose default-root selects are disabled when unchecked; i18n keys added to en.json and synced (other locales keep TODO placeholders).
This commit is contained in:
@@ -27,6 +27,14 @@ vi.mock('../../../static/js/state/index.js', () => ({
|
||||
}
|
||||
}));
|
||||
|
||||
// Mock the shared Other Models helpers (exercised by their own tests)
|
||||
vi.mock('../../../static/js/utils/otherModels.js', () => ({
|
||||
enableOtherModels: vi.fn().mockResolvedValue(),
|
||||
openOtherModelsSettings: vi.fn(),
|
||||
}));
|
||||
|
||||
import { enableOtherModels, openOtherModelsSettings } from '../../../static/js/utils/otherModels.js';
|
||||
|
||||
describe('BannerService', () => {
|
||||
beforeEach(() => {
|
||||
// Clear all mocks
|
||||
@@ -186,6 +194,91 @@ describe('BannerService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Other Models announcement', () => {
|
||||
const OTHER_MODELS_BANNER_ID = 'other-models-announcement';
|
||||
|
||||
const prepareBanner = (dismissed = []) => {
|
||||
storageHelpers.getStorageItem.mockImplementation((key, defaultValue) => {
|
||||
if (key === 'dismissed_banners') {
|
||||
return dismissed;
|
||||
}
|
||||
return defaultValue;
|
||||
});
|
||||
bannerService.container = document.getElementById('banner-container');
|
||||
bannerService.initialized = true;
|
||||
bannerService.prepareOtherModelsBanner();
|
||||
};
|
||||
|
||||
const bannerElement = () =>
|
||||
document.querySelector(`[data-banner-id="${OTHER_MODELS_BANNER_ID}"]`);
|
||||
|
||||
beforeEach(() => {
|
||||
state.global.settings.enable_other_models = false;
|
||||
});
|
||||
|
||||
it('announces the feature while it is switched off', () => {
|
||||
prepareBanner();
|
||||
|
||||
const element = bannerElement();
|
||||
expect(element).not.toBeNull();
|
||||
expect(element.querySelector('.banner-title').textContent)
|
||||
.toContain('Other Models Management is available');
|
||||
});
|
||||
|
||||
it('stays silent once the feature is enabled', () => {
|
||||
state.global.settings.enable_other_models = true;
|
||||
|
||||
prepareBanner();
|
||||
|
||||
expect(bannerElement()).toBeNull();
|
||||
});
|
||||
|
||||
it('stays silent when it was dismissed before', () => {
|
||||
prepareBanner([OTHER_MODELS_BANNER_ID]);
|
||||
|
||||
expect(bannerElement()).toBeNull();
|
||||
});
|
||||
|
||||
it('enables the feature from the primary action', () => {
|
||||
prepareBanner();
|
||||
|
||||
const button = bannerElement().querySelector(
|
||||
'.banner-action[data-action="enable-other-models"]'
|
||||
);
|
||||
expect(button).not.toBeNull();
|
||||
|
||||
button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||
|
||||
expect(enableOtherModels).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('opens the settings section from the secondary action', () => {
|
||||
prepareBanner();
|
||||
|
||||
const button = bannerElement().querySelector(
|
||||
'.banner-action[data-action="open-other-models-settings"]'
|
||||
);
|
||||
expect(button).not.toBeNull();
|
||||
|
||||
button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||
|
||||
expect(openOtherModelsSettings).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('can drop the announcement without dismissing it', () => {
|
||||
prepareBanner();
|
||||
expect(bannerService.banners.has(OTHER_MODELS_BANNER_ID)).toBe(true);
|
||||
|
||||
bannerService.removeOtherModelsAnnouncement();
|
||||
|
||||
expect(bannerService.banners.has(OTHER_MODELS_BANNER_ID)).toBe(false);
|
||||
expect(storageHelpers.setStorageItem).not.toHaveBeenCalledWith(
|
||||
'dismissed_banners',
|
||||
expect.arrayContaining([OTHER_MODELS_BANNER_ID])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Banner Dismissal', () => {
|
||||
it('should add banner to dismissed_banners array when dismissed', () => {
|
||||
storageHelpers.getStorageItem.mockImplementation((key, defaultValue) => {
|
||||
|
||||
Reference in New Issue
Block a user