Story 2386: Library Page Integration#2420
Conversation
julioest
left a comment
There was a problem hiding this comment.
🚀 Great work on this! Pre-approving, with one inline comment to address before merge.
jlchilders11
left a comment
There was a problem hiding this comment.
Looks good to me, thanks for all of the work!
herzog0
left a comment
There was a problem hiding this comment.
Heya! Amazing work!!
I just have one note about the min/max logic, which I think should be discussed with Rob.
Pre-approving though 🚢
| if (this.maxCpp !== 'all' && data.cpp_min && cppRank(data.cpp_min) > cppRank(this.maxCpp)) return false; | ||
| if (this.minCpp !== 'all' && data.cpp_max && cppRank(data.cpp_max) < cppRank(this.minCpp)) return false; |
There was a problem hiding this comment.
Since this only works when the cpp_max version gets populated, and that will require a tremendous amount of work on the Cpp Alliance side (having to reach out to every developer, asking what's their maximum supported version, which may not be an easy task for them to find out as well), I think we should play safe and, if there's no max version reported for the library, we don't show it if its cpp_min is less than the selected value.
I mean adding a filter like if (this.minCpp !== 'all' && data.cpp_min && !data.cpp_max && cppRank(data.cpp_min) < cppRank(this.minCpp)) return false;.
Because if the user trusts the website blindly and a lib's max version isn't populated, they might introduce a bug in their project.
Either that or we be more explicit in the UI, adding a new column and renaming the current one to "Min Version" and "Max Version" (which I actually think should be added anyway).
1c2d358 to
47f6bb5
Compare
…le C++ version list
…values using max list
47f6bb5 to
636db41
Compare
Issue: #2386 , #2409
Summary & Context
Ships interactive filter, fuzzy token search (Fuse.js), sort, and empty state designs on the V3 Libraries Page. Adds a new
cpp_standard_maximummodel field so the C++ version filter can enforce a min/max range.Filter state lives in an Alpine component, syncs to the URL, and operates on a compact dataset embedded once per page load — no per-keystroke server requests.
Changes
Library page filtering
New UI (
_library_filter.html,library_page.html)_library_empty_state.html) with light/dark illustration; distinguishes "no search match" from "no filter match"<noscript>fallback hides JS-dependent controls and force-showsx-cloak'd sections so the page still rendersState & wiring
libraryFilter()Alpine component owns state;syncUrl()hydrates from and writes back?grading=…&min_cpp=…&max_cpp=…&category=…&q=…&sort=…LibraryListBase.get_v3_context_datacentralizes filter fields, defaults, the dataset payload, search query, and Clear All URLV3 field include extensions
_field_dropdown.html—deselectableclear button,field-disabled-valueslistener (powers min ≤ max C++),field-setrebroadcast,dropdown--has-valueaccent_field_combo_multi.html— per-tag and clear-all buttons,clear-all-filterslistener, MutationObserver-friendly hidden inputs_field_text.html(used for Search bar) —dispatch_field_changewith 150 ms debounceFuzzy search (Fuse.js)
[email protected]bundled via esbuild (frontend/fuse-entry.js→static/js/v3/fuse.min.js) withyarn build:fusedeferplus aDOMContentLoadedfallback ininit(); if?q=is in the URL when the late build completes,apply()re-runs so deep links workfield-change→querystate →runSearch()→fuse.search(q), results keyed by slug{{ library_dataset|json_script:"library-data" }}(slug, name, description, categories, authors, cpp_min/max, tier)Fuse options
useTokenSearch: true— multi-word queries match regardless of token orderignoreLocation: true— no positional penaltythreshold: 0.3— moderate fuzziness (0 = exact, 1 = match anything)minMatchCharLength: 2— drop single-character matchesincludeScore: true— per-result score for relevance orderingname(3) >category_names(1.5) >author_names(1) =description(1)Max C++ version support
Model & import
LibraryVersion.cpp_standard_maximumfield (nullable,choices=CPP_STANDARDS) + migration0040_libraryversion_cpp_standard_maximumparse_libraries_json(core/githubhelper.py) readscxxstd_max;versions/tasks.pyassigns it on import, mirroring the existingcxxstdflowget_cpp_standard_maximum_display()paralleling the minimum getter (with unit test)Filter behavior
Min. C++ Version,Max. C++ Version); both values in the dataset ascpp_min/cpp_maxfield-disabled-valuesto the other; invalid pairs from URL params auto-correct on load[cpp_min … cpp_max]as a range and passes if it overlaps the selected window (e.g. a C++14–20 library matches a Min=C++17 selection)Risks & Considerations
ordering = "library__name"onLibraryListBase).defer;init()builds the index immediately if available, otherwise retries onDOMContentLoaded. A?q=in the URL triggers a re-apply after the late build so deep links still work.0040adds a nullablecpp_standard_maximumfield — safe forward and reversible. Existing libraries withoutcxxstd_maxin the JSON simply readNoneand display nothing for the max bound.release_tasksCelery chain (also triggerable from Django Admin → "Update Libraries", and on every new release/beta import) reads each library'smeta/libraries.jsonviaparse_libraries_jsonand writescpp_standard_maximumto the matchingLibraryVersionrow inimport_library_versions. The parser useslibraries_json.get("cxxstd_max")so the field is read opportunistically — if upstream addscxxstd_maxto a library's JSON, it flows in on the next run with no code change; if absent, the field staysNone. In the meantime the value is editable directly on theLibraryVersionchange form in Django Admin.Screenshots
Self-review Checklist
Frontend