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

+27 -2
View File
@@ -50,7 +50,7 @@ fn provenance(ui: &mut Ui, by: &str, on: chrono::NaiveDate) {
/// How the books are kept, as the owners decided: conventions, decisions,
/// and what is open (each only when there is something to show).
fn kept_cards(ui: &mut Ui, b: &Books) {
fn kept_cards(ui: &mut Ui, b: &Books, go: &mut Option<Route>) {
let p = pal(ui.ctx());
let kept = b.ledger.conventions();
let conventions: Vec<_> = kept.conventions().filter(|c| c.retired.is_none()).collect();
@@ -95,6 +95,27 @@ fn kept_cards(ui: &mut Ui, b: &Books) {
RichText::new(&d.new.decision_md).font(theme::regular(12.5)),
&d.new.decision_md,
);
if !d.new.projects.is_empty() {
ui.horizontal_wrapped(|ui| {
for &c in &d.new.projects {
if widgets::link(
ui,
RichText::new(format!(
"{} {}",
icon::BRIEFCASE,
b.project_label(c)
))
.font(theme::regular(12.0))
.color(p.accent),
)
.on_hover_text("Open this project")
.clicked()
{
*go = Some(Route::Project(c));
}
}
});
}
provenance(ui, &d.new.decided_by.join(" and "), d.new.decided_on);
ui.add_space(6.0);
}
@@ -132,6 +153,7 @@ fn kept_cards(ui: &mut Ui, b: &Books) {
pub fn show(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
let p = pal(ui.ctx());
let mut kept_go: Option<Route> = None;
page(ui, "company", |ui| {
let c = &b.settings.company;
widgets::page_header(
@@ -192,7 +214,7 @@ pub fn show(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
);
},
);
kept_cards(ui, b);
kept_cards(ui, b, &mut kept_go);
}
_ => {
widgets::titled_card(
@@ -332,6 +354,9 @@ pub fn show(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
recurring(ui, b);
parties(ui, b, shell);
});
if let Some(r) = kept_go {
shell.go(r);
}
}
fn assets(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {