Skip to content

Commit b3248c8

Browse files
VirInvictusclaude
andcommitted
v0.7.2 — Review = Weekly Review merge + drop "Lists" sidebar header
Brandon's after-v0.7.1 review of the Review page surfaced two problems we'd planned to fix in tier 3 of the v0.7 polish arc but hadn't gotten to: the canonical Review page and the seeded "Weekly Review" perspective lived under almost the same name and showed completely different content (Review: "All caught up"; Weekly Review: a long task list). And the upper-left corner still had the centered "Lists" header from libadwaita's default sidebar auto-title, contradicting the magazine-spread treatment v0.7.0 introduced for the right side. 1. Review = Weekly Review merge. The canonical Review page now renders TWO sections in one surface: "Projects to review" (the existing Phase 13 review queue) followed by "This week" (the open-tasks-this-week filter formerly seeded as a saved perspective). Section 2 reuses agenda::build_row for visual consistency; clicking a row opens the Inspector for that task. Both sections show inline notes when empty; "All caught up" status placeholder only appears when both are empty. The seeded "Weekly Review" perspective is retired — seed_initial_perspectives helper, WEEKLY_REVIEW_NAME constant, and the four seed_weekly_review_* tests removed. Filter constant survives as REVIEW_WEEKLY_WALK_FILTER for the GUI's refresh path. Existing user DBs keep their row (we don't delete data); fresh DBs and fixtures land clean. Regression script self-seeds a "CLI Smoke Persp" list- renderer perspective for the kanban-against-list-renderer error case (was riding on the seeded Weekly Review). 2. Drop the "Lists" centered title. Sidebar AdwHeaderBar now carries an empty AdwWindowTitle as its title-widget, suppressing the auto-rendered "Lists" label. Header becomes pure chrome (which is empty since show-end-title-buttons=false); the filter entry below acts as the sidebar's visual top. Mirrors the title-suppression v0.7.0 applied to the content side. Test count: 119 + 169 + 1 + 106 + 106 = 501 (down 4 from v0.7.1 — the seeded-perspective tests are gone). Ship-gate runs in under 2 seconds. No schema changes, no new dependencies, no spec semantics shifted. VERSION + Cargo.toml + spec.md + roadmap.md + patchnotes + AppStream metainfo bumped to 0.7.2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 110a771 commit b3248c8

13 files changed

Lines changed: 358 additions & 203 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ default-members = ["atrium"]
44
resolver = "2"
55

66
[workspace.package]
7-
version = "0.7.1"
7+
version = "0.7.2"
88
edition = "2024"
99
license = "MIT"
1010
authors = ["Brandon LaRocque"]

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.7.1
1+
0.7.2

atrium-core/src/db/mod.rs

Lines changed: 32 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,25 @@ pub mod worker;
2020

2121
use std::path::Path;
2222

23-
use rusqlite::{Connection, params};
23+
use rusqlite::Connection;
2424
use tracing::{debug, info};
25-
use uuid::Uuid;
2625

2726
use crate::error::DbError;
2827

29-
/// v0.6.0 — name of the seeded Weekly Review Perspective. Public so
30-
/// tests can assert against a stable string.
31-
pub const WEEKLY_REVIEW_NAME: &str = "Weekly Review";
32-
33-
/// Filter expression for the Weekly Review seed. Matches anything
34-
/// the user should look at this week per spec §4.2 + §4.3:
35-
/// overdue items, anything scheduled this week, deadlines next week
36-
/// (heads-up window), and tasks just freed from a defer.
37-
pub const WEEKLY_REVIEW_FILTER: &str = "is:overdue OR scheduled:thisweek OR (is:deadline AND due:nextweek) OR (is:deferred AND defer:<=today)";
28+
/// v0.6.0 → v0.7.2 — filter expression for the canonical Review
29+
/// page's "This week" weekly walk section. Matches anything the
30+
/// user should look at this week per spec §4.2 + §4.3: overdue
31+
/// items, anything scheduled this week, deadlines reaching next
32+
/// week (heads-up window), and tasks just freed from a defer.
33+
///
34+
/// Originally seeded as a saved Perspective named "Weekly Review";
35+
/// v0.7.2 retired the seed (Brandon's "Review and Weekly Review
36+
/// showed two different things — confusing" feedback). The
37+
/// canonical Review page now renders this same content as its
38+
/// secondary section, alongside the project-review queue. The
39+
/// constant survives so the GUI window-side fetch can use the
40+
/// same expression atrium_search would parse.
41+
pub const REVIEW_WEEKLY_WALK_FILTER: &str = "is:overdue OR scheduled:thisweek OR (is:deadline AND due:nextweek) OR (is:deferred AND defer:<=today)";
3842

