Skip to content

feat: add offline mode and recommendation search#8

Open
aaronlippold wants to merge 80 commits intomainfrom
feat/offline-and-search
Open

feat: add offline mode and recommendation search#8
aaronlippold wants to merge 80 commits intomainfrom
feat/offline-and-search

Conversation

@aaronlippold
Copy link
Copy Markdown
Member

@aaronlippold aaronlippold commented Jan 29, 2026

Summary

  • Add --offline global flag to prevent accidental network calls
  • Add cache status command to show what's available offline
  • Add find command for FTS5 full-text search within recommendation content
  • Add diff command to compare benchmark versions using DeepDiff
  • 44 new TDD tests (14 offline, 15 find, 15 diff)

New Commands

Offline Mode

cis-bench --offline search "ubuntu"     # Uses cached catalog
cis-bench --offline export 12345        # Uses downloaded benchmark
cis-bench cache status                  # Shows what's cached

Recommendation Search

cis-bench find "SSH"                    # Find SSH-related rules
cis-bench find "AC-7"                   # Find NIST control mappings
cis-bench find "firewall" --profile "Level 1"

Benchmark Diff

cis-bench diff 23598 24001              # Compare by ID
cis-bench diff old.json new.json        # Compare files
cis-bench diff 23598 24001 --format markdown
cis-bench diff 23598 24001 --verbose

Test plan

  • All 1165 tests passing
  • Linting passes (ruff, bandit)
  • Offline mode blocks network commands
  • Offline mode allows local commands
  • Find command searches all recommendation fields
  • Diff detects added/removed/modified/renumbered
  • Diff outputs table/json/markdown/summary formats

Offline Mode:
- Add --offline global flag to prevent network calls
- Add 'cache status' command to show cached data
- Block auth login, catalog refresh, download, get when offline
- 14 TDD tests in tests/unit/test_offline_mode.py

Recommendation Search:
- Add 'find' command for FTS5 search within recommendations
- Search titles, descriptions, audit, remediation, controls
- Add recommendations_fts table indexed on download
- Support --benchmark, --profile filters
- 15 TDD tests in tests/unit/test_recommendation_search.py

Docs:
- Updated commands-reference.md with both features
- Updated CLAUDE.md to use uv instead of pip

Authored by: Aaron Lippold<lippold@gmail.com>
- Add 'diff' command to compare benchmark versions
- Use DeepDiff library for structural comparison
- Match recommendations by ref ID (handles reordering)
- Detect renumbered recommendations via title similarity
- Output formats: table, json, markdown, summary
- 15 TDD tests in tests/unit/test_benchmark_diff.py
- Add deepdiff>=8.0.0 to dependencies

Change types detected:
- Added: New recommendations
- Removed: Deleted recommendations
- Modified: Same ref, content changed
- Renumbered: Similar title (>85%), different ref

Authored by: Aaron Lippold<lippold@gmail.com>
The diff command now automatically fetches benchmarks from CIS WorkBench
if they are not cached locally. This makes comparing benchmark versions
simpler - just provide two IDs and the tool handles the rest.

- Auto-fetch when benchmark not found locally
- Respects --offline flag to prevent network calls
- Caches fetched benchmarks for future use
- Clear error messages for auth requirements
- Updated documentation with new examples

Authored by: Aaron Lippold<lippold@gmail.com>
- Remove fixed column widths, let Rich auto-size based on terminal
- Use ratio-based column sizing for Title (3:1 ratio)
- Show abbreviated field changes with "+N more" for long lists
- Table now expands to use available terminal width

Authored by: Aaron Lippold<lippold@gmail.com>
- "Added" instead of "ADD"
- "Removed" instead of "DEL"
- "Modified" instead of "MOD"
- "Renumbered" instead of "REN"
- More descriptive Changes column text

Authored by: Aaron Lippold<lippold@gmail.com>
- Add diff_tui.py: Interactive side-by-side diff browser with Textual
- Add view.py/view_tui.py: New `cis-bench view` command to browse benchmarks
- Add tui_base.py: Shared TUI components (DetailView, SaveDialog, html_to_markdown)
- Add utils.py: Shared CLI utilities (load_benchmark, output_with_pager, auto_fetch)
- Refactor diff.py to use shared utilities (DRY)

