[feature] Project & milestone progress: auto-calculate from task completion #30
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_biz#30
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Identified in home#211: the progress bar on projects and milestones is unresponsive / always shows 0.
Current state
Both
Project.progress(u8, 0-100) andMilestone.progress(u8, 0-100) are stored fields. Nothing in the handlers or services auto-calculates these values from task completion. If the OSIS backend doesn't set them, they stay at 0.Work required
Option A — Calculate in handler (no persistence)
In
projects_detailandmilestones_detailhandlers, after loading tasks:Pass as a separate
computed_progressfield to the template (do not overwrite the stored value).Option B — Persist on task status change
When a task is updated, recalculate and save the parent project/milestone progress.
Option A is simpler and avoids stale data; recommend starting there.
Notes
task.milestone_sidtask.project_sidproject.progress == 0Implementation Spec for Issue #30
Objective
The progress bar on project detail and milestone detail pages always displays 0% because
Project.progressandMilestone.progressare stored fields that nothing ever writes. This spec adds a computed progress value derived from task completion counts, calculated in each handler after tasks are fetched and passed to the template as a newcomputed_progressfield. The stored values are never mutated.Approach
Option A (recommended): Calculate in handler, pass as
computed_progressto template (no persistence).Requirements
computed_progress: u8inprojects_detailas(done_count * 100 / tasks.len()) as u8, where done tasks haveTaskStatus::DoneorTaskStatus::Closed. Iftasksis empty, result is0.computed_progress: u8inmilestones_detailwith the same formula over the tasks fetched viaget_tasks_for_milestone.project.progressormilestone.progress(no persistence).computed_progress: u8as a new field onProjectDetailTemplateandMilestoneDetailTemplate.ProjectDetailTemplate::render, replaceself.project.progressused in the progress bar withself.computed_progress.MilestoneDetailTemplate::render, replaceself.milestone.progressused in the progress bar withself.computed_progress.TaskStatus::Cancelledis NOT counted as done.Files to Modify
crates/hero_biz_ui/src/web/templates/mod.rscomputed_progress: u8field to both template structs; use it in bothrendermethodscrates/hero_biz_ui/src/web/handlers/mod.rscomputed_progressinprojects_detailandmilestones_detail; pass to template structImplementation Plan
Step 1 — Add
computed_progresstoProjectDetailTemplatestructFile:
crates/hero_biz_ui/src/web/templates/mod.rspub computed_progress: u8,to the struct definitionStep 2 — Add
computed_progresstoMilestoneDetailTemplatestructFile:
crates/hero_biz_ui/src/web/templates/mod.rspub computed_progress: u8,to the struct definitionStep 3 — Update
ProjectDetailTemplate::renderto usecomputed_progressFile:
crates/hero_biz_ui/src/web/templates/mod.rsprogress = self.project.progressbinding toprogress = self.computed_progressStep 4 — Update
MilestoneDetailTemplate::renderto usecomputed_progressFile:
crates/hero_biz_ui/src/web/templates/mod.rsprogress = self.milestone.progressbinding toprogress = self.computed_progressStep 5 — Compute progress in
projects_detailhandlerFile:
crates/hero_biz_ui/src/web/handlers/mod.rsdone_countandcomputed_progresscomputed_progressto theProjectDetailTemplate { ... }struct literalStep 6 — Compute progress in
milestones_detailhandlerFile:
crates/hero_biz_ui/src/web/handlers/mod.rsdone_countandcomputed_progresscomputed_progressto theMilestoneDetailTemplate { ... }struct literalStep 7 — Verify
TaskStatusimport in handlersFile:
crates/hero_biz_ui/src/web/handlers/mod.rsTaskStatusis imported (it likely already is from the Kanban handler); add import if missingAcceptance Criteria
ProjectDetailTemplatestruct has apub computed_progress: u8fieldMilestoneDetailTemplatestruct has apub computed_progress: u8fieldProjectDetailTemplate::renderusesself.computed_progressfor the progress barMilestoneDetailTemplate::renderusesself.computed_progressfor the progress barprojects_detailhandler computes and passescomputed_progressmilestones_detailhandler computes and passescomputed_progressTaskStatus::Cancelledtasks are not counted as donecargo buildpasses with no errorsNotes
rendermethods uses a single named argumentprogress = ...that appears twice in the HTML (the%text and thewidth:style). Changing only the binding on the Rust side is sufficient.project.progressandmilestone.progressfields are not removed and may still appear in other parts of the template (e.g., the milestone list row in project detail), which are intentionally left unchanged.(done_count * 100 / tasks.len()) as u8is intentional and matches the issue formula.Test Results
All tests passed. The single test
parser::tests::test_name_fixin thehero_biz_uicrate passed successfully. The remaining crates (hero_biz,hero_biz_app,hero_biz_sdk) have no tests defined yet.Implementation Summary
Implemented Option A: auto-calculate progress in handlers without persisting the value.
Changes Made
crates/hero_biz_ui/src/web/templates/mod.rscomputed_progress: u8field toProjectDetailTemplatecomputed_progress: u8field toMilestoneDetailTemplateProjectDetailTemplate::rendernow usesself.computed_progressfor the progress bar instead ofself.project.progressMilestoneDetailTemplate::rendernow usesself.computed_progressfor the progress bar instead ofself.milestone.progresscrates/hero_biz_ui/src/web/handlers/mod.rsprojects_detail: after loading tasks, computesdone_count(tasks withTaskStatus::DoneorTaskStatus::Closed) and derivescomputed_progressas(done_count * 100 / tasks.len()) as u8; passes it into the template structmilestones_detail: same computation over the milestone's tasks; passescomputed_progressinto the template structTaskStatus::Cancelledis excluded from the done countTest Results
cargo buildcleanAcceptance Criteria
ProjectDetailTemplatehascomputed_progress: u8MilestoneDetailTemplatehascomputed_progress: u8cargo buildpasses with no errorsImplemented in
e5261a5923. Progress is now computed from task completion in all views: project list, milestone list, projects dashboard, project detail milestone rows, and person detail milestone rows.