fix(workspace): rescan refreshed images and expose ancestor folders
This commit is contained in:
@@ -145,6 +145,13 @@ def create_app(root: Path) -> web.Application:
|
||||
await api._run_in_executor(seed, extra, include_video)
|
||||
return web.json_response({"success": True})
|
||||
|
||||
@routes.post("/__test__/add-nested-image")
|
||||
async def add_nested_image(request: web.Request) -> web.Response:
|
||||
destination = root / "output" / "project" / "day" / "new-output.png"
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(root / "output" / "shared" / "same.png", destination)
|
||||
return web.json_response({"success": True})
|
||||
|
||||
@routes.get("/api/settings/Comfy.ColorPalette")
|
||||
async def palette(request: web.Request) -> web.Response:
|
||||
return web.json_response("dark")
|
||||
|
||||
@@ -433,3 +433,50 @@ test('refresh releases the previous inspector video source', async ({ page, requ
|
||||
await expect.poll(() => page.evaluate(() => !window.__oldInspectorVideo.isConnected)).toBe(true);
|
||||
expect(await page.evaluate(() => window.__oldInspectorVideo.getAttribute('src'))).toBeNull();
|
||||
});
|
||||
|
||||
test('Refresh rescans cached files and preserves the collection when rescan fails', async ({ page, request }) => {
|
||||
await page.goto(workspace);
|
||||
await expect(cards(page)).toHaveCount(2);
|
||||
await expect(await request.post('/__test__/add-nested-image')).toBeOK();
|
||||
await page.route('**/prompt_manager/gallery/rescan', route => route.fulfill({
|
||||
status: 503, json: { success: false, error: 'Rescan unavailable' },
|
||||
}), { times: 1 });
|
||||
await page.getByRole('button', { name: 'Refresh', exact: true }).click();
|
||||
await expect(page.getByRole('alert')).toContainText('could not be refreshed');
|
||||
await expect(cards(page)).toHaveCount(2);
|
||||
await page.getByRole('button', { name: 'Refresh', exact: true }).click();
|
||||
await expect(cards(page)).toHaveCount(3);
|
||||
await expect(cards(page).filter({ hasText: 'new-output.png' })).toHaveCount(1);
|
||||
await expect(page.getByRole('alert')).toBeHidden();
|
||||
});
|
||||
|
||||
test('folder discovery offers ancestors that filter nested images', async ({ page, request }) => {
|
||||
await expect(await request.post('/__test__/add-nested-image')).toBeOK();
|
||||
await page.goto(workspace);
|
||||
await expect(cards(page)).toHaveCount(3);
|
||||
const folder = page.getByRole('combobox', { name: 'Folder', exact: true });
|
||||
await expect(folder.locator('option[value="project"]')).toHaveCount(1);
|
||||
await folder.selectOption('project');
|
||||
await expect(cards(page)).toHaveCount(1);
|
||||
await expect(cards(page)).toContainText('new-output.png');
|
||||
});
|
||||
|
||||
test('leaving during Refresh cancels it without replacing the next workspace', async ({ page }) => {
|
||||
let release;
|
||||
const pending = new Promise(resolve => { release = resolve; });
|
||||
await page.route('**/prompt_manager/gallery/rescan', async route => {
|
||||
await pending;
|
||||
await route.fulfill({ json: { success: true } }).catch(() => {});
|
||||
});
|
||||
await page.goto(workspace);
|
||||
await expect(cards(page)).toHaveCount(2);
|
||||
const requested = page.waitForRequest('**/prompt_manager/gallery/rescan');
|
||||
await page.getByRole('button', { name: 'Refresh', exact: true }).click();
|
||||
await requested;
|
||||
await page.getByRole('navigation', { name: 'Workspace', exact: true })
|
||||
.getByRole('link', { name: 'Overview', exact: true }).click();
|
||||
await expect(page.locator('#workspace-main h1')).toHaveText('Overview');
|
||||
release();
|
||||
await expect(page.getByRole('heading', { name: 'Continue creating', exact: true })).toBeVisible();
|
||||
await expect(page.getByText('Images could not be refreshed. Try Refresh again.', { exact: true })).toHaveCount(0);
|
||||
});
|
||||
|
||||
@@ -61,7 +61,24 @@ export function mountImages(main, api, parentScope) {
|
||||
layouts.append(button);
|
||||
}
|
||||
const refresh = createButton('Refresh');
|
||||
scope.listen(refresh, 'click', () => { loadOptions(); reset(); });
|
||||
scope.listen(refresh, 'click', async () => {
|
||||
if (refresh.disabled) return;
|
||||
refresh.disabled = true;
|
||||
optionsRequest?.abort(); optionsRequest = null;
|
||||
optionsStatus.hidden = true;
|
||||
try {
|
||||
await api.post('/prompt_manager/gallery/rescan', {}, {signal:scope.signal});
|
||||
if (scope.signal.aborted) return;
|
||||
await loadOptions();
|
||||
if (!scope.signal.aborted) reset();
|
||||
} catch {
|
||||
if (scope.signal.aborted) return;
|
||||
optionsStatus.textContent = 'Images could not be refreshed. Try Refresh again.';
|
||||
optionsStatus.hidden = false;
|
||||
} finally {
|
||||
refresh.disabled = false;
|
||||
}
|
||||
});
|
||||
const currentGallery = el('a', 'Current gallery', 'workspace-link');
|
||||
currentGallery.href = resolveUrl('/prompt_manager/gallery');
|
||||
toolbar.append(count, layouts, refresh, currentGallery);
|
||||
@@ -307,7 +324,7 @@ export function mountImages(main, api, parentScope) {
|
||||
optionsRequest?.abort();
|
||||
const request = new AbortController(); optionsRequest = request;
|
||||
try {
|
||||
const params = new URLSearchParams({mode:'workspace'});
|
||||
const params = new URLSearchParams({mode:'workspace', include_ancestors:'true'});
|
||||
if (filters.root !== 'all') params.set('root', filters.root);
|
||||
const data = await api.get(`/prompt_manager/gallery/subfolders?${params}`, {signal:request.signal});
|
||||
if (scope.signal.aborted || request !== optionsRequest) return;
|
||||
|
||||
Reference in New Issue
Block a user