feat(example-images): add remote open mode support

This commit is contained in:
Will Miao
2026-04-27 14:05:21 +08:00
parent cc147a1795
commit ffe0670a27
20 changed files with 621 additions and 21 deletions

View File

@@ -340,4 +340,52 @@ describe('SettingsManager library controls', () => {
expect(aria2PathSetting.style.display).toBe('none');
expect(saveSpy).toHaveBeenCalledWith('downloadBackend', 'download_backend');
});
it('loads example image remote-open settings and updates field visibility', async () => {
const manager = createManager();
document.body.innerHTML = `
<select id="exampleImagesOpenMode">
<option value="system">System</option>
<option value="clipboard">Clipboard</option>
<option value="uri_template">URI</option>
</select>
<div id="exampleImagesLocalRootSetting" style="display: none;"></div>
<div id="exampleImagesUriTemplateSetting" style="display: none;"></div>
<input id="exampleImagesLocalRoot" />
<input id="exampleImagesOpenUriTemplate" />
`;
vi.spyOn(manager, 'loadMetadataArchiveSettings').mockResolvedValue();
vi.spyOn(manager, 'loadBackupSettings').mockResolvedValue();
vi.spyOn(manager, 'loadLibraries').mockResolvedValue();
vi.spyOn(manager, 'loadLoraRoots').mockResolvedValue();
vi.spyOn(manager, 'loadCheckpointRoots').mockResolvedValue();
vi.spyOn(manager, 'loadUnetRoots').mockResolvedValue();
vi.spyOn(manager, 'loadEmbeddingRoots').mockResolvedValue();
state.global.settings = {
example_images_open_mode: 'uri_template',
example_images_local_root: '/Volumes/ComfyUI/examples',
example_images_open_uri_template: 'shortcuts://run-shortcut?text={{encoded_local_path}}',
};
await manager.loadSettingsToUI();
expect(document.getElementById('exampleImagesOpenMode').value).toBe('uri_template');
expect(document.getElementById('exampleImagesLocalRoot').value).toBe('/Volumes/ComfyUI/examples');
expect(document.getElementById('exampleImagesOpenUriTemplate').value)
.toBe('shortcuts://run-shortcut?text={{encoded_local_path}}');
expect(document.getElementById('exampleImagesLocalRootSetting').style.display).toBe('block');
expect(document.getElementById('exampleImagesUriTemplateSetting').style.display).toBe('block');
state.global.settings.example_images_open_mode = 'clipboard';
manager.updateExampleImagesOpenSettingsVisibility();
expect(document.getElementById('exampleImagesLocalRootSetting').style.display).toBe('block');
expect(document.getElementById('exampleImagesUriTemplateSetting').style.display).toBe('none');
state.global.settings.example_images_open_mode = 'system';
manager.updateExampleImagesOpenSettingsVisibility();
expect(document.getElementById('exampleImagesLocalRootSetting').style.display).toBe('none');
expect(document.getElementById('exampleImagesUriTemplateSetting').style.display).toBe('none');
});
});

View File

