feat(classifier): "Partial" Show filter — assigned in the other tab only
Adds a fourth source-tree bucket relative to the active axis: a file assigned on the OTHER axis but not this one. With its own "Show Partial" toggle (and count) you can assign a batch in one tab, switch tabs, show only Partial, and finish them off — working in chunks across the two axes. fileCategory now returns excluded / assigned (this axis) / partial (other axis only) / unassigned (neither); filters, counts and the toolbar checkbox follow. Test: a tracking-only file reads as Partial on the transmittal tab and hides when Partial is unchecked (51 green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
823cfb0d48
commit
645b308ebc
4 changed files with 43 additions and 10 deletions
|
|
@ -145,6 +145,7 @@
|
|||
hideCompliantLabel: document.getElementById('hideCompliantLabel'),
|
||||
classifyFilters: document.getElementById('classifyFilters'),
|
||||
showUnassignedCheckbox: document.getElementById('showUnassignedCheckbox'),
|
||||
showPartialCheckbox: document.getElementById('showPartialCheckbox'),
|
||||
showAssignedCheckbox: document.getElementById('showAssignedCheckbox'),
|
||||
showExcludedCheckbox: document.getElementById('showExcludedCheckbox'),
|
||||
showEmptyCheckbox: document.getElementById('showEmptyCheckbox'),
|
||||
|
|
@ -354,13 +355,14 @@
|
|||
if (app.modules.tree && app.modules.tree.setShowFilters) {
|
||||
app.modules.tree.setShowFilters({
|
||||
unassigned: app.dom.showUnassignedCheckbox.checked,
|
||||
partial: app.dom.showPartialCheckbox.checked,
|
||||
assigned: app.dom.showAssignedCheckbox.checked,
|
||||
excluded: app.dom.showExcludedCheckbox.checked,
|
||||
empty: app.dom.showEmptyCheckbox.checked,
|
||||
});
|
||||
}
|
||||
}
|
||||
[app.dom.showUnassignedCheckbox, app.dom.showAssignedCheckbox, app.dom.showExcludedCheckbox, app.dom.showEmptyCheckbox]
|
||||
[app.dom.showUnassignedCheckbox, app.dom.showPartialCheckbox, app.dom.showAssignedCheckbox, app.dom.showExcludedCheckbox, app.dom.showEmptyCheckbox]
|
||||
.forEach(function (cb) { if (cb) cb.addEventListener('change', pushClassifyFilters); });
|
||||
|
||||
// Collapse tree button
|
||||
|
|
|
|||
|
|
@ -41,29 +41,35 @@
|
|||
// excluded — and three "Show …" toggles control which buckets are visible
|
||||
// (so unchecking Assigned+Excluded leaves only what's left to do). A folder
|
||||
// whose whole scanned subtree is filtered away is itself hidden.
|
||||
var showFilters = { unassigned: true, assigned: true, excluded: true };
|
||||
var showFilters = { unassigned: true, partial: true, assigned: true, excluded: true };
|
||||
var showEmpty = true; // show folders that contain no files
|
||||
function setShowFilters(f) {
|
||||
showFilters = {
|
||||
unassigned: f.unassigned !== false,
|
||||
partial: f.partial !== false,
|
||||
assigned: f.assigned !== false,
|
||||
excluded: f.excluded !== false,
|
||||
};
|
||||
showEmpty = f.empty !== false;
|
||||
render();
|
||||
}
|
||||
function allFiltersOn() { return showFilters.unassigned && showFilters.assigned && showFilters.excluded; }
|
||||
function allFiltersOn() { return showFilters.unassigned && showFilters.partial && showFilters.assigned && showFilters.excluded; }
|
||||
function activeAxis() {
|
||||
var tt = window.app.modules.targetTree;
|
||||
return (tt && tt.activeAxis) ? tt.activeAxis() : 'tracking';
|
||||
}
|
||||
// Bucket a file relative to the active axis: 'excluded' | 'assigned' | 'unassigned'.
|
||||
// Bucket a file relative to the active axis:
|
||||
// 'excluded' | 'assigned' (on this axis) | 'partial' (assigned on the OTHER
|
||||
// axis only — the to-do for this tab) | 'unassigned' (neither axis).
|
||||
function fileCategory(file) {
|
||||
var c = window.app.modules.classify;
|
||||
var a = c.getAssignment(c.srcKeyForFile(file));
|
||||
if (a && a.excluded) return 'excluded';
|
||||
var assigned = a && (activeAxis() === 'transmittal' ? a.transmittalNodeId : a.trackingNodeId);
|
||||
return assigned ? 'assigned' : 'unassigned';
|
||||
var onTransmittal = activeAxis() === 'transmittal';
|
||||
var here = a && (onTransmittal ? a.transmittalNodeId : a.trackingNodeId);
|
||||
if (here) return 'assigned';
|
||||
var other = a && (onTransmittal ? a.trackingNodeId : a.transmittalNodeId);
|
||||
return other ? 'partial' : 'unassigned';
|
||||
}
|
||||
function classifyAllows(file) { return !classifyOn() || !!showFilters[fileCategory(file)]; }
|
||||
|
||||
|
|
@ -142,9 +148,9 @@
|
|||
}
|
||||
function updateFilterCounts() {
|
||||
if (!classifyOn()) return;
|
||||
var n = { unassigned: 0, assigned: 0, excluded: 0 };
|
||||
var n = { unassigned: 0, partial: 0, assigned: 0, excluded: 0 };
|
||||
allClassifyFiles().forEach(function (f) { n[fileCategory(f)]++; });
|
||||
['unassigned', 'assigned', 'excluded'].forEach(function (k) {
|
||||
['unassigned', 'partial', 'assigned', 'excluded'].forEach(function (k) {
|
||||
var el = document.getElementById('show' + k.charAt(0).toUpperCase() + k.slice(1) + 'Count');
|
||||
if (el) el.textContent = '(' + n[k] + ')';
|
||||
});
|
||||
|
|
|
|||
|
|
@ -65,11 +65,15 @@
|
|||
</div>
|
||||
<div id="classifyFilters" class="classify-filters tree-toolbar" hidden>
|
||||
<span class="tree-toolbar__label">Show</span>
|
||||
<label class="checkbox-label" title="Files not yet assigned in the active tab">
|
||||
<label class="checkbox-label" title="Not assigned on either axis">
|
||||
<input type="checkbox" id="showUnassignedCheckbox" checked>
|
||||
Unassigned <span class="filter-count" id="showUnassignedCount"></span>
|
||||
</label>
|
||||
<label class="checkbox-label" title="Files already assigned in the active tab">
|
||||
<label class="checkbox-label" title="Assigned in the OTHER tab but not this one — the to-do for this tab">
|
||||
<input type="checkbox" id="showPartialCheckbox" checked>
|
||||
Partial <span class="filter-count" id="showPartialCount"></span>
|
||||
</label>
|
||||
<label class="checkbox-label" title="Already assigned in the active tab">
|
||||
<input type="checkbox" id="showAssignedCheckbox" checked>
|
||||
Assigned <span class="filter-count" id="showAssignedCount"></span>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -1007,3 +1007,24 @@ test('revision cell links to preview its file and shows no count bubble', async
|
|||
expect(r.previewKey).toBe('foundation.pdf');
|
||||
expect(r.hasBadge).toBe(false); // no count bubble
|
||||
});
|
||||
|
||||
test('Show Partial surfaces files assigned in the other tab only', async ({ page }) => {
|
||||
await page.click('#modeClassifyBtn');
|
||||
const r = await page.evaluate(() => {
|
||||
const c = window.app.modules.classify, tree = window.app.modules.tree, tt = window.app.modules.targetTree;
|
||||
c.reset();
|
||||
const f = { originalFilename: 'a', extension: 'pdf', folderPath: 'Docs' };
|
||||
window.app.folderTree = [{ name: 'Docs', path: 'Docs', expanded: true, scanState: 'done', children: [], files: [f] }];
|
||||
// Assign tracking only, then view the TRANSMITTAL tab → it reads as "partial" there.
|
||||
const leaf = c.addTrackingPath(null, c.parseFolderLevels('ACME-MECH-0001_A (IFR)'));
|
||||
c.place([c.srcKeyForFile(f)], leaf, 'tracking');
|
||||
tt.showTab('transmittal');
|
||||
tree.render();
|
||||
const withPartial = !!document.querySelector('#folderTree .file-item');
|
||||
tree.setShowFilters({ unassigned: true, partial: false, assigned: true, excluded: true });
|
||||
const withoutPartial = !!document.querySelector('#folderTree .file-item');
|
||||
return { withPartial, withoutPartial };
|
||||
});
|
||||
expect(r.withPartial).toBe(true); // shown while Partial is on (to-do for this tab)
|
||||
expect(r.withoutPartial).toBe(false); // hidden once Partial is off
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue