Add design doc for tags, export/import, and changelog improvements

This commit is contained in:
lashman
2026-03-01 00:47:14 +02:00
parent d11546efc6
commit 79519c500a

View File

@@ -0,0 +1,166 @@
# Final UX Improvements Design: Tags, Export/Import, Changelog
## Overview
Three remaining UX improvements from the 30-item enhancement list:
- **#12** App grouping with tags + grouped library sections
- **#13** Unified export/import (shared core for CLI + GUI) with extended fields
- **#14** Bridge changelog gap (GitHub release notes -> release_history) + updates view preview
## #12: Tags + Grouped Library Sections
### Current State
- `tags: Option<String>` field exists in `AppImageRecord` (database.rs:50)
- `update_tags(id, tags)` DB method exists (database.rs:2069)
- No UI for viewing, editing, or filtering by tags
- Library view is flat (grid or list mode, no sections)
### Design
**Detail view - tag editor:**
- Add a "Tags" row in the detail view info section
- Display existing tags as pill-shaped chips with "x" remove buttons
- A "+" button at the end opens an inline text entry to add a new tag
- Tags stored as comma-separated string in the existing `tags` column
- On add/remove, call `db.update_tags()` immediately (no save button)
**Library view - tag filter chips:**
- Add a horizontal scrollable chip bar at the top of the library view (same pattern as catalog category chips)
- "All" chip selected by default, plus one chip per unique tag found across all apps
- Selecting a tag filters the view to only apps with that tag
- Chip bar is only visible when at least one app has tags
**Library view - grouped sections:**
- When no search is active and no tag filter is selected, group apps by their first tag under collapsible section headers
- Apps with no tags go under an "Uncategorized" section at the bottom
- Sort dropdown still works within each group
- In search mode or tag-filter mode, grouping is disabled (flat list)
**Data model:** No schema changes. Comma-separated tags in existing column.
### Files Modified
| File | Changes |
|------|---------|
| `src/ui/detail_view.rs` | Add tag editor chips row in info section |
| `src/ui/library_view.rs` | Add tag filter chip bar, grouped section headers |
| `src/core/database.rs` | Add `get_all_tags()` query to collect distinct tags |
## #13: Unified Export/Import (CLI + GUI)
### Current State
- CLI-only export/import in `cli.rs` (lines 887-1000+)
- JSON format v1 with limited fields: path, app_name, app_version, integrated, notes, categories
- No GUI file picker dialogs for export/import
- No shared module - logic is inline in CLI handlers
### Design
**Shared core module: `src/core/backup.rs`**
New module with two public functions:
```
pub fn export_app_list(db: &Database, path: &Path) -> Result<usize, BackupError>
pub fn import_app_list(db: &Database, path: &Path) -> Result<ImportResult, BackupError>
```
Where `ImportResult` contains:
- `matched: usize` - apps found and metadata merged
- `missing: Vec<String>` - app names/paths not found on disk
**JSON format v2:**
```json
{
"version": 2,
"exported_at": "2026-03-01T10:00:00Z",
"appimages": [
{
"path": "/home/user/Applications/MyApp.AppImage",
"app_name": "MyApp",
"app_version": "1.0.0",
"integrated": true,
"notes": "user notes",
"categories": "Graphics;Utility;",
"tags": "work,design",
"pinned": false,
"launch_args": "--no-sandbox",
"sandbox_mode": "permissive",
"autostart": false
}
]
}
```
Graceful v1 handling: missing fields default to None (not overwritten on import).
**Import merge semantics:**
- Match apps by path (exact match)
- For matched apps, merge each field: only overwrite if the import value is non-empty/non-null AND the existing value is empty/null (preserve user's current data)
- Tags: merge (union of existing + imported tags, no duplicates)
- For unmatched paths: collect into `missing` list
**CLI (cli.rs):**
- `cmd_export()` and `cmd_import()` become thin wrappers calling `backup::export_app_list()` / `backup::import_app_list()`
- Same CLI flags and output messages
**GUI (window.rs):**
- Add "Export app list" and "Import app list" items to the hamburger menu
- Export: `gtk::FileDialog` save picker, default filename `driftwood-apps.json`, calls `backup::export_app_list()`, toast on success
- Import: `gtk::FileDialog` open picker with `.json` filter, calls `backup::import_app_list()`, toast showing "Imported N apps" + dialog listing missing apps if any
- Refresh library view after import
### Files Modified
| File | Changes |
|------|---------|
| `src/core/backup.rs` | New module: export/import logic, JSON v2 format |
| `src/core/mod.rs` | Add `pub mod backup;` |
| `src/cli.rs` | Refactor cmd_export/cmd_import to call backup module |
| `src/window.rs` | Add menu items + file picker dialogs for export/import |
## #14: Bridge Changelog Gap + Updates View Preview
### Current State
- `release_history: Option<String>` field exists in AppImageRecord (JSON array)
- Detail view already renders release history when data exists (detail_view.rs:760-820)
- AppStream parsing populates release_history for local metainfo (rare)
- GitHub enrichment fetches release info but does NOT write to release_history
- Updates view shows update-available cards but no changelog preview
### Design
**Enrichment bridge (github_enrichment.rs):**
- After `enrich_app_release_info()` fetches the latest release, also fetch up to 10 recent releases from the GitHub releases API
- Convert each release to `ReleaseInfo { version, date, description }` format
- Serialize as JSON array and write to `release_history` column
- Only update if the field is currently empty (don't overwrite AppStream data which may be more authoritative)
- The existing detail view Release History section will then automatically display this data for all GitHub-enriched apps
**New DB method:**
- `update_release_history(id: i64, history_json: &str)` - simple UPDATE on the release_history column
**Updates view changelog preview (updates_view.rs):**
- Each update card gets an `adw::ExpanderRow` "What's new" section below the existing content
- If `release_history` is populated, find the entry matching `latest_version` and show its description
- If no matching entry or no release_history data: show "Release notes not available" in dim text
- Collapsed by default to keep the view compact
### Files Modified
| File | Changes |
|------|---------|
| `src/core/github_enrichment.rs` | Fetch recent releases, write to release_history |
| `src/core/database.rs` | Add `update_release_history()` method |
| `src/ui/updates_view.rs` | Add expandable "What's new" section to update cards |
## Implementation Order
1. **#14 first** - Smallest scope, self-contained enrichment + UI change
2. **#12 second** - Tags are self-contained, no dependency on other features
3. **#13 last** - Export should include tags (depends on #12 being functional)