feat(classifier): click-to-preview in Classify & Copy mode
Identifying a file is half the workflow — you preview it to see what it is, then assign its tracking number by drag. Preview was only wired into the old Rename grid; in Classify & Copy a source file now previews on single-click (drag still assigns, right-click excludes). preview.previewFile() resolves a snapshot file's handle from the workspace root (one-click read re-grant) before opening, so it works for resumed workspaces too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
afcba81e61
commit
975c804cc7
3 changed files with 45 additions and 3 deletions
|
|
@ -521,7 +521,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export module
|
// Export module
|
||||||
|
// Preview a file on demand (Classify & Copy mode). Snapshot-loaded files
|
||||||
|
// have no handle yet — resolve it from the workspace root (one-click read
|
||||||
|
// permission re-grant) before opening the preview window.
|
||||||
|
async function previewFile(file) {
|
||||||
|
try {
|
||||||
|
if (!file.handle && !file.isVirtual && window.app.rootHandle) {
|
||||||
|
if (window.app.modules.persist && window.app.modules.persist.verifyPermission) {
|
||||||
|
const ok = await window.app.modules.persist.verifyPermission(window.app.rootHandle, false);
|
||||||
|
if (!ok) { if (window.zddc) window.zddc.toast('Permission to read the source directory was denied.', 'error'); return; }
|
||||||
|
}
|
||||||
|
await window.app.modules.scanner.resolveFileHandle(window.app.rootHandle, file);
|
||||||
|
}
|
||||||
|
await openPreviewWindow(file);
|
||||||
|
} catch (e) {
|
||||||
|
if (window.zddc) {
|
||||||
|
window.zddc.toast('Couldn’t preview ' + (file.originalFilename || 'file') + ' — ' + (e.message || e), 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.app.modules.preview = {
|
window.app.modules.preview = {
|
||||||
init
|
init,
|
||||||
|
previewFile
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,7 @@
|
||||||
item.className = 'file-item';
|
item.className = 'file-item';
|
||||||
item.style.paddingLeft = `${level * 1.5}rem`;
|
item.style.paddingLeft = `${level * 1.5}rem`;
|
||||||
item.draggable = true;
|
item.draggable = true;
|
||||||
|
item.title = 'Click to preview · drag onto a tracking folder or transmittal to assign';
|
||||||
const key = c.srcKeyForFile(file);
|
const key = c.srcKeyForFile(file);
|
||||||
item.dataset.key = key;
|
item.dataset.key = key;
|
||||||
const st = c.fileState(file);
|
const st = c.fileState(file);
|
||||||
|
|
@ -688,11 +689,15 @@
|
||||||
var ft = window.app.dom.folderTree;
|
var ft = window.app.dom.folderTree;
|
||||||
if (!ft) { classifyWired = false; return; }
|
if (!ft) { classifyWired = false; return; }
|
||||||
ft.addEventListener('contextmenu', onContextMenu);
|
ft.addEventListener('contextmenu', onContextMenu);
|
||||||
|
// Single-click a source file → preview it (the "look at it, then assign"
|
||||||
|
// half of the workflow). Drag still assigns; right-click excludes.
|
||||||
ft.addEventListener('click', function (e) {
|
ft.addEventListener('click', function (e) {
|
||||||
if (!classifyOn()) return;
|
if (!classifyOn()) return;
|
||||||
var fe = e.target.closest('.file-item');
|
var fe = e.target.closest('.file-item');
|
||||||
if (fe && fe.dataset.key && window.app.modules.targetTree) {
|
if (!fe || !fe.dataset.key) return;
|
||||||
window.app.modules.targetTree.reveal(fe.dataset.key);
|
var file = findFileByKey(fe.dataset.key);
|
||||||
|
if (file && window.app.modules.preview && window.app.modules.preview.previewFile) {
|
||||||
|
window.app.modules.preview.previewFile(file);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,22 @@ test('source file rows render with a state dot in classify mode', async ({ page
|
||||||
await expect(page.locator('#folderTree .file-item .cl-dot--none')).toBeVisible();
|
await expect(page.locator('#folderTree .file-item .cl-dot--none')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('classify: single-click a source file triggers preview', async ({ page }) => {
|
||||||
|
await page.click('#modeClassifyBtn');
|
||||||
|
const previewed = await page.evaluate(() => {
|
||||||
|
let got = null;
|
||||||
|
window.app.modules.preview.previewFile = (f) => { got = f.originalFilename; }; // capture, skip popup
|
||||||
|
window.app.folderTree = [{
|
||||||
|
name: 'Root', path: 'Root', expanded: true, scanState: 'done',
|
||||||
|
files: [{ originalFilename: 'Foundation Plan', extension: 'pdf', folderPath: 'Root' }], children: [],
|
||||||
|
}];
|
||||||
|
window.app.modules.tree.render();
|
||||||
|
document.querySelector('#folderTree .file-item').click();
|
||||||
|
return got;
|
||||||
|
});
|
||||||
|
expect(previewed).toBe('Foundation Plan');
|
||||||
|
});
|
||||||
|
|
||||||
test('classify: a folder with files but no subfolders is expandable (drag source)', async ({ page }) => {
|
test('classify: a folder with files but no subfolders is expandable (drag source)', async ({ page }) => {
|
||||||
await page.click('#modeClassifyBtn');
|
await page.click('#modeClassifyBtn');
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue