feat: Add filter presets, persistent column widths, and enhanced export options

This commit is contained in:
William Valentin
2025-08-08 12:51:59 -07:00
parent 30896e4975
commit 5354b963ac
3 changed files with 93 additions and 0 deletions

View File

@@ -487,3 +487,19 @@ Primary action buttons show their keyboard shortcuts in the button text (e.g., "
*This document was generated by the documentation consolidation system.*
*Last updated: 2025-08-05 14:53:36*
## New in v1.14.9: Filters, columns, and exports
### Filter presets (Save/Load/Delete)
- Open the Search/Filter panel (Ctrl+F), set filters, then click Save to store a named preset.
- A themed modal dialog asks for a name and shows if youll overwrite an existing preset.
- Load via the presets dropdown → Load. Delete via Delete.
- Presets persist across restarts.
### Persistent column widths and sort
- Resize columns; widths are saved automatically and restored next run.
- Click a header to sort; the last sorted column and direction are remembered and re-applied on refresh/startup.
### Export current (filtered) data
- In Export (Ctrl+E), choose scope: All data or Current filtered view.
- Works with CSV, JSON, XML, and PDF exporters.

View File

@@ -209,6 +209,11 @@ Powerful data filtering and search capabilities for analyzing your health data.
- Filter to last 30 days with depression scores between 3-6
- Combine filters: High anxiety + specific medicine + date range
#### Presets and Persistence (v1.14.9)
- Save/Load/Delete filter presets directly from the Search/Filter panel. Presets are named and persist across restarts. Save dialog is themed and shows overwrite/new hints.
- Column widths and last sorted column/direction are remembered. Resizing headers or sorting stores preferences; theyre re-applied on refresh/startup.
- Export can target the current filtered view: choose in the Export window to export only matching rows (CSV/JSON/XML/PDF).
### 📝 Data Management
Robust data handling with comprehensive backup and migration support.

View File

@@ -0,0 +1,72 @@
"""Tests for persistence features: column widths and last sort reapplication."""
import tkinter as tk
from tkinter import ttk
import pytest
from src.ui_manager import UIManager
@pytest.fixture
def root_window():
root = tk.Tk()
yield root
root.destroy()
@pytest.fixture
def ui_manager(root_window, mock_logger):
return UIManager(root_window, mock_logger)
def test_table_applies_saved_column_widths(ui_manager, root_window, monkeypatch):
# Provide a fake get_pref that returns widths for some columns
saved = {"column_widths": {"Date": 123, "Note": 456}}
def fake_get_pref(key, default=None): # type: ignore[override]
return saved.get(key, default)
monkeypatch.setattr("src.ui_manager.get_pref", fake_get_pref)
main = ttk.Frame(root_window)
table_ui = ui_manager.create_table_frame(main)
tree: ttk.Treeview = table_ui["tree"]
# Verify widths applied
assert int(tree.column("Date", option="width")) == 123
assert int(tree.column("Note", option="width")) == 456
def test_reapply_last_sort_descending(ui_manager, root_window, monkeypatch):
# Simulate last sort on 'Date' descending
saved = {"last_sort": {"column": "Date", "ascending": False}}
def fake_get_pref(key, default=None): # type: ignore[override]
return saved.get(key, default)
monkeypatch.setattr("src.ui_manager.get_pref", fake_get_pref)
main = ttk.Frame(root_window)
table_ui = ui_manager.create_table_frame(main)
tree: ttk.Treeview = table_ui["tree"]
# Insert a few rows with Date values that sort numerically
# Columns are dynamic; ensure we provide a value for each column
cols = list(tree["columns"])
idx_date = cols.index("Date")
def row_with_date(val: str):
row = [""] * len(cols)
row[idx_date] = val
return row
tree.insert("", "end", values=row_with_date("1"))
tree.insert("", "end", values=row_with_date("3"))
tree.insert("", "end", values=row_with_date("2"))
# Reapply last sort (descending) and verify first row has Date '3'
ui_manager.reapply_last_sort(tree)
first_item = tree.get_children("")[0]
first_vals = tree.item(first_item, "values")
assert str(first_vals[idx_date]) == "3"