feat: make Week Ahead review readable and editable (Closes #1190)
CI / lint (pull_request) Successful in 3m21s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 4m38s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-20 18:33:37 +00:00
1 parent 356f11b9c1
commit 9f40a4c5ac
6 files changed
+135 -11

No files matched your search

+22 -4
View File
@@ -44,7 +44,11 @@ def test_release_artifact_plans_seven_touch_safe_mobile_dates(
}))
return
route.fulfill(status=200, content_type="application/json", body=json.dumps({
"revision": 0, "timezone": None, "days": [],
"revision": 0, "timezone": None, "days": [{
"plan_date": (date.today() + timedelta(days=1)).isoformat(),
"ids": ["issue:acme/mobile:41:"], "capacity_minutes": 60,
"estimates": {"issue:acme/mobile:41:": 30},
}],
}))
page.route("**/api/v1/week", week_route)
@@ -67,18 +71,32 @@ def test_release_artifact_plans_seven_touch_safe_mobile_dates(
assert bounds and bounds["height"] >= 44
dates.nth(2).click()
expect(dates.nth(2)).to_have_attribute("aria-current", "date")
expect(page.locator("#week-plan-progress")).to_have_text("Day 3 of 7 · 0 planned")
expect(page.locator("#week-plan-progress")).to_have_text("Day 3 of 7 · 1 planned")
expect(page.locator("#save-today-plan")).to_have_text("Save & next")
page.locator("#save-today-plan").click()
expect(page.locator("#plan-today-sheet")).to_be_visible()
expect(dates.nth(3)).to_have_attribute("aria-current", "date")
expect(page.locator("#week-plan-progress")).to_have_text("Day 4 of 7 · 0 planned")
expect(page.locator("#week-plan-progress")).to_have_text("Day 4 of 7 · 1 planned")
dates.nth(6).click()
expect(page.locator("#save-today-plan")).to_have_text("Save week")
page.locator("#save-today-plan").click()
expect(page.locator("#plan-today-sheet")).to_be_visible()
expect(page.locator("#week-review")).to_be_visible()
expect(page.locator("#week-review-days .week-review-day")).to_have_count(7)
first_day = page.locator("#week-review-days .week-review-day").first
expect(first_day).to_contain_text("Ship mobile capture")
expect(first_day).to_contain_text("acme/mobile #41 · Issue · 30 min")
expect(first_day.locator("code")).to_have_count(0)
edit = first_day.locator("[data-week-edit-day]")
bounds = edit.bounding_box()
assert bounds and bounds["height"] >= 44
edit.click()
expect(page.locator("#week-review")).to_be_hidden()
expect(page.locator("#back-to-week-review")).to_be_visible()
expect(page.locator("#save-today-plan")).to_have_text("Save & review")
page.locator("#back-to-week-review").click()
expect(page.locator("#week-review")).to_be_visible()
expect(first_day).to_contain_text("Ship mobile capture")
page.wait_for_function("() => !document.querySelector('#confirm-week-plan').disabled")
confirm = page.locator("#confirm-week-plan")
bounds = confirm.bounding_box()
@@ -86,7 +104,7 @@ def test_release_artifact_plans_seven_touch_safe_mobile_dates(
confirm.click()
expect(page.locator("#plan-today-sheet")).to_be_hidden()
page.wait_for_function("() => document.querySelector('#mobile-week-summary').textContent !== 'Loading Week Ahead…'")
assert saved and len(saved[-1]["days"]) == 2
assert saved and len(saved[-1]["days"]) == 3
assert [day["plan_date"] for day in saved[-1]["days"]] == sorted(
day["plan_date"] for day in saved[-1]["days"]
)
+64
View File
@@ -173,6 +173,70 @@ console.log(JSON.stringify({advanced,reviewing:workflow.reviewing(),reviewMode,
assert "shared" in result["duplicates"]
def test_week_review_names_work_and_can_edit_a_day_then_return_to_review():
result = run_controller("""
const createWorkflow=createWeekPlan.Workflow;
const dates=['2026-08-21','2026-08-22','2026-08-23','2026-08-24','2026-08-25','2026-08-26','2026-08-27'];
const elements=new Map();
const makeElement=()=>({hidden:false,textContent:'',disabled:false,innerHTML:'',dataset:{},listeners:{},
addEventListener(name,listener){this.listeners[name]=listener;},focus(){this.focused=true;},
querySelectorAll:()=>[],querySelector:()=>null,scrollIntoView:()=>{}});
const dateRoot=makeElement();
Object.defineProperty(dateRoot,'innerHTML',{set(value){this.value=value;this.buttons=[...value.matchAll(/data-week-plan-date=\"([^\"]+)/g)].map(match=>({
dataset:{weekPlanDate:match[1]},addEventListener:()=>{},scrollIntoView:()=>{},focus:()=>{}
}));},get(){return this.value||'';}});
dateRoot.querySelectorAll=()=>dateRoot.buttons||[];
dateRoot.querySelector=selector=>(dateRoot.buttons||[]).find(button=>selector.includes(button.dataset.weekPlanDate))||null;
elements.set('#week-plan-dates',dateRoot);
const reviewDays=makeElement();
Object.defineProperty(reviewDays,'innerHTML',{set(value){
this.value=value;this.editButtons=[...value.matchAll(/data-week-edit-day=\"([^\"]+)/g)].map(match=>{
const button=makeElement();button.dataset.weekEditDay=match[1];return button;
});
},get(){return this.value||'';}});
reviewDays.querySelectorAll=selector=>selector==='[data-week-edit-day]'?reviewDays.editButtons||[]:[];
reviewDays.querySelector=selector=>(reviewDays.editButtons||[]).find(button=>selector.includes(button.dataset.weekEditDay))||null;
elements.set('#week-review-days',reviewDays);
for(const selector of ['#mobile-week-summary','#my-work-action-status','#week-plan-progress','#save-today-plan',
'#week-review','#week-review-duplicates','#confirm-week-plan','#week-review-status','#back-to-week-review']) {
if(!elements.has(selector))elements.set(selector,makeElement());
}
let reviewMode=false;
const review={days:dates.map((date,index)=>({plan_date:date,label:'Day '+(index+1),
ids:index===0?['issue:stackchain/dashboard:42:']:[],capacity_minutes:60,
estimates:index===0?{'issue:stackchain/dashboard:42:':30}:{},planned_minutes:index===0?30:0,overloaded:false})),
duplicates:[],can_confirm:true};
const controller={dates:()=>dates.map((date,index)=>({date,label:'Day '+(index+1)})),day:date=>review.days.find(day=>day.plan_date===date),
pass:date=>{const index=dates.indexOf(date);return {position:index+1,total:7,planned:1,next_date:dates[index+1]||null,last:index===6};},
load:async()=>({}),summary:()=> '1 item across 1 day',review:()=>review,pending:()=>false,move:()=>true,flush:async()=>({})};
const workflow=createWorkflow({controller,qs:selector=>elements.get(selector),getLogin:()=> 'timmy',
getItem:id=>id==='issue:stackchain/dashboard:42:'?{kind:'issue',title:'Fix mobile sign in',repository:'stackchain/dashboard',number:42}:null,
openPlanner:()=>{},setReviewMode:value=>{reviewMode=value;},escapeHtml:value=>value,escapeAttribute:value=>value,
todayWork:{replace:()=>{},replacePlanning:()=>{}},refresh:()=>{},warm:()=>{}});
await workflow.open({disabled:false});
for(let index=0;index<7;index++)workflow.advance();
const markup=reviewDays.innerHTML;
const edit=reviewDays.editButtons[0];edit.listeners.click();
const whileEditing={selected:workflow.selectedDate(),reviewing:workflow.reviewing(),reviewMode,
reviewHidden:elements.get('#week-review').hidden,backHidden:elements.get('#back-to-week-review').hidden};
elements.get('#back-to-week-review').listeners.click();
console.log(JSON.stringify({markup,whileEditing,after:{selected:workflow.selectedDate(),reviewing:workflow.reviewing(),reviewMode,
reviewHidden:elements.get('#week-review').hidden,editFocused:reviewDays.editButtons[0].focused}}));
""")
assert "Fix mobile sign in" in result["markup"]
assert "stackchain/dashboard #42 · Issue · 30 min" in result["markup"]
assert "<code>issue:stackchain/dashboard:42:</code>" not in result["markup"]
assert result["whileEditing"] == {
"selected": "2026-08-21", "reviewing": False, "reviewMode": False,
"reviewHidden": True, "backHidden": False,
}
assert result["after"] == {
"selected": None, "reviewing": True, "reviewMode": True,
"reviewHidden": False, "editFocused": True,
}
def test_week_controller_preserves_both_versions_when_another_device_changes_the_week():
result = run_controller("""
let calls=0;