fix(thumbnails): say when the thumbnail settings could not be read
Like Appearance's other server rows, the Thumbnails rows show 'Server settings could not be read.' while the read failed, instead of only staying disabled. Firefox exposed the gap: its JPEG XL note arrived first and changed the row notes the page workflow counted.
This commit is contained in:
@@ -650,14 +650,16 @@ test('server settings that cannot be read say so in their rows', async ({ page }
|
||||
? route.fulfill({ status: 500, contentType: 'application/json', body: JSON.stringify({ success: false, error: 'Injected failure' }) })
|
||||
: route.continue()));
|
||||
await page.goto(`${workspace}#/system/appearance`);
|
||||
for (const id of ['open-mode', 'timeout']) {
|
||||
// #317: the Thumbnails rows are server settings too.
|
||||
for (const id of ['open-mode', 'timeout', 'thumbnail-format', 'thumbnail-quality', 'thumbnail-edge']) {
|
||||
const row = page.locator('#workspace-main .setting-row').filter({ has: page.locator(`#${id}`) });
|
||||
await expect(row.locator('p.small')).toHaveText('Server settings could not be read.');
|
||||
await expect(row.locator('p.small').first()).toHaveText('Server settings could not be read.');
|
||||
await expect(page.locator(`#${id}`)).toBeDisabled();
|
||||
}
|
||||
// The browser rows are this browser's, and work as before.
|
||||
await expect(page.locator('#default-view')).toBeEnabled();
|
||||
await expect(page.locator('#workspace-main .setting-row p.small')).toHaveCount(2);
|
||||
await expect(page.locator('#workspace-main .setting-row p.small', { hasText: 'Server settings could not be read.' })).toHaveCount(5);
|
||||
await expect(page.locator('#workspace-main section.surface').first().locator('.setting-row p.small')).toHaveCount(2);
|
||||
});
|
||||
|
||||
test('stale revision shows the conflict status', async ({ page, request }) => {
|
||||
|
||||
@@ -67,7 +67,7 @@ const HOST = { thumbnail_format: 'webp', thumbnail_quality: 80, thumbnail_edge:
|
||||
const NO_JXL = { webp: { available: true }, jpeg: { available: true },
|
||||
jxl: { available: false, encoder: null, reason: 'No JPEG XL encoder found. Install pillow-jxl-plugin.' } };
|
||||
|
||||
async function mounted({ host = HOST, browserJxl = true, writeHost = async () => ({ success: true, persisted: true, revision: 'sha256:two' }) } = {}) {
|
||||
async function mounted({ host = HOST, browserJxl = true, hostFails = false, writeHost = async () => ({ success: true, persisted: true, revision: 'sha256:two' }) } = {}) {
|
||||
const { mountThumbnailSettings } = await thumbnailsModule;
|
||||
const { createSystemDrafts } = await stateModule;
|
||||
const { createScope } = await coreModule;
|
||||
@@ -75,7 +75,7 @@ async function mounted({ host = HOST, browserJxl = true, writeHost = async () =>
|
||||
let hostValues = null;
|
||||
const drafts = createSystemDrafts({
|
||||
readBrowser: () => ({}), readRuntime: () => ({}),
|
||||
readHost: async () => ({ values: hostValues, revision: 'sha256:one' }),
|
||||
readHost: async () => { if (hostFails) throw new Error('offline'); return { values: hostValues, revision: 'sha256:one' }; },
|
||||
writeBrowser: async () => ({ persisted: true }), writeHost, writeRuntime: async () => ({}),
|
||||
});
|
||||
const scope = createScope();
|
||||
@@ -181,3 +181,15 @@ test('Convert outdated opens Thumbnail maintenance on its convert scope; a forma
|
||||
assert.equal(reviews.length, 1, 'nothing starts by itself');
|
||||
} finally { scope.dispose(); assert.equal(dom.listenerCount(), 0); dom.restore(); }
|
||||
});
|
||||
|
||||
test('rows whose server settings could not be read say so, like Appearance’s host rows', async () => {
|
||||
const { HOST_UNAVAILABLE } = await import('../../web/js/workspace/system-appearance.mjs');
|
||||
const { dom, drafts, scope, surface, byId } = await mounted({ hostFails: true });
|
||||
const notes = () => surface.children.slice(2, 5).map(row => row.children[0].children.slice(2).map(note => note.textContent));
|
||||
try {
|
||||
assert.deepEqual(notes(), [[], [], []]);
|
||||
assert.equal(await drafts.reloadHost(), false);
|
||||
assert.deepEqual(notes(), [[HOST_UNAVAILABLE], [HOST_UNAVAILABLE], [HOST_UNAVAILABLE]]);
|
||||
for (const id of ['thumbnail-format', 'thumbnail-quality', 'thumbnail-edge']) assert.equal(byId(id).disabled, true, id);
|
||||
} finally { scope.dispose(); assert.equal(dom.listenerCount(), 0); dom.restore(); }
|
||||
});
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
* automatic. After a save that changed the format, its line says existing previews keep their old format until
|
||||
* converted.
|
||||
*
|
||||
* Host rows stay disabled until the server settings were read, like Appearance's.
|
||||
* Host rows stay disabled until the server settings were read, like Appearance's, and say "Server settings could not
|
||||
* be read." while a read failed.
|
||||
*/
|
||||
import { settingRow, operationRow } from './system-controls.mjs';
|
||||
import { detectJxlSupport } from './thumbnail-support.mjs';
|
||||
import { openThumbnailReview } from './thumbnail-review.mjs';
|
||||
import { HOST_UNAVAILABLE } from './system-appearance.mjs';
|
||||
|
||||
export const FORMAT_OPTIONS = Object.freeze([['webp', 'WebP'], ['jxl', 'JPEG XL'], ['jpeg', 'JPEG']]);
|
||||
export const QUALITY_LIMIT = Object.freeze({ min: 1, max: 100 });
|
||||
@@ -84,7 +86,6 @@ export function mountThumbnailSettings(container, { scope, drafts, api, activity
|
||||
let browserJxl;
|
||||
let savedFormat;
|
||||
const format = controls[0];
|
||||
const notes = [];
|
||||
const repaint = () => {
|
||||
const encoders = drafts.get('host', 'thumbnail_encoders');
|
||||
for (const { input, key } of controls) {
|
||||
@@ -95,12 +96,13 @@ export function mountThumbnailSettings(container, { scope, drafts, api, activity
|
||||
const jxl = Array.from(format.input.children).find(option => option.value === 'jxl');
|
||||
const unavailable = encoders?.jxl?.available === false;
|
||||
if (jxl) jxl.disabled = unavailable;
|
||||
for (const note of notes.splice(0)) note.remove();
|
||||
const lines = [unavailable ? encoders.jxl.reason : null, browserJxl === false ? BROWSER_NO_JXL : null];
|
||||
for (const line of lines.filter(Boolean)) {
|
||||
const note = el('p', line, 'small');
|
||||
format.text.append(note);
|
||||
notes.push(note);
|
||||
const failed = drafts.hostState?.() === 'failed';
|
||||
for (const row of controls) {
|
||||
for (const note of row.notes ?? []) note.remove();
|
||||
const lines = [failed && drafts.get('host', row.key) === undefined ? HOST_UNAVAILABLE : null];
|
||||
if (row === format) lines.push(unavailable ? encoders.jxl.reason : null, browserJxl === false ? BROWSER_NO_JXL : null);
|
||||
row.notes = lines.filter(Boolean).map(line => el('p', line, 'small'));
|
||||
row.text.append(...row.notes);
|
||||
}
|
||||
// A format save (not the first read) leaves the existing previews outdated: say so, never convert.
|
||||
const saved = drafts.saved('host').thumbnail_format;
|
||||
|
||||
Reference in New Issue
Block a user