mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-21 19:21:27 -03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed7cf418b4 |
@@ -286,4 +286,93 @@ const autoComplete = new AutoComplete(input, 'loras', { showPreview: false, minC
|
|||||||
window.removeEventListener('lora-manager:setting-toggled', listener);
|
window.removeEventListener('lora-manager:setting-toggled', listener);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes a stale first-run hint when the toggle is switched on while the dropdown stays open', async () => {
|
||||||
|
localStorage.removeItem('lm:activefilters-tip-dismissed');
|
||||||
|
let enabled = false;
|
||||||
|
settingGetMock.mockImplementation((key) => {
|
||||||
|
if (key === 'loramanager.lora_active_filters_autocomplete') return enabled;
|
||||||
|
if (key === 'loramanager.autocomplete_append_comma') return false;
|
||||||
|
if (key === 'loramanager.autocomplete_auto_format') return false;
|
||||||
|
if (key === 'loramanager.autocomplete_accept_key') return 'both';
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
fetchApiMock.mockResolvedValue({
|
||||||
|
json: () => Promise.resolve({ success: true, relative_paths: ['models/example.safetensors'] }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = document.createElement('textarea');
|
||||||
|
input.value = 'example';
|
||||||
|
input.selectionStart = 7;
|
||||||
|
document.body.append(input);
|
||||||
|
caretHelperInstance.getBeforeCursor.mockReturnValue('example');
|
||||||
|
|
||||||
|
const { AutoComplete } = await import(AUTOCOMPLETE_MODULE);
|
||||||
|
const autoComplete = new AutoComplete(input, 'loras', {
|
||||||
|
debounceDelay: 0,
|
||||||
|
showPreview: false,
|
||||||
|
minChars: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const triggerShow = async () => {
|
||||||
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
await vi.runOnlyPendingTimersAsync();
|
||||||
|
await vi.runOnlyPendingTimersAsync();
|
||||||
|
await Promise.resolve();
|
||||||
|
return autoComplete.dropdown.querySelector('.lm-autocomplete-first-run-hint');
|
||||||
|
};
|
||||||
|
|
||||||
|
// OFF → the enable hint is shown in the suggestions dropdown.
|
||||||
|
expect(await triggerShow()).not.toBeNull();
|
||||||
|
|
||||||
|
// The node's filter chip toggles the setting ON while the dropdown is
|
||||||
|
// still open (ComfyUI can keep focus in the textarea, so no blur/hide
|
||||||
|
// fires). settings.js broadcasts the setting-toggled event.
|
||||||
|
enabled = true;
|
||||||
|
window.dispatchEvent(new CustomEvent('lora-manager:setting-toggled', {
|
||||||
|
detail: { settingId: 'loramanager.lora_active_filters_autocomplete', value: true },
|
||||||
|
}));
|
||||||
|
|
||||||
|
// The stale OFF hint must be gone even though the dropdown never closed.
|
||||||
|
expect(autoComplete.dropdown.querySelector('.lm-autocomplete-first-run-hint')).toBeNull();
|
||||||
|
|
||||||
|
// Further typing while ON must not resurrect the enable hint.
|
||||||
|
expect(await triggerShow()).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates the command-list footer when the toggle changes while the command list is open', async () => {
|
||||||
|
let enabled = false;
|
||||||
|
settingGetMock.mockImplementation((key) => {
|
||||||
|
if (key === 'loramanager.lora_active_filters_autocomplete') return enabled;
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = document.createElement('textarea');
|
||||||
|
input.value = '/';
|
||||||
|
input.selectionStart = 1;
|
||||||
|
document.body.append(input);
|
||||||
|
caretHelperInstance.getBeforeCursor.mockReturnValue('/');
|
||||||
|
|
||||||
|
const { AutoComplete } = await import(AUTOCOMPLETE_MODULE);
|
||||||
|
const autoComplete = new AutoComplete(input, 'loras', { showPreview: false, minChars: 1 });
|
||||||
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
await vi.runOnlyPendingTimersAsync();
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
const footer = () => autoComplete.dropdown.querySelector('.lm-autocomplete-command-footer');
|
||||||
|
expect(footer()).not.toBeNull();
|
||||||
|
expect(footer().textContent).toContain('Active Filters Search: OFF');
|
||||||
|
expect(footer().textContent).toContain('/activefilters to enable');
|
||||||
|
|
||||||
|
enabled = true;
|
||||||
|
window.dispatchEvent(new CustomEvent('lora-manager:setting-toggled', {
|
||||||
|
detail: { settingId: 'loramanager.lora_active_filters_autocomplete', value: true },
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(footer()).not.toBeNull();
|
||||||
|
expect(footer().textContent).toContain('Active Filters Search: ON');
|
||||||
|
expect(footer().textContent).toContain('/noactivefilters to disable');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ import {
|
|||||||
getAutocompleteAppendCommaPreference,
|
getAutocompleteAppendCommaPreference,
|
||||||
getAutocompleteAutoFormatPreference,
|
getAutocompleteAutoFormatPreference,
|
||||||
getAutocompleteAcceptKeyPreference,
|
getAutocompleteAcceptKeyPreference,
|
||||||
|
LORA_ACTIVE_FILTERS_AUTOCOMPLETE_SETTING_ID,
|
||||||
getLoraActiveFiltersAutocompletePreference,
|
getLoraActiveFiltersAutocompletePreference,
|
||||||
getPromptTagAutocompletePreference,
|
getPromptTagAutocompletePreference,
|
||||||
getTagSpaceReplacementPreference,
|
getTagSpaceReplacementPreference,
|
||||||
|
SETTING_TOGGLED_EVENT_NAME,
|
||||||
setLoraManagerSettingValue,
|
setLoraManagerSettingValue,
|
||||||
} from "./settings.js";
|
} from "./settings.js";
|
||||||
import { showToast } from "./utils.js";
|
import { showToast } from "./utils.js";
|
||||||
@@ -607,6 +609,7 @@ class AutoComplete {
|
|||||||
this.onBlur = null;
|
this.onBlur = null;
|
||||||
this.onDocumentClick = null;
|
this.onDocumentClick = null;
|
||||||
this.onScroll = null;
|
this.onScroll = null;
|
||||||
|
this.onSettingToggled = null;
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
@@ -774,6 +777,22 @@ class AutoComplete {
|
|||||||
};
|
};
|
||||||
document.addEventListener('click', this.onDocumentClick);
|
document.addEventListener('click', this.onDocumentClick);
|
||||||
|
|
||||||
|
// React to setting changes that happen underneath an open dropdown
|
||||||
|
// (e.g. toggling the active-filters search from the node's filter
|
||||||
|
// chip can keep the dropdown open in ComfyUI). Refresh the state
|
||||||
|
// hints so they never show a message for the previous state.
|
||||||
|
if (this.onSettingToggled) {
|
||||||
|
window.removeEventListener(SETTING_TOGGLED_EVENT_NAME, this.onSettingToggled);
|
||||||
|
}
|
||||||
|
this.onSettingToggled = (e) => {
|
||||||
|
const detail = e && e.detail;
|
||||||
|
if (!detail || detail.settingId !== LORA_ACTIVE_FILTERS_AUTOCOMPLETE_SETTING_ID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._refreshStateHints();
|
||||||
|
};
|
||||||
|
window.addEventListener(SETTING_TOGGLED_EVENT_NAME, this.onSettingToggled);
|
||||||
|
|
||||||
// Mark this element as having autocomplete events bound
|
// Mark this element as having autocomplete events bound
|
||||||
this.inputElement._autocompleteEventsBound = true;
|
this.inputElement._autocompleteEventsBound = true;
|
||||||
|
|
||||||
@@ -1811,15 +1830,37 @@ class AutoComplete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh state-dependent dropdown decorations (first-run Tip and the
|
||||||
|
* slash-command-list footer) from the live setting. Called when the
|
||||||
|
* active-filters toggle changes underneath an open dropdown, so the
|
||||||
|
* dropdown never keeps showing a message for the previous state.
|
||||||
|
*/
|
||||||
|
_refreshStateHints() {
|
||||||
|
if (!this.isVisible || this.modelType !== 'loras') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.showingCommands) {
|
||||||
|
// Command list: footer text carries the ON/OFF state.
|
||||||
|
this._renderCommandListFooter();
|
||||||
|
} else {
|
||||||
|
// Plain suggestions: the first-run Tip advertises /activefilters
|
||||||
|
// only while the feature is disabled.
|
||||||
|
this._maybeShowFirstRunHint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a one-time, dismissible hint inside the dropdown surfacing the
|
* Show a one-time, dismissible hint inside the dropdown surfacing the
|
||||||
* toggle commands: prompt nodes advertise /noautocomplete, loras nodes
|
* toggle commands: prompt nodes advertise /noautocomplete, loras nodes
|
||||||
* advertise /activefilters. Dismissal is persisted in localStorage.
|
* advertise /activefilters. Dismissal is persisted in localStorage.
|
||||||
*/
|
*/
|
||||||
_maybeShowFirstRunHint() {
|
_maybeShowFirstRunHint() {
|
||||||
if (this.firstRunHint) {
|
// Dropdown decorations can outlive a state change (the dropdown may
|
||||||
return;
|
// stay open when the setting is toggled from the node, e.g. clicking
|
||||||
}
|
// the active-filters filter chip). Always recompute from the live
|
||||||
|
// state so a stale Tip is never kept for the previous state.
|
||||||
|
this._removeFirstRunHint();
|
||||||
|
|
||||||
let hintText = null;
|
let hintText = null;
|
||||||
let storageKey = null;
|
let storageKey = null;
|
||||||
@@ -3178,6 +3219,11 @@ class AutoComplete {
|
|||||||
this.onDocumentClick = null;
|
this.onDocumentClick = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.onSettingToggled) {
|
||||||
|
window.removeEventListener(SETTING_TOGGLED_EVENT_NAME, this.onSettingToggled);
|
||||||
|
this.onSettingToggled = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.onScroll && this.scrollContainer) {
|
if (this.onScroll && this.scrollContainer) {
|
||||||
this.scrollContainer.removeEventListener('scroll', this.onScroll);
|
this.scrollContainer.removeEventListener('scroll', this.onScroll);
|
||||||
this.onScroll = null;
|
this.onScroll = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user