TUI Features:
- Side-by-side layout (40% list, 60% detail)
- Natural sorting for CIS refs (1.1 < 1.2 < 1.10 < 2.1)
- Reverse sort toggle (r key)
- HTML to Markdown conversion for readable content
- Skip visually identical fields in diffs (no encoding noise)
- Auto-pager for non-interactive output (GNU/Unix standard)
- Save report feature (s key)
- Fullscreen toggle (f key)
- Keyboard navigation (j/k, arrows, tab, page up/down)

View command options:
- Filter by --profile and --status
- Auto-fetch from WorkBench if not cached
- TTY auto-detection for interactive/table mode

Tests: 41 new tests for TUI functionality

Authored by: Aaron Lippold <lippold@gmail.com>
Document the beads workflow for this project:
- Parent/child vs dependencies concepts
- Creating epics with child tasks
- Navigation commands (bd children, bd ready, bd blocked)
- Session recovery workflow

Authored by: Aaron Lippold <lippold@gmail.com>
- Update CLAUDE.md with proper uv run commands for all dev tools
- Update contributing.md with uv run for pytest, ruff, pre-commit
- Update testing.md with uv run commands and test count (1200+)
- Update getting-started.md to recommend uv sync workflow
- Add direnv auto-activation documentation for optional venv activation

This ensures developers use the correct .venv environment instead of
system Python, preventing "module not found" errors.

Authored by: Aaron Lippold<lippold@gmail.com>
- Add HelpScreen modal class to tui_base.py
- Display all keyboard shortcuts when user presses '?'
- Close with Escape, '?', or 'q'
- Add CSS styling for help dialog
- Add action_show_help to BaseBrowserApp
- Add 9 tests for help screen functionality

Authored by: Aaron Lippold<lippold@gmail.com>
- Add offline parameter to DiffApp and ViewApp
- Show [OFFLINE] indicator in summary bar when --offline flag active
- Wire up offline parameter through diff.py and view.py commands
- Update view_tui to use COMMON_BINDINGS (fixes missing ? help key)
- Add 4 tests for offline indicator functionality

Authored by: Aaron Lippold<lippold@gmail.com>
- Add SearchInput widget class for real-time filtering
- Add '/' binding to COMMON_BINDINGS for search
- Implement _apply_search_filter in DiffApp
- Show match count while searching
- Escape cancels search and restores all items
- Add 6 tests for search functionality

Authored by: Aaron Lippold<lippold@gmail.com>
- Document view command with profile and status filters
- Add Interactive TUI Mode section with keyboard shortcuts
- Document search functionality (/ key) and offline indicator
- Add Scenario 15: Interactive Benchmark Exploration workflow

Authored by: Aaron Lippold<lippold@gmail.com>
- Add TUI Layer section to architecture.md with component diagram
- Add Textual to technology stack
- Add TUI file structure to file organization
- Add view/diff commands to CLI commands list
- Add mkdocs-autorefs dependency (fixes build)

Authored by: Aaron Lippold<lippold@gmail.com>
- Add jump to ref (g key) with JumpDialog
- Add copy to clipboard (c key) using pyperclip
- Add filter by change type (1-4, 0) in diff TUI
- Mouse click already works via Textual DataTable

Tests: 74 passing (14 new)

Authored by: Aaron Lippold<lippold@gmail.com>
- Add multi-select support (space key) with selection tracking
- Update commands-reference.md with all new TUI features:
  - Jump to ref (g key)
  - Copy to clipboard (c key)
  - Multi-select (space key)
  - Filter by change type (1-4, 0)

Tests: 78 passing (4 new for multi-select)

Authored by: Aaron Lippold<lippold@gmail.com>
Implements interactive catalog browser TUI:
- CatalogBrowserApp extends BaseBrowserApp for consistent UX
- CatalogDetailView shows benchmark metadata
- Search, multi-select, jump-to-ID from shared components
- New 'cis-bench browse' CLI command with filters

Features:
- Browse catalog with DataTable (ID, Title, Version, Platform, Published)
- Real-time search filter (/ key)
- Multi-select for batch operations (Space key)
- Jump to benchmark ID (g key)
- Star marker for latest versions

Includes 21 unit tests following TDD approach.

Authored by: Aaron Lippold<lippold@gmail.com>
Fixes AttributeError when description field is None during search.

