Rewrite compose filters as cross-filter computation, split views and tests#4
Open
antonio-rodriguez-tam wants to merge 10 commits into
Open
Rewrite compose filters as cross-filter computation, split views and tests#4antonio-rodriguez-tam wants to merge 10 commits into
antonio-rodriguez-tam wants to merge 10 commits into
Conversation
…tests Replace the fragile client-side cascade chain with a single backend endpoint that computes all 6 filter options in one pass on every change. Each filter excludes its own selection but considers all other active selections, eliminating stale-option and circular-pruning bugs. Filters: - Backend computes all filters from all selections every request - Each filter excludes itself (no self-narrowing) - Status is independent of Allocation selection to prevent circular pruning - Project/Department are mutual Tier 1 peers; Allocation/Resource/Status are Tier 2 peers scoped by Tier 1; Role is a leaf - Filter summary tooltips, inline chips, and details modal show live counts, breakdowns, and which filters are narrowing each dropdown - Selections pruned server-side; stale values dropped from response - Filters lock (disable) during in-flight AJAX requests Compose UX: - Form starts empty (no template pre-selected) - Removed hardcoded demo data from filter dropdowns - Removed "All recipients will be BCC'd" badge - Template JSON URL uses Django routing instead of hardcoded path - Validate panel shows active filter summary with human-readable labels - Details button opens full filter breakdown modal Recipient preview: - Always uses project-level scope so role/project/allocation columns are populated regardless of template tokens - Enumerates without server-side dedup so multi-user detection works across pages and dedup-all button persists - Fixed pagination bug (page clamping before row slicing) Code structure: - Split views.py (1116 lines) into views/ package: compose.py, filters.py, campaigns.py, templates.py, settings.py, dashboard.py - Split compose.js (624 lines) into 5 modules: compose_filters.js, compose_validate.js, compose_templates.js, compose_preview.js, compose_init.js - Split test_unit.py (726 lines) into test_resolvers.py, test_validators.py, test_tasks_unit.py, test_conf.py with shared django_setup.py - Removed redundant repo-root static/ directory - Updated CI workflow for new test module paths - Added FILTERS.md documenting the filter architecture - 18 new integration tests; 91 unit tests preserved (verified by name)
recipient_count_view (compose.py): - Replace all_rows list with two-pass streaming: pass 1 counts + collects user_info, pass 2 streams to the requested page slice and breaks early. Memory is now O(page_size) instead of O(total_recipients). compute_filter_options (filters.py): - Use COUNT() queries instead of materializing full querysets for no-narrowing detection - Option helpers use values_list projections instead of full model hydration - Role query uses single reverse join instead of two-step PK lookup - Active-filter labels looked up from already-computed option dicts instead of re-querying the DB BCC fix (tasks.py): - Extra recipients are BCC'd on the first email only, not every email UI (compose.html): - Remove "via BCC" from send warning text
- Fix _allocation_options producing duplicates from M2M values_list on resources. Reverted to select_related + get_parent_resource. - Reorder filter dropdowns by tier: Project, Department, Resource, Allocation Status, Allocation, Role. - Add spacing between Details button and inline summary chips.
Major refactor of coldfront_notifications plugin: Backend: - filters.py: FilterDataBuilder, RecipientResolver, 6 filter classes with initial_options() + _apply() — fixes broken department filter that used naive join instead of org_relation tree traversal - template_variable_value_resolver.py: ResolverRegistry with grouped resolver classes replacing flat lambda dict - notification_validator.py: NotificationValidator class with rich error context (project, allocation info per error) - campaign_sender.py: CampaignSender, TemplateRenderer, SmtpDelivery with incremental progress updates during batch sending - views/helpers.py: StaffRequiredMixin + dispatch_send extracted Frontend: - State-driven filter cascade with getEffectiveIds() — downstream filters read upstream visible set, not just selected - Bottom-up selection: role auto-selects matching departments - Filter detail cards with breakdown and "filtered by" info - Draft auto-save (30s interval), resume via ?draft=pk, beforeunload - Validate button turns green/red, errors shown at top and bottom Code quality: - All modules renamed to meaningful names (no more resolvers.py, validators.py, tasks.py, utils.py) - TextChoices for all model constants - Top-level imports only (no deferred imports) - Explicit variable names throughout (no single-letter vars) - Templates moved to coldfront_notifications/ namespace - API endpoints grouped under api/ prefix - No dash-style section comments
- tests.yml: update test module names and coverage paths to match renamed files (resolvers→template_variable_value_resolver, validators→notification_validator, tasks→campaign_sender) - tests.yml: update wheel verify import to use new module names - tests.yml: add test_filters to the test run - campaign_sender.py: remove unused defaultdict import (F401), remove unused bcc_recipients variable (F841), fix extra blank line - notification_validator.py: fix extra blank line (E303) - template_variable_value_resolver.py: fix extra blank lines (E303)
552c5c6 to
d24d75f
Compare
Plugin code keeps all ColdFront imports at the top level. The test harness (django_setup.py) handles both environments: - With ColdFront installed: uses full app stack with real models - Without ColdFront (CI): stubs coldfront.core.* and ifxuser.* so top-level imports resolve to mocks Build job simplified: wheel verify checks install + version import only (no Django setup needed since ColdFront is not available).
d24d75f to
1f42f76
Compare
Filter behavior: - Top-down narrows: department → projects → resources → allocations - Bottom-up informs: selecting a child filter shows context in detail cards (department, project, resource, status) but never modifies other dropdowns - Removed all autoSelected/dismissed/autoSource machinery - collectFilters() sends only manual selections to backend Bug fixes: - Scope no longer forced to allocation by filter selection — only template tokens determine scope (fixes 110→88 user count bug) - Bottom-up auto-select removed entirely (was selecting departments when role was picked, constraining recipient count) Detail cards now show bottom-up context: - Allocation → shows dept, project, resource, status - Project → shows department it belongs to - Role → shows departments and project count where role exists - Resource → shows departments and project count - Status → shows matching allocation count Added FUNCTIONAL_TEST_PROTOCOL.md with 10 scenarios validated.
Draft deletion: - DraftDeleteView: hard-deletes draft campaigns (POST with confirm) - Delete button on campaign list (next to Edit) and campaign detail - URL: campaigns/<pk>/delete-draft/ Resource → Project narrowing: - Selecting a resource now narrows the projects dropdown to only projects that have allocations on that resource - Projects narrowedBy includes RESOURCE_CHANGED - narrowProjects checks both department AND resource selections - Cascade settles in one pass (no circular loop) - Detail card shows "Filtered by: Resource" on projects
- Replicate ColdFront's EMAIL_DEVELOPMENT_EMAIL_LIST interception in campaign_sender so test campaigns don't reach real recipients - Change draft edit/delete buttons to icon-only pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replace the fragile client-side cascade chain with a state-driven filter system. Fix the broken department filter that used a naive join instead of the org_relation
tree traversal. Refactor the entire plugin to OOP with meaningful names. Add draft auto-save so users don't lose compose progress.
Filters
Compose UX
Campaign list & detail
Recipient preview
Code structure
Backend modules renamed and refactored to OOP:
Other structural changes:
Test coverage