3943
/// Open the Atrium database at `path`, applying pragmas and migrations.
4044
///
@@ -56,50 +60,15 @@ pub fn open(path: &Path) -> Result<Connection, DbError> {
5660
let mut conn = Connection::open(path)?;
5761
configure_pragmas(&conn)?;
5862
migrations::migrate(&mut conn)?;
59-
seed_initial_perspectives(&conn)?;
63+
// v0.6.0 → v0.7.2 — the Weekly Review perspective is no
64+
// longer auto-seeded. The canonical Review page now renders
65+
// the same content as its weekly-walk section; seeding a
66+
// duplicate as a saved Perspective just created the
67+
// confusion Brandon flagged. Existing user DBs keep their
68+
// row (we don't delete data); fresh DBs land clean.
6069
Ok(conn)
6170
}
6271

63-
/// v0.6.0 — Phase 15.75 Slice C1. Insert the Weekly Review
64-
/// Perspective on first open. Idempotent: dedupes against an
65-
/// existing row with the same `name`, so users who delete it
66-
/// don't get it re-seeded on next launch (the dedup key is the
67-
/// visible name, not a synthetic flag column — keeps the seed
68-
/// invisible to future migrations).
69-
///
70-
/// The filter matches anything the user should look at this week:
71-
/// overdue tasks, anything scheduled this week, deadlines reaching
72-
/// into next week (the §4.2 Today-list heads-up window), and
73-
/// tasks whose defer just passed today.
74-
pub fn seed_initial_perspectives(conn: &Connection) -> Result<(), DbError> {
75-
let existing: i64 = conn.query_row(
76-
"SELECT count(*) FROM perspective WHERE name = ?1",
77-
params![WEEKLY_REVIEW_NAME],
78-
|r| r.get(0),
79-
)?;
80-
if existing > 0 {
81-
return Ok(());
82-
}
83-
let uuid = Uuid::new_v4().to_string();
84-
// Position 1.0 puts it first alphabetically among any future
85-
// perspectives users add; the row reads as the "default" entry
86-
// even after sort by position then name.
87-
conn.execute(
88-
"INSERT INTO perspective \
89-
(uuid, name, icon, filter_expr, position) \
90-
VALUES (?1, ?2, ?3, ?4, ?5)",
91-
params![
92-
uuid,
93-
WEEKLY_REVIEW_NAME,
94-
"object-select-symbolic",
95-
WEEKLY_REVIEW_FILTER,
96-
1.0_f64,
97-
],
98-
)?;
99-
debug!(uuid, name = WEEKLY_REVIEW_NAME, "seeded perspective");
100-
Ok(())
101-
}
102-
10372
/// Apply pragmas to a connection (writable or read-only). Per spec §3.2
10473
/// and roadmap.md Phase 1.
10574
pub fn configure_pragmas(conn: &Connection) -> Result<(), DbError> {
@@ -398,104 +367,15 @@ mod tests {
398367
let _ = std::fs::remove_file(tmp.with_extension("db-wal"));
399368
}
400369

401-
// ── v0.6.0 Slice C1: Weekly Review seed ────────────────────────
402-
403-
#[test]
404-
fn seed_weekly_review_inserts_on_fresh_db() {
405-
let conn = fresh_db();
406-
// fresh_db() didn't seed; should be zero perspectives.
407-
let count_before: i64 = conn
408-
.query_row("SELECT count(*) FROM perspective", [], |r| r.get(0))
409-
.unwrap();
410-
assert_eq!(count_before, 0);
411-
seed_initial_perspectives(&conn).unwrap();
412-
let count_after: i64 = conn
413-
.query_row("SELECT count(*) FROM perspective", [], |r| r.get(0))
414-
.unwrap();
415-
assert_eq!(count_after, 1);
416-
let (name, icon, filter): (String, Option<String>, String) = conn
417-
.query_row(
418-
"SELECT name, icon, filter_expr FROM perspective WHERE name = ?1",
419-
params![WEEKLY_REVIEW_NAME],
420-
|r| Ok((r.get(0)?, r.get(1)?, r.get(2)?)),
421-
)
422-
.unwrap();
423-
assert_eq!(name, WEEKLY_REVIEW_NAME);
424-
assert_eq!(icon.as_deref(), Some("object-select-symbolic"));
425-
assert_eq!(filter, WEEKLY_REVIEW_FILTER);
426-
}
427-
428-
#[test]
429-
fn seed_weekly_review_idempotent() {
430-
let conn = fresh_db();
431-
seed_initial_perspectives(&conn).unwrap();
432-
seed_initial_perspectives(&conn).unwrap();
433-
seed_initial_perspectives(&conn).unwrap();
434-
let count: i64 = conn
435-
.query_row("SELECT count(*) FROM perspective", [], |r| r.get(0))
436-
.unwrap();
437-
assert_eq!(count, 1, "second + third seed pass must dedupe");
438-
}
439-
440-
#[test]
441-
fn seed_weekly_review_respects_user_deletion() {
442-
// If the user deletes the seeded perspective, re-running the
443-
// seed must not re-insert (we dedupe by name; deleted means
444-
// intentional). But a different perspective also named
445-
// "Weekly Review" *would* satisfy the dedup — that's the
446-
// user's choice, not ours.
447-
let conn = fresh_db();
448-
seed_initial_perspectives(&conn).unwrap();
449-
conn.execute(
450-
"DELETE FROM perspective WHERE name = ?1",
451-
params![WEEKLY_REVIEW_NAME],
452-
)
453-
.unwrap();
454-
seed_initial_perspectives(&conn).unwrap();
455-
let count: i64 = conn
456-
.query_row(
457-
"SELECT count(*) FROM perspective WHERE name = ?1",
458-
params![WEEKLY_REVIEW_NAME],
459-
|r| r.get(0),
460-
)
461-
.unwrap();
462-
// After deletion + re-seed, it should be back. The deletion-
463-
// sticks behaviour relies on the seed only running at open(),
464-
// not on subsequent calls — open() is single-shot per process,
465-
// so a delete during a session stays gone until next launch.
466-
// (Interactive sessions don't re-call open mid-flight; the
467-
// GUI holds one Connection for its lifetime.)
468-
assert_eq!(
469-
count, 1,
470-
"seed re-creates after deletion when invoked directly"
471-
);
472-
}
473-
474-
#[test]
475-
fn seed_weekly_review_runs_through_open() {
476-
let tmp = std::env::temp_dir().join(format!("atrium-seed-test-{}.db", std::process::id()));
477-
let _ = std::fs::remove_file(&tmp);
478-
let conn = open(&tmp).unwrap();
479-
let count: i64 = conn
480-
.query_row(
481-
"SELECT count(*) FROM perspective WHERE name = ?1",
482-
params![WEEKLY_REVIEW_NAME],
483-
|r| r.get(0),
484-
)
485-
.unwrap();
486-
assert_eq!(count, 1);
487-
drop(conn);
488-
489-
// Reopen the same path — the seed must NOT double up.
490-
let conn = open(&tmp).unwrap();
491-
let count: i64 = conn
492-
.query_row("SELECT count(*) FROM perspective", [], |r| r.get(0))
493-
.unwrap();
494-
assert_eq!(count, 1, "reopen must not duplicate the seed");
495-
drop(conn);
496-
497-
let _ = std::fs::remove_file(&tmp);
498-
let _ = std::fs::remove_file(tmp.with_extension("db-shm"));
499-
let _ = std::fs::remove_file(tmp.with_extension("db-wal"));
500-
}
370+
// ── v0.6.0 → v0.7.2: Weekly Review seed retired ───────────────
371+
//
372+
// The four `seed_weekly_review_*` tests that lived here covered
373+
// the seeded Weekly Review perspective. v0.7.2 removed the seed
374+
// (the canonical Review page now renders the same content as
375+
// its weekly-walk section; the saved-search duplicate was the
376+
// source of Brandon's "Review and Weekly Review show two
377+
// different things" confusion). The constants and the
378+
// seed_initial_perspectives helper are gone; only
379+
// REVIEW_WEEKLY_WALK_FILTER survives, used by the GUI window
380+
// when fetching the weekly walk.
501381
}

atrium/src/ui/agenda.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,12 @@ fn build_section<F: Fn(i64) + 'static + Clone>(
263263
card.upcast()
264264
}
265265

266-
fn build_row<F: Fn(i64) + 'static>(
266+
/// v0.7.2 — `pub(crate)` so the canonical Review page can reuse
267+
/// the same task-row treatment for its weekly-walk section. Same
268+
/// shape (title + date chip + project-and-tags meta line + click
269+
/// → Inspector); same CSS class so any styling tweaks apply
270+
/// uniformly across both pages.
271+
pub(crate) fn build_row<F: Fn(i64) + 'static>(
267272
task: &Task,
268273
project_titles: &HashMap<i64, String>,
269274
tag_pills: &TagPillMap,

0 commit comments

Comments
 (0)