Authored by: Aaron Lippold<lippold@gmail.com>
1. Inline version with title - version always visible regardless of width
2. Selection checkbox column - visual indicator (●/○) for selected items
3. Enter key opens action menu - discoverable Download/View/Diff/Export
4. Responsive layout - hides detail pane on narrow terminals (<80 cols)

Also:
- Summary shows selection count
- Search filter includes version matching

Authored by: Aaron Lippold<lippold@gmail.com>
Reorganizes TUI code into modular structure:
- tui/base.py: BaseBrowserApp, DetailView, COMMON_CSS, helpers
- tui/widgets.py: SearchInput, HelpScreen, JumpDialog, SaveDialog
- tui/catalog/: CatalogBrowserApp, CatalogDetailView, ActionMenu

Benefits:
- Clear separation of concerns
- Easier to add new TUI types (diff, view)
- DRY shared components
- Better testability

Old imports (tui_base.py, catalog_tui.py) re-export from
new locations for backwards compatibility.

Authored by: Aaron Lippold<lippold@gmail.com>
- Extract DiffDetailView and DiffApp to tui/diff/ module
- Extract ViewDetailView and ViewApp to tui/view/ module
- Convert diff_tui.py and view_tui.py to re-export shims
- All 1269 tests passing

TUI package structure now complete:
  tui/
  ├── base.py          # BaseBrowserApp, DetailView, COMMON_CSS
  ├── widgets.py       # SearchInput, HelpScreen, JumpDialog, SaveDialog
  ├── catalog/         # CatalogBrowserApp
  ├── diff/            # DiffApp, DiffDetailView
  └── view/            # ViewApp, ViewDetailView

Backwards compatibility maintained via shim files.

Authored by: Aaron Lippold<lippold@gmail.com>
- Delete diff_tui.py, view_tui.py, tui_base.py, catalog_tui.py shims
- Update CLI commands to import from tui/ package directly
- Update tests to import from tui/ package directly

Not released yet, so no backwards compatibility needed.

Authored by: Aaron Lippold<lippold@gmail.com>
Extract shared functionality to BaseBrowserApp:
- compose() with get_detail_view() hook and has_search_container attr
- on_mount() with _get_columns() and _populate_table() hooks
- on_row_highlighted() with _show_detail() hook
- COMMON_CSS extended via CATALOG_CSS = COMMON_CSS + overrides
- COMMON_BINDINGS extended via BINDINGS = COMMON_BINDINGS + [...]
- Standardized _items/_all_items naming across all apps

Removes ~300 lines of duplicated code from catalog/diff/view apps.
All 106 TUI tests passing.

Authored by: Aaron Lippold<lippold@gmail.com>
- action_reverse_sort() moved to BaseBrowserApp, calls abstract _rebuild_table()
- Selection tracking via supports_selection attr and _on_selection_changed() hook
- get_selected_items() now in base class
- Removed duplicate code from all 3 app files

All 114 TUI tests passing.

Authored by: Aaron Lippold<lippold@gmail.com>
- Remove disabled checks from ActionMenu View/Export buttons
  (auto-fetch handles missing content via load_benchmark())
- Update _handle_action() to exit with action info for runner
- Add run_catalog_browser action loop to launch appropriate TUI
- Add direct keybindings: v=view, d=diff, e/s=export (skip menu)
- Diff action validates exactly 2 benchmarks selected
- After ViewApp/DiffApp exits, user returns to catalog browser

Closes ep9.8 (View action), ep9.9 (Diff action)

Authored by: Aaron Lippold<lippold@gmail.com>
- Show pending notifications when returning to catalog after error
- Add on_mount handler to display errors from previous action
- Print loading message to console while fetching
- Differentiate FileNotFoundError from general errors

Authored by: Aaron Lippold<lippold@gmail.com>
This refactor is incomplete and has bugs. DO NOT USE IN PRODUCTION.

Changes attempted:
- Convert exit/restart loop to push_screen pattern
- Create ViewScreen/DiffScreen in screens.py
- Add @work decorators for async loading
- Update CatalogBrowserApp to push screens instead of exit

Known issues:
- DiffScreen._show_detail() has method signature mismatch
- No integration tests to catch runtime errors
- Code needs further debugging

Authored by: Aaron Lippold<lippold@gmail.com>
Add asyncio_mode and asyncio_default_fixture_loop_scope settings
to support async TUI tests using Textual's app.run_test().