@@ -84,6 +84,8 @@ describe('UI helper DOM utilities', () => {
afterEach(() => {
vi.useRealTimers();
delete global.fetch;
delete navigator.clipboard;
delete window.open;
});
it('creates toast elements and cleans them up after timeout', async () => {
@@ -230,4 +232,49 @@ describe('UI helper DOM utilities', () => {
'noopener,noreferrer'
);
});
it('copies mapped local example-image paths when the backend requests clipboard mode', async () => {
global.fetch = vi.fn().mockResolvedValue({
json: async () => ({
success: true,
mode: 'clipboard',
path: '/Volumes/ComfyUI/examples/demo',
}),
});
navigator.clipboard = {
writeText: vi.fn().mockResolvedValue(),
};
const { openExampleImagesFolder } = await import(UI_HELPERS_MODULE);
const result = await openExampleImagesFolder('abc123');
expect(result).toBe(true);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('/Volumes/ComfyUI/examples/demo');
expect(global.fetch).toHaveBeenCalledWith('/api/lm/open-example-images-folder', expect.objectContaining({
method: 'POST',
}));
});
it('opens custom URIs for example-image folders when requested by the backend', async () => {
global.fetch = vi.fn().mockResolvedValue({
json: async () => ({
success: true,
mode: 'uri',
uri: 'shortcuts://run-shortcut?name=OpenFinder',
}),
});
window.open = vi.fn(() => ({}));
const { openExampleImagesFolder } = await import(UI_HELPERS_MODULE);
const result = await openExampleImagesFolder('abc123');
expect(result).toBe(true);
expect(window.open).toHaveBeenCalledWith(
'shortcuts://run-shortcut?name=OpenFinder',
'_blank',
'noopener,noreferrer'
);
});
});

View File

@@ -66,6 +66,97 @@ async def test_open_folder_requires_existing_model_directory(monkeypatch: pytest
assert model_hash in popen_calls[0][-1]
async def test_open_folder_returns_clipboard_mode_with_mapped_local_path(
monkeypatch: pytest.MonkeyPatch, tmp_path
) -> None:
settings_manager = get_settings_manager()
settings_manager.settings["example_images_path"] = str(tmp_path)
settings_manager.settings["example_images_open_mode"] = "clipboard"
settings_manager.settings["example_images_local_root"] = "/Volumes/ComfyUI/examples"
model_hash = "d" * 64
model_folder = tmp_path / "library-a" / model_hash
model_folder.mkdir(parents=True)
(model_folder / "image.png").write_text("data", encoding="utf-8")
popen_calls: list[list[str]] = []
class DummyPopen:
def __init__(self, cmd, *_args, **_kwargs):
popen_calls.append(cmd)
monkeypatch.setattr("subprocess.Popen", DummyPopen)
monkeypatch.setattr("py.utils.example_images_file_manager.get_model_folder", lambda _hash: str(model_folder))
request = JsonRequest({"model_hash": model_hash})
response = await ExampleImagesFileManager.open_folder(request)
body = json.loads(response.text)
assert response.status == 200
assert body == {
"success": True,
"mode": "clipboard",
"path": f"/Volumes/ComfyUI/examples/library-a/{model_hash}",
"relative_path": f"library-a/{model_hash}",
}
assert popen_calls == []
async def test_open_folder_returns_uri_mode_with_rendered_template(
monkeypatch: pytest.MonkeyPatch, tmp_path
) -> None:
settings_manager = get_settings_manager()
settings_manager.settings["example_images_path"] = str(tmp_path)
settings_manager.settings["example_images_open_mode"] = "uri_template"
settings_manager.settings["example_images_local_root"] = "/Volumes/ComfyUI/examples"
settings_manager.settings["example_images_open_uri_template"] = (
"shortcuts://run-shortcut?name=OpenFinder&input=text&text={{encoded_local_path}}"
)
model_hash = "e" * 64
model_folder = tmp_path / model_hash
model_folder.mkdir()
(model_folder / "image.png").write_text("data", encoding="utf-8")
popen_calls: list[list[str]] = []
class DummyPopen:
def __init__(self, cmd, *_args, **_kwargs):
popen_calls.append(cmd)
monkeypatch.setattr("subprocess.Popen", DummyPopen)
request = JsonRequest({"model_hash": model_hash})
response = await ExampleImagesFileManager.open_folder(request)
body = json.loads(response.text)
assert response.status == 200
assert body["success"] is True
assert body["mode"] == "uri"
assert body["path"] == f"/Volumes/ComfyUI/examples/{model_hash}"
assert body["relative_path"] == model_hash
assert body["uri"] == (
"shortcuts://run-shortcut?name=OpenFinder&input=text&text="
f"%2FVolumes%2FComfyUI%2Fexamples%2F{model_hash}"
)
assert popen_calls == []
async def test_open_folder_rejects_missing_uri_template(monkeypatch: pytest.MonkeyPatch, tmp_path) -> None:
settings_manager = get_settings_manager()
settings_manager.settings["example_images_path"] = str(tmp_path)
settings_manager.settings["example_images_open_mode"] = "uri_template"
model_hash = "f" * 64
model_folder = tmp_path / model_hash
model_folder.mkdir()
(model_folder / "image.png").write_text("data", encoding="utf-8")
response = await ExampleImagesFileManager.open_folder(JsonRequest({"model_hash": model_hash}))
body = json.loads(response.text)
assert response.status == 400
assert body["success"] is False
assert body["error"] == "No example image open URI template configured."
async def test_open_folder_rejects_invalid_paths(monkeypatch: pytest.MonkeyPatch, tmp_path) -> None:
settings_manager = get_settings_manager()
settings_manager.settings["example_images_path"] = str(tmp_path)