Bundles a stretch of in-progress work across the SPA tools so the
tree returns to a coherent shippable state ahead of cutting a new
zddc-server stable image:
- landing: substantial rework of the project picker (sortable/filterable
table, presets refactor, ?projects= filter, ?v= channel propagation,
loading/error states)
- archive: presets cleanup, source.js refactor, filtering/url-state
alignment with the landing page
- mdedit: file-system module split, resizer, file-tree improvements,
base/toc styling tweaks
- transmittal/classifier: small template touch-ups for shared chrome
- shared: build-lib.sh helpers, new favicon.svg
- bootstrap, build.sh: pick up the channel-aware install/track zip
generation
- tests: new landing.spec.js, expanded archive/mdedit/build-label specs
- docs: CLAUDE.md picks up the zddc-server section and freshens the
alpha-build exception note
- regenerated artifacts: install.zip, track-{alpha,beta,stable}.zip,
*_alpha.html — these are produced by `sh build.sh` and per project
convention are committed alongside the source changes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
149 lines
4.8 KiB
JavaScript
149 lines
4.8 KiB
JavaScript
// Filtering functionality
|
|
|
|
// Apply all filters
|
|
function applyFilters() {
|
|
// Start with files from selected transmittal folders AND selected grouping folders
|
|
let filtered = window.app.files.filter(file => {
|
|
// Must have at least one grouping folder selected (if grouping folders exist)
|
|
if (window.app.groupingFolders.length > 0 && window.app.selectedGroupingFolders.size === 0) {
|
|
return false;
|
|
}
|
|
|
|
// Must have at least one transmittal folder selected
|
|
if (window.app.selectedTransmittalFolders.size === 0) {
|
|
return false;
|
|
}
|
|
|
|
// Multi-project visibility filter — files under unchecked projects are
|
|
// hidden from view (without re-scanning).
|
|
if (!window.app.modules.app.pathIsInVisibleProject(file.path)) {
|
|
return false;
|
|
}
|
|
|
|
// File must be in a selected transmittal folder
|
|
if (!window.app.selectedTransmittalFolders.has(file.folderPath)) {
|
|
return false;
|
|
}
|
|
|
|
// Outstanding files: actualPath must be under a selected grouping folder that is
|
|
// itself visible (not hidden by folder type toggles).
|
|
if (file.folderPath === '__outstanding__') {
|
|
if (!window.app.modules.app.outstandingFileIsVisible(file)) return false;
|
|
}
|
|
|
|
// If grouping folders exist and are selected, the file's transmittal folder
|
|
// path must contain a path segment matching one of the selected party names.
|
|
// Outstanding files are exempt — their grouping scope is enforced by the
|
|
// actualPath check above.
|
|
if (file.folderPath !== '__outstanding__' && window.app.groupingFolders.length > 0 && window.app.selectedGroupingFolders.size > 0) {
|
|
const inSelectedGrouping = file.folderPath.split('/').some(seg =>
|
|
window.app.selectedGroupingFolders.has(seg)
|
|
);
|
|
if (!inSelectedGrouping) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
|
|
|
|
// Apply column filters
|
|
filtered = applyColumnFilters(filtered);
|
|
|
|
// Apply modifier filter
|
|
if (window.app.selectedModifiers.size < window.app.availableModifiers.size) {
|
|
filtered = filtered.filter(file => window.app.modules.app.filePassesModifierFilter(file));
|
|
}
|
|
|
|
updateResetFiltersBtn();
|
|
|
|
// Apply selected-only filter
|
|
if (window.app.showSelectedOnly) {
|
|
filtered = filtered.filter(file => window.app.selectedFiles.has(file.id));
|
|
}
|
|
|
|
window.app.filteredFiles = filtered;
|
|
window.app.modules.table.updateFileTable();
|
|
window.app.modules.app.updateStatusBar();
|
|
window.app.modules.table.updateSelectAllVisibleCheckbox();
|
|
}
|
|
|
|
|
|
|
|
// Apply column filters using stored ASTs
|
|
function applyColumnFilters(files) {
|
|
const asts = window.app.columnFilterASTs;
|
|
|
|
if (asts.trackingNumber && asts.trackingNumber.length > 0) {
|
|
files = files.filter(file =>
|
|
zddc.filter.matches(file.trackingNumber || '', asts.trackingNumber)
|
|
);
|
|
}
|
|
|
|
if (asts.title && asts.title.length > 0) {
|
|
files = files.filter(file =>
|
|
zddc.filter.matches(file.title || '', asts.title)
|
|
);
|
|
}
|
|
|
|
if (asts.revisions && asts.revisions.length > 0) {
|
|
files = files.filter(file => {
|
|
const revisionText = [
|
|
file.revision,
|
|
file.status,
|
|
file.extension
|
|
].join(' ');
|
|
return zddc.filter.matches(revisionText, asts.revisions);
|
|
});
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
// Clear all filters
|
|
function clearFilters() {
|
|
window.app.columnFilters = {
|
|
trackingNumber: '',
|
|
title: '',
|
|
revisions: ''
|
|
};
|
|
window.app.columnFilterASTs = {
|
|
trackingNumber: null,
|
|
title: null,
|
|
revisions: null
|
|
};
|
|
window.app.groupingFilter = '';
|
|
window.app.transmittalFilter = '';
|
|
|
|
// Clear UI inputs
|
|
const groupingFilterEl = document.getElementById('groupingFilter');
|
|
groupingFilterEl.value = '';
|
|
groupingFilterEl.classList.remove('filter-active');
|
|
const transmittalFilterEl = document.getElementById('transmittalFilter');
|
|
transmittalFilterEl.value = '';
|
|
transmittalFilterEl.classList.remove('filter-active');
|
|
document.querySelectorAll('.column-filter').forEach(input => {
|
|
input.value = '';
|
|
input.classList.remove('filter-active');
|
|
});
|
|
|
|
window.app.modules.app.toggleAllModifiers(true);
|
|
updateResetFiltersBtn();
|
|
applyFilters();
|
|
window.app.modules.urlState.push();
|
|
}
|
|
|
|
// Update reset filters button visibility
|
|
function updateResetFiltersBtn() {
|
|
// Button is always visible — no show/hide logic needed
|
|
}
|
|
|
|
// Register filtering module
|
|
window.app.modules.filtering = {
|
|
applyFilters,
|
|
applyColumnFilters,
|
|
clearFilters,
|
|
updateResetFiltersBtn
|
|
};
|