Authored by: Aaron Lippold<lippold@gmail.com>
BaseBrowserScreen:
- Screen-based equivalent of BaseBrowserApp for SPA navigation
- Uses action_go_back() instead of action_quit() for proper screen stack
- SCREEN_BINDINGS with Escape/q for back navigation

LoadingModal:
- Progress bar with percentage and status message
- Cancellation support via Escape key
- update_progress() for worker thread updates via call_from_thread()
- is_cancelled property for cooperative cancellation

Re-exports added to __init__.py for clean imports.

Part of TUI SPA refactor (cis-bench-247)

Authored by: Aaron Lippold<lippold@gmail.com>
DiffDetailView.update_content() expected change_data['new_ref'] but
DiffScreen only provided 'ref' key for renumbered items.

Added 'new_ref' key to renumbered items dict to match expected format.

Authored by: Aaron Lippold<lippold@gmail.com>
- _load_and_view() shows LoadingModal with progress during benchmark load
- _load_and_diff() shows LoadingModal for both benchmarks during diff
- Workers update progress via call_from_thread()
- User can cancel with Escape key
- Proper cleanup of modal on success, error, or cancellation

Uses @work decorator for background loading with thread=True.

Part of TUI SPA refactor (cis-bench-247)

Authored by: Aaron Lippold<lippold@gmail.com>
Add trailing two spaces to each field for markdown line breaks.
Each detail field now displays on its own line for readability.

Before: "ID: 11511 Platform: almalinux Community: ..."
After:
  ID: 11511
  Platform: almalinux
  Community: CIS AlmaLinux

Authored by: Aaron Lippold<lippold@gmail.com>
Fixed mark_latest_versions() to properly identify latest version within
each benchmark title group (e.g., AlmaLinux OS 8 vs OS 9 vs OS 10).

Issues fixed:
- Used CAST(benchmark_id AS INTEGER) for numeric comparison
  (was doing string comparison: "9794" > "23598")
- Excluded vNext pre-release versions from being marked latest
- Handles NULL published_date by using benchmark_id as proxy

Also improved detail pane formatting with markdown line breaks.

Authored by: Aaron Lippold<lippold@gmail.com>
Authored by: Aaron Lippold<lippold@gmail.com>
Moves the ★ indicator to its own column for cleaner display.
Column order: checkbox, cached, ID, Title, ★, Platform

Authored by: Aaron Lippold<lippold@gmail.com>
Authored by: Aaron Lippold<lippold@gmail.com>
- Add separate Version column between Title and Latest
- Change catalog browser split from 45/55 to 65/35
- View and Diff screens keep their existing 40/60 split

Columns: checkbox, cached, ID, Title, Version, Latest, Platform

Authored by: Aaron Lippold<lippold@gmail.com>
Authored by: Aaron Lippold<lippold@gmail.com>
Authored by: Aaron Lippold<lippold@gmail.com>
- Add 6 tests for mark_latest_versions() logic:
  - Single group marks highest benchmark_id
  - Multiple groups each have own latest
  - Next versions excluded from latest
  - NULL versions excluded from latest
  - Integer comparison (not string) for benchmark_id
  - Resets previous latest flags on re-run

- Fix test_catalog_css_has_overrides: 45/55% -> 65/35%
- Fix test_columns_include_cached_status: 5 -> 7 columns

Authored by: Aaron Lippold<lippold@gmail.com>
Sorting:
- Sort by title alphabetically, then newest first within each group
- Consistent sorting in init, rebuild, and search filter

Detail pane improvements:
- Add Dates section (published, last revision)
- Add Classification section (platform, type, community, owner)
- Use plain URL instead of markdown link (not clickable in terminal)

Tests:
- Update tests to check set membership instead of exact order

Authored by: Aaron Lippold<lippold@gmail.com>
- Add action_open_in_browser using Textual's open_url()
- Add keybinding 'o' for "Open URL"
- Update detail pane with hint: "Press 'o' to open in browser"
- Add tests for binding and action

Authored by: Aaron Lippold<lippold@gmail.com>
- Add Published column showing publication date (YYYY-MM-DD)
- Reduce title width slightly to fit new column
- Update test to expect 8 columns

Authored by: Aaron Lippold<lippold@gmail.com>
Database:
- Add collections (GROUP_CONCAT) to _list_all and search queries
- Add last_revision_date to both queries

Detail pane:
- Show Collections in Classification section

Authored by: Aaron Lippold<lippold@gmail.com>
Add comprehensive metadata extraction from CIS WorkBench detail pages.

