feat(phase 3g dashboard polish): stale-projects card + refresh button + empty-collapse
- gitea.GetRepo returns FullName + UpdatedAt for the stale-card probe - dashboard collectStale: mai-managed items + linked-repo updated_at >60d + zero open tasks + zero open issues. Sorted longest-stale first, ≤20. Multi-repo items need ALL repos quiet to count as stale. Reuses the 4-worker pool + the already-aggregated task/issue counts from the Tasks / Issues cards (no extra DAV/Gitea fetches). - dashboardCache.invalidate(key) busts a single filter's cache entry; ?refresh=1 routes through it so ↻ button gets fresh data. - "updated Nm ago · cached/fresh" label + ↻ refresh link in dashboard chrome. - Empty-card collapse: with no filter + zero rows the card renders as a one-line muted note instead of full chrome. Filter-active cards keep chrome so m can tell "filter hid it" from "nothing there". - design.md §"Dashboard / daily-driver view" extended with the 4 new surfaces; the 3e "stale (3f)" out-of-scope line dropped. - 5 new tests: stale-surface, stale-skip-recent, refresh-busts-cache, empty-collapse, filter-keeps-chrome. 2 unit tests for gitea.GetRepo.
This commit is contained in:
@@ -373,7 +373,17 @@ A single landing surface at `/dashboard` that aggregates open work and recent ac
|
||||
|
||||
**TTL cache**: 60s in-memory map keyed by the encoded TreeFilter. The cache is single-replica only (no shared state needed at single-user scale). The ✓-mark-done handler explicitly invalidates the cache so the row disappears immediately on the next render.
|
||||
|
||||
**Out of scope for 3e**: stale-projects card (3f), real-time updates, full per-section pagination, dashboard-as-root-landing. Tree at `/` stays the default surface; nav bar adds a "dashboard" link so m chooses when to switch.
|
||||
**Out of scope for 3e**: real-time updates, full per-section pagination, dashboard-as-root-landing. Tree at `/` stays the default surface; nav bar adds a "dashboard" link so m chooses when to switch.
|
||||
|
||||
**Phase 3g additions:**
|
||||
|
||||
4. **Stale projects** — items with `'mai' = ANY(management)` AND every linked Gitea repo's `updated_at` older than 60d AND zero open VTODOs across linked CalDAV lists AND zero open Gitea issues. Sorted longest-stale first, capped at 20. Each row shows the project path, the quiet repo, and "last active Nd ago" with the absolute date on hover. "Consider archiving?" framing only — no auto-action.
|
||||
- Uses the same 4-worker pool as the issues card. Per-item task/issue counts are reused from the already-aggregated Tasks/Issues cards (no second DAV/Gitea pass).
|
||||
- Items with NO linked repo are skipped — without a signal there is no way to call them stale.
|
||||
- When an item has multiple linked repos, ALL must be older than the cutoff (so an item with one quiet repo and one busy repo is NOT stale).
|
||||
5. **Last-refresh indicator** — small "updated Nm ago · cached" / "updated Nm ago · fresh" line at the top of the dashboard chrome, derived from the cached payload's BuiltAt timestamp.
|
||||
6. **Force-refresh button** — `↻ refresh` link that adds `?refresh=1` to the current URL. The handler invalidates the matching cache key and re-runs the full aggregation. HTMX swaps the section in-place.
|
||||
7. **Empty-card collapse** — when no filter is active AND a card has zero rows, render a one-line `No open tasks.` / `No open issues.` / `No recent documents.` note instead of the full empty-state block. With a filter active the card chrome stays so m can distinguish "filter hid the data" from "no data".
|
||||
|
||||
## Graph view (Phase 3f)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user