Warn on small picture candidates
This commit is contained in:
@@ -186,6 +186,7 @@ There are three selectable data sources:
|
|||||||
- Source discovery: use manufacturer mapping from Local scrape DB and show exactly which source produced each candidate.
|
- Source discovery: use manufacturer mapping from Local scrape DB and show exactly which source produced each candidate.
|
||||||
- Browser scraping: use the configured browser engine per source and keep the UI responsive while scraping runs.
|
- Browser scraping: use the configured browser engine per source and keep the UI responsive while scraping runs.
|
||||||
- Image extraction: collect original image URLs, dimensions, mime type, file size and source page URL.
|
- Image extraction: collect original image URLs, dimensions, mime type, file size and source page URL.
|
||||||
|
- Image quality: show a clear warning for any picture candidate smaller than `800 x 800`; small thumbnails must remain visible for review but must be marked as not production-ready.
|
||||||
- Duplicate detection: calculate `sha256` for exact duplicates and perceptual hash for visually similar images.
|
- Duplicate detection: calculate `sha256` for exact duplicates and perceptual hash for visually similar images.
|
||||||
- Target assignment: propose whether pictures belong to `color`, `size`, `combination` or `manual` target, then learn from user corrections.
|
- Target assignment: propose whether pictures belong to `color`, `size`, `combination` or `manual` target, then learn from user corrections.
|
||||||
- Persistence: save picture blobs, candidates, hashes, source metadata and learned rules only into Local scrape DB.
|
- Persistence: save picture blobs, candidates, hashes, source metadata and learned rules only into Local scrape DB.
|
||||||
|
|||||||
+12
-3
@@ -61,6 +61,7 @@ const darkContrastSelect = document.querySelector("#darkContrastSelect");
|
|||||||
const catalogScreen = document.querySelector(".catalog-screen");
|
const catalogScreen = document.querySelector(".catalog-screen");
|
||||||
const secondaryPanelToggle = document.querySelector("#secondaryPanelToggle");
|
const secondaryPanelToggle = document.querySelector("#secondaryPanelToggle");
|
||||||
const mainWorkspaceToggle = document.querySelector("#mainWorkspaceToggle");
|
const mainWorkspaceToggle = document.querySelector("#mainWorkspaceToggle");
|
||||||
|
const MIN_PRODUCT_PICTURE_SIZE = 800;
|
||||||
let sidebarUserClosed = false;
|
let sidebarUserClosed = false;
|
||||||
let mappingLoadToken = 0;
|
let mappingLoadToken = 0;
|
||||||
const mappingCacheKey = "catalog-maker:mapping-cache";
|
const mappingCacheKey = "catalog-maker:mapping-cache";
|
||||||
@@ -906,12 +907,20 @@ function renderPictureCandidates(items) {
|
|||||||
dimensions.className = "picture-candidate-dimensions";
|
dimensions.className = "picture-candidate-dimensions";
|
||||||
dimensions.textContent = "Size: loading...";
|
dimensions.textContent = "Size: loading...";
|
||||||
image.addEventListener("load", () => {
|
image.addEventListener("load", () => {
|
||||||
dimensions.textContent = image.naturalWidth && image.naturalHeight
|
if (!image.naturalWidth || !image.naturalHeight) {
|
||||||
? `Size: ${image.naturalWidth} x ${image.naturalHeight}px`
|
dimensions.textContent = "Size: unknown";
|
||||||
: "Size: unknown";
|
row.classList.remove("is-too-small");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isTooSmall = image.naturalWidth < MIN_PRODUCT_PICTURE_SIZE || image.naturalHeight < MIN_PRODUCT_PICTURE_SIZE;
|
||||||
|
row.classList.toggle("is-too-small", isTooSmall);
|
||||||
|
dimensions.textContent = isTooSmall
|
||||||
|
? `Size: ${image.naturalWidth} x ${image.naturalHeight}px - too small, min ${MIN_PRODUCT_PICTURE_SIZE} x ${MIN_PRODUCT_PICTURE_SIZE}`
|
||||||
|
: `Size: ${image.naturalWidth} x ${image.naturalHeight}px`;
|
||||||
});
|
});
|
||||||
image.addEventListener("error", () => {
|
image.addEventListener("error", () => {
|
||||||
dimensions.textContent = "Size: image preview failed";
|
dimensions.textContent = "Size: image preview failed";
|
||||||
|
row.classList.add("is-too-small");
|
||||||
});
|
});
|
||||||
const assignment = document.createElement("span");
|
const assignment = document.createElement("span");
|
||||||
assignment.className = "picture-candidate-target";
|
assignment.className = "picture-candidate-target";
|
||||||
|
|||||||
+13
-3
@@ -61,6 +61,7 @@ const darkContrastSelect = document.querySelector("#darkContrastSelect");
|
|||||||
const catalogScreen = document.querySelector(".catalog-screen");
|
const catalogScreen = document.querySelector(".catalog-screen");
|
||||||
const secondaryPanelToggle = document.querySelector("#secondaryPanelToggle");
|
const secondaryPanelToggle = document.querySelector("#secondaryPanelToggle");
|
||||||
const mainWorkspaceToggle = document.querySelector("#mainWorkspaceToggle");
|
const mainWorkspaceToggle = document.querySelector("#mainWorkspaceToggle");
|
||||||
|
const MIN_PRODUCT_PICTURE_SIZE = 800;
|
||||||
let sidebarUserClosed = false;
|
let sidebarUserClosed = false;
|
||||||
let mappingLoadToken = 0;
|
let mappingLoadToken = 0;
|
||||||
const mappingCacheKey = "catalog-maker:mapping-cache";
|
const mappingCacheKey = "catalog-maker:mapping-cache";
|
||||||
@@ -985,12 +986,21 @@ function renderPictureCandidates(items) {
|
|||||||
dimensions.className = "picture-candidate-dimensions";
|
dimensions.className = "picture-candidate-dimensions";
|
||||||
dimensions.textContent = "Size: loading...";
|
dimensions.textContent = "Size: loading...";
|
||||||
image.addEventListener("load", () => {
|
image.addEventListener("load", () => {
|
||||||
dimensions.textContent = image.naturalWidth && image.naturalHeight
|
if (!image.naturalWidth || !image.naturalHeight) {
|
||||||
? `Size: ${image.naturalWidth} x ${image.naturalHeight}px`
|
dimensions.textContent = "Size: unknown";
|
||||||
: "Size: unknown";
|
row.classList.remove("is-too-small");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTooSmall = image.naturalWidth < MIN_PRODUCT_PICTURE_SIZE || image.naturalHeight < MIN_PRODUCT_PICTURE_SIZE;
|
||||||
|
row.classList.toggle("is-too-small", isTooSmall);
|
||||||
|
dimensions.textContent = isTooSmall
|
||||||
|
? `Size: ${image.naturalWidth} x ${image.naturalHeight}px - too small, min ${MIN_PRODUCT_PICTURE_SIZE} x ${MIN_PRODUCT_PICTURE_SIZE}`
|
||||||
|
: `Size: ${image.naturalWidth} x ${image.naturalHeight}px`;
|
||||||
});
|
});
|
||||||
image.addEventListener("error", () => {
|
image.addEventListener("error", () => {
|
||||||
dimensions.textContent = "Size: image preview failed";
|
dimensions.textContent = "Size: image preview failed";
|
||||||
|
row.classList.add("is-too-small");
|
||||||
});
|
});
|
||||||
|
|
||||||
const assignment = document.createElement("span");
|
const assignment = document.createElement("span");
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -228,6 +228,7 @@
|
|||||||
.source-status.is-ok { @apply bg-emerald-100 text-emerald-700; }
|
.source-status.is-ok { @apply bg-emerald-100 text-emerald-700; }
|
||||||
.source-status.is-muted { @apply bg-slate-200 text-slate-600; }
|
.source-status.is-muted { @apply bg-slate-200 text-slate-600; }
|
||||||
.picture-candidate { @apply grid grid-cols-[72px_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 p-2 text-[10px]; }
|
.picture-candidate { @apply grid grid-cols-[72px_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 p-2 text-[10px]; }
|
||||||
|
.picture-candidate.is-too-small { @apply bg-amber-50; }
|
||||||
.picture-candidate-preview { @apply flex h-16 w-[72px] items-center justify-center bg-white; }
|
.picture-candidate-preview { @apply flex h-16 w-[72px] items-center justify-center bg-white; }
|
||||||
.picture-candidate img { @apply max-h-16 w-[72px] object-contain; }
|
.picture-candidate img { @apply max-h-16 w-[72px] object-contain; }
|
||||||
.picture-candidate-meta { @apply grid min-w-0 gap-0.5; }
|
.picture-candidate-meta { @apply grid min-w-0 gap-0.5; }
|
||||||
@@ -235,6 +236,7 @@
|
|||||||
.picture-candidate-dimensions,
|
.picture-candidate-dimensions,
|
||||||
.picture-candidate-target,
|
.picture-candidate-target,
|
||||||
.picture-candidate-duplicate { @apply min-w-0 truncate text-slate-500; }
|
.picture-candidate-duplicate { @apply min-w-0 truncate text-slate-500; }
|
||||||
|
.picture-candidate.is-too-small .picture-candidate-dimensions { @apply font-semibold text-amber-700; }
|
||||||
.picture-candidate-save { @apply min-w-[76px]; }
|
.picture-candidate-save { @apply min-w-[76px]; }
|
||||||
@media (max-width: 980px) {
|
@media (max-width: 980px) {
|
||||||
.catalog-screen { @apply flex flex-col pl-0; }
|
.catalog-screen { @apply flex flex-col pl-0; }
|
||||||
@@ -364,10 +366,12 @@
|
|||||||
html.dark .source-row { @apply border-slate-700 bg-slate-900 text-slate-100 hover:bg-slate-800; }
|
html.dark .source-row { @apply border-slate-700 bg-slate-900 text-slate-100 hover:bg-slate-800; }
|
||||||
html.dark .suggested-row,
|
html.dark .suggested-row,
|
||||||
html.dark .picture-candidate { @apply border-slate-700; }
|
html.dark .picture-candidate { @apply border-slate-700; }
|
||||||
|
html.dark .picture-candidate.is-too-small { @apply bg-amber-950/40; }
|
||||||
html.dark .picture-candidate-preview { @apply bg-slate-800; }
|
html.dark .picture-candidate-preview { @apply bg-slate-800; }
|
||||||
html.dark .picture-candidate-title { @apply text-slate-100; }
|
html.dark .picture-candidate-title { @apply text-slate-100; }
|
||||||
html.dark .picture-candidate-dimensions,
|
html.dark .picture-candidate-dimensions,
|
||||||
html.dark .picture-candidate-target,
|
html.dark .picture-candidate-target,
|
||||||
html.dark .picture-candidate-duplicate { @apply text-slate-400; }
|
html.dark .picture-candidate-duplicate { @apply text-slate-400; }
|
||||||
|
html.dark .picture-candidate.is-too-small .picture-candidate-dimensions { @apply text-amber-300; }
|
||||||
html.dark .suggested-row:nth-child(even) { @apply bg-slate-800; }
|
html.dark .suggested-row:nth-child(even) { @apply bg-slate-800; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,7 +229,8 @@ test("picture candidates show source, dimensions, target assignment and save act
|
|||||||
|
|
||||||
await expect(page.locator("#sourceModal")).toBeVisible();
|
await expect(page.locator("#sourceModal")).toBeVisible();
|
||||||
await expect(page.locator(".picture-candidate-title").first()).toHaveText("Hudy picture #1");
|
await expect(page.locator(".picture-candidate-title").first()).toHaveText("Hudy picture #1");
|
||||||
await expect(page.locator(".picture-candidate-dimensions").first()).toContainText("Size:");
|
await expect(page.locator(".picture-candidate-dimensions").first()).toContainText("too small, min 800 x 800");
|
||||||
|
await expect(page.locator(".picture-candidate").first()).toHaveClass(/is-too-small/);
|
||||||
await expect(page.locator(".picture-candidate-target").first()).toContainText("Target: color Carbon/Malibu Blue");
|
await expect(page.locator(".picture-candidate-target").first()).toContainText("Target: color Carbon/Malibu Blue");
|
||||||
await expect(page.locator(".picture-candidate-save")).toHaveCount(2);
|
await expect(page.locator(".picture-candidate-save")).toHaveCount(2);
|
||||||
await expect(page.locator("#sourceBatchActionButton")).toBeVisible();
|
await expect(page.locator("#sourceBatchActionButton")).toBeVisible();
|
||||||
|
|||||||
Reference in New Issue
Block a user