- Parse web component JSON attributes (wb-benchmark-assets, wb-recommendation-data)
- Extract from real HTML structure with proper whitespace handling
- WebComponentDataExtractor utility for DRY reusable web component parsing
- 4 real HTML fixtures (OS/Cloud/Container/Database, 393KB)
- 102 parser tests passing (inc. 4 real HTML regression tests)

Authored by: Aaron Lippold <lippold@gmail.com>
Expand Pydantic Benchmark model with 13 new metadata fields.

New Models:
- BenchmarkAsset: title, cpe_id
- RevisionHistoryEntry: date, author, modification_count, diff_url

New Benchmark Fields:
- published_date, published_relative, release_type
- contributors list, contributors_str property (for XCCDF)
- parent_benchmark_url, parent_benchmark_title
- community_url, milestone_name, milestone_url
- intended_audience, acknowledgements
- assets list, revision_history list

Tests: 17 Pydantic model tests passing

Authored by: Aaron Lippold <lippold@gmail.com>
Add database tables and columns for extended metadata with auto-migration.

New Tables:
- benchmark_assets: FK to benchmark, title, cpe_id
- revision_history: FK to benchmark, date, author, modifications, diff_url

New Columns on catalog_benchmarks:
- release_type, contributors, parent_benchmark_id, parent_benchmark_url
- intended_audience, acknowledgements, milestone_name, milestone_url

Migration:
- Auto-runs on database open (adds columns + creates tables)
- Idempotent (safe to run multiple times)
- Updates FTS5 with new searchable fields (contributors, intended_audience)

Refactoring:
- get_benchmark() uses model_dump() (dynamic, not hardcoded dict)
- Query improvements: _list_all() and search() include all new columns

Tests: 60 database tests passing

Authored by: Aaron Lippold <lippold@gmail.com>
Create shared EnrichmentService used by both download paths.

Architecture (DRY):
- EnrichmentService.enrich_catalog_entry() - Single source of truth
- Used by: cis-bench download, cis-bench catalog download
- Prevents code duplication between download paths

Enrichment Process:
- Updates catalog_benchmarks with metadata from downloaded Benchmark
- Populates benchmark_assets table with CPE-IDs
- Populates revision_history table with revision entries
- Clears old data before inserting (handles updates correctly)

Integration:
- Main download command now enriches catalog (if catalog DB exists)
- Catalog download command uses same shared service
- Future refresh command will use same service

Tests: 9 enrichment tests passing

Authored by: Aaron Lippold <lippold@gmail.com>
Update WorkbenchScraper to populate all new Pydantic model fields from parser.

Changes:
- get_benchmark_metadata() uses parse_benchmark_detail_page() for all fields
- download_benchmark() populates all 13 new Benchmark fields from metadata
- Logs published_date and release_type during download

Tests: 32 scraper tests passing (30 existing + 2 new for extended metadata)

Authored by: Aaron Lippold <lippold@gmail.com>
Update all exporters to include complete benchmark metadata.

XCCDF (Critical):
- CPE platform-specification from benchmark.assets
- Published date in Dublin Core (dc:date)
- Release type in Dublin Core (dc:type)
- Contributors in Dublin Core (dc:creator)
- create_platforms() method with version-specific types

Markdown:
- Publication info, Lineage, Contributors, Assets/CPE-IDs, Description sections

CSV:
- New benchmark columns: published_date, release_type, contributors, cpe_ids, parent

JSON/YAML:
- Auto-included via model_dump() (no changes needed)

Tests: 54+ exporter tests passing (inc. 4 new XCCDF metadata tests)

Authored by: Aaron Lippold <lippold@gmail.com>
Update CLI and TUI to display all extended benchmark metadata.

CLI info command:
- Shows all extended metadata (published, release_type, parent, CPE, contributors)
- Supports multiple files (handles wildcards)
- Exits with error code if any file fails

TUI catalog detail pane:
- Publication section (published, release_type, milestone)
- Lineage section (forked from with URL)
- Contributors, Intended Audience, Acknowledgements sections
- Enhanced description display

CLI/TUI Parity:
- Both interfaces show same metadata
- Consistent formatting and organization

Authored by: Aaron Lippold <lippold@gmail.com>
Architecture:
- Catalog tab: browse benchmarks, view details, actions (v/d/e/o)
- Operations tab: bulk download, export, catalog refresh (placeholder)
- Settings tab: auth, preferences, about (placeholder)

