Projects: classes as entities, and the sidebar fits short windows
check / check (push) Canceled after 0s

A project is a class with facts (description, status, kind, party,
dates, links, notes) in one project.set event behind the format
feature projects. Four tools (books.add_project, update_project,
projects, project); documents and decisions link to projects; B-37:
on-spec costs are expensed as incurred, repayment is revenue, and the
unrecovered cost is never below zero (Kani). Viewer: a Projects list
and a project page with its figures, by month and by account. The
sidebar measures its footer instead of reserving a fixed 172 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-22 03:50:52 -06:00
1 parent 0495726001
commit 321b94562a
71 files changed
+7446 -217

No files matched your search

+22 -3
View File
@@ -479,7 +479,26 @@ pub fn describe(b: &Books, line: &JournalLine) -> Option<Event> {
.map_or(Route::Company, Route::Party),
),
),
"class.added" => ev(icon::TAG, format!("Added class {}", s(p, "name")), None),
"class.added" => ev(
icon::BRIEFCASE,
format!("Added project {}", s(p, "name")),
u32::try_from(id).ok().map(Route::Project),
),
"project.set" => {
let status = ledger_core::ProjectStatus::parse(s(p, "status"))
.map_or("", |x| x.words())
.to_lowercase();
let kind = match p.get("kind").and_then(|v| v.as_str()) {
Some(k) => ledger_core::ProjectKind::parse(k)
.map_or(k.to_string(), |x| x.words().to_lowercase()),
None => "kind not recorded".into(),
};
ev(
icon::BRIEFCASE,
format!("Project {}: {status}, {kind}", s(p, "name")),
u32::try_from(id).ok().map(Route::Project),
)
}
"party.added" => {
let roles: Vec<String> = p
.get("roles")
@@ -1114,8 +1133,8 @@ pub fn describe_any(b: &Books, line: &JournalLine) -> Event {
.get("class_id")
.and_then(|v| v.as_u64())
.and_then(|c| b.ledger.get_class(c as u32))
.map(|c| c.name.clone())
.unwrap_or_else(|| "no class".into());
.map(|c| format!("project {}", c.name))
.unwrap_or_else(|| "no project".into());
Event {
icon: icon::TAG,
text: format!(