Repository navigation
Release v0.51.757 — page archived sidebar rows + archived-search refetch (#5200, @santastabber) - #5241
Conversation
|
| Filename | Overview |
|---|---|
| api/routes.py | Adds archived_limit/archived_offset paging in _build_session_list_cache_payload and _query_positive_int helper; session-count metrics computed before slicing (correct for tab badge). Contains redundant inline normalization of values already validated by _query_positive_int. |
| api/route_session_list_cache.py | Extends _session_list_cache_key with archived_limit/archived_offset so differently-paged requests get separate cache slots. Normalization logic here mirrors what _query_positive_int already guarantees at the call site. |
| static/sessions.js | Adds _archivedRowsLoadedLimit state, _sessionArchivePagingFilterActive(), _syncArchivedSearchPagingRefresh(), and the 'Load more archived' DOM widget. Spurious refetch possible when _activeProject is already set and search transitions, but correctness is unaffected. |
| tests/test_session_list_long_history_perf.py | Adds two new backend tests: one end-to-end paging test confirming visible rows are never hidden and archived_count is unaffected by paging, and a cache-key isolation test. |
| tests/test_issue4766_sidebar_source_pushdown.py | Extends JS query-string tests to cover archived_limit injection, search/project suppression, and the _syncArchivedSearchPagingRefresh edge-transition behaviour via Node.js harness. |
| tests/test_sidebar_session_partition.py | Updates source-count assertions to match the new server-count sentinel path and adds archive load-more DOM assertions. |
| CHANGELOG.md | Release entry added for v0.51.757; correctly maintained by the release process per repo convention. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User
participant JS as sessions.js
participant API as /api/sessions
Note over JS: _showArchived=true, no search/project active
JS->>API: "GET /api/sessions?include_archived=1&archived_limit=100"
API-->>JS: "sessions[visible + archived[0:100]], archived_count=N"
JS->>U: Renders sidebar (visible rows + first 100 archived)
JS->>U: Load 100 more archived (N-100 remaining) button
U->>JS: Clicks Load more
JS->>JS: "_archivedRowsLoadedLimit = 200"
JS->>API: "GET /api/sessions?include_archived=1&archived_limit=200"
API-->>JS: sessions[visible + archived[0:200]]
JS->>U: Renders sidebar (200 archived rows now shown)
U->>JS: Types search query in sessionSearch
JS->>JS: filterSessions() → _syncArchivedSearchPagingRefresh(q)
JS->>JS: _archivedSearchPagingQueryActive: false → true
JS->>API: "GET /api/sessions?include_archived=1 (no archived_limit)"
API-->>JS: ALL archived sessions returned
JS->>U: Client-side title filter finds matches beyond page 1
U->>JS: Clears search input
JS->>JS: _syncArchivedSearchPagingRefresh('')
JS->>JS: _archivedSearchPagingQueryActive: true → false
JS->>API: "GET /api/sessions?include_archived=1&archived_limit=200"
API-->>JS: sessions[visible + archived[0:200]]
JS->>U: Paged view restored (200 archived rows)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant U as User
participant JS as sessions.js
participant API as /api/sessions
Note over JS: _showArchived=true, no search/project active
JS->>API: "GET /api/sessions?include_archived=1&archived_limit=100"
API-->>JS: "sessions[visible + archived[0:100]], archived_count=N"
JS->>U: Renders sidebar (visible rows + first 100 archived)
JS->>U: Load 100 more archived (N-100 remaining) button
U->>JS: Clicks Load more
JS->>JS: "_archivedRowsLoadedLimit = 200"
JS->>API: "GET /api/sessions?include_archived=1&archived_limit=200"
API-->>JS: sessions[visible + archived[0:200]]
JS->>U: Renders sidebar (200 archived rows now shown)
U->>JS: Types search query in sessionSearch
JS->>JS: filterSessions() → _syncArchivedSearchPagingRefresh(q)
JS->>JS: _archivedSearchPagingQueryActive: false → true
JS->>API: "GET /api/sessions?include_archived=1 (no archived_limit)"
API-->>JS: ALL archived sessions returned
JS->>U: Client-side title filter finds matches beyond page 1
U->>JS: Clears search input
JS->>JS: _syncArchivedSearchPagingRefresh('')
JS->>JS: _archivedSearchPagingQueryActive: true → false
JS->>API: "GET /api/sessions?include_archived=1&archived_limit=200"
API-->>JS: sessions[visible + archived[0:200]]
JS->>U: Paged view restored (200 archived rows)
Reviews (1): Last reviewed commit: "docs(changelog): page archived sidebar r..." | Re-trigger Greptile
| if include_archived and archived_limit is not None: | ||
| try: | ||
| normalized_archived_limit = max(0, int(archived_limit)) | ||
| except (TypeError, ValueError): | ||
| normalized_archived_limit = None | ||
| try: | ||
| normalized_archived_offset = max(0, int(archived_offset or 0)) | ||
| except (TypeError, ValueError): | ||
| normalized_archived_offset = 0 | ||
| if normalized_archived_limit is not None: | ||
| visible_rows_for_page = [s for s in visible_scoped_filtered if not s.get("archived")] | ||
| archived_rows_for_page = [s for s in archived_scoped_filtered if s.get("archived")] | ||
| scoped = visible_rows_for_page + archived_rows_for_page[ | ||
| normalized_archived_offset: normalized_archived_offset + normalized_archived_limit | ||
| ] |
There was a problem hiding this comment.
Redundant normalization —
archived_limit and archived_offset have already been validated to non-negative integers (or None) by _query_positive_int at the call site, so the try/except blocks here can never fire and the max(0, int(...)) guards are no-ops. The same duplication occurs in _session_list_cache_key. Simplifying to direct use of the incoming values would remove ~10 lines of dead code from both sites.
| if include_archived and archived_limit is not None: | |
| try: | |
| normalized_archived_limit = max(0, int(archived_limit)) | |
| except (TypeError, ValueError): | |
| normalized_archived_limit = None | |
| try: | |
| normalized_archived_offset = max(0, int(archived_offset or 0)) | |
| except (TypeError, ValueError): | |
| normalized_archived_offset = 0 | |
| if normalized_archived_limit is not None: | |
| visible_rows_for_page = [s for s in visible_scoped_filtered if not s.get("archived")] | |
| archived_rows_for_page = [s for s in archived_scoped_filtered if s.get("archived")] | |
| scoped = visible_rows_for_page + archived_rows_for_page[ | |
| normalized_archived_offset: normalized_archived_offset + normalized_archived_limit | |
| ] | |
| if include_archived and archived_limit is not None: | |
| visible_rows_for_page = [s for s in visible_scoped_filtered if not s.get("archived")] | |
| archived_rows_for_page = [s for s in archived_scoped_filtered if s.get("archived")] | |
| scoped = visible_rows_for_page + archived_rows_for_page[ | |
| archived_offset: archived_offset + archived_limit | |
| ] |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
|
||
| function _syncArchivedSearchPagingRefresh(query){ | ||
| const queryActive=Boolean(String(query||'').trim()); | ||
| const previous=_archivedSearchPagingQueryActive; | ||
| _archivedSearchPagingQueryActive=queryActive; | ||
| if(!_showArchived||queryActive===previous) return; | ||
| // Archived title/id filtering is client-side. When search becomes active, | ||
| // refetch without archived_limit so matches beyond the first archived page are | ||
| // reachable; when search clears, refetch again to restore normal archive paging. | ||
| if(typeof renderSessionList==='function') void renderSessionList({deferWhileInteracting:false}); | ||
| } | ||
|
|
||
| function filterSessions(){ | ||
| // Immediate client-side title filter (no flicker) | ||
| // Debounced content search via API for message text | ||
| syncSessionSearchClear(); |
There was a problem hiding this comment.
Spurious refetch when project filter is already active
_syncArchivedSearchPagingRefresh fires renderSessionList whenever _archivedSearchPagingQueryActive transitions between false and true, but _sessionArchivePagingFilterActive() already returns true when _activeProject is non-null — meaning archived_limit is already omitted from the query. If a user has a project filter active and then starts typing (or clears) a search, the false→true (or true→false) transition in _archivedSearchPagingQueryActive triggers an extra HTTP request even though the resulting query string is identical to the one already in flight. No data-correctness problem, but it is an avoidable extra round-trip in that specific mixed state. A guard checking !_activeProject before deciding to refetch would eliminate it.
🎬 Cutter preview — PR #5241
|

Release v0.51.757 — page archived sidebar rows + archived-search refetch (#5200, @santastabber)
Ships #5200 by @santastabber. Perf + correctness fix on the session sidebar.
What it does
Archived sidebar rows are now paged (capped per request) instead of all loaded at once — an instance with thousands of archived sessions no longer renders them all. The contributor PR converged from an earlier gate-fail: when "Show archived" is on and you start a search, the sidebar transparently refetches without the archive cap so a title/id match beyond the first archived page is still reachable, then restores normal paging when the search clears.
Gate (converged from gate-fail, re-gated fresh)
filterSessions()search-input path, so an archived title match past page 1 was unreachable while searching (SILENT data-not-shown). The re-push added_syncArchivedSearchPagingRefresh()+ search-active detection that refetches withoutarchived_limiton the search-active edge and restores paging on clear.Closes #5200.