Implementation:
- TABS config as single source of truth for tab structure
- Tests use config helpers (get_tab_count, get_tab_labels)
- CatalogTabPane with focus toggle between table/detail pane
- BaseTabPane with common bindings for all tab panes
- Research doc on TabbedContent focus management

16 integration tests passing.

Authored by: Aaron Lippold<lippold@gmail.com>
Migrated from standalone catalog/app.py:
- Selection system: _selected_indices, action_toggle_select, get_selected_items
- Downloaded status: _downloaded_ids, _load_downloaded_ids, ✓ indicator
- Open in browser: action_open_in_browser via self.app.open_url()

Tests adapted from test_catalog_browser.py (14 new tests, 30 total passing).

Authored by: Aaron Lippold<lippold@gmail.com>
- Checkbox: cyan bold when selected, dim when not
- Downloaded: green checkmark
- Latest: yellow bold star

Matches standalone catalog/app.py styling.

Authored by: Aaron Lippold<lippold@gmail.com>
- Title: bold cyan
- Version: bold green
- Status: green dot for Published, yellow for other
- Latest: yellow star badge
- ID: cyan
- URL in code block
- Updated action hints

Uses Rich Group to combine styled Text with Markdown sections.

Authored by: Aaron Lippold<lippold@gmail.com>
Phase 2b - Catalog Tab Actions:
- Add view action (v key) → ViewScreen via app.push_screen()
- Add diff action (d key) → DiffScreen for 2 selected benchmarks
- Add export action (e key) → ExportConfigDialog flow
- Add action menu (Enter key) → ActionMenu modal
- Use 'R' (Shift) for refresh (UX: uppercase for network ops)

Phase 2c - Test Reorganization:
- Split tests by type following Python best practices
- Unit tests (23) → tests/unit/test_catalog_tab_pane.py
- Integration tests (16) → tests/integration/test_main_tui.py

All 39 tests passing.

Authored by: Aaron Lippold<lippold@gmail.com>
Document the established pattern for test file organization:
- Unit tests (sync) in tests/unit/
- Integration tests (async) in tests/integration/
- Design decision: split mixed files by test type
- Example from TUI test reorganization (Phase 2c)

Added best practices:
- Separate sync from async tests
- Mirror source structure
- One class per feature area

Authored by: Aaron Lippold<lippold@gmail.com>
Add unit tests following established pattern:
- TestTabConfig: dataclass structure tests
- TestTabsConfig: TABS list validation (unique IDs, labels)
- TestTabHelperFunctions: get_tab_labels, get_tab_count
- TestMainTUIAppBindings: quit binding exists
- TestMainTUIAppClass: title, CSS, compose, inheritance

18 new unit tests, 57 total TUI tests now.

Authored by: Aaron Lippold<lippold@gmail.com>
Reference established test pattern in project CLAUDE.md for session context:
- Unit vs integration test placement criteria
- TUI test file structure with examples
- Link to full testing.md documentation

Ensures Claude Code sessions start with test org context.

Authored by: Aaron Lippold<lippold@gmail.com>
Replace LoadingModal screen with inline ProgressBar + Label widgets.
This eliminates the visible flash caused by push → pop → push sequence.

Before: Catalog → push LoadingModal → pop LoadingModal → push ViewScreen (flash)
After:  Catalog → show inline progress → push ViewScreen (clean transition)

Changes:
- Add ProgressBar and Label widgets to CatalogTabPane compose()
- Add _show_loading, _update_loading, _hide_loading helper methods
- Add escape handling to cancel loading operations
- Refactor view/diff/export flows to use inline progress
- Remove LoadingModal dependency for view/diff/export operations

Acceptance criteria met:
- No visible flash when opening View screen
- No visible flash when opening Diff screen
- Progress percentage shown during load
- Status text shown during operations
- Escape cancels loading operation
- Clean single-screen transition

Authored by: Aaron Lippold<lippold@gmail.com>
ViewScreen and DiffScreen set has_search_container = False but still
inherit the search binding. When pressing /, action_start_search tried
to find #search-container which doesn't exist, causing NoMatches error.

Fix: Check has_search_container before trying to access search widgets.
Show "Search not available in this view" warning if not available.

Authored by: Aaron Lippold<lippold@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant